Repository: eddycjy/go-gin-example Branch: master Commit: 4f5174ca325b Files: 932 Total size: 30.1 MB Directory structure: gitextract_tmwv_ouc/ ├── .gitignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── README_ZH.md ├── conf/ │ └── app.ini ├── docs/ │ ├── docs.go │ ├── sql/ │ │ └── blog.sql │ ├── swagger/ │ │ ├── swagger.json │ │ └── swagger.yaml │ ├── swagger.json │ └── swagger.yaml ├── go.mod ├── go.sum ├── main.go ├── middleware/ │ └── jwt/ │ └── jwt.go ├── models/ │ ├── article.go │ ├── auth.go │ ├── models.go │ └── tag.go ├── pkg/ │ ├── app/ │ │ ├── form.go │ │ ├── request.go │ │ └── response.go │ ├── e/ │ │ ├── cache.go │ │ ├── code.go │ │ └── msg.go │ ├── export/ │ │ └── excel.go │ ├── file/ │ │ └── file.go │ ├── gredis/ │ │ └── redis.go │ ├── logging/ │ │ ├── file.go │ │ └── log.go │ ├── qrcode/ │ │ └── qrcode.go │ ├── setting/ │ │ └── setting.go │ ├── upload/ │ │ └── image.go │ └── util/ │ ├── jwt.go │ ├── md5.go │ ├── pagination.go │ └── util.go ├── routers/ │ ├── api/ │ │ ├── auth.go │ │ ├── upload.go │ │ └── v1/ │ │ ├── article.go │ │ └── tag.go │ └── router.go ├── runtime/ │ └── fonts/ │ └── msyhbd.ttc ├── service/ │ ├── article_service/ │ │ ├── article.go │ │ └── article_poster.go │ ├── auth_service/ │ │ └── auth.go │ ├── cache_service/ │ │ ├── article.go │ │ └── tag.go │ └── tag_service/ │ └── tag.go └── vendor/ ├── github.com/ │ ├── 360EntSecGroup-Skylar/ │ │ └── excelize/ │ │ ├── .travis.yml │ │ ├── CODE_OF_CONDUCT.md │ │ ├── CONTRIBUTING.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── README_zh.md │ │ ├── cell.go │ │ ├── chart.go │ │ ├── col.go │ │ ├── comment.go │ │ ├── date.go │ │ ├── excelize.go │ │ ├── file.go │ │ ├── lib.go │ │ ├── picture.go │ │ ├── rows.go │ │ ├── shape.go │ │ ├── sheet.go │ │ ├── sheetpr.go │ │ ├── sheetview.go │ │ ├── styles.go │ │ ├── table.go │ │ ├── templates.go │ │ ├── vmlDrawing.go │ │ ├── xmlChart.go │ │ ├── xmlComments.go │ │ ├── xmlContentTypes.go │ │ ├── xmlDecodeDrawing.go │ │ ├── xmlDrawing.go │ │ ├── xmlSharedStrings.go │ │ ├── xmlStyles.go │ │ ├── xmlTable.go │ │ ├── xmlWorkbook.go │ │ └── xmlWorksheet.go │ ├── PuerkitoBio/ │ │ ├── purell/ │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ └── purell.go │ │ └── urlesc/ │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ └── urlesc.go │ ├── Unknwon/ │ │ └── com/ │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── cmd.go │ │ ├── convert.go │ │ ├── dir.go │ │ ├── file.go │ │ ├── html.go │ │ ├── http.go │ │ ├── math.go │ │ ├── path.go │ │ ├── regex.go │ │ ├── slice.go │ │ ├── string.go │ │ ├── time.go │ │ └── url.go │ ├── alecthomas/ │ │ └── template/ │ │ ├── LICENSE │ │ ├── README.md │ │ ├── doc.go │ │ ├── exec.go │ │ ├── funcs.go │ │ ├── go.mod │ │ ├── helper.go │ │ ├── parse/ │ │ │ ├── lex.go │ │ │ ├── node.go │ │ │ └── parse.go │ │ └── template.go │ ├── astaxie/ │ │ └── beego/ │ │ ├── LICENSE │ │ └── validation/ │ │ ├── README.md │ │ ├── util.go │ │ ├── validation.go │ │ └── validators.go │ ├── boombuler/ │ │ └── barcode/ │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── barcode.go │ │ ├── qr/ │ │ │ ├── alphanumeric.go │ │ │ ├── automatic.go │ │ │ ├── blocks.go │ │ │ ├── encoder.go │ │ │ ├── errorcorrection.go │ │ │ ├── numeric.go │ │ │ ├── qrcode.go │ │ │ ├── unicode.go │ │ │ └── versioninfo.go │ │ ├── scaledbarcode.go │ │ └── utils/ │ │ ├── base1dcode.go │ │ ├── bitlist.go │ │ ├── galoisfield.go │ │ ├── gfpoly.go │ │ ├── reedsolomon.go │ │ └── runeint.go │ ├── dgrijalva/ │ │ └── jwt-go/ │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── MIGRATION_GUIDE.md │ │ ├── README.md │ │ ├── VERSION_HISTORY.md │ │ ├── claims.go │ │ ├── doc.go │ │ ├── ecdsa.go │ │ ├── ecdsa_utils.go │ │ ├── errors.go │ │ ├── hmac.go │ │ ├── map_claims.go │ │ ├── none.go │ │ ├── parser.go │ │ ├── rsa.go │ │ ├── rsa_pss.go │ │ ├── rsa_utils.go │ │ ├── signing_method.go │ │ └── token.go │ ├── gin-contrib/ │ │ └── sse/ │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── go.mod │ │ ├── go.sum │ │ ├── sse-decoder.go │ │ ├── sse-encoder.go │ │ └── writer.go │ ├── gin-gonic/ │ │ └── gin/ │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── AUTHORS.md │ │ ├── BENCHMARKS.md │ │ ├── CHANGELOG.md │ │ ├── CODE_OF_CONDUCT.md │ │ ├── CONTRIBUTING.md │ │ ├── LICENSE │ │ ├── Makefile │ │ ├── README.md │ │ ├── auth.go │ │ ├── binding/ │ │ │ ├── binding.go │ │ │ ├── default_validator.go │ │ │ ├── form.go │ │ │ ├── form_mapping.go │ │ │ ├── json.go │ │ │ ├── msgpack.go │ │ │ ├── protobuf.go │ │ │ ├── query.go │ │ │ ├── uri.go │ │ │ ├── xml.go │ │ │ └── yaml.go │ │ ├── codecov.yml │ │ ├── context.go │ │ ├── context_appengine.go │ │ ├── debug.go │ │ ├── deprecated.go │ │ ├── doc.go │ │ ├── errors.go │ │ ├── fs.go │ │ ├── gin.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── internal/ │ │ │ └── json/ │ │ │ ├── json.go │ │ │ └── jsoniter.go │ │ ├── logger.go │ │ ├── mode.go │ │ ├── path.go │ │ ├── recovery.go │ │ ├── render/ │ │ │ ├── data.go │ │ │ ├── html.go │ │ │ ├── json.go │ │ │ ├── msgpack.go │ │ │ ├── protobuf.go │ │ │ ├── reader.go │ │ │ ├── redirect.go │ │ │ ├── render.go │ │ │ ├── text.go │ │ │ ├── xml.go │ │ │ └── yaml.go │ │ ├── response_writer.go │ │ ├── routergroup.go │ │ ├── test_helpers.go │ │ ├── tree.go │ │ ├── utils.go │ │ └── version.go │ ├── go-ini/ │ │ └── ini/ │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── Makefile │ │ ├── README.md │ │ ├── README_ZH.md │ │ ├── error.go │ │ ├── file.go │ │ ├── ini.go │ │ ├── key.go │ │ ├── parser.go │ │ ├── section.go │ │ └── struct.go │ ├── go-openapi/ │ │ ├── jsonpointer/ │ │ │ ├── .editorconfig │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── CODE_OF_CONDUCT.md │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ └── pointer.go │ │ ├── jsonreference/ │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── CODE_OF_CONDUCT.md │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ └── reference.go │ │ └── spec/ │ │ ├── .editorconfig │ │ ├── .gitignore │ │ ├── .golangci.yml │ │ ├── .travis.yml │ │ ├── CODE_OF_CONDUCT.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bindata.go │ │ ├── cache.go │ │ ├── contact_info.go │ │ ├── debug.go │ │ ├── expander.go │ │ ├── external_docs.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── header.go │ │ ├── info.go │ │ ├── items.go │ │ ├── license.go │ │ ├── normalizer.go │ │ ├── operation.go │ │ ├── parameter.go │ │ ├── path_item.go │ │ ├── paths.go │ │ ├── ref.go │ │ ├── response.go │ │ ├── responses.go │ │ ├── schema.go │ │ ├── schema_loader.go │ │ ├── security_scheme.go │ │ ├── spec.go │ │ ├── swagger.go │ │ ├── tag.go │ │ ├── unused.go │ │ └── xml_object.go │ ├── go-sql-driver/ │ │ └── mysql/ │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── AUTHORS │ │ ├── CHANGELOG.md │ │ ├── CONTRIBUTING.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── appengine.go │ │ ├── auth.go │ │ ├── buffer.go │ │ ├── collations.go │ │ ├── conncheck.go │ │ ├── conncheck_dummy.go │ │ ├── connection.go │ │ ├── connector.go │ │ ├── const.go │ │ ├── driver.go │ │ ├── driver_go110.go │ │ ├── dsn.go │ │ ├── errors.go │ │ ├── fields.go │ │ ├── infile.go │ │ ├── packets.go │ │ ├── result.go │ │ ├── rows.go │ │ ├── statement.go │ │ ├── transaction.go │ │ └── utils.go │ ├── golang/ │ │ ├── freetype/ │ │ │ ├── AUTHORS │ │ │ ├── CONTRIBUTORS │ │ │ ├── LICENSE │ │ │ ├── README │ │ │ ├── freetype.go │ │ │ ├── raster/ │ │ │ │ ├── geom.go │ │ │ │ ├── paint.go │ │ │ │ ├── raster.go │ │ │ │ └── stroke.go │ │ │ └── truetype/ │ │ │ ├── face.go │ │ │ ├── glyph.go │ │ │ ├── hint.go │ │ │ ├── opcodes.go │ │ │ └── truetype.go │ │ └── protobuf/ │ │ ├── AUTHORS │ │ ├── CONTRIBUTORS │ │ ├── LICENSE │ │ └── proto/ │ │ ├── clone.go │ │ ├── decode.go │ │ ├── deprecated.go │ │ ├── discard.go │ │ ├── encode.go │ │ ├── equal.go │ │ ├── extensions.go │ │ ├── lib.go │ │ ├── message_set.go │ │ ├── pointer_reflect.go │ │ ├── pointer_unsafe.go │ │ ├── properties.go │ │ ├── table_marshal.go │ │ ├── table_merge.go │ │ ├── table_unmarshal.go │ │ ├── text.go │ │ └── text_parser.go │ ├── gomodule/ │ │ └── redigo/ │ │ ├── LICENSE │ │ ├── internal/ │ │ │ └── commandinfo.go │ │ └── redis/ │ │ ├── conn.go │ │ ├── doc.go │ │ ├── go16.go │ │ ├── go17.go │ │ ├── go18.go │ │ ├── log.go │ │ ├── pool.go │ │ ├── pool17.go │ │ ├── pubsub.go │ │ ├── redis.go │ │ ├── reply.go │ │ ├── scan.go │ │ └── script.go │ ├── jinzhu/ │ │ ├── gorm/ │ │ │ ├── .codeclimate.yml │ │ │ ├── .gitignore │ │ │ ├── License │ │ │ ├── README.md │ │ │ ├── association.go │ │ │ ├── callback.go │ │ │ ├── callback_create.go │ │ │ ├── callback_delete.go │ │ │ ├── callback_query.go │ │ │ ├── callback_query_preload.go │ │ │ ├── callback_row_query.go │ │ │ ├── callback_save.go │ │ │ ├── callback_update.go │ │ │ ├── dialect.go │ │ │ ├── dialect_common.go │ │ │ ├── dialect_mysql.go │ │ │ ├── dialect_postgres.go │ │ │ ├── dialect_sqlite3.go │ │ │ ├── dialects/ │ │ │ │ └── mysql/ │ │ │ │ └── mysql.go │ │ │ ├── docker-compose.yml │ │ │ ├── errors.go │ │ │ ├── field.go │ │ │ ├── interface.go │ │ │ ├── join_table_handler.go │ │ │ ├── logger.go │ │ │ ├── main.go │ │ │ ├── model.go │ │ │ ├── model_struct.go │ │ │ ├── scope.go │ │ │ ├── search.go │ │ │ ├── test_all.sh │ │ │ ├── utils.go │ │ │ └── wercker.yml │ │ └── inflection/ │ │ ├── LICENSE │ │ ├── README.md │ │ └── inflections.go │ ├── mailru/ │ │ └── easyjson/ │ │ ├── LICENSE │ │ ├── buffer/ │ │ │ └── pool.go │ │ ├── jlexer/ │ │ │ ├── bytestostr.go │ │ │ ├── bytestostr_nounsafe.go │ │ │ ├── error.go │ │ │ └── lexer.go │ │ └── jwriter/ │ │ └── writer.go │ ├── mattn/ │ │ └── go-isatty/ │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── doc.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── isatty_android.go │ │ ├── isatty_bsd.go │ │ ├── isatty_others.go │ │ ├── isatty_solaris.go │ │ ├── isatty_tcgets.go │ │ └── isatty_windows.go │ ├── modern-go/ │ │ └── concurrent/ │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── executor.go │ │ ├── go_above_19.go │ │ ├── go_below_19.go │ │ ├── log.go │ │ ├── test.sh │ │ └── unbounded_executor.go │ ├── pkg/ │ │ └── errors/ │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── appveyor.yml │ │ ├── errors.go │ │ └── stack.go │ ├── swaggo/ │ │ └── swag/ │ │ ├── .gitignore │ │ ├── .goreleaser.yml │ │ ├── .travis.yml │ │ ├── CODE_OF_CONDUCT.md │ │ ├── CONTRIBUTING.md │ │ ├── Makefile │ │ ├── PULL_REQUEST_TEMPLATE.md │ │ ├── README.md │ │ ├── debug.go │ │ ├── doc.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── license │ │ ├── operation.go │ │ ├── parser.go │ │ ├── property.go │ │ ├── schema.go │ │ ├── swagger.go │ │ └── version.go │ ├── tealeg/ │ │ └── xlsx/ │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── AUTHORS.txt │ │ ├── CODE_OF_CONDUCT.md │ │ ├── LICENSE │ │ ├── README.org │ │ ├── cell.go │ │ ├── col.go │ │ ├── date.go │ │ ├── doc.go │ │ ├── file.go │ │ ├── format_code.go │ │ ├── hsl.go │ │ ├── lib.go │ │ ├── read.go │ │ ├── reftable.go │ │ ├── row.go │ │ ├── sheet.go │ │ ├── stream_file.go │ │ ├── stream_file_builder.go │ │ ├── style.go │ │ ├── templates.go │ │ ├── theme.go │ │ ├── write.go │ │ ├── xmlContentTypes.go │ │ ├── xmlSharedStrings.go │ │ ├── xmlStyle.go │ │ ├── xmlTheme.go │ │ ├── xmlWorkbook.go │ │ └── xmlWorksheet.go │ ├── ugorji/ │ │ └── go/ │ │ └── codec/ │ │ ├── 0_importpath.go │ │ ├── LICENSE │ │ ├── binc.go │ │ ├── build.sh │ │ ├── cbor.go │ │ ├── codecgen.go │ │ ├── decode.go │ │ ├── doc.go │ │ ├── encode.go │ │ ├── fast-path.generated.go │ │ ├── fast-path.go.tmpl │ │ ├── fast-path.not.go │ │ ├── gen-dec-array.go.tmpl │ │ ├── gen-dec-map.go.tmpl │ │ ├── gen-enc-chan.go.tmpl │ │ ├── gen-helper.generated.go │ │ ├── gen-helper.go.tmpl │ │ ├── gen.generated.go │ │ ├── gen.go │ │ ├── go.mod │ │ ├── goversion_arrayof_gte_go15.go │ │ ├── goversion_arrayof_lt_go15.go │ │ ├── goversion_makemap_gte_go19.go │ │ ├── goversion_makemap_lt_go19.go │ │ ├── goversion_unexportedembeddedptr_gte_go110.go │ │ ├── goversion_unexportedembeddedptr_lt_go110.go │ │ ├── goversion_unsupported_lt_go14.go │ │ ├── goversion_vendor_eq_go15.go │ │ ├── goversion_vendor_eq_go16.go │ │ ├── goversion_vendor_gte_go17.go │ │ ├── goversion_vendor_lt_go15.go │ │ ├── helper.go │ │ ├── helper_internal.go │ │ ├── helper_not_unsafe.go │ │ ├── helper_unsafe.go │ │ ├── json.go │ │ ├── mammoth-test.go.tmpl │ │ ├── mammoth2-test.go.tmpl │ │ ├── msgpack.go │ │ ├── prebuild.go │ │ ├── rpc.go │ │ ├── simple.go │ │ ├── sort-slice.generated.go │ │ ├── sort-slice.go.tmpl │ │ ├── test-cbor-goldens.json │ │ └── test.py │ └── unknwon/ │ └── com/ │ ├── go.mod │ └── go.sum ├── golang.org/ │ └── x/ │ ├── image/ │ │ ├── AUTHORS │ │ ├── CONTRIBUTORS │ │ ├── LICENSE │ │ ├── PATENTS │ │ ├── font/ │ │ │ └── font.go │ │ └── math/ │ │ └── fixed/ │ │ └── fixed.go │ ├── net/ │ │ ├── AUTHORS │ │ ├── CONTRIBUTORS │ │ ├── LICENSE │ │ ├── PATENTS │ │ ├── context/ │ │ │ ├── context.go │ │ │ ├── go17.go │ │ │ ├── go19.go │ │ │ ├── pre_go17.go │ │ │ └── pre_go19.go │ │ ├── idna/ │ │ │ ├── idna10.0.0.go │ │ │ ├── idna9.0.0.go │ │ │ ├── punycode.go │ │ │ ├── tables10.0.0.go │ │ │ ├── tables11.0.0.go │ │ │ ├── tables9.0.0.go │ │ │ ├── trie.go │ │ │ └── trieval.go │ │ └── webdav/ │ │ ├── file.go │ │ ├── if.go │ │ ├── internal/ │ │ │ └── xml/ │ │ │ ├── README │ │ │ ├── marshal.go │ │ │ ├── read.go │ │ │ ├── typeinfo.go │ │ │ └── xml.go │ │ ├── lock.go │ │ ├── prop.go │ │ ├── webdav.go │ │ └── xml.go │ ├── sys/ │ │ ├── AUTHORS │ │ ├── CONTRIBUTORS │ │ ├── LICENSE │ │ ├── PATENTS │ │ └── unix/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── affinity_linux.go │ │ ├── aliases.go │ │ ├── asm_aix_ppc64.s │ │ ├── asm_darwin_386.s │ │ ├── asm_darwin_amd64.s │ │ ├── asm_darwin_arm.s │ │ ├── asm_darwin_arm64.s │ │ ├── asm_dragonfly_amd64.s │ │ ├── asm_freebsd_386.s │ │ ├── asm_freebsd_amd64.s │ │ ├── asm_freebsd_arm.s │ │ ├── asm_freebsd_arm64.s │ │ ├── asm_linux_386.s │ │ ├── asm_linux_amd64.s │ │ ├── asm_linux_arm.s │ │ ├── asm_linux_arm64.s │ │ ├── asm_linux_mips64x.s │ │ ├── asm_linux_mipsx.s │ │ ├── asm_linux_ppc64x.s │ │ ├── asm_linux_riscv64.s │ │ ├── asm_linux_s390x.s │ │ ├── asm_netbsd_386.s │ │ ├── asm_netbsd_amd64.s │ │ ├── asm_netbsd_arm.s │ │ ├── asm_netbsd_arm64.s │ │ ├── asm_openbsd_386.s │ │ ├── asm_openbsd_amd64.s │ │ ├── asm_openbsd_arm.s │ │ ├── asm_openbsd_arm64.s │ │ ├── asm_solaris_amd64.s │ │ ├── bluetooth_linux.go │ │ ├── cap_freebsd.go │ │ ├── constants.go │ │ ├── dev_aix_ppc.go │ │ ├── dev_aix_ppc64.go │ │ ├── dev_darwin.go │ │ ├── dev_dragonfly.go │ │ ├── dev_freebsd.go │ │ ├── dev_linux.go │ │ ├── dev_netbsd.go │ │ ├── dev_openbsd.go │ │ ├── dirent.go │ │ ├── endian_big.go │ │ ├── endian_little.go │ │ ├── env_unix.go │ │ ├── errors_freebsd_386.go │ │ ├── errors_freebsd_amd64.go │ │ ├── errors_freebsd_arm.go │ │ ├── fcntl.go │ │ ├── fcntl_darwin.go │ │ ├── fcntl_linux_32bit.go │ │ ├── gccgo.go │ │ ├── gccgo_c.c │ │ ├── gccgo_linux_amd64.go │ │ ├── ioctl.go │ │ ├── mkall.sh │ │ ├── mkerrors.sh │ │ ├── pagesize_unix.go │ │ ├── pledge_openbsd.go │ │ ├── race.go │ │ ├── race0.go │ │ ├── readdirent_getdents.go │ │ ├── readdirent_getdirentries.go │ │ ├── sockcmsg_linux.go │ │ ├── sockcmsg_unix.go │ │ ├── str.go │ │ ├── syscall.go │ │ ├── syscall_aix.go │ │ ├── syscall_aix_ppc.go │ │ ├── syscall_aix_ppc64.go │ │ ├── syscall_bsd.go │ │ ├── syscall_darwin.go │ │ ├── syscall_darwin_386.go │ │ ├── syscall_darwin_amd64.go │ │ ├── syscall_darwin_arm.go │ │ ├── syscall_darwin_arm64.go │ │ ├── syscall_darwin_libSystem.go │ │ ├── syscall_dragonfly.go │ │ ├── syscall_dragonfly_amd64.go │ │ ├── syscall_freebsd.go │ │ ├── syscall_freebsd_386.go │ │ ├── syscall_freebsd_amd64.go │ │ ├── syscall_freebsd_arm.go │ │ ├── syscall_freebsd_arm64.go │ │ ├── syscall_linux.go │ │ ├── syscall_linux_386.go │ │ ├── syscall_linux_amd64.go │ │ ├── syscall_linux_amd64_gc.go │ │ ├── syscall_linux_arm.go │ │ ├── syscall_linux_arm64.go │ │ ├── syscall_linux_gc.go │ │ ├── syscall_linux_gc_386.go │ │ ├── syscall_linux_gccgo_386.go │ │ ├── syscall_linux_gccgo_arm.go │ │ ├── syscall_linux_mips64x.go │ │ ├── syscall_linux_mipsx.go │ │ ├── syscall_linux_ppc64x.go │ │ ├── syscall_linux_riscv64.go │ │ ├── syscall_linux_s390x.go │ │ ├── syscall_linux_sparc64.go │ │ ├── syscall_netbsd.go │ │ ├── syscall_netbsd_386.go │ │ ├── syscall_netbsd_amd64.go │ │ ├── syscall_netbsd_arm.go │ │ ├── syscall_netbsd_arm64.go │ │ ├── syscall_openbsd.go │ │ ├── syscall_openbsd_386.go │ │ ├── syscall_openbsd_amd64.go │ │ ├── syscall_openbsd_arm.go │ │ ├── syscall_openbsd_arm64.go │ │ ├── syscall_solaris.go │ │ ├── syscall_solaris_amd64.go │ │ ├── syscall_unix.go │ │ ├── syscall_unix_gc.go │ │ ├── syscall_unix_gc_ppc64x.go │ │ ├── timestruct.go │ │ ├── unveil_openbsd.go │ │ ├── xattr_bsd.go │ │ ├── zerrors_aix_ppc.go │ │ ├── zerrors_aix_ppc64.go │ │ ├── zerrors_darwin_386.go │ │ ├── zerrors_darwin_amd64.go │ │ ├── zerrors_darwin_arm.go │ │ ├── zerrors_darwin_arm64.go │ │ ├── zerrors_dragonfly_amd64.go │ │ ├── zerrors_freebsd_386.go │ │ ├── zerrors_freebsd_amd64.go │ │ ├── zerrors_freebsd_arm.go │ │ ├── zerrors_freebsd_arm64.go │ │ ├── zerrors_linux_386.go │ │ ├── zerrors_linux_amd64.go │ │ ├── zerrors_linux_arm.go │ │ ├── zerrors_linux_arm64.go │ │ ├── zerrors_linux_mips.go │ │ ├── zerrors_linux_mips64.go │ │ ├── zerrors_linux_mips64le.go │ │ ├── zerrors_linux_mipsle.go │ │ ├── zerrors_linux_ppc64.go │ │ ├── zerrors_linux_ppc64le.go │ │ ├── zerrors_linux_riscv64.go │ │ ├── zerrors_linux_s390x.go │ │ ├── zerrors_linux_sparc64.go │ │ ├── zerrors_netbsd_386.go │ │ ├── zerrors_netbsd_amd64.go │ │ ├── zerrors_netbsd_arm.go │ │ ├── zerrors_netbsd_arm64.go │ │ ├── zerrors_openbsd_386.go │ │ ├── zerrors_openbsd_amd64.go │ │ ├── zerrors_openbsd_arm.go │ │ ├── zerrors_openbsd_arm64.go │ │ ├── zerrors_solaris_amd64.go │ │ ├── zptrace386_linux.go │ │ ├── zptracearm_linux.go │ │ ├── zptracemips_linux.go │ │ ├── zptracemipsle_linux.go │ │ ├── zsyscall_aix_ppc.go │ │ ├── zsyscall_aix_ppc64.go │ │ ├── zsyscall_aix_ppc64_gc.go │ │ ├── zsyscall_aix_ppc64_gccgo.go │ │ ├── zsyscall_darwin_386.1_11.go │ │ ├── zsyscall_darwin_386.go │ │ ├── zsyscall_darwin_386.s │ │ ├── zsyscall_darwin_amd64.1_11.go │ │ ├── zsyscall_darwin_amd64.go │ │ ├── zsyscall_darwin_amd64.s │ │ ├── zsyscall_darwin_arm.1_11.go │ │ ├── zsyscall_darwin_arm.go │ │ ├── zsyscall_darwin_arm.s │ │ ├── zsyscall_darwin_arm64.1_11.go │ │ ├── zsyscall_darwin_arm64.go │ │ ├── zsyscall_darwin_arm64.s │ │ ├── zsyscall_dragonfly_amd64.go │ │ ├── zsyscall_freebsd_386.go │ │ ├── zsyscall_freebsd_amd64.go │ │ ├── zsyscall_freebsd_arm.go │ │ ├── zsyscall_freebsd_arm64.go │ │ ├── zsyscall_linux_386.go │ │ ├── zsyscall_linux_amd64.go │ │ ├── zsyscall_linux_arm.go │ │ ├── zsyscall_linux_arm64.go │ │ ├── zsyscall_linux_mips.go │ │ ├── zsyscall_linux_mips64.go │ │ ├── zsyscall_linux_mips64le.go │ │ ├── zsyscall_linux_mipsle.go │ │ ├── zsyscall_linux_ppc64.go │ │ ├── zsyscall_linux_ppc64le.go │ │ ├── zsyscall_linux_riscv64.go │ │ ├── zsyscall_linux_s390x.go │ │ ├── zsyscall_linux_sparc64.go │ │ ├── zsyscall_netbsd_386.go │ │ ├── zsyscall_netbsd_amd64.go │ │ ├── zsyscall_netbsd_arm.go │ │ ├── zsyscall_netbsd_arm64.go │ │ ├── zsyscall_openbsd_386.go │ │ ├── zsyscall_openbsd_amd64.go │ │ ├── zsyscall_openbsd_arm.go │ │ ├── zsyscall_openbsd_arm64.go │ │ ├── zsyscall_solaris_amd64.go │ │ ├── zsysctl_openbsd_386.go │ │ ├── zsysctl_openbsd_amd64.go │ │ ├── zsysctl_openbsd_arm.go │ │ ├── zsysctl_openbsd_arm64.go │ │ ├── zsysnum_darwin_386.go │ │ ├── zsysnum_darwin_amd64.go │ │ ├── zsysnum_darwin_arm.go │ │ ├── zsysnum_darwin_arm64.go │ │ ├── zsysnum_dragonfly_amd64.go │ │ ├── zsysnum_freebsd_386.go │ │ ├── zsysnum_freebsd_amd64.go │ │ ├── zsysnum_freebsd_arm.go │ │ ├── zsysnum_freebsd_arm64.go │ │ ├── zsysnum_linux_386.go │ │ ├── zsysnum_linux_amd64.go │ │ ├── zsysnum_linux_arm.go │ │ ├── zsysnum_linux_arm64.go │ │ ├── zsysnum_linux_mips.go │ │ ├── zsysnum_linux_mips64.go │ │ ├── zsysnum_linux_mips64le.go │ │ ├── zsysnum_linux_mipsle.go │ │ ├── zsysnum_linux_ppc64.go │ │ ├── zsysnum_linux_ppc64le.go │ │ ├── zsysnum_linux_riscv64.go │ │ ├── zsysnum_linux_s390x.go │ │ ├── zsysnum_linux_sparc64.go │ │ ├── zsysnum_netbsd_386.go │ │ ├── zsysnum_netbsd_amd64.go │ │ ├── zsysnum_netbsd_arm.go │ │ ├── zsysnum_netbsd_arm64.go │ │ ├── zsysnum_openbsd_386.go │ │ ├── zsysnum_openbsd_amd64.go │ │ ├── zsysnum_openbsd_arm.go │ │ ├── zsysnum_openbsd_arm64.go │ │ ├── ztypes_aix_ppc.go │ │ ├── ztypes_aix_ppc64.go │ │ ├── ztypes_darwin_386.go │ │ ├── ztypes_darwin_amd64.go │ │ ├── ztypes_darwin_arm.go │ │ ├── ztypes_darwin_arm64.go │ │ ├── ztypes_dragonfly_amd64.go │ │ ├── ztypes_freebsd_386.go │ │ ├── ztypes_freebsd_amd64.go │ │ ├── ztypes_freebsd_arm.go │ │ ├── ztypes_freebsd_arm64.go │ │ ├── ztypes_linux_386.go │ │ ├── ztypes_linux_amd64.go │ │ ├── ztypes_linux_arm.go │ │ ├── ztypes_linux_arm64.go │ │ ├── ztypes_linux_mips.go │ │ ├── ztypes_linux_mips64.go │ │ ├── ztypes_linux_mips64le.go │ │ ├── ztypes_linux_mipsle.go │ │ ├── ztypes_linux_ppc64.go │ │ ├── ztypes_linux_ppc64le.go │ │ ├── ztypes_linux_riscv64.go │ │ ├── ztypes_linux_s390x.go │ │ ├── ztypes_linux_sparc64.go │ │ ├── ztypes_netbsd_386.go │ │ ├── ztypes_netbsd_amd64.go │ │ ├── ztypes_netbsd_arm.go │ │ ├── ztypes_netbsd_arm64.go │ │ ├── ztypes_openbsd_386.go │ │ ├── ztypes_openbsd_amd64.go │ │ ├── ztypes_openbsd_arm.go │ │ ├── ztypes_openbsd_arm64.go │ │ └── ztypes_solaris_amd64.go │ ├── text/ │ │ ├── AUTHORS │ │ ├── CONTRIBUTORS │ │ ├── LICENSE │ │ ├── PATENTS │ │ ├── secure/ │ │ │ └── bidirule/ │ │ │ ├── bidirule.go │ │ │ ├── bidirule10.0.0.go │ │ │ └── bidirule9.0.0.go │ │ ├── transform/ │ │ │ └── transform.go │ │ ├── unicode/ │ │ │ ├── bidi/ │ │ │ │ ├── bidi.go │ │ │ │ ├── bracket.go │ │ │ │ ├── core.go │ │ │ │ ├── prop.go │ │ │ │ ├── tables10.0.0.go │ │ │ │ ├── tables11.0.0.go │ │ │ │ ├── tables9.0.0.go │ │ │ │ └── trieval.go │ │ │ └── norm/ │ │ │ ├── composition.go │ │ │ ├── forminfo.go │ │ │ ├── input.go │ │ │ ├── iter.go │ │ │ ├── normalize.go │ │ │ ├── readwriter.go │ │ │ ├── tables10.0.0.go │ │ │ ├── tables11.0.0.go │ │ │ ├── tables9.0.0.go │ │ │ ├── transform.go │ │ │ └── trie.go │ │ └── width/ │ │ ├── kind_string.go │ │ ├── tables10.0.0.go │ │ ├── tables11.0.0.go │ │ ├── tables9.0.0.go │ │ ├── transform.go │ │ ├── trieval.go │ │ └── width.go │ └── tools/ │ ├── AUTHORS │ ├── CONTRIBUTORS │ ├── LICENSE │ ├── PATENTS │ └── go/ │ ├── ast/ │ │ └── astutil/ │ │ ├── enclosing.go │ │ ├── imports.go │ │ ├── rewrite.go │ │ └── util.go │ ├── buildutil/ │ │ ├── allpackages.go │ │ ├── fakecontext.go │ │ ├── overlay.go │ │ ├── tags.go │ │ └── util.go │ ├── internal/ │ │ └── cgo/ │ │ ├── cgo.go │ │ └── cgo_pkgconfig.go │ └── loader/ │ ├── doc.go │ ├── loader.go │ └── util.go ├── google.golang.org/ │ └── appengine/ │ ├── LICENSE │ └── cloudsql/ │ ├── cloudsql.go │ ├── cloudsql_classic.go │ └── cloudsql_vm.go ├── gopkg.in/ │ ├── go-playground/ │ │ └── validator.v8/ │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── baked_in.go │ │ ├── cache.go │ │ ├── doc.go │ │ ├── regexes.go │ │ ├── util.go │ │ └── validator.go │ └── yaml.v2/ │ ├── .travis.yml │ ├── LICENSE │ ├── LICENSE.libyaml │ ├── NOTICE │ ├── README.md │ ├── apic.go │ ├── decode.go │ ├── emitterc.go │ ├── encode.go │ ├── go.mod │ ├── parserc.go │ ├── readerc.go │ ├── resolve.go │ ├── scannerc.go │ ├── sorter.go │ ├── writerc.go │ ├── yaml.go │ ├── yamlh.go │ └── yamlprivateh.go └── modules.txt ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .idea/ .DS_Store runtime/* !runtime/qrcode/bg.jpg !runtime/fonts ================================================ FILE: Dockerfile ================================================ FROM golang:latest ENV GOPROXY https://goproxy.cn,direct WORKDIR $GOPATH/src/github.com/EDDYCJY/go-gin-example COPY . $GOPATH/src/github.com/EDDYCJY/go-gin-example RUN go build . EXPOSE 8000 ENTRYPOINT ["./go-gin-example"] ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) The go-gin-example Authors 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. ================================================ FILE: Makefile ================================================ .PHONY: build clean tool lint help all: build build: @go build -v . tool: go vet ./...; true gofmt -w . lint: golint ./... clean: rm -rf go-gin-example go clean -i . help: @echo "make: compile packages and dependencies" @echo "make tool: run specified go tool" @echo "make lint: golint ./..." @echo "make clean: remove object files and cached files" ================================================ FILE: README.md ================================================ # Go Gin Example - Blog API[![rcard](https://goreportcard.com/badge/github.com/EDDYCJY/go-gin-example)](https://goreportcard.com/report/github.com/EDDYCJY/go-gin-example) [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](https://godoc.org/github.com/EDDYCJY/go-gin-example) [![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/EDDYCJY/go-gin-example/master/LICENSE) A production-ready RESTful blog API example built with Go and Gin framework, demonstrating real-world patterns and best practices. [简体中文](https://github.com/EDDYCJY/go-gin-example/blob/master/README_ZH.md) ## Project Overview This project is a comprehensive blog backend API system that provides complete article and tag management functionalities, along with features like JWT authentication, image upload, QR code generation, and Excel import/export. ## Tech Stack | Category | Technology | |----------|------------| | Language | Go | | Web Framework | [Gin](https://github.com/gin-gonic/gin) | | ORM | [GORM](https://github.com/jinzhu/gorm) | | Database | MySQL | | Cache | Redis (via [Redigo](https://github.com/gomodule/redigo)) | | Authentication | JWT ([jwt-go](https://github.com/dgrijalva/jwt-go)) | | Configuration | [go-ini](https://github.com/go-ini/ini) | | API Documentation | [Swagger](https://github.com/swaggo/gin-swagger) | | Excel Processing | [excelize](https://github.com/360EntSecGroup-Skylar/excelize), [xlsx](https://github.com/tealeg/xlsx) | | Image Processing | [freetype](https://github.com/golang/freetype), [barcode](https://github.com/boombuler/barcode) | | Validation | [beego/validation](https://github.com/astaxie/beego/validation) | ## Project Structure ``` go-gin-example/ ├── conf/ # Configuration files │ └── app.ini # Application configuration ├── docs/ # Documentation │ ├── sql/ # Database scripts │ │ └── blog.sql # Database schema │ └── swagger/ # Swagger documentation ├── middleware/ # Middleware │ └── jwt/ # JWT authentication middleware │ └── jwt.go ├── models/ # Data models (ORM) │ ├── article.go # Article model │ ├── auth.go # Auth model │ ├── models.go # Database initialization │ └── tag.go # Tag model ├── pkg/ # Shared packages │ ├── app/ # Application utilities │ │ ├── form.go # Form binding │ │ ├── request.go # Request handling │ │ └── response.go # Response formatting │ ├── e/ # Error codes │ │ ├── cache.go # Cache key constants │ │ ├── code.go # Error code definitions │ │ └── msg.go # Error messages │ ├── export/ # Excel export utilities │ │ └── excel.go │ ├── file/ # File utilities │ │ └── file.go │ ├── gredis/ # Redis client │ │ └── redis.go │ ├── logging/ # Logging utilities │ │ ├── file.go │ │ └── log.go │ ├── qrcode/ # QR code generation │ │ └── qrcode.go │ ├── setting/ # Configuration management │ │ └── setting.go │ ├── upload/ # Image upload utilities │ │ └── image.go │ └── util/ # Common utilities │ ├── jwt.go # JWT utilities │ ├── md5.go # MD5 hashing │ ├── pagination.go # Pagination helper │ └── util.go ├── routers/ # Route definitions │ ├── api/ # API handlers │ │ ├── v1/ # API v1 handlers │ │ │ ├── article.go # Article endpoints │ │ │ └── tag.go # Tag endpoints │ │ ├── auth.go # Authentication endpoint │ │ └── upload.go # Image upload endpoint │ └── router.go # Route initialization ├── runtime/ # Runtime resources │ ├── fonts/ # Font files │ └── qrcode/ # QR code resources ├── service/ # Business logic layer │ ├── article_service/ # Article services │ │ ├── article.go # Article CRUD operations │ │ └── article_poster.go # Poster generation │ ├── auth_service/ # Auth services │ │ └── auth.go │ ├── cache_service/ # Cache key generation │ │ ├── article.go │ │ └── tag.go │ └── tag_service/ # Tag services │ └── tag.go ├── Dockerfile # Docker build file ├── Makefile # Build automation ├── go.mod # Go module definition ├── go.sum # Dependency checksums └── main.go # Application entry point ``` ## Architecture The project follows a layered architecture pattern: ``` ┌─────────────────────────────────────────────────────────────┐ │ HTTP Requests │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Middleware Layer │ │ (JWT Authentication) │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Router Layer │ │ (routers/api/v1/*.go) │ │ - Request validation │ │ - Parameter binding │ │ - Response formatting │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Service Layer │ │ (service/*/*.go) │ │ - Business logic │ │ - Cache management │ │ - Cross-model operations │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Model Layer │ │ (models/*.go) │ │ - Database operations │ │ - CRUD methods │ │ - Data structures │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Storage Layer │ │ MySQL (Primary) + Redis (Cache) │ └─────────────────────────────────────────────────────────────┘ ``` ## Feature Tree ``` Go Gin Blog API ├── Authentication │ └── JWT Login Validation │ ├── Token Generation (3-hour expiry) │ ├── Token Validation │ └── Token Refresh ├── Article Management │ ├── Create Article │ ├── Read Article (with Redis caching) │ ├── Update Article │ ├── Delete Article (soft delete) │ ├── List Articles (paginated) │ ├── Count Articles │ └── Generate Article Poster │ ├── Embed QR Code │ ├── Apply Background Image │ ├── Render Text Overlay │ └── Save Merged Image ├── Tag Management │ ├── CRUD Operations │ │ ├── Create Tag │ │ ├── Read Tags (paginated, cached) │ │ ├── Update Tag │ │ └── Delete Tag (soft delete) │ ├── Export Tags to Excel │ └── Import Tags from Excel ├── File Upload │ └── Image Upload │ ├── Format validation (.jpg, .jpeg, .png) │ ├── Size validation (max 5MB) │ └── MD5-based naming ├── API Documentation │ └── Swagger UI (/swagger/*any) └── Static File Serving ├── Exported Excel files (/export) ├── Uploaded images (/upload/images) └── Generated QR codes (/qrcode) ``` ## API Endpoints ### Public Endpoints | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/auth` | User authentication, returns JWT token | | GET | `/swagger/*any` | Swagger API documentation | | POST | `/upload` | Image upload | | POST | `/tags/export` | Export tags to Excel | | POST | `/tags/import` | Import tags from Excel | ### Protected Endpoints (Require JWT Token) #### Tags | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/v1/tags` | Get tag list (paginated) | | POST | `/api/v1/tags` | Create new tag | | PUT | `/api/v1/tags/:id` | Update tag by ID | | DELETE | `/api/v1/tags/:id` | Delete tag by ID | #### Articles | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/v1/articles` | Get article list (paginated) | | GET | `/api/v1/articles/:id` | Get article by ID | | POST | `/api/v1/articles` | Create new article | | PUT | `/api/v1/articles/:id` | Update article by ID | | DELETE | `/api/v1/articles/:id` | Delete article by ID | | POST | `/api/v1/articles/poster/generate` | Generate article poster with QR code | ## Database Schema ### Tables **blog_auth** - User authentication ```sql - id: INT (PK, AUTO_INCREMENT) - username: VARCHAR(50) - password: VARCHAR(50) ``` **blog_tag** - Article tags ```sql - id: INT (PK, AUTO_INCREMENT) - name: VARCHAR(100) - Tag name - created_on: INT - Creation timestamp - created_by: VARCHAR(100) - Creator - modified_on: INT - Modification timestamp - modified_by: VARCHAR(100) - Modifier - deleted_on: INT - Deletion timestamp (soft delete) - state: TINYINT - Status (0: disabled, 1: enabled) ``` **blog_article** - Articles ```sql - id: INT (PK, AUTO_INCREMENT) - tag_id: INT (FK) - Associated tag ID - title: VARCHAR(100) - Article title - desc: VARCHAR(255) - Description - content: TEXT - Article content - cover_image_url: VARCHAR(255) - Cover image URL - created_on: INT - Creation timestamp - created_by: VARCHAR(100) - Creator - modified_on: INT - Modification timestamp - modified_by: VARCHAR(255) - Modifier - deleted_on: INT - Deletion timestamp (soft delete) - state: TINYINT - Status ``` ## Configuration Configuration is managed through `conf/app.ini`: ```ini [app] PageSize = 10 # Pagination page size JwtSecret = 233 # JWT signing secret PrefixUrl = http://127.0.0.1:8000 RuntimeRootPath = runtime/ ImageSavePath = upload/images/ ImageMaxSize = 5 # Max image size in MB ImageAllowExts = .jpg,.jpeg,.png ExportSavePath = export/ QrCodeSavePath = qrcode/ FontSavePath = fonts/ LogSavePath = logs/ [server] RunMode = debug # debug or release HttpPort = 8000 ReadTimeout = 60 # seconds WriteTimeout = 60 # seconds [database] Type = mysql User = root Password = rootroot Host = 127.0.0.1:3306 Name = blog TablePrefix = blog_ [redis] Host = 127.0.0.1:6379 Password = MaxIdle = 30 MaxActive = 30 IdleTimeout = 200 ``` ## Getting Started ### Prerequisites - Go 1.13+ - MySQL 5.6+ - Redis ### Database Setup 1. Create a MySQL database named `blog` 2. Execute the SQL script: ```bash mysql -u root -p blog < docs/sql/blog.sql ``` ### Configuration 1. Edit `conf/app.ini` to match your environment 2. Update database credentials 3. Update Redis connection settings ### Running the Application ```bash # Build make build # Run ./go-gin-example # Or run directly go run main.go ``` The server will start at `http://localhost:8000` ### Using Docker ```bash # Build image docker build -t go-gin-example . # Run container docker run -p 8000:8000 go-gin-example ``` ## API Usage Examples ### 1. Get Authentication Token ```bash curl -X POST http://localhost:8000/auth \ -d "username=test&password=test123" ``` Response: ```json { "code": 200, "msg": "ok", "data": { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } } ``` ### 2. Create a Tag ```bash curl -X POST "http://localhost:8000/api/v1/tags?token=YOUR_TOKEN" \ -d "name=Go&created_by=admin&state=1" ``` ### 3. Get Tags List ```bash curl "http://localhost:8000/api/v1/tags?token=YOUR_TOKEN" ``` ### 4. Create an Article ```bash curl -X POST "http://localhost:8000/api/v1/articles?token=YOUR_TOKEN" \ -d "tag_id=1&title=Hello Gin&desc=Introduction to Gin&content=Article content...&created_by=admin&cover_image_url=http://example.com/image.jpg&state=1" ``` ### 5. Upload an Image ```bash curl -X POST http://localhost:8000/upload \ -F "image=@/path/to/image.jpg" ``` ### 6. Export Tags to Excel ```bash curl -X POST http://localhost:8000/tags/export ``` ## Key Design Patterns ### 1. Soft Delete All models use soft delete by setting `deleted_on` timestamp instead of actual deletion. ### 2. Redis Caching Articles and tags are cached in Redis with 1-hour TTL to reduce database load. ### 3. Service Layer Pattern Business logic is separated into service layer, keeping handlers thin and focused on request/response handling. ### 4. Unified Response Format All API responses follow consistent format: ```json { "code": 200, "msg": "ok", "data": {} } ``` ### 5. Custom GORM Callbacks Custom callbacks for automatic timestamp management: - `CreatedOn` set on create - `ModifiedOn` updated on modifications - `DeletedOn` set on soft delete ## Error Codes | Code | Description | |------|-------------| | 200 | Success | | 400 | Invalid parameters | | 500 | Internal server error | | 10001 | Tag already exists | | 10003 | Tag not found | | 10011 | Article not found | | 20001 | Token validation failed | | 20002 | Token expired | | 20003 | Token generation error | | 20004 | Authentication failed | | 30001 | Image save failed | | 30002 | Image check failed | | 30003 | Invalid image format | ## Development Commands ```bash # Build make build # Run code analysis make tool # Run linter make lint # Clean build artifacts make clean ``` ## License MIT License - See [LICENSE](LICENSE) for details. ## Credits Project by [EDDYCJY](https://github.com/EDDYCJY/go-gin-example) ================================================ FILE: README_ZH.md ================================================ # Go Gin Example - 博客 API [![rcard](https://goreportcard.com/badge/github.com/EDDYCJY/go-gin-example)](https://goreportcard.com/report/github.com/EDDYCJY/go-gin-example) [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](https://godoc.org/github.com/EDDYCJY/go-gin-example) [![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/EDDYCJY/go-gin-example/master/LICENSE) 一个基于 Go 和 Gin 框架构建的生产级 RESTful 博客 API 示例,展示了真实项目的设计模式和最佳实践。 ## 目录 本项目提供 [Gin实践](https://segmentfault.com/a/1190000013297625) 的连载示例代码 1. [Gin实践 连载一 Golang介绍与环境安装](https://book.eddycjy.com/golang/gin/install.html) 2. [Gin实践 连载二 搭建Blog API's(一)](https://book.eddycjy.com/golang/gin/api-01.html) 3. [Gin实践 连载三 搭建Blog API's(二)](https://book.eddycjy.com/golang/gin/api-02.html) 4. [Gin实践 连载四 搭建Blog API's(三)](https://book.eddycjy.com/golang/gin/api-03.html) 5. [Gin实践 连载五 使用JWT进行身份校验](https://book.eddycjy.com/golang/gin/jwt.html) 6. [Gin实践 连载六 编写一个简单的文件日志](https://book.eddycjy.com/golang/gin/log.html) 7. [Gin实践 连载七 Golang优雅重启HTTP服务](https://book.eddycjy.com/golang/gin/reload-http.html) 8. [Gin实践 连载八 为它加上Swagger](https://book.eddycjy.com/golang/gin/swagger.html) 9. [Gin实践 连载九 将Golang应用部署到Docker](https://book.eddycjy.com/golang/gin/golang-docker.html) 10. [Gin实践 连载十 定制 GORM Callbacks](https://book.eddycjy.com/golang/gin/gorm-callback.html) 11. [Gin实践 连载十一 Cron定时任务](https://book.eddycjy.com/golang/gin/cron.html) 12. [Gin实践 连载十二 优化配置结构及实现图片上传](https://book.eddycjy.com/golang/gin/config-upload.html) 13. [Gin实践 连载十三 优化你的应用结构和实现Redis缓存](https://book.eddycjy.com/golang/gin/application-redis.html) 14. [Gin实践 连载十四 实现导出、导入 Excel](https://book.eddycjy.com/golang/gin/excel.html) 15. [Gin实践 连载十五 生成二维码、合并海报](https://book.eddycjy.com/golang/gin/image.html) 16. [Gin实践 连载十六 在图片上绘制文字](https://book.eddycjy.com/golang/gin/font.html) 17. [Gin实践 连载十七 用 Nginx 部署 Go 应用](https://book.eddycjy.com/golang/gin/nginx.html) 18. [Gin实践 番外 Golang交叉编译](https://book.eddycjy.com/golang/gin/cgo.html) 19. [Gin实践 番外 请入门 Makefile](https://book.eddycjy.com/golang/gin/makefile.html) ## 技术栈 | 分类 | 技术 | |------|------| | 编程语言 | Go | | Web 框架 | [Gin](https://github.com/gin-gonic/gin) | | ORM | [GORM](https://github.com/jinzhu/gorm) | | 数据库 | MySQL | | 缓存 | Redis (通过 [Redigo](https://github.com/gomodule/redigo)) | | 认证 | JWT ([jwt-go](https://github.com/dgrijalva/jwt-go)) | | 配置管理 | [go-ini](https://github.com/go-ini/ini) | | API 文档 | [Swagger](https://github.com/swaggo/gin-swagger) | | Excel 处理 | [excelize](https://github.com/360EntSecGroup-Skylar/excelize), [xlsx](https://github.com/tealeg/xlsx) | | 图片处理 | [freetype](https://github.com/golang/freetype), [barcode](https://github.com/boombuler/barcode) | | 参数校验 | [beego/validation](https://github.com/astaxie/beego/validation) | ## 项目结构 ``` go-gin-example/ ├── conf/ # 配置文件目录 │ └── app.ini # 应用配置文件 ├── docs/ # 文档目录 │ ├── sql/ # 数据库脚本 │ │ └── blog.sql # 数据库表结构 │ └── swagger/ # Swagger 文档 ├── middleware/ # 中间件 │ └── jwt/ # JWT 认证中间件 │ └── jwt.go ├── models/ # 数据模型层 (ORM) │ ├── article.go # 文章模型 │ ├── auth.go # 认证模型 │ ├── models.go # 数据库初始化 │ └── tag.go # 标签模型 ├── pkg/ # 公共包 │ ├── app/ # 应用工具 │ │ ├── form.go # 表单绑定 │ │ ├── request.go # 请求处理 │ │ └── response.go # 响应格式化 │ ├── e/ # 错误码 │ │ ├── cache.go # 缓存键常量 │ │ ├── code.go # 错误码定义 │ │ └── msg.go # 错误信息 │ ├── export/ # Excel 导出工具 │ │ └── excel.go │ ├── file/ # 文件工具 │ │ └── file.go │ ├── gredis/ # Redis 客户端 │ │ └── redis.go │ ├── logging/ # 日志工具 │ │ ├── file.go │ │ └── log.go │ ├── qrcode/ # 二维码生成 │ │ └── qrcode.go │ ├── setting/ # 配置管理 │ │ └── setting.go │ ├── upload/ # 图片上传工具 │ │ └── image.go │ └── util/ # 通用工具 │ ├── jwt.go # JWT 工具 │ ├── md5.go # MD5 哈希 │ ├── pagination.go # 分页助手 │ └── util.go ├── routers/ # 路由定义 │ ├── api/ # API 处理器 │ │ ├── v1/ # API v1 处理器 │ │ │ ├── article.go # 文章接口 │ │ │ └── tag.go # 标签接口 │ │ ├── auth.go # 认证接口 │ │ └── upload.go # 图片上传接口 │ └── router.go # 路由初始化 ├── runtime/ # 运行时资源 │ ├── fonts/ # 字体文件 │ └── qrcode/ # 二维码资源 ├── service/ # 业务逻辑层 │ ├── article_service/ # 文章服务 │ │ ├── article.go # 文章 CRUD 操作 │ │ └── article_poster.go # 海报生成 │ ├── auth_service/ # 认证服务 │ │ └── auth.go │ ├── cache_service/ # 缓存键生成 │ │ ├── article.go │ │ └── tag.go │ └── tag_service/ # 标签服务 │ └── tag.go ├── Dockerfile # Docker 构建文件 ├── Makefile # 构建自动化 ├── go.mod # Go 模块定义 ├── go.sum # 依赖校验 └── main.go # 应用入口 ``` ## 架构设计 项目采用分层架构模式: ``` ┌─────────────────────────────────────────────────────────────┐ │ HTTP 请求 │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 中间件层 │ │ (JWT 认证) │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 路由层 │ │ (routers/api/v1/*.go) │ │ - 请求校验 │ │ - 参数绑定 │ │ - 响应格式化 │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 服务层 │ │ (service/*/*.go) │ │ - 业务逻辑 │ │ - 缓存管理 │ │ - 跨模型操作 │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 模型层 │ │ (models/*.go) │ │ - 数据库操作 │ │ - CRUD 方法 │ │ - 数据结构 │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 存储层 │ │ MySQL (主存储) + Redis (缓存) │ └─────────────────────────────────────────────────────────────┘ ``` ## 功能树 ``` Go Gin 博客 API ├── 认证模块 │ └── JWT 登录验证 │ ├── Token 生成(3小时有效期) │ ├── Token 验证 │ └── Token 刷新 ├── 文章管理 │ ├── 创建文章 │ ├── 查询文章(带 Redis 缓存) │ ├── 更新文章 │ ├── 删除文章(软删除) │ ├── 文章列表(分页) │ ├── 文章统计 │ └── 生成文章海报 │ ├── 嵌入二维码 │ ├── 应用背景图 │ ├── 渲染文字叠加 │ └── 保存合成图片 ├── 标签管理 │ ├── CRUD 操作 │ │ ├── 创建标签 │ │ ├── 查询标签(分页,带缓存) │ │ ├── 更新标签 │ │ └── 删除标签(软删除) │ ├── 导出标签到 Excel │ └── 从 Excel 导入标签 ├── 文件上传 │ └── 图片上传 │ ├── 格式校验 (.jpg, .jpeg, .png) │ ├── 大小校验(最大 5MB) │ └── MD5 命名 ├── API 文档 │ └── Swagger UI (/swagger/*any) └── 静态文件服务 ├── 导出的 Excel 文件 (/export) ├── 上传的图片 (/upload/images) └── 生成的二维码 (/qrcode) ``` ## API 接口 ### 公开接口 | 方法 | 接口 | 描述 | |------|------|------| | POST | `/auth` | 用户认证,返回 JWT Token | | GET | `/swagger/*any` | Swagger API 文档 | | POST | `/upload` | 图片上传 | | POST | `/tags/export` | 导出标签到 Excel | | POST | `/tags/import` | 从 Excel 导入标签 | ### 受保护接口(需要 JWT Token) #### 标签接口 | 方法 | 接口 | 描述 | |------|------|------| | GET | `/api/v1/tags` | 获取标签列表(分页) | | POST | `/api/v1/tags` | 创建新标签 | | PUT | `/api/v1/tags/:id` | 根据 ID 更新标签 | | DELETE | `/api/v1/tags/:id` | 根据 ID 删除标签 | #### 文章接口 | 方法 | 接口 | 描述 | |------|------|------| | GET | `/api/v1/articles` | 获取文章列表(分页) | | GET | `/api/v1/articles/:id` | 根据 ID 获取文章 | | POST | `/api/v1/articles` | 创建新文章 | | PUT | `/api/v1/articles/:id` | 根据 ID 更新文章 | | DELETE | `/api/v1/articles/:id` | 根据 ID 删除文章 | | POST | `/api/v1/articles/poster/generate` | 生成带二维码的文章海报 | ## 数据库设计 ### 数据表 **blog_auth** - 用户认证表 ```sql - id: INT (主键, 自增) - username: VARCHAR(50) - 用户名 - password: VARCHAR(50) - 密码 ``` **blog_tag** - 文章标签表 ```sql - id: INT (主键, 自增) - name: VARCHAR(100) - 标签名称 - created_on: INT - 创建时间戳 - created_by: VARCHAR(100) - 创建人 - modified_on: INT - 修改时间戳 - modified_by: VARCHAR(100) - 修改人 - deleted_on: INT - 删除时间戳(软删除) - state: TINYINT - 状态 (0: 禁用, 1: 启用) ``` **blog_article** - 文章表 ```sql - id: INT (主键, 自增) - tag_id: INT (外键) - 关联标签 ID - title: VARCHAR(100) - 文章标题 - desc: VARCHAR(255) - 文章简述 - content: TEXT - 文章内容 - cover_image_url: VARCHAR(255) - 封面图片地址 - created_on: INT - 创建时间戳 - created_by: VARCHAR(100) - 创建人 - modified_on: INT - 修改时间戳 - modified_by: VARCHAR(255) - 修改人 - deleted_on: INT - 删除时间戳(软删除) - state: TINYINT - 状态 ``` ## 配置说明 配置文件位于 `conf/app.ini`: ```ini [app] PageSize = 10 # 分页大小 JwtSecret = 233 # JWT 签名密钥 PrefixUrl = http://127.0.0.1:8000 RuntimeRootPath = runtime/ ImageSavePath = upload/images/ ImageMaxSize = 5 # 图片最大大小(MB) ImageAllowExts = .jpg,.jpeg,.png ExportSavePath = export/ QrCodeSavePath = qrcode/ FontSavePath = fonts/ LogSavePath = logs/ [server] RunMode = debug # debug 或 release HttpPort = 8000 ReadTimeout = 60 # 秒 WriteTimeout = 60 # 秒 [database] Type = mysql User = root Password = rootroot Host = 127.0.0.1:3306 Name = blog TablePrefix = blog_ [redis] Host = 127.0.0.1:6379 Password = MaxIdle = 30 MaxActive = 30 IdleTimeout = 200 ``` ## 快速开始 ### 环境要求 - Go 1.13+ - MySQL 5.6+ - Redis ### 数据库初始化 1. 创建名为 `blog` 的 MySQL 数据库 2. 执行 SQL 脚本: ```bash mysql -u root -p blog < docs/sql/blog.sql ``` ### 配置修改 1. 编辑 `conf/app.ini` 以匹配您的环境 2. 更新数据库连接信息 3. 更新 Redis 连接配置 ### 运行应用 ```bash # 构建 make build # 运行 ./go-gin-example # 或直接运行 go run main.go ``` 服务将启动在 `http://localhost:8000` ### 使用 Docker ```bash # 构建镜像 docker build -t go-gin-example . # 运行容器 docker run -p 8000:8000 go-gin-example ``` ## API 使用示例 ### 1. 获取认证 Token ```bash curl -X POST http://localhost:8000/auth \ -d "username=test&password=test123" ``` 响应: ```json { "code": 200, "msg": "ok", "data": { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } } ``` ### 2. 创建标签 ```bash curl -X POST "http://localhost:8000/api/v1/tags?token=YOUR_TOKEN" \ -d "name=Go&created_by=admin&state=1" ``` ### 3. 获取标签列表 ```bash curl "http://localhost:8000/api/v1/tags?token=YOUR_TOKEN" ``` ### 4. 创建文章 ```bash curl -X POST "http://localhost:8000/api/v1/articles?token=YOUR_TOKEN" \ -d "tag_id=1&title=Hello Gin&desc=Gin 入门介绍&content=文章内容...&created_by=admin&cover_image_url=http://example.com/image.jpg&state=1" ``` ### 5. 上传图片 ```bash curl -X POST http://localhost:8000/upload \ -F "image=@/path/to/image.jpg" ``` ### 6. 导出标签到 Excel ```bash curl -X POST http://localhost:8000/tags/export ``` ## 核心设计模式 ### 1. 软删除 所有模型使用软删除,通过设置 `deleted_on` 时间戳而非实际删除数据。 ### 2. Redis 缓存 文章和标签数据缓存在 Redis 中,TTL 为 1 小时,以减少数据库负载。 ### 3. 服务层模式 业务逻辑分离到服务层,保持处理器精简,专注于请求/响应处理。 ### 4. 统一响应格式 所有 API 响应遵循统一格式: ```json { "code": 200, "msg": "ok", "data": {} } ``` ### 5. 自定义 GORM 回调 自定义回调实现自动时间戳管理: - `CreatedOn` 在创建时设置 - `ModifiedOn` 在修改时更新 - `DeletedOn` 在软删除时设置 ## 错误码说明 | 错误码 | 描述 | |--------|------| | 200 | 成功 | | 400 | 请求参数无效 | | 500 | 服务器内部错误 | | 10001 | 标签已存在 | | 10003 | 标签不存在 | | 10011 | 文章不存在 | | 20001 | Token 验证失败 | | 20002 | Token 已过期 | | 20003 | Token 生成错误 | | 20004 | 认证失败 | | 30001 | 图片保存失败 | | 30002 | 图片检查失败 | | 30003 | 图片格式无效 | ## 开发命令 ```bash # 构建 make build # 运行代码分析 make tool # 运行代码检查 make lint # 清理构建产物 make clean ``` ## 许可证 MIT License - 详见 [LICENSE](LICENSE) 文件。 ## 联系我 ![image](https://image.eddycjy.com/7074be90379a121746146bc4229819f8.jpg) ================================================ FILE: conf/app.ini ================================================ [app] PageSize = 10 JwtSecret = 233 PrefixUrl = http://127.0.0.1:8000 RuntimeRootPath = runtime/ ImageSavePath = upload/images/ # MB ImageMaxSize = 5 ImageAllowExts = .jpg,.jpeg,.png ExportSavePath = export/ QrCodeSavePath = qrcode/ FontSavePath = fonts/ LogSavePath = logs/ LogSaveName = log LogFileExt = log TimeFormat = 20060102 [server] #debug or release RunMode = debug HttpPort = 8000 ReadTimeout = 60 WriteTimeout = 60 [database] Type = mysql User = root Password = rootroot Host = 127.0.0.1:3306 Name = blog TablePrefix = blog_ [redis] Host = 127.0.0.1:6379 Password = MaxIdle = 30 MaxActive = 30 IdleTimeout = 200 ================================================ FILE: docs/docs.go ================================================ // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT // This file was generated by swaggo/swag at // 2020-03-22 15:19:36.759704 +0800 CST m=+0.052176208 package docs import ( "bytes" "encoding/json" "strings" "github.com/alecthomas/template" "github.com/swaggo/swag" ) var doc = `{ "schemes": {{ marshal .Schemes }}, "swagger": "2.0", "info": { "description": "{{.Description}}", "title": "{{.Title}}", "termsOfService": "https://github.com/EDDYCJY/go-gin-example", "contact": {}, "license": { "name": "MIT", "url": "https://github.com/EDDYCJY/go-gin-example/blob/master/LICENSE" }, "version": "{{.Version}}" }, "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { "/api/v1/articles": { "get": { "produces": [ "application/json" ], "summary": "Get multiple articles", "parameters": [ { "description": "TagID", "name": "tag_id", "in": "body", "schema": { "type": "integer" } }, { "description": "State", "name": "state", "in": "body", "schema": { "type": "integer" } }, { "description": "CreatedBy", "name": "created_by", "in": "body", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } }, "post": { "produces": [ "application/json" ], "summary": "Add article", "parameters": [ { "description": "TagID", "name": "tag_id", "in": "body", "required": true, "schema": { "type": "integer" } }, { "description": "Title", "name": "title", "in": "body", "required": true, "schema": { "type": "string" } }, { "description": "Desc", "name": "desc", "in": "body", "required": true, "schema": { "type": "string" } }, { "description": "Content", "name": "content", "in": "body", "required": true, "schema": { "type": "string" } }, { "description": "CreatedBy", "name": "created_by", "in": "body", "required": true, "schema": { "type": "string" } }, { "description": "State", "name": "state", "in": "body", "required": true, "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } } }, "/api/v1/articles/{id}": { "get": { "produces": [ "application/json" ], "summary": "Get a single article", "parameters": [ { "type": "integer", "description": "ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } }, "put": { "produces": [ "application/json" ], "summary": "Update article", "parameters": [ { "type": "integer", "description": "ID", "name": "id", "in": "path", "required": true }, { "description": "TagID", "name": "tag_id", "in": "body", "schema": { "type": "string" } }, { "description": "Title", "name": "title", "in": "body", "schema": { "type": "string" } }, { "description": "Desc", "name": "desc", "in": "body", "schema": { "type": "string" } }, { "description": "Content", "name": "content", "in": "body", "schema": { "type": "string" } }, { "description": "ModifiedBy", "name": "modified_by", "in": "body", "required": true, "schema": { "type": "string" } }, { "description": "State", "name": "state", "in": "body", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } }, "delete": { "produces": [ "application/json" ], "summary": "Delete article", "parameters": [ { "type": "integer", "description": "ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } } }, "/api/v1/tags": { "get": { "produces": [ "application/json" ], "summary": "Get multiple article tags", "parameters": [ { "type": "string", "description": "Name", "name": "name", "in": "query" }, { "type": "integer", "description": "State", "name": "state", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } }, "post": { "produces": [ "application/json" ], "summary": "Add article tag", "parameters": [ { "description": "Name", "name": "name", "in": "body", "required": true, "schema": { "type": "string" } }, { "description": "State", "name": "state", "in": "body", "schema": { "type": "integer" } }, { "description": "CreatedBy", "name": "created_by", "in": "body", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } } }, "/api/v1/tags/export": { "post": { "produces": [ "application/json" ], "summary": "Export article tag", "parameters": [ { "description": "Name", "name": "name", "in": "body", "schema": { "type": "string" } }, { "description": "State", "name": "state", "in": "body", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } } }, "/api/v1/tags/import": { "post": { "produces": [ "application/json" ], "summary": "Import Image", "parameters": [ { "type": "file", "description": "Image File", "name": "image", "in": "formData", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } } }, "/api/v1/tags/{id}": { "put": { "produces": [ "application/json" ], "summary": "Update article tag", "parameters": [ { "type": "integer", "description": "ID", "name": "id", "in": "path", "required": true }, { "description": "Name", "name": "name", "in": "body", "required": true, "schema": { "type": "string" } }, { "description": "State", "name": "state", "in": "body", "schema": { "type": "integer" } }, { "description": "ModifiedBy", "name": "modified_by", "in": "body", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } }, "delete": { "produces": [ "application/json" ], "summary": "Delete article tag", "parameters": [ { "type": "integer", "description": "ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } } }, "/auth": { "get": { "produces": [ "application/json" ], "summary": "Get Auth", "parameters": [ { "type": "string", "description": "userName", "name": "username", "in": "query", "required": true }, { "type": "string", "description": "password", "name": "password", "in": "query", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } } } }, "definitions": { "app.Response": { "type": "object", "properties": { "code": { "type": "integer" }, "data": { "type": "object" }, "msg": { "type": "string" } } } } }` type swaggerInfo struct { Version string Host string BasePath string Schemes []string Title string Description string } // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = swaggerInfo{ Version: "1.0", Host: "", BasePath: "", Schemes: []string{}, Title: "Golang Gin API", Description: "An example of gin", } type s struct{} func (s *s) ReadDoc() string { sInfo := SwaggerInfo sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1) t, err := template.New("swagger_info").Funcs(template.FuncMap{ "marshal": func(v interface{}) string { a, _ := json.Marshal(v) return string(a) }, }).Parse(doc) if err != nil { return doc } var tpl bytes.Buffer if err := t.Execute(&tpl, sInfo); err != nil { return doc } return tpl.String() } func init() { swag.Register(swag.Name, &s{}) } ================================================ FILE: docs/sql/blog.sql ================================================ /* Navicat MySQL Data Transfer Source Database : blog Target Server Type : MYSQL Target Server Version : 50639 File Encoding : 65001 Date: 2018-03-18 16:52:35 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for blog_article -- ---------------------------- DROP TABLE IF EXISTS `blog_article`; CREATE TABLE `blog_article` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `tag_id` int(10) unsigned DEFAULT '0' COMMENT '标签ID', `title` varchar(100) DEFAULT '' COMMENT '文章标题', `desc` varchar(255) DEFAULT '' COMMENT '简述', `content` text COMMENT '内容', `cover_image_url` varchar(255) DEFAULT '' COMMENT '封面图片地址', `created_on` int(10) unsigned DEFAULT '0' COMMENT '新建时间', `created_by` varchar(100) DEFAULT '' COMMENT '创建人', `modified_on` int(10) unsigned DEFAULT '0' COMMENT '修改时间', `modified_by` varchar(255) DEFAULT '' COMMENT '修改人', `deleted_on` int(10) unsigned DEFAULT '0', `state` tinyint(3) unsigned DEFAULT '1' COMMENT '删除时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='文章管理'; -- ---------------------------- -- Table structure for blog_auth -- ---------------------------- DROP TABLE IF EXISTS `blog_auth`; CREATE TABLE `blog_auth` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(50) DEFAULT '' COMMENT '账号', `password` varchar(50) DEFAULT '' COMMENT '密码', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; INSERT INTO `blog_auth` (`id`, `username`, `password`) VALUES ('1', 'test', 'test123'); -- ---------------------------- -- Table structure for blog_tag -- ---------------------------- DROP TABLE IF EXISTS `blog_tag`; CREATE TABLE `blog_tag` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(100) DEFAULT '' COMMENT '标签名称', `created_on` int(10) unsigned DEFAULT '0' COMMENT '创建时间', `created_by` varchar(100) DEFAULT '' COMMENT '创建人', `modified_on` int(10) unsigned DEFAULT '0' COMMENT '修改时间', `modified_by` varchar(100) DEFAULT '' COMMENT '修改人', `deleted_on` int(10) unsigned DEFAULT '0' COMMENT '删除时间', `state` tinyint(3) unsigned DEFAULT '1' COMMENT '状态 0为禁用、1为启用', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='文章标签管理'; ================================================ FILE: docs/swagger/swagger.json ================================================ { "swagger": "2.0", "info": { "description": "An example of gin", "title": "Golang Gin API", "termsOfService": "https://github.com/EDDYCJY/go-gin-example", "contact": {}, "license": { "name": "MIT", "url": "https://github.com/EDDYCJY/go-gin-example/blob/master/LICENSE" }, "version": "1.0" }, "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { "/api/v1/articles": { "get": { "produces": [ "application/json" ], "summary": "Get multiple articles", "parameters": [ { "description": "TagID", "name": "tag_id", "in": "body", "schema": { "type": "object" } }, { "description": "State", "name": "state", "in": "body", "schema": { "type": "object" } }, { "description": "CreatedBy", "name": "created_by", "in": "body", "schema": { "type": "object" } } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } } } }, "post": { "produces": [ "application/json" ], "summary": "Add article", "parameters": [ { "description": "TagID", "name": "tag_id", "in": "body", "required": true, "schema": { "type": "object" } }, { "description": "Title", "name": "title", "in": "body", "required": true, "schema": { "type": "object" } }, { "description": "Desc", "name": "desc", "in": "body", "required": true, "schema": { "type": "object" } }, { "description": "Content", "name": "content", "in": "body", "required": true, "schema": { "type": "object" } }, { "description": "CreatedBy", "name": "created_by", "in": "body", "required": true, "schema": { "type": "object" } }, { "description": "State", "name": "state", "in": "body", "required": true, "schema": { "type": "object" } } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } } } } }, "/api/v1/articles/{id}": { "get": { "produces": [ "application/json" ], "summary": "Get a single article", "parameters": [ { "type": "integer", "description": "ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } } } }, "put": { "produces": [ "application/json" ], "summary": "Update article", "parameters": [ { "type": "integer", "description": "ID", "name": "id", "in": "path", "required": true }, { "description": "TagID", "name": "tag_id", "in": "body", "schema": { "type": "object" } }, { "description": "Title", "name": "title", "in": "body", "schema": { "type": "object" } }, { "description": "Desc", "name": "desc", "in": "body", "schema": { "type": "object" } }, { "description": "Content", "name": "content", "in": "body", "schema": { "type": "object" } }, { "description": "ModifiedBy", "name": "modified_by", "in": "body", "required": true, "schema": { "type": "object" } }, { "description": "State", "name": "state", "in": "body", "schema": { "type": "object" } } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } } } }, "delete": { "produces": [ "application/json" ], "summary": "Delete article", "parameters": [ { "type": "integer", "description": "ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } } } } }, "/api/v1/tags": { "get": { "produces": [ "application/json" ], "summary": "Get multiple article tags", "parameters": [ { "type": "string", "description": "Name", "name": "name", "in": "query" }, { "type": "integer", "description": "State", "name": "state", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } } } }, "post": { "produces": [ "application/json" ], "summary": "Add article tag", "parameters": [ { "description": "Name", "name": "name", "in": "body", "required": true, "schema": { "type": "object" } }, { "description": "State", "name": "state", "in": "body", "schema": { "type": "object" } }, { "description": "CreatedBy", "name": "created_by", "in": "body", "schema": { "type": "object" } } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } } } } }, "/api/v1/tags/export": { "post": { "produces": [ "application/json" ], "summary": "Export article tag", "parameters": [ { "description": "Name", "name": "name", "in": "body", "schema": { "type": "object" } }, { "description": "State", "name": "state", "in": "body", "schema": { "type": "object" } } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } } } } }, "/api/v1/tags/import": { "post": { "produces": [ "application/json" ], "summary": "Import article tag", "parameters": [ { "description": "Excel File", "name": "file", "in": "body", "required": true, "schema": { "type": "object" } } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } } } } }, "/api/v1/tags/{id}": { "put": { "produces": [ "application/json" ], "summary": "Update article tag", "parameters": [ { "type": "integer", "description": "ID", "name": "id", "in": "path", "required": true }, { "description": "ID", "name": "name", "in": "body", "required": true, "schema": { "type": "object" } }, { "description": "State", "name": "state", "in": "body", "schema": { "type": "object" } }, { "description": "ModifiedBy", "name": "modified_by", "in": "body", "required": true, "schema": { "type": "object" } } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } } } }, "delete": { "produces": [ "application/json" ], "summary": "Delete article tag", "parameters": [ { "type": "integer", "description": "ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "type": "object", "$ref": "#/definitions/app.Response" } } } } } }, "definitions": { "app.Response": { "type": "object", "properties": { "code": { "type": "integer" }, "data": { "type": "object" }, "msg": { "type": "string" } } } } } ================================================ FILE: docs/swagger/swagger.yaml ================================================ basePath: '{{.BasePath}}' definitions: app.Response: properties: code: type: integer data: type: object msg: type: string type: object host: '{{.Host}}' info: contact: {} description: An example of gin license: name: MIT url: https://github.com/EDDYCJY/go-gin-example/blob/master/LICENSE termsOfService: https://github.com/EDDYCJY/go-gin-example title: Golang Gin API version: "1.0" paths: /api/v1/articles: get: parameters: - description: TagID in: body name: tag_id schema: type: object - description: State in: body name: state schema: type: object - description: CreatedBy in: body name: created_by schema: type: object produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' type: object "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' type: object summary: Get multiple articles post: parameters: - description: TagID in: body name: tag_id required: true schema: type: object - description: Title in: body name: title required: true schema: type: object - description: Desc in: body name: desc required: true schema: type: object - description: Content in: body name: content required: true schema: type: object - description: CreatedBy in: body name: created_by required: true schema: type: object - description: State in: body name: state required: true schema: type: object produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' type: object "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' type: object summary: Add article /api/v1/articles/{id}: delete: parameters: - description: ID in: path name: id required: true type: integer produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' type: object "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' type: object summary: Delete article get: parameters: - description: ID in: path name: id required: true type: integer produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' type: object "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' type: object summary: Get a single article put: parameters: - description: ID in: path name: id required: true type: integer - description: TagID in: body name: tag_id schema: type: object - description: Title in: body name: title schema: type: object - description: Desc in: body name: desc schema: type: object - description: Content in: body name: content schema: type: object - description: ModifiedBy in: body name: modified_by required: true schema: type: object - description: State in: body name: state schema: type: object produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' type: object "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' type: object summary: Update article /api/v1/tags: get: parameters: - description: Name in: query name: name type: string - description: State in: query name: state type: integer produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' type: object "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' type: object summary: Get multiple article tags post: parameters: - description: Name in: body name: name required: true schema: type: object - description: State in: body name: state schema: type: object - description: CreatedBy in: body name: created_by schema: type: object produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' type: object "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' type: object summary: Add article tag /api/v1/tags/{id}: delete: parameters: - description: ID in: path name: id required: true type: integer produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' type: object "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' type: object summary: Delete article tag put: parameters: - description: ID in: path name: id required: true type: integer - description: ID in: body name: name required: true schema: type: object - description: State in: body name: state schema: type: object - description: ModifiedBy in: body name: modified_by required: true schema: type: object produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' type: object "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' type: object summary: Update article tag /api/v1/tags/export: post: parameters: - description: Name in: body name: name schema: type: object - description: State in: body name: state schema: type: object produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' type: object "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' type: object summary: Export article tag /api/v1/tags/import: post: parameters: - description: Excel File in: body name: file required: true schema: type: object produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' type: object "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' type: object summary: Import article tag swagger: "2.0" ================================================ FILE: docs/swagger.json ================================================ { "swagger": "2.0", "info": { "description": "An example of gin", "title": "Golang Gin API", "termsOfService": "https://github.com/EDDYCJY/go-gin-example", "contact": {}, "license": { "name": "MIT", "url": "https://github.com/EDDYCJY/go-gin-example/blob/master/LICENSE" }, "version": "1.0" }, "paths": { "/api/v1/articles": { "get": { "produces": [ "application/json" ], "summary": "Get multiple articles", "parameters": [ { "description": "TagID", "name": "tag_id", "in": "body", "schema": { "type": "integer" } }, { "description": "State", "name": "state", "in": "body", "schema": { "type": "integer" } }, { "description": "CreatedBy", "name": "created_by", "in": "body", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } }, "post": { "produces": [ "application/json" ], "summary": "Add article", "parameters": [ { "description": "TagID", "name": "tag_id", "in": "body", "required": true, "schema": { "type": "integer" } }, { "description": "Title", "name": "title", "in": "body", "required": true, "schema": { "type": "string" } }, { "description": "Desc", "name": "desc", "in": "body", "required": true, "schema": { "type": "string" } }, { "description": "Content", "name": "content", "in": "body", "required": true, "schema": { "type": "string" } }, { "description": "CreatedBy", "name": "created_by", "in": "body", "required": true, "schema": { "type": "string" } }, { "description": "State", "name": "state", "in": "body", "required": true, "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } } }, "/api/v1/articles/{id}": { "get": { "produces": [ "application/json" ], "summary": "Get a single article", "parameters": [ { "type": "integer", "description": "ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } }, "put": { "produces": [ "application/json" ], "summary": "Update article", "parameters": [ { "type": "integer", "description": "ID", "name": "id", "in": "path", "required": true }, { "description": "TagID", "name": "tag_id", "in": "body", "schema": { "type": "string" } }, { "description": "Title", "name": "title", "in": "body", "schema": { "type": "string" } }, { "description": "Desc", "name": "desc", "in": "body", "schema": { "type": "string" } }, { "description": "Content", "name": "content", "in": "body", "schema": { "type": "string" } }, { "description": "ModifiedBy", "name": "modified_by", "in": "body", "required": true, "schema": { "type": "string" } }, { "description": "State", "name": "state", "in": "body", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } }, "delete": { "produces": [ "application/json" ], "summary": "Delete article", "parameters": [ { "type": "integer", "description": "ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } } }, "/api/v1/tags": { "get": { "produces": [ "application/json" ], "summary": "Get multiple article tags", "parameters": [ { "type": "string", "description": "Name", "name": "name", "in": "query" }, { "type": "integer", "description": "State", "name": "state", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } }, "post": { "produces": [ "application/json" ], "summary": "Add article tag", "parameters": [ { "description": "Name", "name": "name", "in": "body", "required": true, "schema": { "type": "string" } }, { "description": "State", "name": "state", "in": "body", "schema": { "type": "integer" } }, { "description": "CreatedBy", "name": "created_by", "in": "body", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } } }, "/api/v1/tags/export": { "post": { "produces": [ "application/json" ], "summary": "Export article tag", "parameters": [ { "description": "Name", "name": "name", "in": "body", "schema": { "type": "string" } }, { "description": "State", "name": "state", "in": "body", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } } }, "/api/v1/tags/import": { "post": { "produces": [ "application/json" ], "summary": "Import Image", "parameters": [ { "type": "file", "description": "Image File", "name": "image", "in": "formData", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } } }, "/api/v1/tags/{id}": { "put": { "produces": [ "application/json" ], "summary": "Update article tag", "parameters": [ { "type": "integer", "description": "ID", "name": "id", "in": "path", "required": true }, { "description": "Name", "name": "name", "in": "body", "required": true, "schema": { "type": "string" } }, { "description": "State", "name": "state", "in": "body", "schema": { "type": "integer" } }, { "description": "ModifiedBy", "name": "modified_by", "in": "body", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } }, "delete": { "produces": [ "application/json" ], "summary": "Delete article tag", "parameters": [ { "type": "integer", "description": "ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } } }, "/auth": { "get": { "produces": [ "application/json" ], "summary": "Get Auth", "parameters": [ { "type": "string", "description": "userName", "name": "username", "in": "query", "required": true }, { "type": "string", "description": "password", "name": "password", "in": "query", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/app.Response" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/app.Response" } } } } } }, "definitions": { "app.Response": { "type": "object", "properties": { "code": { "type": "integer" }, "data": { "type": "object" }, "msg": { "type": "string" } } } } } ================================================ FILE: docs/swagger.yaml ================================================ definitions: app.Response: properties: code: type: integer data: type: object msg: type: string type: object info: contact: {} description: An example of gin license: name: MIT url: https://github.com/EDDYCJY/go-gin-example/blob/master/LICENSE termsOfService: https://github.com/EDDYCJY/go-gin-example title: Golang Gin API version: "1.0" paths: /api/v1/articles: get: parameters: - description: TagID in: body name: tag_id schema: type: integer - description: State in: body name: state schema: type: integer - description: CreatedBy in: body name: created_by schema: type: integer produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' summary: Get multiple articles post: parameters: - description: TagID in: body name: tag_id required: true schema: type: integer - description: Title in: body name: title required: true schema: type: string - description: Desc in: body name: desc required: true schema: type: string - description: Content in: body name: content required: true schema: type: string - description: CreatedBy in: body name: created_by required: true schema: type: string - description: State in: body name: state required: true schema: type: integer produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' summary: Add article /api/v1/articles/{id}: delete: parameters: - description: ID in: path name: id required: true type: integer produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' summary: Delete article get: parameters: - description: ID in: path name: id required: true type: integer produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' summary: Get a single article put: parameters: - description: ID in: path name: id required: true type: integer - description: TagID in: body name: tag_id schema: type: string - description: Title in: body name: title schema: type: string - description: Desc in: body name: desc schema: type: string - description: Content in: body name: content schema: type: string - description: ModifiedBy in: body name: modified_by required: true schema: type: string - description: State in: body name: state schema: type: integer produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' summary: Update article /api/v1/tags: get: parameters: - description: Name in: query name: name type: string - description: State in: query name: state type: integer produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' summary: Get multiple article tags post: parameters: - description: Name in: body name: name required: true schema: type: string - description: State in: body name: state schema: type: integer - description: CreatedBy in: body name: created_by schema: type: integer produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' summary: Add article tag /api/v1/tags/{id}: delete: parameters: - description: ID in: path name: id required: true type: integer produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' summary: Delete article tag put: parameters: - description: ID in: path name: id required: true type: integer - description: Name in: body name: name required: true schema: type: string - description: State in: body name: state schema: type: integer - description: ModifiedBy in: body name: modified_by required: true schema: type: string produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' summary: Update article tag /api/v1/tags/export: post: parameters: - description: Name in: body name: name schema: type: string - description: State in: body name: state schema: type: integer produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' summary: Export article tag /api/v1/tags/import: post: parameters: - description: Image File in: formData name: image required: true type: file produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' summary: Import Image /auth: get: parameters: - description: userName in: query name: username required: true type: string - description: password in: query name: password required: true type: string produces: - application/json responses: "200": description: OK schema: $ref: '#/definitions/app.Response' "500": description: Internal Server Error schema: $ref: '#/definitions/app.Response' summary: Get Auth swagger: "2.0" ================================================ FILE: go.mod ================================================ module github.com/EDDYCJY/go-gin-example go 1.13 require ( github.com/360EntSecGroup-Skylar/excelize v1.3.1-0.20180527032555-9e463b461434 github.com/PuerkitoBio/purell v1.1.1-0.20180310210909-975f53781597 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/astaxie/beego v1.9.3-0.20171218111859-f16688817aa4 github.com/boombuler/barcode v1.0.1-0.20180315051053-3c06908149f7 github.com/denisenkom/go-mssqldb v0.0.0-20190920000552-128d9f4ae1cd // indirect github.com/dgrijalva/jwt-go v3.1.0+incompatible github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 // indirect github.com/gin-gonic/gin v1.4.0 github.com/go-ini/ini v1.32.1-0.20180214101753-32e4be5f41bb github.com/go-sql-driver/mysql v1.4.1-0.20190510102335-877a9775f068 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 github.com/gomodule/redigo v2.0.1-0.20180401191855-9352ab68be13+incompatible github.com/jinzhu/gorm v0.0.0-20180213101209-6e1387b44c64 github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d // indirect github.com/jinzhu/now v1.0.1 // indirect github.com/json-iterator/go v1.1.7 // indirect github.com/lib/pq v1.2.0 // indirect github.com/mattn/go-sqlite3 v1.11.0 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.5.1 github.com/tealeg/xlsx v1.0.4-0.20180419195153-f36fa3be8893 github.com/unknwon/com v1.0.1 golang.org/x/image v0.0.0-20180628062038-cc896f830ced // indirect golang.org/x/sys v0.0.0-20190921204832-2dccfee4fd3e // indirect google.golang.org/appengine v1.6.3 // indirect gopkg.in/ini.v1 v1.47.0 // indirect ) ================================================ FILE: go.sum ================================================ github.com/360EntSecGroup-Skylar/excelize v1.3.1-0.20180527032555-9e463b461434 h1:sJVNhDPQ1uL3izsJQGWFQb3lUvFloaTIgqz0ClEp6aQ= github.com/360EntSecGroup-Skylar/excelize v1.3.1-0.20180527032555-9e463b461434/go.mod h1:R8KYLmGns0vDPe6/HyphW0mzW+MFexlGDafU0ykVEnU= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1-0.20180310210909-975f53781597 h1:8+pMa56PPVkN6NbWGZbNIWLVIitrF8AQZ95d4UAhqmE= github.com/PuerkitoBio/purell v1.1.1-0.20180310210909-975f53781597/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/astaxie/beego v1.9.3-0.20171218111859-f16688817aa4 h1:dNIynF6ICiq1NghlpIBxljb2JbyC61/JqWB5A9cfUfo= github.com/astaxie/beego v1.9.3-0.20171218111859-f16688817aa4/go.mod h1:0R4++1tUqERR0WYFWdfkcrsyoVBCG4DgpDGokT3yb+U= github.com/boombuler/barcode v1.0.1-0.20180315051053-3c06908149f7 h1:s7NuEzhW8Z2v7X7lUwHMqXt8HKYYd5YwtEt0CCMff3Q= github.com/boombuler/barcode v1.0.1-0.20180315051053-3c06908149f7/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.0.0-20190920000552-128d9f4ae1cd h1:tXCgEGHPT4XELDS7nB0OBb9968yCOd+MnyNf+6m1u40= github.com/denisenkom/go-mssqldb v0.0.0-20190920000552-128d9f4ae1cd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.1.0+incompatible h1:FFziAwDQQ2dz1XClWMkwvukur3evtZx7x/wMHKM1i20= github.com/dgrijalva/jwt-go v3.1.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cougNAV9szl6CVoj2RYwzS3DpUQNtlY= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.3.0 h1:kCmZyPklC0gVdL728E6Aj20uYBJV93nj/TkwBTKhFbs= github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y= github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/go-ini/ini v1.32.1-0.20180214101753-32e4be5f41bb h1:v+YnQ81wH+hTjaP5nFSpqASFbe9UETYm1vG65qp7Zc0= github.com/go-ini/ini v1.32.1-0.20180214101753-32e4be5f41bb/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-openapi/jsonpointer v0.17.0 h1:nH6xp8XdXHx8dqveo0ZuJBluCO2qGrPbDNZ0dwoRHP0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.0 h1:BqWKpV1dFd+AuiKlgtddwVIFQsuMpxfBDBHGfM2yNpk= github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/spec v0.19.0 h1:A4SZ6IWh3lnjH0rG0Z5lkxazMGBECtrZcbyYQi+64k4= github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/swag v0.17.0 h1:iqrgMg7Q7SvtbWLlltPrkMs0UBJI6oTSs79JFRUi880= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-sql-driver/mysql v1.4.1-0.20190510102335-877a9775f068 h1:q2kwd9Bcgl2QpSi/Wjcx9jzwyICt3EWTP5to43QhwaA= github.com/go-sql-driver/mysql v1.4.1-0.20190510102335-877a9775f068/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/gomodule/redigo v2.0.1-0.20180401191855-9352ab68be13+incompatible h1:cQom4uMS2ufhGPAJgSa67FXfrHg6ytNKmWtKN/l/n+I= github.com/gomodule/redigo v2.0.1-0.20180401191855-9352ab68be13+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/jinzhu/gorm v0.0.0-20180213101209-6e1387b44c64 h1:8I4kQ5M5OjZKNsgRUs20soTdIoo1GbiGApV31kJ9e6Y= github.com/jinzhu/gorm v0.0.0-20180213101209-6e1387b44c64/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d h1:jRQLvyVGL+iVtDElaEIDdKwpPqUIZJfzkNLV34htpEc= github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0= github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI= github.com/swaggo/swag v1.5.1 h1:2Agm8I4K5qb00620mHq0VJ05/KT4FtmALPIcQR9lEZM= github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= github.com/tealeg/xlsx v1.0.4-0.20180419195153-f36fa3be8893 h1:x+HNL/+eUTIzieDdCKbl6QjneUXKuiiTBvC9s5USpT0= github.com/tealeg/xlsx v1.0.4-0.20180419195153-f36fa3be8893/go.mod h1:uxu5UY2ovkuRPWKQ8Q7JG0JbSivrISjdPzZQKeo74mA= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre h1:jyJKFOSEbdOc2HODrf2qcCkYOdq7zzXqA9bhW5oV4fM= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.5-pre h1:5YV9PsFAN+ndcCtTM7s60no7nY7eTG3LPtxhSwuxzCs= github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs= github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/image v0.0.0-20180628062038-cc896f830ced h1:2QsAEqOy4Mp+V4HL2Wr1iBNpZWaL72EvTO4oj5bmr5w= golang.org/x/image v0.0.0-20180628062038-cc896f830ced/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190611141213-3f473d35a33a h1:+KkCgOMgnKSgenxTBoiwkMqTiouMIy/3o8RLdmSbGoY= golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190921204832-2dccfee4fd3e h1:9ZBATxGrhPGloVV3LDg+OqDyEtcYRtQ9eIVlIjan6+M= golang.org/x/sys v0.0.0-20190921204832-2dccfee4fd3e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b h1:mSUCVIwDx4hfXJfWsOPfdzEHxzb2Xjl6BQ8YgPnazQA= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b h1:/mJ+GKieZA6hFDQGdWZrjj4AXPl5ylY+5HusG80roy0= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= google.golang.org/appengine v1.6.3 h1:hvZejVcIxAKHR8Pq2gXaDggf6CWT1QEqO+JEBeOKCG8= google.golang.org/appengine v1.6.3/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/ini.v1 v1.47.0 h1:XAVsOWcIxjm6JVEbCbSZgSBZIF0BrCzXs4orAQr6uc8= gopkg.in/ini.v1 v1.47.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= ================================================ FILE: main.go ================================================ package main import ( "fmt" "log" "net/http" "github.com/gin-gonic/gin" "github.com/EDDYCJY/go-gin-example/models" "github.com/EDDYCJY/go-gin-example/pkg/gredis" "github.com/EDDYCJY/go-gin-example/pkg/logging" "github.com/EDDYCJY/go-gin-example/pkg/setting" "github.com/EDDYCJY/go-gin-example/routers" "github.com/EDDYCJY/go-gin-example/pkg/util" ) func init() { setting.Setup() models.Setup() logging.Setup() gredis.Setup() util.Setup() } // @title Golang Gin API // @version 1.0 // @description An example of gin // @termsOfService https://github.com/EDDYCJY/go-gin-example // @license.name MIT // @license.url https://github.com/EDDYCJY/go-gin-example/blob/master/LICENSE func main() { gin.SetMode(setting.ServerSetting.RunMode) routersInit := routers.InitRouter() readTimeout := setting.ServerSetting.ReadTimeout writeTimeout := setting.ServerSetting.WriteTimeout endPoint := fmt.Sprintf(":%d", setting.ServerSetting.HttpPort) maxHeaderBytes := 1 << 20 server := &http.Server{ Addr: endPoint, Handler: routersInit, ReadTimeout: readTimeout, WriteTimeout: writeTimeout, MaxHeaderBytes: maxHeaderBytes, } log.Printf("[info] start http server listening %s", endPoint) server.ListenAndServe() // If you want Graceful Restart, you need a Unix system and download github.com/fvbock/endless //endless.DefaultReadTimeOut = readTimeout //endless.DefaultWriteTimeOut = writeTimeout //endless.DefaultMaxHeaderBytes = maxHeaderBytes //server := endless.NewServer(endPoint, routersInit) //server.BeforeBegin = func(add string) { // log.Printf("Actual pid is %d", syscall.Getpid()) //} // //err := server.ListenAndServe() //if err != nil { // log.Printf("Server err: %v", err) //} } ================================================ FILE: middleware/jwt/jwt.go ================================================ package jwt import ( "net/http" "github.com/dgrijalva/jwt-go" "github.com/gin-gonic/gin" "github.com/EDDYCJY/go-gin-example/pkg/e" "github.com/EDDYCJY/go-gin-example/pkg/util" ) // JWT is jwt middleware func JWT() gin.HandlerFunc { return func(c *gin.Context) { var code int var data interface{} code = e.SUCCESS token := c.Query("token") if token == "" { code = e.INVALID_PARAMS } else { _, err := util.ParseToken(token) if err != nil { switch err.(*jwt.ValidationError).Errors { case jwt.ValidationErrorExpired: code = e.ERROR_AUTH_CHECK_TOKEN_TIMEOUT default: code = e.ERROR_AUTH_CHECK_TOKEN_FAIL } } } if code != e.SUCCESS { c.JSON(http.StatusUnauthorized, gin.H{ "code": code, "msg": e.GetMsg(code), "data": data, }) c.Abort() return } c.Next() } } ================================================ FILE: models/article.go ================================================ package models import ( "github.com/jinzhu/gorm" ) type Article struct { Model TagID int `json:"tag_id" gorm:"index"` Tag Tag `json:"tag"` Title string `json:"title"` Desc string `json:"desc"` Content string `json:"content"` CoverImageUrl string `json:"cover_image_url"` CreatedBy string `json:"created_by"` ModifiedBy string `json:"modified_by"` State int `json:"state"` } // ExistArticleByID checks if an article exists based on ID func ExistArticleByID(id int) (bool, error) { var article Article err := db.Select("id").Where("id = ? AND deleted_on = ? ", id, 0).First(&article).Error if err != nil && err != gorm.ErrRecordNotFound { return false, err } if article.ID > 0 { return true, nil } return false, nil } // GetArticleTotal gets the total number of articles based on the constraints func GetArticleTotal(maps interface{}) (int, error) { var count int if err := db.Model(&Article{}).Where(maps).Count(&count).Error; err != nil { return 0, err } return count, nil } // GetArticles gets a list of articles based on paging constraints func GetArticles(pageNum int, pageSize int, maps interface{}) ([]*Article, error) { var articles []*Article err := db.Preload("Tag").Where(maps).Offset(pageNum).Limit(pageSize).Find(&articles).Error if err != nil && err != gorm.ErrRecordNotFound { return nil, err } return articles, nil } // GetArticle Get a single article based on ID func GetArticle(id int) (*Article, error) { var article Article err := db.Where("id = ? AND deleted_on = ? ", id, 0).First(&article).Error if err != nil && err != gorm.ErrRecordNotFound { return nil, err } err = db.Model(&article).Related(&article.Tag).Error if err != nil && err != gorm.ErrRecordNotFound { return nil, err } return &article, nil } // EditArticle modify a single article func EditArticle(id int, data interface{}) error { if err := db.Model(&Article{}).Where("id = ? AND deleted_on = ? ", id, 0).Updates(data).Error; err != nil { return err } return nil } // AddArticle add a single article func AddArticle(data map[string]interface{}) error { article := Article{ TagID: data["tag_id"].(int), Title: data["title"].(string), Desc: data["desc"].(string), Content: data["content"].(string), CreatedBy: data["created_by"].(string), State: data["state"].(int), CoverImageUrl: data["cover_image_url"].(string), } if err := db.Create(&article).Error; err != nil { return err } return nil } // DeleteArticle delete a single article func DeleteArticle(id int) error { if err := db.Where("id = ?", id).Delete(Article{}).Error; err != nil { return err } return nil } // CleanAllArticle clear all article func CleanAllArticle() error { if err := db.Unscoped().Where("deleted_on != ? ", 0).Delete(&Article{}).Error; err != nil { return err } return nil } ================================================ FILE: models/auth.go ================================================ package models import "github.com/jinzhu/gorm" type Auth struct { ID int `gorm:"primary_key" json:"id"` Username string `json:"username"` Password string `json:"password"` } // CheckAuth checks if authentication information exists func CheckAuth(username, password string) (bool, error) { var auth Auth err := db.Select("id").Where(Auth{Username: username, Password: password}).First(&auth).Error if err != nil && err != gorm.ErrRecordNotFound { return false, err } if auth.ID > 0 { return true, nil } return false, nil } ================================================ FILE: models/models.go ================================================ package models import ( "fmt" "log" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" "github.com/EDDYCJY/go-gin-example/pkg/setting" "time" ) var db *gorm.DB type Model struct { ID int `gorm:"primary_key" json:"id"` CreatedOn int `json:"created_on"` ModifiedOn int `json:"modified_on"` DeletedOn int `json:"deleted_on"` } // Setup initializes the database instance func Setup() { var err error db, err = gorm.Open(setting.DatabaseSetting.Type, fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=True&loc=Local", setting.DatabaseSetting.User, setting.DatabaseSetting.Password, setting.DatabaseSetting.Host, setting.DatabaseSetting.Name)) if err != nil { log.Fatalf("models.Setup err: %v", err) } gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string { return setting.DatabaseSetting.TablePrefix + defaultTableName } db.SingularTable(true) db.Callback().Create().Replace("gorm:update_time_stamp", updateTimeStampForCreateCallback) db.Callback().Update().Replace("gorm:update_time_stamp", updateTimeStampForUpdateCallback) db.Callback().Delete().Replace("gorm:delete", deleteCallback) db.DB().SetMaxIdleConns(10) db.DB().SetMaxOpenConns(100) } // CloseDB closes database connection (unnecessary) func CloseDB() { defer db.Close() } // updateTimeStampForCreateCallback will set `CreatedOn`, `ModifiedOn` when creating func updateTimeStampForCreateCallback(scope *gorm.Scope) { if !scope.HasError() { nowTime := time.Now().Unix() if createTimeField, ok := scope.FieldByName("CreatedOn"); ok { if createTimeField.IsBlank { createTimeField.Set(nowTime) } } if modifyTimeField, ok := scope.FieldByName("ModifiedOn"); ok { if modifyTimeField.IsBlank { modifyTimeField.Set(nowTime) } } } } // updateTimeStampForUpdateCallback will set `ModifiedOn` when updating func updateTimeStampForUpdateCallback(scope *gorm.Scope) { if _, ok := scope.Get("gorm:update_column"); !ok { scope.SetColumn("ModifiedOn", time.Now().Unix()) } } // deleteCallback will set `DeletedOn` where deleting func deleteCallback(scope *gorm.Scope) { if !scope.HasError() { var extraOption string if str, ok := scope.Get("gorm:delete_option"); ok { extraOption = fmt.Sprint(str) } deletedOnField, hasDeletedOnField := scope.FieldByName("DeletedOn") if !scope.Search.Unscoped && hasDeletedOnField { scope.Raw(fmt.Sprintf( "UPDATE %v SET %v=%v%v%v", scope.QuotedTableName(), scope.Quote(deletedOnField.DBName), scope.AddToVars(time.Now().Unix()), addExtraSpaceIfExist(scope.CombinedConditionSql()), addExtraSpaceIfExist(extraOption), )).Exec() } else { scope.Raw(fmt.Sprintf( "DELETE FROM %v%v%v", scope.QuotedTableName(), addExtraSpaceIfExist(scope.CombinedConditionSql()), addExtraSpaceIfExist(extraOption), )).Exec() } } } // addExtraSpaceIfExist adds a separator func addExtraSpaceIfExist(str string) string { if str != "" { return " " + str } return "" } ================================================ FILE: models/tag.go ================================================ package models import ( "github.com/jinzhu/gorm" ) type Tag struct { Model Name string `json:"name"` CreatedBy string `json:"created_by"` ModifiedBy string `json:"modified_by"` State int `json:"state"` } // ExistTagByName checks if there is a tag with the same name func ExistTagByName(name string) (bool, error) { var tag Tag err := db.Select("id").Where("name = ? AND deleted_on = ? ", name, 0).First(&tag).Error if err != nil && err != gorm.ErrRecordNotFound { return false, err } if tag.ID > 0 { return true, nil } return false, nil } // AddTag Add a Tag func AddTag(name string, state int, createdBy string) error { tag := Tag{ Name: name, State: state, CreatedBy: createdBy, } if err := db.Create(&tag).Error; err != nil { return err } return nil } // GetTags gets a list of tags based on paging and constraints func GetTags(pageNum int, pageSize int, maps interface{}) ([]Tag, error) { var ( tags []Tag err error ) if pageSize > 0 && pageNum > 0 { err = db.Where(maps).Find(&tags).Offset(pageNum).Limit(pageSize).Error } else { err = db.Where(maps).Find(&tags).Error } if err != nil && err != gorm.ErrRecordNotFound { return nil, err } return tags, nil } // GetTagTotal counts the total number of tags based on the constraint func GetTagTotal(maps interface{}) (int, error) { var count int if err := db.Model(&Tag{}).Where(maps).Count(&count).Error; err != nil { return 0, err } return count, nil } // ExistTagByID determines whether a Tag exists based on the ID func ExistTagByID(id int) (bool, error) { var tag Tag err := db.Select("id").Where("id = ? AND deleted_on = ? ", id, 0).First(&tag).Error if err != nil && err != gorm.ErrRecordNotFound { return false, err } if tag.ID > 0 { return true, nil } return false, nil } // DeleteTag delete a tag func DeleteTag(id int) error { if err := db.Where("id = ?", id).Delete(&Tag{}).Error; err != nil { return err } return nil } // EditTag modify a single tag func EditTag(id int, data interface{}) error { if err := db.Model(&Tag{}).Where("id = ? AND deleted_on = ? ", id, 0).Updates(data).Error; err != nil { return err } return nil } // CleanAllTag clear all tag func CleanAllTag() (bool, error) { if err := db.Unscoped().Where("deleted_on != ? ", 0).Delete(&Tag{}).Error; err != nil { return false, err } return true, nil } ================================================ FILE: pkg/app/form.go ================================================ package app import ( "github.com/astaxie/beego/validation" "github.com/gin-gonic/gin" "net/http" "github.com/EDDYCJY/go-gin-example/pkg/e" ) // BindAndValid binds and validates data func BindAndValid(c *gin.Context, form interface{}) (int, int) { err := c.Bind(form) if err != nil { return http.StatusBadRequest, e.INVALID_PARAMS } valid := validation.Validation{} check, err := valid.Valid(form) if err != nil { return http.StatusInternalServerError, e.ERROR } if !check { MarkErrors(valid.Errors) return http.StatusBadRequest, e.INVALID_PARAMS } return http.StatusOK, e.SUCCESS } ================================================ FILE: pkg/app/request.go ================================================ package app import ( "github.com/astaxie/beego/validation" "github.com/EDDYCJY/go-gin-example/pkg/logging" ) // MarkErrors logs error logs func MarkErrors(errors []*validation.Error) { for _, err := range errors { logging.Info(err.Key, err.Message) } return } ================================================ FILE: pkg/app/response.go ================================================ package app import ( "github.com/gin-gonic/gin" "github.com/EDDYCJY/go-gin-example/pkg/e" ) type Gin struct { C *gin.Context } type Response struct { Code int `json:"code"` Msg string `json:"msg"` Data interface{} `json:"data"` } // Response setting gin.JSON func (g *Gin) Response(httpCode, errCode int, data interface{}) { g.C.JSON(httpCode, Response{ Code: errCode, Msg: e.GetMsg(errCode), Data: data, }) return } ================================================ FILE: pkg/e/cache.go ================================================ package e const ( CACHE_ARTICLE = "ARTICLE" CACHE_TAG = "TAG" ) ================================================ FILE: pkg/e/code.go ================================================ package e const ( SUCCESS = 200 ERROR = 500 INVALID_PARAMS = 400 ERROR_EXIST_TAG = 10001 ERROR_EXIST_TAG_FAIL = 10002 ERROR_NOT_EXIST_TAG = 10003 ERROR_GET_TAGS_FAIL = 10004 ERROR_COUNT_TAG_FAIL = 10005 ERROR_ADD_TAG_FAIL = 10006 ERROR_EDIT_TAG_FAIL = 10007 ERROR_DELETE_TAG_FAIL = 10008 ERROR_EXPORT_TAG_FAIL = 10009 ERROR_IMPORT_TAG_FAIL = 10010 ERROR_NOT_EXIST_ARTICLE = 10011 ERROR_CHECK_EXIST_ARTICLE_FAIL = 10012 ERROR_ADD_ARTICLE_FAIL = 10013 ERROR_DELETE_ARTICLE_FAIL = 10014 ERROR_EDIT_ARTICLE_FAIL = 10015 ERROR_COUNT_ARTICLE_FAIL = 10016 ERROR_GET_ARTICLES_FAIL = 10017 ERROR_GET_ARTICLE_FAIL = 10018 ERROR_GEN_ARTICLE_POSTER_FAIL = 10019 ERROR_AUTH_CHECK_TOKEN_FAIL = 20001 ERROR_AUTH_CHECK_TOKEN_TIMEOUT = 20002 ERROR_AUTH_TOKEN = 20003 ERROR_AUTH = 20004 ERROR_UPLOAD_SAVE_IMAGE_FAIL = 30001 ERROR_UPLOAD_CHECK_IMAGE_FAIL = 30002 ERROR_UPLOAD_CHECK_IMAGE_FORMAT = 30003 ) ================================================ FILE: pkg/e/msg.go ================================================ package e var MsgFlags = map[int]string{ SUCCESS: "ok", ERROR: "fail", INVALID_PARAMS: "请求参数错误", ERROR_EXIST_TAG: "已存在该标签名称", ERROR_EXIST_TAG_FAIL: "获取已存在标签失败", ERROR_NOT_EXIST_TAG: "该标签不存在", ERROR_GET_TAGS_FAIL: "获取所有标签失败", ERROR_COUNT_TAG_FAIL: "统计标签失败", ERROR_ADD_TAG_FAIL: "新增标签失败", ERROR_EDIT_TAG_FAIL: "修改标签失败", ERROR_DELETE_TAG_FAIL: "删除标签失败", ERROR_EXPORT_TAG_FAIL: "导出标签失败", ERROR_IMPORT_TAG_FAIL: "导入标签失败", ERROR_NOT_EXIST_ARTICLE: "该文章不存在", ERROR_ADD_ARTICLE_FAIL: "新增文章失败", ERROR_DELETE_ARTICLE_FAIL: "删除文章失败", ERROR_CHECK_EXIST_ARTICLE_FAIL: "检查文章是否存在失败", ERROR_EDIT_ARTICLE_FAIL: "修改文章失败", ERROR_COUNT_ARTICLE_FAIL: "统计文章失败", ERROR_GET_ARTICLES_FAIL: "获取多个文章失败", ERROR_GET_ARTICLE_FAIL: "获取单个文章失败", ERROR_GEN_ARTICLE_POSTER_FAIL: "生成文章海报失败", ERROR_AUTH_CHECK_TOKEN_FAIL: "Token鉴权失败", ERROR_AUTH_CHECK_TOKEN_TIMEOUT: "Token已超时", ERROR_AUTH_TOKEN: "Token生成失败", ERROR_AUTH: "Token错误", ERROR_UPLOAD_SAVE_IMAGE_FAIL: "保存图片失败", ERROR_UPLOAD_CHECK_IMAGE_FAIL: "检查图片失败", ERROR_UPLOAD_CHECK_IMAGE_FORMAT: "校验图片错误,图片格式或大小有问题", } // GetMsg get error information based on Code func GetMsg(code int) string { msg, ok := MsgFlags[code] if ok { return msg } return MsgFlags[ERROR] } ================================================ FILE: pkg/export/excel.go ================================================ package export import "github.com/EDDYCJY/go-gin-example/pkg/setting" const EXT = ".xlsx" // GetExcelFullUrl get the full access path of the Excel file func GetExcelFullUrl(name string) string { return setting.AppSetting.PrefixUrl + "/" + GetExcelPath() + name } // GetExcelPath get the relative save path of the Excel file func GetExcelPath() string { return setting.AppSetting.ExportSavePath } // GetExcelFullPath Get the full save path of the Excel file func GetExcelFullPath() string { return setting.AppSetting.RuntimeRootPath + GetExcelPath() } ================================================ FILE: pkg/file/file.go ================================================ package file import ( "fmt" "io/ioutil" "mime/multipart" "os" "path" ) // GetSize get the file size func GetSize(f multipart.File) (int, error) { content, err := ioutil.ReadAll(f) return len(content), err } // GetExt get the file ext func GetExt(fileName string) string { return path.Ext(fileName) } // CheckNotExist check if the file exists func CheckNotExist(src string) bool { _, err := os.Stat(src) return os.IsNotExist(err) } // CheckPermission check if the file has permission func CheckPermission(src string) bool { _, err := os.Stat(src) return os.IsPermission(err) } // IsNotExistMkDir create a directory if it does not exist func IsNotExistMkDir(src string) error { if notExist := CheckNotExist(src); notExist == true { if err := MkDir(src); err != nil { return err } } return nil } // MkDir create a directory func MkDir(src string) error { err := os.MkdirAll(src, os.ModePerm) if err != nil { return err } return nil } // Open a file according to a specific mode func Open(name string, flag int, perm os.FileMode) (*os.File, error) { f, err := os.OpenFile(name, flag, perm) if err != nil { return nil, err } return f, nil } // MustOpen maximize trying to open the file func MustOpen(fileName, filePath string) (*os.File, error) { dir, err := os.Getwd() if err != nil { return nil, fmt.Errorf("os.Getwd err: %v", err) } src := dir + "/" + filePath perm := CheckPermission(src) if perm == true { return nil, fmt.Errorf("file.CheckPermission Permission denied src: %s", src) } err = IsNotExistMkDir(src) if err != nil { return nil, fmt.Errorf("file.IsNotExistMkDir src: %s, err: %v", src, err) } f, err := Open(src+fileName, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644) if err != nil { return nil, fmt.Errorf("Fail to OpenFile :%v", err) } return f, nil } ================================================ FILE: pkg/gredis/redis.go ================================================ package gredis import ( "encoding/json" "time" "github.com/gomodule/redigo/redis" "github.com/EDDYCJY/go-gin-example/pkg/setting" ) var RedisConn *redis.Pool // Setup Initialize the Redis instance func Setup() error { RedisConn = &redis.Pool{ MaxIdle: setting.RedisSetting.MaxIdle, MaxActive: setting.RedisSetting.MaxActive, IdleTimeout: setting.RedisSetting.IdleTimeout, Dial: func() (redis.Conn, error) { c, err := redis.Dial("tcp", setting.RedisSetting.Host) if err != nil { return nil, err } if setting.RedisSetting.Password != "" { if _, err := c.Do("AUTH", setting.RedisSetting.Password); err != nil { c.Close() return nil, err } } return c, err }, TestOnBorrow: func(c redis.Conn, t time.Time) error { _, err := c.Do("PING") return err }, } return nil } // Set a key/value func Set(key string, data interface{}, time int) error { conn := RedisConn.Get() defer conn.Close() value, err := json.Marshal(data) if err != nil { return err } _, err = conn.Do("SET", key, value) if err != nil { return err } _, err = conn.Do("EXPIRE", key, time) if err != nil { return err } return nil } // Exists check a key func Exists(key string) bool { conn := RedisConn.Get() defer conn.Close() exists, err := redis.Bool(conn.Do("EXISTS", key)) if err != nil { return false } return exists } // Get get a key func Get(key string) ([]byte, error) { conn := RedisConn.Get() defer conn.Close() reply, err := redis.Bytes(conn.Do("GET", key)) if err != nil { return nil, err } return reply, nil } // Delete delete a kye func Delete(key string) (bool, error) { conn := RedisConn.Get() defer conn.Close() return redis.Bool(conn.Do("DEL", key)) } // LikeDeletes batch delete func LikeDeletes(key string) error { conn := RedisConn.Get() defer conn.Close() keys, err := redis.Strings(conn.Do("KEYS", "*"+key+"*")) if err != nil { return err } for _, key := range keys { _, err = Delete(key) if err != nil { return err } } return nil } ================================================ FILE: pkg/logging/file.go ================================================ package logging import ( "fmt" "time" "github.com/EDDYCJY/go-gin-example/pkg/setting" ) // getLogFilePath get the log file save path func getLogFilePath() string { return fmt.Sprintf("%s%s", setting.AppSetting.RuntimeRootPath, setting.AppSetting.LogSavePath) } // getLogFileName get the save name of the log file func getLogFileName() string { return fmt.Sprintf("%s%s.%s", setting.AppSetting.LogSaveName, time.Now().Format(setting.AppSetting.TimeFormat), setting.AppSetting.LogFileExt, ) } ================================================ FILE: pkg/logging/log.go ================================================ package logging import ( "fmt" "github.com/EDDYCJY/go-gin-example/pkg/file" "log" "os" "path/filepath" "runtime" ) type Level int var ( F *os.File DefaultPrefix = "" DefaultCallerDepth = 2 logger *log.Logger logPrefix = "" levelFlags = []string{"DEBUG", "INFO", "WARN", "ERROR", "FATAL"} ) const ( DEBUG Level = iota INFO WARNING ERROR FATAL ) // Setup initialize the log instance func Setup() { var err error filePath := getLogFilePath() fileName := getLogFileName() F, err = file.MustOpen(fileName, filePath) if err != nil { log.Fatalf("logging.Setup err: %v", err) } logger = log.New(F, DefaultPrefix, log.LstdFlags) } // Debug output logs at debug level func Debug(v ...interface{}) { setPrefix(DEBUG) logger.Println(v) } // Info output logs at info level func Info(v ...interface{}) { setPrefix(INFO) logger.Println(v) } // Warn output logs at warn level func Warn(v ...interface{}) { setPrefix(WARNING) logger.Println(v) } // Error output logs at error level func Error(v ...interface{}) { setPrefix(ERROR) logger.Println(v) } // Fatal output logs at fatal level func Fatal(v ...interface{}) { setPrefix(FATAL) logger.Fatalln(v) } // setPrefix set the prefix of the log output func setPrefix(level Level) { _, file, line, ok := runtime.Caller(DefaultCallerDepth) if ok { logPrefix = fmt.Sprintf("[%s][%s:%d]", levelFlags[level], filepath.Base(file), line) } else { logPrefix = fmt.Sprintf("[%s]", levelFlags[level]) } logger.SetPrefix(logPrefix) } ================================================ FILE: pkg/qrcode/qrcode.go ================================================ package qrcode import ( "image/jpeg" "github.com/boombuler/barcode" "github.com/boombuler/barcode/qr" "github.com/EDDYCJY/go-gin-example/pkg/file" "github.com/EDDYCJY/go-gin-example/pkg/setting" "github.com/EDDYCJY/go-gin-example/pkg/util" ) type QrCode struct { URL string Width int Height int Ext string Level qr.ErrorCorrectionLevel Mode qr.Encoding } const ( EXT_JPG = ".jpg" ) // NewQrCode initialize instance func NewQrCode(url string, width, height int, level qr.ErrorCorrectionLevel, mode qr.Encoding) *QrCode { return &QrCode{ URL: url, Width: width, Height: height, Level: level, Mode: mode, Ext: EXT_JPG, } } // GetQrCodePath get save path func GetQrCodePath() string { return setting.AppSetting.QrCodeSavePath } // GetQrCodeFullPath get full save path func GetQrCodeFullPath() string { return setting.AppSetting.RuntimeRootPath + setting.AppSetting.QrCodeSavePath } // GetQrCodeFullUrl get the full access path func GetQrCodeFullUrl(name string) string { return setting.AppSetting.PrefixUrl + "/" + GetQrCodePath() + name } // GetQrCodeFileName get qr file name func GetQrCodeFileName(value string) string { return util.EncodeMD5(value) } // GetQrCodeExt get qr file ext func (q *QrCode) GetQrCodeExt() string { return q.Ext } // Encode generate QR code func (q *QrCode) Encode(path string) (string, string, error) { name := GetQrCodeFileName(q.URL) + q.GetQrCodeExt() src := path + name if file.CheckNotExist(src) == true { code, err := qr.Encode(q.URL, q.Level, q.Mode) if err != nil { return "", "", err } code, err = barcode.Scale(code, q.Width, q.Height) if err != nil { return "", "", err } f, err := file.MustOpen(name, path) if err != nil { return "", "", err } defer f.Close() err = jpeg.Encode(f, code, nil) if err != nil { return "", "", err } } return name, path, nil } ================================================ FILE: pkg/setting/setting.go ================================================ package setting import ( "log" "time" "github.com/go-ini/ini" ) type App struct { JwtSecret string PageSize int PrefixUrl string RuntimeRootPath string ImageSavePath string ImageMaxSize int ImageAllowExts []string ExportSavePath string QrCodeSavePath string FontSavePath string LogSavePath string LogSaveName string LogFileExt string TimeFormat string } var AppSetting = &App{} type Server struct { RunMode string HttpPort int ReadTimeout time.Duration WriteTimeout time.Duration } var ServerSetting = &Server{} type Database struct { Type string User string Password string Host string Name string TablePrefix string } var DatabaseSetting = &Database{} type Redis struct { Host string Password string MaxIdle int MaxActive int IdleTimeout time.Duration } var RedisSetting = &Redis{} var cfg *ini.File // Setup initialize the configuration instance func Setup() { var err error cfg, err = ini.Load("conf/app.ini") if err != nil { log.Fatalf("setting.Setup, fail to parse 'conf/app.ini': %v", err) } mapTo("app", AppSetting) mapTo("server", ServerSetting) mapTo("database", DatabaseSetting) mapTo("redis", RedisSetting) AppSetting.ImageMaxSize = AppSetting.ImageMaxSize * 1024 * 1024 ServerSetting.ReadTimeout = ServerSetting.ReadTimeout * time.Second ServerSetting.WriteTimeout = ServerSetting.WriteTimeout * time.Second RedisSetting.IdleTimeout = RedisSetting.IdleTimeout * time.Second } // mapTo map section func mapTo(section string, v interface{}) { err := cfg.Section(section).MapTo(v) if err != nil { log.Fatalf("Cfg.MapTo %s err: %v", section, err) } } ================================================ FILE: pkg/upload/image.go ================================================ package upload import ( "fmt" "log" "mime/multipart" "os" "path" "strings" "github.com/EDDYCJY/go-gin-example/pkg/file" "github.com/EDDYCJY/go-gin-example/pkg/logging" "github.com/EDDYCJY/go-gin-example/pkg/setting" "github.com/EDDYCJY/go-gin-example/pkg/util" ) // GetImageFullUrl get the full access path func GetImageFullUrl(name string) string { return setting.AppSetting.PrefixUrl + "/" + GetImagePath() + name } // GetImageName get image name func GetImageName(name string) string { ext := path.Ext(name) fileName := strings.TrimSuffix(name, ext) fileName = util.EncodeMD5(fileName) return fileName + ext } // GetImagePath get save path func GetImagePath() string { return setting.AppSetting.ImageSavePath } // GetImageFullPath get full save path func GetImageFullPath() string { return setting.AppSetting.RuntimeRootPath + GetImagePath() } // CheckImageExt check image file ext func CheckImageExt(fileName string) bool { ext := file.GetExt(fileName) for _, allowExt := range setting.AppSetting.ImageAllowExts { if strings.ToUpper(allowExt) == strings.ToUpper(ext) { return true } } return false } // CheckImageSize check image size func CheckImageSize(f multipart.File) bool { size, err := file.GetSize(f) if err != nil { log.Println(err) logging.Warn(err) return false } return size <= setting.AppSetting.ImageMaxSize } // CheckImage check if the file exists func CheckImage(src string) error { dir, err := os.Getwd() if err != nil { return fmt.Errorf("os.Getwd err: %v", err) } err = file.IsNotExistMkDir(dir + "/" + src) if err != nil { return fmt.Errorf("file.IsNotExistMkDir err: %v", err) } perm := file.CheckPermission(src) if perm == true { return fmt.Errorf("file.CheckPermission Permission denied src: %s", src) } return nil } ================================================ FILE: pkg/util/jwt.go ================================================ package util import ( "time" "github.com/dgrijalva/jwt-go" ) var jwtSecret []byte type Claims struct { Username string `json:"username"` Password string `json:"password"` jwt.StandardClaims } // GenerateToken generate tokens used for auth func GenerateToken(username, password string) (string, error) { nowTime := time.Now() expireTime := nowTime.Add(3 * time.Hour) claims := Claims{ EncodeMD5(username), EncodeMD5(password), jwt.StandardClaims{ ExpiresAt: expireTime.Unix(), Issuer: "gin-blog", }, } tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) token, err := tokenClaims.SignedString(jwtSecret) return token, err } // ParseToken parsing token func ParseToken(token string) (*Claims, error) { tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) { return jwtSecret, nil }) if tokenClaims != nil { if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid { return claims, nil } } return nil, err } ================================================ FILE: pkg/util/md5.go ================================================ package util import ( "crypto/md5" "encoding/hex" ) // EncodeMD5 md5 encryption func EncodeMD5(value string) string { m := md5.New() m.Write([]byte(value)) return hex.EncodeToString(m.Sum(nil)) } ================================================ FILE: pkg/util/pagination.go ================================================ package util import ( "github.com/unknwon/com" "github.com/gin-gonic/gin" "github.com/EDDYCJY/go-gin-example/pkg/setting" ) // GetPage get page parameters func GetPage(c *gin.Context) int { result := 0 page := com.StrTo(c.Query("page")).MustInt() if page > 0 { result = (page - 1) * setting.AppSetting.PageSize } return result } ================================================ FILE: pkg/util/util.go ================================================ package util import "github.com/EDDYCJY/go-gin-example/pkg/setting" // Setup Initialize the util func Setup() { jwtSecret = []byte(setting.AppSetting.JwtSecret) } ================================================ FILE: routers/api/auth.go ================================================ package api import ( "net/http" "github.com/astaxie/beego/validation" "github.com/gin-gonic/gin" "github.com/EDDYCJY/go-gin-example/pkg/app" "github.com/EDDYCJY/go-gin-example/pkg/e" "github.com/EDDYCJY/go-gin-example/pkg/util" "github.com/EDDYCJY/go-gin-example/service/auth_service" ) type auth struct { Username string `valid:"Required; MaxSize(50)"` Password string `valid:"Required; MaxSize(50)"` } // @Summary Get Auth // @Produce json // @Param username query string true "userName" // @Param password query string true "password" // @Success 200 {object} app.Response // @Failure 500 {object} app.Response // @Router /auth [get] func GetAuth(c *gin.Context) { appG := app.Gin{C: c} valid := validation.Validation{} username := c.PostForm("username") password := c.PostForm("password") a := auth{Username: username, Password: password} ok, _ := valid.Valid(&a) if !ok { app.MarkErrors(valid.Errors) appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil) return } authService := auth_service.Auth{Username: username, Password: password} isExist, err := authService.Check() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_AUTH_CHECK_TOKEN_FAIL, nil) return } if !isExist { appG.Response(http.StatusUnauthorized, e.ERROR_AUTH, nil) return } token, err := util.GenerateToken(username, password) if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_AUTH_TOKEN, nil) return } appG.Response(http.StatusOK, e.SUCCESS, map[string]string{ "token": token, }) } ================================================ FILE: routers/api/upload.go ================================================ package api import ( "net/http" "github.com/gin-gonic/gin" "github.com/EDDYCJY/go-gin-example/pkg/app" "github.com/EDDYCJY/go-gin-example/pkg/e" "github.com/EDDYCJY/go-gin-example/pkg/logging" "github.com/EDDYCJY/go-gin-example/pkg/upload" ) // @Summary Import Image // @Produce json // @Param image formData file true "Image File" // @Success 200 {object} app.Response // @Failure 500 {object} app.Response // @Router /api/v1/tags/import [post] func UploadImage(c *gin.Context) { appG := app.Gin{C: c} file, image, err := c.Request.FormFile("image") if err != nil { logging.Warn(err) appG.Response(http.StatusInternalServerError, e.ERROR, nil) return } if image == nil { appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil) return } imageName := upload.GetImageName(image.Filename) fullPath := upload.GetImageFullPath() savePath := upload.GetImagePath() src := fullPath + imageName if !upload.CheckImageExt(imageName) || !upload.CheckImageSize(file) { appG.Response(http.StatusBadRequest, e.ERROR_UPLOAD_CHECK_IMAGE_FORMAT, nil) return } err = upload.CheckImage(fullPath) if err != nil { logging.Warn(err) appG.Response(http.StatusInternalServerError, e.ERROR_UPLOAD_CHECK_IMAGE_FAIL, nil) return } if err := c.SaveUploadedFile(image, src); err != nil { logging.Warn(err) appG.Response(http.StatusInternalServerError, e.ERROR_UPLOAD_SAVE_IMAGE_FAIL, nil) return } appG.Response(http.StatusOK, e.SUCCESS, map[string]string{ "image_url": upload.GetImageFullUrl(imageName), "image_save_url": savePath + imageName, }) } ================================================ FILE: routers/api/v1/article.go ================================================ package v1 import ( "net/http" "github.com/unknwon/com" "github.com/astaxie/beego/validation" "github.com/boombuler/barcode/qr" "github.com/gin-gonic/gin" "github.com/EDDYCJY/go-gin-example/pkg/app" "github.com/EDDYCJY/go-gin-example/pkg/e" "github.com/EDDYCJY/go-gin-example/pkg/qrcode" "github.com/EDDYCJY/go-gin-example/pkg/setting" "github.com/EDDYCJY/go-gin-example/pkg/util" "github.com/EDDYCJY/go-gin-example/service/article_service" "github.com/EDDYCJY/go-gin-example/service/tag_service" ) // @Summary Get a single article // @Produce json // @Param id path int true "ID" // @Success 200 {object} app.Response // @Failure 500 {object} app.Response // @Router /api/v1/articles/{id} [get] func GetArticle(c *gin.Context) { appG := app.Gin{C: c} id := com.StrTo(c.Param("id")).MustInt() valid := validation.Validation{} valid.Min(id, 1, "id") if valid.HasErrors() { app.MarkErrors(valid.Errors) appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil) return } articleService := article_service.Article{ID: id} exists, err := articleService.ExistByID() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_CHECK_EXIST_ARTICLE_FAIL, nil) return } if !exists { appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_ARTICLE, nil) return } article, err := articleService.Get() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_GET_ARTICLE_FAIL, nil) return } appG.Response(http.StatusOK, e.SUCCESS, article) } // @Summary Get multiple articles // @Produce json // @Param tag_id body int false "TagID" // @Param state body int false "State" // @Param created_by body int false "CreatedBy" // @Success 200 {object} app.Response // @Failure 500 {object} app.Response // @Router /api/v1/articles [get] func GetArticles(c *gin.Context) { appG := app.Gin{C: c} valid := validation.Validation{} state := -1 if arg := c.PostForm("state"); arg != "" { state = com.StrTo(arg).MustInt() valid.Range(state, 0, 1, "state") } tagId := -1 if arg := c.PostForm("tag_id"); arg != "" { tagId = com.StrTo(arg).MustInt() valid.Min(tagId, 1, "tag_id") } if valid.HasErrors() { app.MarkErrors(valid.Errors) appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil) return } articleService := article_service.Article{ TagID: tagId, State: state, PageNum: util.GetPage(c), PageSize: setting.AppSetting.PageSize, } total, err := articleService.Count() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_COUNT_ARTICLE_FAIL, nil) return } articles, err := articleService.GetAll() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_GET_ARTICLES_FAIL, nil) return } data := make(map[string]interface{}) data["lists"] = articles data["total"] = total appG.Response(http.StatusOK, e.SUCCESS, data) } type AddArticleForm struct { TagID int `form:"tag_id" valid:"Required;Min(1)"` Title string `form:"title" valid:"Required;MaxSize(100)"` Desc string `form:"desc" valid:"Required;MaxSize(255)"` Content string `form:"content" valid:"Required;MaxSize(65535)"` CreatedBy string `form:"created_by" valid:"Required;MaxSize(100)"` CoverImageUrl string `form:"cover_image_url" valid:"Required;MaxSize(255)"` State int `form:"state" valid:"Range(0,1)"` } // @Summary Add article // @Produce json // @Param tag_id body int true "TagID" // @Param title body string true "Title" // @Param desc body string true "Desc" // @Param content body string true "Content" // @Param created_by body string true "CreatedBy" // @Param state body int true "State" // @Success 200 {object} app.Response // @Failure 500 {object} app.Response // @Router /api/v1/articles [post] func AddArticle(c *gin.Context) { var ( appG = app.Gin{C: c} form AddArticleForm ) httpCode, errCode := app.BindAndValid(c, &form) if errCode != e.SUCCESS { appG.Response(httpCode, errCode, nil) return } tagService := tag_service.Tag{ID: form.TagID} exists, err := tagService.ExistByID() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_EXIST_TAG_FAIL, nil) return } if !exists { appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_TAG, nil) return } articleService := article_service.Article{ TagID: form.TagID, Title: form.Title, Desc: form.Desc, Content: form.Content, CoverImageUrl: form.CoverImageUrl, State: form.State, CreatedBy: form.CreatedBy, } if err := articleService.Add(); err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_ADD_ARTICLE_FAIL, nil) return } appG.Response(http.StatusOK, e.SUCCESS, nil) } type EditArticleForm struct { ID int `form:"id" valid:"Required;Min(1)"` TagID int `form:"tag_id" valid:"Required;Min(1)"` Title string `form:"title" valid:"Required;MaxSize(100)"` Desc string `form:"desc" valid:"Required;MaxSize(255)"` Content string `form:"content" valid:"Required;MaxSize(65535)"` ModifiedBy string `form:"modified_by" valid:"Required;MaxSize(100)"` CoverImageUrl string `form:"cover_image_url" valid:"Required;MaxSize(255)"` State int `form:"state" valid:"Range(0,1)"` } // @Summary Update article // @Produce json // @Param id path int true "ID" // @Param tag_id body string false "TagID" // @Param title body string false "Title" // @Param desc body string false "Desc" // @Param content body string false "Content" // @Param modified_by body string true "ModifiedBy" // @Param state body int false "State" // @Success 200 {object} app.Response // @Failure 500 {object} app.Response // @Router /api/v1/articles/{id} [put] func EditArticle(c *gin.Context) { var ( appG = app.Gin{C: c} form = EditArticleForm{ID: com.StrTo(c.Param("id")).MustInt()} ) httpCode, errCode := app.BindAndValid(c, &form) if errCode != e.SUCCESS { appG.Response(httpCode, errCode, nil) return } articleService := article_service.Article{ ID: form.ID, TagID: form.TagID, Title: form.Title, Desc: form.Desc, Content: form.Content, CoverImageUrl: form.CoverImageUrl, ModifiedBy: form.ModifiedBy, State: form.State, } exists, err := articleService.ExistByID() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_CHECK_EXIST_ARTICLE_FAIL, nil) return } if !exists { appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_ARTICLE, nil) return } tagService := tag_service.Tag{ID: form.TagID} exists, err = tagService.ExistByID() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_EXIST_TAG_FAIL, nil) return } if !exists { appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_TAG, nil) return } err = articleService.Edit() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_EDIT_ARTICLE_FAIL, nil) return } appG.Response(http.StatusOK, e.SUCCESS, nil) } // @Summary Delete article // @Produce json // @Param id path int true "ID" // @Success 200 {object} app.Response // @Failure 500 {object} app.Response // @Router /api/v1/articles/{id} [delete] func DeleteArticle(c *gin.Context) { appG := app.Gin{C: c} valid := validation.Validation{} id := com.StrTo(c.Param("id")).MustInt() valid.Min(id, 1, "id").Message("ID必须大于0") if valid.HasErrors() { app.MarkErrors(valid.Errors) appG.Response(http.StatusOK, e.INVALID_PARAMS, nil) return } articleService := article_service.Article{ID: id} exists, err := articleService.ExistByID() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_CHECK_EXIST_ARTICLE_FAIL, nil) return } if !exists { appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_ARTICLE, nil) return } err = articleService.Delete() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_DELETE_ARTICLE_FAIL, nil) return } appG.Response(http.StatusOK, e.SUCCESS, nil) } const ( QRCODE_URL = "https://github.com/EDDYCJY/blog#gin%E7%B3%BB%E5%88%97%E7%9B%AE%E5%BD%95" ) func GenerateArticlePoster(c *gin.Context) { appG := app.Gin{C: c} article := &article_service.Article{} qr := qrcode.NewQrCode(QRCODE_URL, 300, 300, qr.M, qr.Auto) posterName := article_service.GetPosterFlag() + "-" + qrcode.GetQrCodeFileName(qr.URL) + qr.GetQrCodeExt() articlePoster := article_service.NewArticlePoster(posterName, article, qr) articlePosterBgService := article_service.NewArticlePosterBg( "bg.jpg", articlePoster, &article_service.Rect{ X0: 0, Y0: 0, X1: 550, Y1: 700, }, &article_service.Pt{ X: 125, Y: 298, }, ) _, filePath, err := articlePosterBgService.Generate() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_GEN_ARTICLE_POSTER_FAIL, nil) return } appG.Response(http.StatusOK, e.SUCCESS, map[string]string{ "poster_url": qrcode.GetQrCodeFullUrl(posterName), "poster_save_url": filePath + posterName, }) } ================================================ FILE: routers/api/v1/tag.go ================================================ package v1 import ( "net/http" "github.com/unknwon/com" "github.com/astaxie/beego/validation" "github.com/gin-gonic/gin" "github.com/EDDYCJY/go-gin-example/pkg/app" "github.com/EDDYCJY/go-gin-example/pkg/e" "github.com/EDDYCJY/go-gin-example/pkg/export" "github.com/EDDYCJY/go-gin-example/pkg/logging" "github.com/EDDYCJY/go-gin-example/pkg/setting" "github.com/EDDYCJY/go-gin-example/pkg/util" "github.com/EDDYCJY/go-gin-example/service/tag_service" ) // @Summary Get multiple article tags // @Produce json // @Param name query string false "Name" // @Param state query int false "State" // @Success 200 {object} app.Response // @Failure 500 {object} app.Response // @Router /api/v1/tags [get] func GetTags(c *gin.Context) { appG := app.Gin{C: c} name := c.Query("name") state := -1 if arg := c.Query("state"); arg != "" { state = com.StrTo(arg).MustInt() } tagService := tag_service.Tag{ Name: name, State: state, PageNum: util.GetPage(c), PageSize: setting.AppSetting.PageSize, } tags, err := tagService.GetAll() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_GET_TAGS_FAIL, nil) return } count, err := tagService.Count() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_COUNT_TAG_FAIL, nil) return } appG.Response(http.StatusOK, e.SUCCESS, map[string]interface{}{ "lists": tags, "total": count, }) } type AddTagForm struct { Name string `form:"name" valid:"Required;MaxSize(100)"` CreatedBy string `form:"created_by" valid:"Required;MaxSize(100)"` State int `form:"state" valid:"Range(0,1)"` } // @Summary Add article tag // @Produce json // @Param name body string true "Name" // @Param state body int false "State" // @Param created_by body int false "CreatedBy" // @Success 200 {object} app.Response // @Failure 500 {object} app.Response // @Router /api/v1/tags [post] func AddTag(c *gin.Context) { var ( appG = app.Gin{C: c} form AddTagForm ) httpCode, errCode := app.BindAndValid(c, &form) if errCode != e.SUCCESS { appG.Response(httpCode, errCode, nil) return } tagService := tag_service.Tag{ Name: form.Name, CreatedBy: form.CreatedBy, State: form.State, } exists, err := tagService.ExistByName() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_EXIST_TAG_FAIL, nil) return } if exists { appG.Response(http.StatusOK, e.ERROR_EXIST_TAG, nil) return } err = tagService.Add() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_ADD_TAG_FAIL, nil) return } appG.Response(http.StatusOK, e.SUCCESS, nil) } type EditTagForm struct { ID int `form:"id" valid:"Required;Min(1)"` Name string `form:"name" valid:"Required;MaxSize(100)"` ModifiedBy string `form:"modified_by" valid:"Required;MaxSize(100)"` State int `form:"state" valid:"Range(0,1)"` } // @Summary Update article tag // @Produce json // @Param id path int true "ID" // @Param name body string true "Name" // @Param state body int false "State" // @Param modified_by body string true "ModifiedBy" // @Success 200 {object} app.Response // @Failure 500 {object} app.Response // @Router /api/v1/tags/{id} [put] func EditTag(c *gin.Context) { var ( appG = app.Gin{C: c} form = EditTagForm{ID: com.StrTo(c.Param("id")).MustInt()} ) httpCode, errCode := app.BindAndValid(c, &form) if errCode != e.SUCCESS { appG.Response(httpCode, errCode, nil) return } tagService := tag_service.Tag{ ID: form.ID, Name: form.Name, ModifiedBy: form.ModifiedBy, State: form.State, } exists, err := tagService.ExistByID() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_EXIST_TAG_FAIL, nil) return } if !exists { appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_TAG, nil) return } err = tagService.Edit() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_EDIT_TAG_FAIL, nil) return } appG.Response(http.StatusOK, e.SUCCESS, nil) } // @Summary Delete article tag // @Produce json // @Param id path int true "ID" // @Success 200 {object} app.Response // @Failure 500 {object} app.Response // @Router /api/v1/tags/{id} [delete] func DeleteTag(c *gin.Context) { appG := app.Gin{C: c} valid := validation.Validation{} id := com.StrTo(c.Param("id")).MustInt() valid.Min(id, 1, "id").Message("ID必须大于0") if valid.HasErrors() { app.MarkErrors(valid.Errors) appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil) } tagService := tag_service.Tag{ID: id} exists, err := tagService.ExistByID() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_EXIST_TAG_FAIL, nil) return } if !exists { appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_TAG, nil) return } if err := tagService.Delete(); err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_DELETE_TAG_FAIL, nil) return } appG.Response(http.StatusOK, e.SUCCESS, nil) } // @Summary Export article tag // @Produce json // @Param name body string false "Name" // @Param state body int false "State" // @Success 200 {object} app.Response // @Failure 500 {object} app.Response // @Router /api/v1/tags/export [post] func ExportTag(c *gin.Context) { appG := app.Gin{C: c} name := c.PostForm("name") state := -1 if arg := c.PostForm("state"); arg != "" { state = com.StrTo(arg).MustInt() } tagService := tag_service.Tag{ Name: name, State: state, } filename, err := tagService.Export() if err != nil { appG.Response(http.StatusInternalServerError, e.ERROR_EXPORT_TAG_FAIL, nil) return } appG.Response(http.StatusOK, e.SUCCESS, map[string]string{ "export_url": export.GetExcelFullUrl(filename), "export_save_url": export.GetExcelPath() + filename, }) } // @Summary Import article tag // @Produce json // @Param file body file true "Excel File" // @Success 200 {object} app.Response // @Failure 500 {object} app.Response // @Router /api/v1/tags/import [post] func ImportTag(c *gin.Context) { appG := app.Gin{C: c} file, _, err := c.Request.FormFile("file") if err != nil { logging.Warn(err) appG.Response(http.StatusInternalServerError, e.ERROR, nil) return } tagService := tag_service.Tag{} err = tagService.Import(file) if err != nil { logging.Warn(err) appG.Response(http.StatusInternalServerError, e.ERROR_IMPORT_TAG_FAIL, nil) return } appG.Response(http.StatusOK, e.SUCCESS, nil) } ================================================ FILE: routers/router.go ================================================ package routers import ( "net/http" "github.com/gin-gonic/gin" _ "github.com/EDDYCJY/go-gin-example/docs" "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" "github.com/EDDYCJY/go-gin-example/middleware/jwt" "github.com/EDDYCJY/go-gin-example/pkg/export" "github.com/EDDYCJY/go-gin-example/pkg/qrcode" "github.com/EDDYCJY/go-gin-example/pkg/upload" "github.com/EDDYCJY/go-gin-example/routers/api" "github.com/EDDYCJY/go-gin-example/routers/api/v1" ) // InitRouter initialize routing information func InitRouter() *gin.Engine { r := gin.New() r.Use(gin.Logger()) r.Use(gin.Recovery()) r.StaticFS("/export", http.Dir(export.GetExcelFullPath())) r.StaticFS("/upload/images", http.Dir(upload.GetImageFullPath())) r.StaticFS("/qrcode", http.Dir(qrcode.GetQrCodeFullPath())) r.POST("/auth", api.GetAuth) r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) r.POST("/upload", api.UploadImage) apiv1 := r.Group("/api/v1") apiv1.Use(jwt.JWT()) { //获取标签列表 apiv1.GET("/tags", v1.GetTags) //新建标签 apiv1.POST("/tags", v1.AddTag) //更新指定标签 apiv1.PUT("/tags/:id", v1.EditTag) //删除指定标签 apiv1.DELETE("/tags/:id", v1.DeleteTag) //导出标签 r.POST("/tags/export", v1.ExportTag) //导入标签 r.POST("/tags/import", v1.ImportTag) //获取文章列表 apiv1.GET("/articles", v1.GetArticles) //获取指定文章 apiv1.GET("/articles/:id", v1.GetArticle) //新建文章 apiv1.POST("/articles", v1.AddArticle) //更新指定文章 apiv1.PUT("/articles/:id", v1.EditArticle) //删除指定文章 apiv1.DELETE("/articles/:id", v1.DeleteArticle) //生成文章海报 apiv1.POST("/articles/poster/generate", v1.GenerateArticlePoster) } return r } ================================================ FILE: runtime/fonts/msyhbd.ttc ================================================ [File too large to display: 16.0 MB] ================================================ FILE: service/article_service/article.go ================================================ package article_service import ( "encoding/json" "github.com/EDDYCJY/go-gin-example/models" "github.com/EDDYCJY/go-gin-example/pkg/gredis" "github.com/EDDYCJY/go-gin-example/pkg/logging" "github.com/EDDYCJY/go-gin-example/service/cache_service" ) type Article struct { ID int TagID int Title string Desc string Content string CoverImageUrl string State int CreatedBy string ModifiedBy string PageNum int PageSize int } func (a *Article) Add() error { article := map[string]interface{}{ "tag_id": a.TagID, "title": a.Title, "desc": a.Desc, "content": a.Content, "created_by": a.CreatedBy, "cover_image_url": a.CoverImageUrl, "state": a.State, } if err := models.AddArticle(article); err != nil { return err } return nil } func (a *Article) Edit() error { return models.EditArticle(a.ID, map[string]interface{}{ "tag_id": a.TagID, "title": a.Title, "desc": a.Desc, "content": a.Content, "cover_image_url": a.CoverImageUrl, "state": a.State, "modified_by": a.ModifiedBy, }) } func (a *Article) Get() (*models.Article, error) { var cacheArticle *models.Article cache := cache_service.Article{ID: a.ID} key := cache.GetArticleKey() if gredis.Exists(key) { data, err := gredis.Get(key) if err != nil { logging.Info(err) } else { json.Unmarshal(data, &cacheArticle) return cacheArticle, nil } } article, err := models.GetArticle(a.ID) if err != nil { return nil, err } gredis.Set(key, article, 3600) return article, nil } func (a *Article) GetAll() ([]*models.Article, error) { var ( articles, cacheArticles []*models.Article ) cache := cache_service.Article{ TagID: a.TagID, State: a.State, PageNum: a.PageNum, PageSize: a.PageSize, } key := cache.GetArticlesKey() if gredis.Exists(key) { data, err := gredis.Get(key) if err != nil { logging.Info(err) } else { json.Unmarshal(data, &cacheArticles) return cacheArticles, nil } } articles, err := models.GetArticles(a.PageNum, a.PageSize, a.getMaps()) if err != nil { return nil, err } gredis.Set(key, articles, 3600) return articles, nil } func (a *Article) Delete() error { return models.DeleteArticle(a.ID) } func (a *Article) ExistByID() (bool, error) { return models.ExistArticleByID(a.ID) } func (a *Article) Count() (int, error) { return models.GetArticleTotal(a.getMaps()) } func (a *Article) getMaps() map[string]interface{} { maps := make(map[string]interface{}) maps["deleted_on"] = 0 if a.State != -1 { maps["state"] = a.State } if a.TagID != -1 { maps["tag_id"] = a.TagID } return maps } ================================================ FILE: service/article_service/article_poster.go ================================================ package article_service import ( "image" "image/draw" "image/jpeg" "io/ioutil" "os" "github.com/golang/freetype" "github.com/EDDYCJY/go-gin-example/pkg/file" "github.com/EDDYCJY/go-gin-example/pkg/qrcode" "github.com/EDDYCJY/go-gin-example/pkg/setting" ) type ArticlePoster struct { PosterName string *Article Qr *qrcode.QrCode } func NewArticlePoster(posterName string, article *Article, qr *qrcode.QrCode) *ArticlePoster { return &ArticlePoster{ PosterName: posterName, Article: article, Qr: qr, } } func GetPosterFlag() string { return "poster" } func (a *ArticlePoster) CheckMergedImage(path string) bool { if file.CheckNotExist(path+a.PosterName) == true { return false } return true } func (a *ArticlePoster) OpenMergedImage(path string) (*os.File, error) { f, err := file.MustOpen(a.PosterName, path) if err != nil { return nil, err } return f, nil } type ArticlePosterBg struct { Name string *ArticlePoster *Rect *Pt } type Rect struct { Name string X0 int Y0 int X1 int Y1 int } type Pt struct { X int Y int } func NewArticlePosterBg(name string, ap *ArticlePoster, rect *Rect, pt *Pt) *ArticlePosterBg { return &ArticlePosterBg{ Name: name, ArticlePoster: ap, Rect: rect, Pt: pt, } } type DrawText struct { JPG draw.Image Merged *os.File Title string X0 int Y0 int Size0 float64 SubTitle string X1 int Y1 int Size1 float64 } func (a *ArticlePosterBg) DrawPoster(d *DrawText, fontName string) error { fontSource := setting.AppSetting.RuntimeRootPath + setting.AppSetting.FontSavePath + fontName fontSourceBytes, err := ioutil.ReadFile(fontSource) if err != nil { return err } trueTypeFont, err := freetype.ParseFont(fontSourceBytes) if err != nil { return err } fc := freetype.NewContext() fc.SetDPI(72) fc.SetFont(trueTypeFont) fc.SetFontSize(d.Size0) fc.SetClip(d.JPG.Bounds()) fc.SetDst(d.JPG) fc.SetSrc(image.Black) pt := freetype.Pt(d.X0, d.Y0) _, err = fc.DrawString(d.Title, pt) if err != nil { return err } fc.SetFontSize(d.Size1) _, err = fc.DrawString(d.SubTitle, freetype.Pt(d.X1, d.Y1)) if err != nil { return err } err = jpeg.Encode(d.Merged, d.JPG, nil) if err != nil { return err } return nil } func (a *ArticlePosterBg) Generate() (string, string, error) { fullPath := qrcode.GetQrCodeFullPath() fileName, path, err := a.Qr.Encode(fullPath) if err != nil { return "", "", err } if !a.CheckMergedImage(path) { mergedF, err := a.OpenMergedImage(path) if err != nil { return "", "", err } defer mergedF.Close() bgF, err := file.MustOpen(a.Name, path) if err != nil { return "", "", err } defer bgF.Close() qrF, err := file.MustOpen(fileName, path) if err != nil { return "", "", err } defer qrF.Close() bgImage, err := jpeg.Decode(bgF) if err != nil { return "", "", err } qrImage, err := jpeg.Decode(qrF) if err != nil { return "", "", err } jpg := image.NewRGBA(image.Rect(a.Rect.X0, a.Rect.Y0, a.Rect.X1, a.Rect.Y1)) draw.Draw(jpg, jpg.Bounds(), bgImage, bgImage.Bounds().Min, draw.Over) draw.Draw(jpg, jpg.Bounds(), qrImage, qrImage.Bounds().Min.Sub(image.Pt(a.Pt.X, a.Pt.Y)), draw.Over) err = a.DrawPoster(&DrawText{ JPG: jpg, Merged: mergedF, Title: "Golang Gin 系列文章", X0: 80, Y0: 160, Size0: 42, SubTitle: "---煎鱼", X1: 320, Y1: 220, Size1: 36, }, "msyhbd.ttc") if err != nil { return "", "", err } } return fileName, path, nil } ================================================ FILE: service/auth_service/auth.go ================================================ package auth_service import "github.com/EDDYCJY/go-gin-example/models" type Auth struct { Username string Password string } func (a *Auth) Check() (bool, error) { return models.CheckAuth(a.Username, a.Password) } ================================================ FILE: service/cache_service/article.go ================================================ package cache_service import ( "strconv" "strings" "github.com/EDDYCJY/go-gin-example/pkg/e" ) type Article struct { ID int TagID int State int PageNum int PageSize int } func (a *Article) GetArticleKey() string { return e.CACHE_ARTICLE + "_" + strconv.Itoa(a.ID) } func (a *Article) GetArticlesKey() string { keys := []string{ e.CACHE_ARTICLE, "LIST", } if a.ID > 0 { keys = append(keys, strconv.Itoa(a.ID)) } if a.TagID > 0 { keys = append(keys, strconv.Itoa(a.TagID)) } if a.State >= 0 { keys = append(keys, strconv.Itoa(a.State)) } if a.PageNum > 0 { keys = append(keys, strconv.Itoa(a.PageNum)) } if a.PageSize > 0 { keys = append(keys, strconv.Itoa(a.PageSize)) } return strings.Join(keys, "_") } ================================================ FILE: service/cache_service/tag.go ================================================ package cache_service import ( "strconv" "strings" "github.com/EDDYCJY/go-gin-example/pkg/e" ) type Tag struct { ID int Name string State int PageNum int PageSize int } func (t *Tag) GetTagsKey() string { keys := []string{ e.CACHE_TAG, "LIST", } if t.Name != "" { keys = append(keys, t.Name) } if t.State >= 0 { keys = append(keys, strconv.Itoa(t.State)) } if t.PageNum > 0 { keys = append(keys, strconv.Itoa(t.PageNum)) } if t.PageSize > 0 { keys = append(keys, strconv.Itoa(t.PageSize)) } return strings.Join(keys, "_") } ================================================ FILE: service/tag_service/tag.go ================================================ package tag_service import ( "encoding/json" "io" "strconv" "time" "github.com/360EntSecGroup-Skylar/excelize" "github.com/tealeg/xlsx" "github.com/EDDYCJY/go-gin-example/models" "github.com/EDDYCJY/go-gin-example/pkg/export" "github.com/EDDYCJY/go-gin-example/pkg/file" "github.com/EDDYCJY/go-gin-example/pkg/gredis" "github.com/EDDYCJY/go-gin-example/pkg/logging" "github.com/EDDYCJY/go-gin-example/service/cache_service" ) type Tag struct { ID int Name string CreatedBy string ModifiedBy string State int PageNum int PageSize int } func (t *Tag) ExistByName() (bool, error) { return models.ExistTagByName(t.Name) } func (t *Tag) ExistByID() (bool, error) { return models.ExistTagByID(t.ID) } func (t *Tag) Add() error { return models.AddTag(t.Name, t.State, t.CreatedBy) } func (t *Tag) Edit() error { data := make(map[string]interface{}) data["modified_by"] = t.ModifiedBy data["name"] = t.Name if t.State >= 0 { data["state"] = t.State } return models.EditTag(t.ID, data) } func (t *Tag) Delete() error { return models.DeleteTag(t.ID) } func (t *Tag) Count() (int, error) { return models.GetTagTotal(t.getMaps()) } func (t *Tag) GetAll() ([]models.Tag, error) { var ( tags, cacheTags []models.Tag ) cache := cache_service.Tag{ State: t.State, PageNum: t.PageNum, PageSize: t.PageSize, } key := cache.GetTagsKey() if gredis.Exists(key) { data, err := gredis.Get(key) if err != nil { logging.Info(err) } else { json.Unmarshal(data, &cacheTags) return cacheTags, nil } } tags, err := models.GetTags(t.PageNum, t.PageSize, t.getMaps()) if err != nil { return nil, err } gredis.Set(key, tags, 3600) return tags, nil } func (t *Tag) Export() (string, error) { tags, err := t.GetAll() if err != nil { return "", err } xlsFile := xlsx.NewFile() sheet, err := xlsFile.AddSheet("标签信息") if err != nil { return "", err } titles := []string{"ID", "名称", "创建人", "创建时间", "修改人", "修改时间"} row := sheet.AddRow() var cell *xlsx.Cell for _, title := range titles { cell = row.AddCell() cell.Value = title } for _, v := range tags { values := []string{ strconv.Itoa(v.ID), v.Name, v.CreatedBy, strconv.Itoa(v.CreatedOn), v.ModifiedBy, strconv.Itoa(v.ModifiedOn), } row = sheet.AddRow() for _, value := range values { cell = row.AddCell() cell.Value = value } } time := strconv.Itoa(int(time.Now().Unix())) filename := "tags-" + time + export.EXT dirFullPath := export.GetExcelFullPath() err = file.IsNotExistMkDir(dirFullPath) if err != nil { return "", err } err = xlsFile.Save(dirFullPath + filename) if err != nil { return "", err } return filename, nil } func (t *Tag) Import(r io.Reader) error { xlsx, err := excelize.OpenReader(r) if err != nil { return err } rows := xlsx.GetRows("标签信息") for irow, row := range rows { if irow > 0 { var data []string for _, cell := range row { data = append(data, cell) } models.AddTag(data[1], 1, data[2]) } } return nil } func (t *Tag) getMaps() map[string]interface{} { maps := make(map[string]interface{}) maps["deleted_on"] = 0 if t.Name != "" { maps["name"] = t.Name } if t.State >= 0 { maps["state"] = t.State } return maps } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/.travis.yml ================================================ language: go install: - go get -d -t -v ./... && go build -v ./... go: - 1.8.x - 1.9.x script: - go vet ./... - go test ./... -v -coverprofile=coverage.txt -covermode=atomic after_success: - bash <(curl -s https://codecov.io/bash) ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [xuri.me](https://xuri.me). The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/CONTRIBUTING.md ================================================ # Contributing to excelize Want to hack on excelize? Awesome! This page contains information about reporting issues as well as some tips and guidelines useful to experienced open source contributors. Finally, make sure you read our [community guidelines](#community-guidelines) before you start participating. ## Topics * [Reporting Security Issues](#reporting-security-issues) * [Design and Cleanup Proposals](#design-and-cleanup-proposals) * [Reporting Issues](#reporting-other-issues) * [Quick Contribution Tips and Guidelines](#quick-contribution-tips-and-guidelines) * [Community Guidelines](#community-guidelines) ## Reporting security issues The excelize maintainers take security seriously. If you discover a security issue, please bring it to their attention right away! Please **DO NOT** file a public issue, instead send your report privately to [xuri.me](https://xuri.me). Security reports are greatly appreciated and we will publicly thank you for it. We currently do not offer a paid security bounty program, but are not ruling it out in the future. ## Reporting other issues A great way to contribute to the project is to send a detailed report when you encounter an issue. We always appreciate a well-written, thorough bug report, and will thank you for it! Check that [our issue database](https://github.com/360EntSecGroup-Skylar/excelize/issues) doesn't already include that problem or suggestion before submitting an issue. If you find a match, you can use the "subscribe" button to get notified on updates. Do *not* leave random "+1" or "I have this too" comments, as they only clutter the discussion, and don't help resolving it. However, if you have ways to reproduce the issue or have additional information that may help resolving the issue, please leave a comment. When reporting issues, always include the output of `go env`. Also include the steps required to reproduce the problem if possible and applicable. This information will help us review and fix your issue faster. When sending lengthy log-files, consider posting them as a gist [https://gist.github.com](https://gist.github.com). Don't forget to remove sensitive data from your logfiles before posting (you can replace those parts with "REDACTED"). ## Quick contribution tips and guidelines This section gives the experienced contributor some tips and guidelines. ### Pull requests are always welcome Not sure if that typo is worth a pull request? Found a bug and know how to fix it? Do it! We will appreciate it. Any significant improvement should be documented as [a GitHub issue](https://github.com/360EntSecGroup-Skylar/excelize/issues) before anybody starts working on it. We are always thrilled to receive pull requests. We do our best to process them quickly. If your pull request is not accepted on the first try, don't get discouraged! ### Design and cleanup proposals You can propose new designs for existing excelize features. You can also design entirely new features. We really appreciate contributors who want to refactor or otherwise cleanup our project. We try hard to keep excelize lean and focused. Excelize can't do everything for everybody. This means that we might decide against incorporating a new feature. However, there might be a way to implement that feature *on top of* excelize. ### Conventions Fork the repository and make changes on your fork in a feature branch: * If it's a bug fix branch, name it XXXX-something where XXXX is the number of the issue. * If it's a feature branch, create an enhancement issue to announce your intentions, and name it XXXX-something where XXXX is the number of the issue. Submit unit tests for your changes. Go has a great test framework built in; use it! Take a look at existing tests for inspiration. Run the full test on your branch before submitting a pull request. Update the documentation when creating or modifying features. Test your documentation changes for clarity, concision, and correctness, as well as a clean documentation build. Write clean code. Universally formatted code promotes ease of writing, reading, and maintenance. Always run `gofmt -s -w file.go` on each changed file before committing your changes. Most editors have plug-ins that do this automatically. Pull request descriptions should be as clear as possible and include a reference to all the issues that they address. ### Successful Changes Before contributing large or high impact changes, make the effort to coordinate with the maintainers of the project before submitting a pull request. This prevents you from doing extra work that may or may not be merged. Large PRs that are just submitted without any prior communication are unlikely to be successful. While pull requests are the methodology for submitting changes to code, changes are much more likely to be accepted if they are accompanied by additional engineering work. While we don't define this explicitly, most of these goals are accomplished through communication of the design goals and subsequent solutions. Often times, it helps to first state the problem before presenting solutions. Typically, the best methods of accomplishing this are to submit an issue, stating the problem. This issue can include a problem statement and a checklist with requirements. If solutions are proposed, alternatives should be listed and eliminated. Even if the criteria for elimination of a solution is frivolous, say so. Larger changes typically work best with design documents. These are focused on providing context to the design at the time the feature was conceived and can inform future documentation contributions. ### Commit Messages Commit messages must start with a capitalized and short summary written in the imperative, followed by an optional, more detailed explanatory text which is separated from the summary by an empty line. Commit messages should follow best practices, including explaining the context of the problem and how it was solved, including in caveats or follow up changes required. They should tell the story of the change and provide readers understanding of what led to it. In practice, the best approach to maintaining a nice commit message is to leverage a `git add -p` and `git commit --amend` to formulate a solid changeset. This allows one to piece together a change, as information becomes available. If you squash a series of commits, don't just submit that. Re-write the commit message, as if the series of commits was a single stroke of brilliance. That said, there is no requirement to have a single commit for a PR, as long as each commit tells the story. For example, if there is a feature that requires a package, it might make sense to have the package in a separate commit then have a subsequent commit that uses it. Remember, you're telling part of the story with the commit message. Don't make your chapter weird. ### Review Code review comments may be added to your pull request. Discuss, then make the suggested modifications and push additional commits to your feature branch. Post a comment after pushing. New commits show up in the pull request automatically, but the reviewers are notified only when you comment. Pull requests must be cleanly rebased on top of master without multiple branches mixed into the PR. **Git tip**: If your PR no longer merges cleanly, use `rebase master` in your feature branch to update your pull request rather than `merge master`. Before you make a pull request, squash your commits into logical units of work using `git rebase -i` and `git push -f`. A logical unit of work is a consistent set of patches that should be reviewed together: for example, upgrading the version of a vendored dependency and taking advantage of its now available new feature constitute two separate units of work. Implementing a new function and calling it in another file constitute a single logical unit of work. The very high majority of submissions should have a single commit, so if in doubt: squash down to one. After every commit, make sure the test passes. Include documentation changes in the same pull request so that a revert would remove all traces of the feature or fix. Include an issue reference like `Closes #XXXX` or `Fixes #XXXX` in commits that close an issue. Including references automatically closes the issue on a merge. Please see the [Coding Style](#coding-style) for further guidelines. ### Merge approval The excelize maintainers use LGTM (Looks Good To Me) in comments on the code review to indicate acceptance. ### Sign your work The sign-off is a simple line at the end of the explanation for the patch. Your signature certifies that you wrote the patch or otherwise have the right to pass it on as an open-source patch. The rules are pretty simple: if you can certify the below (from [developercertificate.org](http://developercertificate.org/)): ```text Developer Certificate of Origin Version 1.1 Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 1 Letterman Drive Suite D4700 San Francisco, CA, 94129 Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. ``` Then you just add a line to every git commit message: Signed-off-by: Ri Xu https://xuri.me Use your real name (sorry, no pseudonyms or anonymous contributions.) If you set your `user.name` and `user.email` git configs, you can sign your commit automatically with `git commit -s`. ### How can I become a maintainer First, all maintainers have 3 things * They share responsibility in the project's success. * They have made a long-term, recurring time investment to improve the project. * They spend that time doing whatever needs to be done, not necessarily what is the most interesting or fun. Maintainers are often under-appreciated, because their work is harder to appreciate. It's easy to appreciate a really cool and technically advanced feature. It's harder to appreciate the absence of bugs, the slow but steady improvement in stability, or the reliability of a release process. But those things distinguish a good project from a great one. Don't forget: being a maintainer is a time investment. Make sure you will have time to make yourself available. You don't have to be a maintainer to make a difference on the project! If you want to become a meintainer, contact [xuri.me](https://xuri.me) and given a introduction of you. ## Community guidelines We want to keep the community awesome, growing and collaborative. We need your help to keep it that way. To help with this we've come up with some general guidelines for the community as a whole: * Be nice: Be courteous, respectful and polite to fellow community members: no regional, racial, gender, or other abuse will be tolerated. We like nice people way better than mean ones! * Encourage diversity and participation: Make everyone in our community feel welcome, regardless of their background and the extent of their contributions, and do everything possible to encourage participation in our community. * Keep it legal: Basically, don't get us in trouble. Share only content that you own, do not share private or sensitive information, and don't break the law. * Stay on topic: Make sure that you are posting to the correct channel and avoid off-topic discussions. Remember when you update an issue or respond to an email you are potentially sending to a large number of people. Please consider this before you update. Also remember that nobody likes spam. * Don't send email to the maintainers: There's no need to send email to the maintainers to ask them to investigate an issue or to take a look at a pull request. Instead of sending an email, GitHub mentions should be used to ping maintainers to review a pull request, a proposal or an issue. ### Guideline violations — 3 strikes method The point of this section is not to find opportunities to punish people, but we do need a fair way to deal with people who are making our community suck. 1. First occurrence: We'll give you a friendly, but public reminder that the behavior is inappropriate according to our guidelines. 2. Second occurrence: We will send you a private message with a warning that any additional violations will result in removal from the community. 3. Third occurrence: Depending on the violation, we may need to delete or ban your account. **Notes:** * Obvious spammers are banned on first occurrence. If we don't do this, we'll have spam all over the place. * Violations are forgiven after 6 months of good behavior, and we won't hold a grudge. * People who commit minor infractions will get some education, rather than hammering them in the 3 strikes process. * The rules apply equally to everyone in the community, no matter how much you've contributed. * Extreme violations of a threatening, abusive, destructive or illegal nature will be addressed immediately and are not subject to 3 strikes or forgiveness. * Contact [xuri.me](https://xuri.me) to report abuse or appeal violations. In the case of appeals, we know that mistakes happen, and we'll work with you to come up with a fair solution if there has been a misunderstanding. ## Coding Style Unless explicitly stated, we follow all coding guidelines from the Go community. While some of these standards may seem arbitrary, they somehow seem to result in a solid, consistent codebase. It is possible that the code base does not currently comply with these guidelines. We are not looking for a massive PR that fixes this, since that goes against the spirit of the guidelines. All new contributions should make a best effort to clean up and make the code base better than they left it. Obviously, apply your best judgement. Remember, the goal here is to make the code base easier for humans to navigate and understand. Always keep that in mind when nudging others to comply. The rules: 1. All code should be formatted with `gofmt -s`. 2. All code should pass the default levels of [`golint`](https://github.com/golang/lint). 3. All code should follow the guidelines covered in [Effective Go](http://golang.org/doc/effective_go.html) and [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments). 4. Comment the code. Tell us the why, the history and the context. 5. Document _all_ declarations and methods, even private ones. Declare expectations, caveats and anything else that may be important. If a type gets exported, having the comments already there will ensure it's ready. 6. Variable name length should be proportional to its context and no longer. `noCommaALongVariableNameLikeThisIsNotMoreClearWhenASimpleCommentWouldDo`. In practice, short methods will have short variable names and globals will have longer names. 7. No underscores in package names. If you need a compound name, step back, and re-examine why you need a compound name. If you still think you need a compound name, lose the underscore. 8. No utils or helpers packages. If a function is not general enough to warrant its own package, it has not been written generally enough to be a part of a util package. Just leave it unexported and well-documented. 9. All tests should run with `go test` and outside tooling should not be required. No, we don't need another unit testing framework. Assertion packages are acceptable if they provide _real_ incremental value. 10. Even though we call these "rules" above, they are actually just guidelines. Since you've read all the rules, you now know that. If you are having trouble getting into the mood of idiomatic Go, we recommend reading through [Effective Go](https://golang.org/doc/effective_go.html). The [Go Blog](https://blog.golang.org) is also a great resource. Drinking the kool-aid is a lot easier than going thirsty. ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/LICENSE ================================================ BSD 3-Clause License Copyright (c) 2016 - 2018 360 Enterprise Security Group, Endpoint Security, inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * 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 Excelize 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. ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/README.md ================================================ ![Excelize](./excelize.png "Excelize") # Excelize [![Build Status](https://travis-ci.org/360EntSecGroup-Skylar/excelize.svg?branch=master)](https://travis-ci.org/360EntSecGroup-Skylar/excelize) [![Code Coverage](https://codecov.io/gh/360EntSecGroup-Skylar/excelize/branch/master/graph/badge.svg)](https://codecov.io/gh/360EntSecGroup-Skylar/excelize) [![Go Report Card](https://goreportcard.com/badge/github.com/360EntSecGroup-Skylar/excelize)](https://goreportcard.com/report/github.com/360EntSecGroup-Skylar/excelize) [![GoDoc](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize?status.svg)](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize) [![Licenses](https://img.shields.io/badge/license-bsd-orange.svg)](https://opensource.org/licenses/BSD-3-Clause) [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/xuri) ## Introduction Excelize is a library written in pure Go and providing a set of functions that allow you to write to and read from XLSX files. Support reads and writes XLSX file generated by Microsoft Excel™ 2007 and later. Support save file without losing original charts of XLSX. This library needs Go version 1.8 or later. The full API docs can be seen using go's built-in documentation tool, or online at [godoc.org](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize) and [Chinese translation](https://xuri.me/excelize/zh_cn). ## Basic Usage ### Installation ```go go get github.com/360EntSecGroup-Skylar/excelize ``` ### Create XLSX file Here is a minimal example usage that will create XLSX file. ```go package main import ( "fmt" "github.com/360EntSecGroup-Skylar/excelize" ) func main() { xlsx := excelize.NewFile() // Create a new sheet. index := xlsx.NewSheet("Sheet2") // Set value of a cell. xlsx.SetCellValue("Sheet2", "A2", "Hello world.") xlsx.SetCellValue("Sheet1", "B2", 100) // Set active sheet of the workbook. xlsx.SetActiveSheet(index) // Save xlsx file by the given path. err := xlsx.SaveAs("./Book1.xlsx") if err != nil { fmt.Println(err) } } ``` ### Reading XLSX file The following constitutes the bare to read a XLSX document. ```go package main import ( "fmt" "github.com/360EntSecGroup-Skylar/excelize" ) func main() { xlsx, err := excelize.OpenFile("./Book1.xlsx") if err != nil { fmt.Println(err) return } // Get value from cell by given worksheet name and axis. cell := xlsx.GetCellValue("Sheet1", "B2") fmt.Println(cell) // Get all the rows in the Sheet1. rows := xlsx.GetRows("Sheet1") for _, row := range rows { for _, colCell := range row { fmt.Print(colCell, "\t") } fmt.Println() } } ``` ### Add chart to XLSX file With Excelize chart generation and management is as easy as a few lines of code. You can build charts based off data in your worksheet or generate charts without any data in your worksheet at all. ![Excelize](./test/images/chart.png "Excelize") ```go package main import ( "fmt" "github.com/360EntSecGroup-Skylar/excelize" ) func main() { categories := map[string]string{"A2": "Small", "A3": "Normal", "A4": "Large", "B1": "Apple", "C1": "Orange", "D1": "Pear"} values := map[string]int{"B2": 2, "C2": 3, "D2": 3, "B3": 5, "C3": 2, "D3": 4, "B4": 6, "C4": 7, "D4": 8} xlsx := excelize.NewFile() for k, v := range categories { xlsx.SetCellValue("Sheet1", k, v) } for k, v := range values { xlsx.SetCellValue("Sheet1", k, v) } xlsx.AddChart("Sheet1", "E1", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`) // Save xlsx file by the given path. err := xlsx.SaveAs("./Book1.xlsx") if err != nil { fmt.Println(err) } } ``` ### Add picture to XLSX file ```go package main import ( "fmt" _ "image/gif" _ "image/jpeg" _ "image/png" "github.com/360EntSecGroup-Skylar/excelize" ) func main() { xlsx, err := excelize.OpenFile("./Book1.xlsx") if err != nil { fmt.Println(err) return } // Insert a picture. err = xlsx.AddPicture("Sheet1", "A2", "./image1.png", "") if err != nil { fmt.Println(err) } // Insert a picture to worksheet with scaling. err = xlsx.AddPicture("Sheet1", "D2", "./image2.jpg", `{"x_scale": 0.5, "y_scale": 0.5}`) if err != nil { fmt.Println(err) } // Insert a picture offset in the cell with printing support. err = xlsx.AddPicture("Sheet1", "H2", "./image3.gif", `{"x_offset": 15, "y_offset": 10, "print_obj": true, "lock_aspect_ratio": false, "locked": false}`) if err != nil { fmt.Println(err) } // Save the xlsx file with the origin path. err = xlsx.Save() if err != nil { fmt.Println(err) } } ``` ## Contributing Contributions are welcome! Open a pull request to fix a bug, or open an issue to discuss a new feature or change. XML is compliant with [part 1 of the 5th edition of the ECMA-376 Standard for Office Open XML](http://www.ecma-international.org/publications/standards/Ecma-376.htm). ## Credits Some struct of XML originally by [tealeg/xlsx](https://github.com/tealeg/xlsx). ## Licenses This program is under the terms of the BSD 3-Clause License. See [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause). ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/README_zh.md ================================================ ![Excelize](./excelize.png "Excelize") # Excelize [![Build Status](https://travis-ci.org/360EntSecGroup-Skylar/excelize.svg?branch=master)](https://travis-ci.org/360EntSecGroup-Skylar/excelize) [![Code Coverage](https://codecov.io/gh/360EntSecGroup-Skylar/excelize/branch/master/graph/badge.svg)](https://codecov.io/gh/360EntSecGroup-Skylar/excelize) [![Go Report Card](https://goreportcard.com/badge/github.com/360EntSecGroup-Skylar/excelize)](https://goreportcard.com/report/github.com/360EntSecGroup-Skylar/excelize) [![GoDoc](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize?status.svg)](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize) [![Licenses](https://img.shields.io/badge/license-bsd-orange.svg)](https://opensource.org/licenses/BSD-3-Clause) [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/xuri) ## 简介 Excelize 是 Go 语言编写的用于操作 Office Excel 文档类库,基于 ECMA-376 Office OpenXML 标准。可以使用它来读取、写入由 Microsoft Excel™ 2007 及以上版本创建的 XLSX 文档。相比较其他的开源类库,Excelize 支持写入原本带有图片(表)、透视表和切片器等复杂样式的文档,还支持向 Excel 文档中插入图片与图表,并且在保存后不会丢失文档原有样式,可以应用于各类报表系统中。使用本类库要求使用的 Go 语言为 1.8 或更高版本,完整的 API 使用文档请访问 [godoc.org](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize) 或查看 [中文翻译](https://xuri.me/excelize/zh_cn)。 ## 快速上手 ### 安装 ```go go get github.com/360EntSecGroup-Skylar/excelize ``` ### 创建 Excel 文档 下面是一个创建 Excel 文档的简单例子: ```go package main import ( "fmt" "github.com/360EntSecGroup-Skylar/excelize" ) func main() { xlsx := excelize.NewFile() // 创建一个工作表 index := xlsx.NewSheet("Sheet2") // 设置单元格的值 xlsx.SetCellValue("Sheet2", "A2", "Hello world.") xlsx.SetCellValue("Sheet1", "B2", 100) // 设置工作簿的默认工作表 xlsx.SetActiveSheet(index) // 根据指定路径保存文件 err := xlsx.SaveAs("./Book1.xlsx") if err != nil { fmt.Println(err) } } ``` ### 读取 Excel 文档 下面是读取 Excel 文档的例子: ```go package main import ( "fmt" "github.com/360EntSecGroup-Skylar/excelize" ) func main() { xlsx, err := excelize.OpenFile("./Book1.xlsx") if err != nil { fmt.Println(err) return } // 获取工作表中指定单元格的值 cell := xlsx.GetCellValue("Sheet1", "B2") fmt.Println(cell) // 获取 Sheet1 上所有单元格 rows := xlsx.GetRows("Sheet1") for _, row := range rows { for _, colCell := range row { fmt.Print(colCell, "\t") } fmt.Println() } } ``` ### 在 Excel 文档中创建图表 使用 Excelize 生成图表十分简单,仅需几行代码。您可以根据工作表中的已有数据构建图表,或向工作表中添加数据并创建图表。 ![Excelize](./test/images/chart.png "Excelize") ```go package main import ( "fmt" "github.com/360EntSecGroup-Skylar/excelize" ) func main() { categories := map[string]string{"A2": "Small", "A3": "Normal", "A4": "Large", "B1": "Apple", "C1": "Orange", "D1": "Pear"} values := map[string]int{"B2": 2, "C2": 3, "D2": 3, "B3": 5, "C3": 2, "D3": 4, "B4": 6, "C4": 7, "D4": 8} xlsx := excelize.NewFile() for k, v := range categories { xlsx.SetCellValue("Sheet1", k, v) } for k, v := range values { xlsx.SetCellValue("Sheet1", k, v) } xlsx.AddChart("Sheet1", "E1", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`) // 根据指定路径保存文件 err := xlsx.SaveAs("./Book1.xlsx") if err != nil { fmt.Println(err) } } ``` ### 向 Excel 文档中插入图片 ```go package main import ( "fmt" _ "image/gif" _ "image/jpeg" _ "image/png" "github.com/360EntSecGroup-Skylar/excelize" ) func main() { xlsx, err := excelize.OpenFile("./Book1.xlsx") if err != nil { fmt.Println(err) return } // 插入图片 err = xlsx.AddPicture("Sheet1", "A2", "./image1.png", "") if err != nil { fmt.Println(err) } // 在工作表中插入图片,并设置图片的缩放比例 err = xlsx.AddPicture("Sheet1", "D2", "./image2.jpg", `{"x_scale": 0.5, "y_scale": 0.5}`) if err != nil { fmt.Println(err) } // 在工作表中插入图片,并设置图片的打印属性 err = xlsx.AddPicture("Sheet1", "H2", "./image3.gif", `{"x_offset": 15, "y_offset": 10, "print_obj": true, "lock_aspect_ratio": false, "locked": false}`) if err != nil { fmt.Println(err) } // 保存文件 err = xlsx.Save() if err != nil { fmt.Println(err) } } ``` ## 社区合作 欢迎您为此项目贡献代码,提出建议或问题、修复 Bug 以及参与讨论对新功能的想法。 XML 符合标准: [part 1 of the 5th edition of the ECMA-376 Standard for Office Open XML](http://www.ecma-international.org/publications/standards/Ecma-376.htm)。 ## 致谢 本类库中部分 XML 结构体的定义参考了开源项目:[tealeg/xlsx](https://github.com/tealeg/xlsx). ## 开源许可 本项目遵循 BSD 3-Clause 开源许可协议,访问 [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) 查看许可协议文件。 ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/cell.go ================================================ package excelize import ( "encoding/xml" "fmt" "reflect" "strconv" "strings" "time" ) const ( // STCellFormulaTypeArray defined the formula is an array formula. STCellFormulaTypeArray = "array" // STCellFormulaTypeDataTable defined the formula is a data table formula. STCellFormulaTypeDataTable = "dataTable" // STCellFormulaTypeNormal defined the formula is a regular cell formula. STCellFormulaTypeNormal = "normal" // STCellFormulaTypeShared defined the formula is part of a shared formula. STCellFormulaTypeShared = "shared" ) // mergeCellsParser provides function to check merged cells in worksheet by // given axis. func (f *File) mergeCellsParser(xlsx *xlsxWorksheet, axis string) string { axis = strings.ToUpper(axis) if xlsx.MergeCells != nil { for i := 0; i < len(xlsx.MergeCells.Cells); i++ { if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) { axis = strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0] } } } return axis } // SetCellValue provides function to set value of a cell. The following shows // the supported data types: // // int // int8 // int16 // int32 // int64 // uint // uint8 // uint16 // uint32 // uint64 // float32 // float64 // string // []byte // time.Duration // time.Time // bool // nil // // Note that default date format is m/d/yy h:mm of time.Time type value. You can // set numbers format by SetCellStyle() method. func (f *File) SetCellValue(sheet, axis string, value interface{}) { switch t := value.(type) { case float32: f.SetCellDefault(sheet, axis, strconv.FormatFloat(float64(value.(float32)), 'f', -1, 32)) case float64: f.SetCellDefault(sheet, axis, strconv.FormatFloat(float64(value.(float64)), 'f', -1, 64)) case string: f.SetCellStr(sheet, axis, t) case []byte: f.SetCellStr(sheet, axis, string(t)) case time.Duration: f.SetCellDefault(sheet, axis, strconv.FormatFloat(float64(value.(time.Duration).Seconds()/86400), 'f', -1, 32)) f.setDefaultTimeStyle(sheet, axis, 21) case time.Time: f.SetCellDefault(sheet, axis, strconv.FormatFloat(float64(timeToExcelTime(timeToUTCTime(value.(time.Time)))), 'f', -1, 64)) f.setDefaultTimeStyle(sheet, axis, 22) case nil: f.SetCellStr(sheet, axis, "") case bool: f.SetCellBool(sheet, axis, bool(value.(bool))) default: f.setCellIntValue(sheet, axis, value) } } // setCellIntValue provides function to set int value of a cell. func (f *File) setCellIntValue(sheet, axis string, value interface{}) { switch value.(type) { case int: f.SetCellInt(sheet, axis, value.(int)) case int8: f.SetCellInt(sheet, axis, int(value.(int8))) case int16: f.SetCellInt(sheet, axis, int(value.(int16))) case int32: f.SetCellInt(sheet, axis, int(value.(int32))) case int64: f.SetCellInt(sheet, axis, int(value.(int64))) case uint: f.SetCellInt(sheet, axis, int(value.(uint))) case uint8: f.SetCellInt(sheet, axis, int(value.(uint8))) case uint16: f.SetCellInt(sheet, axis, int(value.(uint16))) case uint32: f.SetCellInt(sheet, axis, int(value.(uint32))) case uint64: f.SetCellInt(sheet, axis, int(value.(uint64))) default: f.SetCellStr(sheet, axis, fmt.Sprintf("%v", value)) } } // SetCellBool provides function to set bool type value of a cell by given // worksheet name, cell coordinates and cell value. func (f *File) SetCellBool(sheet, axis string, value bool) { xlsx := f.workSheetReader(sheet) axis = f.mergeCellsParser(xlsx, axis) col := string(strings.Map(letterOnlyMapF, axis)) row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis)) if err != nil { return } xAxis := row - 1 yAxis := TitleToNumber(col) rows := xAxis + 1 cell := yAxis + 1 completeRow(xlsx, rows, cell) completeCol(xlsx, rows, cell) xlsx.SheetData.Row[xAxis].C[yAxis].S = f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S) xlsx.SheetData.Row[xAxis].C[yAxis].T = "b" if value { xlsx.SheetData.Row[xAxis].C[yAxis].V = "1" } else { xlsx.SheetData.Row[xAxis].C[yAxis].V = "0" } } // GetCellValue provides function to get formatted value from cell by given // worksheet name and axis in XLSX file. If it is possible to apply a format to // the cell value, it will do so, if not then an error will be returned, along // with the raw value of the cell. func (f *File) GetCellValue(sheet, axis string) string { xlsx := f.workSheetReader(sheet) axis = f.mergeCellsParser(xlsx, axis) row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis)) if err != nil { return "" } xAxis := row - 1 rows := len(xlsx.SheetData.Row) if rows > 1 { lastRow := xlsx.SheetData.Row[rows-1].R if lastRow >= rows { rows = lastRow } } if rows < xAxis { return "" } for k := range xlsx.SheetData.Row { if xlsx.SheetData.Row[k].R == row { for i := range xlsx.SheetData.Row[k].C { if axis == xlsx.SheetData.Row[k].C[i].R { val, _ := xlsx.SheetData.Row[k].C[i].getValueFrom(f, f.sharedStringsReader()) return val } } } } return "" } // formattedValue provides function to returns a value after formatted. If it is // possible to apply a format to the cell value, it will do so, if not then an // error will be returned, along with the raw value of the cell. func (f *File) formattedValue(s int, v string) string { if s == 0 { return v } styleSheet := f.stylesReader() ok := builtInNumFmtFunc[styleSheet.CellXfs.Xf[s].NumFmtID] if ok != nil { return ok(styleSheet.CellXfs.Xf[s].NumFmtID, v) } return v } // GetCellStyle provides function to get cell style index by given worksheet // name and cell coordinates. func (f *File) GetCellStyle(sheet, axis string) int { xlsx := f.workSheetReader(sheet) axis = f.mergeCellsParser(xlsx, axis) col := string(strings.Map(letterOnlyMapF, axis)) row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis)) if err != nil { return 0 } xAxis := row - 1 yAxis := TitleToNumber(col) rows := xAxis + 1 cell := yAxis + 1 completeRow(xlsx, rows, cell) completeCol(xlsx, rows, cell) return f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S) } // GetCellFormula provides function to get formula from cell by given worksheet // name and axis in XLSX file. func (f *File) GetCellFormula(sheet, axis string) string { xlsx := f.workSheetReader(sheet) axis = f.mergeCellsParser(xlsx, axis) row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis)) if err != nil { return "" } xAxis := row - 1 rows := len(xlsx.SheetData.Row) if rows > 1 { lastRow := xlsx.SheetData.Row[rows-1].R if lastRow >= rows { rows = lastRow } } if rows < xAxis { return "" } for k := range xlsx.SheetData.Row { if xlsx.SheetData.Row[k].R == row { for i := range xlsx.SheetData.Row[k].C { if axis == xlsx.SheetData.Row[k].C[i].R { if xlsx.SheetData.Row[k].C[i].F.T == STCellFormulaTypeShared { return getSharedForumula(xlsx, xlsx.SheetData.Row[k].C[i].F.Si) } if xlsx.SheetData.Row[k].C[i].F != nil { return xlsx.SheetData.Row[k].C[i].F.Content } } } } } return "" } // getSharedForumula find a cell contains the same formula as another cell, // the "shared" value can be used for the t attribute and the si attribute can // be used to refer to the cell containing the formula. Two formulas are // considered to be the same when their respective representations in // R1C1-reference notation, are the same. // // Note that this function not validate ref tag to check the cell if or not in // allow area, and always return origin shared formula. func getSharedForumula(xlsx *xlsxWorksheet, si string) string { for k := range xlsx.SheetData.Row { for i := range xlsx.SheetData.Row[k].C { if xlsx.SheetData.Row[k].C[i].F == nil { continue } if xlsx.SheetData.Row[k].C[i].F.T != STCellFormulaTypeShared { continue } if xlsx.SheetData.Row[k].C[i].F.Si != si { continue } if xlsx.SheetData.Row[k].C[i].F.Ref != "" { return xlsx.SheetData.Row[k].C[i].F.Content } } } return "" } // SetCellFormula provides function to set cell formula by given string and // worksheet name. func (f *File) SetCellFormula(sheet, axis, formula string) { xlsx := f.workSheetReader(sheet) axis = f.mergeCellsParser(xlsx, axis) col := string(strings.Map(letterOnlyMapF, axis)) row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis)) if err != nil { return } xAxis := row - 1 yAxis := TitleToNumber(col) rows := xAxis + 1 cell := yAxis + 1 completeRow(xlsx, rows, cell) completeCol(xlsx, rows, cell) if xlsx.SheetData.Row[xAxis].C[yAxis].F != nil { xlsx.SheetData.Row[xAxis].C[yAxis].F.Content = formula } else { f := xlsxF{ Content: formula, } xlsx.SheetData.Row[xAxis].C[yAxis].F = &f } } // SetCellHyperLink provides function to set cell hyperlink by given worksheet // name and link URL address. LinkType defines two types of hyperlink "External" // for web site or "Location" for moving to one of cell in this workbook. The // below is example for external link. // // xlsx.SetCellHyperLink("Sheet1", "A3", "https://github.com/360EntSecGroup-Skylar/excelize", "External") // // Set underline and font color style for the cell. // style, _ := xlsx.NewStyle(`{"font":{"color":"#1265BE","underline":"single"}}`) // xlsx.SetCellStyle("Sheet1", "A3", "A3", style) // // A this is another example for "Location": // // xlsx.SetCellHyperLink("Sheet1", "A3", "Sheet1!A40", "Location") // func (f *File) SetCellHyperLink(sheet, axis, link, linkType string) { xlsx := f.workSheetReader(sheet) axis = f.mergeCellsParser(xlsx, axis) linkTypes := map[string]xlsxHyperlink{ "External": {}, "Location": {Location: link}, } hyperlink, ok := linkTypes[linkType] if !ok || axis == "" { return } hyperlink.Ref = axis if linkType == "External" { rID := f.addSheetRelationships(sheet, SourceRelationshipHyperLink, link, linkType) hyperlink.RID = "rId" + strconv.Itoa(rID) } if xlsx.Hyperlinks == nil { xlsx.Hyperlinks = &xlsxHyperlinks{} } xlsx.Hyperlinks.Hyperlink = append(xlsx.Hyperlinks.Hyperlink, hyperlink) } // GetCellHyperLink provides function to get cell hyperlink by given worksheet // name and axis. Boolean type value link will be ture if the cell has a // hyperlink and the target is the address of the hyperlink. Otherwise, the // value of link will be false and the value of the target will be a blank // string. For example get hyperlink of Sheet1!H6: // // link, target := xlsx.GetCellHyperLink("Sheet1", "H6") // func (f *File) GetCellHyperLink(sheet, axis string) (bool, string) { var link bool var target string xlsx := f.workSheetReader(sheet) axis = f.mergeCellsParser(xlsx, axis) if xlsx.Hyperlinks == nil || axis == "" { return link, target } for h := range xlsx.Hyperlinks.Hyperlink { if xlsx.Hyperlinks.Hyperlink[h].Ref == axis { link = true target = xlsx.Hyperlinks.Hyperlink[h].Location if xlsx.Hyperlinks.Hyperlink[h].RID != "" { target = f.getSheetRelationshipsTargetByID(sheet, xlsx.Hyperlinks.Hyperlink[h].RID) } } } return link, target } // MergeCell provides function to merge cells by given coordinate area and sheet // name. For example create a merged cell of D3:E9 on Sheet1: // // xlsx.MergeCell("Sheet1", "D3", "E9") // // If you create a merged cell that overlaps with another existing merged cell, // those merged cells that already exist will be removed. func (f *File) MergeCell(sheet, hcell, vcell string) { if hcell == vcell { return } hcell = strings.ToUpper(hcell) vcell = strings.ToUpper(vcell) // Coordinate conversion, convert C1:B3 to 2,0,1,2. hcol := string(strings.Map(letterOnlyMapF, hcell)) hrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, hcell)) hyAxis := hrow - 1 hxAxis := TitleToNumber(hcol) vcol := string(strings.Map(letterOnlyMapF, vcell)) vrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, vcell)) vyAxis := vrow - 1 vxAxis := TitleToNumber(vcol) if vxAxis < hxAxis { hcell, vcell = vcell, hcell vxAxis, hxAxis = hxAxis, vxAxis } if vyAxis < hyAxis { hcell, vcell = vcell, hcell vyAxis, hyAxis = hyAxis, vyAxis } xlsx := f.workSheetReader(sheet) if xlsx.MergeCells != nil { mergeCell := xlsxMergeCell{} // Correct the coordinate area, such correct C1:B3 to B1:C3. mergeCell.Ref = ToAlphaString(hxAxis) + strconv.Itoa(hyAxis+1) + ":" + ToAlphaString(vxAxis) + strconv.Itoa(vyAxis+1) // Delete the merged cells of the overlapping area. for i := 0; i < len(xlsx.MergeCells.Cells); i++ { if checkCellInArea(hcell, xlsx.MergeCells.Cells[i].Ref) || checkCellInArea(strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0], mergeCell.Ref) { xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...) } else if checkCellInArea(vcell, xlsx.MergeCells.Cells[i].Ref) || checkCellInArea(strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[1], mergeCell.Ref) { xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...) } } xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells, &mergeCell) } else { mergeCell := xlsxMergeCell{} // Correct the coordinate area, such correct C1:B3 to B1:C3. mergeCell.Ref = ToAlphaString(hxAxis) + strconv.Itoa(hyAxis+1) + ":" + ToAlphaString(vxAxis) + strconv.Itoa(vyAxis+1) mergeCells := xlsxMergeCells{} mergeCells.Cells = append(mergeCells.Cells, &mergeCell) xlsx.MergeCells = &mergeCells } } // SetCellInt provides function to set int type value of a cell by given // worksheet name, cell coordinates and cell value. func (f *File) SetCellInt(sheet, axis string, value int) { xlsx := f.workSheetReader(sheet) axis = f.mergeCellsParser(xlsx, axis) col := string(strings.Map(letterOnlyMapF, axis)) row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis)) if err != nil { return } xAxis := row - 1 yAxis := TitleToNumber(col) rows := xAxis + 1 cell := yAxis + 1 completeRow(xlsx, rows, cell) completeCol(xlsx, rows, cell) xlsx.SheetData.Row[xAxis].C[yAxis].S = f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S) xlsx.SheetData.Row[xAxis].C[yAxis].T = "" xlsx.SheetData.Row[xAxis].C[yAxis].V = strconv.Itoa(value) } // prepareCellStyle provides function to prepare style index of cell in // worksheet by given column index and style index. func (f *File) prepareCellStyle(xlsx *xlsxWorksheet, col, style int) int { if xlsx.Cols != nil && style == 0 { for _, v := range xlsx.Cols.Col { if v.Min <= col && col <= v.Max { style = v.Style } } } return style } // SetCellStr provides function to set string type value of a cell. Total number // of characters that a cell can contain 32767 characters. func (f *File) SetCellStr(sheet, axis, value string) { xlsx := f.workSheetReader(sheet) axis = f.mergeCellsParser(xlsx, axis) if len(value) > 32767 { value = value[0:32767] } col := string(strings.Map(letterOnlyMapF, axis)) row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis)) if err != nil { return } xAxis := row - 1 yAxis := TitleToNumber(col) rows := xAxis + 1 cell := yAxis + 1 completeRow(xlsx, rows, cell) completeCol(xlsx, rows, cell) // Leading space(s) character detection. if len(value) > 0 { if value[0] == 32 { xlsx.SheetData.Row[xAxis].C[yAxis].XMLSpace = xml.Attr{ Name: xml.Name{Space: NameSpaceXML, Local: "space"}, Value: "preserve", } } } xlsx.SheetData.Row[xAxis].C[yAxis].S = f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S) xlsx.SheetData.Row[xAxis].C[yAxis].T = "str" xlsx.SheetData.Row[xAxis].C[yAxis].V = value } // SetCellDefault provides function to set string type value of a cell as // default format without escaping the cell. func (f *File) SetCellDefault(sheet, axis, value string) { xlsx := f.workSheetReader(sheet) axis = f.mergeCellsParser(xlsx, axis) col := string(strings.Map(letterOnlyMapF, axis)) row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis)) if err != nil { return } xAxis := row - 1 yAxis := TitleToNumber(col) rows := xAxis + 1 cell := yAxis + 1 completeRow(xlsx, rows, cell) completeCol(xlsx, rows, cell) xlsx.SheetData.Row[xAxis].C[yAxis].S = f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S) xlsx.SheetData.Row[xAxis].C[yAxis].T = "" xlsx.SheetData.Row[xAxis].C[yAxis].V = value } // SetSheetRow writes an array to row by given worksheet name, starting // coordinate and a pointer to array type 'slice'. For example, writes an // array to row 6 start with the cell B6 on Sheet1: // // xlsx.SetSheetRow("Sheet1", "B6", &[]interface{}{"1", nil, 2}) // func (f *File) SetSheetRow(sheet, axis string, slice interface{}) { xlsx := f.workSheetReader(sheet) axis = f.mergeCellsParser(xlsx, axis) col := string(strings.Map(letterOnlyMapF, axis)) row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis)) if err != nil { return } // Make sure 'slice' is a Ptr to Slice v := reflect.ValueOf(slice) if v.Kind() != reflect.Ptr { return } v = v.Elem() if v.Kind() != reflect.Slice { return } xAxis := row - 1 yAxis := TitleToNumber(col) rows := xAxis + 1 cell := yAxis + 1 completeRow(xlsx, rows, cell) completeCol(xlsx, rows, cell) idx := 0 for i := cell - 1; i < v.Len()+cell-1; i++ { c := ToAlphaString(i) + strconv.Itoa(row) f.SetCellValue(sheet, c, v.Index(idx).Interface()) idx++ } } // checkCellInArea provides function to determine if a given coordinate is // within an area. func checkCellInArea(cell, area string) bool { cell = strings.ToUpper(cell) area = strings.ToUpper(area) ref := strings.Split(area, ":") if len(ref) < 2 { return false } from := ref[0] to := ref[1] col, row := getCellColRow(cell) fromCol, fromRow := getCellColRow(from) toCol, toRow := getCellColRow(to) return axisLowerOrEqualThan(fromCol, col) && axisLowerOrEqualThan(col, toCol) && axisLowerOrEqualThan(fromRow, row) && axisLowerOrEqualThan(row, toRow) } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/chart.go ================================================ package excelize import ( "encoding/json" "encoding/xml" "strconv" "strings" ) // This section defines the currently supported chart types. const ( Bar = "bar" BarStacked = "barStacked" BarPercentStacked = "barPercentStacked" Bar3DClustered = "bar3DClustered" Bar3DStacked = "bar3DStacked" Bar3DPercentStacked = "bar3DPercentStacked" Col = "col" ColStacked = "colStacked" ColPercentStacked = "colPercentStacked" Col3DClustered = "col3DClustered" Col3D = "col3D" Col3DStacked = "col3DStacked" Col3DPercentStacked = "col3DPercentStacked" Doughnut = "doughnut" Line = "line" Pie = "pie" Pie3D = "pie3D" Radar = "radar" Scatter = "scatter" ) // This section defines the default value of chart properties. var ( chartView3DRotX = map[string]int{ Bar: 0, BarStacked: 0, BarPercentStacked: 0, Bar3DClustered: 15, Bar3DStacked: 15, Bar3DPercentStacked: 15, Col: 0, ColStacked: 0, ColPercentStacked: 0, Col3DClustered: 15, Col3D: 15, Col3DStacked: 15, Col3DPercentStacked: 15, Doughnut: 0, Line: 0, Pie: 0, Pie3D: 30, Radar: 0, Scatter: 0, } chartView3DRotY = map[string]int{ Bar: 0, BarStacked: 0, BarPercentStacked: 0, Bar3DClustered: 20, Bar3DStacked: 20, Bar3DPercentStacked: 20, Col: 0, ColStacked: 0, ColPercentStacked: 0, Col3DClustered: 20, Col3D: 20, Col3DStacked: 20, Col3DPercentStacked: 20, Doughnut: 0, Line: 0, Pie: 0, Pie3D: 0, Radar: 0, Scatter: 0, } chartView3DDepthPercent = map[string]int{ Bar: 100, BarStacked: 100, BarPercentStacked: 100, Bar3DClustered: 100, Bar3DStacked: 100, Bar3DPercentStacked: 100, Col: 100, ColStacked: 100, ColPercentStacked: 100, Col3DClustered: 100, Col3D: 100, Col3DStacked: 100, Col3DPercentStacked: 100, Doughnut: 100, Line: 100, Pie: 100, Pie3D: 100, Radar: 100, Scatter: 100, } chartView3DRAngAx = map[string]int{ Bar: 0, BarStacked: 0, BarPercentStacked: 0, Bar3DClustered: 1, Bar3DStacked: 1, Bar3DPercentStacked: 1, Col: 0, ColStacked: 0, ColPercentStacked: 0, Col3DClustered: 1, Col3D: 1, Col3DStacked: 1, Col3DPercentStacked: 1, Doughnut: 0, Line: 0, Pie: 0, Pie3D: 0, Radar: 0, Scatter: 0, } chartLegendPosition = map[string]string{ "bottom": "b", "left": "l", "right": "r", "top": "t", "top_right": "tr", } chartValAxNumFmtFormatCode = map[string]string{ Bar: "General", BarStacked: "General", BarPercentStacked: "0%", Bar3DClustered: "General", Bar3DStacked: "General", Bar3DPercentStacked: "0%", Col: "General", ColStacked: "General", ColPercentStacked: "0%", Col3DClustered: "General", Col3D: "General", Col3DStacked: "General", Col3DPercentStacked: "0%", Doughnut: "General", Line: "General", Pie: "General", Pie3D: "General", Radar: "General", Scatter: "General", } plotAreaChartGrouping = map[string]string{ Bar: "clustered", BarStacked: "stacked", BarPercentStacked: "percentStacked", Bar3DClustered: "clustered", Bar3DStacked: "stacked", Bar3DPercentStacked: "percentStacked", Col: "clustered", ColStacked: "stacked", ColPercentStacked: "percentStacked", Col3DClustered: "clustered", Col3D: "standard", Col3DStacked: "stacked", Col3DPercentStacked: "percentStacked", Line: "standard", } plotAreaChartBarDir = map[string]string{ Bar: "bar", BarStacked: "bar", BarPercentStacked: "bar", Bar3DClustered: "bar", Bar3DStacked: "bar", Bar3DPercentStacked: "bar", Col: "col", ColStacked: "col", ColPercentStacked: "col", Col3DClustered: "col", Col3D: "col", Col3DStacked: "col", Col3DPercentStacked: "col", Line: "standard", } orientation = map[bool]string{ true: "maxMin", false: "minMax", } catAxPos = map[bool]string{ true: "t", false: "b", } valAxPos = map[bool]string{ true: "r", false: "l", } ) // parseFormatChartSet provides function to parse the format settings of the // chart with default value. func parseFormatChartSet(formatSet string) (*formatChart, error) { format := formatChart{ Dimension: formatChartDimension{ Width: 480, Height: 290, }, Format: formatPicture{ FPrintsWithSheet: true, FLocksWithSheet: false, NoChangeAspect: false, OffsetX: 0, OffsetY: 0, XScale: 1.0, YScale: 1.0, }, Legend: formatChartLegend{ Position: "bottom", ShowLegendKey: false, }, Title: formatChartTitle{ Name: " ", }, ShowBlanksAs: "gap", } err := json.Unmarshal([]byte(formatSet), &format) return &format, err } // AddChart provides the method to add chart in a sheet by given chart format // set (such as offset, scale, aspect ratio setting and print settings) and // properties set. For example, create 3D clustered column chart with data // Sheet1!$A$29:$D$32: // // package main // // import ( // "fmt" // // "github.com/360EntSecGroup-Skylar/excelize" // ) // // func main() { // categories := map[string]string{"A2": "Small", "A3": "Normal", "A4": "Large", "B1": "Apple", "C1": "Orange", "D1": "Pear"} // values := map[string]int{"B2": 2, "C2": 3, "D2": 3, "B3": 5, "C3": 2, "D3": 4, "B4": 6, "C4": 7, "D4": 8} // xlsx := excelize.NewFile() // for k, v := range categories { // xlsx.SetCellValue("Sheet1", k, v) // } // for k, v := range values { // xlsx.SetCellValue("Sheet1", k, v) // } // xlsx.AddChart("Sheet1", "E1", `{"type":"col3DClustered","dimension":{"width":640,"height":480},"series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"bottom","show_legend_key":false},"title":{"name":"Fruit 3D Clustered Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero","x_axis":{"reverse_order":true},"y_axis":{"maximum":7.5,"minimum":0.5}}`) // // Save xlsx file by the given path. // err := xlsx.SaveAs("./Book1.xlsx") // if err != nil { // fmt.Println(err) // } // } // // The following shows the type of chart supported by excelize: // // Type | Chart // ---------------------+------------------------------ // bar | 2D clustered bar chart // barStacked | 2D stacked bar chart // barPercentStacked | 2D 100% stacked bar chart // bar3DClustered | 3D clustered bar chart // bar3DStacked | 3D stacked bar chart // bar3DPercentStacked | 3D 100% stacked bar chart // col | 2D clustered column chart // colStacked | 2D stacked column chart // colPercentStacked | 2D 100% stacked column chart // col3DClustered | 3D clustered column chart // col3D | 3D column chart // col3DStacked | 3D stacked column chart // col3DPercentStacked | 3D 100% stacked column chart // doughnut | doughnut chart // line | line chart // pie | pie chart // pie3D | 3D pie chart // radar | radar chart // scatter | scatter chart // // In Excel a chart series is a collection of information that defines which data is plotted such as values, axis labels and formatting. // // The series options that can be set are: // // name // categories // values // // name: Set the name for the series. The name is displayed in the chart legend and in the formula bar. The name property is optional and if it isn't supplied it will default to Series 1..n. The name can also be a formula such as Sheet1!$A$1 // // categories: This sets the chart category labels. The category is more or less the same as the X axis. In most chart types the categories property is optional and the chart will just assume a sequential series from 1..n. // // values: This is the most important property of a series and is the only mandatory option for every chart object. This option links the chart with the worksheet data that it displays. // // Set properties of the chart legend. The options that can be set are: // // position // show_legend_key // // position: Set the position of the chart legend. The default legend position is right. The available positions are: // // top // bottom // left // right // top_right // // show_legend_key: Set the legend keys shall be shown in data labels. The default value is false. // // Set properties of the chart title. The properties that can be set are: // // title // // name: Set the name (title) for the chart. The name is displayed above the chart. The name can also be a formula such as Sheet1!$A$1 or a list with a sheetname. The name property is optional. The default is to have no chart title. // // Specifies how blank cells are plotted on the chart by show_blanks_as. The default value is gap. The options that can be set are: // // gap // span // zero // // gap: Specifies that blank values shall be left as a gap. // // sapn: Specifies that blank values shall be spanned with a line. // // zero: Specifies that blank values shall be treated as zero. // // Set chart offset, scale, aspect ratio setting and print settings by format, same as function AddPicture. // // Set the position of the chart plot area by plotarea. The properties that can be set are: // // show_bubble_size // show_cat_name // show_leader_lines // show_percent // show_series_name // show_val // // show_bubble_size: Specifies the bubble size shall be shown in a data label. The show_bubble_size property is optional. The default value is false. // // show_cat_name: Specifies that the category name shall be shown in the data label. The show_cat_name property is optional. The default value is true. // // show_leader_lines: Specifies leader lines shall be shown for data labels. The show_leader_lines property is optional. The default value is false. // // show_percent: Specifies that the percentage shall be shown in a data label. The show_percent property is optional. The default value is false. // // show_series_name: Specifies that the series name shall be shown in a data label. The show_series_name property is optional. The default value is false. // // show_val: Specifies that the value shall be shown in a data label. The show_val property is optional. The default value is false. // // Set the primary horizontal and vertical axis options by x_axis and y_axis. The properties that can be set are: // // reverse_order // maximum // minimum // // reverse_order: Specifies that the categories or values on reverse order (orientation of the chart). The reverse_order property is optional. The default value is false. // maximum: Specifies that the fixed maximum, 0 is auto. The maximum property is optional. The default value is auto. // minimum: Specifies that the fixed minimum, 0 is auto. The minimum property is optional. The default value is auto. // // Set chart size by dimension property. The dimension property is optional. The default width is 480, and height is 290. // func (f *File) AddChart(sheet, cell, format string) error { formatSet, err := parseFormatChartSet(format) if err != nil { return err } // Read sheet data. xlsx := f.workSheetReader(sheet) // Add first picture for given sheet, create xl/drawings/ and xl/drawings/_rels/ folder. drawingID := f.countDrawings() + 1 chartID := f.countCharts() + 1 drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml" drawingID, drawingXML = f.prepareDrawing(xlsx, drawingID, sheet, drawingXML) drawingRID := f.addDrawingRelationships(drawingID, SourceRelationshipChart, "../charts/chart"+strconv.Itoa(chartID)+".xml", "") f.addDrawingChart(sheet, drawingXML, cell, formatSet.Dimension.Width, formatSet.Dimension.Height, drawingRID, &formatSet.Format) f.addChart(formatSet) f.addContentTypePart(chartID, "chart") f.addContentTypePart(drawingID, "drawings") return err } // countCharts provides function to get chart files count storage in the // folder xl/charts. func (f *File) countCharts() int { count := 0 for k := range f.XLSX { if strings.Contains(k, "xl/charts/chart") { count++ } } return count } // prepareDrawing provides function to prepare drawing ID and XML by given // drawingID, worksheet name and default drawingXML. func (f *File) prepareDrawing(xlsx *xlsxWorksheet, drawingID int, sheet, drawingXML string) (int, string) { sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml" if xlsx.Drawing != nil { // The worksheet already has a picture or chart relationships, use the relationships drawing ../drawings/drawing%d.xml. sheetRelationshipsDrawingXML = f.getSheetRelationshipsTargetByID(sheet, xlsx.Drawing.RID) drawingID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingXML, "../drawings/drawing"), ".xml")) drawingXML = strings.Replace(sheetRelationshipsDrawingXML, "..", "xl", -1) } else { // Add first picture for given sheet. rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "") f.addSheetDrawing(sheet, rID) } return drawingID, drawingXML } // addChart provides function to create chart as xl/charts/chart%d.xml by given // format sets. func (f *File) addChart(formatSet *formatChart) { count := f.countCharts() xlsxChartSpace := xlsxChartSpace{ XMLNSc: NameSpaceDrawingMLChart, XMLNSa: NameSpaceDrawingML, XMLNSr: SourceRelationship, XMLNSc16r2: SourceRelationshipChart201506, Date1904: &attrValBool{Val: false}, Lang: &attrValString{Val: "en-US"}, RoundedCorners: &attrValBool{Val: false}, Chart: cChart{ Title: &cTitle{ Tx: cTx{ Rich: &cRich{ P: aP{ PPr: &aPPr{ DefRPr: aRPr{ Kern: 1200, Strike: "noStrike", U: "none", Sz: 1400, SolidFill: &aSolidFill{ SchemeClr: &aSchemeClr{ Val: "tx1", LumMod: &attrValInt{ Val: 65000, }, LumOff: &attrValInt{ Val: 35000, }, }, }, Ea: &aEa{ Typeface: "+mn-ea", }, Cs: &aCs{ Typeface: "+mn-cs", }, Latin: &aLatin{ Typeface: "+mn-lt", }, }, }, R: &aR{ RPr: aRPr{ Lang: "en-US", AltLang: "en-US", }, T: formatSet.Title.Name, }, }, }, }, TxPr: cTxPr{ P: aP{ PPr: &aPPr{ DefRPr: aRPr{ Kern: 1200, U: "none", Sz: 14000, Strike: "noStrike", }, }, EndParaRPr: &aEndParaRPr{ Lang: "en-US", }, }, }, }, View3D: &cView3D{ RotX: &attrValInt{Val: chartView3DRotX[formatSet.Type]}, RotY: &attrValInt{Val: chartView3DRotY[formatSet.Type]}, DepthPercent: &attrValInt{Val: chartView3DDepthPercent[formatSet.Type]}, RAngAx: &attrValInt{Val: chartView3DRAngAx[formatSet.Type]}, }, Floor: &cThicknessSpPr{ Thickness: &attrValInt{Val: 0}, }, SideWall: &cThicknessSpPr{ Thickness: &attrValInt{Val: 0}, }, BackWall: &cThicknessSpPr{ Thickness: &attrValInt{Val: 0}, }, PlotArea: &cPlotArea{}, Legend: &cLegend{ LegendPos: &attrValString{Val: chartLegendPosition[formatSet.Legend.Position]}, Overlay: &attrValBool{Val: false}, }, PlotVisOnly: &attrValBool{Val: false}, DispBlanksAs: &attrValString{Val: formatSet.ShowBlanksAs}, ShowDLblsOverMax: &attrValBool{Val: false}, }, SpPr: &cSpPr{ SolidFill: &aSolidFill{ SchemeClr: &aSchemeClr{Val: "bg1"}, }, Ln: &aLn{ W: 9525, Cap: "flat", Cmpd: "sng", Algn: "ctr", SolidFill: &aSolidFill{ SchemeClr: &aSchemeClr{Val: "tx1", LumMod: &attrValInt{ Val: 15000, }, LumOff: &attrValInt{ Val: 85000, }, }, }, }, }, PrintSettings: &cPrintSettings{ PageMargins: &cPageMargins{ B: 0.75, L: 0.7, R: 0.7, T: 0.7, Header: 0.3, Footer: 0.3, }, }, } plotAreaFunc := map[string]func(*formatChart) *cPlotArea{ Bar: f.drawBaseChart, BarStacked: f.drawBaseChart, BarPercentStacked: f.drawBaseChart, Bar3DClustered: f.drawBaseChart, Bar3DStacked: f.drawBaseChart, Bar3DPercentStacked: f.drawBaseChart, Col: f.drawBaseChart, ColStacked: f.drawBaseChart, ColPercentStacked: f.drawBaseChart, Col3DClustered: f.drawBaseChart, Col3D: f.drawBaseChart, Col3DStacked: f.drawBaseChart, Col3DPercentStacked: f.drawBaseChart, Doughnut: f.drawDoughnutChart, Line: f.drawLineChart, Pie3D: f.drawPie3DChart, Pie: f.drawPieChart, Radar: f.drawRadarChart, Scatter: f.drawScatterChart, } xlsxChartSpace.Chart.PlotArea = plotAreaFunc[formatSet.Type](formatSet) chart, _ := xml.Marshal(xlsxChartSpace) media := "xl/charts/chart" + strconv.Itoa(count+1) + ".xml" f.saveFileList(media, chart) } // drawBaseChart provides function to draw the c:plotArea element for bar, // and column series charts by given format sets. func (f *File) drawBaseChart(formatSet *formatChart) *cPlotArea { c := cCharts{ BarDir: &attrValString{ Val: "col", }, Grouping: &attrValString{ Val: "clustered", }, VaryColors: &attrValBool{ Val: true, }, Ser: f.drawChartSeries(formatSet), DLbls: f.drawChartDLbls(formatSet), AxID: []*attrValInt{ {Val: 754001152}, {Val: 753999904}, }, } c.BarDir.Val = plotAreaChartBarDir[formatSet.Type] c.Grouping.Val = plotAreaChartGrouping[formatSet.Type] if formatSet.Type == "colStacked" || formatSet.Type == "barStacked" || formatSet.Type == "barPercentStacked" || formatSet.Type == "colPercentStacked" { c.Overlap = &attrValInt{Val: 100} } catAx := f.drawPlotAreaCatAx(formatSet) valAx := f.drawPlotAreaValAx(formatSet) charts := map[string]*cPlotArea{ "bar": { BarChart: &c, CatAx: catAx, ValAx: valAx, }, "barStacked": { BarChart: &c, CatAx: catAx, ValAx: valAx, }, "barPercentStacked": { BarChart: &c, CatAx: catAx, ValAx: valAx, }, "bar3DClustered": { Bar3DChart: &c, CatAx: catAx, ValAx: valAx, }, "bar3DStacked": { Bar3DChart: &c, CatAx: catAx, ValAx: valAx, }, "bar3DPercentStacked": { Bar3DChart: &c, CatAx: catAx, ValAx: valAx, }, "col": { BarChart: &c, CatAx: catAx, ValAx: valAx, }, "colStacked": { BarChart: &c, CatAx: catAx, ValAx: valAx, }, "colPercentStacked": { BarChart: &c, CatAx: catAx, ValAx: valAx, }, "col3DClustered": { Bar3DChart: &c, CatAx: catAx, ValAx: valAx, }, "col3D": { Bar3DChart: &c, CatAx: catAx, ValAx: valAx, }, "col3DStacked": { Bar3DChart: &c, CatAx: catAx, ValAx: valAx, }, "col3DPercentStacked": { Bar3DChart: &c, CatAx: catAx, ValAx: valAx, }, } return charts[formatSet.Type] } // drawDoughnutChart provides function to draw the c:plotArea element for // doughnut chart by given format sets. func (f *File) drawDoughnutChart(formatSet *formatChart) *cPlotArea { return &cPlotArea{ DoughnutChart: &cCharts{ VaryColors: &attrValBool{ Val: true, }, Ser: f.drawChartSeries(formatSet), HoleSize: &attrValInt{Val: 75}, }, } } // drawLineChart provides function to draw the c:plotArea element for line chart // by given format sets. func (f *File) drawLineChart(formatSet *formatChart) *cPlotArea { return &cPlotArea{ LineChart: &cCharts{ Grouping: &attrValString{ Val: plotAreaChartGrouping[formatSet.Type], }, VaryColors: &attrValBool{ Val: false, }, Ser: f.drawChartSeries(formatSet), DLbls: f.drawChartDLbls(formatSet), Smooth: &attrValBool{ Val: false, }, AxID: []*attrValInt{ {Val: 754001152}, {Val: 753999904}, }, }, CatAx: f.drawPlotAreaCatAx(formatSet), ValAx: f.drawPlotAreaValAx(formatSet), } } // drawPieChart provides function to draw the c:plotArea element for pie chart // by given format sets. func (f *File) drawPieChart(formatSet *formatChart) *cPlotArea { return &cPlotArea{ PieChart: &cCharts{ VaryColors: &attrValBool{ Val: true, }, Ser: f.drawChartSeries(formatSet), }, } } // drawPie3DChart provides function to draw the c:plotArea element for 3D pie // chart by given format sets. func (f *File) drawPie3DChart(formatSet *formatChart) *cPlotArea { return &cPlotArea{ Pie3DChart: &cCharts{ VaryColors: &attrValBool{ Val: true, }, Ser: f.drawChartSeries(formatSet), }, } } // drawRadarChart provides function to draw the c:plotArea element for radar // chart by given format sets. func (f *File) drawRadarChart(formatSet *formatChart) *cPlotArea { return &cPlotArea{ RadarChart: &cCharts{ RadarStyle: &attrValString{ Val: "marker", }, VaryColors: &attrValBool{ Val: false, }, Ser: f.drawChartSeries(formatSet), DLbls: f.drawChartDLbls(formatSet), AxID: []*attrValInt{ {Val: 754001152}, {Val: 753999904}, }, }, CatAx: f.drawPlotAreaCatAx(formatSet), ValAx: f.drawPlotAreaValAx(formatSet), } } // drawScatterChart provides function to draw the c:plotArea element for scatter // chart by given format sets. func (f *File) drawScatterChart(formatSet *formatChart) *cPlotArea { return &cPlotArea{ ScatterChart: &cCharts{ ScatterStyle: &attrValString{ Val: "smoothMarker", // line,lineMarker,marker,none,smooth,smoothMarker }, VaryColors: &attrValBool{ Val: false, }, Ser: f.drawChartSeries(formatSet), DLbls: f.drawChartDLbls(formatSet), AxID: []*attrValInt{ {Val: 754001152}, {Val: 753999904}, }, }, CatAx: f.drawPlotAreaCatAx(formatSet), ValAx: f.drawPlotAreaValAx(formatSet), } } // drawChartSeries provides function to draw the c:ser element by given format // sets. func (f *File) drawChartSeries(formatSet *formatChart) *[]cSer { ser := []cSer{} for k := range formatSet.Series { ser = append(ser, cSer{ IDx: &attrValInt{Val: k}, Order: &attrValInt{Val: k}, Tx: &cTx{ StrRef: &cStrRef{ F: formatSet.Series[k].Name, }, }, SpPr: f.drawChartSeriesSpPr(k, formatSet), Marker: f.drawChartSeriesMarker(k, formatSet), DPt: f.drawChartSeriesDPt(k, formatSet), DLbls: f.drawChartSeriesDLbls(formatSet), Cat: f.drawChartSeriesCat(formatSet.Series[k], formatSet), Val: f.drawChartSeriesVal(formatSet.Series[k], formatSet), XVal: f.drawChartSeriesXVal(formatSet.Series[k], formatSet), YVal: f.drawChartSeriesYVal(formatSet.Series[k], formatSet), }) } return &ser } // drawChartSeriesSpPr provides function to draw the c:spPr element by given // format sets. func (f *File) drawChartSeriesSpPr(i int, formatSet *formatChart) *cSpPr { spPrScatter := &cSpPr{ Ln: &aLn{ W: 25400, NoFill: " ", }, } spPrLine := &cSpPr{ Ln: &aLn{ W: 25400, Cap: "rnd", // rnd, sq, flat SolidFill: &aSolidFill{ SchemeClr: &aSchemeClr{Val: "accent" + strconv.Itoa(i+1)}, }, }, } chartSeriesSpPr := map[string]*cSpPr{Bar: nil, BarStacked: nil, BarPercentStacked: nil, Bar3DClustered: nil, Bar3DStacked: nil, Bar3DPercentStacked: nil, Col: nil, ColStacked: nil, ColPercentStacked: nil, Col3DClustered: nil, Col3D: nil, Col3DStacked: nil, Col3DPercentStacked: nil, Doughnut: nil, Line: spPrLine, Pie: nil, Pie3D: nil, Radar: nil, Scatter: spPrScatter} return chartSeriesSpPr[formatSet.Type] } // drawChartSeriesDPt provides function to draw the c:dPt element by given data // index and format sets. func (f *File) drawChartSeriesDPt(i int, formatSet *formatChart) []*cDPt { dpt := []*cDPt{{ IDx: &attrValInt{Val: i}, Bubble3D: &attrValBool{Val: false}, SpPr: &cSpPr{ SolidFill: &aSolidFill{ SchemeClr: &aSchemeClr{Val: "accent" + strconv.Itoa(i+1)}, }, Ln: &aLn{ W: 25400, Cap: "rnd", SolidFill: &aSolidFill{ SchemeClr: &aSchemeClr{Val: "lt" + strconv.Itoa(i+1)}, }, }, Sp3D: &aSp3D{ ContourW: 25400, ContourClr: &aContourClr{ SchemeClr: &aSchemeClr{Val: "lt" + strconv.Itoa(i+1)}, }, }, }, }} chartSeriesDPt := map[string][]*cDPt{Bar: nil, BarStacked: nil, BarPercentStacked: nil, Bar3DClustered: nil, Bar3DStacked: nil, Bar3DPercentStacked: nil, Col: nil, ColStacked: nil, ColPercentStacked: nil, Col3DClustered: nil, Col3D: nil, Col3DStacked: nil, Col3DPercentStacked: nil, Doughnut: nil, Line: nil, Pie: dpt, Pie3D: dpt, Radar: nil, Scatter: nil} return chartSeriesDPt[formatSet.Type] } // drawChartSeriesCat provides function to draw the c:cat element by given chart // series and format sets. func (f *File) drawChartSeriesCat(v formatChartSeries, formatSet *formatChart) *cCat { cat := &cCat{ StrRef: &cStrRef{ F: v.Categories, }, } chartSeriesCat := map[string]*cCat{Bar: cat, BarStacked: cat, BarPercentStacked: cat, Bar3DClustered: cat, Bar3DStacked: cat, Bar3DPercentStacked: cat, Col: cat, ColStacked: cat, ColPercentStacked: cat, Col3DClustered: cat, Col3D: cat, Col3DStacked: cat, Col3DPercentStacked: cat, Doughnut: cat, Line: cat, Pie: cat, Pie3D: cat, Radar: cat, Scatter: nil} return chartSeriesCat[formatSet.Type] } // drawChartSeriesVal provides function to draw the c:val element by given chart // series and format sets. func (f *File) drawChartSeriesVal(v formatChartSeries, formatSet *formatChart) *cVal { val := &cVal{ NumRef: &cNumRef{ F: v.Values, }, } chartSeriesVal := map[string]*cVal{Bar: val, BarStacked: val, BarPercentStacked: val, Bar3DClustered: val, Bar3DStacked: val, Bar3DPercentStacked: val, Col: val, ColStacked: val, ColPercentStacked: val, Col3DClustered: val, Col3D: val, Col3DStacked: val, Col3DPercentStacked: val, Doughnut: val, Line: val, Pie: val, Pie3D: val, Radar: val, Scatter: nil} return chartSeriesVal[formatSet.Type] } // drawChartSeriesMarker provides function to draw the c:marker element by given // data index and format sets. func (f *File) drawChartSeriesMarker(i int, formatSet *formatChart) *cMarker { marker := &cMarker{ Symbol: &attrValString{Val: "circle"}, Size: &attrValInt{Val: 5}, SpPr: &cSpPr{ SolidFill: &aSolidFill{ SchemeClr: &aSchemeClr{ Val: "accent" + strconv.Itoa(i+1), }, }, Ln: &aLn{ W: 9252, SolidFill: &aSolidFill{ SchemeClr: &aSchemeClr{ Val: "accent" + strconv.Itoa(i+1), }, }, }, }, } chartSeriesMarker := map[string]*cMarker{Bar: nil, BarStacked: nil, BarPercentStacked: nil, Bar3DClustered: nil, Bar3DStacked: nil, Bar3DPercentStacked: nil, Col: nil, ColStacked: nil, ColPercentStacked: nil, Col3DClustered: nil, Col3D: nil, Col3DStacked: nil, Col3DPercentStacked: nil, Doughnut: nil, Line: nil, Pie: nil, Pie3D: nil, Radar: nil, Scatter: marker} return chartSeriesMarker[formatSet.Type] } // drawChartSeriesXVal provides function to draw the c:xVal element by given // chart series and format sets. func (f *File) drawChartSeriesXVal(v formatChartSeries, formatSet *formatChart) *cCat { cat := &cCat{ StrRef: &cStrRef{ F: v.Categories, }, } chartSeriesXVal := map[string]*cCat{Bar: nil, BarStacked: nil, BarPercentStacked: nil, Bar3DClustered: nil, Bar3DStacked: nil, Bar3DPercentStacked: nil, Col: nil, ColStacked: nil, ColPercentStacked: nil, Col3DClustered: nil, Col3D: nil, Col3DStacked: nil, Col3DPercentStacked: nil, Doughnut: nil, Line: nil, Pie: nil, Pie3D: nil, Radar: nil, Scatter: cat} return chartSeriesXVal[formatSet.Type] } // drawChartSeriesYVal provides function to draw the c:yVal element by given // chart series and format sets. func (f *File) drawChartSeriesYVal(v formatChartSeries, formatSet *formatChart) *cVal { val := &cVal{ NumRef: &cNumRef{ F: v.Values, }, } chartSeriesYVal := map[string]*cVal{Bar: nil, BarStacked: nil, BarPercentStacked: nil, Bar3DClustered: nil, Bar3DStacked: nil, Bar3DPercentStacked: nil, Col: nil, ColStacked: nil, ColPercentStacked: nil, Col3DClustered: nil, Col3D: nil, Col3DStacked: nil, Col3DPercentStacked: nil, Doughnut: nil, Line: nil, Pie: nil, Pie3D: nil, Radar: nil, Scatter: val} return chartSeriesYVal[formatSet.Type] } // drawChartDLbls provides function to draw the c:dLbls element by given format // sets. func (f *File) drawChartDLbls(formatSet *formatChart) *cDLbls { return &cDLbls{ ShowLegendKey: &attrValBool{Val: formatSet.Legend.ShowLegendKey}, ShowVal: &attrValBool{Val: formatSet.Plotarea.ShowVal}, ShowCatName: &attrValBool{Val: formatSet.Plotarea.ShowCatName}, ShowSerName: &attrValBool{Val: formatSet.Plotarea.ShowSerName}, ShowBubbleSize: &attrValBool{Val: formatSet.Plotarea.ShowBubbleSize}, ShowPercent: &attrValBool{Val: formatSet.Plotarea.ShowPercent}, ShowLeaderLines: &attrValBool{Val: formatSet.Plotarea.ShowLeaderLines}, } } // drawChartSeriesDLbls provides function to draw the c:dLbls element by given // format sets. func (f *File) drawChartSeriesDLbls(formatSet *formatChart) *cDLbls { dLbls := f.drawChartDLbls(formatSet) chartSeriesDLbls := map[string]*cDLbls{Bar: dLbls, BarStacked: dLbls, BarPercentStacked: dLbls, Bar3DClustered: dLbls, Bar3DStacked: dLbls, Bar3DPercentStacked: dLbls, Col: dLbls, ColStacked: dLbls, ColPercentStacked: dLbls, Col3DClustered: dLbls, Col3D: dLbls, Col3DStacked: dLbls, Col3DPercentStacked: dLbls, Doughnut: dLbls, Line: dLbls, Pie: dLbls, Pie3D: dLbls, Radar: dLbls, Scatter: nil} return chartSeriesDLbls[formatSet.Type] } // drawPlotAreaCatAx provides function to draw the c:catAx element. func (f *File) drawPlotAreaCatAx(formatSet *formatChart) []*cAxs { min := &attrValFloat{Val: formatSet.XAxis.Minimum} max := &attrValFloat{Val: formatSet.XAxis.Maximum} if formatSet.XAxis.Minimum == 0 { min = nil } if formatSet.XAxis.Maximum == 0 { max = nil } return []*cAxs{ { AxID: &attrValInt{Val: 754001152}, Scaling: &cScaling{ Orientation: &attrValString{Val: orientation[formatSet.XAxis.ReverseOrder]}, Max: max, Min: min, }, Delete: &attrValBool{Val: false}, AxPos: &attrValString{Val: catAxPos[formatSet.XAxis.ReverseOrder]}, NumFmt: &cNumFmt{ FormatCode: "General", SourceLinked: true, }, MajorTickMark: &attrValString{Val: "none"}, MinorTickMark: &attrValString{Val: "none"}, TickLblPos: &attrValString{Val: "nextTo"}, SpPr: f.drawPlotAreaSpPr(), TxPr: f.drawPlotAreaTxPr(), CrossAx: &attrValInt{Val: 753999904}, Crosses: &attrValString{Val: "autoZero"}, Auto: &attrValBool{Val: true}, LblAlgn: &attrValString{Val: "ctr"}, LblOffset: &attrValInt{Val: 100}, NoMultiLvlLbl: &attrValBool{Val: false}, }, } } // drawPlotAreaValAx provides function to draw the c:valAx element. func (f *File) drawPlotAreaValAx(formatSet *formatChart) []*cAxs { min := &attrValFloat{Val: formatSet.YAxis.Minimum} max := &attrValFloat{Val: formatSet.YAxis.Maximum} if formatSet.YAxis.Minimum == 0 { min = nil } if formatSet.YAxis.Maximum == 0 { max = nil } return []*cAxs{ { AxID: &attrValInt{Val: 753999904}, Scaling: &cScaling{ Orientation: &attrValString{Val: orientation[formatSet.YAxis.ReverseOrder]}, Max: max, Min: min, }, Delete: &attrValBool{Val: false}, AxPos: &attrValString{Val: valAxPos[formatSet.YAxis.ReverseOrder]}, NumFmt: &cNumFmt{ FormatCode: chartValAxNumFmtFormatCode[formatSet.Type], SourceLinked: true, }, MajorTickMark: &attrValString{Val: "none"}, MinorTickMark: &attrValString{Val: "none"}, TickLblPos: &attrValString{Val: "nextTo"}, SpPr: f.drawPlotAreaSpPr(), TxPr: f.drawPlotAreaTxPr(), CrossAx: &attrValInt{Val: 754001152}, Crosses: &attrValString{Val: "autoZero"}, CrossBetween: &attrValString{Val: "between"}, }, } } // drawPlotAreaSpPr provides function to draw the c:spPr element. func (f *File) drawPlotAreaSpPr() *cSpPr { return &cSpPr{ Ln: &aLn{ W: 9525, Cap: "flat", Cmpd: "sng", Algn: "ctr", SolidFill: &aSolidFill{ SchemeClr: &aSchemeClr{ Val: "tx1", LumMod: &attrValInt{Val: 15000}, LumOff: &attrValInt{Val: 85000}, }, }, }, } } // drawPlotAreaTxPr provides function to draw the c:txPr element. func (f *File) drawPlotAreaTxPr() *cTxPr { return &cTxPr{ BodyPr: aBodyPr{ Rot: -60000000, SpcFirstLastPara: true, VertOverflow: "ellipsis", Vert: "horz", Wrap: "square", Anchor: "ctr", AnchorCtr: true, }, P: aP{ PPr: &aPPr{ DefRPr: aRPr{ Sz: 900, B: false, I: false, U: "none", Strike: "noStrike", Kern: 1200, Baseline: 0, SolidFill: &aSolidFill{ SchemeClr: &aSchemeClr{ Val: "tx1", LumMod: &attrValInt{Val: 15000}, LumOff: &attrValInt{Val: 85000}, }, }, Latin: &aLatin{Typeface: "+mn-lt"}, Ea: &aEa{Typeface: "+mn-ea"}, Cs: &aCs{Typeface: "+mn-cs"}, }, }, EndParaRPr: &aEndParaRPr{Lang: "en-US"}, }, } } // drawingParser provides function to parse drawingXML. In order to solve the // problem that the label structure is changed after serialization and // deserialization, two different structures: decodeWsDr and encodeWsDr are // defined. func (f *File) drawingParser(drawingXML string, content *xlsxWsDr) int { cNvPrID := 1 _, ok := f.XLSX[drawingXML] if ok { // Append Model decodeWsDr := decodeWsDr{} _ = xml.Unmarshal([]byte(f.readXML(drawingXML)), &decodeWsDr) content.R = decodeWsDr.R cNvPrID = len(decodeWsDr.OneCellAnchor) + len(decodeWsDr.TwoCellAnchor) + 1 for _, v := range decodeWsDr.OneCellAnchor { content.OneCellAnchor = append(content.OneCellAnchor, &xdrCellAnchor{ EditAs: v.EditAs, GraphicFrame: v.Content, }) } for _, v := range decodeWsDr.TwoCellAnchor { content.TwoCellAnchor = append(content.TwoCellAnchor, &xdrCellAnchor{ EditAs: v.EditAs, GraphicFrame: v.Content, }) } } return cNvPrID } // addDrawingChart provides function to add chart graphic frame by given sheet, // drawingXML, cell, width, height, relationship index and format sets. func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rID int, formatSet *formatPicture) { cell = strings.ToUpper(cell) fromCol := string(strings.Map(letterOnlyMapF, cell)) fromRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell)) row := fromRow - 1 col := TitleToNumber(fromCol) width = int(float64(width) * formatSet.XScale) height = int(float64(height) * formatSet.YScale) colStart, rowStart, _, _, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, formatSet.OffsetX, formatSet.OffsetY, width, height) content := xlsxWsDr{} content.A = NameSpaceDrawingML content.Xdr = NameSpaceDrawingMLSpreadSheet cNvPrID := f.drawingParser(drawingXML, &content) twoCellAnchor := xdrCellAnchor{} twoCellAnchor.EditAs = formatSet.Positioning from := xlsxFrom{} from.Col = colStart from.ColOff = formatSet.OffsetX * EMU from.Row = rowStart from.RowOff = formatSet.OffsetY * EMU to := xlsxTo{} to.Col = colEnd to.ColOff = x2 * EMU to.Row = rowEnd to.RowOff = y2 * EMU twoCellAnchor.From = &from twoCellAnchor.To = &to graphicFrame := xlsxGraphicFrame{ NvGraphicFramePr: xlsxNvGraphicFramePr{ CNvPr: &xlsxCNvPr{ ID: f.countCharts() + f.countMedia() + 1, Name: "Chart " + strconv.Itoa(cNvPrID), }, }, Graphic: &xlsxGraphic{ GraphicData: &xlsxGraphicData{ URI: NameSpaceDrawingMLChart, Chart: &xlsxChart{ C: NameSpaceDrawingMLChart, R: SourceRelationship, RID: "rId" + strconv.Itoa(rID), }, }, }, } graphic, _ := xml.Marshal(graphicFrame) twoCellAnchor.GraphicFrame = string(graphic) twoCellAnchor.ClientData = &xdrClientData{ FLocksWithSheet: formatSet.FLocksWithSheet, FPrintsWithSheet: formatSet.FPrintsWithSheet, } content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor) output, _ := xml.Marshal(content) f.saveFileList(drawingXML, output) } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/col.go ================================================ package excelize import ( "bytes" "math" "strconv" "strings" ) // Define the default cell size and EMU unit of measurement. const ( defaultColWidthPixels float64 = 64 defaultRowHeightPixels float64 = 20 EMU int = 9525 ) // GetColVisible provides a function to get visible of a single column by given // worksheet name and column name. For example, get visible state of column D // in Sheet1: // // xlsx.GetColVisible("Sheet1", "D") // func (f *File) GetColVisible(sheet, column string) bool { xlsx := f.workSheetReader(sheet) col := TitleToNumber(strings.ToUpper(column)) + 1 visible := true if xlsx.Cols == nil { return visible } for c := range xlsx.Cols.Col { if xlsx.Cols.Col[c].Min <= col && col <= xlsx.Cols.Col[c].Max { visible = !xlsx.Cols.Col[c].Hidden } } return visible } // SetColVisible provides a function to set visible of a single column by given // worksheet name and column name. For example, hide column D in Sheet1: // // xlsx.SetColVisible("Sheet1", "D", false) // func (f *File) SetColVisible(sheet, column string, visible bool) { xlsx := f.workSheetReader(sheet) c := TitleToNumber(strings.ToUpper(column)) + 1 col := xlsxCol{ Min: c, Max: c, Hidden: !visible, CustomWidth: true, } if xlsx.Cols == nil { cols := xlsxCols{} cols.Col = append(cols.Col, col) xlsx.Cols = &cols return } for v := range xlsx.Cols.Col { if xlsx.Cols.Col[v].Min <= c && c <= xlsx.Cols.Col[v].Max { col = xlsx.Cols.Col[v] } } col.Min = c col.Max = c col.Hidden = !visible col.CustomWidth = true xlsx.Cols.Col = append(xlsx.Cols.Col, col) } // GetColOutlineLevel provides a function to get outline level of a single // column by given worksheet name and column name. For example, get outline // level of column D in Sheet1: // // xlsx.GetColOutlineLevel("Sheet1", "D") // func (f *File) GetColOutlineLevel(sheet, column string) uint8 { xlsx := f.workSheetReader(sheet) col := TitleToNumber(strings.ToUpper(column)) + 1 level := uint8(0) if xlsx.Cols == nil { return level } for c := range xlsx.Cols.Col { if xlsx.Cols.Col[c].Min <= col && col <= xlsx.Cols.Col[c].Max { level = xlsx.Cols.Col[c].OutlineLevel } } return level } // SetColOutlineLevel provides a function to set outline level of a single // column by given worksheet name and column name. For example, set outline // level of column D in Sheet1 to 2: // // xlsx.SetColOutlineLevel("Sheet1", "D", 2) // func (f *File) SetColOutlineLevel(sheet, column string, level uint8) { xlsx := f.workSheetReader(sheet) c := TitleToNumber(strings.ToUpper(column)) + 1 col := xlsxCol{ Min: c, Max: c, OutlineLevel: level, CustomWidth: true, } if xlsx.Cols == nil { cols := xlsxCols{} cols.Col = append(cols.Col, col) xlsx.Cols = &cols return } for v := range xlsx.Cols.Col { if xlsx.Cols.Col[v].Min <= c && c <= xlsx.Cols.Col[v].Max { col = xlsx.Cols.Col[v] } } col.Min = c col.Max = c col.OutlineLevel = level col.CustomWidth = true xlsx.Cols.Col = append(xlsx.Cols.Col, col) } // SetColWidth provides function to set the width of a single column or multiple // columns. For example: // // xlsx := excelize.NewFile() // xlsx.SetColWidth("Sheet1", "A", "H", 20) // err := xlsx.Save() // if err != nil { // fmt.Println(err) // } // func (f *File) SetColWidth(sheet, startcol, endcol string, width float64) { min := TitleToNumber(strings.ToUpper(startcol)) + 1 max := TitleToNumber(strings.ToUpper(endcol)) + 1 if min > max { min, max = max, min } xlsx := f.workSheetReader(sheet) col := xlsxCol{ Min: min, Max: max, Width: width, CustomWidth: true, } if xlsx.Cols != nil { xlsx.Cols.Col = append(xlsx.Cols.Col, col) } else { cols := xlsxCols{} cols.Col = append(cols.Col, col) xlsx.Cols = &cols } } // positionObjectPixels calculate the vertices that define the position of a // graphical object within the worksheet in pixels. // // +------------+------------+ // | A | B | // +-----+------------+------------+ // | |(x1,y1) | | // | 1 |(A1)._______|______ | // | | | | | // | | | | | // +-----+----| OBJECT |-----+ // | | | | | // | 2 | |______________. | // | | | (B2)| // | | | (x2,y2)| // +-----+------------+------------+ // // Example of an object that covers some of the area from cell A1 to B2. // // Based on the width and height of the object we need to calculate 8 vars: // // colStart, rowStart, colEnd, rowEnd, x1, y1, x2, y2. // // We also calculate the absolute x and y position of the top left vertex of // the object. This is required for images. // // The width and height of the cells that the object occupies can be // variable and have to be taken into account. // // The values of col_start and row_start are passed in from the calling // function. The values of col_end and row_end are calculated by // subtracting the width and height of the object from the width and // height of the underlying cells. // // colStart # Col containing upper left corner of object. // x1 # Distance to left side of object. // // rowStart # Row containing top left corner of object. // y1 # Distance to top of object. // // colEnd # Col containing lower right corner of object. // x2 # Distance to right side of object. // // rowEnd # Row containing bottom right corner of object. // y2 # Distance to bottom of object. // // width # Width of object frame. // height # Height of object frame. // // xAbs # Absolute distance to left side of object. // yAbs # Absolute distance to top side of object. // func (f *File) positionObjectPixels(sheet string, colStart, rowStart, x1, y1, width, height int) (int, int, int, int, int, int, int, int) { xAbs := 0 yAbs := 0 // Calculate the absolute x offset of the top-left vertex. for colID := 1; colID <= colStart; colID++ { xAbs += f.getColWidth(sheet, colID) } xAbs += x1 // Calculate the absolute y offset of the top-left vertex. // Store the column change to allow optimisations. for rowID := 1; rowID <= rowStart; rowID++ { yAbs += f.getRowHeight(sheet, rowID) } yAbs += y1 // Adjust start column for offsets that are greater than the col width. for x1 >= f.getColWidth(sheet, colStart) { x1 -= f.getColWidth(sheet, colStart) colStart++ } // Adjust start row for offsets that are greater than the row height. for y1 >= f.getRowHeight(sheet, rowStart) { y1 -= f.getRowHeight(sheet, rowStart) rowStart++ } // Initialise end cell to the same as the start cell. colEnd := colStart rowEnd := rowStart width += x1 height += y1 // Subtract the underlying cell widths to find end cell of the object. for width >= f.getColWidth(sheet, colEnd) { colEnd++ width -= f.getColWidth(sheet, colEnd) } // Subtract the underlying cell heights to find end cell of the object. for height >= f.getRowHeight(sheet, rowEnd) { rowEnd++ height -= f.getRowHeight(sheet, rowEnd) } // The end vertices are whatever is left from the width and height. x2 := width y2 := height return colStart, rowStart, xAbs, yAbs, colEnd, rowEnd, x2, y2 } // getColWidth provides function to get column width in pixels by given sheet // name and column index. func (f *File) getColWidth(sheet string, col int) int { xlsx := f.workSheetReader(sheet) if xlsx.Cols != nil { var width float64 for _, v := range xlsx.Cols.Col { if v.Min <= col && col <= v.Max { width = v.Width } } if width != 0 { return int(convertColWidthToPixels(width)) } } // Optimisation for when the column widths haven't changed. return int(defaultColWidthPixels) } // GetColWidth provides function to get column width by given worksheet name and // column index. func (f *File) GetColWidth(sheet, column string) float64 { col := TitleToNumber(strings.ToUpper(column)) + 1 xlsx := f.workSheetReader(sheet) if xlsx.Cols != nil { var width float64 for _, v := range xlsx.Cols.Col { if v.Min <= col && col <= v.Max { width = v.Width } } if width != 0 { return width } } // Optimisation for when the column widths haven't changed. return defaultColWidthPixels } // InsertCol provides function to insert a new column before given column index. // For example, create a new column before column C in Sheet1: // // xlsx.InsertCol("Sheet1", "C") // func (f *File) InsertCol(sheet, column string) { col := TitleToNumber(strings.ToUpper(column)) f.adjustHelper(sheet, col, -1, 1) } // RemoveCol provides function to remove single column by given worksheet name // and column index. For example, remove column C in Sheet1: // // xlsx.RemoveCol("Sheet1", "C") // func (f *File) RemoveCol(sheet, column string) { xlsx := f.workSheetReader(sheet) for r := range xlsx.SheetData.Row { for k, v := range xlsx.SheetData.Row[r].C { axis := v.R col := string(strings.Map(letterOnlyMapF, axis)) if col == column { xlsx.SheetData.Row[r].C = append(xlsx.SheetData.Row[r].C[:k], xlsx.SheetData.Row[r].C[k+1:]...) } } } col := TitleToNumber(strings.ToUpper(column)) f.adjustHelper(sheet, col, -1, -1) } // Completion column element tags of XML in a sheet. func completeCol(xlsx *xlsxWorksheet, row, cell int) { buffer := bytes.Buffer{} for r := range xlsx.SheetData.Row { if len(xlsx.SheetData.Row[r].C) < cell { start := len(xlsx.SheetData.Row[r].C) for iii := start; iii < cell; iii++ { buffer.WriteString(ToAlphaString(iii)) buffer.WriteString(strconv.Itoa(r + 1)) xlsx.SheetData.Row[r].C = append(xlsx.SheetData.Row[r].C, xlsxC{ R: buffer.String(), }) buffer.Reset() } } } } // convertColWidthToPixels provieds function to convert the width of a cell from // user's units to pixels. Excel rounds the column width to the nearest pixel. // If the width hasn't been set by the user we use the default value. If the // column is hidden it has a value of zero. func convertColWidthToPixels(width float64) float64 { var padding float64 = 5 var pixels float64 var maxDigitWidth float64 = 7 if width == 0 { return pixels } if width < 1 { pixels = (width * 12) + 0.5 return math.Ceil(pixels) } pixels = (width*maxDigitWidth + 0.5) + padding return math.Ceil(pixels) } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/comment.go ================================================ package excelize import ( "encoding/json" "encoding/xml" "strconv" "strings" ) // parseFormatCommentsSet provides function to parse the format settings of the // comment with default value. func parseFormatCommentsSet(formatSet string) (*formatComment, error) { format := formatComment{ Author: "Author:", Text: " ", } err := json.Unmarshal([]byte(formatSet), &format) return &format, err } // AddComment provides the method to add comment in a sheet by given worksheet // index, cell and format set (such as author and text). Note that the max // author length is 255 and the max text length is 32512. For example, add a // comment in Sheet1!$A$30: // // xlsx.AddComment("Sheet1", "A30", `{"author":"Excelize: ","text":"This is a comment."}`) // func (f *File) AddComment(sheet, cell, format string) error { formatSet, err := parseFormatCommentsSet(format) if err != nil { return err } // Read sheet data. xlsx := f.workSheetReader(sheet) commentID := f.countComments() + 1 drawingVML := "xl/drawings/vmlDrawing" + strconv.Itoa(commentID) + ".vml" sheetRelationshipsComments := "../comments" + strconv.Itoa(commentID) + ".xml" sheetRelationshipsDrawingVML := "../drawings/vmlDrawing" + strconv.Itoa(commentID) + ".vml" if xlsx.LegacyDrawing != nil { // The worksheet already has a comments relationships, use the relationships drawing ../drawings/vmlDrawing%d.vml. sheetRelationshipsDrawingVML = f.getSheetRelationshipsTargetByID(sheet, xlsx.LegacyDrawing.RID) commentID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingVML, "../drawings/vmlDrawing"), ".vml")) drawingVML = strings.Replace(sheetRelationshipsDrawingVML, "..", "xl", -1) } else { // Add first comment for given sheet. rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingVML, sheetRelationshipsDrawingVML, "") f.addSheetRelationships(sheet, SourceRelationshipComments, sheetRelationshipsComments, "") f.addSheetLegacyDrawing(sheet, rID) } commentsXML := "xl/comments" + strconv.Itoa(commentID) + ".xml" f.addComment(commentsXML, cell, formatSet) f.addDrawingVML(commentID, drawingVML, cell) f.addContentTypePart(commentID, "comments") return err } // addDrawingVML provides function to create comment as // xl/drawings/vmlDrawing%d.vml by given commit ID and cell. func (f *File) addDrawingVML(commentID int, drawingVML, cell string) { col := string(strings.Map(letterOnlyMapF, cell)) row, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell)) xAxis := row - 1 yAxis := TitleToNumber(col) vml := vmlDrawing{ XMLNSv: "urn:schemas-microsoft-com:vml", XMLNSo: "urn:schemas-microsoft-com:office:office", XMLNSx: "urn:schemas-microsoft-com:office:excel", XMLNSmv: "http://macVmlSchemaUri", Shapelayout: &xlsxShapelayout{ Ext: "edit", IDmap: &xlsxIDmap{ Ext: "edit", Data: commentID, }, }, Shapetype: &xlsxShapetype{ ID: "_x0000_t202", Coordsize: "21600,21600", Spt: 202, Path: "m0,0l0,21600,21600,21600,21600,0xe", Stroke: &xlsxStroke{ Joinstyle: "miter", }, VPath: &vPath{ Gradientshapeok: "t", Connecttype: "rect", }, }, } sp := encodeShape{ Fill: &vFill{ Color2: "#fbfe82", Angle: -180, Type: "gradient", Fill: &oFill{ Ext: "view", Type: "gradientUnscaled", }, }, Shadow: &vShadow{ On: "t", Color: "black", Obscured: "t", }, Path: &vPath{ Connecttype: "none", }, Textbox: &vTextbox{ Style: "mso-direction-alt:auto", Div: &xlsxDiv{ Style: "text-align:left", }, }, ClientData: &xClientData{ ObjectType: "Note", Anchor: "3, 15, 8, 6, 4, 54, 13, 2", AutoFill: "False", Row: xAxis, Column: yAxis, }, } s, _ := xml.Marshal(sp) shape := xlsxShape{ ID: "_x0000_s1025", Type: "#_x0000_t202", Style: "position:absolute;73.5pt;width:108pt;height:59.25pt;z-index:1;visibility:hidden", Fillcolor: "#fbf6d6", Strokecolor: "#edeaa1", Val: string(s[13 : len(s)-14]), } c, ok := f.XLSX[drawingVML] if ok { d := decodeVmlDrawing{} _ = xml.Unmarshal([]byte(c), &d) for _, v := range d.Shape { s := xlsxShape{ ID: "_x0000_s1025", Type: "#_x0000_t202", Style: "position:absolute;73.5pt;width:108pt;height:59.25pt;z-index:1;visibility:hidden", Fillcolor: "#fbf6d6", Strokecolor: "#edeaa1", Val: v.Val, } vml.Shape = append(vml.Shape, s) } } vml.Shape = append(vml.Shape, shape) v, _ := xml.Marshal(vml) f.XLSX[drawingVML] = v } // addComment provides function to create chart as xl/comments%d.xml by given // cell and format sets. func (f *File) addComment(commentsXML, cell string, formatSet *formatComment) { a := formatSet.Author t := formatSet.Text if len(a) > 255 { a = a[0:255] } if len(t) > 32512 { t = t[0:32512] } comments := xlsxComments{ Authors: []xlsxAuthor{ { Author: formatSet.Author, }, }, } cmt := xlsxComment{ Ref: cell, AuthorID: 0, Text: xlsxText{ R: []xlsxR{ { RPr: &xlsxRPr{ B: " ", Sz: &attrValFloat{Val: 9}, Color: &xlsxColor{ Indexed: 81, }, RFont: &attrValString{Val: "Calibri"}, Family: &attrValInt{Val: 2}, }, T: a, }, { RPr: &xlsxRPr{ Sz: &attrValFloat{Val: 9}, Color: &xlsxColor{ Indexed: 81, }, RFont: &attrValString{Val: "Calibri"}, Family: &attrValInt{Val: 2}, }, T: t, }, }, }, } c, ok := f.XLSX[commentsXML] if ok { d := xlsxComments{} _ = xml.Unmarshal([]byte(c), &d) comments.CommentList.Comment = append(comments.CommentList.Comment, d.CommentList.Comment...) } comments.CommentList.Comment = append(comments.CommentList.Comment, cmt) v, _ := xml.Marshal(comments) f.saveFileList(commentsXML, v) } // countComments provides function to get comments files count storage in the // folder xl. func (f *File) countComments() int { count := 0 for k := range f.XLSX { if strings.Contains(k, "xl/comments") { count++ } } return count } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/date.go ================================================ package excelize import ( "math" "time" ) // timeLocationUTC defined the UTC time location. var timeLocationUTC, _ = time.LoadLocation("UTC") // timeToUTCTime provides function to convert time to UTC time. func timeToUTCTime(t time.Time) time.Time { return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), timeLocationUTC) } // timeToExcelTime provides function to convert time to Excel time. func timeToExcelTime(t time.Time) float64 { return float64(t.UnixNano())/8.64e13 + 25569.0 } // shiftJulianToNoon provides function to process julian date to noon. func shiftJulianToNoon(julianDays, julianFraction float64) (float64, float64) { switch { case -0.5 < julianFraction && julianFraction < 0.5: julianFraction += 0.5 case julianFraction >= 0.5: julianDays++ julianFraction -= 0.5 case julianFraction <= -0.5: julianDays-- julianFraction += 1.5 } return julianDays, julianFraction } // fractionOfADay provides function to return the integer values for hour, // minutes, seconds and nanoseconds that comprised a given fraction of a day. // values would round to 1 us. func fractionOfADay(fraction float64) (hours, minutes, seconds, nanoseconds int) { const ( c1us = 1e3 c1s = 1e9 c1day = 24 * 60 * 60 * c1s ) frac := int64(c1day*fraction + c1us/2) nanoseconds = int((frac%c1s)/c1us) * c1us frac /= c1s seconds = int(frac % 60) frac /= 60 minutes = int(frac % 60) hours = int(frac / 60) return } // julianDateToGregorianTime provides function to convert julian date to // gregorian time. func julianDateToGregorianTime(part1, part2 float64) time.Time { part1I, part1F := math.Modf(part1) part2I, part2F := math.Modf(part2) julianDays := part1I + part2I julianFraction := part1F + part2F julianDays, julianFraction = shiftJulianToNoon(julianDays, julianFraction) day, month, year := doTheFliegelAndVanFlandernAlgorithm(int(julianDays)) hours, minutes, seconds, nanoseconds := fractionOfADay(julianFraction) return time.Date(year, time.Month(month), day, hours, minutes, seconds, nanoseconds, time.UTC) } // By this point generations of programmers have repeated the algorithm sent to // the editor of "Communications of the ACM" in 1968 (published in CACM, volume // 11, number 10, October 1968, p.657). None of those programmers seems to have // found it necessary to explain the constants or variable names set out by // Henry F. Fliegel and Thomas C. Van Flandern. Maybe one day I'll buy that // jounal and expand an explanation here - that day is not today. func doTheFliegelAndVanFlandernAlgorithm(jd int) (day, month, year int) { l := jd + 68569 n := (4 * l) / 146097 l = l - (146097*n+3)/4 i := (4000 * (l + 1)) / 1461001 l = l - (1461*i)/4 + 31 j := (80 * l) / 2447 d := l - (2447*j)/80 l = j / 11 m := j + 2 - (12 * l) y := 100*(n-49) + i + l return d, m, y } // timeFromExcelTime provides function to convert an excelTime representation // (stored as a floating point number) to a time.Time. func timeFromExcelTime(excelTime float64, date1904 bool) time.Time { var date time.Time var intPart = int64(excelTime) // Excel uses Julian dates prior to March 1st 1900, and Gregorian // thereafter. if intPart <= 61 { const OFFSET1900 = 15018.0 const OFFSET1904 = 16480.0 const MJD0 float64 = 2400000.5 var date time.Time if date1904 { date = julianDateToGregorianTime(MJD0, excelTime+OFFSET1904) } else { date = julianDateToGregorianTime(MJD0, excelTime+OFFSET1900) } return date } var floatPart = excelTime - float64(intPart) var dayNanoSeconds float64 = 24 * 60 * 60 * 1000 * 1000 * 1000 if date1904 { date = time.Date(1904, 1, 1, 0, 0, 0, 0, time.UTC) } else { date = time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC) } durationDays := time.Duration(intPart) * time.Hour * 24 durationPart := time.Duration(dayNanoSeconds * floatPart) return date.Add(durationDays).Add(durationPart) } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/excelize.go ================================================ package excelize import ( "archive/zip" "bytes" "encoding/xml" "io" "io/ioutil" "os" "strconv" "strings" ) // File define a populated XLSX file struct. type File struct { checked map[string]bool sheetMap map[string]string ContentTypes *xlsxTypes Path string SharedStrings *xlsxSST Sheet map[string]*xlsxWorksheet SheetCount int Styles *xlsxStyleSheet WorkBook *xlsxWorkbook WorkBookRels *xlsxWorkbookRels XLSX map[string][]byte } // OpenFile take the name of an XLSX file and returns a populated XLSX file // struct for it. func OpenFile(filename string) (*File, error) { file, err := os.Open(filename) if err != nil { return nil, err } defer file.Close() f, err := OpenReader(file) if err != nil { return nil, err } f.Path = filename return f, nil } // OpenReader take an io.Reader and return a populated XLSX file. func OpenReader(r io.Reader) (*File, error) { b, err := ioutil.ReadAll(r) if err != nil { return nil, err } zr, err := zip.NewReader(bytes.NewReader(b), int64(len(b))) if err != nil { return nil, err } file, sheetCount, err := ReadZipReader(zr) if err != nil { return nil, err } f := &File{ checked: make(map[string]bool), Sheet: make(map[string]*xlsxWorksheet), SheetCount: sheetCount, XLSX: file, } f.sheetMap = f.getSheetMap() f.Styles = f.stylesReader() return f, nil } // setDefaultTimeStyle provides function to set default numbers format for // time.Time type cell value by given worksheet name, cell coordinates and // number format code. func (f *File) setDefaultTimeStyle(sheet, axis string, format int) { if f.GetCellStyle(sheet, axis) == 0 { style, _ := f.NewStyle(`{"number_format": ` + strconv.Itoa(format) + `}`) f.SetCellStyle(sheet, axis, axis, style) } } // workSheetReader provides function to get the pointer to the structure after // deserialization by given worksheet name. func (f *File) workSheetReader(sheet string) *xlsxWorksheet { name, ok := f.sheetMap[trimSheetName(sheet)] if !ok { name = "xl/worksheets/" + strings.ToLower(sheet) + ".xml" } if f.Sheet[name] == nil { var xlsx xlsxWorksheet _ = xml.Unmarshal(f.readXML(name), &xlsx) if f.checked == nil { f.checked = make(map[string]bool) } ok := f.checked[name] if !ok { checkSheet(&xlsx) checkRow(&xlsx) f.checked[name] = true } f.Sheet[name] = &xlsx } return f.Sheet[name] } // checkSheet provides function to fill each row element and make that is // continuous in a worksheet of XML. func checkSheet(xlsx *xlsxWorksheet) { row := len(xlsx.SheetData.Row) if row >= 1 { lastRow := xlsx.SheetData.Row[row-1].R if lastRow >= row { row = lastRow } } sheetData := xlsxSheetData{} existsRows := map[int]int{} for k := range xlsx.SheetData.Row { existsRows[xlsx.SheetData.Row[k].R] = k } for i := 0; i < row; i++ { _, ok := existsRows[i+1] if ok { sheetData.Row = append(sheetData.Row, xlsx.SheetData.Row[existsRows[i+1]]) } else { sheetData.Row = append(sheetData.Row, xlsxRow{ R: i + 1, }) } } xlsx.SheetData = sheetData } // replaceWorkSheetsRelationshipsNameSpaceBytes provides function to replace // xl/worksheets/sheet%d.xml XML tags to self-closing for compatible Microsoft // Office Excel 2007. func replaceWorkSheetsRelationshipsNameSpaceBytes(workbookMarshal []byte) []byte { var oldXmlns = []byte(``) var newXmlns = []byte(``) workbookMarshal = bytes.Replace(workbookMarshal, oldXmlns, newXmlns, -1) return workbookMarshal } // UpdateLinkedValue fix linked values within a spreadsheet are not updating in // Office Excel 2007 and 2010. This function will be remove value tag when met a // cell have a linked value. Reference // https://social.technet.microsoft.com/Forums/office/en-US/e16bae1f-6a2c-4325-8013-e989a3479066/excel-2010-linked-cells-not-updating?forum=excel // // Notice: after open XLSX file Excel will be update linked value and generate // new value and will prompt save file or not. // // For example: // // // // SUM(Sheet2!D2,Sheet2!D11) // 100 // // // // to // // // // SUM(Sheet2!D2,Sheet2!D11) // // // func (f *File) UpdateLinkedValue() { for _, name := range f.GetSheetMap() { xlsx := f.workSheetReader(name) for indexR := range xlsx.SheetData.Row { for indexC, col := range xlsx.SheetData.Row[indexR].C { if col.F != nil && col.V != "" { xlsx.SheetData.Row[indexR].C[indexC].V = "" xlsx.SheetData.Row[indexR].C[indexC].T = "" } } } } } // adjustHelper provides function to adjust rows and columns dimensions, // hyperlinks, merged cells and auto filter when inserting or deleting rows or // columns. // // sheet: Worksheet name that we're editing // column: Index number of the column we're inserting/deleting before // row: Index number of the row we're inserting/deleting before // offset: Number of rows/column to insert/delete negative values indicate deletion // // TODO: adjustPageBreaks, adjustComments, adjustDataValidations, adjustProtectedCells // func (f *File) adjustHelper(sheet string, column, row, offset int) { xlsx := f.workSheetReader(sheet) f.adjustRowDimensions(xlsx, row, offset) f.adjustColDimensions(xlsx, column, offset) f.adjustHyperlinks(sheet, column, row, offset) f.adjustMergeCells(xlsx, column, row, offset) f.adjustAutoFilter(xlsx, column, row, offset) checkSheet(xlsx) checkRow(xlsx) } // adjustColDimensions provides function to update column dimensions when // inserting or deleting rows or columns. func (f *File) adjustColDimensions(xlsx *xlsxWorksheet, column, offset int) { for i, r := range xlsx.SheetData.Row { for k, v := range r.C { axis := v.R col := string(strings.Map(letterOnlyMapF, axis)) row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis)) yAxis := TitleToNumber(col) if yAxis >= column && column != -1 { xlsx.SheetData.Row[i].C[k].R = ToAlphaString(yAxis+offset) + strconv.Itoa(row) } } } } // adjustRowDimensions provides function to update row dimensions when inserting // or deleting rows or columns. func (f *File) adjustRowDimensions(xlsx *xlsxWorksheet, rowIndex, offset int) { if rowIndex == -1 { return } for i, r := range xlsx.SheetData.Row { if r.R >= rowIndex { xlsx.SheetData.Row[i].R += offset for k, v := range xlsx.SheetData.Row[i].C { axis := v.R col := string(strings.Map(letterOnlyMapF, axis)) row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis)) xAxis := row + offset xlsx.SheetData.Row[i].C[k].R = col + strconv.Itoa(xAxis) } } } } // adjustHyperlinks provides function to update hyperlinks when inserting or // deleting rows or columns. func (f *File) adjustHyperlinks(sheet string, column, rowIndex, offset int) { xlsx := f.workSheetReader(sheet) // order is important if xlsx.Hyperlinks != nil && offset < 0 { for i, v := range xlsx.Hyperlinks.Hyperlink { axis := v.Ref col := string(strings.Map(letterOnlyMapF, axis)) row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis)) yAxis := TitleToNumber(col) if row == rowIndex || yAxis == column { f.deleteSheetRelationships(sheet, v.RID) if len(xlsx.Hyperlinks.Hyperlink) > 1 { xlsx.Hyperlinks.Hyperlink = append(xlsx.Hyperlinks.Hyperlink[:i], xlsx.Hyperlinks.Hyperlink[i+1:]...) } else { xlsx.Hyperlinks = nil } } } } if xlsx.Hyperlinks != nil { for i, v := range xlsx.Hyperlinks.Hyperlink { axis := v.Ref col := string(strings.Map(letterOnlyMapF, axis)) row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis)) xAxis := row + offset yAxis := TitleToNumber(col) if rowIndex != -1 && row >= rowIndex { xlsx.Hyperlinks.Hyperlink[i].Ref = col + strconv.Itoa(xAxis) } if column != -1 && yAxis >= column { xlsx.Hyperlinks.Hyperlink[i].Ref = ToAlphaString(yAxis+offset) + strconv.Itoa(row) } } } } // adjustMergeCellsHelper provides function to update merged cells when inserting or // deleting rows or columns. func (f *File) adjustMergeCellsHelper(xlsx *xlsxWorksheet, column, rowIndex, offset int) { if xlsx.MergeCells != nil { for k, v := range xlsx.MergeCells.Cells { beg := strings.Split(v.Ref, ":")[0] end := strings.Split(v.Ref, ":")[1] begcol := string(strings.Map(letterOnlyMapF, beg)) begrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, beg)) begxAxis := begrow + offset begyAxis := TitleToNumber(begcol) endcol := string(strings.Map(letterOnlyMapF, end)) endrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, end)) endxAxis := endrow + offset endyAxis := TitleToNumber(endcol) if rowIndex != -1 { if begrow > 1 && begrow >= rowIndex { beg = begcol + strconv.Itoa(begxAxis) } if endrow > 1 && endrow >= rowIndex { end = endcol + strconv.Itoa(endxAxis) } } if column != -1 { if begyAxis >= column { beg = ToAlphaString(begyAxis+offset) + strconv.Itoa(endrow) } if endyAxis >= column { end = ToAlphaString(endyAxis+offset) + strconv.Itoa(endrow) } } xlsx.MergeCells.Cells[k].Ref = beg + ":" + end } } } // adjustMergeCells provides function to update merged cells when inserting or // deleting rows or columns. func (f *File) adjustMergeCells(xlsx *xlsxWorksheet, column, rowIndex, offset int) { f.adjustMergeCellsHelper(xlsx, column, rowIndex, offset) if xlsx.MergeCells != nil && offset < 0 { for k, v := range xlsx.MergeCells.Cells { beg := strings.Split(v.Ref, ":")[0] end := strings.Split(v.Ref, ":")[1] if beg == end { xlsx.MergeCells.Count += offset if len(xlsx.MergeCells.Cells) > 1 { xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:k], xlsx.MergeCells.Cells[k+1:]...) } else { xlsx.MergeCells = nil } } } } } // adjustAutoFilter provides function to update the auto filter when inserting // or deleting rows or columns. func (f *File) adjustAutoFilter(xlsx *xlsxWorksheet, column, rowIndex, offset int) { f.adjustAutoFilterHelper(xlsx, column, rowIndex, offset) if xlsx.AutoFilter != nil { beg := strings.Split(xlsx.AutoFilter.Ref, ":")[0] end := strings.Split(xlsx.AutoFilter.Ref, ":")[1] begcol := string(strings.Map(letterOnlyMapF, beg)) begrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, beg)) begxAxis := begrow + offset endcol := string(strings.Map(letterOnlyMapF, end)) endrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, end)) endxAxis := endrow + offset endyAxis := TitleToNumber(endcol) if rowIndex != -1 { if begrow >= rowIndex { beg = begcol + strconv.Itoa(begxAxis) } if endrow >= rowIndex { end = endcol + strconv.Itoa(endxAxis) } } if column != -1 && endyAxis >= column { end = ToAlphaString(endyAxis+offset) + strconv.Itoa(endrow) } xlsx.AutoFilter.Ref = beg + ":" + end } } // adjustAutoFilterHelper provides function to update the auto filter when // inserting or deleting rows or columns. func (f *File) adjustAutoFilterHelper(xlsx *xlsxWorksheet, column, rowIndex, offset int) { if xlsx.AutoFilter != nil { beg := strings.Split(xlsx.AutoFilter.Ref, ":")[0] end := strings.Split(xlsx.AutoFilter.Ref, ":")[1] begcol := string(strings.Map(letterOnlyMapF, beg)) begrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, beg)) begyAxis := TitleToNumber(begcol) endcol := string(strings.Map(letterOnlyMapF, end)) endyAxis := TitleToNumber(endcol) endrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, end)) if (begrow == rowIndex && offset < 0) || (column == begyAxis && column == endyAxis) { xlsx.AutoFilter = nil for i, r := range xlsx.SheetData.Row { if begrow < r.R && r.R <= endrow { xlsx.SheetData.Row[i].Hidden = false } } } } } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/file.go ================================================ package excelize import ( "archive/zip" "bytes" "fmt" "io" "os" ) // NewFile provides function to create new file by default template. For // example: // // xlsx := NewFile() // func NewFile() *File { file := make(map[string][]byte) file["_rels/.rels"] = []byte(XMLHeader + templateRels) file["docProps/app.xml"] = []byte(XMLHeader + templateDocpropsApp) file["docProps/core.xml"] = []byte(XMLHeader + templateDocpropsCore) file["xl/_rels/workbook.xml.rels"] = []byte(XMLHeader + templateWorkbookRels) file["xl/theme/theme1.xml"] = []byte(XMLHeader + templateTheme) file["xl/worksheets/sheet1.xml"] = []byte(XMLHeader + templateSheet) file["xl/styles.xml"] = []byte(XMLHeader + templateStyles) file["xl/workbook.xml"] = []byte(XMLHeader + templateWorkbook) file["[Content_Types].xml"] = []byte(XMLHeader + templateContentTypes) f := &File{ sheetMap: make(map[string]string), Sheet: make(map[string]*xlsxWorksheet), SheetCount: 1, XLSX: file, } f.ContentTypes = f.contentTypesReader() f.Styles = f.stylesReader() f.WorkBook = f.workbookReader() f.WorkBookRels = f.workbookRelsReader() f.Sheet["xl/worksheets/sheet1.xml"] = f.workSheetReader("Sheet1") f.sheetMap["Sheet1"] = "xl/worksheets/sheet1.xml" return f } // Save provides function to override the xlsx file with origin path. func (f *File) Save() error { if f.Path == "" { return fmt.Errorf("No path defined for file, consider File.WriteTo or File.Write") } return f.SaveAs(f.Path) } // SaveAs provides function to create or update to an xlsx file at the provided // path. func (f *File) SaveAs(name string) error { file, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666) if err != nil { return err } defer file.Close() return f.Write(file) } // Write provides function to write to an io.Writer. func (f *File) Write(w io.Writer) error { buf := new(bytes.Buffer) zw := zip.NewWriter(buf) f.contentTypesWriter() f.workbookWriter() f.workbookRelsWriter() f.worksheetWriter() f.styleSheetWriter() for path, content := range f.XLSX { fi, err := zw.Create(path) if err != nil { return err } _, err = fi.Write(content) if err != nil { return err } } err := zw.Close() if err != nil { return err } if _, err := buf.WriteTo(w); err != nil { return err } return nil } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/lib.go ================================================ package excelize import ( "archive/zip" "bytes" "encoding/gob" "io" "log" "math" "unicode" ) // ReadZipReader can be used to read an XLSX in memory without touching the // filesystem. func ReadZipReader(r *zip.Reader) (map[string][]byte, int, error) { fileList := make(map[string][]byte) worksheets := 0 for _, v := range r.File { fileList[v.Name] = readFile(v) if len(v.Name) > 18 { if v.Name[0:19] == "xl/worksheets/sheet" { worksheets++ } } } return fileList, worksheets, nil } // readXML provides function to read XML content as string. func (f *File) readXML(name string) []byte { if content, ok := f.XLSX[name]; ok { return content } return []byte{} } // saveFileList provides function to update given file content in file list of // XLSX. func (f *File) saveFileList(name string, content []byte) { newContent := make([]byte, 0, len(XMLHeader)+len(content)) newContent = append(newContent, []byte(XMLHeader)...) newContent = append(newContent, content...) f.XLSX[name] = newContent } // Read file content as string in a archive file. func readFile(file *zip.File) []byte { rc, err := file.Open() if err != nil { log.Fatal(err) } buff := bytes.NewBuffer(nil) _, _ = io.Copy(buff, rc) rc.Close() return buff.Bytes() } // ToAlphaString provides function to convert integer to Excel sheet column // title. For example convert 36 to column title AK: // // excelize.ToAlphaString(36) // func ToAlphaString(value int) string { if value < 0 { return "" } var ans string i := value + 1 for i > 0 { ans = string((i-1)%26+65) + ans i = (i - 1) / 26 } return ans } // TitleToNumber provides function to convert Excel sheet column title to int // (this function doesn't do value check currently). For example convert AK // and ak to column title 36: // // excelize.TitleToNumber("AK") // excelize.TitleToNumber("ak") // func TitleToNumber(s string) int { weight := 0.0 sum := 0 for i := len(s) - 1; i >= 0; i-- { ch := int(s[i]) if int(s[i]) >= int('a') && int(s[i]) <= int('z') { ch = int(s[i]) - 32 } sum = sum + (ch-int('A')+1)*int(math.Pow(26, weight)) weight++ } return sum - 1 } // letterOnlyMapF is used in conjunction with strings.Map to return only the // characters A-Z and a-z in a string. func letterOnlyMapF(rune rune) rune { switch { case 'A' <= rune && rune <= 'Z': return rune case 'a' <= rune && rune <= 'z': return rune - 32 } return -1 } // intOnlyMapF is used in conjunction with strings.Map to return only the // numeric portions of a string. func intOnlyMapF(rune rune) rune { if rune >= 48 && rune < 58 { return rune } return -1 } // deepCopy provides method to creates a deep copy of whatever is passed to it // and returns the copy in an interface. The returned value will need to be // asserted to the correct type. func deepCopy(dst, src interface{}) error { var buf bytes.Buffer if err := gob.NewEncoder(&buf).Encode(src); err != nil { return err } return gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dst) } // boolPtr returns a pointer to a bool with the given value. func boolPtr(b bool) *bool { return &b } // defaultTrue returns true if b is nil, or the pointed value. func defaultTrue(b *bool) bool { if b == nil { return true } return *b } // axisLowerOrEqualThan returns true if axis1 <= axis2 // axis1/axis2 can be either a column or a row axis, e.g. "A", "AAE", "42", "1", etc. // // For instance, the following comparisons are all true: // // "A" <= "B" // "A" <= "AA" // "B" <= "AA" // "BC" <= "ABCD" (in a XLSX sheet, the BC col comes before the ABCD col) // "1" <= "2" // "2" <= "11" (in a XLSX sheet, the row 2 comes before the row 11) // and so on func axisLowerOrEqualThan(axis1, axis2 string) bool { if len(axis1) < len(axis2) { return true } else if len(axis1) > len(axis2) { return false } else { return axis1 <= axis2 } } // getCellColRow returns the two parts of a cell identifier (its col and row) as strings // // For instance: // // "C220" => "C", "220" // "aaef42" => "aaef", "42" // "" => "", "" func getCellColRow(cell string) (col, row string) { for index, rune := range cell { if unicode.IsDigit(rune) { return cell[:index], cell[index:] } } return cell, "" } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/picture.go ================================================ package excelize import ( "bytes" "encoding/json" "encoding/xml" "errors" "image" "io/ioutil" "os" "path" "path/filepath" "strconv" "strings" ) // parseFormatPictureSet provides function to parse the format settings of the // picture with default value. func parseFormatPictureSet(formatSet string) (*formatPicture, error) { format := formatPicture{ FPrintsWithSheet: true, FLocksWithSheet: false, NoChangeAspect: false, OffsetX: 0, OffsetY: 0, XScale: 1.0, YScale: 1.0, } err := json.Unmarshal([]byte(formatSet), &format) return &format, err } // AddPicture provides the method to add picture in a sheet by given picture // format set (such as offset, scale, aspect ratio setting and print settings) // and file path. For example: // // package main // // import ( // "fmt" // _ "image/gif" // _ "image/jpeg" // _ "image/png" // // "github.com/360EntSecGroup-Skylar/excelize" // ) // // func main() { // xlsx := excelize.NewFile() // // Insert a picture. // err := xlsx.AddPicture("Sheet1", "A2", "./image1.jpg", "") // if err != nil { // fmt.Println(err) // } // // Insert a picture scaling in the cell with location hyperlink. // err = xlsx.AddPicture("Sheet1", "D2", "./image1.png", `{"x_scale": 0.5, "y_scale": 0.5, "hyperlink": "#Sheet2!D8", "hyperlink_type": "Location"}`) // if err != nil { // fmt.Println(err) // } // // Insert a picture offset in the cell with external hyperlink, printing and positioning support. // err = xlsx.AddPicture("Sheet1", "H2", "./image3.gif", `{"x_offset": 15, "y_offset": 10, "hyperlink": "https://github.com/360EntSecGroup-Skylar/excelize", "hyperlink_type": "External", "print_obj": true, "lock_aspect_ratio": false, "locked": false, "positioning": "oneCell"}`) // if err != nil { // fmt.Println(err) // } // err = xlsx.SaveAs("./Book1.xlsx") // if err != nil { // fmt.Println(err) // } // } // // LinkType defines two types of hyperlink "External" for web site or // "Location" for moving to one of cell in this workbook. When the // "hyperlink_type" is "Location", coordinates need to start with "#". // // Positioning defines two types of the position of a picture in an Excel // spreadsheet, "oneCell" (Move but don't size with cells) or "absolute" // (Don't move or size with cells). If you don't set this parameter, default // positioning is move and size with cells. func (f *File) AddPicture(sheet, cell, picture, format string) error { var err error var drawingHyperlinkRID int var hyperlinkType string // Check picture exists first. if _, err = os.Stat(picture); os.IsNotExist(err) { return err } ext, ok := supportImageTypes[path.Ext(picture)] if !ok { return errors.New("Unsupported image extension") } readFile, _ := os.Open(picture) image, _, _ := image.DecodeConfig(readFile) _, file := filepath.Split(picture) formatSet, err := parseFormatPictureSet(format) if err != nil { return err } // Read sheet data. xlsx := f.workSheetReader(sheet) // Add first picture for given sheet, create xl/drawings/ and xl/drawings/_rels/ folder. drawingID := f.countDrawings() + 1 pictureID := f.countMedia() + 1 drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml" drawingID, drawingXML = f.prepareDrawing(xlsx, drawingID, sheet, drawingXML) drawingRID := f.addDrawingRelationships(drawingID, SourceRelationshipImage, "../media/image"+strconv.Itoa(pictureID)+ext, hyperlinkType) // Add picture with hyperlink. if formatSet.Hyperlink != "" && formatSet.HyperlinkType != "" { if formatSet.HyperlinkType == "External" { hyperlinkType = formatSet.HyperlinkType } drawingHyperlinkRID = f.addDrawingRelationships(drawingID, SourceRelationshipHyperLink, formatSet.Hyperlink, hyperlinkType) } f.addDrawingPicture(sheet, drawingXML, cell, file, image.Width, image.Height, drawingRID, drawingHyperlinkRID, formatSet) f.addMedia(picture, ext) f.addContentTypePart(drawingID, "drawings") return err } // addSheetRelationships provides function to add // xl/worksheets/_rels/sheet%d.xml.rels by given worksheet name, relationship // type and target. func (f *File) addSheetRelationships(sheet, relType, target, targetMode string) int { name, ok := f.sheetMap[trimSheetName(sheet)] if !ok { name = strings.ToLower(sheet) + ".xml" } var rels = "xl/worksheets/_rels/" + strings.TrimPrefix(name, "xl/worksheets/") + ".rels" var sheetRels xlsxWorkbookRels var rID = 1 var ID bytes.Buffer ID.WriteString("rId") ID.WriteString(strconv.Itoa(rID)) _, ok = f.XLSX[rels] if ok { ID.Reset() _ = xml.Unmarshal([]byte(f.readXML(rels)), &sheetRels) rID = len(sheetRels.Relationships) + 1 ID.WriteString("rId") ID.WriteString(strconv.Itoa(rID)) } sheetRels.Relationships = append(sheetRels.Relationships, xlsxWorkbookRelation{ ID: ID.String(), Type: relType, Target: target, TargetMode: targetMode, }) output, _ := xml.Marshal(sheetRels) f.saveFileList(rels, output) return rID } // deleteSheetRelationships provides function to delete relationships in // xl/worksheets/_rels/sheet%d.xml.rels by given worksheet name and relationship // index. func (f *File) deleteSheetRelationships(sheet, rID string) { name, ok := f.sheetMap[trimSheetName(sheet)] if !ok { name = strings.ToLower(sheet) + ".xml" } var rels = "xl/worksheets/_rels/" + strings.TrimPrefix(name, "xl/worksheets/") + ".rels" var sheetRels xlsxWorkbookRels _ = xml.Unmarshal([]byte(f.readXML(rels)), &sheetRels) for k, v := range sheetRels.Relationships { if v.ID == rID { sheetRels.Relationships = append(sheetRels.Relationships[:k], sheetRels.Relationships[k+1:]...) } } output, _ := xml.Marshal(sheetRels) f.saveFileList(rels, output) } // addSheetLegacyDrawing provides function to add legacy drawing element to // xl/worksheets/sheet%d.xml by given worksheet name and relationship index. func (f *File) addSheetLegacyDrawing(sheet string, rID int) { xlsx := f.workSheetReader(sheet) xlsx.LegacyDrawing = &xlsxLegacyDrawing{ RID: "rId" + strconv.Itoa(rID), } } // addSheetDrawing provides function to add drawing element to // xl/worksheets/sheet%d.xml by given worksheet name and relationship index. func (f *File) addSheetDrawing(sheet string, rID int) { xlsx := f.workSheetReader(sheet) xlsx.Drawing = &xlsxDrawing{ RID: "rId" + strconv.Itoa(rID), } } // addSheetPicture provides function to add picture element to // xl/worksheets/sheet%d.xml by given worksheet name and relationship index. func (f *File) addSheetPicture(sheet string, rID int) { xlsx := f.workSheetReader(sheet) xlsx.Picture = &xlsxPicture{ RID: "rId" + strconv.Itoa(rID), } } // countDrawings provides function to get drawing files count storage in the // folder xl/drawings. func (f *File) countDrawings() int { count := 0 for k := range f.XLSX { if strings.Contains(k, "xl/drawings/drawing") { count++ } } return count } // addDrawingPicture provides function to add picture by given sheet, // drawingXML, cell, file name, width, height relationship index and format // sets. func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, height, rID, hyperlinkRID int, formatSet *formatPicture) { cell = strings.ToUpper(cell) fromCol := string(strings.Map(letterOnlyMapF, cell)) fromRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell)) row := fromRow - 1 col := TitleToNumber(fromCol) width = int(float64(width) * formatSet.XScale) height = int(float64(height) * formatSet.YScale) colStart, rowStart, _, _, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, formatSet.OffsetX, formatSet.OffsetY, width, height) content := xlsxWsDr{} content.A = NameSpaceDrawingML content.Xdr = NameSpaceDrawingMLSpreadSheet cNvPrID := f.drawingParser(drawingXML, &content) twoCellAnchor := xdrCellAnchor{} twoCellAnchor.EditAs = formatSet.Positioning from := xlsxFrom{} from.Col = colStart from.ColOff = formatSet.OffsetX * EMU from.Row = rowStart from.RowOff = formatSet.OffsetY * EMU to := xlsxTo{} to.Col = colEnd to.ColOff = x2 * EMU to.Row = rowEnd to.RowOff = y2 * EMU twoCellAnchor.From = &from twoCellAnchor.To = &to pic := xlsxPic{} pic.NvPicPr.CNvPicPr.PicLocks.NoChangeAspect = formatSet.NoChangeAspect pic.NvPicPr.CNvPr.ID = f.countCharts() + f.countMedia() + 1 pic.NvPicPr.CNvPr.Descr = file pic.NvPicPr.CNvPr.Name = "Picture " + strconv.Itoa(cNvPrID) if hyperlinkRID != 0 { pic.NvPicPr.CNvPr.HlinkClick = &xlsxHlinkClick{ R: SourceRelationship, RID: "rId" + strconv.Itoa(hyperlinkRID), } } pic.BlipFill.Blip.R = SourceRelationship pic.BlipFill.Blip.Embed = "rId" + strconv.Itoa(rID) pic.SpPr.PrstGeom.Prst = "rect" twoCellAnchor.Pic = &pic twoCellAnchor.ClientData = &xdrClientData{ FLocksWithSheet: formatSet.FLocksWithSheet, FPrintsWithSheet: formatSet.FPrintsWithSheet, } content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor) output, _ := xml.Marshal(content) f.saveFileList(drawingXML, output) } // addDrawingRelationships provides function to add image part relationships in // the file xl/drawings/_rels/drawing%d.xml.rels by given drawing index, // relationship type and target. func (f *File) addDrawingRelationships(index int, relType, target, targetMode string) int { var rels = "xl/drawings/_rels/drawing" + strconv.Itoa(index) + ".xml.rels" var drawingRels xlsxWorkbookRels var rID = 1 var ID bytes.Buffer ID.WriteString("rId") ID.WriteString(strconv.Itoa(rID)) _, ok := f.XLSX[rels] if ok { ID.Reset() _ = xml.Unmarshal([]byte(f.readXML(rels)), &drawingRels) rID = len(drawingRels.Relationships) + 1 ID.WriteString("rId") ID.WriteString(strconv.Itoa(rID)) } drawingRels.Relationships = append(drawingRels.Relationships, xlsxWorkbookRelation{ ID: ID.String(), Type: relType, Target: target, TargetMode: targetMode, }) output, _ := xml.Marshal(drawingRels) f.saveFileList(rels, output) return rID } // countMedia provides function to get media files count storage in the folder // xl/media/image. func (f *File) countMedia() int { count := 0 for k := range f.XLSX { if strings.Contains(k, "xl/media/image") { count++ } } return count } // addMedia provides function to add picture into folder xl/media/image by given // file name and extension name. func (f *File) addMedia(file, ext string) { count := f.countMedia() dat, _ := ioutil.ReadFile(file) media := "xl/media/image" + strconv.Itoa(count+1) + ext f.XLSX[media] = dat } // setContentTypePartImageExtensions provides function to set the content type // for relationship parts and the Main Document part. func (f *File) setContentTypePartImageExtensions() { var imageTypes = map[string]bool{"jpeg": false, "png": false, "gif": false} content := f.contentTypesReader() for _, v := range content.Defaults { _, ok := imageTypes[v.Extension] if ok { imageTypes[v.Extension] = true } } for k, v := range imageTypes { if !v { content.Defaults = append(content.Defaults, xlsxDefault{ Extension: k, ContentType: "image/" + k, }) } } } // setContentTypePartVMLExtensions provides function to set the content type // for relationship parts and the Main Document part. func (f *File) setContentTypePartVMLExtensions() { vml := false content := f.contentTypesReader() for _, v := range content.Defaults { if v.Extension == "vml" { vml = true } } if !vml { content.Defaults = append(content.Defaults, xlsxDefault{ Extension: "vml", ContentType: "application/vnd.openxmlformats-officedocument.vmlDrawing", }) } } // addContentTypePart provides function to add content type part relationships // in the file [Content_Types].xml by given index. func (f *File) addContentTypePart(index int, contentType string) { setContentType := map[string]func(){ "comments": f.setContentTypePartVMLExtensions, "drawings": f.setContentTypePartImageExtensions, } partNames := map[string]string{ "chart": "/xl/charts/chart" + strconv.Itoa(index) + ".xml", "comments": "/xl/comments" + strconv.Itoa(index) + ".xml", "drawings": "/xl/drawings/drawing" + strconv.Itoa(index) + ".xml", "table": "/xl/tables/table" + strconv.Itoa(index) + ".xml", } contentTypes := map[string]string{ "chart": "application/vnd.openxmlformats-officedocument.drawingml.chart+xml", "comments": "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml", "drawings": "application/vnd.openxmlformats-officedocument.drawing+xml", "table": "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml", } s, ok := setContentType[contentType] if ok { s() } content := f.contentTypesReader() for _, v := range content.Overrides { if v.PartName == partNames[contentType] { return } } content.Overrides = append(content.Overrides, xlsxOverride{ PartName: partNames[contentType], ContentType: contentTypes[contentType], }) } // getSheetRelationshipsTargetByID provides function to get Target attribute // value in xl/worksheets/_rels/sheet%d.xml.rels by given worksheet name and // relationship index. func (f *File) getSheetRelationshipsTargetByID(sheet, rID string) string { name, ok := f.sheetMap[trimSheetName(sheet)] if !ok { name = strings.ToLower(sheet) + ".xml" } var rels = "xl/worksheets/_rels/" + strings.TrimPrefix(name, "xl/worksheets/") + ".rels" var sheetRels xlsxWorkbookRels _ = xml.Unmarshal([]byte(f.readXML(rels)), &sheetRels) for _, v := range sheetRels.Relationships { if v.ID == rID { return v.Target } } return "" } // GetPicture provides function to get picture base name and raw content embed // in XLSX by given worksheet and cell name. This function returns the file name // in XLSX and file contents as []byte data types. For example: // // xlsx, err := excelize.OpenFile("./Book1.xlsx") // if err != nil { // fmt.Println(err) // return // } // file, raw := xlsx.GetPicture("Sheet1", "A2") // if file == "" { // return // } // err := ioutil.WriteFile(file, raw, 0644) // if err != nil { // fmt.Println(err) // } // func (f *File) GetPicture(sheet, cell string) (string, []byte) { xlsx := f.workSheetReader(sheet) if xlsx.Drawing == nil { return "", []byte{} } target := f.getSheetRelationshipsTargetByID(sheet, xlsx.Drawing.RID) drawingXML := strings.Replace(target, "..", "xl", -1) _, ok := f.XLSX[drawingXML] if !ok { return "", nil } decodeWsDr := decodeWsDr{} _ = xml.Unmarshal([]byte(f.readXML(drawingXML)), &decodeWsDr) cell = strings.ToUpper(cell) fromCol := string(strings.Map(letterOnlyMapF, cell)) fromRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell)) row := fromRow - 1 col := TitleToNumber(fromCol) drawingRelationships := strings.Replace(strings.Replace(target, "../drawings", "xl/drawings/_rels", -1), ".xml", ".xml.rels", -1) for _, anchor := range decodeWsDr.TwoCellAnchor { decodeTwoCellAnchor := decodeTwoCellAnchor{} _ = xml.Unmarshal([]byte(""+anchor.Content+""), &decodeTwoCellAnchor) if decodeTwoCellAnchor.From != nil && decodeTwoCellAnchor.Pic != nil { if decodeTwoCellAnchor.From.Col == col && decodeTwoCellAnchor.From.Row == row { xlsxWorkbookRelation := f.getDrawingRelationships(drawingRelationships, decodeTwoCellAnchor.Pic.BlipFill.Blip.Embed) _, ok := supportImageTypes[filepath.Ext(xlsxWorkbookRelation.Target)] if ok { return filepath.Base(xlsxWorkbookRelation.Target), []byte(f.XLSX[strings.Replace(xlsxWorkbookRelation.Target, "..", "xl", -1)]) } } } } return "", []byte{} } // getDrawingRelationships provides function to get drawing relationships from // xl/drawings/_rels/drawing%s.xml.rels by given file name and relationship ID. func (f *File) getDrawingRelationships(rels, rID string) *xlsxWorkbookRelation { _, ok := f.XLSX[rels] if !ok { return nil } var drawingRels xlsxWorkbookRels _ = xml.Unmarshal([]byte(f.readXML(rels)), &drawingRels) for _, v := range drawingRels.Relationships { if v.ID == rID { return &v } } return nil } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/rows.go ================================================ package excelize import ( "bytes" "encoding/xml" "fmt" "io" "math" "strconv" "strings" ) // GetRows return all the rows in a sheet by given worksheet name (case // sensitive). For example: // // for _, row := range xlsx.GetRows("Sheet1") { // for _, colCell := range row { // fmt.Print(colCell, "\t") // } // fmt.Println() // } // func (f *File) GetRows(sheet string) [][]string { xlsx := f.workSheetReader(sheet) rows := [][]string{} name, ok := f.sheetMap[trimSheetName(sheet)] if !ok { return rows } if xlsx != nil { output, _ := xml.Marshal(f.Sheet[name]) f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpaceBytes(output)) } xml.NewDecoder(bytes.NewReader(f.readXML(name))) d := f.sharedStringsReader() var inElement string var r xlsxRow var row []string tr, tc := f.getTotalRowsCols(name) for i := 0; i < tr; i++ { row = []string{} for j := 0; j <= tc; j++ { row = append(row, "") } rows = append(rows, row) } decoder := xml.NewDecoder(bytes.NewReader(f.readXML(name))) for { token, _ := decoder.Token() if token == nil { break } switch startElement := token.(type) { case xml.StartElement: inElement = startElement.Name.Local if inElement == "row" { r = xlsxRow{} _ = decoder.DecodeElement(&r, &startElement) cr := r.R - 1 for _, colCell := range r.C { c := TitleToNumber(strings.Map(letterOnlyMapF, colCell.R)) val, _ := colCell.getValueFrom(f, d) rows[cr][c] = val } } default: } } return rows } // Rows defines an iterator to a sheet type Rows struct { decoder *xml.Decoder token xml.Token err error f *File } // Next will return true if find the next row element. func (rows *Rows) Next() bool { for { rows.token, rows.err = rows.decoder.Token() if rows.err == io.EOF { rows.err = nil } if rows.token == nil { return false } switch startElement := rows.token.(type) { case xml.StartElement: inElement := startElement.Name.Local if inElement == "row" { return true } } } } // Error will return the error when the find next row element func (rows *Rows) Error() error { return rows.err } // Columns return the current row's column values func (rows *Rows) Columns() []string { if rows.token == nil { return []string{} } startElement := rows.token.(xml.StartElement) r := xlsxRow{} _ = rows.decoder.DecodeElement(&r, &startElement) d := rows.f.sharedStringsReader() row := make([]string, len(r.C)) for _, colCell := range r.C { c := TitleToNumber(strings.Map(letterOnlyMapF, colCell.R)) val, _ := colCell.getValueFrom(rows.f, d) row[c] = val } return row } // ErrSheetNotExist defines an error of sheet is not exist type ErrSheetNotExist struct { SheetName string } func (err ErrSheetNotExist) Error() string { return fmt.Sprintf("Sheet %s is not exist", string(err.SheetName)) } // Rows return a rows iterator. For example: // // rows, err := xlsx.GetRows("Sheet1") // for rows.Next() { // for _, colCell := range rows.Columns() { // fmt.Print(colCell, "\t") // } // fmt.Println() // } // func (f *File) Rows(sheet string) (*Rows, error) { xlsx := f.workSheetReader(sheet) name, ok := f.sheetMap[trimSheetName(sheet)] if !ok { return nil, ErrSheetNotExist{sheet} } if xlsx != nil { output, _ := xml.Marshal(f.Sheet[name]) f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpaceBytes(output)) } return &Rows{ f: f, decoder: xml.NewDecoder(bytes.NewReader(f.readXML(name))), }, nil } // getTotalRowsCols provides a function to get total columns and rows in a // worksheet. func (f *File) getTotalRowsCols(name string) (int, int) { decoder := xml.NewDecoder(bytes.NewReader(f.readXML(name))) var inElement string var r xlsxRow var tr, tc int for { token, _ := decoder.Token() if token == nil { break } switch startElement := token.(type) { case xml.StartElement: inElement = startElement.Name.Local if inElement == "row" { r = xlsxRow{} _ = decoder.DecodeElement(&r, &startElement) tr = r.R for _, colCell := range r.C { col := TitleToNumber(strings.Map(letterOnlyMapF, colCell.R)) if col > tc { tc = col } } } default: } } return tr, tc } // SetRowHeight provides a function to set the height of a single row. For // example, set the height of the first row in Sheet1: // // xlsx.SetRowHeight("Sheet1", 1, 50) // func (f *File) SetRowHeight(sheet string, row int, height float64) { xlsx := f.workSheetReader(sheet) cells := 0 rowIdx := row - 1 completeRow(xlsx, row, cells) xlsx.SheetData.Row[rowIdx].Ht = height xlsx.SheetData.Row[rowIdx].CustomHeight = true } // getRowHeight provides function to get row height in pixels by given sheet // name and row index. func (f *File) getRowHeight(sheet string, row int) int { xlsx := f.workSheetReader(sheet) for _, v := range xlsx.SheetData.Row { if v.R == row+1 && v.Ht != 0 { return int(convertRowHeightToPixels(v.Ht)) } } // Optimisation for when the row heights haven't changed. return int(defaultRowHeightPixels) } // GetRowHeight provides function to get row height by given worksheet name // and row index. For example, get the height of the first row in Sheet1: // // xlsx.GetRowHeight("Sheet1", 1) // func (f *File) GetRowHeight(sheet string, row int) float64 { xlsx := f.workSheetReader(sheet) for _, v := range xlsx.SheetData.Row { if v.R == row && v.Ht != 0 { return v.Ht } } // Optimisation for when the row heights haven't changed. return defaultRowHeightPixels } // sharedStringsReader provides function to get the pointer to the structure // after deserialization of xl/sharedStrings.xml. func (f *File) sharedStringsReader() *xlsxSST { if f.SharedStrings == nil { var sharedStrings xlsxSST ss := f.readXML("xl/sharedStrings.xml") if len(ss) == 0 { ss = f.readXML("xl/SharedStrings.xml") } _ = xml.Unmarshal([]byte(ss), &sharedStrings) f.SharedStrings = &sharedStrings } return f.SharedStrings } // getValueFrom return a value from a column/row cell, this function is inteded // to be used with for range on rows an argument with the xlsx opened file. func (xlsx *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) { switch xlsx.T { case "s": xlsxSI := 0 xlsxSI, _ = strconv.Atoi(xlsx.V) if len(d.SI[xlsxSI].R) > 0 { value := "" for _, v := range d.SI[xlsxSI].R { value += v.T } return value, nil } return f.formattedValue(xlsx.S, d.SI[xlsxSI].T), nil case "str": return f.formattedValue(xlsx.S, xlsx.V), nil case "inlineStr": return f.formattedValue(xlsx.S, xlsx.IS.T), nil default: return f.formattedValue(xlsx.S, xlsx.V), nil } } // SetRowVisible provides a function to set visible of a single row by given // worksheet name and row index. For example, hide row 2 in Sheet1: // // xlsx.SetRowVisible("Sheet1", 2, false) // func (f *File) SetRowVisible(sheet string, rowIndex int, visible bool) { xlsx := f.workSheetReader(sheet) rows := rowIndex + 1 cells := 0 completeRow(xlsx, rows, cells) if visible { xlsx.SheetData.Row[rowIndex].Hidden = false return } xlsx.SheetData.Row[rowIndex].Hidden = true } // GetRowVisible provides a function to get visible of a single row by given // worksheet name and row index. For example, get visible state of row 2 in // Sheet1: // // xlsx.GetRowVisible("Sheet1", 2) // func (f *File) GetRowVisible(sheet string, rowIndex int) bool { xlsx := f.workSheetReader(sheet) rows := rowIndex + 1 cells := 0 completeRow(xlsx, rows, cells) return !xlsx.SheetData.Row[rowIndex].Hidden } // SetRowOutlineLevel provides a function to set outline level number of a // single row by given worksheet name and row index. For example, outline row // 2 in Sheet1 to level 1: // // xlsx.SetRowOutlineLevel("Sheet1", 2, 1) // func (f *File) SetRowOutlineLevel(sheet string, rowIndex int, level uint8) { xlsx := f.workSheetReader(sheet) rows := rowIndex + 1 cells := 0 completeRow(xlsx, rows, cells) xlsx.SheetData.Row[rowIndex].OutlineLevel = level } // GetRowOutlineLevel provides a function to get outline level number of a single row by given // worksheet name and row index. For example, get outline number of row 2 in // Sheet1: // // xlsx.GetRowOutlineLevel("Sheet1", 2) // func (f *File) GetRowOutlineLevel(sheet string, rowIndex int) uint8 { xlsx := f.workSheetReader(sheet) rows := rowIndex + 1 cells := 0 completeRow(xlsx, rows, cells) return xlsx.SheetData.Row[rowIndex].OutlineLevel } // RemoveRow provides function to remove single row by given worksheet name and // row index. For example, remove row 3 in Sheet1: // // xlsx.RemoveRow("Sheet1", 2) // func (f *File) RemoveRow(sheet string, row int) { if row < 0 { return } xlsx := f.workSheetReader(sheet) row++ for i, r := range xlsx.SheetData.Row { if r.R == row { xlsx.SheetData.Row = append(xlsx.SheetData.Row[:i], xlsx.SheetData.Row[i+1:]...) f.adjustHelper(sheet, -1, row, -1) return } } } // InsertRow provides function to insert a new row before given row index. For // example, create a new row before row 3 in Sheet1: // // xlsx.InsertRow("Sheet1", 2) // func (f *File) InsertRow(sheet string, row int) { if row < 0 { return } row++ f.adjustHelper(sheet, -1, row, 1) } // checkRow provides function to check and fill each column element for all rows // and make that is continuous in a worksheet of XML. For example: // // // // // // // // // in this case, we should to change it to // // // // // // // // // // // // Noteice: this method could be very slow for large spreadsheets (more than // 3000 rows one sheet). func checkRow(xlsx *xlsxWorksheet) { buffer := bytes.Buffer{} for k := range xlsx.SheetData.Row { lenCol := len(xlsx.SheetData.Row[k].C) if lenCol > 0 { endR := string(strings.Map(letterOnlyMapF, xlsx.SheetData.Row[k].C[lenCol-1].R)) endRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, xlsx.SheetData.Row[k].C[lenCol-1].R)) endCol := TitleToNumber(endR) + 1 if lenCol < endCol { oldRow := xlsx.SheetData.Row[k].C xlsx.SheetData.Row[k].C = xlsx.SheetData.Row[k].C[:0] tmp := []xlsxC{} for i := 0; i < endCol; i++ { buffer.WriteString(ToAlphaString(i)) buffer.WriteString(strconv.Itoa(endRow)) tmp = append(tmp, xlsxC{ R: buffer.String(), }) buffer.Reset() } xlsx.SheetData.Row[k].C = tmp for _, y := range oldRow { colAxis := TitleToNumber(string(strings.Map(letterOnlyMapF, y.R))) xlsx.SheetData.Row[k].C[colAxis] = y } } } } } // completeRow provides function to check and fill each column element for a // single row and make that is continuous in a worksheet of XML by given row // index and axis. func completeRow(xlsx *xlsxWorksheet, row, cell int) { currentRows := len(xlsx.SheetData.Row) if currentRows > 1 { lastRow := xlsx.SheetData.Row[currentRows-1].R if lastRow >= row { row = lastRow } } for i := currentRows; i < row; i++ { xlsx.SheetData.Row = append(xlsx.SheetData.Row, xlsxRow{ R: i + 1, }) } buffer := bytes.Buffer{} for ii := currentRows; ii < row; ii++ { start := len(xlsx.SheetData.Row[ii].C) if start == 0 { for iii := start; iii < cell; iii++ { buffer.WriteString(ToAlphaString(iii)) buffer.WriteString(strconv.Itoa(ii + 1)) xlsx.SheetData.Row[ii].C = append(xlsx.SheetData.Row[ii].C, xlsxC{ R: buffer.String(), }) buffer.Reset() } } } } // convertRowHeightToPixels provides function to convert the height of a cell // from user's units to pixels. If the height hasn't been set by the user we use // the default value. If the row is hidden it has a value of zero. func convertRowHeightToPixels(height float64) float64 { var pixels float64 if height == 0 { return pixels } pixels = math.Ceil(4.0 / 3.0 * height) return pixels } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/shape.go ================================================ package excelize import ( "encoding/json" "encoding/xml" "strconv" "strings" ) // parseFormatShapeSet provides function to parse the format settings of the // shape with default value. func parseFormatShapeSet(formatSet string) (*formatShape, error) { format := formatShape{ Width: 160, Height: 160, Format: formatPicture{ FPrintsWithSheet: true, FLocksWithSheet: false, NoChangeAspect: false, OffsetX: 0, OffsetY: 0, XScale: 1.0, YScale: 1.0, }, } err := json.Unmarshal([]byte(formatSet), &format) return &format, err } // AddShape provides the method to add shape in a sheet by given worksheet // index, shape format set (such as offset, scale, aspect ratio setting and // print settings) and properties set. For example, add text box (rect shape) in // Sheet1: // // xlsx.AddShape("Sheet1", "G6", `{"type":"rect","color":{"line":"#4286F4","fill":"#8eb9ff"},"paragraph":[{"text":"Rectangle Shape","font":{"bold":true,"italic":true,"family":"Berlin Sans FB Demi","size":36,"color":"#777777","underline":"sng"}}],"width":180,"height": 90}`) // // The following shows the type of shape supported by excelize: // // accentBorderCallout1 (Callout 1 with Border and Accent Shape) // accentBorderCallout2 (Callout 2 with Border and Accent Shape) // accentBorderCallout3 (Callout 3 with Border and Accent Shape) // accentCallout1 (Callout 1 Shape) // accentCallout2 (Callout 2 Shape) // accentCallout3 (Callout 3 Shape) // actionButtonBackPrevious (Back or Previous Button Shape) // actionButtonBeginning (Beginning Button Shape) // actionButtonBlank (Blank Button Shape) // actionButtonDocument (Document Button Shape) // actionButtonEnd (End Button Shape) // actionButtonForwardNext (Forward or Next Button Shape) // actionButtonHelp (Help Button Shape) // actionButtonHome (Home Button Shape) // actionButtonInformation (Information Button Shape) // actionButtonMovie (Movie Button Shape) // actionButtonReturn (Return Button Shape) // actionButtonSound (Sound Button Shape) // arc (Curved Arc Shape) // bentArrow (Bent Arrow Shape) // bentConnector2 (Bent Connector 2 Shape) // bentConnector3 (Bent Connector 3 Shape) // bentConnector4 (Bent Connector 4 Shape) // bentConnector5 (Bent Connector 5 Shape) // bentUpArrow (Bent Up Arrow Shape) // bevel (Bevel Shape) // blockArc (Block Arc Shape) // borderCallout1 (Callout 1 with Border Shape) // borderCallout2 (Callout 2 with Border Shape) // borderCallout3 (Callout 3 with Border Shape) // bracePair (Brace Pair Shape) // bracketPair (Bracket Pair Shape) // callout1 (Callout 1 Shape) // callout2 (Callout 2 Shape) // callout3 (Callout 3 Shape) // can (Can Shape) // chartPlus (Chart Plus Shape) // chartStar (Chart Star Shape) // chartX (Chart X Shape) // chevron (Chevron Shape) // chord (Chord Shape) // circularArrow (Circular Arrow Shape) // cloud (Cloud Shape) // cloudCallout (Callout Cloud Shape) // corner (Corner Shape) // cornerTabs (Corner Tabs Shape) // cube (Cube Shape) // curvedConnector2 (Curved Connector 2 Shape) // curvedConnector3 (Curved Connector 3 Shape) // curvedConnector4 (Curved Connector 4 Shape) // curvedConnector5 (Curved Connector 5 Shape) // curvedDownArrow (Curved Down Arrow Shape) // curvedLeftArrow (Curved Left Arrow Shape) // curvedRightArrow (Curved Right Arrow Shape) // curvedUpArrow (Curved Up Arrow Shape) // decagon (Decagon Shape) // diagStripe (Diagonal Stripe Shape) // diamond (Diamond Shape) // dodecagon (Dodecagon Shape) // donut (Donut Shape) // doubleWave (Double Wave Shape) // downArrow (Down Arrow Shape) // downArrowCallout (Callout Down Arrow Shape) // ellipse (Ellipse Shape) // ellipseRibbon (Ellipse Ribbon Shape) // ellipseRibbon2 (Ellipse Ribbon 2 Shape) // flowChartAlternateProcess (Alternate Process Flow Shape) // flowChartCollate (Collate Flow Shape) // flowChartConnector (Connector Flow Shape) // flowChartDecision (Decision Flow Shape) // flowChartDelay (Delay Flow Shape) // flowChartDisplay (Display Flow Shape) // flowChartDocument (Document Flow Shape) // flowChartExtract (Extract Flow Shape) // flowChartInputOutput (Input Output Flow Shape) // flowChartInternalStorage (Internal Storage Flow Shape) // flowChartMagneticDisk (Magnetic Disk Flow Shape) // flowChartMagneticDrum (Magnetic Drum Flow Shape) // flowChartMagneticTape (Magnetic Tape Flow Shape) // flowChartManualInput (Manual Input Flow Shape) // flowChartManualOperation (Manual Operation Flow Shape) // flowChartMerge (Merge Flow Shape) // flowChartMultidocument (Multi-Document Flow Shape) // flowChartOfflineStorage (Offline Storage Flow Shape) // flowChartOffpageConnector (Off-Page Connector Flow Shape) // flowChartOnlineStorage (Online Storage Flow Shape) // flowChartOr (Or Flow Shape) // flowChartPredefinedProcess (Predefined Process Flow Shape) // flowChartPreparation (Preparation Flow Shape) // flowChartProcess (Process Flow Shape) // flowChartPunchedCard (Punched Card Flow Shape) // flowChartPunchedTape (Punched Tape Flow Shape) // flowChartSort (Sort Flow Shape) // flowChartSummingJunction (Summing Junction Flow Shape) // flowChartTerminator (Terminator Flow Shape) // foldedCorner (Folded Corner Shape) // frame (Frame Shape) // funnel (Funnel Shape) // gear6 (Gear 6 Shape) // gear9 (Gear 9 Shape) // halfFrame (Half Frame Shape) // heart (Heart Shape) // heptagon (Heptagon Shape) // hexagon (Hexagon Shape) // homePlate (Home Plate Shape) // horizontalScroll (Horizontal Scroll Shape) // irregularSeal1 (Irregular Seal 1 Shape) // irregularSeal2 (Irregular Seal 2 Shape) // leftArrow (Left Arrow Shape) // leftArrowCallout (Callout Left Arrow Shape) // leftBrace (Left Brace Shape) // leftBracket (Left Bracket Shape) // leftCircularArrow (Left Circular Arrow Shape) // leftRightArrow (Left Right Arrow Shape) // leftRightArrowCallout (Callout Left Right Arrow Shape) // leftRightCircularArrow (Left Right Circular Arrow Shape) // leftRightRibbon (Left Right Ribbon Shape) // leftRightUpArrow (Left Right Up Arrow Shape) // leftUpArrow (Left Up Arrow Shape) // lightningBolt (Lightning Bolt Shape) // line (Line Shape) // lineInv (Line Inverse Shape) // mathDivide (Divide Math Shape) // mathEqual (Equal Math Shape) // mathMinus (Minus Math Shape) // mathMultiply (Multiply Math Shape) // mathNotEqual (Not Equal Math Shape) // mathPlus (Plus Math Shape) // moon (Moon Shape) // nonIsoscelesTrapezoid (Non-Isosceles Trapezoid Shape) // noSmoking (No Smoking Shape) // notchedRightArrow (Notched Right Arrow Shape) // octagon (Octagon Shape) // parallelogram (Parallelogram Shape) // pentagon (Pentagon Shape) // pie (Pie Shape) // pieWedge (Pie Wedge Shape) // plaque (Plaque Shape) // plaqueTabs (Plaque Tabs Shape) // plus (Plus Shape) // quadArrow (Quad-Arrow Shape) // quadArrowCallout (Callout Quad-Arrow Shape) // rect (Rectangle Shape) // ribbon (Ribbon Shape) // ribbon2 (Ribbon 2 Shape) // rightArrow (Right Arrow Shape) // rightArrowCallout (Callout Right Arrow Shape) // rightBrace (Right Brace Shape) // rightBracket (Right Bracket Shape) // round1Rect (One Round Corner Rectangle Shape) // round2DiagRect (Two Diagonal Round Corner Rectangle Shape) // round2SameRect (Two Same-side Round Corner Rectangle Shape) // roundRect (Round Corner Rectangle Shape) // rtTriangle (Right Triangle Shape) // smileyFace (Smiley Face Shape) // snip1Rect (One Snip Corner Rectangle Shape) // snip2DiagRect (Two Diagonal Snip Corner Rectangle Shape) // snip2SameRect (Two Same-side Snip Corner Rectangle Shape) // snipRoundRect (One Snip One Round Corner Rectangle Shape) // squareTabs (Square Tabs Shape) // star10 (Ten Pointed Star Shape) // star12 (Twelve Pointed Star Shape) // star16 (Sixteen Pointed Star Shape) // star24 (Twenty Four Pointed Star Shape) // star32 (Thirty Two Pointed Star Shape) // star4 (Four Pointed Star Shape) // star5 (Five Pointed Star Shape) // star6 (Six Pointed Star Shape) // star7 (Seven Pointed Star Shape) // star8 (Eight Pointed Star Shape) // straightConnector1 (Straight Connector 1 Shape) // stripedRightArrow (Striped Right Arrow Shape) // sun (Sun Shape) // swooshArrow (Swoosh Arrow Shape) // teardrop (Teardrop Shape) // trapezoid (Trapezoid Shape) // triangle (Triangle Shape) // upArrow (Up Arrow Shape) // upArrowCallout (Callout Up Arrow Shape) // upDownArrow (Up Down Arrow Shape) // upDownArrowCallout (Callout Up Down Arrow Shape) // uturnArrow (U-Turn Arrow Shape) // verticalScroll (Vertical Scroll Shape) // wave (Wave Shape) // wedgeEllipseCallout (Callout Wedge Ellipse Shape) // wedgeRectCallout (Callout Wedge Rectangle Shape) // wedgeRoundRectCallout (Callout Wedge Round Rectangle Shape) // // The following shows the type of text underline supported by excelize: // // none // words // sng // dbl // heavy // dotted // dottedHeavy // dash // dashHeavy // dashLong // dashLongHeavy // dotDash // dotDashHeavy // dotDotDash // dotDotDashHeavy // wavy // wavyHeavy // wavyDbl // func (f *File) AddShape(sheet, cell, format string) error { formatSet, err := parseFormatShapeSet(format) if err != nil { return err } // Read sheet data. xlsx := f.workSheetReader(sheet) // Add first shape for given sheet, create xl/drawings/ and xl/drawings/_rels/ folder. drawingID := f.countDrawings() + 1 drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml" sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml" if xlsx.Drawing != nil { // The worksheet already has a shape or chart relationships, use the relationships drawing ../drawings/drawing%d.xml. sheetRelationshipsDrawingXML = f.getSheetRelationshipsTargetByID(sheet, xlsx.Drawing.RID) drawingID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingXML, "../drawings/drawing"), ".xml")) drawingXML = strings.Replace(sheetRelationshipsDrawingXML, "..", "xl", -1) } else { // Add first shape for given sheet. rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "") f.addSheetDrawing(sheet, rID) } f.addDrawingShape(sheet, drawingXML, cell, formatSet) f.addContentTypePart(drawingID, "drawings") return err } // addDrawingShape provides function to add preset geometry by given sheet, // drawingXMLand format sets. func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *formatShape) { textUnderlineType := map[string]bool{"none": true, "words": true, "sng": true, "dbl": true, "heavy": true, "dotted": true, "dottedHeavy": true, "dash": true, "dashHeavy": true, "dashLong": true, "dashLongHeavy": true, "dotDash": true, "dotDashHeavy": true, "dotDotDash": true, "dotDotDashHeavy": true, "wavy": true, "wavyHeavy": true, "wavyDbl": true} cell = strings.ToUpper(cell) fromCol := string(strings.Map(letterOnlyMapF, cell)) fromRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell)) row := fromRow - 1 col := TitleToNumber(fromCol) width := int(float64(formatSet.Width) * formatSet.Format.XScale) height := int(float64(formatSet.Height) * formatSet.Format.YScale) colStart, rowStart, _, _, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, formatSet.Format.OffsetX, formatSet.Format.OffsetY, width, height) content := xlsxWsDr{} content.A = NameSpaceDrawingML content.Xdr = NameSpaceDrawingMLSpreadSheet cNvPrID := f.drawingParser(drawingXML, &content) twoCellAnchor := xdrCellAnchor{} twoCellAnchor.EditAs = formatSet.Format.Positioning from := xlsxFrom{} from.Col = colStart from.ColOff = formatSet.Format.OffsetX * EMU from.Row = rowStart from.RowOff = formatSet.Format.OffsetY * EMU to := xlsxTo{} to.Col = colEnd to.ColOff = x2 * EMU to.Row = rowEnd to.RowOff = y2 * EMU twoCellAnchor.From = &from twoCellAnchor.To = &to shape := xdrSp{ NvSpPr: &xdrNvSpPr{ CNvPr: &xlsxCNvPr{ ID: cNvPrID, Name: "Shape " + strconv.Itoa(cNvPrID), }, CNvSpPr: &xdrCNvSpPr{ TxBox: true, }, }, SpPr: &xlsxSpPr{ PrstGeom: xlsxPrstGeom{ Prst: formatSet.Type, }, }, Style: &xdrStyle{ LnRef: setShapeRef(formatSet.Color.Line, 2), FillRef: setShapeRef(formatSet.Color.Fill, 1), EffectRef: setShapeRef(formatSet.Color.Effect, 0), FontRef: &aFontRef{ Idx: "minor", SchemeClr: &attrValString{ Val: "tx1", }, }, }, TxBody: &xdrTxBody{ BodyPr: &aBodyPr{ VertOverflow: "clip", HorzOverflow: "clip", Wrap: "none", RtlCol: false, Anchor: "t", }, }, } if len(formatSet.Paragraph) < 1 { formatSet.Paragraph = []formatShapeParagraph{ { Font: formatFont{ Bold: false, Italic: false, Underline: "none", Family: "Calibri", Size: 11, Color: "#000000", }, Text: " ", }, } } for _, p := range formatSet.Paragraph { u := p.Font.Underline _, ok := textUnderlineType[u] if !ok { u = "none" } text := p.Text if text == "" { text = " " } paragraph := &aP{ R: &aR{ RPr: aRPr{ I: p.Font.Italic, B: p.Font.Bold, Lang: "en-US", AltLang: "en-US", U: u, Sz: p.Font.Size * 100, Latin: &aLatin{Typeface: p.Font.Family}, SolidFill: &aSolidFill{ SrgbClr: &attrValString{ Val: strings.Replace(strings.ToUpper(p.Font.Color), "#", "", -1), }, }, }, T: text, }, EndParaRPr: &aEndParaRPr{ Lang: "en-US", }, } shape.TxBody.P = append(shape.TxBody.P, paragraph) } twoCellAnchor.Sp = &shape twoCellAnchor.ClientData = &xdrClientData{ FLocksWithSheet: formatSet.Format.FLocksWithSheet, FPrintsWithSheet: formatSet.Format.FPrintsWithSheet, } content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor) output, _ := xml.Marshal(content) f.saveFileList(drawingXML, output) } // setShapeRef provides function to set color with hex model by given actual // color value. func setShapeRef(color string, i int) *aRef { if color == "" { return &aRef{ Idx: 0, ScrgbClr: &aScrgbClr{ R: 0, G: 0, B: 0, }, } } return &aRef{ Idx: i, SrgbClr: &attrValString{ Val: strings.Replace(strings.ToUpper(color), "#", "", -1), }, } } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/sheet.go ================================================ package excelize import ( "bytes" "encoding/json" "encoding/xml" "errors" "os" "path" "strconv" "strings" "unicode/utf8" ) // NewSheet provides function to create a new sheet by given worksheet name, // when creating a new XLSX file, the default sheet will be create, when you // create a new file. func (f *File) NewSheet(name string) int { // Check if the worksheet already exists if f.GetSheetIndex(name) != 0 { return f.SheetCount } f.SheetCount++ // Update docProps/app.xml f.setAppXML() // Update [Content_Types].xml f.setContentTypes(f.SheetCount) // Create new sheet /xl/worksheets/sheet%d.xml f.setSheet(f.SheetCount, name) // Update xl/_rels/workbook.xml.rels rID := f.addXlsxWorkbookRels(f.SheetCount) // Update xl/workbook.xml f.setWorkbook(name, rID) return f.SheetCount } // contentTypesReader provides function to get the pointer to the // [Content_Types].xml structure after deserialization. func (f *File) contentTypesReader() *xlsxTypes { if f.ContentTypes == nil { var content xlsxTypes _ = xml.Unmarshal([]byte(f.readXML("[Content_Types].xml")), &content) f.ContentTypes = &content } return f.ContentTypes } // contentTypesWriter provides function to save [Content_Types].xml after // serialize structure. func (f *File) contentTypesWriter() { if f.ContentTypes != nil { output, _ := xml.Marshal(f.ContentTypes) f.saveFileList("[Content_Types].xml", output) } } // workbookReader provides function to get the pointer to the xl/workbook.xml // structure after deserialization. func (f *File) workbookReader() *xlsxWorkbook { if f.WorkBook == nil { var content xlsxWorkbook _ = xml.Unmarshal([]byte(f.readXML("xl/workbook.xml")), &content) f.WorkBook = &content } return f.WorkBook } // workbookWriter provides function to save xl/workbook.xml after serialize // structure. func (f *File) workbookWriter() { if f.WorkBook != nil { output, _ := xml.Marshal(f.WorkBook) f.saveFileList("xl/workbook.xml", replaceRelationshipsNameSpaceBytes(output)) } } // worksheetWriter provides function to save xl/worksheets/sheet%d.xml after // serialize structure. func (f *File) worksheetWriter() { for path, sheet := range f.Sheet { if sheet != nil { for k, v := range sheet.SheetData.Row { f.Sheet[path].SheetData.Row[k].C = trimCell(v.C) } output, _ := xml.Marshal(sheet) f.saveFileList(path, replaceWorkSheetsRelationshipsNameSpaceBytes(output)) ok := f.checked[path] if ok { f.checked[path] = false } } } } // trimCell provides function to trim blank cells which created by completeCol. func trimCell(column []xlsxC) []xlsxC { col := make([]xlsxC, len(column)) i := 0 for _, c := range column { if c.S != 0 || c.V != "" || c.F != nil || c.T != "" { col[i] = c i++ } } return col[0:i] } // Read and update property of contents type of XLSX. func (f *File) setContentTypes(index int) { content := f.contentTypesReader() content.Overrides = append(content.Overrides, xlsxOverride{ PartName: "/xl/worksheets/sheet" + strconv.Itoa(index) + ".xml", ContentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml", }) } // Update sheet property by given index. func (f *File) setSheet(index int, name string) { var xlsx xlsxWorksheet xlsx.Dimension.Ref = "A1" xlsx.SheetViews.SheetView = append(xlsx.SheetViews.SheetView, xlsxSheetView{ WorkbookViewID: 0, }) path := "xl/worksheets/sheet" + strconv.Itoa(index) + ".xml" f.sheetMap[trimSheetName(name)] = path f.Sheet[path] = &xlsx } // setWorkbook update workbook property of XLSX. Maximum 31 characters are // allowed in sheet title. func (f *File) setWorkbook(name string, rid int) { content := f.workbookReader() content.Sheets.Sheet = append(content.Sheets.Sheet, xlsxSheet{ Name: trimSheetName(name), SheetID: strconv.Itoa(rid), ID: "rId" + strconv.Itoa(rid), }) } // workbookRelsReader provides function to read and unmarshal workbook // relationships of XLSX file. func (f *File) workbookRelsReader() *xlsxWorkbookRels { if f.WorkBookRels == nil { var content xlsxWorkbookRels _ = xml.Unmarshal([]byte(f.readXML("xl/_rels/workbook.xml.rels")), &content) f.WorkBookRels = &content } return f.WorkBookRels } // workbookRelsWriter provides function to save xl/_rels/workbook.xml.rels after // serialize structure. func (f *File) workbookRelsWriter() { if f.WorkBookRels != nil { output, _ := xml.Marshal(f.WorkBookRels) f.saveFileList("xl/_rels/workbook.xml.rels", output) } } // addXlsxWorkbookRels update workbook relationships property of XLSX. func (f *File) addXlsxWorkbookRels(sheet int) int { content := f.workbookRelsReader() rID := 0 for _, v := range content.Relationships { t, _ := strconv.Atoi(strings.TrimPrefix(v.ID, "rId")) if t > rID { rID = t } } rID++ ID := bytes.Buffer{} ID.WriteString("rId") ID.WriteString(strconv.Itoa(rID)) target := bytes.Buffer{} target.WriteString("worksheets/sheet") target.WriteString(strconv.Itoa(sheet)) target.WriteString(".xml") content.Relationships = append(content.Relationships, xlsxWorkbookRelation{ ID: ID.String(), Target: target.String(), Type: SourceRelationshipWorkSheet, }) return rID } // setAppXML update docProps/app.xml file of XML. func (f *File) setAppXML() { f.saveFileList("docProps/app.xml", []byte(templateDocpropsApp)) } // Some tools that read XLSX files have very strict requirements about the // structure of the input XML. In particular both Numbers on the Mac and SAS // dislike inline XML namespace declarations, or namespace prefixes that don't // match the ones that Excel itself uses. This is a problem because the Go XML // library doesn't multiple namespace declarations in a single element of a // document. This function is a horrible hack to fix that after the XML // marshalling is completed. func replaceRelationshipsNameSpaceBytes(workbookMarshal []byte) []byte { oldXmlns := []byte(``) newXmlns := []byte(``) return bytes.Replace(workbookMarshal, oldXmlns, newXmlns, -1) } // SetActiveSheet provides function to set default active worksheet of XLSX by // given index. Note that active index is different with the index that got by // function GetSheetMap, and it should be greater than 0 and less than total // worksheet numbers. func (f *File) SetActiveSheet(index int) { if index < 1 { index = 1 } index-- content := f.workbookReader() if len(content.BookViews.WorkBookView) > 0 { content.BookViews.WorkBookView[0].ActiveTab = index } else { content.BookViews.WorkBookView = append(content.BookViews.WorkBookView, xlsxWorkBookView{ ActiveTab: index, }) } index++ for idx, name := range f.GetSheetMap() { xlsx := f.workSheetReader(name) if index == idx { if len(xlsx.SheetViews.SheetView) > 0 { xlsx.SheetViews.SheetView[0].TabSelected = true } else { xlsx.SheetViews.SheetView = append(xlsx.SheetViews.SheetView, xlsxSheetView{ TabSelected: true, }) } } else { if len(xlsx.SheetViews.SheetView) > 0 { xlsx.SheetViews.SheetView[0].TabSelected = false } } } } // GetActiveSheetIndex provides function to get active sheet of XLSX. If not // found the active sheet will be return integer 0. func (f *File) GetActiveSheetIndex() int { buffer := bytes.Buffer{} content := f.workbookReader() for _, v := range content.Sheets.Sheet { xlsx := xlsxWorksheet{} buffer.WriteString("xl/worksheets/sheet") buffer.WriteString(strings.TrimPrefix(v.ID, "rId")) buffer.WriteString(".xml") _ = xml.Unmarshal([]byte(f.readXML(buffer.String())), &xlsx) for _, sheetView := range xlsx.SheetViews.SheetView { if sheetView.TabSelected { ID, _ := strconv.Atoi(strings.TrimPrefix(v.ID, "rId")) return ID } } buffer.Reset() } return 0 } // SetSheetName provides function to set the worksheet name be given old and new // worksheet name. Maximum 31 characters are allowed in sheet title and this // function only changes the name of the sheet and will not update the sheet // name in the formula or reference associated with the cell. So there may be // problem formula error or reference missing. func (f *File) SetSheetName(oldName, newName string) { oldName = trimSheetName(oldName) newName = trimSheetName(newName) content := f.workbookReader() for k, v := range content.Sheets.Sheet { if v.Name == oldName { content.Sheets.Sheet[k].Name = newName f.sheetMap[newName] = f.sheetMap[oldName] delete(f.sheetMap, oldName) } } } // GetSheetName provides function to get worksheet name of XLSX by given // worksheet index. If given sheet index is invalid, will return an empty // string. func (f *File) GetSheetName(index int) string { content := f.workbookReader() rels := f.workbookRelsReader() for _, rel := range rels.Relationships { rID, _ := strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(rel.Target, "worksheets/sheet"), ".xml")) if rID == index { for _, v := range content.Sheets.Sheet { if v.ID == rel.ID { return v.Name } } } } return "" } // GetSheetIndex provides function to get worksheet index of XLSX by given sheet // name. If given worksheet name is invalid, will return an integer type value // 0. func (f *File) GetSheetIndex(name string) int { content := f.workbookReader() rels := f.workbookRelsReader() for _, v := range content.Sheets.Sheet { if v.Name == name { for _, rel := range rels.Relationships { if v.ID == rel.ID { rID, _ := strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(rel.Target, "worksheets/sheet"), ".xml")) return rID } } } } return 0 } // GetSheetMap provides function to get worksheet name and index map of XLSX. // For example: // // xlsx, err := excelize.OpenFile("./Book1.xlsx") // if err != nil { // return // } // for index, name := range xlsx.GetSheetMap() { // fmt.Println(index, name) // } // func (f *File) GetSheetMap() map[int]string { content := f.workbookReader() rels := f.workbookRelsReader() sheetMap := map[int]string{} for _, v := range content.Sheets.Sheet { for _, rel := range rels.Relationships { if rel.ID == v.ID { rID, _ := strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(rel.Target, "worksheets/sheet"), ".xml")) sheetMap[rID] = v.Name } } } return sheetMap } // getSheetMap provides function to get worksheet name and XML file path map of // XLSX. func (f *File) getSheetMap() map[string]string { maps := make(map[string]string) for idx, name := range f.GetSheetMap() { maps[name] = "xl/worksheets/sheet" + strconv.Itoa(idx) + ".xml" } return maps } // SetSheetBackground provides function to set background picture by given // worksheet name. func (f *File) SetSheetBackground(sheet, picture string) error { var err error // Check picture exists first. if _, err = os.Stat(picture); os.IsNotExist(err) { return err } ext, ok := supportImageTypes[path.Ext(picture)] if !ok { return errors.New("Unsupported image extension") } pictureID := f.countMedia() + 1 rID := f.addSheetRelationships(sheet, SourceRelationshipImage, "../media/image"+strconv.Itoa(pictureID)+ext, "") f.addSheetPicture(sheet, rID) f.addMedia(picture, ext) f.setContentTypePartImageExtensions() return err } // DeleteSheet provides function to delete worksheet in a workbook by given // worksheet name. Use this method with caution, which will affect changes in // references such as formulas, charts, and so on. If there is any referenced // value of the deleted worksheet, it will cause a file error when you open it. // This function will be invalid when only the one worksheet is left. func (f *File) DeleteSheet(name string) { content := f.workbookReader() for k, v := range content.Sheets.Sheet { if v.Name == trimSheetName(name) && len(content.Sheets.Sheet) > 1 { content.Sheets.Sheet = append(content.Sheets.Sheet[:k], content.Sheets.Sheet[k+1:]...) sheet := "xl/worksheets/sheet" + strings.TrimPrefix(v.ID, "rId") + ".xml" rels := "xl/worksheets/_rels/sheet" + strings.TrimPrefix(v.ID, "rId") + ".xml.rels" target := f.deleteSheetFromWorkbookRels(v.ID) f.deleteSheetFromContentTypes(target) delete(f.sheetMap, name) delete(f.XLSX, sheet) delete(f.XLSX, rels) delete(f.Sheet, sheet) f.SheetCount-- } } f.SetActiveSheet(len(f.GetSheetMap())) } // deleteSheetFromWorkbookRels provides function to remove worksheet // relationships by given relationships ID in the file // xl/_rels/workbook.xml.rels. func (f *File) deleteSheetFromWorkbookRels(rID string) string { content := f.workbookRelsReader() for k, v := range content.Relationships { if v.ID == rID { content.Relationships = append(content.Relationships[:k], content.Relationships[k+1:]...) return v.Target } } return "" } // deleteSheetFromContentTypes provides function to remove worksheet // relationships by given target name in the file [Content_Types].xml. func (f *File) deleteSheetFromContentTypes(target string) { content := f.contentTypesReader() for k, v := range content.Overrides { if v.PartName == "/xl/"+target { content.Overrides = append(content.Overrides[:k], content.Overrides[k+1:]...) } } } // CopySheet provides function to duplicate a worksheet by gave source and // target worksheet index. Note that currently doesn't support duplicate // workbooks that contain tables, charts or pictures. For Example: // // // Sheet1 already exists... // index := xlsx.NewSheet("Sheet2") // err := xlsx.CopySheet(1, index) // return err // func (f *File) CopySheet(from, to int) error { if from < 1 || to < 1 || from == to || f.GetSheetName(from) == "" || f.GetSheetName(to) == "" { return errors.New("Invalid worksheet index") } return f.copySheet(from, to) } // copySheet provides function to duplicate a worksheet by gave source and // target worksheet name. func (f *File) copySheet(from, to int) error { sheet := f.workSheetReader("sheet" + strconv.Itoa(from)) worksheet := xlsxWorksheet{} err := deepCopy(&worksheet, &sheet) if err != nil { return err } path := "xl/worksheets/sheet" + strconv.Itoa(to) + ".xml" if len(worksheet.SheetViews.SheetView) > 0 { worksheet.SheetViews.SheetView[0].TabSelected = false } worksheet.Drawing = nil worksheet.TableParts = nil worksheet.PageSetUp = nil f.Sheet[path] = &worksheet toRels := "xl/worksheets/_rels/sheet" + strconv.Itoa(to) + ".xml.rels" fromRels := "xl/worksheets/_rels/sheet" + strconv.Itoa(from) + ".xml.rels" _, ok := f.XLSX[fromRels] if ok { f.XLSX[toRels] = f.XLSX[fromRels] } return err } // SetSheetVisible provides function to set worksheet visible by given worksheet // name. A workbook must contain at least one visible worksheet. If the given // worksheet has been activated, this setting will be invalidated. Sheet state // values as defined by http://msdn.microsoft.com/en-us/library/office/documentformat.openxml.spreadsheet.sheetstatevalues.aspx // // visible // hidden // veryHidden // // For example, hide Sheet1: // // xlsx.SetSheetVisible("Sheet1", false) // func (f *File) SetSheetVisible(name string, visible bool) { name = trimSheetName(name) content := f.workbookReader() if visible { for k, v := range content.Sheets.Sheet { if v.Name == name { content.Sheets.Sheet[k].State = "" } } return } count := 0 for _, v := range content.Sheets.Sheet { if v.State != "hidden" { count++ } } for k, v := range content.Sheets.Sheet { xlsx := f.workSheetReader(f.GetSheetMap()[k]) tabSelected := false if len(xlsx.SheetViews.SheetView) > 0 { tabSelected = xlsx.SheetViews.SheetView[0].TabSelected } if v.Name == name && count > 1 && !tabSelected { content.Sheets.Sheet[k].State = "hidden" } } } // parseFormatPanesSet provides function to parse the panes settings. func parseFormatPanesSet(formatSet string) (*formatPanes, error) { format := formatPanes{} err := json.Unmarshal([]byte(formatSet), &format) return &format, err } // SetPanes provides function to create and remove freeze panes and split panes // by given worksheet name and panes format set. // // activePane defines the pane that is active. The possible values for this // attribute are defined in the following table: // // Enumeration Value | Description // --------------------------------+------------------------------------------------------------- // bottomLeft (Bottom Left Pane) | Bottom left pane, when both vertical and horizontal // | splits are applied. // | // | This value is also used when only a horizontal split has // | been applied, dividing the pane into upper and lower // | regions. In that case, this value specifies the bottom // | pane. // | // bottomRight (Bottom Right Pane) | Bottom right pane, when both vertical and horizontal // | splits are applied. // | // topLeft (Top Left Pane) | Top left pane, when both vertical and horizontal splits // | are applied. // | // | This value is also used when only a horizontal split has // | been applied, dividing the pane into upper and lower // | regions. In that case, this value specifies the top pane. // | // | This value is also used when only a vertical split has // | been applied, dividing the pane into right and left // | regions. In that case, this value specifies the left pane // | // topRight (Top Right Pane) | Top right pane, when both vertical and horizontal // | splits are applied. // | // | This value is also used when only a vertical split has // | been applied, dividing the pane into right and left // | regions. In that case, this value specifies the right // | pane. // // Pane state type is restricted to the values supported currently listed in the following table: // // Enumeration Value | Description // --------------------------------+------------------------------------------------------------- // frozen (Frozen) | Panes are frozen, but were not split being frozen. In // | this state, when the panes are unfrozen again, a single // | pane results, with no split. // | // | In this state, the split bars are not adjustable. // | // split (Split) | Panes are split, but not frozen. In this state, the split // | bars are adjustable by the user. // // x_split (Horizontal Split Position): Horizontal position of the split, in // 1/20th of a point; 0 (zero) if none. If the pane is frozen, this value // indicates the number of columns visible in the top pane. // // y_split (Vertical Split Position): Vertical position of the split, in 1/20th // of a point; 0 (zero) if none. If the pane is frozen, this value indicates the // number of rows visible in the left pane. The possible values for this // attribute are defined by the W3C XML Schema double datatype. // // top_left_cell: Location of the top left visible cell in the bottom right pane // (when in Left-To-Right mode). // // sqref (Sequence of References): Range of the selection. Can be non-contiguous // set of ranges. // // An example of how to freeze column A in the Sheet1 and set the active cell on // Sheet1!K16: // // xlsx.SetPanes("Sheet1", `{"freeze":true,"split":false,"x_split":1,"y_split":0,"top_left_cell":"B1","active_pane":"topRight","panes":[{"sqref":"K16","active_cell":"K16","pane":"topRight"}]}`) // // An example of how to freeze rows 1 to 9 in the Sheet1 and set the active cell // ranges on Sheet1!A11:XFD11: // // xlsx.SetPanes("Sheet1", `{"freeze":true,"split":false,"x_split":0,"y_split":9,"top_left_cell":"A34","active_pane":"bottomLeft","panes":[{"sqref":"A11:XFD11","active_cell":"A11","pane":"bottomLeft"}]}`) // // An example of how to create split panes in the Sheet1 and set the active cell // on Sheet1!J60: // // xlsx.SetPanes("Sheet1", `{"freeze":false,"split":true,"x_split":3270,"y_split":1800,"top_left_cell":"N57","active_pane":"bottomLeft","panes":[{"sqref":"I36","active_cell":"I36"},{"sqref":"G33","active_cell":"G33","pane":"topRight"},{"sqref":"J60","active_cell":"J60","pane":"bottomLeft"},{"sqref":"O60","active_cell":"O60","pane":"bottomRight"}]}`) // // An example of how to unfreeze and remove all panes on Sheet1: // // xlsx.SetPanes("Sheet1", `{"freeze":false,"split":false}`) // func (f *File) SetPanes(sheet, panes string) { fs, _ := parseFormatPanesSet(panes) xlsx := f.workSheetReader(sheet) p := &xlsxPane{ ActivePane: fs.ActivePane, TopLeftCell: fs.TopLeftCell, XSplit: float64(fs.XSplit), YSplit: float64(fs.YSplit), } if fs.Freeze { p.State = "frozen" } xlsx.SheetViews.SheetView[len(xlsx.SheetViews.SheetView)-1].Pane = p if !(fs.Freeze) && !(fs.Split) { if len(xlsx.SheetViews.SheetView) > 0 { xlsx.SheetViews.SheetView[len(xlsx.SheetViews.SheetView)-1].Pane = nil } } s := []*xlsxSelection{} for _, p := range fs.Panes { s = append(s, &xlsxSelection{ ActiveCell: p.ActiveCell, Pane: p.Pane, SQRef: p.SQRef, }) } xlsx.SheetViews.SheetView[len(xlsx.SheetViews.SheetView)-1].Selection = s } // GetSheetVisible provides function to get worksheet visible by given worksheet // name. For example, get visible state of Sheet1: // // xlsx.GetSheetVisible("Sheet1") // func (f *File) GetSheetVisible(name string) bool { content := f.workbookReader() visible := false for k, v := range content.Sheets.Sheet { if v.Name == trimSheetName(name) { if content.Sheets.Sheet[k].State == "" || content.Sheets.Sheet[k].State == "visible" { visible = true } } } return visible } // trimSheetName provides function to trim invaild characters by given worksheet // name. func trimSheetName(name string) string { r := []rune{} for _, v := range name { switch v { case 58, 92, 47, 63, 42, 91, 93: // replace :\/?*[] continue default: r = append(r, v) } } name = string(r) if utf8.RuneCountInString(name) > 31 { name = string([]rune(name)[0:31]) } return name } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/sheetpr.go ================================================ package excelize // SheetPrOption is an option of a view of a worksheet. See SetSheetPrOptions(). type SheetPrOption interface { setSheetPrOption(view *xlsxSheetPr) } // SheetPrOptionPtr is a writable SheetPrOption. See GetSheetPrOptions(). type SheetPrOptionPtr interface { SheetPrOption getSheetPrOption(view *xlsxSheetPr) } type ( // CodeName is a SheetPrOption CodeName string // EnableFormatConditionsCalculation is a SheetPrOption EnableFormatConditionsCalculation bool // Published is a SheetPrOption Published bool // FitToPage is a SheetPrOption FitToPage bool // AutoPageBreaks is a SheetPrOption AutoPageBreaks bool ) func (o CodeName) setSheetPrOption(pr *xlsxSheetPr) { pr.CodeName = string(o) } func (o *CodeName) getSheetPrOption(pr *xlsxSheetPr) { if pr == nil { *o = "" return } *o = CodeName(pr.CodeName) } func (o EnableFormatConditionsCalculation) setSheetPrOption(pr *xlsxSheetPr) { pr.EnableFormatConditionsCalculation = boolPtr(bool(o)) } func (o *EnableFormatConditionsCalculation) getSheetPrOption(pr *xlsxSheetPr) { if pr == nil { *o = true return } *o = EnableFormatConditionsCalculation(defaultTrue(pr.EnableFormatConditionsCalculation)) } func (o Published) setSheetPrOption(pr *xlsxSheetPr) { pr.Published = boolPtr(bool(o)) } func (o *Published) getSheetPrOption(pr *xlsxSheetPr) { if pr == nil { *o = true return } *o = Published(defaultTrue(pr.Published)) } func (o FitToPage) setSheetPrOption(pr *xlsxSheetPr) { if pr.PageSetUpPr == nil { if !o { return } pr.PageSetUpPr = new(xlsxPageSetUpPr) } pr.PageSetUpPr.FitToPage = bool(o) } func (o *FitToPage) getSheetPrOption(pr *xlsxSheetPr) { // Excel default: false if pr == nil || pr.PageSetUpPr == nil { *o = false return } *o = FitToPage(pr.PageSetUpPr.FitToPage) } func (o AutoPageBreaks) setSheetPrOption(pr *xlsxSheetPr) { if pr.PageSetUpPr == nil { if !o { return } pr.PageSetUpPr = new(xlsxPageSetUpPr) } pr.PageSetUpPr.AutoPageBreaks = bool(o) } func (o *AutoPageBreaks) getSheetPrOption(pr *xlsxSheetPr) { // Excel default: false if pr == nil || pr.PageSetUpPr == nil { *o = false return } *o = AutoPageBreaks(pr.PageSetUpPr.AutoPageBreaks) } // SetSheetPrOptions provides function to sets worksheet properties. // // Available options: // CodeName(string) // EnableFormatConditionsCalculation(bool) // Published(bool) // FitToPage(bool) // AutoPageBreaks(bool) func (f *File) SetSheetPrOptions(name string, opts ...SheetPrOption) error { sheet := f.workSheetReader(name) pr := sheet.SheetPr if pr == nil { pr = new(xlsxSheetPr) sheet.SheetPr = pr } for _, opt := range opts { opt.setSheetPrOption(pr) } return nil } // GetSheetPrOptions provides function to gets worksheet properties. // // Available options: // CodeName(string) // EnableFormatConditionsCalculation(bool) // Published(bool) // FitToPage(bool) // AutoPageBreaks(bool) func (f *File) GetSheetPrOptions(name string, opts ...SheetPrOptionPtr) error { sheet := f.workSheetReader(name) pr := sheet.SheetPr for _, opt := range opts { opt.getSheetPrOption(pr) } return nil } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/sheetview.go ================================================ package excelize import "fmt" // SheetViewOption is an option of a view of a worksheet. See SetSheetViewOptions(). type SheetViewOption interface { setSheetViewOption(view *xlsxSheetView) } // SheetViewOptionPtr is a writable SheetViewOption. See GetSheetViewOptions(). type SheetViewOptionPtr interface { SheetViewOption getSheetViewOption(view *xlsxSheetView) } type ( // DefaultGridColor is a SheetViewOption. DefaultGridColor bool // RightToLeft is a SheetViewOption. RightToLeft bool // ShowFormulas is a SheetViewOption. ShowFormulas bool // ShowGridLines is a SheetViewOption. ShowGridLines bool // ShowRowColHeaders is a SheetViewOption. ShowRowColHeaders bool // ZoomScale is a SheetViewOption. ZoomScale float64 /* TODO // ShowWhiteSpace is a SheetViewOption. ShowWhiteSpace bool // ShowZeros is a SheetViewOption. ShowZeros bool // WindowProtection is a SheetViewOption. WindowProtection bool */ ) // Defaults for each option are described in XML schema for CT_SheetView func (o DefaultGridColor) setSheetViewOption(view *xlsxSheetView) { view.DefaultGridColor = boolPtr(bool(o)) } func (o *DefaultGridColor) getSheetViewOption(view *xlsxSheetView) { *o = DefaultGridColor(defaultTrue(view.DefaultGridColor)) // Excel default: true } func (o RightToLeft) setSheetViewOption(view *xlsxSheetView) { view.RightToLeft = bool(o) // Excel default: false } func (o *RightToLeft) getSheetViewOption(view *xlsxSheetView) { *o = RightToLeft(view.RightToLeft) } func (o ShowFormulas) setSheetViewOption(view *xlsxSheetView) { view.ShowFormulas = bool(o) // Excel default: false } func (o *ShowFormulas) getSheetViewOption(view *xlsxSheetView) { *o = ShowFormulas(view.ShowFormulas) // Excel default: false } func (o ShowGridLines) setSheetViewOption(view *xlsxSheetView) { view.ShowGridLines = boolPtr(bool(o)) } func (o *ShowGridLines) getSheetViewOption(view *xlsxSheetView) { *o = ShowGridLines(defaultTrue(view.ShowGridLines)) // Excel default: true } func (o ShowRowColHeaders) setSheetViewOption(view *xlsxSheetView) { view.ShowRowColHeaders = boolPtr(bool(o)) } func (o *ShowRowColHeaders) getSheetViewOption(view *xlsxSheetView) { *o = ShowRowColHeaders(defaultTrue(view.ShowRowColHeaders)) // Excel default: true } func (o ZoomScale) setSheetViewOption(view *xlsxSheetView) { //This attribute is restricted to values ranging from 10 to 400. if float64(o) >= 10 && float64(o) <= 400 { view.ZoomScale = float64(o) } } func (o *ZoomScale) getSheetViewOption(view *xlsxSheetView) { *o = ZoomScale(view.ZoomScale) } // getSheetView returns the SheetView object func (f *File) getSheetView(sheetName string, viewIndex int) (*xlsxSheetView, error) { xlsx := f.workSheetReader(sheetName) if viewIndex < 0 { if viewIndex < -len(xlsx.SheetViews.SheetView) { return nil, fmt.Errorf("view index %d out of range", viewIndex) } viewIndex = len(xlsx.SheetViews.SheetView) + viewIndex } else if viewIndex >= len(xlsx.SheetViews.SheetView) { return nil, fmt.Errorf("view index %d out of range", viewIndex) } return &(xlsx.SheetViews.SheetView[viewIndex]), nil } // SetSheetViewOptions sets sheet view options. // The viewIndex may be negative and if so is counted backward (-1 is the last view). // // Available options: // DefaultGridColor(bool) // RightToLeft(bool) // ShowFormulas(bool) // ShowGridLines(bool) // ShowRowColHeaders(bool) // Example: // err = f.SetSheetViewOptions("Sheet1", -1, ShowGridLines(false)) func (f *File) SetSheetViewOptions(name string, viewIndex int, opts ...SheetViewOption) error { view, err := f.getSheetView(name, viewIndex) if err != nil { return err } for _, opt := range opts { opt.setSheetViewOption(view) } return nil } // GetSheetViewOptions gets the value of sheet view options. // The viewIndex may be negative and if so is counted backward (-1 is the last view). // // Available options: // DefaultGridColor(bool) // RightToLeft(bool) // ShowFormulas(bool) // ShowGridLines(bool) // ShowRowColHeaders(bool) // Example: // var showGridLines excelize.ShowGridLines // err = f.GetSheetViewOptions("Sheet1", -1, &showGridLines) func (f *File) GetSheetViewOptions(name string, viewIndex int, opts ...SheetViewOptionPtr) error { view, err := f.getSheetView(name, viewIndex) if err != nil { return err } for _, opt := range opts { opt.getSheetViewOption(view) } return nil } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/styles.go ================================================ package excelize import ( "encoding/json" "encoding/xml" "fmt" "math" "strconv" "strings" ) // Excel styles can reference number formats that are built-in, all of which // have an id less than 164. This is a possibly incomplete list comprised of as // many of them as I could find. var builtInNumFmt = map[int]string{ 0: "general", 1: "0", 2: "0.00", 3: "#,##0", 4: "#,##0.00", 9: "0%", 10: "0.00%", 11: "0.00e+00", 12: "# ?/?", 13: "# ??/??", 14: "mm-dd-yy", 15: "d-mmm-yy", 16: "d-mmm", 17: "mmm-yy", 18: "h:mm am/pm", 19: "h:mm:ss am/pm", 20: "h:mm", 21: "h:mm:ss", 22: "m/d/yy h:mm", 37: "#,##0 ;(#,##0)", 38: "#,##0 ;[red](#,##0)", 39: "#,##0.00;(#,##0.00)", 40: "#,##0.00;[red](#,##0.00)", 41: `_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)`, 42: `_("$"* #,##0_);_("$* \(#,##0\);_("$"* "-"_);_(@_)`, 43: `_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)`, 44: `_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)`, 45: "mm:ss", 46: "[h]:mm:ss", 47: "mmss.0", 48: "##0.0e+0", 49: "@", } // langNumFmt defined number format code (with unicode values provided for // language glyphs where they occur) in different language. var langNumFmt = map[string]map[int]string{ "zh-tw": { 27: "[$-404]e/m/d", 28: `[$-404]e"年"m"月"d"日"`, 29: `[$-404]e"年"m"月"d"日"`, 30: "m/d/yy", 31: `yyyy"年"m"月"d"日"`, 32: `hh"時"mm"分"`, 33: `hh"時"mm"分"ss"秒"`, 34: `上午/下午 hh"時"mm"分"`, 35: `上午/下午 hh"時"mm"分"ss"秒"`, 36: "[$-404]e/m/d", 50: "[$-404]e/m/d", 51: `[$-404]e"年"m"月"d"日"`, 52: `上午/下午 hh"時"mm"分"`, 53: `上午/下午 hh"時"mm"分"ss"秒"`, 54: `[$-404]e"年"m"月"d"日"`, 55: `上午/下午 hh"時"mm"分"`, 56: `上午/下午 hh"時"mm"分"ss"秒"`, 57: "[$-404]e/m/d", 58: `[$-404]e"年"m"月"d"日"`, }, "zh-cn": { 27: `yyyy"年"m"月"`, 28: `m"月"d"日"`, 29: `m"月"d"日"`, 30: "m-d-yy", 31: `yyyy"年"m"月"d"日"`, 32: `h"时"mm"分"`, 33: `h"时"mm"分"ss"秒"`, 34: `上午/下午 h"时"mm"分"`, 35: `上午/下午 h"时"mm"分"ss"秒"`, 36: `yyyy"年"m"月"`, 50: `yyyy"年"m"月"`, 51: `m"月"d"日"`, 52: `yyyy"年"m"月"`, 53: `m"月"d"日"`, 54: `m"月"d"日"`, 55: `上午/下午 h"时"mm"分"`, 56: `上午/下午 h"时"mm"分"ss"秒"`, 57: `yyyy"年"m"月"`, 58: `m"月"d"日"`, }, "zh-tw_unicode": { 27: "[$-404]e/m/d", 28: `[$-404]e"5E74"m"6708"d"65E5"`, 29: `[$-404]e"5E74"m"6708"d"65E5"`, 30: "m/d/yy", 31: `yyyy"5E74"m"6708"d"65E5"`, 32: `hh"6642"mm"5206"`, 33: `hh"6642"mm"5206"ss"79D2"`, 34: `4E0A5348/4E0B5348hh"6642"mm"5206"`, 35: `4E0A5348/4E0B5348hh"6642"mm"5206"ss"79D2"`, 36: "[$-404]e/m/d", 50: "[$-404]e/m/d", 51: `[$-404]e"5E74"m"6708"d"65E5"`, 52: `4E0A5348/4E0B5348hh"6642"mm"5206"`, 53: `4E0A5348/4E0B5348hh"6642"mm"5206"ss"79D2"`, 54: `[$-404]e"5E74"m"6708"d"65E5"`, 55: `4E0A5348/4E0B5348hh"6642"mm"5206"`, 56: `4E0A5348/4E0B5348hh"6642"mm"5206"ss"79D2"`, 57: "[$-404]e/m/d", 58: `[$-404]e"5E74"m"6708"d"65E5"`, }, "zh-cn_unicode": { 27: `yyyy"5E74"m"6708"`, 28: `m"6708"d"65E5"`, 29: `m"6708"d"65E5"`, 30: "m-d-yy", 31: `yyyy"5E74"m"6708"d"65E5"`, 32: `h"65F6"mm"5206"`, 33: `h"65F6"mm"5206"ss"79D2"`, 34: `4E0A5348/4E0B5348h"65F6"mm"5206"`, 35: `4E0A5348/4E0B5348h"65F6"mm"5206"ss"79D2"`, 36: `yyyy"5E74"m"6708"`, 50: `yyyy"5E74"m"6708"`, 51: `m"6708"d"65E5"`, 52: `yyyy"5E74"m"6708"`, 53: `m"6708"d"65E5"`, 54: `m"6708"d"65E5"`, 55: `4E0A5348/4E0B5348h"65F6"mm"5206"`, 56: `4E0A5348/4E0B5348h"65F6"mm"5206"ss"79D2"`, 57: `yyyy"5E74"m"6708"`, 58: `m"6708"d"65E5"`, }, "ja-jp": { 27: "[$-411]ge.m.d", 28: `[$-411]ggge"年"m"月"d"日"`, 29: `[$-411]ggge"年"m"月"d"日"`, 30: "m/d/yy", 31: `yyyy"年"m"月"d"日"`, 32: `h"時"mm"分"`, 33: `h"時"mm"分"ss"秒"`, 34: `yyyy"年"m"月"`, 35: `m"月"d"日"`, 36: "[$-411]ge.m.d", 50: "[$-411]ge.m.d", 51: `[$-411]ggge"年"m"月"d"日"`, 52: `yyyy"年"m"月"`, 53: `m"月"d"日"`, 54: `[$-411]ggge"年"m"月"d"日"`, 55: `yyyy"年"m"月"`, 56: `m"月"d"日"`, 57: "[$-411]ge.m.d", 58: `[$-411]ggge"年"m"月"d"日"`, }, "ko-kr": { 27: `yyyy"年" mm"月" dd"日"`, 28: "mm-dd", 29: "mm-dd", 30: "mm-dd-yy", 31: `yyyy"년" mm"월" dd"일"`, 32: `h"시" mm"분"`, 33: `h"시" mm"분" ss"초"`, 34: `yyyy-mm-dd`, 35: `yyyy-mm-dd`, 36: `yyyy"年" mm"月" dd"日"`, 50: `yyyy"年" mm"月" dd"日"`, 51: "mm-dd", 52: "yyyy-mm-dd", 53: "yyyy-mm-dd", 54: "mm-dd", 55: "yyyy-mm-dd", 56: "yyyy-mm-dd", 57: `yyyy"年" mm"月" dd"日"`, 58: "mm-dd", }, "ja-jp_unicode": { 27: "[$-411]ge.m.d", 28: `[$-411]ggge"5E74"m"6708"d"65E5"`, 29: `[$-411]ggge"5E74"m"6708"d"65E5"`, 30: "m/d/yy", 31: `yyyy"5E74"m"6708"d"65E5"`, 32: `h"6642"mm"5206"`, 33: `h"6642"mm"5206"ss"79D2"`, 34: `yyyy"5E74"m"6708"`, 35: `m"6708"d"65E5"`, 36: "[$-411]ge.m.d", 50: "[$-411]ge.m.d", 51: `[$-411]ggge"5E74"m"6708"d"65E5"`, 52: `yyyy"5E74"m"6708"`, 53: `m"6708"d"65E5"`, 54: `[$-411]ggge"5E74"m"6708"d"65E5"`, 55: `yyyy"5E74"m"6708"`, 56: `m"6708"d"65E5"`, 57: "[$-411]ge.m.d", 58: `[$-411]ggge"5E74"m"6708"d"65E5"`, }, "ko-kr_unicode": { 27: `yyyy"5E74" mm"6708" dd"65E5"`, 28: "mm-dd", 29: "mm-dd", 30: "mm-dd-yy", 31: `yyyy"B144" mm"C6D4" dd"C77C"`, 32: `h"C2DC" mm"BD84"`, 33: `h"C2DC" mm"BD84" ss"CD08"`, 34: "yyyy-mm-dd", 35: "yyyy-mm-dd", 36: `yyyy"5E74" mm"6708" dd"65E5"`, 50: `yyyy"5E74" mm"6708" dd"65E5"`, 51: "mm-dd", 52: "yyyy-mm-dd", 53: "yyyy-mm-dd", 54: "mm-dd", 55: "yyyy-mm-dd", 56: "yyyy-mm-dd", 57: `yyyy"5E74" mm"6708" dd"65E5"`, 58: "mm-dd", }, "th-th": { 59: "t0", 60: "t0.00", 61: "t#,##0", 62: "t#,##0.00", 67: "t0%", 68: "t0.00%", 69: "t# ?/?", 70: "t# ??/??", 71: "ว/ด/ปปปป", 72: "ว-ดดด-ปป", 73: "ว-ดดด", 74: "ดดด-ปป", 75: "ช:นน", 76: "ช:นน:ทท", 77: "ว/ด/ปปปป ช:นน", 78: "นน:ทท", 79: "[ช]:นน:ทท", 80: "นน:ทท.0", 81: "d/m/bb", }, "th-th_unicode": { 59: "t0", 60: "t0.00", 61: "t#,##0", 62: "t#,##0.00", 67: "t0%", 68: "t0.00%", 69: "t# ?/?", 70: "t# ??/??", 71: "0E27/0E14/0E1B0E1B0E1B0E1B", 72: "0E27-0E140E140E14-0E1B0E1B", 73: "0E27-0E140E140E14", 74: "0E140E140E14-0E1B0E1B", 75: "0E0A:0E190E19", 76: "0E0A:0E190E19:0E170E17", 77: "0E27/0E14/0E1B0E1B0E1B0E1B 0E0A:0E190E19", 78: "0E190E19:0E170E17", 79: "[0E0A]:0E190E19:0E170E17", 80: "0E190E19:0E170E17.0", 81: "d/m/bb", }, } // currencyNumFmt defined the currency number format map. var currencyNumFmt = map[int]string{ 164: `"CN¥",##0.00`, 165: "[$$-409]#,##0.00", 166: "[$$-45C]#,##0.00", 167: "[$$-1004]#,##0.00", 168: "[$$-404]#,##0.00", 169: "[$$-C09]#,##0.00", 170: "[$$-2809]#,##0.00", 171: "[$$-1009]#,##0.00", 172: "[$$-2009]#,##0.00", 173: "[$$-1409]#,##0.00", 174: "[$$-4809]#,##0.00", 175: "[$$-2C09]#,##0.00", 176: "[$$-2409]#,##0.00", 177: "[$$-1000]#,##0.00", 178: `#,##0.00\ [$$-C0C]`, 179: "[$$-475]#,##0.00", 180: "[$$-83E]#,##0.00", 181: `[$$-86B]\ #,##0.00`, 182: `[$$-340A]\ #,##0.00`, 183: "[$$-240A]#,##0.00", 184: `[$$-300A]\ #,##0.00`, 185: "[$$-440A]#,##0.00", 186: "[$$-80A]#,##0.00", 187: "[$$-500A]#,##0.00", 188: "[$$-540A]#,##0.00", 189: `[$$-380A]\ #,##0.00`, 190: "[$£-809]#,##0.00", 191: "[$£-491]#,##0.00", 192: "[$£-452]#,##0.00", 193: "[$¥-804]#,##0.00", 194: "[$¥-411]#,##0.00", 195: "[$¥-478]#,##0.00", 196: "[$¥-451]#,##0.00", 197: "[$¥-480]#,##0.00", 198: "#,##0.00\\ [$\u058F-42B]", 199: "[$\u060B-463]#,##0.00", 200: "[$\u060B-48C]#,##0.00", 201: "[$\u09F3-845]\\ #,##0.00", 202: "#,##0.00[$\u17DB-453]", 203: "[$\u20A1-140A]#,##0.00", 204: "[$\u20A6-468]\\ #,##0.00", 205: "[$\u20A6-470]\\ #,##0.00", 206: "[$\u20A9-412]#,##0.00", 207: "[$\u20AA-40D]\\ #,##0.00", 208: "#,##0.00\\ [$\u20AB-42A]", 209: "#,##0.00\\ [$\u20AC-42D]", 210: "#,##0.00\\ [$\u20AC-47E]", 211: "#,##0.00\\ [$\u20AC-403]", 212: "#,##0.00\\ [$\u20AC-483]", 213: "[$\u20AC-813]\\ #,##0.00", 214: "[$\u20AC-413]\\ #,##0.00", 215: "[$\u20AC-1809]#,##0.00", 216: "#,##0.00\\ [$\u20AC-425]", 217: "[$\u20AC-2]\\ #,##0.00", 218: "#,##0.00\\ [$\u20AC-1]", 219: "#,##0.00\\ [$\u20AC-40B]", 220: "#,##0.00\\ [$\u20AC-80C]", 221: "#,##0.00\\ [$\u20AC-40C]", 222: "#,##0.00\\ [$\u20AC-140C]", 223: "#,##0.00\\ [$\u20AC-180C]", 224: "[$\u20AC-200C]#,##0.00", 225: "#,##0.00\\ [$\u20AC-456]", 226: "#,##0.00\\ [$\u20AC-C07]", 227: "#,##0.00\\ [$\u20AC-407]", 228: "#,##0.00\\ [$\u20AC-1007]", 229: "#,##0.00\\ [$\u20AC-408]", 230: "#,##0.00\\ [$\u20AC-243B]", 231: "[$\u20AC-83C]#,##0.00", 232: "[$\u20AC-410]\\ #,##0.00", 233: "[$\u20AC-476]#,##0.00", 234: "#,##0.00\\ [$\u20AC-2C1A]", 235: "[$\u20AC-426]\\ #,##0.00", 236: "#,##0.00\\ [$\u20AC-427]", 237: "#,##0.00\\ [$\u20AC-82E]", 238: "#,##0.00\\ [$\u20AC-46E]", 239: "[$\u20AC-43A]#,##0.00", 240: "#,##0.00\\ [$\u20AC-C3B]", 241: "#,##0.00\\ [$\u20AC-482]", 242: "#,##0.00\\ [$\u20AC-816]", 243: "#,##0.00\\ [$\u20AC-301A]", 244: "#,##0.00\\ [$\u20AC-203B]", 245: "#,##0.00\\ [$\u20AC-41B]", 246: "#,##0.00\\ [$\u20AC-424]", 247: "#,##0.00\\ [$\u20AC-C0A]", 248: "#,##0.00\\ [$\u20AC-81D]", 249: "#,##0.00\\ [$\u20AC-484]", 250: "#,##0.00\\ [$\u20AC-42E]", 251: "[$\u20AC-462]\\ #,##0.00", 252: "#,##0.00\\ [$₭-454]", 253: "#,##0.00\\ [$₮-450]", 254: "[$\u20AE-C50]#,##0.00", 255: "[$\u20B1-3409]#,##0.00", 256: "[$\u20B1-464]#,##0.00", 257: "#,##0.00[$\u20B4-422]", 258: "[$\u20B8-43F]#,##0.00", 259: "[$\u20B9-460]#,##0.00", 260: "[$\u20B9-4009]\\ #,##0.00", 261: "[$\u20B9-447]\\ #,##0.00", 262: "[$\u20B9-439]\\ #,##0.00", 263: "[$\u20B9-44B]\\ #,##0.00", 264: "[$\u20B9-860]#,##0.00", 265: "[$\u20B9-457]\\ #,##0.00", 266: "[$\u20B9-458]#,##0.00", 267: "[$\u20B9-44E]\\ #,##0.00", 268: "[$\u20B9-861]#,##0.00", 269: "[$\u20B9-448]\\ #,##0.00", 270: "[$\u20B9-446]\\ #,##0.00", 271: "[$\u20B9-44F]\\ #,##0.00", 272: "[$\u20B9-459]#,##0.00", 273: "[$\u20B9-449]\\ #,##0.00", 274: "[$\u20B9-820]#,##0.00", 275: "#,##0.00\\ [$\u20BA-41F]", 276: "#,##0.00\\ [$\u20BC-42C]", 277: "#,##0.00\\ [$\u20BC-82C]", 278: "#,##0.00\\ [$\u20BD-419]", 279: "#,##0.00[$\u20BD-485]", 280: "#,##0.00\\ [$\u20BE-437]", 281: "[$B/.-180A]\\ #,##0.00", 282: "[$Br-472]#,##0.00", 283: "[$Br-477]#,##0.00", 284: "#,##0.00[$Br-473]", 285: "[$Bs-46B]\\ #,##0.00", 286: "[$Bs-400A]\\ #,##0.00", 287: "[$Bs.-200A]\\ #,##0.00", 288: "[$BWP-832]\\ #,##0.00", 289: "[$C$-4C0A]#,##0.00", 290: "[$CA$-85D]#,##0.00", 291: "[$CA$-47C]#,##0.00", 292: "[$CA$-45D]#,##0.00", 293: "[$CFA-340C]#,##0.00", 294: "[$CFA-280C]#,##0.00", 295: "#,##0.00\\ [$CFA-867]", 296: "#,##0.00\\ [$CFA-488]", 297: "#,##0.00\\ [$CHF-100C]", 298: "[$CHF-1407]\\ #,##0.00", 299: "[$CHF-807]\\ #,##0.00", 300: "[$CHF-810]\\ #,##0.00", 301: "[$CHF-417]\\ #,##0.00", 302: "[$CLP-47A]\\ #,##0.00", 303: "[$CN¥-850]#,##0.00", 304: "#,##0.00\\ [$DZD-85F]", 305: "[$FCFA-2C0C]#,##0.00", 306: "#,##0.00\\ [$Ft-40E]", 307: "[$G-3C0C]#,##0.00", 308: "[$Gs.-3C0A]\\ #,##0.00", 309: "[$GTQ-486]#,##0.00", 310: "[$HK$-C04]#,##0.00", 311: "[$HK$-3C09]#,##0.00", 312: "#,##0.00\\ [$HRK-41A]", 313: "[$IDR-3809]#,##0.00", 314: "[$IQD-492]#,##0.00", 315: "#,##0.00\\ [$ISK-40F]", 316: "[$K-455]#,##0.00", 317: "#,##0.00\\ [$K\u010D-405]", 318: "#,##0.00\\ [$KM-141A]", 319: "#,##0.00\\ [$KM-101A]", 320: "#,##0.00\\ [$KM-181A]", 321: "[$kr-438]\\ #,##0.00", 322: "[$kr-43B]\\ #,##0.00", 323: "#,##0.00\\ [$kr-83B]", 324: "[$kr-414]\\ #,##0.00", 325: "[$kr-814]\\ #,##0.00", 326: "#,##0.00\\ [$kr-41D]", 327: "[$kr.-406]\\ #,##0.00", 328: "[$kr.-46F]\\ #,##0.00", 329: "[$Ksh-441]#,##0.00", 330: "[$L-818]#,##0.00", 331: "[$L-819]#,##0.00", 332: "[$L-480A]\\ #,##0.00", 333: "#,##0.00\\ [$Lek\u00EB-41C]", 334: "[$MAD-45F]#,##0.00", 335: "[$MAD-380C]#,##0.00", 336: "#,##0.00\\ [$MAD-105F]", 337: "[$MOP$-1404]#,##0.00", 338: "#,##0.00\\ [$MVR-465]_-", 339: "#,##0.00[$Nfk-873]", 340: "[$NGN-466]#,##0.00", 341: "[$NGN-467]#,##0.00", 342: "[$NGN-469]#,##0.00", 343: "[$NGN-471]#,##0.00", 344: "[$NOK-103B]\\ #,##0.00", 345: "[$NOK-183B]\\ #,##0.00", 346: "[$NZ$-481]#,##0.00", 347: "[$PKR-859]\\ #,##0.00", 348: "[$PYG-474]#,##0.00", 349: "[$Q-100A]#,##0.00", 350: "[$R-436]\\ #,##0.00", 351: "[$R-1C09]\\ #,##0.00", 352: "[$R-435]\\ #,##0.00", 353: "[$R$-416]\\ #,##0.00", 354: "[$RD$-1C0A]#,##0.00", 355: "#,##0.00\\ [$RF-487]", 356: "[$RM-4409]#,##0.00", 357: "[$RM-43E]#,##0.00", 358: "#,##0.00\\ [$RON-418]", 359: "[$Rp-421]#,##0.00", 360: "[$Rs-420]#,##0.00_-", 361: "[$Rs.-849]\\ #,##0.00", 362: "#,##0.00\\ [$RSD-81A]", 363: "#,##0.00\\ [$RSD-C1A]", 364: "#,##0.00\\ [$RUB-46D]", 365: "#,##0.00\\ [$RUB-444]", 366: "[$S/.-C6B]\\ #,##0.00", 367: "[$S/.-280A]\\ #,##0.00", 368: "#,##0.00\\ [$SEK-143B]", 369: "#,##0.00\\ [$SEK-1C3B]", 370: "#,##0.00\\ [$so\u02BBm-443]", 371: "#,##0.00\\ [$so\u02BBm-843]", 372: "#,##0.00\\ [$SYP-45A]", 373: "[$THB-41E]#,##0.00", 374: "#,##0.00[$TMT-442]", 375: "[$US$-3009]#,##0.00", 376: "[$ZAR-46C]\\ #,##0.00", 377: "[$ZAR-430]#,##0.00", 378: "[$ZAR-431]#,##0.00", 379: "[$ZAR-432]\\ #,##0.00", 380: "[$ZAR-433]#,##0.00", 381: "[$ZAR-434]\\ #,##0.00", 382: "#,##0.00\\ [$z\u0142-415]", 383: "#,##0.00\\ [$\u0434\u0435\u043D-42F]", 384: "#,##0.00\\ [$КМ-201A]", 385: "#,##0.00\\ [$КМ-1C1A]", 386: "#,##0.00\\ [$\u043B\u0432.-402]", 387: "#,##0.00\\ [$р.-423]", 388: "#,##0.00\\ [$\u0441\u043E\u043C-440]", 389: "#,##0.00\\ [$\u0441\u043E\u043C-428]", 390: "[$\u062C.\u0645.-C01]\\ #,##0.00_-", 391: "[$\u062F.\u0623.-2C01]\\ #,##0.00_-", 392: "[$\u062F.\u0625.-3801]\\ #,##0.00_-", 393: "[$\u062F.\u0628.-3C01]\\ #,##0.00_-", 394: "[$\u062F.\u062A.-1C01]\\ #,##0.00_-", 395: "[$\u062F.\u062C.-1401]\\ #,##0.00_-", 396: "[$\u062F.\u0639.-801]\\ #,##0.00_-", 397: "[$\u062F.\u0643.-3401]\\ #,##0.00_-", 398: "[$\u062F.\u0644.-1001]#,##0.00_-", 399: "[$\u062F.\u0645.-1801]\\ #,##0.00_-", 400: "[$\u0631-846]\\ #,##0.00", 401: "[$\u0631.\u0633.-401]\\ #,##0.00_-", 402: "[$\u0631.\u0639.-2001]\\ #,##0.00_-", 403: "[$\u0631.\u0642.-4001]\\ #,##0.00_-", 404: "[$\u0631.\u064A.-2401]\\ #,##0.00_-", 405: "[$\u0631\u06CC\u0627\u0644-429]#,##0.00_-", 406: "[$\u0644.\u0633.-2801]\\ #,##0.00_-", 407: "[$\u0644.\u0644.-3001]\\ #,##0.00_-", 408: "[$\u1265\u122D-45E]#,##0.00", 409: "[$\u0930\u0942-461]#,##0.00", 410: "[$\u0DBB\u0DD4.-45B]\\ #,##0.00", 411: "[$ADP]\\ #,##0.00", 412: "[$AED]\\ #,##0.00", 413: "[$AFA]\\ #,##0.00", 414: "[$AFN]\\ #,##0.00", 415: "[$ALL]\\ #,##0.00", 416: "[$AMD]\\ #,##0.00", 417: "[$ANG]\\ #,##0.00", 418: "[$AOA]\\ #,##0.00", 419: "[$ARS]\\ #,##0.00", 420: "[$ATS]\\ #,##0.00", 421: "[$AUD]\\ #,##0.00", 422: "[$AWG]\\ #,##0.00", 423: "[$AZM]\\ #,##0.00", 424: "[$AZN]\\ #,##0.00", 425: "[$BAM]\\ #,##0.00", 426: "[$BBD]\\ #,##0.00", 427: "[$BDT]\\ #,##0.00", 428: "[$BEF]\\ #,##0.00", 429: "[$BGL]\\ #,##0.00", 430: "[$BGN]\\ #,##0.00", 431: "[$BHD]\\ #,##0.00", 432: "[$BIF]\\ #,##0.00", 433: "[$BMD]\\ #,##0.00", 434: "[$BND]\\ #,##0.00", 435: "[$BOB]\\ #,##0.00", 436: "[$BOV]\\ #,##0.00", 437: "[$BRL]\\ #,##0.00", 438: "[$BSD]\\ #,##0.00", 439: "[$BTN]\\ #,##0.00", 440: "[$BWP]\\ #,##0.00", 441: "[$BYR]\\ #,##0.00", 442: "[$BZD]\\ #,##0.00", 443: "[$CAD]\\ #,##0.00", 444: "[$CDF]\\ #,##0.00", 445: "[$CHE]\\ #,##0.00", 446: "[$CHF]\\ #,##0.00", 447: "[$CHW]\\ #,##0.00", 448: "[$CLF]\\ #,##0.00", 449: "[$CLP]\\ #,##0.00", 450: "[$CNY]\\ #,##0.00", 451: "[$COP]\\ #,##0.00", 452: "[$COU]\\ #,##0.00", 453: "[$CRC]\\ #,##0.00", 454: "[$CSD]\\ #,##0.00", 455: "[$CUC]\\ #,##0.00", 456: "[$CVE]\\ #,##0.00", 457: "[$CYP]\\ #,##0.00", 458: "[$CZK]\\ #,##0.00", 459: "[$DEM]\\ #,##0.00", 460: "[$DJF]\\ #,##0.00", 461: "[$DKK]\\ #,##0.00", 462: "[$DOP]\\ #,##0.00", 463: "[$DZD]\\ #,##0.00", 464: "[$ECS]\\ #,##0.00", 465: "[$ECV]\\ #,##0.00", 466: "[$EEK]\\ #,##0.00", 467: "[$EGP]\\ #,##0.00", 468: "[$ERN]\\ #,##0.00", 469: "[$ESP]\\ #,##0.00", 470: "[$ETB]\\ #,##0.00", 471: "[$EUR]\\ #,##0.00", 472: "[$FIM]\\ #,##0.00", 473: "[$FJD]\\ #,##0.00", 474: "[$FKP]\\ #,##0.00", 475: "[$FRF]\\ #,##0.00", 476: "[$GBP]\\ #,##0.00", 477: "[$GEL]\\ #,##0.00", 478: "[$GHC]\\ #,##0.00", 479: "[$GHS]\\ #,##0.00", 480: "[$GIP]\\ #,##0.00", 481: "[$GMD]\\ #,##0.00", 482: "[$GNF]\\ #,##0.00", 483: "[$GRD]\\ #,##0.00", 484: "[$GTQ]\\ #,##0.00", 485: "[$GYD]\\ #,##0.00", 486: "[$HKD]\\ #,##0.00", 487: "[$HNL]\\ #,##0.00", 488: "[$HRK]\\ #,##0.00", 489: "[$HTG]\\ #,##0.00", 490: "[$HUF]\\ #,##0.00", 491: "[$IDR]\\ #,##0.00", 492: "[$IEP]\\ #,##0.00", 493: "[$ILS]\\ #,##0.00", 494: "[$INR]\\ #,##0.00", 495: "[$IQD]\\ #,##0.00", 496: "[$IRR]\\ #,##0.00", 497: "[$ISK]\\ #,##0.00", 498: "[$ITL]\\ #,##0.00", 499: "[$JMD]\\ #,##0.00", 500: "[$JOD]\\ #,##0.00", 501: "[$JPY]\\ #,##0.00", 502: "[$KAF]\\ #,##0.00", 503: "[$KES]\\ #,##0.00", 504: "[$KGS]\\ #,##0.00", 505: "[$KHR]\\ #,##0.00", 506: "[$KMF]\\ #,##0.00", 507: "[$KPW]\\ #,##0.00", 508: "[$KRW]\\ #,##0.00", 509: "[$KWD]\\ #,##0.00", 510: "[$KYD]\\ #,##0.00", 511: "[$KZT]\\ #,##0.00", 512: "[$LAK]\\ #,##0.00", 513: "[$LBP]\\ #,##0.00", 514: "[$LKR]\\ #,##0.00", 515: "[$LRD]\\ #,##0.00", 516: "[$LSL]\\ #,##0.00", 517: "[$LTL]\\ #,##0.00", 518: "[$LUF]\\ #,##0.00", 519: "[$LVL]\\ #,##0.00", 520: "[$LYD]\\ #,##0.00", 521: "[$MAD]\\ #,##0.00", 522: "[$MDL]\\ #,##0.00", 523: "[$MGA]\\ #,##0.00", 524: "[$MGF]\\ #,##0.00", 525: "[$MKD]\\ #,##0.00", 526: "[$MMK]\\ #,##0.00", 527: "[$MNT]\\ #,##0.00", 528: "[$MOP]\\ #,##0.00", 529: "[$MRO]\\ #,##0.00", 530: "[$MTL]\\ #,##0.00", 531: "[$MUR]\\ #,##0.00", 532: "[$MVR]\\ #,##0.00", 533: "[$MWK]\\ #,##0.00", 534: "[$MXN]\\ #,##0.00", 535: "[$MXV]\\ #,##0.00", 536: "[$MYR]\\ #,##0.00", 537: "[$MZM]\\ #,##0.00", 538: "[$MZN]\\ #,##0.00", 539: "[$NAD]\\ #,##0.00", 540: "[$NGN]\\ #,##0.00", 541: "[$NIO]\\ #,##0.00", 542: "[$NLG]\\ #,##0.00", 543: "[$NOK]\\ #,##0.00", 544: "[$NPR]\\ #,##0.00", 545: "[$NTD]\\ #,##0.00", 546: "[$NZD]\\ #,##0.00", 547: "[$OMR]\\ #,##0.00", 548: "[$PAB]\\ #,##0.00", 549: "[$PEN]\\ #,##0.00", 550: "[$PGK]\\ #,##0.00", 551: "[$PHP]\\ #,##0.00", 552: "[$PKR]\\ #,##0.00", 553: "[$PLN]\\ #,##0.00", 554: "[$PTE]\\ #,##0.00", 555: "[$PYG]\\ #,##0.00", 556: "[$QAR]\\ #,##0.00", 557: "[$ROL]\\ #,##0.00", 558: "[$RON]\\ #,##0.00", 559: "[$RSD]\\ #,##0.00", 560: "[$RUB]\\ #,##0.00", 561: "[$RUR]\\ #,##0.00", 562: "[$RWF]\\ #,##0.00", 563: "[$SAR]\\ #,##0.00", 564: "[$SBD]\\ #,##0.00", 565: "[$SCR]\\ #,##0.00", 566: "[$SDD]\\ #,##0.00", 567: "[$SDG]\\ #,##0.00", 568: "[$SDP]\\ #,##0.00", 569: "[$SEK]\\ #,##0.00", 570: "[$SGD]\\ #,##0.00", 571: "[$SHP]\\ #,##0.00", 572: "[$SIT]\\ #,##0.00", 573: "[$SKK]\\ #,##0.00", 574: "[$SLL]\\ #,##0.00", 575: "[$SOS]\\ #,##0.00", 576: "[$SPL]\\ #,##0.00", 577: "[$SRD]\\ #,##0.00", 578: "[$SRG]\\ #,##0.00", 579: "[$STD]\\ #,##0.00", 580: "[$SVC]\\ #,##0.00", 581: "[$SYP]\\ #,##0.00", 582: "[$SZL]\\ #,##0.00", 583: "[$THB]\\ #,##0.00", 584: "[$TJR]\\ #,##0.00", 585: "[$TJS]\\ #,##0.00", 586: "[$TMM]\\ #,##0.00", 587: "[$TMT]\\ #,##0.00", 588: "[$TND]\\ #,##0.00", 589: "[$TOP]\\ #,##0.00", 590: "[$TRL]\\ #,##0.00", 591: "[$TRY]\\ #,##0.00", 592: "[$TTD]\\ #,##0.00", 593: "[$TWD]\\ #,##0.00", 594: "[$TZS]\\ #,##0.00", 595: "[$UAH]\\ #,##0.00", 596: "[$UGX]\\ #,##0.00", 597: "[$USD]\\ #,##0.00", 598: "[$USN]\\ #,##0.00", 599: "[$USS]\\ #,##0.00", 600: "[$UYI]\\ #,##0.00", 601: "[$UYU]\\ #,##0.00", 602: "[$UZS]\\ #,##0.00", 603: "[$VEB]\\ #,##0.00", 604: "[$VEF]\\ #,##0.00", 605: "[$VND]\\ #,##0.00", 606: "[$VUV]\\ #,##0.00", 607: "[$WST]\\ #,##0.00", 608: "[$XAF]\\ #,##0.00", 609: "[$XAG]\\ #,##0.00", 610: "[$XAU]\\ #,##0.00", 611: "[$XB5]\\ #,##0.00", 612: "[$XBA]\\ #,##0.00", 613: "[$XBB]\\ #,##0.00", 614: "[$XBC]\\ #,##0.00", 615: "[$XBD]\\ #,##0.00", 616: "[$XCD]\\ #,##0.00", 617: "[$XDR]\\ #,##0.00", 618: "[$XFO]\\ #,##0.00", 619: "[$XFU]\\ #,##0.00", 620: "[$XOF]\\ #,##0.00", 621: "[$XPD]\\ #,##0.00", 622: "[$XPF]\\ #,##0.00", 623: "[$XPT]\\ #,##0.00", 624: "[$XTS]\\ #,##0.00", 625: "[$XXX]\\ #,##0.00", 626: "[$YER]\\ #,##0.00", 627: "[$YUM]\\ #,##0.00", 628: "[$ZAR]\\ #,##0.00", 629: "[$ZMK]\\ #,##0.00", 630: "[$ZMW]\\ #,##0.00", 631: "[$ZWD]\\ #,##0.00", 632: "[$ZWL]\\ #,##0.00", 633: "[$ZWN]\\ #,##0.00", 634: "[$ZWR]\\ #,##0.00", } // builtInNumFmtFunc defined the format conversion functions map. Partial format // code doesn't support currently and will return original string. var builtInNumFmtFunc = map[int]func(i int, v string) string{ 0: formatToString, 1: formatToInt, 2: formatToFloat, 3: formatToInt, 4: formatToFloat, 9: formatToC, 10: formatToD, 11: formatToE, 12: formatToString, // Doesn't support currently 13: formatToString, // Doesn't support currently 14: parseTime, 15: parseTime, 16: parseTime, 17: parseTime, 18: parseTime, 19: parseTime, 20: parseTime, 21: parseTime, 22: parseTime, 37: formatToA, 38: formatToA, 39: formatToB, 40: formatToB, 41: formatToString, // Doesn't support currently 42: formatToString, // Doesn't support currently 43: formatToString, // Doesn't support currently 44: formatToString, // Doesn't support currently 45: parseTime, 46: parseTime, 47: parseTime, 48: formatToE, 49: formatToString, } // validType defined the list of valid validation types. var validType = map[string]string{ "cell": "cellIs", "date": "date", // Doesn't support currently "time": "time", // Doesn't support currently "average": "aboveAverage", "duplicate": "duplicateValues", "unique": "uniqueValues", "top": "top10", "bottom": "top10", "text": "text", // Doesn't support currently "time_period": "timePeriod", // Doesn't support currently "blanks": "containsBlanks", // Doesn't support currently "no_blanks": "notContainsBlanks", // Doesn't support currently "errors": "containsErrors", // Doesn't support currently "no_errors": "notContainsErrors", // Doesn't support currently "2_color_scale": "2_color_scale", "3_color_scale": "3_color_scale", "data_bar": "dataBar", "formula": "expression", } // criteriaType defined the list of valid criteria types. var criteriaType = map[string]string{ "between": "between", "not between": "notBetween", "equal to": "equal", "=": "equal", "==": "equal", "not equal to": "notEqual", "!=": "notEqual", "<>": "notEqual", "greater than": "greaterThan", ">": "greaterThan", "less than": "lessThan", "<": "lessThan", "greater than or equal to": "greaterThanOrEqual", ">=": "greaterThanOrEqual", "less than or equal to": "lessThanOrEqual", "<=": "lessThanOrEqual", "containing": "containsText", "not containing": "notContains", "begins with": "beginsWith", "ends with": "endsWith", "yesterday": "yesterday", "today": "today", "last 7 days": "last7Days", "last week": "lastWeek", "this week": "thisWeek", "continue week": "continueWeek", "last month": "lastMonth", "this month": "thisMonth", "continue month": "continueMonth", } // formatToString provides function to return original string by given built-in // number formats code and cell string. func formatToString(i int, v string) string { return v } // formatToInt provides function to convert original string to integer format as // string type by given built-in number formats code and cell string. func formatToInt(i int, v string) string { f, err := strconv.ParseFloat(v, 64) if err != nil { return v } return fmt.Sprintf("%d", int(f)) } // formatToFloat provides function to convert original string to float format as // string type by given built-in number formats code and cell string. func formatToFloat(i int, v string) string { f, err := strconv.ParseFloat(v, 64) if err != nil { return v } return fmt.Sprintf("%.2f", f) } // formatToA provides function to convert original string to special format as // string type by given built-in number formats code and cell string. func formatToA(i int, v string) string { f, err := strconv.ParseFloat(v, 64) if err != nil { return v } if f < 0 { t := int(math.Abs(f)) return fmt.Sprintf("(%d)", t) } t := int(f) return fmt.Sprintf("%d", t) } // formatToB provides function to convert original string to special format as // string type by given built-in number formats code and cell string. func formatToB(i int, v string) string { f, err := strconv.ParseFloat(v, 64) if err != nil { return v } if f < 0 { return fmt.Sprintf("(%.2f)", f) } return fmt.Sprintf("%.2f", f) } // formatToC provides function to convert original string to special format as // string type by given built-in number formats code and cell string. func formatToC(i int, v string) string { f, err := strconv.ParseFloat(v, 64) if err != nil { return v } f = f * 100 return fmt.Sprintf("%d%%", int(f)) } // formatToD provides function to convert original string to special format as // string type by given built-in number formats code and cell string. func formatToD(i int, v string) string { f, err := strconv.ParseFloat(v, 64) if err != nil { return v } f = f * 100 return fmt.Sprintf("%.2f%%", f) } // formatToE provides function to convert original string to special format as // string type by given built-in number formats code and cell string. func formatToE(i int, v string) string { f, err := strconv.ParseFloat(v, 64) if err != nil { return v } return fmt.Sprintf("%.e", f) } // parseTime provides function to returns a string parsed using time.Time. // Replace Excel placeholders with Go time placeholders. For example, replace // yyyy with 2006. These are in a specific order, due to the fact that m is used // in month, minute, and am/pm. It would be easier to fix that with regular // expressions, but if it's possible to keep this simple it would be easier to // maintain. Full-length month and days (e.g. March, Tuesday) have letters in // them that would be replaced by other characters below (such as the 'h' in // March, or the 'd' in Tuesday) below. First we convert them to arbitrary // characters unused in Excel Date formats, and then at the end, turn them to // what they should actually be. // Based off: http://www.ozgrid.com/Excel/CustomFormats.htm func parseTime(i int, v string) string { f, err := strconv.ParseFloat(v, 64) if err != nil { return v } val := timeFromExcelTime(f, false) format := builtInNumFmt[i] replacements := []struct{ xltime, gotime string }{ {"yyyy", "2006"}, {"yy", "06"}, {"mmmm", "%%%%"}, {"dddd", "&&&&"}, {"dd", "02"}, {"d", "2"}, {"mmm", "Jan"}, {"mmss", "0405"}, {"ss", "05"}, {"mm:", "04:"}, {":mm", ":04"}, {"mm", "01"}, {"am/pm", "pm"}, {"m/", "1/"}, {"%%%%", "January"}, {"&&&&", "Monday"}, } // It is the presence of the "am/pm" indicator that determines if this is // a 12 hour or 24 hours time format, not the number of 'h' characters. if is12HourTime(format) { format = strings.Replace(format, "hh", "03", 1) format = strings.Replace(format, "h", "3", 1) } else { format = strings.Replace(format, "hh", "15", 1) format = strings.Replace(format, "h", "15", 1) } for _, repl := range replacements { format = strings.Replace(format, repl.xltime, repl.gotime, 1) } // If the hour is optional, strip it out, along with the possible dangling // colon that would remain. if val.Hour() < 1 { format = strings.Replace(format, "]:", "]", 1) format = strings.Replace(format, "[03]", "", 1) format = strings.Replace(format, "[3]", "", 1) format = strings.Replace(format, "[15]", "", 1) } else { format = strings.Replace(format, "[3]", "3", 1) format = strings.Replace(format, "[15]", "15", 1) } return val.Format(format) } // is12HourTime checks whether an Excel time format string is a 12 hours form. func is12HourTime(format string) bool { return strings.Contains(format, "am/pm") || strings.Contains(format, "AM/PM") || strings.Contains(format, "a/p") || strings.Contains(format, "A/P") } // stylesReader provides function to get the pointer to the structure after // deserialization of xl/styles.xml. func (f *File) stylesReader() *xlsxStyleSheet { if f.Styles == nil { var styleSheet xlsxStyleSheet _ = xml.Unmarshal([]byte(f.readXML("xl/styles.xml")), &styleSheet) f.Styles = &styleSheet } return f.Styles } // styleSheetWriter provides function to save xl/styles.xml after serialize // structure. func (f *File) styleSheetWriter() { if f.Styles != nil { output, _ := xml.Marshal(f.Styles) f.saveFileList("xl/styles.xml", replaceWorkSheetsRelationshipsNameSpaceBytes(output)) } } // parseFormatStyleSet provides function to parse the format settings of the // cells and conditional formats. func parseFormatStyleSet(style string) (*formatStyle, error) { format := formatStyle{ DecimalPlaces: 2, } err := json.Unmarshal([]byte(style), &format) return &format, err } // NewStyle provides function to create style for cells by given style format. // Note that the color field uses RGB color code. // // The following shows the border styles sorted by excelize index number: // // Index | Name | Weight | Style // -------+---------------+--------+------------- // 0 | None | 0 | // 1 | Continuous | 1 | ----------- // 2 | Continuous | 2 | ----------- // 3 | Dash | 1 | - - - - - - // 4 | Dot | 1 | . . . . . . // 5 | Continuous | 3 | ----------- // 6 | Double | 3 | =========== // 7 | Continuous | 0 | ----------- // 8 | Dash | 2 | - - - - - - // 9 | Dash Dot | 1 | - . - . - . // 10 | Dash Dot | 2 | - . - . - . // 11 | Dash Dot Dot | 1 | - . . - . . // 12 | Dash Dot Dot | 2 | - . . - . . // 13 | SlantDash Dot | 2 | / - . / - . // // The following shows the borders in the order shown in the Excel dialog: // // Index | Style | Index | Style // -------+-------------+-------+------------- // 0 | None | 12 | - . . - . . // 7 | ----------- | 13 | / - . / - . // 4 | . . . . . . | 10 | - . - . - . // 11 | - . . - . . | 8 | - - - - - - // 9 | - . - . - . | 2 | ----------- // 3 | - - - - - - | 5 | ----------- // 1 | ----------- | 6 | =========== // // The following shows the shading styles sorted by excelize index number: // // Index | Style | Index | Style // -------+-----------------+-------+----------------- // 0 | Horizontal | 3 | Diagonal down // 1 | Vertical | 4 | From corner // 2 | Diagonal Up | 5 | From center // // The following shows the patterns styles sorted by excelize index number: // // Index | Style | Index | Style // -------+-----------------+-------+----------------- // 0 | None | 10 | darkTrellis // 1 | solid | 11 | lightHorizontal // 2 | mediumGray | 12 | lightVertical // 3 | darkGray | 13 | lightDown // 4 | lightGray | 14 | lightUp // 5 | darkHorizontal | 15 | lightGrid // 6 | darkVertical | 16 | lightTrellis // 7 | darkDown | 17 | gray125 // 8 | darkUp | 18 | gray0625 // 9 | darkGrid | | // // The following the type of horizontal alignment in cells: // // Style // ------------------ // left // center // right // fill // justify // centerContinuous // distributed // // The following the type of vertical alignment in cells: // // Style // ------------------ // top // center // justify // distributed // // The following the type of font underline style: // // Style // ------------------ // single // double // // Excel's built-in all languages formats are shown in the following table: // // Index | Format String // -------+---------------------------------------------------- // 0 | General // 1 | 0 // 2 | 0.00 // 3 | #,##0 // 4 | #,##0.00 // 5 | ($#,##0_);($#,##0) // 6 | ($#,##0_);[Red]($#,##0) // 7 | ($#,##0.00_);($#,##0.00) // 8 | ($#,##0.00_);[Red]($#,##0.00) // 9 | 0% // 10 | 0.00% // 11 | 0.00E+00 // 12 | # ?/? // 13 | # ??/?? // 14 | m/d/yy // 15 | d-mmm-yy // 16 | d-mmm // 17 | mmm-yy // 18 | h:mm AM/PM // 19 | h:mm:ss AM/PM // 20 | h:mm // 21 | h:mm:ss // 22 | m/d/yy h:mm // ... | ... // 37 | (#,##0_);(#,##0) // 38 | (#,##0_);[Red](#,##0) // 39 | (#,##0.00_);(#,##0.00) // 40 | (#,##0.00_);[Red](#,##0.00) // 41 | _(* #,##0_);_(* (#,##0);_(* "-"_);_(@_) // 42 | _($* #,##0_);_($* (#,##0);_($* "-"_);_(@_) // 43 | _(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_) // 44 | _($* #,##0.00_);_($* (#,##0.00);_($* "-"??_);_(@_) // 45 | mm:ss // 46 | [h]:mm:ss // 47 | mm:ss.0 // 48 | ##0.0E+0 // 49 | @ // // Number format code in zh-tw language: // // Index | Symbol // -------+------------------------------------------- // 27 | [$-404]e/m/d // 28 | [$-404]e"年"m"月"d"日" // 29 | [$-404]e"年"m"月"d"日" // 30 | m/d/yy // 31 | yyyy"年"m"月"d"日" // 32 | hh"時"mm"分" // 33 | hh"時"mm"分"ss"秒" // 34 | 上午/下午 hh"時"mm"分" // 35 | 上午/下午 hh"時"mm"分"ss"秒" // 36 | [$-404]e/m/d // 50 | [$-404]e/m/d // 51 | [$-404]e"年"m"月"d"日" // 52 | 上午/下午 hh"時"mm"分" // 53 | 上午/下午 hh"時"mm"分"ss"秒" // 54 | [$-404]e"年"m"月"d"日" // 55 | 上午/下午 hh"時"mm"分" // 56 | 上午/下午 hh"時"mm"分"ss"秒" // 57 | [$-404]e/m/d // 58 | [$-404]e"年"m"月"d"日" // // Number format code in zh-cn language: // // Index | Symbol // -------+------------------------------------------- // 27 | yyyy"年"m"月" // 28 | m"月"d"日" // 29 | m"月"d"日" // 30 | m-d-yy // 31 | yyyy"年"m"月"d"日" // 32 | h"时"mm"分" // 33 | h"时"mm"分"ss"秒" // 34 | 上午/下午 h"时"mm"分" // 35 | 上午/下午 h"时"mm"分"ss"秒 // 36 | yyyy"年"m"月 // 50 | yyyy"年"m"月 // 51 | m"月"d"日 // 52 | yyyy"年"m"月 // 53 | m"月"d"日 // 54 | m"月"d"日 // 55 | 上午/下午 h"时"mm"分 // 56 | 上午/下午 h"时"mm"分"ss"秒 // 57 | yyyy"年"m"月 // 58 | m"月"d"日" // // Number format code with unicode values provided for language glyphs where // they occur in zh-tw language: // // Index | Symbol // -------+------------------------------------------- // 27 | [$-404]e/m/ // 28 | [$-404]e"5E74"m"6708"d"65E5 // 29 | [$-404]e"5E74"m"6708"d"65E5 // 30 | m/d/y // 31 | yyyy"5E74"m"6708"d"65E5 // 32 | hh"6642"mm"5206 // 33 | hh"6642"mm"5206"ss"79D2 // 34 | 4E0A5348/4E0B5348hh"6642"mm"5206 // 35 | 4E0A5348/4E0B5348hh"6642"mm"5206"ss"79D2 // 36 | [$-404]e/m/ // 50 | [$-404]e/m/ // 51 | [$-404]e"5E74"m"6708"d"65E5 // 52 | 4E0A5348/4E0B5348hh"6642"mm"5206 // 53 | 4E0A5348/4E0B5348hh"6642"mm"5206"ss"79D2 // 54 | [$-404]e"5E74"m"6708"d"65E5 // 55 | 4E0A5348/4E0B5348hh"6642"mm"5206 // 56 | 4E0A5348/4E0B5348hh"6642"mm"5206"ss"79D2 // 57 | [$-404]e/m/ // 58 | [$-404]e"5E74"m"6708"d"65E5" // // Number format code with unicode values provided for language glyphs where // they occur in zh-cn language: // // Index | Symbol // -------+------------------------------------------- // 27 | yyyy"5E74"m"6708 // 28 | m"6708"d"65E5 // 29 | m"6708"d"65E5 // 30 | m-d-y // 31 | yyyy"5E74"m"6708"d"65E5 // 32 | h"65F6"mm"5206 // 33 | h"65F6"mm"5206"ss"79D2 // 34 | 4E0A5348/4E0B5348h"65F6"mm"5206 // 35 | 4E0A5348/4E0B5348h"65F6"mm"5206"ss"79D2 // 36 | yyyy"5E74"m"6708 // 50 | yyyy"5E74"m"6708 // 51 | m"6708"d"65E5 // 52 | yyyy"5E74"m"6708 // 53 | m"6708"d"65E5 // 54 | m"6708"d"65E5 // 55 | 4E0A5348/4E0B5348h"65F6"mm"5206 // 56 | 4E0A5348/4E0B5348h"65F6"mm"5206"ss"79D2 // 57 | yyyy"5E74"m"6708 // 58 | m"6708"d"65E5" // // Number format code in ja-jp language: // // Index | Symbol // -------+------------------------------------------- // 27 | [$-411]ge.m.d // 28 | [$-411]ggge"年"m"月"d"日 // 29 | [$-411]ggge"年"m"月"d"日 // 30 | m/d/y // 31 | yyyy"年"m"月"d"日 // 32 | h"時"mm"分 // 33 | h"時"mm"分"ss"秒 // 34 | yyyy"年"m"月 // 35 | m"月"d"日 // 36 | [$-411]ge.m.d // 50 | [$-411]ge.m.d // 51 | [$-411]ggge"年"m"月"d"日 // 52 | yyyy"年"m"月 // 53 | m"月"d"日 // 54 | [$-411]ggge"年"m"月"d"日 // 55 | yyyy"年"m"月 // 56 | m"月"d"日 // 57 | [$-411]ge.m.d // 58 | [$-411]ggge"年"m"月"d"日" // // Number format code in ko-kr language: // // Index | Symbol // -------+------------------------------------------- // 27 | yyyy"年" mm"月" dd"日 // 28 | mm-d // 29 | mm-d // 30 | mm-dd-y // 31 | yyyy"년" mm"월" dd"일 // 32 | h"시" mm"분 // 33 | h"시" mm"분" ss"초 // 34 | yyyy-mm-d // 35 | yyyy-mm-d // 36 | yyyy"年" mm"月" dd"日 // 50 | yyyy"年" mm"月" dd"日 // 51 | mm-d // 52 | yyyy-mm-d // 53 | yyyy-mm-d // 54 | mm-d // 55 | yyyy-mm-d // 56 | yyyy-mm-d // 57 | yyyy"年" mm"月" dd"日 // 58 | mm-dd // // Number format code with unicode values provided for language glyphs where // they occur in ja-jp language: // // Index | Symbol // -------+------------------------------------------- // 27 | [$-411]ge.m.d // 28 | [$-411]ggge"5E74"m"6708"d"65E5 // 29 | [$-411]ggge"5E74"m"6708"d"65E5 // 30 | m/d/y // 31 | yyyy"5E74"m"6708"d"65E5 // 32 | h"6642"mm"5206 // 33 | h"6642"mm"5206"ss"79D2 // 34 | yyyy"5E74"m"6708 // 35 | m"6708"d"65E5 // 36 | [$-411]ge.m.d // 50 | [$-411]ge.m.d // 51 | [$-411]ggge"5E74"m"6708"d"65E5 // 52 | yyyy"5E74"m"6708 // 53 | m"6708"d"65E5 // 54 | [$-411]ggge"5E74"m"6708"d"65E5 // 55 | yyyy"5E74"m"6708 // 56 | m"6708"d"65E5 // 57 | [$-411]ge.m.d // 58 | [$-411]ggge"5E74"m"6708"d"65E5" // // Number format code with unicode values provided for language glyphs where // they occur in ko-kr language: // // Index | Symbol // -------+------------------------------------------- // 27 | yyyy"5E74" mm"6708" dd"65E5 // 28 | mm-d // 29 | mm-d // 30 | mm-dd-y // 31 | yyyy"B144" mm"C6D4" dd"C77C // 32 | h"C2DC" mm"BD84 // 33 | h"C2DC" mm"BD84" ss"CD08 // 34 | yyyy-mm-d // 35 | yyyy-mm-d // 36 | yyyy"5E74" mm"6708" dd"65E5 // 50 | yyyy"5E74" mm"6708" dd"65E5 // 51 | mm-d // 52 | yyyy-mm-d // 53 | yyyy-mm-d // 54 | mm-d // 55 | yyyy-mm-d // 56 | yyyy-mm-d // 57 | yyyy"5E74" mm"6708" dd"65E5 // 58 | mm-dd // // Number format code in th-th language: // // Index | Symbol // -------+------------------------------------------- // 59 | t // 60 | t0.0 // 61 | t#,## // 62 | t#,##0.0 // 67 | t0 // 68 | t0.00 // 69 | t# ?/ // 70 | t# ??/? // 71 | ว/ด/ปปป // 72 | ว-ดดด-ป // 73 | ว-ดด // 74 | ดดด-ป // 75 | ช:น // 76 | ช:นน:ท // 77 | ว/ด/ปปปป ช:น // 78 | นน:ท // 79 | [ช]:นน:ท // 80 | นน:ทท. // 81 | d/m/bb // // Number format code with unicode values provided for language glyphs where // they occur in th-th language: // // Index | Symbol // -------+------------------------------------------- // 59 | t // 60 | t0.0 // 61 | t#,## // 62 | t#,##0.0 // 67 | t0 // 68 | t0.00 // 69 | t# ?/ // 70 | t# ??/? // 71 | 0E27/0E14/0E1B0E1B0E1B0E1 // 72 | 0E27-0E140E140E14-0E1B0E1 // 73 | 0E27-0E140E140E1 // 74 | 0E140E140E14-0E1B0E1 // 75 | 0E0A:0E190E1 // 76 | 0E0A:0E190E19:0E170E1 // 77 | 0E27/0E14/0E1B0E1B0E1B0E1B 0E0A:0E190E1 // 78 | 0E190E19:0E170E1 // 79 | [0E0A]:0E190E19:0E170E1 // 80 | 0E190E19:0E170E17. // 81 | d/m/bb // // Excelize built-in currency formats are shown in the following table, only // support these types in the following table (Index number is used only for // markup and is not used inside an Excel file and you can't get formatted value // by the function GetCellValue) currently: // // Index | Symbol // -------+--------------------------------------------------------------- // 164 | CN¥ // 165 | $ English (China) // 166 | $ Cherokee (United States) // 167 | $ Chinese (Singapore) // 168 | $ Chinese (Taiwan) // 169 | $ English (Australia) // 170 | $ English (Belize) // 171 | $ English (Canada) // 172 | $ English (Jamaica) // 173 | $ English (New Zealand) // 174 | $ English (Singapore) // 175 | $ English (Trinidad & Tobago) // 176 | $ English (U.S. Vigin Islands) // 177 | $ English (United States) // 178 | $ French (Canada) // 179 | $ Hawaiian (United States) // 180 | $ Malay (Brunei) // 181 | $ Quechua (Ecuador) // 182 | $ Spanish (Chile) // 183 | $ Spanish (Colombia) // 184 | $ Spanish (Ecuador) // 185 | $ Spanish (El Salvador) // 186 | $ Spanish (Mexico) // 187 | $ Spanish (Puerto Rico) // 188 | $ Spanish (United States) // 189 | $ Spanish (Uruguay) // 190 | £ English (United Kingdom) // 191 | £ Scottish Gaelic (United Kingdom) // 192 | £ Welsh (United Kindom) // 193 | ¥ Chinese (China) // 194 | ¥ Japanese (Japan) // 195 | ¥ Sichuan Yi (China) // 196 | ¥ Tibetan (China) // 197 | ¥ Uyghur (China) // 198 | ֏ Armenian (Armenia) // 199 | ؋ Pashto (Afghanistan) // 200 | ؋ Persian (Afghanistan) // 201 | ৳ Bengali (Bangladesh) // 202 | ៛ Khmer (Cambodia) // 203 | ₡ Spanish (Costa Rica) // 204 | ₦ Hausa (Nigeria) // 205 | ₦ Igbo (Nigeria) // 206 | ₦ Yoruba (Nigeria) // 207 | ₩ Korean (South Korea) // 208 | ₪ Hebrew (Israel) // 209 | ₫ Vietnamese (Vietnam) // 210 | € Basque (Spain) // 211 | € Breton (France) // 212 | € Catalan (Spain) // 213 | € Corsican (France) // 214 | € Dutch (Belgium) // 215 | € Dutch (Netherlands) // 216 | € English (Ireland) // 217 | € Estonian (Estonia) // 218 | € Euro (€ 123) // 219 | € Euro (123 €) // 220 | € Finnish (Finland) // 221 | € French (Belgium) // 222 | € French (France) // 223 | € French (Luxembourg) // 224 | € French (Monaco) // 225 | € French (Réunion) // 226 | € Galician (Spain) // 227 | € German (Austria) // 228 | € German (Luxembourg) // 229 | € Greek (Greece) // 230 | € Inari Sami (Finland) // 231 | € Irish (Ireland) // 232 | € Italian (Italy) // 233 | € Latin (Italy) // 234 | € Latin, Serbian (Montenegro) // 235 | € Larvian (Latvia) // 236 | € Lithuanian (Lithuania) // 237 | € Lower Sorbian (Germany) // 238 | € Luxembourgish (Luxembourg) // 239 | € Maltese (Malta) // 240 | € Northern Sami (Finland) // 241 | € Occitan (France) // 242 | € Portuguese (Portugal) // 243 | € Serbian (Montenegro) // 244 | € Skolt Sami (Finland) // 245 | € Slovak (Slovakia) // 246 | € Slovenian (Slovenia) // 247 | € Spanish (Spain) // 248 | € Swedish (Finland) // 249 | € Swiss German (France) // 250 | € Upper Sorbian (Germany) // 251 | € Western Frisian (Netherlands) // 252 | ₭ Lao (Laos) // 253 | ₮ Mongolian (Mongolia) // 254 | ₮ Mongolian, Mongolian (Mongolia) // 255 | ₱ English (Philippines) // 256 | ₱ Filipino (Philippines) // 257 | ₴ Ukrainian (Ukraine) // 258 | ₸ Kazakh (Kazakhstan) // 259 | ₹ Arabic, Kashmiri (India) // 260 | ₹ English (India) // 261 | ₹ Gujarati (India) // 262 | ₹ Hindi (India) // 263 | ₹ Kannada (India) // 264 | ₹ Kashmiri (India) // 265 | ₹ Konkani (India) // 266 | ₹ Manipuri (India) // 267 | ₹ Marathi (India) // 268 | ₹ Nepali (India) // 269 | ₹ Oriya (India) // 270 | ₹ Punjabi (India) // 271 | ₹ Sanskrit (India) // 272 | ₹ Sindhi (India) // 273 | ₹ Tamil (India) // 274 | ₹ Urdu (India) // 275 | ₺ Turkish (Turkey) // 276 | ₼ Azerbaijani (Azerbaijan) // 277 | ₼ Cyrillic, Azerbaijani (Azerbaijan) // 278 | ₽ Russian (Russia) // 279 | ₽ Sakha (Russia) // 280 | ₾ Georgian (Georgia) // 281 | B/. Spanish (Panama) // 282 | Br Oromo (Ethiopia) // 283 | Br Somali (Ethiopia) // 284 | Br Tigrinya (Ethiopia) // 285 | Bs Quechua (Bolivia) // 286 | Bs Spanish (Bolivia) // 287 | BS. Spanish (Venezuela) // 288 | BWP Tswana (Botswana) // 289 | C$ Spanish (Nicaragua) // 290 | CA$ Latin, Inuktitut (Canada) // 291 | CA$ Mohawk (Canada) // 292 | CA$ Unified Canadian Aboriginal Syllabics, Inuktitut (Canada) // 293 | CFA French (Mali) // 294 | CFA French (Senegal) // 295 | CFA Fulah (Senegal) // 296 | CFA Wolof (Senegal) // 297 | CHF French (Switzerland) // 298 | CHF German (Liechtenstein) // 299 | CHF German (Switzerland) // 300 | CHF Italian (Switzerland) // 301 | CHF Romansh (Switzerland) // 302 | CLP Mapuche (Chile) // 303 | CN¥ Mongolian, Mongolian (China) // 304 | DZD Central Atlas Tamazight (Algeria) // 305 | FCFA French (Cameroon) // 306 | Ft Hungarian (Hungary) // 307 | G French (Haiti) // 308 | Gs. Spanish (Paraguay) // 309 | GTQ K'iche' (Guatemala) // 310 | HK$ Chinese (Hong Kong (China)) // 311 | HK$ English (Hong Kong (China)) // 312 | HRK Croatian (Croatia) // 313 | IDR English (Indonesia) // 314 | IQD Arbic, Central Kurdish (Iraq) // 315 | ISK Icelandic (Iceland) // 316 | K Burmese (Myanmar (Burma)) // 317 | Kč Czech (Czech Republic) // 318 | KM Bosnian (Bosnia & Herzegovina) // 319 | KM Croatian (Bosnia & Herzegovina) // 320 | KM Latin, Serbian (Bosnia & Herzegovina) // 321 | kr Faroese (Faroe Islands) // 322 | kr Northern Sami (Norway) // 323 | kr Northern Sami (Sweden) // 324 | kr Norwegian Bokmål (Norway) // 325 | kr Norwegian Nynorsk (Norway) // 326 | kr Swedish (Sweden) // 327 | kr. Danish (Denmark) // 328 | kr. Kalaallisut (Greenland) // 329 | Ksh Swahili (kenya) // 330 | L Romanian (Moldova) // 331 | L Russian (Moldova) // 332 | L Spanish (Honduras) // 333 | Lekë Albanian (Albania) // 334 | MAD Arabic, Central Atlas Tamazight (Morocco) // 335 | MAD French (Morocco) // 336 | MAD Tifinagh, Central Atlas Tamazight (Morocco) // 337 | MOP$ Chinese (Macau (China)) // 338 | MVR Divehi (Maldives) // 339 | Nfk Tigrinya (Eritrea) // 340 | NGN Bini (Nigeria) // 341 | NGN Fulah (Nigeria) // 342 | NGN Ibibio (Nigeria) // 343 | NGN Kanuri (Nigeria) // 344 | NOK Lule Sami (Norway) // 345 | NOK Southern Sami (Norway) // 346 | NZ$ Maori (New Zealand) // 347 | PKR Sindhi (Pakistan) // 348 | PYG Guarani (Paraguay) // 349 | Q Spanish (Guatemala) // 350 | R Afrikaans (South Africa) // 351 | R English (South Africa) // 352 | R Zulu (South Africa) // 353 | R$ Portuguese (Brazil) // 354 | RD$ Spanish (Dominican Republic) // 355 | RF Kinyarwanda (Rwanda) // 356 | RM English (Malaysia) // 357 | RM Malay (Malaysia) // 358 | RON Romanian (Romania) // 359 | Rp Indonesoan (Indonesia) // 360 | Rs Urdu (Pakistan) // 361 | Rs. Tamil (Sri Lanka) // 362 | RSD Latin, Serbian (Serbia) // 363 | RSD Serbian (Serbia) // 364 | RUB Bashkir (Russia) // 365 | RUB Tatar (Russia) // 366 | S/. Quechua (Peru) // 367 | S/. Spanish (Peru) // 368 | SEK Lule Sami (Sweden) // 369 | SEK Southern Sami (Sweden) // 370 | soʻm Latin, Uzbek (Uzbekistan) // 371 | soʻm Uzbek (Uzbekistan) // 372 | SYP Syriac (Syria) // 373 | THB Thai (Thailand) // 374 | TMT Turkmen (Turkmenistan) // 375 | US$ English (Zimbabwe) // 376 | ZAR Northern Sotho (South Africa) // 377 | ZAR Southern Sotho (South Africa) // 378 | ZAR Tsonga (South Africa) // 379 | ZAR Tswana (south Africa) // 380 | ZAR Venda (South Africa) // 381 | ZAR Xhosa (South Africa) // 382 | zł Polish (Poland) // 383 | ден Macedonian (Macedonia) // 384 | KM Cyrillic, Bosnian (Bosnia & Herzegovina) // 385 | KM Serbian (Bosnia & Herzegovina) // 386 | лв. Bulgarian (Bulgaria) // 387 | p. Belarusian (Belarus) // 388 | сом Kyrgyz (Kyrgyzstan) // 389 | сом Tajik (Tajikistan) // 390 | ج.م. Arabic (Egypt) // 391 | د.أ. Arabic (Jordan) // 392 | د.أ. Arabic (United Arab Emirates) // 393 | د.ب. Arabic (Bahrain) // 394 | د.ت. Arabic (Tunisia) // 395 | د.ج. Arabic (Algeria) // 396 | د.ع. Arabic (Iraq) // 397 | د.ك. Arabic (Kuwait) // 398 | د.ل. Arabic (Libya) // 399 | د.م. Arabic (Morocco) // 400 | ر Punjabi (Pakistan) // 401 | ر.س. Arabic (Saudi Arabia) // 402 | ر.ع. Arabic (Oman) // 403 | ر.ق. Arabic (Qatar) // 404 | ر.ي. Arabic (Yemen) // 405 | ریال Persian (Iran) // 406 | ل.س. Arabic (Syria) // 407 | ل.ل. Arabic (Lebanon) // 408 | ብር Amharic (Ethiopia) // 409 | रू Nepaol (Nepal) // 410 | රු. Sinhala (Sri Lanka) // 411 | ADP // 412 | AED // 413 | AFA // 414 | AFN // 415 | ALL // 416 | AMD // 417 | ANG // 418 | AOA // 419 | ARS // 420 | ATS // 421 | AUD // 422 | AWG // 423 | AZM // 424 | AZN // 425 | BAM // 426 | BBD // 427 | BDT // 428 | BEF // 429 | BGL // 430 | BGN // 431 | BHD // 432 | BIF // 433 | BMD // 434 | BND // 435 | BOB // 436 | BOV // 437 | BRL // 438 | BSD // 439 | BTN // 440 | BWP // 441 | BYR // 442 | BZD // 443 | CAD // 444 | CDF // 445 | CHE // 446 | CHF // 447 | CHW // 448 | CLF // 449 | CLP // 450 | CNY // 451 | COP // 452 | COU // 453 | CRC // 454 | CSD // 455 | CUC // 456 | CVE // 457 | CYP // 458 | CZK // 459 | DEM // 460 | DJF // 461 | DKK // 462 | DOP // 463 | DZD // 464 | ECS // 465 | ECV // 466 | EEK // 467 | EGP // 468 | ERN // 469 | ESP // 470 | ETB // 471 | EUR // 472 | FIM // 473 | FJD // 474 | FKP // 475 | FRF // 476 | GBP // 477 | GEL // 478 | GHC // 479 | GHS // 480 | GIP // 481 | GMD // 482 | GNF // 483 | GRD // 484 | GTQ // 485 | GYD // 486 | HKD // 487 | HNL // 488 | HRK // 489 | HTG // 490 | HUF // 491 | IDR // 492 | IEP // 493 | ILS // 494 | INR // 495 | IQD // 496 | IRR // 497 | ISK // 498 | ITL // 499 | JMD // 500 | JOD // 501 | JPY // 502 | KAF // 503 | KES // 504 | KGS // 505 | KHR // 506 | KMF // 507 | KPW // 508 | KRW // 509 | KWD // 510 | KYD // 511 | KZT // 512 | LAK // 513 | LBP // 514 | LKR // 515 | LRD // 516 | LSL // 517 | LTL // 518 | LUF // 519 | LVL // 520 | LYD // 521 | MAD // 522 | MDL // 523 | MGA // 524 | MGF // 525 | MKD // 526 | MMK // 527 | MNT // 528 | MOP // 529 | MRO // 530 | MTL // 531 | MUR // 532 | MVR // 533 | MWK // 534 | MXN // 535 | MXV // 536 | MYR // 537 | MZM // 538 | MZN // 539 | NAD // 540 | NGN // 541 | NIO // 542 | NLG // 543 | NOK // 544 | NPR // 545 | NTD // 546 | NZD // 547 | OMR // 548 | PAB // 549 | PEN // 550 | PGK // 551 | PHP // 552 | PKR // 553 | PLN // 554 | PTE // 555 | PYG // 556 | QAR // 557 | ROL // 558 | RON // 559 | RSD // 560 | RUB // 561 | RUR // 562 | RWF // 563 | SAR // 564 | SBD // 565 | SCR // 566 | SDD // 567 | SDG // 568 | SDP // 569 | SEK // 570 | SGD // 571 | SHP // 572 | SIT // 573 | SKK // 574 | SLL // 575 | SOS // 576 | SPL // 577 | SRD // 578 | SRG // 579 | STD // 580 | SVC // 581 | SYP // 582 | SZL // 583 | THB // 584 | TJR // 585 | TJS // 586 | TMM // 587 | TMT // 588 | TND // 589 | TOP // 590 | TRL // 591 | TRY // 592 | TTD // 593 | TWD // 594 | TZS // 595 | UAH // 596 | UGX // 597 | USD // 598 | USN // 599 | USS // 600 | UYI // 601 | UYU // 602 | UZS // 603 | VEB // 604 | VEF // 605 | VND // 606 | VUV // 607 | WST // 608 | XAF // 609 | XAG // 610 | XAU // 611 | XB5 // 612 | XBA // 613 | XBB // 614 | XBC // 615 | XBD // 616 | XCD // 617 | XDR // 618 | XFO // 619 | XFU // 620 | XOF // 621 | XPD // 622 | XPF // 623 | XPT // 624 | XTS // 625 | XXX // 626 | YER // 627 | YUM // 628 | ZAR // 629 | ZMK // 630 | ZMW // 631 | ZWD // 632 | ZWL // 633 | ZWN // 634 | ZWR // // Excelize support set custom number format for cell. For example, set number // as date type in Uruguay (Spanish) format for Sheet1!A6: // // xlsx := excelize.NewFile() // xlsx.SetCellValue("Sheet1", "A6", 42920.5) // style, _ := xlsx.NewStyle(`{"custom_number_format": "[$-380A]dddd\\,\\ dd\" de \"mmmm\" de \"yyyy;@"}`) // xlsx.SetCellStyle("Sheet1", "A6", "A6", style) // // Cell Sheet1!A6 in the Excel Application: martes, 04 de Julio de 2017 // func (f *File) NewStyle(style string) (int, error) { var cellXfsID, fontID, borderID, fillID int s := f.stylesReader() fs, err := parseFormatStyleSet(style) if err != nil { return cellXfsID, err } numFmtID := setNumFmt(s, fs) if fs.Font != nil { font, _ := xml.Marshal(setFont(fs)) s.Fonts.Count++ s.Fonts.Font = append(s.Fonts.Font, &xlsxFont{ Font: string(font[6 : len(font)-7]), }) fontID = s.Fonts.Count - 1 } s.Borders.Count++ s.Borders.Border = append(s.Borders.Border, setBorders(fs)) borderID = s.Borders.Count - 1 s.Fills.Count++ s.Fills.Fill = append(s.Fills.Fill, setFills(fs, true)) fillID = s.Fills.Count - 1 applyAlignment, alignment := fs.Alignment != nil, setAlignment(fs) applyProtection, protection := fs.Protection != nil, setProtection(fs) cellXfsID = setCellXfs(s, fontID, numFmtID, fillID, borderID, applyAlignment, applyProtection, alignment, protection) return cellXfsID, nil } // NewConditionalStyle provides function to create style for conditional format // by given style format. The parameters are the same as function NewStyle(). // Note that the color field uses RGB color code and only support to set font, // fills, alignment and borders currently. func (f *File) NewConditionalStyle(style string) (int, error) { s := f.stylesReader() fs, err := parseFormatStyleSet(style) if err != nil { return 0, err } dxf := dxf{ Fill: setFills(fs, false), Alignment: setAlignment(fs), Border: setBorders(fs), } if fs.Font != nil { dxf.Font = setFont(fs) } dxfStr, _ := xml.Marshal(dxf) if s.Dxfs == nil { s.Dxfs = &xlsxDxfs{} } s.Dxfs.Count++ s.Dxfs.Dxfs = append(s.Dxfs.Dxfs, &xlsxDxf{ Dxf: string(dxfStr[5 : len(dxfStr)-6]), }) return s.Dxfs.Count - 1, nil } // setFont provides function to add font style by given cell format settings. func setFont(formatStyle *formatStyle) *font { fontUnderlineType := map[string]string{"single": "single", "double": "double"} if formatStyle.Font.Size < 1 { formatStyle.Font.Size = 11 } if formatStyle.Font.Color == "" { formatStyle.Font.Color = "#000000" } f := font{ B: formatStyle.Font.Bold, I: formatStyle.Font.Italic, Sz: &attrValInt{Val: formatStyle.Font.Size}, Color: &xlsxColor{RGB: getPaletteColor(formatStyle.Font.Color)}, Name: &attrValString{Val: formatStyle.Font.Family}, Family: &attrValInt{Val: 2}, } if f.Name.Val == "" { f.Name.Val = "Calibri" f.Scheme = &attrValString{Val: "minor"} } val, ok := fontUnderlineType[formatStyle.Font.Underline] if ok { f.U = &attrValString{Val: val} } return &f } // setNumFmt provides function to check if number format code in the range of // built-in values. func setNumFmt(style *xlsxStyleSheet, formatStyle *formatStyle) int { dp := "0." numFmtID := 164 // Default custom number format code from 164. if formatStyle.DecimalPlaces < 0 || formatStyle.DecimalPlaces > 30 { formatStyle.DecimalPlaces = 2 } for i := 0; i < formatStyle.DecimalPlaces; i++ { dp += "0" } if formatStyle.CustomNumFmt != nil { return setCustomNumFmt(style, formatStyle) } _, ok := builtInNumFmt[formatStyle.NumFmt] if !ok { fc, currency := currencyNumFmt[formatStyle.NumFmt] if !currency { return setLangNumFmt(style, formatStyle) } fc = strings.Replace(fc, "0.00", dp, -1) if formatStyle.NegRed { fc = fc + ";[Red]" + fc } if style.NumFmts != nil { numFmtID = style.NumFmts.NumFmt[len(style.NumFmts.NumFmt)-1].NumFmtID + 1 nf := xlsxNumFmt{ FormatCode: fc, NumFmtID: numFmtID, } style.NumFmts.NumFmt = append(style.NumFmts.NumFmt, &nf) style.NumFmts.Count++ } else { nf := xlsxNumFmt{ FormatCode: fc, NumFmtID: numFmtID, } numFmts := xlsxNumFmts{ NumFmt: []*xlsxNumFmt{&nf}, Count: 1, } style.NumFmts = &numFmts } return numFmtID } return formatStyle.NumFmt } // setCustomNumFmt provides function to set custom number format code. func setCustomNumFmt(style *xlsxStyleSheet, formatStyle *formatStyle) int { nf := xlsxNumFmt{FormatCode: *formatStyle.CustomNumFmt} if style.NumFmts != nil { nf.NumFmtID = style.NumFmts.NumFmt[len(style.NumFmts.NumFmt)-1].NumFmtID + 1 style.NumFmts.NumFmt = append(style.NumFmts.NumFmt, &nf) style.NumFmts.Count++ } else { nf.NumFmtID = 164 numFmts := xlsxNumFmts{ NumFmt: []*xlsxNumFmt{&nf}, Count: 1, } style.NumFmts = &numFmts } return nf.NumFmtID } // setLangNumFmt provides function to set number format code with language. func setLangNumFmt(style *xlsxStyleSheet, formatStyle *formatStyle) int { numFmts, ok := langNumFmt[formatStyle.Lang] if !ok { return 0 } var fc string fc, ok = numFmts[formatStyle.NumFmt] if !ok { return 0 } nf := xlsxNumFmt{FormatCode: fc} if style.NumFmts != nil { nf.NumFmtID = style.NumFmts.NumFmt[len(style.NumFmts.NumFmt)-1].NumFmtID + 1 style.NumFmts.NumFmt = append(style.NumFmts.NumFmt, &nf) style.NumFmts.Count++ } else { nf.NumFmtID = formatStyle.NumFmt numFmts := xlsxNumFmts{ NumFmt: []*xlsxNumFmt{&nf}, Count: 1, } style.NumFmts = &numFmts } return nf.NumFmtID } // setFills provides function to add fill elements in the styles.xml by given // cell format settings. func setFills(formatStyle *formatStyle, fg bool) *xlsxFill { var patterns = []string{ "none", "solid", "mediumGray", "darkGray", "lightGray", "darkHorizontal", "darkVertical", "darkDown", "darkUp", "darkGrid", "darkTrellis", "lightHorizontal", "lightVertical", "lightDown", "lightUp", "lightGrid", "lightTrellis", "gray125", "gray0625", } var variants = []float64{ 90, 0, 45, 135, } var fill xlsxFill switch formatStyle.Fill.Type { case "gradient": if len(formatStyle.Fill.Color) != 2 { break } var gradient xlsxGradientFill switch formatStyle.Fill.Shading { case 0, 1, 2, 3: gradient.Degree = variants[formatStyle.Fill.Shading] case 4: gradient.Type = "path" case 5: gradient.Type = "path" gradient.Bottom = 0.5 gradient.Left = 0.5 gradient.Right = 0.5 gradient.Top = 0.5 default: break } var stops []*xlsxGradientFillStop for index, color := range formatStyle.Fill.Color { var stop xlsxGradientFillStop stop.Position = float64(index) stop.Color.RGB = getPaletteColor(color) stops = append(stops, &stop) } gradient.Stop = stops fill.GradientFill = &gradient case "pattern": if formatStyle.Fill.Pattern > 18 || formatStyle.Fill.Pattern < 0 { break } if len(formatStyle.Fill.Color) < 1 { break } var pattern xlsxPatternFill pattern.PatternType = patterns[formatStyle.Fill.Pattern] if fg { pattern.FgColor.RGB = getPaletteColor(formatStyle.Fill.Color[0]) } else { pattern.BgColor.RGB = getPaletteColor(formatStyle.Fill.Color[0]) } fill.PatternFill = &pattern } return &fill } // setAlignment provides function to formatting information pertaining to text // alignment in cells. There are a variety of choices for how text is aligned // both horizontally and vertically, as well as indentation settings, and so on. func setAlignment(formatStyle *formatStyle) *xlsxAlignment { var alignment xlsxAlignment if formatStyle.Alignment != nil { alignment.Horizontal = formatStyle.Alignment.Horizontal alignment.Indent = formatStyle.Alignment.Indent alignment.JustifyLastLine = formatStyle.Alignment.JustifyLastLine alignment.ReadingOrder = formatStyle.Alignment.ReadingOrder alignment.RelativeIndent = formatStyle.Alignment.RelativeIndent alignment.ShrinkToFit = formatStyle.Alignment.ShrinkToFit alignment.TextRotation = formatStyle.Alignment.TextRotation alignment.Vertical = formatStyle.Alignment.Vertical alignment.WrapText = formatStyle.Alignment.WrapText } return &alignment } // setProtection provides function to set protection properties associated // with the cell. func setProtection(formatStyle *formatStyle) *xlsxProtection { var protection xlsxProtection if formatStyle.Protection != nil { protection.Hidden = formatStyle.Protection.Hidden protection.Locked = formatStyle.Protection.Locked } return &protection } // setBorders provides function to add border elements in the styles.xml by // given borders format settings. func setBorders(formatStyle *formatStyle) *xlsxBorder { var styles = []string{ "none", "thin", "medium", "dashed", "dotted", "thick", "double", "hair", "mediumDashed", "dashDot", "mediumDashDot", "dashDotDot", "mediumDashDotDot", "slantDashDot", } var border xlsxBorder for _, v := range formatStyle.Border { if 0 <= v.Style && v.Style < 14 { var color xlsxColor color.RGB = getPaletteColor(v.Color) switch v.Type { case "left": border.Left.Style = styles[v.Style] border.Left.Color = &color case "right": border.Right.Style = styles[v.Style] border.Right.Color = &color case "top": border.Top.Style = styles[v.Style] border.Top.Color = &color case "bottom": border.Bottom.Style = styles[v.Style] border.Bottom.Color = &color case "diagonalUp": border.Diagonal.Style = styles[v.Style] border.Diagonal.Color = &color border.DiagonalUp = true case "diagonalDown": border.Diagonal.Style = styles[v.Style] border.Diagonal.Color = &color border.DiagonalDown = true } } } return &border } // setCellXfs provides function to set describes all of the formatting for a // cell. func setCellXfs(style *xlsxStyleSheet, fontID, numFmtID, fillID, borderID int, applyAlignment, applyProtection bool, alignment *xlsxAlignment, protection *xlsxProtection) int { var xf xlsxXf xf.FontID = fontID if fontID != 0 { xf.ApplyFont = true } xf.NumFmtID = numFmtID if numFmtID != 0 { xf.ApplyNumberFormat = true } xf.FillID = fillID xf.BorderID = borderID style.CellXfs.Count++ xf.Alignment = alignment xf.ApplyAlignment = applyAlignment if applyProtection { xf.ApplyProtection = applyProtection xf.Protection = protection } xfID := 0 xf.XfID = &xfID style.CellXfs.Xf = append(style.CellXfs.Xf, xf) return style.CellXfs.Count - 1 } // SetCellStyle provides function to add style attribute for cells by given // worksheet name, coordinate area and style ID. Note that diagonalDown and // diagonalUp type border should be use same color in the same coordinate area. // // For example create a borders of cell H9 on Sheet1: // // style, err := xlsx.NewStyle(`{"border":[{"type":"left","color":"0000FF","style":3},{"type":"top","color":"00FF00","style":4},{"type":"bottom","color":"FFFF00","style":5},{"type":"right","color":"FF0000","style":6},{"type":"diagonalDown","color":"A020F0","style":7},{"type":"diagonalUp","color":"A020F0","style":8}]}`) // if err != nil { // fmt.Println(err) // } // xlsx.SetCellStyle("Sheet1", "H9", "H9", style) // // Set gradient fill with vertical variants shading styles for cell H9 on // Sheet1: // // style, err := xlsx.NewStyle(`{"fill":{"type":"gradient","color":["#FFFFFF","#E0EBF5"],"shading":1}}`) // if err != nil { // fmt.Println(err) // } // xlsx.SetCellStyle("Sheet1", "H9", "H9", style) // // Set solid style pattern fill for cell H9 on Sheet1: // // style, err := xlsx.NewStyle(`{"fill":{"type":"pattern","color":["#E0EBF5"],"pattern":1}}`) // if err != nil { // fmt.Println(err) // } // xlsx.SetCellStyle("Sheet1", "H9", "H9", style) // // Set alignment style for cell H9 on Sheet1: // // style, err := xlsx.NewStyle(`{"alignment":{"horizontal":"center","ident":1,"justify_last_line":true,"reading_order":0,"relative_indent":1,"shrink_to_fit":true,"text_rotation":45,"vertical":"","wrap_text":true}}`) // if err != nil { // fmt.Println(err) // } // xlsx.SetCellStyle("Sheet1", "H9", "H9", style) // // Dates and times in Excel are represented by real numbers, for example "Apr 7 // 2017 12:00 PM" is represented by the number 42920.5. Set date and time format // for cell H9 on Sheet1: // // xlsx.SetCellValue("Sheet1", "H9", 42920.5) // style, err := xlsx.NewStyle(`{"number_format": 22}`) // if err != nil { // fmt.Println(err) // } // xlsx.SetCellStyle("Sheet1", "H9", "H9", style) // // Set font style for cell H9 on Sheet1: // // style, err := xlsx.NewStyle(`{"font":{"bold":true,"italic":true,"family":"Berlin Sans FB Demi","size":36,"color":"#777777"}}`) // if err != nil { // fmt.Println(err) // } // xlsx.SetCellStyle("Sheet1", "H9", "H9", style) // // Hide and lock for cell H9 on Sheet1: // // style, err := xlsx.NewStyle(`{"protection":{"hidden":true, "locked":true}}`) // if err != nil { // fmt.Println(err) // } // xlsx.SetCellStyle("Sheet1", "H9", "H9", style) // func (f *File) SetCellStyle(sheet, hcell, vcell string, styleID int) { hcell = strings.ToUpper(hcell) vcell = strings.ToUpper(vcell) // Coordinate conversion, convert C1:B3 to 2,0,1,2. hcol := string(strings.Map(letterOnlyMapF, hcell)) hrow, err := strconv.Atoi(strings.Map(intOnlyMapF, hcell)) if err != nil { return } hyAxis := hrow - 1 hxAxis := TitleToNumber(hcol) vcol := string(strings.Map(letterOnlyMapF, vcell)) vrow, err := strconv.Atoi(strings.Map(intOnlyMapF, vcell)) if err != nil { return } vyAxis := vrow - 1 vxAxis := TitleToNumber(vcol) // Correct the coordinate area, such correct C1:B3 to B1:C3. if vxAxis < hxAxis { vxAxis, hxAxis = hxAxis, vxAxis } if vyAxis < hyAxis { vyAxis, hyAxis = hyAxis, vyAxis } xlsx := f.workSheetReader(sheet) completeRow(xlsx, vyAxis+1, vxAxis+1) completeCol(xlsx, vyAxis+1, vxAxis+1) for r := hyAxis; r <= vyAxis; r++ { for k := hxAxis; k <= vxAxis; k++ { xlsx.SheetData.Row[r].C[k].S = styleID } } } // SetConditionalFormat provides function to create conditional formatting rule // for cell value. Conditional formatting is a feature of Excel which allows you // to apply a format to a cell or a range of cells based on certain criteria. // // The type option is a required parameter and it has no default value. // Allowable type values and their associated parameters are: // // Type | Parameters // ---------------+------------------------------------ // cell | criteria // | value // | minimum // | maximum // date | criteria // | value // | minimum // | maximum // time_period | criteria // text | criteria // | value // average | criteria // duplicate | (none) // unique | (none) // top | criteria // | value // bottom | criteria // | value // blanks | (none) // no_blanks | (none) // errors | (none) // no_errors | (none) // 2_color_scale | min_type // | max_type // | min_value // | max_value // | min_color // | max_color // 3_color_scale | min_type // | mid_type // | max_type // | min_value // | mid_value // | max_value // | min_color // | mid_color // | max_color // data_bar | min_type // | max_type // | min_value // | max_value // | bar_color // formula | criteria // // The criteria parameter is used to set the criteria by which the cell data // will be evaluated. It has no default value. The most common criteria as // applied to {'type': 'cell'} are: // // between | // not between | // equal to | == // not equal to | != // greater than | > // less than | < // greater than or equal to | >= // less than or equal to | <= // // You can either use Excel's textual description strings, in the first column // above, or the more common symbolic alternatives. // // Additional criteria which are specific to other conditional format types are // shown in the relevant sections below. // // value: The value is generally used along with the criteria parameter to set // the rule by which the cell data will be evaluated: // // xlsx.SetConditionalFormat("Sheet1", "D1:D10", fmt.Sprintf(`[{"type":"cell","criteria":">","format":%d,"value":"6"}]`, format)) // // The value property can also be an cell reference: // // xlsx.SetConditionalFormat("Sheet1", "D1:D10", fmt.Sprintf(`[{"type":"cell","criteria":">","format":%d,"value":"$C$1"}]`, format)) // // type: format - The format parameter is used to specify the format that will // be applied to the cell when the conditional formatting criterion is met. The // format is created using the NewConditionalStyle() method in the same way as // cell formats: // // format, err = xlsx.NewConditionalStyle(`{"font":{"color":"#9A0511"},"fill":{"type":"pattern","color":["#FEC7CE"],"pattern":1}}`) // if err != nil { // fmt.Println(err) // } // xlsx.SetConditionalFormat("Sheet1", "A1:A10", fmt.Sprintf(`[{"type":"cell","criteria":">","format":%d,"value":"6"}]`, format)) // // Note: In Excel, a conditional format is superimposed over the existing cell // format and not all cell format properties can be modified. Properties that // cannot be modified in a conditional format are font name, font size, // superscript and subscript, diagonal borders, all alignment properties and all // protection properties. // // Excel specifies some default formats to be used with conditional formatting. // These can be replicated using the following excelize formats: // // // Rose format for bad conditional. // format1, err = xlsx.NewConditionalStyle(`{"font":{"color":"#9A0511"},"fill":{"type":"pattern","color":["#FEC7CE"],"pattern":1}}`) // // // Light yellow format for neutral conditional. // format2, err = xlsx.NewConditionalStyle(`{"font":{"color":"#9B5713"},"fill":{"type":"pattern","color":["#FEEAA0"],"pattern":1}}`) // // // Light green format for good conditional. // format3, err = xlsx.NewConditionalStyle(`{"font":{"color":"#09600B"},"fill":{"type":"pattern","color":["#C7EECF"],"pattern":1}}`) // // type: minimum - The minimum parameter is used to set the lower limiting value // when the criteria is either "between" or "not between". // // // Hightlight cells rules: between... // xlsx.SetConditionalFormat("Sheet1", "A1:A10", fmt.Sprintf(`[{"type":"cell","criteria":"between","format":%d,"minimum":"6","maximum":"8"}]`, format)) // // type: maximum - The maximum parameter is used to set the upper limiting value // when the criteria is either "between" or "not between". See the previous // example. // // type: average - The average type is used to specify Excel's "Average" style // conditional format: // // // Top/Bottom rules: Above Average... // xlsx.SetConditionalFormat("Sheet1", "A1:A10", fmt.Sprintf(`[{"type":"average","criteria":"=","format":%d, "above_average": true}]`, format1)) // // // Top/Bottom rules: Below Average... // xlsx.SetConditionalFormat("Sheet1", "B1:B10", fmt.Sprintf(`[{"type":"average","criteria":"=","format":%d, "above_average": false}]`, format2)) // // type: duplicate - The duplicate type is used to highlight duplicate cells in a range: // // // Hightlight cells rules: Duplicate Values... // xlsx.SetConditionalFormat("Sheet1", "A1:A10", fmt.Sprintf(`[{"type":"duplicate","criteria":"=","format":%d}]`, format)) // // type: unique - The unique type is used to highlight unique cells in a range: // // // Hightlight cells rules: Not Equal To... // xlsx.SetConditionalFormat("Sheet1", "A1:A10", fmt.Sprintf(`[{"type":"unique","criteria":"=","format":%d}]`, format)) // // type: top - The top type is used to specify the top n values by number or percentage in a range: // // // Top/Bottom rules: Top 10. // xlsx.SetConditionalFormat("Sheet1", "H1:H10", fmt.Sprintf(`[{"type":"top","criteria":"=","format":%d,"value":"6"}]`, format)) // // The criteria can be used to indicate that a percentage condition is required: // // xlsx.SetConditionalFormat("Sheet1", "A1:A10", fmt.Sprintf(`[{"type":"top","criteria":"=","format":%d,"value":"6","percent":true}]`, format)) // // type: 2_color_scale - The 2_color_scale type is used to specify Excel's "2 // Color Scale" style conditional format: // // // Color scales: 2 color. // xlsx.SetConditionalFormat("Sheet1", "A1:A10", `[{"type":"2_color_scale","criteria":"=","min_type":"min","max_type":"max","min_color":"#F8696B","max_color":"#63BE7B"}]`) // // This conditional type can be modified with min_type, max_type, min_value, // max_value, min_color and max_color, see below. // // type: 3_color_scale - The 3_color_scale type is used to specify Excel's "3 // Color Scale" style conditional format: // // // Color scales: 3 color. // xlsx.SetConditionalFormat("Sheet1", "A1:A10", `[{"type":"3_color_scale","criteria":"=","min_type":"min","mid_type":"percentile","max_type":"max","min_color":"#F8696B","mid_color":"#FFEB84","max_color":"#63BE7B"}]`) // // This conditional type can be modified with min_type, mid_type, max_type, // min_value, mid_value, max_value, min_color, mid_color and max_color, see // below. // // type: data_bar - The data_bar type is used to specify Excel's "Data Bar" // style conditional format. // // min_type - The min_type and max_type properties are available when the conditional formatting type is 2_color_scale, 3_color_scale or data_bar. The mid_type is available for 3_color_scale. The properties are used as follows: // // // Data Bars: Gradient Fill. // xlsx.SetConditionalFormat("Sheet1", "K1:K10", `[{"type":"data_bar", "criteria":"=", "min_type":"min","max_type":"max","bar_color":"#638EC6"}]`) // // The available min/mid/max types are: // // min (for min_type only) // num // percent // percentile // formula // max (for max_type only) // // mid_type - Used for 3_color_scale. Same as min_type, see above. // // max_type - Same as min_type, see above. // // min_value - The min_value and max_value properties are available when the // conditional formatting type is 2_color_scale, 3_color_scale or data_bar. The // mid_value is available for 3_color_scale. // // mid_value - Used for 3_color_scale. Same as min_value, see above. // // max_value - Same as min_value, see above. // // min_color - The min_color and max_color properties are available when the // conditional formatting type is 2_color_scale, 3_color_scale or data_bar. // The mid_color is available for 3_color_scale. The properties are used as // follows: // // // Color scales: 3 color. // xlsx.SetConditionalFormat("Sheet1", "B1:B10", `[{"type":"3_color_scale","criteria":"=","min_type":"min","mid_type":"percentile","max_type":"max","min_color":"#F8696B","mid_color":"#FFEB84","max_color":"#63BE7B"}]`) // // mid_color - Used for 3_color_scale. Same as min_color, see above. // // max_color - Same as min_color, see above. // // bar_color - Used for data_bar. Same as min_color, see above. // func (f *File) SetConditionalFormat(sheet, area, formatSet string) error { var format []*formatConditional err := json.Unmarshal([]byte(formatSet), &format) if err != nil { return err } drawContFmtFunc := map[string]func(p int, ct string, fmtCond *formatConditional) *xlsxCfRule{ "cellIs": drawCondFmtCellIs, "top10": drawCondFmtTop10, "aboveAverage": drawCondFmtAboveAverage, "duplicateValues": drawCondFmtDuplicateUniqueValues, "uniqueValues": drawCondFmtDuplicateUniqueValues, "2_color_scale": drawCondFmtColorScale, "3_color_scale": drawCondFmtColorScale, "dataBar": drawCondFmtDataBar, "expression": drawConfFmtExp, } xlsx := f.workSheetReader(sheet) cfRule := []*xlsxCfRule{} for p, v := range format { var vt, ct string var ok bool // "type" is a required parameter, check for valid validation types. vt, ok = validType[v.Type] if ok { // Check for valid criteria types. ct, ok = criteriaType[v.Criteria] if ok || vt == "expression" { drawfunc, ok := drawContFmtFunc[vt] if ok { cfRule = append(cfRule, drawfunc(p, ct, v)) } } } } xlsx.ConditionalFormatting = append(xlsx.ConditionalFormatting, &xlsxConditionalFormatting{ SQRef: area, CfRule: cfRule, }) return err } // drawCondFmtCellIs provides function to create conditional formatting rule for // cell value (include between, not between, equal, not equal, greater than and // less than) by given priority, criteria type and format settings. func drawCondFmtCellIs(p int, ct string, format *formatConditional) *xlsxCfRule { c := &xlsxCfRule{ Priority: p + 1, Type: validType[format.Type], Operator: ct, DxfID: &format.Format, } // "between" and "not between" criteria require 2 values. _, ok := map[string]bool{"between": true, "notBetween": true}[ct] if ok { c.Formula = append(c.Formula, format.Minimum) c.Formula = append(c.Formula, format.Maximum) } _, ok = map[string]bool{"equal": true, "notEqual": true, "greaterThan": true, "lessThan": true}[ct] if ok { c.Formula = append(c.Formula, format.Value) } return c } // drawCondFmtTop10 provides function to create conditional formatting rule for // top N (default is top 10) by given priority, criteria type and format // settings. func drawCondFmtTop10(p int, ct string, format *formatConditional) *xlsxCfRule { c := &xlsxCfRule{ Priority: p + 1, Type: validType[format.Type], Rank: 10, DxfID: &format.Format, Percent: format.Percent, } rank, err := strconv.Atoi(format.Value) if err == nil { c.Rank = rank } return c } // drawCondFmtAboveAverage provides function to create conditional formatting // rule for above average and below average by given priority, criteria type and // format settings. func drawCondFmtAboveAverage(p int, ct string, format *formatConditional) *xlsxCfRule { return &xlsxCfRule{ Priority: p + 1, Type: validType[format.Type], AboveAverage: &format.AboveAverage, DxfID: &format.Format, } } // drawCondFmtDuplicateUniqueValues provides function to create conditional // formatting rule for duplicate and unique values by given priority, criteria // type and format settings. func drawCondFmtDuplicateUniqueValues(p int, ct string, format *formatConditional) *xlsxCfRule { return &xlsxCfRule{ Priority: p + 1, Type: validType[format.Type], DxfID: &format.Format, } } // drawCondFmtColorScale provides function to create conditional formatting rule // for color scale (include 2 color scale and 3 color scale) by given priority, // criteria type and format settings. func drawCondFmtColorScale(p int, ct string, format *formatConditional) *xlsxCfRule { c := &xlsxCfRule{ Priority: p + 1, Type: "colorScale", ColorScale: &xlsxColorScale{ Cfvo: []*xlsxCfvo{ {Type: format.MinType}, }, Color: []*xlsxColor{ {RGB: getPaletteColor(format.MinColor)}, }, }, } if validType[format.Type] == "3_color_scale" { c.ColorScale.Cfvo = append(c.ColorScale.Cfvo, &xlsxCfvo{Type: format.MidType, Val: 50}) c.ColorScale.Color = append(c.ColorScale.Color, &xlsxColor{RGB: getPaletteColor(format.MidColor)}) } c.ColorScale.Cfvo = append(c.ColorScale.Cfvo, &xlsxCfvo{Type: format.MaxType}) c.ColorScale.Color = append(c.ColorScale.Color, &xlsxColor{RGB: getPaletteColor(format.MaxColor)}) return c } // drawCondFmtDataBar provides function to create conditional formatting rule // for data bar by given priority, criteria type and format settings. func drawCondFmtDataBar(p int, ct string, format *formatConditional) *xlsxCfRule { return &xlsxCfRule{ Priority: p + 1, Type: validType[format.Type], DataBar: &xlsxDataBar{ Cfvo: []*xlsxCfvo{{Type: format.MinType}, {Type: format.MaxType}}, Color: []*xlsxColor{{RGB: getPaletteColor(format.BarColor)}}, }, } } // drawConfFmtExp provides function to create conditional formatting rule for // expression by given priority, criteria type and format settings. func drawConfFmtExp(p int, ct string, format *formatConditional) *xlsxCfRule { return &xlsxCfRule{ Priority: p + 1, Type: validType[format.Type], Formula: []string{format.Criteria}, DxfID: &format.Format, } } // getPaletteColor provides function to convert the RBG color by given string. func getPaletteColor(color string) string { return "FF" + strings.Replace(strings.ToUpper(color), "#", "", -1) } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/table.go ================================================ package excelize import ( "encoding/json" "encoding/xml" "fmt" "regexp" "strconv" "strings" ) // parseFormatTableSet provides function to parse the format settings of the // table with default value. func parseFormatTableSet(formatSet string) (*formatTable, error) { format := formatTable{ TableStyle: "", ShowRowStripes: true, } err := json.Unmarshal([]byte(formatSet), &format) return &format, err } // AddTable provides the method to add table in a worksheet by given worksheet // name, coordinate area and format set. For example, create a table of A1:D5 // on Sheet1: // // xlsx.AddTable("Sheet1", "A1", "D5", ``) // // Create a table of F2:H6 on Sheet2 with format set: // // xlsx.AddTable("Sheet2", "F2", "H6", `{"table_name":"table","table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`) // // Note that the table at least two lines include string type header. Multiple // tables coordinate areas can't have an intersection. // // table_name: The name of the table, in the same worksheet name of the table should be unique // // table_style: The built-in table style names // // TableStyleLight1 - TableStyleLight21 // TableStyleMedium1 - TableStyleMedium28 // TableStyleDark1 - TableStyleDark11 // func (f *File) AddTable(sheet, hcell, vcell, format string) error { formatSet, err := parseFormatTableSet(format) if err != nil { return err } hcell = strings.ToUpper(hcell) vcell = strings.ToUpper(vcell) // Coordinate conversion, convert C1:B3 to 2,0,1,2. hcol := string(strings.Map(letterOnlyMapF, hcell)) hrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, hcell)) hyAxis := hrow - 1 hxAxis := TitleToNumber(hcol) vcol := string(strings.Map(letterOnlyMapF, vcell)) vrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, vcell)) vyAxis := vrow - 1 vxAxis := TitleToNumber(vcol) if vxAxis < hxAxis { vxAxis, hxAxis = hxAxis, vxAxis } if vyAxis < hyAxis { vyAxis, hyAxis = hyAxis, vyAxis } tableID := f.countTables() + 1 sheetRelationshipsTableXML := "../tables/table" + strconv.Itoa(tableID) + ".xml" tableXML := strings.Replace(sheetRelationshipsTableXML, "..", "xl", -1) // Add first table for given sheet. rID := f.addSheetRelationships(sheet, SourceRelationshipTable, sheetRelationshipsTableXML, "") f.addSheetTable(sheet, rID) f.addTable(sheet, tableXML, hxAxis, hyAxis, vxAxis, vyAxis, tableID, formatSet) f.addContentTypePart(tableID, "table") return err } // countTables provides function to get table files count storage in the folder // xl/tables. func (f *File) countTables() int { count := 0 for k := range f.XLSX { if strings.Contains(k, "xl/tables/table") { count++ } } return count } // addSheetTable provides function to add tablePart element to // xl/worksheets/sheet%d.xml by given worksheet name and relationship index. func (f *File) addSheetTable(sheet string, rID int) { xlsx := f.workSheetReader(sheet) table := &xlsxTablePart{ RID: "rId" + strconv.Itoa(rID), } if xlsx.TableParts == nil { xlsx.TableParts = &xlsxTableParts{} } xlsx.TableParts.Count++ xlsx.TableParts.TableParts = append(xlsx.TableParts.TableParts, table) } // addTable provides function to add table by given worksheet name, coordinate // area and format set. func (f *File) addTable(sheet, tableXML string, hxAxis, hyAxis, vxAxis, vyAxis, i int, formatSet *formatTable) { // Correct the minimum number of rows, the table at least two lines. if hyAxis == vyAxis { vyAxis++ } // Correct table reference coordinate area, such correct C1:B3 to B1:C3. ref := ToAlphaString(hxAxis) + strconv.Itoa(hyAxis+1) + ":" + ToAlphaString(vxAxis) + strconv.Itoa(vyAxis+1) tableColumn := []*xlsxTableColumn{} idx := 0 for i := hxAxis; i <= vxAxis; i++ { idx++ cell := ToAlphaString(i) + strconv.Itoa(hyAxis+1) name := f.GetCellValue(sheet, cell) if _, err := strconv.Atoi(name); err == nil { f.SetCellStr(sheet, cell, name) } if name == "" { name = "Column" + strconv.Itoa(idx) f.SetCellStr(sheet, cell, name) } tableColumn = append(tableColumn, &xlsxTableColumn{ ID: idx, Name: name, }) } name := formatSet.TableName if name == "" { name = "Table" + strconv.Itoa(i) } t := xlsxTable{ XMLNS: NameSpaceSpreadSheet, ID: i, Name: name, DisplayName: name, Ref: ref, AutoFilter: &xlsxAutoFilter{ Ref: ref, }, TableColumns: &xlsxTableColumns{ Count: idx, TableColumn: tableColumn, }, TableStyleInfo: &xlsxTableStyleInfo{ Name: formatSet.TableStyle, ShowFirstColumn: formatSet.ShowFirstColumn, ShowLastColumn: formatSet.ShowLastColumn, ShowRowStripes: formatSet.ShowRowStripes, ShowColumnStripes: formatSet.ShowColumnStripes, }, } table, _ := xml.Marshal(t) f.saveFileList(tableXML, table) } // parseAutoFilterSet provides function to parse the settings of the auto // filter. func parseAutoFilterSet(formatSet string) (*formatAutoFilter, error) { format := formatAutoFilter{} err := json.Unmarshal([]byte(formatSet), &format) return &format, err } // AutoFilter provides the method to add auto filter in a worksheet by given // worksheet name, coordinate area and settings. An autofilter in Excel is a // way of filtering a 2D range of data based on some simple criteria. For // example applying an autofilter to a cell range A1:D4 in the Sheet1: // // err = xlsx.AutoFilter("Sheet1", "A1", "D4", "") // // Filter data in an autofilter: // // err = xlsx.AutoFilter("Sheet1", "A1", "D4", `{"column":"B","expression":"x != blanks"}`) // // column defines the filter columns in a autofilter range based on simple // criteria // // It isn't sufficient to just specify the filter condition. You must also // hide any rows that don't match the filter condition. Rows are hidden using // the SetRowVisible() method. Excelize can't filter rows automatically since // this isn't part of the file format. // // Setting a filter criteria for a column: // // expression defines the conditions, the following operators are available // for setting the filter criteria: // // == // != // > // < // >= // <= // and // or // // An expression can comprise a single statement or two statements separated // by the 'and' and 'or' operators. For example: // // x < 2000 // x > 2000 // x == 2000 // x > 2000 and x < 5000 // x == 2000 or x == 5000 // // Filtering of blank or non-blank data can be achieved by using a value of // Blanks or NonBlanks in the expression: // // x == Blanks // x == NonBlanks // // Excel also allows some simple string matching operations: // // x == b* // begins with b // x != b* // doesnt begin with b // x == *b // ends with b // x != *b // doesnt end with b // x == *b* // contains b // x != *b* // doesn't contains b // // You can also use '*' to match any character or number and '?' to match any // single character or number. No other regular expression quantifier is // supported by Excel's filters. Excel's regular expression characters can be // escaped using '~'. // // The placeholder variable x in the above examples can be replaced by any // simple string. The actual placeholder name is ignored internally so the // following are all equivalent: // // x < 2000 // col < 2000 // Price < 2000 // func (f *File) AutoFilter(sheet, hcell, vcell, format string) error { formatSet, _ := parseAutoFilterSet(format) hcell = strings.ToUpper(hcell) vcell = strings.ToUpper(vcell) // Coordinate conversion, convert C1:B3 to 2,0,1,2. hcol := string(strings.Map(letterOnlyMapF, hcell)) hrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, hcell)) hyAxis := hrow - 1 hxAxis := TitleToNumber(hcol) vcol := string(strings.Map(letterOnlyMapF, vcell)) vrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, vcell)) vyAxis := vrow - 1 vxAxis := TitleToNumber(vcol) if vxAxis < hxAxis { vxAxis, hxAxis = hxAxis, vxAxis } if vyAxis < hyAxis { vyAxis, hyAxis = hyAxis, vyAxis } ref := ToAlphaString(hxAxis) + strconv.Itoa(hyAxis+1) + ":" + ToAlphaString(vxAxis) + strconv.Itoa(vyAxis+1) refRange := vxAxis - hxAxis return f.autoFilter(sheet, ref, refRange, hxAxis, formatSet) } // autoFilter provides function to extract the tokens from the filter // expression. The tokens are mainly non-whitespace groups. func (f *File) autoFilter(sheet, ref string, refRange, hxAxis int, formatSet *formatAutoFilter) error { xlsx := f.workSheetReader(sheet) if xlsx.SheetPr != nil { xlsx.SheetPr.FilterMode = true } xlsx.SheetPr = &xlsxSheetPr{FilterMode: true} filter := &xlsxAutoFilter{ Ref: ref, } xlsx.AutoFilter = filter if formatSet.Column == "" || formatSet.Expression == "" { return nil } col := TitleToNumber(formatSet.Column) offset := col - hxAxis if offset < 0 || offset > refRange { return fmt.Errorf("Incorrect index of column '%s'", formatSet.Column) } filter.FilterColumn = &xlsxFilterColumn{ ColID: offset, } re := regexp.MustCompile(`"(?:[^"]|"")*"|\S+`) token := re.FindAllString(formatSet.Expression, -1) if len(token) != 3 && len(token) != 7 { return fmt.Errorf("Incorrect number of tokens in criteria '%s'", formatSet.Expression) } expressions, tokens, err := f.parseFilterExpression(formatSet.Expression, token) if err != nil { return err } f.writeAutoFilter(filter, expressions, tokens) xlsx.AutoFilter = filter return nil } // writeAutoFilter provides function to check for single or double custom filters // as default filters and handle them accordingly. func (f *File) writeAutoFilter(filter *xlsxAutoFilter, exp []int, tokens []string) { if len(exp) == 1 && exp[0] == 2 { // Single equality. filters := []*xlsxFilter{} filters = append(filters, &xlsxFilter{Val: tokens[0]}) filter.FilterColumn.Filters = &xlsxFilters{Filter: filters} } else if len(exp) == 3 && exp[0] == 2 && exp[1] == 1 && exp[2] == 2 { // Double equality with "or" operator. filters := []*xlsxFilter{} for _, v := range tokens { filters = append(filters, &xlsxFilter{Val: v}) } filter.FilterColumn.Filters = &xlsxFilters{Filter: filters} } else { // Non default custom filter. expRel := map[int]int{0: 0, 1: 2} andRel := map[int]bool{0: true, 1: false} for k, v := range tokens { f.writeCustomFilter(filter, exp[expRel[k]], v) if k == 1 { filter.FilterColumn.CustomFilters.And = andRel[exp[k]] } } } } // writeCustomFilter provides function to write the element. func (f *File) writeCustomFilter(filter *xlsxAutoFilter, operator int, val string) { operators := map[int]string{ 1: "lessThan", 2: "equal", 3: "lessThanOrEqual", 4: "greaterThan", 5: "notEqual", 6: "greaterThanOrEqual", 22: "equal", } customFilter := xlsxCustomFilter{ Operator: operators[operator], Val: val, } if filter.FilterColumn.CustomFilters != nil { filter.FilterColumn.CustomFilters.CustomFilter = append(filter.FilterColumn.CustomFilters.CustomFilter, &customFilter) } else { customFilters := []*xlsxCustomFilter{} customFilters = append(customFilters, &customFilter) filter.FilterColumn.CustomFilters = &xlsxCustomFilters{CustomFilter: customFilters} } } // parseFilterExpression provides function to converts the tokens of a possibly // conditional expression into 1 or 2 sub expressions for further parsing. // // Examples: // // ('x', '==', 2000) -> exp1 // ('x', '>', 2000, 'and', 'x', '<', 5000) -> exp1 and exp2 // func (f *File) parseFilterExpression(expression string, tokens []string) ([]int, []string, error) { expressions := []int{} t := []string{} if len(tokens) == 7 { // The number of tokens will be either 3 (for 1 expression) or 7 (for 2 // expressions). conditional := 0 c := tokens[3] re, _ := regexp.Match(`(or|\|\|)`, []byte(c)) if re { conditional = 1 } expression1, token1, err := f.parseFilterTokens(expression, tokens[0:3]) if err != nil { return expressions, t, err } expression2, token2, err := f.parseFilterTokens(expression, tokens[4:7]) if err != nil { return expressions, t, err } expressions = []int{expression1[0], conditional, expression2[0]} t = []string{token1, token2} } else { exp, token, err := f.parseFilterTokens(expression, tokens) if err != nil { return expressions, t, err } expressions = exp t = []string{token} } return expressions, t, nil } // parseFilterTokens provides function to parse the 3 tokens of a filter // expression and return the operator and token. func (f *File) parseFilterTokens(expression string, tokens []string) ([]int, string, error) { operators := map[string]int{ "==": 2, "=": 2, "=~": 2, "eq": 2, "!=": 5, "!~": 5, "ne": 5, "<>": 5, "<": 1, "<=": 3, ">": 4, ">=": 6, } operator, ok := operators[strings.ToLower(tokens[1])] if !ok { // Convert the operator from a number to a descriptive string. return []int{}, "", fmt.Errorf("Unknown operator: %s", tokens[1]) } token := tokens[2] // Special handling for Blanks/NonBlanks. re, _ := regexp.Match("blanks|nonblanks", []byte(strings.ToLower(token))) if re { // Only allow Equals or NotEqual in this context. if operator != 2 && operator != 5 { return []int{operator}, token, fmt.Errorf("The operator '%s' in expression '%s' is not valid in relation to Blanks/NonBlanks'", tokens[1], expression) } token = strings.ToLower(token) // The operator should always be 2 (=) to flag a "simple" equality in // the binary record. Therefore we convert <> to =. if token == "blanks" { if operator == 5 { token = " " } } else { if operator == 5 { operator = 2 token = "blanks" } else { operator = 5 token = " " } } } // if the string token contains an Excel match character then change the // operator type to indicate a non "simple" equality. re, _ = regexp.Match("[*?]", []byte(token)) if operator == 2 && re { operator = 22 } return []int{operator}, token, nil } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/templates.go ================================================ // This file contains default templates for XML files we don't yet populated // based on content. package excelize // XMLHeader define an XML declaration can also contain a standalone declaration. const XMLHeader = "\n" var ( // XMLHeaderByte define an XML declaration can also contain a standalone // declaration. XMLHeaderByte = []byte(XMLHeader) ) const templateDocpropsApp = `0Go Excelize` const templateContentTypes = `` const templateWorkbook = `` const templateStyles = `` const templateSheet = `` const templateWorkbookRels = `` const templateDocpropsCore = `xuri2006-09-16T00:00:00Z2006-09-16T00:00:00Z` const templateRels = `` const templateTheme = `` ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/vmlDrawing.go ================================================ package excelize import "encoding/xml" // vmlDrawing directly maps the root element in the file // xl/drawings/vmlDrawing%d.vml. type vmlDrawing struct { XMLName xml.Name `xml:"xml"` XMLNSv string `xml:"xmlns:v,attr"` XMLNSo string `xml:"xmlns:o,attr"` XMLNSx string `xml:"xmlns:x,attr"` XMLNSmv string `xml:"xmlns:mv,attr"` Shapelayout *xlsxShapelayout `xml:"o:shapelayout"` Shapetype *xlsxShapetype `xml:"v:shapetype"` Shape []xlsxShape `xml:"v:shape"` } // xlsxShapelayout directly maps the shapelayout element. This element contains // child elements that store information used in the editing and layout of // shapes. type xlsxShapelayout struct { Ext string `xml:"v:ext,attr"` IDmap *xlsxIDmap `xml:"o:idmap"` } // xlsxIDmap directly maps the idmap element. type xlsxIDmap struct { Ext string `xml:"v:ext,attr"` Data int `xml:"data,attr"` } // xlsxShape directly maps the shape element. type xlsxShape struct { XMLName xml.Name `xml:"v:shape"` ID string `xml:"id,attr"` Type string `xml:"type,attr"` Style string `xml:"style,attr"` Fillcolor string `xml:"fillcolor,attr"` Insetmode string `xml:"urn:schemas-microsoft-com:office:office insetmode,attr,omitempty"` Strokecolor string `xml:"strokecolor,attr,omitempty"` Val string `xml:",innerxml"` } // xlsxShapetype directly maps the shapetype element. type xlsxShapetype struct { ID string `xml:"id,attr"` Coordsize string `xml:"coordsize,attr"` Spt int `xml:"o:spt,attr"` Path string `xml:"path,attr"` Stroke *xlsxStroke `xml:"v:stroke"` VPath *vPath `xml:"v:path"` } // xlsxStroke directly maps the stroke element. type xlsxStroke struct { Joinstyle string `xml:"joinstyle,attr"` } // vPath directly maps the v:path element. type vPath struct { Gradientshapeok string `xml:"gradientshapeok,attr,omitempty"` Connecttype string `xml:"o:connecttype,attr"` } // vFill directly maps the v:fill element. This element must be defined within a // Shape element. type vFill struct { Angle int `xml:"angle,attr,omitempty"` Color2 string `xml:"color2,attr"` Type string `xml:"type,attr,omitempty"` Fill *oFill `xml:"o:fill"` } // oFill directly maps the o:fill element. type oFill struct { Ext string `xml:"v:ext,attr"` Type string `xml:"type,attr,omitempty"` } // vShadow directly maps the v:shadow element. This element must be defined // within a Shape element. In addition, the On attribute must be set to True. type vShadow struct { On string `xml:"on,attr"` Color string `xml:"color,attr,omitempty"` Obscured string `xml:"obscured,attr"` } // vTextbox directly maps the v:textbox element. This element must be defined // within a Shape element. type vTextbox struct { Style string `xml:"style,attr"` Div *xlsxDiv `xml:"div"` } // xlsxDiv directly maps the div element. type xlsxDiv struct { Style string `xml:"style,attr"` } // xClientData (Attached Object Data) directly maps the x:ClientData element. // This element specifies data associated with objects attached to a // spreadsheet. While this element might contain any of the child elements // below, only certain combinations are meaningful. The ObjectType attribute // determines the kind of object the element represents and which subset of // child elements is appropriate. Relevant groups are identified for each child // element. type xClientData struct { ObjectType string `xml:"ObjectType,attr"` MoveWithCells string `xml:"x:MoveWithCells,omitempty"` SizeWithCells string `xml:"x:SizeWithCells,omitempty"` Anchor string `xml:"x:Anchor"` AutoFill string `xml:"x:AutoFill"` Row int `xml:"x:Row"` Column int `xml:"x:Column"` } // decodeVmlDrawing defines the structure used to parse the file // xl/drawings/vmlDrawing%d.vml. type decodeVmlDrawing struct { Shape []decodeShape `xml:"urn:schemas-microsoft-com:vml shape"` } // decodeShape defines the structure used to parse the particular shape element. type decodeShape struct { Val string `xml:",innerxml"` } // encodeShape defines the structure used to re-serialization shape element. type encodeShape struct { Fill *vFill `xml:"v:fill"` Shadow *vShadow `xml:"v:shadow"` Path *vPath `xml:"v:path"` Textbox *vTextbox `xml:"v:textbox"` ClientData *xClientData `xml:"x:ClientData"` } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/xmlChart.go ================================================ package excelize import "encoding/xml" // xlsxChartSpace directly maps the c:chartSpace element. The chart namespace in // DrawingML is for representing visualizations of numeric data with column // charts, pie charts, scatter charts, or other types of charts. type xlsxChartSpace struct { XMLName xml.Name `xml:"c:chartSpace"` XMLNSc string `xml:"xmlns:c,attr"` XMLNSa string `xml:"xmlns:a,attr"` XMLNSr string `xml:"xmlns:r,attr"` XMLNSc16r2 string `xml:"xmlns:c16r2,attr"` Date1904 *attrValBool `xml:"c:date1904"` Lang *attrValString `xml:"c:lang"` RoundedCorners *attrValBool `xml:"c:roundedCorners"` Chart cChart `xml:"c:chart"` SpPr *cSpPr `xml:"c:spPr"` TxPr *cTxPr `xml:"c:txPr"` PrintSettings *cPrintSettings `xml:"c:printSettings"` } // cThicknessSpPr directly maps the element that specifies the thickness of the // walls or floor as a percentage of the largest dimension of the plot volume // and SpPr element. type cThicknessSpPr struct { Thickness *attrValInt `xml:"c:thickness"` SpPr *cSpPr `xml:"c:spPr"` } // cChart (Chart) directly maps the c:chart element. This element specifies a // title. type cChart struct { Title *cTitle `xml:"c:title"` AutoTitleDeleted *cAutoTitleDeleted `xml:"c:autoTitleDeleted"` View3D *cView3D `xml:"c:view3D"` Floor *cThicknessSpPr `xml:"c:floor"` SideWall *cThicknessSpPr `xml:"c:sideWall"` BackWall *cThicknessSpPr `xml:"c:backWall"` PlotArea *cPlotArea `xml:"c:plotArea"` Legend *cLegend `xml:"c:legend"` PlotVisOnly *attrValBool `xml:"c:plotVisOnly"` DispBlanksAs *attrValString `xml:"c:dispBlanksAs"` ShowDLblsOverMax *attrValBool `xml:"c:showDLblsOverMax"` } // cTitle (Title) directly maps the c:title element. This element specifies a // title. type cTitle struct { Tx cTx `xml:"c:tx,omitempty"` Layout string `xml:"c:layout,omitempty"` Overlay attrValBool `xml:"c:overlay,omitempty"` SpPr cSpPr `xml:"c:spPr,omitempty"` TxPr cTxPr `xml:"c:txPr,omitempty"` } // cTx (Chart Text) directly maps the c:tx element. This element specifies text // to use on a chart, including rich text formatting. type cTx struct { StrRef *cStrRef `xml:"c:strRef"` Rich *cRich `xml:"c:rich,omitempty"` } // cRich (Rich Text) directly maps the c:rich element. This element contains a // string with rich text formatting. type cRich struct { BodyPr aBodyPr `xml:"a:bodyPr,omitempty"` LstStyle string `xml:"a:lstStyle,omitempty"` P aP `xml:"a:p"` } // aBodyPr (Body Properties) directly maps the a:bodyPr element. This element // defines the body properties for the text body within a shape. type aBodyPr struct { Anchor string `xml:"anchor,attr,omitempty"` AnchorCtr bool `xml:"anchorCtr,attr"` Rot int `xml:"rot,attr"` BIns float64 `xml:"bIns,attr,omitempty"` CompatLnSpc bool `xml:"compatLnSpc,attr,omitempty"` ForceAA bool `xml:"forceAA,attr,omitempty"` FromWordArt bool `xml:"fromWordArt,attr,omitempty"` HorzOverflow string `xml:"horzOverflow,attr,omitempty"` LIns float64 `xml:"lIns,attr,omitempty"` NumCol int `xml:"numCol,attr,omitempty"` RIns float64 `xml:"rIns,attr,omitempty"` RtlCol bool `xml:"rtlCol,attr,omitempty"` SpcCol int `xml:"spcCol,attr,omitempty"` SpcFirstLastPara bool `xml:"spcFirstLastPara,attr"` TIns float64 `xml:"tIns,attr,omitempty"` Upright bool `xml:"upright,attr,omitempty"` Vert string `xml:"vert,attr,omitempty"` VertOverflow string `xml:"vertOverflow,attr,omitempty"` Wrap string `xml:"wrap,attr,omitempty"` } // aP (Paragraph) directly maps the a:p element. This element specifies a // paragraph of content in the document. type aP struct { PPr *aPPr `xml:"a:pPr"` R *aR `xml:"a:r"` EndParaRPr *aEndParaRPr `xml:"a:endParaRPr"` } // aPPr (Paragraph Properties) directly maps the a:pPr element. This element // specifies a set of paragraph properties which shall be applied to the // contents of the parent paragraph after all style/numbering/table properties // have been applied to the text. These properties are defined as direct // formatting, since they are directly applied to the paragraph and supersede // any formatting from styles. type aPPr struct { DefRPr aRPr `xml:"a:defRPr"` } // aSolidFill (Solid Fill) directly maps the solidFill element. This element // specifies a solid color fill. The shape is filled entirely with the specified // color. type aSolidFill struct { SchemeClr *aSchemeClr `xml:"a:schemeClr"` SrgbClr *attrValString `xml:"a:srgbClr"` } // aSchemeClr (Scheme Color) directly maps the a:schemeClr element. This // element specifies a color bound to a user's theme. As with all elements which // define a color, it is possible to apply a list of color transforms to the // base color defined. type aSchemeClr struct { Val string `xml:"val,attr,omitempty"` LumMod *attrValInt `xml:"a:lumMod"` LumOff *attrValInt `xml:"a:lumOff"` } // attrValInt directly maps the val element with integer data type as an // attribute。 type attrValInt struct { Val int `xml:"val,attr"` } // attrValFloat directly maps the val element with float64 data type as an // attribute。 type attrValFloat struct { Val float64 `xml:"val,attr"` } // attrValBool directly maps the val element with boolean data type as an // attribute。 type attrValBool struct { Val bool `xml:"val,attr"` } // attrValString directly maps the val element with string data type as an // attribute。 type attrValString struct { Val string `xml:"val,attr"` } // aCs directly maps the a:cs element. type aCs struct { Typeface string `xml:"typeface,attr"` } // aEa directly maps the a:ea element. type aEa struct { Typeface string `xml:"typeface,attr"` } // aLatin (Latin Font) directly maps the a:latin element. This element // specifies that a Latin font be used for a specific run of text. This font is // specified with a typeface attribute much like the others but is specifically // classified as a Latin font. type aLatin struct { Typeface string `xml:"typeface,attr"` } // aR directly maps the a:r element. type aR struct { RPr aRPr `xml:"a:rPr,omitempty"` T string `xml:"a:t,omitempty"` } // aRPr (Run Properties) directly maps the c:rPr element. This element // specifies a set of run properties which shall be applied to the contents of // the parent run after all style formatting has been applied to the text. These // properties are defined as direct formatting, since they are directly applied // to the run and supersede any formatting from styles. type aRPr struct { AltLang string `xml:"altLang,attr,omitempty"` B bool `xml:"b,attr"` Baseline int `xml:"baseline,attr"` Bmk string `xml:"bmk,attr,omitempty"` Cap string `xml:"cap,attr,omitempty"` Dirty bool `xml:"dirty,attr,omitempty"` Err bool `xml:"err,attr,omitempty"` I bool `xml:"i,attr"` Kern int `xml:"kern,attr"` Kumimoji bool `xml:"kumimoji,attr,omitempty"` Lang string `xml:"lang,attr,omitempty"` NoProof bool `xml:"noProof,attr,omitempty"` NormalizeH bool `xml:"normalizeH,attr,omitempty"` SmtClean bool `xml:"smtClean,attr,omitempty"` SmtID uint64 `xml:"smtId,attr,omitempty"` Spc int `xml:"spc,attr"` Strike string `xml:"strike,attr,omitempty"` Sz int `xml:"sz,attr,omitempty"` U string `xml:"u,attr,omitempty"` SolidFill *aSolidFill `xml:"a:solidFill"` Latin *aLatin `xml:"a:latin"` Ea *aEa `xml:"a:ea"` Cs *aCs `xml:"a:cs"` } // cSpPr (Shape Properties) directly maps the c:spPr element. This element // specifies the visual shape properties that can be applied to a shape. These // properties include the shape fill, outline, geometry, effects, and 3D // orientation. type cSpPr struct { NoFill *string `xml:"a:noFill"` SolidFill *aSolidFill `xml:"a:solidFill"` Ln *aLn `xml:"a:ln"` Sp3D *aSp3D `xml:"a:sp3d"` EffectLst *string `xml:"a:effectLst"` } // aSp3D (3-D Shape Properties) directly maps the a:sp3d element. This element // defines the 3D properties associated with a particular shape in DrawingML. // The 3D properties which can be applied to a shape are top and bottom bevels, // a contour and an extrusion. type aSp3D struct { ContourW int `xml:"contourW,attr"` ContourClr *aContourClr `xml:"a:contourClr"` } // aContourClr (Contour Color) directly maps the a:contourClr element. This // element defines the color for the contour on a shape. The contour of a shape // is a solid filled line which surrounds the outer edges of the shape. type aContourClr struct { SchemeClr *aSchemeClr `xml:"a:schemeClr"` } // aLn (Outline) directly maps the a:ln element. This element specifies an // outline style that can be applied to a number of different objects such as // shapes and text. The line allows for the specifying of many different types // of outlines including even line dashes and bevels. type aLn struct { Algn string `xml:"algn,attr,omitempty"` Cap string `xml:"cap,attr,omitempty"` Cmpd string `xml:"cmpd,attr,omitempty"` W int `xml:"w,attr,omitempty" ` NoFill string `xml:"a:noFill,omitempty"` Round string `xml:"a:round,omitempty"` SolidFill *aSolidFill `xml:"a:solidFill"` } // cTxPr (Text Properties) directly maps the c:txPr element. This element // specifies text formatting. The lstStyle element is not supported. type cTxPr struct { BodyPr aBodyPr `xml:"a:bodyPr,omitempty"` LstStyle string `xml:"a:lstStyle,omitempty"` P aP `xml:"a:p,omitempty"` } // aEndParaRPr (End Paragraph Run Properties) directly maps the a:endParaRPr // element. This element specifies the text run properties that are to be used // if another run is inserted after the last run specified. This effectively // saves the run property state so that it can be applied when the user enters // additional text. If this element is omitted, then the application can // determine which default properties to apply. It is recommended that this // element be specified at the end of the list of text runs within the paragraph // so that an orderly list is maintained. type aEndParaRPr struct { Lang string `xml:"lang,attr"` AltLang string `xml:"altLang,attr,omitempty"` Sz int `xml:"sz,attr,omitempty"` } // cAutoTitleDeleted (Auto Title Is Deleted) directly maps the // c:autoTitleDeleted element. This element specifies the title shall not be // shown for this chart. type cAutoTitleDeleted struct { Val bool `xml:"val,attr"` } // cView3D (View In 3D) directly maps the c:view3D element. This element // specifies the 3-D view of the chart. type cView3D struct { RotX *attrValInt `xml:"c:rotX"` RotY *attrValInt `xml:"c:rotY"` DepthPercent *attrValInt `xml:"c:depthPercent"` RAngAx *attrValInt `xml:"c:rAngAx"` } // cPlotArea directly maps the c:plotArea element. This element specifies the // plot area of the chart. type cPlotArea struct { Layout *string `xml:"c:layout"` BarChart *cCharts `xml:"c:barChart"` Bar3DChart *cCharts `xml:"c:bar3DChart"` DoughnutChart *cCharts `xml:"c:doughnutChart"` LineChart *cCharts `xml:"c:lineChart"` PieChart *cCharts `xml:"c:pieChart"` Pie3DChart *cCharts `xml:"c:pie3DChart"` RadarChart *cCharts `xml:"c:radarChart"` ScatterChart *cCharts `xml:"c:scatterChart"` CatAx []*cAxs `xml:"c:catAx"` ValAx []*cAxs `xml:"c:valAx"` SpPr *cSpPr `xml:"c:spPr"` } // cCharts specifies the common element of the chart. type cCharts struct { BarDir *attrValString `xml:"c:barDir"` Grouping *attrValString `xml:"c:grouping"` RadarStyle *attrValString `xml:"c:radarStyle"` ScatterStyle *attrValString `xml:"c:scatterStyle"` VaryColors *attrValBool `xml:"c:varyColors"` Ser *[]cSer `xml:"c:ser"` DLbls *cDLbls `xml:"c:dLbls"` HoleSize *attrValInt `xml:"c:holeSize"` Smooth *attrValBool `xml:"c:smooth"` Overlap *attrValInt `xml:"c:overlap"` AxID []*attrValInt `xml:"c:axId"` } // cAxs directly maps the c:catAx and c:valAx element. type cAxs struct { AxID *attrValInt `xml:"c:axId"` Scaling *cScaling `xml:"c:scaling"` Delete *attrValBool `xml:"c:delete"` AxPos *attrValString `xml:"c:axPos"` NumFmt *cNumFmt `xml:"c:numFmt"` MajorTickMark *attrValString `xml:"c:majorTickMark"` MinorTickMark *attrValString `xml:"c:minorTickMark"` TickLblPos *attrValString `xml:"c:tickLblPos"` SpPr *cSpPr `xml:"c:spPr"` TxPr *cTxPr `xml:"c:txPr"` CrossAx *attrValInt `xml:"c:crossAx"` Crosses *attrValString `xml:"c:crosses"` CrossBetween *attrValString `xml:"c:crossBetween"` Auto *attrValBool `xml:"c:auto"` LblAlgn *attrValString `xml:"c:lblAlgn"` LblOffset *attrValInt `xml:"c:lblOffset"` NoMultiLvlLbl *attrValBool `xml:"c:noMultiLvlLbl"` } // cScaling directly maps the c:scaling element. This element contains // additional axis settings. type cScaling struct { Orientation *attrValString `xml:"c:orientation"` Max *attrValFloat `xml:"c:max"` Min *attrValFloat `xml:"c:min"` } // cNumFmt (Numbering Format) directly maps the c:numFmt element. This element // specifies number formatting for the parent element. type cNumFmt struct { FormatCode string `xml:"formatCode,attr"` SourceLinked bool `xml:"sourceLinked,attr"` } // cSer directly maps the c:ser element. This element specifies a series on a // chart. type cSer struct { IDx *attrValInt `xml:"c:idx"` Order *attrValInt `xml:"c:order"` Tx *cTx `xml:"c:tx"` SpPr *cSpPr `xml:"c:spPr"` DPt []*cDPt `xml:"c:dPt"` DLbls *cDLbls `xml:"c:dLbls"` Marker *cMarker `xml:"c:marker"` InvertIfNegative *attrValBool `xml:"c:invertIfNegative"` Cat *cCat `xml:"c:cat"` Val *cVal `xml:"c:val"` XVal *cCat `xml:"c:xVal"` YVal *cVal `xml:"c:yVal"` Smooth *attrValBool `xml:"c:smooth"` } // cMarker (Marker) directly maps the c:marker element. This element specifies a // data marker. type cMarker struct { Symbol *attrValString `xml:"c:symbol"` Size *attrValInt `xml:"c:size"` SpPr *cSpPr `xml:"c:spPr"` } // cDPt (Data Point) directly maps the c:dPt element. This element specifies a // single data point. type cDPt struct { IDx *attrValInt `xml:"c:idx"` Bubble3D *attrValBool `xml:"c:bubble3D"` SpPr *cSpPr `xml:"c:spPr"` } // cCat (Category Axis Data) directly maps the c:cat element. This element // specifies the data used for the category axis. type cCat struct { StrRef *cStrRef `xml:"c:strRef"` } // cStrRef (String Reference) directly maps the c:strRef element. This element // specifies a reference to data for a single data label or title with a cache // of the last values used. type cStrRef struct { F string `xml:"c:f"` StrCache *cStrCache `xml:"c:strCache"` } // cStrCache (String Cache) directly maps the c:strCache element. This element // specifies the last string data used for a chart. type cStrCache struct { Pt []*cPt `xml:"c:pt"` PtCount *attrValInt `xml:"c:ptCount"` } // cPt directly maps the c:pt element. This element specifies data for a // particular data point. type cPt struct { IDx int `xml:"idx,attr"` V *string `xml:"c:v"` } // cVal directly maps the c:val element. This element specifies the data values // which shall be used to define the location of data markers on a chart. type cVal struct { NumRef *cNumRef `xml:"c:numRef"` } // cNumRef directly maps the c:numRef element. This element specifies a // reference to numeric data with a cache of the last values used. type cNumRef struct { F string `xml:"c:f"` NumCache *cNumCache `xml:"c:numCache"` } // cNumCache directly maps the c:numCache element. This element specifies the // last data shown on the chart for a series. type cNumCache struct { FormatCode string `xml:"c:formatCode"` Pt []*cPt `xml:"c:pt"` PtCount *attrValInt `xml:"c:ptCount"` } // cDLbls (Data Lables) directly maps the c:dLbls element. This element serves // as a root element that specifies the settings for the data labels for an // entire series or the entire chart. It contains child elements that specify // the specific formatting and positioning settings. type cDLbls struct { ShowLegendKey *attrValBool `xml:"c:showLegendKey"` ShowVal *attrValBool `xml:"c:showVal"` ShowCatName *attrValBool `xml:"c:showCatName"` ShowSerName *attrValBool `xml:"c:showSerName"` ShowPercent *attrValBool `xml:"c:showPercent"` ShowBubbleSize *attrValBool `xml:"c:showBubbleSize"` ShowLeaderLines *attrValBool `xml:"c:showLeaderLines"` } // cLegend (Legend) directly maps the c:legend element. This element specifies // the legend. type cLegend struct { Layout *string `xml:"c:layout"` LegendPos *attrValString `xml:"c:legendPos"` Overlay *attrValBool `xml:"c:overlay"` SpPr *cSpPr `xml:"c:spPr"` TxPr *cTxPr `xml:"c:txPr"` } // cPrintSettings directly maps the c:printSettings element. This element // specifies the print settings for the chart. type cPrintSettings struct { HeaderFooter *string `xml:"c:headerFooter"` PageMargins *cPageMargins `xml:"c:pageMargins"` PageSetup *string `xml:"c:pageSetup"` } // cPageMargins directly maps the c:pageMargins element. This element specifies // the page margins for a chart. type cPageMargins struct { B float64 `xml:"b,attr"` Footer float64 `xml:"footer,attr"` Header float64 `xml:"header,attr"` L float64 `xml:"l,attr"` R float64 `xml:"r,attr"` T float64 `xml:"t,attr"` } // formatChartAxis directly maps the format settings of the chart axis. type formatChartAxis struct { Crossing string `json:"crossing"` MajorTickMark string `json:"major_tick_mark"` MinorTickMark string `json:"minor_tick_mark"` MinorUnitType string `json:"minor_unit_type"` MajorUnit int `json:"major_unit"` MajorUnitType string `json:"major_unit_type"` DisplayUnits string `json:"display_units"` DisplayUnitsVisible bool `json:"display_units_visible"` DateAxis bool `json:"date_axis"` ReverseOrder bool `json:"reverse_order"` Maximum float64 `json:"maximum"` Minimum float64 `json:"minimum"` NumFormat string `json:"num_format"` NumFont struct { Color string `json:"color"` Bold bool `json:"bold"` Italic bool `json:"italic"` Underline bool `json:"underline"` } `json:"num_font"` NameLayout formatLayout `json:"name_layout"` } type formatChartDimension struct { Width int `json:"width"` Height int `json:"height"` } // formatChart directly maps the format settings of the chart. type formatChart struct { Type string `json:"type"` Series []formatChartSeries `json:"series"` Format formatPicture `json:"format"` Dimension formatChartDimension `json:"dimension"` Legend formatChartLegend `json:"legend"` Title formatChartTitle `json:"title"` XAxis formatChartAxis `json:"x_axis"` YAxis formatChartAxis `json:"y_axis"` Chartarea struct { Border struct { None bool `json:"none"` } `json:"border"` Fill struct { Color string `json:"color"` } `json:"fill"` Pattern struct { Pattern string `json:"pattern"` FgColor string `json:"fg_color"` BgColor string `json:"bg_color"` } `json:"pattern"` } `json:"chartarea"` Plotarea struct { ShowBubbleSize bool `json:"show_bubble_size"` ShowCatName bool `json:"show_cat_name"` ShowLeaderLines bool `json:"show_leader_lines"` ShowPercent bool `json:"show_percent"` ShowSerName bool `json:"show_series_name"` ShowVal bool `json:"show_val"` Gradient struct { Colors []string `json:"colors"` } `json:"gradient"` Border struct { Color string `json:"color"` Width int `json:"width"` DashType string `json:"dash_type"` } `json:"border"` Fill struct { Color string `json:"color"` } `json:"fill"` Layout formatLayout `json:"layout"` } `json:"plotarea"` ShowBlanksAs string `json:"show_blanks_as"` ShowHiddenData bool `json:"show_hidden_data"` SetRotation int `json:"set_rotation"` SetHoleSize int `json:"set_hole_size"` } // formatChartLegend directly maps the format settings of the chart legend. type formatChartLegend struct { None bool `json:"none"` DeleteSeries []int `json:"delete_series"` Font formatFont `json:"font"` Layout formatLayout `json:"layout"` Position string `json:"position"` ShowLegendEntry bool `json:"show_legend_entry"` ShowLegendKey bool `json:"show_legend_key"` } // formatChartSeries directly maps the format settings of the chart series. type formatChartSeries struct { Name string `json:"name"` Categories string `json:"categories"` Values string `json:"values"` Line struct { None bool `json:"none"` Color string `json:"color"` } `json:"line"` Marker struct { Type string `json:"type"` Size int `json:"size,"` Width float64 `json:"width"` Border struct { Color string `json:"color"` None bool `json:"none"` } `json:"border"` Fill struct { Color string `json:"color"` None bool `json:"none"` } `json:"fill"` } `json:"marker"` } // formatChartTitle directly maps the format settings of the chart title. type formatChartTitle struct { None bool `json:"none"` Name string `json:"name"` Overlay bool `json:"overlay"` Layout formatLayout `json:"layout"` } // formatLayout directly maps the format settings of the element layout. type formatLayout struct { X float64 `json:"x"` Y float64 `json:"y"` Width float64 `json:"width"` Height float64 `json:"height"` } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/xmlComments.go ================================================ package excelize import "encoding/xml" // xlsxComments directly maps the comments element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main. A comment is a // rich text note that is attached to and associated with a cell, separate from // other cell content. Comment content is stored separate from the cell, and is // displayed in a drawing object (like a text box) that is separate from, but // associated with, a cell. Comments are used as reminders, such as noting how a // complex formula works, or to provide feedback to other users. Comments can // also be used to explain assumptions made in a formula or to call out // something special about the cell. type xlsxComments struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main comments"` Authors []xlsxAuthor `xml:"authors"` CommentList xlsxCommentList `xml:"commentList"` } // xlsxAuthor directly maps the author element. This element holds a string // representing the name of a single author of comments. Every comment shall // have an author. The maximum length of the author string is an implementation // detail, but a good guideline is 255 chars. type xlsxAuthor struct { Author string `xml:"author"` } // xlsxCommentList (List of Comments) directly maps the xlsxCommentList element. // This element is a container that holds a list of comments for the sheet. type xlsxCommentList struct { Comment []xlsxComment `xml:"comment"` } // xlsxComment directly maps the comment element. This element represents a // single user entered comment. Each comment shall have an author and can // optionally contain richly formatted text. type xlsxComment struct { Ref string `xml:"ref,attr"` AuthorID int `xml:"authorId,attr"` Text xlsxText `xml:"text"` } // xlsxText directly maps the text element. This element contains rich text // which represents the text of a comment. The maximum length for this text is a // spreadsheet application implementation detail. A recommended guideline is // 32767 chars. type xlsxText struct { R []xlsxR `xml:"r"` } // formatComment directly maps the format settings of the comment. type formatComment struct { Author string `json:"author"` Text string `json:"text"` } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/xmlContentTypes.go ================================================ package excelize import "encoding/xml" // xlsxTypes directly maps the types element of content types for relationship // parts, it takes a Multipurpose Internet Mail Extension (MIME) media type as a // value. type xlsxTypes struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/content-types Types"` Overrides []xlsxOverride `xml:"Override"` Defaults []xlsxDefault `xml:"Default"` } // xlsxOverride directly maps the override element in the namespace // http://schemas.openxmlformats.org/package/2006/content-types type xlsxOverride struct { PartName string `xml:",attr"` ContentType string `xml:",attr"` } // xlsxDefault directly maps the default element in the namespace // http://schemas.openxmlformats.org/package/2006/content-types type xlsxDefault struct { Extension string `xml:",attr"` ContentType string `xml:",attr"` } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/xmlDecodeDrawing.go ================================================ package excelize import "encoding/xml" // decodeCellAnchor directly maps the oneCellAnchor (One Cell Anchor Shape Size) // and twoCellAnchor (Two Cell Anchor Shape Size). This element specifies a two // cell anchor placeholder for a group, a shape, or a drawing element. It moves // with cells and its extents are in EMU units. type decodeCellAnchor struct { EditAs string `xml:"editAs,attr,omitempty"` Content string `xml:",innerxml"` } // decodeWsDr directly maps the root element for a part of this content type // shall wsDr. In order to solve the problem that the label structure is changed // after serialization and deserialization, two different structures are // defined. decodeWsDr just for deserialization. type decodeWsDr struct { A string `xml:"xmlns a,attr"` Xdr string `xml:"xmlns xdr,attr"` R string `xml:"xmlns r,attr"` OneCellAnchor []*decodeCellAnchor `xml:"oneCellAnchor,omitempty"` TwoCellAnchor []*decodeCellAnchor `xml:"twoCellAnchor,omitempty"` XMLName xml.Name `xml:"http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing wsDr,omitempty"` } // decodeTwoCellAnchor directly maps the oneCellAnchor (One Cell Anchor Shape // Size) and twoCellAnchor (Two Cell Anchor Shape Size). This element specifies // a two cell anchor placeholder for a group, a shape, or a drawing element. It // moves with cells and its extents are in EMU units. type decodeTwoCellAnchor struct { From *decodeFrom `xml:"from"` To *decodeTo `xml:"to"` Pic *decodePic `xml:"pic,omitempty"` ClientData *decodeClientData `xml:"clientData"` } // decodeCNvPr directly maps the cNvPr (Non-Visual Drawing Properties). This // element specifies non-visual canvas properties. This allows for additional // information that does not affect the appearance of the picture to be stored. type decodeCNvPr struct { ID int `xml:"id,attr"` Name string `xml:"name,attr"` Descr string `xml:"descr,attr"` Title string `xml:"title,attr,omitempty"` } // decodePicLocks directly maps the picLocks (Picture Locks). This element // specifies all locking properties for a graphic frame. These properties inform // the generating application about specific properties that have been // previously locked and thus should not be changed. type decodePicLocks struct { NoAdjustHandles bool `xml:"noAdjustHandles,attr,omitempty"` NoChangeArrowheads bool `xml:"noChangeArrowheads,attr,omitempty"` NoChangeAspect bool `xml:"noChangeAspect,attr"` NoChangeShapeType bool `xml:"noChangeShapeType,attr,omitempty"` NoCrop bool `xml:"noCrop,attr,omitempty"` NoEditPoints bool `xml:"noEditPoints,attr,omitempty"` NoGrp bool `xml:"noGrp,attr,omitempty"` NoMove bool `xml:"noMove,attr,omitempty"` NoResize bool `xml:"noResize,attr,omitempty"` NoRot bool `xml:"noRot,attr,omitempty"` NoSelect bool `xml:"noSelect,attr,omitempty"` } // decodeBlip directly maps the blip element in the namespace // http://purl.oclc.org/ooxml/officeDoc ument/relationships - This element // specifies the existence of an image (binary large image or picture) and // contains a reference to the image data. type decodeBlip struct { Embed string `xml:"embed,attr"` Cstate string `xml:"cstate,attr,omitempty"` R string `xml:"r,attr"` } // decodeStretch directly maps the stretch element. This element specifies that // a BLIP should be stretched to fill the target rectangle. The other option is // a tile where a BLIP is tiled to fill the available area. type decodeStretch struct { FillRect string `xml:"fillRect"` } // decodeOff directly maps the colOff and rowOff element. This element is used // to specify the column offset within a cell. type decodeOff struct { X int `xml:"x,attr"` Y int `xml:"y,attr"` } // decodeExt directly maps the ext element. type decodeExt struct { Cx int `xml:"cx,attr"` Cy int `xml:"cy,attr"` } // decodePrstGeom directly maps the prstGeom (Preset geometry). This element // specifies when a preset geometric shape should be used instead of a custom // geometric shape. The generating application should be able to render all // preset geometries enumerated in the ST_ShapeType list. type decodePrstGeom struct { Prst string `xml:"prst,attr"` } // decodeXfrm directly maps the xfrm (2D Transform for Graphic Frame). This // element specifies the transform to be applied to the corresponding graphic // frame. This transformation is applied to the graphic frame just as it would // be for a shape or group shape. type decodeXfrm struct { Off decodeOff `xml:"off"` Ext decodeExt `xml:"ext"` } // decodeCNvPicPr directly maps the cNvPicPr (Non-Visual Picture Drawing // Properties). This element specifies the non-visual properties for the picture // canvas. These properties are to be used by the generating application to // determine how certain properties are to be changed for the picture object in // question. type decodeCNvPicPr struct { PicLocks decodePicLocks `xml:"picLocks"` } // directly maps the nvPicPr (Non-Visual Properties for a Picture). This element // specifies all non-visual properties for a picture. This element is a // container for the non-visual identification properties, shape properties and // application properties that are to be associated with a picture. This allows // for additional information that does not affect the appearance of the picture // to be stored. type decodeNvPicPr struct { CNvPr decodeCNvPr `xml:"cNvPr"` CNvPicPr decodeCNvPicPr `xml:"cNvPicPr"` } // decodeBlipFill directly maps the blipFill (Picture Fill). This element // specifies the kind of picture fill that the picture object has. Because a // picture has a picture fill already by default, it is possible to have two // fills specified for a picture object. type decodeBlipFill struct { Blip decodeBlip `xml:"blip"` Stretch decodeStretch `xml:"stretch"` } // decodeSpPr directly maps the spPr (Shape Properties). This element specifies // the visual shape properties that can be applied to a picture. These are the // same properties that are allowed to describe the visual properties of a shape // but are used here to describe the visual appearance of a picture within a // document. type decodeSpPr struct { Xfrm decodeXfrm `xml:"a:xfrm"` PrstGeom decodePrstGeom `xml:"a:prstGeom"` } // decodePic elements encompass the definition of pictures within the DrawingML // framework. While pictures are in many ways very similar to shapes they have // specific properties that are unique in order to optimize for picture- // specific scenarios. type decodePic struct { NvPicPr decodeNvPicPr `xml:"nvPicPr"` BlipFill decodeBlipFill `xml:"blipFill"` SpPr decodeSpPr `xml:"spPr"` } // decodeFrom specifies the starting anchor. type decodeFrom struct { Col int `xml:"col"` ColOff int `xml:"colOff"` Row int `xml:"row"` RowOff int `xml:"rowOff"` } // decodeTo directly specifies the ending anchor. type decodeTo struct { Col int `xml:"col"` ColOff int `xml:"colOff"` Row int `xml:"row"` RowOff int `xml:"rowOff"` } // decodeClientData directly maps the clientData element. An empty element which // specifies (via attributes) certain properties related to printing and // selection of the drawing object. The fLocksWithSheet attribute (either true // or false) determines whether to disable selection when the sheet is // protected, and fPrintsWithSheet attribute (either true or false) determines // whether the object is printed when the sheet is printed. type decodeClientData struct { FLocksWithSheet bool `xml:"fLocksWithSheet,attr"` FPrintsWithSheet bool `xml:"fPrintsWithSheet,attr"` } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/xmlDrawing.go ================================================ package excelize import "encoding/xml" // Source relationship and namespace. const ( SourceRelationship = "http://schemas.openxmlformats.org/officeDocument/2006/relationships" SourceRelationshipChart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart" SourceRelationshipComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments" SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" SourceRelationshipTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table" SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing" SourceRelationshipDrawingVML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing" SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" SourceRelationshipChart201506 = "http://schemas.microsoft.com/office/drawing/2015/06/chart" SourceRelationshipChart20070802 = "http://schemas.microsoft.com/office/drawing/2007/8/2/chart" SourceRelationshipChart2014 = "http://schemas.microsoft.com/office/drawing/2014/chart" SourceRelationshipCompatibility = "http://schemas.openxmlformats.org/markup-compatibility/2006" NameSpaceDrawingML = "http://schemas.openxmlformats.org/drawingml/2006/main" NameSpaceDrawingMLChart = "http://schemas.openxmlformats.org/drawingml/2006/chart" NameSpaceDrawingMLSpreadSheet = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" NameSpaceSpreadSheet = "http://schemas.openxmlformats.org/spreadsheetml/2006/main" NameSpaceXML = "http://www.w3.org/XML/1998/namespace" ) var supportImageTypes = map[string]string{".gif": ".gif", ".jpg": ".jpeg", ".jpeg": ".jpeg", ".png": ".png"} // xlsxCNvPr directly maps the cNvPr (Non-Visual Drawing Properties). This // element specifies non-visual canvas properties. This allows for additional // information that does not affect the appearance of the picture to be stored. type xlsxCNvPr struct { ID int `xml:"id,attr"` Name string `xml:"name,attr"` Descr string `xml:"descr,attr"` Title string `xml:"title,attr,omitempty"` HlinkClick *xlsxHlinkClick `xml:"a:hlinkClick"` } // xlsxHlinkClick (Click Hyperlink) Specifies the on-click hyperlink // information to be applied to a run of text. When the hyperlink text is // clicked the link is fetched. type xlsxHlinkClick struct { R string `xml:"xmlns:r,attr,omitempty"` RID string `xml:"r:id,attr,omitempty"` InvalidURL string `xml:"invalidUrl,attr,omitempty"` Action string `xml:"action,attr,omitempty"` TgtFrame string `xml:"tgtFrame,attr,omitempty"` Tooltip string `xml:"tooltip,attr,omitempty"` History bool `xml:"history,attr,omitempty"` HighlightClick bool `xml:"highlightClick,attr,omitempty"` EndSnd bool `xml:"endSnd,attr,omitempty"` } // xlsxPicLocks directly maps the picLocks (Picture Locks). This element // specifies all locking properties for a graphic frame. These properties inform // the generating application about specific properties that have been // previously locked and thus should not be changed. type xlsxPicLocks struct { NoAdjustHandles bool `xml:"noAdjustHandles,attr,omitempty"` NoChangeArrowheads bool `xml:"noChangeArrowheads,attr,omitempty"` NoChangeAspect bool `xml:"noChangeAspect,attr"` NoChangeShapeType bool `xml:"noChangeShapeType,attr,omitempty"` NoCrop bool `xml:"noCrop,attr,omitempty"` NoEditPoints bool `xml:"noEditPoints,attr,omitempty"` NoGrp bool `xml:"noGrp,attr,omitempty"` NoMove bool `xml:"noMove,attr,omitempty"` NoResize bool `xml:"noResize,attr,omitempty"` NoRot bool `xml:"noRot,attr,omitempty"` NoSelect bool `xml:"noSelect,attr,omitempty"` } // xlsxBlip directly maps the blip element in the namespace // http://purl.oclc.org/ooxml/officeDoc ument/relationships - This element // specifies the existence of an image (binary large image or picture) and // contains a reference to the image data. type xlsxBlip struct { Embed string `xml:"r:embed,attr"` Cstate string `xml:"cstate,attr,omitempty"` R string `xml:"xmlns:r,attr"` } // xlsxStretch directly maps the stretch element. This element specifies that a // BLIP should be stretched to fill the target rectangle. The other option is a // tile where a BLIP is tiled to fill the available area. type xlsxStretch struct { FillRect string `xml:"a:fillRect"` } // xlsxOff directly maps the colOff and rowOff element. This element is used to // specify the column offset within a cell. type xlsxOff struct { X int `xml:"x,attr"` Y int `xml:"y,attr"` } // xlsxExt directly maps the ext element. type xlsxExt struct { Cx int `xml:"cx,attr"` Cy int `xml:"cy,attr"` } // xlsxPrstGeom directly maps the prstGeom (Preset geometry). This element // specifies when a preset geometric shape should be used instead of a custom // geometric shape. The generating application should be able to render all // preset geometries enumerated in the ST_ShapeType list. type xlsxPrstGeom struct { Prst string `xml:"prst,attr"` } // xlsxXfrm directly maps the xfrm (2D Transform for Graphic Frame). This // element specifies the transform to be applied to the corresponding graphic // frame. This transformation is applied to the graphic frame just as it would // be for a shape or group shape. type xlsxXfrm struct { Off xlsxOff `xml:"a:off"` Ext xlsxExt `xml:"a:ext"` } // xlsxCNvPicPr directly maps the cNvPicPr (Non-Visual Picture Drawing // Properties). This element specifies the non-visual properties for the picture // canvas. These properties are to be used by the generating application to // determine how certain properties are to be changed for the picture object in // question. type xlsxCNvPicPr struct { PicLocks xlsxPicLocks `xml:"a:picLocks"` } // directly maps the nvPicPr (Non-Visual Properties for a Picture). This element // specifies all non-visual properties for a picture. This element is a // container for the non-visual identification properties, shape properties and // application properties that are to be associated with a picture. This allows // for additional information that does not affect the appearance of the picture // to be stored. type xlsxNvPicPr struct { CNvPr xlsxCNvPr `xml:"xdr:cNvPr"` CNvPicPr xlsxCNvPicPr `xml:"xdr:cNvPicPr"` } // xlsxBlipFill directly maps the blipFill (Picture Fill). This element // specifies the kind of picture fill that the picture object has. Because a // picture has a picture fill already by default, it is possible to have two // fills specified for a picture object. type xlsxBlipFill struct { Blip xlsxBlip `xml:"a:blip"` Stretch xlsxStretch `xml:"a:stretch"` } // xlsxSpPr directly maps the spPr (Shape Properties). This element specifies // the visual shape properties that can be applied to a picture. These are the // same properties that are allowed to describe the visual properties of a shape // but are used here to describe the visual appearance of a picture within a // document. type xlsxSpPr struct { Xfrm xlsxXfrm `xml:"a:xfrm"` PrstGeom xlsxPrstGeom `xml:"a:prstGeom"` } // xlsxPic elements encompass the definition of pictures within the DrawingML // framework. While pictures are in many ways very similar to shapes they have // specific properties that are unique in order to optimize for picture- // specific scenarios. type xlsxPic struct { NvPicPr xlsxNvPicPr `xml:"xdr:nvPicPr"` BlipFill xlsxBlipFill `xml:"xdr:blipFill"` SpPr xlsxSpPr `xml:"xdr:spPr"` } // xlsxFrom specifies the starting anchor. type xlsxFrom struct { Col int `xml:"xdr:col"` ColOff int `xml:"xdr:colOff"` Row int `xml:"xdr:row"` RowOff int `xml:"xdr:rowOff"` } // xlsxTo directly specifies the ending anchor. type xlsxTo struct { Col int `xml:"xdr:col"` ColOff int `xml:"xdr:colOff"` Row int `xml:"xdr:row"` RowOff int `xml:"xdr:rowOff"` } // xdrClientData directly maps the clientData element. An empty element which // specifies (via attributes) certain properties related to printing and // selection of the drawing object. The fLocksWithSheet attribute (either true // or false) determines whether to disable selection when the sheet is // protected, and fPrintsWithSheet attribute (either true or false) determines // whether the object is printed when the sheet is printed. type xdrClientData struct { FLocksWithSheet bool `xml:"fLocksWithSheet,attr"` FPrintsWithSheet bool `xml:"fPrintsWithSheet,attr"` } // xdrCellAnchor directly maps the oneCellAnchor (One Cell Anchor Shape Size) // and twoCellAnchor (Two Cell Anchor Shape Size). This element specifies a two // cell anchor placeholder for a group, a shape, or a drawing element. It moves // with cells and its extents are in EMU units. type xdrCellAnchor struct { EditAs string `xml:"editAs,attr,omitempty"` From *xlsxFrom `xml:"xdr:from"` To *xlsxTo `xml:"xdr:to"` Ext *xlsxExt `xml:"xdr:ext"` Sp *xdrSp `xml:"xdr:sp"` Pic *xlsxPic `xml:"xdr:pic,omitempty"` GraphicFrame string `xml:",innerxml"` ClientData *xdrClientData `xml:"xdr:clientData"` } // xlsxWsDr directly maps the root element for a part of this content type shall // wsDr. type xlsxWsDr struct { XMLName xml.Name `xml:"xdr:wsDr"` OneCellAnchor []*xdrCellAnchor `xml:"xdr:oneCellAnchor"` TwoCellAnchor []*xdrCellAnchor `xml:"xdr:twoCellAnchor"` A string `xml:"xmlns:a,attr,omitempty"` Xdr string `xml:"xmlns:xdr,attr,omitempty"` R string `xml:"xmlns:r,attr,omitempty"` } // xlsxGraphicFrame (Graphic Frame) directly maps the xdr:graphicFrame element. // This element specifies the existence of a graphics frame. This frame contains // a graphic that was generated by an external source and needs a container in // which to be displayed on the slide surface. type xlsxGraphicFrame struct { XMLName xml.Name `xml:"xdr:graphicFrame"` Macro string `xml:"macro,attr"` NvGraphicFramePr xlsxNvGraphicFramePr `xml:"xdr:nvGraphicFramePr"` Xfrm xlsxXfrm `xml:"xdr:xfrm"` Graphic *xlsxGraphic `xml:"a:graphic"` } // xlsxNvGraphicFramePr (Non-Visual Properties for a Graphic Frame) directly // maps the xdr:nvGraphicFramePr element. This element specifies all non-visual // properties for a graphic frame. This element is a container for the non- // visual identification properties, shape properties and application properties // that are to be associated with a graphic frame. This allows for additional // information that does not affect the appearance of the graphic frame to be // stored. type xlsxNvGraphicFramePr struct { CNvPr *xlsxCNvPr `xml:"xdr:cNvPr"` ChicNvGraphicFramePr string `xml:"xdr:cNvGraphicFramePr"` } // xlsxGraphic (Graphic Object) directly maps the a:graphic element. This // element specifies the existence of a single graphic object. Document authors // should refer to this element when they wish to persist a graphical object of // some kind. The specification for this graphical object is provided entirely // by the document author and referenced within the graphicData child element. type xlsxGraphic struct { GraphicData *xlsxGraphicData `xml:"a:graphicData"` } // xlsxGraphicData (Graphic Object Data) directly maps the a:graphicData // element. This element specifies the reference to a graphic object within the // document. This graphic object is provided entirely by the document authors // who choose to persist this data within the document. type xlsxGraphicData struct { URI string `xml:"uri,attr"` Chart *xlsxChart `xml:"c:chart,omitempty"` } // xlsxChart (Chart) directly maps the c:chart element. type xlsxChart struct { C string `xml:"xmlns:c,attr"` RID string `xml:"r:id,attr"` R string `xml:"xmlns:r,attr"` } // xdrSp (Shape) directly maps the xdr:sp element. This element specifies the // existence of a single shape. A shape can either be a preset or a custom // geometry, defined using the SpreadsheetDrawingML framework. In addition to a // geometry each shape can have both visual and non-visual properties attached. // Text and corresponding styling information can also be attached to a shape. // This shape is specified along with all other shapes within either the shape // tree or group shape elements. type xdrSp struct { Macro string `xml:"macro,attr"` Textlink string `xml:"textlink,attr"` NvSpPr *xdrNvSpPr `xml:"xdr:nvSpPr"` SpPr *xlsxSpPr `xml:"xdr:spPr"` Style *xdrStyle `xml:"xdr:style"` TxBody *xdrTxBody `xml:"xdr:txBody"` } // xdrNvSpPr (Non-Visual Properties for a Shape) directly maps the xdr:nvSpPr // element. This element specifies all non-visual properties for a shape. This // element is a container for the non-visual identification properties, shape // properties and application properties that are to be associated with a shape. // This allows for additional information that does not affect the appearance of // the shape to be stored. type xdrNvSpPr struct { CNvPr *xlsxCNvPr `xml:"xdr:cNvPr"` CNvSpPr *xdrCNvSpPr `xml:"xdr:cNvSpPr"` } // xdrCNvSpPr (Connection Non-Visual Shape Properties) directly maps the // xdr:cNvSpPr element. This element specifies the set of non-visual properties // for a connection shape. These properties specify all data about the // connection shape which do not affect its display within a spreadsheet. type xdrCNvSpPr struct { TxBox bool `xml:"txBox,attr"` } // xdrStyle (Shape Style) directly maps the xdr:style element. The element // specifies the style that is applied to a shape and the corresponding // references for each of the style components such as lines and fills. type xdrStyle struct { LnRef *aRef `xml:"a:lnRef"` FillRef *aRef `xml:"a:fillRef"` EffectRef *aRef `xml:"a:effectRef"` FontRef *aFontRef `xml:"a:fontRef"` } // aRef directly maps the a:lnRef, a:fillRef and a:effectRef element. type aRef struct { Idx int `xml:"idx,attr"` ScrgbClr *aScrgbClr `xml:"a:scrgbClr"` SchemeClr *attrValString `xml:"a:schemeClr"` SrgbClr *attrValString `xml:"a:srgbClr"` } // aScrgbClr (RGB Color Model - Percentage Variant) directly maps the a:scrgbClr // element. This element specifies a color using the red, green, blue RGB color // model. Each component, red, green, and blue is expressed as a percentage from // 0% to 100%. A linear gamma of 1.0 is assumed. type aScrgbClr struct { R float64 `xml:"r,attr"` G float64 `xml:"g,attr"` B float64 `xml:"b,attr"` } // aFontRef (Font Reference) directly maps the a:fontRef element. This element // represents a reference to a themed font. When used it specifies which themed // font to use along with a choice of color. type aFontRef struct { Idx string `xml:"idx,attr"` SchemeClr *attrValString `xml:"a:schemeClr"` } // xdrTxBody (Shape Text Body) directly maps the xdr:txBody element. This // element specifies the existence of text to be contained within the // corresponding shape. All visible text and visible text related properties are // contained within this element. There can be multiple paragraphs and within // paragraphs multiple runs of text. type xdrTxBody struct { BodyPr *aBodyPr `xml:"a:bodyPr"` P []*aP `xml:"a:p"` } // formatPicture directly maps the format settings of the picture. type formatPicture struct { FPrintsWithSheet bool `json:"print_obj"` FLocksWithSheet bool `json:"locked"` NoChangeAspect bool `json:"lock_aspect_ratio"` OffsetX int `json:"x_offset"` OffsetY int `json:"y_offset"` XScale float64 `json:"x_scale"` YScale float64 `json:"y_scale"` Hyperlink string `json:"hyperlink"` HyperlinkType string `json:"hyperlink_type"` Positioning string `json:"positioning"` } // formatShape directly maps the format settings of the shape. type formatShape struct { Type string `json:"type"` Width int `json:"width"` Height int `json:"height"` Format formatPicture `json:"format"` Color formatShapeColor `json:"color"` Paragraph []formatShapeParagraph `json:"paragraph"` } // formatShapeParagraph directly maps the format settings of the paragraph in // the shape. type formatShapeParagraph struct { Font formatFont `json:"font"` Text string `json:"text"` } // formatShapeColor directly maps the color settings of the shape. type formatShapeColor struct { Line string `json:"line"` Fill string `json:"fill"` Effect string `json:"effect"` } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/xmlSharedStrings.go ================================================ package excelize import "encoding/xml" // xlsxSST directly maps the sst element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main. String values may // be stored directly inside spreadsheet cell elements; however, storing the // same value inside multiple cell elements can result in very large worksheet // Parts, possibly resulting in performance degradation. The Shared String Table // is an indexed list of string values, shared across the workbook, which allows // implementations to store values only once. type xlsxSST struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main sst"` Count int `xml:"count,attr"` UniqueCount int `xml:"uniqueCount,attr"` SI []xlsxSI `xml:"si"` } // xlsxSI directly maps the si element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked this for completeness - it does as much as I need. type xlsxSI struct { T string `xml:"t"` R []xlsxR `xml:"r"` } // xlsxR directly maps the r element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked this for completeness - it does as much as I need. type xlsxR struct { RPr *xlsxRPr `xml:"rPr"` T string `xml:"t"` } // xlsxRPr (Run Properties) specifies a set of run properties which shall be // applied to the contents of the parent run after all style formatting has been // applied to the text. These properties are defined as direct formatting, since // they are directly applied to the run and supersede any formatting from // styles. type xlsxRPr struct { B string `xml:"b,omitempty"` Sz *attrValFloat `xml:"sz"` Color *xlsxColor `xml:"color"` RFont *attrValString `xml:"rFont"` Family *attrValInt `xml:"family"` } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/xmlStyles.go ================================================ package excelize import "encoding/xml" // xlsxStyleSheet directly maps the stylesheet element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked it for completeness - it does as much as I need. type xlsxStyleSheet struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main styleSheet"` NumFmts *xlsxNumFmts `xml:"numFmts,omitempty"` Fonts *xlsxFonts `xml:"fonts,omitempty"` Fills *xlsxFills `xml:"fills,omitempty"` Borders *xlsxBorders `xml:"borders,omitempty"` CellStyleXfs *xlsxCellStyleXfs `xml:"cellStyleXfs,omitempty"` CellXfs *xlsxCellXfs `xml:"cellXfs,omitempty"` CellStyles *xlsxCellStyles `xml:"cellStyles,omitempty"` Dxfs *xlsxDxfs `xml:"dxfs,omitempty"` TableStyles *xlsxTableStyles `xml:"tableStyles,omitempty"` Colors *xlsxStyleColors `xml:"colors,omitempty"` ExtLst *xlsxExtLst `xml:"extLst"` } // xlsxAlignment formatting information pertaining to text alignment in cells. // There are a variety of choices for how text is aligned both horizontally and // vertically, as well as indentation settings, and so on. type xlsxAlignment struct { Horizontal string `xml:"horizontal,attr,omitempty"` Indent int `xml:"indent,attr,omitempty"` JustifyLastLine bool `xml:"justifyLastLine,attr,omitempty"` ReadingOrder uint64 `xml:"readingOrder,attr,omitempty"` RelativeIndent int `xml:"relativeIndent,attr,omitempty"` ShrinkToFit bool `xml:"shrinkToFit,attr,omitempty"` TextRotation int `xml:"textRotation,attr,omitempty"` Vertical string `xml:"vertical,attr,omitempty"` WrapText bool `xml:"wrapText,attr,omitempty"` } // xlsxProtection (Protection Properties) contains protection properties // associated with the cell. Each cell has protection properties that can be // set. The cell protection properties do not take effect unless the sheet has // been protected. type xlsxProtection struct { Hidden bool `xml:"hidden,attr"` Locked bool `xml:"locked,attr"` } // xlsxLine directly maps the line style element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked it for completeness - it does as much as I need. type xlsxLine struct { Style string `xml:"style,attr,omitempty"` Color *xlsxColor `xml:"color,omitempty"` } // xlsxColor is a common mapping used for both the fgColor and bgColor elements. // Foreground color of the cell fill pattern. Cell fill patterns operate with // two colors: a background color and a foreground color. These combine together // to make a patterned cell fill. Background color of the cell fill pattern. // Cell fill patterns operate with two colors: a background color and a // foreground color. These combine together to make a patterned cell fill. type xlsxColor struct { Auto bool `xml:"auto,attr,omitempty"` RGB string `xml:"rgb,attr,omitempty"` Indexed int `xml:"indexed,attr,omitempty"` Theme *int `xml:"theme,attr"` Tint float64 `xml:"tint,attr,omitempty"` } // xlsxFonts directly maps the font element. This element contains all font // definitions for this workbook. type xlsxFonts struct { Count int `xml:"count,attr"` Font []*xlsxFont `xml:"font"` } // font directly maps the font element. type font struct { Name *attrValString `xml:"name"` Charset *attrValInt `xml:"charset"` Family *attrValInt `xml:"family"` B bool `xml:"b,omitempty"` I bool `xml:"i,omitempty"` Strike bool `xml:"strike,omitempty"` Outline bool `xml:"outline,omitempty"` Shadow bool `xml:"shadow,omitempty"` Condense bool `xml:"condense,omitempty"` Extend bool `xml:"extend,omitempty"` Color *xlsxColor `xml:"color"` Sz *attrValInt `xml:"sz"` U *attrValString `xml:"u"` Scheme *attrValString `xml:"scheme"` } // xlsxFont directly maps the font element. This element defines the properties // for one of the fonts used in this workbook. type xlsxFont struct { Font string `xml:",innerxml"` } // xlsxFills directly maps the fills element. This element defines the cell // fills portion of the Styles part, consisting of a sequence of fill records. A // cell fill consists of a background color, foreground color, and pattern to be // applied across the cell. type xlsxFills struct { Count int `xml:"count,attr"` Fill []*xlsxFill `xml:"fill,omitempty"` } // xlsxFill directly maps the fill element. This element specifies fill // formatting. type xlsxFill struct { PatternFill *xlsxPatternFill `xml:"patternFill,omitempty"` GradientFill *xlsxGradientFill `xml:"gradientFill,omitempty"` } // xlsxPatternFill directly maps the patternFill element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked it for completeness - it does as much as I need. This element is // used to specify cell fill information for pattern and solid color cell fills. // For solid cell fills (no pattern), fgColor is used. For cell fills with // patterns specified, then the cell fill color is specified by the bgColor // element. type xlsxPatternFill struct { PatternType string `xml:"patternType,attr,omitempty"` FgColor xlsxColor `xml:"fgColor,omitempty"` BgColor xlsxColor `xml:"bgColor,omitempty"` } // xlsxGradientFill defines a gradient-style cell fill. Gradient cell fills can // use one or two colors as the end points of color interpolation. type xlsxGradientFill struct { Bottom float64 `xml:"bottom,attr,omitempty"` Degree float64 `xml:"degree,attr,omitempty"` Left float64 `xml:"left,attr,omitempty"` Right float64 `xml:"right,attr,omitempty"` Top float64 `xml:"top,attr,omitempty"` Type string `xml:"type,attr,omitempty"` Stop []*xlsxGradientFillStop `xml:"stop,omitempty"` } // xlsxGradientFillStop directly maps the stop element. type xlsxGradientFillStop struct { Position float64 `xml:"position,attr"` Color xlsxColor `xml:"color,omitempty"` } // xlsxBorders directly maps the borders element. This element contains borders // formatting information, specifying all border definitions for all cells in // the workbook. type xlsxBorders struct { Count int `xml:"count,attr"` Border []*xlsxBorder `xml:"border,omitempty"` } // xlsxBorder directly maps the border element. Expresses a single set of cell // border formats (left, right, top, bottom, diagonal). Color is optional. When // missing, 'automatic' is implied. type xlsxBorder struct { DiagonalDown bool `xml:"diagonalDown,attr,omitempty"` DiagonalUp bool `xml:"diagonalUp,attr,omitempty"` Outline bool `xml:"outline,attr,omitempty"` Left xlsxLine `xml:"left,omitempty"` Right xlsxLine `xml:"right,omitempty"` Top xlsxLine `xml:"top,omitempty"` Bottom xlsxLine `xml:"bottom,omitempty"` Diagonal xlsxLine `xml:"diagonal,omitempty"` } // xlsxCellStyles directly maps the cellStyles element. This element contains // the named cell styles, consisting of a sequence of named style records. A // named cell style is a collection of direct or themed formatting (e.g., cell // border, cell fill, and font type/size/style) grouped together into a single // named style, and can be applied to a cell. type xlsxCellStyles struct { XMLName xml.Name `xml:"cellStyles"` Count int `xml:"count,attr"` CellStyle []*xlsxCellStyle `xml:"cellStyle,omitempty"` } // xlsxCellStyle directly maps the cellStyle element. This element represents // the name and related formatting records for a named cell style in this // workbook. type xlsxCellStyle struct { XMLName xml.Name `xml:"cellStyle"` BuiltInID *int `xml:"builtinId,attr,omitempty"` CustomBuiltIn *bool `xml:"customBuiltin,attr,omitempty"` Hidden *bool `xml:"hidden,attr,omitempty"` ILevel *bool `xml:"iLevel,attr,omitempty"` Name string `xml:"name,attr"` XfID int `xml:"xfId,attr"` } // xlsxCellStyleXfs directly maps the cellStyleXfs element. This element // contains the master formatting records (xf's) which define the formatting for // all named cell styles in this workbook. Master formatting records reference // individual elements of formatting (e.g., number format, font definitions, // cell fills, etc) by specifying a zero-based index into those collections. // Master formatting records also specify whether to apply or ignore particular // aspects of formatting. type xlsxCellStyleXfs struct { Count int `xml:"count,attr"` Xf []xlsxXf `xml:"xf,omitempty"` } // xlsxXf directly maps the xf element. A single xf element describes all of the // formatting for a cell. type xlsxXf struct { ApplyAlignment bool `xml:"applyAlignment,attr"` ApplyBorder bool `xml:"applyBorder,attr"` ApplyFill bool `xml:"applyFill,attr"` ApplyFont bool `xml:"applyFont,attr"` ApplyNumberFormat bool `xml:"applyNumberFormat,attr"` ApplyProtection bool `xml:"applyProtection,attr"` BorderID int `xml:"borderId,attr"` FillID int `xml:"fillId,attr"` FontID int `xml:"fontId,attr"` NumFmtID int `xml:"numFmtId,attr"` PivotButton bool `xml:"pivotButton,attr,omitempty"` QuotePrefix bool `xml:"quotePrefix,attr,omitempty"` XfID *int `xml:"xfId,attr"` Alignment *xlsxAlignment `xml:"alignment"` Protection *xlsxProtection `xml:"protection"` } // xlsxCellXfs directly maps the cellXfs element. This element contains the // master formatting records (xf) which define the formatting applied to cells // in this workbook. These records are the starting point for determining the // formatting for a cell. Cells in the Sheet Part reference the xf records by // zero-based index. type xlsxCellXfs struct { Count int `xml:"count,attr"` Xf []xlsxXf `xml:"xf,omitempty"` } // xlsxDxfs directly maps the dxfs element. This element contains the master // differential formatting records (dxf's) which define formatting for all non- // cell formatting in this workbook. Whereas xf records fully specify a // particular aspect of formatting (e.g., cell borders) by referencing those // formatting definitions elsewhere in the Styles part, dxf records specify // incremental (or differential) aspects of formatting directly inline within // the dxf element. The dxf formatting is to be applied on top of or in addition // to any formatting already present on the object using the dxf record. type xlsxDxfs struct { Count int `xml:"count,attr"` Dxfs []*xlsxDxf `xml:"dxf,omitempty"` } // xlsxDxf directly maps the dxf element. A single dxf record, expressing // incremental formatting to be applied. type xlsxDxf struct { Dxf string `xml:",innerxml"` } // dxf directly maps the dxf element. type dxf struct { Font *font `xml:"font"` NumFmt *xlsxNumFmt `xml:"numFmt"` Fill *xlsxFill `xml:"fill"` Alignment *xlsxAlignment `xml:"alignment"` Border *xlsxBorder `xml:"border"` Protection *xlsxProtection `xml:"protection"` ExtLst *xlsxExt `xml:"extLst"` } // xlsxTableStyles directly maps the tableStyles element. This element // represents a collection of Table style definitions for Table styles and // PivotTable styles used in this workbook. It consists of a sequence of // tableStyle records, each defining a single Table style. type xlsxTableStyles struct { Count int `xml:"count,attr"` DefaultPivotStyle string `xml:"defaultPivotStyle,attr"` DefaultTableStyle string `xml:"defaultTableStyle,attr"` TableStyles []*xlsxTableStyle `xml:"tableStyle,omitempty"` } // xlsxTableStyle directly maps the tableStyle element. This element represents // a single table style definition that indicates how a spreadsheet application // should format and display a table. type xlsxTableStyle struct { Name string `xml:"name,attr,omitempty"` Pivot int `xml:"pivot,attr"` Count int `xml:"count,attr,omitempty"` Table bool `xml:"table,attr,omitempty"` TableStyleElement string `xml:",innerxml"` } // xlsxNumFmts directly maps the numFmts element. This element defines the // number formats in this workbook, consisting of a sequence of numFmt records, // where each numFmt record defines a particular number format, indicating how // to format and render the numeric value of a cell. type xlsxNumFmts struct { Count int `xml:"count,attr"` NumFmt []*xlsxNumFmt `xml:"numFmt,omitempty"` } // xlsxNumFmt directly maps the numFmt element. This element specifies number // format properties which indicate how to format and render the numeric value // of a cell. type xlsxNumFmt struct { NumFmtID int `xml:"numFmtId,attr,omitempty"` FormatCode string `xml:"formatCode,attr,omitempty"` } // xlsxStyleColors directly maps the colors element. Color information // associated with this stylesheet. This collection is written whenever the // legacy color palette has been modified (backwards compatibility settings) or // a custom color has been selected while using this workbook. type xlsxStyleColors struct { Color string `xml:",innerxml"` } // formatFont directly maps the styles settings of the fonts. type formatFont struct { Bold bool `json:"bold"` Italic bool `json:"italic"` Underline string `json:"underline"` Family string `json:"family"` Size int `json:"size"` Color string `json:"color"` } // formatStyle directly maps the styles settings of the cells. type formatStyle struct { Border []struct { Type string `json:"type"` Color string `json:"color"` Style int `json:"style"` } `json:"border"` Fill struct { Type string `json:"type"` Pattern int `json:"pattern"` Color []string `json:"color"` Shading int `json:"shading"` } `json:"fill"` Font *formatFont `json:"font"` Alignment *struct { Horizontal string `json:"horizontal"` Indent int `json:"indent"` JustifyLastLine bool `json:"justify_last_line"` ReadingOrder uint64 `json:"reading_order"` RelativeIndent int `json:"relative_indent"` ShrinkToFit bool `json:"shrink_to_fit"` TextRotation int `json:"text_rotation"` Vertical string `json:"vertical"` WrapText bool `json:"wrap_text"` } `json:"alignment"` Protection *struct { Hidden bool `json:"hidden"` Locked bool `json:"locked"` } `json:"protection"` NumFmt int `json:"number_format"` DecimalPlaces int `json:"decimal_places"` CustomNumFmt *string `json:"custom_number_format"` Lang string `json:"lang"` NegRed bool `json:"negred"` } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/xmlTable.go ================================================ package excelize import "encoding/xml" // xlsxTable directly maps the table element. A table helps organize and provide // structure to lists of information in a worksheet. Tables have clearly labeled // columns, rows, and data regions. Tables make it easier for users to sort, // analyze, format, manage, add, and delete information. This element is the // root element for a table that is not a single cell XML table. type xlsxTable struct { XMLName xml.Name `xml:"table"` XMLNS string `xml:"xmlns,attr"` DataCellStyle string `xml:"dataCellStyle,attr,omitempty"` DataDxfID int `xml:"dataDxfId,attr,omitempty"` DisplayName string `xml:"displayName,attr,omitempty"` HeaderRowBorderDxfID int `xml:"headerRowBorderDxfId,attr,omitempty"` HeaderRowCellStyle string `xml:"headerRowCellStyle,attr,omitempty"` HeaderRowCount int `xml:"headerRowCount,attr,omitempty"` HeaderRowDxfID int `xml:"headerRowDxfId,attr,omitempty"` ID int `xml:"id,attr"` InsertRow bool `xml:"insertRow,attr,omitempty"` InsertRowShift bool `xml:"insertRowShift,attr,omitempty"` Name string `xml:"name,attr"` Published bool `xml:"published,attr,omitempty"` Ref string `xml:"ref,attr"` TotalsRowCount int `xml:"totalsRowCount,attr,omitempty"` TotalsRowDxfID int `xml:"totalsRowDxfId,attr,omitempty"` TotalsRowShown bool `xml:"totalsRowShown,attr"` AutoFilter *xlsxAutoFilter `xml:"autoFilter"` TableColumns *xlsxTableColumns `xml:"tableColumns"` TableStyleInfo *xlsxTableStyleInfo `xml:"tableStyleInfo"` } // xlsxAutoFilter temporarily hides rows based on a filter criteria, which is // applied column by column to a table of data in the worksheet. This collection // expresses AutoFilter settings. type xlsxAutoFilter struct { Ref string `xml:"ref,attr"` FilterColumn *xlsxFilterColumn `xml:"filterColumn"` } // xlsxFilterColumn directly maps the filterColumn element. The filterColumn // collection identifies a particular column in the AutoFilter range and // specifies filter information that has been applied to this column. If a // column in the AutoFilter range has no criteria specified, then there is no // corresponding filterColumn collection expressed for that column. type xlsxFilterColumn struct { ColID int `xml:"colId,attr"` HiddenButton bool `xml:"hiddenButton,attr,omitempty"` ShowButton bool `xml:"showButton,attr,omitempty"` CustomFilters *xlsxCustomFilters `xml:"customFilters"` Filters *xlsxFilters `xml:"filters"` ColorFilter *xlsxColorFilter `xml:"colorFilter"` DynamicFilter *xlsxDynamicFilter `xml:"dynamicFilter"` IconFilter *xlsxIconFilter `xml:"iconFilter"` Top10 *xlsxTop10 `xml:"top10"` } // xlsxCustomFilters directly maps the customFilters element. When there is more // than one custom filter criteria to apply (an 'and' or 'or' joining two // criteria), then this element groups the customFilter elements together. type xlsxCustomFilters struct { And bool `xml:"and,attr,omitempty"` CustomFilter []*xlsxCustomFilter `xml:"customFilter"` } // xlsxCustomFilter directly maps the customFilter element. A custom AutoFilter // specifies an operator and a value. There can be at most two customFilters // specified, and in that case the parent element specifies whether the two // conditions are joined by 'and' or 'or'. For any cells whose values do not // meet the specified criteria, the corresponding rows shall be hidden from view // when the filter is applied. type xlsxCustomFilter struct { Operator string `xml:"operator,attr,omitempty"` Val string `xml:"val,attr,omitempty"` } // xlsxFilters directly maps the filters (Filter Criteria) element. When // multiple values are chosen to filter by, or when a group of date values are // chosen to filter by, this element groups those criteria together. type xlsxFilters struct { Blank bool `xml:"blank,attr,omitempty"` CalendarType string `xml:"calendarType,attr,omitempty"` Filter []*xlsxFilter `xml:"filter"` DateGroupItem []*xlsxDateGroupItem `xml:"dateGroupItem"` } // xlsxFilter directly maps the filter element. This element expresses a filter // criteria value. type xlsxFilter struct { Val string `xml:"val,attr,omitempty"` } // xlsxColorFilter directly maps the colorFilter element. This element specifies // the color to filter by and whether to use the cell's fill or font color in // the filter criteria. If the cell's font or fill color does not match the // color specified in the criteria, the rows corresponding to those cells are // hidden from view. type xlsxColorFilter struct { CellColor bool `xml:"cellColor,attr"` DxfID int `xml:"dxfId,attr"` } // xlsxDynamicFilter directly maps the dynamicFilter element. This collection // specifies dynamic filter criteria. These criteria are considered dynamic // because they can change, either with the data itself (e.g., "above average") // or with the current system date (e.g., show values for "today"). For any // cells whose values do not meet the specified criteria, the corresponding rows // shall be hidden from view when the filter is applied. type xlsxDynamicFilter struct { MaxValISO string `xml:"maxValIso,attr,omitempty"` Type string `xml:"type,attr,omitempty"` Val float64 `xml:"val,attr,omitempty"` ValISO string `xml:"valIso,attr,omitempty"` } // xlsxIconFilter directly maps the iconFilter element. This element specifies // the icon set and particular icon within that set to filter by. For any cells // whose icon does not match the specified criteria, the corresponding rows // shall be hidden from view when the filter is applied. type xlsxIconFilter struct { IconID int `xml:"iconId,attr"` IconSet string `xml:"iconSet,attr,omitempty"` } // xlsxTop10 directly maps the top10 element. This element specifies the top N // (percent or number of items) to filter by. type xlsxTop10 struct { FilterVal float64 `xml:"filterVal,attr,omitempty"` Percent bool `xml:"percent,attr,omitempty"` Top bool `xml:"top,attr"` Val float64 `xml:"val,attr,omitempty"` } // xlsxDateGroupItem directly maps the dateGroupItem element. This collection is // used to express a group of dates or times which are used in an AutoFilter // criteria. [Note: See parent element for an example. end note] Values are // always written in the calendar type of the first date encountered in the // filter range, so that all subsequent dates, even when formatted or // represented by other calendar types, can be correctly compared for the // purposes of filtering. type xlsxDateGroupItem struct { DateTimeGrouping string `xml:"dateTimeGrouping,attr,omitempty"` Day int `xml:"day,attr,omitempty"` Hour int `xml:"hour,attr,omitempty"` Minute int `xml:"minute,attr,omitempty"` Month int `xml:"month,attr,omitempty"` Second int `xml:"second,attr,omitempty"` Year int `xml:"year,attr,omitempty"` } // xlsxTableColumns directly maps the element representing the collection of all // table columns for this table. type xlsxTableColumns struct { Count int `xml:"count,attr"` TableColumn []*xlsxTableColumn `xml:"tableColumn"` } // xlsxTableColumn directly maps the element representing a single column for // this table. type xlsxTableColumn struct { DataCellStyle string `xml:"dataCellStyle,attr,omitempty"` DataDxfID int `xml:"dataDxfId,attr,omitempty"` HeaderRowCellStyle string `xml:"headerRowCellStyle,attr,omitempty"` HeaderRowDxfID int `xml:"headerRowDxfId,attr,omitempty"` ID int `xml:"id,attr"` Name string `xml:"name,attr"` QueryTableFieldID int `xml:"queryTableFieldId,attr,omitempty"` TotalsRowCellStyle string `xml:"totalsRowCellStyle,attr,omitempty"` TotalsRowDxfID int `xml:"totalsRowDxfId,attr,omitempty"` TotalsRowFunction string `xml:"totalsRowFunction,attr,omitempty"` TotalsRowLabel string `xml:"totalsRowLabel,attr,omitempty"` UniqueName string `xml:"uniqueName,attr,omitempty"` } // xlsxTableStyleInfo directly maps the tableStyleInfo element. This element // describes which style is used to display this table, and specifies which // portions of the table have the style applied. type xlsxTableStyleInfo struct { Name string `xml:"name,attr,omitempty"` ShowFirstColumn bool `xml:"showFirstColumn,attr"` ShowLastColumn bool `xml:"showLastColumn,attr"` ShowRowStripes bool `xml:"showRowStripes,attr"` ShowColumnStripes bool `xml:"showColumnStripes,attr"` } // formatTable directly maps the format settings of the table. type formatTable struct { TableName string `json:"table_name"` TableStyle string `json:"table_style"` ShowFirstColumn bool `json:"show_first_column"` ShowLastColumn bool `json:"show_last_column"` ShowRowStripes bool `json:"show_row_stripes"` ShowColumnStripes bool `json:"show_column_stripes"` } // formatAutoFilter directly maps the auto filter settings. type formatAutoFilter struct { Column string `json:"column"` Expression string `json:"expression"` FilterList []struct { Column string `json:"column"` Value []int `json:"value"` } `json:"filter_list"` } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/xmlWorkbook.go ================================================ package excelize import "encoding/xml" // xmlxWorkbookRels contains xmlxWorkbookRelations which maps sheet id and sheet XML. type xlsxWorkbookRels struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/relationships Relationships"` Relationships []xlsxWorkbookRelation `xml:"Relationship"` } // xmlxWorkbookRelation maps sheet id and xl/worksheets/_rels/sheet%d.xml.rels type xlsxWorkbookRelation struct { ID string `xml:"Id,attr"` Target string `xml:",attr"` Type string `xml:",attr"` TargetMode string `xml:",attr,omitempty"` } // xlsxWorkbook directly maps the workbook element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked it for completeness - it does as much as I need. type xlsxWorkbook struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main workbook"` FileVersion *xlsxFileVersion `xml:"fileVersion"` WorkbookPr *xlsxWorkbookPr `xml:"workbookPr"` WorkbookProtection *xlsxWorkbookProtection `xml:"workbookProtection"` BookViews xlsxBookViews `xml:"bookViews"` Sheets xlsxSheets `xml:"sheets"` ExternalReferences *xlsxExternalReferences `xml:"externalReferences"` DefinedNames *xlsxDefinedNames `xml:"definedNames"` CalcPr *xlsxCalcPr `xml:"calcPr"` CustomWorkbookViews *xlsxCustomWorkbookViews `xml:"customWorkbookViews"` PivotCaches *xlsxPivotCaches `xml:"pivotCaches"` ExtLst *xlsxExtLst `xml:"extLst"` FileRecoveryPr *xlsxFileRecoveryPr `xml:"fileRecoveryPr"` } // xlsxFileRecoveryPr maps sheet recovery information. This element defines // properties that track the state of the workbook file, such as whether the // file was saved during a crash, or whether it should be opened in auto-recover // mode. type xlsxFileRecoveryPr struct { AutoRecover bool `xml:"autoRecover,attr,omitempty"` CrashSave bool `xml:"crashSave,attr,omitempty"` DataExtractLoad bool `xml:"dataExtractLoad,attr,omitempty"` RepairLoad bool `xml:"repairLoad,attr,omitempty"` } // xlsxWorkbookProtection directly maps the workbookProtection element. This // element specifies options for protecting data in the workbook. Applications // might use workbook protection to prevent anyone from accidentally changing, // moving, or deleting important data. This protection can be ignored by // applications which choose not to support this optional protection mechanism. // When a password is to be hashed and stored in this element, it shall be // hashed as defined below, starting from a UTF-16LE encoded string value. If // there is a leading BOM character (U+FEFF) in the encoded password it is // removed before hash calculation. type xlsxWorkbookProtection struct { LockRevision bool `xml:"lockRevision,attr,omitempty"` LockStructure bool `xml:"lockStructure,attr,omitempty"` LockWindows bool `xml:"lockWindows,attr,omitempty"` RevisionsAlgorithmName string `xml:"revisionsAlgorithmName,attr,omitempty"` RevisionsHashValue string `xml:"revisionsHashValue,attr,omitempty"` RevisionsSaltValue string `xml:"revisionsSaltValue,attr,omitempty"` RevisionsSpinCount int `xml:"revisionsSpinCount,attr,omitempty"` WorkbookAlgorithmName string `xml:"workbookAlgorithmName,attr,omitempty"` WorkbookHashValue string `xml:"workbookHashValue,attr,omitempty"` WorkbookSaltValue string `xml:"workbookSaltValue,attr,omitempty"` WorkbookSpinCount int `xml:"workbookSpinCount,attr,omitempty"` } // xlsxFileVersion directly maps the fileVersion element. This element defines // properties that track which version of the application accessed the data and // source code contained in the file. type xlsxFileVersion struct { AppName string `xml:"appName,attr,omitempty"` CodeName string `xml:"codeName,attr,omitempty"` LastEdited string `xml:"lastEdited,attr,omitempty"` LowestEdited string `xml:"lowestEdited,attr,omitempty"` RupBuild string `xml:"rupBuild,attr,omitempty"` } // xlsxWorkbookPr directly maps the workbookPr element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main This element // defines a collection of workbook properties. type xlsxWorkbookPr struct { AllowRefreshQuery bool `xml:"allowRefreshQuery,attr,omitempty"` AutoCompressPictures bool `xml:"autoCompressPictures,attr,omitempty"` BackupFile bool `xml:"backupFile,attr,omitempty"` CheckCompatibility bool `xml:"checkCompatibility,attr,omitempty"` CodeName string `xml:"codeName,attr,omitempty"` Date1904 bool `xml:"date1904,attr,omitempty"` DefaultThemeVersion string `xml:"defaultThemeVersion,attr,omitempty"` FilterPrivacy bool `xml:"filterPrivacy,attr,omitempty"` HidePivotFieldList bool `xml:"hidePivotFieldList,attr,omitempty"` PromptedSolutions bool `xml:"promptedSolutions,attr,omitempty"` PublishItems bool `xml:"publishItems,attr,omitempty"` RefreshAllConnections bool `xml:"refreshAllConnections,attr,omitempty"` SaveExternalLinkValues bool `xml:"saveExternalLinkValues,attr,omitempty"` ShowBorderUnselectedTables bool `xml:"showBorderUnselectedTables,attr,omitempty"` ShowInkAnnotation bool `xml:"showInkAnnotation,attr,omitempty"` ShowObjects string `xml:"showObjects,attr,omitempty"` ShowPivotChartFilter bool `xml:"showPivotChartFilter,attr,omitempty"` UpdateLinks string `xml:"updateLinks,attr,omitempty"` } // xlsxBookViews directly maps the bookViews element. This element specifies the // collection of workbook views of the enclosing workbook. Each view can specify // a window position, filter options, and other configurations. There is no // limit on the number of workbook views that can be defined for a workbook. type xlsxBookViews struct { WorkBookView []xlsxWorkBookView `xml:"workbookView"` } // xlsxWorkBookView directly maps the workbookView element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main This element // specifies a single Workbook view. type xlsxWorkBookView struct { ActiveTab int `xml:"activeTab,attr,omitempty"` AutoFilterDateGrouping bool `xml:"autoFilterDateGrouping,attr,omitempty"` FirstSheet int `xml:"firstSheet,attr,omitempty"` Minimized bool `xml:"minimized,attr,omitempty"` ShowHorizontalScroll bool `xml:"showHorizontalScroll,attr,omitempty"` ShowSheetTabs bool `xml:"showSheetTabs,attr,omitempty"` ShowVerticalScroll bool `xml:"showVerticalScroll,attr,omitempty"` TabRatio int `xml:"tabRatio,attr,omitempty"` Visibility string `xml:"visibility,attr,omitempty"` WindowHeight int `xml:"windowHeight,attr,omitempty"` WindowWidth int `xml:"windowWidth,attr,omitempty"` XWindow string `xml:"xWindow,attr,omitempty"` YWindow string `xml:"yWindow,attr,omitempty"` } // xlsxSheets directly maps the sheets element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main. type xlsxSheets struct { Sheet []xlsxSheet `xml:"sheet"` } // xlsxSheet directly maps the sheet element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked it for completeness - it does as much as I need. type xlsxSheet struct { Name string `xml:"name,attr,omitempty"` SheetID string `xml:"sheetId,attr,omitempty"` ID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` State string `xml:"state,attr,omitempty"` } // xlsxExternalReferences directly maps the externalReferences element of the // external workbook references part. type xlsxExternalReferences struct { ExternalReference []xlsxExternalReference `xml:"externalReference"` } // xlsxExternalReference directly maps the externalReference element of the // external workbook references part. type xlsxExternalReference struct { RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` } // xlsxPivotCaches element enumerates pivot cache definition parts used by pivot // tables and formulas in this workbook. type xlsxPivotCaches struct { PivotCache []xlsxPivotCache `xml:"pivotCache"` } // xlsxPivotCache directly maps the pivotCache element. type xlsxPivotCache struct { CacheID int `xml:"cacheId,attr,omitempty"` RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` } // extLst element provides a convention for extending spreadsheetML in // predefined locations. The locations shall be denoted with the extLst element, // and are called extension lists. Extension list locations within the markup // document are specified in the markup specification and can be used to store // extensions to the markup specification, whether those are future version // extensions of the markup specification or are private extensions implemented // independently from the markup specification. Markup within an extension might // not be understood by a consumer. type xlsxExtLst struct { Ext string `xml:",innerxml"` } // xlsxDefinedNames directly maps the definedNames element. This element defines // the collection of defined names for this workbook. Defined names are // descriptive names to represent cells, ranges of cells, formulas, or constant // values. Defined names can be used to represent a range on any worksheet. type xlsxDefinedNames struct { DefinedName []xlsxDefinedName `xml:"definedName"` } // xlsxDefinedName directly maps the definedName element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main This element // defines a defined name within this workbook. A defined name is descriptive // text that is used to represents a cell, range of cells, formula, or constant // value. For a descriptions of the attributes see https://msdn.microsoft.com/en-us/library/office/documentformat.openxml.spreadsheet.definedname.aspx type xlsxDefinedName struct { Comment string `xml:"comment,attr,omitempty"` CustomMenu string `xml:"customMenu,attr,omitempty"` Description string `xml:"description,attr,omitempty"` Function bool `xml:"function,attr,omitempty"` FunctionGroupID int `xml:"functionGroupId,attr,omitempty"` Help string `xml:"help,attr,omitempty"` Hidden bool `xml:"hidden,attr,omitempty"` LocalSheetID *int `xml:"localSheetId,attr"` Name string `xml:"name,attr,omitempty"` PublishToServer bool `xml:"publishToServer,attr,omitempty"` ShortcutKey string `xml:"shortcutKey,attr,omitempty"` StatusBar string `xml:"statusBar,attr,omitempty"` VbProcedure bool `xml:"vbProcedure,attr,omitempty"` WorkbookParameter bool `xml:"workbookParameter,attr,omitempty"` Xlm bool `xml:"xml,attr,omitempty"` Data string `xml:",chardata"` } // xlsxCalcPr directly maps the calcPr element. This element defines the // collection of properties the application uses to record calculation status // and details. Calculation is the process of computing formulas and then // displaying the results as values in the cells that contain the formulas. type xlsxCalcPr struct { CalcCompleted bool `xml:"calcCompleted,attr,omitempty"` CalcID string `xml:"calcId,attr,omitempty"` CalcMode string `xml:"calcMode,attr,omitempty"` CalcOnSave bool `xml:"calcOnSave,attr,omitempty"` ConcurrentCalc *bool `xml:"concurrentCalc,attr"` ConcurrentManualCount int `xml:"concurrentManualCount,attr,omitempty"` ForceFullCalc bool `xml:"forceFullCalc,attr,omitempty"` FullCalcOnLoad bool `xml:"fullCalcOnLoad,attr,omitempty"` FullPrecision bool `xml:"fullPrecision,attr,omitempty"` Iterate bool `xml:"iterate,attr,omitempty"` IterateCount int `xml:"iterateCount,attr,omitempty"` IterateDelta float64 `xml:"iterateDelta,attr,omitempty"` RefMode string `xml:"refMode,attr,omitempty"` } // xlsxCustomWorkbookViews defines the collection of custom workbook views that // are defined for this workbook. A customWorkbookView is similar in concept to // a workbookView in that its attributes contain settings related to the way // that the workbook should be displayed on a screen by a spreadsheet // application. type xlsxCustomWorkbookViews struct { CustomWorkbookView []xlsxCustomWorkbookView `xml:"customWorkbookView"` } // xlsxCustomWorkbookView directly maps the customWorkbookView element. This // element specifies a single custom workbook view. A custom workbook view // consists of a set of display and print settings that you can name and apply // to a workbook. You can create more than one custom workbook view of the same // workbook. Custom Workbook Views are not required in order to construct a // valid SpreadsheetML document, and are not necessary if the document is never // displayed by a spreadsheet application, or if the spreadsheet application has // a fixed display for workbooks. However, if a spreadsheet application chooses // to implement configurable display modes, the customWorkbookView element // should be used to persist the settings for those display modes. type xlsxCustomWorkbookView struct { ActiveSheetID *int `xml:"activeSheetId,attr"` AutoUpdate *bool `xml:"autoUpdate,attr"` ChangesSavedWin *bool `xml:"changesSavedWin,attr"` GUID *string `xml:"guid,attr"` IncludeHiddenRowCol *bool `xml:"includeHiddenRowCol,attr"` IncludePrintSettings *bool `xml:"includePrintSettings,attr"` Maximized *bool `xml:"maximized,attr"` MergeInterval int `xml:"mergeInterval,attr"` Minimized *bool `xml:"minimized,attr"` Name *string `xml:"name,attr"` OnlySync *bool `xml:"onlySync,attr"` PersonalView *bool `xml:"personalView,attr"` ShowComments *string `xml:"showComments,attr"` ShowFormulaBar *bool `xml:"showFormulaBar,attr"` ShowHorizontalScroll *bool `xml:"showHorizontalScroll,attr"` ShowObjects *string `xml:"showObjects,attr"` ShowSheetTabs *bool `xml:"showSheetTabs,attr"` ShowStatusbar *bool `xml:"showStatusbar,attr"` ShowVerticalScroll *bool `xml:"showVerticalScroll,attr"` TabRatio *int `xml:"tabRatio,attr"` WindowHeight *int `xml:"windowHeight,attr"` WindowWidth *int `xml:"windowWidth,attr"` XWindow *int `xml:"xWindow,attr"` YWindow *int `xml:"yWindow,attr"` } ================================================ FILE: vendor/github.com/360EntSecGroup-Skylar/excelize/xmlWorksheet.go ================================================ package excelize import "encoding/xml" // xlsxWorksheet directly maps the worksheet element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked it for completeness - it does as much as I need. type xlsxWorksheet struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main worksheet"` SheetPr *xlsxSheetPr `xml:"sheetPr"` Dimension xlsxDimension `xml:"dimension"` SheetViews xlsxSheetViews `xml:"sheetViews,omitempty"` SheetFormatPr *xlsxSheetFormatPr `xml:"sheetFormatPr"` Cols *xlsxCols `xml:"cols,omitempty"` SheetData xlsxSheetData `xml:"sheetData"` SheetProtection *xlsxSheetProtection `xml:"sheetProtection"` AutoFilter *xlsxAutoFilter `xml:"autoFilter"` MergeCells *xlsxMergeCells `xml:"mergeCells"` PhoneticPr *xlsxPhoneticPr `xml:"phoneticPr"` ConditionalFormatting []*xlsxConditionalFormatting `xml:"conditionalFormatting"` DataValidations *xlsxDataValidations `xml:"dataValidations"` Hyperlinks *xlsxHyperlinks `xml:"hyperlinks"` PrintOptions *xlsxPrintOptions `xml:"printOptions"` PageMargins *xlsxPageMargins `xml:"pageMargins"` PageSetUp *xlsxPageSetUp `xml:"pageSetup"` HeaderFooter *xlsxHeaderFooter `xml:"headerFooter"` Drawing *xlsxDrawing `xml:"drawing"` LegacyDrawing *xlsxLegacyDrawing `xml:"legacyDrawing"` Picture *xlsxPicture `xml:"picture"` TableParts *xlsxTableParts `xml:"tableParts"` ExtLst *xlsxExtLst `xml:"extLst"` } // xlsxDrawing change r:id to rid in the namespace. type xlsxDrawing struct { RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` } // xlsxHeaderFooter directly maps the headerFooter element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - When printed or // viewed in page layout view (§18.18.69), each page of a worksheet can have a // page header, a page footer, or both. The headers and footers on odd-numbered // pages can differ from those on even-numbered pages, and the headers and // footers on the first page can differ from those on odd- and even-numbered // pages. In the latter case, the first page is not considered an odd page. type xlsxHeaderFooter struct { DifferentFirst bool `xml:"differentFirst,attr,omitempty"` DifferentOddEven bool `xml:"differentOddEven,attr,omitempty"` OddHeader []*xlsxOddHeader `xml:"oddHeader"` OddFooter []*xlsxOddFooter `xml:"oddFooter"` } // xlsxOddHeader directly maps the oddHeader element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked it for completeness - it does as much as I need. type xlsxOddHeader struct { Content string `xml:",chardata"` } // xlsxOddFooter directly maps the oddFooter element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked it for completeness - it does as much as I need. type xlsxOddFooter struct { Content string `xml:",chardata"` } // xlsxPageSetUp directly maps the pageSetup element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - Page setup // settings for the worksheet. type xlsxPageSetUp struct { BlackAndWhite bool `xml:"blackAndWhite,attr,omitempty"` CellComments string `xml:"cellComments,attr,omitempty"` Copies int `xml:"copies,attr,omitempty"` Draft bool `xml:"draft,attr,omitempty"` Errors string `xml:"errors,attr,omitempty"` FirstPageNumber int `xml:"firstPageNumber,attr,omitempty"` FitToHeight *int `xml:"fitToHeight,attr"` FitToWidth int `xml:"fitToWidth,attr,omitempty"` HorizontalDPI float32 `xml:"horizontalDpi,attr,omitempty"` RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` Orientation string `xml:"orientation,attr,omitempty"` PageOrder string `xml:"pageOrder,attr,omitempty"` PaperHeight string `xml:"paperHeight,attr,omitempty"` PaperSize string `xml:"paperSize,attr,omitempty"` PaperWidth string `xml:"paperWidth,attr,omitempty"` Scale int `xml:"scale,attr,omitempty"` UseFirstPageNumber bool `xml:"useFirstPageNumber,attr,omitempty"` UsePrinterDefaults bool `xml:"usePrinterDefaults,attr,omitempty"` VerticalDPI float32 `xml:"verticalDpi,attr,omitempty"` } // xlsxPrintOptions directly maps the printOptions element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - Print options for // the sheet. Printer-specific settings are stored separately in the Printer // Settings part. type xlsxPrintOptions struct { GridLines bool `xml:"gridLines,attr,omitempty"` GridLinesSet bool `xml:"gridLinesSet,attr,omitempty"` Headings bool `xml:"headings,attr,omitempty"` HorizontalCentered bool `xml:"horizontalCentered,attr,omitempty"` VerticalCentered bool `xml:"verticalCentered,attr,omitempty"` } // xlsxPageMargins directly maps the pageMargins element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - Page margins for // a sheet or a custom sheet view. type xlsxPageMargins struct { Bottom float64 `xml:"bottom,attr"` Footer float64 `xml:"footer,attr"` Header float64 `xml:"header,attr"` Left float64 `xml:"left,attr"` Right float64 `xml:"right,attr"` Top float64 `xml:"top,attr"` } // xlsxSheetFormatPr directly maps the sheetFormatPr element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main. This element // specifies the sheet formatting properties. type xlsxSheetFormatPr struct { BaseColWidth uint8 `xml:"baseColWidth,attr,omitempty"` DefaultColWidth float64 `xml:"defaultColWidth,attr,omitempty"` DefaultRowHeight float64 `xml:"defaultRowHeight,attr"` CustomHeight bool `xml:"customHeight,attr,omitempty"` ZeroHeight bool `xml:"zeroHeight,attr,omitempty"` ThickTop bool `xml:"thickTop,attr,omitempty"` ThickBottom bool `xml:"thickBottom,attr,omitempty"` OutlineLevelRow uint8 `xml:"outlineLevelRow,attr,omitempty"` OutlineLevelCol uint8 `xml:"outlineLevelCol,attr,omitempty"` } // xlsxSheetViews directly maps the sheetViews element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - Worksheet views // collection. type xlsxSheetViews struct { SheetView []xlsxSheetView `xml:"sheetView"` } // xlsxSheetView directly maps the sheetView element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked it for completeness - it does as much as I need. A single sheet // view definition. When more than one sheet view is defined in the file, it // means that when opening the workbook, each sheet view corresponds to a // separate window within the spreadsheet application, where each window is // showing the particular sheet containing the same workbookViewId value, the // last sheetView definition is loaded, and the others are discarded. When // multiple windows are viewing the same sheet, multiple sheetView elements // (with corresponding workbookView entries) are saved. // See https://msdn.microsoft.com/en-us/library/office/documentformat.openxml.spreadsheet.sheetview.aspx type xlsxSheetView struct { WindowProtection bool `xml:"windowProtection,attr,omitempty"` ShowFormulas bool `xml:"showFormulas,attr,omitempty"` ShowGridLines *bool `xml:"showGridLines,attr"` ShowRowColHeaders *bool `xml:"showRowColHeaders,attr"` ShowZeros bool `xml:"showZeros,attr,omitempty"` RightToLeft bool `xml:"rightToLeft,attr,omitempty"` TabSelected bool `xml:"tabSelected,attr,omitempty"` ShowWhiteSpace *bool `xml:"showWhiteSpace,attr"` ShowOutlineSymbols bool `xml:"showOutlineSymbols,attr,omitempty"` DefaultGridColor *bool `xml:"defaultGridColor,attr"` View string `xml:"view,attr,omitempty"` TopLeftCell string `xml:"topLeftCell,attr,omitempty"` ColorID int `xml:"colorId,attr,omitempty"` ZoomScale float64 `xml:"zoomScale,attr,omitempty"` ZoomScaleNormal float64 `xml:"zoomScaleNormal,attr,omitempty"` ZoomScalePageLayoutView float64 `xml:"zoomScalePageLayoutView,attr,omitempty"` ZoomScaleSheetLayoutView float64 `xml:"zoomScaleSheetLayoutView,attr,omitempty"` WorkbookViewID int `xml:"workbookViewId,attr"` Pane *xlsxPane `xml:"pane,omitempty"` Selection []*xlsxSelection `xml:"selection"` } // xlsxSelection directly maps the selection element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - Worksheet view // selection. type xlsxSelection struct { ActiveCell string `xml:"activeCell,attr,omitempty"` ActiveCellID *int `xml:"activeCellId,attr"` Pane string `xml:"pane,attr,omitempty"` SQRef string `xml:"sqref,attr,omitempty"` } // xlsxSelection directly maps the selection element. Worksheet view pane. type xlsxPane struct { ActivePane string `xml:"activePane,attr,omitempty"` State string `xml:"state,attr,omitempty"` // Either "split" or "frozen" TopLeftCell string `xml:"topLeftCell,attr,omitempty"` XSplit float64 `xml:"xSplit,attr,omitempty"` YSplit float64 `xml:"ySplit,attr,omitempty"` } // xlsxSheetPr directly maps the sheetPr element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - Sheet-level // properties. type xlsxSheetPr struct { XMLName xml.Name `xml:"sheetPr"` CodeName string `xml:"codeName,attr,omitempty"` EnableFormatConditionsCalculation *bool `xml:"enableFormatConditionsCalculation,attr"` FilterMode bool `xml:"filterMode,attr,omitempty"` Published *bool `xml:"published,attr"` SyncHorizontal bool `xml:"syncHorizontal,attr,omitempty"` SyncVertical bool `xml:"syncVertical,attr,omitempty"` TransitionEntry bool `xml:"transitionEntry,attr,omitempty"` TabColor *xlsxTabColor `xml:"tabColor,omitempty"` PageSetUpPr *xlsxPageSetUpPr `xml:"pageSetUpPr,omitempty"` } // xlsxPageSetUpPr directly maps the pageSetupPr element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - Page setup // properties of the worksheet. type xlsxPageSetUpPr struct { AutoPageBreaks bool `xml:"autoPageBreaks,attr,omitempty"` FitToPage bool `xml:"fitToPage,attr,omitempty"` // Flag indicating whether the Fit to Page print option is enabled. } // xlsxTabColor directly maps the tabColor element in the namespace currently I // have not checked it for completeness - it does as much as I need. type xlsxTabColor struct { Theme int `xml:"theme,attr,omitempty"` Tint float64 `xml:"tint,attr,omitempty"` } // xlsxCols directly maps the cols element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked it for completeness - it does as much as I need. type xlsxCols struct { Col []xlsxCol `xml:"col"` } // xlsxCol directly maps the col (Column Width & Formatting). Defines column // width and column formatting for one or more columns of the worksheet. type xlsxCol struct { BestFit bool `xml:"bestFit,attr,omitempty"` Collapsed bool `xml:"collapsed,attr"` CustomWidth bool `xml:"customWidth,attr,omitempty"` Hidden bool `xml:"hidden,attr"` Max int `xml:"max,attr"` Min int `xml:"min,attr"` OutlineLevel uint8 `xml:"outlineLevel,attr,omitempty"` Phonetic bool `xml:"phonetic,attr,omitempty"` Style int `xml:"style,attr"` Width float64 `xml:"width,attr"` } // xlsxDimension directly maps the dimension element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - This element // specifies the used range of the worksheet. It specifies the row and column // bounds of used cells in the worksheet. This is optional and is not required. // Used cells include cells with formulas, text content, and cell formatting. // When an entire column is formatted, only the first cell in that column is // considered used. type xlsxDimension struct { Ref string `xml:"ref,attr"` } // xlsxSheetData directly maps the sheetData element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked it for completeness - it does as much as I need. type xlsxSheetData struct { XMLName xml.Name `xml:"sheetData"` Row []xlsxRow `xml:"row"` } // xlsxRow directly maps the row element. The element expresses information // about an entire row of a worksheet, and contains all cell definitions for a // particular row in the worksheet. type xlsxRow struct { Collapsed bool `xml:"collapsed,attr,omitempty"` CustomFormat bool `xml:"customFormat,attr,omitempty"` CustomHeight bool `xml:"customHeight,attr,omitempty"` Hidden bool `xml:"hidden,attr,omitempty"` Ht float64 `xml:"ht,attr,omitempty"` OutlineLevel uint8 `xml:"outlineLevel,attr,omitempty"` Ph bool `xml:"ph,attr,omitempty"` R int `xml:"r,attr,omitempty"` S int `xml:"s,attr,omitempty"` Spans string `xml:"spans,attr,omitempty"` ThickBot bool `xml:"thickBot,attr,omitempty"` ThickTop bool `xml:"thickTop,attr,omitempty"` C []xlsxC `xml:"c"` } // xlsxMergeCell directly maps the mergeCell element. A single merged cell. type xlsxMergeCell struct { Ref string `xml:"ref,attr,omitempty"` } // xlsxMergeCells directly maps the mergeCells element. This collection // expresses all the merged cells in the sheet. type xlsxMergeCells struct { Count int `xml:"count,attr,omitempty"` Cells []*xlsxMergeCell `xml:"mergeCell,omitempty"` } // xlsxDataValidations expresses all data validation information for cells in a // sheet which have data validation features applied. type xlsxDataValidations struct { Count int `xml:"count,attr,omitempty"` DisablePrompts bool `xml:"disablePrompts,attr,omitempty"` XWindow int `xml:"xWindow,attr,omitempty"` YWindow int `xml:"yWindow,attr,omitempty"` DataValidation string `xml:",innerxml"` } // xlsxC directly maps the c element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked it for completeness - it does as much as I need. // // This simple type is restricted to the values listed in the following table: // // Enumeration Value | Description // ---------------------------+--------------------------------- // b (Boolean) | Cell containing a boolean. // d (Date) | Cell contains a date in the ISO 8601 format. // e (Error) | Cell containing an error. // inlineStr (Inline String) | Cell containing an (inline) rich string, i.e., one not in the shared string table. If this cell type is used, then the cell value is in the is element rather than the v element in the cell (c element). // n (Number) | Cell containing a number. // s (Shared String) | Cell containing a shared string. // str (String) | Cell containing a formula string. // type xlsxC struct { R string `xml:"r,attr"` // Cell ID, e.g. A1 S int `xml:"s,attr,omitempty"` // Style reference. // Str string `xml:"str,attr,omitempty"` // Style reference. T string `xml:"t,attr,omitempty"` // Type. F *xlsxF `xml:"f,omitempty"` // Formula V string `xml:"v,omitempty"` // Value IS *xlsxIS `xml:"is"` XMLSpace xml.Attr `xml:"space,attr,omitempty"` } // xlsxIS directly maps the t element. Cell containing an (inline) rich // string, i.e., one not in the shared string table. If this cell type is // used, then the cell value is in the is element rather than the v element in // the cell (c element). type xlsxIS struct { T string `xml:"t"` } // xlsxF directly maps the f element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked it for completeness - it does as much as I need. type xlsxF struct { Content string `xml:",chardata"` T string `xml:"t,attr,omitempty"` // Formula type Ref string `xml:"ref,attr,omitempty"` // Shared formula ref Si string `xml:"si,attr,omitempty"` // Shared formula index } // xlsxSheetProtection collection expresses the sheet protection options to // enforce when the sheet is protected. type xlsxSheetProtection struct { AlgorithmName string `xml:"algorithmName,attr,omitempty"` AutoFilter int `xml:"autoFilter,attr,omitempty"` DeleteColumns int `xml:"deleteColumns,attr,omitempty"` DeleteRows int `xml:"deleteRows,attr,omitempty"` FormatCells int `xml:"formatCells,attr,omitempty"` FormatColumns int `xml:"formatColumns,attr,omitempty"` FormatRows int `xml:"formatRows,attr,omitempty"` HashValue string `xml:"hashValue,attr,omitempty"` InsertColumns int `xml:"insertColumns,attr,omitempty"` InsertHyperlinks int `xml:"insertHyperlinks,attr,omitempty"` InsertRows int `xml:"insertRows,attr,omitempty"` Objects int `xml:"objects,attr,omitempty"` PivotTables int `xml:"pivotTables,attr,omitempty"` SaltValue string `xml:"saltValue,attr,omitempty"` Scenarios int `xml:"scenarios,attr,omitempty"` SelectLockedCells int `xml:"selectLockedCells,attr,omitempty"` SelectUnlockedCell int `xml:"selectUnlockedCell,attr,omitempty"` Sheet int `xml:"sheet,attr,omitempty"` Sort int `xml:"sort,attr,omitempty"` SpinCount int `xml:"spinCount,attr,omitempty"` } // xlsxPhoneticPr (Phonetic Properties) represents a collection of phonetic // properties that affect the display of phonetic text for this String Item // (si). Phonetic text is used to give hints as to the pronunciation of an East // Asian language, and the hints are displayed as text within the spreadsheet // cells across the top portion of the cell. Since the phonetic hints are text, // every phonetic hint is expressed as a phonetic run (rPh), and these // properties specify how to display that phonetic run. type xlsxPhoneticPr struct { Alignment string `xml:"alignment,attr,omitempty"` FontID *int `xml:"fontId,attr"` Type string `xml:"type,attr,omitempty"` } // A Conditional Format is a format, such as cell shading or font color, that a // spreadsheet application can automatically apply to cells if a specified // condition is true. This collection expresses conditional formatting rules // applied to a particular cell or range. type xlsxConditionalFormatting struct { SQRef string `xml:"sqref,attr,omitempty"` CfRule []*xlsxCfRule `xml:"cfRule"` } // xlsxCfRule (Conditional Formatting Rule) represents a description of a // conditional formatting rule. type xlsxCfRule struct { AboveAverage *bool `xml:"aboveAverage,attr"` Bottom bool `xml:"bottom,attr,omitempty"` DxfID *int `xml:"dxfId,attr"` EqualAverage bool `xml:"equalAverage,attr,omitempty"` Operator string `xml:"operator,attr,omitempty"` Percent bool `xml:"percent,attr,omitempty"` Priority int `xml:"priority,attr,omitempty"` Rank int `xml:"rank,attr,omitempty"` StdDev int `xml:"stdDev,attr,omitempty"` StopIfTrue bool `xml:"stopIfTrue,attr,omitempty"` Text string `xml:"text,attr,omitempty"` TimePeriod string `xml:"timePeriod,attr,omitempty"` Type string `xml:"type,attr,omitempty"` Formula []string `xml:"formula,omitempty"` ColorScale *xlsxColorScale `xml:"colorScale"` DataBar *xlsxDataBar `xml:"dataBar"` IconSet *xlsxIconSet `xml:"iconSet"` ExtLst *xlsxExtLst `xml:"extLst"` } // xlsxColorScale (Color Scale) describes a gradated color scale in this // conditional formatting rule. type xlsxColorScale struct { Cfvo []*xlsxCfvo `xml:"cfvo"` Color []*xlsxColor `xml:"color"` } // dataBar (Data Bar) describes a data bar conditional formatting rule. type xlsxDataBar struct { MaxLength int `xml:"maxLength,attr,omitempty"` MinLength int `xml:"minLength,attr,omitempty"` ShowValue bool `xml:"showValue,attr,omitempty"` Cfvo []*xlsxCfvo `xml:"cfvo"` Color []*xlsxColor `xml:"color"` } // xlsxIconSet (Icon Set) describes an icon set conditional formatting rule. type xlsxIconSet struct { Cfvo []*xlsxCfvo `xml:"cfvo"` IconSet string `xml:"iconSet,attr,omitempty"` ShowValue bool `xml:"showValue,attr,omitempty"` Percent bool `xml:"percent,attr,omitempty"` Reverse bool `xml:"reverse,attr,omitempty"` } // cfvo (Conditional Format Value Object) describes the values of the // interpolation points in a gradient scale. type xlsxCfvo struct { Gte bool `xml:"gte,attr,omitempty"` Type string `xml:"type,attr,omitempty"` Val int `xml:"val,attr"` ExtLst *xlsxExtLst `xml:"extLst"` } // xlsxHyperlinks directly maps the hyperlinks element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - A hyperlink can // be stored in a package as a relationship. Hyperlinks shall be identified by // containing a target which specifies the destination of the given hyperlink. type xlsxHyperlinks struct { Hyperlink []xlsxHyperlink `xml:"hyperlink"` } // xlsxHyperlink directly maps the hyperlink element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main type xlsxHyperlink struct { Ref string `xml:"ref,attr"` Location string `xml:"location,attr,omitempty"` Display string `xml:"display,attr,omitempty"` RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` } // xlsxTableParts directly maps the tableParts element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - The table element // has several attributes applied to identify the table and the data range it // covers. The table id attribute needs to be unique across all table parts, the // same goes for the name and displayName. The displayName has the further // restriction that it must be unique across all defined names in the workbook. // Later on we will see that you can define names for many elements, such as // cells or formulas. The name value is used for the object model in Microsoft // Office Excel. The displayName is used for references in formulas. The ref // attribute is used to identify the cell range that the table covers. This // includes not only the table data, but also the table header containing column // names. // To add columns to your table you add new tableColumn elements to the // tableColumns container. Similar to the shared string table the collection // keeps a count attribute identifying the number of columns. Besides the table // definition in the table part there is also the need to identify which tables // are displayed in the worksheet. The worksheet part has a separate element // tableParts to store this information. Each table part is referenced through // the relationship ID and again a count of the number of table parts is // maintained. The following markup sample is taken from the documents // accompanying this book. The sheet data element has been removed to reduce the // size of the sample. To reference the table, just add the tableParts element, // of course after having created and stored the table part. For example: // // // ... // // // // // type xlsxTableParts struct { Count int `xml:"count,attr,omitempty"` TableParts []*xlsxTablePart `xml:"tablePart"` } // xlsxTablePart directly maps the tablePart element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main type xlsxTablePart struct { RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` } // xlsxPicture directly maps the picture element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - Background sheet // image. For example: // // // type xlsxPicture struct { RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` } // xlsxLegacyDrawing directly maps the legacyDrawing element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - A comment is a // rich text note that is attached to, and associated with, a cell, separate // from other cell content. Comment content is stored separate from the cell, // and is displayed in a drawing object (like a text box) that is separate from, // but associated with, a cell. Comments are used as reminders, such as noting // how a complex formula works, or to provide feedback to other users. Comments // can also be used to explain assumptions made in a formula or to call out // something special about the cell. type xlsxLegacyDrawing struct { RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` } // formatPanes directly maps the settings of the panes. type formatPanes struct { Freeze bool `json:"freeze"` Split bool `json:"split"` XSplit int `json:"x_split"` YSplit int `json:"y_split"` TopLeftCell string `json:"top_left_cell"` ActivePane string `json:"active_pane"` Panes []struct { SQRef string `json:"sqref"` ActiveCell string `json:"active_cell"` Pane string `json:"pane"` } `json:"panes"` } // formatConditional directly maps the conditional format settings of the cells. type formatConditional struct { Type string `json:"type"` AboveAverage bool `json:"above_average"` Percent bool `json:"percent"` Format int `json:"format"` Criteria string `json:"criteria"` Value string `json:"value,omitempty"` Minimum string `json:"minimum,omitempty"` Maximum string `json:"maximum,omitempty"` MinType string `json:"min_type,omitempty"` MidType string `json:"mid_type,omitempty"` MaxType string `json:"max_type,omitempty"` MinValue string `json:"min_value,omitempty"` MidValue string `json:"mid_value,omitempty"` MaxValue string `json:"max_value,omitempty"` MinColor string `json:"min_color,omitempty"` MidColor string `json:"mid_color,omitempty"` MaxColor string `json:"max_color,omitempty"` MinLength string `json:"min_length,omitempty"` MaxLength string `json:"max_length,omitempty"` MultiRange string `json:"multi_range,omitempty"` BarColor string `json:"bar_color,omitempty"` } ================================================ FILE: vendor/github.com/PuerkitoBio/purell/.gitignore ================================================ *.sublime-* .DS_Store *.swp *.swo tags ================================================ FILE: vendor/github.com/PuerkitoBio/purell/.travis.yml ================================================ language: go go: - 1.4.x - 1.5.x - 1.6.x - 1.7.x - 1.8.x - 1.9.x - "1.10.x" - tip ================================================ FILE: vendor/github.com/PuerkitoBio/purell/LICENSE ================================================ Copyright (c) 2012, Martin Angers 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 author 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. ================================================ FILE: vendor/github.com/PuerkitoBio/purell/README.md ================================================ # Purell Purell is a tiny Go library to normalize URLs. It returns a pure URL. Pure-ell. Sanitizer and all. Yeah, I know... Based on the [wikipedia paper][wiki] and the [RFC 3986 document][rfc]. [![build status](https://travis-ci.org/PuerkitoBio/purell.svg?branch=master)](http://travis-ci.org/PuerkitoBio/purell) ## Install `go get github.com/PuerkitoBio/purell` ## Changelog * **2016-11-14 (v1.1.0)** : IDN: Conform to RFC 5895: Fold character width (thanks to @beeker1121). * **2016-07-27 (v1.0.0)** : Normalize IDN to ASCII (thanks to @zenovich). * **2015-02-08** : Add fix for relative paths issue ([PR #5][pr5]) and add fix for unnecessary encoding of reserved characters ([see issue #7][iss7]). * **v0.2.0** : Add benchmarks, Attempt IDN support. * **v0.1.0** : Initial release. ## Examples From `example_test.go` (note that in your code, you would import "github.com/PuerkitoBio/purell", and would prefix references to its methods and constants with "purell."): ```go package purell import ( "fmt" "net/url" ) func ExampleNormalizeURLString() { if normalized, err := NormalizeURLString("hTTp://someWEBsite.com:80/Amazing%3f/url/", FlagLowercaseScheme|FlagLowercaseHost|FlagUppercaseEscapes); err != nil { panic(err) } else { fmt.Print(normalized) } // Output: http://somewebsite.com:80/Amazing%3F/url/ } func ExampleMustNormalizeURLString() { normalized := MustNormalizeURLString("hTTpS://someWEBsite.com:443/Amazing%fa/url/", FlagsUnsafeGreedy) fmt.Print(normalized) // Output: http://somewebsite.com/Amazing%FA/url } func ExampleNormalizeURL() { if u, err := url.Parse("Http://SomeUrl.com:8080/a/b/.././c///g?c=3&a=1&b=9&c=0#target"); err != nil { panic(err) } else { normalized := NormalizeURL(u, FlagsUsuallySafeGreedy|FlagRemoveDuplicateSlashes|FlagRemoveFragment) fmt.Print(normalized) } // Output: http://someurl.com:8080/a/c/g?c=3&a=1&b=9&c=0 } ``` ## API As seen in the examples above, purell offers three methods, `NormalizeURLString(string, NormalizationFlags) (string, error)`, `MustNormalizeURLString(string, NormalizationFlags) (string)` and `NormalizeURL(*url.URL, NormalizationFlags) (string)`. They all normalize the provided URL based on the specified flags. Here are the available flags: ```go const ( // Safe normalizations FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1 FlagLowercaseHost // http://HOST -> http://host FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$ FlagRemoveDefaultPort // http://host:80 -> http://host FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path // Usually safe normalizations FlagRemoveTrailingSlash // http://host/path/ -> http://host/path FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags) FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c // Unsafe normalizations FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/ FlagRemoveFragment // http://host/path#fragment -> http://host/path FlagForceHTTP // https://host -> http://host FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b FlagRemoveWWW // http://www.host/ -> http://host/ FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags) FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3 // Normalizations not in the wikipedia article, required to cover tests cases // submitted by jehiah FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147 FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147 FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147 FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path // Convenience set of safe normalizations FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator // For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags, // while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix". // Convenience set of usually safe normalizations (includes FlagsSafe) FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments // Convenience set of unsafe normalizations (includes FlagsUsuallySafe) FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery // Convenience set of all available flags FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator ) ``` For convenience, the set of flags `FlagsSafe`, `FlagsUsuallySafe[Greedy|NonGreedy]`, `FlagsUnsafe[Greedy|NonGreedy]` and `FlagsAll[Greedy|NonGreedy]` are provided for the similarly grouped normalizations on [wikipedia's URL normalization page][wiki]. You can add (using the bitwise OR `|` operator) or remove (using the bitwise AND NOT `&^` operator) individual flags from the sets if required, to build your own custom set. The [full godoc reference is available on gopkgdoc][godoc]. Some things to note: * `FlagDecodeUnnecessaryEscapes`, `FlagEncodeNecessaryEscapes`, `FlagUppercaseEscapes` and `FlagRemoveEmptyQuerySeparator` are always implicitly set, because internally, the URL string is parsed as an URL object, which automatically decodes unnecessary escapes, uppercases and encodes necessary ones, and removes empty query separators (an unnecessary `?` at the end of the url). So this operation cannot **not** be done. For this reason, `FlagRemoveEmptyQuerySeparator` (as well as the other three) has been included in the `FlagsSafe` convenience set, instead of `FlagsUnsafe`, where Wikipedia puts it. * The `FlagDecodeUnnecessaryEscapes` decodes the following escapes (*from -> to*): - %24 -> $ - %26 -> & - %2B-%3B -> +,-./0123456789:; - %3D -> = - %40-%5A -> @ABCDEFGHIJKLMNOPQRSTUVWXYZ - %5F -> _ - %61-%7A -> abcdefghijklmnopqrstuvwxyz - %7E -> ~ * When the `NormalizeURL` function is used (passing an URL object), this source URL object is modified (that is, after the call, the URL object will be modified to reflect the normalization). * The *replace IP with domain name* normalization (`http://208.77.188.166/ → http://www.example.com/`) is obviously not possible for a library without making some network requests. This is not implemented in purell. * The *remove unused query string parameters* and *remove default query parameters* are also not implemented, since this is a very case-specific normalization, and it is quite trivial to do with an URL object. ### Safe vs Usually Safe vs Unsafe Purell allows you to control the level of risk you take while normalizing an URL. You can aggressively normalize, play it totally safe, or anything in between. Consider the following URL: `HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid` Normalizing with the `FlagsSafe` gives: `https://www.root.com/toto/tE%1F///a/./b/../c/?z=3&w=2&a=4&w=1#invalid` With the `FlagsUsuallySafeGreedy`: `https://www.root.com/toto/tE%1F///a/c?z=3&w=2&a=4&w=1#invalid` And with `FlagsUnsafeGreedy`: `http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3` ## TODOs * Add a class/default instance to allow specifying custom directory index names? At the moment, removing directory index removes `(^|/)((?:default|index)\.\w{1,4})$`. ## Thanks / Contributions @rogpeppe @jehiah @opennota @pchristopher1275 @zenovich @beeker1121 ## License The [BSD 3-Clause license][bsd]. [bsd]: http://opensource.org/licenses/BSD-3-Clause [wiki]: http://en.wikipedia.org/wiki/URL_normalization [rfc]: http://tools.ietf.org/html/rfc3986#section-6 [godoc]: http://go.pkgdoc.org/github.com/PuerkitoBio/purell [pr5]: https://github.com/PuerkitoBio/purell/pull/5 [iss7]: https://github.com/PuerkitoBio/purell/issues/7 ================================================ FILE: vendor/github.com/PuerkitoBio/purell/purell.go ================================================ /* Package purell offers URL normalization as described on the wikipedia page: http://en.wikipedia.org/wiki/URL_normalization */ package purell import ( "bytes" "fmt" "net/url" "regexp" "sort" "strconv" "strings" "github.com/PuerkitoBio/urlesc" "golang.org/x/net/idna" "golang.org/x/text/unicode/norm" "golang.org/x/text/width" ) // A set of normalization flags determines how a URL will // be normalized. type NormalizationFlags uint const ( // Safe normalizations FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1 FlagLowercaseHost // http://HOST -> http://host FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$ FlagRemoveDefaultPort // http://host:80 -> http://host FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path // Usually safe normalizations FlagRemoveTrailingSlash // http://host/path/ -> http://host/path FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags) FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c // Unsafe normalizations FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/ FlagRemoveFragment // http://host/path#fragment -> http://host/path FlagForceHTTP // https://host -> http://host FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b FlagRemoveWWW // http://www.host/ -> http://host/ FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags) FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3 // Normalizations not in the wikipedia article, required to cover tests cases // submitted by jehiah FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147 FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147 FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147 FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path // Convenience set of safe normalizations FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator // For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags, // while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix". // Convenience set of usually safe normalizations (includes FlagsSafe) FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments // Convenience set of unsafe normalizations (includes FlagsUsuallySafe) FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery // Convenience set of all available flags FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator ) const ( defaultHttpPort = ":80" defaultHttpsPort = ":443" ) // Regular expressions used by the normalizations var rxPort = regexp.MustCompile(`(:\d+)/?$`) var rxDirIndex = regexp.MustCompile(`(^|/)((?:default|index)\.\w{1,4})$`) var rxDupSlashes = regexp.MustCompile(`/{2,}`) var rxDWORDHost = regexp.MustCompile(`^(\d+)((?:\.+)?(?:\:\d*)?)$`) var rxOctalHost = regexp.MustCompile(`^(0\d*)\.(0\d*)\.(0\d*)\.(0\d*)((?:\.+)?(?:\:\d*)?)$`) var rxHexHost = regexp.MustCompile(`^0x([0-9A-Fa-f]+)((?:\.+)?(?:\:\d*)?)$`) var rxHostDots = regexp.MustCompile(`^(.+?)(:\d+)?$`) var rxEmptyPort = regexp.MustCompile(`:+$`) // Map of flags to implementation function. // FlagDecodeUnnecessaryEscapes has no action, since it is done automatically // by parsing the string as an URL. Same for FlagUppercaseEscapes and FlagRemoveEmptyQuerySeparator. // Since maps have undefined traversing order, make a slice of ordered keys var flagsOrder = []NormalizationFlags{ FlagLowercaseScheme, FlagLowercaseHost, FlagRemoveDefaultPort, FlagRemoveDirectoryIndex, FlagRemoveDotSegments, FlagRemoveFragment, FlagForceHTTP, // Must be after remove default port (because https=443/http=80) FlagRemoveDuplicateSlashes, FlagRemoveWWW, FlagAddWWW, FlagSortQuery, FlagDecodeDWORDHost, FlagDecodeOctalHost, FlagDecodeHexHost, FlagRemoveUnnecessaryHostDots, FlagRemoveEmptyPortSeparator, FlagRemoveTrailingSlash, // These two (add/remove trailing slash) must be last FlagAddTrailingSlash, } // ... and then the map, where order is unimportant var flags = map[NormalizationFlags]func(*url.URL){ FlagLowercaseScheme: lowercaseScheme, FlagLowercaseHost: lowercaseHost, FlagRemoveDefaultPort: removeDefaultPort, FlagRemoveDirectoryIndex: removeDirectoryIndex, FlagRemoveDotSegments: removeDotSegments, FlagRemoveFragment: removeFragment, FlagForceHTTP: forceHTTP, FlagRemoveDuplicateSlashes: removeDuplicateSlashes, FlagRemoveWWW: removeWWW, FlagAddWWW: addWWW, FlagSortQuery: sortQuery, FlagDecodeDWORDHost: decodeDWORDHost, FlagDecodeOctalHost: decodeOctalHost, FlagDecodeHexHost: decodeHexHost, FlagRemoveUnnecessaryHostDots: removeUnncessaryHostDots, FlagRemoveEmptyPortSeparator: removeEmptyPortSeparator, FlagRemoveTrailingSlash: removeTrailingSlash, FlagAddTrailingSlash: addTrailingSlash, } // MustNormalizeURLString returns the normalized string, and panics if an error occurs. // It takes an URL string as input, as well as the normalization flags. func MustNormalizeURLString(u string, f NormalizationFlags) string { result, e := NormalizeURLString(u, f) if e != nil { panic(e) } return result } // NormalizeURLString returns the normalized string, or an error if it can't be parsed into an URL object. // It takes an URL string as input, as well as the normalization flags. func NormalizeURLString(u string, f NormalizationFlags) (string, error) { parsed, err := url.Parse(u) if err != nil { return "", err } if f&FlagLowercaseHost == FlagLowercaseHost { parsed.Host = strings.ToLower(parsed.Host) } // The idna package doesn't fully conform to RFC 5895 // (https://tools.ietf.org/html/rfc5895), so we do it here. // Taken from Go 1.8 cycle source, courtesy of bradfitz. // TODO: Remove when (if?) idna package conforms to RFC 5895. parsed.Host = width.Fold.String(parsed.Host) parsed.Host = norm.NFC.String(parsed.Host) if parsed.Host, err = idna.ToASCII(parsed.Host); err != nil { return "", err } return NormalizeURL(parsed, f), nil } // NormalizeURL returns the normalized string. // It takes a parsed URL object as input, as well as the normalization flags. func NormalizeURL(u *url.URL, f NormalizationFlags) string { for _, k := range flagsOrder { if f&k == k { flags[k](u) } } return urlesc.Escape(u) } func lowercaseScheme(u *url.URL) { if len(u.Scheme) > 0 { u.Scheme = strings.ToLower(u.Scheme) } } func lowercaseHost(u *url.URL) { if len(u.Host) > 0 { u.Host = strings.ToLower(u.Host) } } func removeDefaultPort(u *url.URL) { if len(u.Host) > 0 { scheme := strings.ToLower(u.Scheme) u.Host = rxPort.ReplaceAllStringFunc(u.Host, func(val string) string { if (scheme == "http" && val == defaultHttpPort) || (scheme == "https" && val == defaultHttpsPort) { return "" } return val }) } } func removeTrailingSlash(u *url.URL) { if l := len(u.Path); l > 0 { if strings.HasSuffix(u.Path, "/") { u.Path = u.Path[:l-1] } } else if l = len(u.Host); l > 0 { if strings.HasSuffix(u.Host, "/") { u.Host = u.Host[:l-1] } } } func addTrailingSlash(u *url.URL) { if l := len(u.Path); l > 0 { if !strings.HasSuffix(u.Path, "/") { u.Path += "/" } } else if l = len(u.Host); l > 0 { if !strings.HasSuffix(u.Host, "/") { u.Host += "/" } } } func removeDotSegments(u *url.URL) { if len(u.Path) > 0 { var dotFree []string var lastIsDot bool sections := strings.Split(u.Path, "/") for _, s := range sections { if s == ".." { if len(dotFree) > 0 { dotFree = dotFree[:len(dotFree)-1] } } else if s != "." { dotFree = append(dotFree, s) } lastIsDot = (s == "." || s == "..") } // Special case if host does not end with / and new path does not begin with / u.Path = strings.Join(dotFree, "/") if u.Host != "" && !strings.HasSuffix(u.Host, "/") && !strings.HasPrefix(u.Path, "/") { u.Path = "/" + u.Path } // Special case if the last segment was a dot, make sure the path ends with a slash if lastIsDot && !strings.HasSuffix(u.Path, "/") { u.Path += "/" } } } func removeDirectoryIndex(u *url.URL) { if len(u.Path) > 0 { u.Path = rxDirIndex.ReplaceAllString(u.Path, "$1") } } func removeFragment(u *url.URL) { u.Fragment = "" } func forceHTTP(u *url.URL) { if strings.ToLower(u.Scheme) == "https" { u.Scheme = "http" } } func removeDuplicateSlashes(u *url.URL) { if len(u.Path) > 0 { u.Path = rxDupSlashes.ReplaceAllString(u.Path, "/") } } func removeWWW(u *url.URL) { if len(u.Host) > 0 && strings.HasPrefix(strings.ToLower(u.Host), "www.") { u.Host = u.Host[4:] } } func addWWW(u *url.URL) { if len(u.Host) > 0 && !strings.HasPrefix(strings.ToLower(u.Host), "www.") { u.Host = "www." + u.Host } } func sortQuery(u *url.URL) { q := u.Query() if len(q) > 0 { arKeys := make([]string, len(q)) i := 0 for k := range q { arKeys[i] = k i++ } sort.Strings(arKeys) buf := new(bytes.Buffer) for _, k := range arKeys { sort.Strings(q[k]) for _, v := range q[k] { if buf.Len() > 0 { buf.WriteRune('&') } buf.WriteString(fmt.Sprintf("%s=%s", k, urlesc.QueryEscape(v))) } } // Rebuild the raw query string u.RawQuery = buf.String() } } func decodeDWORDHost(u *url.URL) { if len(u.Host) > 0 { if matches := rxDWORDHost.FindStringSubmatch(u.Host); len(matches) > 2 { var parts [4]int64 dword, _ := strconv.ParseInt(matches[1], 10, 0) for i, shift := range []uint{24, 16, 8, 0} { parts[i] = dword >> shift & 0xFF } u.Host = fmt.Sprintf("%d.%d.%d.%d%s", parts[0], parts[1], parts[2], parts[3], matches[2]) } } } func decodeOctalHost(u *url.URL) { if len(u.Host) > 0 { if matches := rxOctalHost.FindStringSubmatch(u.Host); len(matches) > 5 { var parts [4]int64 for i := 1; i <= 4; i++ { parts[i-1], _ = strconv.ParseInt(matches[i], 8, 0) } u.Host = fmt.Sprintf("%d.%d.%d.%d%s", parts[0], parts[1], parts[2], parts[3], matches[5]) } } } func decodeHexHost(u *url.URL) { if len(u.Host) > 0 { if matches := rxHexHost.FindStringSubmatch(u.Host); len(matches) > 2 { // Conversion is safe because of regex validation parsed, _ := strconv.ParseInt(matches[1], 16, 0) // Set host as DWORD (base 10) encoded host u.Host = fmt.Sprintf("%d%s", parsed, matches[2]) // The rest is the same as decoding a DWORD host decodeDWORDHost(u) } } } func removeUnncessaryHostDots(u *url.URL) { if len(u.Host) > 0 { if matches := rxHostDots.FindStringSubmatch(u.Host); len(matches) > 1 { // Trim the leading and trailing dots u.Host = strings.Trim(matches[1], ".") if len(matches) > 2 { u.Host += matches[2] } } } } func removeEmptyPortSeparator(u *url.URL) { if len(u.Host) > 0 { u.Host = rxEmptyPort.ReplaceAllString(u.Host, "") } } ================================================ FILE: vendor/github.com/PuerkitoBio/urlesc/.travis.yml ================================================ language: go go: - 1.4.x - 1.5.x - 1.6.x - 1.7.x - 1.8.x - tip install: - go build . script: - go test -v ================================================ FILE: vendor/github.com/PuerkitoBio/urlesc/LICENSE ================================================ 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. ================================================ FILE: vendor/github.com/PuerkitoBio/urlesc/README.md ================================================ urlesc [![Build Status](https://travis-ci.org/PuerkitoBio/urlesc.svg?branch=master)](https://travis-ci.org/PuerkitoBio/urlesc) [![GoDoc](http://godoc.org/github.com/PuerkitoBio/urlesc?status.svg)](http://godoc.org/github.com/PuerkitoBio/urlesc) ====== Package urlesc implements query escaping as per RFC 3986. It contains some parts of the net/url package, modified so as to allow some reserved characters incorrectly escaped by net/url (see [issue 5684](https://github.com/golang/go/issues/5684)). ## Install go get github.com/PuerkitoBio/urlesc ## License Go license (BSD-3-Clause) ================================================ FILE: vendor/github.com/PuerkitoBio/urlesc/urlesc.go ================================================ // 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 urlesc implements query escaping as per RFC 3986. // It contains some parts of the net/url package, modified so as to allow // some reserved characters incorrectly escaped by net/url. // See https://github.com/golang/go/issues/5684 package urlesc import ( "bytes" "net/url" "strings" ) type encoding int const ( encodePath encoding = 1 + iota encodeUserPassword encodeQueryComponent encodeFragment ) // Return true if the specified character should be escaped when // appearing in a URL string, according to RFC 3986. func shouldEscape(c byte, mode encoding) bool { // §2.3 Unreserved characters (alphanum) if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' { return false } switch c { case '-', '.', '_', '~': // §2.3 Unreserved characters (mark) return false // §2.2 Reserved characters (reserved) case ':', '/', '?', '#', '[', ']', '@', // gen-delims '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=': // sub-delims // Different sections of the URL allow a few of // the reserved characters to appear unescaped. switch mode { case encodePath: // §3.3 // The RFC allows sub-delims and : @. // '/', '[' and ']' can be used to assign meaning to individual path // segments. This package only manipulates the path as a whole, // so we allow those as well. That leaves only ? and # to escape. return c == '?' || c == '#' case encodeUserPassword: // §3.2.1 // The RFC allows : and sub-delims in // userinfo. The parsing of userinfo treats ':' as special so we must escape // all the gen-delims. return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@' case encodeQueryComponent: // §3.4 // The RFC allows / and ?. return c != '/' && c != '?' case encodeFragment: // §4.1 // The RFC text is silent but the grammar allows // everything, so escape nothing but # return c == '#' } } // Everything else must be escaped. return true } // QueryEscape escapes the string so it can be safely placed // inside a URL query. func QueryEscape(s string) string { return escape(s, encodeQueryComponent) } func escape(s string, mode encoding) string { spaceCount, hexCount := 0, 0 for i := 0; i < len(s); i++ { c := s[i] if shouldEscape(c, mode) { if c == ' ' && mode == encodeQueryComponent { spaceCount++ } else { hexCount++ } } } if spaceCount == 0 && hexCount == 0 { return s } t := make([]byte, len(s)+2*hexCount) j := 0 for i := 0; i < len(s); i++ { switch c := s[i]; { case c == ' ' && mode == encodeQueryComponent: t[j] = '+' j++ case shouldEscape(c, mode): t[j] = '%' t[j+1] = "0123456789ABCDEF"[c>>4] t[j+2] = "0123456789ABCDEF"[c&15] j += 3 default: t[j] = s[i] j++ } } return string(t) } var uiReplacer = strings.NewReplacer( "%21", "!", "%27", "'", "%28", "(", "%29", ")", "%2A", "*", ) // unescapeUserinfo unescapes some characters that need not to be escaped as per RFC3986. func unescapeUserinfo(s string) string { return uiReplacer.Replace(s) } // Escape reassembles the URL into a valid URL string. // The general form of the result is one of: // // scheme:opaque // scheme://userinfo@host/path?query#fragment // // If u.Opaque is non-empty, String uses the first form; // otherwise it uses the second form. // // In the second form, the following rules apply: // - if u.Scheme is empty, scheme: is omitted. // - if u.User is nil, userinfo@ is omitted. // - if u.Host is empty, host/ is omitted. // - if u.Scheme and u.Host are empty and u.User is nil, // the entire scheme://userinfo@host/ is omitted. // - if u.Host is non-empty and u.Path begins with a /, // the form host/path does not add its own /. // - if u.RawQuery is empty, ?query is omitted. // - if u.Fragment is empty, #fragment is omitted. func Escape(u *url.URL) string { var buf bytes.Buffer if u.Scheme != "" { buf.WriteString(u.Scheme) buf.WriteByte(':') } if u.Opaque != "" { buf.WriteString(u.Opaque) } else { if u.Scheme != "" || u.Host != "" || u.User != nil { buf.WriteString("//") if ui := u.User; ui != nil { buf.WriteString(unescapeUserinfo(ui.String())) buf.WriteByte('@') } if h := u.Host; h != "" { buf.WriteString(h) } } if u.Path != "" && u.Path[0] != '/' && u.Host != "" { buf.WriteByte('/') } buf.WriteString(escape(u.Path, encodePath)) } if u.RawQuery != "" { buf.WriteByte('?') buf.WriteString(u.RawQuery) } if u.Fragment != "" { buf.WriteByte('#') buf.WriteString(escape(u.Fragment, encodeFragment)) } return buf.String() } ================================================ FILE: vendor/github.com/Unknwon/com/.gitignore ================================================ # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test .idea # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.iml ================================================ FILE: vendor/github.com/Unknwon/com/.travis.yml ================================================ language: go go: - 1.3.x - 1.4.x - 1.5.x - 1.6.x - 1.7.x - 1.8.x - 1.9.x - 1.10.x - 1.11.x - 1.12.x install: go get -v -t ================================================ FILE: vendor/github.com/Unknwon/com/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/github.com/Unknwon/com/README.md ================================================ Common Functions ================ [![Build Status](https://travis-ci.org/unknwon/com.svg)](https://travis-ci.org/unknwon/com) [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/unknwon/com) This is an open source project for commonly used functions for the Go programming language. This package need >= **go 1.3** Code Convention: based on [Go Code Convention](https://github.com/unknwon/go-code-convention). ## Contribute Your contribute is welcome, but you have to check following steps after you added some functions and commit them: 1. Make sure you wrote user-friendly comments for **all functions** . 2. Make sure you wrote test cases with any possible condition for **all functions** in file `*_test.go`. 3. Make sure you wrote benchmarks for **all functions** in file `*_test.go`. 4. Make sure you wrote useful examples for **all functions** in file `example_test.go`. 5. Make sure you ran `go test` and got **PASS** . ================================================ FILE: vendor/github.com/Unknwon/com/cmd.go ================================================ // +build go1.3 // Copyright 2013 com authors // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. // Package com is an open source project for commonly used functions for the Go programming language. package com import ( "bytes" "fmt" "os/exec" "runtime" "strings" ) // ExecCmdDirBytes executes system command in given directory // and return stdout, stderr in bytes type, along with possible error. func ExecCmdDirBytes(dir, cmdName string, args ...string) ([]byte, []byte, error) { bufOut := new(bytes.Buffer) bufErr := new(bytes.Buffer) cmd := exec.Command(cmdName, args...) cmd.Dir = dir cmd.Stdout = bufOut cmd.Stderr = bufErr err := cmd.Run() return bufOut.Bytes(), bufErr.Bytes(), err } // ExecCmdBytes executes system command // and return stdout, stderr in bytes type, along with possible error. func ExecCmdBytes(cmdName string, args ...string) ([]byte, []byte, error) { return ExecCmdDirBytes("", cmdName, args...) } // ExecCmdDir executes system command in given directory // and return stdout, stderr in string type, along with possible error. func ExecCmdDir(dir, cmdName string, args ...string) (string, string, error) { bufOut, bufErr, err := ExecCmdDirBytes(dir, cmdName, args...) return string(bufOut), string(bufErr), err } // ExecCmd executes system command // and return stdout, stderr in string type, along with possible error. func ExecCmd(cmdName string, args ...string) (string, string, error) { return ExecCmdDir("", cmdName, args...) } // _________ .__ .____ // \_ ___ \ ____ | | ___________ | | ____ ____ // / \ \/ / _ \| | / _ \_ __ \ | | / _ \ / ___\ // \ \___( <_> ) |_( <_> ) | \/ | |__( <_> ) /_/ > // \______ /\____/|____/\____/|__| |_______ \____/\___ / // \/ \/ /_____/ // Color number constants. const ( Gray = uint8(iota + 90) Red Green Yellow Blue Magenta //NRed = uint8(31) // Normal EndColor = "\033[0m" ) // getColorLevel returns colored level string by given level. func getColorLevel(level string) string { level = strings.ToUpper(level) switch level { case "TRAC": return fmt.Sprintf("\033[%dm%s\033[0m", Blue, level) case "ERRO": return fmt.Sprintf("\033[%dm%s\033[0m", Red, level) case "WARN": return fmt.Sprintf("\033[%dm%s\033[0m", Magenta, level) case "SUCC": return fmt.Sprintf("\033[%dm%s\033[0m", Green, level) default: return level } } // ColorLogS colors log and return colored content. // Log format: [ error ]. // Level: TRAC -> blue; ERRO -> red; WARN -> Magenta; SUCC -> green; others -> default. // Content: default; path: yellow; error -> red. // Level has to be surrounded by "[" and "]". // Highlights have to be surrounded by "# " and " #"(space), "#" will be deleted. // Paths have to be surrounded by "( " and " )"(space). // Errors have to be surrounded by "[ " and " ]"(space). // Note: it hasn't support windows yet, contribute is welcome. func ColorLogS(format string, a ...interface{}) string { log := fmt.Sprintf(format, a...) var clog string if runtime.GOOS != "windows" { // Level. i := strings.Index(log, "]") if log[0] == '[' && i > -1 { clog += "[" + getColorLevel(log[1:i]) + "]" } log = log[i+1:] // Error. log = strings.Replace(log, "[ ", fmt.Sprintf("[\033[%dm", Red), -1) log = strings.Replace(log, " ]", EndColor+"]", -1) // Path. log = strings.Replace(log, "( ", fmt.Sprintf("(\033[%dm", Yellow), -1) log = strings.Replace(log, " )", EndColor+")", -1) // Highlights. log = strings.Replace(log, "# ", fmt.Sprintf("\033[%dm", Gray), -1) log = strings.Replace(log, " #", EndColor, -1) } else { // Level. i := strings.Index(log, "]") if log[0] == '[' && i > -1 { clog += "[" + log[1:i] + "]" } log = log[i+1:] // Error. log = strings.Replace(log, "[ ", "[", -1) log = strings.Replace(log, " ]", "]", -1) // Path. log = strings.Replace(log, "( ", "(", -1) log = strings.Replace(log, " )", ")", -1) // Highlights. log = strings.Replace(log, "# ", "", -1) log = strings.Replace(log, " #", "", -1) } return clog + log } // ColorLog prints colored log to stdout. // See color rules in function 'ColorLogS'. func ColorLog(format string, a ...interface{}) { fmt.Print(ColorLogS(format, a...)) } ================================================ FILE: vendor/github.com/Unknwon/com/convert.go ================================================ // Copyright 2014 com authors // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package com import ( "fmt" "strconv" ) // Convert string to specify type. type StrTo string func (f StrTo) Exist() bool { return string(f) != string(0x1E) } func (f StrTo) Uint8() (uint8, error) { v, err := strconv.ParseUint(f.String(), 10, 8) return uint8(v), err } func (f StrTo) Int() (int, error) { v, err := strconv.ParseInt(f.String(), 10, 0) return int(v), err } func (f StrTo) Int64() (int64, error) { v, err := strconv.ParseInt(f.String(), 10, 64) return int64(v), err } func (f StrTo) Float64() (float64, error) { v, err := strconv.ParseFloat(f.String(), 64) return float64(v), err } func (f StrTo) MustUint8() uint8 { v, _ := f.Uint8() return v } func (f StrTo) MustInt() int { v, _ := f.Int() return v } func (f StrTo) MustInt64() int64 { v, _ := f.Int64() return v } func (f StrTo) MustFloat64() float64 { v, _ := f.Float64() return v } func (f StrTo) String() string { if f.Exist() { return string(f) } return "" } // Convert any type to string. func ToStr(value interface{}, args ...int) (s string) { switch v := value.(type) { case bool: s = strconv.FormatBool(v) case float32: s = strconv.FormatFloat(float64(v), 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 32)) case float64: s = strconv.FormatFloat(v, 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 64)) case int: s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10)) case int8: s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10)) case int16: s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10)) case int32: s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10)) case int64: s = strconv.FormatInt(v, argInt(args).Get(0, 10)) case uint: s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10)) case uint8: s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10)) case uint16: s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10)) case uint32: s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10)) case uint64: s = strconv.FormatUint(v, argInt(args).Get(0, 10)) case string: s = v case []byte: s = string(v) default: s = fmt.Sprintf("%v", v) } return s } type argInt []int func (a argInt) Get(i int, args ...int) (r int) { if i >= 0 && i < len(a) { r = a[i] } else if len(args) > 0 { r = args[0] } return } // HexStr2int converts hex format string to decimal number. func HexStr2int(hexStr string) (int, error) { num := 0 length := len(hexStr) for i := 0; i < length; i++ { char := hexStr[length-i-1] factor := -1 switch { case char >= '0' && char <= '9': factor = int(char) - '0' case char >= 'a' && char <= 'f': factor = int(char) - 'a' + 10 default: return -1, fmt.Errorf("invalid hex: %s", string(char)) } num += factor * PowInt(16, i) } return num, nil } // Int2HexStr converts decimal number to hex format string. func Int2HexStr(num int) (hex string) { if num == 0 { return "0" } for num > 0 { r := num % 16 c := "?" if r >= 0 && r <= 9 { c = string(r + '0') } else { c = string(r + 'a' - 10) } hex = c + hex num = num / 16 } return hex } ================================================ FILE: vendor/github.com/Unknwon/com/dir.go ================================================ // Copyright 2013 com authors // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package com import ( "errors" "fmt" "os" "path" "strings" ) // IsDir returns true if given path is a directory, // or returns false when it's a file or does not exist. func IsDir(dir string) bool { f, e := os.Stat(dir) if e != nil { return false } return f.IsDir() } func statDir(dirPath, recPath string, includeDir, isDirOnly, followSymlinks bool) ([]string, error) { dir, err := os.Open(dirPath) if err != nil { return nil, err } defer dir.Close() fis, err := dir.Readdir(0) if err != nil { return nil, err } statList := make([]string, 0) for _, fi := range fis { if strings.Contains(fi.Name(), ".DS_Store") { continue } relPath := path.Join(recPath, fi.Name()) curPath := path.Join(dirPath, fi.Name()) if fi.IsDir() { if includeDir { statList = append(statList, relPath+"/") } s, err := statDir(curPath, relPath, includeDir, isDirOnly, followSymlinks) if err != nil { return nil, err } statList = append(statList, s...) } else if !isDirOnly { statList = append(statList, relPath) } else if followSymlinks && fi.Mode()&os.ModeSymlink != 0 { link, err := os.Readlink(curPath) if err != nil { return nil, err } if IsDir(link) { if includeDir { statList = append(statList, relPath+"/") } s, err := statDir(curPath, relPath, includeDir, isDirOnly, followSymlinks) if err != nil { return nil, err } statList = append(statList, s...) } } } return statList, nil } // StatDir gathers information of given directory by depth-first. // It returns slice of file list and includes subdirectories if enabled; // it returns error and nil slice when error occurs in underlying functions, // or given path is not a directory or does not exist. // // Slice does not include given path itself. // If subdirectories is enabled, they will have suffix '/'. func StatDir(rootPath string, includeDir ...bool) ([]string, error) { if !IsDir(rootPath) { return nil, errors.New("not a directory or does not exist: " + rootPath) } isIncludeDir := false if len(includeDir) >= 1 { isIncludeDir = includeDir[0] } return statDir(rootPath, "", isIncludeDir, false, false) } // LstatDir gathers information of given directory by depth-first. // It returns slice of file list, follows symbolic links and includes subdirectories if enabled; // it returns error and nil slice when error occurs in underlying functions, // or given path is not a directory or does not exist. // // Slice does not include given path itself. // If subdirectories is enabled, they will have suffix '/'. func LstatDir(rootPath string, includeDir ...bool) ([]string, error) { if !IsDir(rootPath) { return nil, errors.New("not a directory or does not exist: " + rootPath) } isIncludeDir := false if len(includeDir) >= 1 { isIncludeDir = includeDir[0] } return statDir(rootPath, "", isIncludeDir, false, true) } // GetAllSubDirs returns all subdirectories of given root path. // Slice does not include given path itself. func GetAllSubDirs(rootPath string) ([]string, error) { if !IsDir(rootPath) { return nil, errors.New("not a directory or does not exist: " + rootPath) } return statDir(rootPath, "", true, true, false) } // LgetAllSubDirs returns all subdirectories of given root path, including // following symbolic links, if any. // Slice does not include given path itself. func LgetAllSubDirs(rootPath string) ([]string, error) { if !IsDir(rootPath) { return nil, errors.New("not a directory or does not exist: " + rootPath) } return statDir(rootPath, "", true, true, true) } // GetFileListBySuffix returns an ordered list of file paths. // It recognize if given path is a file, and don't do recursive find. func GetFileListBySuffix(dirPath, suffix string) ([]string, error) { if !IsExist(dirPath) { return nil, fmt.Errorf("given path does not exist: %s", dirPath) } else if IsFile(dirPath) { return []string{dirPath}, nil } // Given path is a directory. dir, err := os.Open(dirPath) if err != nil { return nil, err } fis, err := dir.Readdir(0) if err != nil { return nil, err } files := make([]string, 0, len(fis)) for _, fi := range fis { if strings.HasSuffix(fi.Name(), suffix) { files = append(files, path.Join(dirPath, fi.Name())) } } return files, nil } // CopyDir copy files recursively from source to target directory. // // The filter accepts a function that process the path info. // and should return true for need to filter. // // It returns error when error occurs in underlying functions. func CopyDir(srcPath, destPath string, filters ...func(filePath string) bool) error { // Check if target directory exists. if IsExist(destPath) { return errors.New("file or directory alreay exists: " + destPath) } err := os.MkdirAll(destPath, os.ModePerm) if err != nil { return err } // Gather directory info. infos, err := StatDir(srcPath, true) if err != nil { return err } var filter func(filePath string) bool if len(filters) > 0 { filter = filters[0] } for _, info := range infos { if filter != nil && filter(info) { continue } curPath := path.Join(destPath, info) if strings.HasSuffix(info, "/") { err = os.MkdirAll(curPath, os.ModePerm) } else { err = Copy(path.Join(srcPath, info), curPath) } if err != nil { return err } } return nil } ================================================ FILE: vendor/github.com/Unknwon/com/file.go ================================================ // Copyright 2013 com authors // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package com import ( "fmt" "io" "io/ioutil" "math" "os" "path" ) // Storage unit constants. const ( Byte = 1 KByte = Byte * 1024 MByte = KByte * 1024 GByte = MByte * 1024 TByte = GByte * 1024 PByte = TByte * 1024 EByte = PByte * 1024 ) func logn(n, b float64) float64 { return math.Log(n) / math.Log(b) } func humanateBytes(s uint64, base float64, sizes []string) string { if s < 10 { return fmt.Sprintf("%dB", s) } e := math.Floor(logn(float64(s), base)) suffix := sizes[int(e)] val := float64(s) / math.Pow(base, math.Floor(e)) f := "%.0f" if val < 10 { f = "%.1f" } return fmt.Sprintf(f+"%s", val, suffix) } // HumaneFileSize calculates the file size and generate user-friendly string. func HumaneFileSize(s uint64) string { sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"} return humanateBytes(s, 1024, sizes) } // FileMTime returns file modified time and possible error. func FileMTime(file string) (int64, error) { f, err := os.Stat(file) if err != nil { return 0, err } return f.ModTime().Unix(), nil } // FileSize returns file size in bytes and possible error. func FileSize(file string) (int64, error) { f, err := os.Stat(file) if err != nil { return 0, err } return f.Size(), nil } // Copy copies file from source to target path. func Copy(src, dest string) error { // Gather file information to set back later. si, err := os.Lstat(src) if err != nil { return err } // Handle symbolic link. if si.Mode()&os.ModeSymlink != 0 { target, err := os.Readlink(src) if err != nil { return err } // NOTE: os.Chmod and os.Chtimes don't recoganize symbolic link, // which will lead "no such file or directory" error. return os.Symlink(target, dest) } sr, err := os.Open(src) if err != nil { return err } defer sr.Close() dw, err := os.Create(dest) if err != nil { return err } defer dw.Close() if _, err = io.Copy(dw, sr); err != nil { return err } // Set back file information. if err = os.Chtimes(dest, si.ModTime(), si.ModTime()); err != nil { return err } return os.Chmod(dest, si.Mode()) } // WriteFile writes data to a file named by filename. // If the file does not exist, WriteFile creates it // and its upper level paths. func WriteFile(filename string, data []byte) error { os.MkdirAll(path.Dir(filename), os.ModePerm) return ioutil.WriteFile(filename, data, 0655) } // IsFile returns true if given path is a file, // or returns false when it's a directory or does not exist. func IsFile(filePath string) bool { f, e := os.Stat(filePath) if e != nil { return false } return !f.IsDir() } // IsExist checks whether a file or directory exists. // It returns false when the file or directory does not exist. func IsExist(path string) bool { _, err := os.Stat(path) return err == nil || os.IsExist(err) } ================================================ FILE: vendor/github.com/Unknwon/com/html.go ================================================ // Copyright 2013 com authors // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package com import ( "html" "regexp" "strings" ) // Html2JS converts []byte type of HTML content into JS format. func Html2JS(data []byte) []byte { s := string(data) s = strings.Replace(s, `\`, `\\`, -1) s = strings.Replace(s, "\n", `\n`, -1) s = strings.Replace(s, "\r", "", -1) s = strings.Replace(s, "\"", `\"`, -1) s = strings.Replace(s, "", "<table>", -1) return []byte(s) } // encode html chars to string func HtmlEncode(str string) string { return html.EscapeString(str) } // HtmlDecode decodes string to html chars func HtmlDecode(str string) string { return html.UnescapeString(str) } // strip tags in html string func StripTags(src string) string { //去除style,script,html tag re := regexp.MustCompile(`(?s)<(?:style|script)[^<>]*>.*?|]*>|`) src = re.ReplaceAllString(src, "") //trim all spaces(2+) into \n re = regexp.MustCompile(`\s{2,}`) src = re.ReplaceAllString(src, "\n") return strings.TrimSpace(src) } // change \n to
func Nl2br(str string) string { return strings.Replace(str, "\n", "
", -1) } ================================================ FILE: vendor/github.com/Unknwon/com/http.go ================================================ // Copyright 2013 com authors // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package com import ( "bytes" "encoding/json" "fmt" "io" "io/ioutil" "net/http" "os" "path" ) type NotFoundError struct { Message string } func (e NotFoundError) Error() string { return e.Message } type RemoteError struct { Host string Err error } func (e *RemoteError) Error() string { return e.Err.Error() } var UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1541.0 Safari/537.36" // HttpCall makes HTTP method call. func HttpCall(client *http.Client, method, url string, header http.Header, body io.Reader) (io.ReadCloser, error) { req, err := http.NewRequest(method, url, body) if err != nil { return nil, err } req.Header.Set("User-Agent", UserAgent) for k, vs := range header { req.Header[k] = vs } resp, err := client.Do(req) if err != nil { return nil, err } if resp.StatusCode == 200 { return resp.Body, nil } resp.Body.Close() if resp.StatusCode == 404 { // 403 can be rate limit error. || resp.StatusCode == 403 { err = fmt.Errorf("resource not found: %s", url) } else { err = fmt.Errorf("%s %s -> %d", method, url, resp.StatusCode) } return nil, err } // HttpGet gets the specified resource. // ErrNotFound is returned if the server responds with status 404. func HttpGet(client *http.Client, url string, header http.Header) (io.ReadCloser, error) { return HttpCall(client, "GET", url, header, nil) } // HttpPost posts the specified resource. // ErrNotFound is returned if the server responds with status 404. func HttpPost(client *http.Client, url string, header http.Header, body []byte) (io.ReadCloser, error) { return HttpCall(client, "POST", url, header, bytes.NewBuffer(body)) } // HttpGetToFile gets the specified resource and writes to file. // ErrNotFound is returned if the server responds with status 404. func HttpGetToFile(client *http.Client, url string, header http.Header, fileName string) error { rc, err := HttpGet(client, url, header) if err != nil { return err } defer rc.Close() os.MkdirAll(path.Dir(fileName), os.ModePerm) f, err := os.Create(fileName) if err != nil { return err } defer f.Close() _, err = io.Copy(f, rc) return err } // HttpGetBytes gets the specified resource. ErrNotFound is returned if the server // responds with status 404. func HttpGetBytes(client *http.Client, url string, header http.Header) ([]byte, error) { rc, err := HttpGet(client, url, header) if err != nil { return nil, err } defer rc.Close() return ioutil.ReadAll(rc) } // HttpGetJSON gets the specified resource and mapping to struct. // ErrNotFound is returned if the server responds with status 404. func HttpGetJSON(client *http.Client, url string, v interface{}) error { rc, err := HttpGet(client, url, nil) if err != nil { return err } defer rc.Close() err = json.NewDecoder(rc).Decode(v) if _, ok := err.(*json.SyntaxError); ok { return fmt.Errorf("JSON syntax error at %s", url) } return nil } // HttpPostJSON posts the specified resource with struct values, // and maps results to struct. // ErrNotFound is returned if the server responds with status 404. func HttpPostJSON(client *http.Client, url string, body, v interface{}) error { data, err := json.Marshal(body) if err != nil { return err } rc, err := HttpPost(client, url, http.Header{"content-type": []string{"application/json"}}, data) if err != nil { return err } defer rc.Close() err = json.NewDecoder(rc).Decode(v) if _, ok := err.(*json.SyntaxError); ok { return fmt.Errorf("JSON syntax error at %s", url) } return nil } // A RawFile describes a file that can be downloaded. type RawFile interface { Name() string RawUrl() string Data() []byte SetData([]byte) } // FetchFiles fetches files specified by the rawURL field in parallel. func FetchFiles(client *http.Client, files []RawFile, header http.Header) error { ch := make(chan error, len(files)) for i := range files { go func(i int) { p, err := HttpGetBytes(client, files[i].RawUrl(), nil) if err != nil { ch <- err return } files[i].SetData(p) ch <- nil }(i) } for _ = range files { if err := <-ch; err != nil { return err } } return nil } // FetchFilesCurl uses command `curl` to fetch files specified by the rawURL field in parallel. func FetchFilesCurl(files []RawFile, curlOptions ...string) error { ch := make(chan error, len(files)) for i := range files { go func(i int) { stdout, _, err := ExecCmd("curl", append(curlOptions, files[i].RawUrl())...) if err != nil { ch <- err return } files[i].SetData([]byte(stdout)) ch <- nil }(i) } for _ = range files { if err := <-ch; err != nil { return err } } return nil } ================================================ FILE: vendor/github.com/Unknwon/com/math.go ================================================ // Copyright 2014 com authors // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package com // PowInt is int type of math.Pow function. func PowInt(x int, y int) int { if y <= 0 { return 1 } else { if y%2 == 0 { sqrt := PowInt(x, y/2) return sqrt * sqrt } else { return PowInt(x, y-1) * x } } } ================================================ FILE: vendor/github.com/Unknwon/com/path.go ================================================ // Copyright 2013 com authors // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package com import ( "errors" "os" "path/filepath" "runtime" "strings" ) // GetGOPATHs returns all paths in GOPATH variable. func GetGOPATHs() []string { gopath := os.Getenv("GOPATH") var paths []string if runtime.GOOS == "windows" { gopath = strings.Replace(gopath, "\\", "/", -1) paths = strings.Split(gopath, ";") } else { paths = strings.Split(gopath, ":") } return paths } // GetSrcPath returns app. source code path. // It only works when you have src. folder in GOPATH, // it returns error not able to locate source folder path. func GetSrcPath(importPath string) (appPath string, err error) { paths := GetGOPATHs() for _, p := range paths { if IsExist(p + "/src/" + importPath + "/") { appPath = p + "/src/" + importPath + "/" break } } if len(appPath) == 0 { return "", errors.New("Unable to locate source folder path") } appPath = filepath.Dir(appPath) + "/" if runtime.GOOS == "windows" { // Replace all '\' to '/'. appPath = strings.Replace(appPath, "\\", "/", -1) } return appPath, nil } // HomeDir returns path of '~'(in Linux) on Windows, // it returns error when the variable does not exist. func HomeDir() (home string, err error) { if runtime.GOOS == "windows" { home = os.Getenv("USERPROFILE") if len(home) == 0 { home = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") } } else { home = os.Getenv("HOME") } if len(home) == 0 { return "", errors.New("Cannot specify home directory because it's empty") } return home, nil } ================================================ FILE: vendor/github.com/Unknwon/com/regex.go ================================================ // Copyright 2013 com authors // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package com import "regexp" const ( regex_email_pattern = `(?i)[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}` regex_strict_email_pattern = `(?i)[A-Z0-9!#$%&'*+/=?^_{|}~-]+` + `(?:\.[A-Z0-9!#$%&'*+/=?^_{|}~-]+)*` + `@(?:[A-Z0-9](?:[A-Z0-9-]*[A-Z0-9])?\.)+` + `[A-Z0-9](?:[A-Z0-9-]*[A-Z0-9])?` regex_url_pattern = `(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?` ) var ( regex_email *regexp.Regexp regex_strict_email *regexp.Regexp regex_url *regexp.Regexp ) func init() { regex_email = regexp.MustCompile(regex_email_pattern) regex_strict_email = regexp.MustCompile(regex_strict_email_pattern) regex_url = regexp.MustCompile(regex_url_pattern) } // IsEmail validates string is an email address, if not return false // basically validation can match 99% cases func IsEmail(email string) bool { return regex_email.MatchString(email) } // IsEmailRFC validates string is an email address, if not return false // this validation omits RFC 2822 func IsEmailRFC(email string) bool { return regex_strict_email.MatchString(email) } // IsUrl validates string is a url link, if not return false // simple validation can match 99% cases func IsUrl(url string) bool { return regex_url.MatchString(url) } ================================================ FILE: vendor/github.com/Unknwon/com/slice.go ================================================ // Copyright 2013 com authors // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package com import ( "strings" ) // AppendStr appends string to slice with no duplicates. func AppendStr(strs []string, str string) []string { for _, s := range strs { if s == str { return strs } } return append(strs, str) } // CompareSliceStr compares two 'string' type slices. // It returns true if elements and order are both the same. func CompareSliceStr(s1, s2 []string) bool { if len(s1) != len(s2) { return false } for i := range s1 { if s1[i] != s2[i] { return false } } return true } // CompareSliceStrU compares two 'string' type slices. // It returns true if elements are the same, and ignores the order. func CompareSliceStrU(s1, s2 []string) bool { if len(s1) != len(s2) { return false } for i := range s1 { for j := len(s2) - 1; j >= 0; j-- { if s1[i] == s2[j] { s2 = append(s2[:j], s2[j+1:]...) break } } } if len(s2) > 0 { return false } return true } // IsSliceContainsStr returns true if the string exists in given slice, ignore case. func IsSliceContainsStr(sl []string, str string) bool { str = strings.ToLower(str) for _, s := range sl { if strings.ToLower(s) == str { return true } } return false } // IsSliceContainsInt64 returns true if the int64 exists in given slice. func IsSliceContainsInt64(sl []int64, i int64) bool { for _, s := range sl { if s == i { return true } } return false } ================================================ FILE: vendor/github.com/Unknwon/com/string.go ================================================ // Copyright 2013 com authors // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package com import ( "bytes" "crypto/aes" "crypto/cipher" "crypto/rand" "errors" r "math/rand" "strconv" "strings" "time" "unicode" "unicode/utf8" ) // AESGCMEncrypt encrypts plaintext with the given key using AES in GCM mode. func AESGCMEncrypt(key, plaintext []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonce := make([]byte, gcm.NonceSize()) if _, err := rand.Read(nonce); err != nil { return nil, err } ciphertext := gcm.Seal(nil, nonce, plaintext, nil) return append(nonce, ciphertext...), nil } // AESGCMDecrypt decrypts ciphertext with the given key using AES in GCM mode. func AESGCMDecrypt(key, ciphertext []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } size := gcm.NonceSize() if len(ciphertext)-size <= 0 { return nil, errors.New("Ciphertext is empty") } nonce := ciphertext[:size] ciphertext = ciphertext[size:] plainText, err := gcm.Open(nil, nonce, ciphertext, nil) if err != nil { return nil, err } return plainText, nil } // IsLetter returns true if the 'l' is an English letter. func IsLetter(l uint8) bool { n := (l | 0x20) - 'a' if n >= 0 && n < 26 { return true } return false } // Expand replaces {k} in template with match[k] or subs[atoi(k)] if k is not in match. func Expand(template string, match map[string]string, subs ...string) string { var p []byte var i int for { i = strings.Index(template, "{") if i < 0 { break } p = append(p, template[:i]...) template = template[i+1:] i = strings.Index(template, "}") if s, ok := match[template[:i]]; ok { p = append(p, s...) } else { j, _ := strconv.Atoi(template[:i]) if j >= len(subs) { p = append(p, []byte("Missing")...) } else { p = append(p, subs[j]...) } } template = template[i+1:] } p = append(p, template...) return string(p) } // Reverse s string, support unicode func Reverse(s string) string { n := len(s) runes := make([]rune, n) for _, rune := range s { n-- runes[n] = rune } return string(runes[n:]) } // RandomCreateBytes generate random []byte by specify chars. func RandomCreateBytes(n int, alphabets ...byte) []byte { const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" var bytes = make([]byte, n) var randby bool if num, err := rand.Read(bytes); num != n || err != nil { r.Seed(time.Now().UnixNano()) randby = true } for i, b := range bytes { if len(alphabets) == 0 { if randby { bytes[i] = alphanum[r.Intn(len(alphanum))] } else { bytes[i] = alphanum[b%byte(len(alphanum))] } } else { if randby { bytes[i] = alphabets[r.Intn(len(alphabets))] } else { bytes[i] = alphabets[b%byte(len(alphabets))] } } } return bytes } // ToSnakeCase can convert all upper case characters in a string to // underscore format. // // Some samples. // "FirstName" => "first_name" // "HTTPServer" => "http_server" // "NoHTTPS" => "no_https" // "GO_PATH" => "go_path" // "GO PATH" => "go_path" // space is converted to underscore. // "GO-PATH" => "go_path" // hyphen is converted to underscore. // // From https://github.com/huandu/xstrings func ToSnakeCase(str string) string { if len(str) == 0 { return "" } buf := &bytes.Buffer{} var prev, r0, r1 rune var size int r0 = '_' for len(str) > 0 { prev = r0 r0, size = utf8.DecodeRuneInString(str) str = str[size:] switch { case r0 == utf8.RuneError: buf.WriteByte(byte(str[0])) case unicode.IsUpper(r0): if prev != '_' { buf.WriteRune('_') } buf.WriteRune(unicode.ToLower(r0)) if len(str) == 0 { break } r0, size = utf8.DecodeRuneInString(str) str = str[size:] if !unicode.IsUpper(r0) { buf.WriteRune(r0) break } // find next non-upper-case character and insert `_` properly. // it's designed to convert `HTTPServer` to `http_server`. // if there are more than 2 adjacent upper case characters in a word, // treat them as an abbreviation plus a normal word. for len(str) > 0 { r1 = r0 r0, size = utf8.DecodeRuneInString(str) str = str[size:] if r0 == utf8.RuneError { buf.WriteRune(unicode.ToLower(r1)) buf.WriteByte(byte(str[0])) break } if !unicode.IsUpper(r0) { if r0 == '_' || r0 == ' ' || r0 == '-' { r0 = '_' buf.WriteRune(unicode.ToLower(r1)) } else { buf.WriteRune('_') buf.WriteRune(unicode.ToLower(r1)) buf.WriteRune(r0) } break } buf.WriteRune(unicode.ToLower(r1)) } if len(str) == 0 || r0 == '_' { buf.WriteRune(unicode.ToLower(r0)) break } default: if r0 == ' ' || r0 == '-' { r0 = '_' } buf.WriteRune(r0) } } return buf.String() } ================================================ FILE: vendor/github.com/Unknwon/com/time.go ================================================ // Copyright 2013 com authors // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package com import ( "fmt" "strconv" "strings" "time" ) // Format unix time int64 to string func Date(ti int64, format string) string { t := time.Unix(int64(ti), 0) return DateT(t, format) } // Format unix time string to string func DateS(ts string, format string) string { i, _ := strconv.ParseInt(ts, 10, 64) return Date(i, format) } // Format time.Time struct to string // MM - month - 01 // M - month - 1, single bit // DD - day - 02 // D - day 2 // YYYY - year - 2006 // YY - year - 06 // HH - 24 hours - 03 // H - 24 hours - 3 // hh - 12 hours - 03 // h - 12 hours - 3 // mm - minute - 04 // m - minute - 4 // ss - second - 05 // s - second = 5 func DateT(t time.Time, format string) string { res := strings.Replace(format, "MM", t.Format("01"), -1) res = strings.Replace(res, "M", t.Format("1"), -1) res = strings.Replace(res, "DD", t.Format("02"), -1) res = strings.Replace(res, "D", t.Format("2"), -1) res = strings.Replace(res, "YYYY", t.Format("2006"), -1) res = strings.Replace(res, "YY", t.Format("06"), -1) res = strings.Replace(res, "HH", fmt.Sprintf("%02d", t.Hour()), -1) res = strings.Replace(res, "H", fmt.Sprintf("%d", t.Hour()), -1) res = strings.Replace(res, "hh", t.Format("03"), -1) res = strings.Replace(res, "h", t.Format("3"), -1) res = strings.Replace(res, "mm", t.Format("04"), -1) res = strings.Replace(res, "m", t.Format("4"), -1) res = strings.Replace(res, "ss", t.Format("05"), -1) res = strings.Replace(res, "s", t.Format("5"), -1) return res } // DateFormat pattern rules. var datePatterns = []string{ // year "Y", "2006", // A full numeric representation of a year, 4 digits Examples: 1999 or 2003 "y", "06", //A two digit representation of a year Examples: 99 or 03 // month "m", "01", // Numeric representation of a month, with leading zeros 01 through 12 "n", "1", // Numeric representation of a month, without leading zeros 1 through 12 "M", "Jan", // A short textual representation of a month, three letters Jan through Dec "F", "January", // A full textual representation of a month, such as January or March January through December // day "d", "02", // Day of the month, 2 digits with leading zeros 01 to 31 "j", "2", // Day of the month without leading zeros 1 to 31 // week "D", "Mon", // A textual representation of a day, three letters Mon through Sun "l", "Monday", // A full textual representation of the day of the week Sunday through Saturday // time "g", "3", // 12-hour format of an hour without leading zeros 1 through 12 "G", "15", // 24-hour format of an hour without leading zeros 0 through 23 "h", "03", // 12-hour format of an hour with leading zeros 01 through 12 "H", "15", // 24-hour format of an hour with leading zeros 00 through 23 "a", "pm", // Lowercase Ante meridiem and Post meridiem am or pm "A", "PM", // Uppercase Ante meridiem and Post meridiem AM or PM "i", "04", // Minutes with leading zeros 00 to 59 "s", "05", // Seconds, with leading zeros 00 through 59 // time zone "T", "MST", "P", "-07:00", "O", "-0700", // RFC 2822 "r", time.RFC1123Z, } // Parse Date use PHP time format. func DateParse(dateString, format string) (time.Time, error) { replacer := strings.NewReplacer(datePatterns...) format = replacer.Replace(format) return time.ParseInLocation(format, dateString, time.Local) } ================================================ FILE: vendor/github.com/Unknwon/com/url.go ================================================ // Copyright 2013 com authors // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package com import ( "encoding/base64" "net/url" ) // url encode string, is + not %20 func UrlEncode(str string) string { return url.QueryEscape(str) } // url decode string func UrlDecode(str string) (string, error) { return url.QueryUnescape(str) } // base64 encode func Base64Encode(str string) string { return base64.StdEncoding.EncodeToString([]byte(str)) } // base64 decode func Base64Decode(str string) (string, error) { s, e := base64.StdEncoding.DecodeString(str) return string(s), e } ================================================ FILE: vendor/github.com/alecthomas/template/LICENSE ================================================ 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. ================================================ FILE: vendor/github.com/alecthomas/template/README.md ================================================ # Go's `text/template` package with newline elision This is a fork of Go 1.4's [text/template](http://golang.org/pkg/text/template/) package with one addition: a backslash immediately after a closing delimiter will delete all subsequent newlines until a non-newline. eg. ``` {{if true}}\ hello {{end}}\ ``` Will result in: ``` hello\n ``` Rather than: ``` \n hello\n \n ``` ================================================ FILE: vendor/github.com/alecthomas/template/doc.go ================================================ // 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 template implements data-driven templates for generating textual output. To generate HTML output, see package html/template, which has the same interface as this package but automatically secures HTML output against certain attacks. Templates are executed by applying them to a data structure. Annotations in the template refer to elements of the data structure (typically a field of a struct or a key in a map) to control execution and derive values to be displayed. Execution of the template walks the structure and sets the cursor, represented by a period '.' and called "dot", to the value at the current location in the structure as execution proceeds. The input text for a template is UTF-8-encoded text in any format. "Actions"--data evaluations or control structures--are delimited by "{{" and "}}"; all text outside actions is copied to the output unchanged. Actions may not span newlines, although comments can. Once parsed, a template may be executed safely in parallel. Here is a trivial example that prints "17 items are made of wool". type Inventory struct { Material string Count uint } sweaters := Inventory{"wool", 17} tmpl, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}") if err != nil { panic(err) } err = tmpl.Execute(os.Stdout, sweaters) if err != nil { panic(err) } More intricate examples appear below. Actions Here is the list of actions. "Arguments" and "pipelines" are evaluations of data, defined in detail below. */ // {{/* a comment */}} // A comment; discarded. May contain newlines. // Comments do not nest and must start and end at the // delimiters, as shown here. /* {{pipeline}} The default textual representation of the value of the pipeline is copied to the output. {{if pipeline}} T1 {{end}} If the value of the pipeline is empty, no output is generated; otherwise, T1 is executed. The empty values are false, 0, any nil pointer or interface value, and any array, slice, map, or string of length zero. Dot is unaffected. {{if pipeline}} T1 {{else}} T0 {{end}} If the value of the pipeline is empty, T0 is executed; otherwise, T1 is executed. Dot is unaffected. {{if pipeline}} T1 {{else if pipeline}} T0 {{end}} To simplify the appearance of if-else chains, the else action of an if may include another if directly; the effect is exactly the same as writing {{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}} {{range pipeline}} T1 {{end}} The value of the pipeline must be an array, slice, map, or channel. If the value of the pipeline has length zero, nothing is output; otherwise, dot is set to the successive elements of the array, slice, or map and T1 is executed. If the value is a map and the keys are of basic type with a defined order ("comparable"), the elements will be visited in sorted key order. {{range pipeline}} T1 {{else}} T0 {{end}} The value of the pipeline must be an array, slice, map, or channel. If the value of the pipeline has length zero, dot is unaffected and T0 is executed; otherwise, dot is set to the successive elements of the array, slice, or map and T1 is executed. {{template "name"}} The template with the specified name is executed with nil data. {{template "name" pipeline}} The template with the specified name is executed with dot set to the value of the pipeline. {{with pipeline}} T1 {{end}} If the value of the pipeline is empty, no output is generated; otherwise, dot is set to the value of the pipeline and T1 is executed. {{with pipeline}} T1 {{else}} T0 {{end}} If the value of the pipeline is empty, dot is unaffected and T0 is executed; otherwise, dot is set to the value of the pipeline and T1 is executed. Arguments An argument is a simple value, denoted by one of the following. - A boolean, string, character, integer, floating-point, imaginary or complex constant in Go syntax. These behave like Go's untyped constants, although raw strings may not span newlines. - The keyword nil, representing an untyped Go nil. - The character '.' (period): . The result is the value of dot. - A variable name, which is a (possibly empty) alphanumeric string preceded by a dollar sign, such as $piOver2 or $ The result is the value of the variable. Variables are described below. - The name of a field of the data, which must be a struct, preceded by a period, such as .Field The result is the value of the field. Field invocations may be chained: .Field1.Field2 Fields can also be evaluated on variables, including chaining: $x.Field1.Field2 - The name of a key of the data, which must be a map, preceded by a period, such as .Key The result is the map element value indexed by the key. Key invocations may be chained and combined with fields to any depth: .Field1.Key1.Field2.Key2 Although the key must be an alphanumeric identifier, unlike with field names they do not need to start with an upper case letter. Keys can also be evaluated on variables, including chaining: $x.key1.key2 - The name of a niladic method of the data, preceded by a period, such as .Method The result is the value of invoking the method with dot as the receiver, dot.Method(). Such a method must have one return value (of any type) or two return values, the second of which is an error. If it has two and the returned error is non-nil, execution terminates and an error is returned to the caller as the value of Execute. Method invocations may be chained and combined with fields and keys to any depth: .Field1.Key1.Method1.Field2.Key2.Method2 Methods can also be evaluated on variables, including chaining: $x.Method1.Field - The name of a niladic function, such as fun The result is the value of invoking the function, fun(). The return types and values behave as in methods. Functions and function names are described below. - A parenthesized instance of one the above, for grouping. The result may be accessed by a field or map key invocation. print (.F1 arg1) (.F2 arg2) (.StructValuedMethod "arg").Field Arguments may evaluate to any type; if they are pointers the implementation automatically indirects to the base type when required. If an evaluation yields a function value, such as a function-valued field of a struct, the function is not invoked automatically, but it can be used as a truth value for an if action and the like. To invoke it, use the call function, defined below. A pipeline is a possibly chained sequence of "commands". A command is a simple value (argument) or a function or method call, possibly with multiple arguments: Argument The result is the value of evaluating the argument. .Method [Argument...] The method can be alone or the last element of a chain but, unlike methods in the middle of a chain, it can take arguments. The result is the value of calling the method with the arguments: dot.Method(Argument1, etc.) functionName [Argument...] The result is the value of calling the function associated with the name: function(Argument1, etc.) Functions and function names are described below. Pipelines A pipeline may be "chained" by separating a sequence of commands with pipeline characters '|'. In a chained pipeline, the result of the each command is passed as the last argument of the following command. The output of the final command in the pipeline is the value of the pipeline. The output of a command will be either one value or two values, the second of which has type error. If that second value is present and evaluates to non-nil, execution terminates and the error is returned to the caller of Execute. Variables A pipeline inside an action may initialize a variable to capture the result. The initialization has syntax $variable := pipeline where $variable is the name of the variable. An action that declares a variable produces no output. If a "range" action initializes a variable, the variable is set to the successive elements of the iteration. Also, a "range" may declare two variables, separated by a comma: range $index, $element := pipeline in which case $index and $element are set to the successive values of the array/slice index or map key and element, respectively. Note that if there is only one variable, it is assigned the element; this is opposite to the convention in Go range clauses. A variable's scope extends to the "end" action of the control structure ("if", "with", or "range") in which it is declared, or to the end of the template if there is no such control structure. A template invocation does not inherit variables from the point of its invocation. When execution begins, $ is set to the data argument passed to Execute, that is, to the starting value of dot. Examples Here are some example one-line templates demonstrating pipelines and variables. All produce the quoted word "output": {{"\"output\""}} A string constant. {{`"output"`}} A raw string constant. {{printf "%q" "output"}} A function call. {{"output" | printf "%q"}} A function call whose final argument comes from the previous command. {{printf "%q" (print "out" "put")}} A parenthesized argument. {{"put" | printf "%s%s" "out" | printf "%q"}} A more elaborate call. {{"output" | printf "%s" | printf "%q"}} A longer chain. {{with "output"}}{{printf "%q" .}}{{end}} A with action using dot. {{with $x := "output" | printf "%q"}}{{$x}}{{end}} A with action that creates and uses a variable. {{with $x := "output"}}{{printf "%q" $x}}{{end}} A with action that uses the variable in another action. {{with $x := "output"}}{{$x | printf "%q"}}{{end}} The same, but pipelined. Functions During execution functions are found in two function maps: first in the template, then in the global function map. By default, no functions are defined in the template but the Funcs method can be used to add them. Predefined global functions are named as follows. and Returns the boolean AND of its arguments by returning the first empty argument or the last argument, that is, "and x y" behaves as "if x then y else x". All the arguments are evaluated. call Returns the result of calling the first argument, which must be a function, with the remaining arguments as parameters. Thus "call .X.Y 1 2" is, in Go notation, dot.X.Y(1, 2) where Y is a func-valued field, map entry, or the like. The first argument must be the result of an evaluation that yields a value of function type (as distinct from a predefined function such as print). The function must return either one or two result values, the second of which is of type error. If the arguments don't match the function or the returned error value is non-nil, execution stops. html Returns the escaped HTML equivalent of the textual representation of its arguments. index Returns the result of indexing its first argument by the following arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each indexed item must be a map, slice, or array. js Returns the escaped JavaScript equivalent of the textual representation of its arguments. len Returns the integer length of its argument. not Returns the boolean negation of its single argument. or Returns the boolean OR of its arguments by returning the first non-empty argument or the last argument, that is, "or x y" behaves as "if x then x else y". All the arguments are evaluated. print An alias for fmt.Sprint printf An alias for fmt.Sprintf println An alias for fmt.Sprintln urlquery Returns the escaped value of the textual representation of its arguments in a form suitable for embedding in a URL query. The boolean functions take any zero value to be false and a non-zero value to be true. There is also a set of binary comparison operators defined as functions: eq Returns the boolean truth of arg1 == arg2 ne Returns the boolean truth of arg1 != arg2 lt Returns the boolean truth of arg1 < arg2 le Returns the boolean truth of arg1 <= arg2 gt Returns the boolean truth of arg1 > arg2 ge Returns the boolean truth of arg1 >= arg2 For simpler multi-way equality tests, eq (only) accepts two or more arguments and compares the second and subsequent to the first, returning in effect arg1==arg2 || arg1==arg3 || arg1==arg4 ... (Unlike with || in Go, however, eq is a function call and all the arguments will be evaluated.) The comparison functions work on basic types only (or named basic types, such as "type Celsius float32"). They implement the Go rules for comparison of values, except that size and exact type are ignored, so any integer value, signed or unsigned, may be compared with any other integer value. (The arithmetic value is compared, not the bit pattern, so all negative integers are less than all unsigned integers.) However, as usual, one may not compare an int with a float32 and so on. Associated templates Each template is named by a string specified when it is created. Also, each template is associated with zero or more other templates that it may invoke by name; such associations are transitive and form a name space of templates. A template may use a template invocation to instantiate another associated template; see the explanation of the "template" action above. The name must be that of a template associated with the template that contains the invocation. Nested template definitions When parsing a template, another template may be defined and associated with the template being parsed. Template definitions must appear at the top level of the template, much like global variables in a Go program. The syntax of such definitions is to surround each template declaration with a "define" and "end" action. The define action names the template being created by providing a string constant. Here is a simple example: `{{define "T1"}}ONE{{end}} {{define "T2"}}TWO{{end}} {{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}} {{template "T3"}}` This defines two templates, T1 and T2, and a third T3 that invokes the other two when it is executed. Finally it invokes T3. If executed this template will produce the text ONE TWO By construction, a template may reside in only one association. If it's necessary to have a template addressable from multiple associations, the template definition must be parsed multiple times to create distinct *Template values, or must be copied with the Clone or AddParseTree method. Parse may be called multiple times to assemble the various associated templates; see the ParseFiles and ParseGlob functions and methods for simple ways to parse related templates stored in files. A template may be executed directly or through ExecuteTemplate, which executes an associated template identified by name. To invoke our example above, we might write, err := tmpl.Execute(os.Stdout, "no data needed") if err != nil { log.Fatalf("execution failed: %s", err) } or to invoke a particular template explicitly by name, err := tmpl.ExecuteTemplate(os.Stdout, "T2", "no data needed") if err != nil { log.Fatalf("execution failed: %s", err) } */ package template ================================================ FILE: vendor/github.com/alecthomas/template/exec.go ================================================ // 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 template import ( "bytes" "fmt" "io" "reflect" "runtime" "sort" "strings" "github.com/alecthomas/template/parse" ) // state represents the state of an execution. It's not part of the // template so that multiple executions of the same template // can execute in parallel. type state struct { tmpl *Template wr io.Writer node parse.Node // current node, for errors vars []variable // push-down stack of variable values. } // variable holds the dynamic value of a variable such as $, $x etc. type variable struct { name string value reflect.Value } // push pushes a new variable on the stack. func (s *state) push(name string, value reflect.Value) { s.vars = append(s.vars, variable{name, value}) } // mark returns the length of the variable stack. func (s *state) mark() int { return len(s.vars) } // pop pops the variable stack up to the mark. func (s *state) pop(mark int) { s.vars = s.vars[0:mark] } // setVar overwrites the top-nth variable on the stack. Used by range iterations. func (s *state) setVar(n int, value reflect.Value) { s.vars[len(s.vars)-n].value = value } // varValue returns the value of the named variable. func (s *state) varValue(name string) reflect.Value { for i := s.mark() - 1; i >= 0; i-- { if s.vars[i].name == name { return s.vars[i].value } } s.errorf("undefined variable: %s", name) return zero } var zero reflect.Value // at marks the state to be on node n, for error reporting. func (s *state) at(node parse.Node) { s.node = node } // doublePercent returns the string with %'s replaced by %%, if necessary, // so it can be used safely inside a Printf format string. func doublePercent(str string) string { if strings.Contains(str, "%") { str = strings.Replace(str, "%", "%%", -1) } return str } // errorf formats the error and terminates processing. func (s *state) errorf(format string, args ...interface{}) { name := doublePercent(s.tmpl.Name()) if s.node == nil { format = fmt.Sprintf("template: %s: %s", name, format) } else { location, context := s.tmpl.ErrorContext(s.node) format = fmt.Sprintf("template: %s: executing %q at <%s>: %s", location, name, doublePercent(context), format) } panic(fmt.Errorf(format, args...)) } // errRecover is the handler that turns panics into returns from the top // level of Parse. func errRecover(errp *error) { e := recover() if e != nil { switch err := e.(type) { case runtime.Error: panic(e) case error: *errp = err default: panic(e) } } } // ExecuteTemplate applies the template associated with t that has the given name // to the specified data object and writes the output to wr. // If an error occurs executing the template or writing its output, // execution stops, but partial results may already have been written to // the output writer. // A template may be executed safely in parallel. func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error { tmpl := t.tmpl[name] if tmpl == nil { return fmt.Errorf("template: no template %q associated with template %q", name, t.name) } return tmpl.Execute(wr, data) } // Execute applies a parsed template to the specified data object, // and writes the output to wr. // If an error occurs executing the template or writing its output, // execution stops, but partial results may already have been written to // the output writer. // A template may be executed safely in parallel. func (t *Template) Execute(wr io.Writer, data interface{}) (err error) { defer errRecover(&err) value := reflect.ValueOf(data) state := &state{ tmpl: t, wr: wr, vars: []variable{{"$", value}}, } t.init() if t.Tree == nil || t.Root == nil { var b bytes.Buffer for name, tmpl := range t.tmpl { if tmpl.Tree == nil || tmpl.Root == nil { continue } if b.Len() > 0 { b.WriteString(", ") } fmt.Fprintf(&b, "%q", name) } var s string if b.Len() > 0 { s = "; defined templates are: " + b.String() } state.errorf("%q is an incomplete or empty template%s", t.Name(), s) } state.walk(value, t.Root) return } // Walk functions step through the major pieces of the template structure, // generating output as they go. func (s *state) walk(dot reflect.Value, node parse.Node) { s.at(node) switch node := node.(type) { case *parse.ActionNode: // Do not pop variables so they persist until next end. // Also, if the action declares variables, don't print the result. val := s.evalPipeline(dot, node.Pipe) if len(node.Pipe.Decl) == 0 { s.printValue(node, val) } case *parse.IfNode: s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList) case *parse.ListNode: for _, node := range node.Nodes { s.walk(dot, node) } case *parse.RangeNode: s.walkRange(dot, node) case *parse.TemplateNode: s.walkTemplate(dot, node) case *parse.TextNode: if _, err := s.wr.Write(node.Text); err != nil { s.errorf("%s", err) } case *parse.WithNode: s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList) default: s.errorf("unknown node: %s", node) } } // walkIfOrWith walks an 'if' or 'with' node. The two control structures // are identical in behavior except that 'with' sets dot. func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) { defer s.pop(s.mark()) val := s.evalPipeline(dot, pipe) truth, ok := isTrue(val) if !ok { s.errorf("if/with can't use %v", val) } if truth { if typ == parse.NodeWith { s.walk(val, list) } else { s.walk(dot, list) } } else if elseList != nil { s.walk(dot, elseList) } } // isTrue reports whether the value is 'true', in the sense of not the zero of its type, // and whether the value has a meaningful truth value. func isTrue(val reflect.Value) (truth, ok bool) { if !val.IsValid() { // Something like var x interface{}, never set. It's a form of nil. return false, true } switch val.Kind() { case reflect.Array, reflect.Map, reflect.Slice, reflect.String: truth = val.Len() > 0 case reflect.Bool: truth = val.Bool() case reflect.Complex64, reflect.Complex128: truth = val.Complex() != 0 case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface: truth = !val.IsNil() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: truth = val.Int() != 0 case reflect.Float32, reflect.Float64: truth = val.Float() != 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: truth = val.Uint() != 0 case reflect.Struct: truth = true // Struct values are always true. default: return } return truth, true } func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) { s.at(r) defer s.pop(s.mark()) val, _ := indirect(s.evalPipeline(dot, r.Pipe)) // mark top of stack before any variables in the body are pushed. mark := s.mark() oneIteration := func(index, elem reflect.Value) { // Set top var (lexically the second if there are two) to the element. if len(r.Pipe.Decl) > 0 { s.setVar(1, elem) } // Set next var (lexically the first if there are two) to the index. if len(r.Pipe.Decl) > 1 { s.setVar(2, index) } s.walk(elem, r.List) s.pop(mark) } switch val.Kind() { case reflect.Array, reflect.Slice: if val.Len() == 0 { break } for i := 0; i < val.Len(); i++ { oneIteration(reflect.ValueOf(i), val.Index(i)) } return case reflect.Map: if val.Len() == 0 { break } for _, key := range sortKeys(val.MapKeys()) { oneIteration(key, val.MapIndex(key)) } return case reflect.Chan: if val.IsNil() { break } i := 0 for ; ; i++ { elem, ok := val.Recv() if !ok { break } oneIteration(reflect.ValueOf(i), elem) } if i == 0 { break } return case reflect.Invalid: break // An invalid value is likely a nil map, etc. and acts like an empty map. default: s.errorf("range can't iterate over %v", val) } if r.ElseList != nil { s.walk(dot, r.ElseList) } } func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) { s.at(t) tmpl := s.tmpl.tmpl[t.Name] if tmpl == nil { s.errorf("template %q not defined", t.Name) } // Variables declared by the pipeline persist. dot = s.evalPipeline(dot, t.Pipe) newState := *s newState.tmpl = tmpl // No dynamic scoping: template invocations inherit no variables. newState.vars = []variable{{"$", dot}} newState.walk(dot, tmpl.Root) } // Eval functions evaluate pipelines, commands, and their elements and extract // values from the data structure by examining fields, calling methods, and so on. // The printing of those values happens only through walk functions. // evalPipeline returns the value acquired by evaluating a pipeline. If the // pipeline has a variable declaration, the variable will be pushed on the // stack. Callers should therefore pop the stack after they are finished // executing commands depending on the pipeline value. func (s *state) evalPipeline(dot reflect.Value, pipe *parse.PipeNode) (value reflect.Value) { if pipe == nil { return } s.at(pipe) for _, cmd := range pipe.Cmds { value = s.evalCommand(dot, cmd, value) // previous value is this one's final arg. // If the object has type interface{}, dig down one level to the thing inside. if value.Kind() == reflect.Interface && value.Type().NumMethod() == 0 { value = reflect.ValueOf(value.Interface()) // lovely! } } for _, variable := range pipe.Decl { s.push(variable.Ident[0], value) } return value } func (s *state) notAFunction(args []parse.Node, final reflect.Value) { if len(args) > 1 || final.IsValid() { s.errorf("can't give argument to non-function %s", args[0]) } } func (s *state) evalCommand(dot reflect.Value, cmd *parse.CommandNode, final reflect.Value) reflect.Value { firstWord := cmd.Args[0] switch n := firstWord.(type) { case *parse.FieldNode: return s.evalFieldNode(dot, n, cmd.Args, final) case *parse.ChainNode: return s.evalChainNode(dot, n, cmd.Args, final) case *parse.IdentifierNode: // Must be a function. return s.evalFunction(dot, n, cmd, cmd.Args, final) case *parse.PipeNode: // Parenthesized pipeline. The arguments are all inside the pipeline; final is ignored. return s.evalPipeline(dot, n) case *parse.VariableNode: return s.evalVariableNode(dot, n, cmd.Args, final) } s.at(firstWord) s.notAFunction(cmd.Args, final) switch word := firstWord.(type) { case *parse.BoolNode: return reflect.ValueOf(word.True) case *parse.DotNode: return dot case *parse.NilNode: s.errorf("nil is not a command") case *parse.NumberNode: return s.idealConstant(word) case *parse.StringNode: return reflect.ValueOf(word.Text) } s.errorf("can't evaluate command %q", firstWord) panic("not reached") } // idealConstant is called to return the value of a number in a context where // we don't know the type. In that case, the syntax of the number tells us // its type, and we use Go rules to resolve. Note there is no such thing as // a uint ideal constant in this situation - the value must be of int type. func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value { // These are ideal constants but we don't know the type // and we have no context. (If it was a method argument, // we'd know what we need.) The syntax guides us to some extent. s.at(constant) switch { case constant.IsComplex: return reflect.ValueOf(constant.Complex128) // incontrovertible. case constant.IsFloat && !isHexConstant(constant.Text) && strings.IndexAny(constant.Text, ".eE") >= 0: return reflect.ValueOf(constant.Float64) case constant.IsInt: n := int(constant.Int64) if int64(n) != constant.Int64 { s.errorf("%s overflows int", constant.Text) } return reflect.ValueOf(n) case constant.IsUint: s.errorf("%s overflows int", constant.Text) } return zero } func isHexConstant(s string) bool { return len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') } func (s *state) evalFieldNode(dot reflect.Value, field *parse.FieldNode, args []parse.Node, final reflect.Value) reflect.Value { s.at(field) return s.evalFieldChain(dot, dot, field, field.Ident, args, final) } func (s *state) evalChainNode(dot reflect.Value, chain *parse.ChainNode, args []parse.Node, final reflect.Value) reflect.Value { s.at(chain) // (pipe).Field1.Field2 has pipe as .Node, fields as .Field. Eval the pipeline, then the fields. pipe := s.evalArg(dot, nil, chain.Node) if len(chain.Field) == 0 { s.errorf("internal error: no fields in evalChainNode") } return s.evalFieldChain(dot, pipe, chain, chain.Field, args, final) } func (s *state) evalVariableNode(dot reflect.Value, variable *parse.VariableNode, args []parse.Node, final reflect.Value) reflect.Value { // $x.Field has $x as the first ident, Field as the second. Eval the var, then the fields. s.at(variable) value := s.varValue(variable.Ident[0]) if len(variable.Ident) == 1 { s.notAFunction(args, final) return value } return s.evalFieldChain(dot, value, variable, variable.Ident[1:], args, final) } // evalFieldChain evaluates .X.Y.Z possibly followed by arguments. // dot is the environment in which to evaluate arguments, while // receiver is the value being walked along the chain. func (s *state) evalFieldChain(dot, receiver reflect.Value, node parse.Node, ident []string, args []parse.Node, final reflect.Value) reflect.Value { n := len(ident) for i := 0; i < n-1; i++ { receiver = s.evalField(dot, ident[i], node, nil, zero, receiver) } // Now if it's a method, it gets the arguments. return s.evalField(dot, ident[n-1], node, args, final, receiver) } func (s *state) evalFunction(dot reflect.Value, node *parse.IdentifierNode, cmd parse.Node, args []parse.Node, final reflect.Value) reflect.Value { s.at(node) name := node.Ident function, ok := findFunction(name, s.tmpl) if !ok { s.errorf("%q is not a defined function", name) } return s.evalCall(dot, function, cmd, name, args, final) } // evalField evaluates an expression like (.Field) or (.Field arg1 arg2). // The 'final' argument represents the return value from the preceding // value of the pipeline, if any. func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, args []parse.Node, final, receiver reflect.Value) reflect.Value { if !receiver.IsValid() { return zero } typ := receiver.Type() receiver, _ = indirect(receiver) // Unless it's an interface, need to get to a value of type *T to guarantee // we see all methods of T and *T. ptr := receiver if ptr.Kind() != reflect.Interface && ptr.CanAddr() { ptr = ptr.Addr() } if method := ptr.MethodByName(fieldName); method.IsValid() { return s.evalCall(dot, method, node, fieldName, args, final) } hasArgs := len(args) > 1 || final.IsValid() // It's not a method; must be a field of a struct or an element of a map. The receiver must not be nil. receiver, isNil := indirect(receiver) if isNil { s.errorf("nil pointer evaluating %s.%s", typ, fieldName) } switch receiver.Kind() { case reflect.Struct: tField, ok := receiver.Type().FieldByName(fieldName) if ok { field := receiver.FieldByIndex(tField.Index) if tField.PkgPath != "" { // field is unexported s.errorf("%s is an unexported field of struct type %s", fieldName, typ) } // If it's a function, we must call it. if hasArgs { s.errorf("%s has arguments but cannot be invoked as function", fieldName) } return field } s.errorf("%s is not a field of struct type %s", fieldName, typ) case reflect.Map: // If it's a map, attempt to use the field name as a key. nameVal := reflect.ValueOf(fieldName) if nameVal.Type().AssignableTo(receiver.Type().Key()) { if hasArgs { s.errorf("%s is not a method but has arguments", fieldName) } return receiver.MapIndex(nameVal) } } s.errorf("can't evaluate field %s in type %s", fieldName, typ) panic("not reached") } var ( errorType = reflect.TypeOf((*error)(nil)).Elem() fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() ) // evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so // it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0] // as the function itself. func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, args []parse.Node, final reflect.Value) reflect.Value { if args != nil { args = args[1:] // Zeroth arg is function name/node; not passed to function. } typ := fun.Type() numIn := len(args) if final.IsValid() { numIn++ } numFixed := len(args) if typ.IsVariadic() { numFixed = typ.NumIn() - 1 // last arg is the variadic one. if numIn < numFixed { s.errorf("wrong number of args for %s: want at least %d got %d", name, typ.NumIn()-1, len(args)) } } else if numIn < typ.NumIn()-1 || !typ.IsVariadic() && numIn != typ.NumIn() { s.errorf("wrong number of args for %s: want %d got %d", name, typ.NumIn(), len(args)) } if !goodFunc(typ) { // TODO: This could still be a confusing error; maybe goodFunc should provide info. s.errorf("can't call method/function %q with %d results", name, typ.NumOut()) } // Build the arg list. argv := make([]reflect.Value, numIn) // Args must be evaluated. Fixed args first. i := 0 for ; i < numFixed && i < len(args); i++ { argv[i] = s.evalArg(dot, typ.In(i), args[i]) } // Now the ... args. if typ.IsVariadic() { argType := typ.In(typ.NumIn() - 1).Elem() // Argument is a slice. for ; i < len(args); i++ { argv[i] = s.evalArg(dot, argType, args[i]) } } // Add final value if necessary. if final.IsValid() { t := typ.In(typ.NumIn() - 1) if typ.IsVariadic() { t = t.Elem() } argv[i] = s.validateType(final, t) } result := fun.Call(argv) // If we have an error that is not nil, stop execution and return that error to the caller. if len(result) == 2 && !result[1].IsNil() { s.at(node) s.errorf("error calling %s: %s", name, result[1].Interface().(error)) } return result[0] } // canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero. func canBeNil(typ reflect.Type) bool { switch typ.Kind() { case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: return true } return false } // validateType guarantees that the value is valid and assignable to the type. func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Value { if !value.IsValid() { if typ == nil || canBeNil(typ) { // An untyped nil interface{}. Accept as a proper nil value. return reflect.Zero(typ) } s.errorf("invalid value; expected %s", typ) } if typ != nil && !value.Type().AssignableTo(typ) { if value.Kind() == reflect.Interface && !value.IsNil() { value = value.Elem() if value.Type().AssignableTo(typ) { return value } // fallthrough } // Does one dereference or indirection work? We could do more, as we // do with method receivers, but that gets messy and method receivers // are much more constrained, so it makes more sense there than here. // Besides, one is almost always all you need. switch { case value.Kind() == reflect.Ptr && value.Type().Elem().AssignableTo(typ): value = value.Elem() if !value.IsValid() { s.errorf("dereference of nil pointer of type %s", typ) } case reflect.PtrTo(value.Type()).AssignableTo(typ) && value.CanAddr(): value = value.Addr() default: s.errorf("wrong type for value; expected %s; got %s", typ, value.Type()) } } return value } func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) reflect.Value { s.at(n) switch arg := n.(type) { case *parse.DotNode: return s.validateType(dot, typ) case *parse.NilNode: if canBeNil(typ) { return reflect.Zero(typ) } s.errorf("cannot assign nil to %s", typ) case *parse.FieldNode: return s.validateType(s.evalFieldNode(dot, arg, []parse.Node{n}, zero), typ) case *parse.VariableNode: return s.validateType(s.evalVariableNode(dot, arg, nil, zero), typ) case *parse.PipeNode: return s.validateType(s.evalPipeline(dot, arg), typ) case *parse.IdentifierNode: return s.evalFunction(dot, arg, arg, nil, zero) case *parse.ChainNode: return s.validateType(s.evalChainNode(dot, arg, nil, zero), typ) } switch typ.Kind() { case reflect.Bool: return s.evalBool(typ, n) case reflect.Complex64, reflect.Complex128: return s.evalComplex(typ, n) case reflect.Float32, reflect.Float64: return s.evalFloat(typ, n) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return s.evalInteger(typ, n) case reflect.Interface: if typ.NumMethod() == 0 { return s.evalEmptyInterface(dot, n) } case reflect.String: return s.evalString(typ, n) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return s.evalUnsignedInteger(typ, n) } s.errorf("can't handle %s for arg of type %s", n, typ) panic("not reached") } func (s *state) evalBool(typ reflect.Type, n parse.Node) reflect.Value { s.at(n) if n, ok := n.(*parse.BoolNode); ok { value := reflect.New(typ).Elem() value.SetBool(n.True) return value } s.errorf("expected bool; found %s", n) panic("not reached") } func (s *state) evalString(typ reflect.Type, n parse.Node) reflect.Value { s.at(n) if n, ok := n.(*parse.StringNode); ok { value := reflect.New(typ).Elem() value.SetString(n.Text) return value } s.errorf("expected string; found %s", n) panic("not reached") } func (s *state) evalInteger(typ reflect.Type, n parse.Node) reflect.Value { s.at(n) if n, ok := n.(*parse.NumberNode); ok && n.IsInt { value := reflect.New(typ).Elem() value.SetInt(n.Int64) return value } s.errorf("expected integer; found %s", n) panic("not reached") } func (s *state) evalUnsignedInteger(typ reflect.Type, n parse.Node) reflect.Value { s.at(n) if n, ok := n.(*parse.NumberNode); ok && n.IsUint { value := reflect.New(typ).Elem() value.SetUint(n.Uint64) return value } s.errorf("expected unsigned integer; found %s", n) panic("not reached") } func (s *state) evalFloat(typ reflect.Type, n parse.Node) reflect.Value { s.at(n) if n, ok := n.(*parse.NumberNode); ok && n.IsFloat { value := reflect.New(typ).Elem() value.SetFloat(n.Float64) return value } s.errorf("expected float; found %s", n) panic("not reached") } func (s *state) evalComplex(typ reflect.Type, n parse.Node) reflect.Value { if n, ok := n.(*parse.NumberNode); ok && n.IsComplex { value := reflect.New(typ).Elem() value.SetComplex(n.Complex128) return value } s.errorf("expected complex; found %s", n) panic("not reached") } func (s *state) evalEmptyInterface(dot reflect.Value, n parse.Node) reflect.Value { s.at(n) switch n := n.(type) { case *parse.BoolNode: return reflect.ValueOf(n.True) case *parse.DotNode: return dot case *parse.FieldNode: return s.evalFieldNode(dot, n, nil, zero) case *parse.IdentifierNode: return s.evalFunction(dot, n, n, nil, zero) case *parse.NilNode: // NilNode is handled in evalArg, the only place that calls here. s.errorf("evalEmptyInterface: nil (can't happen)") case *parse.NumberNode: return s.idealConstant(n) case *parse.StringNode: return reflect.ValueOf(n.Text) case *parse.VariableNode: return s.evalVariableNode(dot, n, nil, zero) case *parse.PipeNode: return s.evalPipeline(dot, n) } s.errorf("can't handle assignment of %s to empty interface argument", n) panic("not reached") } // indirect returns the item at the end of indirection, and a bool to indicate if it's nil. // We indirect through pointers and empty interfaces (only) because // non-empty interfaces have methods we might need. func indirect(v reflect.Value) (rv reflect.Value, isNil bool) { for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() { if v.IsNil() { return v, true } if v.Kind() == reflect.Interface && v.NumMethod() > 0 { break } } return v, false } // printValue writes the textual representation of the value to the output of // the template. func (s *state) printValue(n parse.Node, v reflect.Value) { s.at(n) iface, ok := printableValue(v) if !ok { s.errorf("can't print %s of type %s", n, v.Type()) } fmt.Fprint(s.wr, iface) } // printableValue returns the, possibly indirected, interface value inside v that // is best for a call to formatted printer. func printableValue(v reflect.Value) (interface{}, bool) { if v.Kind() == reflect.Ptr { v, _ = indirect(v) // fmt.Fprint handles nil. } if !v.IsValid() { return "", true } if !v.Type().Implements(errorType) && !v.Type().Implements(fmtStringerType) { if v.CanAddr() && (reflect.PtrTo(v.Type()).Implements(errorType) || reflect.PtrTo(v.Type()).Implements(fmtStringerType)) { v = v.Addr() } else { switch v.Kind() { case reflect.Chan, reflect.Func: return nil, false } } } return v.Interface(), true } // Types to help sort the keys in a map for reproducible output. type rvs []reflect.Value func (x rvs) Len() int { return len(x) } func (x rvs) Swap(i, j int) { x[i], x[j] = x[j], x[i] } type rvInts struct{ rvs } func (x rvInts) Less(i, j int) bool { return x.rvs[i].Int() < x.rvs[j].Int() } type rvUints struct{ rvs } func (x rvUints) Less(i, j int) bool { return x.rvs[i].Uint() < x.rvs[j].Uint() } type rvFloats struct{ rvs } func (x rvFloats) Less(i, j int) bool { return x.rvs[i].Float() < x.rvs[j].Float() } type rvStrings struct{ rvs } func (x rvStrings) Less(i, j int) bool { return x.rvs[i].String() < x.rvs[j].String() } // sortKeys sorts (if it can) the slice of reflect.Values, which is a slice of map keys. func sortKeys(v []reflect.Value) []reflect.Value { if len(v) <= 1 { return v } switch v[0].Kind() { case reflect.Float32, reflect.Float64: sort.Sort(rvFloats{v}) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: sort.Sort(rvInts{v}) case reflect.String: sort.Sort(rvStrings{v}) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: sort.Sort(rvUints{v}) } return v } ================================================ FILE: vendor/github.com/alecthomas/template/funcs.go ================================================ // 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 template import ( "bytes" "errors" "fmt" "io" "net/url" "reflect" "strings" "unicode" "unicode/utf8" ) // FuncMap is the type of the map defining the mapping from names to functions. // Each function must have either a single return value, or two return values of // which the second has type error. In that case, if the second (error) // return value evaluates to non-nil during execution, execution terminates and // Execute returns that error. type FuncMap map[string]interface{} var builtins = FuncMap{ "and": and, "call": call, "html": HTMLEscaper, "index": index, "js": JSEscaper, "len": length, "not": not, "or": or, "print": fmt.Sprint, "printf": fmt.Sprintf, "println": fmt.Sprintln, "urlquery": URLQueryEscaper, // Comparisons "eq": eq, // == "ge": ge, // >= "gt": gt, // > "le": le, // <= "lt": lt, // < "ne": ne, // != } var builtinFuncs = createValueFuncs(builtins) // createValueFuncs turns a FuncMap into a map[string]reflect.Value func createValueFuncs(funcMap FuncMap) map[string]reflect.Value { m := make(map[string]reflect.Value) addValueFuncs(m, funcMap) return m } // addValueFuncs adds to values the functions in funcs, converting them to reflect.Values. func addValueFuncs(out map[string]reflect.Value, in FuncMap) { for name, fn := range in { v := reflect.ValueOf(fn) if v.Kind() != reflect.Func { panic("value for " + name + " not a function") } if !goodFunc(v.Type()) { panic(fmt.Errorf("can't install method/function %q with %d results", name, v.Type().NumOut())) } out[name] = v } } // addFuncs adds to values the functions in funcs. It does no checking of the input - // call addValueFuncs first. func addFuncs(out, in FuncMap) { for name, fn := range in { out[name] = fn } } // goodFunc checks that the function or method has the right result signature. func goodFunc(typ reflect.Type) bool { // We allow functions with 1 result or 2 results where the second is an error. switch { case typ.NumOut() == 1: return true case typ.NumOut() == 2 && typ.Out(1) == errorType: return true } return false } // findFunction looks for a function in the template, and global map. func findFunction(name string, tmpl *Template) (reflect.Value, bool) { if tmpl != nil && tmpl.common != nil { if fn := tmpl.execFuncs[name]; fn.IsValid() { return fn, true } } if fn := builtinFuncs[name]; fn.IsValid() { return fn, true } return reflect.Value{}, false } // Indexing. // index returns the result of indexing its first argument by the following // arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each // indexed item must be a map, slice, or array. func index(item interface{}, indices ...interface{}) (interface{}, error) { v := reflect.ValueOf(item) for _, i := range indices { index := reflect.ValueOf(i) var isNil bool if v, isNil = indirect(v); isNil { return nil, fmt.Errorf("index of nil pointer") } switch v.Kind() { case reflect.Array, reflect.Slice, reflect.String: var x int64 switch index.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: x = index.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: x = int64(index.Uint()) default: return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type()) } if x < 0 || x >= int64(v.Len()) { return nil, fmt.Errorf("index out of range: %d", x) } v = v.Index(int(x)) case reflect.Map: if !index.IsValid() { index = reflect.Zero(v.Type().Key()) } if !index.Type().AssignableTo(v.Type().Key()) { return nil, fmt.Errorf("%s is not index type for %s", index.Type(), v.Type()) } if x := v.MapIndex(index); x.IsValid() { v = x } else { v = reflect.Zero(v.Type().Elem()) } default: return nil, fmt.Errorf("can't index item of type %s", v.Type()) } } return v.Interface(), nil } // Length // length returns the length of the item, with an error if it has no defined length. func length(item interface{}) (int, error) { v, isNil := indirect(reflect.ValueOf(item)) if isNil { return 0, fmt.Errorf("len of nil pointer") } switch v.Kind() { case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String: return v.Len(), nil } return 0, fmt.Errorf("len of type %s", v.Type()) } // Function invocation // call returns the result of evaluating the first argument as a function. // The function must return 1 result, or 2 results, the second of which is an error. func call(fn interface{}, args ...interface{}) (interface{}, error) { v := reflect.ValueOf(fn) typ := v.Type() if typ.Kind() != reflect.Func { return nil, fmt.Errorf("non-function of type %s", typ) } if !goodFunc(typ) { return nil, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut()) } numIn := typ.NumIn() var dddType reflect.Type if typ.IsVariadic() { if len(args) < numIn-1 { return nil, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1) } dddType = typ.In(numIn - 1).Elem() } else { if len(args) != numIn { return nil, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn) } } argv := make([]reflect.Value, len(args)) for i, arg := range args { value := reflect.ValueOf(arg) // Compute the expected type. Clumsy because of variadics. var argType reflect.Type if !typ.IsVariadic() || i < numIn-1 { argType = typ.In(i) } else { argType = dddType } if !value.IsValid() && canBeNil(argType) { value = reflect.Zero(argType) } if !value.Type().AssignableTo(argType) { return nil, fmt.Errorf("arg %d has type %s; should be %s", i, value.Type(), argType) } argv[i] = value } result := v.Call(argv) if len(result) == 2 && !result[1].IsNil() { return result[0].Interface(), result[1].Interface().(error) } return result[0].Interface(), nil } // Boolean logic. func truth(a interface{}) bool { t, _ := isTrue(reflect.ValueOf(a)) return t } // and computes the Boolean AND of its arguments, returning // the first false argument it encounters, or the last argument. func and(arg0 interface{}, args ...interface{}) interface{} { if !truth(arg0) { return arg0 } for i := range args { arg0 = args[i] if !truth(arg0) { break } } return arg0 } // or computes the Boolean OR of its arguments, returning // the first true argument it encounters, or the last argument. func or(arg0 interface{}, args ...interface{}) interface{} { if truth(arg0) { return arg0 } for i := range args { arg0 = args[i] if truth(arg0) { break } } return arg0 } // not returns the Boolean negation of its argument. func not(arg interface{}) (truth bool) { truth, _ = isTrue(reflect.ValueOf(arg)) return !truth } // Comparison. // TODO: Perhaps allow comparison between signed and unsigned integers. var ( errBadComparisonType = errors.New("invalid type for comparison") errBadComparison = errors.New("incompatible types for comparison") errNoComparison = errors.New("missing argument for comparison") ) type kind int const ( invalidKind kind = iota boolKind complexKind intKind floatKind integerKind stringKind uintKind ) func basicKind(v reflect.Value) (kind, error) { switch v.Kind() { case reflect.Bool: return boolKind, nil case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return intKind, nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return uintKind, nil case reflect.Float32, reflect.Float64: return floatKind, nil case reflect.Complex64, reflect.Complex128: return complexKind, nil case reflect.String: return stringKind, nil } return invalidKind, errBadComparisonType } // eq evaluates the comparison a == b || a == c || ... func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) { v1 := reflect.ValueOf(arg1) k1, err := basicKind(v1) if err != nil { return false, err } if len(arg2) == 0 { return false, errNoComparison } for _, arg := range arg2 { v2 := reflect.ValueOf(arg) k2, err := basicKind(v2) if err != nil { return false, err } truth := false if k1 != k2 { // Special case: Can compare integer values regardless of type's sign. switch { case k1 == intKind && k2 == uintKind: truth = v1.Int() >= 0 && uint64(v1.Int()) == v2.Uint() case k1 == uintKind && k2 == intKind: truth = v2.Int() >= 0 && v1.Uint() == uint64(v2.Int()) default: return false, errBadComparison } } else { switch k1 { case boolKind: truth = v1.Bool() == v2.Bool() case complexKind: truth = v1.Complex() == v2.Complex() case floatKind: truth = v1.Float() == v2.Float() case intKind: truth = v1.Int() == v2.Int() case stringKind: truth = v1.String() == v2.String() case uintKind: truth = v1.Uint() == v2.Uint() default: panic("invalid kind") } } if truth { return true, nil } } return false, nil } // ne evaluates the comparison a != b. func ne(arg1, arg2 interface{}) (bool, error) { // != is the inverse of ==. equal, err := eq(arg1, arg2) return !equal, err } // lt evaluates the comparison a < b. func lt(arg1, arg2 interface{}) (bool, error) { v1 := reflect.ValueOf(arg1) k1, err := basicKind(v1) if err != nil { return false, err } v2 := reflect.ValueOf(arg2) k2, err := basicKind(v2) if err != nil { return false, err } truth := false if k1 != k2 { // Special case: Can compare integer values regardless of type's sign. switch { case k1 == intKind && k2 == uintKind: truth = v1.Int() < 0 || uint64(v1.Int()) < v2.Uint() case k1 == uintKind && k2 == intKind: truth = v2.Int() >= 0 && v1.Uint() < uint64(v2.Int()) default: return false, errBadComparison } } else { switch k1 { case boolKind, complexKind: return false, errBadComparisonType case floatKind: truth = v1.Float() < v2.Float() case intKind: truth = v1.Int() < v2.Int() case stringKind: truth = v1.String() < v2.String() case uintKind: truth = v1.Uint() < v2.Uint() default: panic("invalid kind") } } return truth, nil } // le evaluates the comparison <= b. func le(arg1, arg2 interface{}) (bool, error) { // <= is < or ==. lessThan, err := lt(arg1, arg2) if lessThan || err != nil { return lessThan, err } return eq(arg1, arg2) } // gt evaluates the comparison a > b. func gt(arg1, arg2 interface{}) (bool, error) { // > is the inverse of <=. lessOrEqual, err := le(arg1, arg2) if err != nil { return false, err } return !lessOrEqual, nil } // ge evaluates the comparison a >= b. func ge(arg1, arg2 interface{}) (bool, error) { // >= is the inverse of <. lessThan, err := lt(arg1, arg2) if err != nil { return false, err } return !lessThan, nil } // HTML escaping. var ( htmlQuot = []byte(""") // shorter than """ htmlApos = []byte("'") // shorter than "'" and apos was not in HTML until HTML5 htmlAmp = []byte("&") htmlLt = []byte("<") htmlGt = []byte(">") ) // HTMLEscape writes to w the escaped HTML equivalent of the plain text data b. func HTMLEscape(w io.Writer, b []byte) { last := 0 for i, c := range b { var html []byte switch c { case '"': html = htmlQuot case '\'': html = htmlApos case '&': html = htmlAmp case '<': html = htmlLt case '>': html = htmlGt default: continue } w.Write(b[last:i]) w.Write(html) last = i + 1 } w.Write(b[last:]) } // HTMLEscapeString returns the escaped HTML equivalent of the plain text data s. func HTMLEscapeString(s string) string { // Avoid allocation if we can. if strings.IndexAny(s, `'"&<>`) < 0 { return s } var b bytes.Buffer HTMLEscape(&b, []byte(s)) return b.String() } // HTMLEscaper returns the escaped HTML equivalent of the textual // representation of its arguments. func HTMLEscaper(args ...interface{}) string { return HTMLEscapeString(evalArgs(args)) } // JavaScript escaping. var ( jsLowUni = []byte(`\u00`) hex = []byte("0123456789ABCDEF") jsBackslash = []byte(`\\`) jsApos = []byte(`\'`) jsQuot = []byte(`\"`) jsLt = []byte(`\x3C`) jsGt = []byte(`\x3E`) ) // JSEscape writes to w the escaped JavaScript equivalent of the plain text data b. func JSEscape(w io.Writer, b []byte) { last := 0 for i := 0; i < len(b); i++ { c := b[i] if !jsIsSpecial(rune(c)) { // fast path: nothing to do continue } w.Write(b[last:i]) if c < utf8.RuneSelf { // Quotes, slashes and angle brackets get quoted. // Control characters get written as \u00XX. switch c { case '\\': w.Write(jsBackslash) case '\'': w.Write(jsApos) case '"': w.Write(jsQuot) case '<': w.Write(jsLt) case '>': w.Write(jsGt) default: w.Write(jsLowUni) t, b := c>>4, c&0x0f w.Write(hex[t : t+1]) w.Write(hex[b : b+1]) } } else { // Unicode rune. r, size := utf8.DecodeRune(b[i:]) if unicode.IsPrint(r) { w.Write(b[i : i+size]) } else { fmt.Fprintf(w, "\\u%04X", r) } i += size - 1 } last = i + 1 } w.Write(b[last:]) } // JSEscapeString returns the escaped JavaScript equivalent of the plain text data s. func JSEscapeString(s string) string { // Avoid allocation if we can. if strings.IndexFunc(s, jsIsSpecial) < 0 { return s } var b bytes.Buffer JSEscape(&b, []byte(s)) return b.String() } func jsIsSpecial(r rune) bool { switch r { case '\\', '\'', '"', '<', '>': return true } return r < ' ' || utf8.RuneSelf <= r } // JSEscaper returns the escaped JavaScript equivalent of the textual // representation of its arguments. func JSEscaper(args ...interface{}) string { return JSEscapeString(evalArgs(args)) } // URLQueryEscaper returns the escaped value of the textual representation of // its arguments in a form suitable for embedding in a URL query. func URLQueryEscaper(args ...interface{}) string { return url.QueryEscape(evalArgs(args)) } // evalArgs formats the list of arguments into a string. It is therefore equivalent to // fmt.Sprint(args...) // except that each argument is indirected (if a pointer), as required, // using the same rules as the default string evaluation during template // execution. func evalArgs(args []interface{}) string { ok := false var s string // Fast path for simple common case. if len(args) == 1 { s, ok = args[0].(string) } if !ok { for i, arg := range args { a, ok := printableValue(reflect.ValueOf(arg)) if ok { args[i] = a } // else left fmt do its thing } s = fmt.Sprint(args...) } return s } ================================================ FILE: vendor/github.com/alecthomas/template/go.mod ================================================ module github.com/alecthomas/template ================================================ FILE: vendor/github.com/alecthomas/template/helper.go ================================================ // 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. // Helper functions to make constructing templates easier. package template import ( "fmt" "io/ioutil" "path/filepath" ) // Functions and methods to parse templates. // Must is a helper that wraps a call to a function returning (*Template, error) // and panics if the error is non-nil. It is intended for use in variable // initializations such as // var t = template.Must(template.New("name").Parse("text")) func Must(t *Template, err error) *Template { if err != nil { panic(err) } return t } // ParseFiles creates a new Template and parses the template definitions from // the named files. The returned template's name will have the (base) name and // (parsed) contents of the first file. There must be at least one file. // If an error occurs, parsing stops and the returned *Template is nil. func ParseFiles(filenames ...string) (*Template, error) { return parseFiles(nil, filenames...) } // ParseFiles parses the named files and associates the resulting templates with // t. If an error occurs, parsing stops and the returned template is nil; // otherwise it is t. There must be at least one file. func (t *Template) ParseFiles(filenames ...string) (*Template, error) { return parseFiles(t, filenames...) } // parseFiles is the helper for the method and function. If the argument // template is nil, it is created from the first file. func parseFiles(t *Template, filenames ...string) (*Template, error) { if len(filenames) == 0 { // Not really a problem, but be consistent. return nil, fmt.Errorf("template: no files named in call to ParseFiles") } for _, filename := range filenames { b, err := ioutil.ReadFile(filename) if err != nil { return nil, err } s := string(b) name := filepath.Base(filename) // First template becomes return value if not already defined, // and we use that one for subsequent New calls to associate // all the templates together. Also, if this file has the same name // as t, this file becomes the contents of t, so // t, err := New(name).Funcs(xxx).ParseFiles(name) // works. Otherwise we create a new template associated with t. var tmpl *Template if t == nil { t = New(name) } if name == t.Name() { tmpl = t } else { tmpl = t.New(name) } _, err = tmpl.Parse(s) if err != nil { return nil, err } } return t, nil } // ParseGlob creates a new Template and parses the template definitions from the // files identified by the pattern, which must match at least one file. The // returned template will have the (base) name and (parsed) contents of the // first file matched by the pattern. ParseGlob is equivalent to calling // ParseFiles with the list of files matched by the pattern. func ParseGlob(pattern string) (*Template, error) { return parseGlob(nil, pattern) } // ParseGlob parses the template definitions in the files identified by the // pattern and associates the resulting templates with t. The pattern is // processed by filepath.Glob and must match at least one file. ParseGlob is // equivalent to calling t.ParseFiles with the list of files matched by the // pattern. func (t *Template) ParseGlob(pattern string) (*Template, error) { return parseGlob(t, pattern) } // parseGlob is the implementation of the function and method ParseGlob. func parseGlob(t *Template, pattern string) (*Template, error) { filenames, err := filepath.Glob(pattern) if err != nil { return nil, err } if len(filenames) == 0 { return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern) } return parseFiles(t, filenames...) } ================================================ FILE: vendor/github.com/alecthomas/template/parse/lex.go ================================================ // 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 parse import ( "fmt" "strings" "unicode" "unicode/utf8" ) // item represents a token or text string returned from the scanner. type item struct { typ itemType // The type of this item. pos Pos // The starting position, in bytes, of this item in the input string. val string // The value of this item. } func (i item) String() string { switch { case i.typ == itemEOF: return "EOF" case i.typ == itemError: return i.val case i.typ > itemKeyword: return fmt.Sprintf("<%s>", i.val) case len(i.val) > 10: return fmt.Sprintf("%.10q...", i.val) } return fmt.Sprintf("%q", i.val) } // itemType identifies the type of lex items. type itemType int const ( itemError itemType = iota // error occurred; value is text of error itemBool // boolean constant itemChar // printable ASCII character; grab bag for comma etc. itemCharConstant // character constant itemComplex // complex constant (1+2i); imaginary is just a number itemColonEquals // colon-equals (':=') introducing a declaration itemEOF itemField // alphanumeric identifier starting with '.' itemIdentifier // alphanumeric identifier not starting with '.' itemLeftDelim // left action delimiter itemLeftParen // '(' inside action itemNumber // simple number, including imaginary itemPipe // pipe symbol itemRawString // raw quoted string (includes quotes) itemRightDelim // right action delimiter itemElideNewline // elide newline after right delim itemRightParen // ')' inside action itemSpace // run of spaces separating arguments itemString // quoted string (includes quotes) itemText // plain text itemVariable // variable starting with '$', such as '$' or '$1' or '$hello' // Keywords appear after all the rest. itemKeyword // used only to delimit the keywords itemDot // the cursor, spelled '.' itemDefine // define keyword itemElse // else keyword itemEnd // end keyword itemIf // if keyword itemNil // the untyped nil constant, easiest to treat as a keyword itemRange // range keyword itemTemplate // template keyword itemWith // with keyword ) var key = map[string]itemType{ ".": itemDot, "define": itemDefine, "else": itemElse, "end": itemEnd, "if": itemIf, "range": itemRange, "nil": itemNil, "template": itemTemplate, "with": itemWith, } const eof = -1 // stateFn represents the state of the scanner as a function that returns the next state. type stateFn func(*lexer) stateFn // lexer holds the state of the scanner. type lexer struct { name string // the name of the input; used only for error reports input string // the string being scanned leftDelim string // start of action rightDelim string // end of action state stateFn // the next lexing function to enter pos Pos // current position in the input start Pos // start position of this item width Pos // width of last rune read from input lastPos Pos // position of most recent item returned by nextItem items chan item // channel of scanned items parenDepth int // nesting depth of ( ) exprs } // next returns the next rune in the input. func (l *lexer) next() rune { if int(l.pos) >= len(l.input) { l.width = 0 return eof } r, w := utf8.DecodeRuneInString(l.input[l.pos:]) l.width = Pos(w) l.pos += l.width return r } // peek returns but does not consume the next rune in the input. func (l *lexer) peek() rune { r := l.next() l.backup() return r } // backup steps back one rune. Can only be called once per call of next. func (l *lexer) backup() { l.pos -= l.width } // emit passes an item back to the client. func (l *lexer) emit(t itemType) { l.items <- item{t, l.start, l.input[l.start:l.pos]} l.start = l.pos } // ignore skips over the pending input before this point. func (l *lexer) ignore() { l.start = l.pos } // accept consumes the next rune if it's from the valid set. func (l *lexer) accept(valid string) bool { if strings.IndexRune(valid, l.next()) >= 0 { return true } l.backup() return false } // acceptRun consumes a run of runes from the valid set. func (l *lexer) acceptRun(valid string) { for strings.IndexRune(valid, l.next()) >= 0 { } l.backup() } // lineNumber reports which line we're on, based on the position of // the previous item returned by nextItem. Doing it this way // means we don't have to worry about peek double counting. func (l *lexer) lineNumber() int { return 1 + strings.Count(l.input[:l.lastPos], "\n") } // errorf returns an error token and terminates the scan by passing // back a nil pointer that will be the next state, terminating l.nextItem. func (l *lexer) errorf(format string, args ...interface{}) stateFn { l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)} return nil } // nextItem returns the next item from the input. func (l *lexer) nextItem() item { item := <-l.items l.lastPos = item.pos return item } // lex creates a new scanner for the input string. func lex(name, input, left, right string) *lexer { if left == "" { left = leftDelim } if right == "" { right = rightDelim } l := &lexer{ name: name, input: input, leftDelim: left, rightDelim: right, items: make(chan item), } go l.run() return l } // run runs the state machine for the lexer. func (l *lexer) run() { for l.state = lexText; l.state != nil; { l.state = l.state(l) } } // state functions const ( leftDelim = "{{" rightDelim = "}}" leftComment = "/*" rightComment = "*/" ) // lexText scans until an opening action delimiter, "{{". func lexText(l *lexer) stateFn { for { if strings.HasPrefix(l.input[l.pos:], l.leftDelim) { if l.pos > l.start { l.emit(itemText) } return lexLeftDelim } if l.next() == eof { break } } // Correctly reached EOF. if l.pos > l.start { l.emit(itemText) } l.emit(itemEOF) return nil } // lexLeftDelim scans the left delimiter, which is known to be present. func lexLeftDelim(l *lexer) stateFn { l.pos += Pos(len(l.leftDelim)) if strings.HasPrefix(l.input[l.pos:], leftComment) { return lexComment } l.emit(itemLeftDelim) l.parenDepth = 0 return lexInsideAction } // lexComment scans a comment. The left comment marker is known to be present. func lexComment(l *lexer) stateFn { l.pos += Pos(len(leftComment)) i := strings.Index(l.input[l.pos:], rightComment) if i < 0 { return l.errorf("unclosed comment") } l.pos += Pos(i + len(rightComment)) if !strings.HasPrefix(l.input[l.pos:], l.rightDelim) { return l.errorf("comment ends before closing delimiter") } l.pos += Pos(len(l.rightDelim)) l.ignore() return lexText } // lexRightDelim scans the right delimiter, which is known to be present. func lexRightDelim(l *lexer) stateFn { l.pos += Pos(len(l.rightDelim)) l.emit(itemRightDelim) if l.peek() == '\\' { l.pos++ l.emit(itemElideNewline) } return lexText } // lexInsideAction scans the elements inside action delimiters. func lexInsideAction(l *lexer) stateFn { // Either number, quoted string, or identifier. // Spaces separate arguments; runs of spaces turn into itemSpace. // Pipe symbols separate and are emitted. if strings.HasPrefix(l.input[l.pos:], l.rightDelim+"\\") || strings.HasPrefix(l.input[l.pos:], l.rightDelim) { if l.parenDepth == 0 { return lexRightDelim } return l.errorf("unclosed left paren") } switch r := l.next(); { case r == eof || isEndOfLine(r): return l.errorf("unclosed action") case isSpace(r): return lexSpace case r == ':': if l.next() != '=' { return l.errorf("expected :=") } l.emit(itemColonEquals) case r == '|': l.emit(itemPipe) case r == '"': return lexQuote case r == '`': return lexRawQuote case r == '$': return lexVariable case r == '\'': return lexChar case r == '.': // special look-ahead for ".field" so we don't break l.backup(). if l.pos < Pos(len(l.input)) { r := l.input[l.pos] if r < '0' || '9' < r { return lexField } } fallthrough // '.' can start a number. case r == '+' || r == '-' || ('0' <= r && r <= '9'): l.backup() return lexNumber case isAlphaNumeric(r): l.backup() return lexIdentifier case r == '(': l.emit(itemLeftParen) l.parenDepth++ return lexInsideAction case r == ')': l.emit(itemRightParen) l.parenDepth-- if l.parenDepth < 0 { return l.errorf("unexpected right paren %#U", r) } return lexInsideAction case r <= unicode.MaxASCII && unicode.IsPrint(r): l.emit(itemChar) return lexInsideAction default: return l.errorf("unrecognized character in action: %#U", r) } return lexInsideAction } // lexSpace scans a run of space characters. // One space has already been seen. func lexSpace(l *lexer) stateFn { for isSpace(l.peek()) { l.next() } l.emit(itemSpace) return lexInsideAction } // lexIdentifier scans an alphanumeric. func lexIdentifier(l *lexer) stateFn { Loop: for { switch r := l.next(); { case isAlphaNumeric(r): // absorb. default: l.backup() word := l.input[l.start:l.pos] if !l.atTerminator() { return l.errorf("bad character %#U", r) } switch { case key[word] > itemKeyword: l.emit(key[word]) case word[0] == '.': l.emit(itemField) case word == "true", word == "false": l.emit(itemBool) default: l.emit(itemIdentifier) } break Loop } } return lexInsideAction } // lexField scans a field: .Alphanumeric. // The . has been scanned. func lexField(l *lexer) stateFn { return lexFieldOrVariable(l, itemField) } // lexVariable scans a Variable: $Alphanumeric. // The $ has been scanned. func lexVariable(l *lexer) stateFn { if l.atTerminator() { // Nothing interesting follows -> "$". l.emit(itemVariable) return lexInsideAction } return lexFieldOrVariable(l, itemVariable) } // lexVariable scans a field or variable: [.$]Alphanumeric. // The . or $ has been scanned. func lexFieldOrVariable(l *lexer, typ itemType) stateFn { if l.atTerminator() { // Nothing interesting follows -> "." or "$". if typ == itemVariable { l.emit(itemVariable) } else { l.emit(itemDot) } return lexInsideAction } var r rune for { r = l.next() if !isAlphaNumeric(r) { l.backup() break } } if !l.atTerminator() { return l.errorf("bad character %#U", r) } l.emit(typ) return lexInsideAction } // atTerminator reports whether the input is at valid termination character to // appear after an identifier. Breaks .X.Y into two pieces. Also catches cases // like "$x+2" not being acceptable without a space, in case we decide one // day to implement arithmetic. func (l *lexer) atTerminator() bool { r := l.peek() if isSpace(r) || isEndOfLine(r) { return true } switch r { case eof, '.', ',', '|', ':', ')', '(': return true } // Does r start the delimiter? This can be ambiguous (with delim=="//", $x/2 will // succeed but should fail) but only in extremely rare cases caused by willfully // bad choice of delimiter. if rd, _ := utf8.DecodeRuneInString(l.rightDelim); rd == r { return true } return false } // lexChar scans a character constant. The initial quote is already // scanned. Syntax checking is done by the parser. func lexChar(l *lexer) stateFn { Loop: for { switch l.next() { case '\\': if r := l.next(); r != eof && r != '\n' { break } fallthrough case eof, '\n': return l.errorf("unterminated character constant") case '\'': break Loop } } l.emit(itemCharConstant) return lexInsideAction } // lexNumber scans a number: decimal, octal, hex, float, or imaginary. This // isn't a perfect number scanner - for instance it accepts "." and "0x0.2" // and "089" - but when it's wrong the input is invalid and the parser (via // strconv) will notice. func lexNumber(l *lexer) stateFn { if !l.scanNumber() { return l.errorf("bad number syntax: %q", l.input[l.start:l.pos]) } if sign := l.peek(); sign == '+' || sign == '-' { // Complex: 1+2i. No spaces, must end in 'i'. if !l.scanNumber() || l.input[l.pos-1] != 'i' { return l.errorf("bad number syntax: %q", l.input[l.start:l.pos]) } l.emit(itemComplex) } else { l.emit(itemNumber) } return lexInsideAction } func (l *lexer) scanNumber() bool { // Optional leading sign. l.accept("+-") // Is it hex? digits := "0123456789" if l.accept("0") && l.accept("xX") { digits = "0123456789abcdefABCDEF" } l.acceptRun(digits) if l.accept(".") { l.acceptRun(digits) } if l.accept("eE") { l.accept("+-") l.acceptRun("0123456789") } // Is it imaginary? l.accept("i") // Next thing mustn't be alphanumeric. if isAlphaNumeric(l.peek()) { l.next() return false } return true } // lexQuote scans a quoted string. func lexQuote(l *lexer) stateFn { Loop: for { switch l.next() { case '\\': if r := l.next(); r != eof && r != '\n' { break } fallthrough case eof, '\n': return l.errorf("unterminated quoted string") case '"': break Loop } } l.emit(itemString) return lexInsideAction } // lexRawQuote scans a raw quoted string. func lexRawQuote(l *lexer) stateFn { Loop: for { switch l.next() { case eof, '\n': return l.errorf("unterminated raw quoted string") case '`': break Loop } } l.emit(itemRawString) return lexInsideAction } // isSpace reports whether r is a space character. func isSpace(r rune) bool { return r == ' ' || r == '\t' } // isEndOfLine reports whether r is an end-of-line character. func isEndOfLine(r rune) bool { return r == '\r' || r == '\n' } // isAlphaNumeric reports whether r is an alphabetic, digit, or underscore. func isAlphaNumeric(r rune) bool { return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) } ================================================ FILE: vendor/github.com/alecthomas/template/parse/node.go ================================================ // 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. // Parse nodes. package parse import ( "bytes" "fmt" "strconv" "strings" ) var textFormat = "%s" // Changed to "%q" in tests for better error messages. // A Node is an element in the parse tree. The interface is trivial. // The interface contains an unexported method so that only // types local to this package can satisfy it. type Node interface { Type() NodeType String() string // Copy does a deep copy of the Node and all its components. // To avoid type assertions, some XxxNodes also have specialized // CopyXxx methods that return *XxxNode. Copy() Node Position() Pos // byte position of start of node in full original input string // tree returns the containing *Tree. // It is unexported so all implementations of Node are in this package. tree() *Tree } // NodeType identifies the type of a parse tree node. type NodeType int // Pos represents a byte position in the original input text from which // this template was parsed. type Pos int func (p Pos) Position() Pos { return p } // Type returns itself and provides an easy default implementation // for embedding in a Node. Embedded in all non-trivial Nodes. func (t NodeType) Type() NodeType { return t } const ( NodeText NodeType = iota // Plain text. NodeAction // A non-control action such as a field evaluation. NodeBool // A boolean constant. NodeChain // A sequence of field accesses. NodeCommand // An element of a pipeline. NodeDot // The cursor, dot. nodeElse // An else action. Not added to tree. nodeEnd // An end action. Not added to tree. NodeField // A field or method name. NodeIdentifier // An identifier; always a function name. NodeIf // An if action. NodeList // A list of Nodes. NodeNil // An untyped nil constant. NodeNumber // A numerical constant. NodePipe // A pipeline of commands. NodeRange // A range action. NodeString // A string constant. NodeTemplate // A template invocation action. NodeVariable // A $ variable. NodeWith // A with action. ) // Nodes. // ListNode holds a sequence of nodes. type ListNode struct { NodeType Pos tr *Tree Nodes []Node // The element nodes in lexical order. } func (t *Tree) newList(pos Pos) *ListNode { return &ListNode{tr: t, NodeType: NodeList, Pos: pos} } func (l *ListNode) append(n Node) { l.Nodes = append(l.Nodes, n) } func (l *ListNode) tree() *Tree { return l.tr } func (l *ListNode) String() string { b := new(bytes.Buffer) for _, n := range l.Nodes { fmt.Fprint(b, n) } return b.String() } func (l *ListNode) CopyList() *ListNode { if l == nil { return l } n := l.tr.newList(l.Pos) for _, elem := range l.Nodes { n.append(elem.Copy()) } return n } func (l *ListNode) Copy() Node { return l.CopyList() } // TextNode holds plain text. type TextNode struct { NodeType Pos tr *Tree Text []byte // The text; may span newlines. } func (t *Tree) newText(pos Pos, text string) *TextNode { return &TextNode{tr: t, NodeType: NodeText, Pos: pos, Text: []byte(text)} } func (t *TextNode) String() string { return fmt.Sprintf(textFormat, t.Text) } func (t *TextNode) tree() *Tree { return t.tr } func (t *TextNode) Copy() Node { return &TextNode{tr: t.tr, NodeType: NodeText, Pos: t.Pos, Text: append([]byte{}, t.Text...)} } // PipeNode holds a pipeline with optional declaration type PipeNode struct { NodeType Pos tr *Tree Line int // The line number in the input (deprecated; kept for compatibility) Decl []*VariableNode // Variable declarations in lexical order. Cmds []*CommandNode // The commands in lexical order. } func (t *Tree) newPipeline(pos Pos, line int, decl []*VariableNode) *PipeNode { return &PipeNode{tr: t, NodeType: NodePipe, Pos: pos, Line: line, Decl: decl} } func (p *PipeNode) append(command *CommandNode) { p.Cmds = append(p.Cmds, command) } func (p *PipeNode) String() string { s := "" if len(p.Decl) > 0 { for i, v := range p.Decl { if i > 0 { s += ", " } s += v.String() } s += " := " } for i, c := range p.Cmds { if i > 0 { s += " | " } s += c.String() } return s } func (p *PipeNode) tree() *Tree { return p.tr } func (p *PipeNode) CopyPipe() *PipeNode { if p == nil { return p } var decl []*VariableNode for _, d := range p.Decl { decl = append(decl, d.Copy().(*VariableNode)) } n := p.tr.newPipeline(p.Pos, p.Line, decl) for _, c := range p.Cmds { n.append(c.Copy().(*CommandNode)) } return n } func (p *PipeNode) Copy() Node { return p.CopyPipe() } // ActionNode holds an action (something bounded by delimiters). // Control actions have their own nodes; ActionNode represents simple // ones such as field evaluations and parenthesized pipelines. type ActionNode struct { NodeType Pos tr *Tree Line int // The line number in the input (deprecated; kept for compatibility) Pipe *PipeNode // The pipeline in the action. } func (t *Tree) newAction(pos Pos, line int, pipe *PipeNode) *ActionNode { return &ActionNode{tr: t, NodeType: NodeAction, Pos: pos, Line: line, Pipe: pipe} } func (a *ActionNode) String() string { return fmt.Sprintf("{{%s}}", a.Pipe) } func (a *ActionNode) tree() *Tree { return a.tr } func (a *ActionNode) Copy() Node { return a.tr.newAction(a.Pos, a.Line, a.Pipe.CopyPipe()) } // CommandNode holds a command (a pipeline inside an evaluating action). type CommandNode struct { NodeType Pos tr *Tree Args []Node // Arguments in lexical order: Identifier, field, or constant. } func (t *Tree) newCommand(pos Pos) *CommandNode { return &CommandNode{tr: t, NodeType: NodeCommand, Pos: pos} } func (c *CommandNode) append(arg Node) { c.Args = append(c.Args, arg) } func (c *CommandNode) String() string { s := "" for i, arg := range c.Args { if i > 0 { s += " " } if arg, ok := arg.(*PipeNode); ok { s += "(" + arg.String() + ")" continue } s += arg.String() } return s } func (c *CommandNode) tree() *Tree { return c.tr } func (c *CommandNode) Copy() Node { if c == nil { return c } n := c.tr.newCommand(c.Pos) for _, c := range c.Args { n.append(c.Copy()) } return n } // IdentifierNode holds an identifier. type IdentifierNode struct { NodeType Pos tr *Tree Ident string // The identifier's name. } // NewIdentifier returns a new IdentifierNode with the given identifier name. func NewIdentifier(ident string) *IdentifierNode { return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident} } // SetPos sets the position. NewIdentifier is a public method so we can't modify its signature. // Chained for convenience. // TODO: fix one day? func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode { i.Pos = pos return i } // SetTree sets the parent tree for the node. NewIdentifier is a public method so we can't modify its signature. // Chained for convenience. // TODO: fix one day? func (i *IdentifierNode) SetTree(t *Tree) *IdentifierNode { i.tr = t return i } func (i *IdentifierNode) String() string { return i.Ident } func (i *IdentifierNode) tree() *Tree { return i.tr } func (i *IdentifierNode) Copy() Node { return NewIdentifier(i.Ident).SetTree(i.tr).SetPos(i.Pos) } // VariableNode holds a list of variable names, possibly with chained field // accesses. The dollar sign is part of the (first) name. type VariableNode struct { NodeType Pos tr *Tree Ident []string // Variable name and fields in lexical order. } func (t *Tree) newVariable(pos Pos, ident string) *VariableNode { return &VariableNode{tr: t, NodeType: NodeVariable, Pos: pos, Ident: strings.Split(ident, ".")} } func (v *VariableNode) String() string { s := "" for i, id := range v.Ident { if i > 0 { s += "." } s += id } return s } func (v *VariableNode) tree() *Tree { return v.tr } func (v *VariableNode) Copy() Node { return &VariableNode{tr: v.tr, NodeType: NodeVariable, Pos: v.Pos, Ident: append([]string{}, v.Ident...)} } // DotNode holds the special identifier '.'. type DotNode struct { NodeType Pos tr *Tree } func (t *Tree) newDot(pos Pos) *DotNode { return &DotNode{tr: t, NodeType: NodeDot, Pos: pos} } func (d *DotNode) Type() NodeType { // Override method on embedded NodeType for API compatibility. // TODO: Not really a problem; could change API without effect but // api tool complains. return NodeDot } func (d *DotNode) String() string { return "." } func (d *DotNode) tree() *Tree { return d.tr } func (d *DotNode) Copy() Node { return d.tr.newDot(d.Pos) } // NilNode holds the special identifier 'nil' representing an untyped nil constant. type NilNode struct { NodeType Pos tr *Tree } func (t *Tree) newNil(pos Pos) *NilNode { return &NilNode{tr: t, NodeType: NodeNil, Pos: pos} } func (n *NilNode) Type() NodeType { // Override method on embedded NodeType for API compatibility. // TODO: Not really a problem; could change API without effect but // api tool complains. return NodeNil } func (n *NilNode) String() string { return "nil" } func (n *NilNode) tree() *Tree { return n.tr } func (n *NilNode) Copy() Node { return n.tr.newNil(n.Pos) } // FieldNode holds a field (identifier starting with '.'). // The names may be chained ('.x.y'). // The period is dropped from each ident. type FieldNode struct { NodeType Pos tr *Tree Ident []string // The identifiers in lexical order. } func (t *Tree) newField(pos Pos, ident string) *FieldNode { return &FieldNode{tr: t, NodeType: NodeField, Pos: pos, Ident: strings.Split(ident[1:], ".")} // [1:] to drop leading period } func (f *FieldNode) String() string { s := "" for _, id := range f.Ident { s += "." + id } return s } func (f *FieldNode) tree() *Tree { return f.tr } func (f *FieldNode) Copy() Node { return &FieldNode{tr: f.tr, NodeType: NodeField, Pos: f.Pos, Ident: append([]string{}, f.Ident...)} } // ChainNode holds a term followed by a chain of field accesses (identifier starting with '.'). // The names may be chained ('.x.y'). // The periods are dropped from each ident. type ChainNode struct { NodeType Pos tr *Tree Node Node Field []string // The identifiers in lexical order. } func (t *Tree) newChain(pos Pos, node Node) *ChainNode { return &ChainNode{tr: t, NodeType: NodeChain, Pos: pos, Node: node} } // Add adds the named field (which should start with a period) to the end of the chain. func (c *ChainNode) Add(field string) { if len(field) == 0 || field[0] != '.' { panic("no dot in field") } field = field[1:] // Remove leading dot. if field == "" { panic("empty field") } c.Field = append(c.Field, field) } func (c *ChainNode) String() string { s := c.Node.String() if _, ok := c.Node.(*PipeNode); ok { s = "(" + s + ")" } for _, field := range c.Field { s += "." + field } return s } func (c *ChainNode) tree() *Tree { return c.tr } func (c *ChainNode) Copy() Node { return &ChainNode{tr: c.tr, NodeType: NodeChain, Pos: c.Pos, Node: c.Node, Field: append([]string{}, c.Field...)} } // BoolNode holds a boolean constant. type BoolNode struct { NodeType Pos tr *Tree True bool // The value of the boolean constant. } func (t *Tree) newBool(pos Pos, true bool) *BoolNode { return &BoolNode{tr: t, NodeType: NodeBool, Pos: pos, True: true} } func (b *BoolNode) String() string { if b.True { return "true" } return "false" } func (b *BoolNode) tree() *Tree { return b.tr } func (b *BoolNode) Copy() Node { return b.tr.newBool(b.Pos, b.True) } // NumberNode holds a number: signed or unsigned integer, float, or complex. // The value is parsed and stored under all the types that can represent the value. // This simulates in a small amount of code the behavior of Go's ideal constants. type NumberNode struct { NodeType Pos tr *Tree IsInt bool // Number has an integral value. IsUint bool // Number has an unsigned integral value. IsFloat bool // Number has a floating-point value. IsComplex bool // Number is complex. Int64 int64 // The signed integer value. Uint64 uint64 // The unsigned integer value. Float64 float64 // The floating-point value. Complex128 complex128 // The complex value. Text string // The original textual representation from the input. } func (t *Tree) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error) { n := &NumberNode{tr: t, NodeType: NodeNumber, Pos: pos, Text: text} switch typ { case itemCharConstant: rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0]) if err != nil { return nil, err } if tail != "'" { return nil, fmt.Errorf("malformed character constant: %s", text) } n.Int64 = int64(rune) n.IsInt = true n.Uint64 = uint64(rune) n.IsUint = true n.Float64 = float64(rune) // odd but those are the rules. n.IsFloat = true return n, nil case itemComplex: // fmt.Sscan can parse the pair, so let it do the work. if _, err := fmt.Sscan(text, &n.Complex128); err != nil { return nil, err } n.IsComplex = true n.simplifyComplex() return n, nil } // Imaginary constants can only be complex unless they are zero. if len(text) > 0 && text[len(text)-1] == 'i' { f, err := strconv.ParseFloat(text[:len(text)-1], 64) if err == nil { n.IsComplex = true n.Complex128 = complex(0, f) n.simplifyComplex() return n, nil } } // Do integer test first so we get 0x123 etc. u, err := strconv.ParseUint(text, 0, 64) // will fail for -0; fixed below. if err == nil { n.IsUint = true n.Uint64 = u } i, err := strconv.ParseInt(text, 0, 64) if err == nil { n.IsInt = true n.Int64 = i if i == 0 { n.IsUint = true // in case of -0. n.Uint64 = u } } // If an integer extraction succeeded, promote the float. if n.IsInt { n.IsFloat = true n.Float64 = float64(n.Int64) } else if n.IsUint { n.IsFloat = true n.Float64 = float64(n.Uint64) } else { f, err := strconv.ParseFloat(text, 64) if err == nil { n.IsFloat = true n.Float64 = f // If a floating-point extraction succeeded, extract the int if needed. if !n.IsInt && float64(int64(f)) == f { n.IsInt = true n.Int64 = int64(f) } if !n.IsUint && float64(uint64(f)) == f { n.IsUint = true n.Uint64 = uint64(f) } } } if !n.IsInt && !n.IsUint && !n.IsFloat { return nil, fmt.Errorf("illegal number syntax: %q", text) } return n, nil } // simplifyComplex pulls out any other types that are represented by the complex number. // These all require that the imaginary part be zero. func (n *NumberNode) simplifyComplex() { n.IsFloat = imag(n.Complex128) == 0 if n.IsFloat { n.Float64 = real(n.Complex128) n.IsInt = float64(int64(n.Float64)) == n.Float64 if n.IsInt { n.Int64 = int64(n.Float64) } n.IsUint = float64(uint64(n.Float64)) == n.Float64 if n.IsUint { n.Uint64 = uint64(n.Float64) } } } func (n *NumberNode) String() string { return n.Text } func (n *NumberNode) tree() *Tree { return n.tr } func (n *NumberNode) Copy() Node { nn := new(NumberNode) *nn = *n // Easy, fast, correct. return nn } // StringNode holds a string constant. The value has been "unquoted". type StringNode struct { NodeType Pos tr *Tree Quoted string // The original text of the string, with quotes. Text string // The string, after quote processing. } func (t *Tree) newString(pos Pos, orig, text string) *StringNode { return &StringNode{tr: t, NodeType: NodeString, Pos: pos, Quoted: orig, Text: text} } func (s *StringNode) String() string { return s.Quoted } func (s *StringNode) tree() *Tree { return s.tr } func (s *StringNode) Copy() Node { return s.tr.newString(s.Pos, s.Quoted, s.Text) } // endNode represents an {{end}} action. // It does not appear in the final parse tree. type endNode struct { NodeType Pos tr *Tree } func (t *Tree) newEnd(pos Pos) *endNode { return &endNode{tr: t, NodeType: nodeEnd, Pos: pos} } func (e *endNode) String() string { return "{{end}}" } func (e *endNode) tree() *Tree { return e.tr } func (e *endNode) Copy() Node { return e.tr.newEnd(e.Pos) } // elseNode represents an {{else}} action. Does not appear in the final tree. type elseNode struct { NodeType Pos tr *Tree Line int // The line number in the input (deprecated; kept for compatibility) } func (t *Tree) newElse(pos Pos, line int) *elseNode { return &elseNode{tr: t, NodeType: nodeElse, Pos: pos, Line: line} } func (e *elseNode) Type() NodeType { return nodeElse } func (e *elseNode) String() string { return "{{else}}" } func (e *elseNode) tree() *Tree { return e.tr } func (e *elseNode) Copy() Node { return e.tr.newElse(e.Pos, e.Line) } // BranchNode is the common representation of if, range, and with. type BranchNode struct { NodeType Pos tr *Tree Line int // The line number in the input (deprecated; kept for compatibility) Pipe *PipeNode // The pipeline to be evaluated. List *ListNode // What to execute if the value is non-empty. ElseList *ListNode // What to execute if the value is empty (nil if absent). } func (b *BranchNode) String() string { name := "" switch b.NodeType { case NodeIf: name = "if" case NodeRange: name = "range" case NodeWith: name = "with" default: panic("unknown branch type") } if b.ElseList != nil { return fmt.Sprintf("{{%s %s}}%s{{else}}%s{{end}}", name, b.Pipe, b.List, b.ElseList) } return fmt.Sprintf("{{%s %s}}%s{{end}}", name, b.Pipe, b.List) } func (b *BranchNode) tree() *Tree { return b.tr } func (b *BranchNode) Copy() Node { switch b.NodeType { case NodeIf: return b.tr.newIf(b.Pos, b.Line, b.Pipe, b.List, b.ElseList) case NodeRange: return b.tr.newRange(b.Pos, b.Line, b.Pipe, b.List, b.ElseList) case NodeWith: return b.tr.newWith(b.Pos, b.Line, b.Pipe, b.List, b.ElseList) default: panic("unknown branch type") } } // IfNode represents an {{if}} action and its commands. type IfNode struct { BranchNode } func (t *Tree) newIf(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *IfNode { return &IfNode{BranchNode{tr: t, NodeType: NodeIf, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}} } func (i *IfNode) Copy() Node { return i.tr.newIf(i.Pos, i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList()) } // RangeNode represents a {{range}} action and its commands. type RangeNode struct { BranchNode } func (t *Tree) newRange(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode { return &RangeNode{BranchNode{tr: t, NodeType: NodeRange, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}} } func (r *RangeNode) Copy() Node { return r.tr.newRange(r.Pos, r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList()) } // WithNode represents a {{with}} action and its commands. type WithNode struct { BranchNode } func (t *Tree) newWith(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *WithNode { return &WithNode{BranchNode{tr: t, NodeType: NodeWith, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}} } func (w *WithNode) Copy() Node { return w.tr.newWith(w.Pos, w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList()) } // TemplateNode represents a {{template}} action. type TemplateNode struct { NodeType Pos tr *Tree Line int // The line number in the input (deprecated; kept for compatibility) Name string // The name of the template (unquoted). Pipe *PipeNode // The command to evaluate as dot for the template. } func (t *Tree) newTemplate(pos Pos, line int, name string, pipe *PipeNode) *TemplateNode { return &TemplateNode{tr: t, NodeType: NodeTemplate, Pos: pos, Line: line, Name: name, Pipe: pipe} } func (t *TemplateNode) String() string { if t.Pipe == nil { return fmt.Sprintf("{{template %q}}", t.Name) } return fmt.Sprintf("{{template %q %s}}", t.Name, t.Pipe) } func (t *TemplateNode) tree() *Tree { return t.tr } func (t *TemplateNode) Copy() Node { return t.tr.newTemplate(t.Pos, t.Line, t.Name, t.Pipe.CopyPipe()) } ================================================ FILE: vendor/github.com/alecthomas/template/parse/parse.go ================================================ // 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 parse builds parse trees for templates as defined by text/template // and html/template. Clients should use those packages to construct templates // rather than this one, which provides shared internal data structures not // intended for general use. package parse import ( "bytes" "fmt" "runtime" "strconv" "strings" ) // Tree is the representation of a single parsed template. type Tree struct { Name string // name of the template represented by the tree. ParseName string // name of the top-level template during parsing, for error messages. Root *ListNode // top-level root of the tree. text string // text parsed to create the template (or its parent) // Parsing only; cleared after parse. funcs []map[string]interface{} lex *lexer token [3]item // three-token lookahead for parser. peekCount int vars []string // variables defined at the moment. } // Copy returns a copy of the Tree. Any parsing state is discarded. func (t *Tree) Copy() *Tree { if t == nil { return nil } return &Tree{ Name: t.Name, ParseName: t.ParseName, Root: t.Root.CopyList(), text: t.text, } } // Parse returns a map from template name to parse.Tree, created by parsing the // templates described in the argument string. The top-level template will be // given the specified name. If an error is encountered, parsing stops and an // empty map is returned with the error. func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (treeSet map[string]*Tree, err error) { treeSet = make(map[string]*Tree) t := New(name) t.text = text _, err = t.Parse(text, leftDelim, rightDelim, treeSet, funcs...) return } // next returns the next token. func (t *Tree) next() item { if t.peekCount > 0 { t.peekCount-- } else { t.token[0] = t.lex.nextItem() } return t.token[t.peekCount] } // backup backs the input stream up one token. func (t *Tree) backup() { t.peekCount++ } // backup2 backs the input stream up two tokens. // The zeroth token is already there. func (t *Tree) backup2(t1 item) { t.token[1] = t1 t.peekCount = 2 } // backup3 backs the input stream up three tokens // The zeroth token is already there. func (t *Tree) backup3(t2, t1 item) { // Reverse order: we're pushing back. t.token[1] = t1 t.token[2] = t2 t.peekCount = 3 } // peek returns but does not consume the next token. func (t *Tree) peek() item { if t.peekCount > 0 { return t.token[t.peekCount-1] } t.peekCount = 1 t.token[0] = t.lex.nextItem() return t.token[0] } // nextNonSpace returns the next non-space token. func (t *Tree) nextNonSpace() (token item) { for { token = t.next() if token.typ != itemSpace { break } } return token } // peekNonSpace returns but does not consume the next non-space token. func (t *Tree) peekNonSpace() (token item) { for { token = t.next() if token.typ != itemSpace { break } } t.backup() return token } // Parsing. // New allocates a new parse tree with the given name. func New(name string, funcs ...map[string]interface{}) *Tree { return &Tree{ Name: name, funcs: funcs, } } // ErrorContext returns a textual representation of the location of the node in the input text. // The receiver is only used when the node does not have a pointer to the tree inside, // which can occur in old code. func (t *Tree) ErrorContext(n Node) (location, context string) { pos := int(n.Position()) tree := n.tree() if tree == nil { tree = t } text := tree.text[:pos] byteNum := strings.LastIndex(text, "\n") if byteNum == -1 { byteNum = pos // On first line. } else { byteNum++ // After the newline. byteNum = pos - byteNum } lineNum := 1 + strings.Count(text, "\n") context = n.String() if len(context) > 20 { context = fmt.Sprintf("%.20s...", context) } return fmt.Sprintf("%s:%d:%d", tree.ParseName, lineNum, byteNum), context } // errorf formats the error and terminates processing. func (t *Tree) errorf(format string, args ...interface{}) { t.Root = nil format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.lex.lineNumber(), format) panic(fmt.Errorf(format, args...)) } // error terminates processing. func (t *Tree) error(err error) { t.errorf("%s", err) } // expect consumes the next token and guarantees it has the required type. func (t *Tree) expect(expected itemType, context string) item { token := t.nextNonSpace() if token.typ != expected { t.unexpected(token, context) } return token } // expectOneOf consumes the next token and guarantees it has one of the required types. func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item { token := t.nextNonSpace() if token.typ != expected1 && token.typ != expected2 { t.unexpected(token, context) } return token } // unexpected complains about the token and terminates processing. func (t *Tree) unexpected(token item, context string) { t.errorf("unexpected %s in %s", token, context) } // recover is the handler that turns panics into returns from the top level of Parse. func (t *Tree) recover(errp *error) { e := recover() if e != nil { if _, ok := e.(runtime.Error); ok { panic(e) } if t != nil { t.stopParse() } *errp = e.(error) } return } // startParse initializes the parser, using the lexer. func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer) { t.Root = nil t.lex = lex t.vars = []string{"$"} t.funcs = funcs } // stopParse terminates parsing. func (t *Tree) stopParse() { t.lex = nil t.vars = nil t.funcs = nil } // Parse parses the template definition string to construct a representation of // the template for execution. If either action delimiter string is empty, the // default ("{{" or "}}") is used. Embedded template definitions are added to // the treeSet map. func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) { defer t.recover(&err) t.ParseName = t.Name t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim)) t.text = text t.parse(treeSet) t.add(treeSet) t.stopParse() return t, nil } // add adds tree to the treeSet. func (t *Tree) add(treeSet map[string]*Tree) { tree := treeSet[t.Name] if tree == nil || IsEmptyTree(tree.Root) { treeSet[t.Name] = t return } if !IsEmptyTree(t.Root) { t.errorf("template: multiple definition of template %q", t.Name) } } // IsEmptyTree reports whether this tree (node) is empty of everything but space. func IsEmptyTree(n Node) bool { switch n := n.(type) { case nil: return true case *ActionNode: case *IfNode: case *ListNode: for _, node := range n.Nodes { if !IsEmptyTree(node) { return false } } return true case *RangeNode: case *TemplateNode: case *TextNode: return len(bytes.TrimSpace(n.Text)) == 0 case *WithNode: default: panic("unknown node: " + n.String()) } return false } // parse is the top-level parser for a template, essentially the same // as itemList except it also parses {{define}} actions. // It runs to EOF. func (t *Tree) parse(treeSet map[string]*Tree) (next Node) { t.Root = t.newList(t.peek().pos) for t.peek().typ != itemEOF { if t.peek().typ == itemLeftDelim { delim := t.next() if t.nextNonSpace().typ == itemDefine { newT := New("definition") // name will be updated once we know it. newT.text = t.text newT.ParseName = t.ParseName newT.startParse(t.funcs, t.lex) newT.parseDefinition(treeSet) continue } t.backup2(delim) } n := t.textOrAction() if n.Type() == nodeEnd { t.errorf("unexpected %s", n) } t.Root.append(n) } return nil } // parseDefinition parses a {{define}} ... {{end}} template definition and // installs the definition in the treeSet map. The "define" keyword has already // been scanned. func (t *Tree) parseDefinition(treeSet map[string]*Tree) { const context = "define clause" name := t.expectOneOf(itemString, itemRawString, context) var err error t.Name, err = strconv.Unquote(name.val) if err != nil { t.error(err) } t.expect(itemRightDelim, context) var end Node t.Root, end = t.itemList() if end.Type() != nodeEnd { t.errorf("unexpected %s in %s", end, context) } t.add(treeSet) t.stopParse() } // itemList: // textOrAction* // Terminates at {{end}} or {{else}}, returned separately. func (t *Tree) itemList() (list *ListNode, next Node) { list = t.newList(t.peekNonSpace().pos) for t.peekNonSpace().typ != itemEOF { n := t.textOrAction() switch n.Type() { case nodeEnd, nodeElse: return list, n } list.append(n) } t.errorf("unexpected EOF") return } // textOrAction: // text | action func (t *Tree) textOrAction() Node { switch token := t.nextNonSpace(); token.typ { case itemElideNewline: return t.elideNewline() case itemText: return t.newText(token.pos, token.val) case itemLeftDelim: return t.action() default: t.unexpected(token, "input") } return nil } // elideNewline: // Remove newlines trailing rightDelim if \\ is present. func (t *Tree) elideNewline() Node { token := t.peek() if token.typ != itemText { t.unexpected(token, "input") return nil } t.next() stripped := strings.TrimLeft(token.val, "\n\r") diff := len(token.val) - len(stripped) if diff > 0 { // This is a bit nasty. We mutate the token in-place to remove // preceding newlines. token.pos += Pos(diff) token.val = stripped } return t.newText(token.pos, token.val) } // Action: // control // command ("|" command)* // Left delim is past. Now get actions. // First word could be a keyword such as range. func (t *Tree) action() (n Node) { switch token := t.nextNonSpace(); token.typ { case itemElse: return t.elseControl() case itemEnd: return t.endControl() case itemIf: return t.ifControl() case itemRange: return t.rangeControl() case itemTemplate: return t.templateControl() case itemWith: return t.withControl() } t.backup() // Do not pop variables; they persist until "end". return t.newAction(t.peek().pos, t.lex.lineNumber(), t.pipeline("command")) } // Pipeline: // declarations? command ('|' command)* func (t *Tree) pipeline(context string) (pipe *PipeNode) { var decl []*VariableNode pos := t.peekNonSpace().pos // Are there declarations? for { if v := t.peekNonSpace(); v.typ == itemVariable { t.next() // Since space is a token, we need 3-token look-ahead here in the worst case: // in "$x foo" we need to read "foo" (as opposed to ":=") to know that $x is an // argument variable rather than a declaration. So remember the token // adjacent to the variable so we can push it back if necessary. tokenAfterVariable := t.peek() if next := t.peekNonSpace(); next.typ == itemColonEquals || (next.typ == itemChar && next.val == ",") { t.nextNonSpace() variable := t.newVariable(v.pos, v.val) decl = append(decl, variable) t.vars = append(t.vars, v.val) if next.typ == itemChar && next.val == "," { if context == "range" && len(decl) < 2 { continue } t.errorf("too many declarations in %s", context) } } else if tokenAfterVariable.typ == itemSpace { t.backup3(v, tokenAfterVariable) } else { t.backup2(v) } } break } pipe = t.newPipeline(pos, t.lex.lineNumber(), decl) for { switch token := t.nextNonSpace(); token.typ { case itemRightDelim, itemRightParen: if len(pipe.Cmds) == 0 { t.errorf("missing value for %s", context) } if token.typ == itemRightParen { t.backup() } return case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier, itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen: t.backup() pipe.append(t.command()) default: t.unexpected(token, context) } } } func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) { defer t.popVars(len(t.vars)) line = t.lex.lineNumber() pipe = t.pipeline(context) var next Node list, next = t.itemList() switch next.Type() { case nodeEnd: //done case nodeElse: if allowElseIf { // Special case for "else if". If the "else" is followed immediately by an "if", // the elseControl will have left the "if" token pending. Treat // {{if a}}_{{else if b}}_{{end}} // as // {{if a}}_{{else}}{{if b}}_{{end}}{{end}}. // To do this, parse the if as usual and stop at it {{end}}; the subsequent{{end}} // is assumed. This technique works even for long if-else-if chains. // TODO: Should we allow else-if in with and range? if t.peek().typ == itemIf { t.next() // Consume the "if" token. elseList = t.newList(next.Position()) elseList.append(t.ifControl()) // Do not consume the next item - only one {{end}} required. break } } elseList, next = t.itemList() if next.Type() != nodeEnd { t.errorf("expected end; found %s", next) } } return pipe.Position(), line, pipe, list, elseList } // If: // {{if pipeline}} itemList {{end}} // {{if pipeline}} itemList {{else}} itemList {{end}} // If keyword is past. func (t *Tree) ifControl() Node { return t.newIf(t.parseControl(true, "if")) } // Range: // {{range pipeline}} itemList {{end}} // {{range pipeline}} itemList {{else}} itemList {{end}} // Range keyword is past. func (t *Tree) rangeControl() Node { return t.newRange(t.parseControl(false, "range")) } // With: // {{with pipeline}} itemList {{end}} // {{with pipeline}} itemList {{else}} itemList {{end}} // If keyword is past. func (t *Tree) withControl() Node { return t.newWith(t.parseControl(false, "with")) } // End: // {{end}} // End keyword is past. func (t *Tree) endControl() Node { return t.newEnd(t.expect(itemRightDelim, "end").pos) } // Else: // {{else}} // Else keyword is past. func (t *Tree) elseControl() Node { // Special case for "else if". peek := t.peekNonSpace() if peek.typ == itemIf { // We see "{{else if ... " but in effect rewrite it to {{else}}{{if ... ". return t.newElse(peek.pos, t.lex.lineNumber()) } return t.newElse(t.expect(itemRightDelim, "else").pos, t.lex.lineNumber()) } // Template: // {{template stringValue pipeline}} // Template keyword is past. The name must be something that can evaluate // to a string. func (t *Tree) templateControl() Node { var name string token := t.nextNonSpace() switch token.typ { case itemString, itemRawString: s, err := strconv.Unquote(token.val) if err != nil { t.error(err) } name = s default: t.unexpected(token, "template invocation") } var pipe *PipeNode if t.nextNonSpace().typ != itemRightDelim { t.backup() // Do not pop variables; they persist until "end". pipe = t.pipeline("template") } return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe) } // command: // operand (space operand)* // space-separated arguments up to a pipeline character or right delimiter. // we consume the pipe character but leave the right delim to terminate the action. func (t *Tree) command() *CommandNode { cmd := t.newCommand(t.peekNonSpace().pos) for { t.peekNonSpace() // skip leading spaces. operand := t.operand() if operand != nil { cmd.append(operand) } switch token := t.next(); token.typ { case itemSpace: continue case itemError: t.errorf("%s", token.val) case itemRightDelim, itemRightParen: t.backup() case itemPipe: default: t.errorf("unexpected %s in operand; missing space?", token) } break } if len(cmd.Args) == 0 { t.errorf("empty command") } return cmd } // operand: // term .Field* // An operand is a space-separated component of a command, // a term possibly followed by field accesses. // A nil return means the next item is not an operand. func (t *Tree) operand() Node { node := t.term() if node == nil { return nil } if t.peek().typ == itemField { chain := t.newChain(t.peek().pos, node) for t.peek().typ == itemField { chain.Add(t.next().val) } // Compatibility with original API: If the term is of type NodeField // or NodeVariable, just put more fields on the original. // Otherwise, keep the Chain node. // TODO: Switch to Chains always when we can. switch node.Type() { case NodeField: node = t.newField(chain.Position(), chain.String()) case NodeVariable: node = t.newVariable(chain.Position(), chain.String()) default: node = chain } } return node } // term: // literal (number, string, nil, boolean) // function (identifier) // . // .Field // $ // '(' pipeline ')' // A term is a simple "expression". // A nil return means the next item is not a term. func (t *Tree) term() Node { switch token := t.nextNonSpace(); token.typ { case itemError: t.errorf("%s", token.val) case itemIdentifier: if !t.hasFunction(token.val) { t.errorf("function %q not defined", token.val) } return NewIdentifier(token.val).SetTree(t).SetPos(token.pos) case itemDot: return t.newDot(token.pos) case itemNil: return t.newNil(token.pos) case itemVariable: return t.useVar(token.pos, token.val) case itemField: return t.newField(token.pos, token.val) case itemBool: return t.newBool(token.pos, token.val == "true") case itemCharConstant, itemComplex, itemNumber: number, err := t.newNumber(token.pos, token.val, token.typ) if err != nil { t.error(err) } return number case itemLeftParen: pipe := t.pipeline("parenthesized pipeline") if token := t.next(); token.typ != itemRightParen { t.errorf("unclosed right paren: unexpected %s", token) } return pipe case itemString, itemRawString: s, err := strconv.Unquote(token.val) if err != nil { t.error(err) } return t.newString(token.pos, token.val, s) } t.backup() return nil } // hasFunction reports if a function name exists in the Tree's maps. func (t *Tree) hasFunction(name string) bool { for _, funcMap := range t.funcs { if funcMap == nil { continue } if funcMap[name] != nil { return true } } return false } // popVars trims the variable list to the specified length func (t *Tree) popVars(n int) { t.vars = t.vars[:n] } // useVar returns a node for a variable reference. It errors if the // variable is not defined. func (t *Tree) useVar(pos Pos, name string) Node { v := t.newVariable(pos, name) for _, varName := range t.vars { if varName == v.Ident[0] { return v } } t.errorf("undefined variable %q", v.Ident[0]) return nil } ================================================ FILE: vendor/github.com/alecthomas/template/template.go ================================================ // 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 template import ( "fmt" "reflect" "github.com/alecthomas/template/parse" ) // common holds the information shared by related templates. type common struct { tmpl map[string]*Template // We use two maps, one for parsing and one for execution. // This separation makes the API cleaner since it doesn't // expose reflection to the client. parseFuncs FuncMap execFuncs map[string]reflect.Value } // Template is the representation of a parsed template. The *parse.Tree // field is exported only for use by html/template and should be treated // as unexported by all other clients. type Template struct { name string *parse.Tree *common leftDelim string rightDelim string } // New allocates a new template with the given name. func New(name string) *Template { return &Template{ name: name, } } // Name returns the name of the template. func (t *Template) Name() string { return t.name } // New allocates a new template associated with the given one and with the same // delimiters. The association, which is transitive, allows one template to // invoke another with a {{template}} action. func (t *Template) New(name string) *Template { t.init() return &Template{ name: name, common: t.common, leftDelim: t.leftDelim, rightDelim: t.rightDelim, } } func (t *Template) init() { if t.common == nil { t.common = new(common) t.tmpl = make(map[string]*Template) t.parseFuncs = make(FuncMap) t.execFuncs = make(map[string]reflect.Value) } } // Clone returns a duplicate of the template, including all associated // templates. The actual representation is not copied, but the name space of // associated templates is, so further calls to Parse in the copy will add // templates to the copy but not to the original. Clone can be used to prepare // common templates and use them with variant definitions for other templates // by adding the variants after the clone is made. func (t *Template) Clone() (*Template, error) { nt := t.copy(nil) nt.init() nt.tmpl[t.name] = nt for k, v := range t.tmpl { if k == t.name { // Already installed. continue } // The associated templates share nt's common structure. tmpl := v.copy(nt.common) nt.tmpl[k] = tmpl } for k, v := range t.parseFuncs { nt.parseFuncs[k] = v } for k, v := range t.execFuncs { nt.execFuncs[k] = v } return nt, nil } // copy returns a shallow copy of t, with common set to the argument. func (t *Template) copy(c *common) *Template { nt := New(t.name) nt.Tree = t.Tree nt.common = c nt.leftDelim = t.leftDelim nt.rightDelim = t.rightDelim return nt } // AddParseTree creates a new template with the name and parse tree // and associates it with t. func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) { if t.common != nil && t.tmpl[name] != nil { return nil, fmt.Errorf("template: redefinition of template %q", name) } nt := t.New(name) nt.Tree = tree t.tmpl[name] = nt return nt, nil } // Templates returns a slice of the templates associated with t, including t // itself. func (t *Template) Templates() []*Template { if t.common == nil { return nil } // Return a slice so we don't expose the map. m := make([]*Template, 0, len(t.tmpl)) for _, v := range t.tmpl { m = append(m, v) } return m } // Delims sets the action delimiters to the specified strings, to be used in // subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template // definitions will inherit the settings. An empty delimiter stands for the // corresponding default: {{ or }}. // The return value is the template, so calls can be chained. func (t *Template) Delims(left, right string) *Template { t.leftDelim = left t.rightDelim = right return t } // Funcs adds the elements of the argument map to the template's function map. // It panics if a value in the map is not a function with appropriate return // type. However, it is legal to overwrite elements of the map. The return // value is the template, so calls can be chained. func (t *Template) Funcs(funcMap FuncMap) *Template { t.init() addValueFuncs(t.execFuncs, funcMap) addFuncs(t.parseFuncs, funcMap) return t } // Lookup returns the template with the given name that is associated with t, // or nil if there is no such template. func (t *Template) Lookup(name string) *Template { if t.common == nil { return nil } return t.tmpl[name] } // Parse parses a string into a template. Nested template definitions will be // associated with the top-level template t. Parse may be called multiple times // to parse definitions of templates to associate with t. It is an error if a // resulting template is non-empty (contains content other than template // definitions) and would replace a non-empty template with the same name. // (In multiple calls to Parse with the same receiver template, only one call // can contain text other than space, comments, and template definitions.) func (t *Template) Parse(text string) (*Template, error) { t.init() trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins) if err != nil { return nil, err } // Add the newly parsed trees, including the one for t, into our common structure. for name, tree := range trees { // If the name we parsed is the name of this template, overwrite this template. // The associate method checks it's not a redefinition. tmpl := t if name != t.name { tmpl = t.New(name) } // Even if t == tmpl, we need to install it in the common.tmpl map. if replace, err := t.associate(tmpl, tree); err != nil { return nil, err } else if replace { tmpl.Tree = tree } tmpl.leftDelim = t.leftDelim tmpl.rightDelim = t.rightDelim } return t, nil } // associate installs the new template into the group of templates associated // with t. It is an error to reuse a name except to overwrite an empty // template. The two are already known to share the common structure. // The boolean return value reports wither to store this tree as t.Tree. func (t *Template) associate(new *Template, tree *parse.Tree) (bool, error) { if new.common != t.common { panic("internal error: associate not common") } name := new.name if old := t.tmpl[name]; old != nil { oldIsEmpty := parse.IsEmptyTree(old.Root) newIsEmpty := parse.IsEmptyTree(tree.Root) if newIsEmpty { // Whether old is empty or not, new is empty; no reason to replace old. return false, nil } if !oldIsEmpty { return false, fmt.Errorf("template: redefinition of template %q", name) } } t.tmpl[name] = new return true, nil } ================================================ FILE: vendor/github.com/astaxie/beego/LICENSE ================================================ Copyright 2014 astaxie Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/github.com/astaxie/beego/validation/README.md ================================================ validation ============== validation is a form validation for a data validation and error collecting using Go. ## Installation and tests Install: go get github.com/astaxie/beego/validation Test: go test github.com/astaxie/beego/validation ## Example Direct Use: import ( "github.com/astaxie/beego/validation" "log" ) type User struct { Name string Age int } func main() { u := User{"man", 40} valid := validation.Validation{} valid.Required(u.Name, "name") valid.MaxSize(u.Name, 15, "nameMax") valid.Range(u.Age, 0, 140, "age") if valid.HasErrors() { // validation does not pass // print invalid message for _, err := range valid.Errors { log.Println(err.Key, err.Message) } } // or use like this if v := valid.Max(u.Age, 140, "ageMax"); !v.Ok { log.Println(v.Error.Key, v.Error.Message) } } Struct Tag Use: import ( "github.com/astaxie/beego/validation" ) // validation function follow with "valid" tag // functions divide with ";" // parameters in parentheses "()" and divide with "," // Match function's pattern string must in "//" type user struct { Id int Name string `valid:"Required;Match(/^(test)?\\w*@;com$/)"` Age int `valid:"Required;Range(1, 140)"` } func main() { valid := validation.Validation{} // ignore empty field valid // see CanSkipFuncs // valid := validation.Validation{RequiredFirst:true} u := user{Name: "test", Age: 40} b, err := valid.Valid(u) if err != nil { // handle error } if !b { // validation does not pass // blabla... } } Use custom function: import ( "github.com/astaxie/beego/validation" ) type user struct { Id int Name string `valid:"Required;IsMe"` Age int `valid:"Required;Range(1, 140)"` } func IsMe(v *validation.Validation, obj interface{}, key string) { name, ok:= obj.(string) if !ok { // wrong use case? return } if name != "me" { // valid false v.SetError("Name", "is not me!") } } func main() { valid := validation.Validation{} if err := validation.AddCustomFunc("IsMe", IsMe); err != nil { // hadle error } u := user{Name: "test", Age: 40} b, err := valid.Valid(u) if err != nil { // handle error } if !b { // validation does not pass // blabla... } } Struct Tag Functions: Required Min(min int) Max(max int) Range(min, max int) MinSize(min int) MaxSize(max int) Length(length int) Alpha Numeric AlphaNumeric Match(pattern string) AlphaDash Email IP Base64 Mobile Tel Phone ZipCode ## LICENSE BSD License http://creativecommons.org/licenses/BSD/ ================================================ FILE: vendor/github.com/astaxie/beego/validation/util.go ================================================ // Copyright 2014 beego Author. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package validation import ( "fmt" "reflect" "regexp" "strconv" "strings" ) const ( // ValidTag struct tag ValidTag = "valid" wordsize = 32 << (^uint(0) >> 32 & 1) ) var ( // key: function name // value: the number of parameters funcs = make(Funcs) // doesn't belong to validation functions unFuncs = map[string]bool{ "Clear": true, "HasErrors": true, "ErrorMap": true, "Error": true, "apply": true, "Check": true, "Valid": true, "NoMatch": true, } // ErrInt64On32 show 32 bit platform not support int64 ErrInt64On32 = fmt.Errorf("not support int64 on 32-bit platform") ) func init() { v := &Validation{} t := reflect.TypeOf(v) for i := 0; i < t.NumMethod(); i++ { m := t.Method(i) if !unFuncs[m.Name] { funcs[m.Name] = m.Func } } } // CustomFunc is for custom validate function type CustomFunc func(v *Validation, obj interface{}, key string) // AddCustomFunc Add a custom function to validation // The name can not be: // Clear // HasErrors // ErrorMap // Error // Check // Valid // NoMatch // If the name is same with exists function, it will replace the origin valid function func AddCustomFunc(name string, f CustomFunc) error { if unFuncs[name] { return fmt.Errorf("invalid function name: %s", name) } funcs[name] = reflect.ValueOf(f) return nil } // ValidFunc Valid function type type ValidFunc struct { Name string Params []interface{} } // Funcs Validate function map type Funcs map[string]reflect.Value // Call validate values with named type string func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) { defer func() { if r := recover(); r != nil { err = fmt.Errorf("%v", r) } }() if _, ok := f[name]; !ok { err = fmt.Errorf("%s does not exist", name) return } if len(params) != f[name].Type().NumIn() { err = fmt.Errorf("The number of params is not adapted") return } in := make([]reflect.Value, len(params)) for k, param := range params { in[k] = reflect.ValueOf(param) } result = f[name].Call(in) return } func isStruct(t reflect.Type) bool { return t.Kind() == reflect.Struct } func isStructPtr(t reflect.Type) bool { return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct } func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) { tag := f.Tag.Get(ValidTag) if len(tag) == 0 { return } if vfs, tag, err = getRegFuncs(tag, f.Name); err != nil { return } fs := strings.Split(tag, ";") for _, vfunc := range fs { var vf ValidFunc if len(vfunc) == 0 { continue } vf, err = parseFunc(vfunc, f.Name) if err != nil { return } vfs = append(vfs, vf) } return } // Get Match function // May be get NoMatch function in the future func getRegFuncs(tag, key string) (vfs []ValidFunc, str string, err error) { tag = strings.TrimSpace(tag) index := strings.Index(tag, "Match(/") if index == -1 { str = tag return } end := strings.LastIndex(tag, "/)") if end < index { err = fmt.Errorf("invalid Match function") return } reg, err := regexp.Compile(tag[index+len("Match(/") : end]) if err != nil { return } vfs = []ValidFunc{{"Match", []interface{}{reg, key + ".Match"}}} str = strings.TrimSpace(tag[:index]) + strings.TrimSpace(tag[end+len("/)"):]) return } func parseFunc(vfunc, key string) (v ValidFunc, err error) { defer func() { if r := recover(); r != nil { err = fmt.Errorf("%v", r) } }() vfunc = strings.TrimSpace(vfunc) start := strings.Index(vfunc, "(") var num int // doesn't need parameter valid function if start == -1 { if num, err = numIn(vfunc); err != nil { return } if num != 0 { err = fmt.Errorf("%s require %d parameters", vfunc, num) return } v = ValidFunc{vfunc, []interface{}{key + "." + vfunc}} return } end := strings.Index(vfunc, ")") if end == -1 { err = fmt.Errorf("invalid valid function") return } name := strings.TrimSpace(vfunc[:start]) if num, err = numIn(name); err != nil { return } params := strings.Split(vfunc[start+1:end], ",") // the num of param must be equal if num != len(params) { err = fmt.Errorf("%s require %d parameters", name, num) return } tParams, err := trim(name, key+"."+name, params) if err != nil { return } v = ValidFunc{name, tParams} return } func numIn(name string) (num int, err error) { fn, ok := funcs[name] if !ok { err = fmt.Errorf("doesn't exsits %s valid function", name) return } // sub *Validation obj and key num = fn.Type().NumIn() - 3 return } func trim(name, key string, s []string) (ts []interface{}, err error) { ts = make([]interface{}, len(s), len(s)+1) fn, ok := funcs[name] if !ok { err = fmt.Errorf("doesn't exsits %s valid function", name) return } for i := 0; i < len(s); i++ { var param interface{} // skip *Validation and obj params if param, err = parseParam(fn.Type().In(i+2), strings.TrimSpace(s[i])); err != nil { return } ts[i] = param } ts = append(ts, key) return } // modify the parameters's type to adapt the function input parameters' type func parseParam(t reflect.Type, s string) (i interface{}, err error) { switch t.Kind() { case reflect.Int: i, err = strconv.Atoi(s) case reflect.Int64: if wordsize == 32 { return nil, ErrInt64On32 } i, err = strconv.ParseInt(s, 10, 64) case reflect.Int32: var v int64 v, err = strconv.ParseInt(s, 10, 32) if err == nil { i = int32(v) } case reflect.Int16: var v int64 v, err = strconv.ParseInt(s, 10, 16) if err == nil { i = int16(v) } case reflect.Int8: var v int64 v, err = strconv.ParseInt(s, 10, 8) if err == nil { i = int8(v) } case reflect.String: i = s case reflect.Ptr: if t.Elem().String() != "regexp.Regexp" { err = fmt.Errorf("not support %s", t.Elem().String()) return } i, err = regexp.Compile(s) default: err = fmt.Errorf("not support %s", t.Kind().String()) } return } func mergeParam(v *Validation, obj interface{}, params []interface{}) []interface{} { return append([]interface{}{v, obj}, params...) } ================================================ FILE: vendor/github.com/astaxie/beego/validation/validation.go ================================================ // Copyright 2014 beego Author. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package validation for validations // // import ( // "github.com/astaxie/beego/validation" // "log" // ) // // type User struct { // Name string // Age int // } // // func main() { // u := User{"man", 40} // valid := validation.Validation{} // valid.Required(u.Name, "name") // valid.MaxSize(u.Name, 15, "nameMax") // valid.Range(u.Age, 0, 140, "age") // if valid.HasErrors() { // // validation does not pass // // print invalid message // for _, err := range valid.Errors { // log.Println(err.Key, err.Message) // } // } // // or use like this // if v := valid.Max(u.Age, 140, "ageMax"); !v.Ok { // log.Println(v.Error.Key, v.Error.Message) // } // } // // more info: http://beego.me/docs/mvc/controller/validation.md package validation import ( "fmt" "reflect" "regexp" "strings" ) // ValidFormer valid interface type ValidFormer interface { Valid(*Validation) } // Error show the error type Error struct { Message, Key, Name, Field, Tmpl string Value interface{} LimitValue interface{} } // String Returns the Message. func (e *Error) String() string { if e == nil { return "" } return e.Message } // Implement Error interface. // Return e.String() func (e *Error) Error() string { return e.String() } // Result is returned from every validation method. // It provides an indication of success, and a pointer to the Error (if any). type Result struct { Error *Error Ok bool } // Key Get Result by given key string. func (r *Result) Key(key string) *Result { if r.Error != nil { r.Error.Key = key } return r } // Message Set Result message by string or format string with args func (r *Result) Message(message string, args ...interface{}) *Result { if r.Error != nil { if len(args) == 0 { r.Error.Message = message } else { r.Error.Message = fmt.Sprintf(message, args...) } } return r } // A Validation context manages data validation and error messages. type Validation struct { // if this field set true, in struct tag valid // if the struct field vale is empty // it will skip those valid functions, see CanSkipFuncs RequiredFirst bool Errors []*Error ErrorsMap map[string][]*Error } // Clear Clean all ValidationError. func (v *Validation) Clear() { v.Errors = []*Error{} v.ErrorsMap = nil } // HasErrors Has ValidationError nor not. func (v *Validation) HasErrors() bool { return len(v.Errors) > 0 } // ErrorMap Return the errors mapped by key. // If there are multiple validation errors associated with a single key, the // first one "wins". (Typically the first validation will be the more basic). func (v *Validation) ErrorMap() map[string][]*Error { return v.ErrorsMap } // Error Add an error to the validation context. func (v *Validation) Error(message string, args ...interface{}) *Result { result := (&Result{ Ok: false, Error: &Error{}, }).Message(message, args...) v.Errors = append(v.Errors, result.Error) return result } // Required Test that the argument is non-nil and non-empty (if string or list) func (v *Validation) Required(obj interface{}, key string) *Result { return v.apply(Required{key}, obj) } // Min Test that the obj is greater than min if obj's type is int func (v *Validation) Min(obj interface{}, min int, key string) *Result { return v.apply(Min{min, key}, obj) } // Max Test that the obj is less than max if obj's type is int func (v *Validation) Max(obj interface{}, max int, key string) *Result { return v.apply(Max{max, key}, obj) } // Range Test that the obj is between mni and max if obj's type is int func (v *Validation) Range(obj interface{}, min, max int, key string) *Result { return v.apply(Range{Min{Min: min}, Max{Max: max}, key}, obj) } // MinSize Test that the obj is longer than min size if type is string or slice func (v *Validation) MinSize(obj interface{}, min int, key string) *Result { return v.apply(MinSize{min, key}, obj) } // MaxSize Test that the obj is shorter than max size if type is string or slice func (v *Validation) MaxSize(obj interface{}, max int, key string) *Result { return v.apply(MaxSize{max, key}, obj) } // Length Test that the obj is same length to n if type is string or slice func (v *Validation) Length(obj interface{}, n int, key string) *Result { return v.apply(Length{n, key}, obj) } // Alpha Test that the obj is [a-zA-Z] if type is string func (v *Validation) Alpha(obj interface{}, key string) *Result { return v.apply(Alpha{key}, obj) } // Numeric Test that the obj is [0-9] if type is string func (v *Validation) Numeric(obj interface{}, key string) *Result { return v.apply(Numeric{key}, obj) } // AlphaNumeric Test that the obj is [0-9a-zA-Z] if type is string func (v *Validation) AlphaNumeric(obj interface{}, key string) *Result { return v.apply(AlphaNumeric{key}, obj) } // Match Test that the obj matches regexp if type is string func (v *Validation) Match(obj interface{}, regex *regexp.Regexp, key string) *Result { return v.apply(Match{regex, key}, obj) } // NoMatch Test that the obj doesn't match regexp if type is string func (v *Validation) NoMatch(obj interface{}, regex *regexp.Regexp, key string) *Result { return v.apply(NoMatch{Match{Regexp: regex}, key}, obj) } // AlphaDash Test that the obj is [0-9a-zA-Z_-] if type is string func (v *Validation) AlphaDash(obj interface{}, key string) *Result { return v.apply(AlphaDash{NoMatch{Match: Match{Regexp: alphaDashPattern}}, key}, obj) } // Email Test that the obj is email address if type is string func (v *Validation) Email(obj interface{}, key string) *Result { return v.apply(Email{Match{Regexp: emailPattern}, key}, obj) } // IP Test that the obj is IP address if type is string func (v *Validation) IP(obj interface{}, key string) *Result { return v.apply(IP{Match{Regexp: ipPattern}, key}, obj) } // Base64 Test that the obj is base64 encoded if type is string func (v *Validation) Base64(obj interface{}, key string) *Result { return v.apply(Base64{Match{Regexp: base64Pattern}, key}, obj) } // Mobile Test that the obj is chinese mobile number if type is string func (v *Validation) Mobile(obj interface{}, key string) *Result { return v.apply(Mobile{Match{Regexp: mobilePattern}, key}, obj) } // Tel Test that the obj is chinese telephone number if type is string func (v *Validation) Tel(obj interface{}, key string) *Result { return v.apply(Tel{Match{Regexp: telPattern}, key}, obj) } // Phone Test that the obj is chinese mobile or telephone number if type is string func (v *Validation) Phone(obj interface{}, key string) *Result { return v.apply(Phone{Mobile{Match: Match{Regexp: mobilePattern}}, Tel{Match: Match{Regexp: telPattern}}, key}, obj) } // ZipCode Test that the obj is chinese zip code if type is string func (v *Validation) ZipCode(obj interface{}, key string) *Result { return v.apply(ZipCode{Match{Regexp: zipCodePattern}, key}, obj) } func (v *Validation) apply(chk Validator, obj interface{}) *Result { if chk.IsSatisfied(obj) { return &Result{Ok: true} } // Add the error to the validation context. key := chk.GetKey() Name := key Field := "" parts := strings.Split(key, ".") if len(parts) == 2 { Field = parts[0] Name = parts[1] } err := &Error{ Message: chk.DefaultMessage(), Key: key, Name: Name, Field: Field, Value: obj, Tmpl: MessageTmpls[Name], LimitValue: chk.GetLimitValue(), } v.setError(err) // Also return it in the result. return &Result{ Ok: false, Error: err, } } // AddError adds independent error message for the provided key func (v *Validation) AddError(key, message string) { Name := key Field := "" parts := strings.Split(key, ".") if len(parts) == 2 { Field = parts[0] Name = parts[1] } err := &Error{ Message: message, Key: key, Name: Name, Field: Field, } v.setError(err) } func (v *Validation) setError(err *Error) { v.Errors = append(v.Errors, err) if v.ErrorsMap == nil { v.ErrorsMap = make(map[string][]*Error) } if _, ok := v.ErrorsMap[err.Field]; !ok { v.ErrorsMap[err.Field] = []*Error{} } v.ErrorsMap[err.Field] = append(v.ErrorsMap[err.Field], err) } // SetError Set error message for one field in ValidationError func (v *Validation) SetError(fieldName string, errMsg string) *Error { err := &Error{Key: fieldName, Field: fieldName, Tmpl: errMsg, Message: errMsg} v.setError(err) return err } // Check Apply a group of validators to a field, in order, and return the // ValidationResult from the first one that fails, or the last one that // succeeds. func (v *Validation) Check(obj interface{}, checks ...Validator) *Result { var result *Result for _, check := range checks { result = v.apply(check, obj) if !result.Ok { return result } } return result } // Valid Validate a struct. // the obj parameter must be a struct or a struct pointer func (v *Validation) Valid(obj interface{}) (b bool, err error) { objT := reflect.TypeOf(obj) objV := reflect.ValueOf(obj) switch { case isStruct(objT): case isStructPtr(objT): objT = objT.Elem() objV = objV.Elem() default: err = fmt.Errorf("%v must be a struct or a struct pointer", obj) return } for i := 0; i < objT.NumField(); i++ { var vfs []ValidFunc if vfs, err = getValidFuncs(objT.Field(i)); err != nil { return } var hasReuired bool for _, vf := range vfs { if vf.Name == "Required" { hasReuired = true } if !hasReuired && v.RequiredFirst && len(objV.Field(i).String()) == 0 { if _, ok := CanSkipFuncs[vf.Name]; ok { continue } } if _, err = funcs.Call(vf.Name, mergeParam(v, objV.Field(i).Interface(), vf.Params)...); err != nil { return } } } if !v.HasErrors() { if form, ok := obj.(ValidFormer); ok { form.Valid(v) } } return !v.HasErrors(), nil } // RecursiveValid Recursively validate a struct. // Step1: Validate by v.Valid // Step2: If pass on step1, then reflect obj's fields // Step3: Do the Recursively validation to all struct or struct pointer fields func (v *Validation) RecursiveValid(objc interface{}) (bool, error) { //Step 1: validate obj itself firstly // fails if objc is not struct pass, err := v.Valid(objc) if err != nil || !pass { return pass, err // Stop recursive validation } // Step 2: Validate struct's struct fields objT := reflect.TypeOf(objc) objV := reflect.ValueOf(objc) if isStructPtr(objT) { objT = objT.Elem() objV = objV.Elem() } for i := 0; i < objT.NumField(); i++ { t := objT.Field(i).Type // Recursive applies to struct or pointer to structs fields if isStruct(t) || isStructPtr(t) { // Step 3: do the recursive validation // Only valid the Public field recursively if objV.Field(i).CanInterface() { pass, err = v.RecursiveValid(objV.Field(i).Interface()) } } } return pass, err } ================================================ FILE: vendor/github.com/astaxie/beego/validation/validators.go ================================================ // Copyright 2014 beego Author. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package validation import ( "fmt" "reflect" "regexp" "strings" "time" "unicode/utf8" ) // CanSkipFuncs will skip valid if RequiredFirst is true and the struct field's value is empty var CanSkipFuncs = map[string]struct{}{ "Email": {}, "IP": {}, "Mobile": {}, "Tel": {}, "Phone": {}, "ZipCode": {}, } // MessageTmpls store commond validate template var MessageTmpls = map[string]string{ "Required": "Can not be empty", "Min": "Minimum is %d", "Max": "Maximum is %d", "Range": "Range is %d to %d", "MinSize": "Minimum size is %d", "MaxSize": "Maximum size is %d", "Length": "Required length is %d", "Alpha": "Must be valid alpha characters", "Numeric": "Must be valid numeric characters", "AlphaNumeric": "Must be valid alpha or numeric characters", "Match": "Must match %s", "NoMatch": "Must not match %s", "AlphaDash": "Must be valid alpha or numeric or dash(-_) characters", "Email": "Must be a valid email address", "IP": "Must be a valid ip address", "Base64": "Must be valid base64 characters", "Mobile": "Must be valid mobile number", "Tel": "Must be valid telephone number", "Phone": "Must be valid telephone or mobile phone number", "ZipCode": "Must be valid zipcode", } // SetDefaultMessage set default messages // if not set, the default messages are // "Required": "Can not be empty", // "Min": "Minimum is %d", // "Max": "Maximum is %d", // "Range": "Range is %d to %d", // "MinSize": "Minimum size is %d", // "MaxSize": "Maximum size is %d", // "Length": "Required length is %d", // "Alpha": "Must be valid alpha characters", // "Numeric": "Must be valid numeric characters", // "AlphaNumeric": "Must be valid alpha or numeric characters", // "Match": "Must match %s", // "NoMatch": "Must not match %s", // "AlphaDash": "Must be valid alpha or numeric or dash(-_) characters", // "Email": "Must be a valid email address", // "IP": "Must be a valid ip address", // "Base64": "Must be valid base64 characters", // "Mobile": "Must be valid mobile number", // "Tel": "Must be valid telephone number", // "Phone": "Must be valid telephone or mobile phone number", // "ZipCode": "Must be valid zipcode", func SetDefaultMessage(msg map[string]string) { if len(msg) == 0 { return } for name := range msg { MessageTmpls[name] = msg[name] } } // Validator interface type Validator interface { IsSatisfied(interface{}) bool DefaultMessage() string GetKey() string GetLimitValue() interface{} } // Required struct type Required struct { Key string } // IsSatisfied judge whether obj has value func (r Required) IsSatisfied(obj interface{}) bool { if obj == nil { return false } if str, ok := obj.(string); ok { return len(strings.TrimSpace(str)) > 0 } if _, ok := obj.(bool); ok { return true } if i, ok := obj.(int); ok { return i != 0 } if i, ok := obj.(uint); ok { return i != 0 } if i, ok := obj.(int8); ok { return i != 0 } if i, ok := obj.(uint8); ok { return i != 0 } if i, ok := obj.(int16); ok { return i != 0 } if i, ok := obj.(uint16); ok { return i != 0 } if i, ok := obj.(uint32); ok { return i != 0 } if i, ok := obj.(int32); ok { return i != 0 } if i, ok := obj.(int64); ok { return i != 0 } if i, ok := obj.(uint64); ok { return i != 0 } if t, ok := obj.(time.Time); ok { return !t.IsZero() } v := reflect.ValueOf(obj) if v.Kind() == reflect.Slice { return v.Len() > 0 } return true } // DefaultMessage return the default error message func (r Required) DefaultMessage() string { return MessageTmpls["Required"] } // GetKey return the r.Key func (r Required) GetKey() string { return r.Key } // GetLimitValue return nil now func (r Required) GetLimitValue() interface{} { return nil } // Min check struct type Min struct { Min int Key string } // IsSatisfied judge whether obj is valid // not support int64 on 32-bit platform func (m Min) IsSatisfied(obj interface{}) bool { var v int switch obj.(type) { case int64: if wordsize == 32 { return false } v = int(obj.(int64)) case int: v = obj.(int) case int32: v = int(obj.(int32)) case int16: v = int(obj.(int16)) case int8: v = int(obj.(int8)) default: return false } return v >= m.Min } // DefaultMessage return the default min error message func (m Min) DefaultMessage() string { return fmt.Sprintf(MessageTmpls["Min"], m.Min) } // GetKey return the m.Key func (m Min) GetKey() string { return m.Key } // GetLimitValue return the limit value, Min func (m Min) GetLimitValue() interface{} { return m.Min } // Max validate struct type Max struct { Max int Key string } // IsSatisfied judge whether obj is valid // not support int64 on 32-bit platform func (m Max) IsSatisfied(obj interface{}) bool { var v int switch obj.(type) { case int64: if wordsize == 32 { return false } v = int(obj.(int64)) case int: v = obj.(int) case int32: v = int(obj.(int32)) case int16: v = int(obj.(int16)) case int8: v = int(obj.(int8)) default: return false } return v <= m.Max } // DefaultMessage return the default max error message func (m Max) DefaultMessage() string { return fmt.Sprintf(MessageTmpls["Max"], m.Max) } // GetKey return the m.Key func (m Max) GetKey() string { return m.Key } // GetLimitValue return the limit value, Max func (m Max) GetLimitValue() interface{} { return m.Max } // Range Requires an integer to be within Min, Max inclusive. type Range struct { Min Max Key string } // IsSatisfied judge whether obj is valid // not support int64 on 32-bit platform func (r Range) IsSatisfied(obj interface{}) bool { return r.Min.IsSatisfied(obj) && r.Max.IsSatisfied(obj) } // DefaultMessage return the default Range error message func (r Range) DefaultMessage() string { return fmt.Sprintf(MessageTmpls["Range"], r.Min.Min, r.Max.Max) } // GetKey return the m.Key func (r Range) GetKey() string { return r.Key } // GetLimitValue return the limit value, Max func (r Range) GetLimitValue() interface{} { return []int{r.Min.Min, r.Max.Max} } // MinSize Requires an array or string to be at least a given length. type MinSize struct { Min int Key string } // IsSatisfied judge whether obj is valid func (m MinSize) IsSatisfied(obj interface{}) bool { if str, ok := obj.(string); ok { return utf8.RuneCountInString(str) >= m.Min } v := reflect.ValueOf(obj) if v.Kind() == reflect.Slice { return v.Len() >= m.Min } return false } // DefaultMessage return the default MinSize error message func (m MinSize) DefaultMessage() string { return fmt.Sprintf(MessageTmpls["MinSize"], m.Min) } // GetKey return the m.Key func (m MinSize) GetKey() string { return m.Key } // GetLimitValue return the limit value func (m MinSize) GetLimitValue() interface{} { return m.Min } // MaxSize Requires an array or string to be at most a given length. type MaxSize struct { Max int Key string } // IsSatisfied judge whether obj is valid func (m MaxSize) IsSatisfied(obj interface{}) bool { if str, ok := obj.(string); ok { return utf8.RuneCountInString(str) <= m.Max } v := reflect.ValueOf(obj) if v.Kind() == reflect.Slice { return v.Len() <= m.Max } return false } // DefaultMessage return the default MaxSize error message func (m MaxSize) DefaultMessage() string { return fmt.Sprintf(MessageTmpls["MaxSize"], m.Max) } // GetKey return the m.Key func (m MaxSize) GetKey() string { return m.Key } // GetLimitValue return the limit value func (m MaxSize) GetLimitValue() interface{} { return m.Max } // Length Requires an array or string to be exactly a given length. type Length struct { N int Key string } // IsSatisfied judge whether obj is valid func (l Length) IsSatisfied(obj interface{}) bool { if str, ok := obj.(string); ok { return utf8.RuneCountInString(str) == l.N } v := reflect.ValueOf(obj) if v.Kind() == reflect.Slice { return v.Len() == l.N } return false } // DefaultMessage return the default Length error message func (l Length) DefaultMessage() string { return fmt.Sprintf(MessageTmpls["Length"], l.N) } // GetKey return the m.Key func (l Length) GetKey() string { return l.Key } // GetLimitValue return the limit value func (l Length) GetLimitValue() interface{} { return l.N } // Alpha check the alpha type Alpha struct { Key string } // IsSatisfied judge whether obj is valid func (a Alpha) IsSatisfied(obj interface{}) bool { if str, ok := obj.(string); ok { for _, v := range str { if ('Z' < v || v < 'A') && ('z' < v || v < 'a') { return false } } return true } return false } // DefaultMessage return the default Length error message func (a Alpha) DefaultMessage() string { return MessageTmpls["Alpha"] } // GetKey return the m.Key func (a Alpha) GetKey() string { return a.Key } // GetLimitValue return the limit value func (a Alpha) GetLimitValue() interface{} { return nil } // Numeric check number type Numeric struct { Key string } // IsSatisfied judge whether obj is valid func (n Numeric) IsSatisfied(obj interface{}) bool { if str, ok := obj.(string); ok { for _, v := range str { if '9' < v || v < '0' { return false } } return true } return false } // DefaultMessage return the default Length error message func (n Numeric) DefaultMessage() string { return MessageTmpls["Numeric"] } // GetKey return the n.Key func (n Numeric) GetKey() string { return n.Key } // GetLimitValue return the limit value func (n Numeric) GetLimitValue() interface{} { return nil } // AlphaNumeric check alpha and number type AlphaNumeric struct { Key string } // IsSatisfied judge whether obj is valid func (a AlphaNumeric) IsSatisfied(obj interface{}) bool { if str, ok := obj.(string); ok { for _, v := range str { if ('Z' < v || v < 'A') && ('z' < v || v < 'a') && ('9' < v || v < '0') { return false } } return true } return false } // DefaultMessage return the default Length error message func (a AlphaNumeric) DefaultMessage() string { return MessageTmpls["AlphaNumeric"] } // GetKey return the a.Key func (a AlphaNumeric) GetKey() string { return a.Key } // GetLimitValue return the limit value func (a AlphaNumeric) GetLimitValue() interface{} { return nil } // Match Requires a string to match a given regex. type Match struct { Regexp *regexp.Regexp Key string } // IsSatisfied judge whether obj is valid func (m Match) IsSatisfied(obj interface{}) bool { return m.Regexp.MatchString(fmt.Sprintf("%v", obj)) } // DefaultMessage return the default Match error message func (m Match) DefaultMessage() string { return fmt.Sprintf(MessageTmpls["Match"], m.Regexp.String()) } // GetKey return the m.Key func (m Match) GetKey() string { return m.Key } // GetLimitValue return the limit value func (m Match) GetLimitValue() interface{} { return m.Regexp.String() } // NoMatch Requires a string to not match a given regex. type NoMatch struct { Match Key string } // IsSatisfied judge whether obj is valid func (n NoMatch) IsSatisfied(obj interface{}) bool { return !n.Match.IsSatisfied(obj) } // DefaultMessage return the default NoMatch error message func (n NoMatch) DefaultMessage() string { return fmt.Sprintf(MessageTmpls["NoMatch"], n.Regexp.String()) } // GetKey return the n.Key func (n NoMatch) GetKey() string { return n.Key } // GetLimitValue return the limit value func (n NoMatch) GetLimitValue() interface{} { return n.Regexp.String() } var alphaDashPattern = regexp.MustCompile(`[^\d\w-_]`) // AlphaDash check not Alpha type AlphaDash struct { NoMatch Key string } // DefaultMessage return the default AlphaDash error message func (a AlphaDash) DefaultMessage() string { return MessageTmpls["AlphaDash"] } // GetKey return the n.Key func (a AlphaDash) GetKey() string { return a.Key } // GetLimitValue return the limit value func (a AlphaDash) GetLimitValue() interface{} { return nil } var emailPattern = regexp.MustCompile(`^[\w!#$%&'*+/=?^_` + "`" + `{|}~-]+(?:\.[\w!#$%&'*+/=?^_` + "`" + `{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[a-zA-Z0-9](?:[\w-]*[\w])?$`) // Email check struct type Email struct { Match Key string } // DefaultMessage return the default Email error message func (e Email) DefaultMessage() string { return MessageTmpls["Email"] } // GetKey return the n.Key func (e Email) GetKey() string { return e.Key } // GetLimitValue return the limit value func (e Email) GetLimitValue() interface{} { return nil } var ipPattern = regexp.MustCompile(`^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$`) // IP check struct type IP struct { Match Key string } // DefaultMessage return the default IP error message func (i IP) DefaultMessage() string { return MessageTmpls["IP"] } // GetKey return the i.Key func (i IP) GetKey() string { return i.Key } // GetLimitValue return the limit value func (i IP) GetLimitValue() interface{} { return nil } var base64Pattern = regexp.MustCompile(`^(?:[A-Za-z0-99+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$`) // Base64 check struct type Base64 struct { Match Key string } // DefaultMessage return the default Base64 error message func (b Base64) DefaultMessage() string { return MessageTmpls["Base64"] } // GetKey return the b.Key func (b Base64) GetKey() string { return b.Key } // GetLimitValue return the limit value func (b Base64) GetLimitValue() interface{} { return nil } // just for chinese mobile phone number var mobilePattern = regexp.MustCompile(`^((\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][06789]|[4][579]))\d{8}$`) // Mobile check struct type Mobile struct { Match Key string } // DefaultMessage return the default Mobile error message func (m Mobile) DefaultMessage() string { return MessageTmpls["Mobile"] } // GetKey return the m.Key func (m Mobile) GetKey() string { return m.Key } // GetLimitValue return the limit value func (m Mobile) GetLimitValue() interface{} { return nil } // just for chinese telephone number var telPattern = regexp.MustCompile(`^(0\d{2,3}(\-)?)?\d{7,8}$`) // Tel check telephone struct type Tel struct { Match Key string } // DefaultMessage return the default Tel error message func (t Tel) DefaultMessage() string { return MessageTmpls["Tel"] } // GetKey return the t.Key func (t Tel) GetKey() string { return t.Key } // GetLimitValue return the limit value func (t Tel) GetLimitValue() interface{} { return nil } // Phone just for chinese telephone or mobile phone number type Phone struct { Mobile Tel Key string } // IsSatisfied judge whether obj is valid func (p Phone) IsSatisfied(obj interface{}) bool { return p.Mobile.IsSatisfied(obj) || p.Tel.IsSatisfied(obj) } // DefaultMessage return the default Phone error message func (p Phone) DefaultMessage() string { return MessageTmpls["Phone"] } // GetKey return the p.Key func (p Phone) GetKey() string { return p.Key } // GetLimitValue return the limit value func (p Phone) GetLimitValue() interface{} { return nil } // just for chinese zipcode var zipCodePattern = regexp.MustCompile(`^[1-9]\d{5}$`) // ZipCode check the zip struct type ZipCode struct { Match Key string } // DefaultMessage return the default Zip error message func (z ZipCode) DefaultMessage() string { return MessageTmpls["ZipCode"] } // GetKey return the z.Key func (z ZipCode) GetKey() string { return z.Key } // GetLimitValue return the limit value func (z ZipCode) GetLimitValue() interface{} { return nil } ================================================ FILE: vendor/github.com/boombuler/barcode/.gitignore ================================================ .vscode/ ================================================ FILE: vendor/github.com/boombuler/barcode/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Florian Sundermann 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. ================================================ FILE: vendor/github.com/boombuler/barcode/README.md ================================================ [![Join the chat at https://gitter.im/golang-barcode/Lobby](https://badges.gitter.im/golang-barcode/Lobby.svg)](https://gitter.im/golang-barcode/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ## Introduction ## This is a package for GO which can be used to create different types of barcodes. ## Supported Barcode Types ## * 2 of 5 * Aztec Code * Codabar * Code 128 * Code 39 * Code 93 * Datamatrix * EAN 13 * EAN 8 * PDF 417 * QR Code ## Example ## This is a simple example on how to create a QR-Code and write it to a png-file ```go package main import ( "image/png" "os" "github.com/boombuler/barcode" "github.com/boombuler/barcode/qr" ) func main() { // Create the barcode qrCode, _ := qr.Encode("Hello World", qr.M, qr.Auto) // Scale the barcode to 200x200 pixels qrCode, _ = barcode.Scale(qrCode, 200, 200) // create the output file file, _ := os.Create("qrcode.png") defer file.Close() // encode the barcode as png png.Encode(file, qrCode) } ``` ## Documentation ## See [GoDoc](https://godoc.org/github.com/boombuler/barcode) To create a barcode use the Encode function from one of the subpackages. ================================================ FILE: vendor/github.com/boombuler/barcode/barcode.go ================================================ package barcode import "image" const ( TypeAztec = "Aztec" TypeCodabar = "Codabar" TypeCode128 = "Code 128" TypeCode39 = "Code 39" TypeCode93 = "Code 93" TypeDataMatrix = "DataMatrix" TypeEAN8 = "EAN 8" TypeEAN13 = "EAN 13" TypePDF = "PDF417" TypeQR = "QR Code" Type2of5 = "2 of 5" Type2of5Interleaved = "2 of 5 (interleaved)" ) // Contains some meta information about a barcode type Metadata struct { // the name of the barcode kind CodeKind string // contains 1 for 1D barcodes or 2 for 2D barcodes Dimensions byte } // a rendered and encoded barcode type Barcode interface { image.Image // returns some meta information about the barcode Metadata() Metadata // the data that was encoded in this barcode Content() string } // Additional interface that some barcodes might implement to provide // the value of its checksum. type BarcodeIntCS interface { Barcode CheckSum() int } ================================================ FILE: vendor/github.com/boombuler/barcode/qr/alphanumeric.go ================================================ package qr import ( "errors" "fmt" "strings" "github.com/boombuler/barcode/utils" ) const charSet string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:" func stringToAlphaIdx(content string) <-chan int { result := make(chan int) go func() { for _, r := range content { idx := strings.IndexRune(charSet, r) result <- idx if idx < 0 { break } } close(result) }() return result } func encodeAlphaNumeric(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) { contentLenIsOdd := len(content)%2 == 1 contentBitCount := (len(content) / 2) * 11 if contentLenIsOdd { contentBitCount += 6 } vi := findSmallestVersionInfo(ecl, alphaNumericMode, contentBitCount) if vi == nil { return nil, nil, errors.New("To much data to encode") } res := new(utils.BitList) res.AddBits(int(alphaNumericMode), 4) res.AddBits(len(content), vi.charCountBits(alphaNumericMode)) encoder := stringToAlphaIdx(content) for idx := 0; idx < len(content)/2; idx++ { c1 := <-encoder c2 := <-encoder if c1 < 0 || c2 < 0 { return nil, nil, fmt.Errorf("\"%s\" can not be encoded as %s", content, AlphaNumeric) } res.AddBits(c1*45+c2, 11) } if contentLenIsOdd { c := <-encoder if c < 0 { return nil, nil, fmt.Errorf("\"%s\" can not be encoded as %s", content, AlphaNumeric) } res.AddBits(c, 6) } addPaddingAndTerminator(res, vi) return res, vi, nil } ================================================ FILE: vendor/github.com/boombuler/barcode/qr/automatic.go ================================================ package qr import ( "fmt" "github.com/boombuler/barcode/utils" ) func encodeAuto(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) { bits, vi, _ := Numeric.getEncoder()(content, ecl) if bits != nil && vi != nil { return bits, vi, nil } bits, vi, _ = AlphaNumeric.getEncoder()(content, ecl) if bits != nil && vi != nil { return bits, vi, nil } bits, vi, _ = Unicode.getEncoder()(content, ecl) if bits != nil && vi != nil { return bits, vi, nil } return nil, nil, fmt.Errorf("No encoding found to encode \"%s\"", content) } ================================================ FILE: vendor/github.com/boombuler/barcode/qr/blocks.go ================================================ package qr type block struct { data []byte ecc []byte } type blockList []*block func splitToBlocks(data <-chan byte, vi *versionInfo) blockList { result := make(blockList, vi.NumberOfBlocksInGroup1+vi.NumberOfBlocksInGroup2) for b := 0; b < int(vi.NumberOfBlocksInGroup1); b++ { blk := new(block) blk.data = make([]byte, vi.DataCodeWordsPerBlockInGroup1) for cw := 0; cw < int(vi.DataCodeWordsPerBlockInGroup1); cw++ { blk.data[cw] = <-data } blk.ecc = ec.calcECC(blk.data, vi.ErrorCorrectionCodewordsPerBlock) result[b] = blk } for b := 0; b < int(vi.NumberOfBlocksInGroup2); b++ { blk := new(block) blk.data = make([]byte, vi.DataCodeWordsPerBlockInGroup2) for cw := 0; cw < int(vi.DataCodeWordsPerBlockInGroup2); cw++ { blk.data[cw] = <-data } blk.ecc = ec.calcECC(blk.data, vi.ErrorCorrectionCodewordsPerBlock) result[int(vi.NumberOfBlocksInGroup1)+b] = blk } return result } func (bl blockList) interleave(vi *versionInfo) []byte { var maxCodewordCount int if vi.DataCodeWordsPerBlockInGroup1 > vi.DataCodeWordsPerBlockInGroup2 { maxCodewordCount = int(vi.DataCodeWordsPerBlockInGroup1) } else { maxCodewordCount = int(vi.DataCodeWordsPerBlockInGroup2) } resultLen := (vi.DataCodeWordsPerBlockInGroup1+vi.ErrorCorrectionCodewordsPerBlock)*vi.NumberOfBlocksInGroup1 + (vi.DataCodeWordsPerBlockInGroup2+vi.ErrorCorrectionCodewordsPerBlock)*vi.NumberOfBlocksInGroup2 result := make([]byte, 0, resultLen) for i := 0; i < maxCodewordCount; i++ { for b := 0; b < len(bl); b++ { if len(bl[b].data) > i { result = append(result, bl[b].data[i]) } } } for i := 0; i < int(vi.ErrorCorrectionCodewordsPerBlock); i++ { for b := 0; b < len(bl); b++ { result = append(result, bl[b].ecc[i]) } } return result } ================================================ FILE: vendor/github.com/boombuler/barcode/qr/encoder.go ================================================ // Package qr can be used to create QR barcodes. package qr import ( "image" "github.com/boombuler/barcode" "github.com/boombuler/barcode/utils" ) type encodeFn func(content string, eccLevel ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) // Encoding mode for QR Codes. type Encoding byte const ( // Auto will choose ths best matching encoding Auto Encoding = iota // Numeric encoding only encodes numbers [0-9] Numeric // AlphaNumeric encoding only encodes uppercase letters, numbers and [Space], $, %, *, +, -, ., /, : AlphaNumeric // Unicode encoding encodes the string as utf-8 Unicode // only for testing purpose unknownEncoding ) func (e Encoding) getEncoder() encodeFn { switch e { case Auto: return encodeAuto case Numeric: return encodeNumeric case AlphaNumeric: return encodeAlphaNumeric case Unicode: return encodeUnicode } return nil } func (e Encoding) String() string { switch e { case Auto: return "Auto" case Numeric: return "Numeric" case AlphaNumeric: return "AlphaNumeric" case Unicode: return "Unicode" } return "" } // Encode returns a QR barcode with the given content, error correction level and uses the given encoding func Encode(content string, level ErrorCorrectionLevel, mode Encoding) (barcode.Barcode, error) { bits, vi, err := mode.getEncoder()(content, level) if err != nil { return nil, err } blocks := splitToBlocks(bits.IterateBytes(), vi) data := blocks.interleave(vi) result := render(data, vi) result.content = content return result, nil } func render(data []byte, vi *versionInfo) *qrcode { dim := vi.modulWidth() results := make([]*qrcode, 8) for i := 0; i < 8; i++ { results[i] = newBarcode(dim) } occupied := newBarcode(dim) setAll := func(x int, y int, val bool) { occupied.Set(x, y, true) for i := 0; i < 8; i++ { results[i].Set(x, y, val) } } drawFinderPatterns(vi, setAll) drawAlignmentPatterns(occupied, vi, setAll) //Timing Pattern: var i int for i = 0; i < dim; i++ { if !occupied.Get(i, 6) { setAll(i, 6, i%2 == 0) } if !occupied.Get(6, i) { setAll(6, i, i%2 == 0) } } // Dark Module setAll(8, dim-8, true) drawVersionInfo(vi, setAll) drawFormatInfo(vi, -1, occupied.Set) for i := 0; i < 8; i++ { drawFormatInfo(vi, i, results[i].Set) } // Write the data var curBitNo int for pos := range iterateModules(occupied) { var curBit bool if curBitNo < len(data)*8 { curBit = ((data[curBitNo/8] >> uint(7-(curBitNo%8))) & 1) == 1 } else { curBit = false } for i := 0; i < 8; i++ { setMasked(pos.X, pos.Y, curBit, i, results[i].Set) } curBitNo++ } lowestPenalty := ^uint(0) lowestPenaltyIdx := -1 for i := 0; i < 8; i++ { p := results[i].calcPenalty() if p < lowestPenalty { lowestPenalty = p lowestPenaltyIdx = i } } return results[lowestPenaltyIdx] } func setMasked(x, y int, val bool, mask int, set func(int, int, bool)) { switch mask { case 0: val = val != (((y + x) % 2) == 0) break case 1: val = val != ((y % 2) == 0) break case 2: val = val != ((x % 3) == 0) break case 3: val = val != (((y + x) % 3) == 0) break case 4: val = val != (((y/2 + x/3) % 2) == 0) break case 5: val = val != (((y*x)%2)+((y*x)%3) == 0) break case 6: val = val != ((((y*x)%2)+((y*x)%3))%2 == 0) break case 7: val = val != ((((y+x)%2)+((y*x)%3))%2 == 0) } set(x, y, val) } func iterateModules(occupied *qrcode) <-chan image.Point { result := make(chan image.Point) allPoints := make(chan image.Point) go func() { curX := occupied.dimension - 1 curY := occupied.dimension - 1 isUpward := true for true { if isUpward { allPoints <- image.Pt(curX, curY) allPoints <- image.Pt(curX-1, curY) curY-- if curY < 0 { curY = 0 curX -= 2 if curX == 6 { curX-- } if curX < 0 { break } isUpward = false } } else { allPoints <- image.Pt(curX, curY) allPoints <- image.Pt(curX-1, curY) curY++ if curY >= occupied.dimension { curY = occupied.dimension - 1 curX -= 2 if curX == 6 { curX-- } isUpward = true if curX < 0 { break } } } } close(allPoints) }() go func() { for pt := range allPoints { if !occupied.Get(pt.X, pt.Y) { result <- pt } } close(result) }() return result } func drawFinderPatterns(vi *versionInfo, set func(int, int, bool)) { dim := vi.modulWidth() drawPattern := func(xoff int, yoff int) { for x := -1; x < 8; x++ { for y := -1; y < 8; y++ { val := (x == 0 || x == 6 || y == 0 || y == 6 || (x > 1 && x < 5 && y > 1 && y < 5)) && (x <= 6 && y <= 6 && x >= 0 && y >= 0) if x+xoff >= 0 && x+xoff < dim && y+yoff >= 0 && y+yoff < dim { set(x+xoff, y+yoff, val) } } } } drawPattern(0, 0) drawPattern(0, dim-7) drawPattern(dim-7, 0) } func drawAlignmentPatterns(occupied *qrcode, vi *versionInfo, set func(int, int, bool)) { drawPattern := func(xoff int, yoff int) { for x := -2; x <= 2; x++ { for y := -2; y <= 2; y++ { val := x == -2 || x == 2 || y == -2 || y == 2 || (x == 0 && y == 0) set(x+xoff, y+yoff, val) } } } positions := vi.alignmentPatternPlacements() for _, x := range positions { for _, y := range positions { if occupied.Get(x, y) { continue } drawPattern(x, y) } } } var formatInfos = map[ErrorCorrectionLevel]map[int][]bool{ L: { 0: []bool{true, true, true, false, true, true, true, true, true, false, false, false, true, false, false}, 1: []bool{true, true, true, false, false, true, false, true, true, true, true, false, false, true, true}, 2: []bool{true, true, true, true, true, false, true, true, false, true, false, true, false, true, false}, 3: []bool{true, true, true, true, false, false, false, true, false, false, true, true, true, false, true}, 4: []bool{true, true, false, false, true, true, false, false, false, true, false, true, true, true, true}, 5: []bool{true, true, false, false, false, true, true, false, false, false, true, true, false, false, false}, 6: []bool{true, true, false, true, true, false, false, false, true, false, false, false, false, false, true}, 7: []bool{true, true, false, true, false, false, true, false, true, true, true, false, true, true, false}, }, M: { 0: []bool{true, false, true, false, true, false, false, false, false, false, true, false, false, true, false}, 1: []bool{true, false, true, false, false, false, true, false, false, true, false, false, true, false, true}, 2: []bool{true, false, true, true, true, true, false, false, true, true, true, true, true, false, false}, 3: []bool{true, false, true, true, false, true, true, false, true, false, false, true, false, true, true}, 4: []bool{true, false, false, false, true, false, true, true, true, true, true, true, false, false, true}, 5: []bool{true, false, false, false, false, false, false, true, true, false, false, true, true, true, false}, 6: []bool{true, false, false, true, true, true, true, true, false, false, true, false, true, true, true}, 7: []bool{true, false, false, true, false, true, false, true, false, true, false, false, false, false, false}, }, Q: { 0: []bool{false, true, true, false, true, false, true, false, true, false, true, true, true, true, true}, 1: []bool{false, true, true, false, false, false, false, false, true, true, false, true, false, false, false}, 2: []bool{false, true, true, true, true, true, true, false, false, true, true, false, false, false, true}, 3: []bool{false, true, true, true, false, true, false, false, false, false, false, false, true, true, false}, 4: []bool{false, true, false, false, true, false, false, true, false, true, true, false, true, false, false}, 5: []bool{false, true, false, false, false, false, true, true, false, false, false, false, false, true, true}, 6: []bool{false, true, false, true, true, true, false, true, true, false, true, true, false, true, false}, 7: []bool{false, true, false, true, false, true, true, true, true, true, false, true, true, false, true}, }, H: { 0: []bool{false, false, true, false, true, true, false, true, false, false, false, true, false, false, true}, 1: []bool{false, false, true, false, false, true, true, true, false, true, true, true, true, true, false}, 2: []bool{false, false, true, true, true, false, false, true, true, true, false, false, true, true, true}, 3: []bool{false, false, true, true, false, false, true, true, true, false, true, false, false, false, false}, 4: []bool{false, false, false, false, true, true, true, false, true, true, false, false, false, true, false}, 5: []bool{false, false, false, false, false, true, false, false, true, false, true, false, true, false, true}, 6: []bool{false, false, false, true, true, false, true, false, false, false, false, true, true, false, false}, 7: []bool{false, false, false, true, false, false, false, false, false, true, true, true, false, true, true}, }, } func drawFormatInfo(vi *versionInfo, usedMask int, set func(int, int, bool)) { var formatInfo []bool if usedMask == -1 { formatInfo = []bool{true, true, true, true, true, true, true, true, true, true, true, true, true, true, true} // Set all to true cause -1 --> occupied mask. } else { formatInfo = formatInfos[vi.Level][usedMask] } if len(formatInfo) == 15 { dim := vi.modulWidth() set(0, 8, formatInfo[0]) set(1, 8, formatInfo[1]) set(2, 8, formatInfo[2]) set(3, 8, formatInfo[3]) set(4, 8, formatInfo[4]) set(5, 8, formatInfo[5]) set(7, 8, formatInfo[6]) set(8, 8, formatInfo[7]) set(8, 7, formatInfo[8]) set(8, 5, formatInfo[9]) set(8, 4, formatInfo[10]) set(8, 3, formatInfo[11]) set(8, 2, formatInfo[12]) set(8, 1, formatInfo[13]) set(8, 0, formatInfo[14]) set(8, dim-1, formatInfo[0]) set(8, dim-2, formatInfo[1]) set(8, dim-3, formatInfo[2]) set(8, dim-4, formatInfo[3]) set(8, dim-5, formatInfo[4]) set(8, dim-6, formatInfo[5]) set(8, dim-7, formatInfo[6]) set(dim-8, 8, formatInfo[7]) set(dim-7, 8, formatInfo[8]) set(dim-6, 8, formatInfo[9]) set(dim-5, 8, formatInfo[10]) set(dim-4, 8, formatInfo[11]) set(dim-3, 8, formatInfo[12]) set(dim-2, 8, formatInfo[13]) set(dim-1, 8, formatInfo[14]) } } var versionInfoBitsByVersion = map[byte][]bool{ 7: []bool{false, false, false, true, true, true, true, true, false, false, true, false, false, true, false, true, false, false}, 8: []bool{false, false, true, false, false, false, false, true, false, true, true, false, true, true, true, true, false, false}, 9: []bool{false, false, true, false, false, true, true, false, true, false, true, false, false, true, true, false, false, true}, 10: []bool{false, false, true, false, true, false, false, true, false, false, true, true, false, true, false, false, true, true}, 11: []bool{false, false, true, false, true, true, true, false, true, true, true, true, true, true, false, true, true, false}, 12: []bool{false, false, true, true, false, false, false, true, true, true, false, true, true, false, false, false, true, false}, 13: []bool{false, false, true, true, false, true, true, false, false, false, false, true, false, false, false, true, true, true}, 14: []bool{false, false, true, true, true, false, false, true, true, false, false, false, false, false, true, true, false, true}, 15: []bool{false, false, true, true, true, true, true, false, false, true, false, false, true, false, true, false, false, false}, 16: []bool{false, true, false, false, false, false, true, false, true, true, false, true, true, true, true, false, false, false}, 17: []bool{false, true, false, false, false, true, false, true, false, false, false, true, false, true, true, true, false, true}, 18: []bool{false, true, false, false, true, false, true, false, true, false, false, false, false, true, false, true, true, true}, 19: []bool{false, true, false, false, true, true, false, true, false, true, false, false, true, true, false, false, true, false}, 20: []bool{false, true, false, true, false, false, true, false, false, true, true, false, true, false, false, true, true, false}, 21: []bool{false, true, false, true, false, true, false, true, true, false, true, false, false, false, false, false, true, true}, 22: []bool{false, true, false, true, true, false, true, false, false, false, true, true, false, false, true, false, false, true}, 23: []bool{false, true, false, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false}, 24: []bool{false, true, true, false, false, false, true, true, true, false, true, true, false, false, false, true, false, false}, 25: []bool{false, true, true, false, false, true, false, false, false, true, true, true, true, false, false, false, false, true}, 26: []bool{false, true, true, false, true, false, true, true, true, true, true, false, true, false, true, false, true, true}, 27: []bool{false, true, true, false, true, true, false, false, false, false, true, false, false, false, true, true, true, false}, 28: []bool{false, true, true, true, false, false, true, true, false, false, false, false, false, true, true, false, true, false}, 29: []bool{false, true, true, true, false, true, false, false, true, true, false, false, true, true, true, true, true, true}, 30: []bool{false, true, true, true, true, false, true, true, false, true, false, true, true, true, false, true, false, true}, 31: []bool{false, true, true, true, true, true, false, false, true, false, false, true, false, true, false, false, false, false}, 32: []bool{true, false, false, false, false, false, true, false, false, true, true, true, false, true, false, true, false, true}, 33: []bool{true, false, false, false, false, true, false, true, true, false, true, true, true, true, false, false, false, false}, 34: []bool{true, false, false, false, true, false, true, false, false, false, true, false, true, true, true, false, true, false}, 35: []bool{true, false, false, false, true, true, false, true, true, true, true, false, false, true, true, true, true, true}, 36: []bool{true, false, false, true, false, false, true, false, true, true, false, false, false, false, true, false, true, true}, 37: []bool{true, false, false, true, false, true, false, true, false, false, false, false, true, false, true, true, true, false}, 38: []bool{true, false, false, true, true, false, true, false, true, false, false, true, true, false, false, true, false, false}, 39: []bool{true, false, false, true, true, true, false, true, false, true, false, true, false, false, false, false, false, true}, 40: []bool{true, false, true, false, false, false, true, true, false, false, false, true, true, false, true, false, false, true}, } func drawVersionInfo(vi *versionInfo, set func(int, int, bool)) { versionInfoBits, ok := versionInfoBitsByVersion[vi.Version] if ok && len(versionInfoBits) > 0 { for i := 0; i < len(versionInfoBits); i++ { x := (vi.modulWidth() - 11) + i%3 y := i / 3 set(x, y, versionInfoBits[len(versionInfoBits)-i-1]) set(y, x, versionInfoBits[len(versionInfoBits)-i-1]) } } } func addPaddingAndTerminator(bl *utils.BitList, vi *versionInfo) { for i := 0; i < 4 && bl.Len() < vi.totalDataBytes()*8; i++ { bl.AddBit(false) } for bl.Len()%8 != 0 { bl.AddBit(false) } for i := 0; bl.Len() < vi.totalDataBytes()*8; i++ { if i%2 == 0 { bl.AddByte(236) } else { bl.AddByte(17) } } } ================================================ FILE: vendor/github.com/boombuler/barcode/qr/errorcorrection.go ================================================ package qr import ( "github.com/boombuler/barcode/utils" ) type errorCorrection struct { rs *utils.ReedSolomonEncoder } var ec = newErrorCorrection() func newErrorCorrection() *errorCorrection { fld := utils.NewGaloisField(285, 256, 0) return &errorCorrection{utils.NewReedSolomonEncoder(fld)} } func (ec *errorCorrection) calcECC(data []byte, eccCount byte) []byte { dataInts := make([]int, len(data)) for i := 0; i < len(data); i++ { dataInts[i] = int(data[i]) } res := ec.rs.Encode(dataInts, int(eccCount)) result := make([]byte, len(res)) for i := 0; i < len(res); i++ { result[i] = byte(res[i]) } return result } ================================================ FILE: vendor/github.com/boombuler/barcode/qr/numeric.go ================================================ package qr import ( "errors" "fmt" "strconv" "github.com/boombuler/barcode/utils" ) func encodeNumeric(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) { contentBitCount := (len(content) / 3) * 10 switch len(content) % 3 { case 1: contentBitCount += 4 case 2: contentBitCount += 7 } vi := findSmallestVersionInfo(ecl, numericMode, contentBitCount) if vi == nil { return nil, nil, errors.New("To much data to encode") } res := new(utils.BitList) res.AddBits(int(numericMode), 4) res.AddBits(len(content), vi.charCountBits(numericMode)) for pos := 0; pos < len(content); pos += 3 { var curStr string if pos+3 <= len(content) { curStr = content[pos : pos+3] } else { curStr = content[pos:] } i, err := strconv.Atoi(curStr) if err != nil || i < 0 { return nil, nil, fmt.Errorf("\"%s\" can not be encoded as %s", content, Numeric) } var bitCnt byte switch len(curStr) % 3 { case 0: bitCnt = 10 case 1: bitCnt = 4 break case 2: bitCnt = 7 break } res.AddBits(i, bitCnt) } addPaddingAndTerminator(res, vi) return res, vi, nil } ================================================ FILE: vendor/github.com/boombuler/barcode/qr/qrcode.go ================================================ package qr import ( "image" "image/color" "math" "github.com/boombuler/barcode" "github.com/boombuler/barcode/utils" ) type qrcode struct { dimension int data *utils.BitList content string } func (qr *qrcode) Content() string { return qr.content } func (qr *qrcode) Metadata() barcode.Metadata { return barcode.Metadata{barcode.TypeQR, 2} } func (qr *qrcode) ColorModel() color.Model { return color.Gray16Model } func (qr *qrcode) Bounds() image.Rectangle { return image.Rect(0, 0, qr.dimension, qr.dimension) } func (qr *qrcode) At(x, y int) color.Color { if qr.Get(x, y) { return color.Black } return color.White } func (qr *qrcode) Get(x, y int) bool { return qr.data.GetBit(x*qr.dimension + y) } func (qr *qrcode) Set(x, y int, val bool) { qr.data.SetBit(x*qr.dimension+y, val) } func (qr *qrcode) calcPenalty() uint { return qr.calcPenaltyRule1() + qr.calcPenaltyRule2() + qr.calcPenaltyRule3() + qr.calcPenaltyRule4() } func (qr *qrcode) calcPenaltyRule1() uint { var result uint for x := 0; x < qr.dimension; x++ { checkForX := false var cntX uint checkForY := false var cntY uint for y := 0; y < qr.dimension; y++ { if qr.Get(x, y) == checkForX { cntX++ } else { checkForX = !checkForX if cntX >= 5 { result += cntX - 2 } cntX = 1 } if qr.Get(y, x) == checkForY { cntY++ } else { checkForY = !checkForY if cntY >= 5 { result += cntY - 2 } cntY = 1 } } if cntX >= 5 { result += cntX - 2 } if cntY >= 5 { result += cntY - 2 } } return result } func (qr *qrcode) calcPenaltyRule2() uint { var result uint for x := 0; x < qr.dimension-1; x++ { for y := 0; y < qr.dimension-1; y++ { check := qr.Get(x, y) if qr.Get(x, y+1) == check && qr.Get(x+1, y) == check && qr.Get(x+1, y+1) == check { result += 3 } } } return result } func (qr *qrcode) calcPenaltyRule3() uint { pattern1 := []bool{true, false, true, true, true, false, true, false, false, false, false} pattern2 := []bool{false, false, false, false, true, false, true, true, true, false, true} var result uint for x := 0; x <= qr.dimension-len(pattern1); x++ { for y := 0; y < qr.dimension; y++ { pattern1XFound := true pattern2XFound := true pattern1YFound := true pattern2YFound := true for i := 0; i < len(pattern1); i++ { iv := qr.Get(x+i, y) if iv != pattern1[i] { pattern1XFound = false } if iv != pattern2[i] { pattern2XFound = false } iv = qr.Get(y, x+i) if iv != pattern1[i] { pattern1YFound = false } if iv != pattern2[i] { pattern2YFound = false } } if pattern1XFound || pattern2XFound { result += 40 } if pattern1YFound || pattern2YFound { result += 40 } } } return result } func (qr *qrcode) calcPenaltyRule4() uint { totalNum := qr.data.Len() trueCnt := 0 for i := 0; i < totalNum; i++ { if qr.data.GetBit(i) { trueCnt++ } } percDark := float64(trueCnt) * 100 / float64(totalNum) floor := math.Abs(math.Floor(percDark/5) - 10) ceil := math.Abs(math.Ceil(percDark/5) - 10) return uint(math.Min(floor, ceil) * 10) } func newBarcode(dim int) *qrcode { res := new(qrcode) res.dimension = dim res.data = utils.NewBitList(dim * dim) return res } ================================================ FILE: vendor/github.com/boombuler/barcode/qr/unicode.go ================================================ package qr import ( "errors" "github.com/boombuler/barcode/utils" ) func encodeUnicode(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) { data := []byte(content) vi := findSmallestVersionInfo(ecl, byteMode, len(data)*8) if vi == nil { return nil, nil, errors.New("To much data to encode") } // It's not correct to add the unicode bytes to the result directly but most readers can't handle the // required ECI header... res := new(utils.BitList) res.AddBits(int(byteMode), 4) res.AddBits(len(content), vi.charCountBits(byteMode)) for _, b := range data { res.AddByte(b) } addPaddingAndTerminator(res, vi) return res, vi, nil } ================================================ FILE: vendor/github.com/boombuler/barcode/qr/versioninfo.go ================================================ package qr import "math" // ErrorCorrectionLevel indicates the amount of "backup data" stored in the QR code type ErrorCorrectionLevel byte const ( // L recovers 7% of data L ErrorCorrectionLevel = iota // M recovers 15% of data M // Q recovers 25% of data Q // H recovers 30% of data H ) func (ecl ErrorCorrectionLevel) String() string { switch ecl { case L: return "L" case M: return "M" case Q: return "Q" case H: return "H" } return "unknown" } type encodingMode byte const ( numericMode encodingMode = 1 alphaNumericMode encodingMode = 2 byteMode encodingMode = 4 kanjiMode encodingMode = 8 ) type versionInfo struct { Version byte Level ErrorCorrectionLevel ErrorCorrectionCodewordsPerBlock byte NumberOfBlocksInGroup1 byte DataCodeWordsPerBlockInGroup1 byte NumberOfBlocksInGroup2 byte DataCodeWordsPerBlockInGroup2 byte } var versionInfos = []*versionInfo{ &versionInfo{1, L, 7, 1, 19, 0, 0}, &versionInfo{1, M, 10, 1, 16, 0, 0}, &versionInfo{1, Q, 13, 1, 13, 0, 0}, &versionInfo{1, H, 17, 1, 9, 0, 0}, &versionInfo{2, L, 10, 1, 34, 0, 0}, &versionInfo{2, M, 16, 1, 28, 0, 0}, &versionInfo{2, Q, 22, 1, 22, 0, 0}, &versionInfo{2, H, 28, 1, 16, 0, 0}, &versionInfo{3, L, 15, 1, 55, 0, 0}, &versionInfo{3, M, 26, 1, 44, 0, 0}, &versionInfo{3, Q, 18, 2, 17, 0, 0}, &versionInfo{3, H, 22, 2, 13, 0, 0}, &versionInfo{4, L, 20, 1, 80, 0, 0}, &versionInfo{4, M, 18, 2, 32, 0, 0}, &versionInfo{4, Q, 26, 2, 24, 0, 0}, &versionInfo{4, H, 16, 4, 9, 0, 0}, &versionInfo{5, L, 26, 1, 108, 0, 0}, &versionInfo{5, M, 24, 2, 43, 0, 0}, &versionInfo{5, Q, 18, 2, 15, 2, 16}, &versionInfo{5, H, 22, 2, 11, 2, 12}, &versionInfo{6, L, 18, 2, 68, 0, 0}, &versionInfo{6, M, 16, 4, 27, 0, 0}, &versionInfo{6, Q, 24, 4, 19, 0, 0}, &versionInfo{6, H, 28, 4, 15, 0, 0}, &versionInfo{7, L, 20, 2, 78, 0, 0}, &versionInfo{7, M, 18, 4, 31, 0, 0}, &versionInfo{7, Q, 18, 2, 14, 4, 15}, &versionInfo{7, H, 26, 4, 13, 1, 14}, &versionInfo{8, L, 24, 2, 97, 0, 0}, &versionInfo{8, M, 22, 2, 38, 2, 39}, &versionInfo{8, Q, 22, 4, 18, 2, 19}, &versionInfo{8, H, 26, 4, 14, 2, 15}, &versionInfo{9, L, 30, 2, 116, 0, 0}, &versionInfo{9, M, 22, 3, 36, 2, 37}, &versionInfo{9, Q, 20, 4, 16, 4, 17}, &versionInfo{9, H, 24, 4, 12, 4, 13}, &versionInfo{10, L, 18, 2, 68, 2, 69}, &versionInfo{10, M, 26, 4, 43, 1, 44}, &versionInfo{10, Q, 24, 6, 19, 2, 20}, &versionInfo{10, H, 28, 6, 15, 2, 16}, &versionInfo{11, L, 20, 4, 81, 0, 0}, &versionInfo{11, M, 30, 1, 50, 4, 51}, &versionInfo{11, Q, 28, 4, 22, 4, 23}, &versionInfo{11, H, 24, 3, 12, 8, 13}, &versionInfo{12, L, 24, 2, 92, 2, 93}, &versionInfo{12, M, 22, 6, 36, 2, 37}, &versionInfo{12, Q, 26, 4, 20, 6, 21}, &versionInfo{12, H, 28, 7, 14, 4, 15}, &versionInfo{13, L, 26, 4, 107, 0, 0}, &versionInfo{13, M, 22, 8, 37, 1, 38}, &versionInfo{13, Q, 24, 8, 20, 4, 21}, &versionInfo{13, H, 22, 12, 11, 4, 12}, &versionInfo{14, L, 30, 3, 115, 1, 116}, &versionInfo{14, M, 24, 4, 40, 5, 41}, &versionInfo{14, Q, 20, 11, 16, 5, 17}, &versionInfo{14, H, 24, 11, 12, 5, 13}, &versionInfo{15, L, 22, 5, 87, 1, 88}, &versionInfo{15, M, 24, 5, 41, 5, 42}, &versionInfo{15, Q, 30, 5, 24, 7, 25}, &versionInfo{15, H, 24, 11, 12, 7, 13}, &versionInfo{16, L, 24, 5, 98, 1, 99}, &versionInfo{16, M, 28, 7, 45, 3, 46}, &versionInfo{16, Q, 24, 15, 19, 2, 20}, &versionInfo{16, H, 30, 3, 15, 13, 16}, &versionInfo{17, L, 28, 1, 107, 5, 108}, &versionInfo{17, M, 28, 10, 46, 1, 47}, &versionInfo{17, Q, 28, 1, 22, 15, 23}, &versionInfo{17, H, 28, 2, 14, 17, 15}, &versionInfo{18, L, 30, 5, 120, 1, 121}, &versionInfo{18, M, 26, 9, 43, 4, 44}, &versionInfo{18, Q, 28, 17, 22, 1, 23}, &versionInfo{18, H, 28, 2, 14, 19, 15}, &versionInfo{19, L, 28, 3, 113, 4, 114}, &versionInfo{19, M, 26, 3, 44, 11, 45}, &versionInfo{19, Q, 26, 17, 21, 4, 22}, &versionInfo{19, H, 26, 9, 13, 16, 14}, &versionInfo{20, L, 28, 3, 107, 5, 108}, &versionInfo{20, M, 26, 3, 41, 13, 42}, &versionInfo{20, Q, 30, 15, 24, 5, 25}, &versionInfo{20, H, 28, 15, 15, 10, 16}, &versionInfo{21, L, 28, 4, 116, 4, 117}, &versionInfo{21, M, 26, 17, 42, 0, 0}, &versionInfo{21, Q, 28, 17, 22, 6, 23}, &versionInfo{21, H, 30, 19, 16, 6, 17}, &versionInfo{22, L, 28, 2, 111, 7, 112}, &versionInfo{22, M, 28, 17, 46, 0, 0}, &versionInfo{22, Q, 30, 7, 24, 16, 25}, &versionInfo{22, H, 24, 34, 13, 0, 0}, &versionInfo{23, L, 30, 4, 121, 5, 122}, &versionInfo{23, M, 28, 4, 47, 14, 48}, &versionInfo{23, Q, 30, 11, 24, 14, 25}, &versionInfo{23, H, 30, 16, 15, 14, 16}, &versionInfo{24, L, 30, 6, 117, 4, 118}, &versionInfo{24, M, 28, 6, 45, 14, 46}, &versionInfo{24, Q, 30, 11, 24, 16, 25}, &versionInfo{24, H, 30, 30, 16, 2, 17}, &versionInfo{25, L, 26, 8, 106, 4, 107}, &versionInfo{25, M, 28, 8, 47, 13, 48}, &versionInfo{25, Q, 30, 7, 24, 22, 25}, &versionInfo{25, H, 30, 22, 15, 13, 16}, &versionInfo{26, L, 28, 10, 114, 2, 115}, &versionInfo{26, M, 28, 19, 46, 4, 47}, &versionInfo{26, Q, 28, 28, 22, 6, 23}, &versionInfo{26, H, 30, 33, 16, 4, 17}, &versionInfo{27, L, 30, 8, 122, 4, 123}, &versionInfo{27, M, 28, 22, 45, 3, 46}, &versionInfo{27, Q, 30, 8, 23, 26, 24}, &versionInfo{27, H, 30, 12, 15, 28, 16}, &versionInfo{28, L, 30, 3, 117, 10, 118}, &versionInfo{28, M, 28, 3, 45, 23, 46}, &versionInfo{28, Q, 30, 4, 24, 31, 25}, &versionInfo{28, H, 30, 11, 15, 31, 16}, &versionInfo{29, L, 30, 7, 116, 7, 117}, &versionInfo{29, M, 28, 21, 45, 7, 46}, &versionInfo{29, Q, 30, 1, 23, 37, 24}, &versionInfo{29, H, 30, 19, 15, 26, 16}, &versionInfo{30, L, 30, 5, 115, 10, 116}, &versionInfo{30, M, 28, 19, 47, 10, 48}, &versionInfo{30, Q, 30, 15, 24, 25, 25}, &versionInfo{30, H, 30, 23, 15, 25, 16}, &versionInfo{31, L, 30, 13, 115, 3, 116}, &versionInfo{31, M, 28, 2, 46, 29, 47}, &versionInfo{31, Q, 30, 42, 24, 1, 25}, &versionInfo{31, H, 30, 23, 15, 28, 16}, &versionInfo{32, L, 30, 17, 115, 0, 0}, &versionInfo{32, M, 28, 10, 46, 23, 47}, &versionInfo{32, Q, 30, 10, 24, 35, 25}, &versionInfo{32, H, 30, 19, 15, 35, 16}, &versionInfo{33, L, 30, 17, 115, 1, 116}, &versionInfo{33, M, 28, 14, 46, 21, 47}, &versionInfo{33, Q, 30, 29, 24, 19, 25}, &versionInfo{33, H, 30, 11, 15, 46, 16}, &versionInfo{34, L, 30, 13, 115, 6, 116}, &versionInfo{34, M, 28, 14, 46, 23, 47}, &versionInfo{34, Q, 30, 44, 24, 7, 25}, &versionInfo{34, H, 30, 59, 16, 1, 17}, &versionInfo{35, L, 30, 12, 121, 7, 122}, &versionInfo{35, M, 28, 12, 47, 26, 48}, &versionInfo{35, Q, 30, 39, 24, 14, 25}, &versionInfo{35, H, 30, 22, 15, 41, 16}, &versionInfo{36, L, 30, 6, 121, 14, 122}, &versionInfo{36, M, 28, 6, 47, 34, 48}, &versionInfo{36, Q, 30, 46, 24, 10, 25}, &versionInfo{36, H, 30, 2, 15, 64, 16}, &versionInfo{37, L, 30, 17, 122, 4, 123}, &versionInfo{37, M, 28, 29, 46, 14, 47}, &versionInfo{37, Q, 30, 49, 24, 10, 25}, &versionInfo{37, H, 30, 24, 15, 46, 16}, &versionInfo{38, L, 30, 4, 122, 18, 123}, &versionInfo{38, M, 28, 13, 46, 32, 47}, &versionInfo{38, Q, 30, 48, 24, 14, 25}, &versionInfo{38, H, 30, 42, 15, 32, 16}, &versionInfo{39, L, 30, 20, 117, 4, 118}, &versionInfo{39, M, 28, 40, 47, 7, 48}, &versionInfo{39, Q, 30, 43, 24, 22, 25}, &versionInfo{39, H, 30, 10, 15, 67, 16}, &versionInfo{40, L, 30, 19, 118, 6, 119}, &versionInfo{40, M, 28, 18, 47, 31, 48}, &versionInfo{40, Q, 30, 34, 24, 34, 25}, &versionInfo{40, H, 30, 20, 15, 61, 16}, } func (vi *versionInfo) totalDataBytes() int { g1Data := int(vi.NumberOfBlocksInGroup1) * int(vi.DataCodeWordsPerBlockInGroup1) g2Data := int(vi.NumberOfBlocksInGroup2) * int(vi.DataCodeWordsPerBlockInGroup2) return (g1Data + g2Data) } func (vi *versionInfo) charCountBits(m encodingMode) byte { switch m { case numericMode: if vi.Version < 10 { return 10 } else if vi.Version < 27 { return 12 } return 14 case alphaNumericMode: if vi.Version < 10 { return 9 } else if vi.Version < 27 { return 11 } return 13 case byteMode: if vi.Version < 10 { return 8 } return 16 case kanjiMode: if vi.Version < 10 { return 8 } else if vi.Version < 27 { return 10 } return 12 default: return 0 } } func (vi *versionInfo) modulWidth() int { return ((int(vi.Version) - 1) * 4) + 21 } func (vi *versionInfo) alignmentPatternPlacements() []int { if vi.Version == 1 { return make([]int, 0) } first := 6 last := vi.modulWidth() - 7 space := float64(last - first) count := int(math.Ceil(space/28)) + 1 result := make([]int, count) result[0] = first result[len(result)-1] = last if count > 2 { step := int(math.Ceil(float64(last-first) / float64(count-1))) if step%2 == 1 { frac := float64(last-first) / float64(count-1) _, x := math.Modf(frac) if x >= 0.5 { frac = math.Ceil(frac) } else { frac = math.Floor(frac) } if int(frac)%2 == 0 { step-- } else { step++ } } for i := 1; i <= count-2; i++ { result[i] = last - (step * (count - 1 - i)) } } return result } func findSmallestVersionInfo(ecl ErrorCorrectionLevel, mode encodingMode, dataBits int) *versionInfo { dataBits = dataBits + 4 // mode indicator for _, vi := range versionInfos { if vi.Level == ecl { if (vi.totalDataBytes() * 8) >= (dataBits + int(vi.charCountBits(mode))) { return vi } } } return nil } ================================================ FILE: vendor/github.com/boombuler/barcode/scaledbarcode.go ================================================ package barcode import ( "errors" "fmt" "image" "image/color" "math" ) type wrapFunc func(x, y int) color.Color type scaledBarcode struct { wrapped Barcode wrapperFunc wrapFunc rect image.Rectangle } type intCSscaledBC struct { scaledBarcode } func (bc *scaledBarcode) Content() string { return bc.wrapped.Content() } func (bc *scaledBarcode) Metadata() Metadata { return bc.wrapped.Metadata() } func (bc *scaledBarcode) ColorModel() color.Model { return bc.wrapped.ColorModel() } func (bc *scaledBarcode) Bounds() image.Rectangle { return bc.rect } func (bc *scaledBarcode) At(x, y int) color.Color { return bc.wrapperFunc(x, y) } func (bc *intCSscaledBC) CheckSum() int { if cs, ok := bc.wrapped.(BarcodeIntCS); ok { return cs.CheckSum() } return 0 } // Scale returns a resized barcode with the given width and height. func Scale(bc Barcode, width, height int) (Barcode, error) { switch bc.Metadata().Dimensions { case 1: return scale1DCode(bc, width, height) case 2: return scale2DCode(bc, width, height) } return nil, errors.New("unsupported barcode format") } func newScaledBC(wrapped Barcode, wrapperFunc wrapFunc, rect image.Rectangle) Barcode { result := &scaledBarcode{ wrapped: wrapped, wrapperFunc: wrapperFunc, rect: rect, } if _, ok := wrapped.(BarcodeIntCS); ok { return &intCSscaledBC{*result} } return result } func scale2DCode(bc Barcode, width, height int) (Barcode, error) { orgBounds := bc.Bounds() orgWidth := orgBounds.Max.X - orgBounds.Min.X orgHeight := orgBounds.Max.Y - orgBounds.Min.Y factor := int(math.Min(float64(width)/float64(orgWidth), float64(height)/float64(orgHeight))) if factor <= 0 { return nil, fmt.Errorf("can not scale barcode to an image smaller than %dx%d", orgWidth, orgHeight) } offsetX := (width - (orgWidth * factor)) / 2 offsetY := (height - (orgHeight * factor)) / 2 wrap := func(x, y int) color.Color { if x < offsetX || y < offsetY { return color.White } x = (x - offsetX) / factor y = (y - offsetY) / factor if x >= orgWidth || y >= orgHeight { return color.White } return bc.At(x, y) } return newScaledBC( bc, wrap, image.Rect(0, 0, width, height), ), nil } func scale1DCode(bc Barcode, width, height int) (Barcode, error) { orgBounds := bc.Bounds() orgWidth := orgBounds.Max.X - orgBounds.Min.X factor := int(float64(width) / float64(orgWidth)) if factor <= 0 { return nil, fmt.Errorf("can not scale barcode to an image smaller than %dx1", orgWidth) } offsetX := (width - (orgWidth * factor)) / 2 wrap := func(x, y int) color.Color { if x < offsetX { return color.White } x = (x - offsetX) / factor if x >= orgWidth { return color.White } return bc.At(x, 0) } return newScaledBC( bc, wrap, image.Rect(0, 0, width, height), ), nil } ================================================ FILE: vendor/github.com/boombuler/barcode/utils/base1dcode.go ================================================ // Package utils contain some utilities which are needed to create barcodes package utils import ( "image" "image/color" "github.com/boombuler/barcode" ) type base1DCode struct { *BitList kind string content string } type base1DCodeIntCS struct { base1DCode checksum int } func (c *base1DCode) Content() string { return c.content } func (c *base1DCode) Metadata() barcode.Metadata { return barcode.Metadata{c.kind, 1} } func (c *base1DCode) ColorModel() color.Model { return color.Gray16Model } func (c *base1DCode) Bounds() image.Rectangle { return image.Rect(0, 0, c.Len(), 1) } func (c *base1DCode) At(x, y int) color.Color { if c.GetBit(x) { return color.Black } return color.White } func (c *base1DCodeIntCS) CheckSum() int { return c.checksum } // New1DCode creates a new 1D barcode where the bars are represented by the bits in the bars BitList func New1DCodeIntCheckSum(codeKind, content string, bars *BitList, checksum int) barcode.BarcodeIntCS { return &base1DCodeIntCS{base1DCode{bars, codeKind, content}, checksum} } // New1DCode creates a new 1D barcode where the bars are represented by the bits in the bars BitList func New1DCode(codeKind, content string, bars *BitList) barcode.Barcode { return &base1DCode{bars, codeKind, content} } ================================================ FILE: vendor/github.com/boombuler/barcode/utils/bitlist.go ================================================ package utils // BitList is a list that contains bits type BitList struct { count int data []int32 } // NewBitList returns a new BitList with the given length // all bits are initialize with false func NewBitList(capacity int) *BitList { bl := new(BitList) bl.count = capacity x := 0 if capacity%32 != 0 { x = 1 } bl.data = make([]int32, capacity/32+x) return bl } // Len returns the number of contained bits func (bl *BitList) Len() int { return bl.count } func (bl *BitList) grow() { growBy := len(bl.data) if growBy < 128 { growBy = 128 } else if growBy >= 1024 { growBy = 1024 } nd := make([]int32, len(bl.data)+growBy) copy(nd, bl.data) bl.data = nd } // AddBit appends the given bits to the end of the list func (bl *BitList) AddBit(bits ...bool) { for _, bit := range bits { itmIndex := bl.count / 32 for itmIndex >= len(bl.data) { bl.grow() } bl.SetBit(bl.count, bit) bl.count++ } } // SetBit sets the bit at the given index to the given value func (bl *BitList) SetBit(index int, value bool) { itmIndex := index / 32 itmBitShift := 31 - (index % 32) if value { bl.data[itmIndex] = bl.data[itmIndex] | 1<> uint(itmBitShift)) & 1) == 1 } // AddByte appends all 8 bits of the given byte to the end of the list func (bl *BitList) AddByte(b byte) { for i := 7; i >= 0; i-- { bl.AddBit(((b >> uint(i)) & 1) == 1) } } // AddBits appends the last (LSB) 'count' bits of 'b' the the end of the list func (bl *BitList) AddBits(b int, count byte) { for i := int(count) - 1; i >= 0; i-- { bl.AddBit(((b >> uint(i)) & 1) == 1) } } // GetBytes returns all bits of the BitList as a []byte func (bl *BitList) GetBytes() []byte { len := bl.count >> 3 if (bl.count % 8) != 0 { len++ } result := make([]byte, len) for i := 0; i < len; i++ { shift := (3 - (i % 4)) * 8 result[i] = (byte)((bl.data[i/4] >> uint(shift)) & 0xFF) } return result } // IterateBytes iterates through all bytes contained in the BitList func (bl *BitList) IterateBytes() <-chan byte { res := make(chan byte) go func() { c := bl.count shift := 24 i := 0 for c > 0 { res <- byte((bl.data[i] >> uint(shift)) & 0xFF) shift -= 8 if shift < 0 { shift = 24 i++ } c -= 8 } close(res) }() return res } ================================================ FILE: vendor/github.com/boombuler/barcode/utils/galoisfield.go ================================================ package utils // GaloisField encapsulates galois field arithmetics type GaloisField struct { Size int Base int ALogTbl []int LogTbl []int } // NewGaloisField creates a new galois field func NewGaloisField(pp, fieldSize, b int) *GaloisField { result := new(GaloisField) result.Size = fieldSize result.Base = b result.ALogTbl = make([]int, fieldSize) result.LogTbl = make([]int, fieldSize) x := 1 for i := 0; i < fieldSize; i++ { result.ALogTbl[i] = x x = x * 2 if x >= fieldSize { x = (x ^ pp) & (fieldSize - 1) } } for i := 0; i < fieldSize; i++ { result.LogTbl[result.ALogTbl[i]] = int(i) } return result } func (gf *GaloisField) Zero() *GFPoly { return NewGFPoly(gf, []int{0}) } // AddOrSub add or substract two numbers func (gf *GaloisField) AddOrSub(a, b int) int { return a ^ b } // Multiply multiplys two numbers func (gf *GaloisField) Multiply(a, b int) int { if a == 0 || b == 0 { return 0 } return gf.ALogTbl[(gf.LogTbl[a]+gf.LogTbl[b])%(gf.Size-1)] } // Divide divides two numbers func (gf *GaloisField) Divide(a, b int) int { if b == 0 { panic("divide by zero") } else if a == 0 { return 0 } return gf.ALogTbl[(gf.LogTbl[a]-gf.LogTbl[b])%(gf.Size-1)] } func (gf *GaloisField) Invers(num int) int { return gf.ALogTbl[(gf.Size-1)-gf.LogTbl[num]] } ================================================ FILE: vendor/github.com/boombuler/barcode/utils/gfpoly.go ================================================ package utils type GFPoly struct { gf *GaloisField Coefficients []int } func (gp *GFPoly) Degree() int { return len(gp.Coefficients) - 1 } func (gp *GFPoly) Zero() bool { return gp.Coefficients[0] == 0 } // GetCoefficient returns the coefficient of x ^ degree func (gp *GFPoly) GetCoefficient(degree int) int { return gp.Coefficients[gp.Degree()-degree] } func (gp *GFPoly) AddOrSubstract(other *GFPoly) *GFPoly { if gp.Zero() { return other } else if other.Zero() { return gp } smallCoeff := gp.Coefficients largeCoeff := other.Coefficients if len(smallCoeff) > len(largeCoeff) { largeCoeff, smallCoeff = smallCoeff, largeCoeff } sumDiff := make([]int, len(largeCoeff)) lenDiff := len(largeCoeff) - len(smallCoeff) copy(sumDiff, largeCoeff[:lenDiff]) for i := lenDiff; i < len(largeCoeff); i++ { sumDiff[i] = int(gp.gf.AddOrSub(int(smallCoeff[i-lenDiff]), int(largeCoeff[i]))) } return NewGFPoly(gp.gf, sumDiff) } func (gp *GFPoly) MultByMonominal(degree int, coeff int) *GFPoly { if coeff == 0 { return gp.gf.Zero() } size := len(gp.Coefficients) result := make([]int, size+degree) for i := 0; i < size; i++ { result[i] = int(gp.gf.Multiply(int(gp.Coefficients[i]), int(coeff))) } return NewGFPoly(gp.gf, result) } func (gp *GFPoly) Multiply(other *GFPoly) *GFPoly { if gp.Zero() || other.Zero() { return gp.gf.Zero() } aCoeff := gp.Coefficients aLen := len(aCoeff) bCoeff := other.Coefficients bLen := len(bCoeff) product := make([]int, aLen+bLen-1) for i := 0; i < aLen; i++ { ac := int(aCoeff[i]) for j := 0; j < bLen; j++ { bc := int(bCoeff[j]) product[i+j] = int(gp.gf.AddOrSub(int(product[i+j]), gp.gf.Multiply(ac, bc))) } } return NewGFPoly(gp.gf, product) } func (gp *GFPoly) Divide(other *GFPoly) (quotient *GFPoly, remainder *GFPoly) { quotient = gp.gf.Zero() remainder = gp fld := gp.gf denomLeadTerm := other.GetCoefficient(other.Degree()) inversDenomLeadTerm := fld.Invers(int(denomLeadTerm)) for remainder.Degree() >= other.Degree() && !remainder.Zero() { degreeDiff := remainder.Degree() - other.Degree() scale := int(fld.Multiply(int(remainder.GetCoefficient(remainder.Degree())), inversDenomLeadTerm)) term := other.MultByMonominal(degreeDiff, scale) itQuot := NewMonominalPoly(fld, degreeDiff, scale) quotient = quotient.AddOrSubstract(itQuot) remainder = remainder.AddOrSubstract(term) } return } func NewMonominalPoly(field *GaloisField, degree int, coeff int) *GFPoly { if coeff == 0 { return field.Zero() } result := make([]int, degree+1) result[0] = coeff return NewGFPoly(field, result) } func NewGFPoly(field *GaloisField, coefficients []int) *GFPoly { for len(coefficients) > 1 && coefficients[0] == 0 { coefficients = coefficients[1:] } return &GFPoly{field, coefficients} } ================================================ FILE: vendor/github.com/boombuler/barcode/utils/reedsolomon.go ================================================ package utils import ( "sync" ) type ReedSolomonEncoder struct { gf *GaloisField polynomes []*GFPoly m *sync.Mutex } func NewReedSolomonEncoder(gf *GaloisField) *ReedSolomonEncoder { return &ReedSolomonEncoder{ gf, []*GFPoly{NewGFPoly(gf, []int{1})}, new(sync.Mutex), } } func (rs *ReedSolomonEncoder) getPolynomial(degree int) *GFPoly { rs.m.Lock() defer rs.m.Unlock() if degree >= len(rs.polynomes) { last := rs.polynomes[len(rs.polynomes)-1] for d := len(rs.polynomes); d <= degree; d++ { next := last.Multiply(NewGFPoly(rs.gf, []int{1, rs.gf.ALogTbl[d-1+rs.gf.Base]})) rs.polynomes = append(rs.polynomes, next) last = next } } return rs.polynomes[degree] } func (rs *ReedSolomonEncoder) Encode(data []int, eccCount int) []int { generator := rs.getPolynomial(eccCount) info := NewGFPoly(rs.gf, data) info = info.MultByMonominal(eccCount, 1) _, remainder := info.Divide(generator) result := make([]int, eccCount) numZero := int(eccCount) - len(remainder.Coefficients) copy(result[numZero:], remainder.Coefficients) return result } ================================================ FILE: vendor/github.com/boombuler/barcode/utils/runeint.go ================================================ package utils // RuneToInt converts a rune between '0' and '9' to an integer between 0 and 9 // If the rune is outside of this range -1 is returned. func RuneToInt(r rune) int { if r >= '0' && r <= '9' { return int(r - '0') } return -1 } // IntToRune converts a digit 0 - 9 to the rune '0' - '9'. If the given int is outside // of this range 'F' is returned! func IntToRune(i int) rune { if i >= 0 && i <= 9 { return rune(i + '0') } return 'F' } ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/.gitignore ================================================ .DS_Store bin ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/.travis.yml ================================================ language: go script: - go vet ./... - go test -v ./... go: - 1.3 - 1.4 - 1.5 - 1.6 - 1.7 - tip ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/LICENSE ================================================ Copyright (c) 2012 Dave Grijalva 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. ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md ================================================ ## Migration Guide from v2 -> v3 Version 3 adds several new, frequently requested features. To do so, it introduces a few breaking changes. We've worked to keep these as minimal as possible. This guide explains the breaking changes and how you can quickly update your code. ### `Token.Claims` is now an interface type The most requested feature from the 2.0 verison of this library was the ability to provide a custom type to the JSON parser for claims. This was implemented by introducing a new interface, `Claims`, to replace `map[string]interface{}`. We also included two concrete implementations of `Claims`: `MapClaims` and `StandardClaims`. `MapClaims` is an alias for `map[string]interface{}` with built in validation behavior. It is the default claims type when using `Parse`. The usage is unchanged except you must type cast the claims property. The old example for parsing a token looked like this.. ```go if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil { fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"]) } ``` is now directly mapped to... ```go if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil { claims := token.Claims.(jwt.MapClaims) fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"]) } ``` `StandardClaims` is designed to be embedded in your custom type. You can supply a custom claims type with the new `ParseWithClaims` function. Here's an example of using a custom claims type. ```go type MyCustomClaims struct { User string *StandardClaims } if token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, keyLookupFunc); err == nil { claims := token.Claims.(*MyCustomClaims) fmt.Printf("Token for user %v expires %v", claims.User, claims.StandardClaims.ExpiresAt) } ``` ### `ParseFromRequest` has been moved To keep this library focused on the tokens without becoming overburdened with complex request processing logic, `ParseFromRequest` and its new companion `ParseFromRequestWithClaims` have been moved to a subpackage, `request`. The method signatues have also been augmented to receive a new argument: `Extractor`. `Extractors` do the work of picking the token string out of a request. The interface is simple and composable. This simple parsing example: ```go if token, err := jwt.ParseFromRequest(tokenString, req, keyLookupFunc); err == nil { fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"]) } ``` is directly mapped to: ```go if token, err := request.ParseFromRequest(req, request.OAuth2Extractor, keyLookupFunc); err == nil { claims := token.Claims.(jwt.MapClaims) fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"]) } ``` There are several concrete `Extractor` types provided for your convenience: * `HeaderExtractor` will search a list of headers until one contains content. * `ArgumentExtractor` will search a list of keys in request query and form arguments until one contains content. * `MultiExtractor` will try a list of `Extractors` in order until one returns content. * `AuthorizationHeaderExtractor` will look in the `Authorization` header for a `Bearer` token. * `OAuth2Extractor` searches the places an OAuth2 token would be specified (per the spec): `Authorization` header and `access_token` argument * `PostExtractionFilter` wraps an `Extractor`, allowing you to process the content before it's parsed. A simple example is stripping the `Bearer ` text from a header ### RSA signing methods no longer accept `[]byte` keys Due to a [critical vulnerability](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/), we've decided the convenience of accepting `[]byte` instead of `rsa.PublicKey` or `rsa.PrivateKey` isn't worth the risk of misuse. To replace this behavior, we've added two helper methods: `ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error)` and `ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error)`. These are just simple helpers for unpacking PEM encoded PKCS1 and PKCS8 keys. If your keys are encoded any other way, all you need to do is convert them to the `crypto/rsa` package's types. ```go func keyLookupFunc(*Token) (interface{}, error) { // Don't forget to validate the alg is what you expect: if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) } // Look up key key, err := lookupPublicKey(token.Header["kid"]) if err != nil { return nil, err } // Unpack key from PEM encoded PKCS8 return jwt.ParseRSAPublicKeyFromPEM(key) } ``` ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/README.md ================================================ A [go](http://www.golang.org) (or 'golang' for search engine friendliness) implementation of [JSON Web Tokens](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html) [![Build Status](https://travis-ci.org/dgrijalva/jwt-go.svg?branch=master)](https://travis-ci.org/dgrijalva/jwt-go) **BREAKING CHANGES:*** Version 3.0.0 is here. It includes _a lot_ of changes including a few that break the API. We've tried to break as few things as possible, so there should just be a few type signature changes. A full list of breaking changes is available in `VERSION_HISTORY.md`. See `MIGRATION_GUIDE.md` for more information on updating your code. **NOTICE:** It's important that you [validate the `alg` presented is what you expect](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). This library attempts to make it easy to do the right thing by requiring key types match the expected alg, but you should take the extra step to verify it in your usage. See the examples provided. ## What the heck is a JWT? JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web Tokens. In short, it's a signed JSON object that does something useful (for example, authentication). It's commonly used for `Bearer` tokens in Oauth 2. A token is made of three parts, separated by `.`'s. The first two parts are JSON objects, that have been [base64url](http://tools.ietf.org/html/rfc4648) encoded. The last part is the signature, encoded the same way. The first part is called the header. It contains the necessary information for verifying the last part, the signature. For example, which encryption method was used for signing and what key was used. The part in the middle is the interesting bit. It's called the Claims and contains the actual stuff you care about. Refer to [the RFC](http://self-issued.info/docs/draft-jones-json-web-token.html) for information about reserved keys and the proper way to add your own. ## What's in the box? This library supports the parsing and verification as well as the generation and signing of JWTs. Current supported signing algorithms are HMAC SHA, RSA, RSA-PSS, and ECDSA, though hooks are present for adding your own. ## Examples See [the project documentation](https://godoc.org/github.com/dgrijalva/jwt-go) for examples of usage: * [Simple example of parsing and validating a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-Parse--Hmac) * [Simple example of building and signing a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-New--Hmac) * [Directory of Examples](https://godoc.org/github.com/dgrijalva/jwt-go#pkg-examples) ## Extensions This library publishes all the necessary components for adding your own signing methods. Simply implement the `SigningMethod` interface and register a factory method using `RegisterSigningMethod`. Here's an example of an extension that integrates with the Google App Engine signing tools: https://github.com/someone1/gcp-jwt-go ## Compliance This library was last reviewed to comply with [RTF 7519](http://www.rfc-editor.org/info/rfc7519) dated May 2015 with a few notable differences: * In order to protect against accidental use of [Unsecured JWTs](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#UnsecuredJWT), tokens using `alg=none` will only be accepted if the constant `jwt.UnsafeAllowNoneSignatureType` is provided as the key. ## Project Status & Versioning This library is considered production ready. Feedback and feature requests are appreciated. The API should be considered stable. There should be very few backwards-incompatible changes outside of major version updates (and only with good reason). This project uses [Semantic Versioning 2.0.0](http://semver.org). Accepted pull requests will land on `master`. Periodically, versions will be tagged from `master`. You can find all the releases on [the project releases page](https://github.com/dgrijalva/jwt-go/releases). While we try to make it obvious when we make breaking changes, there isn't a great mechanism for pushing announcements out to users. You may want to use this alternative package include: `gopkg.in/dgrijalva/jwt-go.v2`. It will do the right thing WRT semantic versioning. ## Usage Tips ### Signing vs Encryption A token is simply a JSON object that is signed by its author. this tells you exactly two things about the data: * The author of the token was in the possession of the signing secret * The data has not been modified since it was signed It's important to know that JWT does not provide encryption, which means anyone who has access to the token can read its contents. If you need to protect (encrypt) the data, there is a companion spec, `JWE`, that provides this functionality. JWE is currently outside the scope of this library. ### Choosing a Signing Method There are several signing methods available, and you should probably take the time to learn about the various options before choosing one. The principal design decision is most likely going to be symmetric vs asymmetric. Symmetric signing methods, such as HSA, use only a single secret. This is probably the simplest signing method to use since any `[]byte` can be used as a valid secret. They are also slightly computationally faster to use, though this rarely is enough to matter. Symmetric signing methods work the best when both producers and consumers of tokens are trusted, or even the same system. Since the same secret is used to both sign and validate tokens, you can't easily distribute the key for validation. Asymmetric signing methods, such as RSA, use different keys for signing and verifying tokens. This makes it possible to produce tokens with a private key, and allow any consumer to access the public key for verification. ### JWT and OAuth It's worth mentioning that OAuth and JWT are not the same thing. A JWT token is simply a signed JSON object. It can be used anywhere such a thing is useful. There is some confusion, though, as JWT is the most common type of bearer token used in OAuth2 authentication. Without going too far down the rabbit hole, here's a description of the interaction of these technologies: * OAuth is a protocol for allowing an identity provider to be separate from the service a user is logging in to. For example, whenever you use Facebook to log into a different service (Yelp, Spotify, etc), you are using OAuth. * OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token. * Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL. ## More Documentation can be found [on godoc.org](http://godoc.org/github.com/dgrijalva/jwt-go). The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in the documentation. ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md ================================================ ## `jwt-go` Version History #### 3.1.0 * Improvements to `jwt` command line tool * Added `SkipClaimsValidation` option to `Parser` * Documentation updates #### 3.0.0 * **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code * Dropped support for `[]byte` keys when using RSA signing methods. This convenience feature could contribute to security vulnerabilities involving mismatched key types with signing methods. * `ParseFromRequest` has been moved to `request` subpackage and usage has changed * The `Claims` property on `Token` is now type `Claims` instead of `map[string]interface{}`. The default value is type `MapClaims`, which is an alias to `map[string]interface{}`. This makes it possible to use a custom type when decoding claims. * Other Additions and Changes * Added `Claims` interface type to allow users to decode the claims into a custom type * Added `ParseWithClaims`, which takes a third argument of type `Claims`. Use this function instead of `Parse` if you have a custom type you'd like to decode into. * Dramatically improved the functionality and flexibility of `ParseFromRequest`, which is now in the `request` subpackage * Added `ParseFromRequestWithClaims` which is the `FromRequest` equivalent of `ParseWithClaims` * Added new interface type `Extractor`, which is used for extracting JWT strings from http requests. Used with `ParseFromRequest` and `ParseFromRequestWithClaims`. * Added several new, more specific, validation errors to error type bitmask * Moved examples from README to executable example files * Signing method registry is now thread safe * Added new property to `ValidationError`, which contains the raw error returned by calls made by parse/verify (such as those returned by keyfunc or json parser) #### 2.7.0 This will likely be the last backwards compatible release before 3.0.0, excluding essential bug fixes. * Added new option `-show` to the `jwt` command that will just output the decoded token without verifying * Error text for expired tokens includes how long it's been expired * Fixed incorrect error returned from `ParseRSAPublicKeyFromPEM` * Documentation updates #### 2.6.0 * Exposed inner error within ValidationError * Fixed validation errors when using UseJSONNumber flag * Added several unit tests #### 2.5.0 * Added support for signing method none. You shouldn't use this. The API tries to make this clear. * Updated/fixed some documentation * Added more helpful error message when trying to parse tokens that begin with `BEARER ` #### 2.4.0 * Added new type, Parser, to allow for configuration of various parsing parameters * You can now specify a list of valid signing methods. Anything outside this set will be rejected. * You can now opt to use the `json.Number` type instead of `float64` when parsing token JSON * Added support for [Travis CI](https://travis-ci.org/dgrijalva/jwt-go) * Fixed some bugs with ECDSA parsing #### 2.3.0 * Added support for ECDSA signing methods * Added support for RSA PSS signing methods (requires go v1.4) #### 2.2.0 * Gracefully handle a `nil` `Keyfunc` being passed to `Parse`. Result will now be the parsed token and an error, instead of a panic. #### 2.1.0 Backwards compatible API change that was missed in 2.0.0. * The `SignedString` method on `Token` now takes `interface{}` instead of `[]byte` #### 2.0.0 There were two major reasons for breaking backwards compatibility with this update. The first was a refactor required to expand the width of the RSA and HMAC-SHA signing implementations. There will likely be no required code changes to support this change. The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods. Not all keys used for all signing methods have a single standard on-disk representation. Requiring `[]byte` as the type for all keys proved too limiting. Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys. Backwards compatibilty has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`. It is likely the only integration change required here will be to change `func(t *jwt.Token) ([]byte, error)` to `func(t *jwt.Token) (interface{}, error)` when calling `Parse`. * **Compatibility Breaking Changes** * `SigningMethodHS256` is now `*SigningMethodHMAC` instead of `type struct` * `SigningMethodRS256` is now `*SigningMethodRSA` instead of `type struct` * `KeyFunc` now returns `interface{}` instead of `[]byte` * `SigningMethod.Sign` now takes `interface{}` instead of `[]byte` for the key * `SigningMethod.Verify` now takes `interface{}` instead of `[]byte` for the key * Renamed type `SigningMethodHS256` to `SigningMethodHMAC`. Specific sizes are now just instances of this type. * Added public package global `SigningMethodHS256` * Added public package global `SigningMethodHS384` * Added public package global `SigningMethodHS512` * Renamed type `SigningMethodRS256` to `SigningMethodRSA`. Specific sizes are now just instances of this type. * Added public package global `SigningMethodRS256` * Added public package global `SigningMethodRS384` * Added public package global `SigningMethodRS512` * Moved sample private key for HMAC tests from an inline value to a file on disk. Value is unchanged. * Refactored the RSA implementation to be easier to read * Exposed helper methods `ParseRSAPrivateKeyFromPEM` and `ParseRSAPublicKeyFromPEM` #### 1.0.2 * Fixed bug in parsing public keys from certificates * Added more tests around the parsing of keys for RS256 * Code refactoring in RS256 implementation. No functional changes #### 1.0.1 * Fixed panic if RS256 signing method was passed an invalid key #### 1.0.0 * First versioned release * API stabilized * Supports creating, signing, parsing, and validating JWT tokens * Supports RS256 and HS256 signing methods ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/claims.go ================================================ package jwt import ( "crypto/subtle" "fmt" "time" ) // For a type to be a Claims object, it must just have a Valid method that determines // if the token is invalid for any supported reason type Claims interface { Valid() error } // Structured version of Claims Section, as referenced at // https://tools.ietf.org/html/rfc7519#section-4.1 // See examples for how to use this with your own claim types type StandardClaims struct { Audience string `json:"aud,omitempty"` ExpiresAt int64 `json:"exp,omitempty"` Id string `json:"jti,omitempty"` IssuedAt int64 `json:"iat,omitempty"` Issuer string `json:"iss,omitempty"` NotBefore int64 `json:"nbf,omitempty"` Subject string `json:"sub,omitempty"` } // Validates time based claims "exp, iat, nbf". // There is no accounting for clock skew. // As well, if any of the above claims are not in the token, it will still // be considered a valid claim. func (c StandardClaims) Valid() error { vErr := new(ValidationError) now := TimeFunc().Unix() // The claims below are optional, by default, so if they are set to the // default value in Go, let's not fail the verification for them. if c.VerifyExpiresAt(now, false) == false { delta := time.Unix(now, 0).Sub(time.Unix(c.ExpiresAt, 0)) vErr.Inner = fmt.Errorf("token is expired by %v", delta) vErr.Errors |= ValidationErrorExpired } if c.VerifyIssuedAt(now, false) == false { vErr.Inner = fmt.Errorf("Token used before issued") vErr.Errors |= ValidationErrorIssuedAt } if c.VerifyNotBefore(now, false) == false { vErr.Inner = fmt.Errorf("token is not valid yet") vErr.Errors |= ValidationErrorNotValidYet } if vErr.valid() { return nil } return vErr } // Compares the aud claim against cmp. // If required is false, this method will return true if the value matches or is unset func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool { return verifyAud(c.Audience, cmp, req) } // Compares the exp claim against cmp. // If required is false, this method will return true if the value matches or is unset func (c *StandardClaims) VerifyExpiresAt(cmp int64, req bool) bool { return verifyExp(c.ExpiresAt, cmp, req) } // Compares the iat claim against cmp. // If required is false, this method will return true if the value matches or is unset func (c *StandardClaims) VerifyIssuedAt(cmp int64, req bool) bool { return verifyIat(c.IssuedAt, cmp, req) } // Compares the iss claim against cmp. // If required is false, this method will return true if the value matches or is unset func (c *StandardClaims) VerifyIssuer(cmp string, req bool) bool { return verifyIss(c.Issuer, cmp, req) } // Compares the nbf claim against cmp. // If required is false, this method will return true if the value matches or is unset func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool { return verifyNbf(c.NotBefore, cmp, req) } // ----- helpers func verifyAud(aud string, cmp string, required bool) bool { if aud == "" { return !required } if subtle.ConstantTimeCompare([]byte(aud), []byte(cmp)) != 0 { return true } else { return false } } func verifyExp(exp int64, now int64, required bool) bool { if exp == 0 { return !required } return now <= exp } func verifyIat(iat int64, now int64, required bool) bool { if iat == 0 { return !required } return now >= iat } func verifyIss(iss string, cmp string, required bool) bool { if iss == "" { return !required } if subtle.ConstantTimeCompare([]byte(iss), []byte(cmp)) != 0 { return true } else { return false } } func verifyNbf(nbf int64, now int64, required bool) bool { if nbf == 0 { return !required } return now >= nbf } ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/doc.go ================================================ // Package jwt is a Go implementation of JSON Web Tokens: http://self-issued.info/docs/draft-jones-json-web-token.html // // See README.md for more info. package jwt ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/ecdsa.go ================================================ package jwt import ( "crypto" "crypto/ecdsa" "crypto/rand" "errors" "math/big" ) var ( // Sadly this is missing from crypto/ecdsa compared to crypto/rsa ErrECDSAVerification = errors.New("crypto/ecdsa: verification error") ) // Implements the ECDSA family of signing methods signing methods type SigningMethodECDSA struct { Name string Hash crypto.Hash KeySize int CurveBits int } // Specific instances for EC256 and company var ( SigningMethodES256 *SigningMethodECDSA SigningMethodES384 *SigningMethodECDSA SigningMethodES512 *SigningMethodECDSA ) func init() { // ES256 SigningMethodES256 = &SigningMethodECDSA{"ES256", crypto.SHA256, 32, 256} RegisterSigningMethod(SigningMethodES256.Alg(), func() SigningMethod { return SigningMethodES256 }) // ES384 SigningMethodES384 = &SigningMethodECDSA{"ES384", crypto.SHA384, 48, 384} RegisterSigningMethod(SigningMethodES384.Alg(), func() SigningMethod { return SigningMethodES384 }) // ES512 SigningMethodES512 = &SigningMethodECDSA{"ES512", crypto.SHA512, 66, 521} RegisterSigningMethod(SigningMethodES512.Alg(), func() SigningMethod { return SigningMethodES512 }) } func (m *SigningMethodECDSA) Alg() string { return m.Name } // Implements the Verify method from SigningMethod // For this verify method, key must be an ecdsa.PublicKey struct func (m *SigningMethodECDSA) Verify(signingString, signature string, key interface{}) error { var err error // Decode the signature var sig []byte if sig, err = DecodeSegment(signature); err != nil { return err } // Get the key var ecdsaKey *ecdsa.PublicKey switch k := key.(type) { case *ecdsa.PublicKey: ecdsaKey = k default: return ErrInvalidKeyType } if len(sig) != 2*m.KeySize { return ErrECDSAVerification } r := big.NewInt(0).SetBytes(sig[:m.KeySize]) s := big.NewInt(0).SetBytes(sig[m.KeySize:]) // Create hasher if !m.Hash.Available() { return ErrHashUnavailable } hasher := m.Hash.New() hasher.Write([]byte(signingString)) // Verify the signature if verifystatus := ecdsa.Verify(ecdsaKey, hasher.Sum(nil), r, s); verifystatus == true { return nil } else { return ErrECDSAVerification } } // Implements the Sign method from SigningMethod // For this signing method, key must be an ecdsa.PrivateKey struct func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string, error) { // Get the key var ecdsaKey *ecdsa.PrivateKey switch k := key.(type) { case *ecdsa.PrivateKey: ecdsaKey = k default: return "", ErrInvalidKeyType } // Create the hasher if !m.Hash.Available() { return "", ErrHashUnavailable } hasher := m.Hash.New() hasher.Write([]byte(signingString)) // Sign the string and return r, s if r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, hasher.Sum(nil)); err == nil { curveBits := ecdsaKey.Curve.Params().BitSize if m.CurveBits != curveBits { return "", ErrInvalidKey } keyBytes := curveBits / 8 if curveBits%8 > 0 { keyBytes += 1 } // We serialize the outpus (r and s) into big-endian byte arrays and pad // them with zeros on the left to make sure the sizes work out. Both arrays // must be keyBytes long, and the output must be 2*keyBytes long. rBytes := r.Bytes() rBytesPadded := make([]byte, keyBytes) copy(rBytesPadded[keyBytes-len(rBytes):], rBytes) sBytes := s.Bytes() sBytesPadded := make([]byte, keyBytes) copy(sBytesPadded[keyBytes-len(sBytes):], sBytes) out := append(rBytesPadded, sBytesPadded...) return EncodeSegment(out), nil } else { return "", err } } ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/ecdsa_utils.go ================================================ package jwt import ( "crypto/ecdsa" "crypto/x509" "encoding/pem" "errors" ) var ( ErrNotECPublicKey = errors.New("Key is not a valid ECDSA public key") ErrNotECPrivateKey = errors.New("Key is not a valid ECDSA private key") ) // Parse PEM encoded Elliptic Curve Private Key Structure func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, 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.ParseECPrivateKey(block.Bytes); err != nil { return nil, err } var pkey *ecdsa.PrivateKey var ok bool if pkey, ok = parsedKey.(*ecdsa.PrivateKey); !ok { return nil, ErrNotECPrivateKey } return pkey, nil } // Parse PEM encoded PKCS1 or PKCS8 public key func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.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 *ecdsa.PublicKey var ok bool if pkey, ok = parsedKey.(*ecdsa.PublicKey); !ok { return nil, ErrNotECPublicKey } return pkey, nil } ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/errors.go ================================================ package jwt import ( "errors" ) // Error constants var ( ErrInvalidKey = errors.New("key is invalid") ErrInvalidKeyType = errors.New("key is of invalid type") ErrHashUnavailable = errors.New("the requested hash function is unavailable") ) // The errors that might occur when parsing and validating a token const ( ValidationErrorMalformed uint32 = 1 << iota // Token is malformed ValidationErrorUnverifiable // Token could not be verified because of signing problems ValidationErrorSignatureInvalid // Signature validation failed // Standard Claim validation errors ValidationErrorAudience // AUD validation failed ValidationErrorExpired // EXP validation failed ValidationErrorIssuedAt // IAT validation failed ValidationErrorIssuer // ISS validation failed ValidationErrorNotValidYet // NBF validation failed ValidationErrorId // JTI validation failed ValidationErrorClaimsInvalid // Generic claims validation error ) // Helper for constructing a ValidationError with a string error message func NewValidationError(errorText string, errorFlags uint32) *ValidationError { return &ValidationError{ text: errorText, Errors: errorFlags, } } // The error from Parse if token is not valid type ValidationError struct { Inner error // stores the error returned by external dependencies, i.e.: KeyFunc Errors uint32 // bitfield. see ValidationError... constants text string // errors that do not have a valid error just have text } // Validation error is an error type func (e ValidationError) Error() string { if e.Inner != nil { return e.Inner.Error() } else if e.text != "" { return e.text } else { return "token is invalid" } } // No errors func (e *ValidationError) valid() bool { return e.Errors == 0 } ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/hmac.go ================================================ package jwt import ( "crypto" "crypto/hmac" "errors" ) // Implements the HMAC-SHA family of signing methods signing methods type SigningMethodHMAC struct { Name string Hash crypto.Hash } // Specific instances for HS256 and company var ( SigningMethodHS256 *SigningMethodHMAC SigningMethodHS384 *SigningMethodHMAC SigningMethodHS512 *SigningMethodHMAC ErrSignatureInvalid = errors.New("signature is invalid") ) func init() { // HS256 SigningMethodHS256 = &SigningMethodHMAC{"HS256", crypto.SHA256} RegisterSigningMethod(SigningMethodHS256.Alg(), func() SigningMethod { return SigningMethodHS256 }) // HS384 SigningMethodHS384 = &SigningMethodHMAC{"HS384", crypto.SHA384} RegisterSigningMethod(SigningMethodHS384.Alg(), func() SigningMethod { return SigningMethodHS384 }) // HS512 SigningMethodHS512 = &SigningMethodHMAC{"HS512", crypto.SHA512} RegisterSigningMethod(SigningMethodHS512.Alg(), func() SigningMethod { return SigningMethodHS512 }) } func (m *SigningMethodHMAC) Alg() string { return m.Name } // Verify the signature of HSXXX tokens. Returns nil if the signature is valid. func (m *SigningMethodHMAC) Verify(signingString, signature string, key interface{}) error { // Verify the key is the right type keyBytes, ok := key.([]byte) if !ok { return ErrInvalidKeyType } // Decode signature, for comparison sig, err := DecodeSegment(signature) if err != nil { return err } // Can we use the specified hashing method? if !m.Hash.Available() { return ErrHashUnavailable } // This signing method is symmetric, so we validate the signature // by reproducing the signature from the signing string and key, then // comparing that against the provided signature. hasher := hmac.New(m.Hash.New, keyBytes) hasher.Write([]byte(signingString)) if !hmac.Equal(sig, hasher.Sum(nil)) { return ErrSignatureInvalid } // No validation errors. Signature is good. return nil } // Implements the Sign method from SigningMethod for this signing method. // Key must be []byte func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, error) { if keyBytes, ok := key.([]byte); ok { if !m.Hash.Available() { return "", ErrHashUnavailable } hasher := hmac.New(m.Hash.New, keyBytes) hasher.Write([]byte(signingString)) return EncodeSegment(hasher.Sum(nil)), nil } return "", ErrInvalidKey } ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/map_claims.go ================================================ package jwt import ( "encoding/json" "errors" // "fmt" ) // Claims type that uses the map[string]interface{} for JSON decoding // This is the default claims type if you don't supply one type MapClaims map[string]interface{} // Compares the aud claim against cmp. // If required is false, this method will return true if the value matches or is unset func (m MapClaims) VerifyAudience(cmp string, req bool) bool { aud, _ := m["aud"].(string) return verifyAud(aud, cmp, req) } // Compares the exp claim against cmp. // If required is false, this method will return true if the value matches or is unset func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool { switch exp := m["exp"].(type) { case float64: return verifyExp(int64(exp), cmp, req) case json.Number: v, _ := exp.Int64() return verifyExp(v, cmp, req) } return req == false } // Compares the iat claim against cmp. // If required is false, this method will return true if the value matches or is unset func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool { switch iat := m["iat"].(type) { case float64: return verifyIat(int64(iat), cmp, req) case json.Number: v, _ := iat.Int64() return verifyIat(v, cmp, req) } return req == false } // Compares the iss claim against cmp. // If required is false, this method will return true if the value matches or is unset func (m MapClaims) VerifyIssuer(cmp string, req bool) bool { iss, _ := m["iss"].(string) return verifyIss(iss, cmp, req) } // Compares the nbf claim against cmp. // If required is false, this method will return true if the value matches or is unset func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool { switch nbf := m["nbf"].(type) { case float64: return verifyNbf(int64(nbf), cmp, req) case json.Number: v, _ := nbf.Int64() return verifyNbf(v, cmp, req) } return req == false } // Validates time based claims "exp, iat, nbf". // There is no accounting for clock skew. // As well, if any of the above claims are not in the token, it will still // be considered a valid claim. func (m MapClaims) Valid() error { vErr := new(ValidationError) now := TimeFunc().Unix() if m.VerifyExpiresAt(now, false) == false { vErr.Inner = errors.New("Token is expired") vErr.Errors |= ValidationErrorExpired } if m.VerifyIssuedAt(now, false) == false { vErr.Inner = errors.New("Token used before issued") vErr.Errors |= ValidationErrorIssuedAt } if m.VerifyNotBefore(now, false) == false { vErr.Inner = errors.New("Token is not valid yet") vErr.Errors |= ValidationErrorNotValidYet } if vErr.valid() { return nil } return vErr } ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/none.go ================================================ package jwt // Implements the none signing method. This is required by the spec // but you probably should never use it. var SigningMethodNone *signingMethodNone const UnsafeAllowNoneSignatureType unsafeNoneMagicConstant = "none signing method allowed" var NoneSignatureTypeDisallowedError error type signingMethodNone struct{} type unsafeNoneMagicConstant string func init() { SigningMethodNone = &signingMethodNone{} NoneSignatureTypeDisallowedError = NewValidationError("'none' signature type is not allowed", ValidationErrorSignatureInvalid) RegisterSigningMethod(SigningMethodNone.Alg(), func() SigningMethod { return SigningMethodNone }) } func (m *signingMethodNone) Alg() string { return "none" } // Only allow 'none' alg type if UnsafeAllowNoneSignatureType is specified as the key func (m *signingMethodNone) Verify(signingString, signature string, key interface{}) (err error) { // Key must be UnsafeAllowNoneSignatureType to prevent accidentally // accepting 'none' signing method if _, ok := key.(unsafeNoneMagicConstant); !ok { return NoneSignatureTypeDisallowedError } // If signing method is none, signature must be an empty string if signature != "" { return NewValidationError( "'none' signing method with non-empty signature", ValidationErrorSignatureInvalid, ) } // Accept 'none' signing method. return nil } // Only allow 'none' signing if UnsafeAllowNoneSignatureType is specified as the key func (m *signingMethodNone) Sign(signingString string, key interface{}) (string, error) { if _, ok := key.(unsafeNoneMagicConstant); ok { return "", nil } return "", NoneSignatureTypeDisallowedError } ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/parser.go ================================================ package jwt import ( "bytes" "encoding/json" "fmt" "strings" ) type Parser struct { ValidMethods []string // If populated, only these methods will be considered valid UseJSONNumber bool // Use JSON Number format in JSON decoder SkipClaimsValidation bool // Skip claims validation during token parsing } // Parse, validate, and return a token. // keyFunc will receive the parsed token and should return the key for validating. // If everything is kosher, err will be nil func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) { return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc) } func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) { parts := strings.Split(tokenString, ".") if len(parts) != 3 { return nil, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed) } var err error token := &Token{Raw: tokenString} // parse Header var headerBytes []byte if headerBytes, err = DecodeSegment(parts[0]); err != nil { if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") { return token, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed) } return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} } if err = json.Unmarshal(headerBytes, &token.Header); err != nil { return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} } // parse Claims var claimBytes []byte token.Claims = claims if claimBytes, err = DecodeSegment(parts[1]); err != nil { return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} } dec := json.NewDecoder(bytes.NewBuffer(claimBytes)) if p.UseJSONNumber { dec.UseNumber() } // JSON Decode. Special case for map type to avoid weird pointer behavior if c, ok := token.Claims.(MapClaims); ok { err = dec.Decode(&c) } else { err = dec.Decode(&claims) } // Handle decode error if err != nil { return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} } // Lookup signature method if method, ok := token.Header["alg"].(string); ok { if token.Method = GetSigningMethod(method); token.Method == nil { return token, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable) } } else { return token, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable) } // Verify signing method is in the required set if p.ValidMethods != nil { var signingMethodValid = false var alg = token.Method.Alg() for _, m := range p.ValidMethods { if m == alg { signingMethodValid = true break } } if !signingMethodValid { // signing method is not in the listed set return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid) } } // Lookup key var key interface{} if keyFunc == nil { // keyFunc was not provided. short circuiting validation return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable) } if key, err = keyFunc(token); err != nil { // keyFunc returned an error return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable} } vErr := &ValidationError{} // Validate Claims if !p.SkipClaimsValidation { if err := token.Claims.Valid(); err != nil { // If the Claims Valid returned an error, check if it is a validation error, // If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set if e, ok := err.(*ValidationError); !ok { vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid} } else { vErr = e } } } // Perform validation token.Signature = parts[2] if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil { vErr.Inner = err vErr.Errors |= ValidationErrorSignatureInvalid } if vErr.valid() { token.Valid = true return token, nil } return token, vErr } ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/rsa.go ================================================ package jwt import ( "crypto" "crypto/rand" "crypto/rsa" ) // Implements the RSA family of signing methods signing methods type SigningMethodRSA struct { Name string Hash crypto.Hash } // Specific instances for RS256 and company var ( SigningMethodRS256 *SigningMethodRSA SigningMethodRS384 *SigningMethodRSA SigningMethodRS512 *SigningMethodRSA ) func init() { // RS256 SigningMethodRS256 = &SigningMethodRSA{"RS256", crypto.SHA256} RegisterSigningMethod(SigningMethodRS256.Alg(), func() SigningMethod { return SigningMethodRS256 }) // RS384 SigningMethodRS384 = &SigningMethodRSA{"RS384", crypto.SHA384} RegisterSigningMethod(SigningMethodRS384.Alg(), func() SigningMethod { return SigningMethodRS384 }) // RS512 SigningMethodRS512 = &SigningMethodRSA{"RS512", crypto.SHA512} RegisterSigningMethod(SigningMethodRS512.Alg(), func() SigningMethod { return SigningMethodRS512 }) } func (m *SigningMethodRSA) Alg() string { return m.Name } // Implements the Verify method from SigningMethod // For this signing method, must be an rsa.PublicKey structure. func (m *SigningMethodRSA) Verify(signingString, signature string, key interface{}) error { var err error // Decode the signature var sig []byte if sig, err = DecodeSegment(signature); err != nil { return err } var rsaKey *rsa.PublicKey var ok bool if rsaKey, ok = key.(*rsa.PublicKey); !ok { return ErrInvalidKeyType } // Create hasher if !m.Hash.Available() { return ErrHashUnavailable } hasher := m.Hash.New() hasher.Write([]byte(signingString)) // Verify the signature return rsa.VerifyPKCS1v15(rsaKey, m.Hash, hasher.Sum(nil), sig) } // Implements the Sign method from SigningMethod // For this signing method, must be an rsa.PrivateKey structure. func (m *SigningMethodRSA) Sign(signingString string, key interface{}) (string, error) { var rsaKey *rsa.PrivateKey var ok bool // Validate type of key if rsaKey, ok = key.(*rsa.PrivateKey); !ok { return "", ErrInvalidKey } // Create the hasher if !m.Hash.Available() { return "", ErrHashUnavailable } hasher := m.Hash.New() hasher.Write([]byte(signingString)) // Sign the string and return the encoded bytes if sigBytes, err := rsa.SignPKCS1v15(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil)); err == nil { return EncodeSegment(sigBytes), nil } else { return "", err } } ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/rsa_pss.go ================================================ // +build go1.4 package jwt import ( "crypto" "crypto/rand" "crypto/rsa" ) // Implements the RSAPSS family of signing methods signing methods type SigningMethodRSAPSS struct { *SigningMethodRSA Options *rsa.PSSOptions } // Specific instances for RS/PS and company var ( SigningMethodPS256 *SigningMethodRSAPSS SigningMethodPS384 *SigningMethodRSAPSS SigningMethodPS512 *SigningMethodRSAPSS ) func init() { // PS256 SigningMethodPS256 = &SigningMethodRSAPSS{ &SigningMethodRSA{ Name: "PS256", Hash: crypto.SHA256, }, &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthAuto, Hash: crypto.SHA256, }, } RegisterSigningMethod(SigningMethodPS256.Alg(), func() SigningMethod { return SigningMethodPS256 }) // PS384 SigningMethodPS384 = &SigningMethodRSAPSS{ &SigningMethodRSA{ Name: "PS384", Hash: crypto.SHA384, }, &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthAuto, Hash: crypto.SHA384, }, } RegisterSigningMethod(SigningMethodPS384.Alg(), func() SigningMethod { return SigningMethodPS384 }) // PS512 SigningMethodPS512 = &SigningMethodRSAPSS{ &SigningMethodRSA{ Name: "PS512", Hash: crypto.SHA512, }, &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthAuto, Hash: crypto.SHA512, }, } RegisterSigningMethod(SigningMethodPS512.Alg(), func() SigningMethod { return SigningMethodPS512 }) } // Implements the Verify method from SigningMethod // For this verify method, key must be an rsa.PublicKey struct func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interface{}) error { var err error // Decode the signature var sig []byte if sig, err = DecodeSegment(signature); err != nil { return err } var rsaKey *rsa.PublicKey switch k := key.(type) { case *rsa.PublicKey: rsaKey = k default: return ErrInvalidKey } // Create hasher if !m.Hash.Available() { return ErrHashUnavailable } hasher := m.Hash.New() hasher.Write([]byte(signingString)) return rsa.VerifyPSS(rsaKey, m.Hash, hasher.Sum(nil), sig, m.Options) } // Implements the Sign method from SigningMethod // For this signing method, key must be an rsa.PrivateKey struct func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) (string, error) { var rsaKey *rsa.PrivateKey switch k := key.(type) { case *rsa.PrivateKey: rsaKey = k default: return "", ErrInvalidKeyType } // Create the hasher if !m.Hash.Available() { return "", ErrHashUnavailable } hasher := m.Hash.New() hasher.Write([]byte(signingString)) // Sign the string and return the encoded bytes if sigBytes, err := rsa.SignPSS(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil), m.Options); err == nil { return EncodeSegment(sigBytes), nil } else { return "", err } } ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/rsa_utils.go ================================================ package jwt import ( "crypto/rsa" "crypto/x509" "encoding/pem" "errors" ) 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") ) // Parse 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 } // Parse 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 } ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/signing_method.go ================================================ package jwt import ( "sync" ) var signingMethods = map[string]func() SigningMethod{} var signingMethodLock = new(sync.RWMutex) // Implement SigningMethod to add new methods for signing or verifying tokens. type SigningMethod interface { Verify(signingString, signature string, key interface{}) error // Returns nil if signature is valid Sign(signingString string, key interface{}) (string, error) // Returns encoded signature or error Alg() string // returns the alg identifier for this method (example: 'HS256') } // Register the "alg" name and a factory function for signing method. // This is typically done during init() in the method's implementation func RegisterSigningMethod(alg string, f func() SigningMethod) { signingMethodLock.Lock() defer signingMethodLock.Unlock() signingMethods[alg] = f } // Get a signing method from an "alg" string func GetSigningMethod(alg string) (method SigningMethod) { signingMethodLock.RLock() defer signingMethodLock.RUnlock() if methodF, ok := signingMethods[alg]; ok { method = methodF() } return } ================================================ FILE: vendor/github.com/dgrijalva/jwt-go/token.go ================================================ package jwt import ( "encoding/base64" "encoding/json" "strings" "time" ) // TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time). // You can override it to use another time value. This is useful for testing or if your // server uses a different time zone than your tokens. var TimeFunc = time.Now // Parse methods use this callback function to supply // the key for verification. The function receives the parsed, // but unverified Token. This allows you to use properties in the // Header of the token (such as `kid`) to identify which key to use. type Keyfunc func(*Token) (interface{}, error) // A JWT Token. Different fields will be used depending on whether you're // creating or parsing/verifying a token. type Token struct { Raw string // The raw token. Populated when you Parse a token Method SigningMethod // The signing method used or to be used Header map[string]interface{} // The first segment of the token Claims Claims // The second segment of the token Signature string // The third segment of the token. Populated when you Parse a token Valid bool // Is the token valid? Populated when you Parse/Verify a token } // Create a new Token. Takes a signing method func New(method SigningMethod) *Token { return NewWithClaims(method, MapClaims{}) } func NewWithClaims(method SigningMethod, claims Claims) *Token { return &Token{ Header: map[string]interface{}{ "typ": "JWT", "alg": method.Alg(), }, Claims: claims, Method: method, } } // Get the complete, signed token func (t *Token) SignedString(key interface{}) (string, error) { var sig, sstr string var err error if sstr, err = t.SigningString(); err != nil { return "", err } if sig, err = t.Method.Sign(sstr, key); err != nil { return "", err } return strings.Join([]string{sstr, sig}, "."), nil } // Generate the signing string. This is the // most expensive part of the whole deal. Unless you // need this for something special, just go straight for // the SignedString. func (t *Token) SigningString() (string, error) { var err error parts := make([]string, 2) for i, _ := range parts { var jsonValue []byte if i == 0 { if jsonValue, err = json.Marshal(t.Header); err != nil { return "", err } } else { if jsonValue, err = json.Marshal(t.Claims); err != nil { return "", err } } parts[i] = EncodeSegment(jsonValue) } return strings.Join(parts, "."), nil } // Parse, validate, and return a token. // keyFunc will receive the parsed token and should return the key for validating. // If everything is kosher, err will be nil func Parse(tokenString string, keyFunc Keyfunc) (*Token, error) { return new(Parser).Parse(tokenString, keyFunc) } func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) { return new(Parser).ParseWithClaims(tokenString, claims, keyFunc) } // Encode JWT specific base64url encoding with padding stripped func EncodeSegment(seg []byte) string { return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=") } // Decode JWT specific base64url encoding with padding stripped func DecodeSegment(seg string) ([]byte, error) { if l := len(seg) % 4; l > 0 { seg += strings.Repeat("=", 4-l) } return base64.URLEncoding.DecodeString(seg) } ================================================ FILE: vendor/github.com/gin-contrib/sse/.travis.yml ================================================ language: go sudo: false go: - 1.8.x - 1.9.x - 1.10.x - 1.11.x - 1.12.x - master git: depth: 10 matrix: fast_finish: true include: - go: 1.11.x env: GO111MODULE=on - go: 1.12.x env: GO111MODULE=on script: - go test -v -covermode=count -coverprofile=coverage.out after_success: - bash <(curl -s https://codecov.io/bash) ================================================ FILE: vendor/github.com/gin-contrib/sse/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Manuel Martínez-Almeida 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. ================================================ FILE: vendor/github.com/gin-contrib/sse/README.md ================================================ # Server-Sent Events [![GoDoc](https://godoc.org/github.com/gin-contrib/sse?status.svg)](https://godoc.org/github.com/gin-contrib/sse) [![Build Status](https://travis-ci.org/gin-contrib/sse.svg)](https://travis-ci.org/gin-contrib/sse) [![codecov](https://codecov.io/gh/gin-contrib/sse/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-contrib/sse) [![Go Report Card](https://goreportcard.com/badge/github.com/gin-contrib/sse)](https://goreportcard.com/report/github.com/gin-contrib/sse) Server-sent events (SSE) is a technology where a browser receives automatic updates from a server via HTTP connection. The Server-Sent Events EventSource API is [standardized as part of HTML5[1] by the W3C](http://www.w3.org/TR/2009/WD-eventsource-20091029/). - [Read this great SSE introduction by the HTML5Rocks guys](http://www.html5rocks.com/en/tutorials/eventsource/basics/) - [Browser support](http://caniuse.com/#feat=eventsource) ## Sample code ```go import "github.com/gin-contrib/sse" func httpHandler(w http.ResponseWriter, req *http.Request) { // data can be a primitive like a string, an integer or a float sse.Encode(w, sse.Event{ Event: "message", Data: "some data\nmore data", }) // also a complex type, like a map, a struct or a slice sse.Encode(w, sse.Event{ Id: "124", Event: "message", Data: map[string]interface{}{ "user": "manu", "date": time.Now().Unix(), "content": "hi!", }, }) } ``` ``` event: message data: some data\\nmore data id: 124 event: message data: {"content":"hi!","date":1431540810,"user":"manu"} ``` ## Content-Type ```go fmt.Println(sse.ContentType) ``` ``` text/event-stream ``` ## Decoding support There is a client-side implementation of SSE coming soon. ================================================ FILE: vendor/github.com/gin-contrib/sse/go.mod ================================================ module github.com/gin-contrib/sse go 1.12 require github.com/stretchr/testify v1.3.0 ================================================ FILE: vendor/github.com/gin-contrib/sse/go.sum ================================================ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= ================================================ FILE: vendor/github.com/gin-contrib/sse/sse-decoder.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package sse import ( "bytes" "io" "io/ioutil" ) type decoder struct { events []Event } func Decode(r io.Reader) ([]Event, error) { var dec decoder return dec.decode(r) } func (d *decoder) dispatchEvent(event Event, data string) { dataLength := len(data) if dataLength > 0 { //If the data buffer's last character is a U+000A LINE FEED (LF) character, then remove the last character from the data buffer. data = data[:dataLength-1] dataLength-- } if dataLength == 0 && event.Event == "" { return } if event.Event == "" { event.Event = "message" } event.Data = data d.events = append(d.events, event) } func (d *decoder) decode(r io.Reader) ([]Event, error) { buf, err := ioutil.ReadAll(r) if err != nil { return nil, err } var currentEvent Event var dataBuffer *bytes.Buffer = new(bytes.Buffer) // TODO (and unit tests) // Lines must be separated by either a U+000D CARRIAGE RETURN U+000A LINE FEED (CRLF) character pair, // a single U+000A LINE FEED (LF) character, // or a single U+000D CARRIAGE RETURN (CR) character. lines := bytes.Split(buf, []byte{'\n'}) for _, line := range lines { if len(line) == 0 { // If the line is empty (a blank line). Dispatch the event. d.dispatchEvent(currentEvent, dataBuffer.String()) // reset current event and data buffer currentEvent = Event{} dataBuffer.Reset() continue } if line[0] == byte(':') { // If the line starts with a U+003A COLON character (:), ignore the line. continue } var field, value []byte colonIndex := bytes.IndexRune(line, ':') if colonIndex != -1 { // If the line contains a U+003A COLON character character (:) // Collect the characters on the line before the first U+003A COLON character (:), // and let field be that string. field = line[:colonIndex] // Collect the characters on the line after the first U+003A COLON character (:), // and let value be that string. value = line[colonIndex+1:] // If value starts with a single U+0020 SPACE character, remove it from value. if len(value) > 0 && value[0] == ' ' { value = value[1:] } } else { // Otherwise, the string is not empty but does not contain a U+003A COLON character character (:) // Use the whole line as the field name, and the empty string as the field value. field = line value = []byte{} } // The steps to process the field given a field name and a field value depend on the field name, // as given in the following list. Field names must be compared literally, // with no case folding performed. switch string(field) { case "event": // Set the event name buffer to field value. currentEvent.Event = string(value) case "id": // Set the event stream's last event ID to the field value. currentEvent.Id = string(value) case "retry": // If the field value consists of only characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), // then interpret the field value as an integer in base ten, and set the event stream's reconnection time to that integer. // Otherwise, ignore the field. currentEvent.Id = string(value) case "data": // Append the field value to the data buffer, dataBuffer.Write(value) // then append a single U+000A LINE FEED (LF) character to the data buffer. dataBuffer.WriteString("\n") default: //Otherwise. The field is ignored. continue } } // Once the end of the file is reached, the user agent must dispatch the event one final time. d.dispatchEvent(currentEvent, dataBuffer.String()) return d.events, nil } ================================================ FILE: vendor/github.com/gin-contrib/sse/sse-encoder.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package sse import ( "encoding/json" "fmt" "io" "net/http" "reflect" "strconv" "strings" ) // Server-Sent Events // W3C Working Draft 29 October 2009 // http://www.w3.org/TR/2009/WD-eventsource-20091029/ const ContentType = "text/event-stream" var contentType = []string{ContentType} var noCache = []string{"no-cache"} var fieldReplacer = strings.NewReplacer( "\n", "\\n", "\r", "\\r") var dataReplacer = strings.NewReplacer( "\n", "\ndata:", "\r", "\\r") type Event struct { Event string Id string Retry uint Data interface{} } func Encode(writer io.Writer, event Event) error { w := checkWriter(writer) writeId(w, event.Id) writeEvent(w, event.Event) writeRetry(w, event.Retry) return writeData(w, event.Data) } func writeId(w stringWriter, id string) { if len(id) > 0 { w.WriteString("id:") fieldReplacer.WriteString(w, id) w.WriteString("\n") } } func writeEvent(w stringWriter, event string) { if len(event) > 0 { w.WriteString("event:") fieldReplacer.WriteString(w, event) w.WriteString("\n") } } func writeRetry(w stringWriter, retry uint) { if retry > 0 { w.WriteString("retry:") w.WriteString(strconv.FormatUint(uint64(retry), 10)) w.WriteString("\n") } } func writeData(w stringWriter, data interface{}) error { w.WriteString("data:") switch kindOfData(data) { case reflect.Struct, reflect.Slice, reflect.Map: err := json.NewEncoder(w).Encode(data) if err != nil { return err } w.WriteString("\n") default: dataReplacer.WriteString(w, fmt.Sprint(data)) w.WriteString("\n\n") } return nil } func (r Event) Render(w http.ResponseWriter) error { r.WriteContentType(w) return Encode(w, r) } func (r Event) WriteContentType(w http.ResponseWriter) { header := w.Header() header["Content-Type"] = contentType if _, exist := header["Cache-Control"]; !exist { header["Cache-Control"] = noCache } } func kindOfData(data interface{}) reflect.Kind { value := reflect.ValueOf(data) valueType := value.Kind() if valueType == reflect.Ptr { valueType = value.Elem().Kind() } return valueType } ================================================ FILE: vendor/github.com/gin-contrib/sse/writer.go ================================================ package sse import "io" type stringWriter interface { io.Writer WriteString(string) (int, error) } type stringWrapper struct { io.Writer } func (w stringWrapper) WriteString(str string) (int, error) { return w.Writer.Write([]byte(str)) } func checkWriter(writer io.Writer) stringWriter { if w, ok := writer.(stringWriter); ok { return w } else { return stringWrapper{writer} } } ================================================ FILE: vendor/github.com/gin-gonic/gin/.gitignore ================================================ vendor/* !vendor/vendor.json coverage.out count.out test profile.out tmp.out ================================================ FILE: vendor/github.com/gin-gonic/gin/.travis.yml ================================================ language: go matrix: fast_finish: true include: - go: 1.8.x - go: 1.9.x - go: 1.10.x - go: 1.11.x env: GO111MODULE=on - go: 1.12.x env: GO111MODULE=on - go: master env: GO111MODULE=on git: depth: 10 before_install: - if [[ "${GO111MODULE}" = "on" ]]; then mkdir "${HOME}/go"; export GOPATH="${HOME}/go"; fi install: - if [[ "${GO111MODULE}" = "on" ]]; then go mod download; else make install; fi - if [[ "${GO111MODULE}" = "on" ]]; then export PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}"; fi - if [[ "${GO111MODULE}" = "on" ]]; then make tools; fi go_import_path: github.com/gin-gonic/gin script: - make vet - make fmt-check - make misspell-check - make test after_success: - bash <(curl -s https://codecov.io/bash) notifications: webhooks: urls: - https://webhooks.gitter.im/e/7f95bf605c4d356372f4 on_success: change # options: [always|never|change] default: always on_failure: always # options: [always|never|change] default: always on_start: false # default: false ================================================ FILE: vendor/github.com/gin-gonic/gin/AUTHORS.md ================================================ List of all the awesome people working to make Gin the best Web Framework in Go. ## gin 1.x series authors **Gin Core Team:** Bo-Yi Wu (@appleboy), 田欧 (@thinkerou), Javier Provecho (@javierprovecho) ## gin 0.x series authors **Maintainers:** Manu Martinez-Almeida (@manucorporat), Javier Provecho (@javierprovecho) People and companies, who have contributed, in alphabetical order. **@858806258 (杰哥)** - Fix typo in example **@achedeuzot (Klemen Sever)** - Fix newline debug printing **@adammck (Adam Mckaig)** - Add MIT license **@AlexanderChen1989 (Alexander)** - Typos in README **@alexanderdidenko (Aleksandr Didenko)** - Add support multipart/form-data **@alexandernyquist (Alexander Nyquist)** - Using template.Must to fix multiple return issue - ★ Added support for OPTIONS verb - ★ Setting response headers before calling WriteHeader - Improved documentation for model binding - ★ Added Content.Redirect() - ★ Added tons of Unit tests **@austinheap (Austin Heap)** - Added travis CI integration **@andredublin (Andre Dublin)** - Fix typo in comment **@bredov (Ludwig Valda Vasquez)** - Fix html templating in debug mode **@bluele (Jun Kimura)** - Fixes code examples in README **@chad-russell** - ★ Support for serializing gin.H into XML **@dickeyxxx (Jeff Dickey)** - Typos in README - Add example about serving static files **@donileo (Adonis)** - Add NoMethod handler **@dutchcoders (DutchCoders)** - ★ Fix security bug that allows client to spoof ip - Fix typo. r.HTMLTemplates -> SetHTMLTemplate **@el3ctro- (Joshua Loper)** - Fix typo in example **@ethankan (Ethan Kan)** - Unsigned integers in binding **(Evgeny Persienko)** - Validate sub structures **@frankbille (Frank Bille)** - Add support for HTTP Realm Auth **@fmd (Fareed Dudhia)** - Fix typo. SetHTTPTemplate -> SetHTMLTemplate **@ironiridis (Christopher Harrington)** - Remove old reference **@jammie-stackhouse (Jamie Stackhouse)** - Add more shortcuts for router methods **@jasonrhansen** - Fix spelling and grammar errors in documentation **@JasonSoft (Jason Lee)** - Fix typo in comment **@joiggama (Ignacio Galindo)** - Add utf-8 charset header on renders **@julienschmidt (Julien Schmidt)** - gofmt the code examples **@kelcecil (Kel Cecil)** - Fix readme typo **@kyledinh (Kyle Dinh)** - Adds RunTLS() **@LinusU (Linus Unnebäck)** - Small fixes in README **@loongmxbt (Saint Asky)** - Fix typo in example **@lucas-clemente (Lucas Clemente)** - ★ work around path.Join removing trailing slashes from routes **@mattn (Yasuhiro Matsumoto)** - Improve color logger **@mdigger (Dmitry Sedykh)** - Fixes Form binding when content-type is x-www-form-urlencoded - No repeat call c.Writer.Status() in gin.Logger - Fixes Content-Type for json render **@mirzac (Mirza Ceric)** - Fix debug printing **@mopemope (Yutaka Matsubara)** - ★ Adds Godep support (Dependencies Manager) - Fix variadic parameter in the flexible render API - Fix Corrupted plain render - Add Pluggable View Renderer Example **@msemenistyi (Mykyta Semenistyi)** - update Readme.md. Add code to String method **@msoedov (Sasha Myasoedov)** - ★ Adds tons of unit tests. **@ngerakines (Nick Gerakines)** - ★ Improves API, c.GET() doesn't panic - Adds MustGet() method **@r8k (Rajiv Kilaparti)** - Fix Port usage in README. **@rayrod2030 (Ray Rodriguez)** - Fix typo in example **@rns** - Fix typo in example **@RobAWilkinson (Robert Wilkinson)** - Add example of forms and params **@rogierlommers (Rogier Lommers)** - Add updated static serve example **@se77en (Damon Zhao)** - Improve color logging **@silasb (Silas Baronda)** - Fixing quotes in README **@SkuliOskarsson (Skuli Oskarsson)** - Fixes some texts in README II **@slimmy (Jimmy Pettersson)** - Added messages for required bindings **@smira (Andrey Smirnov)** - Add support for ignored/unexported fields in binding **@superalsrk (SRK.Lyu)** - Update httprouter godeps **@tebeka (Miki Tebeka)** - Use net/http constants instead of numeric values **@techjanitor** - Update context.go reserved IPs **@yosssi (Keiji Yoshida)** - Fix link in README **@yuyabee** - Fixed README ================================================ FILE: vendor/github.com/gin-gonic/gin/BENCHMARKS.md ================================================ ## Benchmark System **VM HOST:** DigitalOcean **Machine:** 4 CPU, 8 GB RAM. Ubuntu 16.04.2 x64 **Date:** July 19th, 2017 **Go Version:** 1.8.3 linux/amd64 **Source:** [Go HTTP Router Benchmark](https://github.com/julienschmidt/go-http-routing-benchmark) ## Static Routes: 157 ``` Gin: 30512 Bytes HttpServeMux: 17344 Bytes Ace: 30080 Bytes Bear: 30472 Bytes Beego: 96408 Bytes Bone: 37904 Bytes Denco: 10464 Bytes Echo: 73680 Bytes GocraftWeb: 55720 Bytes Goji: 27200 Bytes Gojiv2: 104464 Bytes GoJsonRest: 136472 Bytes GoRestful: 914904 Bytes GorillaMux: 675568 Bytes HttpRouter: 21128 Bytes HttpTreeMux: 73448 Bytes Kocha: 115072 Bytes LARS: 30120 Bytes Macaron: 37984 Bytes Martini: 310832 Bytes Pat: 20464 Bytes Possum: 91328 Bytes R2router: 23712 Bytes Rivet: 23880 Bytes Tango: 28008 Bytes TigerTonic: 80368 Bytes Traffic: 626480 Bytes Vulcan: 369064 Bytes ``` ## GithubAPI Routes: 203 ``` Gin: 52672 Bytes Ace: 48992 Bytes Bear: 161592 Bytes Beego: 147992 Bytes Bone: 97728 Bytes Denco: 36440 Bytes Echo: 95672 Bytes GocraftWeb: 95640 Bytes Goji: 86088 Bytes Gojiv2: 144392 Bytes GoJsonRest: 134648 Bytes GoRestful: 1410760 Bytes GorillaMux: 1509488 Bytes HttpRouter: 37464 Bytes HttpTreeMux: 78800 Bytes Kocha: 785408 Bytes LARS: 49032 Bytes Macaron: 132712 Bytes Martini: 564352 Bytes Pat: 21200 Bytes Possum: 83888 Bytes R2router: 47104 Bytes Rivet: 42840 Bytes Tango: 54584 Bytes TigerTonic: 96384 Bytes Traffic: 1061920 Bytes Vulcan: 465296 Bytes ``` ## GPlusAPI Routes: 13 ``` Gin: 3968 Bytes Ace: 3600 Bytes Bear: 7112 Bytes Beego: 10048 Bytes Bone: 6480 Bytes Denco: 3256 Bytes Echo: 9000 Bytes GocraftWeb: 7496 Bytes Goji: 2912 Bytes Gojiv2: 7376 Bytes GoJsonRest: 11544 Bytes GoRestful: 88776 Bytes GorillaMux: 71488 Bytes HttpRouter: 2712 Bytes HttpTreeMux: 7440 Bytes Kocha: 128880 Bytes LARS: 3640 Bytes Macaron: 8656 Bytes Martini: 23936 Bytes Pat: 1856 Bytes Possum: 7248 Bytes R2router: 3928 Bytes Rivet: 3064 Bytes Tango: 4912 Bytes TigerTonic: 9408 Bytes Traffic: 49472 Bytes Vulcan: 25496 Bytes ``` ## ParseAPI Routes: 26 ``` Gin: 6928 Bytes Ace: 6592 Bytes Bear: 12320 Bytes Beego: 18960 Bytes Bone: 11024 Bytes Denco: 4184 Bytes Echo: 11168 Bytes GocraftWeb: 12800 Bytes Goji: 5232 Bytes Gojiv2: 14464 Bytes GoJsonRest: 14216 Bytes GoRestful: 127368 Bytes GorillaMux: 123016 Bytes HttpRouter: 4976 Bytes HttpTreeMux: 7848 Bytes Kocha: 181712 Bytes LARS: 6632 Bytes Macaron: 13648 Bytes Martini: 45952 Bytes Pat: 2560 Bytes Possum: 9200 Bytes R2router: 7056 Bytes Rivet: 5680 Bytes Tango: 8664 Bytes TigerTonic: 9840 Bytes Traffic: 93480 Bytes Vulcan: 44504 Bytes ``` ## Static Routes ``` BenchmarkGin_StaticAll 50000 34506 ns/op 0 B/op 0 allocs/op BenchmarkAce_StaticAll 30000 49657 ns/op 0 B/op 0 allocs/op BenchmarkHttpServeMux_StaticAll 2000 1183737 ns/op 96 B/op 8 allocs/op BenchmarkBeego_StaticAll 5000 412621 ns/op 57776 B/op 628 allocs/op BenchmarkBear_StaticAll 10000 149242 ns/op 20336 B/op 461 allocs/op BenchmarkBone_StaticAll 10000 118583 ns/op 0 B/op 0 allocs/op BenchmarkDenco_StaticAll 100000 13247 ns/op 0 B/op 0 allocs/op BenchmarkEcho_StaticAll 20000 79914 ns/op 5024 B/op 157 allocs/op BenchmarkGocraftWeb_StaticAll 10000 211823 ns/op 46440 B/op 785 allocs/op BenchmarkGoji_StaticAll 10000 109390 ns/op 0 B/op 0 allocs/op BenchmarkGojiv2_StaticAll 3000 415533 ns/op 145696 B/op 1099 allocs/op BenchmarkGoJsonRest_StaticAll 5000 364403 ns/op 51653 B/op 1727 allocs/op BenchmarkGoRestful_StaticAll 500 2578579 ns/op 314936 B/op 3144 allocs/op BenchmarkGorillaMux_StaticAll 500 2704856 ns/op 115648 B/op 1578 allocs/op BenchmarkHttpRouter_StaticAll 100000 18541 ns/op 0 B/op 0 allocs/op BenchmarkHttpTreeMux_StaticAll 100000 22332 ns/op 0 B/op 0 allocs/op BenchmarkKocha_StaticAll 50000 31176 ns/op 0 B/op 0 allocs/op BenchmarkLARS_StaticAll 50000 40840 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_StaticAll 5000 517656 ns/op 120576 B/op 1413 allocs/op BenchmarkMartini_StaticAll 300 4462289 ns/op 125442 B/op 1717 allocs/op BenchmarkPat_StaticAll 500 2157275 ns/op 533904 B/op 11123 allocs/op BenchmarkPossum_StaticAll 10000 254701 ns/op 65312 B/op 471 allocs/op BenchmarkR2router_StaticAll 10000 133956 ns/op 22608 B/op 628 allocs/op BenchmarkRivet_StaticAll 30000 46812 ns/op 0 B/op 0 allocs/op BenchmarkTango_StaticAll 5000 390613 ns/op 39225 B/op 1256 allocs/op BenchmarkTigerTonic_StaticAll 20000 88060 ns/op 7504 B/op 157 allocs/op BenchmarkTraffic_StaticAll 500 2910236 ns/op 729736 B/op 14287 allocs/op BenchmarkVulcan_StaticAll 5000 277366 ns/op 15386 B/op 471 allocs/op ``` ## Micro Benchmarks ``` BenchmarkGin_Param 20000000 113 ns/op 0 B/op 0 allocs/op BenchmarkAce_Param 5000000 375 ns/op 32 B/op 1 allocs/op BenchmarkBear_Param 1000000 1709 ns/op 456 B/op 5 allocs/op BenchmarkBeego_Param 1000000 2484 ns/op 368 B/op 4 allocs/op BenchmarkBone_Param 1000000 2391 ns/op 688 B/op 5 allocs/op BenchmarkDenco_Param 10000000 240 ns/op 32 B/op 1 allocs/op BenchmarkEcho_Param 5000000 366 ns/op 32 B/op 1 allocs/op BenchmarkGocraftWeb_Param 1000000 2343 ns/op 648 B/op 8 allocs/op BenchmarkGoji_Param 1000000 1197 ns/op 336 B/op 2 allocs/op BenchmarkGojiv2_Param 1000000 2771 ns/op 944 B/op 8 allocs/op BenchmarkGoJsonRest_Param 1000000 2993 ns/op 649 B/op 13 allocs/op BenchmarkGoRestful_Param 200000 8860 ns/op 2296 B/op 21 allocs/op BenchmarkGorillaMux_Param 500000 4461 ns/op 1056 B/op 11 allocs/op BenchmarkHttpRouter_Param 10000000 175 ns/op 32 B/op 1 allocs/op BenchmarkHttpTreeMux_Param 1000000 1167 ns/op 352 B/op 3 allocs/op BenchmarkKocha_Param 3000000 429 ns/op 56 B/op 3 allocs/op BenchmarkLARS_Param 10000000 134 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_Param 500000 4635 ns/op 1056 B/op 10 allocs/op BenchmarkMartini_Param 200000 9933 ns/op 1072 B/op 10 allocs/op BenchmarkPat_Param 1000000 2929 ns/op 648 B/op 12 allocs/op BenchmarkPossum_Param 1000000 2503 ns/op 560 B/op 6 allocs/op BenchmarkR2router_Param 1000000 1507 ns/op 432 B/op 5 allocs/op BenchmarkRivet_Param 5000000 297 ns/op 48 B/op 1 allocs/op BenchmarkTango_Param 1000000 1862 ns/op 248 B/op 8 allocs/op BenchmarkTigerTonic_Param 500000 5660 ns/op 992 B/op 17 allocs/op BenchmarkTraffic_Param 200000 8408 ns/op 1960 B/op 21 allocs/op BenchmarkVulcan_Param 2000000 963 ns/op 98 B/op 3 allocs/op BenchmarkAce_Param5 2000000 740 ns/op 160 B/op 1 allocs/op BenchmarkBear_Param5 1000000 2777 ns/op 501 B/op 5 allocs/op BenchmarkBeego_Param5 1000000 3740 ns/op 368 B/op 4 allocs/op BenchmarkBone_Param5 1000000 2950 ns/op 736 B/op 5 allocs/op BenchmarkDenco_Param5 2000000 644 ns/op 160 B/op 1 allocs/op BenchmarkEcho_Param5 3000000 558 ns/op 32 B/op 1 allocs/op BenchmarkGin_Param5 10000000 198 ns/op 0 B/op 0 allocs/op BenchmarkGocraftWeb_Param5 500000 3870 ns/op 920 B/op 11 allocs/op BenchmarkGoji_Param5 1000000 1746 ns/op 336 B/op 2 allocs/op BenchmarkGojiv2_Param5 1000000 3214 ns/op 1008 B/op 8 allocs/op BenchmarkGoJsonRest_Param5 500000 5509 ns/op 1097 B/op 16 allocs/op BenchmarkGoRestful_Param5 200000 11232 ns/op 2392 B/op 21 allocs/op BenchmarkGorillaMux_Param5 300000 7777 ns/op 1184 B/op 11 allocs/op BenchmarkHttpRouter_Param5 3000000 631 ns/op 160 B/op 1 allocs/op BenchmarkHttpTreeMux_Param5 1000000 2800 ns/op 576 B/op 6 allocs/op BenchmarkKocha_Param5 1000000 2053 ns/op 440 B/op 10 allocs/op BenchmarkLARS_Param5 10000000 232 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_Param5 500000 5888 ns/op 1056 B/op 10 allocs/op BenchmarkMartini_Param5 200000 12807 ns/op 1232 B/op 11 allocs/op BenchmarkPat_Param5 300000 7320 ns/op 964 B/op 32 allocs/op BenchmarkPossum_Param5 1000000 2495 ns/op 560 B/op 6 allocs/op BenchmarkR2router_Param5 1000000 1844 ns/op 432 B/op 5 allocs/op BenchmarkRivet_Param5 2000000 935 ns/op 240 B/op 1 allocs/op BenchmarkTango_Param5 1000000 2327 ns/op 360 B/op 8 allocs/op BenchmarkTigerTonic_Param5 100000 18514 ns/op 2551 B/op 43 allocs/op BenchmarkTraffic_Param5 200000 11997 ns/op 2248 B/op 25 allocs/op BenchmarkVulcan_Param5 1000000 1333 ns/op 98 B/op 3 allocs/op BenchmarkAce_Param20 1000000 2031 ns/op 640 B/op 1 allocs/op BenchmarkBear_Param20 200000 7285 ns/op 1664 B/op 5 allocs/op BenchmarkBeego_Param20 300000 6224 ns/op 368 B/op 4 allocs/op BenchmarkBone_Param20 200000 8023 ns/op 1903 B/op 5 allocs/op BenchmarkDenco_Param20 1000000 2262 ns/op 640 B/op 1 allocs/op BenchmarkEcho_Param20 1000000 1387 ns/op 32 B/op 1 allocs/op BenchmarkGin_Param20 3000000 503 ns/op 0 B/op 0 allocs/op BenchmarkGocraftWeb_Param20 100000 14408 ns/op 3795 B/op 15 allocs/op BenchmarkGoji_Param20 500000 5272 ns/op 1247 B/op 2 allocs/op BenchmarkGojiv2_Param20 1000000 4163 ns/op 1248 B/op 8 allocs/op BenchmarkGoJsonRest_Param20 100000 17866 ns/op 4485 B/op 20 allocs/op BenchmarkGoRestful_Param20 100000 21022 ns/op 4724 B/op 23 allocs/op BenchmarkGorillaMux_Param20 100000 17055 ns/op 3547 B/op 13 allocs/op BenchmarkHttpRouter_Param20 1000000 1748 ns/op 640 B/op 1 allocs/op BenchmarkHttpTreeMux_Param20 200000 12246 ns/op 3196 B/op 10 allocs/op BenchmarkKocha_Param20 300000 6861 ns/op 1808 B/op 27 allocs/op BenchmarkLARS_Param20 3000000 526 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_Param20 100000 13069 ns/op 2906 B/op 12 allocs/op BenchmarkMartini_Param20 100000 23602 ns/op 3597 B/op 13 allocs/op BenchmarkPat_Param20 50000 32143 ns/op 4688 B/op 111 allocs/op BenchmarkPossum_Param20 1000000 2396 ns/op 560 B/op 6 allocs/op BenchmarkR2router_Param20 200000 8907 ns/op 2283 B/op 7 allocs/op BenchmarkRivet_Param20 1000000 3280 ns/op 1024 B/op 1 allocs/op BenchmarkTango_Param20 500000 4640 ns/op 856 B/op 8 allocs/op BenchmarkTigerTonic_Param20 20000 67581 ns/op 10532 B/op 138 allocs/op BenchmarkTraffic_Param20 50000 40313 ns/op 7941 B/op 45 allocs/op BenchmarkVulcan_Param20 1000000 2264 ns/op 98 B/op 3 allocs/op BenchmarkAce_ParamWrite 3000000 532 ns/op 40 B/op 2 allocs/op BenchmarkBear_ParamWrite 1000000 1778 ns/op 456 B/op 5 allocs/op BenchmarkBeego_ParamWrite 1000000 2596 ns/op 376 B/op 5 allocs/op BenchmarkBone_ParamWrite 1000000 2519 ns/op 688 B/op 5 allocs/op BenchmarkDenco_ParamWrite 5000000 411 ns/op 32 B/op 1 allocs/op BenchmarkEcho_ParamWrite 2000000 718 ns/op 40 B/op 2 allocs/op BenchmarkGin_ParamWrite 5000000 283 ns/op 0 B/op 0 allocs/op BenchmarkGocraftWeb_ParamWrite 1000000 2561 ns/op 656 B/op 9 allocs/op BenchmarkGoji_ParamWrite 1000000 1378 ns/op 336 B/op 2 allocs/op BenchmarkGojiv2_ParamWrite 1000000 3128 ns/op 976 B/op 10 allocs/op BenchmarkGoJsonRest_ParamWrite 500000 4446 ns/op 1128 B/op 18 allocs/op BenchmarkGoRestful_ParamWrite 200000 10291 ns/op 2304 B/op 22 allocs/op BenchmarkGorillaMux_ParamWrite 500000 5153 ns/op 1064 B/op 12 allocs/op BenchmarkHttpRouter_ParamWrite 5000000 263 ns/op 32 B/op 1 allocs/op BenchmarkHttpTreeMux_ParamWrite 1000000 1351 ns/op 352 B/op 3 allocs/op BenchmarkKocha_ParamWrite 3000000 538 ns/op 56 B/op 3 allocs/op BenchmarkLARS_ParamWrite 5000000 316 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_ParamWrite 500000 5756 ns/op 1160 B/op 14 allocs/op BenchmarkMartini_ParamWrite 200000 13097 ns/op 1176 B/op 14 allocs/op BenchmarkPat_ParamWrite 500000 4954 ns/op 1072 B/op 17 allocs/op BenchmarkPossum_ParamWrite 1000000 2499 ns/op 560 B/op 6 allocs/op BenchmarkR2router_ParamWrite 1000000 1531 ns/op 432 B/op 5 allocs/op BenchmarkRivet_ParamWrite 3000000 570 ns/op 112 B/op 2 allocs/op BenchmarkTango_ParamWrite 2000000 957 ns/op 136 B/op 4 allocs/op BenchmarkTigerTonic_ParamWrite 200000 7025 ns/op 1424 B/op 23 allocs/op BenchmarkTraffic_ParamWrite 200000 10112 ns/op 2384 B/op 25 allocs/op BenchmarkVulcan_ParamWrite 1000000 1006 ns/op 98 B/op 3 allocs/op ``` ## GitHub ``` BenchmarkGin_GithubStatic 10000000 156 ns/op 0 B/op 0 allocs/op BenchmarkAce_GithubStatic 5000000 294 ns/op 0 B/op 0 allocs/op BenchmarkBear_GithubStatic 2000000 893 ns/op 120 B/op 3 allocs/op BenchmarkBeego_GithubStatic 1000000 2491 ns/op 368 B/op 4 allocs/op BenchmarkBone_GithubStatic 50000 25300 ns/op 2880 B/op 60 allocs/op BenchmarkDenco_GithubStatic 20000000 76.0 ns/op 0 B/op 0 allocs/op BenchmarkEcho_GithubStatic 2000000 516 ns/op 32 B/op 1 allocs/op BenchmarkGocraftWeb_GithubStatic 1000000 1448 ns/op 296 B/op 5 allocs/op BenchmarkGoji_GithubStatic 3000000 496 ns/op 0 B/op 0 allocs/op BenchmarkGojiv2_GithubStatic 1000000 2941 ns/op 928 B/op 7 allocs/op BenchmarkGoRestful_GithubStatic 100000 27256 ns/op 3224 B/op 22 allocs/op BenchmarkGoJsonRest_GithubStatic 1000000 2196 ns/op 329 B/op 11 allocs/op BenchmarkGorillaMux_GithubStatic 50000 31617 ns/op 736 B/op 10 allocs/op BenchmarkHttpRouter_GithubStatic 20000000 88.4 ns/op 0 B/op 0 allocs/op BenchmarkHttpTreeMux_GithubStatic 10000000 134 ns/op 0 B/op 0 allocs/op BenchmarkKocha_GithubStatic 20000000 113 ns/op 0 B/op 0 allocs/op BenchmarkLARS_GithubStatic 10000000 195 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_GithubStatic 500000 3740 ns/op 768 B/op 9 allocs/op BenchmarkMartini_GithubStatic 50000 27673 ns/op 768 B/op 9 allocs/op BenchmarkPat_GithubStatic 100000 19470 ns/op 3648 B/op 76 allocs/op BenchmarkPossum_GithubStatic 1000000 1729 ns/op 416 B/op 3 allocs/op BenchmarkR2router_GithubStatic 2000000 879 ns/op 144 B/op 4 allocs/op BenchmarkRivet_GithubStatic 10000000 231 ns/op 0 B/op 0 allocs/op BenchmarkTango_GithubStatic 1000000 2325 ns/op 248 B/op 8 allocs/op BenchmarkTigerTonic_GithubStatic 3000000 610 ns/op 48 B/op 1 allocs/op BenchmarkTraffic_GithubStatic 20000 62973 ns/op 18904 B/op 148 allocs/op BenchmarkVulcan_GithubStatic 1000000 1447 ns/op 98 B/op 3 allocs/op BenchmarkAce_GithubParam 2000000 686 ns/op 96 B/op 1 allocs/op BenchmarkBear_GithubParam 1000000 2155 ns/op 496 B/op 5 allocs/op BenchmarkBeego_GithubParam 1000000 2713 ns/op 368 B/op 4 allocs/op BenchmarkBone_GithubParam 100000 15088 ns/op 1760 B/op 18 allocs/op BenchmarkDenco_GithubParam 2000000 629 ns/op 128 B/op 1 allocs/op BenchmarkEcho_GithubParam 2000000 653 ns/op 32 B/op 1 allocs/op BenchmarkGin_GithubParam 5000000 255 ns/op 0 B/op 0 allocs/op BenchmarkGocraftWeb_GithubParam 1000000 3145 ns/op 712 B/op 9 allocs/op BenchmarkGoji_GithubParam 1000000 1916 ns/op 336 B/op 2 allocs/op BenchmarkGojiv2_GithubParam 1000000 3975 ns/op 1024 B/op 10 allocs/op BenchmarkGoJsonRest_GithubParam 300000 4134 ns/op 713 B/op 14 allocs/op BenchmarkGoRestful_GithubParam 50000 30782 ns/op 2360 B/op 21 allocs/op BenchmarkGorillaMux_GithubParam 100000 17148 ns/op 1088 B/op 11 allocs/op BenchmarkHttpRouter_GithubParam 3000000 523 ns/op 96 B/op 1 allocs/op BenchmarkHttpTreeMux_GithubParam 1000000 1671 ns/op 384 B/op 4 allocs/op BenchmarkKocha_GithubParam 1000000 1021 ns/op 128 B/op 5 allocs/op BenchmarkLARS_GithubParam 5000000 283 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_GithubParam 500000 4270 ns/op 1056 B/op 10 allocs/op BenchmarkMartini_GithubParam 100000 21728 ns/op 1152 B/op 11 allocs/op BenchmarkPat_GithubParam 200000 11208 ns/op 2464 B/op 48 allocs/op BenchmarkPossum_GithubParam 1000000 2334 ns/op 560 B/op 6 allocs/op BenchmarkR2router_GithubParam 1000000 1487 ns/op 432 B/op 5 allocs/op BenchmarkRivet_GithubParam 2000000 782 ns/op 96 B/op 1 allocs/op BenchmarkTango_GithubParam 1000000 2653 ns/op 344 B/op 8 allocs/op BenchmarkTigerTonic_GithubParam 300000 14073 ns/op 1440 B/op 24 allocs/op BenchmarkTraffic_GithubParam 50000 29164 ns/op 5992 B/op 52 allocs/op BenchmarkVulcan_GithubParam 1000000 2529 ns/op 98 B/op 3 allocs/op BenchmarkAce_GithubAll 10000 134059 ns/op 13792 B/op 167 allocs/op BenchmarkBear_GithubAll 5000 534445 ns/op 86448 B/op 943 allocs/op BenchmarkBeego_GithubAll 3000 592444 ns/op 74705 B/op 812 allocs/op BenchmarkBone_GithubAll 200 6957308 ns/op 698784 B/op 8453 allocs/op BenchmarkDenco_GithubAll 10000 158819 ns/op 20224 B/op 167 allocs/op BenchmarkEcho_GithubAll 10000 154700 ns/op 6496 B/op 203 allocs/op BenchmarkGin_GithubAll 30000 48375 ns/op 0 B/op 0 allocs/op BenchmarkGocraftWeb_GithubAll 3000 570806 ns/op 131656 B/op 1686 allocs/op BenchmarkGoji_GithubAll 2000 818034 ns/op 56112 B/op 334 allocs/op BenchmarkGojiv2_GithubAll 2000 1213973 ns/op 274768 B/op 3712 allocs/op BenchmarkGoJsonRest_GithubAll 2000 785796 ns/op 134371 B/op 2737 allocs/op BenchmarkGoRestful_GithubAll 300 5238188 ns/op 689672 B/op 4519 allocs/op BenchmarkGorillaMux_GithubAll 100 10257726 ns/op 211840 B/op 2272 allocs/op BenchmarkHttpRouter_GithubAll 20000 105414 ns/op 13792 B/op 167 allocs/op BenchmarkHttpTreeMux_GithubAll 10000 319934 ns/op 65856 B/op 671 allocs/op BenchmarkKocha_GithubAll 10000 209442 ns/op 23304 B/op 843 allocs/op BenchmarkLARS_GithubAll 20000 62565 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_GithubAll 2000 1161270 ns/op 204194 B/op 2000 allocs/op BenchmarkMartini_GithubAll 200 9991713 ns/op 226549 B/op 2325 allocs/op BenchmarkPat_GithubAll 200 5590793 ns/op 1499568 B/op 27435 allocs/op BenchmarkPossum_GithubAll 10000 319768 ns/op 84448 B/op 609 allocs/op BenchmarkR2router_GithubAll 10000 305134 ns/op 77328 B/op 979 allocs/op BenchmarkRivet_GithubAll 10000 132134 ns/op 16272 B/op 167 allocs/op BenchmarkTango_GithubAll 3000 552754 ns/op 63826 B/op 1618 allocs/op BenchmarkTigerTonic_GithubAll 1000 1439483 ns/op 239104 B/op 5374 allocs/op BenchmarkTraffic_GithubAll 100 11383067 ns/op 2659329 B/op 21848 allocs/op BenchmarkVulcan_GithubAll 5000 394253 ns/op 19894 B/op 609 allocs/op ``` ## Google+ ``` BenchmarkGin_GPlusStatic 10000000 183 ns/op 0 B/op 0 allocs/op BenchmarkAce_GPlusStatic 5000000 276 ns/op 0 B/op 0 allocs/op BenchmarkBear_GPlusStatic 2000000 652 ns/op 104 B/op 3 allocs/op BenchmarkBeego_GPlusStatic 1000000 2239 ns/op 368 B/op 4 allocs/op BenchmarkBone_GPlusStatic 5000000 380 ns/op 32 B/op 1 allocs/op BenchmarkDenco_GPlusStatic 30000000 45.8 ns/op 0 B/op 0 allocs/op BenchmarkEcho_GPlusStatic 5000000 338 ns/op 32 B/op 1 allocs/op BenchmarkGocraftWeb_GPlusStatic 1000000 1158 ns/op 280 B/op 5 allocs/op BenchmarkGoji_GPlusStatic 5000000 331 ns/op 0 B/op 0 allocs/op BenchmarkGojiv2_GPlusStatic 1000000 2106 ns/op 928 B/op 7 allocs/op BenchmarkGoJsonRest_GPlusStatic 1000000 1626 ns/op 329 B/op 11 allocs/op BenchmarkGoRestful_GPlusStatic 300000 7598 ns/op 1976 B/op 20 allocs/op BenchmarkGorillaMux_GPlusStatic 1000000 2629 ns/op 736 B/op 10 allocs/op BenchmarkHttpRouter_GPlusStatic 30000000 52.5 ns/op 0 B/op 0 allocs/op BenchmarkHttpTreeMux_GPlusStatic 20000000 85.8 ns/op 0 B/op 0 allocs/op BenchmarkKocha_GPlusStatic 20000000 89.2 ns/op 0 B/op 0 allocs/op BenchmarkLARS_GPlusStatic 10000000 162 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_GPlusStatic 500000 3479 ns/op 768 B/op 9 allocs/op BenchmarkMartini_GPlusStatic 200000 9092 ns/op 768 B/op 9 allocs/op BenchmarkPat_GPlusStatic 3000000 493 ns/op 96 B/op 2 allocs/op BenchmarkPossum_GPlusStatic 1000000 1467 ns/op 416 B/op 3 allocs/op BenchmarkR2router_GPlusStatic 2000000 788 ns/op 144 B/op 4 allocs/op BenchmarkRivet_GPlusStatic 20000000 114 ns/op 0 B/op 0 allocs/op BenchmarkTango_GPlusStatic 1000000 1534 ns/op 200 B/op 8 allocs/op BenchmarkTigerTonic_GPlusStatic 5000000 282 ns/op 32 B/op 1 allocs/op BenchmarkTraffic_GPlusStatic 500000 3798 ns/op 1192 B/op 15 allocs/op BenchmarkVulcan_GPlusStatic 2000000 1125 ns/op 98 B/op 3 allocs/op BenchmarkAce_GPlusParam 3000000 528 ns/op 64 B/op 1 allocs/op BenchmarkBear_GPlusParam 1000000 1570 ns/op 480 B/op 5 allocs/op BenchmarkBeego_GPlusParam 1000000 2369 ns/op 368 B/op 4 allocs/op BenchmarkBone_GPlusParam 1000000 2028 ns/op 688 B/op 5 allocs/op BenchmarkDenco_GPlusParam 5000000 385 ns/op 64 B/op 1 allocs/op BenchmarkEcho_GPlusParam 3000000 441 ns/op 32 B/op 1 allocs/op BenchmarkGin_GPlusParam 10000000 174 ns/op 0 B/op 0 allocs/op BenchmarkGocraftWeb_GPlusParam 1000000 2033 ns/op 648 B/op 8 allocs/op BenchmarkGoji_GPlusParam 1000000 1399 ns/op 336 B/op 2 allocs/op BenchmarkGojiv2_GPlusParam 1000000 2641 ns/op 944 B/op 8 allocs/op BenchmarkGoJsonRest_GPlusParam 1000000 2824 ns/op 649 B/op 13 allocs/op BenchmarkGoRestful_GPlusParam 200000 8875 ns/op 2296 B/op 21 allocs/op BenchmarkGorillaMux_GPlusParam 200000 6291 ns/op 1056 B/op 11 allocs/op BenchmarkHttpRouter_GPlusParam 5000000 316 ns/op 64 B/op 1 allocs/op BenchmarkHttpTreeMux_GPlusParam 1000000 1129 ns/op 352 B/op 3 allocs/op BenchmarkKocha_GPlusParam 3000000 538 ns/op 56 B/op 3 allocs/op BenchmarkLARS_GPlusParam 10000000 198 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_GPlusParam 500000 3554 ns/op 1056 B/op 10 allocs/op BenchmarkMartini_GPlusParam 200000 9831 ns/op 1072 B/op 10 allocs/op BenchmarkPat_GPlusParam 1000000 2706 ns/op 688 B/op 12 allocs/op BenchmarkPossum_GPlusParam 1000000 2297 ns/op 560 B/op 6 allocs/op BenchmarkR2router_GPlusParam 1000000 1318 ns/op 432 B/op 5 allocs/op BenchmarkRivet_GPlusParam 5000000 399 ns/op 48 B/op 1 allocs/op BenchmarkTango_GPlusParam 1000000 2070 ns/op 264 B/op 8 allocs/op BenchmarkTigerTonic_GPlusParam 500000 4853 ns/op 1056 B/op 17 allocs/op BenchmarkTraffic_GPlusParam 200000 8278 ns/op 1976 B/op 21 allocs/op BenchmarkVulcan_GPlusParam 1000000 1243 ns/op 98 B/op 3 allocs/op BenchmarkAce_GPlus2Params 3000000 549 ns/op 64 B/op 1 allocs/op BenchmarkBear_GPlus2Params 1000000 2112 ns/op 496 B/op 5 allocs/op BenchmarkBeego_GPlus2Params 500000 2750 ns/op 368 B/op 4 allocs/op BenchmarkBone_GPlus2Params 300000 7032 ns/op 1040 B/op 9 allocs/op BenchmarkDenco_GPlus2Params 3000000 502 ns/op 64 B/op 1 allocs/op BenchmarkEcho_GPlus2Params 3000000 641 ns/op 32 B/op 1 allocs/op BenchmarkGin_GPlus2Params 5000000 250 ns/op 0 B/op 0 allocs/op BenchmarkGocraftWeb_GPlus2Params 1000000 2681 ns/op 712 B/op 9 allocs/op BenchmarkGoji_GPlus2Params 1000000 1926 ns/op 336 B/op 2 allocs/op BenchmarkGojiv2_GPlus2Params 500000 3996 ns/op 1024 B/op 11 allocs/op BenchmarkGoJsonRest_GPlus2Params 500000 3886 ns/op 713 B/op 14 allocs/op BenchmarkGoRestful_GPlus2Params 200000 10376 ns/op 2360 B/op 21 allocs/op BenchmarkGorillaMux_GPlus2Params 100000 14162 ns/op 1088 B/op 11 allocs/op BenchmarkHttpRouter_GPlus2Params 5000000 336 ns/op 64 B/op 1 allocs/op BenchmarkHttpTreeMux_GPlus2Params 1000000 1523 ns/op 384 B/op 4 allocs/op BenchmarkKocha_GPlus2Params 2000000 970 ns/op 128 B/op 5 allocs/op BenchmarkLARS_GPlus2Params 5000000 238 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_GPlus2Params 500000 4016 ns/op 1056 B/op 10 allocs/op BenchmarkMartini_GPlus2Params 100000 21253 ns/op 1200 B/op 13 allocs/op BenchmarkPat_GPlus2Params 200000 8632 ns/op 2256 B/op 34 allocs/op BenchmarkPossum_GPlus2Params 1000000 2171 ns/op 560 B/op 6 allocs/op BenchmarkR2router_GPlus2Params 1000000 1340 ns/op 432 B/op 5 allocs/op BenchmarkRivet_GPlus2Params 3000000 557 ns/op 96 B/op 1 allocs/op BenchmarkTango_GPlus2Params 1000000 2186 ns/op 344 B/op 8 allocs/op BenchmarkTigerTonic_GPlus2Params 200000 9060 ns/op 1488 B/op 24 allocs/op BenchmarkTraffic_GPlus2Params 100000 20324 ns/op 3272 B/op 31 allocs/op BenchmarkVulcan_GPlus2Params 1000000 2039 ns/op 98 B/op 3 allocs/op BenchmarkAce_GPlusAll 300000 6603 ns/op 640 B/op 11 allocs/op BenchmarkBear_GPlusAll 100000 22363 ns/op 5488 B/op 61 allocs/op BenchmarkBeego_GPlusAll 50000 38757 ns/op 4784 B/op 52 allocs/op BenchmarkBone_GPlusAll 20000 54916 ns/op 10336 B/op 98 allocs/op BenchmarkDenco_GPlusAll 300000 4959 ns/op 672 B/op 11 allocs/op BenchmarkEcho_GPlusAll 200000 6558 ns/op 416 B/op 13 allocs/op BenchmarkGin_GPlusAll 500000 2757 ns/op 0 B/op 0 allocs/op BenchmarkGocraftWeb_GPlusAll 50000 34615 ns/op 8040 B/op 103 allocs/op BenchmarkGoji_GPlusAll 100000 16002 ns/op 3696 B/op 22 allocs/op BenchmarkGojiv2_GPlusAll 50000 35060 ns/op 12624 B/op 115 allocs/op BenchmarkGoJsonRest_GPlusAll 50000 41479 ns/op 8117 B/op 170 allocs/op BenchmarkGoRestful_GPlusAll 10000 131653 ns/op 32024 B/op 275 allocs/op BenchmarkGorillaMux_GPlusAll 10000 101380 ns/op 13296 B/op 142 allocs/op BenchmarkHttpRouter_GPlusAll 500000 3711 ns/op 640 B/op 11 allocs/op BenchmarkHttpTreeMux_GPlusAll 100000 14438 ns/op 4032 B/op 38 allocs/op BenchmarkKocha_GPlusAll 200000 8039 ns/op 976 B/op 43 allocs/op BenchmarkLARS_GPlusAll 500000 2630 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_GPlusAll 30000 51123 ns/op 13152 B/op 128 allocs/op BenchmarkMartini_GPlusAll 10000 176157 ns/op 14016 B/op 145 allocs/op BenchmarkPat_GPlusAll 20000 69911 ns/op 16576 B/op 298 allocs/op BenchmarkPossum_GPlusAll 100000 20716 ns/op 5408 B/op 39 allocs/op BenchmarkR2router_GPlusAll 100000 17463 ns/op 5040 B/op 63 allocs/op BenchmarkRivet_GPlusAll 300000 5142 ns/op 768 B/op 11 allocs/op BenchmarkTango_GPlusAll 50000 27321 ns/op 3656 B/op 104 allocs/op BenchmarkTigerTonic_GPlusAll 20000 77597 ns/op 14512 B/op 288 allocs/op BenchmarkTraffic_GPlusAll 10000 151406 ns/op 37360 B/op 392 allocs/op BenchmarkVulcan_GPlusAll 100000 18555 ns/op 1274 B/op 39 allocs/op ``` ## Parse.com ``` BenchmarkGin_ParseStatic 10000000 133 ns/op 0 B/op 0 allocs/op BenchmarkAce_ParseStatic 5000000 241 ns/op 0 B/op 0 allocs/op BenchmarkBear_ParseStatic 2000000 728 ns/op 120 B/op 3 allocs/op BenchmarkBeego_ParseStatic 1000000 2623 ns/op 368 B/op 4 allocs/op BenchmarkBone_ParseStatic 1000000 1285 ns/op 144 B/op 3 allocs/op BenchmarkDenco_ParseStatic 30000000 57.8 ns/op 0 B/op 0 allocs/op BenchmarkEcho_ParseStatic 5000000 342 ns/op 32 B/op 1 allocs/op BenchmarkGocraftWeb_ParseStatic 1000000 1478 ns/op 296 B/op 5 allocs/op BenchmarkGoji_ParseStatic 3000000 415 ns/op 0 B/op 0 allocs/op BenchmarkGojiv2_ParseStatic 1000000 2087 ns/op 928 B/op 7 allocs/op BenchmarkGoJsonRest_ParseStatic 1000000 1712 ns/op 329 B/op 11 allocs/op BenchmarkGoRestful_ParseStatic 200000 11072 ns/op 3224 B/op 22 allocs/op BenchmarkGorillaMux_ParseStatic 500000 4129 ns/op 752 B/op 11 allocs/op BenchmarkHttpRouter_ParseStatic 30000000 52.4 ns/op 0 B/op 0 allocs/op BenchmarkHttpTreeMux_ParseStatic 20000000 109 ns/op 0 B/op 0 allocs/op BenchmarkKocha_ParseStatic 20000000 81.8 ns/op 0 B/op 0 allocs/op BenchmarkLARS_ParseStatic 10000000 150 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_ParseStatic 1000000 3288 ns/op 768 B/op 9 allocs/op BenchmarkMartini_ParseStatic 200000 9110 ns/op 768 B/op 9 allocs/op BenchmarkPat_ParseStatic 1000000 1135 ns/op 240 B/op 5 allocs/op BenchmarkPossum_ParseStatic 1000000 1557 ns/op 416 B/op 3 allocs/op BenchmarkR2router_ParseStatic 2000000 730 ns/op 144 B/op 4 allocs/op BenchmarkRivet_ParseStatic 10000000 121 ns/op 0 B/op 0 allocs/op BenchmarkTango_ParseStatic 1000000 1688 ns/op 248 B/op 8 allocs/op BenchmarkTigerTonic_ParseStatic 3000000 427 ns/op 48 B/op 1 allocs/op BenchmarkTraffic_ParseStatic 500000 5962 ns/op 1816 B/op 20 allocs/op BenchmarkVulcan_ParseStatic 2000000 969 ns/op 98 B/op 3 allocs/op BenchmarkAce_ParseParam 3000000 497 ns/op 64 B/op 1 allocs/op BenchmarkBear_ParseParam 1000000 1473 ns/op 467 B/op 5 allocs/op BenchmarkBeego_ParseParam 1000000 2384 ns/op 368 B/op 4 allocs/op BenchmarkBone_ParseParam 1000000 2513 ns/op 768 B/op 6 allocs/op BenchmarkDenco_ParseParam 5000000 364 ns/op 64 B/op 1 allocs/op BenchmarkEcho_ParseParam 5000000 418 ns/op 32 B/op 1 allocs/op BenchmarkGin_ParseParam 10000000 163 ns/op 0 B/op 0 allocs/op BenchmarkGocraftWeb_ParseParam 1000000 2361 ns/op 664 B/op 8 allocs/op BenchmarkGoji_ParseParam 1000000 1590 ns/op 336 B/op 2 allocs/op BenchmarkGojiv2_ParseParam 1000000 2851 ns/op 976 B/op 9 allocs/op BenchmarkGoJsonRest_ParseParam 1000000 2965 ns/op 649 B/op 13 allocs/op BenchmarkGoRestful_ParseParam 200000 12207 ns/op 3544 B/op 23 allocs/op BenchmarkGorillaMux_ParseParam 500000 5187 ns/op 1088 B/op 12 allocs/op BenchmarkHttpRouter_ParseParam 5000000 275 ns/op 64 B/op 1 allocs/op BenchmarkHttpTreeMux_ParseParam 1000000 1108 ns/op 352 B/op 3 allocs/op BenchmarkKocha_ParseParam 3000000 495 ns/op 56 B/op 3 allocs/op BenchmarkLARS_ParseParam 10000000 192 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_ParseParam 500000 4103 ns/op 1056 B/op 10 allocs/op BenchmarkMartini_ParseParam 200000 9878 ns/op 1072 B/op 10 allocs/op BenchmarkPat_ParseParam 500000 3657 ns/op 1120 B/op 17 allocs/op BenchmarkPossum_ParseParam 1000000 2084 ns/op 560 B/op 6 allocs/op BenchmarkR2router_ParseParam 1000000 1251 ns/op 432 B/op 5 allocs/op BenchmarkRivet_ParseParam 5000000 335 ns/op 48 B/op 1 allocs/op BenchmarkTango_ParseParam 1000000 1854 ns/op 280 B/op 8 allocs/op BenchmarkTigerTonic_ParseParam 500000 4582 ns/op 1008 B/op 17 allocs/op BenchmarkTraffic_ParseParam 200000 8125 ns/op 2248 B/op 23 allocs/op BenchmarkVulcan_ParseParam 1000000 1148 ns/op 98 B/op 3 allocs/op BenchmarkAce_Parse2Params 3000000 539 ns/op 64 B/op 1 allocs/op BenchmarkBear_Parse2Params 1000000 1778 ns/op 496 B/op 5 allocs/op BenchmarkBeego_Parse2Params 1000000 2519 ns/op 368 B/op 4 allocs/op BenchmarkBone_Parse2Params 1000000 2596 ns/op 720 B/op 5 allocs/op BenchmarkDenco_Parse2Params 3000000 492 ns/op 64 B/op 1 allocs/op BenchmarkEcho_Parse2Params 3000000 484 ns/op 32 B/op 1 allocs/op BenchmarkGin_Parse2Params 10000000 193 ns/op 0 B/op 0 allocs/op BenchmarkGocraftWeb_Parse2Params 1000000 2575 ns/op 712 B/op 9 allocs/op BenchmarkGoji_Parse2Params 1000000 1373 ns/op 336 B/op 2 allocs/op BenchmarkGojiv2_Parse2Params 500000 2416 ns/op 960 B/op 8 allocs/op BenchmarkGoJsonRest_Parse2Params 300000 3452 ns/op 713 B/op 14 allocs/op BenchmarkGoRestful_Parse2Params 100000 17719 ns/op 6008 B/op 25 allocs/op BenchmarkGorillaMux_Parse2Params 300000 5102 ns/op 1088 B/op 11 allocs/op BenchmarkHttpRouter_Parse2Params 5000000 303 ns/op 64 B/op 1 allocs/op BenchmarkHttpTreeMux_Parse2Params 1000000 1372 ns/op 384 B/op 4 allocs/op BenchmarkKocha_Parse2Params 2000000 874 ns/op 128 B/op 5 allocs/op BenchmarkLARS_Parse2Params 10000000 192 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_Parse2Params 500000 3871 ns/op 1056 B/op 10 allocs/op BenchmarkMartini_Parse2Params 200000 9954 ns/op 1152 B/op 11 allocs/op BenchmarkPat_Parse2Params 500000 4194 ns/op 832 B/op 17 allocs/op BenchmarkPossum_Parse2Params 1000000 2121 ns/op 560 B/op 6 allocs/op BenchmarkR2router_Parse2Params 1000000 1415 ns/op 432 B/op 5 allocs/op BenchmarkRivet_Parse2Params 3000000 457 ns/op 96 B/op 1 allocs/op BenchmarkTango_Parse2Params 1000000 1914 ns/op 312 B/op 8 allocs/op BenchmarkTigerTonic_Parse2Params 300000 6895 ns/op 1408 B/op 24 allocs/op BenchmarkTraffic_Parse2Params 200000 8317 ns/op 2040 B/op 22 allocs/op BenchmarkVulcan_Parse2Params 1000000 1274 ns/op 98 B/op 3 allocs/op BenchmarkAce_ParseAll 200000 10401 ns/op 640 B/op 16 allocs/op BenchmarkBear_ParseAll 50000 37743 ns/op 8928 B/op 110 allocs/op BenchmarkBeego_ParseAll 20000 63193 ns/op 9568 B/op 104 allocs/op BenchmarkBone_ParseAll 20000 61767 ns/op 14160 B/op 131 allocs/op BenchmarkDenco_ParseAll 300000 7036 ns/op 928 B/op 16 allocs/op BenchmarkEcho_ParseAll 200000 11824 ns/op 832 B/op 26 allocs/op BenchmarkGin_ParseAll 300000 4199 ns/op 0 B/op 0 allocs/op BenchmarkGocraftWeb_ParseAll 30000 51758 ns/op 13728 B/op 181 allocs/op BenchmarkGoji_ParseAll 50000 29614 ns/op 5376 B/op 32 allocs/op BenchmarkGojiv2_ParseAll 20000 68676 ns/op 24464 B/op 199 allocs/op BenchmarkGoJsonRest_ParseAll 20000 76135 ns/op 13866 B/op 321 allocs/op BenchmarkGoRestful_ParseAll 5000 389487 ns/op 110928 B/op 600 allocs/op BenchmarkGorillaMux_ParseAll 10000 221250 ns/op 24864 B/op 292 allocs/op BenchmarkHttpRouter_ParseAll 200000 6444 ns/op 640 B/op 16 allocs/op BenchmarkHttpTreeMux_ParseAll 50000 30702 ns/op 5728 B/op 51 allocs/op BenchmarkKocha_ParseAll 200000 13712 ns/op 1112 B/op 54 allocs/op BenchmarkLARS_ParseAll 300000 6925 ns/op 0 B/op 0 allocs/op BenchmarkMacaron_ParseAll 20000 96278 ns/op 24576 B/op 250 allocs/op BenchmarkMartini_ParseAll 5000 271352 ns/op 25072 B/op 253 allocs/op BenchmarkPat_ParseAll 20000 74941 ns/op 17264 B/op 343 allocs/op BenchmarkPossum_ParseAll 50000 39947 ns/op 10816 B/op 78 allocs/op BenchmarkR2router_ParseAll 50000 42479 ns/op 8352 B/op 120 allocs/op BenchmarkRivet_ParseAll 200000 7726 ns/op 912 B/op 16 allocs/op BenchmarkTango_ParseAll 30000 50014 ns/op 7168 B/op 208 allocs/op BenchmarkTigerTonic_ParseAll 10000 106550 ns/op 19728 B/op 379 allocs/op BenchmarkTraffic_ParseAll 10000 216037 ns/op 57776 B/op 642 allocs/op BenchmarkVulcan_ParseAll 50000 34379 ns/op 2548 B/op 78 allocs/op ``` ================================================ FILE: vendor/github.com/gin-gonic/gin/CHANGELOG.md ================================================ ### Gin 1.4.0 - [NEW] Support for [Go Modules](https://github.com/golang/go/wiki/Modules) [#1569](https://github.com/gin-gonic/gin/pull/1569) - [NEW] Refactor of form mapping multipart requesta [#1829](https://github.com/gin-gonic/gin/pull/1829) - [FIX] Truncate Latency precision in long running request [#1830](https://github.com/gin-gonic/gin/pull/1830) - [FIX] IsTerm flag should not be affected by DisableConsoleColor method. [#1802](https://github.com/gin-gonic/gin/pull/1802) - [NEW] Supporting file binding [#1264](https://github.com/gin-gonic/gin/pull/1264) - [NEW] Add support for mapping arrays [#1797](https://github.com/gin-gonic/gin/pull/1797) - [FIX] Readme updates [#1793](https://github.com/gin-gonic/gin/pull/1793) [#1788](https://github.com/gin-gonic/gin/pull/1788) [1789](https://github.com/gin-gonic/gin/pull/1789) - [FIX] StaticFS: Fixed Logging two log lines on 404. [#1805](https://github.com/gin-gonic/gin/pull/1805), [#1804](https://github.com/gin-gonic/gin/pull/1804) - [NEW] Make context.Keys available as LogFormatterParams [#1779](https://github.com/gin-gonic/gin/pull/1779) - [NEW] Use internal/json for Marshal/Unmarshal [#1791](https://github.com/gin-gonic/gin/pull/1791) - [NEW] Support mapping time.Duration [#1794](https://github.com/gin-gonic/gin/pull/1794) - [NEW] Refactor form mappings [#1749](https://github.com/gin-gonic/gin/pull/1749) - [NEW] Added flag to context.Stream indicates if client disconnected in middle of stream [#1252](https://github.com/gin-gonic/gin/pull/1252) - [FIX] Moved [examples](https://github.com/gin-gonic/examples) to stand alone Repo [#1775](https://github.com/gin-gonic/gin/pull/1775) - [NEW] Extend context.File to allow for the content-dispositon attachments via a new method context.Attachment [#1260](https://github.com/gin-gonic/gin/pull/1260) - [FIX] Support HTTP content negotiation wildcards [#1112](https://github.com/gin-gonic/gin/pull/1112) - [NEW] Add prefix from X-Forwarded-Prefix in redirectTrailingSlash [#1238](https://github.com/gin-gonic/gin/pull/1238) - [FIX] context.Copy() race condition [#1020](https://github.com/gin-gonic/gin/pull/1020) - [NEW] Add context.HandlerNames() [#1729](https://github.com/gin-gonic/gin/pull/1729) - [FIX] Change color methods to public in the defaultLogger. [#1771](https://github.com/gin-gonic/gin/pull/1771) - [FIX] Update writeHeaders method to use http.Header.Set [#1722](https://github.com/gin-gonic/gin/pull/1722) - [NEW] Add response size to LogFormatterParams [#1752](https://github.com/gin-gonic/gin/pull/1752) - [NEW] Allow ignoring field on form mapping [#1733](https://github.com/gin-gonic/gin/pull/1733) - [NEW] Add a function to force color in console output. [#1724](https://github.com/gin-gonic/gin/pull/1724) - [FIX] Context.Next() - recheck len of handlers on every iteration. [#1745](https://github.com/gin-gonic/gin/pull/1745) - [FIX] Fix all errcheck warnings [#1739](https://github.com/gin-gonic/gin/pull/1739) [#1653](https://github.com/gin-gonic/gin/pull/1653) - [NEW] context: inherits context cancellation and deadline from http.Request context for Go>=1.7 [#1690](https://github.com/gin-gonic/gin/pull/1690) - [NEW] Binding for URL Params [#1694](https://github.com/gin-gonic/gin/pull/1694) - [NEW] Add LoggerWithFormatter method [#1677](https://github.com/gin-gonic/gin/pull/1677) - [FIX] CI testing updates [#1671](https://github.com/gin-gonic/gin/pull/1671) [#1670](https://github.com/gin-gonic/gin/pull/1670) [#1682](https://github.com/gin-gonic/gin/pull/1682) [#1669](https://github.com/gin-gonic/gin/pull/1669) - [FIX] StaticFS(): Send 404 when path does not exist [#1663](https://github.com/gin-gonic/gin/pull/1663) - [FIX] Handle nil body for JSON binding [#1638](https://github.com/gin-gonic/gin/pull/1638) - [FIX] Support bind uri param [#1612](https://github.com/gin-gonic/gin/pull/1612) - [FIX] recovery: fix issue with syscall import on google app engine [#1640](https://github.com/gin-gonic/gin/pull/1640) - [FIX] Make sure the debug log contains line breaks [#1650](https://github.com/gin-gonic/gin/pull/1650) - [FIX] Panic stack trace being printed during recovery of broken pipe [#1089](https://github.com/gin-gonic/gin/pull/1089) [#1259](https://github.com/gin-gonic/gin/pull/1259) - [NEW] RunFd method to run http.Server through a file descriptor [#1609](https://github.com/gin-gonic/gin/pull/1609) - [NEW] Yaml binding support [#1618](https://github.com/gin-gonic/gin/pull/1618) - [FIX] Pass MaxMultipartMemory when FormFile is called [#1600](https://github.com/gin-gonic/gin/pull/1600) - [FIX] LoadHTML* tests [#1559](https://github.com/gin-gonic/gin/pull/1559) - [FIX] Removed use of sync.pool from HandleContext [#1565](https://github.com/gin-gonic/gin/pull/1565) - [FIX] Format output log to os.Stderr [#1571](https://github.com/gin-gonic/gin/pull/1571) - [FIX] Make logger use a yellow background and a darkgray text for legibility [#1570](https://github.com/gin-gonic/gin/pull/1570) - [FIX] Remove sensitive request information from panic log. [#1370](https://github.com/gin-gonic/gin/pull/1370) - [FIX] log.Println() does not print timestamp [#829](https://github.com/gin-gonic/gin/pull/829) [#1560](https://github.com/gin-gonic/gin/pull/1560) - [NEW] Add PureJSON renderer [#694](https://github.com/gin-gonic/gin/pull/694) - [FIX] Add missing copyright and update if/else [#1497](https://github.com/gin-gonic/gin/pull/1497) - [FIX] Update msgpack usage [#1498](https://github.com/gin-gonic/gin/pull/1498) - [FIX] Use protobuf on render [#1496](https://github.com/gin-gonic/gin/pull/1496) - [FIX] Add support for Protobuf format response [#1479](https://github.com/gin-gonic/gin/pull/1479) - [NEW] Set default time format in form binding [#1487](https://github.com/gin-gonic/gin/pull/1487) - [FIX] Add BindXML and ShouldBindXML [#1485](https://github.com/gin-gonic/gin/pull/1485) - [NEW] Upgrade dependency libraries [#1491](https://github.com/gin-gonic/gin/pull/1491) ### Gin 1.3.0 - [NEW] Add [`func (*Context) QueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.QueryMap), [`func (*Context) GetQueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetQueryMap), [`func (*Context) PostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.PostFormMap) and [`func (*Context) GetPostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetPostFormMap) to support `type map[string]string` as query string or form parameters, see [#1383](https://github.com/gin-gonic/gin/pull/1383) - [NEW] Add [`func (*Context) AsciiJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.AsciiJSON), see [#1358](https://github.com/gin-gonic/gin/pull/1358) - [NEW] Add `Pusher()` in [`type ResponseWriter`](https://godoc.org/github.com/gin-gonic/gin#ResponseWriter) for supporting http2 push, see [#1273](https://github.com/gin-gonic/gin/pull/1273) - [NEW] Add [`func (*Context) DataFromReader`](https://godoc.org/github.com/gin-gonic/gin#Context.DataFromReader) for serving dynamic data, see [#1304](https://github.com/gin-gonic/gin/pull/1304) - [NEW] Add [`func (*Context) ShouldBindBodyWith`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindBodyWith) allowing to call binding multiple times, see [#1341](https://github.com/gin-gonic/gin/pull/1341) - [NEW] Support pointers in form binding, see [#1336](https://github.com/gin-gonic/gin/pull/1336) - [NEW] Add [`func (*Context) JSONP`](https://godoc.org/github.com/gin-gonic/gin#Context.JSONP), see [#1333](https://github.com/gin-gonic/gin/pull/1333) - [NEW] Support default value in form binding, see [#1138](https://github.com/gin-gonic/gin/pull/1138) - [NEW] Expose validator engine in [`type StructValidator`](https://godoc.org/github.com/gin-gonic/gin/binding#StructValidator), see [#1277](https://github.com/gin-gonic/gin/pull/1277) - [NEW] Add [`func (*Context) ShouldBind`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBind), [`func (*Context) ShouldBindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindQuery) and [`func (*Context) ShouldBindJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindJSON), see [#1047](https://github.com/gin-gonic/gin/pull/1047) - [NEW] Add support for `time.Time` location in form binding, see [#1117](https://github.com/gin-gonic/gin/pull/1117) - [NEW] Add [`func (*Context) BindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.BindQuery), see [#1029](https://github.com/gin-gonic/gin/pull/1029) - [NEW] Make [jsonite](https://github.com/json-iterator/go) optional with build tags, see [#1026](https://github.com/gin-gonic/gin/pull/1026) - [NEW] Show query string in logger, see [#999](https://github.com/gin-gonic/gin/pull/999) - [NEW] Add [`func (*Context) SecureJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.SecureJSON), see [#987](https://github.com/gin-gonic/gin/pull/987) and [#993](https://github.com/gin-gonic/gin/pull/993) - [DEPRECATE] `func (*Context) GetCookie` for [`func (*Context) Cookie`](https://godoc.org/github.com/gin-gonic/gin#Context.Cookie) - [FIX] Don't display color tags if [`func DisableConsoleColor`](https://godoc.org/github.com/gin-gonic/gin#DisableConsoleColor) called, see [#1072](https://github.com/gin-gonic/gin/pull/1072) - [FIX] Gin Mode `""` when calling [`func Mode`](https://godoc.org/github.com/gin-gonic/gin#Mode) now returns `const DebugMode`, see [#1250](https://github.com/gin-gonic/gin/pull/1250) - [FIX] `Flush()` now doesn't overwrite `responseWriter` status code, see [#1460](https://github.com/gin-gonic/gin/pull/1460) ### Gin 1.2.0 - [NEW] Switch from godeps to govendor - [NEW] Add support for Let's Encrypt via gin-gonic/autotls - [NEW] Improve README examples and add extra at examples folder - [NEW] Improved support with App Engine - [NEW] Add custom template delimiters, see #860 - [NEW] Add Template Func Maps, see #962 - [NEW] Add \*context.Handler(), see #928 - [NEW] Add \*context.GetRawData() - [NEW] Add \*context.GetHeader() (request) - [NEW] Add \*context.AbortWithStatusJSON() (JSON content type) - [NEW] Add \*context.Keys type cast helpers - [NEW] Add \*context.ShouldBindWith() - [NEW] Add \*context.MustBindWith() - [NEW] Add \*engine.SetFuncMap() - [DEPRECATE] On next release: \*context.BindWith(), see #855 - [FIX] Refactor render - [FIX] Reworked tests - [FIX] logger now supports cygwin - [FIX] Use X-Forwarded-For before X-Real-Ip - [FIX] time.Time binding (#904) ### Gin 1.1.4 - [NEW] Support google appengine for IsTerminal func ### Gin 1.1.3 - [FIX] Reverted Logger: skip ANSI color commands ### Gin 1.1 - [NEW] Implement QueryArray and PostArray methods - [NEW] Refactor GetQuery and GetPostForm - [NEW] Add contribution guide - [FIX] Corrected typos in README - [FIX] Removed additional Iota - [FIX] Changed imports to gopkg instead of github in README (#733) - [FIX] Logger: skip ANSI color commands if output is not a tty ### Gin 1.0rc2 (...) - [PERFORMANCE] Fast path for writing Content-Type. - [PERFORMANCE] Much faster 404 routing - [PERFORMANCE] Allocation optimizations - [PERFORMANCE] Faster root tree lookup - [PERFORMANCE] Zero overhead, String() and JSON() rendering. - [PERFORMANCE] Faster ClientIP parsing - [PERFORMANCE] Much faster SSE implementation - [NEW] Benchmarks suite - [NEW] Bind validation can be disabled and replaced with custom validators. - [NEW] More flexible HTML render - [NEW] Multipart and PostForm bindings - [NEW] Adds method to return all the registered routes - [NEW] Context.HandlerName() returns the main handler's name - [NEW] Adds Error.IsType() helper - [FIX] Binding multipart form - [FIX] Integration tests - [FIX] Crash when binding non struct object in Context. - [FIX] RunTLS() implementation - [FIX] Logger() unit tests - [FIX] Adds SetHTMLTemplate() warning - [FIX] Context.IsAborted() - [FIX] More unit tests - [FIX] JSON, XML, HTML renders accept custom content-types - [FIX] gin.AbortIndex is unexported - [FIX] Better approach to avoid directory listing in StaticFS() - [FIX] Context.ClientIP() always returns the IP with trimmed spaces. - [FIX] Better warning when running in debug mode. - [FIX] Google App Engine integration. debugPrint does not use os.Stdout - [FIX] Fixes integer overflow in error type - [FIX] Error implements the json.Marshaller interface - [FIX] MIT license in every file ### Gin 1.0rc1 (May 22, 2015) - [PERFORMANCE] Zero allocation router - [PERFORMANCE] Faster JSON, XML and text rendering - [PERFORMANCE] Custom hand optimized HttpRouter for Gin - [PERFORMANCE] Misc code optimizations. Inlining, tail call optimizations - [NEW] Built-in support for golang.org/x/net/context - [NEW] Any(path, handler). Create a route that matches any path - [NEW] Refactored rendering pipeline (faster and static typeded) - [NEW] Refactored errors API - [NEW] IndentedJSON() prints pretty JSON - [NEW] Added gin.DefaultWriter - [NEW] UNIX socket support - [NEW] RouterGroup.BasePath is exposed - [NEW] JSON validation using go-validate-yourself (very powerful options) - [NEW] Completed suite of unit tests - [NEW] HTTP streaming with c.Stream() - [NEW] StaticFile() creates a router for serving just one file. - [NEW] StaticFS() has an option to disable directory listing. - [NEW] StaticFS() for serving static files through virtual filesystems - [NEW] Server-Sent Events native support - [NEW] WrapF() and WrapH() helpers for wrapping http.HandlerFunc and http.Handler - [NEW] Added LoggerWithWriter() middleware - [NEW] Added RecoveryWithWriter() middleware - [NEW] Added DefaultPostFormValue() - [NEW] Added DefaultFormValue() - [NEW] Added DefaultParamValue() - [FIX] BasicAuth() when using custom realm - [FIX] Bug when serving static files in nested routing group - [FIX] Redirect using built-in http.Redirect() - [FIX] Logger when printing the requested path - [FIX] Documentation typos - [FIX] Context.Engine renamed to Context.engine - [FIX] Better debugging messages - [FIX] ErrorLogger - [FIX] Debug HTTP render - [FIX] Refactored binding and render modules - [FIX] Refactored Context initialization - [FIX] Refactored BasicAuth() - [FIX] NoMethod/NoRoute handlers - [FIX] Hijacking http - [FIX] Better support for Google App Engine (using log instead of fmt) ### Gin 0.6 (Mar 9, 2015) - [NEW] Support multipart/form-data - [NEW] NoMethod handler - [NEW] Validate sub structures - [NEW] Support for HTTP Realm Auth - [FIX] Unsigned integers in binding - [FIX] Improve color logger ### Gin 0.5 (Feb 7, 2015) - [NEW] Content Negotiation - [FIX] Solved security bug that allow a client to spoof ip - [FIX] Fix unexported/ignored fields in binding ### Gin 0.4 (Aug 21, 2014) - [NEW] Development mode - [NEW] Unit tests - [NEW] Add Content.Redirect() - [FIX] Deferring WriteHeader() - [FIX] Improved documentation for model binding ### Gin 0.3 (Jul 18, 2014) - [PERFORMANCE] Normal log and error log are printed in the same call. - [PERFORMANCE] Improve performance of NoRouter() - [PERFORMANCE] Improve context's memory locality, reduce CPU cache faults. - [NEW] Flexible rendering API - [NEW] Add Context.File() - [NEW] Add shorcut RunTLS() for http.ListenAndServeTLS - [FIX] Rename NotFound404() to NoRoute() - [FIX] Errors in context are purged - [FIX] Adds HEAD method in Static file serving - [FIX] Refactors Static() file serving - [FIX] Using keyed initialization to fix app-engine integration - [FIX] Can't unmarshal JSON array, #63 - [FIX] Renaming Context.Req to Context.Request - [FIX] Check application/x-www-form-urlencoded when parsing form ### Gin 0.2b (Jul 08, 2014) - [PERFORMANCE] Using sync.Pool to allocatio/gc overhead - [NEW] Travis CI integration - [NEW] Completely new logger - [NEW] New API for serving static files. gin.Static() - [NEW] gin.H() can be serialized into XML - [NEW] Typed errors. Errors can be typed. Internet/external/custom. - [NEW] Support for Godeps - [NEW] Travis/Godocs badges in README - [NEW] New Bind() and BindWith() methods for parsing request body. - [NEW] Add Content.Copy() - [NEW] Add context.LastError() - [NEW] Add shorcut for OPTIONS HTTP method - [FIX] Tons of README fixes - [FIX] Header is written before body - [FIX] BasicAuth() and changes API a little bit - [FIX] Recovery() middleware only prints panics - [FIX] Context.Get() does not panic anymore. Use MustGet() instead. - [FIX] Multiple http.WriteHeader() in NotFound handlers - [FIX] Engine.Run() panics if http server can't be setted up - [FIX] Crash when route path doesn't start with '/' - [FIX] Do not update header when status code is negative - [FIX] Setting response headers before calling WriteHeader in context.String() - [FIX] Add MIT license - [FIX] Changes behaviour of ErrorLogger() and Logger() ================================================ FILE: vendor/github.com/gin-gonic/gin/CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at teamgingonic@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: vendor/github.com/gin-gonic/gin/CONTRIBUTING.md ================================================ ## Contributing - With issues: - Use the search tool before opening a new issue. - Please provide source code and commit sha if you found a bug. - Review existing issues and provide feedback or react to them. - With pull requests: - Open your pull request against `master` - Your pull request should have no more than two commits, if not you should squash them. - It should pass all tests in the available continuous integrations systems such as TravisCI. - You should add/modify tests to cover your proposed code changes. - If your pull request contains a new feature, please document it on the README. ================================================ FILE: vendor/github.com/gin-gonic/gin/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Manuel Martínez-Almeida 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. ================================================ FILE: vendor/github.com/gin-gonic/gin/Makefile ================================================ GO ?= go GOFMT ?= gofmt "-s" PACKAGES ?= $(shell $(GO) list ./... | grep -v /vendor/) VETPACKAGES ?= $(shell $(GO) list ./... | grep -v /vendor/ | grep -v /examples/) GOFILES := $(shell find . -name "*.go" -type f -not -path "./vendor/*") TESTFOLDER := $(shell $(GO) list ./... | grep -E 'gin$$|binding$$|render$$' | grep -v examples) all: install install: deps govendor sync .PHONY: test test: echo "mode: count" > coverage.out for d in $(TESTFOLDER); do \ $(GO) test -v -covermode=count -coverprofile=profile.out $$d > tmp.out; \ cat tmp.out; \ if grep -q "^--- FAIL" tmp.out; then \ rm tmp.out; \ exit 1; \ elif grep -q "build failed" tmp.out; then \ rm tmp.out; \ exit 1; \ elif grep -q "setup failed" tmp.out; then \ rm tmp.out; \ exit 1; \ fi; \ if [ -f profile.out ]; then \ cat profile.out | grep -v "mode:" >> coverage.out; \ rm profile.out; \ fi; \ done .PHONY: fmt fmt: $(GOFMT) -w $(GOFILES) .PHONY: fmt-check fmt-check: @diff=$$($(GOFMT) -d $(GOFILES)); \ if [ -n "$$diff" ]; then \ echo "Please run 'make fmt' and commit the result:"; \ echo "$${diff}"; \ exit 1; \ fi; vet: $(GO) vet $(VETPACKAGES) deps: @hash govendor > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(GO) get -u github.com/kardianos/govendor; \ fi .PHONY: lint lint: @hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(GO) get -u golang.org/x/lint/golint; \ fi for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done; .PHONY: misspell-check misspell-check: @hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(GO) get -u github.com/client9/misspell/cmd/misspell; \ fi misspell -error $(GOFILES) .PHONY: misspell misspell: @hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(GO) get -u github.com/client9/misspell/cmd/misspell; \ fi misspell -w $(GOFILES) .PHONY: tools tools: go install golang.org/x/lint/golint; \ go install github.com/client9/misspell/cmd/misspell; ================================================ FILE: vendor/github.com/gin-gonic/gin/README.md ================================================ # Gin Web Framework [![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin) [![codecov](https://codecov.io/gh/gin-gonic/gin/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-gonic/gin) [![Go Report Card](https://goreportcard.com/badge/github.com/gin-gonic/gin)](https://goreportcard.com/report/github.com/gin-gonic/gin) [![GoDoc](https://godoc.org/github.com/gin-gonic/gin?status.svg)](https://godoc.org/github.com/gin-gonic/gin) [![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Sourcegraph](https://sourcegraph.com/github.com/gin-gonic/gin/-/badge.svg)](https://sourcegraph.com/github.com/gin-gonic/gin?badge) [![Open Source Helpers](https://www.codetriage.com/gin-gonic/gin/badges/users.svg)](https://www.codetriage.com/gin-gonic/gin) [![Release](https://img.shields.io/github/release/gin-gonic/gin.svg?style=flat-square)](https://github.com/gin-gonic/gin/releases) Gin is a web framework written in Go (Golang). It features a martini-like API with much better performance, up to 40 times faster thanks to [httprouter](https://github.com/julienschmidt/httprouter). If you need performance and good productivity, you will love Gin. ## Contents - [Installation](#installation) - [Prerequisite](#prerequisite) - [Quick start](#quick-start) - [Benchmarks](#benchmarks) - [Gin v1.stable](#gin-v1-stable) - [Build with jsoniter](#build-with-jsoniter) - [API Examples](#api-examples) - [Using GET,POST,PUT,PATCH,DELETE and OPTIONS](#using-get-post-put-patch-delete-and-options) - [Parameters in path](#parameters-in-path) - [Querystring parameters](#querystring-parameters) - [Multipart/Urlencoded Form](#multiparturlencoded-form) - [Another example: query + post form](#another-example-query--post-form) - [Map as querystring or postform parameters](#map-as-querystring-or-postform-parameters) - [Upload files](#upload-files) - [Grouping routes](#grouping-routes) - [Blank Gin without middleware by default](#blank-gin-without-middleware-by-default) - [Using middleware](#using-middleware) - [How to write log file](#how-to-write-log-file) - [Custom Log Format](#custom-log-format) - [Model binding and validation](#model-binding-and-validation) - [Custom Validators](#custom-validators) - [Only Bind Query String](#only-bind-query-string) - [Bind Query String or Post Data](#bind-query-string-or-post-data) - [Bind Uri](#bind-uri) - [Bind HTML checkboxes](#bind-html-checkboxes) - [Multipart/Urlencoded binding](#multiparturlencoded-binding) - [XML, JSON, YAML and ProtoBuf rendering](#xml-json-yaml-and-protobuf-rendering) - [JSONP rendering](#jsonp) - [Serving static files](#serving-static-files) - [Serving data from reader](#serving-data-from-reader) - [HTML rendering](#html-rendering) - [Multitemplate](#multitemplate) - [Redirects](#redirects) - [Custom Middleware](#custom-middleware) - [Using BasicAuth() middleware](#using-basicauth-middleware) - [Goroutines inside a middleware](#goroutines-inside-a-middleware) - [Custom HTTP configuration](#custom-http-configuration) - [Support Let's Encrypt](#support-lets-encrypt) - [Run multiple service using Gin](#run-multiple-service-using-gin) - [Graceful restart or stop](#graceful-restart-or-stop) - [Build a single binary with templates](#build-a-single-binary-with-templates) - [Bind form-data request with custom struct](#bind-form-data-request-with-custom-struct) - [Try to bind body into different structs](#try-to-bind-body-into-different-structs) - [http2 server push](#http2-server-push) - [Define format for the log of routes](#define-format-for-the-log-of-routes) - [Set and get a cookie](#set-and-get-a-cookie) - [Testing](#testing) - [Users](#users) ## Installation To install Gin package, you need to install Go and set your Go workspace first. 1. The first need [Go](https://golang.org/) installed (**version 1.8+ is required**), then you can use the below Go command to install Gin. ```sh $ go get -u github.com/gin-gonic/gin ``` 2. Import it in your code: ```go import "github.com/gin-gonic/gin" ``` 3. (Optional) Import `net/http`. This is required for example if using constants such as `http.StatusOK`. ```go import "net/http" ``` ### Use a vendor tool like [Govendor](https://github.com/kardianos/govendor) 1. `go get` govendor ```sh $ go get github.com/kardianos/govendor ``` 2. Create your project folder and `cd` inside ```sh $ mkdir -p $GOPATH/src/github.com/myusername/project && cd "$_" ``` 3. Vendor init your project and add gin ```sh $ govendor init $ govendor fetch github.com/gin-gonic/gin@v1.3 ``` 4. Copy a starting template inside your project ```sh $ curl https://raw.githubusercontent.com/gin-gonic/examples/master/basic/main.go > main.go ``` 5. Run your project ```sh $ go run main.go ``` ## Prerequisite Now Gin requires Go 1.6 or later and Go 1.7 will be required soon. ## Quick start ```sh # assume the following codes in example.go file $ cat example.go ``` ```go package main import "github.com/gin-gonic/gin" func main() { r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) r.Run() // listen and serve on 0.0.0.0:8080 } ``` ``` # run example.go and visit 0.0.0.0:8080/ping on browser $ go run example.go ``` ## Benchmarks Gin uses a custom version of [HttpRouter](https://github.com/julienschmidt/httprouter) [See all benchmarks](/BENCHMARKS.md) Benchmark name | (1) | (2) | (3) | (4) --------------------------------------------|-----------:|------------:|-----------:|---------: **BenchmarkGin_GithubAll** | **30000** | **48375** | **0** | **0** BenchmarkAce_GithubAll | 10000 | 134059 | 13792 | 167 BenchmarkBear_GithubAll | 5000 | 534445 | 86448 | 943 BenchmarkBeego_GithubAll | 3000 | 592444 | 74705 | 812 BenchmarkBone_GithubAll | 200 | 6957308 | 698784 | 8453 BenchmarkDenco_GithubAll | 10000 | 158819 | 20224 | 167 BenchmarkEcho_GithubAll | 10000 | 154700 | 6496 | 203 BenchmarkGocraftWeb_GithubAll | 3000 | 570806 | 131656 | 1686 BenchmarkGoji_GithubAll | 2000 | 818034 | 56112 | 334 BenchmarkGojiv2_GithubAll | 2000 | 1213973 | 274768 | 3712 BenchmarkGoJsonRest_GithubAll | 2000 | 785796 | 134371 | 2737 BenchmarkGoRestful_GithubAll | 300 | 5238188 | 689672 | 4519 BenchmarkGorillaMux_GithubAll | 100 | 10257726 | 211840 | 2272 BenchmarkHttpRouter_GithubAll | 20000 | 105414 | 13792 | 167 BenchmarkHttpTreeMux_GithubAll | 10000 | 319934 | 65856 | 671 BenchmarkKocha_GithubAll | 10000 | 209442 | 23304 | 843 BenchmarkLARS_GithubAll | 20000 | 62565 | 0 | 0 BenchmarkMacaron_GithubAll | 2000 | 1161270 | 204194 | 2000 BenchmarkMartini_GithubAll | 200 | 9991713 | 226549 | 2325 BenchmarkPat_GithubAll | 200 | 5590793 | 1499568 | 27435 BenchmarkPossum_GithubAll | 10000 | 319768 | 84448 | 609 BenchmarkR2router_GithubAll | 10000 | 305134 | 77328 | 979 BenchmarkRivet_GithubAll | 10000 | 132134 | 16272 | 167 BenchmarkTango_GithubAll | 3000 | 552754 | 63826 | 1618 BenchmarkTigerTonic_GithubAll | 1000 | 1439483 | 239104 | 5374 BenchmarkTraffic_GithubAll | 100 | 11383067 | 2659329 | 21848 BenchmarkVulcan_GithubAll | 5000 | 394253 | 19894 | 609 - (1): Total Repetitions achieved in constant time, higher means more confident result - (2): Single Repetition Duration (ns/op), lower is better - (3): Heap Memory (B/op), lower is better - (4): Average Allocations per Repetition (allocs/op), lower is better ## Gin v1. stable - [x] Zero allocation router. - [x] Still the fastest http router and framework. From routing to writing. - [x] Complete suite of unit tests - [x] Battle tested - [x] API frozen, new releases will not break your code. ## Build with [jsoniter](https://github.com/json-iterator/go) Gin uses `encoding/json` as default json package but you can change to [jsoniter](https://github.com/json-iterator/go) by build from other tags. ```sh $ go build -tags=jsoniter . ``` ## API Examples You can find a number of ready-to-run examples at [Gin examples repository](https://github.com/gin-gonic/examples). ### Using GET, POST, PUT, PATCH, DELETE and OPTIONS ```go func main() { // Creates a gin router with default middleware: // logger and recovery (crash-free) middleware router := gin.Default() router.GET("/someGet", getting) router.POST("/somePost", posting) router.PUT("/somePut", putting) router.DELETE("/someDelete", deleting) router.PATCH("/somePatch", patching) router.HEAD("/someHead", head) router.OPTIONS("/someOptions", options) // By default it serves on :8080 unless a // PORT environment variable was defined. router.Run() // router.Run(":3000") for a hard coded port } ``` ### Parameters in path ```go func main() { router := gin.Default() // This handler will match /user/john but will not match /user/ or /user router.GET("/user/:name", func(c *gin.Context) { name := c.Param("name") c.String(http.StatusOK, "Hello %s", name) }) // However, this one will match /user/john/ and also /user/john/send // If no other routers match /user/john, it will redirect to /user/john/ router.GET("/user/:name/*action", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") message := name + " is " + action c.String(http.StatusOK, message) }) router.Run(":8080") } ``` ### Querystring parameters ```go func main() { router := gin.Default() // Query string parameters are parsed using the existing underlying request object. // The request responds to a url matching: /welcome?firstname=Jane&lastname=Doe router.GET("/welcome", func(c *gin.Context) { firstname := c.DefaultQuery("firstname", "Guest") lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname") c.String(http.StatusOK, "Hello %s %s", firstname, lastname) }) router.Run(":8080") } ``` ### Multipart/Urlencoded Form ```go func main() { router := gin.Default() router.POST("/form_post", func(c *gin.Context) { message := c.PostForm("message") nick := c.DefaultPostForm("nick", "anonymous") c.JSON(200, gin.H{ "status": "posted", "message": message, "nick": nick, }) }) router.Run(":8080") } ``` ### Another example: query + post form ``` POST /post?id=1234&page=1 HTTP/1.1 Content-Type: application/x-www-form-urlencoded name=manu&message=this_is_great ``` ```go func main() { router := gin.Default() router.POST("/post", func(c *gin.Context) { id := c.Query("id") page := c.DefaultQuery("page", "0") name := c.PostForm("name") message := c.PostForm("message") fmt.Printf("id: %s; page: %s; name: %s; message: %s", id, page, name, message) }) router.Run(":8080") } ``` ``` id: 1234; page: 1; name: manu; message: this_is_great ``` ### Map as querystring or postform parameters ``` POST /post?ids[a]=1234&ids[b]=hello HTTP/1.1 Content-Type: application/x-www-form-urlencoded names[first]=thinkerou&names[second]=tianou ``` ```go func main() { router := gin.Default() router.POST("/post", func(c *gin.Context) { ids := c.QueryMap("ids") names := c.PostFormMap("names") fmt.Printf("ids: %v; names: %v", ids, names) }) router.Run(":8080") } ``` ``` ids: map[b:hello a:1234], names: map[second:tianou first:thinkerou] ``` ### Upload files #### Single file References issue [#774](https://github.com/gin-gonic/gin/issues/774) and detail [example code](https://github.com/gin-gonic/examples/tree/master/upload-file/single). `file.Filename` **SHOULD NOT** be trusted. See [`Content-Disposition` on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#Directives) and [#1693](https://github.com/gin-gonic/gin/issues/1693) > The filename is always optional and must not be used blindly by the application: path information should be stripped, and conversion to the server file system rules should be done. ```go func main() { router := gin.Default() // Set a lower memory limit for multipart forms (default is 32 MiB) // router.MaxMultipartMemory = 8 << 20 // 8 MiB router.POST("/upload", func(c *gin.Context) { // single file file, _ := c.FormFile("file") log.Println(file.Filename) // Upload the file to specific dst. // c.SaveUploadedFile(file, dst) c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename)) }) router.Run(":8080") } ``` How to `curl`: ```bash curl -X POST http://localhost:8080/upload \ -F "file=@/Users/appleboy/test.zip" \ -H "Content-Type: multipart/form-data" ``` #### Multiple files See the detail [example code](https://github.com/gin-gonic/examples/tree/master/upload-file/multiple). ```go func main() { router := gin.Default() // Set a lower memory limit for multipart forms (default is 32 MiB) // router.MaxMultipartMemory = 8 << 20 // 8 MiB router.POST("/upload", func(c *gin.Context) { // Multipart form form, _ := c.MultipartForm() files := form.File["upload[]"] for _, file := range files { log.Println(file.Filename) // Upload the file to specific dst. // c.SaveUploadedFile(file, dst) } c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files))) }) router.Run(":8080") } ``` How to `curl`: ```bash curl -X POST http://localhost:8080/upload \ -F "upload[]=@/Users/appleboy/test1.zip" \ -F "upload[]=@/Users/appleboy/test2.zip" \ -H "Content-Type: multipart/form-data" ``` ### Grouping routes ```go func main() { router := gin.Default() // Simple group: v1 v1 := router.Group("/v1") { v1.POST("/login", loginEndpoint) v1.POST("/submit", submitEndpoint) v1.POST("/read", readEndpoint) } // Simple group: v2 v2 := router.Group("/v2") { v2.POST("/login", loginEndpoint) v2.POST("/submit", submitEndpoint) v2.POST("/read", readEndpoint) } router.Run(":8080") } ``` ### Blank Gin without middleware by default Use ```go r := gin.New() ``` instead of ```go // Default With the Logger and Recovery middleware already attached r := gin.Default() ``` ### Using middleware ```go func main() { // Creates a router without any middleware by default r := gin.New() // Global middleware // Logger middleware will write the logs to gin.DefaultWriter even if you set with GIN_MODE=release. // By default gin.DefaultWriter = os.Stdout r.Use(gin.Logger()) // Recovery middleware recovers from any panics and writes a 500 if there was one. r.Use(gin.Recovery()) // Per route middleware, you can add as many as you desire. r.GET("/benchmark", MyBenchLogger(), benchEndpoint) // Authorization group // authorized := r.Group("/", AuthRequired()) // exactly the same as: authorized := r.Group("/") // per group middleware! in this case we use the custom created // AuthRequired() middleware just in the "authorized" group. authorized.Use(AuthRequired()) { authorized.POST("/login", loginEndpoint) authorized.POST("/submit", submitEndpoint) authorized.POST("/read", readEndpoint) // nested group testing := authorized.Group("testing") testing.GET("/analytics", analyticsEndpoint) } // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` ### How to write log file ```go func main() { // Disable Console Color, you don't need console color when writing the logs to file. gin.DisableConsoleColor() // Logging to a file. f, _ := os.Create("gin.log") gin.DefaultWriter = io.MultiWriter(f) // Use the following code if you need to write the logs to file and console at the same time. // gin.DefaultWriter = io.MultiWriter(f, os.Stdout) router := gin.Default() router.GET("/ping", func(c *gin.Context) { c.String(200, "pong") })    router.Run(":8080") } ``` ### Custom Log Format ```go func main() { router := gin.New() // LoggerWithFormatter middleware will write the logs to gin.DefaultWriter // By default gin.DefaultWriter = os.Stdout router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string { // your custom format return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n", param.ClientIP, param.TimeStamp.Format(time.RFC1123), param.Method, param.Path, param.Request.Proto, param.StatusCode, param.Latency, param.Request.UserAgent(), param.ErrorMessage, ) })) router.Use(gin.Recovery()) router.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) router.Run(":8080") } ``` **Sample Output** ``` ::1 - [Fri, 07 Dec 2018 17:04:38 JST] "GET /ping HTTP/1.1 200 122.767µs "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36" " ``` ### Controlling Log output coloring By default, logs output on console should be colorized depending on the detected TTY. Never colorize logs: ```go func main() { // Disable log's color gin.DisableConsoleColor() // Creates a gin router with default middleware: // logger and recovery (crash-free) middleware router := gin.Default() router.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) router.Run(":8080") } ``` Always colorize logs: ```go func main() { // Force log's color gin.ForceConsoleColor() // Creates a gin router with default middleware: // logger and recovery (crash-free) middleware router := gin.Default() router.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) router.Run(":8080") } ``` ### Model binding and validation To bind a request body into a type, use model binding. We currently support binding of JSON, XML, YAML and standard form values (foo=bar&boo=baz). Gin uses [**go-playground/validator.v8**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](http://godoc.org/gopkg.in/go-playground/validator.v8#hdr-Baked_In_Validators_and_Tags). Note that you need to set the corresponding binding tag on all fields you want to bind. For example, when binding from JSON, set `json:"fieldname"`. Also, Gin provides two sets of methods for binding: - **Type** - Must bind - **Methods** - `Bind`, `BindJSON`, `BindXML`, `BindQuery`, `BindYAML` - **Behavior** - These methods use `MustBindWith` under the hood. If there is a binding error, the request is aborted with `c.AbortWithError(400, err).SetType(ErrorTypeBind)`. This sets the response status code to 400 and the `Content-Type` header is set to `text/plain; charset=utf-8`. Note that if you try to set the response code after this, it will result in a warning `[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422`. If you wish to have greater control over the behavior, consider using the `ShouldBind` equivalent method. - **Type** - Should bind - **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindXML`, `ShouldBindQuery`, `ShouldBindYAML` - **Behavior** - These methods use `ShouldBindWith` under the hood. If there is a binding error, the error is returned and it is the developer's responsibility to handle the request and error appropriately. When using the Bind-method, Gin tries to infer the binder depending on the Content-Type header. If you are sure what you are binding, you can use `MustBindWith` or `ShouldBindWith`. You can also specify that specific fields are required. If a field is decorated with `binding:"required"` and has a empty value when binding, an error will be returned. ```go // Binding from JSON type Login struct { User string `form:"user" json:"user" xml:"user" binding:"required"` Password string `form:"password" json:"password" xml:"password" binding:"required"` } func main() { router := gin.Default() // Example for binding JSON ({"user": "manu", "password": "123"}) router.POST("/loginJSON", func(c *gin.Context) { var json Login if err := c.ShouldBindJSON(&json); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if json.User != "manu" || json.Password != "123" { c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) return } c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) }) // Example for binding XML ( // // // user // 123 // ) router.POST("/loginXML", func(c *gin.Context) { var xml Login if err := c.ShouldBindXML(&xml); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if xml.User != "manu" || xml.Password != "123" { c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) return } c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) }) // Example for binding a HTML form (user=manu&password=123) router.POST("/loginForm", func(c *gin.Context) { var form Login // This will infer what binder to use depending on the content-type header. if err := c.ShouldBind(&form); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if form.User != "manu" || form.Password != "123" { c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) return } c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) }) // Listen and serve on 0.0.0.0:8080 router.Run(":8080") } ``` **Sample request** ```shell $ curl -v -X POST \ http://localhost:8080/loginJSON \ -H 'content-type: application/json' \ -d '{ "user": "manu" }' > POST /loginJSON HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.51.0 > Accept: */* > content-type: application/json > Content-Length: 18 > * upload completely sent off: 18 out of 18 bytes < HTTP/1.1 400 Bad Request < Content-Type: application/json; charset=utf-8 < Date: Fri, 04 Aug 2017 03:51:31 GMT < Content-Length: 100 < {"error":"Key: 'Login.Password' Error:Field validation for 'Password' failed on the 'required' tag"} ``` **Skip validate** When running the above example using the above the `curl` command, it returns error. Because the example use `binding:"required"` for `Password`. If use `binding:"-"` for `Password`, then it will not return error when running the above example again. ### Custom Validators It is also possible to register custom validators. See the [example code](https://github.com/gin-gonic/examples/tree/master/custom-validation/server.go). ```go package main import ( "net/http" "reflect" "time" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "gopkg.in/go-playground/validator.v8" ) // Booking contains binded and validated data. type Booking struct { CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"` CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"` } func bookableDate( v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string, ) bool { if date, ok := field.Interface().(time.Time); ok { today := time.Now() if today.Year() > date.Year() || today.YearDay() > date.YearDay() { return false } } return true } func main() { route := gin.Default() if v, ok := binding.Validator.Engine().(*validator.Validate); ok { v.RegisterValidation("bookabledate", bookableDate) } route.GET("/bookable", getBookable) route.Run(":8085") } func getBookable(c *gin.Context) { var b Booking if err := c.ShouldBindWith(&b, binding.Query); err == nil { c.JSON(http.StatusOK, gin.H{"message": "Booking dates are valid!"}) } else { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) } } ``` ```console $ curl "localhost:8085/bookable?check_in=2018-04-16&check_out=2018-04-17" {"message":"Booking dates are valid!"} $ curl "localhost:8085/bookable?check_in=2018-03-08&check_out=2018-03-09" {"error":"Key: 'Booking.CheckIn' Error:Field validation for 'CheckIn' failed on the 'bookabledate' tag"} ``` [Struct level validations](https://github.com/go-playground/validator/releases/tag/v8.7) can also be registered this way. See the [struct-lvl-validation example](https://github.com/gin-gonic/examples/tree/master/struct-lvl-validations) to learn more. ### Only Bind Query String `ShouldBindQuery` function only binds the query params and not the post data. See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-315953017). ```go package main import ( "log" "github.com/gin-gonic/gin" ) type Person struct { Name string `form:"name"` Address string `form:"address"` } func main() { route := gin.Default() route.Any("/testing", startPage) route.Run(":8085") } func startPage(c *gin.Context) { var person Person if c.ShouldBindQuery(&person) == nil { log.Println("====== Only Bind By Query String ======") log.Println(person.Name) log.Println(person.Address) } c.String(200, "Success") } ``` ### Bind Query String or Post Data See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-264681292). ```go package main import ( "log" "time" "github.com/gin-gonic/gin" ) type Person struct { Name string `form:"name"` Address string `form:"address"` Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"` } func main() { route := gin.Default() route.GET("/testing", startPage) route.Run(":8085") } func startPage(c *gin.Context) { var person Person // If `GET`, only `Form` binding engine (`query`) used. // If `POST`, first checks the `content-type` for `JSON` or `XML`, then uses `Form` (`form-data`). // See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L48 if c.ShouldBind(&person) == nil { log.Println(person.Name) log.Println(person.Address) log.Println(person.Birthday) } c.String(200, "Success") } ``` Test it with: ```sh $ curl -X GET "localhost:8085/testing?name=appleboy&address=xyz&birthday=1992-03-15" ``` ### Bind Uri See the [detail information](https://github.com/gin-gonic/gin/issues/846). ```go package main import "github.com/gin-gonic/gin" type Person struct { ID string `uri:"id" binding:"required,uuid"` Name string `uri:"name" binding:"required"` } func main() { route := gin.Default() route.GET("/:name/:id", func(c *gin.Context) { var person Person if err := c.ShouldBindUri(&person); err != nil { c.JSON(400, gin.H{"msg": err}) return } c.JSON(200, gin.H{"name": person.Name, "uuid": person.ID}) }) route.Run(":8088") } ``` Test it with: ```sh $ curl -v localhost:8088/thinkerou/987fbc97-4bed-5078-9f07-9141ba07c9f3 $ curl -v localhost:8088/thinkerou/not-uuid ``` ### Bind HTML checkboxes See the [detail information](https://github.com/gin-gonic/gin/issues/129#issuecomment-124260092) main.go ```go ... type myForm struct { Colors []string `form:"colors[]"` } ... func formHandler(c *gin.Context) { var fakeForm myForm c.ShouldBind(&fakeForm) c.JSON(200, gin.H{"color": fakeForm.Colors}) } ... ``` form.html ```html

Check some colors

``` result: ``` {"color":["red","green","blue"]} ``` ### Multipart/Urlencoded binding ```go package main import ( "github.com/gin-gonic/gin" ) type LoginForm struct { User string `form:"user" binding:"required"` Password string `form:"password" binding:"required"` } func main() { router := gin.Default() router.POST("/login", func(c *gin.Context) { // you can bind multipart form with explicit binding declaration: // c.ShouldBindWith(&form, binding.Form) // or you can simply use autobinding with ShouldBind method: var form LoginForm // in this case proper binding will be automatically selected if c.ShouldBind(&form) == nil { if form.User == "user" && form.Password == "password" { c.JSON(200, gin.H{"status": "you are logged in"}) } else { c.JSON(401, gin.H{"status": "unauthorized"}) } } }) router.Run(":8080") } ``` Test it with: ```sh $ curl -v --form user=user --form password=password http://localhost:8080/login ``` ### XML, JSON, YAML and ProtoBuf rendering ```go func main() { r := gin.Default() // gin.H is a shortcut for map[string]interface{} r.GET("/someJSON", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.GET("/moreJSON", func(c *gin.Context) { // You also can use a struct var msg struct { Name string `json:"user"` Message string Number int } msg.Name = "Lena" msg.Message = "hey" msg.Number = 123 // Note that msg.Name becomes "user" in the JSON // Will output : {"user": "Lena", "Message": "hey", "Number": 123} c.JSON(http.StatusOK, msg) }) r.GET("/someXML", func(c *gin.Context) { c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.GET("/someYAML", func(c *gin.Context) { c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.GET("/someProtoBuf", func(c *gin.Context) { reps := []int64{int64(1), int64(2)} label := "test" // The specific definition of protobuf is written in the testdata/protoexample file. data := &protoexample.Test{ Label: &label, Reps: reps, } // Note that data becomes binary data in the response // Will output protoexample.Test protobuf serialized data c.ProtoBuf(http.StatusOK, data) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` #### SecureJSON Using SecureJSON to prevent json hijacking. Default prepends `"while(1),"` to response body if the given struct is array values. ```go func main() { r := gin.Default() // You can also use your own secure json prefix // r.SecureJsonPrefix(")]}',\n") r.GET("/someJSON", func(c *gin.Context) { names := []string{"lena", "austin", "foo"} // Will output : while(1);["lena","austin","foo"] c.SecureJSON(http.StatusOK, names) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` #### JSONP Using JSONP to request data from a server in a different domain. Add callback to response body if the query parameter callback exists. ```go func main() { r := gin.Default() r.GET("/JSONP?callback=x", func(c *gin.Context) { data := map[string]interface{}{ "foo": "bar", } //callback is x // Will output : x({\"foo\":\"bar\"}) c.JSONP(http.StatusOK, data) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` #### AsciiJSON Using AsciiJSON to Generates ASCII-only JSON with escaped non-ASCII chracters. ```go func main() { r := gin.Default() r.GET("/someJSON", func(c *gin.Context) { data := map[string]interface{}{ "lang": "GO语言", "tag": "
", } // will output : {"lang":"GO\u8bed\u8a00","tag":"\u003cbr\u003e"} c.AsciiJSON(http.StatusOK, data) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` #### PureJSON Normally, JSON replaces special HTML characters with their unicode entities, e.g. `<` becomes `\u003c`. If you want to encode such characters literally, you can use PureJSON instead. This feature is unavailable in Go 1.6 and lower. ```go func main() { r := gin.Default() // Serves unicode entities r.GET("/json", func(c *gin.Context) { c.JSON(200, gin.H{ "html": "Hello, world!", }) }) // Serves literal characters r.GET("/purejson", func(c *gin.Context) { c.PureJSON(200, gin.H{ "html": "Hello, world!", }) }) // listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` ### Serving static files ```go func main() { router := gin.Default() router.Static("/assets", "./assets") router.StaticFS("/more_static", http.Dir("my_file_system")) router.StaticFile("/favicon.ico", "./resources/favicon.ico") // Listen and serve on 0.0.0.0:8080 router.Run(":8080") } ``` ### Serving data from reader ```go func main() { router := gin.Default() router.GET("/someDataFromReader", func(c *gin.Context) { response, err := http.Get("https://raw.githubusercontent.com/gin-gonic/logo/master/color.png") if err != nil || response.StatusCode != http.StatusOK { c.Status(http.StatusServiceUnavailable) return } reader := response.Body contentLength := response.ContentLength contentType := response.Header.Get("Content-Type") extraHeaders := map[string]string{ "Content-Disposition": `attachment; filename="gopher.png"`, } c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders) }) router.Run(":8080") } ``` ### HTML rendering Using LoadHTMLGlob() or LoadHTMLFiles() ```go func main() { router := gin.Default() router.LoadHTMLGlob("templates/*") //router.LoadHTMLFiles("templates/template1.html", "templates/template2.html") router.GET("/index", func(c *gin.Context) { c.HTML(http.StatusOK, "index.tmpl", gin.H{ "title": "Main website", }) }) router.Run(":8080") } ``` templates/index.tmpl ```html

{{ .title }}

``` Using templates with same name in different directories ```go func main() { router := gin.Default() router.LoadHTMLGlob("templates/**/*") router.GET("/posts/index", func(c *gin.Context) { c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{ "title": "Posts", }) }) router.GET("/users/index", func(c *gin.Context) { c.HTML(http.StatusOK, "users/index.tmpl", gin.H{ "title": "Users", }) }) router.Run(":8080") } ``` templates/posts/index.tmpl ```html {{ define "posts/index.tmpl" }}

{{ .title }}

Using posts/index.tmpl

{{ end }} ``` templates/users/index.tmpl ```html {{ define "users/index.tmpl" }}

{{ .title }}

Using users/index.tmpl

{{ end }} ``` #### Custom Template renderer You can also use your own html template render ```go import "html/template" func main() { router := gin.Default() html := template.Must(template.ParseFiles("file1", "file2")) router.SetHTMLTemplate(html) router.Run(":8080") } ``` #### Custom Delimiters You may use custom delims ```go r := gin.Default() r.Delims("{[{", "}]}") r.LoadHTMLGlob("/path/to/templates") ``` #### Custom Template Funcs See the detail [example code](https://github.com/gin-gonic/examples/tree/master/template). main.go ```go import ( "fmt" "html/template" "net/http" "time" "github.com/gin-gonic/gin" ) func formatAsDate(t time.Time) string { year, month, day := t.Date() return fmt.Sprintf("%d%02d/%02d", year, month, day) } func main() { router := gin.Default() router.Delims("{[{", "}]}") router.SetFuncMap(template.FuncMap{ "formatAsDate": formatAsDate, }) router.LoadHTMLFiles("./testdata/template/raw.tmpl") router.GET("/raw", func(c *gin.Context) { c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{ "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC), }) }) router.Run(":8080") } ``` raw.tmpl ```html Date: {[{.now | formatAsDate}]} ``` Result: ``` Date: 2017/07/01 ``` ### Multitemplate Gin allow by default use only one html.Template. Check [a multitemplate render](https://github.com/gin-contrib/multitemplate) for using features like go 1.6 `block template`. ### Redirects Issuing a HTTP redirect is easy. Both internal and external locations are supported. ```go r.GET("/test", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, "http://www.google.com/") }) ``` Issuing a Router redirect, use `HandleContext` like below. ``` go r.GET("/test", func(c *gin.Context) { c.Request.URL.Path = "/test2" r.HandleContext(c) }) r.GET("/test2", func(c *gin.Context) { c.JSON(200, gin.H{"hello": "world"}) }) ``` ### Custom Middleware ```go func Logger() gin.HandlerFunc { return func(c *gin.Context) { t := time.Now() // Set example variable c.Set("example", "12345") // before request c.Next() // after request latency := time.Since(t) log.Print(latency) // access the status we are sending status := c.Writer.Status() log.Println(status) } } func main() { r := gin.New() r.Use(Logger()) r.GET("/test", func(c *gin.Context) { example := c.MustGet("example").(string) // it would print: "12345" log.Println(example) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` ### Using BasicAuth() middleware ```go // simulate some private data var secrets = gin.H{ "foo": gin.H{"email": "foo@bar.com", "phone": "123433"}, "austin": gin.H{"email": "austin@example.com", "phone": "666"}, "lena": gin.H{"email": "lena@guapa.com", "phone": "523443"}, } func main() { r := gin.Default() // Group using gin.BasicAuth() middleware // gin.Accounts is a shortcut for map[string]string authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{ "foo": "bar", "austin": "1234", "lena": "hello2", "manu": "4321", })) // /admin/secrets endpoint // hit "localhost:8080/admin/secrets authorized.GET("/secrets", func(c *gin.Context) { // get user, it was set by the BasicAuth middleware user := c.MustGet(gin.AuthUserKey).(string) if secret, ok := secrets[user]; ok { c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret}) } else { c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET :("}) } }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` ### Goroutines inside a middleware When starting new Goroutines inside a middleware or handler, you **SHOULD NOT** use the original context inside it, you have to use a read-only copy. ```go func main() { r := gin.Default() r.GET("/long_async", func(c *gin.Context) { // create copy to be used inside the goroutine cCp := c.Copy() go func() { // simulate a long task with time.Sleep(). 5 seconds time.Sleep(5 * time.Second) // note that you are using the copied context "cCp", IMPORTANT log.Println("Done! in path " + cCp.Request.URL.Path) }() }) r.GET("/long_sync", func(c *gin.Context) { // simulate a long task with time.Sleep(). 5 seconds time.Sleep(5 * time.Second) // since we are NOT using a goroutine, we do not have to copy the context log.Println("Done! in path " + c.Request.URL.Path) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` ### Custom HTTP configuration Use `http.ListenAndServe()` directly, like this: ```go func main() { router := gin.Default() http.ListenAndServe(":8080", router) } ``` or ```go func main() { router := gin.Default() s := &http.Server{ Addr: ":8080", Handler: router, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, } s.ListenAndServe() } ``` ### Support Let's Encrypt example for 1-line LetsEncrypt HTTPS servers. ```go package main import ( "log" "github.com/gin-gonic/autotls" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() // Ping handler r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) log.Fatal(autotls.Run(r, "example1.com", "example2.com")) } ``` example for custom autocert manager. ```go package main import ( "log" "github.com/gin-gonic/autotls" "github.com/gin-gonic/gin" "golang.org/x/crypto/acme/autocert" ) func main() { r := gin.Default() // Ping handler r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) m := autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"), Cache: autocert.DirCache("/var/www/.cache"), } log.Fatal(autotls.RunWithManager(r, &m)) } ``` ### Run multiple service using Gin See the [question](https://github.com/gin-gonic/gin/issues/346) and try the following example: ```go package main import ( "log" "net/http" "time" "github.com/gin-gonic/gin" "golang.org/x/sync/errgroup" ) var ( g errgroup.Group ) func router01() http.Handler { e := gin.New() e.Use(gin.Recovery()) e.GET("/", func(c *gin.Context) { c.JSON( http.StatusOK, gin.H{ "code": http.StatusOK, "error": "Welcome server 01", }, ) }) return e } func router02() http.Handler { e := gin.New() e.Use(gin.Recovery()) e.GET("/", func(c *gin.Context) { c.JSON( http.StatusOK, gin.H{ "code": http.StatusOK, "error": "Welcome server 02", }, ) }) return e } func main() { server01 := &http.Server{ Addr: ":8080", Handler: router01(), ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } server02 := &http.Server{ Addr: ":8081", Handler: router02(), ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } g.Go(func() error { return server01.ListenAndServe() }) g.Go(func() error { return server02.ListenAndServe() }) if err := g.Wait(); err != nil { log.Fatal(err) } } ``` ### Graceful restart or stop Do you want to graceful restart or stop your web server? There are some ways this can be done. We can use [fvbock/endless](https://github.com/fvbock/endless) to replace the default `ListenAndServe`. Refer issue [#296](https://github.com/gin-gonic/gin/issues/296) for more details. ```go router := gin.Default() router.GET("/", handler) // [...] endless.ListenAndServe(":4242", router) ``` An alternative to endless: * [manners](https://github.com/braintree/manners): A polite Go HTTP server that shuts down gracefully. * [graceful](https://github.com/tylerb/graceful): Graceful is a Go package enabling graceful shutdown of an http.Handler server. * [grace](https://github.com/facebookgo/grace): Graceful restart & zero downtime deploy for Go servers. If you are using Go 1.8, you may not need to use this library! Consider using http.Server's built-in [Shutdown()](https://golang.org/pkg/net/http/#Server.Shutdown) method for graceful shutdowns. See the full [graceful-shutdown](https://github.com/gin-gonic/examples/tree/master/graceful-shutdown) example with gin. ```go // +build go1.8 package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" "github.com/gin-gonic/gin" ) func main() { router := gin.Default() router.GET("/", func(c *gin.Context) { time.Sleep(5 * time.Second) c.String(http.StatusOK, "Welcome Gin Server") }) srv := &http.Server{ Addr: ":8080", Handler: router, } go func() { // service connections if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("listen: %s\n", err) } }() // Wait for interrupt signal to gracefully shutdown the server with // a timeout of 5 seconds. quit := make(chan os.Signal) // kill (no param) default send syscall.SIGTERM // kill -2 is syscall.SIGINT // kill -9 is syscall.SIGKILL but can"t be catch, so don't need add it signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Println("Shutdown Server ...") ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Fatal("Server Shutdown:", err) } // catching ctx.Done(). timeout of 5 seconds. select { case <-ctx.Done(): log.Println("timeout of 5 seconds.") } log.Println("Server exiting") } ``` ### Build a single binary with templates You can build a server into a single binary containing templates by using [go-assets][]. [go-assets]: https://github.com/jessevdk/go-assets ```go func main() { r := gin.New() t, err := loadTemplate() if err != nil { panic(err) } r.SetHTMLTemplate(t) r.GET("/", func(c *gin.Context) { c.HTML(http.StatusOK, "/html/index.tmpl",nil) }) r.Run(":8080") } // loadTemplate loads templates embedded by go-assets-builder func loadTemplate() (*template.Template, error) { t := template.New("") for name, file := range Assets.Files { if file.IsDir() || !strings.HasSuffix(name, ".tmpl") { continue } h, err := ioutil.ReadAll(file) if err != nil { return nil, err } t, err = t.New(name).Parse(string(h)) if err != nil { return nil, err } } return t, nil } ``` See a complete example in the `https://github.com/gin-gonic/examples/tree/master/assets-in-binary` directory. ### Bind form-data request with custom struct The follow example using custom struct: ```go type StructA struct { FieldA string `form:"field_a"` } type StructB struct { NestedStruct StructA FieldB string `form:"field_b"` } type StructC struct { NestedStructPointer *StructA FieldC string `form:"field_c"` } type StructD struct { NestedAnonyStruct struct { FieldX string `form:"field_x"` } FieldD string `form:"field_d"` } func GetDataB(c *gin.Context) { var b StructB c.Bind(&b) c.JSON(200, gin.H{ "a": b.NestedStruct, "b": b.FieldB, }) } func GetDataC(c *gin.Context) { var b StructC c.Bind(&b) c.JSON(200, gin.H{ "a": b.NestedStructPointer, "c": b.FieldC, }) } func GetDataD(c *gin.Context) { var b StructD c.Bind(&b) c.JSON(200, gin.H{ "x": b.NestedAnonyStruct, "d": b.FieldD, }) } func main() { r := gin.Default() r.GET("/getb", GetDataB) r.GET("/getc", GetDataC) r.GET("/getd", GetDataD) r.Run() } ``` Using the command `curl` command result: ``` $ curl "http://localhost:8080/getb?field_a=hello&field_b=world" {"a":{"FieldA":"hello"},"b":"world"} $ curl "http://localhost:8080/getc?field_a=hello&field_c=world" {"a":{"FieldA":"hello"},"c":"world"} $ curl "http://localhost:8080/getd?field_x=hello&field_d=world" {"d":"world","x":{"FieldX":"hello"}} ``` ### Try to bind body into different structs The normal methods for binding request body consumes `c.Request.Body` and they cannot be called multiple times. ```go type formA struct { Foo string `json:"foo" xml:"foo" binding:"required"` } type formB struct { Bar string `json:"bar" xml:"bar" binding:"required"` } func SomeHandler(c *gin.Context) { objA := formA{} objB := formB{} // This c.ShouldBind consumes c.Request.Body and it cannot be reused. if errA := c.ShouldBind(&objA); errA == nil { c.String(http.StatusOK, `the body should be formA`) // Always an error is occurred by this because c.Request.Body is EOF now. } else if errB := c.ShouldBind(&objB); errB == nil { c.String(http.StatusOK, `the body should be formB`) } else { ... } } ``` For this, you can use `c.ShouldBindBodyWith`. ```go func SomeHandler(c *gin.Context) { objA := formA{} objB := formB{} // This reads c.Request.Body and stores the result into the context. if errA := c.ShouldBindBodyWith(&objA, binding.JSON); errA == nil { c.String(http.StatusOK, `the body should be formA`) // At this time, it reuses body stored in the context. } else if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil { c.String(http.StatusOK, `the body should be formB JSON`) // And it can accepts other formats } else if errB2 := c.ShouldBindBodyWith(&objB, binding.XML); errB2 == nil { c.String(http.StatusOK, `the body should be formB XML`) } else { ... } } ``` * `c.ShouldBindBodyWith` stores body into the context before binding. This has a slight impact to performance, so you should not use this method if you are enough to call binding at once. * This feature is only needed for some formats -- `JSON`, `XML`, `MsgPack`, `ProtoBuf`. For other formats, `Query`, `Form`, `FormPost`, `FormMultipart`, can be called by `c.ShouldBind()` multiple times without any damage to performance (See [#1341](https://github.com/gin-gonic/gin/pull/1341)). ### http2 server push http.Pusher is supported only **go1.8+**. See the [golang blog](https://blog.golang.org/h2push) for detail information. ```go package main import ( "html/template" "log" "github.com/gin-gonic/gin" ) var html = template.Must(template.New("https").Parse(` Https Test

Welcome, Ginner!

`)) func main() { r := gin.Default() r.Static("/assets", "./assets") r.SetHTMLTemplate(html) r.GET("/", func(c *gin.Context) { if pusher := c.Writer.Pusher(); pusher != nil { // use pusher.Push() to do server push if err := pusher.Push("/assets/app.js", nil); err != nil { log.Printf("Failed to push: %v", err) } } c.HTML(200, "https", gin.H{ "status": "success", }) }) // Listen and Server in https://127.0.0.1:8080 r.RunTLS(":8080", "./testdata/server.pem", "./testdata/server.key") } ``` ### Define format for the log of routes The default log of routes is: ``` [GIN-debug] POST /foo --> main.main.func1 (3 handlers) [GIN-debug] GET /bar --> main.main.func2 (3 handlers) [GIN-debug] GET /status --> main.main.func3 (3 handlers) ``` If you want to log this information in given format (e.g. JSON, key values or something else), then you can define this format with `gin.DebugPrintRouteFunc`. In the example below, we log all routes with standard log package but you can use another log tools that suits of your needs. ```go import ( "log" "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) { log.Printf("endpoint %v %v %v %v\n", httpMethod, absolutePath, handlerName, nuHandlers) } r.POST("/foo", func(c *gin.Context) { c.JSON(http.StatusOK, "foo") }) r.GET("/bar", func(c *gin.Context) { c.JSON(http.StatusOK, "bar") }) r.GET("/status", func(c *gin.Context) { c.JSON(http.StatusOK, "ok") }) // Listen and Server in http://0.0.0.0:8080 r.Run() } ``` ### Set and get a cookie ```go import ( "fmt" "github.com/gin-gonic/gin" ) func main() { router := gin.Default() router.GET("/cookie", func(c *gin.Context) { cookie, err := c.Cookie("gin_cookie") if err != nil { cookie = "NotSet" c.SetCookie("gin_cookie", "test", 3600, "/", "localhost", false, true) } fmt.Printf("Cookie value: %s \n", cookie) }) router.Run() } ``` ## Testing The `net/http/httptest` package is preferable way for HTTP testing. ```go package main func setupRouter() *gin.Engine { r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) return r } func main() { r := setupRouter() r.Run(":8080") } ``` Test for code example above: ```go package main import ( "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/assert" ) func TestPingRoute(t *testing.T) { router := setupRouter() w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/ping", nil) router.ServeHTTP(w, req) assert.Equal(t, 200, w.Code) assert.Equal(t, "pong", w.Body.String()) } ``` ## Users Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framework. * [gorush](https://github.com/appleboy/gorush): A push notification server written in Go. * [fnproject](https://github.com/fnproject/fn): The container native, cloud agnostic serverless platform. * [photoprism](https://github.com/photoprism/photoprism): Personal photo management powered by Go and Google TensorFlow. * [krakend](https://github.com/devopsfaith/krakend): Ultra performant API Gateway with middlewares. * [picfit](https://github.com/thoas/picfit): An image resizing server written in Go. ================================================ FILE: vendor/github.com/gin-gonic/gin/auth.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin import ( "crypto/subtle" "encoding/base64" "net/http" "strconv" ) // AuthUserKey is the cookie name for user credential in basic auth. const AuthUserKey = "user" // Accounts defines a key/value for user/pass list of authorized logins. type Accounts map[string]string type authPair struct { value string user string } type authPairs []authPair func (a authPairs) searchCredential(authValue string) (string, bool) { if authValue == "" { return "", false } for _, pair := range a { if pair.value == authValue { return pair.user, true } } return "", false } // BasicAuthForRealm returns a Basic HTTP Authorization middleware. It takes as arguments a map[string]string where // the key is the user name and the value is the password, as well as the name of the Realm. // If the realm is empty, "Authorization Required" will be used by default. // (see http://tools.ietf.org/html/rfc2617#section-1.2) func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc { if realm == "" { realm = "Authorization Required" } realm = "Basic realm=" + strconv.Quote(realm) pairs := processAccounts(accounts) return func(c *Context) { // Search user in the slice of allowed credentials user, found := pairs.searchCredential(c.requestHeader("Authorization")) if !found { // Credentials doesn't match, we return 401 and abort handlers chain. c.Header("WWW-Authenticate", realm) c.AbortWithStatus(http.StatusUnauthorized) return } // The user credentials was found, set user's id to key AuthUserKey in this context, the user's id can be read later using // c.MustGet(gin.AuthUserKey). c.Set(AuthUserKey, user) } } // BasicAuth returns a Basic HTTP Authorization middleware. It takes as argument a map[string]string where // the key is the user name and the value is the password. func BasicAuth(accounts Accounts) HandlerFunc { return BasicAuthForRealm(accounts, "") } func processAccounts(accounts Accounts) authPairs { assert1(len(accounts) > 0, "Empty list of authorized credentials") pairs := make(authPairs, 0, len(accounts)) for user, password := range accounts { assert1(user != "", "User can not be empty") value := authorizationHeader(user, password) pairs = append(pairs, authPair{ value: value, user: user, }) } return pairs } func authorizationHeader(user, password string) string { base := user + ":" + password return "Basic " + base64.StdEncoding.EncodeToString([]byte(base)) } func secureCompare(given, actual string) bool { if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 { return subtle.ConstantTimeCompare([]byte(given), []byte(actual)) == 1 } // Securely compare actual to itself to keep constant time, but always return false. return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false } ================================================ FILE: vendor/github.com/gin-gonic/gin/binding/binding.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package binding import "net/http" // Content-Type MIME of the most common data formats. const ( MIMEJSON = "application/json" MIMEHTML = "text/html" MIMEXML = "application/xml" MIMEXML2 = "text/xml" MIMEPlain = "text/plain" MIMEPOSTForm = "application/x-www-form-urlencoded" MIMEMultipartPOSTForm = "multipart/form-data" MIMEPROTOBUF = "application/x-protobuf" MIMEMSGPACK = "application/x-msgpack" MIMEMSGPACK2 = "application/msgpack" MIMEYAML = "application/x-yaml" ) // Binding describes the interface which needs to be implemented for binding the // data present in the request such as JSON request body, query parameters or // the form POST. type Binding interface { Name() string Bind(*http.Request, interface{}) error } // BindingBody adds BindBody method to Binding. BindBody is similar with Bind, // but it reads the body from supplied bytes instead of req.Body. type BindingBody interface { Binding BindBody([]byte, interface{}) error } // BindingUri adds BindUri method to Binding. BindUri is similar with Bind, // but it read the Params. type BindingUri interface { Name() string BindUri(map[string][]string, interface{}) error } // StructValidator is the minimal interface which needs to be implemented in // order for it to be used as the validator engine for ensuring the correctness // of the request. Gin provides a default implementation for this using // https://github.com/go-playground/validator/tree/v8.18.2. type StructValidator interface { // ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right. // If the received type is not a struct, any validation should be skipped and nil must be returned. // If the received type is a struct or pointer to a struct, the validation should be performed. // If the struct is not valid or the validation itself fails, a descriptive error should be returned. // Otherwise nil must be returned. ValidateStruct(interface{}) error // Engine returns the underlying validator engine which powers the // StructValidator implementation. Engine() interface{} } // Validator is the default validator which implements the StructValidator // interface. It uses https://github.com/go-playground/validator/tree/v8.18.2 // under the hood. var Validator StructValidator = &defaultValidator{} // These implement the Binding interface and can be used to bind the data // present in the request to struct instances. var ( JSON = jsonBinding{} XML = xmlBinding{} Form = formBinding{} Query = queryBinding{} FormPost = formPostBinding{} FormMultipart = formMultipartBinding{} ProtoBuf = protobufBinding{} MsgPack = msgpackBinding{} YAML = yamlBinding{} Uri = uriBinding{} ) // Default returns the appropriate Binding instance based on the HTTP method // and the content type. func Default(method, contentType string) Binding { if method == "GET" { return Form } switch contentType { case MIMEJSON: return JSON case MIMEXML, MIMEXML2: return XML case MIMEPROTOBUF: return ProtoBuf case MIMEMSGPACK, MIMEMSGPACK2: return MsgPack case MIMEYAML: return YAML case MIMEMultipartPOSTForm: return FormMultipart default: // case MIMEPOSTForm: return Form } } func validate(obj interface{}) error { if Validator == nil { return nil } return Validator.ValidateStruct(obj) } ================================================ FILE: vendor/github.com/gin-gonic/gin/binding/default_validator.go ================================================ // Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package binding import ( "reflect" "sync" "gopkg.in/go-playground/validator.v8" ) type defaultValidator struct { once sync.Once validate *validator.Validate } var _ StructValidator = &defaultValidator{} // ValidateStruct receives any kind of type, but only performed struct or pointer to struct type. func (v *defaultValidator) ValidateStruct(obj interface{}) error { value := reflect.ValueOf(obj) valueType := value.Kind() if valueType == reflect.Ptr { valueType = value.Elem().Kind() } if valueType == reflect.Struct { v.lazyinit() if err := v.validate.Struct(obj); err != nil { return err } } return nil } // Engine returns the underlying validator engine which powers the default // Validator instance. This is useful if you want to register custom validations // or struct level validations. See validator GoDoc for more info - // https://godoc.org/gopkg.in/go-playground/validator.v8 func (v *defaultValidator) Engine() interface{} { v.lazyinit() return v.validate } func (v *defaultValidator) lazyinit() { v.once.Do(func() { config := &validator.Config{TagName: "binding"} v.validate = validator.New(config) }) } ================================================ FILE: vendor/github.com/gin-gonic/gin/binding/form.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package binding import ( "mime/multipart" "net/http" "reflect" ) const defaultMemory = 32 * 1024 * 1024 type formBinding struct{} type formPostBinding struct{} type formMultipartBinding struct{} func (formBinding) Name() string { return "form" } func (formBinding) Bind(req *http.Request, obj interface{}) error { if err := req.ParseForm(); err != nil { return err } if err := req.ParseMultipartForm(defaultMemory); err != nil { if err != http.ErrNotMultipart { return err } } if err := mapForm(obj, req.Form); err != nil { return err } return validate(obj) } func (formPostBinding) Name() string { return "form-urlencoded" } func (formPostBinding) Bind(req *http.Request, obj interface{}) error { if err := req.ParseForm(); err != nil { return err } if err := mapForm(obj, req.PostForm); err != nil { return err } return validate(obj) } func (formMultipartBinding) Name() string { return "multipart/form-data" } func (formMultipartBinding) Bind(req *http.Request, obj interface{}) error { if err := req.ParseMultipartForm(defaultMemory); err != nil { return err } if err := mappingByPtr(obj, (*multipartRequest)(req), "form"); err != nil { return err } return validate(obj) } type multipartRequest http.Request var _ setter = (*multipartRequest)(nil) var ( multipartFileHeaderStructType = reflect.TypeOf(multipart.FileHeader{}) ) // TrySet tries to set a value by the multipart request with the binding a form file func (r *multipartRequest) TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error) { if value.Type() == multipartFileHeaderStructType { _, file, err := (*http.Request)(r).FormFile(key) if err != nil { return false, err } if file != nil { value.Set(reflect.ValueOf(*file)) return true, nil } } return setByForm(value, field, r.MultipartForm.Value, key, opt) } ================================================ FILE: vendor/github.com/gin-gonic/gin/binding/form_mapping.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package binding import ( "errors" "fmt" "reflect" "strconv" "strings" "time" "github.com/gin-gonic/gin/internal/json" ) var errUnknownType = errors.New("Unknown type") func mapUri(ptr interface{}, m map[string][]string) error { return mapFormByTag(ptr, m, "uri") } func mapForm(ptr interface{}, form map[string][]string) error { return mapFormByTag(ptr, form, "form") } var emptyField = reflect.StructField{} func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error { return mappingByPtr(ptr, formSource(form), tag) } // setter tries to set value on a walking by fields of a struct type setter interface { TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error) } type formSource map[string][]string var _ setter = formSource(nil) // TrySet tries to set a value by request's form source (like map[string][]string) func (form formSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSetted bool, err error) { return setByForm(value, field, form, tagValue, opt) } func mappingByPtr(ptr interface{}, setter setter, tag string) error { _, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag) return err } func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) { var vKind = value.Kind() if vKind == reflect.Ptr { var isNew bool vPtr := value if value.IsNil() { isNew = true vPtr = reflect.New(value.Type().Elem()) } isSetted, err := mapping(vPtr.Elem(), field, setter, tag) if err != nil { return false, err } if isNew && isSetted { value.Set(vPtr) } return isSetted, nil } ok, err := tryToSetValue(value, field, setter, tag) if err != nil { return false, err } if ok { return true, nil } if vKind == reflect.Struct { tValue := value.Type() var isSetted bool for i := 0; i < value.NumField(); i++ { if !value.Field(i).CanSet() { continue } ok, err := mapping(value.Field(i), tValue.Field(i), setter, tag) if err != nil { return false, err } isSetted = isSetted || ok } return isSetted, nil } return false, nil } type setOptions struct { isDefaultExists bool defaultValue string } func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) { var tagValue string var setOpt setOptions tagValue = field.Tag.Get(tag) tagValue, opts := head(tagValue, ",") if tagValue == "-" { // just ignoring this field return false, nil } if tagValue == "" { // default value is FieldName tagValue = field.Name } if tagValue == "" { // when field is "emptyField" variable return false, nil } var opt string for len(opts) > 0 { opt, opts = head(opts, ",") k, v := head(opt, "=") switch k { case "default": setOpt.isDefaultExists = true setOpt.defaultValue = v } } return setter.TrySet(value, field, tagValue, setOpt) } func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSetted bool, err error) { vs, ok := form[tagValue] if !ok && !opt.isDefaultExists { return false, nil } switch value.Kind() { case reflect.Slice: if !ok { vs = []string{opt.defaultValue} } return true, setSlice(vs, value, field) case reflect.Array: if !ok { vs = []string{opt.defaultValue} } if len(vs) != value.Len() { return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String()) } return true, setArray(vs, value, field) default: var val string if !ok { val = opt.defaultValue } if len(vs) > 0 { val = vs[0] } return true, setWithProperType(val, value, field) } } func setWithProperType(val string, value reflect.Value, field reflect.StructField) error { switch value.Kind() { case reflect.Int: return setIntField(val, 0, value) case reflect.Int8: return setIntField(val, 8, value) case reflect.Int16: return setIntField(val, 16, value) case reflect.Int32: return setIntField(val, 32, value) case reflect.Int64: switch value.Interface().(type) { case time.Duration: return setTimeDuration(val, value, field) } return setIntField(val, 64, value) case reflect.Uint: return setUintField(val, 0, value) case reflect.Uint8: return setUintField(val, 8, value) case reflect.Uint16: return setUintField(val, 16, value) case reflect.Uint32: return setUintField(val, 32, value) case reflect.Uint64: return setUintField(val, 64, value) case reflect.Bool: return setBoolField(val, value) case reflect.Float32: return setFloatField(val, 32, value) case reflect.Float64: return setFloatField(val, 64, value) case reflect.String: value.SetString(val) case reflect.Struct: switch value.Interface().(type) { case time.Time: return setTimeField(val, field, value) } return json.Unmarshal([]byte(val), value.Addr().Interface()) case reflect.Map: return json.Unmarshal([]byte(val), value.Addr().Interface()) default: return errUnknownType } return nil } func setIntField(val string, bitSize int, field reflect.Value) error { if val == "" { val = "0" } intVal, err := strconv.ParseInt(val, 10, bitSize) if err == nil { field.SetInt(intVal) } return err } func setUintField(val string, bitSize int, field reflect.Value) error { if val == "" { val = "0" } uintVal, err := strconv.ParseUint(val, 10, bitSize) if err == nil { field.SetUint(uintVal) } return err } func setBoolField(val string, field reflect.Value) error { if val == "" { val = "false" } boolVal, err := strconv.ParseBool(val) if err == nil { field.SetBool(boolVal) } return err } func setFloatField(val string, bitSize int, field reflect.Value) error { if val == "" { val = "0.0" } floatVal, err := strconv.ParseFloat(val, bitSize) if err == nil { field.SetFloat(floatVal) } return err } func setTimeField(val string, structField reflect.StructField, value reflect.Value) error { timeFormat := structField.Tag.Get("time_format") if timeFormat == "" { timeFormat = time.RFC3339 } if val == "" { value.Set(reflect.ValueOf(time.Time{})) return nil } l := time.Local if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC { l = time.UTC } if locTag := structField.Tag.Get("time_location"); locTag != "" { loc, err := time.LoadLocation(locTag) if err != nil { return err } l = loc } t, err := time.ParseInLocation(timeFormat, val, l) if err != nil { return err } value.Set(reflect.ValueOf(t)) return nil } func setArray(vals []string, value reflect.Value, field reflect.StructField) error { for i, s := range vals { err := setWithProperType(s, value.Index(i), field) if err != nil { return err } } return nil } func setSlice(vals []string, value reflect.Value, field reflect.StructField) error { slice := reflect.MakeSlice(value.Type(), len(vals), len(vals)) err := setArray(vals, slice, field) if err != nil { return err } value.Set(slice) return nil } func setTimeDuration(val string, value reflect.Value, field reflect.StructField) error { d, err := time.ParseDuration(val) if err != nil { return err } value.Set(reflect.ValueOf(d)) return nil } func head(str, sep string) (head string, tail string) { idx := strings.Index(str, sep) if idx < 0 { return str, "" } return str[:idx], str[idx+len(sep):] } ================================================ FILE: vendor/github.com/gin-gonic/gin/binding/json.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package binding import ( "bytes" "fmt" "io" "net/http" "github.com/gin-gonic/gin/internal/json" ) // EnableDecoderUseNumber is used to call the UseNumber method on the JSON // Decoder instance. UseNumber causes the Decoder to unmarshal a number into an // interface{} as a Number instead of as a float64. var EnableDecoderUseNumber = false type jsonBinding struct{} func (jsonBinding) Name() string { return "json" } func (jsonBinding) Bind(req *http.Request, obj interface{}) error { if req == nil || req.Body == nil { return fmt.Errorf("invalid request") } return decodeJSON(req.Body, obj) } func (jsonBinding) BindBody(body []byte, obj interface{}) error { return decodeJSON(bytes.NewReader(body), obj) } func decodeJSON(r io.Reader, obj interface{}) error { decoder := json.NewDecoder(r) if EnableDecoderUseNumber { decoder.UseNumber() } if err := decoder.Decode(obj); err != nil { return err } return validate(obj) } ================================================ FILE: vendor/github.com/gin-gonic/gin/binding/msgpack.go ================================================ // Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package binding import ( "bytes" "io" "net/http" "github.com/ugorji/go/codec" ) type msgpackBinding struct{} func (msgpackBinding) Name() string { return "msgpack" } func (msgpackBinding) Bind(req *http.Request, obj interface{}) error { return decodeMsgPack(req.Body, obj) } func (msgpackBinding) BindBody(body []byte, obj interface{}) error { return decodeMsgPack(bytes.NewReader(body), obj) } func decodeMsgPack(r io.Reader, obj interface{}) error { cdc := new(codec.MsgpackHandle) if err := codec.NewDecoder(r, cdc).Decode(&obj); err != nil { return err } return validate(obj) } ================================================ FILE: vendor/github.com/gin-gonic/gin/binding/protobuf.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package binding import ( "io/ioutil" "net/http" "github.com/golang/protobuf/proto" ) type protobufBinding struct{} func (protobufBinding) Name() string { return "protobuf" } func (b protobufBinding) Bind(req *http.Request, obj interface{}) error { buf, err := ioutil.ReadAll(req.Body) if err != nil { return err } return b.BindBody(buf, obj) } func (protobufBinding) BindBody(body []byte, obj interface{}) error { if err := proto.Unmarshal(body, obj.(proto.Message)); err != nil { return err } // Here it's same to return validate(obj), but util now we can't add // `binding:""` to the struct which automatically generate by gen-proto return nil // return validate(obj) } ================================================ FILE: vendor/github.com/gin-gonic/gin/binding/query.go ================================================ // Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package binding import "net/http" type queryBinding struct{} func (queryBinding) Name() string { return "query" } func (queryBinding) Bind(req *http.Request, obj interface{}) error { values := req.URL.Query() if err := mapForm(obj, values); err != nil { return err } return validate(obj) } ================================================ FILE: vendor/github.com/gin-gonic/gin/binding/uri.go ================================================ // Copyright 2018 Gin Core Team. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package binding type uriBinding struct{} func (uriBinding) Name() string { return "uri" } func (uriBinding) BindUri(m map[string][]string, obj interface{}) error { if err := mapUri(obj, m); err != nil { return err } return validate(obj) } ================================================ FILE: vendor/github.com/gin-gonic/gin/binding/xml.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package binding import ( "bytes" "encoding/xml" "io" "net/http" ) type xmlBinding struct{} func (xmlBinding) Name() string { return "xml" } func (xmlBinding) Bind(req *http.Request, obj interface{}) error { return decodeXML(req.Body, obj) } func (xmlBinding) BindBody(body []byte, obj interface{}) error { return decodeXML(bytes.NewReader(body), obj) } func decodeXML(r io.Reader, obj interface{}) error { decoder := xml.NewDecoder(r) if err := decoder.Decode(obj); err != nil { return err } return validate(obj) } ================================================ FILE: vendor/github.com/gin-gonic/gin/binding/yaml.go ================================================ // Copyright 2018 Gin Core Team. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package binding import ( "bytes" "io" "net/http" "gopkg.in/yaml.v2" ) type yamlBinding struct{} func (yamlBinding) Name() string { return "yaml" } func (yamlBinding) Bind(req *http.Request, obj interface{}) error { return decodeYAML(req.Body, obj) } func (yamlBinding) BindBody(body []byte, obj interface{}) error { return decodeYAML(bytes.NewReader(body), obj) } func decodeYAML(r io.Reader, obj interface{}) error { decoder := yaml.NewDecoder(r) if err := decoder.Decode(obj); err != nil { return err } return validate(obj) } ================================================ FILE: vendor/github.com/gin-gonic/gin/codecov.yml ================================================ coverage: notify: gitter: default: url: https://webhooks.gitter.im/e/d90dcdeeab2f1e357165 ================================================ FILE: vendor/github.com/gin-gonic/gin/context.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin import ( "errors" "fmt" "io" "io/ioutil" "math" "mime/multipart" "net" "net/http" "net/url" "os" "strings" "time" "github.com/gin-contrib/sse" "github.com/gin-gonic/gin/binding" "github.com/gin-gonic/gin/render" ) // Content-Type MIME of the most common data formats. const ( MIMEJSON = binding.MIMEJSON MIMEHTML = binding.MIMEHTML MIMEXML = binding.MIMEXML MIMEXML2 = binding.MIMEXML2 MIMEPlain = binding.MIMEPlain MIMEPOSTForm = binding.MIMEPOSTForm MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm MIMEYAML = binding.MIMEYAML BodyBytesKey = "_gin-gonic/gin/bodybyteskey" ) const abortIndex int8 = math.MaxInt8 / 2 // Context is the most important part of gin. It allows us to pass variables between middleware, // manage the flow, validate the JSON of a request and render a JSON response for example. type Context struct { writermem responseWriter Request *http.Request Writer ResponseWriter Params Params handlers HandlersChain index int8 engine *Engine // Keys is a key/value pair exclusively for the context of each request. Keys map[string]interface{} // Errors is a list of errors attached to all the handlers/middlewares who used this context. Errors errorMsgs // Accepted defines a list of manually accepted formats for content negotiation. Accepted []string } /************************************/ /********** CONTEXT CREATION ********/ /************************************/ func (c *Context) reset() { c.Writer = &c.writermem c.Params = c.Params[0:0] c.handlers = nil c.index = -1 c.Keys = nil c.Errors = c.Errors[0:0] c.Accepted = nil } // Copy returns a copy of the current context that can be safely used outside the request's scope. // This has to be used when the context has to be passed to a goroutine. func (c *Context) Copy() *Context { var cp = *c cp.writermem.ResponseWriter = nil cp.Writer = &cp.writermem cp.index = abortIndex cp.handlers = nil cp.Keys = map[string]interface{}{} for k, v := range c.Keys { cp.Keys[k] = v } return &cp } // HandlerName returns the main handler's name. For example if the handler is "handleGetUsers()", // this function will return "main.handleGetUsers". func (c *Context) HandlerName() string { return nameOfFunction(c.handlers.Last()) } // HandlerNames returns a list of all registered handlers for this context in descending order, // following the semantics of HandlerName() func (c *Context) HandlerNames() []string { hn := make([]string, 0, len(c.handlers)) for _, val := range c.handlers { hn = append(hn, nameOfFunction(val)) } return hn } // Handler returns the main handler. func (c *Context) Handler() HandlerFunc { return c.handlers.Last() } /************************************/ /*********** FLOW CONTROL ***********/ /************************************/ // Next should be used only inside middleware. // It executes the pending handlers in the chain inside the calling handler. // See example in GitHub. func (c *Context) Next() { c.index++ for c.index < int8(len(c.handlers)) { c.handlers[c.index](c) c.index++ } } // IsAborted returns true if the current context was aborted. func (c *Context) IsAborted() bool { return c.index >= abortIndex } // Abort prevents pending handlers from being called. Note that this will not stop the current handler. // Let's say you have an authorization middleware that validates that the current request is authorized. // If the authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers // for this request are not called. func (c *Context) Abort() { c.index = abortIndex } // AbortWithStatus calls `Abort()` and writes the headers with the specified status code. // For example, a failed attempt to authenticate a request could use: context.AbortWithStatus(401). func (c *Context) AbortWithStatus(code int) { c.Status(code) c.Writer.WriteHeaderNow() c.Abort() } // AbortWithStatusJSON calls `Abort()` and then `JSON` internally. // This method stops the chain, writes the status code and return a JSON body. // It also sets the Content-Type as "application/json". func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{}) { c.Abort() c.JSON(code, jsonObj) } // AbortWithError calls `AbortWithStatus()` and `Error()` internally. // This method stops the chain, writes the status code and pushes the specified error to `c.Errors`. // See Context.Error() for more details. func (c *Context) AbortWithError(code int, err error) *Error { c.AbortWithStatus(code) return c.Error(err) } /************************************/ /********* ERROR MANAGEMENT *********/ /************************************/ // Error attaches an error to the current context. The error is pushed to a list of errors. // It's a good idea to call Error for each error that occurred during the resolution of a request. // A middleware can be used to collect all the errors and push them to a database together, // print a log, or append it in the HTTP response. // Error will panic if err is nil. func (c *Context) Error(err error) *Error { if err == nil { panic("err is nil") } parsedError, ok := err.(*Error) if !ok { parsedError = &Error{ Err: err, Type: ErrorTypePrivate, } } c.Errors = append(c.Errors, parsedError) return parsedError } /************************************/ /******** METADATA MANAGEMENT********/ /************************************/ // Set is used to store a new key/value pair exclusively for this context. // It also lazy initializes c.Keys if it was not used previously. func (c *Context) Set(key string, value interface{}) { if c.Keys == nil { c.Keys = make(map[string]interface{}) } c.Keys[key] = value } // Get returns the value for the given key, ie: (value, true). // If the value does not exists it returns (nil, false) func (c *Context) Get(key string) (value interface{}, exists bool) { value, exists = c.Keys[key] return } // MustGet returns the value for the given key if it exists, otherwise it panics. func (c *Context) MustGet(key string) interface{} { if value, exists := c.Get(key); exists { return value } panic("Key \"" + key + "\" does not exist") } // GetString returns the value associated with the key as a string. func (c *Context) GetString(key string) (s string) { if val, ok := c.Get(key); ok && val != nil { s, _ = val.(string) } return } // GetBool returns the value associated with the key as a boolean. func (c *Context) GetBool(key string) (b bool) { if val, ok := c.Get(key); ok && val != nil { b, _ = val.(bool) } return } // GetInt returns the value associated with the key as an integer. func (c *Context) GetInt(key string) (i int) { if val, ok := c.Get(key); ok && val != nil { i, _ = val.(int) } return } // GetInt64 returns the value associated with the key as an integer. func (c *Context) GetInt64(key string) (i64 int64) { if val, ok := c.Get(key); ok && val != nil { i64, _ = val.(int64) } return } // GetFloat64 returns the value associated with the key as a float64. func (c *Context) GetFloat64(key string) (f64 float64) { if val, ok := c.Get(key); ok && val != nil { f64, _ = val.(float64) } return } // GetTime returns the value associated with the key as time. func (c *Context) GetTime(key string) (t time.Time) { if val, ok := c.Get(key); ok && val != nil { t, _ = val.(time.Time) } return } // GetDuration returns the value associated with the key as a duration. func (c *Context) GetDuration(key string) (d time.Duration) { if val, ok := c.Get(key); ok && val != nil { d, _ = val.(time.Duration) } return } // GetStringSlice returns the value associated with the key as a slice of strings. func (c *Context) GetStringSlice(key string) (ss []string) { if val, ok := c.Get(key); ok && val != nil { ss, _ = val.([]string) } return } // GetStringMap returns the value associated with the key as a map of interfaces. func (c *Context) GetStringMap(key string) (sm map[string]interface{}) { if val, ok := c.Get(key); ok && val != nil { sm, _ = val.(map[string]interface{}) } return } // GetStringMapString returns the value associated with the key as a map of strings. func (c *Context) GetStringMapString(key string) (sms map[string]string) { if val, ok := c.Get(key); ok && val != nil { sms, _ = val.(map[string]string) } return } // GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings. func (c *Context) GetStringMapStringSlice(key string) (smss map[string][]string) { if val, ok := c.Get(key); ok && val != nil { smss, _ = val.(map[string][]string) } return } /************************************/ /************ INPUT DATA ************/ /************************************/ // Param returns the value of the URL param. // It is a shortcut for c.Params.ByName(key) // router.GET("/user/:id", func(c *gin.Context) { // // a GET request to /user/john // id := c.Param("id") // id == "john" // }) func (c *Context) Param(key string) string { return c.Params.ByName(key) } // Query returns the keyed url query value if it exists, // otherwise it returns an empty string `("")`. // It is shortcut for `c.Request.URL.Query().Get(key)` // GET /path?id=1234&name=Manu&value= // c.Query("id") == "1234" // c.Query("name") == "Manu" // c.Query("value") == "" // c.Query("wtf") == "" func (c *Context) Query(key string) string { value, _ := c.GetQuery(key) return value } // DefaultQuery returns the keyed url query value if it exists, // otherwise it returns the specified defaultValue string. // See: Query() and GetQuery() for further information. // GET /?name=Manu&lastname= // c.DefaultQuery("name", "unknown") == "Manu" // c.DefaultQuery("id", "none") == "none" // c.DefaultQuery("lastname", "none") == "" func (c *Context) DefaultQuery(key, defaultValue string) string { if value, ok := c.GetQuery(key); ok { return value } return defaultValue } // GetQuery is like Query(), it returns the keyed url query value // if it exists `(value, true)` (even when the value is an empty string), // otherwise it returns `("", false)`. // It is shortcut for `c.Request.URL.Query().Get(key)` // GET /?name=Manu&lastname= // ("Manu", true) == c.GetQuery("name") // ("", false) == c.GetQuery("id") // ("", true) == c.GetQuery("lastname") func (c *Context) GetQuery(key string) (string, bool) { if values, ok := c.GetQueryArray(key); ok { return values[0], ok } return "", false } // QueryArray returns a slice of strings for a given query key. // The length of the slice depends on the number of params with the given key. func (c *Context) QueryArray(key string) []string { values, _ := c.GetQueryArray(key) return values } // GetQueryArray returns a slice of strings for a given query key, plus // a boolean value whether at least one value exists for the given key. func (c *Context) GetQueryArray(key string) ([]string, bool) { if values, ok := c.Request.URL.Query()[key]; ok && len(values) > 0 { return values, true } return []string{}, false } // QueryMap returns a map for a given query key. func (c *Context) QueryMap(key string) map[string]string { dicts, _ := c.GetQueryMap(key) return dicts } // GetQueryMap returns a map for a given query key, plus a boolean value // whether at least one value exists for the given key. func (c *Context) GetQueryMap(key string) (map[string]string, bool) { return c.get(c.Request.URL.Query(), key) } // PostForm returns the specified key from a POST urlencoded form or multipart form // when it exists, otherwise it returns an empty string `("")`. func (c *Context) PostForm(key string) string { value, _ := c.GetPostForm(key) return value } // DefaultPostForm returns the specified key from a POST urlencoded form or multipart form // when it exists, otherwise it returns the specified defaultValue string. // See: PostForm() and GetPostForm() for further information. func (c *Context) DefaultPostForm(key, defaultValue string) string { if value, ok := c.GetPostForm(key); ok { return value } return defaultValue } // GetPostForm is like PostForm(key). It returns the specified key from a POST urlencoded // form or multipart form when it exists `(value, true)` (even when the value is an empty string), // otherwise it returns ("", false). // For example, during a PATCH request to update the user's email: // email=mail@example.com --> ("mail@example.com", true) := GetPostForm("email") // set email to "mail@example.com" // email= --> ("", true) := GetPostForm("email") // set email to "" // --> ("", false) := GetPostForm("email") // do nothing with email func (c *Context) GetPostForm(key string) (string, bool) { if values, ok := c.GetPostFormArray(key); ok { return values[0], ok } return "", false } // PostFormArray returns a slice of strings for a given form key. // The length of the slice depends on the number of params with the given key. func (c *Context) PostFormArray(key string) []string { values, _ := c.GetPostFormArray(key) return values } // GetPostFormArray returns a slice of strings for a given form key, plus // a boolean value whether at least one value exists for the given key. func (c *Context) GetPostFormArray(key string) ([]string, bool) { req := c.Request if err := req.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil { if err != http.ErrNotMultipart { debugPrint("error on parse multipart form array: %v", err) } } if values := req.PostForm[key]; len(values) > 0 { return values, true } return []string{}, false } // PostFormMap returns a map for a given form key. func (c *Context) PostFormMap(key string) map[string]string { dicts, _ := c.GetPostFormMap(key) return dicts } // GetPostFormMap returns a map for a given form key, plus a boolean value // whether at least one value exists for the given key. func (c *Context) GetPostFormMap(key string) (map[string]string, bool) { req := c.Request if err := req.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil { if err != http.ErrNotMultipart { debugPrint("error on parse multipart form map: %v", err) } } return c.get(req.PostForm, key) } // get is an internal method and returns a map which satisfy conditions. func (c *Context) get(m map[string][]string, key string) (map[string]string, bool) { dicts := make(map[string]string) exist := false for k, v := range m { if i := strings.IndexByte(k, '['); i >= 1 && k[0:i] == key { if j := strings.IndexByte(k[i+1:], ']'); j >= 1 { exist = true dicts[k[i+1:][:j]] = v[0] } } } return dicts, exist } // FormFile returns the first file for the provided form key. func (c *Context) FormFile(name string) (*multipart.FileHeader, error) { if c.Request.MultipartForm == nil { if err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil { return nil, err } } _, fh, err := c.Request.FormFile(name) return fh, err } // MultipartForm is the parsed multipart form, including file uploads. func (c *Context) MultipartForm() (*multipart.Form, error) { err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory) return c.Request.MultipartForm, err } // SaveUploadedFile uploads the form file to specific dst. func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error { src, err := file.Open() if err != nil { return err } defer src.Close() out, err := os.Create(dst) if err != nil { return err } defer out.Close() _, err = io.Copy(out, src) return err } // Bind checks the Content-Type to select a binding engine automatically, // Depending the "Content-Type" header different bindings are used: // "application/json" --> JSON binding // "application/xml" --> XML binding // otherwise --> returns an error. // It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. // It decodes the json payload into the struct specified as a pointer. // It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid. func (c *Context) Bind(obj interface{}) error { b := binding.Default(c.Request.Method, c.ContentType()) return c.MustBindWith(obj, b) } // BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON). func (c *Context) BindJSON(obj interface{}) error { return c.MustBindWith(obj, binding.JSON) } // BindXML is a shortcut for c.MustBindWith(obj, binding.BindXML). func (c *Context) BindXML(obj interface{}) error { return c.MustBindWith(obj, binding.XML) } // BindQuery is a shortcut for c.MustBindWith(obj, binding.Query). func (c *Context) BindQuery(obj interface{}) error { return c.MustBindWith(obj, binding.Query) } // BindYAML is a shortcut for c.MustBindWith(obj, binding.YAML). func (c *Context) BindYAML(obj interface{}) error { return c.MustBindWith(obj, binding.YAML) } // BindUri binds the passed struct pointer using binding.Uri. // It will abort the request with HTTP 400 if any error occurs. func (c *Context) BindUri(obj interface{}) error { if err := c.ShouldBindUri(obj); err != nil { c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck return err } return nil } // MustBindWith binds the passed struct pointer using the specified binding engine. // It will abort the request with HTTP 400 if any error occurs. // See the binding package. func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error { if err := c.ShouldBindWith(obj, b); err != nil { c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck return err } return nil } // ShouldBind checks the Content-Type to select a binding engine automatically, // Depending the "Content-Type" header different bindings are used: // "application/json" --> JSON binding // "application/xml" --> XML binding // otherwise --> returns an error // It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. // It decodes the json payload into the struct specified as a pointer. // Like c.Bind() but this method does not set the response status code to 400 and abort if the json is not valid. func (c *Context) ShouldBind(obj interface{}) error { b := binding.Default(c.Request.Method, c.ContentType()) return c.ShouldBindWith(obj, b) } // ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON). func (c *Context) ShouldBindJSON(obj interface{}) error { return c.ShouldBindWith(obj, binding.JSON) } // ShouldBindXML is a shortcut for c.ShouldBindWith(obj, binding.XML). func (c *Context) ShouldBindXML(obj interface{}) error { return c.ShouldBindWith(obj, binding.XML) } // ShouldBindQuery is a shortcut for c.ShouldBindWith(obj, binding.Query). func (c *Context) ShouldBindQuery(obj interface{}) error { return c.ShouldBindWith(obj, binding.Query) } // ShouldBindYAML is a shortcut for c.ShouldBindWith(obj, binding.YAML). func (c *Context) ShouldBindYAML(obj interface{}) error { return c.ShouldBindWith(obj, binding.YAML) } // ShouldBindUri binds the passed struct pointer using the specified binding engine. func (c *Context) ShouldBindUri(obj interface{}) error { m := make(map[string][]string) for _, v := range c.Params { m[v.Key] = []string{v.Value} } return binding.Uri.BindUri(m, obj) } // ShouldBindWith binds the passed struct pointer using the specified binding engine. // See the binding package. func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error { return b.Bind(c.Request, obj) } // ShouldBindBodyWith is similar with ShouldBindWith, but it stores the request // body into the context, and reuse when it is called again. // // NOTE: This method reads the body before binding. So you should use // ShouldBindWith for better performance if you need to call only once. func (c *Context) ShouldBindBodyWith(obj interface{}, bb binding.BindingBody) (err error) { var body []byte if cb, ok := c.Get(BodyBytesKey); ok { if cbb, ok := cb.([]byte); ok { body = cbb } } if body == nil { body, err = ioutil.ReadAll(c.Request.Body) if err != nil { return err } c.Set(BodyBytesKey, body) } return bb.BindBody(body, obj) } // ClientIP implements a best effort algorithm to return the real client IP, it parses // X-Real-IP and X-Forwarded-For in order to work properly with reverse-proxies such us: nginx or haproxy. // Use X-Forwarded-For before X-Real-Ip as nginx uses X-Real-Ip with the proxy's IP. func (c *Context) ClientIP() string { if c.engine.ForwardedByClientIP { clientIP := c.requestHeader("X-Forwarded-For") clientIP = strings.TrimSpace(strings.Split(clientIP, ",")[0]) if clientIP == "" { clientIP = strings.TrimSpace(c.requestHeader("X-Real-Ip")) } if clientIP != "" { return clientIP } } if c.engine.AppEngine { if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" { return addr } } if ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr)); err == nil { return ip } return "" } // ContentType returns the Content-Type header of the request. func (c *Context) ContentType() string { return filterFlags(c.requestHeader("Content-Type")) } // IsWebsocket returns true if the request headers indicate that a websocket // handshake is being initiated by the client. func (c *Context) IsWebsocket() bool { if strings.Contains(strings.ToLower(c.requestHeader("Connection")), "upgrade") && strings.ToLower(c.requestHeader("Upgrade")) == "websocket" { return true } return false } func (c *Context) requestHeader(key string) string { return c.Request.Header.Get(key) } /************************************/ /******** RESPONSE RENDERING ********/ /************************************/ // bodyAllowedForStatus is a copy of http.bodyAllowedForStatus non-exported function. func bodyAllowedForStatus(status int) bool { switch { case status >= 100 && status <= 199: return false case status == http.StatusNoContent: return false case status == http.StatusNotModified: return false } return true } // Status sets the HTTP response code. func (c *Context) Status(code int) { c.writermem.WriteHeader(code) } // Header is a intelligent shortcut for c.Writer.Header().Set(key, value). // It writes a header in the response. // If value == "", this method removes the header `c.Writer.Header().Del(key)` func (c *Context) Header(key, value string) { if value == "" { c.Writer.Header().Del(key) return } c.Writer.Header().Set(key, value) } // GetHeader returns value from request headers. func (c *Context) GetHeader(key string) string { return c.requestHeader(key) } // GetRawData return stream data. func (c *Context) GetRawData() ([]byte, error) { return ioutil.ReadAll(c.Request.Body) } // SetCookie adds a Set-Cookie header to the ResponseWriter's headers. // The provided cookie must have a valid Name. Invalid cookies may be // silently dropped. func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) { if path == "" { path = "/" } http.SetCookie(c.Writer, &http.Cookie{ Name: name, Value: url.QueryEscape(value), MaxAge: maxAge, Path: path, Domain: domain, Secure: secure, HttpOnly: httpOnly, }) } // Cookie returns the named cookie provided in the request or // ErrNoCookie if not found. And return the named cookie is unescaped. // If multiple cookies match the given name, only one cookie will // be returned. func (c *Context) Cookie(name string) (string, error) { cookie, err := c.Request.Cookie(name) if err != nil { return "", err } val, _ := url.QueryUnescape(cookie.Value) return val, nil } // Render writes the response headers and calls render.Render to render data. func (c *Context) Render(code int, r render.Render) { c.Status(code) if !bodyAllowedForStatus(code) { r.WriteContentType(c.Writer) c.Writer.WriteHeaderNow() return } if err := r.Render(c.Writer); err != nil { panic(err) } } // HTML renders the HTTP template specified by its file name. // It also updates the HTTP code and sets the Content-Type as "text/html". // See http://golang.org/doc/articles/wiki/ func (c *Context) HTML(code int, name string, obj interface{}) { instance := c.engine.HTMLRender.Instance(name, obj) c.Render(code, instance) } // IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body. // It also sets the Content-Type as "application/json". // WARNING: we recommend to use this only for development purposes since printing pretty JSON is // more CPU and bandwidth consuming. Use Context.JSON() instead. func (c *Context) IndentedJSON(code int, obj interface{}) { c.Render(code, render.IndentedJSON{Data: obj}) } // SecureJSON serializes the given struct as Secure JSON into the response body. // Default prepends "while(1)," to response body if the given struct is array values. // It also sets the Content-Type as "application/json". func (c *Context) SecureJSON(code int, obj interface{}) { c.Render(code, render.SecureJSON{Prefix: c.engine.secureJsonPrefix, Data: obj}) } // JSONP serializes the given struct as JSON into the response body. // It add padding to response body to request data from a server residing in a different domain than the client. // It also sets the Content-Type as "application/javascript". func (c *Context) JSONP(code int, obj interface{}) { callback := c.DefaultQuery("callback", "") if callback == "" { c.Render(code, render.JSON{Data: obj}) return } c.Render(code, render.JsonpJSON{Callback: callback, Data: obj}) } // JSON serializes the given struct as JSON into the response body. // It also sets the Content-Type as "application/json". func (c *Context) JSON(code int, obj interface{}) { c.Render(code, render.JSON{Data: obj}) } // AsciiJSON serializes the given struct as JSON into the response body with unicode to ASCII string. // It also sets the Content-Type as "application/json". func (c *Context) AsciiJSON(code int, obj interface{}) { c.Render(code, render.AsciiJSON{Data: obj}) } // PureJSON serializes the given struct as JSON into the response body. // PureJSON, unlike JSON, does not replace special html characters with their unicode entities. func (c *Context) PureJSON(code int, obj interface{}) { c.Render(code, render.PureJSON{Data: obj}) } // XML serializes the given struct as XML into the response body. // It also sets the Content-Type as "application/xml". func (c *Context) XML(code int, obj interface{}) { c.Render(code, render.XML{Data: obj}) } // YAML serializes the given struct as YAML into the response body. func (c *Context) YAML(code int, obj interface{}) { c.Render(code, render.YAML{Data: obj}) } // ProtoBuf serializes the given struct as ProtoBuf into the response body. func (c *Context) ProtoBuf(code int, obj interface{}) { c.Render(code, render.ProtoBuf{Data: obj}) } // String writes the given string into the response body. func (c *Context) String(code int, format string, values ...interface{}) { c.Render(code, render.String{Format: format, Data: values}) } // Redirect returns a HTTP redirect to the specific location. func (c *Context) Redirect(code int, location string) { c.Render(-1, render.Redirect{ Code: code, Location: location, Request: c.Request, }) } // Data writes some data into the body stream and updates the HTTP code. func (c *Context) Data(code int, contentType string, data []byte) { c.Render(code, render.Data{ ContentType: contentType, Data: data, }) } // DataFromReader writes the specified reader into the body stream and updates the HTTP code. func (c *Context) DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string) { c.Render(code, render.Reader{ Headers: extraHeaders, ContentType: contentType, ContentLength: contentLength, Reader: reader, }) } // File writes the specified file into the body stream in a efficient way. func (c *Context) File(filepath string) { http.ServeFile(c.Writer, c.Request, filepath) } // FileAttachment writes the specified file into the body stream in an efficient way // On the client side, the file will typically be downloaded with the given filename func (c *Context) FileAttachment(filepath, filename string) { c.Writer.Header().Set("content-disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) http.ServeFile(c.Writer, c.Request, filepath) } // SSEvent writes a Server-Sent Event into the body stream. func (c *Context) SSEvent(name string, message interface{}) { c.Render(-1, sse.Event{ Event: name, Data: message, }) } // Stream sends a streaming response and returns a boolean // indicates "Is client disconnected in middle of stream" func (c *Context) Stream(step func(w io.Writer) bool) bool { w := c.Writer clientGone := w.CloseNotify() for { select { case <-clientGone: return true default: keepOpen := step(w) w.Flush() if !keepOpen { return false } } } } /************************************/ /******** CONTENT NEGOTIATION *******/ /************************************/ // Negotiate contains all negotiations data. type Negotiate struct { Offered []string HTMLName string HTMLData interface{} JSONData interface{} XMLData interface{} Data interface{} } // Negotiate calls different Render according acceptable Accept format. func (c *Context) Negotiate(code int, config Negotiate) { switch c.NegotiateFormat(config.Offered...) { case binding.MIMEJSON: data := chooseData(config.JSONData, config.Data) c.JSON(code, data) case binding.MIMEHTML: data := chooseData(config.HTMLData, config.Data) c.HTML(code, config.HTMLName, data) case binding.MIMEXML: data := chooseData(config.XMLData, config.Data) c.XML(code, data) default: c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) // nolint: errcheck } } // NegotiateFormat returns an acceptable Accept format. func (c *Context) NegotiateFormat(offered ...string) string { assert1(len(offered) > 0, "you must provide at least one offer") if c.Accepted == nil { c.Accepted = parseAccept(c.requestHeader("Accept")) } if len(c.Accepted) == 0 { return offered[0] } for _, accepted := range c.Accepted { for _, offert := range offered { // According to RFC 2616 and RFC 2396, non-ASCII characters are not allowed in headers, // therefore we can just iterate over the string without casting it into []rune i := 0 for ; i < len(accepted); i++ { if accepted[i] == '*' || offert[i] == '*' { return offert } if accepted[i] != offert[i] { break } } if i == len(accepted) { return offert } } } return "" } // SetAccepted sets Accept header data. func (c *Context) SetAccepted(formats ...string) { c.Accepted = formats } /************************************/ /***** GOLANG.ORG/X/NET/CONTEXT *****/ /************************************/ // 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. func (c *Context) Deadline() (deadline time.Time, ok bool) { return } // 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. func (c *Context) Done() <-chan struct{} { return nil } // Err returns a non-nil error value after Done is closed, // successive calls to Err return the same error. // If Done is not yet closed, Err returns nil. // If Done is closed, Err returns a non-nil error explaining why: // Canceled if the context was canceled // or DeadlineExceeded if the context's deadline passed. func (c *Context) Err() error { return nil } // 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. func (c *Context) Value(key interface{}) interface{} { if key == 0 { return c.Request } if keyAsString, ok := key.(string); ok { val, _ := c.Get(keyAsString) return val } return nil } ================================================ FILE: vendor/github.com/gin-gonic/gin/context_appengine.go ================================================ // +build appengine // Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin func init() { defaultAppEngine = true } ================================================ FILE: vendor/github.com/gin-gonic/gin/debug.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin import ( "bytes" "fmt" "html/template" "os" "runtime" "strconv" "strings" ) const ginSupportMinGoVer = 8 // IsDebugging returns true if the framework is running in debug mode. // Use SetMode(gin.ReleaseMode) to disable debug mode. func IsDebugging() bool { return ginMode == debugCode } // DebugPrintRouteFunc indicates debug log output format. var DebugPrintRouteFunc func(httpMethod, absolutePath, handlerName string, nuHandlers int) func debugPrintRoute(httpMethod, absolutePath string, handlers HandlersChain) { if IsDebugging() { nuHandlers := len(handlers) handlerName := nameOfFunction(handlers.Last()) if DebugPrintRouteFunc == nil { debugPrint("%-6s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers) } else { DebugPrintRouteFunc(httpMethod, absolutePath, handlerName, nuHandlers) } } } func debugPrintLoadTemplate(tmpl *template.Template) { if IsDebugging() { var buf bytes.Buffer for _, tmpl := range tmpl.Templates() { buf.WriteString("\t- ") buf.WriteString(tmpl.Name()) buf.WriteString("\n") } debugPrint("Loaded HTML Templates (%d): \n%s\n", len(tmpl.Templates()), buf.String()) } } func debugPrint(format string, values ...interface{}) { if IsDebugging() { if !strings.HasSuffix(format, "\n") { format += "\n" } fmt.Fprintf(os.Stderr, "[GIN-debug] "+format, values...) } } func getMinVer(v string) (uint64, error) { first := strings.IndexByte(v, '.') last := strings.LastIndexByte(v, '.') if first == last { return strconv.ParseUint(v[first+1:], 10, 64) } return strconv.ParseUint(v[first+1:last], 10, 64) } func debugPrintWARNINGDefault() { if v, e := getMinVer(runtime.Version()); e == nil && v <= ginSupportMinGoVer { debugPrint(`[WARNING] Now Gin requires Go 1.8 or later and Go 1.9 will be required soon. `) } debugPrint(`[WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. `) } func debugPrintWARNINGNew() { debugPrint(`[WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode) `) } func debugPrintWARNINGSetHTMLTemplate() { debugPrint(`[WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called at initialization. ie. before any route is registered or the router is listening in a socket: router := gin.Default() router.SetHTMLTemplate(template) // << good place `) } func debugPrintError(err error) { if err != nil { debugPrint("[ERROR] %v\n", err) } } ================================================ FILE: vendor/github.com/gin-gonic/gin/deprecated.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin import ( "log" "github.com/gin-gonic/gin/binding" ) // BindWith binds the passed struct pointer using the specified binding engine. // See the binding package. func (c *Context) BindWith(obj interface{}, b binding.Binding) error { log.Println(`BindWith(\"interface{}, binding.Binding\") error is going to be deprecated, please check issue #662 and either use MustBindWith() if you want HTTP 400 to be automatically returned if any error occur, or use ShouldBindWith() if you need to manage the error.`) return c.MustBindWith(obj, b) } ================================================ FILE: vendor/github.com/gin-gonic/gin/doc.go ================================================ /* Package gin implements a HTTP web framework called gin. See https://gin-gonic.com/ for more information about gin. */ package gin // import "github.com/gin-gonic/gin" ================================================ FILE: vendor/github.com/gin-gonic/gin/errors.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin import ( "bytes" "fmt" "reflect" "github.com/gin-gonic/gin/internal/json" ) // ErrorType is an unsigned 64-bit error code as defined in the gin spec. type ErrorType uint64 const ( // ErrorTypeBind is used when Context.Bind() fails. ErrorTypeBind ErrorType = 1 << 63 // ErrorTypeRender is used when Context.Render() fails. ErrorTypeRender ErrorType = 1 << 62 // ErrorTypePrivate indicates a private error. ErrorTypePrivate ErrorType = 1 << 0 // ErrorTypePublic indicates a public error. ErrorTypePublic ErrorType = 1 << 1 // ErrorTypeAny indicates any other error. ErrorTypeAny ErrorType = 1<<64 - 1 // ErrorTypeNu indicates any other error. ErrorTypeNu = 2 ) // Error represents a error's specification. type Error struct { Err error Type ErrorType Meta interface{} } type errorMsgs []*Error var _ error = &Error{} // SetType sets the error's type. func (msg *Error) SetType(flags ErrorType) *Error { msg.Type = flags return msg } // SetMeta sets the error's meta data. func (msg *Error) SetMeta(data interface{}) *Error { msg.Meta = data return msg } // JSON creates a properly formatted JSON func (msg *Error) JSON() interface{} { json := H{} if msg.Meta != nil { value := reflect.ValueOf(msg.Meta) switch value.Kind() { case reflect.Struct: return msg.Meta case reflect.Map: for _, key := range value.MapKeys() { json[key.String()] = value.MapIndex(key).Interface() } default: json["meta"] = msg.Meta } } if _, ok := json["error"]; !ok { json["error"] = msg.Error() } return json } // MarshalJSON implements the json.Marshaller interface. func (msg *Error) MarshalJSON() ([]byte, error) { return json.Marshal(msg.JSON()) } // Error implements the error interface. func (msg Error) Error() string { return msg.Err.Error() } // IsType judges one error. func (msg *Error) IsType(flags ErrorType) bool { return (msg.Type & flags) > 0 } // ByType returns a readonly copy filtered the byte. // ie ByType(gin.ErrorTypePublic) returns a slice of errors with type=ErrorTypePublic. func (a errorMsgs) ByType(typ ErrorType) errorMsgs { if len(a) == 0 { return nil } if typ == ErrorTypeAny { return a } var result errorMsgs for _, msg := range a { if msg.IsType(typ) { result = append(result, msg) } } return result } // Last returns the last error in the slice. It returns nil if the array is empty. // Shortcut for errors[len(errors)-1]. func (a errorMsgs) Last() *Error { if length := len(a); length > 0 { return a[length-1] } return nil } // Errors returns an array will all the error messages. // Example: // c.Error(errors.New("first")) // c.Error(errors.New("second")) // c.Error(errors.New("third")) // c.Errors.Errors() // == []string{"first", "second", "third"} func (a errorMsgs) Errors() []string { if len(a) == 0 { return nil } errorStrings := make([]string, len(a)) for i, err := range a { errorStrings[i] = err.Error() } return errorStrings } func (a errorMsgs) JSON() interface{} { switch len(a) { case 0: return nil case 1: return a.Last().JSON() default: json := make([]interface{}, len(a)) for i, err := range a { json[i] = err.JSON() } return json } } // MarshalJSON implements the json.Marshaller interface. func (a errorMsgs) MarshalJSON() ([]byte, error) { return json.Marshal(a.JSON()) } func (a errorMsgs) String() string { if len(a) == 0 { return "" } var buffer bytes.Buffer for i, msg := range a { fmt.Fprintf(&buffer, "Error #%02d: %s\n", i+1, msg.Err) if msg.Meta != nil { fmt.Fprintf(&buffer, " Meta: %v\n", msg.Meta) } } return buffer.String() } ================================================ FILE: vendor/github.com/gin-gonic/gin/fs.go ================================================ // Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin import ( "net/http" "os" ) type onlyfilesFS struct { fs http.FileSystem } type neuteredReaddirFile struct { http.File } // Dir returns a http.Filesystem that can be used by http.FileServer(). It is used internally // in router.Static(). // if listDirectory == true, then it works the same as http.Dir() otherwise it returns // a filesystem that prevents http.FileServer() to list the directory files. func Dir(root string, listDirectory bool) http.FileSystem { fs := http.Dir(root) if listDirectory { return fs } return &onlyfilesFS{fs} } // Open conforms to http.Filesystem. func (fs onlyfilesFS) Open(name string) (http.File, error) { f, err := fs.fs.Open(name) if err != nil { return nil, err } return neuteredReaddirFile{f}, nil } // Readdir overrides the http.File default implementation. func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) { // this disables directory listing return nil, nil } ================================================ FILE: vendor/github.com/gin-gonic/gin/gin.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin import ( "fmt" "html/template" "net" "net/http" "os" "path" "sync" "github.com/gin-gonic/gin/render" ) const defaultMultipartMemory = 32 << 20 // 32 MB var ( default404Body = []byte("404 page not found") default405Body = []byte("405 method not allowed") defaultAppEngine bool ) // HandlerFunc defines the handler used by gin middleware as return value. type HandlerFunc func(*Context) // HandlersChain defines a HandlerFunc array. type HandlersChain []HandlerFunc // Last returns the last handler in the chain. ie. the last handler is the main own. func (c HandlersChain) Last() HandlerFunc { if length := len(c); length > 0 { return c[length-1] } return nil } // RouteInfo represents a request route's specification which contains method and path and its handler. type RouteInfo struct { Method string Path string Handler string HandlerFunc HandlerFunc } // RoutesInfo defines a RouteInfo array. type RoutesInfo []RouteInfo // Engine is the framework's instance, it contains the muxer, middleware and configuration settings. // Create an instance of Engine, by using New() or Default() type Engine struct { RouterGroup // Enables automatic redirection if the current route can't be matched but a // handler for the path with (without) the trailing slash exists. // For example if /foo/ is requested but a route only exists for /foo, the // client is redirected to /foo with http status code 301 for GET requests // and 307 for all other request methods. RedirectTrailingSlash bool // If enabled, the router tries to fix the current request path, if no // handle is registered for it. // First superfluous path elements like ../ or // are removed. // Afterwards the router does a case-insensitive lookup of the cleaned path. // If a handle can be found for this route, the router makes a redirection // to the corrected path with status code 301 for GET requests and 307 for // all other request methods. // For example /FOO and /..//Foo could be redirected to /foo. // RedirectTrailingSlash is independent of this option. RedirectFixedPath bool // If enabled, the router checks if another method is allowed for the // current route, if the current request can not be routed. // If this is the case, the request is answered with 'Method Not Allowed' // and HTTP status code 405. // If no other Method is allowed, the request is delegated to the NotFound // handler. HandleMethodNotAllowed bool ForwardedByClientIP bool // #726 #755 If enabled, it will thrust some headers starting with // 'X-AppEngine...' for better integration with that PaaS. AppEngine bool // If enabled, the url.RawPath will be used to find parameters. UseRawPath bool // If true, the path value will be unescaped. // If UseRawPath is false (by default), the UnescapePathValues effectively is true, // as url.Path gonna be used, which is already unescaped. UnescapePathValues bool // Value of 'maxMemory' param that is given to http.Request's ParseMultipartForm // method call. MaxMultipartMemory int64 delims render.Delims secureJsonPrefix string HTMLRender render.HTMLRender FuncMap template.FuncMap allNoRoute HandlersChain allNoMethod HandlersChain noRoute HandlersChain noMethod HandlersChain pool sync.Pool trees methodTrees } var _ IRouter = &Engine{} // New returns a new blank Engine instance without any middleware attached. // By default the configuration is: // - RedirectTrailingSlash: true // - RedirectFixedPath: false // - HandleMethodNotAllowed: false // - ForwardedByClientIP: true // - UseRawPath: false // - UnescapePathValues: true func New() *Engine { debugPrintWARNINGNew() engine := &Engine{ RouterGroup: RouterGroup{ Handlers: nil, basePath: "/", root: true, }, FuncMap: template.FuncMap{}, RedirectTrailingSlash: true, RedirectFixedPath: false, HandleMethodNotAllowed: false, ForwardedByClientIP: true, AppEngine: defaultAppEngine, UseRawPath: false, UnescapePathValues: true, MaxMultipartMemory: defaultMultipartMemory, trees: make(methodTrees, 0, 9), delims: render.Delims{Left: "{{", Right: "}}"}, secureJsonPrefix: "while(1);", } engine.RouterGroup.engine = engine engine.pool.New = func() interface{} { return engine.allocateContext() } return engine } // Default returns an Engine instance with the Logger and Recovery middleware already attached. func Default() *Engine { debugPrintWARNINGDefault() engine := New() engine.Use(Logger(), Recovery()) return engine } func (engine *Engine) allocateContext() *Context { return &Context{engine: engine} } // Delims sets template left and right delims and returns a Engine instance. func (engine *Engine) Delims(left, right string) *Engine { engine.delims = render.Delims{Left: left, Right: right} return engine } // SecureJsonPrefix sets the secureJsonPrefix used in Context.SecureJSON. func (engine *Engine) SecureJsonPrefix(prefix string) *Engine { engine.secureJsonPrefix = prefix return engine } // LoadHTMLGlob loads HTML files identified by glob pattern // and associates the result with HTML renderer. func (engine *Engine) LoadHTMLGlob(pattern string) { left := engine.delims.Left right := engine.delims.Right templ := template.Must(template.New("").Delims(left, right).Funcs(engine.FuncMap).ParseGlob(pattern)) if IsDebugging() { debugPrintLoadTemplate(templ) engine.HTMLRender = render.HTMLDebug{Glob: pattern, FuncMap: engine.FuncMap, Delims: engine.delims} return } engine.SetHTMLTemplate(templ) } // LoadHTMLFiles loads a slice of HTML files // and associates the result with HTML renderer. func (engine *Engine) LoadHTMLFiles(files ...string) { if IsDebugging() { engine.HTMLRender = render.HTMLDebug{Files: files, FuncMap: engine.FuncMap, Delims: engine.delims} return } templ := template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).Funcs(engine.FuncMap).ParseFiles(files...)) engine.SetHTMLTemplate(templ) } // SetHTMLTemplate associate a template with HTML renderer. func (engine *Engine) SetHTMLTemplate(templ *template.Template) { if len(engine.trees) > 0 { debugPrintWARNINGSetHTMLTemplate() } engine.HTMLRender = render.HTMLProduction{Template: templ.Funcs(engine.FuncMap)} } // SetFuncMap sets the FuncMap used for template.FuncMap. func (engine *Engine) SetFuncMap(funcMap template.FuncMap) { engine.FuncMap = funcMap } // NoRoute adds handlers for NoRoute. It return a 404 code by default. func (engine *Engine) NoRoute(handlers ...HandlerFunc) { engine.noRoute = handlers engine.rebuild404Handlers() } // NoMethod sets the handlers called when... TODO. func (engine *Engine) NoMethod(handlers ...HandlerFunc) { engine.noMethod = handlers engine.rebuild405Handlers() } // Use attaches a global middleware to the router. ie. the middleware attached though Use() will be // included in the handlers chain for every single request. Even 404, 405, static files... // For example, this is the right place for a logger or error management middleware. func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes { engine.RouterGroup.Use(middleware...) engine.rebuild404Handlers() engine.rebuild405Handlers() return engine } func (engine *Engine) rebuild404Handlers() { engine.allNoRoute = engine.combineHandlers(engine.noRoute) } func (engine *Engine) rebuild405Handlers() { engine.allNoMethod = engine.combineHandlers(engine.noMethod) } func (engine *Engine) addRoute(method, path string, handlers HandlersChain) { assert1(path[0] == '/', "path must begin with '/'") assert1(method != "", "HTTP method can not be empty") assert1(len(handlers) > 0, "there must be at least one handler") debugPrintRoute(method, path, handlers) root := engine.trees.get(method) if root == nil { root = new(node) engine.trees = append(engine.trees, methodTree{method: method, root: root}) } root.addRoute(path, handlers) } // Routes returns a slice of registered routes, including some useful information, such as: // the http method, path and the handler name. func (engine *Engine) Routes() (routes RoutesInfo) { for _, tree := range engine.trees { routes = iterate("", tree.method, routes, tree.root) } return routes } func iterate(path, method string, routes RoutesInfo, root *node) RoutesInfo { path += root.path if len(root.handlers) > 0 { handlerFunc := root.handlers.Last() routes = append(routes, RouteInfo{ Method: method, Path: path, Handler: nameOfFunction(handlerFunc), HandlerFunc: handlerFunc, }) } for _, child := range root.children { routes = iterate(path, method, routes, child) } return routes } // Run attaches the router to a http.Server and starts listening and serving HTTP requests. // It is a shortcut for http.ListenAndServe(addr, router) // Note: this method will block the calling goroutine indefinitely unless an error happens. func (engine *Engine) Run(addr ...string) (err error) { defer func() { debugPrintError(err) }() address := resolveAddress(addr) debugPrint("Listening and serving HTTP on %s\n", address) err = http.ListenAndServe(address, engine) return } // RunTLS attaches the router to a http.Server and starts listening and serving HTTPS (secure) requests. // It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router) // Note: this method will block the calling goroutine indefinitely unless an error happens. func (engine *Engine) RunTLS(addr, certFile, keyFile string) (err error) { debugPrint("Listening and serving HTTPS on %s\n", addr) defer func() { debugPrintError(err) }() err = http.ListenAndServeTLS(addr, certFile, keyFile, engine) return } // RunUnix attaches the router to a http.Server and starts listening and serving HTTP requests // through the specified unix socket (ie. a file). // Note: this method will block the calling goroutine indefinitely unless an error happens. func (engine *Engine) RunUnix(file string) (err error) { debugPrint("Listening and serving HTTP on unix:/%s", file) defer func() { debugPrintError(err) }() os.Remove(file) listener, err := net.Listen("unix", file) if err != nil { return } defer listener.Close() os.Chmod(file, 0777) err = http.Serve(listener, engine) return } // RunFd attaches the router to a http.Server and starts listening and serving HTTP requests // through the specified file descriptor. // Note: this method will block the calling goroutine indefinitely unless an error happens. func (engine *Engine) RunFd(fd int) (err error) { debugPrint("Listening and serving HTTP on fd@%d", fd) defer func() { debugPrintError(err) }() f := os.NewFile(uintptr(fd), fmt.Sprintf("fd@%d", fd)) listener, err := net.FileListener(f) if err != nil { return } defer listener.Close() err = http.Serve(listener, engine) return } // ServeHTTP conforms to the http.Handler interface. func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { c := engine.pool.Get().(*Context) c.writermem.reset(w) c.Request = req c.reset() engine.handleHTTPRequest(c) engine.pool.Put(c) } // HandleContext re-enter a context that has been rewritten. // This can be done by setting c.Request.URL.Path to your new target. // Disclaimer: You can loop yourself to death with this, use wisely. func (engine *Engine) HandleContext(c *Context) { oldIndexValue := c.index c.reset() engine.handleHTTPRequest(c) c.index = oldIndexValue } func (engine *Engine) handleHTTPRequest(c *Context) { httpMethod := c.Request.Method rPath := c.Request.URL.Path unescape := false if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 { rPath = c.Request.URL.RawPath unescape = engine.UnescapePathValues } rPath = cleanPath(rPath) // Find root of the tree for the given HTTP method t := engine.trees for i, tl := 0, len(t); i < tl; i++ { if t[i].method != httpMethod { continue } root := t[i].root // Find route in tree handlers, params, tsr := root.getValue(rPath, c.Params, unescape) if handlers != nil { c.handlers = handlers c.Params = params c.Next() c.writermem.WriteHeaderNow() return } if httpMethod != "CONNECT" && rPath != "/" { if tsr && engine.RedirectTrailingSlash { redirectTrailingSlash(c) return } if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) { return } } break } if engine.HandleMethodNotAllowed { for _, tree := range engine.trees { if tree.method == httpMethod { continue } if handlers, _, _ := tree.root.getValue(rPath, nil, unescape); handlers != nil { c.handlers = engine.allNoMethod serveError(c, http.StatusMethodNotAllowed, default405Body) return } } } c.handlers = engine.allNoRoute serveError(c, http.StatusNotFound, default404Body) } var mimePlain = []string{MIMEPlain} func serveError(c *Context, code int, defaultMessage []byte) { c.writermem.status = code c.Next() if c.writermem.Written() { return } if c.writermem.Status() == code { c.writermem.Header()["Content-Type"] = mimePlain _, err := c.Writer.Write(defaultMessage) if err != nil { debugPrint("cannot write message to writer during serve error: %v", err) } return } c.writermem.WriteHeaderNow() return } func redirectTrailingSlash(c *Context) { req := c.Request p := req.URL.Path if prefix := path.Clean(c.Request.Header.Get("X-Forwarded-Prefix")); prefix != "." { p = prefix + "/" + req.URL.Path } code := http.StatusMovedPermanently // Permanent redirect, request with GET method if req.Method != "GET" { code = http.StatusTemporaryRedirect } req.URL.Path = p + "/" if length := len(p); length > 1 && p[length-1] == '/' { req.URL.Path = p[:length-1] } debugPrint("redirecting request %d: %s --> %s", code, p, req.URL.String()) http.Redirect(c.Writer, req, req.URL.String(), code) c.writermem.WriteHeaderNow() } func redirectFixedPath(c *Context, root *node, trailingSlash bool) bool { req := c.Request rPath := req.URL.Path if fixedPath, ok := root.findCaseInsensitivePath(cleanPath(rPath), trailingSlash); ok { code := http.StatusMovedPermanently // Permanent redirect, request with GET method if req.Method != "GET" { code = http.StatusTemporaryRedirect } req.URL.Path = string(fixedPath) debugPrint("redirecting request %d: %s --> %s", code, rPath, req.URL.String()) http.Redirect(c.Writer, req, req.URL.String(), code) c.writermem.WriteHeaderNow() return true } return false } ================================================ FILE: vendor/github.com/gin-gonic/gin/go.mod ================================================ module github.com/gin-gonic/gin go 1.12 require ( github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 github.com/golang/protobuf v1.3.1 github.com/json-iterator/go v1.1.6 github.com/mattn/go-isatty v0.0.7 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect github.com/stretchr/testify v1.3.0 github.com/ugorji/go v1.1.4 golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/go-playground/validator.v8 v8.18.2 gopkg.in/yaml.v2 v2.2.2 ) ================================================ FILE: vendor/github.com/gin-gonic/gin/go.sum ================================================ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= ================================================ FILE: vendor/github.com/gin-gonic/gin/internal/json/json.go ================================================ // Copyright 2017 Bo-Yi Wu. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. // +build !jsoniter package json import "encoding/json" var ( // Marshal is exported by gin/json package. Marshal = json.Marshal // Unmarshal is exported by gin/json package. Unmarshal = json.Unmarshal // MarshalIndent is exported by gin/json package. MarshalIndent = json.MarshalIndent // NewDecoder is exported by gin/json package. NewDecoder = json.NewDecoder // NewEncoder is exported by gin/json package. NewEncoder = json.NewEncoder ) ================================================ FILE: vendor/github.com/gin-gonic/gin/internal/json/jsoniter.go ================================================ // Copyright 2017 Bo-Yi Wu. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. // +build jsoniter package json import "github.com/json-iterator/go" var ( json = jsoniter.ConfigCompatibleWithStandardLibrary // Marshal is exported by gin/json package. Marshal = json.Marshal // Unmarshal is exported by gin/json package. Unmarshal = json.Unmarshal // MarshalIndent is exported by gin/json package. MarshalIndent = json.MarshalIndent // NewDecoder is exported by gin/json package. NewDecoder = json.NewDecoder // NewEncoder is exported by gin/json package. NewEncoder = json.NewEncoder ) ================================================ FILE: vendor/github.com/gin-gonic/gin/logger.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin import ( "fmt" "io" "net/http" "os" "time" "github.com/mattn/go-isatty" ) type consoleColorModeValue int const ( autoColor consoleColorModeValue = iota disableColor forceColor ) var ( green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109}) white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109}) yellow = string([]byte{27, 91, 57, 48, 59, 52, 51, 109}) red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109}) blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109}) magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109}) cyan = string([]byte{27, 91, 57, 55, 59, 52, 54, 109}) reset = string([]byte{27, 91, 48, 109}) consoleColorMode = autoColor ) // LoggerConfig defines the config for Logger middleware. type LoggerConfig struct { // Optional. Default value is gin.defaultLogFormatter Formatter LogFormatter // Output is a writer where logs are written. // Optional. Default value is gin.DefaultWriter. Output io.Writer // SkipPaths is a url path array which logs are not written. // Optional. SkipPaths []string } // LogFormatter gives the signature of the formatter function passed to LoggerWithFormatter type LogFormatter func(params LogFormatterParams) string // LogFormatterParams is the structure any formatter will be handed when time to log comes type LogFormatterParams struct { Request *http.Request // TimeStamp shows the time after the server returns a response. TimeStamp time.Time // StatusCode is HTTP response code. StatusCode int // Latency is how much time the server cost to process a certain request. Latency time.Duration // ClientIP equals Context's ClientIP method. ClientIP string // Method is the HTTP method given to the request. Method string // Path is a path the client requests. Path string // ErrorMessage is set if error has occurred in processing the request. ErrorMessage string // isTerm shows whether does gin's output descriptor refers to a terminal. isTerm bool // BodySize is the size of the Response Body BodySize int // Keys are the keys set on the request's context. Keys map[string]interface{} } // StatusCodeColor is the ANSI color for appropriately logging http status code to a terminal. func (p *LogFormatterParams) StatusCodeColor() string { code := p.StatusCode switch { case code >= http.StatusOK && code < http.StatusMultipleChoices: return green case code >= http.StatusMultipleChoices && code < http.StatusBadRequest: return white case code >= http.StatusBadRequest && code < http.StatusInternalServerError: return yellow default: return red } } // MethodColor is the ANSI color for appropriately logging http method to a terminal. func (p *LogFormatterParams) MethodColor() string { method := p.Method switch method { case "GET": return blue case "POST": return cyan case "PUT": return yellow case "DELETE": return red case "PATCH": return green case "HEAD": return magenta case "OPTIONS": return white default: return reset } } // ResetColor resets all escape attributes. func (p *LogFormatterParams) ResetColor() string { return reset } // IsOutputColor indicates whether can colors be outputted to the log. func (p *LogFormatterParams) IsOutputColor() bool { return consoleColorMode == forceColor || (consoleColorMode == autoColor && p.isTerm) } // defaultLogFormatter is the default log format function Logger middleware uses. var defaultLogFormatter = func(param LogFormatterParams) string { var statusColor, methodColor, resetColor string if param.IsOutputColor() { statusColor = param.StatusCodeColor() methodColor = param.MethodColor() resetColor = param.ResetColor() } if param.Latency > time.Minute { // Truncate in a golang < 1.8 safe way param.Latency = param.Latency - param.Latency%time.Second } return fmt.Sprintf("[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %s\n%s", param.TimeStamp.Format("2006/01/02 - 15:04:05"), statusColor, param.StatusCode, resetColor, param.Latency, param.ClientIP, methodColor, param.Method, resetColor, param.Path, param.ErrorMessage, ) } // DisableConsoleColor disables color output in the console. func DisableConsoleColor() { consoleColorMode = disableColor } // ForceConsoleColor force color output in the console. func ForceConsoleColor() { consoleColorMode = forceColor } // ErrorLogger returns a handlerfunc for any error type. func ErrorLogger() HandlerFunc { return ErrorLoggerT(ErrorTypeAny) } // ErrorLoggerT returns a handlerfunc for a given error type. func ErrorLoggerT(typ ErrorType) HandlerFunc { return func(c *Context) { c.Next() errors := c.Errors.ByType(typ) if len(errors) > 0 { c.JSON(-1, errors) } } } // Logger instances a Logger middleware that will write the logs to gin.DefaultWriter. // By default gin.DefaultWriter = os.Stdout. func Logger() HandlerFunc { return LoggerWithConfig(LoggerConfig{}) } // LoggerWithFormatter instance a Logger middleware with the specified log format function. func LoggerWithFormatter(f LogFormatter) HandlerFunc { return LoggerWithConfig(LoggerConfig{ Formatter: f, }) } // LoggerWithWriter instance a Logger middleware with the specified writer buffer. // Example: os.Stdout, a file opened in write mode, a socket... func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc { return LoggerWithConfig(LoggerConfig{ Output: out, SkipPaths: notlogged, }) } // LoggerWithConfig instance a Logger middleware with config. func LoggerWithConfig(conf LoggerConfig) HandlerFunc { formatter := conf.Formatter if formatter == nil { formatter = defaultLogFormatter } out := conf.Output if out == nil { out = DefaultWriter } notlogged := conf.SkipPaths isTerm := true if w, ok := out.(*os.File); !ok || os.Getenv("TERM") == "dumb" || (!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd())) { isTerm = false } var skip map[string]struct{} if length := len(notlogged); length > 0 { skip = make(map[string]struct{}, length) for _, path := range notlogged { skip[path] = struct{}{} } } return func(c *Context) { // Start timer start := time.Now() path := c.Request.URL.Path raw := c.Request.URL.RawQuery // Process request c.Next() // Log only when path is not being skipped if _, ok := skip[path]; !ok { param := LogFormatterParams{ Request: c.Request, isTerm: isTerm, Keys: c.Keys, } // Stop timer param.TimeStamp = time.Now() param.Latency = param.TimeStamp.Sub(start) param.ClientIP = c.ClientIP() param.Method = c.Request.Method param.StatusCode = c.Writer.Status() param.ErrorMessage = c.Errors.ByType(ErrorTypePrivate).String() param.BodySize = c.Writer.Size() if raw != "" { path = path + "?" + raw } param.Path = path fmt.Fprint(out, formatter(param)) } } } ================================================ FILE: vendor/github.com/gin-gonic/gin/mode.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin import ( "io" "os" "github.com/gin-gonic/gin/binding" ) // EnvGinMode indicates environment name for gin mode. const EnvGinMode = "GIN_MODE" const ( // DebugMode indicates gin mode is debug. DebugMode = "debug" // ReleaseMode indicates gin mode is release. ReleaseMode = "release" // TestMode indicates gin mode is test. TestMode = "test" ) const ( debugCode = iota releaseCode testCode ) // DefaultWriter is the default io.Writer used by Gin for debug output and // middleware output like Logger() or Recovery(). // Note that both Logger and Recovery provides custom ways to configure their // output io.Writer. // To support coloring in Windows use: // import "github.com/mattn/go-colorable" // gin.DefaultWriter = colorable.NewColorableStdout() var DefaultWriter io.Writer = os.Stdout // DefaultErrorWriter is the default io.Writer used by Gin to debug errors var DefaultErrorWriter io.Writer = os.Stderr var ginMode = debugCode var modeName = DebugMode func init() { mode := os.Getenv(EnvGinMode) SetMode(mode) } // SetMode sets gin mode according to input string. func SetMode(value string) { switch value { case DebugMode, "": ginMode = debugCode case ReleaseMode: ginMode = releaseCode case TestMode: ginMode = testCode default: panic("gin mode unknown: " + value) } if value == "" { value = DebugMode } modeName = value } // DisableBindValidation closes the default validator. func DisableBindValidation() { binding.Validator = nil } // EnableJsonDecoderUseNumber sets true for binding.EnableDecoderUseNumberto to // call the UseNumber method on the JSON Decoder instance. func EnableJsonDecoderUseNumber() { binding.EnableDecoderUseNumber = true } // Mode returns currently gin mode. func Mode() string { return modeName } ================================================ FILE: vendor/github.com/gin-gonic/gin/path.go ================================================ // Copyright 2013 Julien Schmidt. All rights reserved. // Based on the path package, Copyright 2009 The Go Authors. // Use of this source code is governed by a BSD-style license that can be found // at https://github.com/julienschmidt/httprouter/blob/master/LICENSE. package gin // cleanPath is the URL version of path.Clean, it returns a canonical URL path // for p, eliminating . and .. elements. // // The following rules are applied iteratively until no further processing can // be done: // 1. Replace multiple slashes with a single slash. // 2. Eliminate each . path name element (the current directory). // 3. Eliminate each inner .. path name element (the parent directory) // along with the non-.. element that precedes it. // 4. Eliminate .. elements that begin a rooted path: // that is, replace "/.." by "/" at the beginning of a path. // // If the result of this process is an empty string, "/" is returned. func cleanPath(p string) string { // Turn empty string into "/" if p == "" { return "/" } n := len(p) var buf []byte // Invariants: // reading from path; r is index of next byte to process. // writing to buf; w is index of next byte to write. // path must start with '/' r := 1 w := 1 if p[0] != '/' { r = 0 buf = make([]byte, n+1) buf[0] = '/' } trailing := n > 1 && p[n-1] == '/' // A bit more clunky without a 'lazybuf' like the path package, but the loop // gets completely inlined (bufApp). So in contrast to the path package this // loop has no expensive function calls (except 1x make) for r < n { switch { case p[r] == '/': // empty path element, trailing slash is added after the end r++ case p[r] == '.' && r+1 == n: trailing = true r++ case p[r] == '.' && p[r+1] == '/': // . element r += 2 case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'): // .. element: remove to last / r += 3 if w > 1 { // can backtrack w-- if buf == nil { for w > 1 && p[w] != '/' { w-- } } else { for w > 1 && buf[w] != '/' { w-- } } } default: // real path element. // add slash if needed if w > 1 { bufApp(&buf, p, w, '/') w++ } // copy element for r < n && p[r] != '/' { bufApp(&buf, p, w, p[r]) w++ r++ } } } // re-append trailing slash if trailing && w > 1 { bufApp(&buf, p, w, '/') w++ } if buf == nil { return p[:w] } return string(buf[:w]) } // internal helper to lazily create a buffer if necessary. func bufApp(buf *[]byte, s string, w int, c byte) { if *buf == nil { if s[w] == c { return } *buf = make([]byte, len(s)) copy(*buf, s[:w]) } (*buf)[w] = c } ================================================ FILE: vendor/github.com/gin-gonic/gin/recovery.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin import ( "bytes" "fmt" "io" "io/ioutil" "log" "net" "net/http" "net/http/httputil" "os" "runtime" "strings" "time" ) var ( dunno = []byte("???") centerDot = []byte("·") dot = []byte(".") slash = []byte("/") ) // Recovery returns a middleware that recovers from any panics and writes a 500 if there was one. func Recovery() HandlerFunc { return RecoveryWithWriter(DefaultErrorWriter) } // RecoveryWithWriter returns a middleware for a given writer that recovers from any panics and writes a 500 if there was one. func RecoveryWithWriter(out io.Writer) HandlerFunc { var logger *log.Logger if out != nil { logger = log.New(out, "\n\n\x1b[31m", log.LstdFlags) } return func(c *Context) { defer func() { if err := recover(); err != nil { // Check for a broken connection, as it is not really a // condition that warrants a panic stack trace. var brokenPipe bool if ne, ok := err.(*net.OpError); ok { if se, ok := ne.Err.(*os.SyscallError); ok { if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") { brokenPipe = true } } } if logger != nil { stack := stack(3) httpRequest, _ := httputil.DumpRequest(c.Request, false) headers := strings.Split(string(httpRequest), "\r\n") for idx, header := range headers { current := strings.Split(header, ":") if current[0] == "Authorization" { headers[idx] = current[0] + ": *" } } if brokenPipe { logger.Printf("%s\n%s%s", err, string(httpRequest), reset) } else if IsDebugging() { logger.Printf("[Recovery] %s panic recovered:\n%s\n%s\n%s%s", timeFormat(time.Now()), strings.Join(headers, "\r\n"), err, stack, reset) } else { logger.Printf("[Recovery] %s panic recovered:\n%s\n%s%s", timeFormat(time.Now()), err, stack, reset) } } // If the connection is dead, we can't write a status to it. if brokenPipe { c.Error(err.(error)) // nolint: errcheck c.Abort() } else { c.AbortWithStatus(http.StatusInternalServerError) } } }() c.Next() } } // stack returns a nicely formatted stack frame, skipping skip frames. func stack(skip int) []byte { buf := new(bytes.Buffer) // the returned data // As we loop, we open files and read them. These variables record the currently // loaded file. var lines [][]byte var lastFile string for i := skip; ; i++ { // Skip the expected number of frames pc, file, line, ok := runtime.Caller(i) if !ok { break } // Print this much at least. If we can't find the source, it won't show. fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc) if file != lastFile { data, err := ioutil.ReadFile(file) if err != nil { continue } lines = bytes.Split(data, []byte{'\n'}) lastFile = file } fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line)) } return buf.Bytes() } // source returns a space-trimmed slice of the n'th line. func source(lines [][]byte, n int) []byte { n-- // in stack trace, lines are 1-indexed but our array is 0-indexed if n < 0 || n >= len(lines) { return dunno } return bytes.TrimSpace(lines[n]) } // function returns, if possible, the name of the function containing the PC. func function(pc uintptr) []byte { fn := runtime.FuncForPC(pc) if fn == nil { return dunno } name := []byte(fn.Name()) // The name includes the path name to the package, which is unnecessary // since the file name is already included. Plus, it has center dots. // That is, we see // runtime/debug.*T·ptrmethod // and want // *T.ptrmethod // Also the package path might contains dot (e.g. code.google.com/...), // so first eliminate the path prefix if lastSlash := bytes.LastIndex(name, slash); lastSlash >= 0 { name = name[lastSlash+1:] } if period := bytes.Index(name, dot); period >= 0 { name = name[period+1:] } name = bytes.Replace(name, centerDot, dot, -1) return name } func timeFormat(t time.Time) string { var timeString = t.Format("2006/01/02 - 15:04:05") return timeString } ================================================ FILE: vendor/github.com/gin-gonic/gin/render/data.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package render import "net/http" // Data contains ContentType and bytes data. type Data struct { ContentType string Data []byte } // Render (Data) writes data with custom ContentType. func (r Data) Render(w http.ResponseWriter) (err error) { r.WriteContentType(w) _, err = w.Write(r.Data) return } // WriteContentType (Data) writes custom ContentType. func (r Data) WriteContentType(w http.ResponseWriter) { writeContentType(w, []string{r.ContentType}) } ================================================ FILE: vendor/github.com/gin-gonic/gin/render/html.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package render import ( "html/template" "net/http" ) // Delims represents a set of Left and Right delimiters for HTML template rendering. type Delims struct { // Left delimiter, defaults to {{. Left string // Right delimiter, defaults to }}. Right string } // HTMLRender interface is to be implemented by HTMLProduction and HTMLDebug. type HTMLRender interface { // Instance returns an HTML instance. Instance(string, interface{}) Render } // HTMLProduction contains template reference and its delims. type HTMLProduction struct { Template *template.Template Delims Delims } // HTMLDebug contains template delims and pattern and function with file list. type HTMLDebug struct { Files []string Glob string Delims Delims FuncMap template.FuncMap } // HTML contains template reference and its name with given interface object. type HTML struct { Template *template.Template Name string Data interface{} } var htmlContentType = []string{"text/html; charset=utf-8"} // Instance (HTMLProduction) returns an HTML instance which it realizes Render interface. func (r HTMLProduction) Instance(name string, data interface{}) Render { return HTML{ Template: r.Template, Name: name, Data: data, } } // Instance (HTMLDebug) returns an HTML instance which it realizes Render interface. func (r HTMLDebug) Instance(name string, data interface{}) Render { return HTML{ Template: r.loadTemplate(), Name: name, Data: data, } } func (r HTMLDebug) loadTemplate() *template.Template { if r.FuncMap == nil { r.FuncMap = template.FuncMap{} } if len(r.Files) > 0 { return template.Must(template.New("").Delims(r.Delims.Left, r.Delims.Right).Funcs(r.FuncMap).ParseFiles(r.Files...)) } if r.Glob != "" { return template.Must(template.New("").Delims(r.Delims.Left, r.Delims.Right).Funcs(r.FuncMap).ParseGlob(r.Glob)) } panic("the HTML debug render was created without files or glob pattern") } // Render (HTML) executes template and writes its result with custom ContentType for response. func (r HTML) Render(w http.ResponseWriter) error { r.WriteContentType(w) if r.Name == "" { return r.Template.Execute(w, r.Data) } return r.Template.ExecuteTemplate(w, r.Name, r.Data) } // WriteContentType (HTML) writes HTML ContentType. func (r HTML) WriteContentType(w http.ResponseWriter) { writeContentType(w, htmlContentType) } ================================================ FILE: vendor/github.com/gin-gonic/gin/render/json.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package render import ( "bytes" "fmt" "html/template" "net/http" "github.com/gin-gonic/gin/internal/json" ) // JSON contains the given interface object. type JSON struct { Data interface{} } // IndentedJSON contains the given interface object. type IndentedJSON struct { Data interface{} } // SecureJSON contains the given interface object and its prefix. type SecureJSON struct { Prefix string Data interface{} } // JsonpJSON contains the given interface object its callback. type JsonpJSON struct { Callback string Data interface{} } // AsciiJSON contains the given interface object. type AsciiJSON struct { Data interface{} } // SecureJSONPrefix is a string which represents SecureJSON prefix. type SecureJSONPrefix string // PureJSON contains the given interface object. type PureJSON struct { Data interface{} } var jsonContentType = []string{"application/json; charset=utf-8"} var jsonpContentType = []string{"application/javascript; charset=utf-8"} var jsonAsciiContentType = []string{"application/json"} // Render (JSON) writes data with custom ContentType. func (r JSON) Render(w http.ResponseWriter) (err error) { if err = WriteJSON(w, r.Data); err != nil { panic(err) } return } // WriteContentType (JSON) writes JSON ContentType. func (r JSON) WriteContentType(w http.ResponseWriter) { writeContentType(w, jsonContentType) } // WriteJSON marshals the given interface object and writes it with custom ContentType. func WriteJSON(w http.ResponseWriter, obj interface{}) error { writeContentType(w, jsonContentType) jsonBytes, err := json.Marshal(obj) if err != nil { return err } _, err = w.Write(jsonBytes) return err } // Render (IndentedJSON) marshals the given interface object and writes it with custom ContentType. func (r IndentedJSON) Render(w http.ResponseWriter) error { r.WriteContentType(w) jsonBytes, err := json.MarshalIndent(r.Data, "", " ") if err != nil { return err } _, err = w.Write(jsonBytes) return err } // WriteContentType (IndentedJSON) writes JSON ContentType. func (r IndentedJSON) WriteContentType(w http.ResponseWriter) { writeContentType(w, jsonContentType) } // Render (SecureJSON) marshals the given interface object and writes it with custom ContentType. func (r SecureJSON) Render(w http.ResponseWriter) error { r.WriteContentType(w) jsonBytes, err := json.Marshal(r.Data) if err != nil { return err } // if the jsonBytes is array values if bytes.HasPrefix(jsonBytes, []byte("[")) && bytes.HasSuffix(jsonBytes, []byte("]")) { _, err = w.Write([]byte(r.Prefix)) if err != nil { return err } } _, err = w.Write(jsonBytes) return err } // WriteContentType (SecureJSON) writes JSON ContentType. func (r SecureJSON) WriteContentType(w http.ResponseWriter) { writeContentType(w, jsonContentType) } // Render (JsonpJSON) marshals the given interface object and writes it and its callback with custom ContentType. func (r JsonpJSON) Render(w http.ResponseWriter) (err error) { r.WriteContentType(w) ret, err := json.Marshal(r.Data) if err != nil { return err } if r.Callback == "" { _, err = w.Write(ret) return err } callback := template.JSEscapeString(r.Callback) _, err = w.Write([]byte(callback)) if err != nil { return err } _, err = w.Write([]byte("(")) if err != nil { return err } _, err = w.Write(ret) if err != nil { return err } _, err = w.Write([]byte(")")) if err != nil { return err } return nil } // WriteContentType (JsonpJSON) writes Javascript ContentType. func (r JsonpJSON) WriteContentType(w http.ResponseWriter) { writeContentType(w, jsonpContentType) } // Render (AsciiJSON) marshals the given interface object and writes it with custom ContentType. func (r AsciiJSON) Render(w http.ResponseWriter) (err error) { r.WriteContentType(w) ret, err := json.Marshal(r.Data) if err != nil { return err } var buffer bytes.Buffer for _, r := range string(ret) { cvt := string(r) if r >= 128 { cvt = fmt.Sprintf("\\u%04x", int64(r)) } buffer.WriteString(cvt) } _, err = w.Write(buffer.Bytes()) return err } // WriteContentType (AsciiJSON) writes JSON ContentType. func (r AsciiJSON) WriteContentType(w http.ResponseWriter) { writeContentType(w, jsonAsciiContentType) } // Render (PureJSON) writes custom ContentType and encodes the given interface object. func (r PureJSON) Render(w http.ResponseWriter) error { r.WriteContentType(w) encoder := json.NewEncoder(w) encoder.SetEscapeHTML(false) return encoder.Encode(r.Data) } // WriteContentType (PureJSON) writes custom ContentType. func (r PureJSON) WriteContentType(w http.ResponseWriter) { writeContentType(w, jsonContentType) } ================================================ FILE: vendor/github.com/gin-gonic/gin/render/msgpack.go ================================================ // Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package render import ( "net/http" "github.com/ugorji/go/codec" ) // MsgPack contains the given interface object. type MsgPack struct { Data interface{} } var msgpackContentType = []string{"application/msgpack; charset=utf-8"} // WriteContentType (MsgPack) writes MsgPack ContentType. func (r MsgPack) WriteContentType(w http.ResponseWriter) { writeContentType(w, msgpackContentType) } // Render (MsgPack) encodes the given interface object and writes data with custom ContentType. func (r MsgPack) Render(w http.ResponseWriter) error { return WriteMsgPack(w, r.Data) } // WriteMsgPack writes MsgPack ContentType and encodes the given interface object. func WriteMsgPack(w http.ResponseWriter, obj interface{}) error { writeContentType(w, msgpackContentType) var mh codec.MsgpackHandle return codec.NewEncoder(w, &mh).Encode(obj) } ================================================ FILE: vendor/github.com/gin-gonic/gin/render/protobuf.go ================================================ // Copyright 2018 Gin Core Team. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package render import ( "net/http" "github.com/golang/protobuf/proto" ) // ProtoBuf contains the given interface object. type ProtoBuf struct { Data interface{} } var protobufContentType = []string{"application/x-protobuf"} // Render (ProtoBuf) marshals the given interface object and writes data with custom ContentType. func (r ProtoBuf) Render(w http.ResponseWriter) error { r.WriteContentType(w) bytes, err := proto.Marshal(r.Data.(proto.Message)) if err != nil { return err } _, err = w.Write(bytes) return err } // WriteContentType (ProtoBuf) writes ProtoBuf ContentType. func (r ProtoBuf) WriteContentType(w http.ResponseWriter) { writeContentType(w, protobufContentType) } ================================================ FILE: vendor/github.com/gin-gonic/gin/render/reader.go ================================================ // Copyright 2018 Gin Core Team. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package render import ( "io" "net/http" "strconv" ) // Reader contains the IO reader and its length, and custom ContentType and other headers. type Reader struct { ContentType string ContentLength int64 Reader io.Reader Headers map[string]string } // Render (Reader) writes data with custom ContentType and headers. func (r Reader) Render(w http.ResponseWriter) (err error) { r.WriteContentType(w) r.Headers["Content-Length"] = strconv.FormatInt(r.ContentLength, 10) r.writeHeaders(w, r.Headers) _, err = io.Copy(w, r.Reader) return } // WriteContentType (Reader) writes custom ContentType. func (r Reader) WriteContentType(w http.ResponseWriter) { writeContentType(w, []string{r.ContentType}) } // writeHeaders writes custom Header. func (r Reader) writeHeaders(w http.ResponseWriter, headers map[string]string) { header := w.Header() for k, v := range headers { if header.Get(k) == "" { header.Set(k, v) } } } ================================================ FILE: vendor/github.com/gin-gonic/gin/render/redirect.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package render import ( "fmt" "net/http" ) // Redirect contains the http request reference and redirects status code and location. type Redirect struct { Code int Request *http.Request Location string } // Render (Redirect) redirects the http request to new location and writes redirect response. func (r Redirect) Render(w http.ResponseWriter) error { if (r.Code < http.StatusMultipleChoices || r.Code > http.StatusPermanentRedirect) && r.Code != http.StatusCreated { panic(fmt.Sprintf("Cannot redirect with status code %d", r.Code)) } http.Redirect(w, r.Request, r.Location, r.Code) return nil } // WriteContentType (Redirect) don't write any ContentType. func (r Redirect) WriteContentType(http.ResponseWriter) {} ================================================ FILE: vendor/github.com/gin-gonic/gin/render/render.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package render import "net/http" // Render interface is to be implemented by JSON, XML, HTML, YAML and so on. type Render interface { // Render writes data with custom ContentType. Render(http.ResponseWriter) error // WriteContentType writes custom ContentType. WriteContentType(w http.ResponseWriter) } var ( _ Render = JSON{} _ Render = IndentedJSON{} _ Render = SecureJSON{} _ Render = JsonpJSON{} _ Render = XML{} _ Render = String{} _ Render = Redirect{} _ Render = Data{} _ Render = HTML{} _ HTMLRender = HTMLDebug{} _ HTMLRender = HTMLProduction{} _ Render = YAML{} _ Render = MsgPack{} _ Render = Reader{} _ Render = AsciiJSON{} _ Render = ProtoBuf{} ) func writeContentType(w http.ResponseWriter, value []string) { header := w.Header() if val := header["Content-Type"]; len(val) == 0 { header["Content-Type"] = value } } ================================================ FILE: vendor/github.com/gin-gonic/gin/render/text.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package render import ( "fmt" "io" "net/http" ) // String contains the given interface object slice and its format. type String struct { Format string Data []interface{} } var plainContentType = []string{"text/plain; charset=utf-8"} // Render (String) writes data with custom ContentType. func (r String) Render(w http.ResponseWriter) error { return WriteString(w, r.Format, r.Data) } // WriteContentType (String) writes Plain ContentType. func (r String) WriteContentType(w http.ResponseWriter) { writeContentType(w, plainContentType) } // WriteString writes data according to its format and write custom ContentType. func WriteString(w http.ResponseWriter, format string, data []interface{}) (err error) { writeContentType(w, plainContentType) if len(data) > 0 { _, err = fmt.Fprintf(w, format, data...) return } _, err = io.WriteString(w, format) return } ================================================ FILE: vendor/github.com/gin-gonic/gin/render/xml.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package render import ( "encoding/xml" "net/http" ) // XML contains the given interface object. type XML struct { Data interface{} } var xmlContentType = []string{"application/xml; charset=utf-8"} // Render (XML) encodes the given interface object and writes data with custom ContentType. func (r XML) Render(w http.ResponseWriter) error { r.WriteContentType(w) return xml.NewEncoder(w).Encode(r.Data) } // WriteContentType (XML) writes XML ContentType for response. func (r XML) WriteContentType(w http.ResponseWriter) { writeContentType(w, xmlContentType) } ================================================ FILE: vendor/github.com/gin-gonic/gin/render/yaml.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package render import ( "net/http" "gopkg.in/yaml.v2" ) // YAML contains the given interface object. type YAML struct { Data interface{} } var yamlContentType = []string{"application/x-yaml; charset=utf-8"} // Render (YAML) marshals the given interface object and writes data with custom ContentType. func (r YAML) Render(w http.ResponseWriter) error { r.WriteContentType(w) bytes, err := yaml.Marshal(r.Data) if err != nil { return err } _, err = w.Write(bytes) return err } // WriteContentType (YAML) writes YAML ContentType for response. func (r YAML) WriteContentType(w http.ResponseWriter) { writeContentType(w, yamlContentType) } ================================================ FILE: vendor/github.com/gin-gonic/gin/response_writer.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin import ( "bufio" "io" "net" "net/http" ) const ( noWritten = -1 defaultStatus = http.StatusOK ) // ResponseWriter ... type ResponseWriter interface { http.ResponseWriter http.Hijacker http.Flusher http.CloseNotifier // Returns the HTTP response status code of the current request. Status() int // Returns the number of bytes already written into the response http body. // See Written() Size() int // Writes the string into the response body. WriteString(string) (int, error) // Returns true if the response body was already written. Written() bool // Forces to write the http header (status code + headers). WriteHeaderNow() // get the http.Pusher for server push Pusher() http.Pusher } type responseWriter struct { http.ResponseWriter size int status int } var _ ResponseWriter = &responseWriter{} func (w *responseWriter) reset(writer http.ResponseWriter) { w.ResponseWriter = writer w.size = noWritten w.status = defaultStatus } func (w *responseWriter) WriteHeader(code int) { if code > 0 && w.status != code { if w.Written() { debugPrint("[WARNING] Headers were already written. Wanted to override status code %d with %d", w.status, code) } w.status = code } } func (w *responseWriter) WriteHeaderNow() { if !w.Written() { w.size = 0 w.ResponseWriter.WriteHeader(w.status) } } func (w *responseWriter) Write(data []byte) (n int, err error) { w.WriteHeaderNow() n, err = w.ResponseWriter.Write(data) w.size += n return } func (w *responseWriter) WriteString(s string) (n int, err error) { w.WriteHeaderNow() n, err = io.WriteString(w.ResponseWriter, s) w.size += n return } func (w *responseWriter) Status() int { return w.status } func (w *responseWriter) Size() int { return w.size } func (w *responseWriter) Written() bool { return w.size != noWritten } // Hijack implements the http.Hijacker interface. func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { if w.size < 0 { w.size = 0 } return w.ResponseWriter.(http.Hijacker).Hijack() } // CloseNotify implements the http.CloseNotify interface. func (w *responseWriter) CloseNotify() <-chan bool { return w.ResponseWriter.(http.CloseNotifier).CloseNotify() } // Flush implements the http.Flush interface. func (w *responseWriter) Flush() { w.WriteHeaderNow() w.ResponseWriter.(http.Flusher).Flush() } func (w *responseWriter) Pusher() (pusher http.Pusher) { if pusher, ok := w.ResponseWriter.(http.Pusher); ok { return pusher } return nil } ================================================ FILE: vendor/github.com/gin-gonic/gin/routergroup.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin import ( "net/http" "path" "regexp" "strings" ) // IRouter defines all router handle interface includes single and group router. type IRouter interface { IRoutes Group(string, ...HandlerFunc) *RouterGroup } // IRoutes defines all router handle interface. type IRoutes interface { Use(...HandlerFunc) IRoutes Handle(string, string, ...HandlerFunc) IRoutes Any(string, ...HandlerFunc) IRoutes GET(string, ...HandlerFunc) IRoutes POST(string, ...HandlerFunc) IRoutes DELETE(string, ...HandlerFunc) IRoutes PATCH(string, ...HandlerFunc) IRoutes PUT(string, ...HandlerFunc) IRoutes OPTIONS(string, ...HandlerFunc) IRoutes HEAD(string, ...HandlerFunc) IRoutes StaticFile(string, string) IRoutes Static(string, string) IRoutes StaticFS(string, http.FileSystem) IRoutes } // RouterGroup is used internally to configure router, a RouterGroup is associated with // a prefix and an array of handlers (middleware). type RouterGroup struct { Handlers HandlersChain basePath string engine *Engine root bool } var _ IRouter = &RouterGroup{} // Use adds middleware to the group, see example code in GitHub. func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes { group.Handlers = append(group.Handlers, middleware...) return group.returnObj() } // Group creates a new router group. You should add all the routes that have common middlewares or the same path prefix. // For example, all the routes that use a common middleware for authorization could be grouped. func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup { return &RouterGroup{ Handlers: group.combineHandlers(handlers), basePath: group.calculateAbsolutePath(relativePath), engine: group.engine, } } // BasePath returns the base path of router group. // For example, if v := router.Group("/rest/n/v1/api"), v.BasePath() is "/rest/n/v1/api". func (group *RouterGroup) BasePath() string { return group.basePath } func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes { absolutePath := group.calculateAbsolutePath(relativePath) handlers = group.combineHandlers(handlers) group.engine.addRoute(httpMethod, absolutePath, handlers) return group.returnObj() } // Handle registers a new request handle and middleware with the given path and method. // The last handler should be the real handler, the other ones should be middleware that can and should be shared among different routes. // See the example code in GitHub. // // For GET, POST, PUT, PATCH and DELETE requests the respective shortcut // functions can be used. // // This function is intended for bulk loading and to allow the usage of less // frequently used, non-standardized or custom methods (e.g. for internal // communication with a proxy). func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes { if matches, err := regexp.MatchString("^[A-Z]+$", httpMethod); !matches || err != nil { panic("http method " + httpMethod + " is not valid") } return group.handle(httpMethod, relativePath, handlers) } // POST is a shortcut for router.Handle("POST", path, handle). func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle("POST", relativePath, handlers) } // GET is a shortcut for router.Handle("GET", path, handle). func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle("GET", relativePath, handlers) } // DELETE is a shortcut for router.Handle("DELETE", path, handle). func (group *RouterGroup) DELETE(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle("DELETE", relativePath, handlers) } // PATCH is a shortcut for router.Handle("PATCH", path, handle). func (group *RouterGroup) PATCH(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle("PATCH", relativePath, handlers) } // PUT is a shortcut for router.Handle("PUT", path, handle). func (group *RouterGroup) PUT(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle("PUT", relativePath, handlers) } // OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle). func (group *RouterGroup) OPTIONS(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle("OPTIONS", relativePath, handlers) } // HEAD is a shortcut for router.Handle("HEAD", path, handle). func (group *RouterGroup) HEAD(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle("HEAD", relativePath, handlers) } // Any registers a route that matches all the HTTP methods. // GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE. func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) IRoutes { group.handle("GET", relativePath, handlers) group.handle("POST", relativePath, handlers) group.handle("PUT", relativePath, handlers) group.handle("PATCH", relativePath, handlers) group.handle("HEAD", relativePath, handlers) group.handle("OPTIONS", relativePath, handlers) group.handle("DELETE", relativePath, handlers) group.handle("CONNECT", relativePath, handlers) group.handle("TRACE", relativePath, handlers) return group.returnObj() } // StaticFile registers a single route in order to serve a single file of the local filesystem. // router.StaticFile("favicon.ico", "./resources/favicon.ico") func (group *RouterGroup) StaticFile(relativePath, filepath string) IRoutes { if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") { panic("URL parameters can not be used when serving a static file") } handler := func(c *Context) { c.File(filepath) } group.GET(relativePath, handler) group.HEAD(relativePath, handler) return group.returnObj() } // Static serves files from the given file system root. // Internally a http.FileServer is used, therefore http.NotFound is used instead // of the Router's NotFound handler. // To use the operating system's file system implementation, // use : // router.Static("/static", "/var/www") func (group *RouterGroup) Static(relativePath, root string) IRoutes { return group.StaticFS(relativePath, Dir(root, false)) } // StaticFS works just like `Static()` but a custom `http.FileSystem` can be used instead. // Gin by default user: gin.Dir() func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRoutes { if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") { panic("URL parameters can not be used when serving a static folder") } handler := group.createStaticHandler(relativePath, fs) urlPattern := path.Join(relativePath, "/*filepath") // Register GET and HEAD handlers group.GET(urlPattern, handler) group.HEAD(urlPattern, handler) return group.returnObj() } func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc { absolutePath := group.calculateAbsolutePath(relativePath) fileServer := http.StripPrefix(absolutePath, http.FileServer(fs)) return func(c *Context) { if _, nolisting := fs.(*onlyfilesFS); nolisting { c.Writer.WriteHeader(http.StatusNotFound) } file := c.Param("filepath") // Check if file exists and/or if we have permission to access it if _, err := fs.Open(file); err != nil { c.Writer.WriteHeader(http.StatusNotFound) c.handlers = group.engine.noRoute // Reset index c.index = -1 return } fileServer.ServeHTTP(c.Writer, c.Request) } } func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain { finalSize := len(group.Handlers) + len(handlers) if finalSize >= int(abortIndex) { panic("too many handlers") } mergedHandlers := make(HandlersChain, finalSize) copy(mergedHandlers, group.Handlers) copy(mergedHandlers[len(group.Handlers):], handlers) return mergedHandlers } func (group *RouterGroup) calculateAbsolutePath(relativePath string) string { return joinPaths(group.basePath, relativePath) } func (group *RouterGroup) returnObj() IRoutes { if group.root { return group.engine } return group } ================================================ FILE: vendor/github.com/gin-gonic/gin/test_helpers.go ================================================ // Copyright 2017 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin import "net/http" // CreateTestContext returns a fresh engine and context for testing purposes func CreateTestContext(w http.ResponseWriter) (c *Context, r *Engine) { r = New() c = r.allocateContext() c.reset() c.writermem.reset(w) return } ================================================ FILE: vendor/github.com/gin-gonic/gin/tree.go ================================================ // Copyright 2013 Julien Schmidt. All rights reserved. // Use of this source code is governed by a BSD-style license that can be found // at https://github.com/julienschmidt/httprouter/blob/master/LICENSE package gin import ( "net/url" "strings" "unicode" ) // Param is a single URL parameter, consisting of a key and a value. type Param struct { Key string Value string } // Params is a Param-slice, as returned by the router. // The slice is ordered, the first URL parameter is also the first slice value. // It is therefore safe to read values by the index. type Params []Param // Get returns the value of the first Param which key matches the given name. // If no matching Param is found, an empty string is returned. func (ps Params) Get(name string) (string, bool) { for _, entry := range ps { if entry.Key == name { return entry.Value, true } } return "", false } // ByName returns the value of the first Param which key matches the given name. // If no matching Param is found, an empty string is returned. func (ps Params) ByName(name string) (va string) { va, _ = ps.Get(name) return } type methodTree struct { method string root *node } type methodTrees []methodTree func (trees methodTrees) get(method string) *node { for _, tree := range trees { if tree.method == method { return tree.root } } return nil } func min(a, b int) int { if a <= b { return a } return b } func countParams(path string) uint8 { var n uint for i := 0; i < len(path); i++ { if path[i] != ':' && path[i] != '*' { continue } n++ } if n >= 255 { return 255 } return uint8(n) } type nodeType uint8 const ( static nodeType = iota // default root param catchAll ) type node struct { path string indices string children []*node handlers HandlersChain priority uint32 nType nodeType maxParams uint8 wildChild bool } // increments priority of the given child and reorders if necessary. func (n *node) incrementChildPrio(pos int) int { n.children[pos].priority++ prio := n.children[pos].priority // adjust position (move to front) newPos := pos for newPos > 0 && n.children[newPos-1].priority < prio { // swap node positions n.children[newPos-1], n.children[newPos] = n.children[newPos], n.children[newPos-1] newPos-- } // build new index char string if newPos != pos { n.indices = n.indices[:newPos] + // unchanged prefix, might be empty n.indices[pos:pos+1] + // the index char we move n.indices[newPos:pos] + n.indices[pos+1:] // rest without char at 'pos' } return newPos } // addRoute adds a node with the given handle to the path. // Not concurrency-safe! func (n *node) addRoute(path string, handlers HandlersChain) { fullPath := path n.priority++ numParams := countParams(path) // non-empty tree if len(n.path) > 0 || len(n.children) > 0 { walk: for { // Update maxParams of the current node if numParams > n.maxParams { n.maxParams = numParams } // Find the longest common prefix. // This also implies that the common prefix contains no ':' or '*' // since the existing key can't contain those chars. i := 0 max := min(len(path), len(n.path)) for i < max && path[i] == n.path[i] { i++ } // Split edge if i < len(n.path) { child := node{ path: n.path[i:], wildChild: n.wildChild, indices: n.indices, children: n.children, handlers: n.handlers, priority: n.priority - 1, } // Update maxParams (max of all children) for i := range child.children { if child.children[i].maxParams > child.maxParams { child.maxParams = child.children[i].maxParams } } n.children = []*node{&child} // []byte for proper unicode char conversion, see #65 n.indices = string([]byte{n.path[i]}) n.path = path[:i] n.handlers = nil n.wildChild = false } // Make new node a child of this node if i < len(path) { path = path[i:] if n.wildChild { n = n.children[0] n.priority++ // Update maxParams of the child node if numParams > n.maxParams { n.maxParams = numParams } numParams-- // Check if the wildcard matches if len(path) >= len(n.path) && n.path == path[:len(n.path)] { // check for longer wildcard, e.g. :name and :names if len(n.path) >= len(path) || path[len(n.path)] == '/' { continue walk } } pathSeg := path if n.nType != catchAll { pathSeg = strings.SplitN(path, "/", 2)[0] } prefix := fullPath[:strings.Index(fullPath, pathSeg)] + n.path panic("'" + pathSeg + "' in new path '" + fullPath + "' conflicts with existing wildcard '" + n.path + "' in existing prefix '" + prefix + "'") } c := path[0] // slash after param if n.nType == param && c == '/' && len(n.children) == 1 { n = n.children[0] n.priority++ continue walk } // Check if a child with the next path byte exists for i := 0; i < len(n.indices); i++ { if c == n.indices[i] { i = n.incrementChildPrio(i) n = n.children[i] continue walk } } // Otherwise insert it if c != ':' && c != '*' { // []byte for proper unicode char conversion, see #65 n.indices += string([]byte{c}) child := &node{ maxParams: numParams, } n.children = append(n.children, child) n.incrementChildPrio(len(n.indices) - 1) n = child } n.insertChild(numParams, path, fullPath, handlers) return } else if i == len(path) { // Make node a (in-path) leaf if n.handlers != nil { panic("handlers are already registered for path '" + fullPath + "'") } n.handlers = handlers } return } } else { // Empty tree n.insertChild(numParams, path, fullPath, handlers) n.nType = root } } func (n *node) insertChild(numParams uint8, path string, fullPath string, handlers HandlersChain) { var offset int // already handled bytes of the path // find prefix until first wildcard (beginning with ':' or '*') for i, max := 0, len(path); numParams > 0; i++ { c := path[i] if c != ':' && c != '*' { continue } // find wildcard end (either '/' or path end) end := i + 1 for end < max && path[end] != '/' { switch path[end] { // the wildcard name must not contain ':' and '*' case ':', '*': panic("only one wildcard per path segment is allowed, has: '" + path[i:] + "' in path '" + fullPath + "'") default: end++ } } // check if this Node existing children which would be // unreachable if we insert the wildcard here if len(n.children) > 0 { panic("wildcard route '" + path[i:end] + "' conflicts with existing children in path '" + fullPath + "'") } // check if the wildcard has a name if end-i < 2 { panic("wildcards must be named with a non-empty name in path '" + fullPath + "'") } if c == ':' { // param // split path at the beginning of the wildcard if i > 0 { n.path = path[offset:i] offset = i } child := &node{ nType: param, maxParams: numParams, } n.children = []*node{child} n.wildChild = true n = child n.priority++ numParams-- // if the path doesn't end with the wildcard, then there // will be another non-wildcard subpath starting with '/' if end < max { n.path = path[offset:end] offset = end child := &node{ maxParams: numParams, priority: 1, } n.children = []*node{child} n = child } } else { // catchAll if end != max || numParams > 1 { panic("catch-all routes are only allowed at the end of the path in path '" + fullPath + "'") } if len(n.path) > 0 && n.path[len(n.path)-1] == '/' { panic("catch-all conflicts with existing handle for the path segment root in path '" + fullPath + "'") } // currently fixed width 1 for '/' i-- if path[i] != '/' { panic("no / before catch-all in path '" + fullPath + "'") } n.path = path[offset:i] // first node: catchAll node with empty path child := &node{ wildChild: true, nType: catchAll, maxParams: 1, } n.children = []*node{child} n.indices = string(path[i]) n = child n.priority++ // second node: node holding the variable child = &node{ path: path[i:], nType: catchAll, maxParams: 1, handlers: handlers, priority: 1, } n.children = []*node{child} return } } // insert remaining path part and handle to the leaf n.path = path[offset:] n.handlers = handlers } // getValue returns the handle registered with the given path (key). The values of // wildcards are saved to a map. // If no handle can be found, a TSR (trailing slash redirect) recommendation is // made if a handle exists with an extra (without the) trailing slash for the // given path. func (n *node) getValue(path string, po Params, unescape bool) (handlers HandlersChain, p Params, tsr bool) { p = po walk: // Outer loop for walking the tree for { if len(path) > len(n.path) { if path[:len(n.path)] == n.path { path = path[len(n.path):] // If this node does not have a wildcard (param or catchAll) // child, we can just look up the next child node and continue // to walk down the tree if !n.wildChild { c := path[0] for i := 0; i < len(n.indices); i++ { if c == n.indices[i] { n = n.children[i] continue walk } } // Nothing found. // We can recommend to redirect to the same URL without a // trailing slash if a leaf exists for that path. tsr = path == "/" && n.handlers != nil return } // handle wildcard child n = n.children[0] switch n.nType { case param: // find param end (either '/' or path end) end := 0 for end < len(path) && path[end] != '/' { end++ } // save param value if cap(p) < int(n.maxParams) { p = make(Params, 0, n.maxParams) } i := len(p) p = p[:i+1] // expand slice within preallocated capacity p[i].Key = n.path[1:] val := path[:end] if unescape { var err error if p[i].Value, err = url.QueryUnescape(val); err != nil { p[i].Value = val // fallback, in case of error } } else { p[i].Value = val } // we need to go deeper! if end < len(path) { if len(n.children) > 0 { path = path[end:] n = n.children[0] continue walk } // ... but we can't tsr = len(path) == end+1 return } if handlers = n.handlers; handlers != nil { return } if len(n.children) == 1 { // No handle found. Check if a handle for this path + a // trailing slash exists for TSR recommendation n = n.children[0] tsr = n.path == "/" && n.handlers != nil } return case catchAll: // save param value if cap(p) < int(n.maxParams) { p = make(Params, 0, n.maxParams) } i := len(p) p = p[:i+1] // expand slice within preallocated capacity p[i].Key = n.path[2:] if unescape { var err error if p[i].Value, err = url.QueryUnescape(path); err != nil { p[i].Value = path // fallback, in case of error } } else { p[i].Value = path } handlers = n.handlers return default: panic("invalid node type") } } } else if path == n.path { // We should have reached the node containing the handle. // Check if this node has a handle registered. if handlers = n.handlers; handlers != nil { return } if path == "/" && n.wildChild && n.nType != root { tsr = true return } // No handle found. Check if a handle for this path + a // trailing slash exists for trailing slash recommendation for i := 0; i < len(n.indices); i++ { if n.indices[i] == '/' { n = n.children[i] tsr = (len(n.path) == 1 && n.handlers != nil) || (n.nType == catchAll && n.children[0].handlers != nil) return } } return } // Nothing found. We can recommend to redirect to the same URL with an // extra trailing slash if a leaf exists for that path tsr = (path == "/") || (len(n.path) == len(path)+1 && n.path[len(path)] == '/' && path == n.path[:len(n.path)-1] && n.handlers != nil) return } } // findCaseInsensitivePath makes a case-insensitive lookup of the given path and tries to find a handler. // It can optionally also fix trailing slashes. // It returns the case-corrected path and a bool indicating whether the lookup // was successful. func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash bool) (ciPath []byte, found bool) { ciPath = make([]byte, 0, len(path)+1) // preallocate enough memory // Outer loop for walking the tree for len(path) >= len(n.path) && strings.ToLower(path[:len(n.path)]) == strings.ToLower(n.path) { path = path[len(n.path):] ciPath = append(ciPath, n.path...) if len(path) > 0 { // If this node does not have a wildcard (param or catchAll) child, // we can just look up the next child node and continue to walk down // the tree if !n.wildChild { r := unicode.ToLower(rune(path[0])) for i, index := range n.indices { // must use recursive approach since both index and // ToLower(index) could exist. We must check both. if r == unicode.ToLower(index) { out, found := n.children[i].findCaseInsensitivePath(path, fixTrailingSlash) if found { return append(ciPath, out...), true } } } // Nothing found. We can recommend to redirect to the same URL // without a trailing slash if a leaf exists for that path found = fixTrailingSlash && path == "/" && n.handlers != nil return } n = n.children[0] switch n.nType { case param: // find param end (either '/' or path end) k := 0 for k < len(path) && path[k] != '/' { k++ } // add param value to case insensitive path ciPath = append(ciPath, path[:k]...) // we need to go deeper! if k < len(path) { if len(n.children) > 0 { path = path[k:] n = n.children[0] continue } // ... but we can't if fixTrailingSlash && len(path) == k+1 { return ciPath, true } return } if n.handlers != nil { return ciPath, true } else if fixTrailingSlash && len(n.children) == 1 { // No handle found. Check if a handle for this path + a // trailing slash exists n = n.children[0] if n.path == "/" && n.handlers != nil { return append(ciPath, '/'), true } } return case catchAll: return append(ciPath, path...), true default: panic("invalid node type") } } else { // We should have reached the node containing the handle. // Check if this node has a handle registered. if n.handlers != nil { return ciPath, true } // No handle found. // Try to fix the path by adding a trailing slash if fixTrailingSlash { for i := 0; i < len(n.indices); i++ { if n.indices[i] == '/' { n = n.children[i] if (len(n.path) == 1 && n.handlers != nil) || (n.nType == catchAll && n.children[0].handlers != nil) { return append(ciPath, '/'), true } return } } } return } } // Nothing found. // Try to fix the path by adding / removing a trailing slash if fixTrailingSlash { if path == "/" { return ciPath, true } if len(path)+1 == len(n.path) && n.path[len(path)] == '/' && strings.ToLower(path) == strings.ToLower(n.path[:len(path)]) && n.handlers != nil { return append(ciPath, n.path...), true } } return } ================================================ FILE: vendor/github.com/gin-gonic/gin/utils.go ================================================ // Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin import ( "encoding/xml" "net/http" "os" "path" "reflect" "runtime" "strings" ) // BindKey indicates a default bind key. const BindKey = "_gin-gonic/gin/bindkey" // Bind is a helper function for given interface object and returns a Gin middleware. func Bind(val interface{}) HandlerFunc { value := reflect.ValueOf(val) if value.Kind() == reflect.Ptr { panic(`Bind struct can not be a pointer. Example: Use: gin.Bind(Struct{}) instead of gin.Bind(&Struct{}) `) } typ := value.Type() return func(c *Context) { obj := reflect.New(typ).Interface() if c.Bind(obj) == nil { c.Set(BindKey, obj) } } } // WrapF is a helper function for wrapping http.HandlerFunc and returns a Gin middleware. func WrapF(f http.HandlerFunc) HandlerFunc { return func(c *Context) { f(c.Writer, c.Request) } } // WrapH is a helper function for wrapping http.Handler and returns a Gin middleware. func WrapH(h http.Handler) HandlerFunc { return func(c *Context) { h.ServeHTTP(c.Writer, c.Request) } } // H is a shortcut for map[string]interface{} type H map[string]interface{} // MarshalXML allows type H to be used with xml.Marshal. func (h H) MarshalXML(e *xml.Encoder, start xml.StartElement) error { start.Name = xml.Name{ Space: "", Local: "map", } if err := e.EncodeToken(start); err != nil { return err } for key, value := range h { elem := xml.StartElement{ Name: xml.Name{Space: "", Local: key}, Attr: []xml.Attr{}, } if err := e.EncodeElement(value, elem); err != nil { return err } } return e.EncodeToken(xml.EndElement{Name: start.Name}) } func assert1(guard bool, text string) { if !guard { panic(text) } } func filterFlags(content string) string { for i, char := range content { if char == ' ' || char == ';' { return content[:i] } } return content } func chooseData(custom, wildcard interface{}) interface{} { if custom == nil { if wildcard == nil { panic("negotiation config is invalid") } return wildcard } return custom } func parseAccept(acceptHeader string) []string { parts := strings.Split(acceptHeader, ",") out := make([]string, 0, len(parts)) for _, part := range parts { if part = strings.TrimSpace(strings.Split(part, ";")[0]); part != "" { out = append(out, part) } } return out } func lastChar(str string) uint8 { if str == "" { panic("The length of the string can't be 0") } return str[len(str)-1] } func nameOfFunction(f interface{}) string { return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() } func joinPaths(absolutePath, relativePath string) string { if relativePath == "" { return absolutePath } finalPath := path.Join(absolutePath, relativePath) appendSlash := lastChar(relativePath) == '/' && lastChar(finalPath) != '/' if appendSlash { return finalPath + "/" } return finalPath } func resolveAddress(addr []string) string { switch len(addr) { case 0: if port := os.Getenv("PORT"); port != "" { debugPrint("Environment variable PORT=\"%s\"", port) return ":" + port } debugPrint("Environment variable PORT is undefined. Using port :8080 by default") return ":8080" case 1: return addr[0] default: panic("too much parameters") } } ================================================ FILE: vendor/github.com/gin-gonic/gin/version.go ================================================ // Copyright 2018 Gin Core Team. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin // Version is the current gin framework's version. const Version = "v1.4.0" ================================================ FILE: vendor/github.com/go-ini/ini/.gitignore ================================================ testdata/conf_out.ini ini.sublime-project ini.sublime-workspace testdata/conf_reflect.ini .idea /.vscode ================================================ FILE: vendor/github.com/go-ini/ini/.travis.yml ================================================ sudo: false language: go go: - 1.5.x - 1.6.x - 1.7.x - 1.8.x - 1.9.x script: - go get golang.org/x/tools/cmd/cover - go get github.com/smartystreets/goconvey - mkdir -p $HOME/gopath/src/gopkg.in - ln -s $HOME/gopath/src/github.com/go-ini/ini $HOME/gopath/src/gopkg.in/ini.v1 - go test -v -cover -race ================================================ FILE: vendor/github.com/go-ini/ini/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2014 Unknwon Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/github.com/go-ini/ini/Makefile ================================================ .PHONY: build test bench vet coverage build: vet bench test: go test -v -cover -race bench: go test -v -cover -race -test.bench=. -test.benchmem vet: go vet coverage: go test -coverprofile=c.out && go tool cover -html=c.out && rm c.out ================================================ FILE: vendor/github.com/go-ini/ini/README.md ================================================ INI [![Build Status](https://travis-ci.org/go-ini/ini.svg?branch=master)](https://travis-ci.org/go-ini/ini) [![Sourcegraph](https://sourcegraph.com/github.com/go-ini/ini/-/badge.svg)](https://sourcegraph.com/github.com/go-ini/ini?badge) === ![](https://avatars0.githubusercontent.com/u/10216035?v=3&s=200) Package ini provides INI file read and write functionality in Go. [简体中文](README_ZH.md) ## Feature - Load multiple data sources(`[]byte`, file and `io.ReadCloser`) with overwrites. - Read with recursion values. - Read with parent-child sections. - Read with auto-increment key names. - Read with multiple-line values. - Read with tons of helper methods. - Read and convert values to Go types. - Read and **WRITE** comments of sections and keys. - Manipulate sections, keys and comments with ease. - Keep sections and keys in order as you parse and save. ## Installation To use a tagged revision: go get gopkg.in/ini.v1 To use with latest changes: go get github.com/go-ini/ini Please add `-u` flag to update in the future. ### Testing If you want to test on your machine, please apply `-t` flag: go get -t gopkg.in/ini.v1 Please add `-u` flag to update in the future. ## Getting Started ### Loading from data sources A **Data Source** is either raw data in type `[]byte`, a file name with type `string` or `io.ReadCloser`. You can load **as many data sources as you want**. Passing other types will simply return an error. ```go cfg, err := ini.Load([]byte("raw data"), "filename", ioutil.NopCloser(bytes.NewReader([]byte("some other data")))) ``` Or start with an empty object: ```go cfg := ini.Empty() ``` When you cannot decide how many data sources to load at the beginning, you will still be able to **Append()** them later. ```go err := cfg.Append("other file", []byte("other raw data")) ``` If you have a list of files with possibilities that some of them may not available at the time, and you don't know exactly which ones, you can use `LooseLoad` to ignore nonexistent files without returning error. ```go cfg, err := ini.LooseLoad("filename", "filename_404") ``` The cool thing is, whenever the file is available to load while you're calling `Reload` method, it will be counted as usual. #### Ignore cases of key name When you do not care about cases of section and key names, you can use `InsensitiveLoad` to force all names to be lowercased while parsing. ```go cfg, err := ini.InsensitiveLoad("filename") //... // sec1 and sec2 are the exactly same section object sec1, err := cfg.GetSection("Section") sec2, err := cfg.GetSection("SecTIOn") // key1 and key2 are the exactly same key object key1, err := sec1.GetKey("Key") key2, err := sec2.GetKey("KeY") ``` #### MySQL-like boolean key MySQL's configuration allows a key without value as follows: ```ini [mysqld] ... skip-host-cache skip-name-resolve ``` By default, this is considered as missing value. But if you know you're going to deal with those cases, you can assign advanced load options: ```go cfg, err := ini.LoadSources(ini.LoadOptions{AllowBooleanKeys: true}, "my.cnf")) ``` The value of those keys are always `true`, and when you save to a file, it will keep in the same foramt as you read. To generate such keys in your program, you could use `NewBooleanKey`: ```go key, err := sec.NewBooleanKey("skip-host-cache") ``` #### Comment Take care that following format will be treated as comment: 1. Line begins with `#` or `;` 2. Words after `#` or `;` 3. Words after section name (i.e words after `[some section name]`) If you want to save a value with `#` or `;`, please quote them with ``` ` ``` or ``` """ ```. Alternatively, you can use following `LoadOptions` to completely ignore inline comments: ```go cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: true}, "app.ini")) ``` ### Working with sections To get a section, you would need to: ```go section, err := cfg.GetSection("section name") ``` For a shortcut for default section, just give an empty string as name: ```go section, err := cfg.GetSection("") ``` When you're pretty sure the section exists, following code could make your life easier: ```go section := cfg.Section("section name") ``` What happens when the section somehow does not exist? Don't panic, it automatically creates and returns a new section to you. To create a new section: ```go err := cfg.NewSection("new section") ``` To get a list of sections or section names: ```go sections := cfg.Sections() names := cfg.SectionStrings() ``` ### Working with keys To get a key under a section: ```go key, err := cfg.Section("").GetKey("key name") ``` Same rule applies to key operations: ```go key := cfg.Section("").Key("key name") ``` To check if a key exists: ```go yes := cfg.Section("").HasKey("key name") ``` To create a new key: ```go err := cfg.Section("").NewKey("name", "value") ``` To get a list of keys or key names: ```go keys := cfg.Section("").Keys() names := cfg.Section("").KeyStrings() ``` To get a clone hash of keys and corresponding values: ```go hash := cfg.Section("").KeysHash() ``` ### Working with values To get a string value: ```go val := cfg.Section("").Key("key name").String() ``` To validate key value on the fly: ```go val := cfg.Section("").Key("key name").Validate(func(in string) string { if len(in) == 0 { return "default" } return in }) ``` If you do not want any auto-transformation (such as recursive read) for the values, you can get raw value directly (this way you get much better performance): ```go val := cfg.Section("").Key("key name").Value() ``` To check if raw value exists: ```go yes := cfg.Section("").HasValue("test value") ``` To get value with types: ```go // For boolean values: // true when value is: 1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On // false when value is: 0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off v, err = cfg.Section("").Key("BOOL").Bool() v, err = cfg.Section("").Key("FLOAT64").Float64() v, err = cfg.Section("").Key("INT").Int() v, err = cfg.Section("").Key("INT64").Int64() v, err = cfg.Section("").Key("UINT").Uint() v, err = cfg.Section("").Key("UINT64").Uint64() v, err = cfg.Section("").Key("TIME").TimeFormat(time.RFC3339) v, err = cfg.Section("").Key("TIME").Time() // RFC3339 v = cfg.Section("").Key("BOOL").MustBool() v = cfg.Section("").Key("FLOAT64").MustFloat64() v = cfg.Section("").Key("INT").MustInt() v = cfg.Section("").Key("INT64").MustInt64() v = cfg.Section("").Key("UINT").MustUint() v = cfg.Section("").Key("UINT64").MustUint64() v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339) v = cfg.Section("").Key("TIME").MustTime() // RFC3339 // Methods start with Must also accept one argument for default value // when key not found or fail to parse value to given type. // Except method MustString, which you have to pass a default value. v = cfg.Section("").Key("String").MustString("default") v = cfg.Section("").Key("BOOL").MustBool(true) v = cfg.Section("").Key("FLOAT64").MustFloat64(1.25) v = cfg.Section("").Key("INT").MustInt(10) v = cfg.Section("").Key("INT64").MustInt64(99) v = cfg.Section("").Key("UINT").MustUint(3) v = cfg.Section("").Key("UINT64").MustUint64(6) v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339, time.Now()) v = cfg.Section("").Key("TIME").MustTime(time.Now()) // RFC3339 ``` What if my value is three-line long? ```ini [advance] ADDRESS = """404 road, NotFound, State, 5000 Earth""" ``` Not a problem! ```go cfg.Section("advance").Key("ADDRESS").String() /* --- start --- 404 road, NotFound, State, 5000 Earth ------ end --- */ ``` That's cool, how about continuation lines? ```ini [advance] two_lines = how about \ continuation lines? lots_of_lines = 1 \ 2 \ 3 \ 4 ``` Piece of cake! ```go cfg.Section("advance").Key("two_lines").String() // how about continuation lines? cfg.Section("advance").Key("lots_of_lines").String() // 1 2 3 4 ``` Well, I hate continuation lines, how do I disable that? ```go cfg, err := ini.LoadSources(ini.LoadOptions{ IgnoreContinuation: true, }, "filename") ``` Holy crap! Note that single quotes around values will be stripped: ```ini foo = "some value" // foo: some value bar = 'some value' // bar: some value ``` Sometimes you downloaded file from [Crowdin](https://crowdin.com/) has values like the following (value is surrounded by double quotes and quotes in the value are escaped): ```ini create_repo="created repository %s" ``` How do you transform this to regular format automatically? ```go cfg, err := ini.LoadSources(ini.LoadOptions{UnescapeValueDoubleQuotes: true}, "en-US.ini")) cfg.Section("").Key("create_repo").String() // You got: created repository %s ``` That's all? Hmm, no. #### Helper methods of working with values To get value with given candidates: ```go v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"}) v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75}) v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30}) v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30}) v = cfg.Section("").Key("UINT").InUint(4, []int{3, 6, 9}) v = cfg.Section("").Key("UINT64").InUint64(8, []int64{3, 6, 9}) v = cfg.Section("").Key("TIME").InTimeFormat(time.RFC3339, time.Now(), []time.Time{time1, time2, time3}) v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3}) // RFC3339 ``` Default value will be presented if value of key is not in candidates you given, and default value does not need be one of candidates. To validate value in a given range: ```go vals = cfg.Section("").Key("FLOAT64").RangeFloat64(0.0, 1.1, 2.2) vals = cfg.Section("").Key("INT").RangeInt(0, 10, 20) vals = cfg.Section("").Key("INT64").RangeInt64(0, 10, 20) vals = cfg.Section("").Key("UINT").RangeUint(0, 3, 9) vals = cfg.Section("").Key("UINT64").RangeUint64(0, 3, 9) vals = cfg.Section("").Key("TIME").RangeTimeFormat(time.RFC3339, time.Now(), minTime, maxTime) vals = cfg.Section("").Key("TIME").RangeTime(time.Now(), minTime, maxTime) // RFC3339 ``` ##### Auto-split values into a slice To use zero value of type for invalid inputs: ```go // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] // Input: how, 2.2, are, you -> [0.0 2.2 0.0 0.0] vals = cfg.Section("").Key("STRINGS").Strings(",") vals = cfg.Section("").Key("FLOAT64S").Float64s(",") vals = cfg.Section("").Key("INTS").Ints(",") vals = cfg.Section("").Key("INT64S").Int64s(",") vals = cfg.Section("").Key("UINTS").Uints(",") vals = cfg.Section("").Key("UINT64S").Uint64s(",") vals = cfg.Section("").Key("TIMES").Times(",") ``` To exclude invalid values out of result slice: ```go // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] // Input: how, 2.2, are, you -> [2.2] vals = cfg.Section("").Key("FLOAT64S").ValidFloat64s(",") vals = cfg.Section("").Key("INTS").ValidInts(",") vals = cfg.Section("").Key("INT64S").ValidInt64s(",") vals = cfg.Section("").Key("UINTS").ValidUints(",") vals = cfg.Section("").Key("UINT64S").ValidUint64s(",") vals = cfg.Section("").Key("TIMES").ValidTimes(",") ``` Or to return nothing but error when have invalid inputs: ```go // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] // Input: how, 2.2, are, you -> error vals = cfg.Section("").Key("FLOAT64S").StrictFloat64s(",") vals = cfg.Section("").Key("INTS").StrictInts(",") vals = cfg.Section("").Key("INT64S").StrictInt64s(",") vals = cfg.Section("").Key("UINTS").StrictUints(",") vals = cfg.Section("").Key("UINT64S").StrictUint64s(",") vals = cfg.Section("").Key("TIMES").StrictTimes(",") ``` ### Save your configuration Finally, it's time to save your configuration to somewhere. A typical way to save configuration is writing it to a file: ```go // ... err = cfg.SaveTo("my.ini") err = cfg.SaveToIndent("my.ini", "\t") ``` Another way to save is writing to a `io.Writer` interface: ```go // ... cfg.WriteTo(writer) cfg.WriteToIndent(writer, "\t") ``` By default, spaces are used to align "=" sign between key and values, to disable that: ```go ini.PrettyFormat = false ``` ## Advanced Usage ### Recursive Values For all value of keys, there is a special syntax `%()s`, where `` is the key name in same section or default section, and `%()s` will be replaced by corresponding value(empty string if key not found). You can use this syntax at most 99 level of recursions. ```ini NAME = ini [author] NAME = Unknwon GITHUB = https://github.com/%(NAME)s [package] FULL_NAME = github.com/go-ini/%(NAME)s ``` ```go cfg.Section("author").Key("GITHUB").String() // https://github.com/Unknwon cfg.Section("package").Key("FULL_NAME").String() // github.com/go-ini/ini ``` ### Parent-child Sections You can use `.` in section name to indicate parent-child relationship between two or more sections. If the key not found in the child section, library will try again on its parent section until there is no parent section. ```ini NAME = ini VERSION = v1 IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s [package] CLONE_URL = https://%(IMPORT_PATH)s [package.sub] ``` ```go cfg.Section("package.sub").Key("CLONE_URL").String() // https://gopkg.in/ini.v1 ``` #### Retrieve parent keys available to a child section ```go cfg.Section("package.sub").ParentKeys() // ["CLONE_URL"] ``` ### Unparseable Sections Sometimes, you have sections that do not contain key-value pairs but raw content, to handle such case, you can use `LoadOptions.UnparsableSections`: ```go cfg, err := ini.LoadSources(ini.LoadOptions{UnparseableSections: []string{"COMMENTS"}}, `[COMMENTS] <1> This slide has the fuel listed in the wrong units `)) body := cfg.Section("COMMENTS").Body() /* --- start --- <1> This slide has the fuel listed in the wrong units ------ end --- */ ``` ### Auto-increment Key Names If key name is `-` in data source, then it would be seen as special syntax for auto-increment key name start from 1, and every section is independent on counter. ```ini [features] -: Support read/write comments of keys and sections -: Support auto-increment of key names -: Support load multiple files to overwrite key values ``` ```go cfg.Section("features").KeyStrings() // []{"#1", "#2", "#3"} ``` ### Map To Struct Want more objective way to play with INI? Cool. ```ini Name = Unknwon age = 21 Male = true Born = 1993-01-01T20:17:05Z [Note] Content = Hi is a good man! Cities = HangZhou, Boston ``` ```go type Note struct { Content string Cities []string } type Person struct { Name string Age int `ini:"age"` Male bool Born time.Time Note Created time.Time `ini:"-"` } func main() { cfg, err := ini.Load("path/to/ini") // ... p := new(Person) err = cfg.MapTo(p) // ... // Things can be simpler. err = ini.MapTo(p, "path/to/ini") // ... // Just map a section? Fine. n := new(Note) err = cfg.Section("Note").MapTo(n) // ... } ``` Can I have default value for field? Absolutely. Assign it before you map to struct. It will keep the value as it is if the key is not presented or got wrong type. ```go // ... p := &Person{ Name: "Joe", } // ... ``` It's really cool, but what's the point if you can't give me my file back from struct? ### Reflect From Struct Why not? ```go type Embeded struct { Dates []time.Time `delim:"|" comment:"Time data"` Places []string `ini:"places,omitempty"` None []int `ini:",omitempty"` } type Author struct { Name string `ini:"NAME"` Male bool Age int `comment:"Author's age"` GPA float64 NeverMind string `ini:"-"` *Embeded `comment:"Embeded section"` } func main() { a := &Author{"Unknwon", true, 21, 2.8, "", &Embeded{ []time.Time{time.Now(), time.Now()}, []string{"HangZhou", "Boston"}, []int{}, }} cfg := ini.Empty() err = ini.ReflectFrom(cfg, a) // ... } ``` So, what do I get? ```ini NAME = Unknwon Male = true ; Author's age Age = 21 GPA = 2.8 ; Embeded section [Embeded] ; Time data Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00 places = HangZhou,Boston ``` #### Name Mapper To save your time and make your code cleaner, this library supports [`NameMapper`](https://gowalker.org/gopkg.in/ini.v1#NameMapper) between struct field and actual section and key name. There are 2 built-in name mappers: - `AllCapsUnderscore`: it converts to format `ALL_CAPS_UNDERSCORE` then match section or key. - `TitleUnderscore`: it converts to format `title_underscore` then match section or key. To use them: ```go type Info struct { PackageName string } func main() { err = ini.MapToWithMapper(&Info{}, ini.TitleUnderscore, []byte("package_name=ini")) // ... cfg, err := ini.Load([]byte("PACKAGE_NAME=ini")) // ... info := new(Info) cfg.NameMapper = ini.AllCapsUnderscore err = cfg.MapTo(info) // ... } ``` Same rules of name mapper apply to `ini.ReflectFromWithMapper` function. #### Value Mapper To expand values (e.g. from environment variables), you can use the `ValueMapper` to transform values: ```go type Env struct { Foo string `ini:"foo"` } func main() { cfg, err := ini.Load([]byte("[env]\nfoo = ${MY_VAR}\n") cfg.ValueMapper = os.ExpandEnv // ... env := &Env{} err = cfg.Section("env").MapTo(env) } ``` This would set the value of `env.Foo` to the value of the environment variable `MY_VAR`. #### Other Notes On Map/Reflect Any embedded struct is treated as a section by default, and there is no automatic parent-child relations in map/reflect feature: ```go type Child struct { Age string } type Parent struct { Name string Child } type Config struct { City string Parent } ``` Example configuration: ```ini City = Boston [Parent] Name = Unknwon [Child] Age = 21 ``` What if, yes, I'm paranoid, I want embedded struct to be in the same section. Well, all roads lead to Rome. ```go type Child struct { Age string } type Parent struct { Name string Child `ini:"Parent"` } type Config struct { City string Parent } ``` Example configuration: ```ini City = Boston [Parent] Name = Unknwon Age = 21 ``` ## Getting Help - [API Documentation](https://gowalker.org/gopkg.in/ini.v1) - [File An Issue](https://github.com/go-ini/ini/issues/new) ## FAQs ### What does `BlockMode` field do? By default, library lets you read and write values so we need a locker to make sure your data is safe. But in cases that you are very sure about only reading data through the library, you can set `cfg.BlockMode = false` to speed up read operations about **50-70%** faster. ### Why another INI library? Many people are using my another INI library [goconfig](https://github.com/Unknwon/goconfig), so the reason for this one is I would like to make more Go style code. Also when you set `cfg.BlockMode = false`, this one is about **10-30%** faster. To make those changes I have to confirm API broken, so it's safer to keep it in another place and start using `gopkg.in` to version my package at this time.(PS: shorter import path) ## License This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text. ================================================ FILE: vendor/github.com/go-ini/ini/README_ZH.md ================================================ 本包提供了 Go 语言中读写 INI 文件的功能。 ## 功能特性 - 支持覆盖加载多个数据源(`[]byte`、文件和 `io.ReadCloser`) - 支持递归读取键值 - 支持读取父子分区 - 支持读取自增键名 - 支持读取多行的键值 - 支持大量辅助方法 - 支持在读取时直接转换为 Go 语言类型 - 支持读取和 **写入** 分区和键的注释 - 轻松操作分区、键值和注释 - 在保存文件时分区和键值会保持原有的顺序 ## 下载安装 使用一个特定版本: go get gopkg.in/ini.v1 使用最新版: go get github.com/go-ini/ini 如需更新请添加 `-u` 选项。 ### 测试安装 如果您想要在自己的机器上运行测试,请使用 `-t` 标记: go get -t gopkg.in/ini.v1 如需更新请添加 `-u` 选项。 ## 开始使用 ### 从数据源加载 一个 **数据源** 可以是 `[]byte` 类型的原始数据,`string` 类型的文件路径或 `io.ReadCloser`。您可以加载 **任意多个** 数据源。如果您传递其它类型的数据源,则会直接返回错误。 ```go cfg, err := ini.Load([]byte("raw data"), "filename", ioutil.NopCloser(bytes.NewReader([]byte("some other data")))) ``` 或者从一个空白的文件开始: ```go cfg := ini.Empty() ``` 当您在一开始无法决定需要加载哪些数据源时,仍可以使用 **Append()** 在需要的时候加载它们。 ```go err := cfg.Append("other file", []byte("other raw data")) ``` 当您想要加载一系列文件,但是不能够确定其中哪些文件是不存在的,可以通过调用函数 `LooseLoad` 来忽略它们(`Load` 会因为文件不存在而返回错误): ```go cfg, err := ini.LooseLoad("filename", "filename_404") ``` 更牛逼的是,当那些之前不存在的文件在重新调用 `Reload` 方法的时候突然出现了,那么它们会被正常加载。 #### 忽略键名的大小写 有时候分区和键的名称大小写混合非常烦人,这个时候就可以通过 `InsensitiveLoad` 将所有分区和键名在读取里强制转换为小写: ```go cfg, err := ini.InsensitiveLoad("filename") //... // sec1 和 sec2 指向同一个分区对象 sec1, err := cfg.GetSection("Section") sec2, err := cfg.GetSection("SecTIOn") // key1 和 key2 指向同一个键对象 key1, err := sec1.GetKey("Key") key2, err := sec2.GetKey("KeY") ``` #### 类似 MySQL 配置中的布尔值键 MySQL 的配置文件中会出现没有具体值的布尔类型的键: ```ini [mysqld] ... skip-host-cache skip-name-resolve ``` 默认情况下这被认为是缺失值而无法完成解析,但可以通过高级的加载选项对它们进行处理: ```go cfg, err := ini.LoadSources(ini.LoadOptions{AllowBooleanKeys: true}, "my.cnf")) ``` 这些键的值永远为 `true`,且在保存到文件时也只会输出键名。 如果您想要通过程序来生成此类键,则可以使用 `NewBooleanKey`: ```go key, err := sec.NewBooleanKey("skip-host-cache") ``` #### 关于注释 下述几种情况的内容将被视为注释: 1. 所有以 `#` 或 `;` 开头的行 2. 所有在 `#` 或 `;` 之后的内容 3. 分区标签后的文字 (即 `[分区名]` 之后的内容) 如果你希望使用包含 `#` 或 `;` 的值,请使用 ``` ` ``` 或 ``` """ ``` 进行包覆。 除此之外,您还可以通过 `LoadOptions` 完全忽略行内注释: ```go cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: true}, "app.ini")) ``` ### 操作分区(Section) 获取指定分区: ```go section, err := cfg.GetSection("section name") ``` 如果您想要获取默认分区,则可以用空字符串代替分区名: ```go section, err := cfg.GetSection("") ``` 当您非常确定某个分区是存在的,可以使用以下简便方法: ```go section := cfg.Section("section name") ``` 如果不小心判断错了,要获取的分区其实是不存在的,那会发生什么呢?没事的,它会自动创建并返回一个对应的分区对象给您。 创建一个分区: ```go err := cfg.NewSection("new section") ``` 获取所有分区对象或名称: ```go sections := cfg.Sections() names := cfg.SectionStrings() ``` ### 操作键(Key) 获取某个分区下的键: ```go key, err := cfg.Section("").GetKey("key name") ``` 和分区一样,您也可以直接获取键而忽略错误处理: ```go key := cfg.Section("").Key("key name") ``` 判断某个键是否存在: ```go yes := cfg.Section("").HasKey("key name") ``` 创建一个新的键: ```go err := cfg.Section("").NewKey("name", "value") ``` 获取分区下的所有键或键名: ```go keys := cfg.Section("").Keys() names := cfg.Section("").KeyStrings() ``` 获取分区下的所有键值对的克隆: ```go hash := cfg.Section("").KeysHash() ``` ### 操作键值(Value) 获取一个类型为字符串(string)的值: ```go val := cfg.Section("").Key("key name").String() ``` 获取值的同时通过自定义函数进行处理验证: ```go val := cfg.Section("").Key("key name").Validate(func(in string) string { if len(in) == 0 { return "default" } return in }) ``` 如果您不需要任何对值的自动转变功能(例如递归读取),可以直接获取原值(这种方式性能最佳): ```go val := cfg.Section("").Key("key name").Value() ``` 判断某个原值是否存在: ```go yes := cfg.Section("").HasValue("test value") ``` 获取其它类型的值: ```go // 布尔值的规则: // true 当值为:1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On // false 当值为:0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off v, err = cfg.Section("").Key("BOOL").Bool() v, err = cfg.Section("").Key("FLOAT64").Float64() v, err = cfg.Section("").Key("INT").Int() v, err = cfg.Section("").Key("INT64").Int64() v, err = cfg.Section("").Key("UINT").Uint() v, err = cfg.Section("").Key("UINT64").Uint64() v, err = cfg.Section("").Key("TIME").TimeFormat(time.RFC3339) v, err = cfg.Section("").Key("TIME").Time() // RFC3339 v = cfg.Section("").Key("BOOL").MustBool() v = cfg.Section("").Key("FLOAT64").MustFloat64() v = cfg.Section("").Key("INT").MustInt() v = cfg.Section("").Key("INT64").MustInt64() v = cfg.Section("").Key("UINT").MustUint() v = cfg.Section("").Key("UINT64").MustUint64() v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339) v = cfg.Section("").Key("TIME").MustTime() // RFC3339 // 由 Must 开头的方法名允许接收一个相同类型的参数来作为默认值, // 当键不存在或者转换失败时,则会直接返回该默认值。 // 但是,MustString 方法必须传递一个默认值。 v = cfg.Seciont("").Key("String").MustString("default") v = cfg.Section("").Key("BOOL").MustBool(true) v = cfg.Section("").Key("FLOAT64").MustFloat64(1.25) v = cfg.Section("").Key("INT").MustInt(10) v = cfg.Section("").Key("INT64").MustInt64(99) v = cfg.Section("").Key("UINT").MustUint(3) v = cfg.Section("").Key("UINT64").MustUint64(6) v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339, time.Now()) v = cfg.Section("").Key("TIME").MustTime(time.Now()) // RFC3339 ``` 如果我的值有好多行怎么办? ```ini [advance] ADDRESS = """404 road, NotFound, State, 5000 Earth""" ``` 嗯哼?小 case! ```go cfg.Section("advance").Key("ADDRESS").String() /* --- start --- 404 road, NotFound, State, 5000 Earth ------ end --- */ ``` 赞爆了!那要是我属于一行的内容写不下想要写到第二行怎么办? ```ini [advance] two_lines = how about \ continuation lines? lots_of_lines = 1 \ 2 \ 3 \ 4 ``` 简直是小菜一碟! ```go cfg.Section("advance").Key("two_lines").String() // how about continuation lines? cfg.Section("advance").Key("lots_of_lines").String() // 1 2 3 4 ``` 可是我有时候觉得两行连在一起特别没劲,怎么才能不自动连接两行呢? ```go cfg, err := ini.LoadSources(ini.LoadOptions{ IgnoreContinuation: true, }, "filename") ``` 哇靠给力啊! 需要注意的是,值两侧的单引号会被自动剔除: ```ini foo = "some value" // foo: some value bar = 'some value' // bar: some value ``` 有时您会获得像从 [Crowdin](https://crowdin.com/) 网站下载的文件那样具有特殊格式的值(值使用双引号括起来,内部的双引号被转义): ```ini create_repo="创建了仓库 %s" ``` 那么,怎么自动地将这类值进行处理呢? ```go cfg, err := ini.LoadSources(ini.LoadOptions{UnescapeValueDoubleQuotes: true}, "en-US.ini")) cfg.Section("").Key("create_repo").String() // You got: 创建了仓库 %s ``` 这就是全部了?哈哈,当然不是。 #### 操作键值的辅助方法 获取键值时设定候选值: ```go v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"}) v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75}) v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30}) v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30}) v = cfg.Section("").Key("UINT").InUint(4, []int{3, 6, 9}) v = cfg.Section("").Key("UINT64").InUint64(8, []int64{3, 6, 9}) v = cfg.Section("").Key("TIME").InTimeFormat(time.RFC3339, time.Now(), []time.Time{time1, time2, time3}) v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3}) // RFC3339 ``` 如果获取到的值不是候选值的任意一个,则会返回默认值,而默认值不需要是候选值中的一员。 验证获取的值是否在指定范围内: ```go vals = cfg.Section("").Key("FLOAT64").RangeFloat64(0.0, 1.1, 2.2) vals = cfg.Section("").Key("INT").RangeInt(0, 10, 20) vals = cfg.Section("").Key("INT64").RangeInt64(0, 10, 20) vals = cfg.Section("").Key("UINT").RangeUint(0, 3, 9) vals = cfg.Section("").Key("UINT64").RangeUint64(0, 3, 9) vals = cfg.Section("").Key("TIME").RangeTimeFormat(time.RFC3339, time.Now(), minTime, maxTime) vals = cfg.Section("").Key("TIME").RangeTime(time.Now(), minTime, maxTime) // RFC3339 ``` ##### 自动分割键值到切片(slice) 当存在无效输入时,使用零值代替: ```go // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] // Input: how, 2.2, are, you -> [0.0 2.2 0.0 0.0] vals = cfg.Section("").Key("STRINGS").Strings(",") vals = cfg.Section("").Key("FLOAT64S").Float64s(",") vals = cfg.Section("").Key("INTS").Ints(",") vals = cfg.Section("").Key("INT64S").Int64s(",") vals = cfg.Section("").Key("UINTS").Uints(",") vals = cfg.Section("").Key("UINT64S").Uint64s(",") vals = cfg.Section("").Key("TIMES").Times(",") ``` 从结果切片中剔除无效输入: ```go // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] // Input: how, 2.2, are, you -> [2.2] vals = cfg.Section("").Key("FLOAT64S").ValidFloat64s(",") vals = cfg.Section("").Key("INTS").ValidInts(",") vals = cfg.Section("").Key("INT64S").ValidInt64s(",") vals = cfg.Section("").Key("UINTS").ValidUints(",") vals = cfg.Section("").Key("UINT64S").ValidUint64s(",") vals = cfg.Section("").Key("TIMES").ValidTimes(",") ``` 当存在无效输入时,直接返回错误: ```go // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] // Input: how, 2.2, are, you -> error vals = cfg.Section("").Key("FLOAT64S").StrictFloat64s(",") vals = cfg.Section("").Key("INTS").StrictInts(",") vals = cfg.Section("").Key("INT64S").StrictInt64s(",") vals = cfg.Section("").Key("UINTS").StrictUints(",") vals = cfg.Section("").Key("UINT64S").StrictUint64s(",") vals = cfg.Section("").Key("TIMES").StrictTimes(",") ``` ### 保存配置 终于到了这个时刻,是时候保存一下配置了。 比较原始的做法是输出配置到某个文件: ```go // ... err = cfg.SaveTo("my.ini") err = cfg.SaveToIndent("my.ini", "\t") ``` 另一个比较高级的做法是写入到任何实现 `io.Writer` 接口的对象中: ```go // ... cfg.WriteTo(writer) cfg.WriteToIndent(writer, "\t") ``` 默认情况下,空格将被用于对齐键值之间的等号以美化输出结果,以下代码可以禁用该功能: ```go ini.PrettyFormat = false ``` ## 高级用法 ### 递归读取键值 在获取所有键值的过程中,特殊语法 `%()s` 会被应用,其中 `` 可以是相同分区或者默认分区下的键名。字符串 `%()s` 会被相应的键值所替代,如果指定的键不存在,则会用空字符串替代。您可以最多使用 99 层的递归嵌套。 ```ini NAME = ini [author] NAME = Unknwon GITHUB = https://github.com/%(NAME)s [package] FULL_NAME = github.com/go-ini/%(NAME)s ``` ```go cfg.Section("author").Key("GITHUB").String() // https://github.com/Unknwon cfg.Section("package").Key("FULL_NAME").String() // github.com/go-ini/ini ``` ### 读取父子分区 您可以在分区名称中使用 `.` 来表示两个或多个分区之间的父子关系。如果某个键在子分区中不存在,则会去它的父分区中再次寻找,直到没有父分区为止。 ```ini NAME = ini VERSION = v1 IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s [package] CLONE_URL = https://%(IMPORT_PATH)s [package.sub] ``` ```go cfg.Section("package.sub").Key("CLONE_URL").String() // https://gopkg.in/ini.v1 ``` #### 获取上级父分区下的所有键名 ```go cfg.Section("package.sub").ParentKeys() // ["CLONE_URL"] ``` ### 无法解析的分区 如果遇到一些比较特殊的分区,它们不包含常见的键值对,而是没有固定格式的纯文本,则可以使用 `LoadOptions.UnparsableSections` 进行处理: ```go cfg, err := LoadSources(ini.LoadOptions{UnparseableSections: []string{"COMMENTS"}}, `[COMMENTS] <1> This slide has the fuel listed in the wrong units `)) body := cfg.Section("COMMENTS").Body() /* --- start --- <1> This slide has the fuel listed in the wrong units ------ end --- */ ``` ### 读取自增键名 如果数据源中的键名为 `-`,则认为该键使用了自增键名的特殊语法。计数器从 1 开始,并且分区之间是相互独立的。 ```ini [features] -: Support read/write comments of keys and sections -: Support auto-increment of key names -: Support load multiple files to overwrite key values ``` ```go cfg.Section("features").KeyStrings() // []{"#1", "#2", "#3"} ``` ### 映射到结构 想要使用更加面向对象的方式玩转 INI 吗?好主意。 ```ini Name = Unknwon age = 21 Male = true Born = 1993-01-01T20:17:05Z [Note] Content = Hi is a good man! Cities = HangZhou, Boston ``` ```go type Note struct { Content string Cities []string } type Person struct { Name string Age int `ini:"age"` Male bool Born time.Time Note Created time.Time `ini:"-"` } func main() { cfg, err := ini.Load("path/to/ini") // ... p := new(Person) err = cfg.MapTo(p) // ... // 一切竟可以如此的简单。 err = ini.MapTo(p, "path/to/ini") // ... // 嗯哼?只需要映射一个分区吗? n := new(Note) err = cfg.Section("Note").MapTo(n) // ... } ``` 结构的字段怎么设置默认值呢?很简单,只要在映射之前对指定字段进行赋值就可以了。如果键未找到或者类型错误,该值不会发生改变。 ```go // ... p := &Person{ Name: "Joe", } // ... ``` 这样玩 INI 真的好酷啊!然而,如果不能还给我原来的配置文件,有什么卵用? ### 从结构反射 可是,我有说不能吗? ```go type Embeded struct { Dates []time.Time `delim:"|" comment:"Time data"` Places []string `ini:"places,omitempty"` None []int `ini:",omitempty"` } type Author struct { Name string `ini:"NAME"` Male bool Age int `comment:"Author's age"` GPA float64 NeverMind string `ini:"-"` *Embeded `comment:"Embeded section"` } func main() { a := &Author{"Unknwon", true, 21, 2.8, "", &Embeded{ []time.Time{time.Now(), time.Now()}, []string{"HangZhou", "Boston"}, []int{}, }} cfg := ini.Empty() err = ini.ReflectFrom(cfg, a) // ... } ``` 瞧瞧,奇迹发生了。 ```ini NAME = Unknwon Male = true ; Author's age Age = 21 GPA = 2.8 ; Embeded section [Embeded] ; Time data Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00 places = HangZhou,Boston ``` #### 名称映射器(Name Mapper) 为了节省您的时间并简化代码,本库支持类型为 [`NameMapper`](https://gowalker.org/gopkg.in/ini.v1#NameMapper) 的名称映射器,该映射器负责结构字段名与分区名和键名之间的映射。 目前有 2 款内置的映射器: - `AllCapsUnderscore`:该映射器将字段名转换至格式 `ALL_CAPS_UNDERSCORE` 后再去匹配分区名和键名。 - `TitleUnderscore`:该映射器将字段名转换至格式 `title_underscore` 后再去匹配分区名和键名。 使用方法: ```go type Info struct{ PackageName string } func main() { err = ini.MapToWithMapper(&Info{}, ini.TitleUnderscore, []byte("package_name=ini")) // ... cfg, err := ini.Load([]byte("PACKAGE_NAME=ini")) // ... info := new(Info) cfg.NameMapper = ini.AllCapsUnderscore err = cfg.MapTo(info) // ... } ``` 使用函数 `ini.ReflectFromWithMapper` 时也可应用相同的规则。 #### 值映射器(Value Mapper) 值映射器允许使用一个自定义函数自动展开值的具体内容,例如:运行时获取环境变量: ```go type Env struct { Foo string `ini:"foo"` } func main() { cfg, err := ini.Load([]byte("[env]\nfoo = ${MY_VAR}\n") cfg.ValueMapper = os.ExpandEnv // ... env := &Env{} err = cfg.Section("env").MapTo(env) } ``` 本例中,`env.Foo` 将会是运行时所获取到环境变量 `MY_VAR` 的值。 #### 映射/反射的其它说明 任何嵌入的结构都会被默认认作一个不同的分区,并且不会自动产生所谓的父子分区关联: ```go type Child struct { Age string } type Parent struct { Name string Child } type Config struct { City string Parent } ``` 示例配置文件: ```ini City = Boston [Parent] Name = Unknwon [Child] Age = 21 ``` 很好,但是,我就是要嵌入结构也在同一个分区。好吧,你爹是李刚! ```go type Child struct { Age string } type Parent struct { Name string Child `ini:"Parent"` } type Config struct { City string Parent } ``` 示例配置文件: ```ini City = Boston [Parent] Name = Unknwon Age = 21 ``` ## 获取帮助 - [API 文档](https://gowalker.org/gopkg.in/ini.v1) - [创建工单](https://github.com/go-ini/ini/issues/new) ## 常见问题 ### 字段 `BlockMode` 是什么? 默认情况下,本库会在您进行读写操作时采用锁机制来确保数据时间。但在某些情况下,您非常确定只进行读操作。此时,您可以通过设置 `cfg.BlockMode = false` 来将读操作提升大约 **50-70%** 的性能。 ### 为什么要写另一个 INI 解析库? 许多人都在使用我的 [goconfig](https://github.com/Unknwon/goconfig) 来完成对 INI 文件的操作,但我希望使用更加 Go 风格的代码。并且当您设置 `cfg.BlockMode = false` 时,会有大约 **10-30%** 的性能提升。 为了做出这些改变,我必须对 API 进行破坏,所以新开一个仓库是最安全的做法。除此之外,本库直接使用 `gopkg.in` 来进行版本化发布。(其实真相是导入路径更短了) ================================================ FILE: vendor/github.com/go-ini/ini/error.go ================================================ // Copyright 2016 Unknwon // // 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 ini import ( "fmt" ) type ErrDelimiterNotFound struct { Line string } func IsErrDelimiterNotFound(err error) bool { _, ok := err.(ErrDelimiterNotFound) return ok } func (err ErrDelimiterNotFound) Error() string { return fmt.Sprintf("key-value delimiter not found: %s", err.Line) } ================================================ FILE: vendor/github.com/go-ini/ini/file.go ================================================ // Copyright 2017 Unknwon // // 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 ini import ( "bytes" "errors" "fmt" "io" "io/ioutil" "os" "strings" "sync" ) // File represents a combination of a or more INI file(s) in memory. type File struct { options LoadOptions dataSources []dataSource // Should make things safe, but sometimes doesn't matter. BlockMode bool lock sync.RWMutex // To keep data in order. sectionList []string // Actual data is stored here. sections map[string]*Section NameMapper ValueMapper } // newFile initializes File object with given data sources. func newFile(dataSources []dataSource, opts LoadOptions) *File { return &File{ BlockMode: true, dataSources: dataSources, sections: make(map[string]*Section), sectionList: make([]string, 0, 10), options: opts, } } // Empty returns an empty file object. func Empty() *File { // Ignore error here, we sure our data is good. f, _ := Load([]byte("")) return f } // NewSection creates a new section. func (f *File) NewSection(name string) (*Section, error) { if len(name) == 0 { return nil, errors.New("error creating new section: empty section name") } else if f.options.Insensitive && name != DEFAULT_SECTION { name = strings.ToLower(name) } if f.BlockMode { f.lock.Lock() defer f.lock.Unlock() } if inSlice(name, f.sectionList) { return f.sections[name], nil } f.sectionList = append(f.sectionList, name) f.sections[name] = newSection(f, name) return f.sections[name], nil } // NewRawSection creates a new section with an unparseable body. func (f *File) NewRawSection(name, body string) (*Section, error) { section, err := f.NewSection(name) if err != nil { return nil, err } section.isRawSection = true section.rawBody = body return section, nil } // NewSections creates a list of sections. func (f *File) NewSections(names ...string) (err error) { for _, name := range names { if _, err = f.NewSection(name); err != nil { return err } } return nil } // GetSection returns section by given name. func (f *File) GetSection(name string) (*Section, error) { if len(name) == 0 { name = DEFAULT_SECTION } if f.options.Insensitive { name = strings.ToLower(name) } if f.BlockMode { f.lock.RLock() defer f.lock.RUnlock() } sec := f.sections[name] if sec == nil { return nil, fmt.Errorf("section '%s' does not exist", name) } return sec, nil } // Section assumes named section exists and returns a zero-value when not. func (f *File) Section(name string) *Section { sec, err := f.GetSection(name) if err != nil { // Note: It's OK here because the only possible error is empty section name, // but if it's empty, this piece of code won't be executed. sec, _ = f.NewSection(name) return sec } return sec } // Section returns list of Section. func (f *File) Sections() []*Section { sections := make([]*Section, len(f.sectionList)) for i := range f.sectionList { sections[i] = f.Section(f.sectionList[i]) } return sections } // ChildSections returns a list of child sections of given section name. func (f *File) ChildSections(name string) []*Section { return f.Section(name).ChildSections() } // SectionStrings returns list of section names. func (f *File) SectionStrings() []string { list := make([]string, len(f.sectionList)) copy(list, f.sectionList) return list } // DeleteSection deletes a section. func (f *File) DeleteSection(name string) { if f.BlockMode { f.lock.Lock() defer f.lock.Unlock() } if len(name) == 0 { name = DEFAULT_SECTION } for i, s := range f.sectionList { if s == name { f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...) delete(f.sections, name) return } } } func (f *File) reload(s dataSource) error { r, err := s.ReadCloser() if err != nil { return err } defer r.Close() return f.parse(r) } // Reload reloads and parses all data sources. func (f *File) Reload() (err error) { for _, s := range f.dataSources { if err = f.reload(s); err != nil { // In loose mode, we create an empty default section for nonexistent files. if os.IsNotExist(err) && f.options.Loose { f.parse(bytes.NewBuffer(nil)) continue } return err } } return nil } // Append appends one or more data sources and reloads automatically. func (f *File) Append(source interface{}, others ...interface{}) error { ds, err := parseDataSource(source) if err != nil { return err } f.dataSources = append(f.dataSources, ds) for _, s := range others { ds, err = parseDataSource(s) if err != nil { return err } f.dataSources = append(f.dataSources, ds) } return f.Reload() } func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { equalSign := "=" if PrettyFormat { equalSign = " = " } // Use buffer to make sure target is safe until finish encoding. buf := bytes.NewBuffer(nil) for i, sname := range f.sectionList { sec := f.Section(sname) if len(sec.Comment) > 0 { if sec.Comment[0] != '#' && sec.Comment[0] != ';' { sec.Comment = "; " + sec.Comment } else { sec.Comment = sec.Comment[:1] + " " + strings.TrimSpace(sec.Comment[1:]) } if _, err := buf.WriteString(sec.Comment + LineBreak); err != nil { return nil, err } } if i > 0 || DefaultHeader { if _, err := buf.WriteString("[" + sname + "]" + LineBreak); err != nil { return nil, err } } else { // Write nothing if default section is empty if len(sec.keyList) == 0 { continue } } if sec.isRawSection { if _, err := buf.WriteString(sec.rawBody); err != nil { return nil, err } if PrettySection { // Put a line between sections if _, err := buf.WriteString(LineBreak); err != nil { return nil, err } } continue } // Count and generate alignment length and buffer spaces using the // longest key. Keys may be modifed if they contain certain characters so // we need to take that into account in our calculation. alignLength := 0 if PrettyFormat { for _, kname := range sec.keyList { keyLength := len(kname) // First case will surround key by ` and second by """ if strings.ContainsAny(kname, "\"=:") { keyLength += 2 } else if strings.Contains(kname, "`") { keyLength += 6 } if keyLength > alignLength { alignLength = keyLength } } } alignSpaces := bytes.Repeat([]byte(" "), alignLength) KEY_LIST: for _, kname := range sec.keyList { key := sec.Key(kname) if len(key.Comment) > 0 { if len(indent) > 0 && sname != DEFAULT_SECTION { buf.WriteString(indent) } if key.Comment[0] != '#' && key.Comment[0] != ';' { key.Comment = "; " + key.Comment } else { key.Comment = key.Comment[:1] + " " + strings.TrimSpace(key.Comment[1:]) } if _, err := buf.WriteString(key.Comment + LineBreak); err != nil { return nil, err } } if len(indent) > 0 && sname != DEFAULT_SECTION { buf.WriteString(indent) } switch { case key.isAutoIncrement: kname = "-" case strings.ContainsAny(kname, "\"=:"): kname = "`" + kname + "`" case strings.Contains(kname, "`"): kname = `"""` + kname + `"""` } for _, val := range key.ValueWithShadows() { if _, err := buf.WriteString(kname); err != nil { return nil, err } if key.isBooleanType { if kname != sec.keyList[len(sec.keyList)-1] { buf.WriteString(LineBreak) } continue KEY_LIST } // Write out alignment spaces before "=" sign if PrettyFormat { buf.Write(alignSpaces[:alignLength-len(kname)]) } // In case key value contains "\n", "`", "\"", "#" or ";" if strings.ContainsAny(val, "\n`") { val = `"""` + val + `"""` } else if !f.options.IgnoreInlineComment && strings.ContainsAny(val, "#;") { val = "`" + val + "`" } if _, err := buf.WriteString(equalSign + val + LineBreak); err != nil { return nil, err } } for _, val := range key.nestedValues { if _, err := buf.WriteString(indent + " " + val + LineBreak); err != nil { return nil, err } } } if PrettySection { // Put a line between sections if _, err := buf.WriteString(LineBreak); err != nil { return nil, err } } } return buf, nil } // WriteToIndent writes content into io.Writer with given indention. // If PrettyFormat has been set to be true, // it will align "=" sign with spaces under each section. func (f *File) WriteToIndent(w io.Writer, indent string) (int64, error) { buf, err := f.writeToBuffer(indent) if err != nil { return 0, err } return buf.WriteTo(w) } // WriteTo writes file content into io.Writer. func (f *File) WriteTo(w io.Writer) (int64, error) { return f.WriteToIndent(w, "") } // SaveToIndent writes content to file system with given value indention. func (f *File) SaveToIndent(filename, indent string) error { // Note: Because we are truncating with os.Create, // so it's safer to save to a temporary file location and rename afte done. buf, err := f.writeToBuffer(indent) if err != nil { return err } return ioutil.WriteFile(filename, buf.Bytes(), 0666) } // SaveTo writes content to file system. func (f *File) SaveTo(filename string) error { return f.SaveToIndent(filename, "") } ================================================ FILE: vendor/github.com/go-ini/ini/ini.go ================================================ // Copyright 2014 Unknwon // // 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 ini provides INI file read and write functionality in Go. package ini import ( "bytes" "fmt" "io" "io/ioutil" "os" "regexp" "runtime" ) const ( // Name for default section. You can use this constant or the string literal. // In most of cases, an empty string is all you need to access the section. DEFAULT_SECTION = "DEFAULT" // Maximum allowed depth when recursively substituing variable names. _DEPTH_VALUES = 99 _VERSION = "1.32.1" ) // Version returns current package version literal. func Version() string { return _VERSION } var ( // Delimiter to determine or compose a new line. // This variable will be changed to "\r\n" automatically on Windows // at package init time. LineBreak = "\n" // Variable regexp pattern: %(variable)s varPattern = regexp.MustCompile(`%\(([^\)]+)\)s`) // Indicate whether to align "=" sign with spaces to produce pretty output // or reduce all possible spaces for compact format. PrettyFormat = true // Explicitly write DEFAULT section header DefaultHeader = false // Indicate whether to put a line between sections PrettySection = true ) func init() { if runtime.GOOS == "windows" { LineBreak = "\r\n" } } func inSlice(str string, s []string) bool { for _, v := range s { if str == v { return true } } return false } // dataSource is an interface that returns object which can be read and closed. type dataSource interface { ReadCloser() (io.ReadCloser, error) } // sourceFile represents an object that contains content on the local file system. type sourceFile struct { name string } func (s sourceFile) ReadCloser() (_ io.ReadCloser, err error) { return os.Open(s.name) } // sourceData represents an object that contains content in memory. type sourceData struct { data []byte } func (s *sourceData) ReadCloser() (io.ReadCloser, error) { return ioutil.NopCloser(bytes.NewReader(s.data)), nil } // sourceReadCloser represents an input stream with Close method. type sourceReadCloser struct { reader io.ReadCloser } func (s *sourceReadCloser) ReadCloser() (io.ReadCloser, error) { return s.reader, nil } func parseDataSource(source interface{}) (dataSource, error) { switch s := source.(type) { case string: return sourceFile{s}, nil case []byte: return &sourceData{s}, nil case io.ReadCloser: return &sourceReadCloser{s}, nil default: return nil, fmt.Errorf("error parsing data source: unknown type '%s'", s) } } type LoadOptions struct { // Loose indicates whether the parser should ignore nonexistent files or return error. Loose bool // Insensitive indicates whether the parser forces all section and key names to lowercase. Insensitive bool // IgnoreContinuation indicates whether to ignore continuation lines while parsing. IgnoreContinuation bool // IgnoreInlineComment indicates whether to ignore comments at the end of value and treat it as part of value. IgnoreInlineComment bool // AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing. // This type of keys are mostly used in my.cnf. AllowBooleanKeys bool // AllowShadows indicates whether to keep track of keys with same name under same section. AllowShadows bool // AllowNestedValues indicates whether to allow AWS-like nested values. // Docs: http://docs.aws.amazon.com/cli/latest/topic/config-vars.html#nested-values AllowNestedValues bool // UnescapeValueDoubleQuotes indicates whether to unescape double quotes inside value to regular format // when value is surrounded by double quotes, e.g. key="a \"value\"" => key=a "value" UnescapeValueDoubleQuotes bool // UnescapeValueCommentSymbols indicates to unescape comment symbols (\# and \;) inside value to regular format // when value is NOT surrounded by any quotes. // Note: UNSTABLE, behavior might change to only unescape inside double quotes but may noy necessary at all. UnescapeValueCommentSymbols bool // Some INI formats allow group blocks that store a block of raw content that doesn't otherwise // conform to key/value pairs. Specify the names of those blocks here. UnparseableSections []string } func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) { sources := make([]dataSource, len(others)+1) sources[0], err = parseDataSource(source) if err != nil { return nil, err } for i := range others { sources[i+1], err = parseDataSource(others[i]) if err != nil { return nil, err } } f := newFile(sources, opts) if err = f.Reload(); err != nil { return nil, err } return f, nil } // Load loads and parses from INI data sources. // Arguments can be mixed of file name with string type, or raw data in []byte. // It will return error if list contains nonexistent files. func Load(source interface{}, others ...interface{}) (*File, error) { return LoadSources(LoadOptions{}, source, others...) } // LooseLoad has exactly same functionality as Load function // except it ignores nonexistent files instead of returning error. func LooseLoad(source interface{}, others ...interface{}) (*File, error) { return LoadSources(LoadOptions{Loose: true}, source, others...) } // InsensitiveLoad has exactly same functionality as Load function // except it forces all section and key names to be lowercased. func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) { return LoadSources(LoadOptions{Insensitive: true}, source, others...) } // InsensitiveLoad has exactly same functionality as Load function // except it allows have shadow keys. func ShadowLoad(source interface{}, others ...interface{}) (*File, error) { return LoadSources(LoadOptions{AllowShadows: true}, source, others...) } ================================================ FILE: vendor/github.com/go-ini/ini/key.go ================================================ // Copyright 2014 Unknwon // // 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 ini import ( "bytes" "errors" "fmt" "strconv" "strings" "time" ) // Key represents a key under a section. type Key struct { s *Section Comment string name string value string isAutoIncrement bool isBooleanType bool isShadow bool shadows []*Key nestedValues []string } // newKey simply return a key object with given values. func newKey(s *Section, name, val string) *Key { return &Key{ s: s, name: name, value: val, } } func (k *Key) addShadow(val string) error { if k.isShadow { return errors.New("cannot add shadow to another shadow key") } else if k.isAutoIncrement || k.isBooleanType { return errors.New("cannot add shadow to auto-increment or boolean key") } shadow := newKey(k.s, k.name, val) shadow.isShadow = true k.shadows = append(k.shadows, shadow) return nil } // AddShadow adds a new shadow key to itself. func (k *Key) AddShadow(val string) error { if !k.s.f.options.AllowShadows { return errors.New("shadow key is not allowed") } return k.addShadow(val) } func (k *Key) addNestedValue(val string) error { if k.isAutoIncrement || k.isBooleanType { return errors.New("cannot add nested value to auto-increment or boolean key") } k.nestedValues = append(k.nestedValues, val) return nil } func (k *Key) AddNestedValue(val string) error { if !k.s.f.options.AllowNestedValues { return errors.New("nested value is not allowed") } return k.addNestedValue(val) } // ValueMapper represents a mapping function for values, e.g. os.ExpandEnv type ValueMapper func(string) string // Name returns name of key. func (k *Key) Name() string { return k.name } // Value returns raw value of key for performance purpose. func (k *Key) Value() string { return k.value } // ValueWithShadows returns raw values of key and its shadows if any. func (k *Key) ValueWithShadows() []string { if len(k.shadows) == 0 { return []string{k.value} } vals := make([]string, len(k.shadows)+1) vals[0] = k.value for i := range k.shadows { vals[i+1] = k.shadows[i].value } return vals } // NestedValues returns nested values stored in the key. // It is possible returned value is nil if no nested values stored in the key. func (k *Key) NestedValues() []string { return k.nestedValues } // transformValue takes a raw value and transforms to its final string. func (k *Key) transformValue(val string) string { if k.s.f.ValueMapper != nil { val = k.s.f.ValueMapper(val) } // Fail-fast if no indicate char found for recursive value if !strings.Contains(val, "%") { return val } for i := 0; i < _DEPTH_VALUES; i++ { vr := varPattern.FindString(val) if len(vr) == 0 { break } // Take off leading '%(' and trailing ')s'. noption := strings.TrimLeft(vr, "%(") noption = strings.TrimRight(noption, ")s") // Search in the same section. nk, err := k.s.GetKey(noption) if err != nil || k == nk { // Search again in default section. nk, _ = k.s.f.Section("").GetKey(noption) } // Substitute by new value and take off leading '%(' and trailing ')s'. val = strings.Replace(val, vr, nk.value, -1) } return val } // String returns string representation of value. func (k *Key) String() string { return k.transformValue(k.value) } // Validate accepts a validate function which can // return modifed result as key value. func (k *Key) Validate(fn func(string) string) string { return fn(k.String()) } // parseBool returns the boolean value represented by the string. // // It accepts 1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On, // 0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off. // Any other value returns an error. func parseBool(str string) (value bool, err error) { switch str { case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "y", "ON", "on", "On": return true, nil case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "n", "OFF", "off", "Off": return false, nil } return false, fmt.Errorf("parsing \"%s\": invalid syntax", str) } // Bool returns bool type value. func (k *Key) Bool() (bool, error) { return parseBool(k.String()) } // Float64 returns float64 type value. func (k *Key) Float64() (float64, error) { return strconv.ParseFloat(k.String(), 64) } // Int returns int type value. func (k *Key) Int() (int, error) { return strconv.Atoi(k.String()) } // Int64 returns int64 type value. func (k *Key) Int64() (int64, error) { return strconv.ParseInt(k.String(), 10, 64) } // Uint returns uint type valued. func (k *Key) Uint() (uint, error) { u, e := strconv.ParseUint(k.String(), 10, 64) return uint(u), e } // Uint64 returns uint64 type value. func (k *Key) Uint64() (uint64, error) { return strconv.ParseUint(k.String(), 10, 64) } // Duration returns time.Duration type value. func (k *Key) Duration() (time.Duration, error) { return time.ParseDuration(k.String()) } // TimeFormat parses with given format and returns time.Time type value. func (k *Key) TimeFormat(format string) (time.Time, error) { return time.Parse(format, k.String()) } // Time parses with RFC3339 format and returns time.Time type value. func (k *Key) Time() (time.Time, error) { return k.TimeFormat(time.RFC3339) } // MustString returns default value if key value is empty. func (k *Key) MustString(defaultVal string) string { val := k.String() if len(val) == 0 { k.value = defaultVal return defaultVal } return val } // MustBool always returns value without error, // it returns false if error occurs. func (k *Key) MustBool(defaultVal ...bool) bool { val, err := k.Bool() if len(defaultVal) > 0 && err != nil { k.value = strconv.FormatBool(defaultVal[0]) return defaultVal[0] } return val } // MustFloat64 always returns value without error, // it returns 0.0 if error occurs. func (k *Key) MustFloat64(defaultVal ...float64) float64 { val, err := k.Float64() if len(defaultVal) > 0 && err != nil { k.value = strconv.FormatFloat(defaultVal[0], 'f', -1, 64) return defaultVal[0] } return val } // MustInt always returns value without error, // it returns 0 if error occurs. func (k *Key) MustInt(defaultVal ...int) int { val, err := k.Int() if len(defaultVal) > 0 && err != nil { k.value = strconv.FormatInt(int64(defaultVal[0]), 10) return defaultVal[0] } return val } // MustInt64 always returns value without error, // it returns 0 if error occurs. func (k *Key) MustInt64(defaultVal ...int64) int64 { val, err := k.Int64() if len(defaultVal) > 0 && err != nil { k.value = strconv.FormatInt(defaultVal[0], 10) return defaultVal[0] } return val } // MustUint always returns value without error, // it returns 0 if error occurs. func (k *Key) MustUint(defaultVal ...uint) uint { val, err := k.Uint() if len(defaultVal) > 0 && err != nil { k.value = strconv.FormatUint(uint64(defaultVal[0]), 10) return defaultVal[0] } return val } // MustUint64 always returns value without error, // it returns 0 if error occurs. func (k *Key) MustUint64(defaultVal ...uint64) uint64 { val, err := k.Uint64() if len(defaultVal) > 0 && err != nil { k.value = strconv.FormatUint(defaultVal[0], 10) return defaultVal[0] } return val } // MustDuration always returns value without error, // it returns zero value if error occurs. func (k *Key) MustDuration(defaultVal ...time.Duration) time.Duration { val, err := k.Duration() if len(defaultVal) > 0 && err != nil { k.value = defaultVal[0].String() return defaultVal[0] } return val } // MustTimeFormat always parses with given format and returns value without error, // it returns zero value if error occurs. func (k *Key) MustTimeFormat(format string, defaultVal ...time.Time) time.Time { val, err := k.TimeFormat(format) if len(defaultVal) > 0 && err != nil { k.value = defaultVal[0].Format(format) return defaultVal[0] } return val } // MustTime always parses with RFC3339 format and returns value without error, // it returns zero value if error occurs. func (k *Key) MustTime(defaultVal ...time.Time) time.Time { return k.MustTimeFormat(time.RFC3339, defaultVal...) } // In always returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) In(defaultVal string, candidates []string) string { val := k.String() for _, cand := range candidates { if val == cand { return val } } return defaultVal } // InFloat64 always returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) InFloat64(defaultVal float64, candidates []float64) float64 { val := k.MustFloat64() for _, cand := range candidates { if val == cand { return val } } return defaultVal } // InInt always returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) InInt(defaultVal int, candidates []int) int { val := k.MustInt() for _, cand := range candidates { if val == cand { return val } } return defaultVal } // InInt64 always returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) InInt64(defaultVal int64, candidates []int64) int64 { val := k.MustInt64() for _, cand := range candidates { if val == cand { return val } } return defaultVal } // InUint always returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) InUint(defaultVal uint, candidates []uint) uint { val := k.MustUint() for _, cand := range candidates { if val == cand { return val } } return defaultVal } // InUint64 always returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) InUint64(defaultVal uint64, candidates []uint64) uint64 { val := k.MustUint64() for _, cand := range candidates { if val == cand { return val } } return defaultVal } // InTimeFormat always parses with given format and returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) InTimeFormat(format string, defaultVal time.Time, candidates []time.Time) time.Time { val := k.MustTimeFormat(format) for _, cand := range candidates { if val == cand { return val } } return defaultVal } // InTime always parses with RFC3339 format and returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) InTime(defaultVal time.Time, candidates []time.Time) time.Time { return k.InTimeFormat(time.RFC3339, defaultVal, candidates) } // RangeFloat64 checks if value is in given range inclusively, // and returns default value if it's not. func (k *Key) RangeFloat64(defaultVal, min, max float64) float64 { val := k.MustFloat64() if val < min || val > max { return defaultVal } return val } // RangeInt checks if value is in given range inclusively, // and returns default value if it's not. func (k *Key) RangeInt(defaultVal, min, max int) int { val := k.MustInt() if val < min || val > max { return defaultVal } return val } // RangeInt64 checks if value is in given range inclusively, // and returns default value if it's not. func (k *Key) RangeInt64(defaultVal, min, max int64) int64 { val := k.MustInt64() if val < min || val > max { return defaultVal } return val } // RangeTimeFormat checks if value with given format is in given range inclusively, // and returns default value if it's not. func (k *Key) RangeTimeFormat(format string, defaultVal, min, max time.Time) time.Time { val := k.MustTimeFormat(format) if val.Unix() < min.Unix() || val.Unix() > max.Unix() { return defaultVal } return val } // RangeTime checks if value with RFC3339 format is in given range inclusively, // and returns default value if it's not. func (k *Key) RangeTime(defaultVal, min, max time.Time) time.Time { return k.RangeTimeFormat(time.RFC3339, defaultVal, min, max) } // Strings returns list of string divided by given delimiter. func (k *Key) Strings(delim string) []string { str := k.String() if len(str) == 0 { return []string{} } runes := []rune(str) vals := make([]string, 0, 2) var buf bytes.Buffer escape := false idx := 0 for { if escape { escape = false if runes[idx] != '\\' && !strings.HasPrefix(string(runes[idx:]), delim) { buf.WriteRune('\\') } buf.WriteRune(runes[idx]) } else { if runes[idx] == '\\' { escape = true } else if strings.HasPrefix(string(runes[idx:]), delim) { idx += len(delim) - 1 vals = append(vals, strings.TrimSpace(buf.String())) buf.Reset() } else { buf.WriteRune(runes[idx]) } } idx += 1 if idx == len(runes) { break } } if buf.Len() > 0 { vals = append(vals, strings.TrimSpace(buf.String())) } return vals } // StringsWithShadows returns list of string divided by given delimiter. // Shadows will also be appended if any. func (k *Key) StringsWithShadows(delim string) []string { vals := k.ValueWithShadows() results := make([]string, 0, len(vals)*2) for i := range vals { if len(vals) == 0 { continue } results = append(results, strings.Split(vals[i], delim)...) } for i := range results { results[i] = k.transformValue(strings.TrimSpace(results[i])) } return results } // Float64s returns list of float64 divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Float64s(delim string) []float64 { vals, _ := k.parseFloat64s(k.Strings(delim), true, false) return vals } // Ints returns list of int divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Ints(delim string) []int { vals, _ := k.parseInts(k.Strings(delim), true, false) return vals } // Int64s returns list of int64 divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Int64s(delim string) []int64 { vals, _ := k.parseInt64s(k.Strings(delim), true, false) return vals } // Uints returns list of uint divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Uints(delim string) []uint { vals, _ := k.parseUints(k.Strings(delim), true, false) return vals } // Uint64s returns list of uint64 divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Uint64s(delim string) []uint64 { vals, _ := k.parseUint64s(k.Strings(delim), true, false) return vals } // TimesFormat parses with given format and returns list of time.Time divided by given delimiter. // Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). func (k *Key) TimesFormat(format, delim string) []time.Time { vals, _ := k.parseTimesFormat(format, k.Strings(delim), true, false) return vals } // Times parses with RFC3339 format and returns list of time.Time divided by given delimiter. // Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). func (k *Key) Times(delim string) []time.Time { return k.TimesFormat(time.RFC3339, delim) } // ValidFloat64s returns list of float64 divided by given delimiter. If some value is not float, then // it will not be included to result list. func (k *Key) ValidFloat64s(delim string) []float64 { vals, _ := k.parseFloat64s(k.Strings(delim), false, false) return vals } // ValidInts returns list of int divided by given delimiter. If some value is not integer, then it will // not be included to result list. func (k *Key) ValidInts(delim string) []int { vals, _ := k.parseInts(k.Strings(delim), false, false) return vals } // ValidInt64s returns list of int64 divided by given delimiter. If some value is not 64-bit integer, // then it will not be included to result list. func (k *Key) ValidInt64s(delim string) []int64 { vals, _ := k.parseInt64s(k.Strings(delim), false, false) return vals } // ValidUints returns list of uint divided by given delimiter. If some value is not unsigned integer, // then it will not be included to result list. func (k *Key) ValidUints(delim string) []uint { vals, _ := k.parseUints(k.Strings(delim), false, false) return vals } // ValidUint64s returns list of uint64 divided by given delimiter. If some value is not 64-bit unsigned // integer, then it will not be included to result list. func (k *Key) ValidUint64s(delim string) []uint64 { vals, _ := k.parseUint64s(k.Strings(delim), false, false) return vals } // ValidTimesFormat parses with given format and returns list of time.Time divided by given delimiter. func (k *Key) ValidTimesFormat(format, delim string) []time.Time { vals, _ := k.parseTimesFormat(format, k.Strings(delim), false, false) return vals } // ValidTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter. func (k *Key) ValidTimes(delim string) []time.Time { return k.ValidTimesFormat(time.RFC3339, delim) } // StrictFloat64s returns list of float64 divided by given delimiter or error on first invalid input. func (k *Key) StrictFloat64s(delim string) ([]float64, error) { return k.parseFloat64s(k.Strings(delim), false, true) } // StrictInts returns list of int divided by given delimiter or error on first invalid input. func (k *Key) StrictInts(delim string) ([]int, error) { return k.parseInts(k.Strings(delim), false, true) } // StrictInt64s returns list of int64 divided by given delimiter or error on first invalid input. func (k *Key) StrictInt64s(delim string) ([]int64, error) { return k.parseInt64s(k.Strings(delim), false, true) } // StrictUints returns list of uint divided by given delimiter or error on first invalid input. func (k *Key) StrictUints(delim string) ([]uint, error) { return k.parseUints(k.Strings(delim), false, true) } // StrictUint64s returns list of uint64 divided by given delimiter or error on first invalid input. func (k *Key) StrictUint64s(delim string) ([]uint64, error) { return k.parseUint64s(k.Strings(delim), false, true) } // StrictTimesFormat parses with given format and returns list of time.Time divided by given delimiter // or error on first invalid input. func (k *Key) StrictTimesFormat(format, delim string) ([]time.Time, error) { return k.parseTimesFormat(format, k.Strings(delim), false, true) } // StrictTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter // or error on first invalid input. func (k *Key) StrictTimes(delim string) ([]time.Time, error) { return k.StrictTimesFormat(time.RFC3339, delim) } // parseFloat64s transforms strings to float64s. func (k *Key) parseFloat64s(strs []string, addInvalid, returnOnInvalid bool) ([]float64, error) { vals := make([]float64, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseFloat(str, 64) if err != nil && returnOnInvalid { return nil, err } if err == nil || addInvalid { vals = append(vals, val) } } return vals, nil } // parseInts transforms strings to ints. func (k *Key) parseInts(strs []string, addInvalid, returnOnInvalid bool) ([]int, error) { vals := make([]int, 0, len(strs)) for _, str := range strs { val, err := strconv.Atoi(str) if err != nil && returnOnInvalid { return nil, err } if err == nil || addInvalid { vals = append(vals, val) } } return vals, nil } // parseInt64s transforms strings to int64s. func (k *Key) parseInt64s(strs []string, addInvalid, returnOnInvalid bool) ([]int64, error) { vals := make([]int64, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseInt(str, 10, 64) if err != nil && returnOnInvalid { return nil, err } if err == nil || addInvalid { vals = append(vals, val) } } return vals, nil } // parseUints transforms strings to uints. func (k *Key) parseUints(strs []string, addInvalid, returnOnInvalid bool) ([]uint, error) { vals := make([]uint, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseUint(str, 10, 0) if err != nil && returnOnInvalid { return nil, err } if err == nil || addInvalid { vals = append(vals, uint(val)) } } return vals, nil } // parseUint64s transforms strings to uint64s. func (k *Key) parseUint64s(strs []string, addInvalid, returnOnInvalid bool) ([]uint64, error) { vals := make([]uint64, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseUint(str, 10, 64) if err != nil && returnOnInvalid { return nil, err } if err == nil || addInvalid { vals = append(vals, val) } } return vals, nil } // parseTimesFormat transforms strings to times in given format. func (k *Key) parseTimesFormat(format string, strs []string, addInvalid, returnOnInvalid bool) ([]time.Time, error) { vals := make([]time.Time, 0, len(strs)) for _, str := range strs { val, err := time.Parse(format, str) if err != nil && returnOnInvalid { return nil, err } if err == nil || addInvalid { vals = append(vals, val) } } return vals, nil } // SetValue changes key value. func (k *Key) SetValue(v string) { if k.s.f.BlockMode { k.s.f.lock.Lock() defer k.s.f.lock.Unlock() } k.value = v k.s.keysHash[k.name] = v } ================================================ FILE: vendor/github.com/go-ini/ini/parser.go ================================================ // Copyright 2015 Unknwon // // 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 ini import ( "bufio" "bytes" "fmt" "io" "strconv" "strings" "unicode" ) type tokenType int const ( _TOKEN_INVALID tokenType = iota _TOKEN_COMMENT _TOKEN_SECTION _TOKEN_KEY ) type parser struct { buf *bufio.Reader isEOF bool count int comment *bytes.Buffer } func newParser(r io.Reader) *parser { return &parser{ buf: bufio.NewReader(r), count: 1, comment: &bytes.Buffer{}, } } // BOM handles header of UTF-8, UTF-16 LE and UTF-16 BE's BOM format. // http://en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_order_marks_by_encoding func (p *parser) BOM() error { mask, err := p.buf.Peek(2) if err != nil && err != io.EOF { return err } else if len(mask) < 2 { return nil } switch { case mask[0] == 254 && mask[1] == 255: fallthrough case mask[0] == 255 && mask[1] == 254: p.buf.Read(mask) case mask[0] == 239 && mask[1] == 187: mask, err := p.buf.Peek(3) if err != nil && err != io.EOF { return err } else if len(mask) < 3 { return nil } if mask[2] == 191 { p.buf.Read(mask) } } return nil } func (p *parser) readUntil(delim byte) ([]byte, error) { data, err := p.buf.ReadBytes(delim) if err != nil { if err == io.EOF { p.isEOF = true } else { return nil, err } } return data, nil } func cleanComment(in []byte) ([]byte, bool) { i := bytes.IndexAny(in, "#;") if i == -1 { return nil, false } return in[i:], true } func readKeyName(in []byte) (string, int, error) { line := string(in) // Check if key name surrounded by quotes. var keyQuote string if line[0] == '"' { if len(line) > 6 && string(line[0:3]) == `"""` { keyQuote = `"""` } else { keyQuote = `"` } } else if line[0] == '`' { keyQuote = "`" } // Get out key name endIdx := -1 if len(keyQuote) > 0 { startIdx := len(keyQuote) // FIXME: fail case -> """"""name"""=value pos := strings.Index(line[startIdx:], keyQuote) if pos == -1 { return "", -1, fmt.Errorf("missing closing key quote: %s", line) } pos += startIdx // Find key-value delimiter i := strings.IndexAny(line[pos+startIdx:], "=:") if i < 0 { return "", -1, ErrDelimiterNotFound{line} } endIdx = pos + i return strings.TrimSpace(line[startIdx:pos]), endIdx + startIdx + 1, nil } endIdx = strings.IndexAny(line, "=:") if endIdx < 0 { return "", -1, ErrDelimiterNotFound{line} } return strings.TrimSpace(line[0:endIdx]), endIdx + 1, nil } func (p *parser) readMultilines(line, val, valQuote string) (string, error) { for { data, err := p.readUntil('\n') if err != nil { return "", err } next := string(data) pos := strings.LastIndex(next, valQuote) if pos > -1 { val += next[:pos] comment, has := cleanComment([]byte(next[pos:])) if has { p.comment.Write(bytes.TrimSpace(comment)) } break } val += next if p.isEOF { return "", fmt.Errorf("missing closing key quote from '%s' to '%s'", line, next) } } return val, nil } func (p *parser) readContinuationLines(val string) (string, error) { for { data, err := p.readUntil('\n') if err != nil { return "", err } next := strings.TrimSpace(string(data)) if len(next) == 0 { break } val += next if val[len(val)-1] != '\\' { break } val = val[:len(val)-1] } return val, nil } // hasSurroundedQuote check if and only if the first and last characters // are quotes \" or \'. // It returns false if any other parts also contain same kind of quotes. func hasSurroundedQuote(in string, quote byte) bool { return len(in) >= 2 && in[0] == quote && in[len(in)-1] == quote && strings.IndexByte(in[1:], quote) == len(in)-2 } func (p *parser) readValue(in []byte, ignoreContinuation, ignoreInlineComment, unescapeValueDoubleQuotes, unescapeValueCommentSymbols bool) (string, error) { line := strings.TrimLeftFunc(string(in), unicode.IsSpace) if len(line) == 0 { return "", nil } var valQuote string if len(line) > 3 && string(line[0:3]) == `"""` { valQuote = `"""` } else if line[0] == '`' { valQuote = "`" } else if unescapeValueDoubleQuotes && line[0] == '"' { valQuote = `"` } if len(valQuote) > 0 { startIdx := len(valQuote) pos := strings.LastIndex(line[startIdx:], valQuote) // Check for multi-line value if pos == -1 { return p.readMultilines(line, line[startIdx:], valQuote) } if unescapeValueDoubleQuotes && valQuote == `"` { return strings.Replace(line[startIdx:pos+startIdx], `\"`, `"`, -1), nil } return line[startIdx : pos+startIdx], nil } // Won't be able to reach here if value only contains whitespace line = strings.TrimSpace(line) // Check continuation lines when desired if !ignoreContinuation && line[len(line)-1] == '\\' { return p.readContinuationLines(line[:len(line)-1]) } // Check if ignore inline comment if !ignoreInlineComment { i := strings.IndexAny(line, "#;") if i > -1 { p.comment.WriteString(line[i:]) line = strings.TrimSpace(line[:i]) } } // Trim single and double quotes if hasSurroundedQuote(line, '\'') || hasSurroundedQuote(line, '"') { line = line[1 : len(line)-1] } else if len(valQuote) == 0 && unescapeValueCommentSymbols { if strings.Contains(line, `\;`) { line = strings.Replace(line, `\;`, ";", -1) } if strings.Contains(line, `\#`) { line = strings.Replace(line, `\#`, "#", -1) } } return line, nil } // parse parses data through an io.Reader. func (f *File) parse(reader io.Reader) (err error) { p := newParser(reader) if err = p.BOM(); err != nil { return fmt.Errorf("BOM: %v", err) } // Ignore error because default section name is never empty string. name := DEFAULT_SECTION if f.options.Insensitive { name = strings.ToLower(DEFAULT_SECTION) } section, _ := f.NewSection(name) // This "last" is not strictly equivalent to "previous one" if current key is not the first nested key var isLastValueEmpty bool var lastRegularKey *Key var line []byte var inUnparseableSection bool for !p.isEOF { line, err = p.readUntil('\n') if err != nil { return err } if f.options.AllowNestedValues && isLastValueEmpty && len(line) > 0 { if line[0] == ' ' || line[0] == '\t' { lastRegularKey.addNestedValue(string(bytes.TrimSpace(line))) continue } } line = bytes.TrimLeftFunc(line, unicode.IsSpace) if len(line) == 0 { continue } // Comments if line[0] == '#' || line[0] == ';' { // Note: we do not care ending line break, // it is needed for adding second line, // so just clean it once at the end when set to value. p.comment.Write(line) continue } // Section if line[0] == '[' { // Read to the next ']' (TODO: support quoted strings) // TODO(unknwon): use LastIndexByte when stop supporting Go1.4 closeIdx := bytes.LastIndex(line, []byte("]")) if closeIdx == -1 { return fmt.Errorf("unclosed section: %s", line) } name := string(line[1:closeIdx]) section, err = f.NewSection(name) if err != nil { return err } comment, has := cleanComment(line[closeIdx+1:]) if has { p.comment.Write(comment) } section.Comment = strings.TrimSpace(p.comment.String()) // Reset aotu-counter and comments p.comment.Reset() p.count = 1 inUnparseableSection = false for i := range f.options.UnparseableSections { if f.options.UnparseableSections[i] == name || (f.options.Insensitive && strings.ToLower(f.options.UnparseableSections[i]) == strings.ToLower(name)) { inUnparseableSection = true continue } } continue } if inUnparseableSection { section.isRawSection = true section.rawBody += string(line) continue } kname, offset, err := readKeyName(line) if err != nil { // Treat as boolean key when desired, and whole line is key name. if IsErrDelimiterNotFound(err) && f.options.AllowBooleanKeys { kname, err := p.readValue(line, f.options.IgnoreContinuation, f.options.IgnoreInlineComment, f.options.UnescapeValueDoubleQuotes, f.options.UnescapeValueCommentSymbols) if err != nil { return err } key, err := section.NewBooleanKey(kname) if err != nil { return err } key.Comment = strings.TrimSpace(p.comment.String()) p.comment.Reset() continue } return err } // Auto increment. isAutoIncr := false if kname == "-" { isAutoIncr = true kname = "#" + strconv.Itoa(p.count) p.count++ } value, err := p.readValue(line[offset:], f.options.IgnoreContinuation, f.options.IgnoreInlineComment, f.options.UnescapeValueDoubleQuotes, f.options.UnescapeValueCommentSymbols) if err != nil { return err } isLastValueEmpty = len(value) == 0 key, err := section.NewKey(kname, value) if err != nil { return err } key.isAutoIncrement = isAutoIncr key.Comment = strings.TrimSpace(p.comment.String()) p.comment.Reset() lastRegularKey = key } return nil } ================================================ FILE: vendor/github.com/go-ini/ini/section.go ================================================ // Copyright 2014 Unknwon // // 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 ini import ( "errors" "fmt" "strings" ) // Section represents a config section. type Section struct { f *File Comment string name string keys map[string]*Key keyList []string keysHash map[string]string isRawSection bool rawBody string } func newSection(f *File, name string) *Section { return &Section{ f: f, name: name, keys: make(map[string]*Key), keyList: make([]string, 0, 10), keysHash: make(map[string]string), } } // Name returns name of Section. func (s *Section) Name() string { return s.name } // Body returns rawBody of Section if the section was marked as unparseable. // It still follows the other rules of the INI format surrounding leading/trailing whitespace. func (s *Section) Body() string { return strings.TrimSpace(s.rawBody) } // SetBody updates body content only if section is raw. func (s *Section) SetBody(body string) { if !s.isRawSection { return } s.rawBody = body } // NewKey creates a new key to given section. func (s *Section) NewKey(name, val string) (*Key, error) { if len(name) == 0 { return nil, errors.New("error creating new key: empty key name") } else if s.f.options.Insensitive { name = strings.ToLower(name) } if s.f.BlockMode { s.f.lock.Lock() defer s.f.lock.Unlock() } if inSlice(name, s.keyList) { if s.f.options.AllowShadows { if err := s.keys[name].addShadow(val); err != nil { return nil, err } } else { s.keys[name].value = val } return s.keys[name], nil } s.keyList = append(s.keyList, name) s.keys[name] = newKey(s, name, val) s.keysHash[name] = val return s.keys[name], nil } // NewBooleanKey creates a new boolean type key to given section. func (s *Section) NewBooleanKey(name string) (*Key, error) { key, err := s.NewKey(name, "true") if err != nil { return nil, err } key.isBooleanType = true return key, nil } // GetKey returns key in section by given name. func (s *Section) GetKey(name string) (*Key, error) { // FIXME: change to section level lock? if s.f.BlockMode { s.f.lock.RLock() } if s.f.options.Insensitive { name = strings.ToLower(name) } key := s.keys[name] if s.f.BlockMode { s.f.lock.RUnlock() } if key == nil { // Check if it is a child-section. sname := s.name for { if i := strings.LastIndex(sname, "."); i > -1 { sname = sname[:i] sec, err := s.f.GetSection(sname) if err != nil { continue } return sec.GetKey(name) } else { break } } return nil, fmt.Errorf("error when getting key of section '%s': key '%s' not exists", s.name, name) } return key, nil } // HasKey returns true if section contains a key with given name. func (s *Section) HasKey(name string) bool { key, _ := s.GetKey(name) return key != nil } // Haskey is a backwards-compatible name for HasKey. // TODO: delete me in v2 func (s *Section) Haskey(name string) bool { return s.HasKey(name) } // HasValue returns true if section contains given raw value. func (s *Section) HasValue(value string) bool { if s.f.BlockMode { s.f.lock.RLock() defer s.f.lock.RUnlock() } for _, k := range s.keys { if value == k.value { return true } } return false } // Key assumes named Key exists in section and returns a zero-value when not. func (s *Section) Key(name string) *Key { key, err := s.GetKey(name) if err != nil { // It's OK here because the only possible error is empty key name, // but if it's empty, this piece of code won't be executed. key, _ = s.NewKey(name, "") return key } return key } // Keys returns list of keys of section. func (s *Section) Keys() []*Key { keys := make([]*Key, len(s.keyList)) for i := range s.keyList { keys[i] = s.Key(s.keyList[i]) } return keys } // ParentKeys returns list of keys of parent section. func (s *Section) ParentKeys() []*Key { var parentKeys []*Key sname := s.name for { if i := strings.LastIndex(sname, "."); i > -1 { sname = sname[:i] sec, err := s.f.GetSection(sname) if err != nil { continue } parentKeys = append(parentKeys, sec.Keys()...) } else { break } } return parentKeys } // KeyStrings returns list of key names of section. func (s *Section) KeyStrings() []string { list := make([]string, len(s.keyList)) copy(list, s.keyList) return list } // KeysHash returns keys hash consisting of names and values. func (s *Section) KeysHash() map[string]string { if s.f.BlockMode { s.f.lock.RLock() defer s.f.lock.RUnlock() } hash := map[string]string{} for key, value := range s.keysHash { hash[key] = value } return hash } // DeleteKey deletes a key from section. func (s *Section) DeleteKey(name string) { if s.f.BlockMode { s.f.lock.Lock() defer s.f.lock.Unlock() } for i, k := range s.keyList { if k == name { s.keyList = append(s.keyList[:i], s.keyList[i+1:]...) delete(s.keys, name) return } } } // ChildSections returns a list of child sections of current section. // For example, "[parent.child1]" and "[parent.child12]" are child sections // of section "[parent]". func (s *Section) ChildSections() []*Section { prefix := s.name + "." children := make([]*Section, 0, 3) for _, name := range s.f.sectionList { if strings.HasPrefix(name, prefix) { children = append(children, s.f.sections[name]) } } return children } ================================================ FILE: vendor/github.com/go-ini/ini/struct.go ================================================ // Copyright 2014 Unknwon // // 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 ini import ( "bytes" "errors" "fmt" "reflect" "strings" "time" "unicode" ) // NameMapper represents a ini tag name mapper. type NameMapper func(string) string // Built-in name getters. var ( // AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE. AllCapsUnderscore NameMapper = func(raw string) string { newstr := make([]rune, 0, len(raw)) for i, chr := range raw { if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { if i > 0 { newstr = append(newstr, '_') } } newstr = append(newstr, unicode.ToUpper(chr)) } return string(newstr) } // TitleUnderscore converts to format title_underscore. TitleUnderscore NameMapper = func(raw string) string { newstr := make([]rune, 0, len(raw)) for i, chr := range raw { if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { if i > 0 { newstr = append(newstr, '_') } chr -= ('A' - 'a') } newstr = append(newstr, chr) } return string(newstr) } ) func (s *Section) parseFieldName(raw, actual string) string { if len(actual) > 0 { return actual } if s.f.NameMapper != nil { return s.f.NameMapper(raw) } return raw } func parseDelim(actual string) string { if len(actual) > 0 { return actual } return "," } var reflectTime = reflect.TypeOf(time.Now()).Kind() // setSliceWithProperType sets proper values to slice based on its type. func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error { var strs []string if allowShadow { strs = key.StringsWithShadows(delim) } else { strs = key.Strings(delim) } numVals := len(strs) if numVals == 0 { return nil } var vals interface{} var err error sliceOf := field.Type().Elem().Kind() switch sliceOf { case reflect.String: vals = strs case reflect.Int: vals, err = key.parseInts(strs, true, false) case reflect.Int64: vals, err = key.parseInt64s(strs, true, false) case reflect.Uint: vals, err = key.parseUints(strs, true, false) case reflect.Uint64: vals, err = key.parseUint64s(strs, true, false) case reflect.Float64: vals, err = key.parseFloat64s(strs, true, false) case reflectTime: vals, err = key.parseTimesFormat(time.RFC3339, strs, true, false) default: return fmt.Errorf("unsupported type '[]%s'", sliceOf) } if err != nil && isStrict { return err } slice := reflect.MakeSlice(field.Type(), numVals, numVals) for i := 0; i < numVals; i++ { switch sliceOf { case reflect.String: slice.Index(i).Set(reflect.ValueOf(vals.([]string)[i])) case reflect.Int: slice.Index(i).Set(reflect.ValueOf(vals.([]int)[i])) case reflect.Int64: slice.Index(i).Set(reflect.ValueOf(vals.([]int64)[i])) case reflect.Uint: slice.Index(i).Set(reflect.ValueOf(vals.([]uint)[i])) case reflect.Uint64: slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i])) case reflect.Float64: slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i])) case reflectTime: slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i])) } } field.Set(slice) return nil } func wrapStrictError(err error, isStrict bool) error { if isStrict { return err } return nil } // setWithProperType sets proper value to field based on its type, // but it does not return error for failing parsing, // because we want to use default value that is already assigned to strcut. func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error { switch t.Kind() { case reflect.String: if len(key.String()) == 0 { return nil } field.SetString(key.String()) case reflect.Bool: boolVal, err := key.Bool() if err != nil { return wrapStrictError(err, isStrict) } field.SetBool(boolVal) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: durationVal, err := key.Duration() // Skip zero value if err == nil && int64(durationVal) > 0 { field.Set(reflect.ValueOf(durationVal)) return nil } intVal, err := key.Int64() if err != nil { return wrapStrictError(err, isStrict) } field.SetInt(intVal) // byte is an alias for uint8, so supporting uint8 breaks support for byte case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: durationVal, err := key.Duration() // Skip zero value if err == nil && int(durationVal) > 0 { field.Set(reflect.ValueOf(durationVal)) return nil } uintVal, err := key.Uint64() if err != nil { return wrapStrictError(err, isStrict) } field.SetUint(uintVal) case reflect.Float32, reflect.Float64: floatVal, err := key.Float64() if err != nil { return wrapStrictError(err, isStrict) } field.SetFloat(floatVal) case reflectTime: timeVal, err := key.Time() if err != nil { return wrapStrictError(err, isStrict) } field.Set(reflect.ValueOf(timeVal)) case reflect.Slice: return setSliceWithProperType(key, field, delim, allowShadow, isStrict) default: return fmt.Errorf("unsupported type '%s'", t) } return nil } func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool) { opts := strings.SplitN(tag, ",", 3) rawName = opts[0] if len(opts) > 1 { omitEmpty = opts[1] == "omitempty" } if len(opts) > 2 { allowShadow = opts[2] == "allowshadow" } return rawName, omitEmpty, allowShadow } func (s *Section) mapTo(val reflect.Value, isStrict bool) error { if val.Kind() == reflect.Ptr { val = val.Elem() } typ := val.Type() for i := 0; i < typ.NumField(); i++ { field := val.Field(i) tpField := typ.Field(i) tag := tpField.Tag.Get("ini") if tag == "-" { continue } rawName, _, allowShadow := parseTagOptions(tag) fieldName := s.parseFieldName(tpField.Name, rawName) if len(fieldName) == 0 || !field.CanSet() { continue } isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous isStruct := tpField.Type.Kind() == reflect.Struct if isAnonymous { field.Set(reflect.New(tpField.Type.Elem())) } if isAnonymous || isStruct { if sec, err := s.f.GetSection(fieldName); err == nil { if err = sec.mapTo(field, isStrict); err != nil { return fmt.Errorf("error mapping field(%s): %v", fieldName, err) } continue } } if key, err := s.GetKey(fieldName); err == nil { delim := parseDelim(tpField.Tag.Get("delim")) if err = setWithProperType(tpField.Type, key, field, delim, allowShadow, isStrict); err != nil { return fmt.Errorf("error mapping field(%s): %v", fieldName, err) } } } return nil } // MapTo maps section to given struct. func (s *Section) MapTo(v interface{}) error { typ := reflect.TypeOf(v) val := reflect.ValueOf(v) if typ.Kind() == reflect.Ptr { typ = typ.Elem() val = val.Elem() } else { return errors.New("cannot map to non-pointer struct") } return s.mapTo(val, false) } // MapTo maps section to given struct in strict mode, // which returns all possible error including value parsing error. func (s *Section) StrictMapTo(v interface{}) error { typ := reflect.TypeOf(v) val := reflect.ValueOf(v) if typ.Kind() == reflect.Ptr { typ = typ.Elem() val = val.Elem() } else { return errors.New("cannot map to non-pointer struct") } return s.mapTo(val, true) } // MapTo maps file to given struct. func (f *File) MapTo(v interface{}) error { return f.Section("").MapTo(v) } // MapTo maps file to given struct in strict mode, // which returns all possible error including value parsing error. func (f *File) StrictMapTo(v interface{}) error { return f.Section("").StrictMapTo(v) } // MapTo maps data sources to given struct with name mapper. func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { cfg, err := Load(source, others...) if err != nil { return err } cfg.NameMapper = mapper return cfg.MapTo(v) } // StrictMapToWithMapper maps data sources to given struct with name mapper in strict mode, // which returns all possible error including value parsing error. func StrictMapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { cfg, err := Load(source, others...) if err != nil { return err } cfg.NameMapper = mapper return cfg.StrictMapTo(v) } // MapTo maps data sources to given struct. func MapTo(v, source interface{}, others ...interface{}) error { return MapToWithMapper(v, nil, source, others...) } // StrictMapTo maps data sources to given struct in strict mode, // which returns all possible error including value parsing error. func StrictMapTo(v, source interface{}, others ...interface{}) error { return StrictMapToWithMapper(v, nil, source, others...) } // reflectSliceWithProperType does the opposite thing as setSliceWithProperType. func reflectSliceWithProperType(key *Key, field reflect.Value, delim string) error { slice := field.Slice(0, field.Len()) if field.Len() == 0 { return nil } var buf bytes.Buffer sliceOf := field.Type().Elem().Kind() for i := 0; i < field.Len(); i++ { switch sliceOf { case reflect.String: buf.WriteString(slice.Index(i).String()) case reflect.Int, reflect.Int64: buf.WriteString(fmt.Sprint(slice.Index(i).Int())) case reflect.Uint, reflect.Uint64: buf.WriteString(fmt.Sprint(slice.Index(i).Uint())) case reflect.Float64: buf.WriteString(fmt.Sprint(slice.Index(i).Float())) case reflectTime: buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339)) default: return fmt.Errorf("unsupported type '[]%s'", sliceOf) } buf.WriteString(delim) } key.SetValue(buf.String()[:buf.Len()-1]) return nil } // reflectWithProperType does the opposite thing as setWithProperType. func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error { switch t.Kind() { case reflect.String: key.SetValue(field.String()) case reflect.Bool: key.SetValue(fmt.Sprint(field.Bool())) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: key.SetValue(fmt.Sprint(field.Int())) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: key.SetValue(fmt.Sprint(field.Uint())) case reflect.Float32, reflect.Float64: key.SetValue(fmt.Sprint(field.Float())) case reflectTime: key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339))) case reflect.Slice: return reflectSliceWithProperType(key, field, delim) default: return fmt.Errorf("unsupported type '%s'", t) } return nil } // CR: copied from encoding/json/encode.go with modifications of time.Time support. // TODO: add more test coverage. func isEmptyValue(v reflect.Value) bool { switch v.Kind() { case reflect.Array, reflect.Map, reflect.Slice, reflect.String: return v.Len() == 0 case reflect.Bool: return !v.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflect.Interface, reflect.Ptr: return v.IsNil() case reflectTime: t, ok := v.Interface().(time.Time) return ok && t.IsZero() } return false } func (s *Section) reflectFrom(val reflect.Value) error { if val.Kind() == reflect.Ptr { val = val.Elem() } typ := val.Type() for i := 0; i < typ.NumField(); i++ { field := val.Field(i) tpField := typ.Field(i) tag := tpField.Tag.Get("ini") if tag == "-" { continue } opts := strings.SplitN(tag, ",", 2) if len(opts) == 2 && opts[1] == "omitempty" && isEmptyValue(field) { continue } fieldName := s.parseFieldName(tpField.Name, opts[0]) if len(fieldName) == 0 || !field.CanSet() { continue } if (tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous) || (tpField.Type.Kind() == reflect.Struct && tpField.Type.Name() != "Time") { // Note: The only error here is section doesn't exist. sec, err := s.f.GetSection(fieldName) if err != nil { // Note: fieldName can never be empty here, ignore error. sec, _ = s.f.NewSection(fieldName) } // Add comment from comment tag if len(sec.Comment) == 0 { sec.Comment = tpField.Tag.Get("comment") } if err = sec.reflectFrom(field); err != nil { return fmt.Errorf("error reflecting field (%s): %v", fieldName, err) } continue } // Note: Same reason as secion. key, err := s.GetKey(fieldName) if err != nil { key, _ = s.NewKey(fieldName, "") } // Add comment from comment tag if len(key.Comment) == 0 { key.Comment = tpField.Tag.Get("comment") } if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil { return fmt.Errorf("error reflecting field (%s): %v", fieldName, err) } } return nil } // ReflectFrom reflects secion from given struct. func (s *Section) ReflectFrom(v interface{}) error { typ := reflect.TypeOf(v) val := reflect.ValueOf(v) if typ.Kind() == reflect.Ptr { typ = typ.Elem() val = val.Elem() } else { return errors.New("cannot reflect from non-pointer struct") } return s.reflectFrom(val) } // ReflectFrom reflects file from given struct. func (f *File) ReflectFrom(v interface{}) error { return f.Section("").ReflectFrom(v) } // ReflectFrom reflects data sources from given struct with name mapper. func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error { cfg.NameMapper = mapper return cfg.ReflectFrom(v) } // ReflectFrom reflects data sources from given struct. func ReflectFrom(cfg *File, v interface{}) error { return ReflectFromWithMapper(cfg, v, nil) } ================================================ FILE: vendor/github.com/go-openapi/jsonpointer/.editorconfig ================================================ # top-most EditorConfig file root = true # Unix-style newlines with a newline ending every file [*] end_of_line = lf insert_final_newline = true indent_style = space indent_size = 2 trim_trailing_whitespace = true # Set default charset [*.{js,py,go,scala,rb,java,html,css,less,sass,md}] charset = utf-8 # Tab indentation (no size specified) [*.go] indent_style = tab [*.md] trim_trailing_whitespace = false # Matches the exact files either package.json or .travis.yml [{package.json,.travis.yml}] indent_style = space indent_size = 2 ================================================ FILE: vendor/github.com/go-openapi/jsonpointer/.gitignore ================================================ secrets.yml ================================================ FILE: vendor/github.com/go-openapi/jsonpointer/.travis.yml ================================================ after_success: - bash <(curl -s https://codecov.io/bash) go: - '1.9' - 1.10.x - 1.11.x install: - go get -u github.com/stretchr/testify/assert - go get -u github.com/go-openapi/swag language: go notifications: slack: secure: a5VgoiwB1G/AZqzmephPZIhEB9avMlsWSlVnM1dSAtYAwdrQHGTQxAmpOxYIoSPDhWNN5bfZmjd29++UlTwLcHSR+e0kJhH6IfDlsHj/HplNCJ9tyI0zYc7XchtdKgeMxMzBKCzgwFXGSbQGydXTliDNBo0HOzmY3cou/daMFTP60K+offcjS+3LRAYb1EroSRXZqrk1nuF/xDL3792DZUdPMiFR/L/Df6y74D6/QP4sTkTDFQitz4Wy/7jbsfj8dG6qK2zivgV6/l+w4OVjFkxVpPXogDWY10vVXNVynqxfJ7to2d1I9lNCHE2ilBCkWMIPdyJF7hjF8pKW+82yP4EzRh0vu8Xn0HT5MZpQxdRY/YMxNrWaG7SxsoEaO4q5uhgdzAqLYY3TRa7MjIK+7Ur+aqOeTXn6OKwVi0CjvZ6mIU3WUKSwiwkFZMbjRAkSb5CYwMEfGFO/z964xz83qGt6WAtBXNotqCQpTIiKtDHQeLOMfksHImCg6JLhQcWBVxamVgu0G3Pdh8Y6DyPnxraXY95+QDavbjqv7TeYT9T/FNnrkXaTTK0s4iWE5H4ACU0Qvz0wUYgfQrZv0/Hp7V17+rabUwnzYySHCy9SWX/7OV9Cfh31iMp9ZIffr76xmmThtOEqs8TrTtU6BWI3rWwvA9cXQipZTVtL0oswrGw= script: - go test -v -race -cover -coverprofile=coverage.txt -covermode=atomic ./... ================================================ FILE: vendor/github.com/go-openapi/jsonpointer/CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at ivan+abuse@flanders.co.nz. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: vendor/github.com/go-openapi/jsonpointer/LICENSE ================================================ 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. ================================================ FILE: vendor/github.com/go-openapi/jsonpointer/README.md ================================================ # gojsonpointer [![Build Status](https://travis-ci.org/go-openapi/jsonpointer.svg?branch=master)](https://travis-ci.org/go-openapi/jsonpointer) [![codecov](https://codecov.io/gh/go-openapi/jsonpointer/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonpointer) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) [![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonpointer/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/jsonpointer?status.svg)](http://godoc.org/github.com/go-openapi/jsonpointer) An implementation of JSON Pointer - Go language ## Status Completed YES Tested YES ## References http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07 ### Note The 4.Evaluation part of the previous reference, starting with 'If the currently referenced value is a JSON array, the reference token MUST contain either...' is not implemented. ================================================ FILE: vendor/github.com/go-openapi/jsonpointer/go.mod ================================================ module github.com/go-openapi/jsonpointer require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-openapi/swag v0.17.0 github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/testify v1.2.2 gopkg.in/yaml.v2 v2.2.1 // indirect ) ================================================ FILE: vendor/github.com/go-openapi/jsonpointer/go.sum ================================================ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-openapi/swag v0.17.0 h1:7wu+dZ5k83kvUWeAb+WUkFiUhDzwGqzTR/NhWzeo1JU= github.com/go-openapi/swag v0.17.0/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= ================================================ FILE: vendor/github.com/go-openapi/jsonpointer/pointer.go ================================================ // Copyright 2013 sigu-399 ( https://github.com/sigu-399 ) // // 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. // author sigu-399 // author-github https://github.com/sigu-399 // author-mail sigu.399@gmail.com // // repository-name jsonpointer // repository-desc An implementation of JSON Pointer - Go language // // description Main and unique file. // // created 25-02-2013 package jsonpointer import ( "errors" "fmt" "reflect" "strconv" "strings" "github.com/go-openapi/swag" ) const ( emptyPointer = `` pointerSeparator = `/` invalidStart = `JSON pointer must be empty or start with a "` + pointerSeparator ) var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem() var jsonSetableType = reflect.TypeOf(new(JSONSetable)).Elem() // JSONPointable is an interface for structs to implement when they need to customize the // json pointer process type JSONPointable interface { JSONLookup(string) (interface{}, error) } // JSONSetable is an interface for structs to implement when they need to customize the // json pointer process type JSONSetable interface { JSONSet(string, interface{}) error } // New creates a new json pointer for the given string func New(jsonPointerString string) (Pointer, error) { var p Pointer err := p.parse(jsonPointerString) return p, err } // Pointer the json pointer reprsentation type Pointer struct { referenceTokens []string } // "Constructor", parses the given string JSON pointer func (p *Pointer) parse(jsonPointerString string) error { var err error if jsonPointerString != emptyPointer { if !strings.HasPrefix(jsonPointerString, pointerSeparator) { err = errors.New(invalidStart) } else { referenceTokens := strings.Split(jsonPointerString, pointerSeparator) for _, referenceToken := range referenceTokens[1:] { p.referenceTokens = append(p.referenceTokens, referenceToken) } } } return err } // Get uses the pointer to retrieve a value from a JSON document func (p *Pointer) Get(document interface{}) (interface{}, reflect.Kind, error) { return p.get(document, swag.DefaultJSONNameProvider) } // Set uses the pointer to set a value from a JSON document func (p *Pointer) Set(document interface{}, value interface{}) (interface{}, error) { return document, p.set(document, value, swag.DefaultJSONNameProvider) } // GetForToken gets a value for a json pointer token 1 level deep func GetForToken(document interface{}, decodedToken string) (interface{}, reflect.Kind, error) { return getSingleImpl(document, decodedToken, swag.DefaultJSONNameProvider) } // SetForToken gets a value for a json pointer token 1 level deep func SetForToken(document interface{}, decodedToken string, value interface{}) (interface{}, error) { return document, setSingleImpl(document, value, decodedToken, swag.DefaultJSONNameProvider) } func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) { rValue := reflect.Indirect(reflect.ValueOf(node)) kind := rValue.Kind() switch kind { case reflect.Struct: if rValue.Type().Implements(jsonPointableType) { r, err := node.(JSONPointable).JSONLookup(decodedToken) if err != nil { return nil, kind, err } return r, kind, nil } nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken) if !ok { return nil, kind, fmt.Errorf("object has no field %q", decodedToken) } fld := rValue.FieldByName(nm) return fld.Interface(), kind, nil case reflect.Map: kv := reflect.ValueOf(decodedToken) mv := rValue.MapIndex(kv) if mv.IsValid() && !swag.IsZero(mv) { return mv.Interface(), kind, nil } return nil, kind, fmt.Errorf("object has no key %q", decodedToken) case reflect.Slice: tokenIndex, err := strconv.Atoi(decodedToken) if err != nil { return nil, kind, err } sLength := rValue.Len() if tokenIndex < 0 || tokenIndex >= sLength { return nil, kind, fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength-1, tokenIndex) } elem := rValue.Index(tokenIndex) return elem.Interface(), kind, nil default: return nil, kind, fmt.Errorf("invalid token reference %q", decodedToken) } } func setSingleImpl(node, data interface{}, decodedToken string, nameProvider *swag.NameProvider) error { rValue := reflect.Indirect(reflect.ValueOf(node)) switch rValue.Kind() { case reflect.Struct: if ns, ok := node.(JSONSetable); ok { // pointer impl return ns.JSONSet(decodedToken, data) } if rValue.Type().Implements(jsonSetableType) { return node.(JSONSetable).JSONSet(decodedToken, data) } nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken) if !ok { return fmt.Errorf("object has no field %q", decodedToken) } fld := rValue.FieldByName(nm) if fld.IsValid() { fld.Set(reflect.ValueOf(data)) } return nil case reflect.Map: kv := reflect.ValueOf(decodedToken) rValue.SetMapIndex(kv, reflect.ValueOf(data)) return nil case reflect.Slice: tokenIndex, err := strconv.Atoi(decodedToken) if err != nil { return err } sLength := rValue.Len() if tokenIndex < 0 || tokenIndex >= sLength { return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex) } elem := rValue.Index(tokenIndex) if !elem.CanSet() { return fmt.Errorf("can't set slice index %s to %v", decodedToken, data) } elem.Set(reflect.ValueOf(data)) return nil default: return fmt.Errorf("invalid token reference %q", decodedToken) } } func (p *Pointer) get(node interface{}, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) { if nameProvider == nil { nameProvider = swag.DefaultJSONNameProvider } kind := reflect.Invalid // Full document when empty if len(p.referenceTokens) == 0 { return node, kind, nil } for _, token := range p.referenceTokens { decodedToken := Unescape(token) r, knd, err := getSingleImpl(node, decodedToken, nameProvider) if err != nil { return nil, knd, err } node, kind = r, knd } rValue := reflect.ValueOf(node) kind = rValue.Kind() return node, kind, nil } func (p *Pointer) set(node, data interface{}, nameProvider *swag.NameProvider) error { knd := reflect.ValueOf(node).Kind() if knd != reflect.Ptr && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array { return fmt.Errorf("only structs, pointers, maps and slices are supported for setting values") } if nameProvider == nil { nameProvider = swag.DefaultJSONNameProvider } // Full document when empty if len(p.referenceTokens) == 0 { return nil } lastI := len(p.referenceTokens) - 1 for i, token := range p.referenceTokens { isLastToken := i == lastI decodedToken := Unescape(token) if isLastToken { return setSingleImpl(node, data, decodedToken, nameProvider) } rValue := reflect.Indirect(reflect.ValueOf(node)) kind := rValue.Kind() switch kind { case reflect.Struct: if rValue.Type().Implements(jsonPointableType) { r, err := node.(JSONPointable).JSONLookup(decodedToken) if err != nil { return err } fld := reflect.ValueOf(r) if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr { node = fld.Addr().Interface() continue } node = r continue } nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken) if !ok { return fmt.Errorf("object has no field %q", decodedToken) } fld := rValue.FieldByName(nm) if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr { node = fld.Addr().Interface() continue } node = fld.Interface() case reflect.Map: kv := reflect.ValueOf(decodedToken) mv := rValue.MapIndex(kv) if !mv.IsValid() { return fmt.Errorf("object has no key %q", decodedToken) } if mv.CanAddr() && mv.Kind() != reflect.Interface && mv.Kind() != reflect.Map && mv.Kind() != reflect.Slice && mv.Kind() != reflect.Ptr { node = mv.Addr().Interface() continue } node = mv.Interface() case reflect.Slice: tokenIndex, err := strconv.Atoi(decodedToken) if err != nil { return err } sLength := rValue.Len() if tokenIndex < 0 || tokenIndex >= sLength { return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex) } elem := rValue.Index(tokenIndex) if elem.CanAddr() && elem.Kind() != reflect.Interface && elem.Kind() != reflect.Map && elem.Kind() != reflect.Slice && elem.Kind() != reflect.Ptr { node = elem.Addr().Interface() continue } node = elem.Interface() default: return fmt.Errorf("invalid token reference %q", decodedToken) } } return nil } // DecodedTokens returns the decoded tokens func (p *Pointer) DecodedTokens() []string { result := make([]string, 0, len(p.referenceTokens)) for _, t := range p.referenceTokens { result = append(result, Unescape(t)) } return result } // IsEmpty returns true if this is an empty json pointer // this indicates that it points to the root document func (p *Pointer) IsEmpty() bool { return len(p.referenceTokens) == 0 } // Pointer to string representation function func (p *Pointer) String() string { if len(p.referenceTokens) == 0 { return emptyPointer } pointerString := pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator) return pointerString } // Specific JSON pointer encoding here // ~0 => ~ // ~1 => / // ... and vice versa const ( encRefTok0 = `~0` encRefTok1 = `~1` decRefTok0 = `~` decRefTok1 = `/` ) // Unescape unescapes a json pointer reference token string to the original representation func Unescape(token string) string { step1 := strings.Replace(token, encRefTok1, decRefTok1, -1) step2 := strings.Replace(step1, encRefTok0, decRefTok0, -1) return step2 } // Escape escapes a pointer reference token string func Escape(token string) string { step1 := strings.Replace(token, decRefTok0, encRefTok0, -1) step2 := strings.Replace(step1, decRefTok1, encRefTok1, -1) return step2 } ================================================ FILE: vendor/github.com/go-openapi/jsonreference/.gitignore ================================================ secrets.yml ================================================ FILE: vendor/github.com/go-openapi/jsonreference/.travis.yml ================================================ after_success: - bash <(curl -s https://codecov.io/bash) go: - '1.9' - 1.10.x - 1.11.x install: - go get -u github.com/stretchr/testify/assert - go get -u github.com/PuerkitoBio/purell - go get -u github.com/go-openapi/jsonpointer language: go notifications: slack: secure: OpQG/36F7DSF00HLm9WZMhyqFCYYyYTsVDObW226cWiR8PWYiNfLZiSEvIzT1Gx4dDjhigKTIqcLhG34CkL5iNXDjm9Yyo2RYhQPlK8NErNqUEXuBqn4RqYHW48VGhEhOyDd4Ei0E2FN5ZbgpvHgtpkdZ6XDi64r3Ac89isP9aPHXQTuv2Jog6b4/OKKiUTftLcTIst0p4Cp3gqOJWf1wnoj+IadWiECNVQT6zb47IYjtyw6+uV8iUjTzdKcRB6Zc6b4Dq7JAg1Zd7Jfxkql3hlKp4PNlRf9Cy7y5iA3G7MLyg3FcPX5z2kmcyPt2jOTRMBWUJ5zIQpOxizAcN8WsT3WWBL5KbuYK6k0PzujrIDLqdxGpNmjkkMfDBT9cKmZpm2FdW+oZgPFJP+oKmAo4u4KJz/vjiPTXgQlN5bmrLuRMCp+AwC5wkIohTqWZVPE2TK6ZSnMYcg/W39s+RP/9mJoyryAvPSpBOLTI+biCgaUCTOAZxNTWpMFc3tPYntc41WWkdKcooZ9JA5DwfcaVFyTGQ3YXz+HvX6G1z/gW0Q/A4dBi9mj2iE1xm7tRTT+4VQ2AXFvSEI1HJpfPgYnwAtwOD1v3Qm2EUHk9sCdtEDR4wVGEPIVn44GnwFMnGKx9JWppMPYwFu3SVDdHt+E+LOlhZUply11Aa+IVrT2KUQ= script: - go test -v -race -cover -coverprofile=coverage.txt -covermode=atomic ./... ================================================ FILE: vendor/github.com/go-openapi/jsonreference/CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at ivan+abuse@flanders.co.nz. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: vendor/github.com/go-openapi/jsonreference/LICENSE ================================================ 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. ================================================ FILE: vendor/github.com/go-openapi/jsonreference/README.md ================================================ # gojsonreference [![Build Status](https://travis-ci.org/go-openapi/jsonreference.svg?branch=master)](https://travis-ci.org/go-openapi/jsonreference) [![codecov](https://codecov.io/gh/go-openapi/jsonreference/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonreference) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) [![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonreference/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/jsonreference?status.svg)](http://godoc.org/github.com/go-openapi/jsonreference) An implementation of JSON Reference - Go language ## Status Work in progress ( 90% done ) ## Dependencies https://github.com/go-openapi/jsonpointer ## References http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07 http://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03 ================================================ FILE: vendor/github.com/go-openapi/jsonreference/go.mod ================================================ module github.com/go-openapi/jsonreference require ( github.com/PuerkitoBio/purell v1.1.0 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-openapi/jsonpointer v0.17.0 github.com/go-openapi/swag v0.17.0 // indirect github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/testify v1.2.2 golang.org/x/net v0.0.0-20181005035420-146acd28ed58 // indirect golang.org/x/text v0.3.0 // indirect gopkg.in/yaml.v2 v2.2.1 // indirect ) ================================================ FILE: vendor/github.com/go-openapi/jsonreference/go.sum ================================================ github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-openapi/jsonpointer v0.17.0 h1:Bpl2DtZ6k7wKqfFs7e+4P08+M9I3FQgn09a1UsRUQbk= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/swag v0.17.0 h1:7wu+dZ5k83kvUWeAb+WUkFiUhDzwGqzTR/NhWzeo1JU= github.com/go-openapi/swag v0.17.0/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/net v0.0.0-20181005035420-146acd28ed58 h1:otZG8yDCO4LVps5+9bxOeNiCvgmOyt96J3roHTYs7oE= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= ================================================ FILE: vendor/github.com/go-openapi/jsonreference/reference.go ================================================ // Copyright 2013 sigu-399 ( https://github.com/sigu-399 ) // // 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. // author sigu-399 // author-github https://github.com/sigu-399 // author-mail sigu.399@gmail.com // // repository-name jsonreference // repository-desc An implementation of JSON Reference - Go language // // description Main and unique file. // // created 26-02-2013 package jsonreference import ( "errors" "net/url" "strings" "github.com/PuerkitoBio/purell" "github.com/go-openapi/jsonpointer" ) const ( fragmentRune = `#` ) // New creates a new reference for the given string func New(jsonReferenceString string) (Ref, error) { var r Ref err := r.parse(jsonReferenceString) return r, err } // MustCreateRef parses the ref string and panics when it's invalid. // Use the New method for a version that returns an error func MustCreateRef(ref string) Ref { r, err := New(ref) if err != nil { panic(err) } return r } // Ref represents a json reference object type Ref struct { referenceURL *url.URL referencePointer jsonpointer.Pointer HasFullURL bool HasURLPathOnly bool HasFragmentOnly bool HasFileScheme bool HasFullFilePath bool } // GetURL gets the URL for this reference func (r *Ref) GetURL() *url.URL { return r.referenceURL } // GetPointer gets the json pointer for this reference func (r *Ref) GetPointer() *jsonpointer.Pointer { return &r.referencePointer } // String returns the best version of the url for this reference func (r *Ref) String() string { if r.referenceURL != nil { return r.referenceURL.String() } if r.HasFragmentOnly { return fragmentRune + r.referencePointer.String() } return r.referencePointer.String() } // IsRoot returns true if this reference is a root document func (r *Ref) IsRoot() bool { return r.referenceURL != nil && !r.IsCanonical() && !r.HasURLPathOnly && r.referenceURL.Fragment == "" } // IsCanonical returns true when this pointer starts with http(s):// or file:// func (r *Ref) IsCanonical() bool { return (r.HasFileScheme && r.HasFullFilePath) || (!r.HasFileScheme && r.HasFullURL) } // "Constructor", parses the given string JSON reference func (r *Ref) parse(jsonReferenceString string) error { parsed, err := url.Parse(jsonReferenceString) if err != nil { return err } r.referenceURL, _ = url.Parse(purell.NormalizeURL(parsed, purell.FlagsSafe|purell.FlagRemoveDuplicateSlashes)) refURL := r.referenceURL if refURL.Scheme != "" && refURL.Host != "" { r.HasFullURL = true } else { if refURL.Path != "" { r.HasURLPathOnly = true } else if refURL.RawQuery == "" && refURL.Fragment != "" { r.HasFragmentOnly = true } } r.HasFileScheme = refURL.Scheme == "file" r.HasFullFilePath = strings.HasPrefix(refURL.Path, "/") // invalid json-pointer error means url has no json-pointer fragment. simply ignore error r.referencePointer, _ = jsonpointer.New(refURL.Fragment) return nil } // Inherits creates a new reference from a parent and a child // If the child cannot inherit from the parent, an error is returned func (r *Ref) Inherits(child Ref) (*Ref, error) { childURL := child.GetURL() parentURL := r.GetURL() if childURL == nil { return nil, errors.New("child url is nil") } if parentURL == nil { return &child, nil } ref, err := New(parentURL.ResolveReference(childURL).String()) if err != nil { return nil, err } return &ref, nil } ================================================ FILE: vendor/github.com/go-openapi/spec/.editorconfig ================================================ # top-most EditorConfig file root = true # Unix-style newlines with a newline ending every file [*] end_of_line = lf insert_final_newline = true indent_style = space indent_size = 2 trim_trailing_whitespace = true # Set default charset [*.{js,py,go,scala,rb,java,html,css,less,sass,md}] charset = utf-8 # Tab indentation (no size specified) [*.go] indent_style = tab [*.md] trim_trailing_whitespace = false # Matches the exact files either package.json or .travis.yml [{package.json,.travis.yml}] indent_style = space indent_size = 2 ================================================ FILE: vendor/github.com/go-openapi/spec/.gitignore ================================================ secrets.yml coverage.out ================================================ FILE: vendor/github.com/go-openapi/spec/.golangci.yml ================================================ linters-settings: govet: check-shadowing: true golint: min-confidence: 0 gocyclo: min-complexity: 45 maligned: suggest-new: true dupl: threshold: 100 goconst: min-len: 2 min-occurrences: 2 linters: enable-all: true disable: - maligned - unparam - lll - gochecknoinits - gochecknoglobals ================================================ FILE: vendor/github.com/go-openapi/spec/.travis.yml ================================================ after_success: - bash <(curl -s https://codecov.io/bash) go: - '1.9' - 1.10.x - 1.11.x install: - go get -u github.com/stretchr/testify - go get -u github.com/go-openapi/swag - go get -u gopkg.in/yaml.v2 - go get -u github.com/go-openapi/jsonpointer - go get -u github.com/go-openapi/jsonreference language: go notifications: slack: secure: QUWvCkBBK09GF7YtEvHHVt70JOkdlNBG0nIKu/5qc4/nW5HP8I2w0SEf/XR2je0eED1Qe3L/AfMCWwrEj+IUZc3l4v+ju8X8R3Lomhme0Eb0jd1MTMCuPcBT47YCj0M7RON7vXtbFfm1hFJ/jLe5+9FXz0hpXsR24PJc5ZIi/ogNwkaPqG4BmndzecpSh0vc2FJPZUD9LT0I09REY/vXR0oQAalLkW0asGD5taHZTUZq/kBpsNxaAFrLM23i4mUcf33M5fjLpvx5LRICrX/57XpBrDh2TooBU6Qj3CgoY0uPRYUmSNxbVx1czNzl2JtEpb5yjoxfVPQeg0BvQM00G8LJINISR+ohrjhkZmAqchDupAX+yFrxTtORa78CtnIL6z/aTNlgwwVD8kvL/1pFA/JWYmKDmz93mV/+6wubGzNSQCstzjkFA4/iZEKewKUoRIAi/fxyscP6L/rCpmY/4llZZvrnyTqVbt6URWpopUpH4rwYqreXAtJxJsfBJIeSmUIiDIOMGkCTvyTEW3fWGmGoqWtSHLoaWDyAIGb7azb+KvfpWtEcoPFWfSWU+LGee0A/YsUhBl7ADB9A0CJEuR8q4BPpKpfLwPKSiKSAXL7zDkyjExyhtgqbSl2jS+rKIHOZNL8JkCcTP2MKMVd563C5rC5FMKqu3S9m2b6380E= script: - go test -v -race -cover -coverprofile=coverage.txt -covermode=atomic ./... ================================================ FILE: vendor/github.com/go-openapi/spec/CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at ivan+abuse@flanders.co.nz. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: vendor/github.com/go-openapi/spec/LICENSE ================================================ 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. ================================================ FILE: vendor/github.com/go-openapi/spec/README.md ================================================ # OAI object model [![Build Status](https://travis-ci.org/go-openapi/spec.svg?branch=master)](https://travis-ci.org/go-openapi/spec) [![codecov](https://codecov.io/gh/go-openapi/spec/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/spec) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) [![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/spec/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/spec?status.svg)](http://godoc.org/github.com/go-openapi/spec) [![GolangCI](https://golangci.com/badges/github.com/go-openapi/spec.svg)](https://golangci.com) [![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/spec)](https://goreportcard.com/report/github.com/go-openapi/spec) The object model for OpenAPI specification documents. Currently supports Swagger 2.0. ================================================ FILE: vendor/github.com/go-openapi/spec/bindata.go ================================================ // Code generated by go-bindata. DO NOT EDIT. // sources: // schemas/jsonschema-draft-04.json (4.357kB) // schemas/v2/schema.json (40.249kB) package spec import ( "bytes" "compress/gzip" "crypto/sha256" "fmt" "io" "io/ioutil" "os" "path/filepath" "strings" "time" ) func bindataRead(data []byte, name string) ([]byte, error) { gz, err := gzip.NewReader(bytes.NewBuffer(data)) if err != nil { return nil, fmt.Errorf("Read %q: %v", name, err) } var buf bytes.Buffer _, err = io.Copy(&buf, gz) clErr := gz.Close() if err != nil { return nil, fmt.Errorf("Read %q: %v", name, err) } if clErr != nil { return nil, err } return buf.Bytes(), nil } type asset struct { bytes []byte info os.FileInfo digest [sha256.Size]byte } type bindataFileInfo struct { name string size int64 mode os.FileMode modTime time.Time } func (fi bindataFileInfo) Name() string { return fi.name } func (fi bindataFileInfo) Size() int64 { return fi.size } func (fi bindataFileInfo) Mode() os.FileMode { return fi.mode } func (fi bindataFileInfo) ModTime() time.Time { return fi.modTime } func (fi bindataFileInfo) IsDir() bool { return false } func (fi bindataFileInfo) Sys() interface{} { return nil } var _jsonschemaDraft04JSON = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x57\x3d\x6f\xdb\x3c\x10\xde\xf3\x2b\x08\x26\x63\xf2\x2a\x2f\xd0\xc9\x5b\xd1\x2e\x01\x5a\x34\x43\x37\x23\x03\x6d\x9d\x6c\x06\x14\xa9\x50\x54\x60\xc3\xd0\x7f\x2f\x28\x4a\x14\x29\x91\x92\x2d\xa7\x8d\x97\x28\xbc\xaf\xe7\x8e\xf7\xc5\xd3\x0d\x42\x08\x61\x9a\xe2\x15\xc2\x7b\xa5\x8a\x55\x92\xbc\x96\x82\x3f\x94\xdb\x3d\xe4\xe4\x3f\x21\x77\x49\x2a\x49\xa6\x1e\x1e\xbf\x24\xe6\xec\x16\xdf\x1b\xa1\x3b\xf3\xff\x02\xc9\x14\xca\xad\xa4\x85\xa2\x82\x6b\xe9\x6f\x42\x02\x32\x2c\x28\x07\x45\x5a\x15\x3d\x77\x46\x39\xd5\xcc\x25\x5e\x21\x83\xb8\x21\x18\xb6\xaf\x52\x92\xa3\x47\x68\x88\xea\x58\x80\x56\x4e\x1a\xf2\xbd\x4f\xcc\x29\x7f\x52\x90\x6b\x7d\xff\x0f\x48\xb4\x3d\x3f\x21\x7c\x27\x21\xd3\x2a\x6e\x31\xaa\x2d\x53\xdd\xf3\xe3\x42\x94\x54\xd1\x77\x78\xe2\x0a\x76\x20\xe3\x20\x68\xcb\x30\x86\x41\xf3\x2a\xc7\x2b\xf4\x78\x8e\xfe\xef\x90\x91\x8a\xa9\xc7\xb1\x1d\xc2\xd8\x2f\x0d\x75\xed\xc1\x4e\x9c\xc8\x25\x43\xac\xa8\xbe\xd7\xcc\xa9\xd1\xa9\x21\xa0\x1a\xbd\x04\x61\x94\x34\x2f\x18\xfc\x3e\x16\x50\x8e\x4d\x03\x6f\x1c\x58\xdb\x48\x23\xbc\x11\x82\x01\xe1\xfa\xd3\x3a\x8e\x30\xaf\x18\x33\x7f\xf3\x8d\x39\x11\x9b\x57\xd8\x2a\xfd\x55\x2a\x49\xf9\x0e\xc7\xec\x37\xd4\x25\xf7\xec\x5c\x66\xc7\xd7\x99\xaa\xcf\x4f\x89\x8a\xd3\xb7\x0a\x3a\xaa\x92\x15\xf4\x30\x6f\x1c\xb0\xd6\x46\xe7\x98\x39\x2d\xa4\x28\x40\x2a\x3a\x88\x9e\x29\xba\x88\x37\x2d\xca\x60\x38\xfa\xba\x5b\x20\xac\xa8\x62\xb0\x4c\xd4\xaf\xda\x45\x0a\xba\x5c\x3b\xb9\xc7\x79\xc5\x14\x2d\x18\x34\x19\x1c\x51\xdb\x25\x4d\xb4\x7e\x06\x14\x38\x6c\x59\x55\xd2\x77\xf8\x69\x59\xfc\x7b\x73\xed\x93\x43\xcb\x32\x6d\x3c\x28\xdc\x1b\x9a\xd3\x62\xab\xc2\x27\xf7\x41\xc9\x08\x2b\x23\x08\xad\x13\x57\x21\x9c\xd3\x72\x0d\x42\x72\xf8\x01\x7c\xa7\xf6\x83\xce\x39\xd7\x82\x3c\x1f\x2f\xd6\x60\x1b\xa2\xdf\x35\x89\x52\x20\xe7\x73\x74\xe0\x66\x26\x64\x4e\xb4\x97\x58\xc2\x0e\x0e\xe1\x60\x92\x34\x6d\xa0\x10\xd6\xb5\x83\x61\x27\xe6\x47\xd3\x89\xbd\x63\xfd\x3b\x8d\x03\x3d\x6c\x42\x2d\x5b\x70\xee\xe8\xdf\x4b\xf4\x66\x4e\xe1\x01\x45\x17\x80\x74\xad\x4f\xc3\xf3\xae\xc6\x1d\xc6\xd7\xc2\xce\xc9\xe1\x29\x30\x86\x2f\x4a\xa6\x4b\x15\x84\x73\xc9\x6f\xfd\x7f\xa5\x6e\x9e\xbd\xf1\xb0\xd4\xdd\x45\x5a\xc2\x3e\x4b\x78\xab\xa8\x84\x74\x4a\x91\x3b\x92\x23\x05\xf2\x1c\x1e\x7b\xf3\x09\xf8\xcf\xab\x24\xb6\x60\xa2\xe8\x4c\x9f\x75\x77\xaa\x8c\xe6\x01\x45\x36\x86\xcf\xc3\x63\x3a\xea\xd4\x8d\x7e\x06\xac\x14\x0a\xe0\x29\xf0\xed\x07\x22\x1a\x65\xda\x44\xae\xa2\x73\x1a\xe6\x90\x69\xa2\x8c\x46\xb2\x2f\xde\x49\x38\x08\xed\xfe\xfd\x41\xaf\x9f\xa9\x55\xd7\xdd\x22\x8d\xfa\x45\x63\xc5\x0f\x80\xf3\xb4\x08\xd6\x79\x30\x9e\x93\xee\x59\xa6\xd0\x4b\xee\x22\xe3\x33\xc1\x3a\x27\x68\x36\x78\x7e\x87\x0a\x06\xd5\x2e\x20\xd3\xaf\x15\xfb\xd8\x3b\x73\x14\xbb\x92\xed\x05\x5d\x2e\x29\x38\x2c\x94\xe4\x42\x45\x5e\xd3\xb5\x7d\xdf\x47\xca\x38\xb4\x5c\xaf\xfb\x7d\xdd\x6d\xf4\xa1\x2d\x77\xdd\x2f\xce\x6d\xc4\x7b\x8b\x4e\x67\xa9\x6f\xfe\x04\x00\x00\xff\xff\xb1\xd1\x27\x78\x05\x11\x00\x00") func jsonschemaDraft04JSONBytes() ([]byte, error) { return bindataRead( _jsonschemaDraft04JSON, "jsonschema-draft-04.json", ) } func jsonschemaDraft04JSON() (*asset, error) { bytes, err := jsonschemaDraft04JSONBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "jsonschema-draft-04.json", size: 4357, mode: os.FileMode(436), modTime: time.Unix(1540282154, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe1, 0x48, 0x9d, 0xb, 0x47, 0x55, 0xf0, 0x27, 0x93, 0x30, 0x25, 0x91, 0xd3, 0xfc, 0xb8, 0xf0, 0x7b, 0x68, 0x93, 0xa8, 0x2a, 0x94, 0xf2, 0x48, 0x95, 0xf8, 0xe4, 0xed, 0xf1, 0x1b, 0x82, 0xe2}} return a, nil } var _v2SchemaJSON = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5d\x4f\x93\xdb\x36\xb2\xbf\xfb\x53\xa0\x14\x57\xd9\xae\xd8\x92\xe3\xf7\x2e\xcf\x97\xd4\xbc\xd8\x49\x66\x37\x5e\x4f\x79\x26\xbb\x87\x78\x5c\x05\x91\x2d\x09\x09\x09\x30\x00\x38\x33\x5a\xef\x7c\xf7\x2d\xf0\x9f\x08\x02\x20\x41\x8a\xd2\xc8\x0e\x0f\xa9\x78\x28\xa0\xd1\xdd\x68\x34\x7e\xdd\xf8\xf7\xf9\x11\x42\x33\x49\x64\x04\xb3\xd7\x68\x76\x86\xfe\x76\xf9\xfe\x1f\xe8\x32\xd8\x40\x8c\xd1\x8a\x71\x74\x79\x8b\xd7\x6b\xe0\xe8\xd5\xfc\x25\x3a\xbb\x38\x9f\xcf\x9e\xab\x0a\x24\x54\xa5\x37\x52\x26\xaf\x17\x0b\x91\x17\x99\x13\xb6\xb8\x79\xb5\x10\x59\xdd\xf9\xef\x82\xd1\x6f\xf2\xc2\x8f\xf3\x4f\xb5\x1a\xea\xc7\x17\x45\x41\xc6\xd7\x8b\x90\xe3\x95\x7c\xf1\xf2\x7f\x8b\xca\x45\x3d\xb9\x4d\x32\xa6\xd8\xf2\x77\x08\x64\xfe\x8d\xc3\x9f\x29\xe1\xa0\x9a\xff\xed\x11\x42\x08\xcd\x8a\xd6\xb3\x9f\x15\x67\x74\xc5\xca\x7f\x27\x58\x6e\xc4\xec\x11\x42\xd7\x59\x5d\x1c\x86\x44\x12\x46\x71\x74\xc1\x59\x02\x5c\x12\x10\xb3\xd7\x68\x85\x23\x01\x59\x81\x04\x4b\x09\x9c\x6a\xbf\x7e\xce\x49\x7d\xba\x7b\x51\xfd\xa1\x44\xe2\xb0\x52\xac\x7d\xb3\x08\x61\x45\x68\x46\x56\x2c\x6e\x80\x86\x8c\xbf\xbd\x93\x40\x05\x61\x74\x96\x95\xbe\x7f\x84\xd0\x7d\x4e\xde\x42\xb7\xe4\xbe\x46\xbb\x14\x5b\x48\x4e\xe8\xba\x90\x05\xa1\x19\xd0\x34\xae\xc4\xce\xbe\xbc\x9a\xbf\x9c\x15\x7f\x5d\x57\xc5\x42\x10\x01\x27\x89\xe2\x48\x51\xb9\xda\x40\xd5\x87\x37\xc0\x15\x5f\x88\xad\x90\xdc\x10\x81\x42\x16\xa4\x31\x50\x39\x2f\x38\xad\xab\xb0\x53\xd8\xac\x94\x56\x6f\xc3\x84\xf4\x11\xa4\x50\xb3\xfa\xe9\xd3\x6f\x9f\x3e\xdf\x2f\xd0\xeb\x8f\x1f\x3f\x7e\xbc\xfe\xf6\xe9\xf7\xaf\x5f\x7f\xfc\x18\x7e\xfb\xec\xfb\xc7\xb3\x36\x79\x54\x43\xe8\x29\xc5\x31\x20\xc6\x11\x49\x9e\xe5\x12\x41\x66\xa0\xe8\xed\x1d\x8e\x93\x08\x5e\xa3\x27\x3b\xc3\x7c\xa2\x73\xba\xc4\x02\x2e\xb0\xdc\xf4\xe5\x76\xd1\xca\x96\xa2\x8a\x94\xcd\x21\xc9\x6c\xec\x2c\x70\x42\x9e\x34\x74\x9d\x19\x7c\xcd\x20\x9c\xea\x2e\x0a\xfe\x42\x84\xd4\x29\x04\x8c\x8a\xb4\x41\xa2\xc1\xdc\x19\x8a\x88\x90\x4a\x49\xef\xce\xdf\xbd\x45\x4a\x52\x81\x70\x10\x40\x22\x21\x44\xcb\x6d\xc5\xec\x4e\x3c\x1c\x45\xef\x57\x9a\xb5\x7d\xae\xfe\xe5\xe4\x31\x86\x90\xe0\xab\x6d\x02\x3b\x2e\xcb\x11\x90\xd9\xa8\xc6\x77\xc2\x59\x98\x06\xfd\xf9\x2e\x78\x45\x01\xa6\xa8\xa0\x71\x5c\xbe\x33\xa7\xd2\xd9\x5f\x95\xef\xd9\xd5\xac\xfd\xdc\x5d\xbf\x5e\xb8\xd1\x3e\xc7\x31\x48\xe0\x5e\x4c\x14\x65\xdf\xb8\xa8\x71\x10\x09\xa3\xc2\xc7\x02\xcb\xa2\x4e\x5a\x02\x82\x94\x13\xb9\xf5\x30\xe6\xb2\xa4\xb5\xfe\x9b\x3e\x7a\xb2\x55\xd2\xa8\x4a\xbc\x16\xb6\x71\x8e\x39\xc7\xdb\x9d\xe1\x10\x09\x71\xbd\x9c\xb3\x41\x89\xd7\xa5\x89\xdc\x57\xb5\x53\x4a\xfe\x4c\xe1\xbc\xa0\x21\x79\x0a\x1a\x0f\x70\xa7\x5c\x08\x8e\xde\xb0\xc0\x43\x24\xad\x74\x63\x0e\xb1\xd9\x90\xe1\xb0\x2d\x13\xa7\x6d\x78\xfd\x04\x14\x38\x8e\x90\xaa\xce\x63\xac\x3e\x23\xbc\x64\xa9\xb4\xf8\x03\x63\xde\xcd\xbe\x16\x13\x4a\x55\xac\x82\x12\xc6\xac\xd4\x35\xf7\x22\xd4\x3a\xff\x22\x73\x0e\x6e\x51\xa0\x75\x1e\xae\x8f\xe8\x5d\xc7\x59\xe6\xe4\x9a\x18\x8d\xd6\x1c\x53\x84\x4d\xb7\x67\x28\x37\x09\x84\x69\x88\x12\x0e\x01\x11\x80\x32\xa2\xf5\xb9\xaa\xc6\xd9\x73\x53\xab\xfb\xb4\x2e\x20\xc6\x54\x92\xa0\x9a\xf3\x69\x1a\x2f\x81\x77\x37\xae\x53\x1a\xce\x40\xc4\xa8\x82\x1c\xb5\xef\xda\x24\x7d\xb9\x61\x69\x14\xa2\x25\xa0\x90\xac\x56\xc0\x81\x4a\xb4\xe2\x2c\xce\x4a\x64\x7a\x9a\x23\xf4\x13\x91\x3f\xa7\x4b\xf4\x63\x84\x6f\x18\x87\x10\xbd\xc3\xfc\x8f\x90\xdd\x52\x44\x04\xc2\x51\xc4\x6e\x21\x74\x48\x21\x81\xc7\xe2\xfd\xea\x12\xf8\x0d\x09\xf6\xe9\x47\x35\xaf\x67\xc4\x14\xf7\x22\x27\x97\xe1\xe2\x76\x2d\x06\x8c\x4a\x1c\x48\x3f\x73\x2d\x0b\x5b\x29\x45\x24\x00\x2a\x0c\x11\xec\x94\xca\xc2\xa6\xc1\x37\x21\x43\x83\x3b\x5f\x97\xf1\x43\x5e\x53\x73\x19\xa5\x36\xd8\x2d\x05\x2e\x34\x0b\xeb\x39\xfc\x1d\x63\x51\x01\xbd\x3d\xbb\x90\x84\x40\x25\x59\x6d\x09\x5d\xa3\x1c\x37\xe6\x5c\x16\x9a\x40\x09\x70\xc1\xe8\x82\xf1\x35\xa6\xe4\xdf\x99\x5c\x8e\x9e\x4d\x79\xb4\x27\x2f\xbf\x7e\xf8\x05\x25\x8c\x50\xa9\x98\x29\x90\x62\x60\xea\x75\xae\x13\xca\xbf\x2b\x1a\x29\x27\x76\xd6\x20\xc6\x64\x5f\xe6\x32\x1a\x08\x87\x21\x07\x21\xbc\xb4\xe4\xe0\x32\x67\xa6\xcd\xf3\x1e\xcd\xd9\x6b\xb6\x6f\x8e\x27\xa7\xed\xdb\xe7\xbc\xcc\x1a\x07\xce\x6f\x87\x33\xf0\xba\x51\x17\x22\x66\x78\x79\x8e\xce\xe5\x13\x81\x80\x06\x2c\xe5\x78\x0d\xa1\xb2\xb8\x54\xa8\x79\x09\xbd\xbf\x3c\x47\x01\x8b\x13\x2c\xc9\x32\xaa\xaa\x1d\xd5\xee\xab\x36\xbd\x6c\xfd\x54\x6c\xc8\x08\x01\x3c\xbd\xe7\x07\x88\xb0\x24\x37\x79\x90\x28\x4a\x1d\x10\x1a\x92\x1b\x12\xa6\x38\x42\x40\xc3\x4c\x43\x62\x8e\xae\x36\xb0\x45\x71\x2a\xa4\x9a\x23\x79\x59\xb1\xa8\xf2\xa4\x0c\x60\x9f\xcc\x8d\x40\xf5\x80\xca\xa8\x99\xc3\xa7\x85\x1f\x31\x25\xa9\x82\xc5\x6d\xbd\xd8\x36\x76\x7c\x02\x28\x97\xf6\x1d\x74\x3b\x11\x7e\x91\xae\x32\xf8\x6c\xf4\xe6\x7b\x9a\xa5\x1f\x62\xc6\x21\xcf\x9a\xe5\xed\x8b\x02\xf3\x2c\x33\x33\xdf\x00\xca\xc9\x09\xb4\x04\xf5\xa5\x08\xd7\xc3\x02\x18\x66\xf1\xab\x1e\x83\x37\x4c\xcd\x12\xc1\x1d\x50\xf6\xaa\xbd\xfe\xe2\x73\x48\x38\x08\xa0\x32\x9b\x18\x44\x86\x0b\x6a\xc1\xaa\x26\x96\x2d\x96\x3c\xa0\x54\x65\x73\x87\x15\xca\x15\xe5\xf5\x94\x46\x9f\x33\x1a\x0c\x9a\xb1\x5a\xd9\x6a\x95\xcd\xcb\x7e\xec\x9a\xc5\x94\x3b\x37\x26\x31\xd7\xfc\xe4\x1f\x13\x8c\x31\x75\x9c\xba\xf7\x87\x3c\xa1\xb7\x4f\x17\x1b\x09\x82\x98\xc4\x70\x95\xd3\xe8\x4c\x48\x5a\xa6\xd6\x2a\x3d\x56\x42\x80\x9f\xaf\xae\x2e\x50\x0c\x42\xe0\x35\x34\x3c\x8a\x62\x03\x37\xba\xb2\x27\x04\xda\x25\x8d\x06\xe2\xa0\x13\x8a\xf3\xf5\xec\x10\x72\x67\x88\x90\x3d\x4b\x64\xeb\xaa\xda\x8f\xf7\x5a\x75\x47\x9a\xa8\x51\x70\x26\xd2\x38\xc6\x7c\xbb\x57\xfc\xbd\xe4\x04\x56\xa8\xa0\x54\x9a\x45\xd5\xf7\x0f\x16\xfc\x57\x1c\x3c\xdf\x23\xba\x77\x38\xda\x16\x4b\x31\x53\x6a\x4d\x9a\x15\x63\xe7\xe1\x18\x69\x9f\x22\xe0\x24\xbb\x94\x4b\x97\xee\x2d\xf9\x70\x87\x72\x7b\xe6\xc4\x33\x2a\x66\x5e\x1c\x35\x72\xe3\x2d\xda\x73\xe4\xc7\x51\x6d\xa4\xa1\x2a\x4f\xde\x94\xcb\xb2\x3e\x31\x48\xae\x82\xce\xc9\xc8\x65\xcd\xc3\xb7\x34\xb6\x2b\xdf\x58\x65\x78\x6e\x73\xac\x5e\x24\x0d\x3f\xdc\x70\x23\xc6\xda\x52\x0b\x2d\x63\x7d\xa9\x49\x2d\x54\x48\x28\xc0\x12\x9c\xe3\x63\xc9\x58\x04\x98\x36\x07\xc8\x0a\xa7\x91\xd4\xf0\xbc\xc1\xa8\xb9\x70\xd0\xc6\xa9\xb6\x78\x80\x5a\xa3\xb4\x2c\xf4\x18\x0b\x8a\x9d\xd0\xb4\x55\x10\xee\x0d\xc5\xd6\xe0\x99\x93\xdc\xa1\x04\xbb\xf1\xa7\x23\xd1\xd1\x97\x8c\x87\x13\x0a\x21\x02\xe9\x99\x25\xed\x20\xc5\x92\x66\x3c\x32\x9c\xd6\x06\xb0\x31\x5c\x86\x29\x0a\xcb\x60\x33\x12\xa5\x91\xfc\x96\x75\xd0\x59\xd7\x13\xbd\xd3\x23\x79\xdd\x2a\x90\xa6\x38\x06\x91\x39\x7f\x20\x72\x03\x1c\x2d\x01\x61\xba\x45\x37\x38\x22\x61\x8e\x71\x85\xc4\x32\x15\x28\x60\x61\x16\xb8\x3d\x29\xdc\x4d\x3d\x2f\x12\x13\x7d\xc8\x7e\x37\xee\xa8\x7f\xfa\xdb\xcb\x17\xff\x77\xfd\xf9\x7f\xee\x9f\x3d\xfe\xcf\xa7\xa7\x45\xfb\xcf\x1e\xf7\xf3\xe0\xff\xc4\x51\x0a\x8e\x4c\xcb\x01\xdc\x0a\x65\xb2\x01\x83\xed\x3d\xe4\xa9\xa3\x4e\x2d\x59\xc5\xe8\x2f\x48\x7d\x5a\x6e\x37\xbf\x5c\x9f\x35\x13\x64\x14\xfa\xef\x0b\x68\xa6\x0d\xb4\x8e\xf1\xa8\xff\xbb\x60\xf4\x03\x64\xab\x5b\x81\x65\x51\xe6\xda\xca\xfa\xf0\xb0\xac\x3e\x9c\xca\x26\x0e\x1d\xdb\x57\x5b\xbb\xb4\x9a\xa6\xb6\x9b\x1a\x6b\xd1\x9a\x9e\x7e\x33\x9a\xec\x41\x69\x45\x22\xb8\xb4\x51\xeb\x04\x77\xca\x6f\x7b\x7b\xc8\xb2\xb0\x95\x92\x25\x5b\xd0\x42\xaa\x2a\xdd\x32\x78\x4f\x0c\xab\x68\x46\x6c\xea\x6d\xf4\x5c\x5e\xde\xc4\xac\xa5\xf9\xd1\x00\x9f\x7d\x98\x65\x24\xbd\xc7\x97\xd4\xb3\x3a\xa8\x2b\xa0\x34\x76\xf9\x65\x5f\x2d\x25\x95\x1b\xcf\xd6\xf4\x9b\x5f\x09\x95\xb0\x36\x3f\xdb\xd0\x39\x2a\x93\x1c\x9d\x03\xa2\x4a\xca\xf5\xf6\x10\xb6\x94\x89\x0b\x6a\x70\x12\x13\x49\x6e\x40\xe4\x29\x12\x2b\xbd\x80\x45\x11\x04\xaa\xc2\x8f\x56\x9e\x5c\x6b\xec\x8d\x5a\x0e\x14\x59\x06\x2b\x1e\x24\xcb\xc2\x56\x4a\x31\xbe\x23\x71\x1a\xfb\x51\x2a\x0b\x3b\x1c\x48\x10\xa5\x82\xdc\xc0\xbb\x3e\x24\x8d\x5a\x76\x2e\x09\xed\xc1\x65\x51\xb8\x83\xcb\x3e\x24\x8d\x5a\x2e\x5d\xfe\x02\x74\x2d\x3d\xf1\xef\xae\xb8\x4b\xe6\x5e\xd4\xaa\xe2\x2e\x5c\x5e\xec\x0e\xf5\x5b\x0c\xcb\x0a\xbb\xa4\x3c\xf7\x1f\x2a\x55\x69\x97\x8c\x7d\x68\x95\xa5\xad\xb4\xf4\x9c\xa5\x07\xb9\x7a\x05\xbb\xad\x50\x6f\xfb\xa0\x4e\x9b\x48\x23\x49\x92\x28\x87\x19\x3e\x32\xee\xca\x3b\x46\x7e\x7f\x18\x64\xcc\xcc\x0f\x34\xe9\x36\x8b\xb7\x6c\xa8\xa5\x5b\x54\x4c\x54\x5b\x15\x3a\xf1\x6c\x2d\xfe\x96\xc8\x0d\xba\x7b\x81\x88\xc8\x23\xab\xee\x7d\x3b\x92\xa7\x60\x29\xe3\xdc\xff\xb8\x64\xe1\xf6\xa2\x5a\x59\xdc\x6f\xeb\x45\x7d\x6a\xd1\x76\x1e\xea\xb8\xf1\xfa\x14\xd3\x36\x63\xe5\xd7\xf3\xe4\xbe\x25\xbd\x5e\x05\xeb\x73\x74\xb5\x21\x2a\x2e\x4e\xa3\x30\xdf\xbf\x43\x28\x2a\xd1\xa5\x2a\x9d\x8a\xfd\x76\xd8\x8d\xbc\x67\x65\xc7\xb8\x03\x45\xec\xa3\xb0\x37\x8a\x70\x4c\x68\x91\x51\x8e\x58\x80\xed\x4a\xf3\x81\x62\xca\x96\xbb\xf1\x52\xcd\x80\xfb\xe4\x4a\x5d\x6c\xdf\x6e\x20\x4b\x80\x30\x8e\x28\x93\xf9\xe9\x8d\x8a\x6d\xd5\x59\x65\x7b\xaa\x44\x9e\xc0\xc2\xd1\x7c\x40\x26\xd6\x1a\xce\xf9\xc5\x69\x7b\x6c\xec\xc8\x71\x7b\xe5\x21\x2e\xd3\xe5\x65\x93\x91\x53\x0b\x7b\x3a\xc7\xfa\x17\x6a\x01\xa7\x33\xd0\xf4\x40\x0f\x39\x87\xda\xe4\x54\x87\x3a\xd5\xe3\xc7\xa6\x8e\x20\xd4\x11\xb2\x4e\xb1\xe9\x14\x9b\x4e\xb1\xe9\x14\x9b\xfe\x15\x63\xd3\x47\xf5\xff\x97\x38\xe9\xcf\x14\xf8\x76\x82\x49\x13\x4c\xaa\x7d\xcd\x6c\x62\x42\x49\x87\x43\x49\x19\x33\x6f\xe3\x44\x6e\x9b\xab\x8a\x3e\x86\xaa\x99\x52\x1b\x5b\x59\x33\x02\x09\xa0\x21\xa1\x6b\x84\x6b\x66\xbb\xdc\x16\x0c\xd3\x68\xab\xec\x36\x4b\xd8\x60\x8a\x40\x31\x85\x6e\x14\x57\x13\xc2\xfb\x92\x10\xde\xbf\x88\xdc\xbc\x53\x5e\x7f\x82\x7a\x13\xd4\x9b\xa0\xde\x04\xf5\x90\x01\xf5\x94\xcb\x7b\x83\x25\x9e\xd0\xde\x84\xf6\x6a\x5f\x4b\xb3\x98\x00\xdf\x04\xf8\x6c\xbc\x7f\x19\x80\xaf\xf1\x71\x45\x22\x98\x40\xe0\x04\x02\x27\x10\xd8\x29\xf5\x04\x02\xff\x4a\x20\x30\xc1\x72\xf3\x65\x02\x40\xd7\xc1\xd1\xe2\x6b\xf1\xa9\x7b\xfb\xe4\x20\xc0\x68\x9d\xd4\xb4\xd3\x96\xb5\xa6\xd1\x41\x20\xe6\x89\xc3\x48\x65\x58\x13\x84\x9c\x56\x56\x3b\x0c\xe0\x6b\x83\x5c\x13\xd2\x9a\x90\xd6\x84\xb4\x26\xa4\x85\x0c\xa4\x45\x19\xfd\xff\x63\x6c\x52\xb5\x1f\x1e\x19\x74\x3a\xcd\xb9\x69\xce\xa6\x3a\x0f\x7a\x2d\x19\xc7\x81\x14\x5d\xcb\xd5\x03\xc9\x39\xd0\xb0\xd1\xb3\xcd\xfb\x7a\x2d\x5d\x3a\x48\xe1\xfa\x2e\xe6\x81\x42\x18\x86\xd6\xc1\xbe\xb1\x23\xd3\xf7\x34\xed\x19\x0a\x0b\xc4\x48\x44\xfd\x22\x50\xb6\x42\x58\xbb\xe5\x3d\xa7\x73\xd4\x8b\xc4\x8c\x70\x61\xec\x73\xee\xc3\x81\x8b\xf5\xe2\xd7\x52\x3e\xcf\xeb\xeb\x17\x3b\x71\x16\xda\x7d\xb8\xde\xf0\x7a\x8f\x06\x2d\xa7\x40\x7b\xc1\x9d\x41\x4d\xb6\x61\xa2\x4e\x9f\x3d\xa0\xc5\xae\xe3\x1c\x1d\x40\x6c\x48\x8b\x63\xa0\xb5\x01\xed\x8e\x02\xe9\x86\xc8\x3b\x06\xee\xdb\x4b\xde\xbd\xc0\xa1\x6f\xcb\xda\xfc\xc2\x44\x16\x87\x9c\x17\x31\xd3\x30\x20\x39\x42\xcb\x6f\xf2\xf1\xf4\x72\x10\xf8\x1c\xa0\xf3\xbd\x10\xea\x21\x35\x7d\xe8\x86\xdb\x15\xed\x81\x81\x07\x28\xbb\x13\x28\xc7\xf8\xce\x7d\x8d\xc2\x31\xb4\x7e\x94\xd6\xdb\x55\xef\x4a\xfb\xed\xc3\x40\x3e\xeb\x9f\xe9\x99\x0f\xdf\x08\x65\x88\x27\x73\x86\x31\x9d\x47\xdf\x55\x19\xba\x3d\xee\x15\x0a\xcd\x8c\xaa\x5e\xb9\xf6\x57\x33\x73\x5a\xa1\x89\x7b\x3b\xa0\xb2\xa4\xc2\xf6\xc1\x53\xb5\x00\xca\x23\xe5\xf4\x60\x6a\xb4\x2d\x74\xea\x4e\xed\x3b\xe3\x47\xfb\xed\x82\x3d\x19\xd4\x3b\x6b\xaf\xae\x2b\x2f\x57\xb3\x82\x68\xcb\xed\x88\x2e\xe1\x5c\xd7\x26\xfa\x0a\x65\xe7\xce\x11\x33\xb4\xdd\x66\xe3\x37\xf6\xfa\x70\xd6\x4f\xa1\x21\x51\xd8\x3c\x26\x14\x4b\xc6\x87\x44\x27\x1c\x70\xf8\x9e\x46\xce\xab\x21\x07\x5f\xc1\x76\x17\x1b\x77\xb4\xda\x75\xa0\x0a\x3a\x30\xe1\xf8\x97\x32\x16\x2b\x00\x75\x85\xee\x62\x46\xef\xd3\x85\xb5\x6b\x60\xbe\xf2\x30\x7a\x8c\x0b\x4b\xa6\xd0\xf9\x64\x42\xe7\x07\x41\x41\xe3\x2c\x5d\xf9\x6d\xe9\x39\x98\x3b\x3b\x5d\x67\xd4\x5c\xed\xf2\xf0\x48\x7b\xbd\x2d\x31\xdd\x3f\x34\xad\x44\x76\x51\x9a\x56\x22\xa7\x95\xc8\x69\x25\xf2\xe1\x56\x22\x1f\x00\x32\x6a\x73\x92\xed\xe1\xc6\x7d\x9f\x49\x2c\x69\x7e\xc8\x31\x4c\x0c\xb4\xf2\x54\x3b\x79\x3b\x9e\x4d\xb4\xd1\x18\x3e\x5f\x9a\x93\xa2\x11\xc3\xda\x27\x0b\xaf\x37\x2e\x5c\x37\xfb\xeb\x9a\xd6\xc3\xac\xc3\xcc\xf8\x1e\x5b\x9d\xac\x22\x64\xb7\xed\x26\xb8\xf3\xb9\x3c\xbb\x1f\xe2\xb0\x22\x77\x43\x6a\x62\x29\x39\x59\xa6\xe6\xe5\xcd\x7b\x83\xc0\x5b\x8e\x93\x64\xac\xeb\xca\x4f\x65\xac\x4a\xbc\x1e\xcd\x82\xfa\x3c\x70\x36\xb6\xb5\xed\x79\xef\xec\x68\x00\xff\x54\xfa\xb5\xe3\xf1\xdb\xe1\xbe\xce\x76\x17\xaf\x57\xb6\x6b\x89\x05\x09\xce\x52\xb9\x01\x2a\x49\xbe\xd9\xf4\xd2\xb8\x7a\xbf\x91\x02\xf3\x22\x8c\x13\xf2\x77\xd8\x8e\x43\x8b\xe1\x54\x6e\x5e\x9d\xc7\x49\x44\x02\x22\xc7\xa4\x79\x81\x85\xb8\x65\x3c\x1c\x93\xe6\x59\xa2\xf8\x1c\x51\x95\x05\xd9\x20\x00\x21\x7e\x60\x21\x58\xa9\x56\xff\xbe\xb6\x5a\x5e\x5b\x3f\x1f\xd6\xd3\x3c\xc4\x4d\xba\x99\xb4\x63\x6e\x7d\x3e\x3d\x57\xd2\x18\x5f\x47\xe8\xc3\x06\x8a\x68\x6c\x7f\x3b\x72\x0f\xe7\xe2\x77\x77\xf1\xd0\x99\xab\xdf\x2e\xfe\xd6\xbb\xcd\x1a\xb9\x90\xd1\xaf\xf2\x38\x3d\xdb\x74\xf8\xeb\xe3\xda\xe8\x2a\x62\xb7\xda\x1b\x07\xa9\xdc\x30\x5e\xbc\x68\xfb\x6b\x9f\x97\xf1\xc6\xb1\xd8\x5c\x29\x1e\x49\x30\xc5\xf7\xde\xad\x91\x42\xf9\xdd\xed\x89\x80\x25\xbe\x37\xd7\xe7\x32\x5c\xe6\x35\xac\xd4\x0c\x2d\xf7\x90\xc4\xe3\xf5\xe3\x2f\x7f\x54\x18\x88\xe3\x61\x47\x85\x64\x7f\xc0\xd7\x3f\x1a\x92\x42\xe9\xc7\x1e\x0d\x95\x76\xa7\x51\xa0\x8f\x02\x1b\x46\x9e\x06\x42\xd1\xf2\x01\x07\x02\xde\xe9\x7d\x1a\x0b\xa7\x32\x16\xcc\xc0\xee\xc4\x90\xd2\x5f\x6f\x98\x54\x5d\xf2\x95\xe1\xa7\x69\x10\x3a\x06\xe1\x65\xb3\x17\x47\x58\x78\xd0\x45\xd6\x5b\xd5\x5f\x25\x1d\x71\x49\xa6\x7a\x64\xda\xd0\x6f\xc7\x3a\x4c\xe3\x09\xc0\x6e\x96\x2c\xa7\xa7\x77\x34\x10\x05\x08\x21\x44\x92\x65\x77\xdf\x20\x5c\xbc\xe7\x97\x3f\xf4\x1a\x45\xd6\xe7\x27\x4a\xde\x74\x27\x66\x11\x7d\x70\xba\xd3\x78\xf9\x1e\x0d\xca\xc8\x39\xde\x7c\xb3\xa6\xe1\xbc\xd7\xc1\x6a\x6f\xb3\x0e\x52\xbe\xe4\x98\x8a\x15\x70\x94\x70\x26\x59\xc0\xa2\xf2\x1c\xfb\xd9\xc5\xf9\xbc\xd5\x92\x9c\xa3\xdf\xe6\x1e\xb3\x0d\x49\xba\x87\x50\x5f\x84\xfe\xe9\xd6\xf8\xbb\xe6\xf0\x7a\xeb\xa6\x65\x3b\x86\x8b\x79\x93\xf5\x59\x20\x6e\xb4\xa7\x44\xf4\x3f\xa5\xfe\x67\x42\x12\xdb\xd3\xe7\xbb\xa5\xa3\x8c\x5c\x2b\x97\xbb\xbb\x7f\x8e\xc5\x6e\xed\x43\x5c\xbf\x74\xc8\x8f\xff\xe6\xd6\xbe\x91\xb6\xf5\x95\xe4\xed\x93\xc4\xa8\x5b\xf9\x76\x4d\x35\xb7\xd8\x8c\xb6\x7d\xaf\x72\xe0\xb6\xbd\x01\x63\x9e\x76\xab\x1a\x32\x76\xe4\x8c\x76\xc2\xad\x6c\xa2\x65\xf7\xcf\xf8\xa7\xda\x2a\xb9\x8c\x3d\x3c\xa3\x9d\x64\x33\xe5\x1a\xb5\x2d\xfb\x86\xa2\x5a\x7f\x19\x5b\x7f\xc6\x3f\xd1\x53\xd3\xe2\x41\x5b\xd3\x4f\xf0\xec\xb0\x42\x73\x43\xd2\x68\x27\xd3\x6a\x6a\x34\xf6\x4e\x1e\x52\x8b\x87\x6c\xcc\xae\x44\xfb\x9e\xa7\x51\x4f\x9d\x55\x03\x81\x8e\x67\xfc\xb4\x69\xf0\x3a\x18\xf2\x40\xd0\xf6\xa8\x34\xe3\xc9\x98\xaf\xf6\xda\x24\xd3\xeb\x60\xb9\x0e\xd3\x1f\xa9\xff\xee\x1f\xfd\x37\x00\x00\xff\xff\x69\x5d\x0a\x6a\x39\x9d\x00\x00") func v2SchemaJSONBytes() ([]byte, error) { return bindataRead( _v2SchemaJSON, "v2/schema.json", ) } func v2SchemaJSON() (*asset, error) { bytes, err := v2SchemaJSONBytes() if err != nil { return nil, err } info := bindataFileInfo{name: "v2/schema.json", size: 40249, mode: os.FileMode(436), modTime: time.Unix(1540282154, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xcb, 0x25, 0x27, 0xe8, 0x46, 0xae, 0x22, 0xc4, 0xf4, 0x8b, 0x1, 0x32, 0x4d, 0x1f, 0xf8, 0xdf, 0x75, 0x15, 0xc8, 0x2d, 0xc7, 0xed, 0xe, 0x7e, 0x0, 0x75, 0xc0, 0xf9, 0xd2, 0x1f, 0x75, 0x57}} return a, nil } // Asset loads and returns the asset for the given name. // It returns an error if the asset could not be found or // could not be loaded. func Asset(name string) ([]byte, error) { canonicalName := strings.Replace(name, "\\", "/", -1) if f, ok := _bindata[canonicalName]; ok { a, err := f() if err != nil { return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) } return a.bytes, nil } return nil, fmt.Errorf("Asset %s not found", name) } // AssetString returns the asset contents as a string (instead of a []byte). func AssetString(name string) (string, error) { data, err := Asset(name) return string(data), err } // MustAsset is like Asset but panics when Asset would return an error. // It simplifies safe initialization of global variables. func MustAsset(name string) []byte { a, err := Asset(name) if err != nil { panic("asset: Asset(" + name + "): " + err.Error()) } return a } // MustAssetString is like AssetString but panics when Asset would return an // error. It simplifies safe initialization of global variables. func MustAssetString(name string) string { return string(MustAsset(name)) } // AssetInfo loads and returns the asset info for the given name. // It returns an error if the asset could not be found or // could not be loaded. func AssetInfo(name string) (os.FileInfo, error) { canonicalName := strings.Replace(name, "\\", "/", -1) if f, ok := _bindata[canonicalName]; ok { a, err := f() if err != nil { return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) } return a.info, nil } return nil, fmt.Errorf("AssetInfo %s not found", name) } // AssetDigest returns the digest of the file with the given name. It returns an // error if the asset could not be found or the digest could not be loaded. func AssetDigest(name string) ([sha256.Size]byte, error) { canonicalName := strings.Replace(name, "\\", "/", -1) if f, ok := _bindata[canonicalName]; ok { a, err := f() if err != nil { return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s can't read by error: %v", name, err) } return a.digest, nil } return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s not found", name) } // Digests returns a map of all known files and their checksums. func Digests() (map[string][sha256.Size]byte, error) { mp := make(map[string][sha256.Size]byte, len(_bindata)) for name := range _bindata { a, err := _bindata[name]() if err != nil { return nil, err } mp[name] = a.digest } return mp, nil } // AssetNames returns the names of the assets. func AssetNames() []string { names := make([]string, 0, len(_bindata)) for name := range _bindata { names = append(names, name) } return names } // _bindata is a table, holding each asset generator, mapped to its name. var _bindata = map[string]func() (*asset, error){ "jsonschema-draft-04.json": jsonschemaDraft04JSON, "v2/schema.json": v2SchemaJSON, } // AssetDir returns the file names below a certain // directory embedded in the file by go-bindata. // For example if you run go-bindata on data/... and data contains the // following hierarchy: // data/ // foo.txt // img/ // a.png // b.png // then AssetDir("data") would return []string{"foo.txt", "img"}, // AssetDir("data/img") would return []string{"a.png", "b.png"}, // AssetDir("foo.txt") and AssetDir("notexist") would return an error, and // AssetDir("") will return []string{"data"}. func AssetDir(name string) ([]string, error) { node := _bintree if len(name) != 0 { canonicalName := strings.Replace(name, "\\", "/", -1) pathList := strings.Split(canonicalName, "/") for _, p := range pathList { node = node.Children[p] if node == nil { return nil, fmt.Errorf("Asset %s not found", name) } } } if node.Func != nil { return nil, fmt.Errorf("Asset %s not found", name) } rv := make([]string, 0, len(node.Children)) for childName := range node.Children { rv = append(rv, childName) } return rv, nil } type bintree struct { Func func() (*asset, error) Children map[string]*bintree } var _bintree = &bintree{nil, map[string]*bintree{ "jsonschema-draft-04.json": &bintree{jsonschemaDraft04JSON, map[string]*bintree{}}, "v2": &bintree{nil, map[string]*bintree{ "schema.json": &bintree{v2SchemaJSON, map[string]*bintree{}}, }}, }} // RestoreAsset restores an asset under the given directory. func RestoreAsset(dir, name string) error { data, err := Asset(name) if err != nil { return err } info, err := AssetInfo(name) if err != nil { return err } err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) if err != nil { return err } err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) if err != nil { return err } return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) } // RestoreAssets restores an asset under the given directory recursively. func RestoreAssets(dir, name string) error { children, err := AssetDir(name) // File if err != nil { return RestoreAsset(dir, name) } // Dir for _, child := range children { err = RestoreAssets(dir, filepath.Join(name, child)) if err != nil { return err } } return nil } func _filePath(dir, name string) string { canonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...) } ================================================ FILE: vendor/github.com/go-openapi/spec/cache.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import "sync" // ResolutionCache a cache for resolving urls type ResolutionCache interface { Get(string) (interface{}, bool) Set(string, interface{}) } type simpleCache struct { lock sync.RWMutex store map[string]interface{} } // Get retrieves a cached URI func (s *simpleCache) Get(uri string) (interface{}, bool) { debugLog("getting %q from resolution cache", uri) s.lock.RLock() v, ok := s.store[uri] debugLog("got %q from resolution cache: %t", uri, ok) s.lock.RUnlock() return v, ok } // Set caches a URI func (s *simpleCache) Set(uri string, data interface{}) { s.lock.Lock() s.store[uri] = data s.lock.Unlock() } var resCache ResolutionCache func init() { resCache = initResolutionCache() } // initResolutionCache initializes the URI resolution cache func initResolutionCache() ResolutionCache { return &simpleCache{store: map[string]interface{}{ "http://swagger.io/v2/schema.json": MustLoadSwagger20Schema(), "http://json-schema.org/draft-04/schema": MustLoadJSONSchemaDraft04(), }} } ================================================ FILE: vendor/github.com/go-openapi/spec/contact_info.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec // ContactInfo contact information for the exposed API. // // For more information: http://goo.gl/8us55a#contactObject type ContactInfo struct { Name string `json:"name,omitempty"` URL string `json:"url,omitempty"` Email string `json:"email,omitempty"` } ================================================ FILE: vendor/github.com/go-openapi/spec/debug.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "fmt" "log" "os" "path/filepath" "runtime" ) var ( // Debug is true when the SWAGGER_DEBUG env var is not empty. // It enables a more verbose logging of this package. Debug = os.Getenv("SWAGGER_DEBUG") != "" // specLogger is a debug logger for this package specLogger *log.Logger ) func init() { debugOptions() } func debugOptions() { specLogger = log.New(os.Stdout, "spec:", log.LstdFlags) } func debugLog(msg string, args ...interface{}) { // A private, trivial trace logger, based on go-openapi/spec/expander.go:debugLog() if Debug { _, file1, pos1, _ := runtime.Caller(1) specLogger.Printf("%s:%d: %s", filepath.Base(file1), pos1, fmt.Sprintf(msg, args...)) } } ================================================ FILE: vendor/github.com/go-openapi/spec/expander.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "encoding/json" "fmt" "strings" ) // ExpandOptions provides options for spec expand type ExpandOptions struct { RelativeBase string SkipSchemas bool ContinueOnError bool AbsoluteCircularRef bool } // ResolveRefWithBase resolves a reference against a context root with preservation of base path func ResolveRefWithBase(root interface{}, ref *Ref, opts *ExpandOptions) (*Schema, error) { resolver, err := defaultSchemaLoader(root, opts, nil, nil) if err != nil { return nil, err } specBasePath := "" if opts != nil && opts.RelativeBase != "" { specBasePath, _ = absPath(opts.RelativeBase) } result := new(Schema) if err := resolver.Resolve(ref, result, specBasePath); err != nil { return nil, err } return result, nil } // ResolveRef resolves a reference against a context root // ref is guaranteed to be in root (no need to go to external files) // ResolveRef is ONLY called from the code generation module func ResolveRef(root interface{}, ref *Ref) (*Schema, error) { res, _, err := ref.GetPointer().Get(root) if err != nil { panic(err) } switch sch := res.(type) { case Schema: return &sch, nil case *Schema: return sch, nil case map[string]interface{}: b, _ := json.Marshal(sch) newSch := new(Schema) _ = json.Unmarshal(b, newSch) return newSch, nil default: return nil, fmt.Errorf("unknown type for the resolved reference") } } // ResolveParameter resolves a parameter reference against a context root func ResolveParameter(root interface{}, ref Ref) (*Parameter, error) { return ResolveParameterWithBase(root, ref, nil) } // ResolveParameterWithBase resolves a parameter reference against a context root and base path func ResolveParameterWithBase(root interface{}, ref Ref, opts *ExpandOptions) (*Parameter, error) { resolver, err := defaultSchemaLoader(root, opts, nil, nil) if err != nil { return nil, err } result := new(Parameter) if err := resolver.Resolve(&ref, result, ""); err != nil { return nil, err } return result, nil } // ResolveResponse resolves response a reference against a context root func ResolveResponse(root interface{}, ref Ref) (*Response, error) { return ResolveResponseWithBase(root, ref, nil) } // ResolveResponseWithBase resolves response a reference against a context root and base path func ResolveResponseWithBase(root interface{}, ref Ref, opts *ExpandOptions) (*Response, error) { resolver, err := defaultSchemaLoader(root, opts, nil, nil) if err != nil { return nil, err } result := new(Response) if err := resolver.Resolve(&ref, result, ""); err != nil { return nil, err } return result, nil } // ResolveItems resolves parameter items reference against a context root and base path. // // NOTE: stricly speaking, this construct is not supported by Swagger 2.0. // Similarly, $ref are forbidden in response headers. func ResolveItems(root interface{}, ref Ref, opts *ExpandOptions) (*Items, error) { resolver, err := defaultSchemaLoader(root, opts, nil, nil) if err != nil { return nil, err } basePath := "" if opts.RelativeBase != "" { basePath = opts.RelativeBase } result := new(Items) if err := resolver.Resolve(&ref, result, basePath); err != nil { return nil, err } return result, nil } // ResolvePathItem resolves response a path item against a context root and base path func ResolvePathItem(root interface{}, ref Ref, opts *ExpandOptions) (*PathItem, error) { resolver, err := defaultSchemaLoader(root, opts, nil, nil) if err != nil { return nil, err } basePath := "" if opts.RelativeBase != "" { basePath = opts.RelativeBase } result := new(PathItem) if err := resolver.Resolve(&ref, result, basePath); err != nil { return nil, err } return result, nil } // ExpandSpec expands the references in a swagger spec func ExpandSpec(spec *Swagger, options *ExpandOptions) error { resolver, err := defaultSchemaLoader(spec, options, nil, nil) // Just in case this ever returns an error. if resolver.shouldStopOnError(err) { return err } // getting the base path of the spec to adjust all subsequent reference resolutions specBasePath := "" if options != nil && options.RelativeBase != "" { specBasePath, _ = absPath(options.RelativeBase) } if options == nil || !options.SkipSchemas { for key, definition := range spec.Definitions { var def *Schema var err error if def, err = expandSchema(definition, []string{fmt.Sprintf("#/definitions/%s", key)}, resolver, specBasePath); resolver.shouldStopOnError(err) { return err } if def != nil { spec.Definitions[key] = *def } } } for key := range spec.Parameters { parameter := spec.Parameters[key] if err := expandParameterOrResponse(¶meter, resolver, specBasePath); resolver.shouldStopOnError(err) { return err } spec.Parameters[key] = parameter } for key := range spec.Responses { response := spec.Responses[key] if err := expandParameterOrResponse(&response, resolver, specBasePath); resolver.shouldStopOnError(err) { return err } spec.Responses[key] = response } if spec.Paths != nil { for key := range spec.Paths.Paths { path := spec.Paths.Paths[key] if err := expandPathItem(&path, resolver, specBasePath); resolver.shouldStopOnError(err) { return err } spec.Paths.Paths[key] = path } } return nil } // baseForRoot loads in the cache the root document and produces a fake "root" base path entry // for further $ref resolution func baseForRoot(root interface{}, cache ResolutionCache) string { // cache the root document to resolve $ref's const rootBase = "root" if root != nil { base, _ := absPath(rootBase) normalizedBase := normalizeAbsPath(base) debugLog("setting root doc in cache at: %s", normalizedBase) if cache == nil { cache = resCache } cache.Set(normalizedBase, root) return rootBase } return "" } // ExpandSchema expands the refs in the schema object with reference to the root object // go-openapi/validate uses this function // notice that it is impossible to reference a json schema in a different file other than root func ExpandSchema(schema *Schema, root interface{}, cache ResolutionCache) error { opts := &ExpandOptions{ // when a root is specified, cache the root as an in-memory document for $ref retrieval RelativeBase: baseForRoot(root, cache), SkipSchemas: false, ContinueOnError: false, // when no base path is specified, remaining $ref (circular) are rendered with an absolute path AbsoluteCircularRef: true, } return ExpandSchemaWithBasePath(schema, cache, opts) } // ExpandSchemaWithBasePath expands the refs in the schema object, base path configured through expand options func ExpandSchemaWithBasePath(schema *Schema, cache ResolutionCache, opts *ExpandOptions) error { if schema == nil { return nil } var basePath string if opts.RelativeBase != "" { basePath, _ = absPath(opts.RelativeBase) } resolver, err := defaultSchemaLoader(nil, opts, cache, nil) if err != nil { return err } refs := []string{""} var s *Schema if s, err = expandSchema(*schema, refs, resolver, basePath); err != nil { return err } *schema = *s return nil } func expandItems(target Schema, parentRefs []string, resolver *schemaLoader, basePath string) (*Schema, error) { if target.Items != nil { if target.Items.Schema != nil { t, err := expandSchema(*target.Items.Schema, parentRefs, resolver, basePath) if err != nil { return nil, err } *target.Items.Schema = *t } for i := range target.Items.Schemas { t, err := expandSchema(target.Items.Schemas[i], parentRefs, resolver, basePath) if err != nil { return nil, err } target.Items.Schemas[i] = *t } } return &target, nil } func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, basePath string) (*Schema, error) { if target.Ref.String() == "" && target.Ref.IsRoot() { // normalizing is important newRef := normalizeFileRef(&target.Ref, basePath) target.Ref = *newRef return &target, nil } // change the base path of resolution when an ID is encountered // otherwise the basePath should inherit the parent's // important: ID can be relative path if target.ID != "" { debugLog("schema has ID: %s", target.ID) // handling the case when id is a folder // remember that basePath has to be a file refPath := target.ID if strings.HasSuffix(target.ID, "/") { // path.Clean here would not work correctly if basepath is http refPath = fmt.Sprintf("%s%s", refPath, "placeholder.json") } basePath = normalizePaths(refPath, basePath) } var t *Schema // if Ref is found, everything else doesn't matter // Ref also changes the resolution scope of children expandSchema if target.Ref.String() != "" { // here the resolution scope is changed because a $ref was encountered normalizedRef := normalizeFileRef(&target.Ref, basePath) normalizedBasePath := normalizedRef.RemoteURI() if resolver.isCircular(normalizedRef, basePath, parentRefs...) { // this means there is a cycle in the recursion tree: return the Ref // - circular refs cannot be expanded. We leave them as ref. // - denormalization means that a new local file ref is set relative to the original basePath debugLog("shortcut circular ref: basePath: %s, normalizedPath: %s, normalized ref: %s", basePath, normalizedBasePath, normalizedRef.String()) if !resolver.options.AbsoluteCircularRef { target.Ref = *denormalizeFileRef(normalizedRef, normalizedBasePath, resolver.context.basePath) } else { target.Ref = *normalizedRef } return &target, nil } debugLog("basePath: %s: calling Resolve with target: %#v", basePath, target) if err := resolver.Resolve(&target.Ref, &t, basePath); resolver.shouldStopOnError(err) { return nil, err } if t != nil { parentRefs = append(parentRefs, normalizedRef.String()) var err error transitiveResolver, err := resolver.transitiveResolver(basePath, target.Ref) if transitiveResolver.shouldStopOnError(err) { return nil, err } basePath = resolver.updateBasePath(transitiveResolver, normalizedBasePath) return expandSchema(*t, parentRefs, transitiveResolver, basePath) } } t, err := expandItems(target, parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { return &target, err } if t != nil { target = *t } for i := range target.AllOf { t, err := expandSchema(target.AllOf[i], parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { return &target, err } target.AllOf[i] = *t } for i := range target.AnyOf { t, err := expandSchema(target.AnyOf[i], parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { return &target, err } target.AnyOf[i] = *t } for i := range target.OneOf { t, err := expandSchema(target.OneOf[i], parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { return &target, err } if t != nil { target.OneOf[i] = *t } } if target.Not != nil { t, err := expandSchema(*target.Not, parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { return &target, err } if t != nil { *target.Not = *t } } for k := range target.Properties { t, err := expandSchema(target.Properties[k], parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { return &target, err } if t != nil { target.Properties[k] = *t } } if target.AdditionalProperties != nil && target.AdditionalProperties.Schema != nil { t, err := expandSchema(*target.AdditionalProperties.Schema, parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { return &target, err } if t != nil { *target.AdditionalProperties.Schema = *t } } for k := range target.PatternProperties { t, err := expandSchema(target.PatternProperties[k], parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { return &target, err } if t != nil { target.PatternProperties[k] = *t } } for k := range target.Dependencies { if target.Dependencies[k].Schema != nil { t, err := expandSchema(*target.Dependencies[k].Schema, parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { return &target, err } if t != nil { *target.Dependencies[k].Schema = *t } } } if target.AdditionalItems != nil && target.AdditionalItems.Schema != nil { t, err := expandSchema(*target.AdditionalItems.Schema, parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { return &target, err } if t != nil { *target.AdditionalItems.Schema = *t } } for k := range target.Definitions { t, err := expandSchema(target.Definitions[k], parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { return &target, err } if t != nil { target.Definitions[k] = *t } } return &target, nil } func expandPathItem(pathItem *PathItem, resolver *schemaLoader, basePath string) error { if pathItem == nil { return nil } parentRefs := []string{} if err := resolver.deref(pathItem, parentRefs, basePath); resolver.shouldStopOnError(err) { return err } if pathItem.Ref.String() != "" { var err error resolver, err = resolver.transitiveResolver(basePath, pathItem.Ref) if resolver.shouldStopOnError(err) { return err } } pathItem.Ref = Ref{} for idx := range pathItem.Parameters { if err := expandParameterOrResponse(&(pathItem.Parameters[idx]), resolver, basePath); resolver.shouldStopOnError(err) { return err } } ops := []*Operation{ pathItem.Get, pathItem.Head, pathItem.Options, pathItem.Put, pathItem.Post, pathItem.Patch, pathItem.Delete, } for _, op := range ops { if err := expandOperation(op, resolver, basePath); resolver.shouldStopOnError(err) { return err } } return nil } func expandOperation(op *Operation, resolver *schemaLoader, basePath string) error { if op == nil { return nil } for i := range op.Parameters { param := op.Parameters[i] if err := expandParameterOrResponse(¶m, resolver, basePath); resolver.shouldStopOnError(err) { return err } op.Parameters[i] = param } if op.Responses != nil { responses := op.Responses if err := expandParameterOrResponse(responses.Default, resolver, basePath); resolver.shouldStopOnError(err) { return err } for code := range responses.StatusCodeResponses { response := responses.StatusCodeResponses[code] if err := expandParameterOrResponse(&response, resolver, basePath); resolver.shouldStopOnError(err) { return err } responses.StatusCodeResponses[code] = response } } return nil } // ExpandResponseWithRoot expands a response based on a root document, not a fetchable document func ExpandResponseWithRoot(response *Response, root interface{}, cache ResolutionCache) error { opts := &ExpandOptions{ RelativeBase: baseForRoot(root, cache), SkipSchemas: false, ContinueOnError: false, // when no base path is specified, remaining $ref (circular) are rendered with an absolute path AbsoluteCircularRef: true, } resolver, err := defaultSchemaLoader(root, opts, nil, nil) if err != nil { return err } return expandParameterOrResponse(response, resolver, opts.RelativeBase) } // ExpandResponse expands a response based on a basepath // This is the exported version of expandResponse // all refs inside response will be resolved relative to basePath func ExpandResponse(response *Response, basePath string) error { var specBasePath string if basePath != "" { specBasePath, _ = absPath(basePath) } opts := &ExpandOptions{ RelativeBase: specBasePath, } resolver, err := defaultSchemaLoader(nil, opts, nil, nil) if err != nil { return err } return expandParameterOrResponse(response, resolver, opts.RelativeBase) } // ExpandParameterWithRoot expands a parameter based on a root document, not a fetchable document func ExpandParameterWithRoot(parameter *Parameter, root interface{}, cache ResolutionCache) error { opts := &ExpandOptions{ RelativeBase: baseForRoot(root, cache), SkipSchemas: false, ContinueOnError: false, // when no base path is specified, remaining $ref (circular) are rendered with an absolute path AbsoluteCircularRef: true, } resolver, err := defaultSchemaLoader(root, opts, nil, nil) if err != nil { return err } return expandParameterOrResponse(parameter, resolver, opts.RelativeBase) } // ExpandParameter expands a parameter based on a basepath. // This is the exported version of expandParameter // all refs inside parameter will be resolved relative to basePath func ExpandParameter(parameter *Parameter, basePath string) error { var specBasePath string if basePath != "" { specBasePath, _ = absPath(basePath) } opts := &ExpandOptions{ RelativeBase: specBasePath, } resolver, err := defaultSchemaLoader(nil, opts, nil, nil) if err != nil { return err } return expandParameterOrResponse(parameter, resolver, opts.RelativeBase) } func getRefAndSchema(input interface{}) (*Ref, *Schema, error) { var ref *Ref var sch *Schema switch refable := input.(type) { case *Parameter: if refable == nil { return nil, nil, nil } ref = &refable.Ref sch = refable.Schema case *Response: if refable == nil { return nil, nil, nil } ref = &refable.Ref sch = refable.Schema default: return nil, nil, fmt.Errorf("expand: unsupported type %T. Input should be of type *Parameter or *Response", input) } return ref, sch, nil } func expandParameterOrResponse(input interface{}, resolver *schemaLoader, basePath string) error { ref, _, err := getRefAndSchema(input) if err != nil { return err } if ref == nil { return nil } parentRefs := []string{} if err := resolver.deref(input, parentRefs, basePath); resolver.shouldStopOnError(err) { return err } ref, sch, _ := getRefAndSchema(input) if ref.String() != "" { transitiveResolver, err := resolver.transitiveResolver(basePath, *ref) if transitiveResolver.shouldStopOnError(err) { return err } basePath = resolver.updateBasePath(transitiveResolver, basePath) resolver = transitiveResolver } if sch != nil && sch.Ref.String() != "" { // schema expanded to a $ref in another root var ern error sch.Ref, ern = NewRef(normalizePaths(sch.Ref.String(), ref.RemoteURI())) if ern != nil { return ern } } if ref != nil { *ref = Ref{} } if !resolver.options.SkipSchemas && sch != nil { s, err := expandSchema(*sch, parentRefs, resolver, basePath) if resolver.shouldStopOnError(err) { return err } *sch = *s } return nil } ================================================ FILE: vendor/github.com/go-openapi/spec/external_docs.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec // ExternalDocumentation allows referencing an external resource for // extended documentation. // // For more information: http://goo.gl/8us55a#externalDocumentationObject type ExternalDocumentation struct { Description string `json:"description,omitempty"` URL string `json:"url,omitempty"` } ================================================ FILE: vendor/github.com/go-openapi/spec/go.mod ================================================ module github.com/go-openapi/spec require ( github.com/PuerkitoBio/purell v1.1.0 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-openapi/jsonpointer v0.17.0 github.com/go-openapi/jsonreference v0.17.0 github.com/go-openapi/swag v0.17.0 github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/testify v1.2.2 golang.org/x/net v0.0.0-20181005035420-146acd28ed58 // indirect golang.org/x/text v0.3.0 // indirect gopkg.in/yaml.v2 v2.2.1 ) ================================================ FILE: vendor/github.com/go-openapi/spec/go.sum ================================================ github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-openapi/jsonpointer v0.17.0 h1:Bpl2DtZ6k7wKqfFs7e+4P08+M9I3FQgn09a1UsRUQbk= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonreference v0.17.0 h1:d/o7/fsLWWQZACbihvZxcyLQ59jfUVs7WOJv/ak7T7A= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/swag v0.17.0 h1:7wu+dZ5k83kvUWeAb+WUkFiUhDzwGqzTR/NhWzeo1JU= github.com/go-openapi/swag v0.17.0/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/net v0.0.0-20181005035420-146acd28ed58 h1:otZG8yDCO4LVps5+9bxOeNiCvgmOyt96J3roHTYs7oE= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= ================================================ FILE: vendor/github.com/go-openapi/spec/header.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "encoding/json" "strings" "github.com/go-openapi/jsonpointer" "github.com/go-openapi/swag" ) const ( jsonArray = "array" ) // HeaderProps describes a response header type HeaderProps struct { Description string `json:"description,omitempty"` } // Header describes a header for a response of the API // // For more information: http://goo.gl/8us55a#headerObject type Header struct { CommonValidations SimpleSchema VendorExtensible HeaderProps } // ResponseHeader creates a new header instance for use in a response func ResponseHeader() *Header { return new(Header) } // WithDescription sets the description on this response, allows for chaining func (h *Header) WithDescription(description string) *Header { h.Description = description return h } // Typed a fluent builder method for the type of parameter func (h *Header) Typed(tpe, format string) *Header { h.Type = tpe h.Format = format return h } // CollectionOf a fluent builder method for an array item func (h *Header) CollectionOf(items *Items, format string) *Header { h.Type = jsonArray h.Items = items h.CollectionFormat = format return h } // WithDefault sets the default value on this item func (h *Header) WithDefault(defaultValue interface{}) *Header { h.Default = defaultValue return h } // WithMaxLength sets a max length value func (h *Header) WithMaxLength(max int64) *Header { h.MaxLength = &max return h } // WithMinLength sets a min length value func (h *Header) WithMinLength(min int64) *Header { h.MinLength = &min return h } // WithPattern sets a pattern value func (h *Header) WithPattern(pattern string) *Header { h.Pattern = pattern return h } // WithMultipleOf sets a multiple of value func (h *Header) WithMultipleOf(number float64) *Header { h.MultipleOf = &number return h } // WithMaximum sets a maximum number value func (h *Header) WithMaximum(max float64, exclusive bool) *Header { h.Maximum = &max h.ExclusiveMaximum = exclusive return h } // WithMinimum sets a minimum number value func (h *Header) WithMinimum(min float64, exclusive bool) *Header { h.Minimum = &min h.ExclusiveMinimum = exclusive return h } // WithEnum sets a the enum values (replace) func (h *Header) WithEnum(values ...interface{}) *Header { h.Enum = append([]interface{}{}, values...) return h } // WithMaxItems sets the max items func (h *Header) WithMaxItems(size int64) *Header { h.MaxItems = &size return h } // WithMinItems sets the min items func (h *Header) WithMinItems(size int64) *Header { h.MinItems = &size return h } // UniqueValues dictates that this array can only have unique items func (h *Header) UniqueValues() *Header { h.UniqueItems = true return h } // AllowDuplicates this array can have duplicates func (h *Header) AllowDuplicates() *Header { h.UniqueItems = false return h } // MarshalJSON marshal this to JSON func (h Header) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(h.CommonValidations) if err != nil { return nil, err } b2, err := json.Marshal(h.SimpleSchema) if err != nil { return nil, err } b3, err := json.Marshal(h.HeaderProps) if err != nil { return nil, err } return swag.ConcatJSON(b1, b2, b3), nil } // UnmarshalJSON unmarshals this header from JSON func (h *Header) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &h.CommonValidations); err != nil { return err } if err := json.Unmarshal(data, &h.SimpleSchema); err != nil { return err } if err := json.Unmarshal(data, &h.VendorExtensible); err != nil { return err } return json.Unmarshal(data, &h.HeaderProps) } // JSONLookup look up a value by the json property name func (h Header) JSONLookup(token string) (interface{}, error) { if ex, ok := h.Extensions[token]; ok { return &ex, nil } r, _, err := jsonpointer.GetForToken(h.CommonValidations, token) if err != nil && !strings.HasPrefix(err.Error(), "object has no field") { return nil, err } if r != nil { return r, nil } r, _, err = jsonpointer.GetForToken(h.SimpleSchema, token) if err != nil && !strings.HasPrefix(err.Error(), "object has no field") { return nil, err } if r != nil { return r, nil } r, _, err = jsonpointer.GetForToken(h.HeaderProps, token) return r, err } ================================================ FILE: vendor/github.com/go-openapi/spec/info.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "encoding/json" "strings" "github.com/go-openapi/jsonpointer" "github.com/go-openapi/swag" ) // Extensions vendor specific extensions type Extensions map[string]interface{} // Add adds a value to these extensions func (e Extensions) Add(key string, value interface{}) { realKey := strings.ToLower(key) e[realKey] = value } // GetString gets a string value from the extensions func (e Extensions) GetString(key string) (string, bool) { if v, ok := e[strings.ToLower(key)]; ok { str, ok := v.(string) return str, ok } return "", false } // GetBool gets a string value from the extensions func (e Extensions) GetBool(key string) (bool, bool) { if v, ok := e[strings.ToLower(key)]; ok { str, ok := v.(bool) return str, ok } return false, false } // GetStringSlice gets a string value from the extensions func (e Extensions) GetStringSlice(key string) ([]string, bool) { if v, ok := e[strings.ToLower(key)]; ok { arr, isSlice := v.([]interface{}) if !isSlice { return nil, false } var strs []string for _, iface := range arr { str, isString := iface.(string) if !isString { return nil, false } strs = append(strs, str) } return strs, ok } return nil, false } // VendorExtensible composition block. type VendorExtensible struct { Extensions Extensions } // AddExtension adds an extension to this extensible object func (v *VendorExtensible) AddExtension(key string, value interface{}) { if value == nil { return } if v.Extensions == nil { v.Extensions = make(map[string]interface{}) } v.Extensions.Add(key, value) } // MarshalJSON marshals the extensions to json func (v VendorExtensible) MarshalJSON() ([]byte, error) { toser := make(map[string]interface{}) for k, v := range v.Extensions { lk := strings.ToLower(k) if strings.HasPrefix(lk, "x-") { toser[k] = v } } return json.Marshal(toser) } // UnmarshalJSON for this extensible object func (v *VendorExtensible) UnmarshalJSON(data []byte) error { var d map[string]interface{} if err := json.Unmarshal(data, &d); err != nil { return err } for k, vv := range d { lk := strings.ToLower(k) if strings.HasPrefix(lk, "x-") { if v.Extensions == nil { v.Extensions = map[string]interface{}{} } v.Extensions[k] = vv } } return nil } // InfoProps the properties for an info definition type InfoProps struct { Description string `json:"description,omitempty"` Title string `json:"title,omitempty"` TermsOfService string `json:"termsOfService,omitempty"` Contact *ContactInfo `json:"contact,omitempty"` License *License `json:"license,omitempty"` Version string `json:"version,omitempty"` } // Info object provides metadata about the API. // The metadata can be used by the clients if needed, and can be presented in the Swagger-UI for convenience. // // For more information: http://goo.gl/8us55a#infoObject type Info struct { VendorExtensible InfoProps } // JSONLookup look up a value by the json property name func (i Info) JSONLookup(token string) (interface{}, error) { if ex, ok := i.Extensions[token]; ok { return &ex, nil } r, _, err := jsonpointer.GetForToken(i.InfoProps, token) return r, err } // MarshalJSON marshal this to JSON func (i Info) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(i.InfoProps) if err != nil { return nil, err } b2, err := json.Marshal(i.VendorExtensible) if err != nil { return nil, err } return swag.ConcatJSON(b1, b2), nil } // UnmarshalJSON marshal this from JSON func (i *Info) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &i.InfoProps); err != nil { return err } return json.Unmarshal(data, &i.VendorExtensible) } ================================================ FILE: vendor/github.com/go-openapi/spec/items.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "encoding/json" "strings" "github.com/go-openapi/jsonpointer" "github.com/go-openapi/swag" ) const ( jsonRef = "$ref" ) // SimpleSchema describe swagger simple schemas for parameters and headers type SimpleSchema struct { Type string `json:"type,omitempty"` Format string `json:"format,omitempty"` Items *Items `json:"items,omitempty"` CollectionFormat string `json:"collectionFormat,omitempty"` Default interface{} `json:"default,omitempty"` Example interface{} `json:"example,omitempty"` } // TypeName return the type (or format) of a simple schema func (s *SimpleSchema) TypeName() string { if s.Format != "" { return s.Format } return s.Type } // ItemsTypeName yields the type of items in a simple schema array func (s *SimpleSchema) ItemsTypeName() string { if s.Items == nil { return "" } return s.Items.TypeName() } // CommonValidations describe common JSON-schema validations type CommonValidations struct { Maximum *float64 `json:"maximum,omitempty"` ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"` Minimum *float64 `json:"minimum,omitempty"` ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"` MaxLength *int64 `json:"maxLength,omitempty"` MinLength *int64 `json:"minLength,omitempty"` Pattern string `json:"pattern,omitempty"` MaxItems *int64 `json:"maxItems,omitempty"` MinItems *int64 `json:"minItems,omitempty"` UniqueItems bool `json:"uniqueItems,omitempty"` MultipleOf *float64 `json:"multipleOf,omitempty"` Enum []interface{} `json:"enum,omitempty"` } // Items a limited subset of JSON-Schema's items object. // It is used by parameter definitions that are not located in "body". // // For more information: http://goo.gl/8us55a#items-object type Items struct { Refable CommonValidations SimpleSchema VendorExtensible } // NewItems creates a new instance of items func NewItems() *Items { return &Items{} } // Typed a fluent builder method for the type of item func (i *Items) Typed(tpe, format string) *Items { i.Type = tpe i.Format = format return i } // CollectionOf a fluent builder method for an array item func (i *Items) CollectionOf(items *Items, format string) *Items { i.Type = jsonArray i.Items = items i.CollectionFormat = format return i } // WithDefault sets the default value on this item func (i *Items) WithDefault(defaultValue interface{}) *Items { i.Default = defaultValue return i } // WithMaxLength sets a max length value func (i *Items) WithMaxLength(max int64) *Items { i.MaxLength = &max return i } // WithMinLength sets a min length value func (i *Items) WithMinLength(min int64) *Items { i.MinLength = &min return i } // WithPattern sets a pattern value func (i *Items) WithPattern(pattern string) *Items { i.Pattern = pattern return i } // WithMultipleOf sets a multiple of value func (i *Items) WithMultipleOf(number float64) *Items { i.MultipleOf = &number return i } // WithMaximum sets a maximum number value func (i *Items) WithMaximum(max float64, exclusive bool) *Items { i.Maximum = &max i.ExclusiveMaximum = exclusive return i } // WithMinimum sets a minimum number value func (i *Items) WithMinimum(min float64, exclusive bool) *Items { i.Minimum = &min i.ExclusiveMinimum = exclusive return i } // WithEnum sets a the enum values (replace) func (i *Items) WithEnum(values ...interface{}) *Items { i.Enum = append([]interface{}{}, values...) return i } // WithMaxItems sets the max items func (i *Items) WithMaxItems(size int64) *Items { i.MaxItems = &size return i } // WithMinItems sets the min items func (i *Items) WithMinItems(size int64) *Items { i.MinItems = &size return i } // UniqueValues dictates that this array can only have unique items func (i *Items) UniqueValues() *Items { i.UniqueItems = true return i } // AllowDuplicates this array can have duplicates func (i *Items) AllowDuplicates() *Items { i.UniqueItems = false return i } // UnmarshalJSON hydrates this items instance with the data from JSON func (i *Items) UnmarshalJSON(data []byte) error { var validations CommonValidations if err := json.Unmarshal(data, &validations); err != nil { return err } var ref Refable if err := json.Unmarshal(data, &ref); err != nil { return err } var simpleSchema SimpleSchema if err := json.Unmarshal(data, &simpleSchema); err != nil { return err } var vendorExtensible VendorExtensible if err := json.Unmarshal(data, &vendorExtensible); err != nil { return err } i.Refable = ref i.CommonValidations = validations i.SimpleSchema = simpleSchema i.VendorExtensible = vendorExtensible return nil } // MarshalJSON converts this items object to JSON func (i Items) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(i.CommonValidations) if err != nil { return nil, err } b2, err := json.Marshal(i.SimpleSchema) if err != nil { return nil, err } b3, err := json.Marshal(i.Refable) if err != nil { return nil, err } b4, err := json.Marshal(i.VendorExtensible) if err != nil { return nil, err } return swag.ConcatJSON(b4, b3, b1, b2), nil } // JSONLookup look up a value by the json property name func (i Items) JSONLookup(token string) (interface{}, error) { if token == jsonRef { return &i.Ref, nil } r, _, err := jsonpointer.GetForToken(i.CommonValidations, token) if err != nil && !strings.HasPrefix(err.Error(), "object has no field") { return nil, err } if r != nil { return r, nil } r, _, err = jsonpointer.GetForToken(i.SimpleSchema, token) return r, err } ================================================ FILE: vendor/github.com/go-openapi/spec/license.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec // License information for the exposed API. // // For more information: http://goo.gl/8us55a#licenseObject type License struct { Name string `json:"name,omitempty"` URL string `json:"url,omitempty"` } ================================================ FILE: vendor/github.com/go-openapi/spec/normalizer.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "fmt" "net/url" "os" "path" "path/filepath" "strings" ) // normalize absolute path for cache. // on Windows, drive letters should be converted to lower as scheme in net/url.URL func normalizeAbsPath(path string) string { u, err := url.Parse(path) if err != nil { debugLog("normalize absolute path failed: %s", err) return path } return u.String() } // base or refPath could be a file path or a URL // given a base absolute path and a ref path, return the absolute path of refPath // 1) if refPath is absolute, return it // 2) if refPath is relative, join it with basePath keeping the scheme, hosts, and ports if exists // base could be a directory or a full file path func normalizePaths(refPath, base string) string { refURL, _ := url.Parse(refPath) if path.IsAbs(refURL.Path) || filepath.IsAbs(refPath) { // refPath is actually absolute if refURL.Host != "" { return refPath } parts := strings.Split(refPath, "#") result := filepath.FromSlash(parts[0]) if len(parts) == 2 { result += "#" + parts[1] } return result } // relative refPath baseURL, _ := url.Parse(base) if !strings.HasPrefix(refPath, "#") { // combining paths if baseURL.Host != "" { baseURL.Path = path.Join(path.Dir(baseURL.Path), refURL.Path) } else { // base is a file newBase := fmt.Sprintf("%s#%s", filepath.Join(filepath.Dir(base), filepath.FromSlash(refURL.Path)), refURL.Fragment) return newBase } } // copying fragment from ref to base baseURL.Fragment = refURL.Fragment return baseURL.String() } // denormalizePaths returns to simplest notation on file $ref, // i.e. strips the absolute path and sets a path relative to the base path. // // This is currently used when we rewrite ref after a circular ref has been detected func denormalizeFileRef(ref *Ref, relativeBase, originalRelativeBase string) *Ref { debugLog("denormalizeFileRef for: %s", ref.String()) if ref.String() == "" || ref.IsRoot() || ref.HasFragmentOnly { return ref } // strip relativeBase from URI relativeBaseURL, _ := url.Parse(relativeBase) relativeBaseURL.Fragment = "" if relativeBaseURL.IsAbs() && strings.HasPrefix(ref.String(), relativeBase) { // this should work for absolute URI (e.g. http://...): we have an exact match, just trim prefix r, _ := NewRef(strings.TrimPrefix(ref.String(), relativeBase)) return &r } if relativeBaseURL.IsAbs() { // other absolute URL get unchanged (i.e. with a non-empty scheme) return ref } // for relative file URIs: originalRelativeBaseURL, _ := url.Parse(originalRelativeBase) originalRelativeBaseURL.Fragment = "" if strings.HasPrefix(ref.String(), originalRelativeBaseURL.String()) { // the resulting ref is in the expanded spec: return a local ref r, _ := NewRef(strings.TrimPrefix(ref.String(), originalRelativeBaseURL.String())) return &r } // check if we may set a relative path, considering the original base path for this spec. // Example: // spec is located at /mypath/spec.json // my normalized ref points to: /mypath/item.json#/target // expected result: item.json#/target parts := strings.Split(ref.String(), "#") relativePath, err := filepath.Rel(path.Dir(originalRelativeBaseURL.String()), parts[0]) if err != nil { // there is no common ancestor (e.g. different drives on windows) // leaves the ref unchanged return ref } if len(parts) == 2 { relativePath += "#" + parts[1] } r, _ := NewRef(relativePath) return &r } // relativeBase could be an ABSOLUTE file path or an ABSOLUTE URL func normalizeFileRef(ref *Ref, relativeBase string) *Ref { // This is important for when the reference is pointing to the root schema if ref.String() == "" { r, _ := NewRef(relativeBase) return &r } debugLog("normalizing %s against %s", ref.String(), relativeBase) s := normalizePaths(ref.String(), relativeBase) r, _ := NewRef(s) return &r } // absPath returns the absolute path of a file func absPath(fname string) (string, error) { if strings.HasPrefix(fname, "http") { return fname, nil } if filepath.IsAbs(fname) { return fname, nil } wd, err := os.Getwd() return filepath.Join(wd, fname), err } ================================================ FILE: vendor/github.com/go-openapi/spec/operation.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "bytes" "encoding/gob" "encoding/json" "sort" "github.com/go-openapi/jsonpointer" "github.com/go-openapi/swag" ) func init() { //gob.Register(map[string][]interface{}{}) gob.Register(map[string]interface{}{}) gob.Register([]interface{}{}) } // OperationProps describes an operation // // NOTES: // - schemes, when present must be from [http, https, ws, wss]: see validate // - Security is handled as a special case: see MarshalJSON function type OperationProps struct { Description string `json:"description,omitempty"` Consumes []string `json:"consumes,omitempty"` Produces []string `json:"produces,omitempty"` Schemes []string `json:"schemes,omitempty"` Tags []string `json:"tags,omitempty"` Summary string `json:"summary,omitempty"` ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"` ID string `json:"operationId,omitempty"` Deprecated bool `json:"deprecated,omitempty"` Security []map[string][]string `json:"security,omitempty"` Parameters []Parameter `json:"parameters,omitempty"` Responses *Responses `json:"responses,omitempty"` } // MarshalJSON takes care of serializing operation properties to JSON // // We use a custom marhaller here to handle a special cases related to // the Security field. We need to preserve zero length slice // while omitting the field when the value is nil/unset. func (op OperationProps) MarshalJSON() ([]byte, error) { type Alias OperationProps if op.Security == nil { return json.Marshal(&struct { Security []map[string][]string `json:"security,omitempty"` *Alias }{ Security: op.Security, Alias: (*Alias)(&op), }) } return json.Marshal(&struct { Security []map[string][]string `json:"security"` *Alias }{ Security: op.Security, Alias: (*Alias)(&op), }) } // Operation describes a single API operation on a path. // // For more information: http://goo.gl/8us55a#operationObject type Operation struct { VendorExtensible OperationProps } // SuccessResponse gets a success response model func (o *Operation) SuccessResponse() (*Response, int, bool) { if o.Responses == nil { return nil, 0, false } responseCodes := make([]int, 0, len(o.Responses.StatusCodeResponses)) for k := range o.Responses.StatusCodeResponses { if k >= 200 && k < 300 { responseCodes = append(responseCodes, k) } } if len(responseCodes) > 0 { sort.Ints(responseCodes) v := o.Responses.StatusCodeResponses[responseCodes[0]] return &v, responseCodes[0], true } return o.Responses.Default, 0, false } // JSONLookup look up a value by the json property name func (o Operation) JSONLookup(token string) (interface{}, error) { if ex, ok := o.Extensions[token]; ok { return &ex, nil } r, _, err := jsonpointer.GetForToken(o.OperationProps, token) return r, err } // UnmarshalJSON hydrates this items instance with the data from JSON func (o *Operation) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &o.OperationProps); err != nil { return err } return json.Unmarshal(data, &o.VendorExtensible) } // MarshalJSON converts this items object to JSON func (o Operation) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(o.OperationProps) if err != nil { return nil, err } b2, err := json.Marshal(o.VendorExtensible) if err != nil { return nil, err } concated := swag.ConcatJSON(b1, b2) return concated, nil } // NewOperation creates a new operation instance. // It expects an ID as parameter but not passing an ID is also valid. func NewOperation(id string) *Operation { op := new(Operation) op.ID = id return op } // WithID sets the ID property on this operation, allows for chaining. func (o *Operation) WithID(id string) *Operation { o.ID = id return o } // WithDescription sets the description on this operation, allows for chaining func (o *Operation) WithDescription(description string) *Operation { o.Description = description return o } // WithSummary sets the summary on this operation, allows for chaining func (o *Operation) WithSummary(summary string) *Operation { o.Summary = summary return o } // WithExternalDocs sets/removes the external docs for/from this operation. // When you pass empty strings as params the external documents will be removed. // When you pass non-empty string as one value then those values will be used on the external docs object. // So when you pass a non-empty description, you should also pass the url and vice versa. func (o *Operation) WithExternalDocs(description, url string) *Operation { if description == "" && url == "" { o.ExternalDocs = nil return o } if o.ExternalDocs == nil { o.ExternalDocs = &ExternalDocumentation{} } o.ExternalDocs.Description = description o.ExternalDocs.URL = url return o } // Deprecate marks the operation as deprecated func (o *Operation) Deprecate() *Operation { o.Deprecated = true return o } // Undeprecate marks the operation as not deprected func (o *Operation) Undeprecate() *Operation { o.Deprecated = false return o } // WithConsumes adds media types for incoming body values func (o *Operation) WithConsumes(mediaTypes ...string) *Operation { o.Consumes = append(o.Consumes, mediaTypes...) return o } // WithProduces adds media types for outgoing body values func (o *Operation) WithProduces(mediaTypes ...string) *Operation { o.Produces = append(o.Produces, mediaTypes...) return o } // WithTags adds tags for this operation func (o *Operation) WithTags(tags ...string) *Operation { o.Tags = append(o.Tags, tags...) return o } // AddParam adds a parameter to this operation, when a parameter for that location // and with that name already exists it will be replaced func (o *Operation) AddParam(param *Parameter) *Operation { if param == nil { return o } for i, p := range o.Parameters { if p.Name == param.Name && p.In == param.In { params := append(o.Parameters[:i], *param) params = append(params, o.Parameters[i+1:]...) o.Parameters = params return o } } o.Parameters = append(o.Parameters, *param) return o } // RemoveParam removes a parameter from the operation func (o *Operation) RemoveParam(name, in string) *Operation { for i, p := range o.Parameters { if p.Name == name && p.In == in { o.Parameters = append(o.Parameters[:i], o.Parameters[i+1:]...) return o } } return o } // SecuredWith adds a security scope to this operation. func (o *Operation) SecuredWith(name string, scopes ...string) *Operation { o.Security = append(o.Security, map[string][]string{name: scopes}) return o } // WithDefaultResponse adds a default response to the operation. // Passing a nil value will remove the response func (o *Operation) WithDefaultResponse(response *Response) *Operation { return o.RespondsWith(0, response) } // RespondsWith adds a status code response to the operation. // When the code is 0 the value of the response will be used as default response value. // When the value of the response is nil it will be removed from the operation func (o *Operation) RespondsWith(code int, response *Response) *Operation { if o.Responses == nil { o.Responses = new(Responses) } if code == 0 { o.Responses.Default = response return o } if response == nil { delete(o.Responses.StatusCodeResponses, code) return o } if o.Responses.StatusCodeResponses == nil { o.Responses.StatusCodeResponses = make(map[int]Response) } o.Responses.StatusCodeResponses[code] = *response return o } type opsAlias OperationProps type gobAlias struct { Security []map[string]struct { List []string Pad bool } Alias *opsAlias SecurityIsEmpty bool } // GobEncode provides a safe gob encoder for Operation, including empty security requirements func (o Operation) GobEncode() ([]byte, error) { raw := struct { Ext VendorExtensible Props OperationProps }{ Ext: o.VendorExtensible, Props: o.OperationProps, } var b bytes.Buffer err := gob.NewEncoder(&b).Encode(raw) return b.Bytes(), err } // GobDecode provides a safe gob decoder for Operation, including empty security requirements func (o *Operation) GobDecode(b []byte) error { var raw struct { Ext VendorExtensible Props OperationProps } buf := bytes.NewBuffer(b) err := gob.NewDecoder(buf).Decode(&raw) if err != nil { return err } o.VendorExtensible = raw.Ext o.OperationProps = raw.Props return nil } // GobEncode provides a safe gob encoder for Operation, including empty security requirements func (op OperationProps) GobEncode() ([]byte, error) { raw := gobAlias{ Alias: (*opsAlias)(&op), } var b bytes.Buffer if op.Security == nil { // nil security requirement err := gob.NewEncoder(&b).Encode(raw) return b.Bytes(), err } if len(op.Security) == 0 { // empty, but non-nil security requirement raw.SecurityIsEmpty = true raw.Alias.Security = nil err := gob.NewEncoder(&b).Encode(raw) return b.Bytes(), err } raw.Security = make([]map[string]struct { List []string Pad bool }, 0, len(op.Security)) for _, req := range op.Security { v := make(map[string]struct { List []string Pad bool }, len(req)) for k, val := range req { v[k] = struct { List []string Pad bool }{ List: val, } } raw.Security = append(raw.Security, v) } err := gob.NewEncoder(&b).Encode(raw) return b.Bytes(), err } // GobDecode provides a safe gob decoder for Operation, including empty security requirements func (op *OperationProps) GobDecode(b []byte) error { var raw gobAlias buf := bytes.NewBuffer(b) err := gob.NewDecoder(buf).Decode(&raw) if err != nil { return err } if raw.Alias == nil { return nil } switch { case raw.SecurityIsEmpty: // empty, but non-nil security requirement raw.Alias.Security = []map[string][]string{} case len(raw.Alias.Security) == 0: // nil security requirement raw.Alias.Security = nil default: raw.Alias.Security = make([]map[string][]string, 0, len(raw.Security)) for _, req := range raw.Security { v := make(map[string][]string, len(req)) for k, val := range req { v[k] = make([]string, 0, len(val.List)) v[k] = append(v[k], val.List...) } raw.Alias.Security = append(raw.Alias.Security, v) } } *op = *(*OperationProps)(raw.Alias) return nil } ================================================ FILE: vendor/github.com/go-openapi/spec/parameter.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "encoding/json" "strings" "github.com/go-openapi/jsonpointer" "github.com/go-openapi/swag" ) // QueryParam creates a query parameter func QueryParam(name string) *Parameter { return &Parameter{ParamProps: ParamProps{Name: name, In: "query"}} } // HeaderParam creates a header parameter, this is always required by default func HeaderParam(name string) *Parameter { return &Parameter{ParamProps: ParamProps{Name: name, In: "header", Required: true}} } // PathParam creates a path parameter, this is always required func PathParam(name string) *Parameter { return &Parameter{ParamProps: ParamProps{Name: name, In: "path", Required: true}} } // BodyParam creates a body parameter func BodyParam(name string, schema *Schema) *Parameter { return &Parameter{ParamProps: ParamProps{Name: name, In: "body", Schema: schema}, SimpleSchema: SimpleSchema{Type: "object"}} } // FormDataParam creates a body parameter func FormDataParam(name string) *Parameter { return &Parameter{ParamProps: ParamProps{Name: name, In: "formData"}} } // FileParam creates a body parameter func FileParam(name string) *Parameter { return &Parameter{ParamProps: ParamProps{Name: name, In: "formData"}, SimpleSchema: SimpleSchema{Type: "file"}} } // SimpleArrayParam creates a param for a simple array (string, int, date etc) func SimpleArrayParam(name, tpe, fmt string) *Parameter { return &Parameter{ParamProps: ParamProps{Name: name}, SimpleSchema: SimpleSchema{Type: jsonArray, CollectionFormat: "csv", Items: &Items{SimpleSchema: SimpleSchema{Type: "string", Format: fmt}}}} } // ParamRef creates a parameter that's a json reference func ParamRef(uri string) *Parameter { p := new(Parameter) p.Ref = MustCreateRef(uri) return p } // ParamProps describes the specific attributes of an operation parameter // // NOTE: // - Schema is defined when "in" == "body": see validate // - AllowEmptyValue is allowed where "in" == "query" || "formData" type ParamProps struct { Description string `json:"description,omitempty"` Name string `json:"name,omitempty"` In string `json:"in,omitempty"` Required bool `json:"required,omitempty"` Schema *Schema `json:"schema,omitempty"` AllowEmptyValue bool `json:"allowEmptyValue,omitempty"` } // Parameter a unique parameter is defined by a combination of a [name](#parameterName) and [location](#parameterIn). // // There are five possible parameter types. // * Path - Used together with [Path Templating](#pathTemplating), where the parameter value is actually part // of the operation's URL. This does not include the host or base path of the API. For example, in `/items/{itemId}`, // the path parameter is `itemId`. // * Query - Parameters that are appended to the URL. For example, in `/items?id=###`, the query parameter is `id`. // * Header - Custom headers that are expected as part of the request. // * Body - The payload that's appended to the HTTP request. Since there can only be one payload, there can only be // _one_ body parameter. The name of the body parameter has no effect on the parameter itself and is used for // documentation purposes only. Since Form parameters are also in the payload, body and form parameters cannot exist // together for the same operation. // * Form - Used to describe the payload of an HTTP request when either `application/x-www-form-urlencoded` or // `multipart/form-data` are used as the content type of the request (in Swagger's definition, // the [`consumes`](#operationConsumes) property of an operation). This is the only parameter type that can be used // to send files, thus supporting the `file` type. Since form parameters are sent in the payload, they cannot be // declared together with a body parameter for the same operation. Form parameters have a different format based on // the content-type used (for further details, consult http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4). // * `application/x-www-form-urlencoded` - Similar to the format of Query parameters but as a payload. // For example, `foo=1&bar=swagger` - both `foo` and `bar` are form parameters. This is normally used for simple // parameters that are being transferred. // * `multipart/form-data` - each parameter takes a section in the payload with an internal header. // For example, for the header `Content-Disposition: form-data; name="submit-name"` the name of the parameter is // `submit-name`. This type of form parameters is more commonly used for file transfers. // // For more information: http://goo.gl/8us55a#parameterObject type Parameter struct { Refable CommonValidations SimpleSchema VendorExtensible ParamProps } // JSONLookup look up a value by the json property name func (p Parameter) JSONLookup(token string) (interface{}, error) { if ex, ok := p.Extensions[token]; ok { return &ex, nil } if token == jsonRef { return &p.Ref, nil } r, _, err := jsonpointer.GetForToken(p.CommonValidations, token) if err != nil && !strings.HasPrefix(err.Error(), "object has no field") { return nil, err } if r != nil { return r, nil } r, _, err = jsonpointer.GetForToken(p.SimpleSchema, token) if err != nil && !strings.HasPrefix(err.Error(), "object has no field") { return nil, err } if r != nil { return r, nil } r, _, err = jsonpointer.GetForToken(p.ParamProps, token) return r, err } // WithDescription a fluent builder method for the description of the parameter func (p *Parameter) WithDescription(description string) *Parameter { p.Description = description return p } // Named a fluent builder method to override the name of the parameter func (p *Parameter) Named(name string) *Parameter { p.Name = name return p } // WithLocation a fluent builder method to override the location of the parameter func (p *Parameter) WithLocation(in string) *Parameter { p.In = in return p } // Typed a fluent builder method for the type of the parameter value func (p *Parameter) Typed(tpe, format string) *Parameter { p.Type = tpe p.Format = format return p } // CollectionOf a fluent builder method for an array parameter func (p *Parameter) CollectionOf(items *Items, format string) *Parameter { p.Type = jsonArray p.Items = items p.CollectionFormat = format return p } // WithDefault sets the default value on this parameter func (p *Parameter) WithDefault(defaultValue interface{}) *Parameter { p.AsOptional() // with default implies optional p.Default = defaultValue return p } // AllowsEmptyValues flags this parameter as being ok with empty values func (p *Parameter) AllowsEmptyValues() *Parameter { p.AllowEmptyValue = true return p } // NoEmptyValues flags this parameter as not liking empty values func (p *Parameter) NoEmptyValues() *Parameter { p.AllowEmptyValue = false return p } // AsOptional flags this parameter as optional func (p *Parameter) AsOptional() *Parameter { p.Required = false return p } // AsRequired flags this parameter as required func (p *Parameter) AsRequired() *Parameter { if p.Default != nil { // with a default required makes no sense return p } p.Required = true return p } // WithMaxLength sets a max length value func (p *Parameter) WithMaxLength(max int64) *Parameter { p.MaxLength = &max return p } // WithMinLength sets a min length value func (p *Parameter) WithMinLength(min int64) *Parameter { p.MinLength = &min return p } // WithPattern sets a pattern value func (p *Parameter) WithPattern(pattern string) *Parameter { p.Pattern = pattern return p } // WithMultipleOf sets a multiple of value func (p *Parameter) WithMultipleOf(number float64) *Parameter { p.MultipleOf = &number return p } // WithMaximum sets a maximum number value func (p *Parameter) WithMaximum(max float64, exclusive bool) *Parameter { p.Maximum = &max p.ExclusiveMaximum = exclusive return p } // WithMinimum sets a minimum number value func (p *Parameter) WithMinimum(min float64, exclusive bool) *Parameter { p.Minimum = &min p.ExclusiveMinimum = exclusive return p } // WithEnum sets a the enum values (replace) func (p *Parameter) WithEnum(values ...interface{}) *Parameter { p.Enum = append([]interface{}{}, values...) return p } // WithMaxItems sets the max items func (p *Parameter) WithMaxItems(size int64) *Parameter { p.MaxItems = &size return p } // WithMinItems sets the min items func (p *Parameter) WithMinItems(size int64) *Parameter { p.MinItems = &size return p } // UniqueValues dictates that this array can only have unique items func (p *Parameter) UniqueValues() *Parameter { p.UniqueItems = true return p } // AllowDuplicates this array can have duplicates func (p *Parameter) AllowDuplicates() *Parameter { p.UniqueItems = false return p } // UnmarshalJSON hydrates this items instance with the data from JSON func (p *Parameter) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &p.CommonValidations); err != nil { return err } if err := json.Unmarshal(data, &p.Refable); err != nil { return err } if err := json.Unmarshal(data, &p.SimpleSchema); err != nil { return err } if err := json.Unmarshal(data, &p.VendorExtensible); err != nil { return err } return json.Unmarshal(data, &p.ParamProps) } // MarshalJSON converts this items object to JSON func (p Parameter) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(p.CommonValidations) if err != nil { return nil, err } b2, err := json.Marshal(p.SimpleSchema) if err != nil { return nil, err } b3, err := json.Marshal(p.Refable) if err != nil { return nil, err } b4, err := json.Marshal(p.VendorExtensible) if err != nil { return nil, err } b5, err := json.Marshal(p.ParamProps) if err != nil { return nil, err } return swag.ConcatJSON(b3, b1, b2, b4, b5), nil } ================================================ FILE: vendor/github.com/go-openapi/spec/path_item.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "encoding/json" "github.com/go-openapi/jsonpointer" "github.com/go-openapi/swag" ) // PathItemProps the path item specific properties type PathItemProps struct { Get *Operation `json:"get,omitempty"` Put *Operation `json:"put,omitempty"` Post *Operation `json:"post,omitempty"` Delete *Operation `json:"delete,omitempty"` Options *Operation `json:"options,omitempty"` Head *Operation `json:"head,omitempty"` Patch *Operation `json:"patch,omitempty"` Parameters []Parameter `json:"parameters,omitempty"` } // PathItem describes the operations available on a single path. // A Path Item may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering). // The path itself is still exposed to the documentation viewer but they will // not know which operations and parameters are available. // // For more information: http://goo.gl/8us55a#pathItemObject type PathItem struct { Refable VendorExtensible PathItemProps } // JSONLookup look up a value by the json property name func (p PathItem) JSONLookup(token string) (interface{}, error) { if ex, ok := p.Extensions[token]; ok { return &ex, nil } if token == jsonRef { return &p.Ref, nil } r, _, err := jsonpointer.GetForToken(p.PathItemProps, token) return r, err } // UnmarshalJSON hydrates this items instance with the data from JSON func (p *PathItem) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &p.Refable); err != nil { return err } if err := json.Unmarshal(data, &p.VendorExtensible); err != nil { return err } return json.Unmarshal(data, &p.PathItemProps) } // MarshalJSON converts this items object to JSON func (p PathItem) MarshalJSON() ([]byte, error) { b3, err := json.Marshal(p.Refable) if err != nil { return nil, err } b4, err := json.Marshal(p.VendorExtensible) if err != nil { return nil, err } b5, err := json.Marshal(p.PathItemProps) if err != nil { return nil, err } concated := swag.ConcatJSON(b3, b4, b5) return concated, nil } ================================================ FILE: vendor/github.com/go-openapi/spec/paths.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "encoding/json" "fmt" "strings" "github.com/go-openapi/swag" ) // Paths holds the relative paths to the individual endpoints. // The path is appended to the [`basePath`](http://goo.gl/8us55a#swaggerBasePath) in order // to construct the full URL. // The Paths may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering). // // For more information: http://goo.gl/8us55a#pathsObject type Paths struct { VendorExtensible Paths map[string]PathItem `json:"-"` // custom serializer to flatten this, each entry must start with "/" } // JSONLookup look up a value by the json property name func (p Paths) JSONLookup(token string) (interface{}, error) { if pi, ok := p.Paths[token]; ok { return &pi, nil } if ex, ok := p.Extensions[token]; ok { return &ex, nil } return nil, fmt.Errorf("object has no field %q", token) } // UnmarshalJSON hydrates this items instance with the data from JSON func (p *Paths) UnmarshalJSON(data []byte) error { var res map[string]json.RawMessage if err := json.Unmarshal(data, &res); err != nil { return err } for k, v := range res { if strings.HasPrefix(strings.ToLower(k), "x-") { if p.Extensions == nil { p.Extensions = make(map[string]interface{}) } var d interface{} if err := json.Unmarshal(v, &d); err != nil { return err } p.Extensions[k] = d } if strings.HasPrefix(k, "/") { if p.Paths == nil { p.Paths = make(map[string]PathItem) } var pi PathItem if err := json.Unmarshal(v, &pi); err != nil { return err } p.Paths[k] = pi } } return nil } // MarshalJSON converts this items object to JSON func (p Paths) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(p.VendorExtensible) if err != nil { return nil, err } pths := make(map[string]PathItem) for k, v := range p.Paths { if strings.HasPrefix(k, "/") { pths[k] = v } } b2, err := json.Marshal(pths) if err != nil { return nil, err } concated := swag.ConcatJSON(b1, b2) return concated, nil } ================================================ FILE: vendor/github.com/go-openapi/spec/ref.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "bytes" "encoding/gob" "encoding/json" "net/http" "os" "path/filepath" "github.com/go-openapi/jsonreference" ) // Refable is a struct for things that accept a $ref property type Refable struct { Ref Ref } // MarshalJSON marshals the ref to json func (r Refable) MarshalJSON() ([]byte, error) { return r.Ref.MarshalJSON() } // UnmarshalJSON unmarshalss the ref from json func (r *Refable) UnmarshalJSON(d []byte) error { return json.Unmarshal(d, &r.Ref) } // Ref represents a json reference that is potentially resolved type Ref struct { jsonreference.Ref } // RemoteURI gets the remote uri part of the ref func (r *Ref) RemoteURI() string { if r.String() == "" { return r.String() } u := *r.GetURL() u.Fragment = "" return u.String() } // IsValidURI returns true when the url the ref points to can be found func (r *Ref) IsValidURI(basepaths ...string) bool { if r.String() == "" { return true } v := r.RemoteURI() if v == "" { return true } if r.HasFullURL { rr, err := http.Get(v) if err != nil { return false } return rr.StatusCode/100 == 2 } if !(r.HasFileScheme || r.HasFullFilePath || r.HasURLPathOnly) { return false } // check for local file pth := v if r.HasURLPathOnly { base := "." if len(basepaths) > 0 { base = filepath.Dir(filepath.Join(basepaths...)) } p, e := filepath.Abs(filepath.ToSlash(filepath.Join(base, pth))) if e != nil { return false } pth = p } fi, err := os.Stat(filepath.ToSlash(pth)) if err != nil { return false } return !fi.IsDir() } // Inherits creates a new reference from a parent and a child // If the child cannot inherit from the parent, an error is returned func (r *Ref) Inherits(child Ref) (*Ref, error) { ref, err := r.Ref.Inherits(child.Ref) if err != nil { return nil, err } return &Ref{Ref: *ref}, nil } // NewRef creates a new instance of a ref object // returns an error when the reference uri is an invalid uri func NewRef(refURI string) (Ref, error) { ref, err := jsonreference.New(refURI) if err != nil { return Ref{}, err } return Ref{Ref: ref}, nil } // MustCreateRef creates a ref object but panics when refURI is invalid. // Use the NewRef method for a version that returns an error. func MustCreateRef(refURI string) Ref { return Ref{Ref: jsonreference.MustCreateRef(refURI)} } // MarshalJSON marshals this ref into a JSON object func (r Ref) MarshalJSON() ([]byte, error) { str := r.String() if str == "" { if r.IsRoot() { return []byte(`{"$ref":""}`), nil } return []byte("{}"), nil } v := map[string]interface{}{"$ref": str} return json.Marshal(v) } // UnmarshalJSON unmarshals this ref from a JSON object func (r *Ref) UnmarshalJSON(d []byte) error { var v map[string]interface{} if err := json.Unmarshal(d, &v); err != nil { return err } return r.fromMap(v) } // GobEncode provides a safe gob encoder for Ref func (r Ref) GobEncode() ([]byte, error) { var b bytes.Buffer raw, err := r.MarshalJSON() if err != nil { return nil, err } err = gob.NewEncoder(&b).Encode(raw) return b.Bytes(), err } // GobDecode provides a safe gob decoder for Ref func (r *Ref) GobDecode(b []byte) error { var raw []byte buf := bytes.NewBuffer(b) err := gob.NewDecoder(buf).Decode(&raw) if err != nil { return err } return json.Unmarshal(raw, r) } func (r *Ref) fromMap(v map[string]interface{}) error { if v == nil { return nil } if vv, ok := v["$ref"]; ok { if str, ok := vv.(string); ok { ref, err := jsonreference.New(str) if err != nil { return err } *r = Ref{Ref: ref} } } return nil } ================================================ FILE: vendor/github.com/go-openapi/spec/response.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "encoding/json" "github.com/go-openapi/jsonpointer" "github.com/go-openapi/swag" ) // ResponseProps properties specific to a response type ResponseProps struct { Description string `json:"description,omitempty"` Schema *Schema `json:"schema,omitempty"` Headers map[string]Header `json:"headers,omitempty"` Examples map[string]interface{} `json:"examples,omitempty"` } // Response describes a single response from an API Operation. // // For more information: http://goo.gl/8us55a#responseObject type Response struct { Refable ResponseProps VendorExtensible } // JSONLookup look up a value by the json property name func (r Response) JSONLookup(token string) (interface{}, error) { if ex, ok := r.Extensions[token]; ok { return &ex, nil } if token == "$ref" { return &r.Ref, nil } ptr, _, err := jsonpointer.GetForToken(r.ResponseProps, token) return ptr, err } // UnmarshalJSON hydrates this items instance with the data from JSON func (r *Response) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &r.ResponseProps); err != nil { return err } if err := json.Unmarshal(data, &r.Refable); err != nil { return err } return json.Unmarshal(data, &r.VendorExtensible) } // MarshalJSON converts this items object to JSON func (r Response) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(r.ResponseProps) if err != nil { return nil, err } b2, err := json.Marshal(r.Refable) if err != nil { return nil, err } b3, err := json.Marshal(r.VendorExtensible) if err != nil { return nil, err } return swag.ConcatJSON(b1, b2, b3), nil } // NewResponse creates a new response instance func NewResponse() *Response { return new(Response) } // ResponseRef creates a response as a json reference func ResponseRef(url string) *Response { resp := NewResponse() resp.Ref = MustCreateRef(url) return resp } // WithDescription sets the description on this response, allows for chaining func (r *Response) WithDescription(description string) *Response { r.Description = description return r } // WithSchema sets the schema on this response, allows for chaining. // Passing a nil argument removes the schema from this response func (r *Response) WithSchema(schema *Schema) *Response { r.Schema = schema return r } // AddHeader adds a header to this response func (r *Response) AddHeader(name string, header *Header) *Response { if header == nil { return r.RemoveHeader(name) } if r.Headers == nil { r.Headers = make(map[string]Header) } r.Headers[name] = *header return r } // RemoveHeader removes a header from this response func (r *Response) RemoveHeader(name string) *Response { delete(r.Headers, name) return r } // AddExample adds an example to this response func (r *Response) AddExample(mediaType string, example interface{}) *Response { if r.Examples == nil { r.Examples = make(map[string]interface{}) } r.Examples[mediaType] = example return r } ================================================ FILE: vendor/github.com/go-openapi/spec/responses.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "encoding/json" "fmt" "reflect" "strconv" "github.com/go-openapi/swag" ) // Responses is a container for the expected responses of an operation. // The container maps a HTTP response code to the expected response. // It is not expected from the documentation to necessarily cover all possible HTTP response codes, // since they may not be known in advance. However, it is expected from the documentation to cover // a successful operation response and any known errors. // // The `default` can be used a default response object for all HTTP codes that are not covered // individually by the specification. // // The `Responses Object` MUST contain at least one response code, and it SHOULD be the response // for a successful operation call. // // For more information: http://goo.gl/8us55a#responsesObject type Responses struct { VendorExtensible ResponsesProps } // JSONLookup implements an interface to customize json pointer lookup func (r Responses) JSONLookup(token string) (interface{}, error) { if token == "default" { return r.Default, nil } if ex, ok := r.Extensions[token]; ok { return &ex, nil } if i, err := strconv.Atoi(token); err == nil { if scr, ok := r.StatusCodeResponses[i]; ok { return scr, nil } } return nil, fmt.Errorf("object has no field %q", token) } // UnmarshalJSON hydrates this items instance with the data from JSON func (r *Responses) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &r.ResponsesProps); err != nil { return err } if err := json.Unmarshal(data, &r.VendorExtensible); err != nil { return err } if reflect.DeepEqual(ResponsesProps{}, r.ResponsesProps) { r.ResponsesProps = ResponsesProps{} } return nil } // MarshalJSON converts this items object to JSON func (r Responses) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(r.ResponsesProps) if err != nil { return nil, err } b2, err := json.Marshal(r.VendorExtensible) if err != nil { return nil, err } concated := swag.ConcatJSON(b1, b2) return concated, nil } // ResponsesProps describes all responses for an operation. // It tells what is the default response and maps all responses with a // HTTP status code. type ResponsesProps struct { Default *Response StatusCodeResponses map[int]Response } // MarshalJSON marshals responses as JSON func (r ResponsesProps) MarshalJSON() ([]byte, error) { toser := map[string]Response{} if r.Default != nil { toser["default"] = *r.Default } for k, v := range r.StatusCodeResponses { toser[strconv.Itoa(k)] = v } return json.Marshal(toser) } // UnmarshalJSON unmarshals responses from JSON func (r *ResponsesProps) UnmarshalJSON(data []byte) error { var res map[string]Response if err := json.Unmarshal(data, &res); err != nil { return nil } if v, ok := res["default"]; ok { r.Default = &v delete(res, "default") } for k, v := range res { if nk, err := strconv.Atoi(k); err == nil { if r.StatusCodeResponses == nil { r.StatusCodeResponses = map[int]Response{} } r.StatusCodeResponses[nk] = v } } return nil } ================================================ FILE: vendor/github.com/go-openapi/spec/schema.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "encoding/json" "fmt" "net/url" "strings" "github.com/go-openapi/jsonpointer" "github.com/go-openapi/swag" ) // BooleanProperty creates a boolean property func BooleanProperty() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"boolean"}}} } // BoolProperty creates a boolean property func BoolProperty() *Schema { return BooleanProperty() } // StringProperty creates a string property func StringProperty() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}} } // CharProperty creates a string property func CharProperty() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}} } // Float64Property creates a float64/double property func Float64Property() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "double"}} } // Float32Property creates a float32/float property func Float32Property() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "float"}} } // Int8Property creates an int8 property func Int8Property() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int8"}} } // Int16Property creates an int16 property func Int16Property() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int16"}} } // Int32Property creates an int32 property func Int32Property() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int32"}} } // Int64Property creates an int64 property func Int64Property() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int64"}} } // StrFmtProperty creates a property for the named string format func StrFmtProperty(format string) *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: format}} } // DateProperty creates a date property func DateProperty() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date"}} } // DateTimeProperty creates a date time property func DateTimeProperty() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date-time"}} } // MapProperty creates a map property func MapProperty(property *Schema) *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"object"}, AdditionalProperties: &SchemaOrBool{Allows: true, Schema: property}}} } // RefProperty creates a ref property func RefProperty(name string) *Schema { return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}} } // RefSchema creates a ref property func RefSchema(name string) *Schema { return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}} } // ArrayProperty creates an array property func ArrayProperty(items *Schema) *Schema { if items == nil { return &Schema{SchemaProps: SchemaProps{Type: []string{"array"}}} } return &Schema{SchemaProps: SchemaProps{Items: &SchemaOrArray{Schema: items}, Type: []string{"array"}}} } // ComposedSchema creates a schema with allOf func ComposedSchema(schemas ...Schema) *Schema { s := new(Schema) s.AllOf = schemas return s } // SchemaURL represents a schema url type SchemaURL string // MarshalJSON marshal this to JSON func (r SchemaURL) MarshalJSON() ([]byte, error) { if r == "" { return []byte("{}"), nil } v := map[string]interface{}{"$schema": string(r)} return json.Marshal(v) } // UnmarshalJSON unmarshal this from JSON func (r *SchemaURL) UnmarshalJSON(data []byte) error { var v map[string]interface{} if err := json.Unmarshal(data, &v); err != nil { return err } return r.fromMap(v) } func (r *SchemaURL) fromMap(v map[string]interface{}) error { if v == nil { return nil } if vv, ok := v["$schema"]; ok { if str, ok := vv.(string); ok { u, err := url.Parse(str) if err != nil { return err } *r = SchemaURL(u.String()) } } return nil } // SchemaProps describes a JSON schema (draft 4) type SchemaProps struct { ID string `json:"id,omitempty"` Ref Ref `json:"-"` Schema SchemaURL `json:"-"` Description string `json:"description,omitempty"` Type StringOrArray `json:"type,omitempty"` Format string `json:"format,omitempty"` Title string `json:"title,omitempty"` Default interface{} `json:"default,omitempty"` Maximum *float64 `json:"maximum,omitempty"` ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"` Minimum *float64 `json:"minimum,omitempty"` ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"` MaxLength *int64 `json:"maxLength,omitempty"` MinLength *int64 `json:"minLength,omitempty"` Pattern string `json:"pattern,omitempty"` MaxItems *int64 `json:"maxItems,omitempty"` MinItems *int64 `json:"minItems,omitempty"` UniqueItems bool `json:"uniqueItems,omitempty"` MultipleOf *float64 `json:"multipleOf,omitempty"` Enum []interface{} `json:"enum,omitempty"` MaxProperties *int64 `json:"maxProperties,omitempty"` MinProperties *int64 `json:"minProperties,omitempty"` Required []string `json:"required,omitempty"` Items *SchemaOrArray `json:"items,omitempty"` AllOf []Schema `json:"allOf,omitempty"` OneOf []Schema `json:"oneOf,omitempty"` AnyOf []Schema `json:"anyOf,omitempty"` Not *Schema `json:"not,omitempty"` Properties map[string]Schema `json:"properties,omitempty"` AdditionalProperties *SchemaOrBool `json:"additionalProperties,omitempty"` PatternProperties map[string]Schema `json:"patternProperties,omitempty"` Dependencies Dependencies `json:"dependencies,omitempty"` AdditionalItems *SchemaOrBool `json:"additionalItems,omitempty"` Definitions Definitions `json:"definitions,omitempty"` } // SwaggerSchemaProps are additional properties supported by swagger schemas, but not JSON-schema (draft 4) type SwaggerSchemaProps struct { Discriminator string `json:"discriminator,omitempty"` ReadOnly bool `json:"readOnly,omitempty"` XML *XMLObject `json:"xml,omitempty"` ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"` Example interface{} `json:"example,omitempty"` } // Schema the schema object allows the definition of input and output data types. // These types can be objects, but also primitives and arrays. // This object is based on the [JSON Schema Specification Draft 4](http://json-schema.org/) // and uses a predefined subset of it. // On top of this subset, there are extensions provided by this specification to allow for more complete documentation. // // For more information: http://goo.gl/8us55a#schemaObject type Schema struct { VendorExtensible SchemaProps SwaggerSchemaProps ExtraProps map[string]interface{} `json:"-"` } // JSONLookup implements an interface to customize json pointer lookup func (s Schema) JSONLookup(token string) (interface{}, error) { if ex, ok := s.Extensions[token]; ok { return &ex, nil } if ex, ok := s.ExtraProps[token]; ok { return &ex, nil } r, _, err := jsonpointer.GetForToken(s.SchemaProps, token) if r != nil || (err != nil && !strings.HasPrefix(err.Error(), "object has no field")) { return r, err } r, _, err = jsonpointer.GetForToken(s.SwaggerSchemaProps, token) return r, err } // WithID sets the id for this schema, allows for chaining func (s *Schema) WithID(id string) *Schema { s.ID = id return s } // WithTitle sets the title for this schema, allows for chaining func (s *Schema) WithTitle(title string) *Schema { s.Title = title return s } // WithDescription sets the description for this schema, allows for chaining func (s *Schema) WithDescription(description string) *Schema { s.Description = description return s } // WithProperties sets the properties for this schema func (s *Schema) WithProperties(schemas map[string]Schema) *Schema { s.Properties = schemas return s } // SetProperty sets a property on this schema func (s *Schema) SetProperty(name string, schema Schema) *Schema { if s.Properties == nil { s.Properties = make(map[string]Schema) } s.Properties[name] = schema return s } // WithAllOf sets the all of property func (s *Schema) WithAllOf(schemas ...Schema) *Schema { s.AllOf = schemas return s } // WithMaxProperties sets the max number of properties an object can have func (s *Schema) WithMaxProperties(max int64) *Schema { s.MaxProperties = &max return s } // WithMinProperties sets the min number of properties an object must have func (s *Schema) WithMinProperties(min int64) *Schema { s.MinProperties = &min return s } // Typed sets the type of this schema for a single value item func (s *Schema) Typed(tpe, format string) *Schema { s.Type = []string{tpe} s.Format = format return s } // AddType adds a type with potential format to the types for this schema func (s *Schema) AddType(tpe, format string) *Schema { s.Type = append(s.Type, tpe) if format != "" { s.Format = format } return s } // CollectionOf a fluent builder method for an array parameter func (s *Schema) CollectionOf(items Schema) *Schema { s.Type = []string{jsonArray} s.Items = &SchemaOrArray{Schema: &items} return s } // WithDefault sets the default value on this parameter func (s *Schema) WithDefault(defaultValue interface{}) *Schema { s.Default = defaultValue return s } // WithRequired flags this parameter as required func (s *Schema) WithRequired(items ...string) *Schema { s.Required = items return s } // AddRequired adds field names to the required properties array func (s *Schema) AddRequired(items ...string) *Schema { s.Required = append(s.Required, items...) return s } // WithMaxLength sets a max length value func (s *Schema) WithMaxLength(max int64) *Schema { s.MaxLength = &max return s } // WithMinLength sets a min length value func (s *Schema) WithMinLength(min int64) *Schema { s.MinLength = &min return s } // WithPattern sets a pattern value func (s *Schema) WithPattern(pattern string) *Schema { s.Pattern = pattern return s } // WithMultipleOf sets a multiple of value func (s *Schema) WithMultipleOf(number float64) *Schema { s.MultipleOf = &number return s } // WithMaximum sets a maximum number value func (s *Schema) WithMaximum(max float64, exclusive bool) *Schema { s.Maximum = &max s.ExclusiveMaximum = exclusive return s } // WithMinimum sets a minimum number value func (s *Schema) WithMinimum(min float64, exclusive bool) *Schema { s.Minimum = &min s.ExclusiveMinimum = exclusive return s } // WithEnum sets a the enum values (replace) func (s *Schema) WithEnum(values ...interface{}) *Schema { s.Enum = append([]interface{}{}, values...) return s } // WithMaxItems sets the max items func (s *Schema) WithMaxItems(size int64) *Schema { s.MaxItems = &size return s } // WithMinItems sets the min items func (s *Schema) WithMinItems(size int64) *Schema { s.MinItems = &size return s } // UniqueValues dictates that this array can only have unique items func (s *Schema) UniqueValues() *Schema { s.UniqueItems = true return s } // AllowDuplicates this array can have duplicates func (s *Schema) AllowDuplicates() *Schema { s.UniqueItems = false return s } // AddToAllOf adds a schema to the allOf property func (s *Schema) AddToAllOf(schemas ...Schema) *Schema { s.AllOf = append(s.AllOf, schemas...) return s } // WithDiscriminator sets the name of the discriminator field func (s *Schema) WithDiscriminator(discriminator string) *Schema { s.Discriminator = discriminator return s } // AsReadOnly flags this schema as readonly func (s *Schema) AsReadOnly() *Schema { s.ReadOnly = true return s } // AsWritable flags this schema as writeable (not read-only) func (s *Schema) AsWritable() *Schema { s.ReadOnly = false return s } // WithExample sets the example for this schema func (s *Schema) WithExample(example interface{}) *Schema { s.Example = example return s } // WithExternalDocs sets/removes the external docs for/from this schema. // When you pass empty strings as params the external documents will be removed. // When you pass non-empty string as one value then those values will be used on the external docs object. // So when you pass a non-empty description, you should also pass the url and vice versa. func (s *Schema) WithExternalDocs(description, url string) *Schema { if description == "" && url == "" { s.ExternalDocs = nil return s } if s.ExternalDocs == nil { s.ExternalDocs = &ExternalDocumentation{} } s.ExternalDocs.Description = description s.ExternalDocs.URL = url return s } // WithXMLName sets the xml name for the object func (s *Schema) WithXMLName(name string) *Schema { if s.XML == nil { s.XML = new(XMLObject) } s.XML.Name = name return s } // WithXMLNamespace sets the xml namespace for the object func (s *Schema) WithXMLNamespace(namespace string) *Schema { if s.XML == nil { s.XML = new(XMLObject) } s.XML.Namespace = namespace return s } // WithXMLPrefix sets the xml prefix for the object func (s *Schema) WithXMLPrefix(prefix string) *Schema { if s.XML == nil { s.XML = new(XMLObject) } s.XML.Prefix = prefix return s } // AsXMLAttribute flags this object as xml attribute func (s *Schema) AsXMLAttribute() *Schema { if s.XML == nil { s.XML = new(XMLObject) } s.XML.Attribute = true return s } // AsXMLElement flags this object as an xml node func (s *Schema) AsXMLElement() *Schema { if s.XML == nil { s.XML = new(XMLObject) } s.XML.Attribute = false return s } // AsWrappedXML flags this object as wrapped, this is mostly useful for array types func (s *Schema) AsWrappedXML() *Schema { if s.XML == nil { s.XML = new(XMLObject) } s.XML.Wrapped = true return s } // AsUnwrappedXML flags this object as an xml node func (s *Schema) AsUnwrappedXML() *Schema { if s.XML == nil { s.XML = new(XMLObject) } s.XML.Wrapped = false return s } // MarshalJSON marshal this to JSON func (s Schema) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(s.SchemaProps) if err != nil { return nil, fmt.Errorf("schema props %v", err) } b2, err := json.Marshal(s.VendorExtensible) if err != nil { return nil, fmt.Errorf("vendor props %v", err) } b3, err := s.Ref.MarshalJSON() if err != nil { return nil, fmt.Errorf("ref prop %v", err) } b4, err := s.Schema.MarshalJSON() if err != nil { return nil, fmt.Errorf("schema prop %v", err) } b5, err := json.Marshal(s.SwaggerSchemaProps) if err != nil { return nil, fmt.Errorf("common validations %v", err) } var b6 []byte if s.ExtraProps != nil { jj, err := json.Marshal(s.ExtraProps) if err != nil { return nil, fmt.Errorf("extra props %v", err) } b6 = jj } return swag.ConcatJSON(b1, b2, b3, b4, b5, b6), nil } // UnmarshalJSON marshal this from JSON func (s *Schema) UnmarshalJSON(data []byte) error { props := struct { SchemaProps SwaggerSchemaProps }{} if err := json.Unmarshal(data, &props); err != nil { return err } sch := Schema{ SchemaProps: props.SchemaProps, SwaggerSchemaProps: props.SwaggerSchemaProps, } var d map[string]interface{} if err := json.Unmarshal(data, &d); err != nil { return err } _ = sch.Ref.fromMap(d) _ = sch.Schema.fromMap(d) delete(d, "$ref") delete(d, "$schema") for _, pn := range swag.DefaultJSONNameProvider.GetJSONNames(s) { delete(d, pn) } for k, vv := range d { lk := strings.ToLower(k) if strings.HasPrefix(lk, "x-") { if sch.Extensions == nil { sch.Extensions = map[string]interface{}{} } sch.Extensions[k] = vv continue } if sch.ExtraProps == nil { sch.ExtraProps = map[string]interface{}{} } sch.ExtraProps[k] = vv } *s = sch return nil } ================================================ FILE: vendor/github.com/go-openapi/spec/schema_loader.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "encoding/json" "fmt" "log" "net/url" "reflect" "strings" "github.com/go-openapi/swag" ) // PathLoader function to use when loading remote refs var PathLoader func(string) (json.RawMessage, error) func init() { PathLoader = func(path string) (json.RawMessage, error) { data, err := swag.LoadFromFileOrHTTP(path) if err != nil { return nil, err } return json.RawMessage(data), nil } } // resolverContext allows to share a context during spec processing. // At the moment, it just holds the index of circular references found. type resolverContext struct { // circulars holds all visited circular references, which allows shortcuts. // NOTE: this is not just a performance improvement: it is required to figure out // circular references which participate several cycles. // This structure is privately instantiated and needs not be locked against // concurrent access, unless we chose to implement a parallel spec walking. circulars map[string]bool basePath string } func newResolverContext(originalBasePath string) *resolverContext { return &resolverContext{ circulars: make(map[string]bool), basePath: originalBasePath, // keep the root base path in context } } type schemaLoader struct { root interface{} options *ExpandOptions cache ResolutionCache context *resolverContext loadDoc func(string) (json.RawMessage, error) } func (r *schemaLoader) transitiveResolver(basePath string, ref Ref) (*schemaLoader, error) { if ref.IsRoot() || ref.HasFragmentOnly { return r, nil } baseRef, _ := NewRef(basePath) currentRef := normalizeFileRef(&ref, basePath) if strings.HasPrefix(currentRef.String(), baseRef.String()) { return r, nil } // Set a new root to resolve against rootURL := currentRef.GetURL() rootURL.Fragment = "" root, _ := r.cache.Get(rootURL.String()) // shallow copy of resolver options to set a new RelativeBase when // traversing multiple documents newOptions := r.options newOptions.RelativeBase = rootURL.String() debugLog("setting new root: %s", newOptions.RelativeBase) resolver, err := defaultSchemaLoader(root, newOptions, r.cache, r.context) if err != nil { return nil, err } return resolver, nil } func (r *schemaLoader) updateBasePath(transitive *schemaLoader, basePath string) string { if transitive != r { debugLog("got a new resolver") if transitive.options != nil && transitive.options.RelativeBase != "" { basePath, _ = absPath(transitive.options.RelativeBase) debugLog("new basePath = %s", basePath) } } return basePath } func (r *schemaLoader) resolveRef(ref *Ref, target interface{}, basePath string) error { tgt := reflect.ValueOf(target) if tgt.Kind() != reflect.Ptr { return fmt.Errorf("resolve ref: target needs to be a pointer") } refURL := ref.GetURL() if refURL == nil { return nil } var res interface{} var data interface{} var err error // Resolve against the root if it isn't nil, and if ref is pointing at the root, or has a fragment only which means // it is pointing somewhere in the root. root := r.root if (ref.IsRoot() || ref.HasFragmentOnly) && root == nil && basePath != "" { if baseRef, erb := NewRef(basePath); erb == nil { root, _, _, _ = r.load(baseRef.GetURL()) } } if (ref.IsRoot() || ref.HasFragmentOnly) && root != nil { data = root } else { baseRef := normalizeFileRef(ref, basePath) debugLog("current ref is: %s", ref.String()) debugLog("current ref normalized file: %s", baseRef.String()) data, _, _, err = r.load(baseRef.GetURL()) if err != nil { return err } } res = data if ref.String() != "" { res, _, err = ref.GetPointer().Get(data) if err != nil { return err } } return swag.DynamicJSONToStruct(res, target) } func (r *schemaLoader) load(refURL *url.URL) (interface{}, url.URL, bool, error) { debugLog("loading schema from url: %s", refURL) toFetch := *refURL toFetch.Fragment = "" normalized := normalizeAbsPath(toFetch.String()) data, fromCache := r.cache.Get(normalized) if !fromCache { b, err := r.loadDoc(normalized) if err != nil { return nil, url.URL{}, false, err } if err := json.Unmarshal(b, &data); err != nil { return nil, url.URL{}, false, err } r.cache.Set(normalized, data) } return data, toFetch, fromCache, nil } // isCircular detects cycles in sequences of $ref. // It relies on a private context (which needs not be locked). func (r *schemaLoader) isCircular(ref *Ref, basePath string, parentRefs ...string) (foundCycle bool) { normalizedRef := normalizePaths(ref.String(), basePath) if _, ok := r.context.circulars[normalizedRef]; ok { // circular $ref has been already detected in another explored cycle foundCycle = true return } foundCycle = swag.ContainsStringsCI(parentRefs, normalizedRef) if foundCycle { r.context.circulars[normalizedRef] = true } return } // Resolve resolves a reference against basePath and stores the result in target // Resolve is not in charge of following references, it only resolves ref by following its URL // if the schema that ref is referring to has more refs in it. Resolve doesn't resolve them // if basePath is an empty string, ref is resolved against the root schema stored in the schemaLoader struct func (r *schemaLoader) Resolve(ref *Ref, target interface{}, basePath string) error { return r.resolveRef(ref, target, basePath) } func (r *schemaLoader) deref(input interface{}, parentRefs []string, basePath string) error { var ref *Ref switch refable := input.(type) { case *Schema: ref = &refable.Ref case *Parameter: ref = &refable.Ref case *Response: ref = &refable.Ref case *PathItem: ref = &refable.Ref default: return fmt.Errorf("deref: unsupported type %T", input) } curRef := ref.String() if curRef != "" { normalizedRef := normalizeFileRef(ref, basePath) normalizedBasePath := normalizedRef.RemoteURI() if r.isCircular(normalizedRef, basePath, parentRefs...) { return nil } if err := r.resolveRef(ref, input, basePath); r.shouldStopOnError(err) { return err } // NOTE(fredbi): removed basePath check => needs more testing if ref.String() != "" && ref.String() != curRef { parentRefs = append(parentRefs, normalizedRef.String()) return r.deref(input, parentRefs, normalizedBasePath) } } return nil } func (r *schemaLoader) shouldStopOnError(err error) bool { if err != nil && !r.options.ContinueOnError { return true } if err != nil { log.Println(err) } return false } func defaultSchemaLoader( root interface{}, expandOptions *ExpandOptions, cache ResolutionCache, context *resolverContext) (*schemaLoader, error) { if cache == nil { cache = resCache } if expandOptions == nil { expandOptions = &ExpandOptions{} } absBase, _ := absPath(expandOptions.RelativeBase) if context == nil { context = newResolverContext(absBase) } return &schemaLoader{ root: root, options: expandOptions, cache: cache, context: context, loadDoc: func(path string) (json.RawMessage, error) { debugLog("fetching document at %q", path) return PathLoader(path) }, }, nil } ================================================ FILE: vendor/github.com/go-openapi/spec/security_scheme.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "encoding/json" "github.com/go-openapi/jsonpointer" "github.com/go-openapi/swag" ) const ( basic = "basic" apiKey = "apiKey" oauth2 = "oauth2" implicit = "implicit" password = "password" application = "application" accessCode = "accessCode" ) // BasicAuth creates a basic auth security scheme func BasicAuth() *SecurityScheme { return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{Type: basic}} } // APIKeyAuth creates an api key auth security scheme func APIKeyAuth(fieldName, valueSource string) *SecurityScheme { return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{Type: apiKey, Name: fieldName, In: valueSource}} } // OAuth2Implicit creates an implicit flow oauth2 security scheme func OAuth2Implicit(authorizationURL string) *SecurityScheme { return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ Type: oauth2, Flow: implicit, AuthorizationURL: authorizationURL, }} } // OAuth2Password creates a password flow oauth2 security scheme func OAuth2Password(tokenURL string) *SecurityScheme { return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ Type: oauth2, Flow: password, TokenURL: tokenURL, }} } // OAuth2Application creates an application flow oauth2 security scheme func OAuth2Application(tokenURL string) *SecurityScheme { return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ Type: oauth2, Flow: application, TokenURL: tokenURL, }} } // OAuth2AccessToken creates an access token flow oauth2 security scheme func OAuth2AccessToken(authorizationURL, tokenURL string) *SecurityScheme { return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ Type: oauth2, Flow: accessCode, AuthorizationURL: authorizationURL, TokenURL: tokenURL, }} } // SecuritySchemeProps describes a swagger security scheme in the securityDefinitions section type SecuritySchemeProps struct { Description string `json:"description,omitempty"` Type string `json:"type"` Name string `json:"name,omitempty"` // api key In string `json:"in,omitempty"` // api key Flow string `json:"flow,omitempty"` // oauth2 AuthorizationURL string `json:"authorizationUrl,omitempty"` // oauth2 TokenURL string `json:"tokenUrl,omitempty"` // oauth2 Scopes map[string]string `json:"scopes,omitempty"` // oauth2 } // AddScope adds a scope to this security scheme func (s *SecuritySchemeProps) AddScope(scope, description string) { if s.Scopes == nil { s.Scopes = make(map[string]string) } s.Scopes[scope] = description } // SecurityScheme allows the definition of a security scheme that can be used by the operations. // Supported schemes are basic authentication, an API key (either as a header or as a query parameter) // and OAuth2's common flows (implicit, password, application and access code). // // For more information: http://goo.gl/8us55a#securitySchemeObject type SecurityScheme struct { VendorExtensible SecuritySchemeProps } // JSONLookup implements an interface to customize json pointer lookup func (s SecurityScheme) JSONLookup(token string) (interface{}, error) { if ex, ok := s.Extensions[token]; ok { return &ex, nil } r, _, err := jsonpointer.GetForToken(s.SecuritySchemeProps, token) return r, err } // MarshalJSON marshal this to JSON func (s SecurityScheme) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(s.SecuritySchemeProps) if err != nil { return nil, err } b2, err := json.Marshal(s.VendorExtensible) if err != nil { return nil, err } return swag.ConcatJSON(b1, b2), nil } // UnmarshalJSON marshal this from JSON func (s *SecurityScheme) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &s.SecuritySchemeProps); err != nil { return err } return json.Unmarshal(data, &s.VendorExtensible) } ================================================ FILE: vendor/github.com/go-openapi/spec/spec.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import "encoding/json" //go:generate curl -L --progress -o ./schemas/v2/schema.json http://swagger.io/v2/schema.json //go:generate curl -L --progress -o ./schemas/jsonschema-draft-04.json http://json-schema.org/draft-04/schema //go:generate go-bindata -pkg=spec -prefix=./schemas -ignore=.*\.md ./schemas/... //go:generate perl -pi -e s,Json,JSON,g bindata.go const ( // SwaggerSchemaURL the url for the swagger 2.0 schema to validate specs SwaggerSchemaURL = "http://swagger.io/v2/schema.json#" // JSONSchemaURL the url for the json schema schema JSONSchemaURL = "http://json-schema.org/draft-04/schema#" ) var ( jsonSchema *Schema swaggerSchema *Schema ) func init() { jsonSchema = MustLoadJSONSchemaDraft04() swaggerSchema = MustLoadSwagger20Schema() } // MustLoadJSONSchemaDraft04 panics when Swagger20Schema returns an error func MustLoadJSONSchemaDraft04() *Schema { d, e := JSONSchemaDraft04() if e != nil { panic(e) } return d } // JSONSchemaDraft04 loads the json schema document for json shema draft04 func JSONSchemaDraft04() (*Schema, error) { b, err := Asset("jsonschema-draft-04.json") if err != nil { return nil, err } schema := new(Schema) if err := json.Unmarshal(b, schema); err != nil { return nil, err } return schema, nil } // MustLoadSwagger20Schema panics when Swagger20Schema returns an error func MustLoadSwagger20Schema() *Schema { d, e := Swagger20Schema() if e != nil { panic(e) } return d } // Swagger20Schema loads the swagger 2.0 schema from the embedded assets func Swagger20Schema() (*Schema, error) { b, err := Asset("v2/schema.json") if err != nil { return nil, err } schema := new(Schema) if err := json.Unmarshal(b, schema); err != nil { return nil, err } return schema, nil } ================================================ FILE: vendor/github.com/go-openapi/spec/swagger.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "encoding/json" "fmt" "strconv" "github.com/go-openapi/jsonpointer" "github.com/go-openapi/swag" ) // Swagger this is the root document object for the API specification. // It combines what previously was the Resource Listing and API Declaration (version 1.2 and earlier) // together into one document. // // For more information: http://goo.gl/8us55a#swagger-object- type Swagger struct { VendorExtensible SwaggerProps } // JSONLookup look up a value by the json property name func (s Swagger) JSONLookup(token string) (interface{}, error) { if ex, ok := s.Extensions[token]; ok { return &ex, nil } r, _, err := jsonpointer.GetForToken(s.SwaggerProps, token) return r, err } // MarshalJSON marshals this swagger structure to json func (s Swagger) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(s.SwaggerProps) if err != nil { return nil, err } b2, err := json.Marshal(s.VendorExtensible) if err != nil { return nil, err } return swag.ConcatJSON(b1, b2), nil } // UnmarshalJSON unmarshals a swagger spec from json func (s *Swagger) UnmarshalJSON(data []byte) error { var sw Swagger if err := json.Unmarshal(data, &sw.SwaggerProps); err != nil { return err } if err := json.Unmarshal(data, &sw.VendorExtensible); err != nil { return err } *s = sw return nil } // SwaggerProps captures the top-level properties of an Api specification // // NOTE: validation rules // - the scheme, when present must be from [http, https, ws, wss] // - BasePath must start with a leading "/" // - Paths is required type SwaggerProps struct { ID string `json:"id,omitempty"` Consumes []string `json:"consumes,omitempty"` Produces []string `json:"produces,omitempty"` Schemes []string `json:"schemes,omitempty"` Swagger string `json:"swagger,omitempty"` Info *Info `json:"info,omitempty"` Host string `json:"host,omitempty"` BasePath string `json:"basePath,omitempty"` Paths *Paths `json:"paths"` Definitions Definitions `json:"definitions,omitempty"` Parameters map[string]Parameter `json:"parameters,omitempty"` Responses map[string]Response `json:"responses,omitempty"` SecurityDefinitions SecurityDefinitions `json:"securityDefinitions,omitempty"` Security []map[string][]string `json:"security,omitempty"` Tags []Tag `json:"tags,omitempty"` ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"` } // Dependencies represent a dependencies property type Dependencies map[string]SchemaOrStringArray // SchemaOrBool represents a schema or boolean value, is biased towards true for the boolean property type SchemaOrBool struct { Allows bool Schema *Schema } // JSONLookup implements an interface to customize json pointer lookup func (s SchemaOrBool) JSONLookup(token string) (interface{}, error) { if token == "allows" { return s.Allows, nil } r, _, err := jsonpointer.GetForToken(s.Schema, token) return r, err } var jsTrue = []byte("true") var jsFalse = []byte("false") // MarshalJSON convert this object to JSON func (s SchemaOrBool) MarshalJSON() ([]byte, error) { if s.Schema != nil { return json.Marshal(s.Schema) } if s.Schema == nil && !s.Allows { return jsFalse, nil } return jsTrue, nil } // UnmarshalJSON converts this bool or schema object from a JSON structure func (s *SchemaOrBool) UnmarshalJSON(data []byte) error { var nw SchemaOrBool if len(data) >= 4 { if data[0] == '{' { var sch Schema if err := json.Unmarshal(data, &sch); err != nil { return err } nw.Schema = &sch } nw.Allows = !(data[0] == 'f' && data[1] == 'a' && data[2] == 'l' && data[3] == 's' && data[4] == 'e') } *s = nw return nil } // SchemaOrStringArray represents a schema or a string array type SchemaOrStringArray struct { Schema *Schema Property []string } // JSONLookup implements an interface to customize json pointer lookup func (s SchemaOrStringArray) JSONLookup(token string) (interface{}, error) { r, _, err := jsonpointer.GetForToken(s.Schema, token) return r, err } // MarshalJSON converts this schema object or array into JSON structure func (s SchemaOrStringArray) MarshalJSON() ([]byte, error) { if len(s.Property) > 0 { return json.Marshal(s.Property) } if s.Schema != nil { return json.Marshal(s.Schema) } return []byte("null"), nil } // UnmarshalJSON converts this schema object or array from a JSON structure func (s *SchemaOrStringArray) UnmarshalJSON(data []byte) error { var first byte if len(data) > 1 { first = data[0] } var nw SchemaOrStringArray if first == '{' { var sch Schema if err := json.Unmarshal(data, &sch); err != nil { return err } nw.Schema = &sch } if first == '[' { if err := json.Unmarshal(data, &nw.Property); err != nil { return err } } *s = nw return nil } // Definitions contains the models explicitly defined in this spec // An object to hold data types that can be consumed and produced by operations. // These data types can be primitives, arrays or models. // // For more information: http://goo.gl/8us55a#definitionsObject type Definitions map[string]Schema // SecurityDefinitions a declaration of the security schemes available to be used in the specification. // This does not enforce the security schemes on the operations and only serves to provide // the relevant details for each scheme. // // For more information: http://goo.gl/8us55a#securityDefinitionsObject type SecurityDefinitions map[string]*SecurityScheme // StringOrArray represents a value that can either be a string // or an array of strings. Mainly here for serialization purposes type StringOrArray []string // Contains returns true when the value is contained in the slice func (s StringOrArray) Contains(value string) bool { for _, str := range s { if str == value { return true } } return false } // JSONLookup implements an interface to customize json pointer lookup func (s SchemaOrArray) JSONLookup(token string) (interface{}, error) { if _, err := strconv.Atoi(token); err == nil { r, _, err := jsonpointer.GetForToken(s.Schemas, token) return r, err } r, _, err := jsonpointer.GetForToken(s.Schema, token) return r, err } // UnmarshalJSON unmarshals this string or array object from a JSON array or JSON string func (s *StringOrArray) UnmarshalJSON(data []byte) error { var first byte if len(data) > 1 { first = data[0] } if first == '[' { var parsed []string if err := json.Unmarshal(data, &parsed); err != nil { return err } *s = StringOrArray(parsed) return nil } var single interface{} if err := json.Unmarshal(data, &single); err != nil { return err } if single == nil { return nil } switch v := single.(type) { case string: *s = StringOrArray([]string{v}) return nil default: return fmt.Errorf("only string or array is allowed, not %T", single) } } // MarshalJSON converts this string or array to a JSON array or JSON string func (s StringOrArray) MarshalJSON() ([]byte, error) { if len(s) == 1 { return json.Marshal([]string(s)[0]) } return json.Marshal([]string(s)) } // SchemaOrArray represents a value that can either be a Schema // or an array of Schema. Mainly here for serialization purposes type SchemaOrArray struct { Schema *Schema Schemas []Schema } // Len returns the number of schemas in this property func (s SchemaOrArray) Len() int { if s.Schema != nil { return 1 } return len(s.Schemas) } // ContainsType returns true when one of the schemas is of the specified type func (s *SchemaOrArray) ContainsType(name string) bool { if s.Schema != nil { return s.Schema.Type != nil && s.Schema.Type.Contains(name) } return false } // MarshalJSON converts this schema object or array into JSON structure func (s SchemaOrArray) MarshalJSON() ([]byte, error) { if len(s.Schemas) > 0 { return json.Marshal(s.Schemas) } return json.Marshal(s.Schema) } // UnmarshalJSON converts this schema object or array from a JSON structure func (s *SchemaOrArray) UnmarshalJSON(data []byte) error { var nw SchemaOrArray var first byte if len(data) > 1 { first = data[0] } if first == '{' { var sch Schema if err := json.Unmarshal(data, &sch); err != nil { return err } nw.Schema = &sch } if first == '[' { if err := json.Unmarshal(data, &nw.Schemas); err != nil { return err } } *s = nw return nil } // vim:set ft=go noet sts=2 sw=2 ts=2: ================================================ FILE: vendor/github.com/go-openapi/spec/tag.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec import ( "encoding/json" "github.com/go-openapi/jsonpointer" "github.com/go-openapi/swag" ) // TagProps describe a tag entry in the top level tags section of a swagger spec type TagProps struct { Description string `json:"description,omitempty"` Name string `json:"name,omitempty"` ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"` } // NewTag creates a new tag func NewTag(name, description string, externalDocs *ExternalDocumentation) Tag { return Tag{TagProps: TagProps{Description: description, Name: name, ExternalDocs: externalDocs}} } // Tag allows adding meta data to a single tag that is used by the // [Operation Object](http://goo.gl/8us55a#operationObject). // It is not mandatory to have a Tag Object per tag used there. // // For more information: http://goo.gl/8us55a#tagObject type Tag struct { VendorExtensible TagProps } // JSONLookup implements an interface to customize json pointer lookup func (t Tag) JSONLookup(token string) (interface{}, error) { if ex, ok := t.Extensions[token]; ok { return &ex, nil } r, _, err := jsonpointer.GetForToken(t.TagProps, token) return r, err } // MarshalJSON marshal this to JSON func (t Tag) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(t.TagProps) if err != nil { return nil, err } b2, err := json.Marshal(t.VendorExtensible) if err != nil { return nil, err } return swag.ConcatJSON(b1, b2), nil } // UnmarshalJSON marshal this from JSON func (t *Tag) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &t.TagProps); err != nil { return err } return json.Unmarshal(data, &t.VendorExtensible) } ================================================ FILE: vendor/github.com/go-openapi/spec/unused.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec /* import ( "net/url" "os" "path" "path/filepath" "github.com/go-openapi/jsonpointer" ) // Some currently unused functions and definitions that // used to be part of the expander. // Moved here for the record and possible future reuse var ( idPtr, _ = jsonpointer.New("/id") refPtr, _ = jsonpointer.New("/$ref") ) func idFromNode(node interface{}) (*Ref, error) { if idValue, _, err := idPtr.Get(node); err == nil { if refStr, ok := idValue.(string); ok && refStr != "" { idRef, err := NewRef(refStr) if err != nil { return nil, err } return &idRef, nil } } return nil, nil } func nextRef(startingNode interface{}, startingRef *Ref, ptr *jsonpointer.Pointer) *Ref { if startingRef == nil { return nil } if ptr == nil { return startingRef } ret := startingRef var idRef *Ref node := startingNode for _, tok := range ptr.DecodedTokens() { node, _, _ = jsonpointer.GetForToken(node, tok) if node == nil { break } idRef, _ = idFromNode(node) if idRef != nil { nw, err := ret.Inherits(*idRef) if err != nil { break } ret = nw } refRef, _, _ := refPtr.Get(node) if refRef != nil { var rf Ref switch value := refRef.(type) { case string: rf, _ = NewRef(value) } nw, err := ret.Inherits(rf) if err != nil { break } nwURL := nw.GetURL() if nwURL.Scheme == "file" || (nwURL.Scheme == "" && nwURL.Host == "") { nwpt := filepath.ToSlash(nwURL.Path) if filepath.IsAbs(nwpt) { _, err := os.Stat(nwpt) if err != nil { nwURL.Path = filepath.Join(".", nwpt) } } } ret = nw } } return ret } // basePathFromSchemaID returns a new basePath based on an existing basePath and a schema ID func basePathFromSchemaID(oldBasePath, id string) string { u, err := url.Parse(oldBasePath) if err != nil { panic(err) } uid, err := url.Parse(id) if err != nil { panic(err) } if path.IsAbs(uid.Path) { return id } u.Path = path.Join(path.Dir(u.Path), uid.Path) return u.String() } */ // type ExtraSchemaProps map[string]interface{} // // JSONSchema represents a structure that is a json schema draft 04 // type JSONSchema struct { // SchemaProps // ExtraSchemaProps // } // // MarshalJSON marshal this to JSON // func (s JSONSchema) MarshalJSON() ([]byte, error) { // b1, err := json.Marshal(s.SchemaProps) // if err != nil { // return nil, err // } // b2, err := s.Ref.MarshalJSON() // if err != nil { // return nil, err // } // b3, err := s.Schema.MarshalJSON() // if err != nil { // return nil, err // } // b4, err := json.Marshal(s.ExtraSchemaProps) // if err != nil { // return nil, err // } // return swag.ConcatJSON(b1, b2, b3, b4), nil // } // // UnmarshalJSON marshal this from JSON // func (s *JSONSchema) UnmarshalJSON(data []byte) error { // var sch JSONSchema // if err := json.Unmarshal(data, &sch.SchemaProps); err != nil { // return err // } // if err := json.Unmarshal(data, &sch.Ref); err != nil { // return err // } // if err := json.Unmarshal(data, &sch.Schema); err != nil { // return err // } // if err := json.Unmarshal(data, &sch.ExtraSchemaProps); err != nil { // return err // } // *s = sch // return nil // } ================================================ FILE: vendor/github.com/go-openapi/spec/xml_object.go ================================================ // Copyright 2015 go-swagger maintainers // // 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 spec // XMLObject a metadata object that allows for more fine-tuned XML model definitions. // // For more information: http://goo.gl/8us55a#xmlObject type XMLObject struct { Name string `json:"name,omitempty"` Namespace string `json:"namespace,omitempty"` Prefix string `json:"prefix,omitempty"` Attribute bool `json:"attribute,omitempty"` Wrapped bool `json:"wrapped,omitempty"` } // WithName sets the xml name for the object func (x *XMLObject) WithName(name string) *XMLObject { x.Name = name return x } // WithNamespace sets the xml namespace for the object func (x *XMLObject) WithNamespace(namespace string) *XMLObject { x.Namespace = namespace return x } // WithPrefix sets the xml prefix for the object func (x *XMLObject) WithPrefix(prefix string) *XMLObject { x.Prefix = prefix return x } // AsAttribute flags this object as xml attribute func (x *XMLObject) AsAttribute() *XMLObject { x.Attribute = true return x } // AsElement flags this object as an xml node func (x *XMLObject) AsElement() *XMLObject { x.Attribute = false return x } // AsWrapped flags this object as wrapped, this is mostly useful for array types func (x *XMLObject) AsWrapped() *XMLObject { x.Wrapped = true return x } // AsUnwrapped flags this object as an xml node func (x *XMLObject) AsUnwrapped() *XMLObject { x.Wrapped = false return x } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/.gitignore ================================================ .DS_Store .DS_Store? ._* .Spotlight-V100 .Trashes Icon? ehthumbs.db Thumbs.db .idea ================================================ FILE: vendor/github.com/go-sql-driver/mysql/.travis.yml ================================================ sudo: false language: go go: - 1.9.x - 1.10.x - 1.11.x - 1.12.x - master before_install: - go get golang.org/x/tools/cmd/cover - go get github.com/mattn/goveralls before_script: - echo -e "[server]\ninnodb_log_file_size=256MB\ninnodb_buffer_pool_size=512MB\nmax_allowed_packet=16MB" | sudo tee -a /etc/mysql/my.cnf - sudo service mysql restart - .travis/wait_mysql.sh - mysql -e 'create database gotest;' matrix: include: - env: DB=MYSQL8 sudo: required dist: trusty go: 1.10.x services: - docker before_install: - go get golang.org/x/tools/cmd/cover - go get github.com/mattn/goveralls - docker pull mysql:8.0 - docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret mysql:8.0 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1 - cp .travis/docker.cnf ~/.my.cnf - .travis/wait_mysql.sh before_script: - export MYSQL_TEST_USER=gotest - export MYSQL_TEST_PASS=secret - export MYSQL_TEST_ADDR=127.0.0.1:3307 - export MYSQL_TEST_CONCURRENT=1 - env: DB=MYSQL57 sudo: required dist: trusty go: 1.10.x services: - docker before_install: - go get golang.org/x/tools/cmd/cover - go get github.com/mattn/goveralls - docker pull mysql:5.7 - docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret mysql:5.7 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1 - cp .travis/docker.cnf ~/.my.cnf - .travis/wait_mysql.sh before_script: - export MYSQL_TEST_USER=gotest - export MYSQL_TEST_PASS=secret - export MYSQL_TEST_ADDR=127.0.0.1:3307 - export MYSQL_TEST_CONCURRENT=1 - env: DB=MARIA55 sudo: required dist: trusty go: 1.10.x services: - docker before_install: - go get golang.org/x/tools/cmd/cover - go get github.com/mattn/goveralls - docker pull mariadb:5.5 - docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret mariadb:5.5 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1 - cp .travis/docker.cnf ~/.my.cnf - .travis/wait_mysql.sh before_script: - export MYSQL_TEST_USER=gotest - export MYSQL_TEST_PASS=secret - export MYSQL_TEST_ADDR=127.0.0.1:3307 - export MYSQL_TEST_CONCURRENT=1 - env: DB=MARIA10_1 sudo: required dist: trusty go: 1.10.x services: - docker before_install: - go get golang.org/x/tools/cmd/cover - go get github.com/mattn/goveralls - docker pull mariadb:10.1 - docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret mariadb:10.1 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB --local-infile=1 - cp .travis/docker.cnf ~/.my.cnf - .travis/wait_mysql.sh before_script: - export MYSQL_TEST_USER=gotest - export MYSQL_TEST_PASS=secret - export MYSQL_TEST_ADDR=127.0.0.1:3307 - export MYSQL_TEST_CONCURRENT=1 - os: osx osx_image: xcode10.1 addons: homebrew: packages: - mysql go: 1.12.x before_install: - go get golang.org/x/tools/cmd/cover - go get github.com/mattn/goveralls before_script: - echo -e "[server]\ninnodb_log_file_size=256MB\ninnodb_buffer_pool_size=512MB\nmax_allowed_packet=16MB\nlocal_infile=1" >> /usr/local/etc/my.cnf - mysql.server start - mysql -uroot -e 'CREATE USER gotest IDENTIFIED BY "secret"' - mysql -uroot -e 'GRANT ALL ON *.* TO gotest' - mysql -uroot -e 'create database gotest;' - export MYSQL_TEST_USER=gotest - export MYSQL_TEST_PASS=secret - export MYSQL_TEST_ADDR=127.0.0.1:3306 - export MYSQL_TEST_CONCURRENT=1 script: - go test -v -covermode=count -coverprofile=coverage.out - go vet ./... - .travis/gofmt.sh after_script: - $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci ================================================ FILE: vendor/github.com/go-sql-driver/mysql/AUTHORS ================================================ # 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 Erwan Martin Evan Shaw Frederick Mayle Gustavo Kristic Hajime Nakagami Hanno Braun Henri Yandell Hirotaka Yamamoto Huyiguang ICHINOSE Shogo Ilia Cimpoes INADA Naoki Jacek Szwec James Harr Jeff Hodges Jeffrey Charles Jerome Meyer 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 Simon J Mudd Soroush Pour Stan Putrya Stanley Gunawan Steven Hartland Thomas Wodarek Tim Ruffles Tom Jenkinson Xiangyu Hu Xiaobing Jiang Xiuming Chen Zhenye Xie # Organizations Barracuda Networks, Inc. Counting Ltd. Facebook Inc. GitHub Inc. Google Inc. InfoSum Ltd. Keybase Inc. Multiplay Ltd. Percona LLC Pivotal Inc. Stripe Inc. ================================================ FILE: vendor/github.com/go-sql-driver/mysql/CHANGELOG.md ================================================ ## 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 ================================================ FILE: vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md ================================================ # 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. ================================================ FILE: vendor/github.com/go-sql-driver/mysql/LICENSE ================================================ 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. ================================================ FILE: vendor/github.com/go-sql-driver/mysql/README.md ================================================ # 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.9 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: utf8mb4_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`. The default collation (`utf8mb4_general_ci`) is supported from MySQL 5.5. You should use an older collation (e.g. `utf8_general_ci`) for older MySQL. Collations for charset "ucs2", "utf16", "utf16le", and "utf32" can not be used ([ref](https://dev.mysql.com/doc/refman/5.7/en/charset-connection.html#charset-connection-impermissible-client-charset)). ##### `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, preferred, 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) or use `preferred` to use TLS only when advertised by the server. This is similar to `skip-verify`, but additionally allows a fallback to a connection which is not encrypted. Neither `skip-verify` nor `preferred` add any reliable security. You can use a custom TLS config after registering it 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 equivalent 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") ================================================ FILE: vendor/github.com/go-sql-driver/mysql/appengine.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. // +build appengine package mysql import ( "context" "net" "google.golang.org/appengine/cloudsql" ) func init() { RegisterDialContext("cloudsql", func(_ context.Context, instance string) (net.Conn, error) { // XXX: the cloudsql driver still does not export a Context-aware dialer. return cloudsql.Dial(instance) }) } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/auth.go ================================================ // 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) } func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, error) { switch plugin { case "caching_sha2_password": authResp := scrambleSHA256Password(authData, mc.cfg.Passwd) return authResp, nil case "mysql_old_password": if !mc.cfg.AllowOldPasswords { return nil, 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 := append(scrambleOldPassword(authData[:8], mc.cfg.Passwd), 0) return authResp, nil case "mysql_clear_password": if !mc.cfg.AllowCleartextPasswords { return nil, 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 append([]byte(mc.cfg.Passwd), 0), nil case "mysql_native_password": if !mc.cfg.AllowNativePasswords { return nil, 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, nil case "sha256_password": if len(mc.cfg.Passwd) == 0 { return []byte{0}, nil } if mc.cfg.tls != nil || mc.cfg.Net == "unix" { // write cleartext auth packet return append([]byte(mc.cfg.Passwd), 0), nil } pubKey := mc.cfg.pubKey if pubKey == nil { // request public key from server return []byte{1}, nil } // encrypted password enc, err := encryptPassword(mc.cfg.Passwd, authData, pubKey) return enc, err default: errLog.Print("unknown auth plugin:", plugin) return nil, 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, err := mc.auth(authData, plugin) if err != nil { return err } if err = mc.writeAuthSwitchPacket(authResp); 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(append([]byte(mc.cfg.Passwd), 0)) if err != nil { return err } } else { pubKey := mc.cfg.pubKey if pubKey == nil { // request public key from server data, err := mc.buf.takeSmallBuffer(4 + 1) if err != nil { return err } data[4] = cachingSha2PasswordRequestPublicKey mc.writePacket(data) // parse public key if data, err = mc.readPacket(); 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 } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/buffer.go ================================================ // 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 const maxCachedBufSize = 256 * 1024 // 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. // This buffer is backed by two byte slices in a double-buffering scheme type buffer struct { buf []byte // buf is a byte buffer who's length and capacity are equal. nc net.Conn idx int length int timeout time.Duration dbuf [2][]byte // dbuf is an array with the two byte slices that back this buffer flipcnt uint // flipccnt is the current buffer counter for double-buffering } // newBuffer allocates and returns a new buffer. func newBuffer(nc net.Conn) buffer { fg := make([]byte, defaultBufSize) return buffer{ buf: fg, nc: nc, dbuf: [2][]byte{fg, nil}, } } // flip replaces the active buffer with the background buffer // this is a delayed flip that simply increases the buffer counter; // the actual flip will be performed the next time we call `buffer.fill` func (b *buffer) flip() { b.flipcnt += 1 } // fill reads into the buffer until at least _need_ bytes are in it func (b *buffer) fill(need int) error { n := b.length // fill data into its double-buffering target: if we've called // flip on this buffer, we'll be copying to the background buffer, // and then filling it with network data; otherwise we'll just move // the contents of the current buffer to the front before filling it dest := b.dbuf[b.flipcnt&1] // grow buffer if necessary to fit the whole packet. if need > len(dest) { // Round up to the next multiple of the default size dest = make([]byte, ((need/defaultBufSize)+1)*defaultBufSize) // if the allocated buffer is not too large, move it to backing storage // to prevent extra allocations on applications that perform large reads if len(dest) <= maxCachedBufSize { b.dbuf[b.flipcnt&1] = dest } } // if we're filling the fg buffer, move the existing data to the start of it. // if we're filling the bg buffer, copy over the data if n > 0 { copy(dest[:n], b.buf[b.idx:]) } b.buf = dest 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 } // takeBuffer 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, error) { if b.length > 0 { return nil, ErrBusyBuffer } // test (cheap) general case first if length <= cap(b.buf) { return b.buf[:length], nil } if length < maxPacketSize { b.buf = make([]byte, length) return b.buf, nil } // buffer is larger than we want to store. return make([]byte, length), nil } // takeSmallBuffer is shortcut which can be used if length is // known to be smaller than defaultBufSize. // Only one buffer (total) can be used at a time. func (b *buffer) takeSmallBuffer(length int) ([]byte, error) { if b.length > 0 { return nil, ErrBusyBuffer } return b.buf[:length], nil } // takeCompleteBuffer returns the complete existing buffer. // This can be used if the necessary buffer size is unknown. // cap and len of the returned buffer will be equal. // Only one buffer (total) can be used at a time. func (b *buffer) takeCompleteBuffer() ([]byte, error) { if b.length > 0 { return nil, ErrBusyBuffer } return b.buf, nil } // store stores buf, an updated buffer, if its suitable to do so. func (b *buffer) store(buf []byte) error { if b.length > 0 { return ErrBusyBuffer } else if cap(buf) <= maxPacketSize && cap(buf) > cap(b.buf) { b.buf = buf[:cap(buf)] } return nil } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/collations.go ================================================ // 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 = "utf8mb4_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 WHERE ID<256 ORDER BY ID // // Handshake packet have only 1 byte for collation_id. So we can't use collations with ID > 255. // // ucs2, utf16, and utf32 can't be used for connection charset. // https://dev.mysql.com/doc/refman/5.7/en/charset-connection.html#charset-connection-impermissible-client-charset // They are commented out to reduce this map. 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, "utf8_tolower_ci": 76, "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, "gb18030_chinese_ci": 248, "gb18030_bin": 249, "gb18030_unicode_520_ci": 250, "utf8mb4_0900_ai_ci": 255, } // 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, "gb18030_chinese_ci": true, "gb18030_bin": true, "gb18030_unicode_520_ci": true, } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/conncheck.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2019 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. // +build !windows,!appengine package mysql import ( "errors" "io" "net" "syscall" ) var errUnexpectedRead = errors.New("unexpected read from socket") func connCheck(c net.Conn) error { var ( n int err error buff [1]byte ) sconn, ok := c.(syscall.Conn) if !ok { return nil } rc, err := sconn.SyscallConn() if err != nil { return err } rerr := rc.Read(func(fd uintptr) bool { n, err = syscall.Read(int(fd), buff[:]) return true }) switch { case rerr != nil: return rerr case n == 0 && err == nil: return io.EOF case n > 0: return errUnexpectedRead case err == syscall.EAGAIN || err == syscall.EWOULDBLOCK: return nil default: return err } } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/conncheck_dummy.go ================================================ // Go MySQL Driver - A MySQL-Driver for Go's database/sql package // // Copyright 2019 The Go-MySQL-Driver Authors. All rights reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. // +build windows appengine package mysql import "net" func connCheck(c net.Conn) error { return nil } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/connection.go ================================================ // 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" ) type mysqlConn struct { buf buffer netConn net.Conn rawConn net.Conn // underlying connection when netConn is TLS connection. affectedRows uint64 insertId uint64 cfg *Config maxAllowedPacket int maxWriteSize int writeTimeout time.Duration flags clientFlag status statusFlag sequence uint8 parseTime bool reset bool // set when the Go SQL package calls ResetSession // for context support (Go 1.8+) watching bool watcher chan<- context.Context 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, err := mc.buf.takeCompleteBuffer() if err != nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(err) 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 uint64: // Handle uint64 explicitly because our custom ConvertValue emits unsigned values buf = strconv.AppendUint(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 mc.markBadConn(err) } 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 } // When ctx is already cancelled, don't watch it. if err := ctx.Err(); err != nil { return err } // When ctx is not cancellable, don't watch it. if ctx.Done() == nil { return nil } // When watcher is not alive, can't watch it. if mc.watcher == nil { return nil } mc.watching = true mc.watcher <- ctx return nil } func (mc *mysqlConn) startWatcher() { watcher := make(chan context.Context, 1) mc.watcher = watcher finished := make(chan struct{}) mc.finished = finished go func() { for { var ctx context.Context 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 } mc.reset = true return nil } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/connector.go ================================================ // 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 ( "context" "database/sql/driver" "net" ) type connector struct { cfg *Config // immutable private copy. } // Connect implements driver.Connector interface. // Connect returns a connection to the database. func (c *connector) Connect(ctx context.Context) (driver.Conn, error) { var err error // New mysqlConn mc := &mysqlConn{ maxAllowedPacket: maxPacketSize, maxWriteSize: maxPacketSize - 1, closech: make(chan struct{}), cfg: c.cfg, } mc.parseTime = mc.cfg.ParseTime // Connect to Server dialsLock.RLock() dial, ok := dials[mc.cfg.Net] dialsLock.RUnlock() if ok { mc.netConn, err = dial(ctx, mc.cfg.Addr) } else { nd := net.Dialer{Timeout: mc.cfg.Timeout} mc.netConn, err = nd.DialContext(ctx, mc.cfg.Net, mc.cfg.Addr) } if err != nil { if nerr, ok := err.(net.Error); ok && nerr.Temporary() { errLog.Print("net.Error from Dial()': ", nerr.Error()) return nil, driver.ErrBadConn } 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() if err := mc.watchCancel(ctx); err != nil { return nil, err } defer mc.finish() 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 } if plugin == "" { plugin = defaultAuthPlugin } // Send Client Authentication Packet authResp, 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, err = mc.auth(authData, plugin) if err != nil { mc.cleanup() return nil, err } } if err = mc.writeHandshakeResponsePacket(authResp, 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 } // Driver implements driver.Connector interface. // Driver returns &MySQLDriver{}. func (c *connector) Driver() driver.Driver { return &MySQLDriver{} } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/const.go ================================================ // 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 ) ================================================ FILE: vendor/github.com/go-sql-driver/mysql/driver.go ================================================ // 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 ( "context" "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 // // Deprecated: users should register a DialContextFunc instead type DialFunc func(addr string) (net.Conn, error) // DialContextFunc is a function which can be used to establish the network connection. // Custom dial functions must be registered with RegisterDialContext type DialContextFunc func(ctx context.Context, addr string) (net.Conn, error) var ( dialsLock sync.RWMutex dials map[string]DialContextFunc ) // RegisterDialContext registers a custom dial function. It can then be used by the // network address mynet(addr), where mynet is the registered new network. // The current context for the connection and its address is passed to the dial function. func RegisterDialContext(net string, dial DialContextFunc) { dialsLock.Lock() defer dialsLock.Unlock() if dials == nil { dials = make(map[string]DialContextFunc) } dials[net] = dial } // 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. // // Deprecated: users should call RegisterDialContext instead func RegisterDial(network string, dial DialFunc) { RegisterDialContext(network, func(_ context.Context, addr string) (net.Conn, error) { return dial(addr) }) } // Open new Connection. // See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how // the DSN string is formatted func (d MySQLDriver) Open(dsn string) (driver.Conn, error) { cfg, err := ParseDSN(dsn) if err != nil { return nil, err } c := &connector{ cfg: cfg, } return c.Connect(context.Background()) } func init() { sql.Register("mysql", &MySQLDriver{}) } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/driver_go110.go ================================================ // 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/. // +build go1.10 package mysql import ( "database/sql/driver" ) // NewConnector returns new driver.Connector. func NewConnector(cfg *Config) (driver.Connector, error) { cfg = cfg.Clone() // normalize the contents of cfg so calls to NewConnector have the same // behavior as MySQLDriver.OpenConnector if err := cfg.normalize(); err != nil { return nil, err } return &connector{cfg: cfg}, nil } // OpenConnector implements driver.DriverContext. func (d MySQLDriver) OpenConnector(dsn string) (driver.Connector, error) { cfg, err := ParseDSN(dsn) if err != nil { return nil, err } return &connector{ cfg: cfg, }, nil } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/dsn.go ================================================ // 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" "math/big" "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) Clone() *Config { cp := *cfg if cp.tls != nil { cp.tls = cfg.tls.Clone() } if len(cp.Params) > 0 { cp.Params = make(map[string]string, len(cfg.Params)) for k, v := range cfg.Params { cp.Params[k] = v } } if cfg.pubKey != nil { cp.pubKey = &rsa.PublicKey{ N: new(big.Int).Set(cfg.pubKey.N), E: cfg.pubKey.E, } } return &cp } 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) } switch cfg.TLSConfig { case "false", "": // don't set anything case "true": cfg.tls = &tls.Config{} case "skip-verify", "preferred": cfg.tls = &tls.Config{InsecureSkipVerify: true} default: cfg.tls = getTLSConfigClone(cfg.TLSConfig) if cfg.tls == nil { return errors.New("invalid value / unknown config name: " + cfg.TLSConfig) } } if cfg.tls != nil && cfg.tls.ServerName == "" && !cfg.tls.InsecureSkipVerify { host, _, err := net.SplitHostPort(cfg.Addr) if err == nil { cfg.tls.ServerName = host } } if cfg.ServerPubKey != "" { cfg.pubKey = getServerPubKey(cfg.ServerPubKey) if cfg.pubKey == nil { return errors.New("invalid value / unknown server pub key name: " + cfg.ServerPubKey) } } 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) } cfg.ServerPubKey = 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" } else { cfg.TLSConfig = "false" } } else if vl := strings.ToLower(value); vl == "skip-verify" || vl == "preferred" { cfg.TLSConfig = vl } else { name, err := url.QueryUnescape(value) if err != nil { return fmt.Errorf("invalid value for TLS config name: %v", err) } cfg.TLSConfig = 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 } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/errors.go ================================================ // 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) } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/fields.go ================================================ // 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 } } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/infile.go ================================================ // 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 } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/packets.go ================================================ // 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 } // Perform a stale connection check. We only perform this check for // the first query on a connection that has been checked out of the // connection pool: a fresh connection from the pool is more likely // to be stale, and it has not performed any previous writes that // could cause data corruption, so it's safe to return ErrBadConn // if the check fails. if mc.reset { mc.reset = false conn := mc.netConn if mc.rawConn != nil { conn = mc.rawConn } var err error // If this connection has a ReadTimeout which we've been setting on // reads, reset it to its default value before we attempt a non-blocking // read, otherwise the scheduler will just time us out before we can read if mc.cfg.ReadTimeout != 0 { err = conn.SetReadDeadline(time.Time{}) } if err == nil { err = connCheck(conn) } if err != nil { errLog.Print("closing bad idle connection: ", err) mc.Close() return driver.ErrBadConn } } 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() (data []byte, plugin string, err 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 } 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 { if mc.cfg.TLSConfig == "preferred" { mc.cfg.tls = nil } else { return nil, "", ErrNoTLS } } pos += 2 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 } // 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, 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 authRespLen := len(authResp) authRespLEI := appendLengthEncodedInteger(authRespLEIBuf[:0], uint64(authRespLen)) 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 // 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, err := mc.buf.takeSmallBuffer(pktLen + 4) if err != nil { // cannot take the buffer. Something must be wrong with the connection errLog.Print(err) 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.rawConn = mc.netConn 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) // 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 pos++ // Send Auth packet return mc.writePacket(data[:pos]) } // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error { pktLen := 4 + len(authData) data, err := mc.buf.takeSmallBuffer(pktLen) if err != nil { // cannot take the buffer. Something must be wrong with the connection errLog.Print(err) return errBadConnNoWrite } // Add the auth data [EOF] copy(data[4:], authData) return mc.writePacket(data) } /****************************************************************************** * Command Packets * ******************************************************************************/ func (mc *mysqlConn) writeCommandPacket(command byte) error { // Reset Packet Sequence mc.sequence = 0 data, err := mc.buf.takeSmallBuffer(4 + 1) if err != nil { // cannot take the buffer. Something must be wrong with the connection errLog.Print(err) 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, err := mc.buf.takeBuffer(pktLen + 4) if err != nil { // cannot take the buffer. Something must be wrong with the connection errLog.Print(err) 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, err := mc.buf.takeSmallBuffer(4 + 1 + 4) if err != nil { // cannot take the buffer. Something must be wrong with the connection errLog.Print(err) 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 threshold 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 var err error if len(args) == 0 { data, err = mc.buf.takeBuffer(minPktLen) } else { data, err = mc.buf.takeCompleteBuffer() // In this case the len(data) == cap(data) which is used to optimise the flow below. } if err != nil { // cannot take the buffer. Something must be wrong with the connection errLog.Print(err) 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 >= cap(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] // No need to clean nullMask as make ensures that. pos += maskLen } else { nullMask = data[pos : pos+maskLen] for i := range nullMask { 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 uint64: paramTypes[i+i] = byte(fieldTypeLongLong) paramTypes[i+i+1] = 0x80 // type is unsigned 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...) if err = mc.buf.store(data); err != nil { errLog.Print(err) return errBadConnNoWrite } } 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 } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/result.go ================================================ // 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 } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/rows.go ================================================ // 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 } // flip the buffer for this connection if we need to drain it. // note that for a successful query (i.e. one where rows.next() // has been called until it returns false), `rows.mc` will be nil // by the time the user calls `(*Rows).Close`, so we won't reach this // see: https://github.com/golang/go/commit/651ddbdb5056ded455f47f9c494c67b389622a47 mc.buf.flip() // 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 } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/statement.go ================================================ // 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" ) 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, reflect.Uint64: return rv.Uint(), 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() } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/transaction.go ================================================ // 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 } ================================================ FILE: vendor/github.com/go-sql-driver/mysql/utils.go ================================================ // 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" || strings.ToLower(key) == "preferred" { 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 whether 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 whether 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) } } ================================================ FILE: vendor/github.com/golang/freetype/AUTHORS ================================================ # This is the official list of Freetype-Go authors for copyright purposes. # This file is distinct from the CONTRIBUTORS files. # See the latter for an explanation. # # Freetype-Go is derived from Freetype, which is written in C. The latter # is copyright 1996-2010 David Turner, Robert Wilhelm, and Werner Lemberg. # Names should be added to this file as # Name or Organization # The email address is not required for organizations. # Please keep the list sorted. Google Inc. Jeff R. Allen Maksim Kochkin Michael Fogleman Rémy Oudompheng Roger Peppe Steven Edwards ================================================ FILE: vendor/github.com/golang/freetype/CONTRIBUTORS ================================================ # This is the official list of people who can contribute # (and typically have contributed) code to the Freetype-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. Andrew Gerrand Jeff R. Allen Maksim Kochkin Michael Fogleman Nigel Tao Rémy Oudompheng Rob Pike Roger Peppe Russ Cox Steven Edwards ================================================ FILE: vendor/github.com/golang/freetype/LICENSE ================================================ Use of the Freetype-Go software is subject to your choice of exactly one of the following two licenses: * The FreeType License, which is similar to the original BSD license with an advertising clause, or * The GNU General Public License (GPL), version 2 or later. The text of these licenses are available in the licenses/ftl.txt and the licenses/gpl.txt files respectively. They are also available at http://freetype.sourceforge.net/license.html The Luxi fonts in the testdata directory are licensed separately. See the testdata/COPYING file for details. ================================================ FILE: vendor/github.com/golang/freetype/README ================================================ The Freetype font rasterizer in the Go programming language. To download and install from source: $ go get github.com/golang/freetype It is an incomplete port: * It only supports TrueType fonts, and not Type 1 fonts nor bitmap fonts. * It only supports the Unicode encoding. There are also some implementation differences: * It uses a 26.6 fixed point co-ordinate system everywhere internally, as opposed to the original Freetype's mix of 26.6 (or 10.6 for 16-bit systems) in some places, and 24.8 in the "smooth" rasterizer. Freetype-Go is derived from Freetype, which is written in C. Freetype is copyright 1996-2010 David Turner, Robert Wilhelm, and Werner Lemberg. Freetype-Go is copyright The Freetype-Go Authors, who are listed in the AUTHORS file. Unless otherwise noted, the Freetype-Go source files are distributed under the BSD-style license found in the LICENSE file. ================================================ FILE: vendor/github.com/golang/freetype/freetype.go ================================================ // Copyright 2010 The Freetype-Go Authors. All rights reserved. // Use of this source code is governed by your choice of either the // FreeType License or the GNU General Public License version 2 (or // any later version), both of which can be found in the LICENSE file. // The freetype package provides a convenient API to draw text onto an image. // Use the freetype/raster and freetype/truetype packages for lower level // control over rasterization and TrueType parsing. package freetype // import "github.com/golang/freetype" import ( "errors" "image" "image/draw" "github.com/golang/freetype/raster" "github.com/golang/freetype/truetype" "golang.org/x/image/font" "golang.org/x/image/math/fixed" ) // These constants determine the size of the glyph cache. The cache is keyed // primarily by the glyph index modulo nGlyphs, and secondarily by sub-pixel // position for the mask image. Sub-pixel positions are quantized to // nXFractions possible values in both the x and y directions. const ( nGlyphs = 256 nXFractions = 4 nYFractions = 1 ) // An entry in the glyph cache is keyed explicitly by the glyph index and // implicitly by the quantized x and y fractional offset. It maps to a mask // image and an offset. type cacheEntry struct { valid bool glyph truetype.Index advanceWidth fixed.Int26_6 mask *image.Alpha offset image.Point } // ParseFont just calls the Parse function from the freetype/truetype package. // It is provided here so that code that imports this package doesn't need // to also include the freetype/truetype package. func ParseFont(b []byte) (*truetype.Font, error) { return truetype.Parse(b) } // Pt converts from a co-ordinate pair measured in pixels to a fixed.Point26_6 // co-ordinate pair measured in fixed.Int26_6 units. func Pt(x, y int) fixed.Point26_6 { return fixed.Point26_6{ X: fixed.Int26_6(x << 6), Y: fixed.Int26_6(y << 6), } } // A Context holds the state for drawing text in a given font and size. type Context struct { r *raster.Rasterizer f *truetype.Font glyphBuf truetype.GlyphBuf // clip is the clip rectangle for drawing. clip image.Rectangle // dst and src are the destination and source images for drawing. dst draw.Image src image.Image // fontSize and dpi are used to calculate scale. scale is the number of // 26.6 fixed point units in 1 em. hinting is the hinting policy. fontSize, dpi float64 scale fixed.Int26_6 hinting font.Hinting // cache is the glyph cache. cache [nGlyphs * nXFractions * nYFractions]cacheEntry } // PointToFixed converts the given number of points (as in "a 12 point font") // into a 26.6 fixed point number of pixels. func (c *Context) PointToFixed(x float64) fixed.Int26_6 { return fixed.Int26_6(x * float64(c.dpi) * (64.0 / 72.0)) } // drawContour draws the given closed contour with the given offset. func (c *Context) drawContour(ps []truetype.Point, dx, dy fixed.Int26_6) { if len(ps) == 0 { return } // The low bit of each point's Flags value is whether the point is on the // curve. Truetype fonts only have quadratic Bézier curves, not cubics. // Thus, two consecutive off-curve points imply an on-curve point in the // middle of those two. // // See http://chanae.walon.org/pub/ttf/ttf_glyphs.htm for more details. // ps[0] is a truetype.Point measured in FUnits and positive Y going // upwards. start is the same thing measured in fixed point units and // positive Y going downwards, and offset by (dx, dy). start := fixed.Point26_6{ X: dx + ps[0].X, Y: dy - ps[0].Y, } others := []truetype.Point(nil) if ps[0].Flags&0x01 != 0 { others = ps[1:] } else { last := fixed.Point26_6{ X: dx + ps[len(ps)-1].X, Y: dy - ps[len(ps)-1].Y, } if ps[len(ps)-1].Flags&0x01 != 0 { start = last others = ps[:len(ps)-1] } else { start = fixed.Point26_6{ X: (start.X + last.X) / 2, Y: (start.Y + last.Y) / 2, } others = ps } } c.r.Start(start) q0, on0 := start, true for _, p := range others { q := fixed.Point26_6{ X: dx + p.X, Y: dy - p.Y, } on := p.Flags&0x01 != 0 if on { if on0 { c.r.Add1(q) } else { c.r.Add2(q0, q) } } else { if on0 { // No-op. } else { mid := fixed.Point26_6{ X: (q0.X + q.X) / 2, Y: (q0.Y + q.Y) / 2, } c.r.Add2(q0, mid) } } q0, on0 = q, on } // Close the curve. if on0 { c.r.Add1(start) } else { c.r.Add2(q0, start) } } // rasterize returns the advance width, glyph mask and integer-pixel offset // to render the given glyph at the given sub-pixel offsets. // The 26.6 fixed point arguments fx and fy must be in the range [0, 1). func (c *Context) rasterize(glyph truetype.Index, fx, fy fixed.Int26_6) ( fixed.Int26_6, *image.Alpha, image.Point, error) { if err := c.glyphBuf.Load(c.f, c.scale, glyph, c.hinting); err != nil { return 0, nil, image.Point{}, err } // Calculate the integer-pixel bounds for the glyph. xmin := int(fx+c.glyphBuf.Bounds.Min.X) >> 6 ymin := int(fy-c.glyphBuf.Bounds.Max.Y) >> 6 xmax := int(fx+c.glyphBuf.Bounds.Max.X+0x3f) >> 6 ymax := int(fy-c.glyphBuf.Bounds.Min.Y+0x3f) >> 6 if xmin > xmax || ymin > ymax { return 0, nil, image.Point{}, errors.New("freetype: negative sized glyph") } // A TrueType's glyph's nodes can have negative co-ordinates, but the // rasterizer clips anything left of x=0 or above y=0. xmin and ymin are // the pixel offsets, based on the font's FUnit metrics, that let a // negative co-ordinate in TrueType space be non-negative in rasterizer // space. xmin and ymin are typically <= 0. fx -= fixed.Int26_6(xmin << 6) fy -= fixed.Int26_6(ymin << 6) // Rasterize the glyph's vectors. c.r.Clear() e0 := 0 for _, e1 := range c.glyphBuf.Ends { c.drawContour(c.glyphBuf.Points[e0:e1], fx, fy) e0 = e1 } a := image.NewAlpha(image.Rect(0, 0, xmax-xmin, ymax-ymin)) c.r.Rasterize(raster.NewAlphaSrcPainter(a)) return c.glyphBuf.AdvanceWidth, a, image.Point{xmin, ymin}, nil } // glyph returns the advance width, glyph mask and integer-pixel offset to // render the given glyph at the given sub-pixel point. It is a cache for the // rasterize method. Unlike rasterize, p's co-ordinates do not have to be in // the range [0, 1). func (c *Context) glyph(glyph truetype.Index, p fixed.Point26_6) ( fixed.Int26_6, *image.Alpha, image.Point, error) { // Split p.X and p.Y into their integer and fractional parts. ix, fx := int(p.X>>6), p.X&0x3f iy, fy := int(p.Y>>6), p.Y&0x3f // Calculate the index t into the cache array. tg := int(glyph) % nGlyphs tx := int(fx) / (64 / nXFractions) ty := int(fy) / (64 / nYFractions) t := ((tg*nXFractions)+tx)*nYFractions + ty // Check for a cache hit. if e := c.cache[t]; e.valid && e.glyph == glyph { return e.advanceWidth, e.mask, e.offset.Add(image.Point{ix, iy}), nil } // Rasterize the glyph and put the result into the cache. advanceWidth, mask, offset, err := c.rasterize(glyph, fx, fy) if err != nil { return 0, nil, image.Point{}, err } c.cache[t] = cacheEntry{true, glyph, advanceWidth, mask, offset} return advanceWidth, mask, offset.Add(image.Point{ix, iy}), nil } // DrawString draws s at p and returns p advanced by the text extent. The text // is placed so that the left edge of the em square of the first character of s // and the baseline intersect at p. The majority of the affected pixels will be // above and to the right of the point, but some may be below or to the left. // For example, drawing a string that starts with a 'J' in an italic font may // affect pixels below and left of the point. // // p is a fixed.Point26_6 and can therefore represent sub-pixel positions. func (c *Context) DrawString(s string, p fixed.Point26_6) (fixed.Point26_6, error) { if c.f == nil { return fixed.Point26_6{}, errors.New("freetype: DrawText called with a nil font") } prev, hasPrev := truetype.Index(0), false for _, rune := range s { index := c.f.Index(rune) if hasPrev { kern := c.f.Kern(c.scale, prev, index) if c.hinting != font.HintingNone { kern = (kern + 32) &^ 63 } p.X += kern } advanceWidth, mask, offset, err := c.glyph(index, p) if err != nil { return fixed.Point26_6{}, err } p.X += advanceWidth glyphRect := mask.Bounds().Add(offset) dr := c.clip.Intersect(glyphRect) if !dr.Empty() { mp := image.Point{0, dr.Min.Y - glyphRect.Min.Y} draw.DrawMask(c.dst, dr, c.src, image.ZP, mask, mp, draw.Over) } prev, hasPrev = index, true } return p, nil } // recalc recalculates scale and bounds values from the font size, screen // resolution and font metrics, and invalidates the glyph cache. func (c *Context) recalc() { c.scale = fixed.Int26_6(c.fontSize * c.dpi * (64.0 / 72.0)) if c.f == nil { c.r.SetBounds(0, 0) } else { // Set the rasterizer's bounds to be big enough to handle the largest glyph. b := c.f.Bounds(c.scale) xmin := +int(b.Min.X) >> 6 ymin := -int(b.Max.Y) >> 6 xmax := +int(b.Max.X+63) >> 6 ymax := -int(b.Min.Y-63) >> 6 c.r.SetBounds(xmax-xmin, ymax-ymin) } for i := range c.cache { c.cache[i] = cacheEntry{} } } // SetDPI sets the screen resolution in dots per inch. func (c *Context) SetDPI(dpi float64) { if c.dpi == dpi { return } c.dpi = dpi c.recalc() } // SetFont sets the font used to draw text. func (c *Context) SetFont(f *truetype.Font) { if c.f == f { return } c.f = f c.recalc() } // SetFontSize sets the font size in points (as in "a 12 point font"). func (c *Context) SetFontSize(fontSize float64) { if c.fontSize == fontSize { return } c.fontSize = fontSize c.recalc() } // SetHinting sets the hinting policy. func (c *Context) SetHinting(hinting font.Hinting) { c.hinting = hinting for i := range c.cache { c.cache[i] = cacheEntry{} } } // SetDst sets the destination image for draw operations. func (c *Context) SetDst(dst draw.Image) { c.dst = dst } // SetSrc sets the source image for draw operations. This is typically an // image.Uniform. func (c *Context) SetSrc(src image.Image) { c.src = src } // SetClip sets the clip rectangle for drawing. func (c *Context) SetClip(clip image.Rectangle) { c.clip = clip } // TODO(nigeltao): implement Context.SetGamma. // NewContext creates a new Context. func NewContext() *Context { return &Context{ r: raster.NewRasterizer(0, 0), fontSize: 12, dpi: 72, scale: 12 << 6, } } ================================================ FILE: vendor/github.com/golang/freetype/raster/geom.go ================================================ // Copyright 2010 The Freetype-Go Authors. All rights reserved. // Use of this source code is governed by your choice of either the // FreeType License or the GNU General Public License version 2 (or // any later version), both of which can be found in the LICENSE file. package raster import ( "fmt" "math" "golang.org/x/image/math/fixed" ) // maxAbs returns the maximum of abs(a) and abs(b). func maxAbs(a, b fixed.Int26_6) fixed.Int26_6 { if a < 0 { a = -a } if b < 0 { b = -b } if a < b { return b } return a } // pNeg returns the vector -p, or equivalently p rotated by 180 degrees. func pNeg(p fixed.Point26_6) fixed.Point26_6 { return fixed.Point26_6{-p.X, -p.Y} } // pDot returns the dot product p·q. func pDot(p fixed.Point26_6, q fixed.Point26_6) fixed.Int52_12 { px, py := int64(p.X), int64(p.Y) qx, qy := int64(q.X), int64(q.Y) return fixed.Int52_12(px*qx + py*qy) } // pLen returns the length of the vector p. func pLen(p fixed.Point26_6) fixed.Int26_6 { // TODO(nigeltao): use fixed point math. x := float64(p.X) y := float64(p.Y) return fixed.Int26_6(math.Sqrt(x*x + y*y)) } // pNorm returns the vector p normalized to the given length, or zero if p is // degenerate. func pNorm(p fixed.Point26_6, length fixed.Int26_6) fixed.Point26_6 { d := pLen(p) if d == 0 { return fixed.Point26_6{} } s, t := int64(length), int64(d) x := int64(p.X) * s / t y := int64(p.Y) * s / t return fixed.Point26_6{fixed.Int26_6(x), fixed.Int26_6(y)} } // pRot45CW returns the vector p rotated clockwise by 45 degrees. // // Note that the Y-axis grows downwards, so {1, 0}.Rot45CW is {1/√2, 1/√2}. func pRot45CW(p fixed.Point26_6) fixed.Point26_6 { // 181/256 is approximately 1/√2, or sin(π/4). px, py := int64(p.X), int64(p.Y) qx := (+px - py) * 181 / 256 qy := (+px + py) * 181 / 256 return fixed.Point26_6{fixed.Int26_6(qx), fixed.Int26_6(qy)} } // pRot90CW returns the vector p rotated clockwise by 90 degrees. // // Note that the Y-axis grows downwards, so {1, 0}.Rot90CW is {0, 1}. func pRot90CW(p fixed.Point26_6) fixed.Point26_6 { return fixed.Point26_6{-p.Y, p.X} } // pRot135CW returns the vector p rotated clockwise by 135 degrees. // // Note that the Y-axis grows downwards, so {1, 0}.Rot135CW is {-1/√2, 1/√2}. func pRot135CW(p fixed.Point26_6) fixed.Point26_6 { // 181/256 is approximately 1/√2, or sin(π/4). px, py := int64(p.X), int64(p.Y) qx := (-px - py) * 181 / 256 qy := (+px - py) * 181 / 256 return fixed.Point26_6{fixed.Int26_6(qx), fixed.Int26_6(qy)} } // pRot45CCW returns the vector p rotated counter-clockwise by 45 degrees. // // Note that the Y-axis grows downwards, so {1, 0}.Rot45CCW is {1/√2, -1/√2}. func pRot45CCW(p fixed.Point26_6) fixed.Point26_6 { // 181/256 is approximately 1/√2, or sin(π/4). px, py := int64(p.X), int64(p.Y) qx := (+px + py) * 181 / 256 qy := (-px + py) * 181 / 256 return fixed.Point26_6{fixed.Int26_6(qx), fixed.Int26_6(qy)} } // pRot90CCW returns the vector p rotated counter-clockwise by 90 degrees. // // Note that the Y-axis grows downwards, so {1, 0}.Rot90CCW is {0, -1}. func pRot90CCW(p fixed.Point26_6) fixed.Point26_6 { return fixed.Point26_6{p.Y, -p.X} } // pRot135CCW returns the vector p rotated counter-clockwise by 135 degrees. // // Note that the Y-axis grows downwards, so {1, 0}.Rot135CCW is {-1/√2, -1/√2}. func pRot135CCW(p fixed.Point26_6) fixed.Point26_6 { // 181/256 is approximately 1/√2, or sin(π/4). px, py := int64(p.X), int64(p.Y) qx := (-px + py) * 181 / 256 qy := (-px - py) * 181 / 256 return fixed.Point26_6{fixed.Int26_6(qx), fixed.Int26_6(qy)} } // An Adder accumulates points on a curve. type Adder interface { // Start starts a new curve at the given point. Start(a fixed.Point26_6) // Add1 adds a linear segment to the current curve. Add1(b fixed.Point26_6) // Add2 adds a quadratic segment to the current curve. Add2(b, c fixed.Point26_6) // Add3 adds a cubic segment to the current curve. Add3(b, c, d fixed.Point26_6) } // A Path is a sequence of curves, and a curve is a start point followed by a // sequence of linear, quadratic or cubic segments. type Path []fixed.Int26_6 // String returns a human-readable representation of a Path. func (p Path) String() string { s := "" for i := 0; i < len(p); { if i != 0 { s += " " } switch p[i] { case 0: s += "S0" + fmt.Sprint([]fixed.Int26_6(p[i+1:i+3])) i += 4 case 1: s += "A1" + fmt.Sprint([]fixed.Int26_6(p[i+1:i+3])) i += 4 case 2: s += "A2" + fmt.Sprint([]fixed.Int26_6(p[i+1:i+5])) i += 6 case 3: s += "A3" + fmt.Sprint([]fixed.Int26_6(p[i+1:i+7])) i += 8 default: panic("freetype/raster: bad path") } } return s } // Clear cancels any previous calls to p.Start or p.AddXxx. func (p *Path) Clear() { *p = (*p)[:0] } // Start starts a new curve at the given point. func (p *Path) Start(a fixed.Point26_6) { *p = append(*p, 0, a.X, a.Y, 0) } // Add1 adds a linear segment to the current curve. func (p *Path) Add1(b fixed.Point26_6) { *p = append(*p, 1, b.X, b.Y, 1) } // Add2 adds a quadratic segment to the current curve. func (p *Path) Add2(b, c fixed.Point26_6) { *p = append(*p, 2, b.X, b.Y, c.X, c.Y, 2) } // Add3 adds a cubic segment to the current curve. func (p *Path) Add3(b, c, d fixed.Point26_6) { *p = append(*p, 3, b.X, b.Y, c.X, c.Y, d.X, d.Y, 3) } // AddPath adds the Path q to p. func (p *Path) AddPath(q Path) { *p = append(*p, q...) } // AddStroke adds a stroked Path. func (p *Path) AddStroke(q Path, width fixed.Int26_6, cr Capper, jr Joiner) { Stroke(p, q, width, cr, jr) } // firstPoint returns the first point in a non-empty Path. func (p Path) firstPoint() fixed.Point26_6 { return fixed.Point26_6{p[1], p[2]} } // lastPoint returns the last point in a non-empty Path. func (p Path) lastPoint() fixed.Point26_6 { return fixed.Point26_6{p[len(p)-3], p[len(p)-2]} } // addPathReversed adds q reversed to p. // For example, if q consists of a linear segment from A to B followed by a // quadratic segment from B to C to D, then the values of q looks like: // index: 01234567890123 // value: 0AA01BB12CCDD2 // So, when adding q backwards to p, we want to Add2(C, B) followed by Add1(A). func addPathReversed(p Adder, q Path) { if len(q) == 0 { return } i := len(q) - 1 for { switch q[i] { case 0: return case 1: i -= 4 p.Add1( fixed.Point26_6{q[i-2], q[i-1]}, ) case 2: i -= 6 p.Add2( fixed.Point26_6{q[i+2], q[i+3]}, fixed.Point26_6{q[i-2], q[i-1]}, ) case 3: i -= 8 p.Add3( fixed.Point26_6{q[i+4], q[i+5]}, fixed.Point26_6{q[i+2], q[i+3]}, fixed.Point26_6{q[i-2], q[i-1]}, ) default: panic("freetype/raster: bad path") } } } ================================================ FILE: vendor/github.com/golang/freetype/raster/paint.go ================================================ // Copyright 2010 The Freetype-Go Authors. All rights reserved. // Use of this source code is governed by your choice of either the // FreeType License or the GNU General Public License version 2 (or // any later version), both of which can be found in the LICENSE file. package raster import ( "image" "image/color" "image/draw" "math" ) // A Span is a horizontal segment of pixels with constant alpha. X0 is an // inclusive bound and X1 is exclusive, the same as for slices. A fully opaque // Span has Alpha == 0xffff. type Span struct { Y, X0, X1 int Alpha uint32 } // A Painter knows how to paint a batch of Spans. Rasterization may involve // Painting multiple batches, and done will be true for the final batch. The // Spans' Y values are monotonically increasing during a rasterization. Paint // may use all of ss as scratch space during the call. type Painter interface { Paint(ss []Span, done bool) } // The PainterFunc type adapts an ordinary function to the Painter interface. type PainterFunc func(ss []Span, done bool) // Paint just delegates the call to f. func (f PainterFunc) Paint(ss []Span, done bool) { f(ss, done) } // An AlphaOverPainter is a Painter that paints Spans onto a *image.Alpha using // the Over Porter-Duff composition operator. type AlphaOverPainter struct { Image *image.Alpha } // Paint satisfies the Painter interface. func (r AlphaOverPainter) Paint(ss []Span, done bool) { b := r.Image.Bounds() for _, s := range ss { if s.Y < b.Min.Y { continue } if s.Y >= b.Max.Y { return } if s.X0 < b.Min.X { s.X0 = b.Min.X } if s.X1 > b.Max.X { s.X1 = b.Max.X } if s.X0 >= s.X1 { continue } base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X p := r.Image.Pix[base+s.X0 : base+s.X1] a := int(s.Alpha >> 8) for i, c := range p { v := int(c) p[i] = uint8((v*255 + (255-v)*a) / 255) } } } // NewAlphaOverPainter creates a new AlphaOverPainter for the given image. func NewAlphaOverPainter(m *image.Alpha) AlphaOverPainter { return AlphaOverPainter{m} } // An AlphaSrcPainter is a Painter that paints Spans onto a *image.Alpha using // the Src Porter-Duff composition operator. type AlphaSrcPainter struct { Image *image.Alpha } // Paint satisfies the Painter interface. func (r AlphaSrcPainter) Paint(ss []Span, done bool) { b := r.Image.Bounds() for _, s := range ss { if s.Y < b.Min.Y { continue } if s.Y >= b.Max.Y { return } if s.X0 < b.Min.X { s.X0 = b.Min.X } if s.X1 > b.Max.X { s.X1 = b.Max.X } if s.X0 >= s.X1 { continue } base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X p := r.Image.Pix[base+s.X0 : base+s.X1] color := uint8(s.Alpha >> 8) for i := range p { p[i] = color } } } // NewAlphaSrcPainter creates a new AlphaSrcPainter for the given image. func NewAlphaSrcPainter(m *image.Alpha) AlphaSrcPainter { return AlphaSrcPainter{m} } // An RGBAPainter is a Painter that paints Spans onto a *image.RGBA. type RGBAPainter struct { // Image is the image to compose onto. Image *image.RGBA // Op is the Porter-Duff composition operator. Op draw.Op // cr, cg, cb and ca are the 16-bit color to paint the spans. cr, cg, cb, ca uint32 } // Paint satisfies the Painter interface. func (r *RGBAPainter) Paint(ss []Span, done bool) { b := r.Image.Bounds() for _, s := range ss { if s.Y < b.Min.Y { continue } if s.Y >= b.Max.Y { return } if s.X0 < b.Min.X { s.X0 = b.Min.X } if s.X1 > b.Max.X { s.X1 = b.Max.X } if s.X0 >= s.X1 { continue } // This code mimics drawGlyphOver in $GOROOT/src/image/draw/draw.go. ma := s.Alpha const m = 1<<16 - 1 i0 := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride + (s.X0-r.Image.Rect.Min.X)*4 i1 := i0 + (s.X1-s.X0)*4 if r.Op == draw.Over { for i := i0; i < i1; i += 4 { dr := uint32(r.Image.Pix[i+0]) dg := uint32(r.Image.Pix[i+1]) db := uint32(r.Image.Pix[i+2]) da := uint32(r.Image.Pix[i+3]) a := (m - (r.ca * ma / m)) * 0x101 r.Image.Pix[i+0] = uint8((dr*a + r.cr*ma) / m >> 8) r.Image.Pix[i+1] = uint8((dg*a + r.cg*ma) / m >> 8) r.Image.Pix[i+2] = uint8((db*a + r.cb*ma) / m >> 8) r.Image.Pix[i+3] = uint8((da*a + r.ca*ma) / m >> 8) } } else { for i := i0; i < i1; i += 4 { r.Image.Pix[i+0] = uint8(r.cr * ma / m >> 8) r.Image.Pix[i+1] = uint8(r.cg * ma / m >> 8) r.Image.Pix[i+2] = uint8(r.cb * ma / m >> 8) r.Image.Pix[i+3] = uint8(r.ca * ma / m >> 8) } } } } // SetColor sets the color to paint the spans. func (r *RGBAPainter) SetColor(c color.Color) { r.cr, r.cg, r.cb, r.ca = c.RGBA() } // NewRGBAPainter creates a new RGBAPainter for the given image. func NewRGBAPainter(m *image.RGBA) *RGBAPainter { return &RGBAPainter{Image: m} } // A MonochromePainter wraps another Painter, quantizing each Span's alpha to // be either fully opaque or fully transparent. type MonochromePainter struct { Painter Painter y, x0, x1 int } // Paint delegates to the wrapped Painter after quantizing each Span's alpha // value and merging adjacent fully opaque Spans. func (m *MonochromePainter) Paint(ss []Span, done bool) { // We compact the ss slice, discarding any Spans whose alpha quantizes to zero. j := 0 for _, s := range ss { if s.Alpha >= 0x8000 { if m.y == s.Y && m.x1 == s.X0 { m.x1 = s.X1 } else { ss[j] = Span{m.y, m.x0, m.x1, 1<<16 - 1} j++ m.y, m.x0, m.x1 = s.Y, s.X0, s.X1 } } } if done { // Flush the accumulated Span. finalSpan := Span{m.y, m.x0, m.x1, 1<<16 - 1} if j < len(ss) { ss[j] = finalSpan j++ m.Painter.Paint(ss[:j], true) } else if j == len(ss) { m.Painter.Paint(ss, false) if cap(ss) > 0 { ss = ss[:1] } else { ss = make([]Span, 1) } ss[0] = finalSpan m.Painter.Paint(ss, true) } else { panic("unreachable") } // Reset the accumulator, so that this Painter can be re-used. m.y, m.x0, m.x1 = 0, 0, 0 } else { m.Painter.Paint(ss[:j], false) } } // NewMonochromePainter creates a new MonochromePainter that wraps the given // Painter. func NewMonochromePainter(p Painter) *MonochromePainter { return &MonochromePainter{Painter: p} } // A GammaCorrectionPainter wraps another Painter, performing gamma-correction // on each Span's alpha value. type GammaCorrectionPainter struct { // Painter is the wrapped Painter. Painter Painter // a is the precomputed alpha values for linear interpolation, with fully // opaque == 0xffff. a [256]uint16 // gammaIsOne is whether gamma correction is a no-op. gammaIsOne bool } // Paint delegates to the wrapped Painter after performing gamma-correction on // each Span. func (g *GammaCorrectionPainter) Paint(ss []Span, done bool) { if !g.gammaIsOne { const n = 0x101 for i, s := range ss { if s.Alpha == 0 || s.Alpha == 0xffff { continue } p, q := s.Alpha/n, s.Alpha%n // The resultant alpha is a linear interpolation of g.a[p] and g.a[p+1]. a := uint32(g.a[p])*(n-q) + uint32(g.a[p+1])*q ss[i].Alpha = (a + n/2) / n } } g.Painter.Paint(ss, done) } // SetGamma sets the gamma value. func (g *GammaCorrectionPainter) SetGamma(gamma float64) { g.gammaIsOne = gamma == 1 if g.gammaIsOne { return } for i := 0; i < 256; i++ { a := float64(i) / 0xff a = math.Pow(a, gamma) g.a[i] = uint16(0xffff * a) } } // NewGammaCorrectionPainter creates a new GammaCorrectionPainter that wraps // the given Painter. func NewGammaCorrectionPainter(p Painter, gamma float64) *GammaCorrectionPainter { g := &GammaCorrectionPainter{Painter: p} g.SetGamma(gamma) return g } ================================================ FILE: vendor/github.com/golang/freetype/raster/raster.go ================================================ // Copyright 2010 The Freetype-Go Authors. All rights reserved. // Use of this source code is governed by your choice of either the // FreeType License or the GNU General Public License version 2 (or // any later version), both of which can be found in the LICENSE file. // Package raster provides an anti-aliasing 2-D rasterizer. // // It is part of the larger Freetype suite of font-related packages, but the // raster package is not specific to font rasterization, and can be used // standalone without any other Freetype package. // // Rasterization is done by the same area/coverage accumulation algorithm as // the Freetype "smooth" module, and the Anti-Grain Geometry library. A // description of the area/coverage algorithm is at // http://projects.tuxee.net/cl-vectors/section-the-cl-aa-algorithm package raster // import "github.com/golang/freetype/raster" import ( "strconv" "golang.org/x/image/math/fixed" ) // A cell is part of a linked list (for a given yi co-ordinate) of accumulated // area/coverage for the pixel at (xi, yi). type cell struct { xi int area, cover int next int } type Rasterizer struct { // If false, the default behavior is to use the even-odd winding fill // rule during Rasterize. UseNonZeroWinding bool // An offset (in pixels) to the painted spans. Dx, Dy int // The width of the Rasterizer. The height is implicit in len(cellIndex). width int // splitScaleN is the scaling factor used to determine how many times // to decompose a quadratic or cubic segment into a linear approximation. splitScale2, splitScale3 int // The current pen position. a fixed.Point26_6 // The current cell and its area/coverage being accumulated. xi, yi int area, cover int // Saved cells. cell []cell // Linked list of cells, one per row. cellIndex []int // Buffers. cellBuf [256]cell cellIndexBuf [64]int spanBuf [64]Span } // findCell returns the index in r.cell for the cell corresponding to // (r.xi, r.yi). The cell is created if necessary. func (r *Rasterizer) findCell() int { if r.yi < 0 || r.yi >= len(r.cellIndex) { return -1 } xi := r.xi if xi < 0 { xi = -1 } else if xi > r.width { xi = r.width } i, prev := r.cellIndex[r.yi], -1 for i != -1 && r.cell[i].xi <= xi { if r.cell[i].xi == xi { return i } i, prev = r.cell[i].next, i } c := len(r.cell) if c == cap(r.cell) { buf := make([]cell, c, 4*c) copy(buf, r.cell) r.cell = buf[0 : c+1] } else { r.cell = r.cell[0 : c+1] } r.cell[c] = cell{xi, 0, 0, i} if prev == -1 { r.cellIndex[r.yi] = c } else { r.cell[prev].next = c } return c } // saveCell saves any accumulated r.area/r.cover for (r.xi, r.yi). func (r *Rasterizer) saveCell() { if r.area != 0 || r.cover != 0 { i := r.findCell() if i != -1 { r.cell[i].area += r.area r.cell[i].cover += r.cover } r.area = 0 r.cover = 0 } } // setCell sets the (xi, yi) cell that r is accumulating area/coverage for. func (r *Rasterizer) setCell(xi, yi int) { if r.xi != xi || r.yi != yi { r.saveCell() r.xi, r.yi = xi, yi } } // scan accumulates area/coverage for the yi'th scanline, going from // x0 to x1 in the horizontal direction (in 26.6 fixed point co-ordinates) // and from y0f to y1f fractional vertical units within that scanline. func (r *Rasterizer) scan(yi int, x0, y0f, x1, y1f fixed.Int26_6) { // Break the 26.6 fixed point X co-ordinates into integral and fractional parts. x0i := int(x0) / 64 x0f := x0 - fixed.Int26_6(64*x0i) x1i := int(x1) / 64 x1f := x1 - fixed.Int26_6(64*x1i) // A perfectly horizontal scan. if y0f == y1f { r.setCell(x1i, yi) return } dx, dy := x1-x0, y1f-y0f // A single cell scan. if x0i == x1i { r.area += int((x0f + x1f) * dy) r.cover += int(dy) return } // There are at least two cells. Apart from the first and last cells, // all intermediate cells go through the full width of the cell, // or 64 units in 26.6 fixed point format. var ( p, q, edge0, edge1 fixed.Int26_6 xiDelta int ) if dx > 0 { p, q = (64-x0f)*dy, dx edge0, edge1, xiDelta = 0, 64, 1 } else { p, q = x0f*dy, -dx edge0, edge1, xiDelta = 64, 0, -1 } yDelta, yRem := p/q, p%q if yRem < 0 { yDelta -= 1 yRem += q } // Do the first cell. xi, y := x0i, y0f r.area += int((x0f + edge1) * yDelta) r.cover += int(yDelta) xi, y = xi+xiDelta, y+yDelta r.setCell(xi, yi) if xi != x1i { // Do all the intermediate cells. p = 64 * (y1f - y + yDelta) fullDelta, fullRem := p/q, p%q if fullRem < 0 { fullDelta -= 1 fullRem += q } yRem -= q for xi != x1i { yDelta = fullDelta yRem += fullRem if yRem >= 0 { yDelta += 1 yRem -= q } r.area += int(64 * yDelta) r.cover += int(yDelta) xi, y = xi+xiDelta, y+yDelta r.setCell(xi, yi) } } // Do the last cell. yDelta = y1f - y r.area += int((edge0 + x1f) * yDelta) r.cover += int(yDelta) } // Start starts a new curve at the given point. func (r *Rasterizer) Start(a fixed.Point26_6) { r.setCell(int(a.X/64), int(a.Y/64)) r.a = a } // Add1 adds a linear segment to the current curve. func (r *Rasterizer) Add1(b fixed.Point26_6) { x0, y0 := r.a.X, r.a.Y x1, y1 := b.X, b.Y dx, dy := x1-x0, y1-y0 // Break the 26.6 fixed point Y co-ordinates into integral and fractional // parts. y0i := int(y0) / 64 y0f := y0 - fixed.Int26_6(64*y0i) y1i := int(y1) / 64 y1f := y1 - fixed.Int26_6(64*y1i) if y0i == y1i { // There is only one scanline. r.scan(y0i, x0, y0f, x1, y1f) } else if dx == 0 { // This is a vertical line segment. We avoid calling r.scan and instead // manipulate r.area and r.cover directly. var ( edge0, edge1 fixed.Int26_6 yiDelta int ) if dy > 0 { edge0, edge1, yiDelta = 0, 64, 1 } else { edge0, edge1, yiDelta = 64, 0, -1 } x0i, yi := int(x0)/64, y0i x0fTimes2 := (int(x0) - (64 * x0i)) * 2 // Do the first pixel. dcover := int(edge1 - y0f) darea := int(x0fTimes2 * dcover) r.area += darea r.cover += dcover yi += yiDelta r.setCell(x0i, yi) // Do all the intermediate pixels. dcover = int(edge1 - edge0) darea = int(x0fTimes2 * dcover) for yi != y1i { r.area += darea r.cover += dcover yi += yiDelta r.setCell(x0i, yi) } // Do the last pixel. dcover = int(y1f - edge0) darea = int(x0fTimes2 * dcover) r.area += darea r.cover += dcover } else { // There are at least two scanlines. Apart from the first and last // scanlines, all intermediate scanlines go through the full height of // the row, or 64 units in 26.6 fixed point format. var ( p, q, edge0, edge1 fixed.Int26_6 yiDelta int ) if dy > 0 { p, q = (64-y0f)*dx, dy edge0, edge1, yiDelta = 0, 64, 1 } else { p, q = y0f*dx, -dy edge0, edge1, yiDelta = 64, 0, -1 } xDelta, xRem := p/q, p%q if xRem < 0 { xDelta -= 1 xRem += q } // Do the first scanline. x, yi := x0, y0i r.scan(yi, x, y0f, x+xDelta, edge1) x, yi = x+xDelta, yi+yiDelta r.setCell(int(x)/64, yi) if yi != y1i { // Do all the intermediate scanlines. p = 64 * dx fullDelta, fullRem := p/q, p%q if fullRem < 0 { fullDelta -= 1 fullRem += q } xRem -= q for yi != y1i { xDelta = fullDelta xRem += fullRem if xRem >= 0 { xDelta += 1 xRem -= q } r.scan(yi, x, edge0, x+xDelta, edge1) x, yi = x+xDelta, yi+yiDelta r.setCell(int(x)/64, yi) } } // Do the last scanline. r.scan(yi, x, edge0, x1, y1f) } // The next lineTo starts from b. r.a = b } // Add2 adds a quadratic segment to the current curve. func (r *Rasterizer) Add2(b, c fixed.Point26_6) { // Calculate nSplit (the number of recursive decompositions) based on how // 'curvy' it is. Specifically, how much the middle point b deviates from // (a+c)/2. dev := maxAbs(r.a.X-2*b.X+c.X, r.a.Y-2*b.Y+c.Y) / fixed.Int26_6(r.splitScale2) nsplit := 0 for dev > 0 { dev /= 4 nsplit++ } // dev is 32-bit, and nsplit++ every time we shift off 2 bits, so maxNsplit // is 16. const maxNsplit = 16 if nsplit > maxNsplit { panic("freetype/raster: Add2 nsplit too large: " + strconv.Itoa(nsplit)) } // Recursively decompose the curve nSplit levels deep. var ( pStack [2*maxNsplit + 3]fixed.Point26_6 sStack [maxNsplit + 1]int i int ) sStack[0] = nsplit pStack[0] = c pStack[1] = b pStack[2] = r.a for i >= 0 { s := sStack[i] p := pStack[2*i:] if s > 0 { // Split the quadratic curve p[:3] into an equivalent set of two // shorter curves: p[:3] and p[2:5]. The new p[4] is the old p[2], // and p[0] is unchanged. mx := p[1].X p[4].X = p[2].X p[3].X = (p[4].X + mx) / 2 p[1].X = (p[0].X + mx) / 2 p[2].X = (p[1].X + p[3].X) / 2 my := p[1].Y p[4].Y = p[2].Y p[3].Y = (p[4].Y + my) / 2 p[1].Y = (p[0].Y + my) / 2 p[2].Y = (p[1].Y + p[3].Y) / 2 // The two shorter curves have one less split to do. sStack[i] = s - 1 sStack[i+1] = s - 1 i++ } else { // Replace the level-0 quadratic with a two-linear-piece // approximation. midx := (p[0].X + 2*p[1].X + p[2].X) / 4 midy := (p[0].Y + 2*p[1].Y + p[2].Y) / 4 r.Add1(fixed.Point26_6{midx, midy}) r.Add1(p[0]) i-- } } } // Add3 adds a cubic segment to the current curve. func (r *Rasterizer) Add3(b, c, d fixed.Point26_6) { // Calculate nSplit (the number of recursive decompositions) based on how // 'curvy' it is. dev2 := maxAbs(r.a.X-3*(b.X+c.X)+d.X, r.a.Y-3*(b.Y+c.Y)+d.Y) / fixed.Int26_6(r.splitScale2) dev3 := maxAbs(r.a.X-2*b.X+d.X, r.a.Y-2*b.Y+d.Y) / fixed.Int26_6(r.splitScale3) nsplit := 0 for dev2 > 0 || dev3 > 0 { dev2 /= 8 dev3 /= 4 nsplit++ } // devN is 32-bit, and nsplit++ every time we shift off 2 bits, so // maxNsplit is 16. const maxNsplit = 16 if nsplit > maxNsplit { panic("freetype/raster: Add3 nsplit too large: " + strconv.Itoa(nsplit)) } // Recursively decompose the curve nSplit levels deep. var ( pStack [3*maxNsplit + 4]fixed.Point26_6 sStack [maxNsplit + 1]int i int ) sStack[0] = nsplit pStack[0] = d pStack[1] = c pStack[2] = b pStack[3] = r.a for i >= 0 { s := sStack[i] p := pStack[3*i:] if s > 0 { // Split the cubic curve p[:4] into an equivalent set of two // shorter curves: p[:4] and p[3:7]. The new p[6] is the old p[3], // and p[0] is unchanged. m01x := (p[0].X + p[1].X) / 2 m12x := (p[1].X + p[2].X) / 2 m23x := (p[2].X + p[3].X) / 2 p[6].X = p[3].X p[5].X = m23x p[1].X = m01x p[2].X = (m01x + m12x) / 2 p[4].X = (m12x + m23x) / 2 p[3].X = (p[2].X + p[4].X) / 2 m01y := (p[0].Y + p[1].Y) / 2 m12y := (p[1].Y + p[2].Y) / 2 m23y := (p[2].Y + p[3].Y) / 2 p[6].Y = p[3].Y p[5].Y = m23y p[1].Y = m01y p[2].Y = (m01y + m12y) / 2 p[4].Y = (m12y + m23y) / 2 p[3].Y = (p[2].Y + p[4].Y) / 2 // The two shorter curves have one less split to do. sStack[i] = s - 1 sStack[i+1] = s - 1 i++ } else { // Replace the level-0 cubic with a two-linear-piece approximation. midx := (p[0].X + 3*(p[1].X+p[2].X) + p[3].X) / 8 midy := (p[0].Y + 3*(p[1].Y+p[2].Y) + p[3].Y) / 8 r.Add1(fixed.Point26_6{midx, midy}) r.Add1(p[0]) i-- } } } // AddPath adds the given Path. func (r *Rasterizer) AddPath(p Path) { for i := 0; i < len(p); { switch p[i] { case 0: r.Start( fixed.Point26_6{p[i+1], p[i+2]}, ) i += 4 case 1: r.Add1( fixed.Point26_6{p[i+1], p[i+2]}, ) i += 4 case 2: r.Add2( fixed.Point26_6{p[i+1], p[i+2]}, fixed.Point26_6{p[i+3], p[i+4]}, ) i += 6 case 3: r.Add3( fixed.Point26_6{p[i+1], p[i+2]}, fixed.Point26_6{p[i+3], p[i+4]}, fixed.Point26_6{p[i+5], p[i+6]}, ) i += 8 default: panic("freetype/raster: bad path") } } } // AddStroke adds a stroked Path. func (r *Rasterizer) AddStroke(q Path, width fixed.Int26_6, cr Capper, jr Joiner) { Stroke(r, q, width, cr, jr) } // areaToAlpha converts an area value to a uint32 alpha value. A completely // filled pixel corresponds to an area of 64*64*2, and an alpha of 0xffff. The // conversion of area values greater than this depends on the winding rule: // even-odd or non-zero. func (r *Rasterizer) areaToAlpha(area int) uint32 { // The C Freetype implementation (version 2.3.12) does "alpha := area>>1" // without the +1. Round-to-nearest gives a more symmetric result than // round-down. The C implementation also returns 8-bit alpha, not 16-bit // alpha. a := (area + 1) >> 1 if a < 0 { a = -a } alpha := uint32(a) if r.UseNonZeroWinding { if alpha > 0x0fff { alpha = 0x0fff } } else { alpha &= 0x1fff if alpha > 0x1000 { alpha = 0x2000 - alpha } else if alpha == 0x1000 { alpha = 0x0fff } } // alpha is now in the range [0x0000, 0x0fff]. Convert that 12-bit alpha to // 16-bit alpha. return alpha<<4 | alpha>>8 } // Rasterize converts r's accumulated curves into Spans for p. The Spans passed // to p are non-overlapping, and sorted by Y and then X. They all have non-zero // width (and 0 <= X0 < X1 <= r.width) and non-zero A, except for the final // Span, which has Y, X0, X1 and A all equal to zero. func (r *Rasterizer) Rasterize(p Painter) { r.saveCell() s := 0 for yi := 0; yi < len(r.cellIndex); yi++ { xi, cover := 0, 0 for c := r.cellIndex[yi]; c != -1; c = r.cell[c].next { if cover != 0 && r.cell[c].xi > xi { alpha := r.areaToAlpha(cover * 64 * 2) if alpha != 0 { xi0, xi1 := xi, r.cell[c].xi if xi0 < 0 { xi0 = 0 } if xi1 >= r.width { xi1 = r.width } if xi0 < xi1 { r.spanBuf[s] = Span{yi + r.Dy, xi0 + r.Dx, xi1 + r.Dx, alpha} s++ } } } cover += r.cell[c].cover alpha := r.areaToAlpha(cover*64*2 - r.cell[c].area) xi = r.cell[c].xi + 1 if alpha != 0 { xi0, xi1 := r.cell[c].xi, xi if xi0 < 0 { xi0 = 0 } if xi1 >= r.width { xi1 = r.width } if xi0 < xi1 { r.spanBuf[s] = Span{yi + r.Dy, xi0 + r.Dx, xi1 + r.Dx, alpha} s++ } } if s > len(r.spanBuf)-2 { p.Paint(r.spanBuf[:s], false) s = 0 } } } p.Paint(r.spanBuf[:s], true) } // Clear cancels any previous calls to r.Start or r.AddXxx. func (r *Rasterizer) Clear() { r.a = fixed.Point26_6{} r.xi = 0 r.yi = 0 r.area = 0 r.cover = 0 r.cell = r.cell[:0] for i := 0; i < len(r.cellIndex); i++ { r.cellIndex[i] = -1 } } // SetBounds sets the maximum width and height of the rasterized image and // calls Clear. The width and height are in pixels, not fixed.Int26_6 units. func (r *Rasterizer) SetBounds(width, height int) { if width < 0 { width = 0 } if height < 0 { height = 0 } // Use the same ssN heuristic as the C Freetype (version 2.4.0) // implementation. ss2, ss3 := 32, 16 if width > 24 || height > 24 { ss2, ss3 = 2*ss2, 2*ss3 if width > 120 || height > 120 { ss2, ss3 = 2*ss2, 2*ss3 } } r.width = width r.splitScale2 = ss2 r.splitScale3 = ss3 r.cell = r.cellBuf[:0] if height > len(r.cellIndexBuf) { r.cellIndex = make([]int, height) } else { r.cellIndex = r.cellIndexBuf[:height] } r.Clear() } // NewRasterizer creates a new Rasterizer with the given bounds. func NewRasterizer(width, height int) *Rasterizer { r := new(Rasterizer) r.SetBounds(width, height) return r } ================================================ FILE: vendor/github.com/golang/freetype/raster/stroke.go ================================================ // Copyright 2010 The Freetype-Go Authors. All rights reserved. // Use of this source code is governed by your choice of either the // FreeType License or the GNU General Public License version 2 (or // any later version), both of which can be found in the LICENSE file. package raster import ( "golang.org/x/image/math/fixed" ) // Two points are considered practically equal if the square of the distance // between them is less than one quarter (i.e. 1024 / 4096). const epsilon = fixed.Int52_12(1024) // A Capper signifies how to begin or end a stroked path. type Capper interface { // Cap adds a cap to p given a pivot point and the normal vector of a // terminal segment. The normal's length is half of the stroke width. Cap(p Adder, halfWidth fixed.Int26_6, pivot, n1 fixed.Point26_6) } // The CapperFunc type adapts an ordinary function to be a Capper. type CapperFunc func(Adder, fixed.Int26_6, fixed.Point26_6, fixed.Point26_6) func (f CapperFunc) Cap(p Adder, halfWidth fixed.Int26_6, pivot, n1 fixed.Point26_6) { f(p, halfWidth, pivot, n1) } // A Joiner signifies how to join interior nodes of a stroked path. type Joiner interface { // Join adds a join to the two sides of a stroked path given a pivot // point and the normal vectors of the trailing and leading segments. // Both normals have length equal to half of the stroke width. Join(lhs, rhs Adder, halfWidth fixed.Int26_6, pivot, n0, n1 fixed.Point26_6) } // The JoinerFunc type adapts an ordinary function to be a Joiner. type JoinerFunc func(lhs, rhs Adder, halfWidth fixed.Int26_6, pivot, n0, n1 fixed.Point26_6) func (f JoinerFunc) Join(lhs, rhs Adder, halfWidth fixed.Int26_6, pivot, n0, n1 fixed.Point26_6) { f(lhs, rhs, halfWidth, pivot, n0, n1) } // RoundCapper adds round caps to a stroked path. var RoundCapper Capper = CapperFunc(roundCapper) func roundCapper(p Adder, halfWidth fixed.Int26_6, pivot, n1 fixed.Point26_6) { // The cubic Bézier approximation to a circle involves the magic number // (√2 - 1) * 4/3, which is approximately 35/64. const k = 35 e := pRot90CCW(n1) side := pivot.Add(e) start, end := pivot.Sub(n1), pivot.Add(n1) d, e := n1.Mul(k), e.Mul(k) p.Add3(start.Add(e), side.Sub(d), side) p.Add3(side.Add(d), end.Add(e), end) } // ButtCapper adds butt caps to a stroked path. var ButtCapper Capper = CapperFunc(buttCapper) func buttCapper(p Adder, halfWidth fixed.Int26_6, pivot, n1 fixed.Point26_6) { p.Add1(pivot.Add(n1)) } // SquareCapper adds square caps to a stroked path. var SquareCapper Capper = CapperFunc(squareCapper) func squareCapper(p Adder, halfWidth fixed.Int26_6, pivot, n1 fixed.Point26_6) { e := pRot90CCW(n1) side := pivot.Add(e) p.Add1(side.Sub(n1)) p.Add1(side.Add(n1)) p.Add1(pivot.Add(n1)) } // RoundJoiner adds round joins to a stroked path. var RoundJoiner Joiner = JoinerFunc(roundJoiner) func roundJoiner(lhs, rhs Adder, haflWidth fixed.Int26_6, pivot, n0, n1 fixed.Point26_6) { dot := pDot(pRot90CW(n0), n1) if dot >= 0 { addArc(lhs, pivot, n0, n1) rhs.Add1(pivot.Sub(n1)) } else { lhs.Add1(pivot.Add(n1)) addArc(rhs, pivot, pNeg(n0), pNeg(n1)) } } // BevelJoiner adds bevel joins to a stroked path. var BevelJoiner Joiner = JoinerFunc(bevelJoiner) func bevelJoiner(lhs, rhs Adder, haflWidth fixed.Int26_6, pivot, n0, n1 fixed.Point26_6) { lhs.Add1(pivot.Add(n1)) rhs.Add1(pivot.Sub(n1)) } // addArc adds a circular arc from pivot+n0 to pivot+n1 to p. The shorter of // the two possible arcs is taken, i.e. the one spanning <= 180 degrees. The // two vectors n0 and n1 must be of equal length. func addArc(p Adder, pivot, n0, n1 fixed.Point26_6) { // r2 is the square of the length of n0. r2 := pDot(n0, n0) if r2 < epsilon { // The arc radius is so small that we collapse to a straight line. p.Add1(pivot.Add(n1)) return } // We approximate the arc by 0, 1, 2 or 3 45-degree quadratic segments plus // a final quadratic segment from s to n1. Each 45-degree segment has // control points {1, 0}, {1, tan(π/8)} and {1/√2, 1/√2} suitably scaled, // rotated and translated. tan(π/8) is approximately 27/64. const tpo8 = 27 var s fixed.Point26_6 // We determine which octant the angle between n0 and n1 is in via three // dot products. m0, m1 and m2 are n0 rotated clockwise by 45, 90 and 135 // degrees. m0 := pRot45CW(n0) m1 := pRot90CW(n0) m2 := pRot90CW(m0) if pDot(m1, n1) >= 0 { if pDot(n0, n1) >= 0 { if pDot(m2, n1) <= 0 { // n1 is between 0 and 45 degrees clockwise of n0. s = n0 } else { // n1 is between 45 and 90 degrees clockwise of n0. p.Add2(pivot.Add(n0).Add(m1.Mul(tpo8)), pivot.Add(m0)) s = m0 } } else { pm1, n0t := pivot.Add(m1), n0.Mul(tpo8) p.Add2(pivot.Add(n0).Add(m1.Mul(tpo8)), pivot.Add(m0)) p.Add2(pm1.Add(n0t), pm1) if pDot(m0, n1) >= 0 { // n1 is between 90 and 135 degrees clockwise of n0. s = m1 } else { // n1 is between 135 and 180 degrees clockwise of n0. p.Add2(pm1.Sub(n0t), pivot.Add(m2)) s = m2 } } } else { if pDot(n0, n1) >= 0 { if pDot(m0, n1) >= 0 { // n1 is between 0 and 45 degrees counter-clockwise of n0. s = n0 } else { // n1 is between 45 and 90 degrees counter-clockwise of n0. p.Add2(pivot.Add(n0).Sub(m1.Mul(tpo8)), pivot.Sub(m2)) s = pNeg(m2) } } else { pm1, n0t := pivot.Sub(m1), n0.Mul(tpo8) p.Add2(pivot.Add(n0).Sub(m1.Mul(tpo8)), pivot.Sub(m2)) p.Add2(pm1.Add(n0t), pm1) if pDot(m2, n1) <= 0 { // n1 is between 90 and 135 degrees counter-clockwise of n0. s = pNeg(m1) } else { // n1 is between 135 and 180 degrees counter-clockwise of n0. p.Add2(pm1.Sub(n0t), pivot.Sub(m0)) s = pNeg(m0) } } } // The final quadratic segment has two endpoints s and n1 and the middle // control point is a multiple of s.Add(n1), i.e. it is on the angle // bisector of those two points. The multiple ranges between 128/256 and // 150/256 as the angle between s and n1 ranges between 0 and 45 degrees. // // When the angle is 0 degrees (i.e. s and n1 are coincident) then // s.Add(n1) is twice s and so the middle control point of the degenerate // quadratic segment should be half s.Add(n1), and half = 128/256. // // When the angle is 45 degrees then 150/256 is the ratio of the lengths of // the two vectors {1, tan(π/8)} and {1 + 1/√2, 1/√2}. // // d is the normalized dot product between s and n1. Since the angle ranges // between 0 and 45 degrees then d ranges between 256/256 and 181/256. d := 256 * pDot(s, n1) / r2 multiple := fixed.Int26_6(150-(150-128)*(d-181)/(256-181)) >> 2 p.Add2(pivot.Add(s.Add(n1).Mul(multiple)), pivot.Add(n1)) } // midpoint returns the midpoint of two Points. func midpoint(a, b fixed.Point26_6) fixed.Point26_6 { return fixed.Point26_6{(a.X + b.X) / 2, (a.Y + b.Y) / 2} } // angleGreaterThan45 returns whether the angle between two vectors is more // than 45 degrees. func angleGreaterThan45(v0, v1 fixed.Point26_6) bool { v := pRot45CCW(v0) return pDot(v, v1) < 0 || pDot(pRot90CW(v), v1) < 0 } // interpolate returns the point (1-t)*a + t*b. func interpolate(a, b fixed.Point26_6, t fixed.Int52_12) fixed.Point26_6 { s := 1<<12 - t x := s*fixed.Int52_12(a.X) + t*fixed.Int52_12(b.X) y := s*fixed.Int52_12(a.Y) + t*fixed.Int52_12(b.Y) return fixed.Point26_6{fixed.Int26_6(x >> 12), fixed.Int26_6(y >> 12)} } // curviest2 returns the value of t for which the quadratic parametric curve // (1-t)²*a + 2*t*(1-t).b + t²*c has maximum curvature. // // The curvature of the parametric curve f(t) = (x(t), y(t)) is // |x′y″-y′x″| / (x′²+y′²)^(3/2). // // Let d = b-a and e = c-2*b+a, so that f′(t) = 2*d+2*e*t and f″(t) = 2*e. // The curvature's numerator is (2*dx+2*ex*t)*(2*ey)-(2*dy+2*ey*t)*(2*ex), // which simplifies to 4*dx*ey-4*dy*ex, which is constant with respect to t. // // Thus, curvature is extreme where the denominator is extreme, i.e. where // (x′²+y′²) is extreme. The first order condition is that // 2*x′*x″+2*y′*y″ = 0, or (dx+ex*t)*ex + (dy+ey*t)*ey = 0. // Solving for t gives t = -(dx*ex+dy*ey) / (ex*ex+ey*ey). func curviest2(a, b, c fixed.Point26_6) fixed.Int52_12 { dx := int64(b.X - a.X) dy := int64(b.Y - a.Y) ex := int64(c.X - 2*b.X + a.X) ey := int64(c.Y - 2*b.Y + a.Y) if ex == 0 && ey == 0 { return 2048 } return fixed.Int52_12(-4096 * (dx*ex + dy*ey) / (ex*ex + ey*ey)) } // A stroker holds state for stroking a path. type stroker struct { // p is the destination that records the stroked path. p Adder // u is the half-width of the stroke. u fixed.Int26_6 // cr and jr specify how to end and connect path segments. cr Capper jr Joiner // r is the reverse path. Stroking a path involves constructing two // parallel paths 2*u apart. The first path is added immediately to p, // the second path is accumulated in r and eventually added in reverse. r Path // a is the most recent segment point. anorm is the segment normal of // length u at that point. a, anorm fixed.Point26_6 } // addNonCurvy2 adds a quadratic segment to the stroker, where the segment // defined by (k.a, b, c) achieves maximum curvature at either k.a or c. func (k *stroker) addNonCurvy2(b, c fixed.Point26_6) { // We repeatedly divide the segment at its middle until it is straight // enough to approximate the stroke by just translating the control points. // ds and ps are stacks of depths and points. t is the top of the stack. const maxDepth = 5 var ( ds [maxDepth + 1]int ps [2*maxDepth + 3]fixed.Point26_6 t int ) // Initially the ps stack has one quadratic segment of depth zero. ds[0] = 0 ps[2] = k.a ps[1] = b ps[0] = c anorm := k.anorm var cnorm fixed.Point26_6 for { depth := ds[t] a := ps[2*t+2] b := ps[2*t+1] c := ps[2*t+0] ab := b.Sub(a) bc := c.Sub(b) abIsSmall := pDot(ab, ab) < fixed.Int52_12(1<<12) bcIsSmall := pDot(bc, bc) < fixed.Int52_12(1<<12) if abIsSmall && bcIsSmall { // Approximate the segment by a circular arc. cnorm = pRot90CCW(pNorm(bc, k.u)) mac := midpoint(a, c) addArc(k.p, mac, anorm, cnorm) addArc(&k.r, mac, pNeg(anorm), pNeg(cnorm)) } else if depth < maxDepth && angleGreaterThan45(ab, bc) { // Divide the segment in two and push both halves on the stack. mab := midpoint(a, b) mbc := midpoint(b, c) t++ ds[t+0] = depth + 1 ds[t-1] = depth + 1 ps[2*t+2] = a ps[2*t+1] = mab ps[2*t+0] = midpoint(mab, mbc) ps[2*t-1] = mbc continue } else { // Translate the control points. bnorm := pRot90CCW(pNorm(c.Sub(a), k.u)) cnorm = pRot90CCW(pNorm(bc, k.u)) k.p.Add2(b.Add(bnorm), c.Add(cnorm)) k.r.Add2(b.Sub(bnorm), c.Sub(cnorm)) } if t == 0 { k.a, k.anorm = c, cnorm return } t-- anorm = cnorm } panic("unreachable") } // Add1 adds a linear segment to the stroker. func (k *stroker) Add1(b fixed.Point26_6) { bnorm := pRot90CCW(pNorm(b.Sub(k.a), k.u)) if len(k.r) == 0 { k.p.Start(k.a.Add(bnorm)) k.r.Start(k.a.Sub(bnorm)) } else { k.jr.Join(k.p, &k.r, k.u, k.a, k.anorm, bnorm) } k.p.Add1(b.Add(bnorm)) k.r.Add1(b.Sub(bnorm)) k.a, k.anorm = b, bnorm } // Add2 adds a quadratic segment to the stroker. func (k *stroker) Add2(b, c fixed.Point26_6) { ab := b.Sub(k.a) bc := c.Sub(b) abnorm := pRot90CCW(pNorm(ab, k.u)) if len(k.r) == 0 { k.p.Start(k.a.Add(abnorm)) k.r.Start(k.a.Sub(abnorm)) } else { k.jr.Join(k.p, &k.r, k.u, k.a, k.anorm, abnorm) } // Approximate nearly-degenerate quadratics by linear segments. abIsSmall := pDot(ab, ab) < epsilon bcIsSmall := pDot(bc, bc) < epsilon if abIsSmall || bcIsSmall { acnorm := pRot90CCW(pNorm(c.Sub(k.a), k.u)) k.p.Add1(c.Add(acnorm)) k.r.Add1(c.Sub(acnorm)) k.a, k.anorm = c, acnorm return } // The quadratic segment (k.a, b, c) has a point of maximum curvature. // If this occurs at an end point, we process the segment as a whole. t := curviest2(k.a, b, c) if t <= 0 || 4096 <= t { k.addNonCurvy2(b, c) return } // Otherwise, we perform a de Casteljau decomposition at the point of // maximum curvature and process the two straighter parts. mab := interpolate(k.a, b, t) mbc := interpolate(b, c, t) mabc := interpolate(mab, mbc, t) // If the vectors ab and bc are close to being in opposite directions, // then the decomposition can become unstable, so we approximate the // quadratic segment by two linear segments joined by an arc. bcnorm := pRot90CCW(pNorm(bc, k.u)) if pDot(abnorm, bcnorm) < -fixed.Int52_12(k.u)*fixed.Int52_12(k.u)*2047/2048 { pArc := pDot(abnorm, bc) < 0 k.p.Add1(mabc.Add(abnorm)) if pArc { z := pRot90CW(abnorm) addArc(k.p, mabc, abnorm, z) addArc(k.p, mabc, z, bcnorm) } k.p.Add1(mabc.Add(bcnorm)) k.p.Add1(c.Add(bcnorm)) k.r.Add1(mabc.Sub(abnorm)) if !pArc { z := pRot90CW(abnorm) addArc(&k.r, mabc, pNeg(abnorm), z) addArc(&k.r, mabc, z, pNeg(bcnorm)) } k.r.Add1(mabc.Sub(bcnorm)) k.r.Add1(c.Sub(bcnorm)) k.a, k.anorm = c, bcnorm return } // Process the decomposed parts. k.addNonCurvy2(mab, mabc) k.addNonCurvy2(mbc, c) } // Add3 adds a cubic segment to the stroker. func (k *stroker) Add3(b, c, d fixed.Point26_6) { panic("freetype/raster: stroke unimplemented for cubic segments") } // stroke adds the stroked Path q to p, where q consists of exactly one curve. func (k *stroker) stroke(q Path) { // Stroking is implemented by deriving two paths each k.u apart from q. // The left-hand-side path is added immediately to k.p; the right-hand-side // path is accumulated in k.r. Once we've finished adding the LHS to k.p, // we add the RHS in reverse order. k.r = make(Path, 0, len(q)) k.a = fixed.Point26_6{q[1], q[2]} for i := 4; i < len(q); { switch q[i] { case 1: k.Add1( fixed.Point26_6{q[i+1], q[i+2]}, ) i += 4 case 2: k.Add2( fixed.Point26_6{q[i+1], q[i+2]}, fixed.Point26_6{q[i+3], q[i+4]}, ) i += 6 case 3: k.Add3( fixed.Point26_6{q[i+1], q[i+2]}, fixed.Point26_6{q[i+3], q[i+4]}, fixed.Point26_6{q[i+5], q[i+6]}, ) i += 8 default: panic("freetype/raster: bad path") } } if len(k.r) == 0 { return } // TODO(nigeltao): if q is a closed curve then we should join the first and // last segments instead of capping them. k.cr.Cap(k.p, k.u, q.lastPoint(), pNeg(k.anorm)) addPathReversed(k.p, k.r) pivot := q.firstPoint() k.cr.Cap(k.p, k.u, pivot, pivot.Sub(fixed.Point26_6{k.r[1], k.r[2]})) } // Stroke adds q stroked with the given width to p. The result is typically // self-intersecting and should be rasterized with UseNonZeroWinding. // cr and jr may be nil, which defaults to a RoundCapper or RoundJoiner. func Stroke(p Adder, q Path, width fixed.Int26_6, cr Capper, jr Joiner) { if len(q) == 0 { return } if cr == nil { cr = RoundCapper } if jr == nil { jr = RoundJoiner } if q[0] != 0 { panic("freetype/raster: bad path") } s := stroker{p: p, u: width / 2, cr: cr, jr: jr} i := 0 for j := 4; j < len(q); { switch q[j] { case 0: s.stroke(q[i:j]) i, j = j, j+4 case 1: j += 4 case 2: j += 6 case 3: j += 8 default: panic("freetype/raster: bad path") } } s.stroke(q[i:]) } ================================================ FILE: vendor/github.com/golang/freetype/truetype/face.go ================================================ // Copyright 2015 The Freetype-Go Authors. All rights reserved. // Use of this source code is governed by your choice of either the // FreeType License or the GNU General Public License version 2 (or // any later version), both of which can be found in the LICENSE file. package truetype import ( "image" "math" "github.com/golang/freetype/raster" "golang.org/x/image/font" "golang.org/x/image/math/fixed" ) func powerOf2(i int) bool { return i != 0 && (i&(i-1)) == 0 } // Options are optional arguments to NewFace. type Options struct { // Size is the font size in points, as in "a 10 point font size". // // A zero value means to use a 12 point font size. Size float64 // DPI is the dots-per-inch resolution. // // A zero value means to use 72 DPI. DPI float64 // Hinting is how to quantize the glyph nodes. // // A zero value means to use no hinting. Hinting font.Hinting // GlyphCacheEntries is the number of entries in the glyph mask image // cache. // // If non-zero, it must be a power of 2. // // A zero value means to use 512 entries. GlyphCacheEntries int // SubPixelsX is the number of sub-pixel locations a glyph's dot is // quantized to, in the horizontal direction. For example, a value of 8 // means that the dot is quantized to 1/8th of a pixel. This quantization // only affects the glyph mask image, not its bounding box or advance // width. A higher value gives a more faithful glyph image, but reduces the // effectiveness of the glyph cache. // // If non-zero, it must be a power of 2, and be between 1 and 64 inclusive. // // A zero value means to use 4 sub-pixel locations. SubPixelsX int // SubPixelsY is the number of sub-pixel locations a glyph's dot is // quantized to, in the vertical direction. For example, a value of 8 // means that the dot is quantized to 1/8th of a pixel. This quantization // only affects the glyph mask image, not its bounding box or advance // width. A higher value gives a more faithful glyph image, but reduces the // effectiveness of the glyph cache. // // If non-zero, it must be a power of 2, and be between 1 and 64 inclusive. // // A zero value means to use 1 sub-pixel location. SubPixelsY int } func (o *Options) size() float64 { if o != nil && o.Size > 0 { return o.Size } return 12 } func (o *Options) dpi() float64 { if o != nil && o.DPI > 0 { return o.DPI } return 72 } func (o *Options) hinting() font.Hinting { if o != nil { switch o.Hinting { case font.HintingVertical, font.HintingFull: // TODO: support vertical hinting. return font.HintingFull } } return font.HintingNone } func (o *Options) glyphCacheEntries() int { if o != nil && powerOf2(o.GlyphCacheEntries) { return o.GlyphCacheEntries } // 512 is 128 * 4 * 1, which lets us cache 128 glyphs at 4 * 1 subpixel // locations in the X and Y direction. return 512 } func (o *Options) subPixelsX() (value uint32, halfQuantum, mask fixed.Int26_6) { if o != nil { switch o.SubPixelsX { case 1, 2, 4, 8, 16, 32, 64: return subPixels(o.SubPixelsX) } } // This default value of 4 isn't based on anything scientific, merely as // small a number as possible that looks almost as good as no quantization, // or returning subPixels(64). return subPixels(4) } func (o *Options) subPixelsY() (value uint32, halfQuantum, mask fixed.Int26_6) { if o != nil { switch o.SubPixelsX { case 1, 2, 4, 8, 16, 32, 64: return subPixels(o.SubPixelsX) } } // This default value of 1 isn't based on anything scientific, merely that // vertical sub-pixel glyph rendering is pretty rare. Baseline locations // can usually afford to snap to the pixel grid, so the vertical direction // doesn't have the deal with the horizontal's fractional advance widths. return subPixels(1) } // subPixels returns q and the bias and mask that leads to q quantized // sub-pixel locations per full pixel. // // For example, q == 4 leads to a bias of 8 and a mask of 0xfffffff0, or -16, // because we want to round fractions of fixed.Int26_6 as: // - 0 to 7 rounds to 0. // - 8 to 23 rounds to 16. // - 24 to 39 rounds to 32. // - 40 to 55 rounds to 48. // - 56 to 63 rounds to 64. // which means to add 8 and then bitwise-and with -16, in two's complement // representation. // // When q == 1, we want bias == 32 and mask == -64. // When q == 2, we want bias == 16 and mask == -32. // When q == 4, we want bias == 8 and mask == -16. // ... // When q == 64, we want bias == 0 and mask == -1. (The no-op case). // The pattern is clear. func subPixels(q int) (value uint32, bias, mask fixed.Int26_6) { return uint32(q), 32 / fixed.Int26_6(q), -64 / fixed.Int26_6(q) } // glyphCacheEntry caches the arguments and return values of rasterize. type glyphCacheEntry struct { key glyphCacheKey val glyphCacheVal } type glyphCacheKey struct { index Index fx, fy uint8 } type glyphCacheVal struct { advanceWidth fixed.Int26_6 offset image.Point gw int gh int } type indexCacheEntry struct { rune rune index Index } // NewFace returns a new font.Face for the given Font. func NewFace(f *Font, opts *Options) font.Face { a := &face{ f: f, hinting: opts.hinting(), scale: fixed.Int26_6(0.5 + (opts.size() * opts.dpi() * 64 / 72)), glyphCache: make([]glyphCacheEntry, opts.glyphCacheEntries()), } a.subPixelX, a.subPixelBiasX, a.subPixelMaskX = opts.subPixelsX() a.subPixelY, a.subPixelBiasY, a.subPixelMaskY = opts.subPixelsY() // Fill the cache with invalid entries. Valid glyph cache entries have fx // and fy in the range [0, 64). Valid index cache entries have rune >= 0. for i := range a.glyphCache { a.glyphCache[i].key.fy = 0xff } for i := range a.indexCache { a.indexCache[i].rune = -1 } // Set the rasterizer's bounds to be big enough to handle the largest glyph. b := f.Bounds(a.scale) xmin := +int(b.Min.X) >> 6 ymin := -int(b.Max.Y) >> 6 xmax := +int(b.Max.X+63) >> 6 ymax := -int(b.Min.Y-63) >> 6 a.maxw = xmax - xmin a.maxh = ymax - ymin a.masks = image.NewAlpha(image.Rect(0, 0, a.maxw, a.maxh*len(a.glyphCache))) a.r.SetBounds(a.maxw, a.maxh) a.p = facePainter{a} return a } type face struct { f *Font hinting font.Hinting scale fixed.Int26_6 subPixelX uint32 subPixelBiasX fixed.Int26_6 subPixelMaskX fixed.Int26_6 subPixelY uint32 subPixelBiasY fixed.Int26_6 subPixelMaskY fixed.Int26_6 masks *image.Alpha glyphCache []glyphCacheEntry r raster.Rasterizer p raster.Painter paintOffset int maxw int maxh int glyphBuf GlyphBuf indexCache [indexCacheLen]indexCacheEntry // TODO: clip rectangle? } const indexCacheLen = 256 func (a *face) index(r rune) Index { const mask = indexCacheLen - 1 c := &a.indexCache[r&mask] if c.rune == r { return c.index } i := a.f.Index(r) c.rune = r c.index = i return i } // Close satisfies the font.Face interface. func (a *face) Close() error { return nil } // Metrics satisfies the font.Face interface. func (a *face) Metrics() font.Metrics { scale := float64(a.scale) fupe := float64(a.f.FUnitsPerEm()) return font.Metrics{ Height: a.scale, Ascent: fixed.Int26_6(math.Ceil(scale * float64(+a.f.ascent) / fupe)), Descent: fixed.Int26_6(math.Ceil(scale * float64(-a.f.descent) / fupe)), } } // Kern satisfies the font.Face interface. func (a *face) Kern(r0, r1 rune) fixed.Int26_6 { i0 := a.index(r0) i1 := a.index(r1) kern := a.f.Kern(a.scale, i0, i1) if a.hinting != font.HintingNone { kern = (kern + 32) &^ 63 } return kern } // Glyph satisfies the font.Face interface. func (a *face) Glyph(dot fixed.Point26_6, r rune) ( dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) { // Quantize to the sub-pixel granularity. dotX := (dot.X + a.subPixelBiasX) & a.subPixelMaskX dotY := (dot.Y + a.subPixelBiasY) & a.subPixelMaskY // Split the coordinates into their integer and fractional parts. ix, fx := int(dotX>>6), dotX&0x3f iy, fy := int(dotY>>6), dotY&0x3f index := a.index(r) cIndex := uint32(index) cIndex = cIndex*a.subPixelX - uint32(fx/a.subPixelMaskX) cIndex = cIndex*a.subPixelY - uint32(fy/a.subPixelMaskY) cIndex &= uint32(len(a.glyphCache) - 1) a.paintOffset = a.maxh * int(cIndex) k := glyphCacheKey{ index: index, fx: uint8(fx), fy: uint8(fy), } var v glyphCacheVal if a.glyphCache[cIndex].key != k { var ok bool v, ok = a.rasterize(index, fx, fy) if !ok { return image.Rectangle{}, nil, image.Point{}, 0, false } a.glyphCache[cIndex] = glyphCacheEntry{k, v} } else { v = a.glyphCache[cIndex].val } dr.Min = image.Point{ X: ix + v.offset.X, Y: iy + v.offset.Y, } dr.Max = image.Point{ X: dr.Min.X + v.gw, Y: dr.Min.Y + v.gh, } return dr, a.masks, image.Point{Y: a.paintOffset}, v.advanceWidth, true } func (a *face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) { if err := a.glyphBuf.Load(a.f, a.scale, a.index(r), a.hinting); err != nil { return fixed.Rectangle26_6{}, 0, false } xmin := +a.glyphBuf.Bounds.Min.X ymin := -a.glyphBuf.Bounds.Max.Y xmax := +a.glyphBuf.Bounds.Max.X ymax := -a.glyphBuf.Bounds.Min.Y if xmin > xmax || ymin > ymax { return fixed.Rectangle26_6{}, 0, false } return fixed.Rectangle26_6{ Min: fixed.Point26_6{ X: xmin, Y: ymin, }, Max: fixed.Point26_6{ X: xmax, Y: ymax, }, }, a.glyphBuf.AdvanceWidth, true } func (a *face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) { if err := a.glyphBuf.Load(a.f, a.scale, a.index(r), a.hinting); err != nil { return 0, false } return a.glyphBuf.AdvanceWidth, true } // rasterize returns the advance width, integer-pixel offset to render at, and // the width and height of the given glyph at the given sub-pixel offsets. // // The 26.6 fixed point arguments fx and fy must be in the range [0, 1). func (a *face) rasterize(index Index, fx, fy fixed.Int26_6) (v glyphCacheVal, ok bool) { if err := a.glyphBuf.Load(a.f, a.scale, index, a.hinting); err != nil { return glyphCacheVal{}, false } // Calculate the integer-pixel bounds for the glyph. xmin := int(fx+a.glyphBuf.Bounds.Min.X) >> 6 ymin := int(fy-a.glyphBuf.Bounds.Max.Y) >> 6 xmax := int(fx+a.glyphBuf.Bounds.Max.X+0x3f) >> 6 ymax := int(fy-a.glyphBuf.Bounds.Min.Y+0x3f) >> 6 if xmin > xmax || ymin > ymax { return glyphCacheVal{}, false } // A TrueType's glyph's nodes can have negative co-ordinates, but the // rasterizer clips anything left of x=0 or above y=0. xmin and ymin are // the pixel offsets, based on the font's FUnit metrics, that let a // negative co-ordinate in TrueType space be non-negative in rasterizer // space. xmin and ymin are typically <= 0. fx -= fixed.Int26_6(xmin << 6) fy -= fixed.Int26_6(ymin << 6) // Rasterize the glyph's vectors. a.r.Clear() pixOffset := a.paintOffset * a.maxw clear(a.masks.Pix[pixOffset : pixOffset+a.maxw*a.maxh]) e0 := 0 for _, e1 := range a.glyphBuf.Ends { a.drawContour(a.glyphBuf.Points[e0:e1], fx, fy) e0 = e1 } a.r.Rasterize(a.p) return glyphCacheVal{ a.glyphBuf.AdvanceWidth, image.Point{xmin, ymin}, xmax - xmin, ymax - ymin, }, true } func clear(pix []byte) { for i := range pix { pix[i] = 0 } } // drawContour draws the given closed contour with the given offset. func (a *face) drawContour(ps []Point, dx, dy fixed.Int26_6) { if len(ps) == 0 { return } // The low bit of each point's Flags value is whether the point is on the // curve. Truetype fonts only have quadratic Bézier curves, not cubics. // Thus, two consecutive off-curve points imply an on-curve point in the // middle of those two. // // See http://chanae.walon.org/pub/ttf/ttf_glyphs.htm for more details. // ps[0] is a truetype.Point measured in FUnits and positive Y going // upwards. start is the same thing measured in fixed point units and // positive Y going downwards, and offset by (dx, dy). start := fixed.Point26_6{ X: dx + ps[0].X, Y: dy - ps[0].Y, } var others []Point if ps[0].Flags&0x01 != 0 { others = ps[1:] } else { last := fixed.Point26_6{ X: dx + ps[len(ps)-1].X, Y: dy - ps[len(ps)-1].Y, } if ps[len(ps)-1].Flags&0x01 != 0 { start = last others = ps[:len(ps)-1] } else { start = fixed.Point26_6{ X: (start.X + last.X) / 2, Y: (start.Y + last.Y) / 2, } others = ps } } a.r.Start(start) q0, on0 := start, true for _, p := range others { q := fixed.Point26_6{ X: dx + p.X, Y: dy - p.Y, } on := p.Flags&0x01 != 0 if on { if on0 { a.r.Add1(q) } else { a.r.Add2(q0, q) } } else { if on0 { // No-op. } else { mid := fixed.Point26_6{ X: (q0.X + q.X) / 2, Y: (q0.Y + q.Y) / 2, } a.r.Add2(q0, mid) } } q0, on0 = q, on } // Close the curve. if on0 { a.r.Add1(start) } else { a.r.Add2(q0, start) } } // facePainter is like a raster.AlphaSrcPainter, with an additional Y offset // (face.paintOffset) to the painted spans. type facePainter struct { a *face } func (p facePainter) Paint(ss []raster.Span, done bool) { m := p.a.masks b := m.Bounds() b.Min.Y = p.a.paintOffset b.Max.Y = p.a.paintOffset + p.a.maxh for _, s := range ss { s.Y += p.a.paintOffset if s.Y < b.Min.Y { continue } if s.Y >= b.Max.Y { return } if s.X0 < b.Min.X { s.X0 = b.Min.X } if s.X1 > b.Max.X { s.X1 = b.Max.X } if s.X0 >= s.X1 { continue } base := (s.Y-m.Rect.Min.Y)*m.Stride - m.Rect.Min.X p := m.Pix[base+s.X0 : base+s.X1] color := uint8(s.Alpha >> 8) for i := range p { p[i] = color } } } ================================================ FILE: vendor/github.com/golang/freetype/truetype/glyph.go ================================================ // Copyright 2010 The Freetype-Go Authors. All rights reserved. // Use of this source code is governed by your choice of either the // FreeType License or the GNU General Public License version 2 (or // any later version), both of which can be found in the LICENSE file. package truetype import ( "golang.org/x/image/font" "golang.org/x/image/math/fixed" ) // TODO: implement VerticalHinting. // A Point is a co-ordinate pair plus whether it is 'on' a contour or an 'off' // control point. type Point struct { X, Y fixed.Int26_6 // The Flags' LSB means whether or not this Point is 'on' the contour. // Other bits are reserved for internal use. Flags uint32 } // A GlyphBuf holds a glyph's contours. A GlyphBuf can be re-used to load a // series of glyphs from a Font. type GlyphBuf struct { // AdvanceWidth is the glyph's advance width. AdvanceWidth fixed.Int26_6 // Bounds is the glyph's bounding box. Bounds fixed.Rectangle26_6 // Points contains all Points from all contours of the glyph. If hinting // was used to load a glyph then Unhinted contains those Points before they // were hinted, and InFontUnits contains those Points before they were // hinted and scaled. Points, Unhinted, InFontUnits []Point // Ends is the point indexes of the end point of each contour. The length // of Ends is the number of contours in the glyph. The i'th contour // consists of points Points[Ends[i-1]:Ends[i]], where Ends[-1] is // interpreted to mean zero. Ends []int font *Font scale fixed.Int26_6 hinting font.Hinting hinter hinter // phantomPoints are the co-ordinates of the synthetic phantom points // used for hinting and bounding box calculations. phantomPoints [4]Point // pp1x is the X co-ordinate of the first phantom point. The '1' is // using 1-based indexing; pp1x is almost always phantomPoints[0].X. // TODO: eliminate this and consistently use phantomPoints[0].X. pp1x fixed.Int26_6 // metricsSet is whether the glyph's metrics have been set yet. For a // compound glyph, a sub-glyph may override the outer glyph's metrics. metricsSet bool // tmp is a scratch buffer. tmp []Point } // Flags for decoding a glyph's contours. These flags are documented at // http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html. const ( flagOnCurve = 1 << iota flagXShortVector flagYShortVector flagRepeat flagPositiveXShortVector flagPositiveYShortVector // The remaining flags are for internal use. flagTouchedX flagTouchedY ) // The same flag bits (0x10 and 0x20) are overloaded to have two meanings, // dependent on the value of the flag{X,Y}ShortVector bits. const ( flagThisXIsSame = flagPositiveXShortVector flagThisYIsSame = flagPositiveYShortVector ) // Load loads a glyph's contours from a Font, overwriting any previously loaded // contours for this GlyphBuf. scale is the number of 26.6 fixed point units in // 1 em, i is the glyph index, and h is the hinting policy. func (g *GlyphBuf) Load(f *Font, scale fixed.Int26_6, i Index, h font.Hinting) error { g.Points = g.Points[:0] g.Unhinted = g.Unhinted[:0] g.InFontUnits = g.InFontUnits[:0] g.Ends = g.Ends[:0] g.font = f g.hinting = h g.scale = scale g.pp1x = 0 g.phantomPoints = [4]Point{} g.metricsSet = false if h != font.HintingNone { if err := g.hinter.init(f, scale); err != nil { return err } } if err := g.load(0, i, true); err != nil { return err } // TODO: this selection of either g.pp1x or g.phantomPoints[0].X isn't ideal, // and should be cleaned up once we have all the testScaling tests passing, // plus additional tests for Freetype-Go's bounding boxes matching C Freetype's. pp1x := g.pp1x if h != font.HintingNone { pp1x = g.phantomPoints[0].X } if pp1x != 0 { for i := range g.Points { g.Points[i].X -= pp1x } } advanceWidth := g.phantomPoints[1].X - g.phantomPoints[0].X if h != font.HintingNone { if len(f.hdmx) >= 8 { if n := u32(f.hdmx, 4); n > 3+uint32(i) { for hdmx := f.hdmx[8:]; uint32(len(hdmx)) >= n; hdmx = hdmx[n:] { if fixed.Int26_6(hdmx[0]) == scale>>6 { advanceWidth = fixed.Int26_6(hdmx[2+i]) << 6 break } } } } advanceWidth = (advanceWidth + 32) &^ 63 } g.AdvanceWidth = advanceWidth // Set g.Bounds to the 'control box', which is the bounding box of the // Bézier curves' control points. This is easier to calculate, no smaller // than and often equal to the tightest possible bounding box of the curves // themselves. This approach is what C Freetype does. We can't just scale // the nominal bounding box in the glyf data as the hinting process and // phantom point adjustment may move points outside of that box. if len(g.Points) == 0 { g.Bounds = fixed.Rectangle26_6{} } else { p := g.Points[0] g.Bounds.Min.X = p.X g.Bounds.Max.X = p.X g.Bounds.Min.Y = p.Y g.Bounds.Max.Y = p.Y for _, p := range g.Points[1:] { if g.Bounds.Min.X > p.X { g.Bounds.Min.X = p.X } else if g.Bounds.Max.X < p.X { g.Bounds.Max.X = p.X } if g.Bounds.Min.Y > p.Y { g.Bounds.Min.Y = p.Y } else if g.Bounds.Max.Y < p.Y { g.Bounds.Max.Y = p.Y } } // Snap the box to the grid, if hinting is on. if h != font.HintingNone { g.Bounds.Min.X &^= 63 g.Bounds.Min.Y &^= 63 g.Bounds.Max.X += 63 g.Bounds.Max.X &^= 63 g.Bounds.Max.Y += 63 g.Bounds.Max.Y &^= 63 } } return nil } func (g *GlyphBuf) load(recursion uint32, i Index, useMyMetrics bool) (err error) { // The recursion limit here is arbitrary, but defends against malformed glyphs. if recursion >= 32 { return UnsupportedError("excessive compound glyph recursion") } // Find the relevant slice of g.font.glyf. var g0, g1 uint32 if g.font.locaOffsetFormat == locaOffsetFormatShort { g0 = 2 * uint32(u16(g.font.loca, 2*int(i))) g1 = 2 * uint32(u16(g.font.loca, 2*int(i)+2)) } else { g0 = u32(g.font.loca, 4*int(i)) g1 = u32(g.font.loca, 4*int(i)+4) } // Decode the contour count and nominal bounding box, from the first // 10 bytes of the glyf data. boundsYMin and boundsXMax, at offsets 4 // and 6, are unused. glyf, ne, boundsXMin, boundsYMax := []byte(nil), 0, fixed.Int26_6(0), fixed.Int26_6(0) if g0+10 <= g1 { glyf = g.font.glyf[g0:g1] ne = int(int16(u16(glyf, 0))) boundsXMin = fixed.Int26_6(int16(u16(glyf, 2))) boundsYMax = fixed.Int26_6(int16(u16(glyf, 8))) } // Create the phantom points. uhm, pp1x := g.font.unscaledHMetric(i), fixed.Int26_6(0) uvm := g.font.unscaledVMetric(i, boundsYMax) g.phantomPoints = [4]Point{ {X: boundsXMin - uhm.LeftSideBearing}, {X: boundsXMin - uhm.LeftSideBearing + uhm.AdvanceWidth}, {X: uhm.AdvanceWidth / 2, Y: boundsYMax + uvm.TopSideBearing}, {X: uhm.AdvanceWidth / 2, Y: boundsYMax + uvm.TopSideBearing - uvm.AdvanceHeight}, } if len(glyf) == 0 { g.addPhantomsAndScale(len(g.Points), len(g.Points), true, true) copy(g.phantomPoints[:], g.Points[len(g.Points)-4:]) g.Points = g.Points[:len(g.Points)-4] // TODO: also trim g.InFontUnits and g.Unhinted? return nil } // Load and hint the contours. if ne < 0 { if ne != -1 { // http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html says that // "the values -2, -3, and so forth, are reserved for future use." return UnsupportedError("negative number of contours") } pp1x = g.font.scale(g.scale * (boundsXMin - uhm.LeftSideBearing)) if err := g.loadCompound(recursion, uhm, i, glyf, useMyMetrics); err != nil { return err } } else { np0, ne0 := len(g.Points), len(g.Ends) program := g.loadSimple(glyf, ne) g.addPhantomsAndScale(np0, np0, true, true) pp1x = g.Points[len(g.Points)-4].X if g.hinting != font.HintingNone { if len(program) != 0 { err := g.hinter.run( program, g.Points[np0:], g.Unhinted[np0:], g.InFontUnits[np0:], g.Ends[ne0:], ) if err != nil { return err } } // Drop the four phantom points. g.InFontUnits = g.InFontUnits[:len(g.InFontUnits)-4] g.Unhinted = g.Unhinted[:len(g.Unhinted)-4] } if useMyMetrics { copy(g.phantomPoints[:], g.Points[len(g.Points)-4:]) } g.Points = g.Points[:len(g.Points)-4] if np0 != 0 { // The hinting program expects the []Ends values to be indexed // relative to the inner glyph, not the outer glyph, so we delay // adding np0 until after the hinting program (if any) has run. for i := ne0; i < len(g.Ends); i++ { g.Ends[i] += np0 } } } if useMyMetrics && !g.metricsSet { g.metricsSet = true g.pp1x = pp1x } return nil } // loadOffset is the initial offset for loadSimple and loadCompound. The first // 10 bytes are the number of contours and the bounding box. const loadOffset = 10 func (g *GlyphBuf) loadSimple(glyf []byte, ne int) (program []byte) { offset := loadOffset for i := 0; i < ne; i++ { g.Ends = append(g.Ends, 1+int(u16(glyf, offset))) offset += 2 } // Note the TrueType hinting instructions. instrLen := int(u16(glyf, offset)) offset += 2 program = glyf[offset : offset+instrLen] offset += instrLen if ne == 0 { return program } np0 := len(g.Points) np1 := np0 + int(g.Ends[len(g.Ends)-1]) // Decode the flags. for i := np0; i < np1; { c := uint32(glyf[offset]) offset++ g.Points = append(g.Points, Point{Flags: c}) i++ if c&flagRepeat != 0 { count := glyf[offset] offset++ for ; count > 0; count-- { g.Points = append(g.Points, Point{Flags: c}) i++ } } } // Decode the co-ordinates. var x int16 for i := np0; i < np1; i++ { f := g.Points[i].Flags if f&flagXShortVector != 0 { dx := int16(glyf[offset]) offset++ if f&flagPositiveXShortVector == 0 { x -= dx } else { x += dx } } else if f&flagThisXIsSame == 0 { x += int16(u16(glyf, offset)) offset += 2 } g.Points[i].X = fixed.Int26_6(x) } var y int16 for i := np0; i < np1; i++ { f := g.Points[i].Flags if f&flagYShortVector != 0 { dy := int16(glyf[offset]) offset++ if f&flagPositiveYShortVector == 0 { y -= dy } else { y += dy } } else if f&flagThisYIsSame == 0 { y += int16(u16(glyf, offset)) offset += 2 } g.Points[i].Y = fixed.Int26_6(y) } return program } func (g *GlyphBuf) loadCompound(recursion uint32, uhm HMetric, i Index, glyf []byte, useMyMetrics bool) error { // Flags for decoding a compound glyph. These flags are documented at // http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html. const ( flagArg1And2AreWords = 1 << iota flagArgsAreXYValues flagRoundXYToGrid flagWeHaveAScale flagUnused flagMoreComponents flagWeHaveAnXAndYScale flagWeHaveATwoByTwo flagWeHaveInstructions flagUseMyMetrics flagOverlapCompound ) np0, ne0 := len(g.Points), len(g.Ends) offset := loadOffset for { flags := u16(glyf, offset) component := Index(u16(glyf, offset+2)) dx, dy, transform, hasTransform := fixed.Int26_6(0), fixed.Int26_6(0), [4]int16{}, false if flags&flagArg1And2AreWords != 0 { dx = fixed.Int26_6(int16(u16(glyf, offset+4))) dy = fixed.Int26_6(int16(u16(glyf, offset+6))) offset += 8 } else { dx = fixed.Int26_6(int16(int8(glyf[offset+4]))) dy = fixed.Int26_6(int16(int8(glyf[offset+5]))) offset += 6 } if flags&flagArgsAreXYValues == 0 { return UnsupportedError("compound glyph transform vector") } if flags&(flagWeHaveAScale|flagWeHaveAnXAndYScale|flagWeHaveATwoByTwo) != 0 { hasTransform = true switch { case flags&flagWeHaveAScale != 0: transform[0] = int16(u16(glyf, offset+0)) transform[3] = transform[0] offset += 2 case flags&flagWeHaveAnXAndYScale != 0: transform[0] = int16(u16(glyf, offset+0)) transform[3] = int16(u16(glyf, offset+2)) offset += 4 case flags&flagWeHaveATwoByTwo != 0: transform[0] = int16(u16(glyf, offset+0)) transform[1] = int16(u16(glyf, offset+2)) transform[2] = int16(u16(glyf, offset+4)) transform[3] = int16(u16(glyf, offset+6)) offset += 8 } } savedPP := g.phantomPoints np0 := len(g.Points) componentUMM := useMyMetrics && (flags&flagUseMyMetrics != 0) if err := g.load(recursion+1, component, componentUMM); err != nil { return err } if flags&flagUseMyMetrics == 0 { g.phantomPoints = savedPP } if hasTransform { for j := np0; j < len(g.Points); j++ { p := &g.Points[j] newX := 0 + fixed.Int26_6((int64(p.X)*int64(transform[0])+1<<13)>>14) + fixed.Int26_6((int64(p.Y)*int64(transform[2])+1<<13)>>14) newY := 0 + fixed.Int26_6((int64(p.X)*int64(transform[1])+1<<13)>>14) + fixed.Int26_6((int64(p.Y)*int64(transform[3])+1<<13)>>14) p.X, p.Y = newX, newY } } dx = g.font.scale(g.scale * dx) dy = g.font.scale(g.scale * dy) if flags&flagRoundXYToGrid != 0 { dx = (dx + 32) &^ 63 dy = (dy + 32) &^ 63 } for j := np0; j < len(g.Points); j++ { p := &g.Points[j] p.X += dx p.Y += dy } // TODO: also adjust g.InFontUnits and g.Unhinted? if flags&flagMoreComponents == 0 { break } } instrLen := 0 if g.hinting != font.HintingNone && offset+2 <= len(glyf) { instrLen = int(u16(glyf, offset)) offset += 2 } g.addPhantomsAndScale(np0, len(g.Points), false, instrLen > 0) points, ends := g.Points[np0:], g.Ends[ne0:] g.Points = g.Points[:len(g.Points)-4] for j := range points { points[j].Flags &^= flagTouchedX | flagTouchedY } if instrLen == 0 { if !g.metricsSet { copy(g.phantomPoints[:], points[len(points)-4:]) } return nil } // Hint the compound glyph. program := glyf[offset : offset+instrLen] // Temporarily adjust the ends to be relative to this compound glyph. if np0 != 0 { for i := range ends { ends[i] -= np0 } } // Hinting instructions of a composite glyph completely refer to the // (already) hinted subglyphs. g.tmp = append(g.tmp[:0], points...) if err := g.hinter.run(program, points, g.tmp, g.tmp, ends); err != nil { return err } if np0 != 0 { for i := range ends { ends[i] += np0 } } if !g.metricsSet { copy(g.phantomPoints[:], points[len(points)-4:]) } return nil } func (g *GlyphBuf) addPhantomsAndScale(np0, np1 int, simple, adjust bool) { // Add the four phantom points. g.Points = append(g.Points, g.phantomPoints[:]...) // Scale the points. if simple && g.hinting != font.HintingNone { g.InFontUnits = append(g.InFontUnits, g.Points[np1:]...) } for i := np1; i < len(g.Points); i++ { p := &g.Points[i] p.X = g.font.scale(g.scale * p.X) p.Y = g.font.scale(g.scale * p.Y) } if g.hinting == font.HintingNone { return } // Round the 1st phantom point to the grid, shifting all other points equally. // Note that "all other points" starts from np0, not np1. // TODO: delete this adjustment and the np0/np1 distinction, when // we update the compatibility tests to C Freetype 2.5.3. // See http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=05c786d990390a7ca18e62962641dac740bacb06 if adjust { pp1x := g.Points[len(g.Points)-4].X if dx := ((pp1x + 32) &^ 63) - pp1x; dx != 0 { for i := np0; i < len(g.Points); i++ { g.Points[i].X += dx } } } if simple { g.Unhinted = append(g.Unhinted, g.Points[np1:]...) } // Round the 2nd and 4th phantom point to the grid. p := &g.Points[len(g.Points)-3] p.X = (p.X + 32) &^ 63 p = &g.Points[len(g.Points)-1] p.Y = (p.Y + 32) &^ 63 } ================================================ FILE: vendor/github.com/golang/freetype/truetype/hint.go ================================================ // Copyright 2012 The Freetype-Go Authors. All rights reserved. // Use of this source code is governed by your choice of either the // FreeType License or the GNU General Public License version 2 (or // any later version), both of which can be found in the LICENSE file. package truetype // This file implements a Truetype bytecode interpreter. // The opcodes are described at https://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html import ( "errors" "math" "golang.org/x/image/math/fixed" ) const ( twilightZone = 0 glyphZone = 1 numZone = 2 ) type pointType uint32 const ( current pointType = 0 unhinted pointType = 1 inFontUnits pointType = 2 numPointType = 3 ) // callStackEntry is a bytecode call stack entry. type callStackEntry struct { program []byte pc int loopCount int32 } // hinter implements bytecode hinting. A hinter can be re-used to hint a series // of glyphs from a Font. type hinter struct { stack, store []int32 // functions is a map from function number to bytecode. functions map[int32][]byte // font and scale are the font and scale last used for this hinter. // Changing the font will require running the new font's fpgm bytecode. // Changing either will require running the font's prep bytecode. font *Font scale fixed.Int26_6 // gs and defaultGS are the current and default graphics state. The // default graphics state is the global default graphics state after // the font's fpgm and prep programs have been run. gs, defaultGS graphicsState // points and ends are the twilight zone's points, glyph's points // and glyph's contour boundaries. points [numZone][numPointType][]Point ends []int // scaledCVT is the lazily initialized scaled Control Value Table. scaledCVTInitialized bool scaledCVT []fixed.Int26_6 } // graphicsState is described at https://developer.apple.com/fonts/TTRefMan/RM04/Chap4.html type graphicsState struct { // Projection vector, freedom vector and dual projection vector. pv, fv, dv [2]f2dot14 // Reference points and zone pointers. rp, zp [3]int32 // Control Value / Single Width Cut-In. controlValueCutIn, singleWidthCutIn, singleWidth fixed.Int26_6 // Delta base / shift. deltaBase, deltaShift int32 // Minimum distance. minDist fixed.Int26_6 // Loop count. loop int32 // Rounding policy. roundPeriod, roundPhase, roundThreshold fixed.Int26_6 roundSuper45 bool // Auto-flip. autoFlip bool } var globalDefaultGS = graphicsState{ pv: [2]f2dot14{0x4000, 0}, // Unit vector along the X axis. fv: [2]f2dot14{0x4000, 0}, dv: [2]f2dot14{0x4000, 0}, zp: [3]int32{1, 1, 1}, controlValueCutIn: (17 << 6) / 16, // 17/16 as a fixed.Int26_6. deltaBase: 9, deltaShift: 3, minDist: 1 << 6, // 1 as a fixed.Int26_6. loop: 1, roundPeriod: 1 << 6, // 1 as a fixed.Int26_6. roundThreshold: 1 << 5, // 1/2 as a fixed.Int26_6. roundSuper45: false, autoFlip: true, } func resetTwilightPoints(f *Font, p []Point) []Point { if n := int(f.maxTwilightPoints) + 4; n <= cap(p) { p = p[:n] for i := range p { p[i] = Point{} } } else { p = make([]Point, n) } return p } func (h *hinter) init(f *Font, scale fixed.Int26_6) error { h.points[twilightZone][0] = resetTwilightPoints(f, h.points[twilightZone][0]) h.points[twilightZone][1] = resetTwilightPoints(f, h.points[twilightZone][1]) h.points[twilightZone][2] = resetTwilightPoints(f, h.points[twilightZone][2]) rescale := h.scale != scale if h.font != f { h.font, rescale = f, true if h.functions == nil { h.functions = make(map[int32][]byte) } else { for k := range h.functions { delete(h.functions, k) } } if x := int(f.maxStackElements); x > len(h.stack) { x += 255 x &^= 255 h.stack = make([]int32, x) } if x := int(f.maxStorage); x > len(h.store) { x += 15 x &^= 15 h.store = make([]int32, x) } if len(f.fpgm) != 0 { if err := h.run(f.fpgm, nil, nil, nil, nil); err != nil { return err } } } if rescale { h.scale = scale h.scaledCVTInitialized = false h.defaultGS = globalDefaultGS if len(f.prep) != 0 { if err := h.run(f.prep, nil, nil, nil, nil); err != nil { return err } h.defaultGS = h.gs // The MS rasterizer doesn't allow the following graphics state // variables to be modified by the CVT program. h.defaultGS.pv = globalDefaultGS.pv h.defaultGS.fv = globalDefaultGS.fv h.defaultGS.dv = globalDefaultGS.dv h.defaultGS.rp = globalDefaultGS.rp h.defaultGS.zp = globalDefaultGS.zp h.defaultGS.loop = globalDefaultGS.loop } } return nil } func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, ends []int) error { h.gs = h.defaultGS h.points[glyphZone][current] = pCurrent h.points[glyphZone][unhinted] = pUnhinted h.points[glyphZone][inFontUnits] = pInFontUnits h.ends = ends if len(program) > 50000 { return errors.New("truetype: hinting: too many instructions") } var ( steps, pc, top int opcode uint8 callStack [32]callStackEntry callStackTop int ) for 0 <= pc && pc < len(program) { steps++ if steps == 100000 { return errors.New("truetype: hinting: too many steps") } opcode = program[pc] if top < int(popCount[opcode]) { return errors.New("truetype: hinting: stack underflow") } switch opcode { case opSVTCA0: h.gs.pv = [2]f2dot14{0, 0x4000} h.gs.fv = [2]f2dot14{0, 0x4000} h.gs.dv = [2]f2dot14{0, 0x4000} case opSVTCA1: h.gs.pv = [2]f2dot14{0x4000, 0} h.gs.fv = [2]f2dot14{0x4000, 0} h.gs.dv = [2]f2dot14{0x4000, 0} case opSPVTCA0: h.gs.pv = [2]f2dot14{0, 0x4000} h.gs.dv = [2]f2dot14{0, 0x4000} case opSPVTCA1: h.gs.pv = [2]f2dot14{0x4000, 0} h.gs.dv = [2]f2dot14{0x4000, 0} case opSFVTCA0: h.gs.fv = [2]f2dot14{0, 0x4000} case opSFVTCA1: h.gs.fv = [2]f2dot14{0x4000, 0} case opSPVTL0, opSPVTL1, opSFVTL0, opSFVTL1: top -= 2 p1 := h.point(0, current, h.stack[top+0]) p2 := h.point(0, current, h.stack[top+1]) if p1 == nil || p2 == nil { return errors.New("truetype: hinting: point out of range") } dx := f2dot14(p1.X - p2.X) dy := f2dot14(p1.Y - p2.Y) if dx == 0 && dy == 0 { dx = 0x4000 } else if opcode&1 != 0 { // Counter-clockwise rotation. dx, dy = -dy, dx } v := normalize(dx, dy) if opcode < opSFVTL0 { h.gs.pv = v h.gs.dv = v } else { h.gs.fv = v } case opSPVFS: top -= 2 h.gs.pv = normalize(f2dot14(h.stack[top]), f2dot14(h.stack[top+1])) h.gs.dv = h.gs.pv case opSFVFS: top -= 2 h.gs.fv = normalize(f2dot14(h.stack[top]), f2dot14(h.stack[top+1])) case opGPV: if top+1 >= len(h.stack) { return errors.New("truetype: hinting: stack overflow") } h.stack[top+0] = int32(h.gs.pv[0]) h.stack[top+1] = int32(h.gs.pv[1]) top += 2 case opGFV: if top+1 >= len(h.stack) { return errors.New("truetype: hinting: stack overflow") } h.stack[top+0] = int32(h.gs.fv[0]) h.stack[top+1] = int32(h.gs.fv[1]) top += 2 case opSFVTPV: h.gs.fv = h.gs.pv case opISECT: top -= 5 p := h.point(2, current, h.stack[top+0]) a0 := h.point(1, current, h.stack[top+1]) a1 := h.point(1, current, h.stack[top+2]) b0 := h.point(0, current, h.stack[top+3]) b1 := h.point(0, current, h.stack[top+4]) if p == nil || a0 == nil || a1 == nil || b0 == nil || b1 == nil { return errors.New("truetype: hinting: point out of range") } dbx := b1.X - b0.X dby := b1.Y - b0.Y dax := a1.X - a0.X day := a1.Y - a0.Y dx := b0.X - a0.X dy := b0.Y - a0.Y discriminant := mulDiv(int64(dax), int64(-dby), 0x40) + mulDiv(int64(day), int64(dbx), 0x40) dotProduct := mulDiv(int64(dax), int64(dbx), 0x40) + mulDiv(int64(day), int64(dby), 0x40) // The discriminant above is actually a cross product of vectors // da and db. Together with the dot product, they can be used as // surrogates for sine and cosine of the angle between the vectors. // Indeed, // dotproduct = |da||db|cos(angle) // discriminant = |da||db|sin(angle) // We use these equations to reject grazing intersections by // thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. absDisc, absDotP := discriminant, dotProduct if absDisc < 0 { absDisc = -absDisc } if absDotP < 0 { absDotP = -absDotP } if 19*absDisc > absDotP { val := mulDiv(int64(dx), int64(-dby), 0x40) + mulDiv(int64(dy), int64(dbx), 0x40) rx := mulDiv(val, int64(dax), discriminant) ry := mulDiv(val, int64(day), discriminant) p.X = a0.X + fixed.Int26_6(rx) p.Y = a0.Y + fixed.Int26_6(ry) } else { p.X = (a0.X + a1.X + b0.X + b1.X) / 4 p.Y = (a0.Y + a1.Y + b0.Y + b1.Y) / 4 } p.Flags |= flagTouchedX | flagTouchedY case opSRP0, opSRP1, opSRP2: top-- h.gs.rp[opcode-opSRP0] = h.stack[top] case opSZP0, opSZP1, opSZP2: top-- h.gs.zp[opcode-opSZP0] = h.stack[top] case opSZPS: top-- h.gs.zp[0] = h.stack[top] h.gs.zp[1] = h.stack[top] h.gs.zp[2] = h.stack[top] case opSLOOP: top-- // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM05/Chap5.html#SLOOP // says that "Setting the loop variable to zero is an error". In // theory, the inequality on the next line should be "<=" instead // of "<". In practice, some font files' bytecode, such as the '2' // glyph in the DejaVuSansMono.ttf that comes with Ubuntu 14.04, // issue SLOOP with a zero on top of the stack. Just like the C // Freetype code, we allow the zero. if h.stack[top] < 0 { return errors.New("truetype: hinting: invalid data") } h.gs.loop = h.stack[top] case opRTG: h.gs.roundPeriod = 1 << 6 h.gs.roundPhase = 0 h.gs.roundThreshold = 1 << 5 h.gs.roundSuper45 = false case opRTHG: h.gs.roundPeriod = 1 << 6 h.gs.roundPhase = 1 << 5 h.gs.roundThreshold = 1 << 5 h.gs.roundSuper45 = false case opSMD: top-- h.gs.minDist = fixed.Int26_6(h.stack[top]) case opELSE: opcode = 1 goto ifelse case opJMPR: top-- pc += int(h.stack[top]) continue case opSCVTCI: top-- h.gs.controlValueCutIn = fixed.Int26_6(h.stack[top]) case opSSWCI: top-- h.gs.singleWidthCutIn = fixed.Int26_6(h.stack[top]) case opSSW: top-- h.gs.singleWidth = h.font.scale(h.scale * fixed.Int26_6(h.stack[top])) case opDUP: if top >= len(h.stack) { return errors.New("truetype: hinting: stack overflow") } h.stack[top] = h.stack[top-1] top++ case opPOP: top-- case opCLEAR: top = 0 case opSWAP: h.stack[top-1], h.stack[top-2] = h.stack[top-2], h.stack[top-1] case opDEPTH: if top >= len(h.stack) { return errors.New("truetype: hinting: stack overflow") } h.stack[top] = int32(top) top++ case opCINDEX, opMINDEX: x := int(h.stack[top-1]) if x <= 0 || x >= top { return errors.New("truetype: hinting: invalid data") } h.stack[top-1] = h.stack[top-1-x] if opcode == opMINDEX { copy(h.stack[top-1-x:top-1], h.stack[top-x:top]) top-- } case opALIGNPTS: top -= 2 p := h.point(1, current, h.stack[top]) q := h.point(0, current, h.stack[top+1]) if p == nil || q == nil { return errors.New("truetype: hinting: point out of range") } d := dotProduct(fixed.Int26_6(q.X-p.X), fixed.Int26_6(q.Y-p.Y), h.gs.pv) / 2 h.move(p, +d, true) h.move(q, -d, true) case opUTP: top-- p := h.point(0, current, h.stack[top]) if p == nil { return errors.New("truetype: hinting: point out of range") } p.Flags &^= flagTouchedX | flagTouchedY case opLOOPCALL, opCALL: if callStackTop >= len(callStack) { return errors.New("truetype: hinting: call stack overflow") } top-- f, ok := h.functions[h.stack[top]] if !ok { return errors.New("truetype: hinting: undefined function") } callStack[callStackTop] = callStackEntry{program, pc, 1} if opcode == opLOOPCALL { top-- if h.stack[top] == 0 { break } callStack[callStackTop].loopCount = h.stack[top] } callStackTop++ program, pc = f, 0 continue case opFDEF: // Save all bytecode up until the next ENDF. startPC := pc + 1 fdefloop: for { pc++ if pc >= len(program) { return errors.New("truetype: hinting: unbalanced FDEF") } switch program[pc] { case opFDEF: return errors.New("truetype: hinting: nested FDEF") case opENDF: top-- h.functions[h.stack[top]] = program[startPC : pc+1] break fdefloop default: var ok bool pc, ok = skipInstructionPayload(program, pc) if !ok { return errors.New("truetype: hinting: unbalanced FDEF") } } } case opENDF: if callStackTop == 0 { return errors.New("truetype: hinting: call stack underflow") } callStackTop-- callStack[callStackTop].loopCount-- if callStack[callStackTop].loopCount != 0 { callStackTop++ pc = 0 continue } program, pc = callStack[callStackTop].program, callStack[callStackTop].pc case opMDAP0, opMDAP1: top-- i := h.stack[top] p := h.point(0, current, i) if p == nil { return errors.New("truetype: hinting: point out of range") } distance := fixed.Int26_6(0) if opcode == opMDAP1 { distance = dotProduct(p.X, p.Y, h.gs.pv) // TODO: metrics compensation. distance = h.round(distance) - distance } h.move(p, distance, true) h.gs.rp[0] = i h.gs.rp[1] = i case opIUP0, opIUP1: iupY, mask := opcode == opIUP0, uint32(flagTouchedX) if iupY { mask = flagTouchedY } prevEnd := 0 for _, end := range h.ends { for i := prevEnd; i < end; i++ { for i < end && h.points[glyphZone][current][i].Flags&mask == 0 { i++ } if i == end { break } firstTouched, curTouched := i, i i++ for ; i < end; i++ { if h.points[glyphZone][current][i].Flags&mask != 0 { h.iupInterp(iupY, curTouched+1, i-1, curTouched, i) curTouched = i } } if curTouched == firstTouched { h.iupShift(iupY, prevEnd, end, curTouched) } else { h.iupInterp(iupY, curTouched+1, end-1, curTouched, firstTouched) if firstTouched > 0 { h.iupInterp(iupY, prevEnd, firstTouched-1, curTouched, firstTouched) } } } prevEnd = end } case opSHP0, opSHP1: if top < int(h.gs.loop) { return errors.New("truetype: hinting: stack underflow") } _, _, d, ok := h.displacement(opcode&1 == 0) if !ok { return errors.New("truetype: hinting: point out of range") } for ; h.gs.loop != 0; h.gs.loop-- { top-- p := h.point(2, current, h.stack[top]) if p == nil { return errors.New("truetype: hinting: point out of range") } h.move(p, d, true) } h.gs.loop = 1 case opSHC0, opSHC1: top-- zonePointer, i, d, ok := h.displacement(opcode&1 == 0) if !ok { return errors.New("truetype: hinting: point out of range") } if h.gs.zp[2] == 0 { // TODO: implement this when we have a glyph that does this. return errors.New("hinting: unimplemented SHC instruction") } contour := h.stack[top] if contour < 0 || len(ends) <= int(contour) { return errors.New("truetype: hinting: contour out of range") } j0, j1 := int32(0), int32(h.ends[contour]) if contour > 0 { j0 = int32(h.ends[contour-1]) } move := h.gs.zp[zonePointer] != h.gs.zp[2] for j := j0; j < j1; j++ { if move || j != i { h.move(h.point(2, current, j), d, true) } } case opSHZ0, opSHZ1: top-- zonePointer, i, d, ok := h.displacement(opcode&1 == 0) if !ok { return errors.New("truetype: hinting: point out of range") } // As per C Freetype, SHZ doesn't move the phantom points, or mark // the points as touched. limit := int32(len(h.points[h.gs.zp[2]][current])) if h.gs.zp[2] == glyphZone { limit -= 4 } for j := int32(0); j < limit; j++ { if i != j || h.gs.zp[zonePointer] != h.gs.zp[2] { h.move(h.point(2, current, j), d, false) } } case opSHPIX: top-- d := fixed.Int26_6(h.stack[top]) if top < int(h.gs.loop) { return errors.New("truetype: hinting: stack underflow") } for ; h.gs.loop != 0; h.gs.loop-- { top-- p := h.point(2, current, h.stack[top]) if p == nil { return errors.New("truetype: hinting: point out of range") } h.move(p, d, true) } h.gs.loop = 1 case opIP: if top < int(h.gs.loop) { return errors.New("truetype: hinting: stack underflow") } pointType := inFontUnits twilight := h.gs.zp[0] == 0 || h.gs.zp[1] == 0 || h.gs.zp[2] == 0 if twilight { pointType = unhinted } p := h.point(1, pointType, h.gs.rp[2]) oldP := h.point(0, pointType, h.gs.rp[1]) oldRange := dotProduct(p.X-oldP.X, p.Y-oldP.Y, h.gs.dv) p = h.point(1, current, h.gs.rp[2]) curP := h.point(0, current, h.gs.rp[1]) curRange := dotProduct(p.X-curP.X, p.Y-curP.Y, h.gs.pv) for ; h.gs.loop != 0; h.gs.loop-- { top-- i := h.stack[top] p = h.point(2, pointType, i) oldDist := dotProduct(p.X-oldP.X, p.Y-oldP.Y, h.gs.dv) p = h.point(2, current, i) curDist := dotProduct(p.X-curP.X, p.Y-curP.Y, h.gs.pv) newDist := fixed.Int26_6(0) if oldDist != 0 { if oldRange != 0 { newDist = fixed.Int26_6(mulDiv(int64(oldDist), int64(curRange), int64(oldRange))) } else { newDist = -oldDist } } h.move(p, newDist-curDist, true) } h.gs.loop = 1 case opMSIRP0, opMSIRP1: top -= 2 i := h.stack[top] distance := fixed.Int26_6(h.stack[top+1]) // TODO: special case h.gs.zp[1] == 0 in C Freetype. ref := h.point(0, current, h.gs.rp[0]) p := h.point(1, current, i) if ref == nil || p == nil { return errors.New("truetype: hinting: point out of range") } curDist := dotProduct(p.X-ref.X, p.Y-ref.Y, h.gs.pv) // Set-RP0 bit. if opcode == opMSIRP1 { h.gs.rp[0] = i } h.gs.rp[1] = h.gs.rp[0] h.gs.rp[2] = i // Move the point. h.move(p, distance-curDist, true) case opALIGNRP: if top < int(h.gs.loop) { return errors.New("truetype: hinting: stack underflow") } ref := h.point(0, current, h.gs.rp[0]) if ref == nil { return errors.New("truetype: hinting: point out of range") } for ; h.gs.loop != 0; h.gs.loop-- { top-- p := h.point(1, current, h.stack[top]) if p == nil { return errors.New("truetype: hinting: point out of range") } h.move(p, -dotProduct(p.X-ref.X, p.Y-ref.Y, h.gs.pv), true) } h.gs.loop = 1 case opRTDG: h.gs.roundPeriod = 1 << 5 h.gs.roundPhase = 0 h.gs.roundThreshold = 1 << 4 h.gs.roundSuper45 = false case opMIAP0, opMIAP1: top -= 2 i := h.stack[top] distance := h.getScaledCVT(h.stack[top+1]) if h.gs.zp[0] == 0 { p := h.point(0, unhinted, i) q := h.point(0, current, i) p.X = fixed.Int26_6((int64(distance) * int64(h.gs.fv[0])) >> 14) p.Y = fixed.Int26_6((int64(distance) * int64(h.gs.fv[1])) >> 14) *q = *p } p := h.point(0, current, i) oldDist := dotProduct(p.X, p.Y, h.gs.pv) if opcode == opMIAP1 { if fabs(distance-oldDist) > h.gs.controlValueCutIn { distance = oldDist } // TODO: metrics compensation. distance = h.round(distance) } h.move(p, distance-oldDist, true) h.gs.rp[0] = i h.gs.rp[1] = i case opNPUSHB: opcode = 0 goto push case opNPUSHW: opcode = 0x80 goto push case opWS: top -= 2 i := int(h.stack[top]) if i < 0 || len(h.store) <= i { return errors.New("truetype: hinting: invalid data") } h.store[i] = h.stack[top+1] case opRS: i := int(h.stack[top-1]) if i < 0 || len(h.store) <= i { return errors.New("truetype: hinting: invalid data") } h.stack[top-1] = h.store[i] case opWCVTP: top -= 2 h.setScaledCVT(h.stack[top], fixed.Int26_6(h.stack[top+1])) case opRCVT: h.stack[top-1] = int32(h.getScaledCVT(h.stack[top-1])) case opGC0, opGC1: i := h.stack[top-1] if opcode == opGC0 { p := h.point(2, current, i) h.stack[top-1] = int32(dotProduct(p.X, p.Y, h.gs.pv)) } else { p := h.point(2, unhinted, i) // Using dv as per C Freetype. h.stack[top-1] = int32(dotProduct(p.X, p.Y, h.gs.dv)) } case opSCFS: top -= 2 i := h.stack[top] p := h.point(2, current, i) if p == nil { return errors.New("truetype: hinting: point out of range") } c := dotProduct(p.X, p.Y, h.gs.pv) h.move(p, fixed.Int26_6(h.stack[top+1])-c, true) if h.gs.zp[2] != 0 { break } q := h.point(2, unhinted, i) if q == nil { return errors.New("truetype: hinting: point out of range") } q.X = p.X q.Y = p.Y case opMD0, opMD1: top-- pt, v, scale := pointType(0), [2]f2dot14{}, false if opcode == opMD0 { pt = current v = h.gs.pv } else if h.gs.zp[0] == 0 || h.gs.zp[1] == 0 { pt = unhinted v = h.gs.dv } else { pt = inFontUnits v = h.gs.dv scale = true } p := h.point(0, pt, h.stack[top-1]) q := h.point(1, pt, h.stack[top]) if p == nil || q == nil { return errors.New("truetype: hinting: point out of range") } d := int32(dotProduct(p.X-q.X, p.Y-q.Y, v)) if scale { d = int32(int64(d*int32(h.scale)) / int64(h.font.fUnitsPerEm)) } h.stack[top-1] = d case opMPPEM, opMPS: if top >= len(h.stack) { return errors.New("truetype: hinting: stack overflow") } // For MPS, point size should be irrelevant; we return the PPEM. h.stack[top] = int32(h.scale) >> 6 top++ case opFLIPON, opFLIPOFF: h.gs.autoFlip = opcode == opFLIPON case opDEBUG: // No-op. case opLT: top-- h.stack[top-1] = bool2int32(h.stack[top-1] < h.stack[top]) case opLTEQ: top-- h.stack[top-1] = bool2int32(h.stack[top-1] <= h.stack[top]) case opGT: top-- h.stack[top-1] = bool2int32(h.stack[top-1] > h.stack[top]) case opGTEQ: top-- h.stack[top-1] = bool2int32(h.stack[top-1] >= h.stack[top]) case opEQ: top-- h.stack[top-1] = bool2int32(h.stack[top-1] == h.stack[top]) case opNEQ: top-- h.stack[top-1] = bool2int32(h.stack[top-1] != h.stack[top]) case opODD, opEVEN: i := h.round(fixed.Int26_6(h.stack[top-1])) >> 6 h.stack[top-1] = int32(i&1) ^ int32(opcode-opODD) case opIF: top-- if h.stack[top] == 0 { opcode = 0 goto ifelse } case opEIF: // No-op. case opAND: top-- h.stack[top-1] = bool2int32(h.stack[top-1] != 0 && h.stack[top] != 0) case opOR: top-- h.stack[top-1] = bool2int32(h.stack[top-1]|h.stack[top] != 0) case opNOT: h.stack[top-1] = bool2int32(h.stack[top-1] == 0) case opDELTAP1: goto delta case opSDB: top-- h.gs.deltaBase = h.stack[top] case opSDS: top-- h.gs.deltaShift = h.stack[top] case opADD: top-- h.stack[top-1] += h.stack[top] case opSUB: top-- h.stack[top-1] -= h.stack[top] case opDIV: top-- if h.stack[top] == 0 { return errors.New("truetype: hinting: division by zero") } h.stack[top-1] = int32(fdiv(fixed.Int26_6(h.stack[top-1]), fixed.Int26_6(h.stack[top]))) case opMUL: top-- h.stack[top-1] = int32(fmul(fixed.Int26_6(h.stack[top-1]), fixed.Int26_6(h.stack[top]))) case opABS: if h.stack[top-1] < 0 { h.stack[top-1] = -h.stack[top-1] } case opNEG: h.stack[top-1] = -h.stack[top-1] case opFLOOR: h.stack[top-1] &^= 63 case opCEILING: h.stack[top-1] += 63 h.stack[top-1] &^= 63 case opROUND00, opROUND01, opROUND10, opROUND11: // The four flavors of opROUND are equivalent. See the comment below on // opNROUND for the rationale. h.stack[top-1] = int32(h.round(fixed.Int26_6(h.stack[top-1]))) case opNROUND00, opNROUND01, opNROUND10, opNROUND11: // No-op. The spec says to add one of four "compensations for the engine // characteristics", to cater for things like "different dot-size printers". // https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#engine_compensation // This code does not implement engine compensation, as we don't expect to // be used to output on dot-matrix printers. case opWCVTF: top -= 2 h.setScaledCVT(h.stack[top], h.font.scale(h.scale*fixed.Int26_6(h.stack[top+1]))) case opDELTAP2, opDELTAP3, opDELTAC1, opDELTAC2, opDELTAC3: goto delta case opSROUND, opS45ROUND: top-- switch (h.stack[top] >> 6) & 0x03 { case 0: h.gs.roundPeriod = 1 << 5 case 1, 3: h.gs.roundPeriod = 1 << 6 case 2: h.gs.roundPeriod = 1 << 7 } h.gs.roundSuper45 = opcode == opS45ROUND if h.gs.roundSuper45 { // The spec says to multiply by √2, but the C Freetype code says 1/√2. // We go with 1/√2. h.gs.roundPeriod *= 46341 h.gs.roundPeriod /= 65536 } h.gs.roundPhase = h.gs.roundPeriod * fixed.Int26_6((h.stack[top]>>4)&0x03) / 4 if x := h.stack[top] & 0x0f; x != 0 { h.gs.roundThreshold = h.gs.roundPeriod * fixed.Int26_6(x-4) / 8 } else { h.gs.roundThreshold = h.gs.roundPeriod - 1 } case opJROT: top -= 2 if h.stack[top+1] != 0 { pc += int(h.stack[top]) continue } case opJROF: top -= 2 if h.stack[top+1] == 0 { pc += int(h.stack[top]) continue } case opROFF: h.gs.roundPeriod = 0 h.gs.roundPhase = 0 h.gs.roundThreshold = 0 h.gs.roundSuper45 = false case opRUTG: h.gs.roundPeriod = 1 << 6 h.gs.roundPhase = 0 h.gs.roundThreshold = 1<<6 - 1 h.gs.roundSuper45 = false case opRDTG: h.gs.roundPeriod = 1 << 6 h.gs.roundPhase = 0 h.gs.roundThreshold = 0 h.gs.roundSuper45 = false case opSANGW, opAA: // These ops are "anachronistic" and no longer used. top-- case opFLIPPT: if top < int(h.gs.loop) { return errors.New("truetype: hinting: stack underflow") } points := h.points[glyphZone][current] for ; h.gs.loop != 0; h.gs.loop-- { top-- i := h.stack[top] if i < 0 || len(points) <= int(i) { return errors.New("truetype: hinting: point out of range") } points[i].Flags ^= flagOnCurve } h.gs.loop = 1 case opFLIPRGON, opFLIPRGOFF: top -= 2 i, j, points := h.stack[top], h.stack[top+1], h.points[glyphZone][current] if i < 0 || len(points) <= int(i) || j < 0 || len(points) <= int(j) { return errors.New("truetype: hinting: point out of range") } for ; i <= j; i++ { if opcode == opFLIPRGON { points[i].Flags |= flagOnCurve } else { points[i].Flags &^= flagOnCurve } } case opSCANCTRL: // We do not support dropout control, as we always rasterize grayscale glyphs. top-- case opSDPVTL0, opSDPVTL1: top -= 2 for i := 0; i < 2; i++ { pt := unhinted if i != 0 { pt = current } p := h.point(1, pt, h.stack[top]) q := h.point(2, pt, h.stack[top+1]) if p == nil || q == nil { return errors.New("truetype: hinting: point out of range") } dx := f2dot14(p.X - q.X) dy := f2dot14(p.Y - q.Y) if dx == 0 && dy == 0 { dx = 0x4000 } else if opcode&1 != 0 { // Counter-clockwise rotation. dx, dy = -dy, dx } if i == 0 { h.gs.dv = normalize(dx, dy) } else { h.gs.pv = normalize(dx, dy) } } case opGETINFO: res := int32(0) if h.stack[top-1]&(1<<0) != 0 { // Set the engine version. We hard-code this to 35, the same as // the C freetype code, which says that "Version~35 corresponds // to MS rasterizer v.1.7 as used e.g. in Windows~98". res |= 35 } if h.stack[top-1]&(1<<5) != 0 { // Set that we support grayscale. res |= 1 << 12 } // We set no other bits, as we do not support rotated or stretched glyphs. h.stack[top-1] = res case opIDEF: // IDEF is for ancient versions of the bytecode interpreter, and is no longer used. return errors.New("truetype: hinting: unsupported IDEF instruction") case opROLL: h.stack[top-1], h.stack[top-3], h.stack[top-2] = h.stack[top-3], h.stack[top-2], h.stack[top-1] case opMAX: top-- if h.stack[top-1] < h.stack[top] { h.stack[top-1] = h.stack[top] } case opMIN: top-- if h.stack[top-1] > h.stack[top] { h.stack[top-1] = h.stack[top] } case opSCANTYPE: // We do not support dropout control, as we always rasterize grayscale glyphs. top-- case opINSTCTRL: // TODO: support instruction execution control? It seems rare, and even when // nominally used (e.g. Source Sans Pro), it seems conditional on extreme or // unusual rasterization conditions. For example, the code snippet at // https://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html#INSTCTRL // uses INSTCTRL when grid-fitting a rotated or stretched glyph, but // freetype-go does not support rotated or stretched glyphs. top -= 2 default: if opcode < opPUSHB000 { return errors.New("truetype: hinting: unrecognized instruction") } if opcode < opMDRP00000 { // PUSHxxxx opcode. if opcode < opPUSHW000 { opcode -= opPUSHB000 - 1 } else { opcode -= opPUSHW000 - 1 - 0x80 } goto push } if opcode < opMIRP00000 { // MDRPxxxxx opcode. top-- i := h.stack[top] ref := h.point(0, current, h.gs.rp[0]) p := h.point(1, current, i) if ref == nil || p == nil { return errors.New("truetype: hinting: point out of range") } oldDist := fixed.Int26_6(0) if h.gs.zp[0] == 0 || h.gs.zp[1] == 0 { p0 := h.point(1, unhinted, i) p1 := h.point(0, unhinted, h.gs.rp[0]) oldDist = dotProduct(p0.X-p1.X, p0.Y-p1.Y, h.gs.dv) } else { p0 := h.point(1, inFontUnits, i) p1 := h.point(0, inFontUnits, h.gs.rp[0]) oldDist = dotProduct(p0.X-p1.X, p0.Y-p1.Y, h.gs.dv) oldDist = h.font.scale(h.scale * oldDist) } // Single-width cut-in test. if x := fabs(oldDist - h.gs.singleWidth); x < h.gs.singleWidthCutIn { if oldDist >= 0 { oldDist = +h.gs.singleWidth } else { oldDist = -h.gs.singleWidth } } // Rounding bit. // TODO: metrics compensation. distance := oldDist if opcode&0x04 != 0 { distance = h.round(oldDist) } // Minimum distance bit. if opcode&0x08 != 0 { if oldDist >= 0 { if distance < h.gs.minDist { distance = h.gs.minDist } } else { if distance > -h.gs.minDist { distance = -h.gs.minDist } } } // Set-RP0 bit. h.gs.rp[1] = h.gs.rp[0] h.gs.rp[2] = i if opcode&0x10 != 0 { h.gs.rp[0] = i } // Move the point. oldDist = dotProduct(p.X-ref.X, p.Y-ref.Y, h.gs.pv) h.move(p, distance-oldDist, true) } else { // MIRPxxxxx opcode. top -= 2 i := h.stack[top] cvtDist := h.getScaledCVT(h.stack[top+1]) if fabs(cvtDist-h.gs.singleWidth) < h.gs.singleWidthCutIn { if cvtDist >= 0 { cvtDist = +h.gs.singleWidth } else { cvtDist = -h.gs.singleWidth } } if h.gs.zp[1] == 0 { // TODO: implement once we have a .ttf file that triggers // this, so that we can step through C's freetype. return errors.New("truetype: hinting: unimplemented twilight point adjustment") } ref := h.point(0, unhinted, h.gs.rp[0]) p := h.point(1, unhinted, i) if ref == nil || p == nil { return errors.New("truetype: hinting: point out of range") } oldDist := dotProduct(p.X-ref.X, p.Y-ref.Y, h.gs.dv) ref = h.point(0, current, h.gs.rp[0]) p = h.point(1, current, i) if ref == nil || p == nil { return errors.New("truetype: hinting: point out of range") } curDist := dotProduct(p.X-ref.X, p.Y-ref.Y, h.gs.pv) if h.gs.autoFlip && oldDist^cvtDist < 0 { cvtDist = -cvtDist } // Rounding bit. // TODO: metrics compensation. distance := cvtDist if opcode&0x04 != 0 { // The CVT value is only used if close enough to oldDist. if (h.gs.zp[0] == h.gs.zp[1]) && (fabs(cvtDist-oldDist) > h.gs.controlValueCutIn) { distance = oldDist } distance = h.round(distance) } // Minimum distance bit. if opcode&0x08 != 0 { if oldDist >= 0 { if distance < h.gs.minDist { distance = h.gs.minDist } } else { if distance > -h.gs.minDist { distance = -h.gs.minDist } } } // Set-RP0 bit. h.gs.rp[1] = h.gs.rp[0] h.gs.rp[2] = i if opcode&0x10 != 0 { h.gs.rp[0] = i } // Move the point. h.move(p, distance-curDist, true) } } pc++ continue ifelse: // Skip past bytecode until the next ELSE (if opcode == 0) or the // next EIF (for all opcodes). Opcode == 0 means that we have come // from an IF. Opcode == 1 means that we have come from an ELSE. { ifelseloop: for depth := 0; ; { pc++ if pc >= len(program) { return errors.New("truetype: hinting: unbalanced IF or ELSE") } switch program[pc] { case opIF: depth++ case opELSE: if depth == 0 && opcode == 0 { break ifelseloop } case opEIF: depth-- if depth < 0 { break ifelseloop } default: var ok bool pc, ok = skipInstructionPayload(program, pc) if !ok { return errors.New("truetype: hinting: unbalanced IF or ELSE") } } } pc++ continue } push: // Push n elements from the program to the stack, where n is the low 7 bits of // opcode. If the low 7 bits are zero, then n is the next byte from the program. // The high bit being 0 means that the elements are zero-extended bytes. // The high bit being 1 means that the elements are sign-extended words. { width := 1 if opcode&0x80 != 0 { opcode &^= 0x80 width = 2 } if opcode == 0 { pc++ if pc >= len(program) { return errors.New("truetype: hinting: insufficient data") } opcode = program[pc] } pc++ if top+int(opcode) > len(h.stack) { return errors.New("truetype: hinting: stack overflow") } if pc+width*int(opcode) > len(program) { return errors.New("truetype: hinting: insufficient data") } for ; opcode > 0; opcode-- { if width == 1 { h.stack[top] = int32(program[pc]) } else { h.stack[top] = int32(int8(program[pc]))<<8 | int32(program[pc+1]) } top++ pc += width } continue } delta: { if opcode >= opDELTAC1 && !h.scaledCVTInitialized { h.initializeScaledCVT() } top-- n := h.stack[top] if int32(top) < 2*n { return errors.New("truetype: hinting: stack underflow") } for ; n > 0; n-- { top -= 2 b := h.stack[top] c := (b & 0xf0) >> 4 switch opcode { case opDELTAP2, opDELTAC2: c += 16 case opDELTAP3, opDELTAC3: c += 32 } c += h.gs.deltaBase if ppem := (int32(h.scale) + 1<<5) >> 6; ppem != c { continue } b = (b & 0x0f) - 8 if b >= 0 { b++ } b = b * 64 / (1 << uint32(h.gs.deltaShift)) if opcode >= opDELTAC1 { a := h.stack[top+1] if a < 0 || len(h.scaledCVT) <= int(a) { return errors.New("truetype: hinting: index out of range") } h.scaledCVT[a] += fixed.Int26_6(b) } else { p := h.point(0, current, h.stack[top+1]) if p == nil { return errors.New("truetype: hinting: point out of range") } h.move(p, fixed.Int26_6(b), true) } } pc++ continue } } return nil } func (h *hinter) initializeScaledCVT() { h.scaledCVTInitialized = true if n := len(h.font.cvt) / 2; n <= cap(h.scaledCVT) { h.scaledCVT = h.scaledCVT[:n] } else { if n < 32 { n = 32 } h.scaledCVT = make([]fixed.Int26_6, len(h.font.cvt)/2, n) } for i := range h.scaledCVT { unscaled := uint16(h.font.cvt[2*i])<<8 | uint16(h.font.cvt[2*i+1]) h.scaledCVT[i] = h.font.scale(h.scale * fixed.Int26_6(int16(unscaled))) } } // getScaledCVT returns the scaled value from the font's Control Value Table. func (h *hinter) getScaledCVT(i int32) fixed.Int26_6 { if !h.scaledCVTInitialized { h.initializeScaledCVT() } if i < 0 || len(h.scaledCVT) <= int(i) { return 0 } return h.scaledCVT[i] } // setScaledCVT overrides the scaled value from the font's Control Value Table. func (h *hinter) setScaledCVT(i int32, v fixed.Int26_6) { if !h.scaledCVTInitialized { h.initializeScaledCVT() } if i < 0 || len(h.scaledCVT) <= int(i) { return } h.scaledCVT[i] = v } func (h *hinter) point(zonePointer uint32, pt pointType, i int32) *Point { points := h.points[h.gs.zp[zonePointer]][pt] if i < 0 || len(points) <= int(i) { return nil } return &points[i] } func (h *hinter) move(p *Point, distance fixed.Int26_6, touch bool) { fvx := int64(h.gs.fv[0]) pvx := int64(h.gs.pv[0]) if fvx == 0x4000 && pvx == 0x4000 { p.X += fixed.Int26_6(distance) if touch { p.Flags |= flagTouchedX } return } fvy := int64(h.gs.fv[1]) pvy := int64(h.gs.pv[1]) if fvy == 0x4000 && pvy == 0x4000 { p.Y += fixed.Int26_6(distance) if touch { p.Flags |= flagTouchedY } return } fvDotPv := (fvx*pvx + fvy*pvy) >> 14 if fvx != 0 { p.X += fixed.Int26_6(mulDiv(fvx, int64(distance), fvDotPv)) if touch { p.Flags |= flagTouchedX } } if fvy != 0 { p.Y += fixed.Int26_6(mulDiv(fvy, int64(distance), fvDotPv)) if touch { p.Flags |= flagTouchedY } } } func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) { if p1 > p2 { return } if ref1 >= len(h.points[glyphZone][current]) || ref2 >= len(h.points[glyphZone][current]) { return } var ifu1, ifu2 fixed.Int26_6 if interpY { ifu1 = h.points[glyphZone][inFontUnits][ref1].Y ifu2 = h.points[glyphZone][inFontUnits][ref2].Y } else { ifu1 = h.points[glyphZone][inFontUnits][ref1].X ifu2 = h.points[glyphZone][inFontUnits][ref2].X } if ifu1 > ifu2 { ifu1, ifu2 = ifu2, ifu1 ref1, ref2 = ref2, ref1 } var unh1, unh2, delta1, delta2 fixed.Int26_6 if interpY { unh1 = h.points[glyphZone][unhinted][ref1].Y unh2 = h.points[glyphZone][unhinted][ref2].Y delta1 = h.points[glyphZone][current][ref1].Y - unh1 delta2 = h.points[glyphZone][current][ref2].Y - unh2 } else { unh1 = h.points[glyphZone][unhinted][ref1].X unh2 = h.points[glyphZone][unhinted][ref2].X delta1 = h.points[glyphZone][current][ref1].X - unh1 delta2 = h.points[glyphZone][current][ref2].X - unh2 } var xy, ifuXY fixed.Int26_6 if ifu1 == ifu2 { for i := p1; i <= p2; i++ { if interpY { xy = h.points[glyphZone][unhinted][i].Y } else { xy = h.points[glyphZone][unhinted][i].X } if xy <= unh1 { xy += delta1 } else { xy += delta2 } if interpY { h.points[glyphZone][current][i].Y = xy } else { h.points[glyphZone][current][i].X = xy } } return } scale, scaleOK := int64(0), false for i := p1; i <= p2; i++ { if interpY { xy = h.points[glyphZone][unhinted][i].Y ifuXY = h.points[glyphZone][inFontUnits][i].Y } else { xy = h.points[glyphZone][unhinted][i].X ifuXY = h.points[glyphZone][inFontUnits][i].X } if xy <= unh1 { xy += delta1 } else if xy >= unh2 { xy += delta2 } else { if !scaleOK { scaleOK = true scale = mulDiv(int64(unh2+delta2-unh1-delta1), 0x10000, int64(ifu2-ifu1)) } numer := int64(ifuXY-ifu1) * scale if numer >= 0 { numer += 0x8000 } else { numer -= 0x8000 } xy = unh1 + delta1 + fixed.Int26_6(numer/0x10000) } if interpY { h.points[glyphZone][current][i].Y = xy } else { h.points[glyphZone][current][i].X = xy } } } func (h *hinter) iupShift(interpY bool, p1, p2, p int) { var delta fixed.Int26_6 if interpY { delta = h.points[glyphZone][current][p].Y - h.points[glyphZone][unhinted][p].Y } else { delta = h.points[glyphZone][current][p].X - h.points[glyphZone][unhinted][p].X } if delta == 0 { return } for i := p1; i < p2; i++ { if i == p { continue } if interpY { h.points[glyphZone][current][i].Y += delta } else { h.points[glyphZone][current][i].X += delta } } } func (h *hinter) displacement(useZP1 bool) (zonePointer uint32, i int32, d fixed.Int26_6, ok bool) { zonePointer, i = uint32(0), h.gs.rp[1] if useZP1 { zonePointer, i = 1, h.gs.rp[2] } p := h.point(zonePointer, current, i) q := h.point(zonePointer, unhinted, i) if p == nil || q == nil { return 0, 0, 0, false } d = dotProduct(p.X-q.X, p.Y-q.Y, h.gs.pv) return zonePointer, i, d, true } // skipInstructionPayload increments pc by the extra data that follows a // variable length PUSHB or PUSHW instruction. func skipInstructionPayload(program []byte, pc int) (newPC int, ok bool) { switch program[pc] { case opNPUSHB: pc++ if pc >= len(program) { return 0, false } pc += int(program[pc]) case opNPUSHW: pc++ if pc >= len(program) { return 0, false } pc += 2 * int(program[pc]) case opPUSHB000, opPUSHB001, opPUSHB010, opPUSHB011, opPUSHB100, opPUSHB101, opPUSHB110, opPUSHB111: pc += int(program[pc] - (opPUSHB000 - 1)) case opPUSHW000, opPUSHW001, opPUSHW010, opPUSHW011, opPUSHW100, opPUSHW101, opPUSHW110, opPUSHW111: pc += 2 * int(program[pc]-(opPUSHW000-1)) } return pc, true } // f2dot14 is a 2.14 fixed point number. type f2dot14 int16 func normalize(x, y f2dot14) [2]f2dot14 { fx, fy := float64(x), float64(y) l := 0x4000 / math.Hypot(fx, fy) fx *= l if fx >= 0 { fx += 0.5 } else { fx -= 0.5 } fy *= l if fy >= 0 { fy += 0.5 } else { fy -= 0.5 } return [2]f2dot14{f2dot14(fx), f2dot14(fy)} } // fabs returns abs(x) in 26.6 fixed point arithmetic. func fabs(x fixed.Int26_6) fixed.Int26_6 { if x < 0 { return -x } return x } // fdiv returns x/y in 26.6 fixed point arithmetic. func fdiv(x, y fixed.Int26_6) fixed.Int26_6 { return fixed.Int26_6((int64(x) << 6) / int64(y)) } // fmul returns x*y in 26.6 fixed point arithmetic. func fmul(x, y fixed.Int26_6) fixed.Int26_6 { return fixed.Int26_6((int64(x)*int64(y) + 1<<5) >> 6) } // dotProduct returns the dot product of [x, y] and q. It is almost the same as // px := int64(x) // py := int64(y) // qx := int64(q[0]) // qy := int64(q[1]) // return fixed.Int26_6((px*qx + py*qy + 1<<13) >> 14) // except that the computation is done with 32-bit integers to produce exactly // the same rounding behavior as C Freetype. func dotProduct(x, y fixed.Int26_6, q [2]f2dot14) fixed.Int26_6 { // Compute x*q[0] as 64-bit value. l := uint32((int32(x) & 0xFFFF) * int32(q[0])) m := (int32(x) >> 16) * int32(q[0]) lo1 := l + (uint32(m) << 16) hi1 := (m >> 16) + (int32(l) >> 31) + bool2int32(lo1 < l) // Compute y*q[1] as 64-bit value. l = uint32((int32(y) & 0xFFFF) * int32(q[1])) m = (int32(y) >> 16) * int32(q[1]) lo2 := l + (uint32(m) << 16) hi2 := (m >> 16) + (int32(l) >> 31) + bool2int32(lo2 < l) // Add them. lo := lo1 + lo2 hi := hi1 + hi2 + bool2int32(lo < lo1) // Divide the result by 2^14 with rounding. s := hi >> 31 l = lo + uint32(s) hi += s + bool2int32(l < lo) lo = l l = lo + 0x2000 hi += bool2int32(l < lo) return fixed.Int26_6((uint32(hi) << 18) | (l >> 14)) } // mulDiv returns x*y/z, rounded to the nearest integer. func mulDiv(x, y, z int64) int64 { xy := x * y if z < 0 { xy, z = -xy, -z } if xy >= 0 { xy += z / 2 } else { xy -= z / 2 } return xy / z } // round rounds the given number. The rounding algorithm is described at // https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding func (h *hinter) round(x fixed.Int26_6) fixed.Int26_6 { if h.gs.roundPeriod == 0 { // Rounding is off. return x } if x >= 0 { ret := x - h.gs.roundPhase + h.gs.roundThreshold if h.gs.roundSuper45 { ret /= h.gs.roundPeriod ret *= h.gs.roundPeriod } else { ret &= -h.gs.roundPeriod } if x != 0 && ret < 0 { ret = 0 } return ret + h.gs.roundPhase } ret := -x - h.gs.roundPhase + h.gs.roundThreshold if h.gs.roundSuper45 { ret /= h.gs.roundPeriod ret *= h.gs.roundPeriod } else { ret &= -h.gs.roundPeriod } if ret < 0 { ret = 0 } return -ret - h.gs.roundPhase } func bool2int32(b bool) int32 { if b { return 1 } return 0 } ================================================ FILE: vendor/github.com/golang/freetype/truetype/opcodes.go ================================================ // Copyright 2012 The Freetype-Go Authors. All rights reserved. // Use of this source code is governed by your choice of either the // FreeType License or the GNU General Public License version 2 (or // any later version), both of which can be found in the LICENSE file. package truetype // The Truetype opcodes are summarized at // https://developer.apple.com/fonts/TTRefMan/RM07/appendixA.html const ( opSVTCA0 = 0x00 // Set freedom and projection Vectors To Coordinate Axis opSVTCA1 = 0x01 // . opSPVTCA0 = 0x02 // Set Projection Vector To Coordinate Axis opSPVTCA1 = 0x03 // . opSFVTCA0 = 0x04 // Set Freedom Vector to Coordinate Axis opSFVTCA1 = 0x05 // . opSPVTL0 = 0x06 // Set Projection Vector To Line opSPVTL1 = 0x07 // . opSFVTL0 = 0x08 // Set Freedom Vector To Line opSFVTL1 = 0x09 // . opSPVFS = 0x0a // Set Projection Vector From Stack opSFVFS = 0x0b // Set Freedom Vector From Stack opGPV = 0x0c // Get Projection Vector opGFV = 0x0d // Get Freedom Vector opSFVTPV = 0x0e // Set Freedom Vector To Projection Vector opISECT = 0x0f // moves point p to the InterSECTion of two lines opSRP0 = 0x10 // Set Reference Point 0 opSRP1 = 0x11 // Set Reference Point 1 opSRP2 = 0x12 // Set Reference Point 2 opSZP0 = 0x13 // Set Zone Pointer 0 opSZP1 = 0x14 // Set Zone Pointer 1 opSZP2 = 0x15 // Set Zone Pointer 2 opSZPS = 0x16 // Set Zone PointerS opSLOOP = 0x17 // Set LOOP variable opRTG = 0x18 // Round To Grid opRTHG = 0x19 // Round To Half Grid opSMD = 0x1a // Set Minimum Distance opELSE = 0x1b // ELSE clause opJMPR = 0x1c // JuMP Relative opSCVTCI = 0x1d // Set Control Value Table Cut-In opSSWCI = 0x1e // Set Single Width Cut-In opSSW = 0x1f // Set Single Width opDUP = 0x20 // DUPlicate top stack element opPOP = 0x21 // POP top stack element opCLEAR = 0x22 // CLEAR the stack opSWAP = 0x23 // SWAP the top two elements on the stack opDEPTH = 0x24 // DEPTH of the stack opCINDEX = 0x25 // Copy the INDEXed element to the top of the stack opMINDEX = 0x26 // Move the INDEXed element to the top of the stack opALIGNPTS = 0x27 // ALIGN PoinTS op_0x28 = 0x28 // deprecated opUTP = 0x29 // UnTouch Point opLOOPCALL = 0x2a // LOOP and CALL function opCALL = 0x2b // CALL function opFDEF = 0x2c // Function DEFinition opENDF = 0x2d // END Function definition opMDAP0 = 0x2e // Move Direct Absolute Point opMDAP1 = 0x2f // . opIUP0 = 0x30 // Interpolate Untouched Points through the outline opIUP1 = 0x31 // . opSHP0 = 0x32 // SHift Point using reference point opSHP1 = 0x33 // . opSHC0 = 0x34 // SHift Contour using reference point opSHC1 = 0x35 // . opSHZ0 = 0x36 // SHift Zone using reference point opSHZ1 = 0x37 // . opSHPIX = 0x38 // SHift point by a PIXel amount opIP = 0x39 // Interpolate Point opMSIRP0 = 0x3a // Move Stack Indirect Relative Point opMSIRP1 = 0x3b // . opALIGNRP = 0x3c // ALIGN to Reference Point opRTDG = 0x3d // Round To Double Grid opMIAP0 = 0x3e // Move Indirect Absolute Point opMIAP1 = 0x3f // . opNPUSHB = 0x40 // PUSH N Bytes opNPUSHW = 0x41 // PUSH N Words opWS = 0x42 // Write Store opRS = 0x43 // Read Store opWCVTP = 0x44 // Write Control Value Table in Pixel units opRCVT = 0x45 // Read Control Value Table entry opGC0 = 0x46 // Get Coordinate projected onto the projection vector opGC1 = 0x47 // . opSCFS = 0x48 // Sets Coordinate From the Stack using projection vector and freedom vector opMD0 = 0x49 // Measure Distance opMD1 = 0x4a // . opMPPEM = 0x4b // Measure Pixels Per EM opMPS = 0x4c // Measure Point Size opFLIPON = 0x4d // set the auto FLIP Boolean to ON opFLIPOFF = 0x4e // set the auto FLIP Boolean to OFF opDEBUG = 0x4f // DEBUG call opLT = 0x50 // Less Than opLTEQ = 0x51 // Less Than or EQual opGT = 0x52 // Greater Than opGTEQ = 0x53 // Greater Than or EQual opEQ = 0x54 // EQual opNEQ = 0x55 // Not EQual opODD = 0x56 // ODD opEVEN = 0x57 // EVEN opIF = 0x58 // IF test opEIF = 0x59 // End IF opAND = 0x5a // logical AND opOR = 0x5b // logical OR opNOT = 0x5c // logical NOT opDELTAP1 = 0x5d // DELTA exception P1 opSDB = 0x5e // Set Delta Base in the graphics state opSDS = 0x5f // Set Delta Shift in the graphics state opADD = 0x60 // ADD opSUB = 0x61 // SUBtract opDIV = 0x62 // DIVide opMUL = 0x63 // MULtiply opABS = 0x64 // ABSolute value opNEG = 0x65 // NEGate opFLOOR = 0x66 // FLOOR opCEILING = 0x67 // CEILING opROUND00 = 0x68 // ROUND value opROUND01 = 0x69 // . opROUND10 = 0x6a // . opROUND11 = 0x6b // . opNROUND00 = 0x6c // No ROUNDing of value opNROUND01 = 0x6d // . opNROUND10 = 0x6e // . opNROUND11 = 0x6f // . opWCVTF = 0x70 // Write Control Value Table in Funits opDELTAP2 = 0x71 // DELTA exception P2 opDELTAP3 = 0x72 // DELTA exception P3 opDELTAC1 = 0x73 // DELTA exception C1 opDELTAC2 = 0x74 // DELTA exception C2 opDELTAC3 = 0x75 // DELTA exception C3 opSROUND = 0x76 // Super ROUND opS45ROUND = 0x77 // Super ROUND 45 degrees opJROT = 0x78 // Jump Relative On True opJROF = 0x79 // Jump Relative On False opROFF = 0x7a // Round OFF op_0x7b = 0x7b // deprecated opRUTG = 0x7c // Round Up To Grid opRDTG = 0x7d // Round Down To Grid opSANGW = 0x7e // Set ANGle Weight opAA = 0x7f // Adjust Angle opFLIPPT = 0x80 // FLIP PoinT opFLIPRGON = 0x81 // FLIP RanGe ON opFLIPRGOFF = 0x82 // FLIP RanGe OFF op_0x83 = 0x83 // deprecated op_0x84 = 0x84 // deprecated opSCANCTRL = 0x85 // SCAN conversion ConTRoL opSDPVTL0 = 0x86 // Set Dual Projection Vector To Line opSDPVTL1 = 0x87 // . opGETINFO = 0x88 // GET INFOrmation opIDEF = 0x89 // Instruction DEFinition opROLL = 0x8a // ROLL the top three stack elements opMAX = 0x8b // MAXimum of top two stack elements opMIN = 0x8c // MINimum of top two stack elements opSCANTYPE = 0x8d // SCANTYPE opINSTCTRL = 0x8e // INSTRuction execution ConTRoL op_0x8f = 0x8f op_0x90 = 0x90 op_0x91 = 0x91 op_0x92 = 0x92 op_0x93 = 0x93 op_0x94 = 0x94 op_0x95 = 0x95 op_0x96 = 0x96 op_0x97 = 0x97 op_0x98 = 0x98 op_0x99 = 0x99 op_0x9a = 0x9a op_0x9b = 0x9b op_0x9c = 0x9c op_0x9d = 0x9d op_0x9e = 0x9e op_0x9f = 0x9f op_0xa0 = 0xa0 op_0xa1 = 0xa1 op_0xa2 = 0xa2 op_0xa3 = 0xa3 op_0xa4 = 0xa4 op_0xa5 = 0xa5 op_0xa6 = 0xa6 op_0xa7 = 0xa7 op_0xa8 = 0xa8 op_0xa9 = 0xa9 op_0xaa = 0xaa op_0xab = 0xab op_0xac = 0xac op_0xad = 0xad op_0xae = 0xae op_0xaf = 0xaf opPUSHB000 = 0xb0 // PUSH Bytes opPUSHB001 = 0xb1 // . opPUSHB010 = 0xb2 // . opPUSHB011 = 0xb3 // . opPUSHB100 = 0xb4 // . opPUSHB101 = 0xb5 // . opPUSHB110 = 0xb6 // . opPUSHB111 = 0xb7 // . opPUSHW000 = 0xb8 // PUSH Words opPUSHW001 = 0xb9 // . opPUSHW010 = 0xba // . opPUSHW011 = 0xbb // . opPUSHW100 = 0xbc // . opPUSHW101 = 0xbd // . opPUSHW110 = 0xbe // . opPUSHW111 = 0xbf // . opMDRP00000 = 0xc0 // Move Direct Relative Point opMDRP00001 = 0xc1 // . opMDRP00010 = 0xc2 // . opMDRP00011 = 0xc3 // . opMDRP00100 = 0xc4 // . opMDRP00101 = 0xc5 // . opMDRP00110 = 0xc6 // . opMDRP00111 = 0xc7 // . opMDRP01000 = 0xc8 // . opMDRP01001 = 0xc9 // . opMDRP01010 = 0xca // . opMDRP01011 = 0xcb // . opMDRP01100 = 0xcc // . opMDRP01101 = 0xcd // . opMDRP01110 = 0xce // . opMDRP01111 = 0xcf // . opMDRP10000 = 0xd0 // . opMDRP10001 = 0xd1 // . opMDRP10010 = 0xd2 // . opMDRP10011 = 0xd3 // . opMDRP10100 = 0xd4 // . opMDRP10101 = 0xd5 // . opMDRP10110 = 0xd6 // . opMDRP10111 = 0xd7 // . opMDRP11000 = 0xd8 // . opMDRP11001 = 0xd9 // . opMDRP11010 = 0xda // . opMDRP11011 = 0xdb // . opMDRP11100 = 0xdc // . opMDRP11101 = 0xdd // . opMDRP11110 = 0xde // . opMDRP11111 = 0xdf // . opMIRP00000 = 0xe0 // Move Indirect Relative Point opMIRP00001 = 0xe1 // . opMIRP00010 = 0xe2 // . opMIRP00011 = 0xe3 // . opMIRP00100 = 0xe4 // . opMIRP00101 = 0xe5 // . opMIRP00110 = 0xe6 // . opMIRP00111 = 0xe7 // . opMIRP01000 = 0xe8 // . opMIRP01001 = 0xe9 // . opMIRP01010 = 0xea // . opMIRP01011 = 0xeb // . opMIRP01100 = 0xec // . opMIRP01101 = 0xed // . opMIRP01110 = 0xee // . opMIRP01111 = 0xef // . opMIRP10000 = 0xf0 // . opMIRP10001 = 0xf1 // . opMIRP10010 = 0xf2 // . opMIRP10011 = 0xf3 // . opMIRP10100 = 0xf4 // . opMIRP10101 = 0xf5 // . opMIRP10110 = 0xf6 // . opMIRP10111 = 0xf7 // . opMIRP11000 = 0xf8 // . opMIRP11001 = 0xf9 // . opMIRP11010 = 0xfa // . opMIRP11011 = 0xfb // . opMIRP11100 = 0xfc // . opMIRP11101 = 0xfd // . opMIRP11110 = 0xfe // . opMIRP11111 = 0xff // . ) // popCount is the number of stack elements that each opcode pops. var popCount = [256]uint8{ // 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 5, // 0x00 - 0x0f 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, // 0x10 - 0x1f 1, 1, 0, 2, 0, 1, 1, 2, 0, 1, 2, 1, 1, 0, 1, 1, // 0x20 - 0x2f 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 2, 2, 0, 0, 2, 2, // 0x30 - 0x3f 0, 0, 2, 1, 2, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, // 0x40 - 0x4f 2, 2, 2, 2, 2, 2, 1, 1, 1, 0, 2, 2, 1, 1, 1, 1, // 0x50 - 0x5f 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 - 0x6f 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0, 0, 0, 1, 1, // 0x70 - 0x7f 0, 2, 2, 0, 0, 1, 2, 2, 1, 1, 3, 2, 2, 1, 2, 0, // 0x80 - 0x8f 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90 - 0x9f 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0 - 0xaf 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xb0 - 0xbf 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xc0 - 0xcf 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xd0 - 0xdf 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xe0 - 0xef 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xf0 - 0xff } ================================================ FILE: vendor/github.com/golang/freetype/truetype/truetype.go ================================================ // Copyright 2010 The Freetype-Go Authors. All rights reserved. // Use of this source code is governed by your choice of either the // FreeType License or the GNU General Public License version 2 (or // any later version), both of which can be found in the LICENSE file. // Package truetype provides a parser for the TTF and TTC file formats. // Those formats are documented at http://developer.apple.com/fonts/TTRefMan/ // and http://www.microsoft.com/typography/otspec/ // // Some of a font's methods provide lengths or co-ordinates, e.g. bounds, font // metrics and control points. All these methods take a scale parameter, which // is the number of pixels in 1 em, expressed as a 26.6 fixed point value. For // example, if 1 em is 10 pixels then scale is fixed.I(10), which is equal to // fixed.Int26_6(10 << 6). // // To measure a TrueType font in ideal FUnit space, use scale equal to // font.FUnitsPerEm(). package truetype // import "github.com/golang/freetype/truetype" import ( "fmt" "golang.org/x/image/math/fixed" ) // An Index is a Font's index of a rune. type Index uint16 // A NameID identifies a name table entry. // // See https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html type NameID uint16 const ( NameIDCopyright NameID = 0 NameIDFontFamily = 1 NameIDFontSubfamily = 2 NameIDUniqueSubfamilyID = 3 NameIDFontFullName = 4 NameIDNameTableVersion = 5 NameIDPostscriptName = 6 NameIDTrademarkNotice = 7 NameIDManufacturerName = 8 NameIDDesignerName = 9 NameIDFontDescription = 10 NameIDFontVendorURL = 11 NameIDFontDesignerURL = 12 NameIDFontLicense = 13 NameIDFontLicenseURL = 14 NameIDPreferredFamily = 16 NameIDPreferredSubfamily = 17 NameIDCompatibleName = 18 NameIDSampleText = 19 ) const ( // A 32-bit encoding consists of a most-significant 16-bit Platform ID and a // least-significant 16-bit Platform Specific ID. The magic numbers are // specified at https://www.microsoft.com/typography/otspec/name.htm unicodeEncodingBMPOnly = 0x00000003 // PID = 0 (Unicode), PSID = 3 (Unicode 2.0 BMP Only) unicodeEncodingFull = 0x00000004 // PID = 0 (Unicode), PSID = 4 (Unicode 2.0 Full Repertoire) microsoftSymbolEncoding = 0x00030000 // PID = 3 (Microsoft), PSID = 0 (Symbol) microsoftUCS2Encoding = 0x00030001 // PID = 3 (Microsoft), PSID = 1 (UCS-2) microsoftUCS4Encoding = 0x0003000a // PID = 3 (Microsoft), PSID = 10 (UCS-4) ) // An HMetric holds the horizontal metrics of a single glyph. type HMetric struct { AdvanceWidth, LeftSideBearing fixed.Int26_6 } // A VMetric holds the vertical metrics of a single glyph. type VMetric struct { AdvanceHeight, TopSideBearing fixed.Int26_6 } // A FormatError reports that the input is not a valid TrueType font. type FormatError string func (e FormatError) Error() string { return "freetype: invalid TrueType format: " + string(e) } // An UnsupportedError reports that the input uses a valid but unimplemented // TrueType feature. type UnsupportedError string func (e UnsupportedError) Error() string { return "freetype: unsupported TrueType feature: " + string(e) } // u32 returns the big-endian uint32 at b[i:]. func u32(b []byte, i int) uint32 { return uint32(b[i])<<24 | uint32(b[i+1])<<16 | uint32(b[i+2])<<8 | uint32(b[i+3]) } // u16 returns the big-endian uint16 at b[i:]. func u16(b []byte, i int) uint16 { return uint16(b[i])<<8 | uint16(b[i+1]) } // readTable returns a slice of the TTF data given by a table's directory entry. func readTable(ttf []byte, offsetLength []byte) ([]byte, error) { offset := int(u32(offsetLength, 0)) if offset < 0 { return nil, FormatError(fmt.Sprintf("offset too large: %d", uint32(offset))) } length := int(u32(offsetLength, 4)) if length < 0 { return nil, FormatError(fmt.Sprintf("length too large: %d", uint32(length))) } end := offset + length if end < 0 || end > len(ttf) { return nil, FormatError(fmt.Sprintf("offset + length too large: %d", uint32(offset)+uint32(length))) } return ttf[offset:end], nil } // parseSubtables returns the offset and platformID of the best subtable in // table, where best favors a Unicode cmap encoding, and failing that, a // Microsoft cmap encoding. offset is the offset of the first subtable in // table, and size is the size of each subtable. // // If pred is non-nil, then only subtables that satisfy that predicate will be // considered. func parseSubtables(table []byte, name string, offset, size int, pred func([]byte) bool) ( bestOffset int, bestPID uint32, retErr error) { if len(table) < 4 { return 0, 0, FormatError(name + " too short") } nSubtables := int(u16(table, 2)) if len(table) < size*nSubtables+offset { return 0, 0, FormatError(name + " too short") } ok := false for i := 0; i < nSubtables; i, offset = i+1, offset+size { if pred != nil && !pred(table[offset:]) { continue } // We read the 16-bit Platform ID and 16-bit Platform Specific ID as a single uint32. // All values are big-endian. pidPsid := u32(table, offset) // We prefer the Unicode cmap encoding. Failing to find that, we fall // back onto the Microsoft cmap encoding. if pidPsid == unicodeEncodingBMPOnly || pidPsid == unicodeEncodingFull { bestOffset, bestPID, ok = offset, pidPsid>>16, true break } else if pidPsid == microsoftSymbolEncoding || pidPsid == microsoftUCS2Encoding || pidPsid == microsoftUCS4Encoding { bestOffset, bestPID, ok = offset, pidPsid>>16, true // We don't break out of the for loop, so that Unicode can override Microsoft. } } if !ok { return 0, 0, UnsupportedError(name + " encoding") } return bestOffset, bestPID, nil } const ( locaOffsetFormatUnknown int = iota locaOffsetFormatShort locaOffsetFormatLong ) // A cm holds a parsed cmap entry. type cm struct { start, end, delta, offset uint32 } // A Font represents a Truetype font. type Font struct { // Tables sliced from the TTF data. The different tables are documented // at http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html cmap, cvt, fpgm, glyf, hdmx, head, hhea, hmtx, kern, loca, maxp, name, os2, prep, vmtx []byte cmapIndexes []byte // Cached values derived from the raw ttf data. cm []cm locaOffsetFormat int nGlyph, nHMetric, nKern int fUnitsPerEm int32 ascent int32 // In FUnits. descent int32 // In FUnits; typically negative. bounds fixed.Rectangle26_6 // In FUnits. // Values from the maxp section. maxTwilightPoints, maxStorage, maxFunctionDefs, maxStackElements uint16 } func (f *Font) parseCmap() error { const ( cmapFormat4 = 4 cmapFormat12 = 12 languageIndependent = 0 ) offset, _, err := parseSubtables(f.cmap, "cmap", 4, 8, nil) if err != nil { return err } offset = int(u32(f.cmap, offset+4)) if offset <= 0 || offset > len(f.cmap) { return FormatError("bad cmap offset") } cmapFormat := u16(f.cmap, offset) switch cmapFormat { case cmapFormat4: language := u16(f.cmap, offset+4) if language != languageIndependent { return UnsupportedError(fmt.Sprintf("language: %d", language)) } segCountX2 := int(u16(f.cmap, offset+6)) if segCountX2%2 == 1 { return FormatError(fmt.Sprintf("bad segCountX2: %d", segCountX2)) } segCount := segCountX2 / 2 offset += 14 f.cm = make([]cm, segCount) for i := 0; i < segCount; i++ { f.cm[i].end = uint32(u16(f.cmap, offset)) offset += 2 } offset += 2 for i := 0; i < segCount; i++ { f.cm[i].start = uint32(u16(f.cmap, offset)) offset += 2 } for i := 0; i < segCount; i++ { f.cm[i].delta = uint32(u16(f.cmap, offset)) offset += 2 } for i := 0; i < segCount; i++ { f.cm[i].offset = uint32(u16(f.cmap, offset)) offset += 2 } f.cmapIndexes = f.cmap[offset:] return nil case cmapFormat12: if u16(f.cmap, offset+2) != 0 { return FormatError(fmt.Sprintf("cmap format: % x", f.cmap[offset:offset+4])) } length := u32(f.cmap, offset+4) language := u32(f.cmap, offset+8) if language != languageIndependent { return UnsupportedError(fmt.Sprintf("language: %d", language)) } nGroups := u32(f.cmap, offset+12) if length != 12*nGroups+16 { return FormatError("inconsistent cmap length") } offset += 16 f.cm = make([]cm, nGroups) for i := uint32(0); i < nGroups; i++ { f.cm[i].start = u32(f.cmap, offset+0) f.cm[i].end = u32(f.cmap, offset+4) f.cm[i].delta = u32(f.cmap, offset+8) - f.cm[i].start offset += 12 } return nil } return UnsupportedError(fmt.Sprintf("cmap format: %d", cmapFormat)) } func (f *Font) parseHead() error { if len(f.head) != 54 { return FormatError(fmt.Sprintf("bad head length: %d", len(f.head))) } f.fUnitsPerEm = int32(u16(f.head, 18)) f.bounds.Min.X = fixed.Int26_6(int16(u16(f.head, 36))) f.bounds.Min.Y = fixed.Int26_6(int16(u16(f.head, 38))) f.bounds.Max.X = fixed.Int26_6(int16(u16(f.head, 40))) f.bounds.Max.Y = fixed.Int26_6(int16(u16(f.head, 42))) switch i := u16(f.head, 50); i { case 0: f.locaOffsetFormat = locaOffsetFormatShort case 1: f.locaOffsetFormat = locaOffsetFormatLong default: return FormatError(fmt.Sprintf("bad indexToLocFormat: %d", i)) } return nil } func (f *Font) parseHhea() error { if len(f.hhea) != 36 { return FormatError(fmt.Sprintf("bad hhea length: %d", len(f.hhea))) } f.ascent = int32(int16(u16(f.hhea, 4))) f.descent = int32(int16(u16(f.hhea, 6))) f.nHMetric = int(u16(f.hhea, 34)) if 4*f.nHMetric+2*(f.nGlyph-f.nHMetric) != len(f.hmtx) { return FormatError(fmt.Sprintf("bad hmtx length: %d", len(f.hmtx))) } return nil } func (f *Font) parseKern() error { // Apple's TrueType documentation (http://developer.apple.com/fonts/TTRefMan/RM06/Chap6kern.html) says: // "Previous versions of the 'kern' table defined both the version and nTables fields in the header // as UInt16 values and not UInt32 values. Use of the older format on the Mac OS is discouraged // (although AAT can sense an old kerning table and still make correct use of it). Microsoft // Windows still uses the older format for the 'kern' table and will not recognize the newer one. // Fonts targeted for the Mac OS only should use the new format; fonts targeted for both the Mac OS // and Windows should use the old format." // Since we expect that almost all fonts aim to be Windows-compatible, we only parse the "older" format, // just like the C Freetype implementation. if len(f.kern) == 0 { if f.nKern != 0 { return FormatError("bad kern table length") } return nil } if len(f.kern) < 18 { return FormatError("kern data too short") } version, offset := u16(f.kern, 0), 2 if version != 0 { return UnsupportedError(fmt.Sprintf("kern version: %d", version)) } n, offset := u16(f.kern, offset), offset+2 if n == 0 { return UnsupportedError("kern nTables: 0") } // TODO: support multiple subtables. In practice, almost all .ttf files // have only one subtable, if they have a kern table at all. But it's not // impossible. Xolonium Regular (https://fontlibrary.org/en/font/xolonium) // has 3 subtables. Those subtables appear to be disjoint, rather than // being the same kerning pairs encoded in three different ways. // // For now, we'll use only the first subtable. offset += 2 // Skip the version. length, offset := int(u16(f.kern, offset)), offset+2 coverage, offset := u16(f.kern, offset), offset+2 if coverage != 0x0001 { // We only support horizontal kerning. return UnsupportedError(fmt.Sprintf("kern coverage: 0x%04x", coverage)) } f.nKern, offset = int(u16(f.kern, offset)), offset+2 if 6*f.nKern != length-14 { return FormatError("bad kern table length") } return nil } func (f *Font) parseMaxp() error { if len(f.maxp) != 32 { return FormatError(fmt.Sprintf("bad maxp length: %d", len(f.maxp))) } f.nGlyph = int(u16(f.maxp, 4)) f.maxTwilightPoints = u16(f.maxp, 16) f.maxStorage = u16(f.maxp, 18) f.maxFunctionDefs = u16(f.maxp, 20) f.maxStackElements = u16(f.maxp, 24) return nil } // scale returns x divided by f.fUnitsPerEm, rounded to the nearest integer. func (f *Font) scale(x fixed.Int26_6) fixed.Int26_6 { if x >= 0 { x += fixed.Int26_6(f.fUnitsPerEm) / 2 } else { x -= fixed.Int26_6(f.fUnitsPerEm) / 2 } return x / fixed.Int26_6(f.fUnitsPerEm) } // Bounds returns the union of a Font's glyphs' bounds. func (f *Font) Bounds(scale fixed.Int26_6) fixed.Rectangle26_6 { b := f.bounds b.Min.X = f.scale(scale * b.Min.X) b.Min.Y = f.scale(scale * b.Min.Y) b.Max.X = f.scale(scale * b.Max.X) b.Max.Y = f.scale(scale * b.Max.Y) return b } // FUnitsPerEm returns the number of FUnits in a Font's em-square's side. func (f *Font) FUnitsPerEm() int32 { return f.fUnitsPerEm } // Index returns a Font's index for the given rune. func (f *Font) Index(x rune) Index { c := uint32(x) for i, j := 0, len(f.cm); i < j; { h := i + (j-i)/2 cm := &f.cm[h] if c < cm.start { j = h } else if cm.end < c { i = h + 1 } else if cm.offset == 0 { return Index(c + cm.delta) } else { offset := int(cm.offset) + 2*(h-len(f.cm)+int(c-cm.start)) return Index(u16(f.cmapIndexes, offset)) } } return 0 } // Name returns the Font's name value for the given NameID. It returns "" if // there was an error, or if that name was not found. func (f *Font) Name(id NameID) string { x, platformID, err := parseSubtables(f.name, "name", 6, 12, func(b []byte) bool { return NameID(u16(b, 6)) == id }) if err != nil { return "" } offset, length := u16(f.name, 4)+u16(f.name, x+10), u16(f.name, x+8) // Return the ASCII value of the encoded string. // The string is encoded as UTF-16 on non-Apple platformIDs; Apple is platformID 1. src := f.name[offset : offset+length] var dst []byte if platformID != 1 { // UTF-16. if len(src)&1 != 0 { return "" } dst = make([]byte, len(src)/2) for i := range dst { dst[i] = printable(u16(src, 2*i)) } } else { // ASCII. dst = make([]byte, len(src)) for i, c := range src { dst[i] = printable(uint16(c)) } } return string(dst) } func printable(r uint16) byte { if 0x20 <= r && r < 0x7f { return byte(r) } return '?' } // unscaledHMetric returns the unscaled horizontal metrics for the glyph with // the given index. func (f *Font) unscaledHMetric(i Index) (h HMetric) { j := int(i) if j < 0 || f.nGlyph <= j { return HMetric{} } if j >= f.nHMetric { p := 4 * (f.nHMetric - 1) return HMetric{ AdvanceWidth: fixed.Int26_6(u16(f.hmtx, p)), LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, p+2*(j-f.nHMetric)+4))), } } return HMetric{ AdvanceWidth: fixed.Int26_6(u16(f.hmtx, 4*j)), LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, 4*j+2))), } } // HMetric returns the horizontal metrics for the glyph with the given index. func (f *Font) HMetric(scale fixed.Int26_6, i Index) HMetric { h := f.unscaledHMetric(i) h.AdvanceWidth = f.scale(scale * h.AdvanceWidth) h.LeftSideBearing = f.scale(scale * h.LeftSideBearing) return h } // unscaledVMetric returns the unscaled vertical metrics for the glyph with // the given index. yMax is the top of the glyph's bounding box. func (f *Font) unscaledVMetric(i Index, yMax fixed.Int26_6) (v VMetric) { j := int(i) if j < 0 || f.nGlyph <= j { return VMetric{} } if 4*j+4 <= len(f.vmtx) { return VMetric{ AdvanceHeight: fixed.Int26_6(u16(f.vmtx, 4*j)), TopSideBearing: fixed.Int26_6(int16(u16(f.vmtx, 4*j+2))), } } // The OS/2 table has grown over time. // https://developer.apple.com/fonts/TTRefMan/RM06/Chap6OS2.html // says that it was originally 68 bytes. Optional fields, including // the ascender and descender, are described at // http://www.microsoft.com/typography/otspec/os2.htm if len(f.os2) >= 72 { sTypoAscender := fixed.Int26_6(int16(u16(f.os2, 68))) sTypoDescender := fixed.Int26_6(int16(u16(f.os2, 70))) return VMetric{ AdvanceHeight: sTypoAscender - sTypoDescender, TopSideBearing: sTypoAscender - yMax, } } return VMetric{ AdvanceHeight: fixed.Int26_6(f.fUnitsPerEm), TopSideBearing: 0, } } // VMetric returns the vertical metrics for the glyph with the given index. func (f *Font) VMetric(scale fixed.Int26_6, i Index) VMetric { // TODO: should 0 be bounds.YMax? v := f.unscaledVMetric(i, 0) v.AdvanceHeight = f.scale(scale * v.AdvanceHeight) v.TopSideBearing = f.scale(scale * v.TopSideBearing) return v } // Kern returns the horizontal adjustment for the given glyph pair. A positive // kern means to move the glyphs further apart. func (f *Font) Kern(scale fixed.Int26_6, i0, i1 Index) fixed.Int26_6 { if f.nKern == 0 { return 0 } g := uint32(i0)<<16 | uint32(i1) lo, hi := 0, f.nKern for lo < hi { i := (lo + hi) / 2 ig := u32(f.kern, 18+6*i) if ig < g { lo = i + 1 } else if ig > g { hi = i } else { return f.scale(scale * fixed.Int26_6(int16(u16(f.kern, 22+6*i)))) } } return 0 } // Parse returns a new Font for the given TTF or TTC data. // // For TrueType Collections, the first font in the collection is parsed. func Parse(ttf []byte) (font *Font, err error) { return parse(ttf, 0) } func parse(ttf []byte, offset int) (font *Font, err error) { if len(ttf)-offset < 12 { err = FormatError("TTF data is too short") return } originalOffset := offset magic, offset := u32(ttf, offset), offset+4 switch magic { case 0x00010000: // No-op. case 0x74746366: // "ttcf" as a big-endian uint32. if originalOffset != 0 { err = FormatError("recursive TTC") return } ttcVersion, offset := u32(ttf, offset), offset+4 if ttcVersion != 0x00010000 && ttcVersion != 0x00020000 { err = FormatError("bad TTC version") return } numFonts, offset := int(u32(ttf, offset)), offset+4 if numFonts <= 0 { err = FormatError("bad number of TTC fonts") return } if len(ttf[offset:])/4 < numFonts { err = FormatError("TTC offset table is too short") return } // TODO: provide an API to select which font in a TrueType collection to return, // not just the first one. This may require an API to parse a TTC's name tables, // so users of this package can select the font in a TTC by name. offset = int(u32(ttf, offset)) if offset <= 0 || offset > len(ttf) { err = FormatError("bad TTC offset") return } return parse(ttf, offset) default: err = FormatError("bad TTF version") return } n, offset := int(u16(ttf, offset)), offset+2 offset += 6 // Skip the searchRange, entrySelector and rangeShift. if len(ttf) < 16*n+offset { err = FormatError("TTF data is too short") return } f := new(Font) // Assign the table slices. for i := 0; i < n; i++ { x := 16*i + offset switch string(ttf[x : x+4]) { case "cmap": f.cmap, err = readTable(ttf, ttf[x+8:x+16]) case "cvt ": f.cvt, err = readTable(ttf, ttf[x+8:x+16]) case "fpgm": f.fpgm, err = readTable(ttf, ttf[x+8:x+16]) case "glyf": f.glyf, err = readTable(ttf, ttf[x+8:x+16]) case "hdmx": f.hdmx, err = readTable(ttf, ttf[x+8:x+16]) case "head": f.head, err = readTable(ttf, ttf[x+8:x+16]) case "hhea": f.hhea, err = readTable(ttf, ttf[x+8:x+16]) case "hmtx": f.hmtx, err = readTable(ttf, ttf[x+8:x+16]) case "kern": f.kern, err = readTable(ttf, ttf[x+8:x+16]) case "loca": f.loca, err = readTable(ttf, ttf[x+8:x+16]) case "maxp": f.maxp, err = readTable(ttf, ttf[x+8:x+16]) case "name": f.name, err = readTable(ttf, ttf[x+8:x+16]) case "OS/2": f.os2, err = readTable(ttf, ttf[x+8:x+16]) case "prep": f.prep, err = readTable(ttf, ttf[x+8:x+16]) case "vmtx": f.vmtx, err = readTable(ttf, ttf[x+8:x+16]) } if err != nil { return } } // Parse and sanity-check the TTF data. if err = f.parseHead(); err != nil { return } if err = f.parseMaxp(); err != nil { return } if err = f.parseCmap(); err != nil { return } if err = f.parseKern(); err != nil { return } if err = f.parseHhea(); err != nil { return } font = f return } ================================================ FILE: vendor/github.com/golang/protobuf/AUTHORS ================================================ # This source code refers to The Go Authors for copyright purposes. # The master list of authors is in the main Go distribution, # visible at http://tip.golang.org/AUTHORS. ================================================ FILE: vendor/github.com/golang/protobuf/CONTRIBUTORS ================================================ # This source code was written by the Go contributors. # The master list of contributors is in the main Go distribution, # visible at http://tip.golang.org/CONTRIBUTORS. ================================================ FILE: vendor/github.com/golang/protobuf/LICENSE ================================================ Copyright 2010 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. ================================================ FILE: vendor/github.com/golang/protobuf/proto/clone.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2011 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Protocol buffer deep copy and merge. // TODO: RawMessage. package proto import ( "fmt" "log" "reflect" "strings" ) // Clone returns a deep copy of a protocol buffer. func Clone(src Message) Message { in := reflect.ValueOf(src) if in.IsNil() { return src } out := reflect.New(in.Type().Elem()) dst := out.Interface().(Message) Merge(dst, src) return dst } // Merger is the interface representing objects that can merge messages of the same type. type Merger interface { // Merge merges src into this message. // Required and optional fields that are set in src will be set to that value in dst. // Elements of repeated fields will be appended. // // Merge may panic if called with a different argument type than the receiver. Merge(src Message) } // generatedMerger is the custom merge method that generated protos will have. // We must add this method since a generate Merge method will conflict with // many existing protos that have a Merge data field already defined. type generatedMerger interface { XXX_Merge(src Message) } // Merge merges src into dst. // Required and optional fields that are set in src will be set to that value in dst. // Elements of repeated fields will be appended. // Merge panics if src and dst are not the same type, or if dst is nil. func Merge(dst, src Message) { if m, ok := dst.(Merger); ok { m.Merge(src) return } in := reflect.ValueOf(src) out := reflect.ValueOf(dst) if out.IsNil() { panic("proto: nil destination") } if in.Type() != out.Type() { panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", dst, src)) } if in.IsNil() { return // Merge from nil src is a noop } if m, ok := dst.(generatedMerger); ok { m.XXX_Merge(src) return } mergeStruct(out.Elem(), in.Elem()) } func mergeStruct(out, in reflect.Value) { sprop := GetProperties(in.Type()) for i := 0; i < in.NumField(); i++ { f := in.Type().Field(i) if strings.HasPrefix(f.Name, "XXX_") { continue } mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) } if emIn, err := extendable(in.Addr().Interface()); err == nil { emOut, _ := extendable(out.Addr().Interface()) mIn, muIn := emIn.extensionsRead() if mIn != nil { mOut := emOut.extensionsWrite() muIn.Lock() mergeExtension(mOut, mIn) muIn.Unlock() } } uf := in.FieldByName("XXX_unrecognized") if !uf.IsValid() { return } uin := uf.Bytes() if len(uin) > 0 { out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) } } // mergeAny performs a merge between two values of the same type. // viaPtr indicates whether the values were indirected through a pointer (implying proto2). // prop is set if this is a struct field (it may be nil). func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { if in.Type() == protoMessageType { if !in.IsNil() { if out.IsNil() { out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) } else { Merge(out.Interface().(Message), in.Interface().(Message)) } } return } switch in.Kind() { case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64: if !viaPtr && isProto3Zero(in) { return } out.Set(in) case reflect.Interface: // Probably a oneof field; copy non-nil values. if in.IsNil() { return } // Allocate destination if it is not set, or set to a different type. // Otherwise we will merge as normal. if out.IsNil() || out.Elem().Type() != in.Elem().Type() { out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T) } mergeAny(out.Elem(), in.Elem(), false, nil) case reflect.Map: if in.Len() == 0 { return } if out.IsNil() { out.Set(reflect.MakeMap(in.Type())) } // For maps with value types of *T or []byte we need to deep copy each value. elemKind := in.Type().Elem().Kind() for _, key := range in.MapKeys() { var val reflect.Value switch elemKind { case reflect.Ptr: val = reflect.New(in.Type().Elem().Elem()) mergeAny(val, in.MapIndex(key), false, nil) case reflect.Slice: val = in.MapIndex(key) val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) default: val = in.MapIndex(key) } out.SetMapIndex(key, val) } case reflect.Ptr: if in.IsNil() { return } if out.IsNil() { out.Set(reflect.New(in.Elem().Type())) } mergeAny(out.Elem(), in.Elem(), true, nil) case reflect.Slice: if in.IsNil() { return } if in.Type().Elem().Kind() == reflect.Uint8 { // []byte is a scalar bytes field, not a repeated field. // Edge case: if this is in a proto3 message, a zero length // bytes field is considered the zero value, and should not // be merged. if prop != nil && prop.proto3 && in.Len() == 0 { return } // Make a deep copy. // Append to []byte{} instead of []byte(nil) so that we never end up // with a nil result. out.SetBytes(append([]byte{}, in.Bytes()...)) return } n := in.Len() if out.IsNil() { out.Set(reflect.MakeSlice(in.Type(), 0, n)) } switch in.Type().Elem().Kind() { case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64: out.Set(reflect.AppendSlice(out, in)) default: for i := 0; i < n; i++ { x := reflect.Indirect(reflect.New(in.Type().Elem())) mergeAny(x, in.Index(i), false, nil) out.Set(reflect.Append(out, x)) } } case reflect.Struct: mergeStruct(out, in) default: // unknown type, so not a protocol buffer log.Printf("proto: don't know how to copy %v", in) } } func mergeExtension(out, in map[int32]Extension) { for extNum, eIn := range in { eOut := Extension{desc: eIn.desc} if eIn.value != nil { v := reflect.New(reflect.TypeOf(eIn.value)).Elem() mergeAny(v, reflect.ValueOf(eIn.value), false, nil) eOut.value = v.Interface() } if eIn.enc != nil { eOut.enc = make([]byte, len(eIn.enc)) copy(eOut.enc, eIn.enc) } out[extNum] = eOut } } ================================================ FILE: vendor/github.com/golang/protobuf/proto/decode.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package proto /* * Routines for decoding protocol buffer data to construct in-memory representations. */ import ( "errors" "fmt" "io" ) // errOverflow is returned when an integer is too large to be represented. var errOverflow = errors.New("proto: integer overflow") // ErrInternalBadWireType is returned by generated code when an incorrect // wire type is encountered. It does not get returned to user code. var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") // DecodeVarint reads a varint-encoded integer from the slice. // It returns the integer and the number of bytes consumed, or // zero if there is not enough. // This is the format for the // int32, int64, uint32, uint64, bool, and enum // protocol buffer types. func DecodeVarint(buf []byte) (x uint64, n int) { for shift := uint(0); shift < 64; shift += 7 { if n >= len(buf) { return 0, 0 } b := uint64(buf[n]) n++ x |= (b & 0x7F) << shift if (b & 0x80) == 0 { return x, n } } // The number is too large to represent in a 64-bit value. return 0, 0 } func (p *Buffer) decodeVarintSlow() (x uint64, err error) { i := p.index l := len(p.buf) for shift := uint(0); shift < 64; shift += 7 { if i >= l { err = io.ErrUnexpectedEOF return } b := p.buf[i] i++ x |= (uint64(b) & 0x7F) << shift if b < 0x80 { p.index = i return } } // The number is too large to represent in a 64-bit value. err = errOverflow return } // DecodeVarint reads a varint-encoded integer from the Buffer. // This is the format for the // int32, int64, uint32, uint64, bool, and enum // protocol buffer types. func (p *Buffer) DecodeVarint() (x uint64, err error) { i := p.index buf := p.buf if i >= len(buf) { return 0, io.ErrUnexpectedEOF } else if buf[i] < 0x80 { p.index++ return uint64(buf[i]), nil } else if len(buf)-i < 10 { return p.decodeVarintSlow() } var b uint64 // we already checked the first byte x = uint64(buf[i]) - 0x80 i++ b = uint64(buf[i]) i++ x += b << 7 if b&0x80 == 0 { goto done } x -= 0x80 << 7 b = uint64(buf[i]) i++ x += b << 14 if b&0x80 == 0 { goto done } x -= 0x80 << 14 b = uint64(buf[i]) i++ x += b << 21 if b&0x80 == 0 { goto done } x -= 0x80 << 21 b = uint64(buf[i]) i++ x += b << 28 if b&0x80 == 0 { goto done } x -= 0x80 << 28 b = uint64(buf[i]) i++ x += b << 35 if b&0x80 == 0 { goto done } x -= 0x80 << 35 b = uint64(buf[i]) i++ x += b << 42 if b&0x80 == 0 { goto done } x -= 0x80 << 42 b = uint64(buf[i]) i++ x += b << 49 if b&0x80 == 0 { goto done } x -= 0x80 << 49 b = uint64(buf[i]) i++ x += b << 56 if b&0x80 == 0 { goto done } x -= 0x80 << 56 b = uint64(buf[i]) i++ x += b << 63 if b&0x80 == 0 { goto done } return 0, errOverflow done: p.index = i return x, nil } // DecodeFixed64 reads a 64-bit integer from the Buffer. // This is the format for the // fixed64, sfixed64, and double protocol buffer types. func (p *Buffer) DecodeFixed64() (x uint64, err error) { // x, err already 0 i := p.index + 8 if i < 0 || i > len(p.buf) { err = io.ErrUnexpectedEOF return } p.index = i x = uint64(p.buf[i-8]) x |= uint64(p.buf[i-7]) << 8 x |= uint64(p.buf[i-6]) << 16 x |= uint64(p.buf[i-5]) << 24 x |= uint64(p.buf[i-4]) << 32 x |= uint64(p.buf[i-3]) << 40 x |= uint64(p.buf[i-2]) << 48 x |= uint64(p.buf[i-1]) << 56 return } // DecodeFixed32 reads a 32-bit integer from the Buffer. // This is the format for the // fixed32, sfixed32, and float protocol buffer types. func (p *Buffer) DecodeFixed32() (x uint64, err error) { // x, err already 0 i := p.index + 4 if i < 0 || i > len(p.buf) { err = io.ErrUnexpectedEOF return } p.index = i x = uint64(p.buf[i-4]) x |= uint64(p.buf[i-3]) << 8 x |= uint64(p.buf[i-2]) << 16 x |= uint64(p.buf[i-1]) << 24 return } // DecodeZigzag64 reads a zigzag-encoded 64-bit integer // from the Buffer. // This is the format used for the sint64 protocol buffer type. func (p *Buffer) DecodeZigzag64() (x uint64, err error) { x, err = p.DecodeVarint() if err != nil { return } x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) return } // DecodeZigzag32 reads a zigzag-encoded 32-bit integer // from the Buffer. // This is the format used for the sint32 protocol buffer type. func (p *Buffer) DecodeZigzag32() (x uint64, err error) { x, err = p.DecodeVarint() if err != nil { return } x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) return } // DecodeRawBytes reads a count-delimited byte buffer from the Buffer. // This is the format used for the bytes protocol buffer // type and for embedded messages. func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { n, err := p.DecodeVarint() if err != nil { return nil, err } nb := int(n) if nb < 0 { return nil, fmt.Errorf("proto: bad byte length %d", nb) } end := p.index + nb if end < p.index || end > len(p.buf) { return nil, io.ErrUnexpectedEOF } if !alloc { // todo: check if can get more uses of alloc=false buf = p.buf[p.index:end] p.index += nb return } buf = make([]byte, nb) copy(buf, p.buf[p.index:]) p.index += nb return } // DecodeStringBytes reads an encoded string from the Buffer. // This is the format used for the proto2 string type. func (p *Buffer) DecodeStringBytes() (s string, err error) { buf, err := p.DecodeRawBytes(false) if err != nil { return } return string(buf), nil } // Unmarshaler is the interface representing objects that can // unmarshal themselves. The argument points to data that may be // overwritten, so implementations should not keep references to the // buffer. // Unmarshal implementations should not clear the receiver. // Any unmarshaled data should be merged into the receiver. // Callers of Unmarshal that do not want to retain existing data // should Reset the receiver before calling Unmarshal. type Unmarshaler interface { Unmarshal([]byte) error } // newUnmarshaler is the interface representing objects that can // unmarshal themselves. The semantics are identical to Unmarshaler. // // This exists to support protoc-gen-go generated messages. // The proto package will stop type-asserting to this interface in the future. // // DO NOT DEPEND ON THIS. type newUnmarshaler interface { XXX_Unmarshal([]byte) error } // Unmarshal parses the protocol buffer representation in buf and places the // decoded result in pb. If the struct underlying pb does not match // the data in buf, the results can be unpredictable. // // Unmarshal resets pb before starting to unmarshal, so any // existing data in pb is always removed. Use UnmarshalMerge // to preserve and append to existing data. func Unmarshal(buf []byte, pb Message) error { pb.Reset() if u, ok := pb.(newUnmarshaler); ok { return u.XXX_Unmarshal(buf) } if u, ok := pb.(Unmarshaler); ok { return u.Unmarshal(buf) } return NewBuffer(buf).Unmarshal(pb) } // UnmarshalMerge parses the protocol buffer representation in buf and // writes the decoded result to pb. If the struct underlying pb does not match // the data in buf, the results can be unpredictable. // // UnmarshalMerge merges into existing data in pb. // Most code should use Unmarshal instead. func UnmarshalMerge(buf []byte, pb Message) error { if u, ok := pb.(newUnmarshaler); ok { return u.XXX_Unmarshal(buf) } if u, ok := pb.(Unmarshaler); ok { // NOTE: The history of proto have unfortunately been inconsistent // whether Unmarshaler should or should not implicitly clear itself. // Some implementations do, most do not. // Thus, calling this here may or may not do what people want. // // See https://github.com/golang/protobuf/issues/424 return u.Unmarshal(buf) } return NewBuffer(buf).Unmarshal(pb) } // DecodeMessage reads a count-delimited message from the Buffer. func (p *Buffer) DecodeMessage(pb Message) error { enc, err := p.DecodeRawBytes(false) if err != nil { return err } return NewBuffer(enc).Unmarshal(pb) } // DecodeGroup reads a tag-delimited group from the Buffer. // StartGroup tag is already consumed. This function consumes // EndGroup tag. func (p *Buffer) DecodeGroup(pb Message) error { b := p.buf[p.index:] x, y := findEndGroup(b) if x < 0 { return io.ErrUnexpectedEOF } err := Unmarshal(b[:x], pb) p.index += y return err } // Unmarshal parses the protocol buffer representation in the // Buffer and places the decoded result in pb. If the struct // underlying pb does not match the data in the buffer, the results can be // unpredictable. // // Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal. func (p *Buffer) Unmarshal(pb Message) error { // If the object can unmarshal itself, let it. if u, ok := pb.(newUnmarshaler); ok { err := u.XXX_Unmarshal(p.buf[p.index:]) p.index = len(p.buf) return err } if u, ok := pb.(Unmarshaler); ok { // NOTE: The history of proto have unfortunately been inconsistent // whether Unmarshaler should or should not implicitly clear itself. // Some implementations do, most do not. // Thus, calling this here may or may not do what people want. // // See https://github.com/golang/protobuf/issues/424 err := u.Unmarshal(p.buf[p.index:]) p.index = len(p.buf) return err } // Slow workaround for messages that aren't Unmarshalers. // This includes some hand-coded .pb.go files and // bootstrap protos. // TODO: fix all of those and then add Unmarshal to // the Message interface. Then: // The cast above and code below can be deleted. // The old unmarshaler can be deleted. // Clients can call Unmarshal directly (can already do that, actually). var info InternalMessageInfo err := info.Unmarshal(pb, p.buf[p.index:]) p.index = len(p.buf) return err } ================================================ FILE: vendor/github.com/golang/protobuf/proto/deprecated.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2018 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" // Deprecated: do not use. type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 } // Deprecated: do not use. func GetStats() Stats { return Stats{} } // Deprecated: do not use. func MarshalMessageSet(interface{}) ([]byte, error) { return nil, errors.New("proto: not implemented") } // Deprecated: do not use. func UnmarshalMessageSet([]byte, interface{}) error { return errors.New("proto: not implemented") } // Deprecated: do not use. func MarshalMessageSetJSON(interface{}) ([]byte, error) { return nil, errors.New("proto: not implemented") } // Deprecated: do not use. func UnmarshalMessageSetJSON([]byte, interface{}) error { return errors.New("proto: not implemented") } // Deprecated: do not use. func RegisterMessageSetType(Message, int32, string) {} ================================================ FILE: vendor/github.com/golang/protobuf/proto/discard.go ================================================ // 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) } } } } ================================================ FILE: vendor/github.com/golang/protobuf/proto/encode.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package proto /* * Routines for encoding data into the wire format for protocol buffers. */ import ( "errors" "reflect" ) var ( // errRepeatedHasNil is the error returned if Marshal is called with // a struct with a repeated field containing a nil element. errRepeatedHasNil = errors.New("proto: repeated field has nil element") // errOneofHasNil is the error returned if Marshal is called with // a struct with a oneof field containing a nil element. errOneofHasNil = errors.New("proto: oneof field has nil value") // ErrNil is the error returned if Marshal is called with nil. ErrNil = errors.New("proto: Marshal called with nil") // ErrTooLarge is the error returned if Marshal is called with a // message that encodes to >2GB. ErrTooLarge = errors.New("proto: message encodes to over 2 GB") ) // The fundamental encoders that put bytes on the wire. // Those that take integer types all accept uint64 and are // therefore of type valueEncoder. const maxVarintBytes = 10 // maximum length of a varint // EncodeVarint returns the varint encoding of x. // This is the format for the // int32, int64, uint32, uint64, bool, and enum // protocol buffer types. // Not used by the package itself, but helpful to clients // wishing to use the same encoding. func EncodeVarint(x uint64) []byte { var buf [maxVarintBytes]byte var n int for n = 0; x > 127; n++ { buf[n] = 0x80 | uint8(x&0x7F) x >>= 7 } buf[n] = uint8(x) n++ return buf[0:n] } // EncodeVarint writes a varint-encoded integer to the Buffer. // This is the format for the // int32, int64, uint32, uint64, bool, and enum // protocol buffer types. func (p *Buffer) EncodeVarint(x uint64) error { for x >= 1<<7 { p.buf = append(p.buf, uint8(x&0x7f|0x80)) x >>= 7 } p.buf = append(p.buf, uint8(x)) return nil } // SizeVarint returns the varint encoding size of an integer. func SizeVarint(x uint64) int { switch { case x < 1<<7: return 1 case x < 1<<14: return 2 case x < 1<<21: return 3 case x < 1<<28: return 4 case x < 1<<35: return 5 case x < 1<<42: return 6 case x < 1<<49: return 7 case x < 1<<56: return 8 case x < 1<<63: return 9 } return 10 } // EncodeFixed64 writes a 64-bit integer to the Buffer. // This is the format for the // fixed64, sfixed64, and double protocol buffer types. func (p *Buffer) EncodeFixed64(x uint64) error { p.buf = append(p.buf, uint8(x), uint8(x>>8), uint8(x>>16), uint8(x>>24), uint8(x>>32), uint8(x>>40), uint8(x>>48), uint8(x>>56)) return nil } // EncodeFixed32 writes a 32-bit integer to the Buffer. // This is the format for the // fixed32, sfixed32, and float protocol buffer types. func (p *Buffer) EncodeFixed32(x uint64) error { p.buf = append(p.buf, uint8(x), uint8(x>>8), uint8(x>>16), uint8(x>>24)) return nil } // EncodeZigzag64 writes a zigzag-encoded 64-bit integer // to the Buffer. // This is the format used for the sint64 protocol buffer type. func (p *Buffer) EncodeZigzag64(x uint64) error { // use signed number to get arithmetic right shift. return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } // EncodeZigzag32 writes a zigzag-encoded 32-bit integer // to the Buffer. // This is the format used for the sint32 protocol buffer type. func (p *Buffer) EncodeZigzag32(x uint64) error { // use signed number to get arithmetic right shift. return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) } // EncodeRawBytes writes a count-delimited byte buffer to the Buffer. // This is the format used for the bytes protocol buffer // type and for embedded messages. func (p *Buffer) EncodeRawBytes(b []byte) error { p.EncodeVarint(uint64(len(b))) p.buf = append(p.buf, b...) return nil } // EncodeStringBytes writes an encoded string to the Buffer. // This is the format used for the proto2 string type. func (p *Buffer) EncodeStringBytes(s string) error { p.EncodeVarint(uint64(len(s))) p.buf = append(p.buf, s...) return nil } // Marshaler is the interface representing objects that can marshal themselves. type Marshaler interface { Marshal() ([]byte, error) } // EncodeMessage writes the protocol buffer to the Buffer, // prefixed by a varint-encoded length. func (p *Buffer) EncodeMessage(pb Message) error { siz := Size(pb) p.EncodeVarint(uint64(siz)) return p.Marshal(pb) } // All protocol buffer fields are nillable, but be careful. func isNil(v reflect.Value) bool { switch v.Kind() { case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: return v.IsNil() } return false } ================================================ FILE: vendor/github.com/golang/protobuf/proto/equal.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2011 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Protocol buffer comparison. package proto import ( "bytes" "log" "reflect" "strings" ) /* Equal returns true iff protocol buffers a and b are equal. The arguments must both be pointers to protocol buffer structs. Equality is defined in this way: - Two messages are equal iff they are the same type, corresponding fields are equal, unknown field sets are equal, and extensions sets are equal. - Two set scalar fields are equal iff their values are equal. If the fields are of a floating-point type, remember that NaN != x for all x, including NaN. If the message is defined in a proto3 .proto file, fields are not "set"; specifically, zero length proto3 "bytes" fields are equal (nil == {}). - Two repeated fields are equal iff their lengths are the same, and their corresponding elements are equal. Note a "bytes" field, although represented by []byte, is not a repeated field and the rule for the scalar fields described above applies. - Two unset fields are equal. - Two unknown field sets are equal if their current encoded state is equal. - Two extension sets are equal iff they have corresponding elements that are pairwise equal. - Two map fields are equal iff their lengths are the same, and they contain the same set of elements. Zero-length map fields are equal. - Every other combination of things are not equal. The return value is undefined if a and b are not protocol buffers. */ func Equal(a, b Message) bool { if a == nil || b == nil { return a == b } v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b) if v1.Type() != v2.Type() { return false } if v1.Kind() == reflect.Ptr { if v1.IsNil() { return v2.IsNil() } if v2.IsNil() { return false } v1, v2 = v1.Elem(), v2.Elem() } if v1.Kind() != reflect.Struct { return false } return equalStruct(v1, v2) } // v1 and v2 are known to have the same type. func equalStruct(v1, v2 reflect.Value) bool { sprop := GetProperties(v1.Type()) for i := 0; i < v1.NumField(); i++ { f := v1.Type().Field(i) if strings.HasPrefix(f.Name, "XXX_") { continue } f1, f2 := v1.Field(i), v2.Field(i) if f.Type.Kind() == reflect.Ptr { if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 { // both unset continue } else if n1 != n2 { // set/unset mismatch return false } f1, f2 = f1.Elem(), f2.Elem() } if !equalAny(f1, f2, sprop.Prop[i]) { return false } } if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() { em2 := v2.FieldByName("XXX_InternalExtensions") if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) { return false } } if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { em2 := v2.FieldByName("XXX_extensions") if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { return false } } uf := v1.FieldByName("XXX_unrecognized") if !uf.IsValid() { return true } u1 := uf.Bytes() u2 := v2.FieldByName("XXX_unrecognized").Bytes() return bytes.Equal(u1, u2) } // v1 and v2 are known to have the same type. // prop may be nil. func equalAny(v1, v2 reflect.Value, prop *Properties) bool { if v1.Type() == protoMessageType { m1, _ := v1.Interface().(Message) m2, _ := v2.Interface().(Message) return Equal(m1, m2) } switch v1.Kind() { case reflect.Bool: return v1.Bool() == v2.Bool() case reflect.Float32, reflect.Float64: return v1.Float() == v2.Float() case reflect.Int32, reflect.Int64: return v1.Int() == v2.Int() case reflect.Interface: // Probably a oneof field; compare the inner values. n1, n2 := v1.IsNil(), v2.IsNil() if n1 || n2 { return n1 == n2 } e1, e2 := v1.Elem(), v2.Elem() if e1.Type() != e2.Type() { return false } return equalAny(e1, e2, nil) case reflect.Map: if v1.Len() != v2.Len() { return false } for _, key := range v1.MapKeys() { val2 := v2.MapIndex(key) if !val2.IsValid() { // This key was not found in the second map. return false } if !equalAny(v1.MapIndex(key), val2, nil) { return false } } return true case reflect.Ptr: // Maps may have nil values in them, so check for nil. if v1.IsNil() && v2.IsNil() { return true } if v1.IsNil() != v2.IsNil() { return false } return equalAny(v1.Elem(), v2.Elem(), prop) case reflect.Slice: if v1.Type().Elem().Kind() == reflect.Uint8 { // short circuit: []byte // Edge case: if this is in a proto3 message, a zero length // bytes field is considered the zero value. if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 { return true } if v1.IsNil() != v2.IsNil() { return false } return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte)) } if v1.Len() != v2.Len() { return false } for i := 0; i < v1.Len(); i++ { if !equalAny(v1.Index(i), v2.Index(i), prop) { return false } } return true case reflect.String: return v1.Interface().(string) == v2.Interface().(string) case reflect.Struct: return equalStruct(v1, v2) case reflect.Uint32, reflect.Uint64: return v1.Uint() == v2.Uint() } // unknown type, so not a protocol buffer log.Printf("proto: don't know how to compare %v", v1) return false } // base is the struct type that the extensions are based on. // x1 and x2 are InternalExtensions. func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool { em1, _ := x1.extensionsRead() em2, _ := x2.extensionsRead() return equalExtMap(base, em1, em2) } func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { if len(em1) != len(em2) { return false } for extNum, e1 := range em1 { e2, ok := em2[extNum] if !ok { return false } m1 := extensionAsLegacyType(e1.value) m2 := extensionAsLegacyType(e2.value) if m1 == nil && m2 == nil { // Both have only encoded form. if bytes.Equal(e1.enc, e2.enc) { continue } // The bytes are different, but the extensions might still be // equal. We need to decode them to compare. } if m1 != nil && m2 != nil { // Both are unencoded. if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { return false } continue } // At least one is encoded. To do a semantically correct comparison // we need to unmarshal them first. var desc *ExtensionDesc if m := extensionMaps[base]; m != nil { desc = m[extNum] } if desc == nil { // If both have only encoded form and the bytes are the same, // it is handled above. We get here when the bytes are different. // We don't know how to decode it, so just compare them as byte // slices. log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) return false } var err error if m1 == nil { m1, err = decodeExtension(e1.enc, desc) } if m2 == nil && err == nil { m2, err = decodeExtension(e2.enc, desc) } if err != nil { // The encoded form is invalid. log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) return false } if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { return false } } return true } ================================================ FILE: vendor/github.com/golang/protobuf/proto/extensions.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package proto /* * Types and routines for supporting protocol buffer extensions. */ import ( "errors" "fmt" "io" "reflect" "strconv" "sync" ) // ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message. var ErrMissingExtension = errors.New("proto: missing extension") // ExtensionRange represents a range of message extensions for a protocol buffer. // Used in code generated by the protocol compiler. type ExtensionRange struct { Start, End int32 // both inclusive } // extendableProto is an interface implemented by any protocol buffer generated by the current // proto compiler that may be extended. type extendableProto interface { Message ExtensionRangeArray() []ExtensionRange extensionsWrite() map[int32]Extension extensionsRead() (map[int32]Extension, sync.Locker) } // extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous // version of the proto compiler that may be extended. type extendableProtoV1 interface { Message ExtensionRangeArray() []ExtensionRange ExtensionMap() map[int32]Extension } // extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto. type extensionAdapter struct { extendableProtoV1 } func (e extensionAdapter) extensionsWrite() map[int32]Extension { return e.ExtensionMap() } func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { return e.ExtensionMap(), notLocker{} } // notLocker is a sync.Locker whose Lock and Unlock methods are nops. type notLocker struct{} func (n notLocker) Lock() {} func (n notLocker) Unlock() {} // extendable returns the extendableProto interface for the given generated proto message. // If the proto message has the old extension format, it returns a wrapper that implements // the extendableProto interface. func extendable(p interface{}) (extendableProto, error) { switch p := p.(type) { case extendableProto: if isNilPtr(p) { return nil, fmt.Errorf("proto: nil %T is not extendable", p) } return p, nil case extendableProtoV1: if isNilPtr(p) { return nil, fmt.Errorf("proto: nil %T is not extendable", p) } return extensionAdapter{p}, nil } // Don't allocate a specific error containing %T: // this is the hot path for Clone and MarshalText. return nil, errNotExtendable } var errNotExtendable = errors.New("proto: not an extendable proto.Message") func isNilPtr(x interface{}) bool { v := reflect.ValueOf(x) return v.Kind() == reflect.Ptr && v.IsNil() } // XXX_InternalExtensions is an internal representation of proto extensions. // // Each generated message struct type embeds an anonymous XXX_InternalExtensions field, // thus gaining the unexported 'extensions' method, which can be called only from the proto package. // // The methods of XXX_InternalExtensions are not concurrency safe in general, // but calls to logically read-only methods such as has and get may be executed concurrently. type XXX_InternalExtensions struct { // The struct must be indirect so that if a user inadvertently copies a // generated message and its embedded XXX_InternalExtensions, they // avoid the mayhem of a copied mutex. // // The mutex serializes all logically read-only operations to p.extensionMap. // It is up to the client to ensure that write operations to p.extensionMap are // mutually exclusive with other accesses. p *struct { mu sync.Mutex extensionMap map[int32]Extension } } // extensionsWrite returns the extension map, creating it on first use. func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension { if e.p == nil { e.p = new(struct { mu sync.Mutex extensionMap map[int32]Extension }) e.p.extensionMap = make(map[int32]Extension) } return e.p.extensionMap } // extensionsRead returns the extensions map for read-only use. It may be nil. // The caller must hold the returned mutex's lock when accessing Elements within the map. func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) { if e.p == nil { return nil, nil } return e.p.extensionMap, &e.p.mu } // ExtensionDesc represents an extension specification. // Used in generated code from the protocol compiler. type ExtensionDesc struct { ExtendedType Message // nil pointer to the type that is being extended ExtensionType interface{} // nil pointer to the extension type Field int32 // field number Name string // fully-qualified name of extension, for text formatting Tag string // protobuf tag style Filename string // name of the file in which the extension is defined } func (ed *ExtensionDesc) repeated() bool { t := reflect.TypeOf(ed.ExtensionType) return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 } // Extension represents an extension in a message. type Extension struct { // When an extension is stored in a message using SetExtension // only desc and value are set. When the message is marshaled // enc will be set to the encoded form of the message. // // When a message is unmarshaled and contains extensions, each // extension will have only enc set. When such an extension is // accessed using GetExtension (or GetExtensions) desc and value // will be set. desc *ExtensionDesc // value is a concrete value for the extension field. Let the type of // desc.ExtensionType be the "API type" and the type of Extension.value // be the "storage type". The API type and storage type are the same except: // * For scalars (except []byte), the API type uses *T, // while the storage type uses T. // * For repeated fields, the API type uses []T, while the storage type // uses *[]T. // // The reason for the divergence is so that the storage type more naturally // matches what is expected of when retrieving the values through the // protobuf reflection APIs. // // The value may only be populated if desc is also populated. value interface{} // enc is the raw bytes for the extension field. enc []byte } // SetRawExtension is for testing only. func SetRawExtension(base Message, id int32, b []byte) { epb, err := extendable(base) if err != nil { return } extmap := epb.extensionsWrite() extmap[id] = Extension{enc: b} } // isExtensionField returns true iff the given field number is in an extension range. func isExtensionField(pb extendableProto, field int32) bool { for _, er := range pb.ExtensionRangeArray() { if er.Start <= field && field <= er.End { return true } } return false } // checkExtensionTypes checks that the given extension is valid for pb. func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { var pbi interface{} = pb // Check the extended type. if ea, ok := pbi.(extensionAdapter); ok { pbi = ea.extendableProtoV1 } if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { return fmt.Errorf("proto: bad extended type; %v does not extend %v", b, a) } // Check the range. if !isExtensionField(pb, extension.Field) { return errors.New("proto: bad extension number; not in declared ranges") } return nil } // extPropKey is sufficient to uniquely identify an extension. type extPropKey struct { base reflect.Type field int32 } var extProp = struct { sync.RWMutex m map[extPropKey]*Properties }{ m: make(map[extPropKey]*Properties), } func extensionProperties(ed *ExtensionDesc) *Properties { key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field} extProp.RLock() if prop, ok := extProp.m[key]; ok { extProp.RUnlock() return prop } extProp.RUnlock() extProp.Lock() defer extProp.Unlock() // Check again. if prop, ok := extProp.m[key]; ok { return prop } prop := new(Properties) prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil) extProp.m[key] = prop return prop } // HasExtension returns whether the given extension is present in pb. func HasExtension(pb Message, extension *ExtensionDesc) bool { // TODO: Check types, field numbers, etc.? epb, err := extendable(pb) if err != nil { return false } extmap, mu := epb.extensionsRead() if extmap == nil { return false } mu.Lock() _, ok := extmap[extension.Field] mu.Unlock() return ok } // ClearExtension removes the given extension from pb. func ClearExtension(pb Message, extension *ExtensionDesc) { epb, err := extendable(pb) if err != nil { return } // TODO: Check types, field numbers, etc.? extmap := epb.extensionsWrite() delete(extmap, extension.Field) } // GetExtension retrieves a proto2 extended field from pb. // // If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil), // then GetExtension parses the encoded field and returns a Go value of the specified type. // If the field is not present, then the default value is returned (if one is specified), // otherwise ErrMissingExtension is reported. // // If the descriptor is not type complete (i.e., ExtensionDesc.ExtensionType is nil), // then GetExtension returns the raw encoded bytes of the field extension. func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { epb, err := extendable(pb) if err != nil { return nil, err } if extension.ExtendedType != nil { // can only check type if this is a complete descriptor if err := checkExtensionTypes(epb, extension); err != nil { return nil, err } } emap, mu := epb.extensionsRead() if emap == nil { return defaultExtensionValue(extension) } mu.Lock() defer mu.Unlock() e, ok := emap[extension.Field] if !ok { // defaultExtensionValue returns the default value or // ErrMissingExtension if there is no default. return defaultExtensionValue(extension) } if e.value != nil { // Already decoded. Check the descriptor, though. if e.desc != extension { // This shouldn't happen. If it does, it means that // GetExtension was called twice with two different // descriptors with the same field number. return nil, errors.New("proto: descriptor conflict") } return extensionAsLegacyType(e.value), nil } if extension.ExtensionType == nil { // incomplete descriptor return e.enc, nil } v, err := decodeExtension(e.enc, extension) if err != nil { return nil, err } // Remember the decoded version and drop the encoded version. // That way it is safe to mutate what we return. e.value = extensionAsStorageType(v) e.desc = extension e.enc = nil emap[extension.Field] = e return extensionAsLegacyType(e.value), nil } // defaultExtensionValue returns the default value for extension. // If no default for an extension is defined ErrMissingExtension is returned. func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { if extension.ExtensionType == nil { // incomplete descriptor, so no default return nil, ErrMissingExtension } t := reflect.TypeOf(extension.ExtensionType) props := extensionProperties(extension) sf, _, err := fieldDefault(t, props) if err != nil { return nil, err } if sf == nil || sf.value == nil { // There is no default value. return nil, ErrMissingExtension } if t.Kind() != reflect.Ptr { // We do not need to return a Ptr, we can directly return sf.value. return sf.value, nil } // We need to return an interface{} that is a pointer to sf.value. value := reflect.New(t).Elem() value.Set(reflect.New(value.Type().Elem())) if sf.kind == reflect.Int32 { // We may have an int32 or an enum, but the underlying data is int32. // Since we can't set an int32 into a non int32 reflect.value directly // set it as a int32. value.Elem().SetInt(int64(sf.value.(int32))) } else { value.Elem().Set(reflect.ValueOf(sf.value)) } return value.Interface(), nil } // decodeExtension decodes an extension encoded in b. func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { t := reflect.TypeOf(extension.ExtensionType) unmarshal := typeUnmarshaler(t, extension.Tag) // t is a pointer to a struct, pointer to basic type or a slice. // Allocate space to store the pointer/slice. value := reflect.New(t).Elem() var err error for { x, n := decodeVarint(b) if n == 0 { return nil, io.ErrUnexpectedEOF } b = b[n:] wire := int(x) & 7 b, err = unmarshal(b, valToPointer(value.Addr()), wire) if err != nil { return nil, err } if len(b) == 0 { break } } return value.Interface(), nil } // GetExtensions returns a slice of the extensions present in pb that are also listed in es. // The returned slice has the same length as es; missing extensions will appear as nil elements. func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { epb, err := extendable(pb) if err != nil { return nil, err } extensions = make([]interface{}, len(es)) for i, e := range es { extensions[i], err = GetExtension(epb, e) if err == ErrMissingExtension { err = nil } if err != nil { return } } return } // ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order. // For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing // just the Field field, which defines the extension's field number. func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { epb, err := extendable(pb) if err != nil { return nil, err } registeredExtensions := RegisteredExtensions(pb) emap, mu := epb.extensionsRead() if emap == nil { return nil, nil } mu.Lock() defer mu.Unlock() extensions := make([]*ExtensionDesc, 0, len(emap)) for extid, e := range emap { desc := e.desc if desc == nil { desc = registeredExtensions[extid] if desc == nil { desc = &ExtensionDesc{Field: extid} } } extensions = append(extensions, desc) } return extensions, nil } // SetExtension sets the specified extension of pb to the specified value. func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { epb, err := extendable(pb) if err != nil { return err } if err := checkExtensionTypes(epb, extension); err != nil { return err } typ := reflect.TypeOf(extension.ExtensionType) if typ != reflect.TypeOf(value) { return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", value, extension.ExtensionType) } // nil extension values need to be caught early, because the // encoder can't distinguish an ErrNil due to a nil extension // from an ErrNil due to a missing field. Extensions are // always optional, so the encoder would just swallow the error // and drop all the extensions from the encoded message. if reflect.ValueOf(value).IsNil() { return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) } extmap := epb.extensionsWrite() extmap[extension.Field] = Extension{desc: extension, value: extensionAsStorageType(value)} return nil } // ClearAllExtensions clears all extensions from pb. func ClearAllExtensions(pb Message) { epb, err := extendable(pb) if err != nil { return } m := epb.extensionsWrite() for k := range m { delete(m, k) } } // A global registry of extensions. // The generated code will register the generated descriptors by calling RegisterExtension. var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) // RegisterExtension is called from the generated code. func RegisterExtension(desc *ExtensionDesc) { st := reflect.TypeOf(desc.ExtendedType).Elem() m := extensionMaps[st] if m == nil { m = make(map[int32]*ExtensionDesc) extensionMaps[st] = m } if _, ok := m[desc.Field]; ok { panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) } m[desc.Field] = desc } // RegisteredExtensions returns a map of the registered extensions of a // protocol buffer struct, indexed by the extension number. // The argument pb should be a nil pointer to the struct type. func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { return extensionMaps[reflect.TypeOf(pb).Elem()] } // extensionAsLegacyType converts an value in the storage type as the API type. // See Extension.value. func extensionAsLegacyType(v interface{}) interface{} { switch rv := reflect.ValueOf(v); rv.Kind() { case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String: // Represent primitive types as a pointer to the value. rv2 := reflect.New(rv.Type()) rv2.Elem().Set(rv) v = rv2.Interface() case reflect.Ptr: // Represent slice types as the value itself. switch rv.Type().Elem().Kind() { case reflect.Slice: if rv.IsNil() { v = reflect.Zero(rv.Type().Elem()).Interface() } else { v = rv.Elem().Interface() } } } return v } // extensionAsStorageType converts an value in the API type as the storage type. // See Extension.value. func extensionAsStorageType(v interface{}) interface{} { switch rv := reflect.ValueOf(v); rv.Kind() { case reflect.Ptr: // Represent slice types as the value itself. switch rv.Type().Elem().Kind() { case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String: if rv.IsNil() { v = reflect.Zero(rv.Type().Elem()).Interface() } else { v = rv.Elem().Interface() } } case reflect.Slice: // Represent slice types as a pointer to the value. if rv.Type().Elem().Kind() != reflect.Uint8 { rv2 := reflect.New(rv.Type()) rv2.Elem().Set(rv) v = rv2.Interface() } } return v } ================================================ FILE: vendor/github.com/golang/protobuf/proto/lib.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* Package proto converts data structures to and from the wire format of protocol buffers. It works in concert with the Go source code generated for .proto files by the protocol compiler. A summary of the properties of the protocol buffer interface for a protocol buffer variable v: - Names are turned from camel_case to CamelCase for export. - There are no methods on v to set fields; just treat them as structure fields. - There are getters that return a field's value if set, and return the field's default value if unset. The getters work even if the receiver is a nil message. - The zero value for a struct is its correct initialization state. All desired fields must be set before marshaling. - A Reset() method will restore a protobuf struct to its zero state. - Non-repeated fields are pointers to the values; nil means unset. That is, optional or required field int32 f becomes F *int32. - Repeated fields are slices. - Helper functions are available to aid the setting of fields. msg.Foo = proto.String("hello") // set field - Constants are defined to hold the default values of all fields that have them. They have the form Default_StructName_FieldName. Because the getter methods handle defaulted values, direct use of these constants should be rare. - Enums are given type names and maps from names to values. Enum values are prefixed by the enclosing message's name, or by the enum's type name if it is a top-level enum. Enum types have a String method, and a Enum method to assist in message construction. - Nested messages, groups and enums have type names prefixed with the name of the surrounding message type. - Extensions are given descriptor names that start with E_, followed by an underscore-delimited list of the nested messages that contain it (if any) followed by the CamelCased name of the extension field itself. HasExtension, ClearExtension, GetExtension and SetExtension are functions for manipulating extensions. - Oneof field sets are given a single field in their message, with distinguished wrapper types for each possible field value. - Marshal and Unmarshal are functions to encode and decode the wire format. When the .proto file specifies `syntax="proto3"`, there are some differences: - Non-repeated fields of non-message type are values instead of pointers. - Enum types do not get an Enum method. The simplest way to describe this is to see an example. Given file test.proto, containing package example; enum FOO { X = 17; } message Test { required string label = 1; optional int32 type = 2 [default=77]; repeated int64 reps = 3; optional group OptionalGroup = 4 { required string RequiredField = 5; } oneof union { int32 number = 6; string name = 7; } } The resulting file, test.pb.go, is: package example import proto "github.com/golang/protobuf/proto" import math "math" type FOO int32 const ( FOO_X FOO = 17 ) var FOO_name = map[int32]string{ 17: "X", } var FOO_value = map[string]int32{ "X": 17, } func (x FOO) Enum() *FOO { p := new(FOO) *p = x return p } func (x FOO) String() string { return proto.EnumName(FOO_name, int32(x)) } func (x *FOO) UnmarshalJSON(data []byte) error { value, err := proto.UnmarshalJSONEnum(FOO_value, data) if err != nil { return err } *x = FOO(value) return nil } type Test struct { Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` // Types that are valid to be assigned to Union: // *Test_Number // *Test_Name Union isTest_Union `protobuf_oneof:"union"` XXX_unrecognized []byte `json:"-"` } func (m *Test) Reset() { *m = Test{} } func (m *Test) String() string { return proto.CompactTextString(m) } func (*Test) ProtoMessage() {} type isTest_Union interface { isTest_Union() } type Test_Number struct { Number int32 `protobuf:"varint,6,opt,name=number"` } type Test_Name struct { Name string `protobuf:"bytes,7,opt,name=name"` } func (*Test_Number) isTest_Union() {} func (*Test_Name) isTest_Union() {} func (m *Test) GetUnion() isTest_Union { if m != nil { return m.Union } return nil } const Default_Test_Type int32 = 77 func (m *Test) GetLabel() string { if m != nil && m.Label != nil { return *m.Label } return "" } func (m *Test) GetType() int32 { if m != nil && m.Type != nil { return *m.Type } return Default_Test_Type } func (m *Test) GetOptionalgroup() *Test_OptionalGroup { if m != nil { return m.Optionalgroup } return nil } type Test_OptionalGroup struct { RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` } func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } func (m *Test_OptionalGroup) GetRequiredField() string { if m != nil && m.RequiredField != nil { return *m.RequiredField } return "" } func (m *Test) GetNumber() int32 { if x, ok := m.GetUnion().(*Test_Number); ok { return x.Number } return 0 } func (m *Test) GetName() string { if x, ok := m.GetUnion().(*Test_Name); ok { return x.Name } return "" } func init() { proto.RegisterEnum("example.FOO", FOO_name, FOO_value) } To create and play with a Test object: package main import ( "log" "github.com/golang/protobuf/proto" pb "./example.pb" ) func main() { test := &pb.Test{ Label: proto.String("hello"), Type: proto.Int32(17), Reps: []int64{1, 2, 3}, Optionalgroup: &pb.Test_OptionalGroup{ RequiredField: proto.String("good bye"), }, Union: &pb.Test_Name{"fred"}, } data, err := proto.Marshal(test) if err != nil { log.Fatal("marshaling error: ", err) } newTest := &pb.Test{} err = proto.Unmarshal(data, newTest) if err != nil { log.Fatal("unmarshaling error: ", err) } // Now test and newTest contain the same data. if test.GetLabel() != newTest.GetLabel() { log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) } // Use a type switch to determine which oneof was set. switch u := test.Union.(type) { case *pb.Test_Number: // u.Number contains the number. case *pb.Test_Name: // u.Name contains the string. } // etc. } */ package proto import ( "encoding/json" "fmt" "log" "reflect" "sort" "strconv" "sync" ) // RequiredNotSetError is an error type returned by either Marshal or Unmarshal. // Marshal reports this when a required field is not initialized. // Unmarshal reports this when a required field is missing from the wire data. type RequiredNotSetError struct{ field string } func (e *RequiredNotSetError) Error() string { if e.field == "" { return fmt.Sprintf("proto: required field not set") } return fmt.Sprintf("proto: required field %q not set", e.field) } func (e *RequiredNotSetError) RequiredNotSet() bool { return true } type invalidUTF8Error struct{ field string } func (e *invalidUTF8Error) Error() string { if e.field == "" { return "proto: invalid UTF-8 detected" } return fmt.Sprintf("proto: field %q contains invalid UTF-8", e.field) } func (e *invalidUTF8Error) InvalidUTF8() bool { return true } // errInvalidUTF8 is a sentinel error to identify fields with invalid UTF-8. // This error should not be exposed to the external API as such errors should // be recreated with the field information. var errInvalidUTF8 = &invalidUTF8Error{} // isNonFatal reports whether the error is either a RequiredNotSet error // or a InvalidUTF8 error. func isNonFatal(err error) bool { if re, ok := err.(interface{ RequiredNotSet() bool }); ok && re.RequiredNotSet() { return true } if re, ok := err.(interface{ InvalidUTF8() bool }); ok && re.InvalidUTF8() { return true } return false } type nonFatal struct{ E error } // Merge merges err into nf and reports whether it was successful. // Otherwise it returns false for any fatal non-nil errors. func (nf *nonFatal) Merge(err error) (ok bool) { if err == nil { return true // not an error } if !isNonFatal(err) { return false // fatal error } if nf.E == nil { nf.E = err // store first instance of non-fatal error } return true } // Message is implemented by generated protocol buffer messages. type Message interface { Reset() String() string ProtoMessage() } // A Buffer is a buffer manager for marshaling and unmarshaling // protocol buffers. It may be reused between invocations to // reduce memory usage. It is not necessary to use a Buffer; // the global functions Marshal and Unmarshal create a // temporary Buffer and are fine for most applications. type Buffer struct { buf []byte // encode/decode byte stream index int // read point deterministic bool } // NewBuffer allocates a new Buffer and initializes its internal data to // the contents of the argument slice. func NewBuffer(e []byte) *Buffer { return &Buffer{buf: e} } // Reset resets the Buffer, ready for marshaling a new protocol buffer. func (p *Buffer) Reset() { p.buf = p.buf[0:0] // for reading/writing p.index = 0 // for reading } // SetBuf replaces the internal buffer with the slice, // ready for unmarshaling the contents of the slice. func (p *Buffer) SetBuf(s []byte) { p.buf = s p.index = 0 } // Bytes returns the contents of the Buffer. func (p *Buffer) Bytes() []byte { return p.buf } // SetDeterministic sets whether to use deterministic serialization. // // Deterministic serialization guarantees that for a given binary, equal // messages will always be serialized to the same bytes. This implies: // // - Repeated serialization of a message will return the same bytes. // - Different processes of the same binary (which may be executing on // different machines) will serialize equal messages to the same bytes. // // Note that the deterministic serialization is NOT canonical across // languages. It is not guaranteed to remain stable over time. It is unstable // across different builds with schema changes due to unknown fields. // Users who need canonical serialization (e.g., persistent storage in a // canonical form, fingerprinting, etc.) should define their own // canonicalization specification and implement their own serializer rather // than relying on this API. // // If deterministic serialization is requested, map entries will be sorted // by keys in lexographical order. This is an implementation detail and // subject to change. func (p *Buffer) SetDeterministic(deterministic bool) { p.deterministic = deterministic } /* * Helper routines for simplifying the creation of optional fields of basic type. */ // Bool is a helper routine that allocates a new bool value // to store v and returns a pointer to it. func Bool(v bool) *bool { return &v } // Int32 is a helper routine that allocates a new int32 value // to store v and returns a pointer to it. func Int32(v int32) *int32 { return &v } // Int is a helper routine that allocates a new int32 value // to store v and returns a pointer to it, but unlike Int32 // its argument value is an int. func Int(v int) *int32 { p := new(int32) *p = int32(v) return p } // Int64 is a helper routine that allocates a new int64 value // to store v and returns a pointer to it. func Int64(v int64) *int64 { return &v } // Float32 is a helper routine that allocates a new float32 value // to store v and returns a pointer to it. func Float32(v float32) *float32 { return &v } // Float64 is a helper routine that allocates a new float64 value // to store v and returns a pointer to it. func Float64(v float64) *float64 { return &v } // Uint32 is a helper routine that allocates a new uint32 value // to store v and returns a pointer to it. func Uint32(v uint32) *uint32 { return &v } // Uint64 is a helper routine that allocates a new uint64 value // to store v and returns a pointer to it. func Uint64(v uint64) *uint64 { return &v } // String is a helper routine that allocates a new string value // to store v and returns a pointer to it. func String(v string) *string { return &v } // EnumName is a helper function to simplify printing protocol buffer enums // by name. Given an enum map and a value, it returns a useful string. func EnumName(m map[int32]string, v int32) string { s, ok := m[v] if ok { return s } return strconv.Itoa(int(v)) } // UnmarshalJSONEnum is a helper function to simplify recovering enum int values // from their JSON-encoded representation. Given a map from the enum's symbolic // names to its int values, and a byte buffer containing the JSON-encoded // value, it returns an int32 that can be cast to the enum type by the caller. // // The function can deal with both JSON representations, numeric and symbolic. func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { if data[0] == '"' { // New style: enums are strings. var repr string if err := json.Unmarshal(data, &repr); err != nil { return -1, err } val, ok := m[repr] if !ok { return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) } return val, nil } // Old style: enums are ints. var val int32 if err := json.Unmarshal(data, &val); err != nil { return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) } return val, nil } // DebugPrint dumps the encoded data in b in a debugging format with a header // including the string s. Used in testing but made available for general debugging. func (p *Buffer) DebugPrint(s string, b []byte) { var u uint64 obuf := p.buf index := p.index p.buf = b p.index = 0 depth := 0 fmt.Printf("\n--- %s ---\n", s) out: for { for i := 0; i < depth; i++ { fmt.Print(" ") } index := p.index if index == len(p.buf) { break } op, err := p.DecodeVarint() if err != nil { fmt.Printf("%3d: fetching op err %v\n", index, err) break out } tag := op >> 3 wire := op & 7 switch wire { default: fmt.Printf("%3d: t=%3d unknown wire=%d\n", index, tag, wire) break out case WireBytes: var r []byte r, err = p.DecodeRawBytes(false) if err != nil { break out } fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) if len(r) <= 6 { for i := 0; i < len(r); i++ { fmt.Printf(" %.2x", r[i]) } } else { for i := 0; i < 3; i++ { fmt.Printf(" %.2x", r[i]) } fmt.Printf(" ..") for i := len(r) - 3; i < len(r); i++ { fmt.Printf(" %.2x", r[i]) } } fmt.Printf("\n") case WireFixed32: u, err = p.DecodeFixed32() if err != nil { fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) break out } fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) case WireFixed64: u, err = p.DecodeFixed64() if err != nil { fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) break out } fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) case WireVarint: u, err = p.DecodeVarint() if err != nil { fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) break out } fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) case WireStartGroup: fmt.Printf("%3d: t=%3d start\n", index, tag) depth++ case WireEndGroup: depth-- fmt.Printf("%3d: t=%3d end\n", index, tag) } } if depth != 0 { fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth) } fmt.Printf("\n") p.buf = obuf p.index = index } // SetDefaults sets unset protocol buffer fields to their default values. // It only modifies fields that are both unset and have defined defaults. // It recursively sets default values in any non-nil sub-messages. func SetDefaults(pb Message) { setDefaults(reflect.ValueOf(pb), true, false) } // v is a pointer to a struct. func setDefaults(v reflect.Value, recur, zeros bool) { v = v.Elem() defaultMu.RLock() dm, ok := defaults[v.Type()] defaultMu.RUnlock() if !ok { dm = buildDefaultMessage(v.Type()) defaultMu.Lock() defaults[v.Type()] = dm defaultMu.Unlock() } for _, sf := range dm.scalars { f := v.Field(sf.index) if !f.IsNil() { // field already set continue } dv := sf.value if dv == nil && !zeros { // no explicit default, and don't want to set zeros continue } fptr := f.Addr().Interface() // **T // TODO: Consider batching the allocations we do here. switch sf.kind { case reflect.Bool: b := new(bool) if dv != nil { *b = dv.(bool) } *(fptr.(**bool)) = b case reflect.Float32: f := new(float32) if dv != nil { *f = dv.(float32) } *(fptr.(**float32)) = f case reflect.Float64: f := new(float64) if dv != nil { *f = dv.(float64) } *(fptr.(**float64)) = f case reflect.Int32: // might be an enum if ft := f.Type(); ft != int32PtrType { // enum f.Set(reflect.New(ft.Elem())) if dv != nil { f.Elem().SetInt(int64(dv.(int32))) } } else { // int32 field i := new(int32) if dv != nil { *i = dv.(int32) } *(fptr.(**int32)) = i } case reflect.Int64: i := new(int64) if dv != nil { *i = dv.(int64) } *(fptr.(**int64)) = i case reflect.String: s := new(string) if dv != nil { *s = dv.(string) } *(fptr.(**string)) = s case reflect.Uint8: // exceptional case: []byte var b []byte if dv != nil { db := dv.([]byte) b = make([]byte, len(db)) copy(b, db) } else { b = []byte{} } *(fptr.(*[]byte)) = b case reflect.Uint32: u := new(uint32) if dv != nil { *u = dv.(uint32) } *(fptr.(**uint32)) = u case reflect.Uint64: u := new(uint64) if dv != nil { *u = dv.(uint64) } *(fptr.(**uint64)) = u default: log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) } } for _, ni := range dm.nested { f := v.Field(ni) // f is *T or []*T or map[T]*T switch f.Kind() { case reflect.Ptr: if f.IsNil() { continue } setDefaults(f, recur, zeros) case reflect.Slice: for i := 0; i < f.Len(); i++ { e := f.Index(i) if e.IsNil() { continue } setDefaults(e, recur, zeros) } case reflect.Map: for _, k := range f.MapKeys() { e := f.MapIndex(k) if e.IsNil() { continue } setDefaults(e, recur, zeros) } } } } var ( // defaults maps a protocol buffer struct type to a slice of the fields, // with its scalar fields set to their proto-declared non-zero default values. defaultMu sync.RWMutex defaults = make(map[reflect.Type]defaultMessage) int32PtrType = reflect.TypeOf((*int32)(nil)) ) // defaultMessage represents information about the default values of a message. type defaultMessage struct { scalars []scalarField nested []int // struct field index of nested messages } type scalarField struct { index int // struct field index kind reflect.Kind // element type (the T in *T or []T) value interface{} // the proto-declared default value, or nil } // t is a struct type. func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { sprop := GetProperties(t) for _, prop := range sprop.Prop { fi, ok := sprop.decoderTags.get(prop.Tag) if !ok { // XXX_unrecognized continue } ft := t.Field(fi).Type sf, nested, err := fieldDefault(ft, prop) switch { case err != nil: log.Print(err) case nested: dm.nested = append(dm.nested, fi) case sf != nil: sf.index = fi dm.scalars = append(dm.scalars, *sf) } } return dm } // fieldDefault returns the scalarField for field type ft. // sf will be nil if the field can not have a default. // nestedMessage will be true if this is a nested message. // Note that sf.index is not set on return. func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) { var canHaveDefault bool switch ft.Kind() { case reflect.Ptr: if ft.Elem().Kind() == reflect.Struct { nestedMessage = true } else { canHaveDefault = true // proto2 scalar field } case reflect.Slice: switch ft.Elem().Kind() { case reflect.Ptr: nestedMessage = true // repeated message case reflect.Uint8: canHaveDefault = true // bytes field } case reflect.Map: if ft.Elem().Kind() == reflect.Ptr { nestedMessage = true // map with message values } } if !canHaveDefault { if nestedMessage { return nil, true, nil } return nil, false, nil } // We now know that ft is a pointer or slice. sf = &scalarField{kind: ft.Elem().Kind()} // scalar fields without defaults if !prop.HasDefault { return sf, false, nil } // a scalar field: either *T or []byte switch ft.Elem().Kind() { case reflect.Bool: x, err := strconv.ParseBool(prop.Default) if err != nil { return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err) } sf.value = x case reflect.Float32: x, err := strconv.ParseFloat(prop.Default, 32) if err != nil { return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err) } sf.value = float32(x) case reflect.Float64: x, err := strconv.ParseFloat(prop.Default, 64) if err != nil { return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err) } sf.value = x case reflect.Int32: x, err := strconv.ParseInt(prop.Default, 10, 32) if err != nil { return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err) } sf.value = int32(x) case reflect.Int64: x, err := strconv.ParseInt(prop.Default, 10, 64) if err != nil { return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err) } sf.value = x case reflect.String: sf.value = prop.Default case reflect.Uint8: // []byte (not *uint8) sf.value = []byte(prop.Default) case reflect.Uint32: x, err := strconv.ParseUint(prop.Default, 10, 32) if err != nil { return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err) } sf.value = uint32(x) case reflect.Uint64: x, err := strconv.ParseUint(prop.Default, 10, 64) if err != nil { return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err) } sf.value = x default: return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind()) } return sf, false, nil } // mapKeys returns a sort.Interface to be used for sorting the map keys. // Map fields may have key types of non-float scalars, strings and enums. func mapKeys(vs []reflect.Value) sort.Interface { s := mapKeySorter{vs: vs} // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps. if len(vs) == 0 { return s } switch vs[0].Kind() { case reflect.Int32, reflect.Int64: s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } case reflect.Uint32, reflect.Uint64: s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } case reflect.Bool: s.less = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() } // false < true case reflect.String: s.less = func(a, b reflect.Value) bool { return a.String() < b.String() } default: panic(fmt.Sprintf("unsupported map key type: %v", vs[0].Kind())) } return s } type mapKeySorter struct { vs []reflect.Value less func(a, b reflect.Value) bool } func (s mapKeySorter) Len() int { return len(s.vs) } func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } func (s mapKeySorter) Less(i, j int) bool { return s.less(s.vs[i], s.vs[j]) } // isProto3Zero reports whether v is a zero proto3 value. func isProto3Zero(v reflect.Value) bool { switch v.Kind() { case reflect.Bool: return !v.Bool() case reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Uint32, reflect.Uint64: return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflect.String: return v.String() == "" } return false } const ( // ProtoPackageIsVersion3 is referenced from generated protocol buffer files // to assert that that code is compatible with this version of the proto package. ProtoPackageIsVersion3 = true // ProtoPackageIsVersion2 is referenced from generated protocol buffer files // to assert that that code is compatible with this version of the proto package. ProtoPackageIsVersion2 = true // ProtoPackageIsVersion1 is referenced from generated protocol buffer files // to assert that that code is compatible with this version of the proto package. 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 } ================================================ FILE: vendor/github.com/golang/protobuf/proto/message_set.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package proto /* * Support for message sets. */ import ( "errors" ) // errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. // A message type ID is required for storing a protocol buffer in a message set. var errNoMessageTypeID = errors.New("proto does not have a message type ID") // The first two types (_MessageSet_Item and messageSet) // model what the protocol compiler produces for the following protocol message: // message MessageSet { // repeated group Item = 1 { // required int32 type_id = 2; // required string message = 3; // }; // } // That is the MessageSet wire format. We can't use a proto to generate these // because that would introduce a circular dependency between it and this package. type _MessageSet_Item struct { TypeId *int32 `protobuf:"varint,2,req,name=type_id"` Message []byte `protobuf:"bytes,3,req,name=message"` } type messageSet struct { Item []*_MessageSet_Item `protobuf:"group,1,rep"` XXX_unrecognized []byte // TODO: caching? } // Make sure messageSet is a Message. var _ Message = (*messageSet)(nil) // messageTypeIder is an interface satisfied by a protocol buffer type // that may be stored in a MessageSet. type messageTypeIder interface { MessageTypeId() int32 } func (ms *messageSet) find(pb Message) *_MessageSet_Item { mti, ok := pb.(messageTypeIder) if !ok { return nil } id := mti.MessageTypeId() for _, item := range ms.Item { if *item.TypeId == id { return item } } return nil } func (ms *messageSet) Has(pb Message) bool { return ms.find(pb) != nil } func (ms *messageSet) Unmarshal(pb Message) error { if item := ms.find(pb); item != nil { return Unmarshal(item.Message, pb) } if _, ok := pb.(messageTypeIder); !ok { return errNoMessageTypeID } return nil // TODO: return error instead? } func (ms *messageSet) Marshal(pb Message) error { msg, err := Marshal(pb) if err != nil { return err } if item := ms.find(pb); item != nil { // reuse existing item item.Message = msg return nil } mti, ok := pb.(messageTypeIder) if !ok { return errNoMessageTypeID } mtid := mti.MessageTypeId() ms.Item = append(ms.Item, &_MessageSet_Item{ TypeId: &mtid, Message: msg, }) return nil } func (ms *messageSet) Reset() { *ms = messageSet{} } func (ms *messageSet) String() string { return CompactTextString(ms) } func (*messageSet) ProtoMessage() {} // Support for the message_set_wire_format message option. func skipVarint(buf []byte) []byte { i := 0 for ; buf[i]&0x80 != 0; i++ { } return buf[i+1:] } // unmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. // It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option. func unmarshalMessageSet(buf []byte, exts interface{}) error { var m map[int32]Extension switch exts := exts.(type) { case *XXX_InternalExtensions: m = exts.extensionsWrite() case map[int32]Extension: m = exts default: return errors.New("proto: not an extension map") } ms := new(messageSet) if err := Unmarshal(buf, ms); err != nil { return err } for _, item := range ms.Item { id := *item.TypeId msg := item.Message // Restore wire type and field number varint, plus length varint. // Be careful to preserve duplicate items. b := EncodeVarint(uint64(id)<<3 | WireBytes) if ext, ok := m[id]; ok { // Existing data; rip off the tag and length varint // so we join the new data correctly. // We can assume that ext.enc is set because we are unmarshaling. o := ext.enc[len(b):] // skip wire type and field number _, n := DecodeVarint(o) // calculate length of length varint o = o[n:] // skip length varint msg = append(o, msg...) // join old data and new data } b = append(b, EncodeVarint(uint64(len(msg)))...) b = append(b, msg...) m[id] = Extension{enc: b} } return nil } ================================================ FILE: vendor/github.com/golang/protobuf/proto/pointer_reflect.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2012 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // +build purego appengine js // This file contains an implementation of proto field accesses using package reflect. // It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can // be used on App Engine. package proto import ( "reflect" "sync" ) const unsafeAllowed = false // A field identifies a field in a struct, accessible from a pointer. // In this implementation, a field is identified by the sequence of field indices // passed to reflect's FieldByIndex. type field []int // toField returns a field equivalent to the given reflect field. func toField(f *reflect.StructField) field { return f.Index } // invalidField is an invalid field identifier. var invalidField = field(nil) // zeroField is a noop when calling pointer.offset. var zeroField = field([]int{}) // IsValid reports whether the field identifier is valid. func (f field) IsValid() bool { return f != nil } // The pointer type is for the table-driven decoder. // The implementation here uses a reflect.Value of pointer type to // create a generic pointer. In pointer_unsafe.go we use unsafe // instead of reflect to implement the same (but faster) interface. type pointer struct { v reflect.Value } // toPointer converts an interface of pointer type to a pointer // that points to the same target. func toPointer(i *Message) pointer { return pointer{v: reflect.ValueOf(*i)} } // toAddrPointer converts an interface to a pointer that points to // the interface data. func toAddrPointer(i *interface{}, isptr, deref bool) pointer { v := reflect.ValueOf(*i) u := reflect.New(v.Type()) u.Elem().Set(v) if deref { u = u.Elem() } return pointer{v: u} } // valToPointer converts v to a pointer. v must be of pointer type. func valToPointer(v reflect.Value) pointer { return pointer{v: v} } // offset converts from a pointer to a structure to a pointer to // one of its fields. func (p pointer) offset(f field) pointer { return pointer{v: p.v.Elem().FieldByIndex(f).Addr()} } func (p pointer) isNil() bool { return p.v.IsNil() } // grow updates the slice s in place to make it one element longer. // s must be addressable. // Returns the (addressable) new element. func grow(s reflect.Value) reflect.Value { n, m := s.Len(), s.Cap() if n < m { s.SetLen(n + 1) } else { s.Set(reflect.Append(s, reflect.Zero(s.Type().Elem()))) } return s.Index(n) } func (p pointer) toInt64() *int64 { return p.v.Interface().(*int64) } func (p pointer) toInt64Ptr() **int64 { return p.v.Interface().(**int64) } func (p pointer) toInt64Slice() *[]int64 { return p.v.Interface().(*[]int64) } var int32ptr = reflect.TypeOf((*int32)(nil)) func (p pointer) toInt32() *int32 { return p.v.Convert(int32ptr).Interface().(*int32) } // The toInt32Ptr/Slice methods don't work because of enums. // Instead, we must use set/get methods for the int32ptr/slice case. /* func (p pointer) toInt32Ptr() **int32 { return p.v.Interface().(**int32) } func (p pointer) toInt32Slice() *[]int32 { return p.v.Interface().(*[]int32) } */ func (p pointer) getInt32Ptr() *int32 { if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { // raw int32 type return p.v.Elem().Interface().(*int32) } // an enum return p.v.Elem().Convert(int32PtrType).Interface().(*int32) } func (p pointer) setInt32Ptr(v int32) { // Allocate value in a *int32. Possibly convert that to a *enum. // Then assign it to a **int32 or **enum. // Note: we can convert *int32 to *enum, but we can't convert // **int32 to **enum! p.v.Elem().Set(reflect.ValueOf(&v).Convert(p.v.Type().Elem())) } // getInt32Slice copies []int32 from p as a new slice. // This behavior differs from the implementation in pointer_unsafe.go. func (p pointer) getInt32Slice() []int32 { if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { // raw int32 type return p.v.Elem().Interface().([]int32) } // an enum // Allocate a []int32, then assign []enum's values into it. // Note: we can't convert []enum to []int32. slice := p.v.Elem() s := make([]int32, slice.Len()) for i := 0; i < slice.Len(); i++ { s[i] = int32(slice.Index(i).Int()) } return s } // setInt32Slice copies []int32 into p as a new slice. // This behavior differs from the implementation in pointer_unsafe.go. func (p pointer) setInt32Slice(v []int32) { if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { // raw int32 type p.v.Elem().Set(reflect.ValueOf(v)) return } // an enum // Allocate a []enum, then assign []int32's values into it. // Note: we can't convert []enum to []int32. slice := reflect.MakeSlice(p.v.Type().Elem(), len(v), cap(v)) for i, x := range v { slice.Index(i).SetInt(int64(x)) } p.v.Elem().Set(slice) } func (p pointer) appendInt32Slice(v int32) { grow(p.v.Elem()).SetInt(int64(v)) } func (p pointer) toUint64() *uint64 { return p.v.Interface().(*uint64) } func (p pointer) toUint64Ptr() **uint64 { return p.v.Interface().(**uint64) } func (p pointer) toUint64Slice() *[]uint64 { return p.v.Interface().(*[]uint64) } func (p pointer) toUint32() *uint32 { return p.v.Interface().(*uint32) } func (p pointer) toUint32Ptr() **uint32 { return p.v.Interface().(**uint32) } func (p pointer) toUint32Slice() *[]uint32 { return p.v.Interface().(*[]uint32) } func (p pointer) toBool() *bool { return p.v.Interface().(*bool) } func (p pointer) toBoolPtr() **bool { return p.v.Interface().(**bool) } func (p pointer) toBoolSlice() *[]bool { return p.v.Interface().(*[]bool) } func (p pointer) toFloat64() *float64 { return p.v.Interface().(*float64) } func (p pointer) toFloat64Ptr() **float64 { return p.v.Interface().(**float64) } func (p pointer) toFloat64Slice() *[]float64 { return p.v.Interface().(*[]float64) } func (p pointer) toFloat32() *float32 { return p.v.Interface().(*float32) } func (p pointer) toFloat32Ptr() **float32 { return p.v.Interface().(**float32) } func (p pointer) toFloat32Slice() *[]float32 { return p.v.Interface().(*[]float32) } func (p pointer) toString() *string { return p.v.Interface().(*string) } func (p pointer) toStringPtr() **string { return p.v.Interface().(**string) } func (p pointer) toStringSlice() *[]string { return p.v.Interface().(*[]string) } func (p pointer) toBytes() *[]byte { return p.v.Interface().(*[]byte) } func (p pointer) toBytesSlice() *[][]byte { return p.v.Interface().(*[][]byte) } func (p pointer) toExtensions() *XXX_InternalExtensions { return p.v.Interface().(*XXX_InternalExtensions) } func (p pointer) toOldExtensions() *map[int32]Extension { return p.v.Interface().(*map[int32]Extension) } func (p pointer) getPointer() pointer { return pointer{v: p.v.Elem()} } func (p pointer) setPointer(q pointer) { p.v.Elem().Set(q.v) } func (p pointer) appendPointer(q pointer) { grow(p.v.Elem()).Set(q.v) } // getPointerSlice copies []*T from p as a new []pointer. // This behavior differs from the implementation in pointer_unsafe.go. func (p pointer) getPointerSlice() []pointer { if p.v.IsNil() { return nil } n := p.v.Elem().Len() s := make([]pointer, n) for i := 0; i < n; i++ { s[i] = pointer{v: p.v.Elem().Index(i)} } return s } // setPointerSlice copies []pointer into p as a new []*T. // This behavior differs from the implementation in pointer_unsafe.go. func (p pointer) setPointerSlice(v []pointer) { if v == nil { p.v.Elem().Set(reflect.New(p.v.Elem().Type()).Elem()) return } s := reflect.MakeSlice(p.v.Elem().Type(), 0, len(v)) for _, p := range v { s = reflect.Append(s, p.v) } p.v.Elem().Set(s) } // getInterfacePointer returns a pointer that points to the // interface data of the interface pointed by p. func (p pointer) getInterfacePointer() pointer { if p.v.Elem().IsNil() { return pointer{v: p.v.Elem()} } return pointer{v: p.v.Elem().Elem().Elem().Field(0).Addr()} // *interface -> interface -> *struct -> struct } func (p pointer) asPointerTo(t reflect.Type) reflect.Value { // TODO: check that p.v.Type().Elem() == t? return p.v } func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { atomicLock.Lock() defer atomicLock.Unlock() return *p } func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { atomicLock.Lock() defer atomicLock.Unlock() *p = v } func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { atomicLock.Lock() defer atomicLock.Unlock() return *p } func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { atomicLock.Lock() defer atomicLock.Unlock() *p = v } func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { atomicLock.Lock() defer atomicLock.Unlock() return *p } func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { atomicLock.Lock() defer atomicLock.Unlock() *p = v } func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { atomicLock.Lock() defer atomicLock.Unlock() return *p } func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { atomicLock.Lock() defer atomicLock.Unlock() *p = v } var atomicLock sync.Mutex ================================================ FILE: vendor/github.com/golang/protobuf/proto/pointer_unsafe.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2012 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // +build !purego,!appengine,!js // This file contains the implementation of the proto field accesses using package unsafe. package proto import ( "reflect" "sync/atomic" "unsafe" ) const unsafeAllowed = true // A field identifies a field in a struct, accessible from a pointer. // In this implementation, a field is identified by its byte offset from the start of the struct. type field uintptr // toField returns a field equivalent to the given reflect field. func toField(f *reflect.StructField) field { return field(f.Offset) } // invalidField is an invalid field identifier. const invalidField = ^field(0) // zeroField is a noop when calling pointer.offset. const zeroField = field(0) // IsValid reports whether the field identifier is valid. func (f field) IsValid() bool { return f != invalidField } // The pointer type below is for the new table-driven encoder/decoder. // The implementation here uses unsafe.Pointer to create a generic pointer. // In pointer_reflect.go we use reflect instead of unsafe to implement // the same (but slower) interface. type pointer struct { p unsafe.Pointer } // size of pointer var ptrSize = unsafe.Sizeof(uintptr(0)) // toPointer converts an interface of pointer type to a pointer // that points to the same target. func toPointer(i *Message) pointer { // Super-tricky - read pointer out of data word of interface value. // Saves ~25ns over the equivalent: // return valToPointer(reflect.ValueOf(*i)) return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} } // toAddrPointer converts an interface to a pointer that points to // the interface data. func toAddrPointer(i *interface{}, isptr, deref bool) (p 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. p = pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)} } else { // The interface is not of pointer type. The data word is the pointer // to the data. p = pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} } if deref { p.p = *(*unsafe.Pointer)(p.p) } 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())} } // offset converts from a pointer to a structure to a pointer to // one of its fields. func (p pointer) offset(f field) pointer { // For safety, we should panic if !f.IsValid, however calling panic causes // this to no longer be inlineable, which is a serious performance cost. /* if !f.IsValid() { panic("invalid field") } */ return pointer{p: unsafe.Pointer(uintptr(p.p) + uintptr(f))} } func (p pointer) isNil() bool { return p.p == nil } func (p pointer) toInt64() *int64 { return (*int64)(p.p) } func (p pointer) toInt64Ptr() **int64 { return (**int64)(p.p) } func (p pointer) toInt64Slice() *[]int64 { return (*[]int64)(p.p) } func (p pointer) toInt32() *int32 { return (*int32)(p.p) } // See pointer_reflect.go for why toInt32Ptr/Slice doesn't exist. /* func (p pointer) toInt32Ptr() **int32 { return (**int32)(p.p) } func (p pointer) toInt32Slice() *[]int32 { return (*[]int32)(p.p) } */ func (p pointer) getInt32Ptr() *int32 { return *(**int32)(p.p) } func (p pointer) setInt32Ptr(v int32) { *(**int32)(p.p) = &v } // getInt32Slice loads a []int32 from p. // The value returned is aliased with the original slice. // This behavior differs from the implementation in pointer_reflect.go. func (p pointer) getInt32Slice() []int32 { return *(*[]int32)(p.p) } // setInt32Slice stores a []int32 to p. // The value set is aliased with the input slice. // This behavior differs from the implementation in pointer_reflect.go. func (p pointer) setInt32Slice(v []int32) { *(*[]int32)(p.p) = v } // TODO: Can we get rid of appendInt32Slice and use setInt32Slice instead? func (p pointer) appendInt32Slice(v int32) { s := (*[]int32)(p.p) *s = append(*s, v) } func (p pointer) toUint64() *uint64 { return (*uint64)(p.p) } func (p pointer) toUint64Ptr() **uint64 { return (**uint64)(p.p) } func (p pointer) toUint64Slice() *[]uint64 { return (*[]uint64)(p.p) } func (p pointer) toUint32() *uint32 { return (*uint32)(p.p) } func (p pointer) toUint32Ptr() **uint32 { return (**uint32)(p.p) } func (p pointer) toUint32Slice() *[]uint32 { return (*[]uint32)(p.p) } func (p pointer) toBool() *bool { return (*bool)(p.p) } func (p pointer) toBoolPtr() **bool { return (**bool)(p.p) } func (p pointer) toBoolSlice() *[]bool { return (*[]bool)(p.p) } func (p pointer) toFloat64() *float64 { return (*float64)(p.p) } func (p pointer) toFloat64Ptr() **float64 { return (**float64)(p.p) } func (p pointer) toFloat64Slice() *[]float64 { return (*[]float64)(p.p) } func (p pointer) toFloat32() *float32 { return (*float32)(p.p) } func (p pointer) toFloat32Ptr() **float32 { return (**float32)(p.p) } func (p pointer) toFloat32Slice() *[]float32 { return (*[]float32)(p.p) } func (p pointer) toString() *string { return (*string)(p.p) } func (p pointer) toStringPtr() **string { return (**string)(p.p) } func (p pointer) toStringSlice() *[]string { return (*[]string)(p.p) } func (p pointer) toBytes() *[]byte { return (*[]byte)(p.p) } func (p pointer) toBytesSlice() *[][]byte { return (*[][]byte)(p.p) } func (p pointer) toExtensions() *XXX_InternalExtensions { return (*XXX_InternalExtensions)(p.p) } func (p pointer) toOldExtensions() *map[int32]Extension { return (*map[int32]Extension)(p.p) } // getPointerSlice loads []*T from p as a []pointer. // The value returned is aliased with the original slice. // This behavior differs from the implementation in pointer_reflect.go. func (p pointer) getPointerSlice() []pointer { // Super-tricky - p should point to a []*T where T is a // message type. We load it as []pointer. return *(*[]pointer)(p.p) } // setPointerSlice stores []pointer into p as a []*T. // The value set is aliased with the input slice. // This behavior differs from the implementation in pointer_reflect.go. func (p pointer) setPointerSlice(v []pointer) { // Super-tricky - p should point to a []*T where T is a // message type. We store it as []pointer. *(*[]pointer)(p.p) = v } // getPointer loads the pointer at p and returns it. func (p pointer) getPointer() pointer { return pointer{p: *(*unsafe.Pointer)(p.p)} } // setPointer stores the pointer q at p. func (p pointer) setPointer(q pointer) { *(*unsafe.Pointer)(p.p) = q.p } // append q to the slice pointed to by p. func (p pointer) appendPointer(q pointer) { s := (*[]unsafe.Pointer)(p.p) *s = append(*s, q.p) } // getInterfacePointer returns a pointer that points to the // interface data of the interface pointed by p. func (p pointer) getInterfacePointer() pointer { // Super-tricky - read pointer out of data word of interface value. return pointer{p: (*(*[2]unsafe.Pointer)(p.p))[1]} } // asPointerTo returns a reflect.Value that is a pointer to an // object of type t stored at p. func (p pointer) asPointerTo(t reflect.Type) reflect.Value { return reflect.NewAt(t, p.p) } func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { return (*unmarshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) } func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) } func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { return (*marshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) } func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) } func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { return (*mergeInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) } func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) } func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { return (*discardInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) } func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) } ================================================ FILE: vendor/github.com/golang/protobuf/proto/properties.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package proto /* * Routines for encoding data into the wire format for protocol buffers. */ import ( "fmt" "log" "os" "reflect" "sort" "strconv" "strings" "sync" ) const debug bool = false // Constants that identify the encoding of a value on the wire. const ( WireVarint = 0 WireFixed64 = 1 WireBytes = 2 WireStartGroup = 3 WireEndGroup = 4 WireFixed32 = 5 ) // tagMap is an optimization over map[int]int for typical protocol buffer // use-cases. Encoded protocol buffers are often in tag order with small tag // numbers. type tagMap struct { fastTags []int slowTags map[int]int } // tagMapFastLimit is the upper bound on the tag number that will be stored in // the tagMap slice rather than its map. const tagMapFastLimit = 1024 func (p *tagMap) get(t int) (int, bool) { if t > 0 && t < tagMapFastLimit { if t >= len(p.fastTags) { return 0, false } fi := p.fastTags[t] return fi, fi >= 0 } fi, ok := p.slowTags[t] return fi, ok } func (p *tagMap) put(t int, fi int) { if t > 0 && t < tagMapFastLimit { for len(p.fastTags) < t+1 { p.fastTags = append(p.fastTags, -1) } p.fastTags[t] = fi return } if p.slowTags == nil { p.slowTags = make(map[int]int) } p.slowTags[t] = fi } // StructProperties represents properties for all the fields of a struct. // decoderTags and decoderOrigNames should only be used by the decoder. type StructProperties struct { Prop []*Properties // properties for each field reqCount int // required count decoderTags tagMap // map from proto tag to struct field number decoderOrigNames map[string]int // map from original name to struct field number order []int // list of struct field numbers in tag order // OneofTypes contains information about the oneof fields in this message. // It is keyed by the original name of a field. OneofTypes map[string]*OneofProperties } // OneofProperties represents information about a specific field in a oneof. type OneofProperties struct { Type reflect.Type // pointer to generated struct type for this oneof field Field int // struct field number of the containing oneof in the message Prop *Properties } // Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec. // See encode.go, (*Buffer).enc_struct. func (sp *StructProperties) Len() int { return len(sp.order) } func (sp *StructProperties) Less(i, j int) bool { return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag } func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } // Properties represents the protocol-specific behavior of a single struct field. type Properties struct { Name string // name of the field, for error messages OrigName string // original name before protocol compiler (always set) JSONName string // name to use for JSON; determined by protoc Wire string WireType int Tag int Required bool Optional bool Repeated bool Packed bool // relevant for repeated primitives only Enum string // set for enum types only proto3 bool // whether this is known to be a proto3 field oneof bool // whether this is a oneof field Default string // default value HasDefault bool // whether an explicit default was provided stype reflect.Type // set for struct types only sprop *StructProperties // set for struct types only mtype reflect.Type // set for map types only MapKeyProp *Properties // set for map types only MapValProp *Properties // set for map types only } // String formats the properties in the protobuf struct field tag style. func (p *Properties) String() string { s := p.Wire s += "," s += strconv.Itoa(p.Tag) if p.Required { s += ",req" } if p.Optional { s += ",opt" } if p.Repeated { s += ",rep" } if p.Packed { s += ",packed" } s += ",name=" + p.OrigName if p.JSONName != p.OrigName { s += ",json=" + p.JSONName } if p.proto3 { s += ",proto3" } if p.oneof { s += ",oneof" } if len(p.Enum) > 0 { s += ",enum=" + p.Enum } if p.HasDefault { s += ",def=" + p.Default } return s } // Parse populates p by parsing a string in the protobuf struct field tag style. func (p *Properties) Parse(s string) { // "bytes,49,opt,name=foo,def=hello!" fields := strings.Split(s, ",") // breaks def=, but handled below. if len(fields) < 2 { fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s) return } p.Wire = fields[0] switch p.Wire { case "varint": p.WireType = WireVarint case "fixed32": p.WireType = WireFixed32 case "fixed64": p.WireType = WireFixed64 case "zigzag32": p.WireType = WireVarint case "zigzag64": p.WireType = WireVarint case "bytes", "group": p.WireType = WireBytes // no numeric converter for non-numeric types default: fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s) return } var err error p.Tag, err = strconv.Atoi(fields[1]) if err != nil { return } outer: for i := 2; i < len(fields); i++ { f := fields[i] switch { case f == "req": p.Required = true case f == "opt": p.Optional = true case f == "rep": p.Repeated = true case f == "packed": p.Packed = true case strings.HasPrefix(f, "name="): p.OrigName = f[5:] case strings.HasPrefix(f, "json="): p.JSONName = f[5:] case strings.HasPrefix(f, "enum="): p.Enum = f[5:] case f == "proto3": p.proto3 = true case f == "oneof": p.oneof = true case strings.HasPrefix(f, "def="): p.HasDefault = true p.Default = f[4:] // rest of string if i+1 < len(fields) { // Commas aren't escaped, and def is always last. p.Default += "," + strings.Join(fields[i+1:], ",") break outer } } } } var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() // setFieldProps initializes the field properties for submessages and maps. func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { switch t1 := typ; t1.Kind() { case reflect.Ptr: if t1.Elem().Kind() == reflect.Struct { p.stype = t1.Elem() } case reflect.Slice: if t2 := t1.Elem(); t2.Kind() == reflect.Ptr && t2.Elem().Kind() == reflect.Struct { p.stype = t2.Elem() } case reflect.Map: p.mtype = t1 p.MapKeyProp = &Properties{} p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) p.MapValProp = &Properties{} vtype := p.mtype.Elem() if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { // The value type is not a message (*T) or bytes ([]byte), // so we need encoders for the pointer to this type. vtype = reflect.PtrTo(vtype) } p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) } if p.stype != nil { if lockGetProp { p.sprop = GetProperties(p.stype) } else { p.sprop = getPropertiesLocked(p.stype) } } } var ( marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() ) // Init populates the properties from a protocol buffer struct tag. func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { p.init(typ, name, tag, f, true) } func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { // "bytes,49,opt,def=hello!" p.Name = name p.OrigName = name if tag == "" { return } p.Parse(tag) p.setFieldProps(typ, f, lockGetProp) } var ( propertiesMu sync.RWMutex propertiesMap = make(map[reflect.Type]*StructProperties) ) // GetProperties returns the list of properties for the type represented by t. // t must represent a generated struct type of a protocol message. func GetProperties(t reflect.Type) *StructProperties { if t.Kind() != reflect.Struct { panic("proto: type must have kind struct") } // Most calls to GetProperties in a long-running program will be // retrieving details for types we have seen before. propertiesMu.RLock() sprop, ok := propertiesMap[t] propertiesMu.RUnlock() if ok { return sprop } propertiesMu.Lock() sprop = getPropertiesLocked(t) propertiesMu.Unlock() return sprop } type ( oneofFuncsIface interface { XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) } oneofWrappersIface interface { XXX_OneofWrappers() []interface{} } ) // getPropertiesLocked requires that propertiesMu is held. func getPropertiesLocked(t reflect.Type) *StructProperties { if prop, ok := propertiesMap[t]; ok { return prop } prop := new(StructProperties) // in case of recursive protos, fill this in now. propertiesMap[t] = prop // build properties prop.Prop = make([]*Properties, t.NumField()) prop.order = make([]int, t.NumField()) for i := 0; i < t.NumField(); i++ { f := t.Field(i) p := new(Properties) name := f.Name p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) oneof := f.Tag.Get("protobuf_oneof") // special case if oneof != "" { // Oneof fields don't use the traditional protobuf tag. p.OrigName = oneof } prop.Prop[i] = p prop.order[i] = i if debug { print(i, " ", f.Name, " ", t.String(), " ") if p.Tag > 0 { print(p.String()) } print("\n") } } // Re-order prop.order. sort.Sort(prop) var oots []interface{} switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { case oneofFuncsIface: _, _, _, oots = m.XXX_OneofFuncs() case oneofWrappersIface: oots = m.XXX_OneofWrappers() } if len(oots) > 0 { // Interpret oneof metadata. prop.OneofTypes = make(map[string]*OneofProperties) for _, oot := range oots { oop := &OneofProperties{ Type: reflect.ValueOf(oot).Type(), // *T Prop: new(Properties), } sft := oop.Type.Elem().Field(0) oop.Prop.Name = sft.Name oop.Prop.Parse(sft.Tag.Get("protobuf")) // There will be exactly one interface field that // this new value is assignable to. for i := 0; i < t.NumField(); i++ { f := t.Field(i) if f.Type.Kind() != reflect.Interface { continue } if !oop.Type.AssignableTo(f.Type) { continue } oop.Field = i break } prop.OneofTypes[oop.Prop.OrigName] = oop } } // build required counts // build tags reqCount := 0 prop.decoderOrigNames = make(map[string]int) for i, p := range prop.Prop { if strings.HasPrefix(p.Name, "XXX_") { // Internal fields should not appear in tags/origNames maps. // They are handled specially when encoding and decoding. continue } if p.Required { reqCount++ } prop.decoderTags.put(p.Tag, i) prop.decoderOrigNames[p.OrigName] = i } prop.reqCount = reqCount return prop } // A global registry of enum types. // The generated code will register the generated maps by calling RegisterEnum. var enumValueMaps = make(map[string]map[string]int32) // RegisterEnum is called from the generated code to install the enum descriptor // maps into the global table to aid parsing text format protocol buffers. func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { if _, ok := enumValueMaps[typeName]; ok { panic("proto: duplicate enum registered: " + typeName) } enumValueMaps[typeName] = valueMap } // EnumValueMap returns the mapping from names to integers of the // enum type enumType, or a nil if not found. func EnumValueMap(enumType string) map[string]int32 { return enumValueMaps[enumType] } // A registry of all linked message types. // The string is a fully-qualified proto name ("pkg.Message"). var ( protoTypedNils = make(map[string]Message) // a map from proto names to typed nil pointers protoMapTypes = make(map[string]reflect.Type) // a map from proto names to map types revProtoTypes = make(map[reflect.Type]string) ) // RegisterType is called from generated code and maps from the fully qualified // proto name to the type (pointer to struct) of the protocol buffer. func RegisterType(x Message, name string) { if _, ok := protoTypedNils[name]; ok { // TODO: Some day, make this a panic. log.Printf("proto: duplicate proto type registered: %s", name) return } t := reflect.TypeOf(x) if v := reflect.ValueOf(x); v.Kind() == reflect.Ptr && v.Pointer() == 0 { // Generated code always calls RegisterType with nil x. // This check is just for extra safety. protoTypedNils[name] = x } else { protoTypedNils[name] = reflect.Zero(t).Interface().(Message) } revProtoTypes[t] = name } // RegisterMapType is called from generated code and maps from the fully qualified // proto name to the native map type of the proto map definition. func RegisterMapType(x interface{}, name string) { if reflect.TypeOf(x).Kind() != reflect.Map { panic(fmt.Sprintf("RegisterMapType(%T, %q); want map", x, name)) } if _, ok := protoMapTypes[name]; ok { log.Printf("proto: duplicate proto type registered: %s", name) return } t := reflect.TypeOf(x) protoMapTypes[name] = t revProtoTypes[t] = name } // MessageName returns the fully-qualified proto name for the given message type. func MessageName(x Message) string { type xname interface { XXX_MessageName() string } if m, ok := x.(xname); ok { return m.XXX_MessageName() } return revProtoTypes[reflect.TypeOf(x)] } // MessageType returns the message type (pointer to struct) for a named message. // The type is not guaranteed to implement proto.Message if the name refers to a // map entry. func MessageType(name string) reflect.Type { if t, ok := protoTypedNils[name]; ok { return reflect.TypeOf(t) } return protoMapTypes[name] } // A registry of all linked proto files. var ( protoFiles = make(map[string][]byte) // file name => fileDescriptor ) // RegisterFile is called from generated code and maps from the // full file name of a .proto file to its compressed FileDescriptorProto. func RegisterFile(filename string, fileDescriptor []byte) { protoFiles[filename] = fileDescriptor } // FileDescriptor returns the compressed FileDescriptorProto for a .proto file. func FileDescriptor(filename string) []byte { return protoFiles[filename] } ================================================ FILE: vendor/github.com/golang/protobuf/proto/table_marshal.go ================================================ // 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) deref bool // dereference the pointer before operating on it; implies isptr } 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, errLater 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 { if ptr.offset(f.field).getPointer().isNil() { // Required field is not set. // We record the error but keep going, to give a complete marshaling. if errLater == nil { errLater = &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 errLater == nil { errLater = &RequiredNotSetError{f.name + "." + err1.field} } continue } if err == errRepeatedHasNil { err = errors.New("proto: repeated field " + f.name + " has nil element") } if err == errInvalidUTF8 { if errLater == nil { fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name errLater = &invalidUTF8Error{fullName} } continue } return b, err } } if u.unrecognized.IsValid() { s := *ptr.offset(u.unrecognized).toBytes() b = append(b, s...) } return b, errLater } // 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{} switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { case oneofFuncsIface: _, _, _, oneofImplementers = m.XXX_OneofFuncs() case oneofWrappersIface: oneofImplementers = m.XXX_OneofWrappers() } 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]) if t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct { t = t.Elem() } sizer, marshaler := typeMarshaler(t, tags, false, false) var deref bool if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { t = reflect.PtrTo(t) deref = true } e = &marshalElemInfo{ wiretag: uint64(tag)<<3 | wt, tagsize: SizeVarint(uint64(tag) << 3), sizer: sizer, marshaler: marshaler, isptr: t.Kind() == reflect.Ptr, deref: deref, } // 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 = math.MaxInt32 // 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, } } } // 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 validateUTF8 := true for i := 2; i < len(tags); i++ { if tags[i] == "packed" { packed = true } if tags[i] == "proto3" { proto3 = true } } validateUTF8 = validateUTF8 && proto3 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 validateUTF8 { if pointer { return sizeStringPtr, appendUTF8StringPtr } if slice { return sizeStringSlice, appendUTF8StringSlice } if nozero { return sizeStringValueNoZero, appendUTF8StringValueNoZero } return sizeStringValue, appendUTF8StringValue } 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() 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 } 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 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 { b = appendVarint(b, wiretag) b = appendVarint(b, uint64(len(v))) b = append(b, v...) } return b, nil } func appendUTF8StringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { var invalidUTF8 bool v := *ptr.toString() if !utf8.ValidString(v) { invalidUTF8 = true } b = appendVarint(b, wiretag) b = appendVarint(b, uint64(len(v))) b = append(b, v...) if invalidUTF8 { return b, errInvalidUTF8 } return b, nil } func appendUTF8StringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { var invalidUTF8 bool v := *ptr.toString() if v == "" { return b, nil } if !utf8.ValidString(v) { invalidUTF8 = true } b = appendVarint(b, wiretag) b = appendVarint(b, uint64(len(v))) b = append(b, v...) if invalidUTF8 { return b, errInvalidUTF8 } return b, nil } func appendUTF8StringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { var invalidUTF8 bool p := *ptr.toStringPtr() if p == nil { return b, nil } v := *p if !utf8.ValidString(v) { invalidUTF8 = true } b = appendVarint(b, wiretag) b = appendVarint(b, uint64(len(v))) b = append(b, v...) if invalidUTF8 { return b, errInvalidUTF8 } return b, nil } func appendUTF8StringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { var invalidUTF8 bool s := *ptr.toStringSlice() for _, v := range s { if !utf8.ValidString(v) { invalidUTF8 = true } b = appendVarint(b, wiretag) b = appendVarint(b, uint64(len(v))) b = append(b, v...) } if invalidUTF8 { return b, errInvalidUTF8 } 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 error var nerr nonFatal 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 !nerr.Merge(err) { if err == ErrNil { err = errRepeatedHasNil } return b, err } } return b, nerr.E } } // 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 error var nerr nonFatal 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 !nerr.Merge(err) { if err == ErrNil { err = errRepeatedHasNil } return b, err } } return b, nerr.E } } // 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 // If value is a message with nested maps, calling // valSizer in marshal may be quadratic. We should use // cached version in marshal (but not in size). // If value is not message type, we don't have size cache, // but it cannot be nested either. Just use valSizer. valCachedSizer := valSizer if valIsPtr && valType.Elem().Kind() == reflect.Struct { u := getMarshalInfo(valType.Elem()) valCachedSizer = func(ptr pointer, tagsize int) int { // Same as message sizer, but use cache. p := ptr.getPointer() if p.isNil() { return 0 } siz := u.cachedsize(p) return siz + SizeVarint(uint64(siz)) + tagsize } } 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, false) // pointer to key vaddr := toAddrPointer(&vi, valIsPtr, false) // 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)) } var nerr nonFatal for _, k := range keys { ki := k.Interface() vi := m.MapIndex(k).Interface() kaddr := toAddrPointer(&ki, false, false) // pointer to key vaddr := toAddrPointer(&vi, valIsPtr, false) // pointer to value b = appendVarint(b, tag) siz := keySizer(kaddr, 1) + valCachedSizer(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 !nerr.Merge(err) { return b, err } b, err = valMarshaler(b, vaddr, valWireTag, deterministic) if err != ErrNil && !nerr.Merge(err) { // allow nil value in map return b, err } } return b, nerr.E } } // 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, ei.deref) 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 var nerr nonFatal // 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, ei.deref) b, err = ei.marshaler(b, p, ei.wiretag, deterministic) if !nerr.Merge(err) { return b, err } } return b, nerr.E } // 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, ei.deref) b, err = ei.marshaler(b, p, ei.wiretag, deterministic) if !nerr.Merge(err) { return b, err } } return b, nerr.E } // 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, ei.deref) 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 var nerr nonFatal // 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, ei.deref) b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) if !nerr.Merge(err) { return b, err } b = append(b, 1<<3|WireEndGroup) } return b, nerr.E } // 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, ei.deref) b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) b = append(b, 1<<3|WireEndGroup) if !nerr.Merge(err) { return b, err } } return b, nerr.E } // 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, ei.deref) 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 var nerr nonFatal 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, ei.deref) b, err = ei.marshaler(b, p, ei.wiretag, deterministic) if !nerr.Merge(err) { return b, err } } return b, nerr.E } // 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...) } ================================================ FILE: vendor/github.com/golang/protobuf/proto/table_merge.go ================================================ // 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) } ================================================ FILE: vendor/github.com/golang/protobuf/proto/table_unmarshal.go ================================================ // 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. if errLater == nil { errLater = r } reqMask |= f.reqMask continue } if err != errInternalBadWireType { if err == errInvalidUTF8 { if errLater == nil { fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name errLater = &invalidUTF8Error{fullName} } continue } 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 reqMask != u.reqMask && errLater == nil { // A required field of this message is missing. for _, n := range u.reqFields { if reqMask&1 == 0 { errLater = &RequiredNotSetError{n} } reqMask >>= 1 } } return errLater } // 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, name) } // Find any types associated with oneof fields. var oneofImplementers []interface{} switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { case oneofFuncsIface: _, _, _, oneofImplementers = m.XXX_OneofFuncs() case oneofWrappersIface: oneofImplementers = m.XXX_OneofWrappers() } for _, v := range oneofImplementers { tptr := reflect.TypeOf(v) // *Msg_X typ := tptr.Elem() // Msg_X f := typ.Field(0) // oneof implementers have one field baseUnmarshal := fieldUnmarshaler(&f) tags := strings.Split(f.Tag.Get("protobuf"), ",") fieldNum, err := strconv.Atoi(tags[1]) if err != nil { panic("protobuf tag field not an integer: " + tags[1]) } var name string for _, tag := range tags { if strings.HasPrefix(tag, "name=") { name = strings.TrimPrefix(tag, "name=") break } } // 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(fieldNum, of.field, unmarshal, 0, name) } } } // 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" proto3 := false validateUTF8 := true for _, tag := range tagArray[3:] { if strings.HasPrefix(tag, "name=") { name = tag[5:] } if tag == "proto3" { proto3 = true } } validateUTF8 = validateUTF8 && proto3 // 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 validateUTF8 { if pointer { return unmarshalUTF8StringPtr } if slice { return unmarshalUTF8StringSlice } return unmarshalUTF8StringValue } 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]) *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]) *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]) s := f.toStringSlice() *s = append(*s, v) return b[x:], nil } func unmarshalUTF8StringValue(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]) *f.toString() = v if !utf8.ValidString(v) { return b[x:], errInvalidUTF8 } return b[x:], nil } func unmarshalUTF8StringPtr(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]) *f.toStringPtr() = &v if !utf8.ValidString(v) { return b[x:], errInvalidUTF8 } return b[x:], nil } func unmarshalUTF8StringSlice(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]) s := f.toStringSlice() *s = append(*s, v) if !utf8.ValidString(v) { return b[x:], errInvalidUTF8 } 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. var nerr nonFatal 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 nerr.Merge(err) { 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, nerr.E } } // 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 var nerr nonFatal b, err = unmarshal(b, valToPointer(v).offset(field0), w) if !nerr.Merge(err) { return nil, err } // Write pointer to holder into target field. f.asPointerTo(ityp).Elem().Set(v) return b, nerr.E } } // 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 } ================================================ FILE: vendor/github.com/golang/protobuf/proto/text.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package proto // Functions for writing the text protocol buffer format. import ( "bufio" "bytes" "encoding" "errors" "fmt" "io" "log" "math" "reflect" "sort" "strings" ) var ( newline = []byte("\n") spaces = []byte(" ") endBraceNewline = []byte("}\n") backslashN = []byte{'\\', 'n'} backslashR = []byte{'\\', 'r'} backslashT = []byte{'\\', 't'} backslashDQ = []byte{'\\', '"'} backslashBS = []byte{'\\', '\\'} posInf = []byte("inf") negInf = []byte("-inf") nan = []byte("nan") ) type writer interface { io.Writer WriteByte(byte) error } // textWriter is an io.Writer that tracks its indentation level. type textWriter struct { ind int complete bool // if the current position is a complete line compact bool // whether to write out as a one-liner w writer } func (w *textWriter) WriteString(s string) (n int, err error) { if !strings.Contains(s, "\n") { if !w.compact && w.complete { w.writeIndent() } w.complete = false return io.WriteString(w.w, s) } // WriteString is typically called without newlines, so this // codepath and its copy are rare. We copy to avoid // duplicating all of Write's logic here. return w.Write([]byte(s)) } func (w *textWriter) Write(p []byte) (n int, err error) { newlines := bytes.Count(p, newline) if newlines == 0 { if !w.compact && w.complete { w.writeIndent() } n, err = w.w.Write(p) w.complete = false return n, err } frags := bytes.SplitN(p, newline, newlines+1) if w.compact { for i, frag := range frags { if i > 0 { if err := w.w.WriteByte(' '); err != nil { return n, err } n++ } nn, err := w.w.Write(frag) n += nn if err != nil { return n, err } } return n, nil } for i, frag := range frags { if w.complete { w.writeIndent() } nn, err := w.w.Write(frag) n += nn if err != nil { return n, err } if i+1 < len(frags) { if err := w.w.WriteByte('\n'); err != nil { return n, err } n++ } } w.complete = len(frags[len(frags)-1]) == 0 return n, nil } func (w *textWriter) WriteByte(c byte) error { if w.compact && c == '\n' { c = ' ' } if !w.compact && w.complete { w.writeIndent() } err := w.w.WriteByte(c) w.complete = c == '\n' return err } func (w *textWriter) indent() { w.ind++ } func (w *textWriter) unindent() { if w.ind == 0 { log.Print("proto: textWriter unindented too far") return } w.ind-- } func writeName(w *textWriter, props *Properties) error { if _, err := w.WriteString(props.OrigName); err != nil { return err } if props.Wire != "group" { return w.WriteByte(':') } return nil } func requiresQuotes(u string) bool { // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. for _, ch := range u { switch { case ch == '.' || ch == '/' || ch == '_': continue case '0' <= ch && ch <= '9': continue case 'A' <= ch && ch <= 'Z': continue case 'a' <= ch && ch <= 'z': continue default: return true } } return false } // isAny reports whether sv is a google.protobuf.Any message func isAny(sv reflect.Value) bool { type wkt interface { XXX_WellKnownType() string } t, ok := sv.Addr().Interface().(wkt) return ok && t.XXX_WellKnownType() == "Any" } // writeProto3Any writes an expanded google.protobuf.Any message. // // It returns (false, nil) if sv value can't be unmarshaled (e.g. because // required messages are not linked in). // // It returns (true, error) when sv was written in expanded format or an error // was encountered. func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { turl := sv.FieldByName("TypeUrl") val := sv.FieldByName("Value") if !turl.IsValid() || !val.IsValid() { return true, errors.New("proto: invalid google.protobuf.Any message") } b, ok := val.Interface().([]byte) if !ok { return true, errors.New("proto: invalid google.protobuf.Any message") } parts := strings.Split(turl.String(), "/") mt := MessageType(parts[len(parts)-1]) if mt == nil { return false, nil } m := reflect.New(mt.Elem()) if err := Unmarshal(b, m.Interface().(Message)); err != nil { return false, nil } w.Write([]byte("[")) u := turl.String() if requiresQuotes(u) { writeString(w, u) } else { w.Write([]byte(u)) } if w.compact { w.Write([]byte("]:<")) } else { w.Write([]byte("]: <\n")) w.ind++ } if err := tm.writeStruct(w, m.Elem()); err != nil { return true, err } if w.compact { w.Write([]byte("> ")) } else { w.ind-- w.Write([]byte(">\n")) } return true, nil } func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { if tm.ExpandAny && isAny(sv) { if canExpand, err := tm.writeProto3Any(w, sv); canExpand { return err } } st := sv.Type() sprops := GetProperties(st) for i := 0; i < sv.NumField(); i++ { fv := sv.Field(i) props := sprops.Prop[i] name := st.Field(i).Name if name == "XXX_NoUnkeyedLiteral" { continue } if strings.HasPrefix(name, "XXX_") { // There are two XXX_ fields: // XXX_unrecognized []byte // XXX_extensions map[int32]proto.Extension // The first is handled here; // the second is handled at the bottom of this function. if name == "XXX_unrecognized" && !fv.IsNil() { if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { return err } } continue } if fv.Kind() == reflect.Ptr && fv.IsNil() { // Field not filled in. This could be an optional field or // a required field that wasn't filled in. Either way, there // isn't anything we can show for it. continue } if fv.Kind() == reflect.Slice && fv.IsNil() { // Repeated field that is empty, or a bytes field that is unused. continue } if props.Repeated && fv.Kind() == reflect.Slice { // Repeated field. for j := 0; j < fv.Len(); j++ { if err := writeName(w, props); err != nil { return err } if !w.compact { if err := w.WriteByte(' '); err != nil { return err } } v := fv.Index(j) if v.Kind() == reflect.Ptr && v.IsNil() { // A nil message in a repeated field is not valid, // but we can handle that more gracefully than panicking. if _, err := w.Write([]byte("\n")); err != nil { return err } continue } if err := tm.writeAny(w, v, props); err != nil { return err } if err := w.WriteByte('\n'); err != nil { return err } } continue } if fv.Kind() == reflect.Map { // Map fields are rendered as a repeated struct with key/value fields. keys := fv.MapKeys() sort.Sort(mapKeys(keys)) for _, key := range keys { val := fv.MapIndex(key) if err := writeName(w, props); err != nil { return err } if !w.compact { if err := w.WriteByte(' '); err != nil { return err } } // open struct if err := w.WriteByte('<'); err != nil { return err } if !w.compact { if err := w.WriteByte('\n'); err != nil { return err } } w.indent() // key if _, err := w.WriteString("key:"); err != nil { return err } if !w.compact { if err := w.WriteByte(' '); err != nil { return err } } if err := tm.writeAny(w, key, props.MapKeyProp); err != nil { return err } if err := w.WriteByte('\n'); err != nil { return err } // nil values aren't legal, but we can avoid panicking because of them. if val.Kind() != reflect.Ptr || !val.IsNil() { // value if _, err := w.WriteString("value:"); err != nil { return err } if !w.compact { if err := w.WriteByte(' '); err != nil { return err } } if err := tm.writeAny(w, val, props.MapValProp); err != nil { return err } if err := w.WriteByte('\n'); err != nil { return err } } // close struct w.unindent() if err := w.WriteByte('>'); err != nil { return err } if err := w.WriteByte('\n'); err != nil { return err } } continue } if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { // empty bytes field continue } if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { // proto3 non-repeated scalar field; skip if zero value if isProto3Zero(fv) { continue } } if fv.Kind() == reflect.Interface { // Check if it is a oneof. if st.Field(i).Tag.Get("protobuf_oneof") != "" { // fv is nil, or holds a pointer to generated struct. // That generated struct has exactly one field, // which has a protobuf struct tag. if fv.IsNil() { continue } inner := fv.Elem().Elem() // interface -> *T -> T tag := inner.Type().Field(0).Tag.Get("protobuf") props = new(Properties) // Overwrite the outer props var, but not its pointee. props.Parse(tag) // Write the value in the oneof, not the oneof itself. fv = inner.Field(0) // Special case to cope with malformed messages gracefully: // If the value in the oneof is a nil pointer, don't panic // in writeAny. if fv.Kind() == reflect.Ptr && fv.IsNil() { // Use errors.New so writeAny won't render quotes. msg := errors.New("/* nil */") fv = reflect.ValueOf(&msg).Elem() } } } if err := writeName(w, props); err != nil { return err } if !w.compact { if err := w.WriteByte(' '); err != nil { return err } } // Enums have a String method, so writeAny will work fine. if err := tm.writeAny(w, fv, props); err != nil { return err } if err := w.WriteByte('\n'); err != nil { return err } } // Extensions (the XXX_extensions field). pv := sv.Addr() if _, err := extendable(pv.Interface()); err == nil { if err := tm.writeExtensions(w, pv); err != nil { return err } } return nil } // writeAny writes an arbitrary field. func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { v = reflect.Indirect(v) // Floats have special cases. if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { x := v.Float() var b []byte switch { case math.IsInf(x, 1): b = posInf case math.IsInf(x, -1): b = negInf case math.IsNaN(x): b = nan } if b != nil { _, err := w.Write(b) return err } // Other values are handled below. } // We don't attempt to serialise every possible value type; only those // that can occur in protocol buffers. switch v.Kind() { case reflect.Slice: // Should only be a []byte; repeated fields are handled in writeStruct. if err := writeString(w, string(v.Bytes())); err != nil { return err } case reflect.String: if err := writeString(w, v.String()); err != nil { return err } case reflect.Struct: // Required/optional group/message. var bra, ket byte = '<', '>' if props != nil && props.Wire == "group" { bra, ket = '{', '}' } if err := w.WriteByte(bra); err != nil { return err } if !w.compact { if err := w.WriteByte('\n'); err != nil { return err } } w.indent() if v.CanAddr() { // Calling v.Interface on a struct causes the reflect package to // copy the entire struct. This is racy with the new Marshaler // since we atomically update the XXX_sizecache. // // Thus, we retrieve a pointer to the struct if possible to avoid // a race since v.Interface on the pointer doesn't copy the struct. // // If v is not addressable, then we are not worried about a race // since it implies that the binary Marshaler cannot possibly be // mutating this value. v = v.Addr() } if etm, ok := v.Interface().(encoding.TextMarshaler); ok { text, err := etm.MarshalText() if err != nil { return err } if _, err = w.Write(text); err != nil { return err } } else { if v.Kind() == reflect.Ptr { v = v.Elem() } if err := tm.writeStruct(w, v); err != nil { return err } } w.unindent() if err := w.WriteByte(ket); err != nil { return err } default: _, err := fmt.Fprint(w, v.Interface()) return err } return nil } // equivalent to C's isprint. func isprint(c byte) bool { return c >= 0x20 && c < 0x7f } // writeString writes a string in the protocol buffer text format. // It is similar to strconv.Quote except we don't use Go escape sequences, // we treat the string as a byte sequence, and we use octal escapes. // These differences are to maintain interoperability with the other // languages' implementations of the text format. func writeString(w *textWriter, s string) error { // use WriteByte here to get any needed indent if err := w.WriteByte('"'); err != nil { return err } // Loop over the bytes, not the runes. for i := 0; i < len(s); i++ { var err error // Divergence from C++: we don't escape apostrophes. // There's no need to escape them, and the C++ parser // copes with a naked apostrophe. switch c := s[i]; c { case '\n': _, err = w.w.Write(backslashN) case '\r': _, err = w.w.Write(backslashR) case '\t': _, err = w.w.Write(backslashT) case '"': _, err = w.w.Write(backslashDQ) case '\\': _, err = w.w.Write(backslashBS) default: if isprint(c) { err = w.w.WriteByte(c) } else { _, err = fmt.Fprintf(w.w, "\\%03o", c) } } if err != nil { return err } } return w.WriteByte('"') } func writeUnknownStruct(w *textWriter, data []byte) (err error) { if !w.compact { if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { return err } } b := NewBuffer(data) for b.index < len(b.buf) { x, err := b.DecodeVarint() if err != nil { _, err := fmt.Fprintf(w, "/* %v */\n", err) return err } wire, tag := x&7, x>>3 if wire == WireEndGroup { w.unindent() if _, err := w.Write(endBraceNewline); err != nil { return err } continue } if _, err := fmt.Fprint(w, tag); err != nil { return err } if wire != WireStartGroup { if err := w.WriteByte(':'); err != nil { return err } } if !w.compact || wire == WireStartGroup { if err := w.WriteByte(' '); err != nil { return err } } switch wire { case WireBytes: buf, e := b.DecodeRawBytes(false) if e == nil { _, err = fmt.Fprintf(w, "%q", buf) } else { _, err = fmt.Fprintf(w, "/* %v */", e) } case WireFixed32: x, err = b.DecodeFixed32() err = writeUnknownInt(w, x, err) case WireFixed64: x, err = b.DecodeFixed64() err = writeUnknownInt(w, x, err) case WireStartGroup: err = w.WriteByte('{') w.indent() case WireVarint: x, err = b.DecodeVarint() err = writeUnknownInt(w, x, err) default: _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) } if err != nil { return err } if err = w.WriteByte('\n'); err != nil { return err } } return nil } func writeUnknownInt(w *textWriter, x uint64, err error) error { if err == nil { _, err = fmt.Fprint(w, x) } else { _, err = fmt.Fprintf(w, "/* %v */", err) } return err } type int32Slice []int32 func (s int32Slice) Len() int { return len(s) } func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // writeExtensions writes all the extensions in pv. // pv is assumed to be a pointer to a protocol message struct that is extendable. func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { emap := extensionMaps[pv.Type().Elem()] ep, _ := extendable(pv.Interface()) // Order the extensions by ID. // This isn't strictly necessary, but it will give us // canonical output, which will also make testing easier. m, mu := ep.extensionsRead() if m == nil { return nil } mu.Lock() ids := make([]int32, 0, len(m)) for id := range m { ids = append(ids, id) } sort.Sort(int32Slice(ids)) mu.Unlock() for _, extNum := range ids { ext := m[extNum] var desc *ExtensionDesc if emap != nil { desc = emap[extNum] } if desc == nil { // Unknown extension. if err := writeUnknownStruct(w, ext.enc); err != nil { return err } continue } pb, err := GetExtension(ep, desc) if err != nil { return fmt.Errorf("failed getting extension: %v", err) } // Repeated extensions will appear as a slice. if !desc.repeated() { if err := tm.writeExtension(w, desc.Name, pb); err != nil { return err } } else { v := reflect.ValueOf(pb) for i := 0; i < v.Len(); i++ { if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { return err } } } } return nil } func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { return err } if !w.compact { if err := w.WriteByte(' '); err != nil { return err } } if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { return err } if err := w.WriteByte('\n'); err != nil { return err } return nil } func (w *textWriter) writeIndent() { if !w.complete { return } remain := w.ind * 2 for remain > 0 { n := remain if n > len(spaces) { n = len(spaces) } w.w.Write(spaces[:n]) remain -= n } w.complete = false } // TextMarshaler is a configurable text format marshaler. type TextMarshaler struct { Compact bool // use compact text format (one line). ExpandAny bool // expand google.protobuf.Any messages of known types } // Marshal writes a given protocol buffer in text format. // The only errors returned are from w. func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { val := reflect.ValueOf(pb) if pb == nil || val.IsNil() { w.Write([]byte("")) return nil } var bw *bufio.Writer ww, ok := w.(writer) if !ok { bw = bufio.NewWriter(w) ww = bw } aw := &textWriter{ w: ww, complete: true, compact: tm.Compact, } if etm, ok := pb.(encoding.TextMarshaler); ok { text, err := etm.MarshalText() if err != nil { return err } if _, err = aw.Write(text); err != nil { return err } if bw != nil { return bw.Flush() } return nil } // Dereference the received pointer so we don't have outer < and >. v := reflect.Indirect(val) if err := tm.writeStruct(aw, v); err != nil { return err } if bw != nil { return bw.Flush() } return nil } // Text is the same as Marshal, but returns the string directly. func (tm *TextMarshaler) Text(pb Message) string { var buf bytes.Buffer tm.Marshal(&buf, pb) return buf.String() } var ( defaultTextMarshaler = TextMarshaler{} compactTextMarshaler = TextMarshaler{Compact: true} ) // TODO: consider removing some of the Marshal functions below. // MarshalText writes a given protocol buffer in text format. // The only errors returned are from w. func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } // MarshalTextString is the same as MarshalText, but returns the string directly. func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } // CompactText writes a given protocol buffer in compact text format (one line). func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } // CompactTextString is the same as CompactText, but returns the string directly. func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } ================================================ FILE: vendor/github.com/golang/protobuf/proto/text_parser.go ================================================ // Go support for Protocol Buffers - Google's data interchange format // // Copyright 2010 The Go Authors. All rights reserved. // https://github.com/golang/protobuf // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package proto // Functions for parsing the Text protocol buffer format. // TODO: message sets. import ( "encoding" "errors" "fmt" "reflect" "strconv" "strings" "unicode/utf8" ) // Error string emitted when deserializing Any and fields are already set const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" type ParseError struct { Message string Line int // 1-based line number Offset int // 0-based byte offset from start of input } func (p *ParseError) Error() string { if p.Line == 1 { // show offset only for first line return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) } return fmt.Sprintf("line %d: %v", p.Line, p.Message) } type token struct { value string err *ParseError line int // line number offset int // byte number from start of input, not start of line unquoted string // the unquoted version of value, if it was a quoted string } func (t *token) String() string { if t.err == nil { return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) } return fmt.Sprintf("parse error: %v", t.err) } type textParser struct { s string // remaining input done bool // whether the parsing is finished (success or error) backed bool // whether back() was called offset, line int cur token } func newTextParser(s string) *textParser { p := new(textParser) p.s = s p.line = 1 p.cur.line = 1 return p } func (p *textParser) errorf(format string, a ...interface{}) *ParseError { pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} p.cur.err = pe p.done = true return pe } // Numbers and identifiers are matched by [-+._A-Za-z0-9] func isIdentOrNumberChar(c byte) bool { switch { case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': return true case '0' <= c && c <= '9': return true } switch c { case '-', '+', '.', '_': return true } return false } func isWhitespace(c byte) bool { switch c { case ' ', '\t', '\n', '\r': return true } return false } func isQuote(c byte) bool { switch c { case '"', '\'': return true } return false } func (p *textParser) skipWhitespace() { i := 0 for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { if p.s[i] == '#' { // comment; skip to end of line or input for i < len(p.s) && p.s[i] != '\n' { i++ } if i == len(p.s) { break } } if p.s[i] == '\n' { p.line++ } i++ } p.offset += i p.s = p.s[i:len(p.s)] if len(p.s) == 0 { p.done = true } } func (p *textParser) advance() { // Skip whitespace p.skipWhitespace() if p.done { return } // Start of non-whitespace p.cur.err = nil p.cur.offset, p.cur.line = p.offset, p.line p.cur.unquoted = "" switch p.s[0] { case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': // Single symbol p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] case '"', '\'': // Quoted string i := 1 for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { if p.s[i] == '\\' && i+1 < len(p.s) { // skip escaped char i++ } i++ } if i >= len(p.s) || p.s[i] != p.s[0] { p.errorf("unmatched quote") return } unq, err := unquoteC(p.s[1:i], rune(p.s[0])) if err != nil { p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) return } p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] p.cur.unquoted = unq default: i := 0 for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { i++ } if i == 0 { p.errorf("unexpected byte %#x", p.s[0]) return } p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] } p.offset += len(p.cur.value) } var ( errBadUTF8 = errors.New("proto: bad UTF-8") ) func unquoteC(s string, quote rune) (string, error) { // This is based on C++'s tokenizer.cc. // Despite its name, this is *not* parsing C syntax. // For instance, "\0" is an invalid quoted string. // Avoid allocation in trivial cases. simple := true for _, r := range s { if r == '\\' || r == quote { simple = false break } } if simple { return s, nil } buf := make([]byte, 0, 3*len(s)/2) for len(s) > 0 { r, n := utf8.DecodeRuneInString(s) if r == utf8.RuneError && n == 1 { return "", errBadUTF8 } s = s[n:] if r != '\\' { if r < utf8.RuneSelf { buf = append(buf, byte(r)) } else { buf = append(buf, string(r)...) } continue } ch, tail, err := unescape(s) if err != nil { return "", err } buf = append(buf, ch...) s = tail } return string(buf), nil } func unescape(s string) (ch string, tail string, err error) { r, n := utf8.DecodeRuneInString(s) if r == utf8.RuneError && n == 1 { return "", "", errBadUTF8 } s = s[n:] switch r { case 'a': return "\a", s, nil case 'b': return "\b", s, nil case 'f': return "\f", s, nil case 'n': return "\n", s, nil case 'r': return "\r", s, nil case 't': return "\t", s, nil case 'v': return "\v", s, nil case '?': return "?", s, nil // trigraph workaround case '\'', '"', '\\': return string(r), s, nil case '0', '1', '2', '3', '4', '5', '6', '7': if len(s) < 2 { return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) } ss := string(r) + s[:2] s = s[2:] i, err := strconv.ParseUint(ss, 8, 8) if err != nil { return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss) } return string([]byte{byte(i)}), s, nil case 'x', 'X', 'u', 'U': var n int switch r { case 'x', 'X': n = 2 case 'u': n = 4 case 'U': n = 8 } if len(s) < n { return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n) } ss := s[:n] s = s[n:] i, err := strconv.ParseUint(ss, 16, 64) if err != nil { return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss) } if r == 'x' || r == 'X' { return string([]byte{byte(i)}), s, nil } if i > utf8.MaxRune { return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss) } return string(i), s, nil } return "", "", fmt.Errorf(`unknown escape \%c`, r) } // Back off the parser by one token. Can only be done between calls to next(). // It makes the next advance() a no-op. func (p *textParser) back() { p.backed = true } // Advances the parser and returns the new current token. func (p *textParser) next() *token { if p.backed || p.done { p.backed = false return &p.cur } p.advance() if p.done { p.cur.value = "" } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { // Look for multiple quoted strings separated by whitespace, // and concatenate them. cat := p.cur for { p.skipWhitespace() if p.done || !isQuote(p.s[0]) { break } p.advance() if p.cur.err != nil { return &p.cur } cat.value += " " + p.cur.value cat.unquoted += p.cur.unquoted } p.done = false // parser may have seen EOF, but we want to return cat p.cur = cat } return &p.cur } func (p *textParser) consumeToken(s string) error { tok := p.next() if tok.err != nil { return tok.err } if tok.value != s { p.back() return p.errorf("expected %q, found %q", s, tok.value) } return nil } // Return a RequiredNotSetError indicating which required field was not set. func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { st := sv.Type() sprops := GetProperties(st) for i := 0; i < st.NumField(); i++ { if !isNil(sv.Field(i)) { continue } props := sprops.Prop[i] if props.Required { return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} } } return &RequiredNotSetError{fmt.Sprintf("%v.", st)} // should not happen } // Returns the index in the struct for the named field, as well as the parsed tag properties. func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { i, ok := sprops.decoderOrigNames[name] if ok { return i, sprops.Prop[i], true } return -1, nil, false } // Consume a ':' from the input stream (if the next token is a colon), // returning an error if a colon is needed but not present. func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { tok := p.next() if tok.err != nil { return tok.err } if tok.value != ":" { // Colon is optional when the field is a group or message. needColon := true switch props.Wire { case "group": needColon = false case "bytes": // A "bytes" field is either a message, a string, or a repeated field; // those three become *T, *string and []T respectively, so we can check for // this field being a pointer to a non-string. if typ.Kind() == reflect.Ptr { // *T or *string if typ.Elem().Kind() == reflect.String { break } } else if typ.Kind() == reflect.Slice { // []T or []*T if typ.Elem().Kind() != reflect.Ptr { break } } else if typ.Kind() == reflect.String { // The proto3 exception is for a string field, // which requires a colon. break } needColon = false } if needColon { return p.errorf("expected ':', found %q", tok.value) } p.back() } return nil } func (p *textParser) readStruct(sv reflect.Value, terminator string) error { st := sv.Type() sprops := GetProperties(st) reqCount := sprops.reqCount var reqFieldErr error fieldSet := make(map[string]bool) // A struct is a sequence of "name: value", terminated by one of // '>' or '}', or the end of the input. A name may also be // "[extension]" or "[type/url]". // // The whole struct can also be an expanded Any message, like: // [type/url] < ... struct contents ... > for { tok := p.next() if tok.err != nil { return tok.err } if tok.value == terminator { break } if tok.value == "[" { // Looks like an extension or an Any. // // TODO: Check whether we need to handle // namespace rooted names (e.g. ".something.Foo"). extName, err := p.consumeExtName() if err != nil { return err } if s := strings.LastIndex(extName, "/"); s >= 0 { // If it contains a slash, it's an Any type URL. messageName := extName[s+1:] mt := MessageType(messageName) if mt == nil { return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) } tok = p.next() if tok.err != nil { return tok.err } // consume an optional colon if tok.value == ":" { tok = p.next() if tok.err != nil { return tok.err } } var terminator string switch tok.value { case "<": terminator = ">" case "{": terminator = "}" default: return p.errorf("expected '{' or '<', found %q", tok.value) } v := reflect.New(mt.Elem()) if pe := p.readStruct(v.Elem(), terminator); pe != nil { return pe } b, err := Marshal(v.Interface().(Message)) if err != nil { return p.errorf("failed to marshal message of type %q: %v", messageName, err) } if fieldSet["type_url"] { return p.errorf(anyRepeatedlyUnpacked, "type_url") } if fieldSet["value"] { return p.errorf(anyRepeatedlyUnpacked, "value") } sv.FieldByName("TypeUrl").SetString(extName) sv.FieldByName("Value").SetBytes(b) fieldSet["type_url"] = true fieldSet["value"] = true continue } var desc *ExtensionDesc // This could be faster, but it's functional. // TODO: Do something smarter than a linear scan. for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { if d.Name == extName { desc = d break } } if desc == nil { return p.errorf("unrecognized extension %q", extName) } props := &Properties{} props.Parse(desc.Tag) typ := reflect.TypeOf(desc.ExtensionType) if err := p.checkForColon(props, typ); err != nil { return err } rep := desc.repeated() // Read the extension structure, and set it in // the value we're constructing. var ext reflect.Value if !rep { ext = reflect.New(typ).Elem() } else { ext = reflect.New(typ.Elem()).Elem() } if err := p.readAny(ext, props); err != nil { if _, ok := err.(*RequiredNotSetError); !ok { return err } reqFieldErr = err } ep := sv.Addr().Interface().(Message) if !rep { SetExtension(ep, desc, ext.Interface()) } else { old, err := GetExtension(ep, desc) var sl reflect.Value if err == nil { sl = reflect.ValueOf(old) // existing slice } else { sl = reflect.MakeSlice(typ, 0, 1) } sl = reflect.Append(sl, ext) SetExtension(ep, desc, sl.Interface()) } if err := p.consumeOptionalSeparator(); err != nil { return err } continue } // This is a normal, non-extension field. name := tok.value var dst reflect.Value fi, props, ok := structFieldByName(sprops, name) if ok { dst = sv.Field(fi) } else if oop, ok := sprops.OneofTypes[name]; ok { // It is a oneof. props = oop.Prop nv := reflect.New(oop.Type.Elem()) dst = nv.Elem().Field(0) field := sv.Field(oop.Field) if !field.IsNil() { return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) } field.Set(nv) } if !dst.IsValid() { return p.errorf("unknown field name %q in %v", name, st) } if dst.Kind() == reflect.Map { // Consume any colon. if err := p.checkForColon(props, dst.Type()); err != nil { return err } // Construct the map if it doesn't already exist. if dst.IsNil() { dst.Set(reflect.MakeMap(dst.Type())) } key := reflect.New(dst.Type().Key()).Elem() val := reflect.New(dst.Type().Elem()).Elem() // The map entry should be this sequence of tokens: // < key : KEY value : VALUE > // However, implementations may omit key or value, and technically // we should support them in any order. See b/28924776 for a time // this went wrong. tok := p.next() var terminator string switch tok.value { case "<": terminator = ">" case "{": terminator = "}" default: return p.errorf("expected '{' or '<', found %q", tok.value) } for { tok := p.next() if tok.err != nil { return tok.err } if tok.value == terminator { break } switch tok.value { case "key": if err := p.consumeToken(":"); err != nil { return err } if err := p.readAny(key, props.MapKeyProp); err != nil { return err } if err := p.consumeOptionalSeparator(); err != nil { return err } case "value": if err := p.checkForColon(props.MapValProp, dst.Type().Elem()); err != nil { return err } if err := p.readAny(val, props.MapValProp); err != nil { return err } if err := p.consumeOptionalSeparator(); err != nil { return err } default: p.back() return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) } } dst.SetMapIndex(key, val) continue } // Check that it's not already set if it's not a repeated field. if !props.Repeated && fieldSet[name] { return p.errorf("non-repeated field %q was repeated", name) } if err := p.checkForColon(props, dst.Type()); err != nil { return err } // Parse into the field. fieldSet[name] = true if err := p.readAny(dst, props); err != nil { if _, ok := err.(*RequiredNotSetError); !ok { return err } reqFieldErr = err } if props.Required { reqCount-- } if err := p.consumeOptionalSeparator(); err != nil { return err } } if reqCount > 0 { return p.missingRequiredFieldError(sv) } return reqFieldErr } // consumeExtName consumes extension name or expanded Any type URL and the // following ']'. It returns the name or URL consumed. func (p *textParser) consumeExtName() (string, error) { tok := p.next() if tok.err != nil { return "", tok.err } // If extension name or type url is quoted, it's a single token. if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) if err != nil { return "", err } return name, p.consumeToken("]") } // Consume everything up to "]" var parts []string for tok.value != "]" { parts = append(parts, tok.value) tok = p.next() if tok.err != nil { return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) } if p.done && tok.value != "]" { return "", p.errorf("unclosed type_url or extension name") } } return strings.Join(parts, ""), nil } // consumeOptionalSeparator consumes an optional semicolon or comma. // It is used in readStruct to provide backward compatibility. func (p *textParser) consumeOptionalSeparator() error { tok := p.next() if tok.err != nil { return tok.err } if tok.value != ";" && tok.value != "," { p.back() } return nil } func (p *textParser) readAny(v reflect.Value, props *Properties) error { tok := p.next() if tok.err != nil { return tok.err } if tok.value == "" { return p.errorf("unexpected EOF") } switch fv := v; fv.Kind() { case reflect.Slice: at := v.Type() if at.Elem().Kind() == reflect.Uint8 { // Special case for []byte if tok.value[0] != '"' && tok.value[0] != '\'' { // Deliberately written out here, as the error after // this switch statement would write "invalid []byte: ...", // which is not as user-friendly. return p.errorf("invalid string: %v", tok.value) } bytes := []byte(tok.unquoted) fv.Set(reflect.ValueOf(bytes)) return nil } // Repeated field. if tok.value == "[" { // Repeated field with list notation, like [1,2,3]. for { fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) err := p.readAny(fv.Index(fv.Len()-1), props) if err != nil { return err } tok := p.next() if tok.err != nil { return tok.err } if tok.value == "]" { break } if tok.value != "," { return p.errorf("Expected ']' or ',' found %q", tok.value) } } return nil } // One value of the repeated field. p.back() fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) return p.readAny(fv.Index(fv.Len()-1), props) case reflect.Bool: // true/1/t/True or false/f/0/False. switch tok.value { case "true", "1", "t", "True": fv.SetBool(true) return nil case "false", "0", "f", "False": fv.SetBool(false) return nil } case reflect.Float32, reflect.Float64: v := tok.value // Ignore 'f' for compatibility with output generated by C++, but don't // remove 'f' when the value is "-inf" or "inf". if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { v = v[:len(v)-1] } if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { fv.SetFloat(f) return nil } case reflect.Int32: if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { fv.SetInt(x) return nil } if len(props.Enum) == 0 { break } m, ok := enumValueMaps[props.Enum] if !ok { break } x, ok := m[tok.value] if !ok { break } fv.SetInt(int64(x)) return nil case reflect.Int64: if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { fv.SetInt(x) return nil } case reflect.Ptr: // A basic field (indirected through pointer), or a repeated message/group p.back() fv.Set(reflect.New(fv.Type().Elem())) return p.readAny(fv.Elem(), props) case reflect.String: if tok.value[0] == '"' || tok.value[0] == '\'' { fv.SetString(tok.unquoted) return nil } case reflect.Struct: var terminator string switch tok.value { case "{": terminator = "}" case "<": terminator = ">" default: return p.errorf("expected '{' or '<', found %q", tok.value) } // TODO: Handle nested messages which implement encoding.TextUnmarshaler. return p.readStruct(fv, terminator) case reflect.Uint32: if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { fv.SetUint(uint64(x)) return nil } case reflect.Uint64: if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { fv.SetUint(x) return nil } } return p.errorf("invalid %v: %v", v.Type(), tok.value) } // UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb // before starting to unmarshal, so any existing data in pb is always removed. // If a required field is not set and no other error occurs, // UnmarshalText returns *RequiredNotSetError. func UnmarshalText(s string, pb Message) error { if um, ok := pb.(encoding.TextUnmarshaler); ok { return um.UnmarshalText([]byte(s)) } pb.Reset() v := reflect.ValueOf(pb) return newTextParser(s).readStruct(v.Elem(), "") } ================================================ FILE: vendor/github.com/gomodule/redigo/LICENSE ================================================ 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. ================================================ FILE: vendor/github.com/gomodule/redigo/internal/commandinfo.go ================================================ // Copyright 2014 Gary Burd // // 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 internal // import "github.com/gomodule/redigo/internal" import ( "strings" ) const ( WatchState = 1 << iota MultiState SubscribeState MonitorState ) type CommandInfo struct { Set, Clear int } var commandInfos = map[string]CommandInfo{ "WATCH": {Set: WatchState}, "UNWATCH": {Clear: WatchState}, "MULTI": {Set: MultiState}, "EXEC": {Clear: WatchState | MultiState}, "DISCARD": {Clear: WatchState | MultiState}, "PSUBSCRIBE": {Set: SubscribeState}, "SUBSCRIBE": {Set: SubscribeState}, "MONITOR": {Set: MonitorState}, } func init() { for n, ci := range commandInfos { commandInfos[strings.ToLower(n)] = ci } } func LookupCommandInfo(commandName string) CommandInfo { if ci, ok := commandInfos[commandName]; ok { return ci } return commandInfos[strings.ToUpper(commandName)] } ================================================ FILE: vendor/github.com/gomodule/redigo/redis/conn.go ================================================ // Copyright 2012 Gary Burd // // 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 redis import ( "bufio" "bytes" "crypto/tls" "errors" "fmt" "io" "net" "net/url" "regexp" "strconv" "sync" "time" ) var ( _ ConnWithTimeout = (*conn)(nil) ) // conn is the low-level implementation of Conn type conn struct { // Shared mu sync.Mutex pending int err error conn net.Conn // Read readTimeout time.Duration br *bufio.Reader // Write writeTimeout time.Duration bw *bufio.Writer // Scratch space for formatting argument length. // '*' or '$', length, "\r\n" lenScratch [32]byte // Scratch space for formatting integers and floats. numScratch [40]byte } // DialTimeout acts like Dial but takes timeouts for establishing the // connection to the server, writing a command and reading a reply. // // Deprecated: Use Dial with options instead. func DialTimeout(network, address string, connectTimeout, readTimeout, writeTimeout time.Duration) (Conn, error) { return Dial(network, address, DialConnectTimeout(connectTimeout), DialReadTimeout(readTimeout), DialWriteTimeout(writeTimeout)) } // DialOption specifies an option for dialing a Redis server. type DialOption struct { f func(*dialOptions) } type dialOptions struct { readTimeout time.Duration writeTimeout time.Duration dialer *net.Dialer dial func(network, addr string) (net.Conn, error) db int password string useTLS bool skipVerify bool tlsConfig *tls.Config } // DialReadTimeout specifies the timeout for reading a single command reply. func DialReadTimeout(d time.Duration) DialOption { return DialOption{func(do *dialOptions) { do.readTimeout = d }} } // DialWriteTimeout specifies the timeout for writing a single command. func DialWriteTimeout(d time.Duration) DialOption { return DialOption{func(do *dialOptions) { do.writeTimeout = d }} } // DialConnectTimeout specifies the timeout for connecting to the Redis server when // no DialNetDial option is specified. func DialConnectTimeout(d time.Duration) DialOption { return DialOption{func(do *dialOptions) { do.dialer.Timeout = d }} } // DialKeepAlive specifies the keep-alive period for TCP connections to the Redis server // when no DialNetDial option is specified. // If zero, keep-alives are not enabled. If no DialKeepAlive option is specified then // the default of 5 minutes is used to ensure that half-closed TCP sessions are detected. func DialKeepAlive(d time.Duration) DialOption { return DialOption{func(do *dialOptions) { do.dialer.KeepAlive = d }} } // DialNetDial specifies a custom dial function for creating TCP // connections, otherwise a net.Dialer customized via the other options is used. // DialNetDial overrides DialConnectTimeout and DialKeepAlive. func DialNetDial(dial func(network, addr string) (net.Conn, error)) DialOption { return DialOption{func(do *dialOptions) { do.dial = dial }} } // DialDatabase specifies the database to select when dialing a connection. func DialDatabase(db int) DialOption { return DialOption{func(do *dialOptions) { do.db = db }} } // DialPassword specifies the password to use when connecting to // the Redis server. func DialPassword(password string) DialOption { return DialOption{func(do *dialOptions) { do.password = password }} } // DialTLSConfig specifies the config to use when a TLS connection is dialed. // Has no effect when not dialing a TLS connection. func DialTLSConfig(c *tls.Config) DialOption { return DialOption{func(do *dialOptions) { do.tlsConfig = c }} } // DialTLSSkipVerify disables server name verification when connecting over // TLS. Has no effect when not dialing a TLS connection. func DialTLSSkipVerify(skip bool) DialOption { return DialOption{func(do *dialOptions) { do.skipVerify = skip }} } // DialUseTLS specifies whether TLS should be used when connecting to the // server. This option is ignore by DialURL. func DialUseTLS(useTLS bool) DialOption { return DialOption{func(do *dialOptions) { do.useTLS = useTLS }} } // Dial connects to the Redis server at the given network and // address using the specified options. func Dial(network, address string, options ...DialOption) (Conn, error) { do := dialOptions{ dialer: &net.Dialer{ KeepAlive: time.Minute * 5, }, } for _, option := range options { option.f(&do) } if do.dial == nil { do.dial = do.dialer.Dial } netConn, err := do.dial(network, address) if err != nil { return nil, err } if do.useTLS { var tlsConfig *tls.Config if do.tlsConfig == nil { tlsConfig = &tls.Config{InsecureSkipVerify: do.skipVerify} } else { tlsConfig = cloneTLSConfig(do.tlsConfig) } if tlsConfig.ServerName == "" { host, _, err := net.SplitHostPort(address) if err != nil { netConn.Close() return nil, err } tlsConfig.ServerName = host } tlsConn := tls.Client(netConn, tlsConfig) if err := tlsConn.Handshake(); err != nil { netConn.Close() return nil, err } netConn = tlsConn } c := &conn{ conn: netConn, bw: bufio.NewWriter(netConn), br: bufio.NewReader(netConn), readTimeout: do.readTimeout, writeTimeout: do.writeTimeout, } if do.password != "" { if _, err := c.Do("AUTH", do.password); err != nil { netConn.Close() return nil, err } } if do.db != 0 { if _, err := c.Do("SELECT", do.db); err != nil { netConn.Close() return nil, err } } return c, nil } var pathDBRegexp = regexp.MustCompile(`/(\d*)\z`) // DialURL connects to a Redis server at the given URL using the Redis // URI scheme. URLs should follow the draft IANA specification for the // scheme (https://www.iana.org/assignments/uri-schemes/prov/redis). func DialURL(rawurl string, options ...DialOption) (Conn, error) { u, err := url.Parse(rawurl) if err != nil { return nil, err } if u.Scheme != "redis" && u.Scheme != "rediss" { return nil, fmt.Errorf("invalid redis URL scheme: %s", u.Scheme) } // As per the IANA draft spec, the host defaults to localhost and // the port defaults to 6379. host, port, err := net.SplitHostPort(u.Host) if err != nil { // assume port is missing host = u.Host port = "6379" } if host == "" { host = "localhost" } address := net.JoinHostPort(host, port) if u.User != nil { password, isSet := u.User.Password() if isSet { options = append(options, DialPassword(password)) } } match := pathDBRegexp.FindStringSubmatch(u.Path) if len(match) == 2 { db := 0 if len(match[1]) > 0 { db, err = strconv.Atoi(match[1]) if err != nil { return nil, fmt.Errorf("invalid database: %s", u.Path[1:]) } } if db != 0 { options = append(options, DialDatabase(db)) } } else if u.Path != "" { return nil, fmt.Errorf("invalid database: %s", u.Path[1:]) } options = append(options, DialUseTLS(u.Scheme == "rediss")) return Dial("tcp", address, options...) } // NewConn returns a new Redigo connection for the given net connection. func NewConn(netConn net.Conn, readTimeout, writeTimeout time.Duration) Conn { return &conn{ conn: netConn, bw: bufio.NewWriter(netConn), br: bufio.NewReader(netConn), readTimeout: readTimeout, writeTimeout: writeTimeout, } } func (c *conn) Close() error { c.mu.Lock() err := c.err if c.err == nil { c.err = errors.New("redigo: closed") err = c.conn.Close() } c.mu.Unlock() return err } func (c *conn) fatal(err error) error { c.mu.Lock() if c.err == nil { c.err = err // Close connection to force errors on subsequent calls and to unblock // other reader or writer. c.conn.Close() } c.mu.Unlock() return err } func (c *conn) Err() error { c.mu.Lock() err := c.err c.mu.Unlock() return err } func (c *conn) writeLen(prefix byte, n int) error { c.lenScratch[len(c.lenScratch)-1] = '\n' c.lenScratch[len(c.lenScratch)-2] = '\r' i := len(c.lenScratch) - 3 for { c.lenScratch[i] = byte('0' + n%10) i -= 1 n = n / 10 if n == 0 { break } } c.lenScratch[i] = prefix _, err := c.bw.Write(c.lenScratch[i:]) return err } func (c *conn) writeString(s string) error { c.writeLen('$', len(s)) c.bw.WriteString(s) _, err := c.bw.WriteString("\r\n") return err } func (c *conn) writeBytes(p []byte) error { c.writeLen('$', len(p)) c.bw.Write(p) _, err := c.bw.WriteString("\r\n") return err } func (c *conn) writeInt64(n int64) error { return c.writeBytes(strconv.AppendInt(c.numScratch[:0], n, 10)) } func (c *conn) writeFloat64(n float64) error { return c.writeBytes(strconv.AppendFloat(c.numScratch[:0], n, 'g', -1, 64)) } func (c *conn) writeCommand(cmd string, args []interface{}) error { c.writeLen('*', 1+len(args)) if err := c.writeString(cmd); err != nil { return err } for _, arg := range args { if err := c.writeArg(arg, true); err != nil { return err } } return nil } func (c *conn) writeArg(arg interface{}, argumentTypeOK bool) (err error) { switch arg := arg.(type) { case string: return c.writeString(arg) case []byte: return c.writeBytes(arg) case int: return c.writeInt64(int64(arg)) case int64: return c.writeInt64(arg) case float64: return c.writeFloat64(arg) case bool: if arg { return c.writeString("1") } else { return c.writeString("0") } case nil: return c.writeString("") case Argument: if argumentTypeOK { return c.writeArg(arg.RedisArg(), false) } // See comment in default clause below. var buf bytes.Buffer fmt.Fprint(&buf, arg) return c.writeBytes(buf.Bytes()) default: // This default clause is intended to handle builtin numeric types. // The function should return an error for other types, but this is not // done for compatibility with previous versions of the package. var buf bytes.Buffer fmt.Fprint(&buf, arg) return c.writeBytes(buf.Bytes()) } } type protocolError string func (pe protocolError) Error() string { return fmt.Sprintf("redigo: %s (possible server error or unsupported concurrent read by application)", string(pe)) } func (c *conn) readLine() ([]byte, error) { p, err := c.br.ReadSlice('\n') if err == bufio.ErrBufferFull { return nil, protocolError("long response line") } if err != nil { return nil, err } i := len(p) - 2 if i < 0 || p[i] != '\r' { return nil, protocolError("bad response line terminator") } return p[:i], nil } // parseLen parses bulk string and array lengths. func parseLen(p []byte) (int, error) { if len(p) == 0 { return -1, protocolError("malformed length") } if p[0] == '-' && len(p) == 2 && p[1] == '1' { // handle $-1 and $-1 null replies. return -1, nil } var n int for _, b := range p { n *= 10 if b < '0' || b > '9' { return -1, protocolError("illegal bytes in length") } n += int(b - '0') } return n, nil } // parseInt parses an integer reply. func parseInt(p []byte) (interface{}, error) { if len(p) == 0 { return 0, protocolError("malformed integer") } var negate bool if p[0] == '-' { negate = true p = p[1:] if len(p) == 0 { return 0, protocolError("malformed integer") } } var n int64 for _, b := range p { n *= 10 if b < '0' || b > '9' { return 0, protocolError("illegal bytes in length") } n += int64(b - '0') } if negate { n = -n } return n, nil } var ( okReply interface{} = "OK" pongReply interface{} = "PONG" ) func (c *conn) readReply() (interface{}, error) { line, err := c.readLine() if err != nil { return nil, err } if len(line) == 0 { return nil, protocolError("short response line") } switch line[0] { case '+': switch { case len(line) == 3 && line[1] == 'O' && line[2] == 'K': // Avoid allocation for frequent "+OK" response. return okReply, nil case len(line) == 5 && line[1] == 'P' && line[2] == 'O' && line[3] == 'N' && line[4] == 'G': // Avoid allocation in PING command benchmarks :) return pongReply, nil default: return string(line[1:]), nil } case '-': return Error(string(line[1:])), nil case ':': return parseInt(line[1:]) case '$': n, err := parseLen(line[1:]) if n < 0 || err != nil { return nil, err } p := make([]byte, n) _, err = io.ReadFull(c.br, p) if err != nil { return nil, err } if line, err := c.readLine(); err != nil { return nil, err } else if len(line) != 0 { return nil, protocolError("bad bulk string format") } return p, nil case '*': n, err := parseLen(line[1:]) if n < 0 || err != nil { return nil, err } r := make([]interface{}, n) for i := range r { r[i], err = c.readReply() if err != nil { return nil, err } } return r, nil } return nil, protocolError("unexpected response line") } func (c *conn) Send(cmd string, args ...interface{}) error { c.mu.Lock() c.pending += 1 c.mu.Unlock() if c.writeTimeout != 0 { c.conn.SetWriteDeadline(time.Now().Add(c.writeTimeout)) } if err := c.writeCommand(cmd, args); err != nil { return c.fatal(err) } return nil } func (c *conn) Flush() error { if c.writeTimeout != 0 { c.conn.SetWriteDeadline(time.Now().Add(c.writeTimeout)) } if err := c.bw.Flush(); err != nil { return c.fatal(err) } return nil } func (c *conn) Receive() (interface{}, error) { return c.ReceiveWithTimeout(c.readTimeout) } func (c *conn) ReceiveWithTimeout(timeout time.Duration) (reply interface{}, err error) { var deadline time.Time if timeout != 0 { deadline = time.Now().Add(timeout) } c.conn.SetReadDeadline(deadline) if reply, err = c.readReply(); err != nil { return nil, c.fatal(err) } // When using pub/sub, the number of receives can be greater than the // number of sends. To enable normal use of the connection after // unsubscribing from all channels, we do not decrement pending to a // negative value. // // The pending field is decremented after the reply is read to handle the // case where Receive is called before Send. c.mu.Lock() if c.pending > 0 { c.pending -= 1 } c.mu.Unlock() if err, ok := reply.(Error); ok { return nil, err } return } func (c *conn) Do(cmd string, args ...interface{}) (interface{}, error) { return c.DoWithTimeout(c.readTimeout, cmd, args...) } func (c *conn) DoWithTimeout(readTimeout time.Duration, cmd string, args ...interface{}) (interface{}, error) { c.mu.Lock() pending := c.pending c.pending = 0 c.mu.Unlock() if cmd == "" && pending == 0 { return nil, nil } if c.writeTimeout != 0 { c.conn.SetWriteDeadline(time.Now().Add(c.writeTimeout)) } if cmd != "" { if err := c.writeCommand(cmd, args); err != nil { return nil, c.fatal(err) } } if err := c.bw.Flush(); err != nil { return nil, c.fatal(err) } var deadline time.Time if readTimeout != 0 { deadline = time.Now().Add(readTimeout) } c.conn.SetReadDeadline(deadline) if cmd == "" { reply := make([]interface{}, pending) for i := range reply { r, e := c.readReply() if e != nil { return nil, c.fatal(e) } reply[i] = r } return reply, nil } var err error var reply interface{} for i := 0; i <= pending; i++ { var e error if reply, e = c.readReply(); e != nil { return nil, c.fatal(e) } if e, ok := reply.(Error); ok && err == nil { err = e } } return reply, err } ================================================ FILE: vendor/github.com/gomodule/redigo/redis/doc.go ================================================ // Copyright 2012 Gary Burd // // 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 redis is a client for the Redis database. // // The Redigo FAQ (https://github.com/gomodule/redigo/wiki/FAQ) contains more // documentation about this package. // // Connections // // The Conn interface is the primary interface for working with Redis. // Applications create connections by calling the Dial, DialWithTimeout or // NewConn functions. In the future, functions will be added for creating // sharded and other types of connections. // // The application must call the connection Close method when the application // is done with the connection. // // Executing Commands // // The Conn interface has a generic method for executing Redis commands: // // Do(commandName string, args ...interface{}) (reply interface{}, err error) // // The Redis command reference (http://redis.io/commands) lists the available // commands. An example of using the Redis APPEND command is: // // n, err := conn.Do("APPEND", "key", "value") // // The Do method converts command arguments to bulk strings for transmission // to the server as follows: // // Go Type Conversion // []byte Sent as is // string Sent as is // int, int64 strconv.FormatInt(v) // float64 strconv.FormatFloat(v, 'g', -1, 64) // bool true -> "1", false -> "0" // nil "" // all other types fmt.Fprint(w, v) // // Redis command reply types are represented using the following Go types: // // Redis type Go type // error redis.Error // integer int64 // simple string string // bulk string []byte or nil if value not present. // array []interface{} or nil if value not present. // // Use type assertions or the reply helper functions to convert from // interface{} to the specific Go type for the command result. // // Pipelining // // Connections support pipelining using the Send, Flush and Receive methods. // // Send(commandName string, args ...interface{}) error // Flush() error // Receive() (reply interface{}, err error) // // Send writes the command to the connection's output buffer. Flush flushes the // connection's output buffer to the server. Receive reads a single reply from // the server. The following example shows a simple pipeline. // // c.Send("SET", "foo", "bar") // c.Send("GET", "foo") // c.Flush() // c.Receive() // reply from SET // v, err = c.Receive() // reply from GET // // The Do method combines the functionality of the Send, Flush and Receive // methods. The Do method starts by writing the command and flushing the output // buffer. Next, the Do method receives all pending replies including the reply // for the command just sent by Do. If any of the received replies is an error, // then Do returns the error. If there are no errors, then Do returns the last // reply. If the command argument to the Do method is "", then the Do method // will flush the output buffer and receive pending replies without sending a // command. // // Use the Send and Do methods to implement pipelined transactions. // // c.Send("MULTI") // c.Send("INCR", "foo") // c.Send("INCR", "bar") // r, err := c.Do("EXEC") // fmt.Println(r) // prints [1, 1] // // Concurrency // // Connections support one concurrent caller to the Receive method and one // concurrent caller to the Send and Flush methods. No other concurrency is // supported including concurrent calls to the Do method. // // For full concurrent access to Redis, use the thread-safe Pool to get, use // and release a connection from within a goroutine. Connections returned from // a Pool have the concurrency restrictions described in the previous // paragraph. // // Publish and Subscribe // // Use the Send, Flush and Receive methods to implement Pub/Sub subscribers. // // c.Send("SUBSCRIBE", "example") // c.Flush() // for { // reply, err := c.Receive() // if err != nil { // return err // } // // process pushed message // } // // The PubSubConn type wraps a Conn with convenience methods for implementing // subscribers. The Subscribe, PSubscribe, Unsubscribe and PUnsubscribe methods // send and flush a subscription management command. The receive method // converts a pushed message to convenient types for use in a type switch. // // psc := redis.PubSubConn{Conn: c} // psc.Subscribe("example") // for { // switch v := psc.Receive().(type) { // case redis.Message: // fmt.Printf("%s: message: %s\n", v.Channel, v.Data) // case redis.Subscription: // fmt.Printf("%s: %s %d\n", v.Channel, v.Kind, v.Count) // case error: // return v // } // } // // Reply Helpers // // The Bool, Int, Bytes, String, Strings and Values functions convert a reply // to a value of a specific type. To allow convenient wrapping of calls to the // connection Do and Receive methods, the functions take a second argument of // type error. If the error is non-nil, then the helper function returns the // error. If the error is nil, the function converts the reply to the specified // type: // // exists, err := redis.Bool(c.Do("EXISTS", "foo")) // if err != nil { // // handle error return from c.Do or type conversion error. // } // // The Scan function converts elements of a array reply to Go types: // // var value1 int // var value2 string // reply, err := redis.Values(c.Do("MGET", "key1", "key2")) // if err != nil { // // handle error // } // if _, err := redis.Scan(reply, &value1, &value2); err != nil { // // handle error // } // // Errors // // Connection methods return error replies from the server as type redis.Error. // // Call the connection Err() method to determine if the connection encountered // non-recoverable error such as a network error or protocol parsing error. If // Err() returns a non-nil value, then the connection is not usable and should // be closed. package redis // import "github.com/gomodule/redigo/redis" ================================================ FILE: vendor/github.com/gomodule/redigo/redis/go16.go ================================================ // +build !go1.7 package redis import "crypto/tls" func cloneTLSConfig(cfg *tls.Config) *tls.Config { return &tls.Config{ Rand: cfg.Rand, Time: cfg.Time, Certificates: cfg.Certificates, NameToCertificate: cfg.NameToCertificate, GetCertificate: cfg.GetCertificate, RootCAs: cfg.RootCAs, NextProtos: cfg.NextProtos, ServerName: cfg.ServerName, ClientAuth: cfg.ClientAuth, ClientCAs: cfg.ClientCAs, InsecureSkipVerify: cfg.InsecureSkipVerify, CipherSuites: cfg.CipherSuites, PreferServerCipherSuites: cfg.PreferServerCipherSuites, ClientSessionCache: cfg.ClientSessionCache, MinVersion: cfg.MinVersion, MaxVersion: cfg.MaxVersion, CurvePreferences: cfg.CurvePreferences, } } ================================================ FILE: vendor/github.com/gomodule/redigo/redis/go17.go ================================================ // +build go1.7,!go1.8 package redis import "crypto/tls" func cloneTLSConfig(cfg *tls.Config) *tls.Config { return &tls.Config{ Rand: cfg.Rand, Time: cfg.Time, Certificates: cfg.Certificates, NameToCertificate: cfg.NameToCertificate, GetCertificate: cfg.GetCertificate, RootCAs: cfg.RootCAs, NextProtos: cfg.NextProtos, ServerName: cfg.ServerName, ClientAuth: cfg.ClientAuth, ClientCAs: cfg.ClientCAs, InsecureSkipVerify: cfg.InsecureSkipVerify, CipherSuites: cfg.CipherSuites, PreferServerCipherSuites: cfg.PreferServerCipherSuites, ClientSessionCache: cfg.ClientSessionCache, MinVersion: cfg.MinVersion, MaxVersion: cfg.MaxVersion, CurvePreferences: cfg.CurvePreferences, DynamicRecordSizingDisabled: cfg.DynamicRecordSizingDisabled, Renegotiation: cfg.Renegotiation, } } ================================================ FILE: vendor/github.com/gomodule/redigo/redis/go18.go ================================================ // +build go1.8 package redis import "crypto/tls" func cloneTLSConfig(cfg *tls.Config) *tls.Config { return cfg.Clone() } ================================================ FILE: vendor/github.com/gomodule/redigo/redis/log.go ================================================ // Copyright 2012 Gary Burd // // 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 redis import ( "bytes" "fmt" "log" "time" ) var ( _ ConnWithTimeout = (*loggingConn)(nil) ) // NewLoggingConn returns a logging wrapper around a connection. func NewLoggingConn(conn Conn, logger *log.Logger, prefix string) Conn { if prefix != "" { prefix = prefix + "." } return &loggingConn{conn, logger, prefix} } type loggingConn struct { Conn logger *log.Logger prefix string } func (c *loggingConn) Close() error { err := c.Conn.Close() var buf bytes.Buffer fmt.Fprintf(&buf, "%sClose() -> (%v)", c.prefix, err) c.logger.Output(2, buf.String()) return err } func (c *loggingConn) printValue(buf *bytes.Buffer, v interface{}) { const chop = 32 switch v := v.(type) { case []byte: if len(v) > chop { fmt.Fprintf(buf, "%q...", v[:chop]) } else { fmt.Fprintf(buf, "%q", v) } case string: if len(v) > chop { fmt.Fprintf(buf, "%q...", v[:chop]) } else { fmt.Fprintf(buf, "%q", v) } case []interface{}: if len(v) == 0 { buf.WriteString("[]") } else { sep := "[" fin := "]" if len(v) > chop { v = v[:chop] fin = "...]" } for _, vv := range v { buf.WriteString(sep) c.printValue(buf, vv) sep = ", " } buf.WriteString(fin) } default: fmt.Fprint(buf, v) } } func (c *loggingConn) print(method, commandName string, args []interface{}, reply interface{}, err error) { var buf bytes.Buffer fmt.Fprintf(&buf, "%s%s(", c.prefix, method) if method != "Receive" { buf.WriteString(commandName) for _, arg := range args { buf.WriteString(", ") c.printValue(&buf, arg) } } buf.WriteString(") -> (") if method != "Send" { c.printValue(&buf, reply) buf.WriteString(", ") } fmt.Fprintf(&buf, "%v)", err) c.logger.Output(3, buf.String()) } func (c *loggingConn) Do(commandName string, args ...interface{}) (interface{}, error) { reply, err := c.Conn.Do(commandName, args...) c.print("Do", commandName, args, reply, err) return reply, err } func (c *loggingConn) DoWithTimeout(timeout time.Duration, commandName string, args ...interface{}) (interface{}, error) { reply, err := DoWithTimeout(c.Conn, timeout, commandName, args...) c.print("DoWithTimeout", commandName, args, reply, err) return reply, err } func (c *loggingConn) Send(commandName string, args ...interface{}) error { err := c.Conn.Send(commandName, args...) c.print("Send", commandName, args, nil, err) return err } func (c *loggingConn) Receive() (interface{}, error) { reply, err := c.Conn.Receive() c.print("Receive", "", nil, reply, err) return reply, err } func (c *loggingConn) ReceiveWithTimeout(timeout time.Duration) (interface{}, error) { reply, err := ReceiveWithTimeout(c.Conn, timeout) c.print("ReceiveWithTimeout", "", nil, reply, err) return reply, err } ================================================ FILE: vendor/github.com/gomodule/redigo/redis/pool.go ================================================ // Copyright 2012 Gary Burd // // 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 redis import ( "bytes" "crypto/rand" "crypto/sha1" "errors" "io" "strconv" "sync" "sync/atomic" "time" "github.com/gomodule/redigo/internal" ) var ( _ ConnWithTimeout = (*activeConn)(nil) _ ConnWithTimeout = (*errorConn)(nil) ) var nowFunc = time.Now // for testing // ErrPoolExhausted is returned from a pool connection method (Do, Send, // Receive, Flush, Err) when the maximum number of database connections in the // pool has been reached. var ErrPoolExhausted = errors.New("redigo: connection pool exhausted") var ( errPoolClosed = errors.New("redigo: connection pool closed") errConnClosed = errors.New("redigo: connection closed") ) // Pool maintains a pool of connections. The application calls the Get method // to get a connection from the pool and the connection's Close method to // return the connection's resources to the pool. // // The following example shows how to use a pool in a web application. The // application creates a pool at application startup and makes it available to // request handlers using a package level variable. The pool configuration used // here is an example, not a recommendation. // // func newPool(addr string) *redis.Pool { // return &redis.Pool{ // MaxIdle: 3, // IdleTimeout: 240 * time.Second, // Dial: func () (redis.Conn, error) { return redis.Dial("tcp", addr) }, // } // } // // var ( // pool *redis.Pool // redisServer = flag.String("redisServer", ":6379", "") // ) // // func main() { // flag.Parse() // pool = newPool(*redisServer) // ... // } // // A request handler gets a connection from the pool and closes the connection // when the handler is done: // // func serveHome(w http.ResponseWriter, r *http.Request) { // conn := pool.Get() // defer conn.Close() // ... // } // // Use the Dial function to authenticate connections with the AUTH command or // select a database with the SELECT command: // // pool := &redis.Pool{ // // Other pool configuration not shown in this example. // Dial: func () (redis.Conn, error) { // c, err := redis.Dial("tcp", server) // if err != nil { // return nil, err // } // if _, err := c.Do("AUTH", password); err != nil { // c.Close() // return nil, err // } // if _, err := c.Do("SELECT", db); err != nil { // c.Close() // return nil, err // } // return c, nil // }, // } // // Use the TestOnBorrow function to check the health of an idle connection // before the connection is returned to the application. This example PINGs // connections that have been idle more than a minute: // // pool := &redis.Pool{ // // Other pool configuration not shown in this example. // TestOnBorrow: func(c redis.Conn, t time.Time) error { // if time.Since(t) < time.Minute { // return nil // } // _, err := c.Do("PING") // return err // }, // } // type Pool struct { // Dial is an application supplied function for creating and configuring a // connection. // // The connection returned from Dial must not be in a special state // (subscribed to pubsub channel, transaction started, ...). Dial func() (Conn, error) // TestOnBorrow is an optional application supplied function for checking // the health of an idle connection before the connection is used again by // the application. Argument t is the time that the connection was returned // to the pool. If the function returns an error, then the connection is // closed. TestOnBorrow func(c Conn, t time.Time) error // Maximum number of idle connections in the pool. MaxIdle int // Maximum number of connections allocated by the pool at a given time. // When zero, there is no limit on the number of connections in the pool. MaxActive int // Close connections after remaining idle for this duration. If the value // is zero, then idle connections are not closed. Applications should set // the timeout to a value less than the server's timeout. IdleTimeout time.Duration // If Wait is true and the pool is at the MaxActive limit, then Get() waits // for a connection to be returned to the pool before returning. Wait bool // Close connections older than this duration. If the value is zero, then // the pool does not close connections based on age. MaxConnLifetime time.Duration chInitialized uint32 // set to 1 when field ch is initialized mu sync.Mutex // mu protects the following fields closed bool // set to true when the pool is closed. active int // the number of open connections in the pool ch chan struct{} // limits open connections when p.Wait is true idle idleList // idle connections } // NewPool creates a new pool. // // Deprecated: Initialize the Pool directory as shown in the example. func NewPool(newFn func() (Conn, error), maxIdle int) *Pool { return &Pool{Dial: newFn, MaxIdle: maxIdle} } // Get gets a connection. The application must close the returned connection. // This method always returns a valid connection so that applications can defer // error handling to the first use of the connection. If there is an error // getting an underlying connection, then the connection Err, Do, Send, Flush // and Receive methods return that error. func (p *Pool) Get() Conn { pc, err := p.get(nil) if err != nil { return errorConn{err} } return &activeConn{p: p, pc: pc} } // PoolStats contains pool statistics. type PoolStats struct { // ActiveCount is the number of connections in the pool. The count includes // idle connections and connections in use. ActiveCount int // IdleCount is the number of idle connections in the pool. IdleCount int } // Stats returns pool's statistics. func (p *Pool) Stats() PoolStats { p.mu.Lock() stats := PoolStats{ ActiveCount: p.active, IdleCount: p.idle.count, } p.mu.Unlock() return stats } // ActiveCount returns the number of connections in the pool. The count // includes idle connections and connections in use. func (p *Pool) ActiveCount() int { p.mu.Lock() active := p.active p.mu.Unlock() return active } // IdleCount returns the number of idle connections in the pool. func (p *Pool) IdleCount() int { p.mu.Lock() idle := p.idle.count p.mu.Unlock() return idle } // Close releases the resources used by the pool. func (p *Pool) Close() error { p.mu.Lock() if p.closed { p.mu.Unlock() return nil } p.closed = true p.active -= p.idle.count pc := p.idle.front p.idle.count = 0 p.idle.front, p.idle.back = nil, nil if p.ch != nil { close(p.ch) } p.mu.Unlock() for ; pc != nil; pc = pc.next { pc.c.Close() } return nil } func (p *Pool) lazyInit() { // Fast path. if atomic.LoadUint32(&p.chInitialized) == 1 { return } // Slow path. p.mu.Lock() if p.chInitialized == 0 { p.ch = make(chan struct{}, p.MaxActive) if p.closed { close(p.ch) } else { for i := 0; i < p.MaxActive; i++ { p.ch <- struct{}{} } } atomic.StoreUint32(&p.chInitialized, 1) } p.mu.Unlock() } // get prunes stale connections and returns a connection from the idle list or // creates a new connection. func (p *Pool) get(ctx interface { Done() <-chan struct{} Err() error }) (*poolConn, error) { // Handle limit for p.Wait == true. if p.Wait && p.MaxActive > 0 { p.lazyInit() if ctx == nil { <-p.ch } else { select { case <-p.ch: case <-ctx.Done(): return nil, ctx.Err() } } } p.mu.Lock() // Prune stale connections at the back of the idle list. if p.IdleTimeout > 0 { n := p.idle.count for i := 0; i < n && p.idle.back != nil && p.idle.back.t.Add(p.IdleTimeout).Before(nowFunc()); i++ { pc := p.idle.back p.idle.popBack() p.mu.Unlock() pc.c.Close() p.mu.Lock() p.active-- } } // Get idle connection from the front of idle list. for p.idle.front != nil { pc := p.idle.front p.idle.popFront() p.mu.Unlock() if (p.TestOnBorrow == nil || p.TestOnBorrow(pc.c, pc.t) == nil) && (p.MaxConnLifetime == 0 || nowFunc().Sub(pc.created) < p.MaxConnLifetime) { return pc, nil } pc.c.Close() p.mu.Lock() p.active-- } // Check for pool closed before dialing a new connection. if p.closed { p.mu.Unlock() return nil, errors.New("redigo: get on closed pool") } // Handle limit for p.Wait == false. if !p.Wait && p.MaxActive > 0 && p.active >= p.MaxActive { p.mu.Unlock() return nil, ErrPoolExhausted } p.active++ p.mu.Unlock() c, err := p.Dial() if err != nil { c = nil p.mu.Lock() p.active-- if p.ch != nil && !p.closed { p.ch <- struct{}{} } p.mu.Unlock() } return &poolConn{c: c, created: nowFunc()}, err } func (p *Pool) put(pc *poolConn, forceClose bool) error { p.mu.Lock() if !p.closed && !forceClose { pc.t = nowFunc() p.idle.pushFront(pc) if p.idle.count > p.MaxIdle { pc = p.idle.back p.idle.popBack() } else { pc = nil } } if pc != nil { p.mu.Unlock() pc.c.Close() p.mu.Lock() p.active-- } if p.ch != nil && !p.closed { p.ch <- struct{}{} } p.mu.Unlock() return nil } type activeConn struct { p *Pool pc *poolConn state int } var ( sentinel []byte sentinelOnce sync.Once ) func initSentinel() { p := make([]byte, 64) if _, err := rand.Read(p); err == nil { sentinel = p } else { h := sha1.New() io.WriteString(h, "Oops, rand failed. Use time instead.") io.WriteString(h, strconv.FormatInt(time.Now().UnixNano(), 10)) sentinel = h.Sum(nil) } } func (ac *activeConn) Close() error { pc := ac.pc if pc == nil { return nil } ac.pc = nil if ac.state&internal.MultiState != 0 { pc.c.Send("DISCARD") ac.state &^= (internal.MultiState | internal.WatchState) } else if ac.state&internal.WatchState != 0 { pc.c.Send("UNWATCH") ac.state &^= internal.WatchState } if ac.state&internal.SubscribeState != 0 { pc.c.Send("UNSUBSCRIBE") pc.c.Send("PUNSUBSCRIBE") // To detect the end of the message stream, ask the server to echo // a sentinel value and read until we see that value. sentinelOnce.Do(initSentinel) pc.c.Send("ECHO", sentinel) pc.c.Flush() for { p, err := pc.c.Receive() if err != nil { break } if p, ok := p.([]byte); ok && bytes.Equal(p, sentinel) { ac.state &^= internal.SubscribeState break } } } pc.c.Do("") ac.p.put(pc, ac.state != 0 || pc.c.Err() != nil) return nil } func (ac *activeConn) Err() error { pc := ac.pc if pc == nil { return errConnClosed } return pc.c.Err() } func (ac *activeConn) Do(commandName string, args ...interface{}) (reply interface{}, err error) { pc := ac.pc if pc == nil { return nil, errConnClosed } ci := internal.LookupCommandInfo(commandName) ac.state = (ac.state | ci.Set) &^ ci.Clear return pc.c.Do(commandName, args...) } func (ac *activeConn) DoWithTimeout(timeout time.Duration, commandName string, args ...interface{}) (reply interface{}, err error) { pc := ac.pc if pc == nil { return nil, errConnClosed } cwt, ok := pc.c.(ConnWithTimeout) if !ok { return nil, errTimeoutNotSupported } ci := internal.LookupCommandInfo(commandName) ac.state = (ac.state | ci.Set) &^ ci.Clear return cwt.DoWithTimeout(timeout, commandName, args...) } func (ac *activeConn) Send(commandName string, args ...interface{}) error { pc := ac.pc if pc == nil { return errConnClosed } ci := internal.LookupCommandInfo(commandName) ac.state = (ac.state | ci.Set) &^ ci.Clear return pc.c.Send(commandName, args...) } func (ac *activeConn) Flush() error { pc := ac.pc if pc == nil { return errConnClosed } return pc.c.Flush() } func (ac *activeConn) Receive() (reply interface{}, err error) { pc := ac.pc if pc == nil { return nil, errConnClosed } return pc.c.Receive() } func (ac *activeConn) ReceiveWithTimeout(timeout time.Duration) (reply interface{}, err error) { pc := ac.pc if pc == nil { return nil, errConnClosed } cwt, ok := pc.c.(ConnWithTimeout) if !ok { return nil, errTimeoutNotSupported } return cwt.ReceiveWithTimeout(timeout) } type errorConn struct{ err error } func (ec errorConn) Do(string, ...interface{}) (interface{}, error) { return nil, ec.err } func (ec errorConn) DoWithTimeout(time.Duration, string, ...interface{}) (interface{}, error) { return nil, ec.err } func (ec errorConn) Send(string, ...interface{}) error { return ec.err } func (ec errorConn) Err() error { return ec.err } func (ec errorConn) Close() error { return nil } func (ec errorConn) Flush() error { return ec.err } func (ec errorConn) Receive() (interface{}, error) { return nil, ec.err } func (ec errorConn) ReceiveWithTimeout(time.Duration) (interface{}, error) { return nil, ec.err } type idleList struct { count int front, back *poolConn } type poolConn struct { c Conn t time.Time created time.Time next, prev *poolConn } func (l *idleList) pushFront(pc *poolConn) { pc.next = l.front pc.prev = nil if l.count == 0 { l.back = pc } else { l.front.prev = pc } l.front = pc l.count++ return } func (l *idleList) popFront() { pc := l.front l.count-- if l.count == 0 { l.front, l.back = nil, nil } else { pc.next.prev = nil l.front = pc.next } pc.next, pc.prev = nil, nil } func (l *idleList) popBack() { pc := l.back l.count-- if l.count == 0 { l.front, l.back = nil, nil } else { pc.prev.next = nil l.back = pc.prev } pc.next, pc.prev = nil, nil } ================================================ FILE: vendor/github.com/gomodule/redigo/redis/pool17.go ================================================ // Copyright 2018 Gary Burd // // 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. // +build go1.7 package redis import "context" // GetContext gets a connection using the provided context. // // The provided Context must be non-nil. If the context expires before the // connection is complete, an error is returned. Any expiration on the context // will not affect the returned connection. // // If the function completes without error, then the application must close the // returned connection. func (p *Pool) GetContext(ctx context.Context) (Conn, error) { pc, err := p.get(ctx) if err != nil { return errorConn{err}, err } return &activeConn{p: p, pc: pc}, nil } ================================================ FILE: vendor/github.com/gomodule/redigo/redis/pubsub.go ================================================ // Copyright 2012 Gary Burd // // 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 redis import ( "errors" "time" ) // Subscription represents a subscribe or unsubscribe notification. type Subscription struct { // Kind is "subscribe", "unsubscribe", "psubscribe" or "punsubscribe" Kind string // The channel that was changed. Channel string // The current number of subscriptions for connection. Count int } // Message represents a message notification. type Message struct { // The originating channel. Channel string // The matched pattern, if any Pattern string // The message data. Data []byte } // Pong represents a pubsub pong notification. type Pong struct { Data string } // PubSubConn wraps a Conn with convenience methods for subscribers. type PubSubConn struct { Conn Conn } // Close closes the connection. func (c PubSubConn) Close() error { return c.Conn.Close() } // Subscribe subscribes the connection to the specified channels. func (c PubSubConn) Subscribe(channel ...interface{}) error { c.Conn.Send("SUBSCRIBE", channel...) return c.Conn.Flush() } // PSubscribe subscribes the connection to the given patterns. func (c PubSubConn) PSubscribe(channel ...interface{}) error { c.Conn.Send("PSUBSCRIBE", channel...) return c.Conn.Flush() } // Unsubscribe unsubscribes the connection from the given channels, or from all // of them if none is given. func (c PubSubConn) Unsubscribe(channel ...interface{}) error { c.Conn.Send("UNSUBSCRIBE", channel...) return c.Conn.Flush() } // PUnsubscribe unsubscribes the connection from the given patterns, or from all // of them if none is given. func (c PubSubConn) PUnsubscribe(channel ...interface{}) error { c.Conn.Send("PUNSUBSCRIBE", channel...) return c.Conn.Flush() } // Ping sends a PING to the server with the specified data. // // The connection must be subscribed to at least one channel or pattern when // calling this method. func (c PubSubConn) Ping(data string) error { c.Conn.Send("PING", data) return c.Conn.Flush() } // Receive returns a pushed message as a Subscription, Message, Pong or error. // The return value is intended to be used directly in a type switch as // illustrated in the PubSubConn example. func (c PubSubConn) Receive() interface{} { return c.receiveInternal(c.Conn.Receive()) } // ReceiveWithTimeout is like Receive, but it allows the application to // override the connection's default timeout. func (c PubSubConn) ReceiveWithTimeout(timeout time.Duration) interface{} { return c.receiveInternal(ReceiveWithTimeout(c.Conn, timeout)) } func (c PubSubConn) receiveInternal(replyArg interface{}, errArg error) interface{} { reply, err := Values(replyArg, errArg) if err != nil { return err } var kind string reply, err = Scan(reply, &kind) if err != nil { return err } switch kind { case "message": var m Message if _, err := Scan(reply, &m.Channel, &m.Data); err != nil { return err } return m case "pmessage": var m Message if _, err := Scan(reply, &m.Pattern, &m.Channel, &m.Data); err != nil { return err } return m case "subscribe", "psubscribe", "unsubscribe", "punsubscribe": s := Subscription{Kind: kind} if _, err := Scan(reply, &s.Channel, &s.Count); err != nil { return err } return s case "pong": var p Pong if _, err := Scan(reply, &p.Data); err != nil { return err } return p } return errors.New("redigo: unknown pubsub notification") } ================================================ FILE: vendor/github.com/gomodule/redigo/redis/redis.go ================================================ // Copyright 2012 Gary Burd // // 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 redis import ( "errors" "time" ) // Error represents an error returned in a command reply. type Error string func (err Error) Error() string { return string(err) } // Conn represents a connection to a Redis server. type Conn interface { // Close closes the connection. Close() error // Err returns a non-nil value when the connection is not usable. Err() error // Do sends a command to the server and returns the received reply. Do(commandName string, args ...interface{}) (reply interface{}, err error) // Send writes the command to the client's output buffer. Send(commandName string, args ...interface{}) error // Flush flushes the output buffer to the Redis server. Flush() error // Receive receives a single reply from the Redis server Receive() (reply interface{}, err error) } // Argument is the interface implemented by an object which wants to control how // the object is converted to Redis bulk strings. type Argument interface { // RedisArg returns a value to be encoded as a bulk string per the // conversions listed in the section 'Executing Commands'. // Implementations should typically return a []byte or string. RedisArg() interface{} } // Scanner is implemented by an object which wants to control its value is // interpreted when read from Redis. type Scanner interface { // RedisScan assigns a value from a Redis value. The argument src is one of // the reply types listed in the section `Executing Commands`. // // An error should be returned if the value cannot be stored without // loss of information. RedisScan(src interface{}) error } // ConnWithTimeout is an optional interface that allows the caller to override // a connection's default read timeout. This interface is useful for executing // the BLPOP, BRPOP, BRPOPLPUSH, XREAD and other commands that block at the // server. // // A connection's default read timeout is set with the DialReadTimeout dial // option. Applications should rely on the default timeout for commands that do // not block at the server. // // All of the Conn implementations in this package satisfy the ConnWithTimeout // interface. // // Use the DoWithTimeout and ReceiveWithTimeout helper functions to simplify // use of this interface. type ConnWithTimeout interface { Conn // Do sends a command to the server and returns the received reply. // The timeout overrides the read timeout set when dialing the // connection. DoWithTimeout(timeout time.Duration, commandName string, args ...interface{}) (reply interface{}, err error) // Receive receives a single reply from the Redis server. The timeout // overrides the read timeout set when dialing the connection. ReceiveWithTimeout(timeout time.Duration) (reply interface{}, err error) } var errTimeoutNotSupported = errors.New("redis: connection does not support ConnWithTimeout") // DoWithTimeout executes a Redis command with the specified read timeout. If // the connection does not satisfy the ConnWithTimeout interface, then an error // is returned. func DoWithTimeout(c Conn, timeout time.Duration, cmd string, args ...interface{}) (interface{}, error) { cwt, ok := c.(ConnWithTimeout) if !ok { return nil, errTimeoutNotSupported } return cwt.DoWithTimeout(timeout, cmd, args...) } // ReceiveWithTimeout receives a reply with the specified read timeout. If the // connection does not satisfy the ConnWithTimeout interface, then an error is // returned. func ReceiveWithTimeout(c Conn, timeout time.Duration) (interface{}, error) { cwt, ok := c.(ConnWithTimeout) if !ok { return nil, errTimeoutNotSupported } return cwt.ReceiveWithTimeout(timeout) } ================================================ FILE: vendor/github.com/gomodule/redigo/redis/reply.go ================================================ // Copyright 2012 Gary Burd // // 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 redis import ( "errors" "fmt" "strconv" ) // ErrNil indicates that a reply value is nil. var ErrNil = errors.New("redigo: nil returned") // Int is a helper that converts a command reply to an integer. If err is not // equal to nil, then Int returns 0, err. Otherwise, Int converts the // reply to an int as follows: // // Reply type Result // integer int(reply), nil // bulk string parsed reply, nil // nil 0, ErrNil // other 0, error func Int(reply interface{}, err error) (int, error) { if err != nil { return 0, err } switch reply := reply.(type) { case int64: x := int(reply) if int64(x) != reply { return 0, strconv.ErrRange } return x, nil case []byte: n, err := strconv.ParseInt(string(reply), 10, 0) return int(n), err case nil: return 0, ErrNil case Error: return 0, reply } return 0, fmt.Errorf("redigo: unexpected type for Int, got type %T", reply) } // Int64 is a helper that converts a command reply to 64 bit integer. If err is // not equal to nil, then Int returns 0, err. Otherwise, Int64 converts the // reply to an int64 as follows: // // Reply type Result // integer reply, nil // bulk string parsed reply, nil // nil 0, ErrNil // other 0, error func Int64(reply interface{}, err error) (int64, error) { if err != nil { return 0, err } switch reply := reply.(type) { case int64: return reply, nil case []byte: n, err := strconv.ParseInt(string(reply), 10, 64) return n, err case nil: return 0, ErrNil case Error: return 0, reply } return 0, fmt.Errorf("redigo: unexpected type for Int64, got type %T", reply) } var errNegativeInt = errors.New("redigo: unexpected value for Uint64") // Uint64 is a helper that converts a command reply to 64 bit integer. If err is // not equal to nil, then Int returns 0, err. Otherwise, Int64 converts the // reply to an int64 as follows: // // Reply type Result // integer reply, nil // bulk string parsed reply, nil // nil 0, ErrNil // other 0, error func Uint64(reply interface{}, err error) (uint64, error) { if err != nil { return 0, err } switch reply := reply.(type) { case int64: if reply < 0 { return 0, errNegativeInt } return uint64(reply), nil case []byte: n, err := strconv.ParseUint(string(reply), 10, 64) return n, err case nil: return 0, ErrNil case Error: return 0, reply } return 0, fmt.Errorf("redigo: unexpected type for Uint64, got type %T", reply) } // Float64 is a helper that converts a command reply to 64 bit float. If err is // not equal to nil, then Float64 returns 0, err. Otherwise, Float64 converts // the reply to an int as follows: // // Reply type Result // bulk string parsed reply, nil // nil 0, ErrNil // other 0, error func Float64(reply interface{}, err error) (float64, error) { if err != nil { return 0, err } switch reply := reply.(type) { case []byte: n, err := strconv.ParseFloat(string(reply), 64) return n, err case nil: return 0, ErrNil case Error: return 0, reply } return 0, fmt.Errorf("redigo: unexpected type for Float64, got type %T", reply) } // String is a helper that converts a command reply to a string. If err is not // equal to nil, then String returns "", err. Otherwise String converts the // reply to a string as follows: // // Reply type Result // bulk string string(reply), nil // simple string reply, nil // nil "", ErrNil // other "", error func String(reply interface{}, err error) (string, error) { if err != nil { return "", err } switch reply := reply.(type) { case []byte: return string(reply), nil case string: return reply, nil case nil: return "", ErrNil case Error: return "", reply } return "", fmt.Errorf("redigo: unexpected type for String, got type %T", reply) } // Bytes is a helper that converts a command reply to a slice of bytes. If err // is not equal to nil, then Bytes returns nil, err. Otherwise Bytes converts // the reply to a slice of bytes as follows: // // Reply type Result // bulk string reply, nil // simple string []byte(reply), nil // nil nil, ErrNil // other nil, error func Bytes(reply interface{}, err error) ([]byte, error) { if err != nil { return nil, err } switch reply := reply.(type) { case []byte: return reply, nil case string: return []byte(reply), nil case nil: return nil, ErrNil case Error: return nil, reply } return nil, fmt.Errorf("redigo: unexpected type for Bytes, got type %T", reply) } // Bool is a helper that converts a command reply to a boolean. If err is not // equal to nil, then Bool returns false, err. Otherwise Bool converts the // reply to boolean as follows: // // Reply type Result // integer value != 0, nil // bulk string strconv.ParseBool(reply) // nil false, ErrNil // other false, error func Bool(reply interface{}, err error) (bool, error) { if err != nil { return false, err } switch reply := reply.(type) { case int64: return reply != 0, nil case []byte: return strconv.ParseBool(string(reply)) case nil: return false, ErrNil case Error: return false, reply } return false, fmt.Errorf("redigo: unexpected type for Bool, got type %T", reply) } // MultiBulk is a helper that converts an array command reply to a []interface{}. // // Deprecated: Use Values instead. func MultiBulk(reply interface{}, err error) ([]interface{}, error) { return Values(reply, err) } // Values is a helper that converts an array command reply to a []interface{}. // If err is not equal to nil, then Values returns nil, err. Otherwise, Values // converts the reply as follows: // // Reply type Result // array reply, nil // nil nil, ErrNil // other nil, error func Values(reply interface{}, err error) ([]interface{}, error) { if err != nil { return nil, err } switch reply := reply.(type) { case []interface{}: return reply, nil case nil: return nil, ErrNil case Error: return nil, reply } return nil, fmt.Errorf("redigo: unexpected type for Values, got type %T", reply) } func sliceHelper(reply interface{}, err error, name string, makeSlice func(int), assign func(int, interface{}) error) error { if err != nil { return err } switch reply := reply.(type) { case []interface{}: makeSlice(len(reply)) for i := range reply { if reply[i] == nil { continue } if err := assign(i, reply[i]); err != nil { return err } } return nil case nil: return ErrNil case Error: return reply } return fmt.Errorf("redigo: unexpected type for %s, got type %T", name, reply) } // Float64s is a helper that converts an array command reply to a []float64. If // err is not equal to nil, then Float64s returns nil, err. Nil array items are // converted to 0 in the output slice. Floats64 returns an error if an array // item is not a bulk string or nil. func Float64s(reply interface{}, err error) ([]float64, error) { var result []float64 err = sliceHelper(reply, err, "Float64s", func(n int) { result = make([]float64, n) }, func(i int, v interface{}) error { p, ok := v.([]byte) if !ok { return fmt.Errorf("redigo: unexpected element type for Floats64, got type %T", v) } f, err := strconv.ParseFloat(string(p), 64) result[i] = f return err }) return result, err } // Strings is a helper that converts an array command reply to a []string. If // err is not equal to nil, then Strings returns nil, err. Nil array items are // converted to "" in the output slice. Strings returns an error if an array // item is not a bulk string or nil. func Strings(reply interface{}, err error) ([]string, error) { var result []string err = sliceHelper(reply, err, "Strings", func(n int) { result = make([]string, n) }, func(i int, v interface{}) error { switch v := v.(type) { case string: result[i] = v return nil case []byte: result[i] = string(v) return nil default: return fmt.Errorf("redigo: unexpected element type for Strings, got type %T", v) } }) return result, err } // ByteSlices is a helper that converts an array command reply to a [][]byte. // If err is not equal to nil, then ByteSlices returns nil, err. Nil array // items are stay nil. ByteSlices returns an error if an array item is not a // bulk string or nil. func ByteSlices(reply interface{}, err error) ([][]byte, error) { var result [][]byte err = sliceHelper(reply, err, "ByteSlices", func(n int) { result = make([][]byte, n) }, func(i int, v interface{}) error { p, ok := v.([]byte) if !ok { return fmt.Errorf("redigo: unexpected element type for ByteSlices, got type %T", v) } result[i] = p return nil }) return result, err } // Int64s is a helper that converts an array command reply to a []int64. // If err is not equal to nil, then Int64s returns nil, err. Nil array // items are stay nil. Int64s returns an error if an array item is not a // bulk string or nil. func Int64s(reply interface{}, err error) ([]int64, error) { var result []int64 err = sliceHelper(reply, err, "Int64s", func(n int) { result = make([]int64, n) }, func(i int, v interface{}) error { switch v := v.(type) { case int64: result[i] = v return nil case []byte: n, err := strconv.ParseInt(string(v), 10, 64) result[i] = n return err default: return fmt.Errorf("redigo: unexpected element type for Int64s, got type %T", v) } }) return result, err } // Ints is a helper that converts an array command reply to a []in. // If err is not equal to nil, then Ints returns nil, err. Nil array // items are stay nil. Ints returns an error if an array item is not a // bulk string or nil. func Ints(reply interface{}, err error) ([]int, error) { var result []int err = sliceHelper(reply, err, "Ints", func(n int) { result = make([]int, n) }, func(i int, v interface{}) error { switch v := v.(type) { case int64: n := int(v) if int64(n) != v { return strconv.ErrRange } result[i] = n return nil case []byte: n, err := strconv.Atoi(string(v)) result[i] = n return err default: return fmt.Errorf("redigo: unexpected element type for Ints, got type %T", v) } }) return result, err } // StringMap is a helper that converts an array of strings (alternating key, value) // into a map[string]string. The HGETALL and CONFIG GET commands return replies in this format. // Requires an even number of values in result. func StringMap(result interface{}, err error) (map[string]string, error) { values, err := Values(result, err) if err != nil { return nil, err } if len(values)%2 != 0 { return nil, errors.New("redigo: StringMap expects even number of values result") } m := make(map[string]string, len(values)/2) for i := 0; i < len(values); i += 2 { key, okKey := values[i].([]byte) value, okValue := values[i+1].([]byte) if !okKey || !okValue { return nil, errors.New("redigo: StringMap key not a bulk string value") } m[string(key)] = string(value) } return m, nil } // IntMap is a helper that converts an array of strings (alternating key, value) // into a map[string]int. The HGETALL commands return replies in this format. // Requires an even number of values in result. func IntMap(result interface{}, err error) (map[string]int, error) { values, err := Values(result, err) if err != nil { return nil, err } if len(values)%2 != 0 { return nil, errors.New("redigo: IntMap expects even number of values result") } m := make(map[string]int, len(values)/2) for i := 0; i < len(values); i += 2 { key, ok := values[i].([]byte) if !ok { return nil, errors.New("redigo: IntMap key not a bulk string value") } value, err := Int(values[i+1], nil) if err != nil { return nil, err } m[string(key)] = value } return m, nil } // Int64Map is a helper that converts an array of strings (alternating key, value) // into a map[string]int64. The HGETALL commands return replies in this format. // Requires an even number of values in result. func Int64Map(result interface{}, err error) (map[string]int64, error) { values, err := Values(result, err) if err != nil { return nil, err } if len(values)%2 != 0 { return nil, errors.New("redigo: Int64Map expects even number of values result") } m := make(map[string]int64, len(values)/2) for i := 0; i < len(values); i += 2 { key, ok := values[i].([]byte) if !ok { return nil, errors.New("redigo: Int64Map key not a bulk string value") } value, err := Int64(values[i+1], nil) if err != nil { return nil, err } m[string(key)] = value } return m, nil } // Positions is a helper that converts an array of positions (lat, long) // into a [][2]float64. The GEOPOS command returns replies in this format. func Positions(result interface{}, err error) ([]*[2]float64, error) { values, err := Values(result, err) if err != nil { return nil, err } positions := make([]*[2]float64, len(values)) for i := range values { if values[i] == nil { continue } p, ok := values[i].([]interface{}) if !ok { return nil, fmt.Errorf("redigo: unexpected element type for interface slice, got type %T", values[i]) } if len(p) != 2 { return nil, fmt.Errorf("redigo: unexpected number of values for a member position, got %d", len(p)) } lat, err := Float64(p[0], nil) if err != nil { return nil, err } long, err := Float64(p[1], nil) if err != nil { return nil, err } positions[i] = &[2]float64{lat, long} } return positions, nil } ================================================ FILE: vendor/github.com/gomodule/redigo/redis/scan.go ================================================ // Copyright 2012 Gary Burd // // 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 redis import ( "errors" "fmt" "reflect" "strconv" "strings" "sync" ) func ensureLen(d reflect.Value, n int) { if n > d.Cap() { d.Set(reflect.MakeSlice(d.Type(), n, n)) } else { d.SetLen(n) } } func cannotConvert(d reflect.Value, s interface{}) error { var sname string switch s.(type) { case string: sname = "Redis simple string" case Error: sname = "Redis error" case int64: sname = "Redis integer" case []byte: sname = "Redis bulk string" case []interface{}: sname = "Redis array" default: sname = reflect.TypeOf(s).String() } return fmt.Errorf("cannot convert from %s to %s", sname, d.Type()) } func convertAssignBulkString(d reflect.Value, s []byte) (err error) { switch d.Type().Kind() { case reflect.Float32, reflect.Float64: var x float64 x, err = strconv.ParseFloat(string(s), d.Type().Bits()) d.SetFloat(x) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: var x int64 x, err = strconv.ParseInt(string(s), 10, d.Type().Bits()) d.SetInt(x) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: var x uint64 x, err = strconv.ParseUint(string(s), 10, d.Type().Bits()) d.SetUint(x) case reflect.Bool: var x bool x, err = strconv.ParseBool(string(s)) d.SetBool(x) case reflect.String: d.SetString(string(s)) case reflect.Slice: if d.Type().Elem().Kind() != reflect.Uint8 { err = cannotConvert(d, s) } else { d.SetBytes(s) } default: err = cannotConvert(d, s) } return } func convertAssignInt(d reflect.Value, s int64) (err error) { switch d.Type().Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: d.SetInt(s) if d.Int() != s { err = strconv.ErrRange d.SetInt(0) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: if s < 0 { err = strconv.ErrRange } else { x := uint64(s) d.SetUint(x) if d.Uint() != x { err = strconv.ErrRange d.SetUint(0) } } case reflect.Bool: d.SetBool(s != 0) default: err = cannotConvert(d, s) } return } func convertAssignValue(d reflect.Value, s interface{}) (err error) { if d.Kind() != reflect.Ptr { if d.CanAddr() { d2 := d.Addr() if d2.CanInterface() { if scanner, ok := d2.Interface().(Scanner); ok { return scanner.RedisScan(s) } } } } else if d.CanInterface() { // Already a reflect.Ptr if d.IsNil() { d.Set(reflect.New(d.Type().Elem())) } if scanner, ok := d.Interface().(Scanner); ok { return scanner.RedisScan(s) } } switch s := s.(type) { case []byte: err = convertAssignBulkString(d, s) case int64: err = convertAssignInt(d, s) default: err = cannotConvert(d, s) } return err } func convertAssignArray(d reflect.Value, s []interface{}) error { if d.Type().Kind() != reflect.Slice { return cannotConvert(d, s) } ensureLen(d, len(s)) for i := 0; i < len(s); i++ { if err := convertAssignValue(d.Index(i), s[i]); err != nil { return err } } return nil } func convertAssign(d interface{}, s interface{}) (err error) { if scanner, ok := d.(Scanner); ok { return scanner.RedisScan(s) } // Handle the most common destination types using type switches and // fall back to reflection for all other types. switch s := s.(type) { case nil: // ignore case []byte: switch d := d.(type) { case *string: *d = string(s) case *int: *d, err = strconv.Atoi(string(s)) case *bool: *d, err = strconv.ParseBool(string(s)) case *[]byte: *d = s case *interface{}: *d = s case nil: // skip value default: if d := reflect.ValueOf(d); d.Type().Kind() != reflect.Ptr { err = cannotConvert(d, s) } else { err = convertAssignBulkString(d.Elem(), s) } } case int64: switch d := d.(type) { case *int: x := int(s) if int64(x) != s { err = strconv.ErrRange x = 0 } *d = x case *bool: *d = s != 0 case *interface{}: *d = s case nil: // skip value default: if d := reflect.ValueOf(d); d.Type().Kind() != reflect.Ptr { err = cannotConvert(d, s) } else { err = convertAssignInt(d.Elem(), s) } } case string: switch d := d.(type) { case *string: *d = s case *interface{}: *d = s case nil: // skip value default: err = cannotConvert(reflect.ValueOf(d), s) } case []interface{}: switch d := d.(type) { case *[]interface{}: *d = s case *interface{}: *d = s case nil: // skip value default: if d := reflect.ValueOf(d); d.Type().Kind() != reflect.Ptr { err = cannotConvert(d, s) } else { err = convertAssignArray(d.Elem(), s) } } case Error: err = s default: err = cannotConvert(reflect.ValueOf(d), s) } return } // Scan copies from src to the values pointed at by dest. // // Scan uses RedisScan if available otherwise: // // The values pointed at by dest must be an integer, float, boolean, string, // []byte, interface{} or slices of these types. Scan uses the standard strconv // package to convert bulk strings to numeric and boolean types. // // If a dest value is nil, then the corresponding src value is skipped. // // If a src element is nil, then the corresponding dest value is not modified. // // To enable easy use of Scan in a loop, Scan returns the slice of src // following the copied values. func Scan(src []interface{}, dest ...interface{}) ([]interface{}, error) { if len(src) < len(dest) { return nil, errors.New("redigo.Scan: array short") } var err error for i, d := range dest { err = convertAssign(d, src[i]) if err != nil { err = fmt.Errorf("redigo.Scan: cannot assign to dest %d: %v", i, err) break } } return src[len(dest):], err } type fieldSpec struct { name string index []int omitEmpty bool } type structSpec struct { m map[string]*fieldSpec l []*fieldSpec } func (ss *structSpec) fieldSpec(name []byte) *fieldSpec { return ss.m[string(name)] } func compileStructSpec(t reflect.Type, depth map[string]int, index []int, ss *structSpec) { for i := 0; i < t.NumField(); i++ { f := t.Field(i) switch { case f.PkgPath != "" && !f.Anonymous: // Ignore unexported fields. case f.Anonymous: // TODO: Handle pointers. Requires change to decoder and // protection against infinite recursion. if f.Type.Kind() == reflect.Struct { compileStructSpec(f.Type, depth, append(index, i), ss) } default: fs := &fieldSpec{name: f.Name} tag := f.Tag.Get("redis") p := strings.Split(tag, ",") if len(p) > 0 { if p[0] == "-" { continue } if len(p[0]) > 0 { fs.name = p[0] } for _, s := range p[1:] { switch s { case "omitempty": fs.omitEmpty = true default: panic(fmt.Errorf("redigo: unknown field tag %s for type %s", s, t.Name())) } } } d, found := depth[fs.name] if !found { d = 1 << 30 } switch { case len(index) == d: // At same depth, remove from result. delete(ss.m, fs.name) j := 0 for i := 0; i < len(ss.l); i++ { if fs.name != ss.l[i].name { ss.l[j] = ss.l[i] j += 1 } } ss.l = ss.l[:j] case len(index) < d: fs.index = make([]int, len(index)+1) copy(fs.index, index) fs.index[len(index)] = i depth[fs.name] = len(index) ss.m[fs.name] = fs ss.l = append(ss.l, fs) } } } } var ( structSpecMutex sync.RWMutex structSpecCache = make(map[reflect.Type]*structSpec) defaultFieldSpec = &fieldSpec{} ) func structSpecForType(t reflect.Type) *structSpec { structSpecMutex.RLock() ss, found := structSpecCache[t] structSpecMutex.RUnlock() if found { return ss } structSpecMutex.Lock() defer structSpecMutex.Unlock() ss, found = structSpecCache[t] if found { return ss } ss = &structSpec{m: make(map[string]*fieldSpec)} compileStructSpec(t, make(map[string]int), nil, ss) structSpecCache[t] = ss return ss } var errScanStructValue = errors.New("redigo.ScanStruct: value must be non-nil pointer to a struct") // ScanStruct scans alternating names and values from src to a struct. The // HGETALL and CONFIG GET commands return replies in this format. // // ScanStruct uses exported field names to match values in the response. Use // 'redis' field tag to override the name: // // Field int `redis:"myName"` // // Fields with the tag redis:"-" are ignored. // // Each field uses RedisScan if available otherwise: // Integer, float, boolean, string and []byte fields are supported. Scan uses the // standard strconv package to convert bulk string values to numeric and // boolean types. // // If a src element is nil, then the corresponding field is not modified. func ScanStruct(src []interface{}, dest interface{}) error { d := reflect.ValueOf(dest) if d.Kind() != reflect.Ptr || d.IsNil() { return errScanStructValue } d = d.Elem() if d.Kind() != reflect.Struct { return errScanStructValue } ss := structSpecForType(d.Type()) if len(src)%2 != 0 { return errors.New("redigo.ScanStruct: number of values not a multiple of 2") } for i := 0; i < len(src); i += 2 { s := src[i+1] if s == nil { continue } name, ok := src[i].([]byte) if !ok { return fmt.Errorf("redigo.ScanStruct: key %d not a bulk string value", i) } fs := ss.fieldSpec(name) if fs == nil { continue } if err := convertAssignValue(d.FieldByIndex(fs.index), s); err != nil { return fmt.Errorf("redigo.ScanStruct: cannot assign field %s: %v", fs.name, err) } } return nil } var ( errScanSliceValue = errors.New("redigo.ScanSlice: dest must be non-nil pointer to a struct") ) // ScanSlice scans src to the slice pointed to by dest. The elements the dest // slice must be integer, float, boolean, string, struct or pointer to struct // values. // // Struct fields must be integer, float, boolean or string values. All struct // fields are used unless a subset is specified using fieldNames. func ScanSlice(src []interface{}, dest interface{}, fieldNames ...string) error { d := reflect.ValueOf(dest) if d.Kind() != reflect.Ptr || d.IsNil() { return errScanSliceValue } d = d.Elem() if d.Kind() != reflect.Slice { return errScanSliceValue } isPtr := false t := d.Type().Elem() if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct { isPtr = true t = t.Elem() } if t.Kind() != reflect.Struct { ensureLen(d, len(src)) for i, s := range src { if s == nil { continue } if err := convertAssignValue(d.Index(i), s); err != nil { return fmt.Errorf("redigo.ScanSlice: cannot assign element %d: %v", i, err) } } return nil } ss := structSpecForType(t) fss := ss.l if len(fieldNames) > 0 { fss = make([]*fieldSpec, len(fieldNames)) for i, name := range fieldNames { fss[i] = ss.m[name] if fss[i] == nil { return fmt.Errorf("redigo.ScanSlice: ScanSlice bad field name %s", name) } } } if len(fss) == 0 { return errors.New("redigo.ScanSlice: no struct fields") } n := len(src) / len(fss) if n*len(fss) != len(src) { return errors.New("redigo.ScanSlice: length not a multiple of struct field count") } ensureLen(d, n) for i := 0; i < n; i++ { d := d.Index(i) if isPtr { if d.IsNil() { d.Set(reflect.New(t)) } d = d.Elem() } for j, fs := range fss { s := src[i*len(fss)+j] if s == nil { continue } if err := convertAssignValue(d.FieldByIndex(fs.index), s); err != nil { return fmt.Errorf("redigo.ScanSlice: cannot assign element %d to field %s: %v", i*len(fss)+j, fs.name, err) } } } return nil } // Args is a helper for constructing command arguments from structured values. type Args []interface{} // Add returns the result of appending value to args. func (args Args) Add(value ...interface{}) Args { return append(args, value...) } // AddFlat returns the result of appending the flattened value of v to args. // // Maps are flattened by appending the alternating keys and map values to args. // // Slices are flattened by appending the slice elements to args. // // Structs are flattened by appending the alternating names and values of // exported fields to args. If v is a nil struct pointer, then nothing is // appended. The 'redis' field tag overrides struct field names. See ScanStruct // for more information on the use of the 'redis' field tag. // // Other types are appended to args as is. func (args Args) AddFlat(v interface{}) Args { rv := reflect.ValueOf(v) switch rv.Kind() { case reflect.Struct: args = flattenStruct(args, rv) case reflect.Slice: for i := 0; i < rv.Len(); i++ { args = append(args, rv.Index(i).Interface()) } case reflect.Map: for _, k := range rv.MapKeys() { args = append(args, k.Interface(), rv.MapIndex(k).Interface()) } case reflect.Ptr: if rv.Type().Elem().Kind() == reflect.Struct { if !rv.IsNil() { args = flattenStruct(args, rv.Elem()) } } else { args = append(args, v) } default: args = append(args, v) } return args } func flattenStruct(args Args, v reflect.Value) Args { ss := structSpecForType(v.Type()) for _, fs := range ss.l { fv := v.FieldByIndex(fs.index) if fs.omitEmpty { var empty = false switch fv.Kind() { case reflect.Array, reflect.Map, reflect.Slice, reflect.String: empty = fv.Len() == 0 case reflect.Bool: empty = !fv.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: empty = fv.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: empty = fv.Uint() == 0 case reflect.Float32, reflect.Float64: empty = fv.Float() == 0 case reflect.Interface, reflect.Ptr: empty = fv.IsNil() } if empty { continue } } args = append(args, fs.name, fv.Interface()) } return args } ================================================ FILE: vendor/github.com/gomodule/redigo/redis/script.go ================================================ // Copyright 2012 Gary Burd // // 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 redis import ( "crypto/sha1" "encoding/hex" "io" "strings" ) // Script encapsulates the source, hash and key count for a Lua script. See // http://redis.io/commands/eval for information on scripts in Redis. type Script struct { keyCount int src string hash string } // NewScript returns a new script object. If keyCount is greater than or equal // to zero, then the count is automatically inserted in the EVAL command // argument list. If keyCount is less than zero, then the application supplies // the count as the first value in the keysAndArgs argument to the Do, Send and // SendHash methods. func NewScript(keyCount int, src string) *Script { h := sha1.New() io.WriteString(h, src) return &Script{keyCount, src, hex.EncodeToString(h.Sum(nil))} } func (s *Script) args(spec string, keysAndArgs []interface{}) []interface{} { var args []interface{} if s.keyCount < 0 { args = make([]interface{}, 1+len(keysAndArgs)) args[0] = spec copy(args[1:], keysAndArgs) } else { args = make([]interface{}, 2+len(keysAndArgs)) args[0] = spec args[1] = s.keyCount copy(args[2:], keysAndArgs) } return args } // Hash returns the script hash. func (s *Script) Hash() string { return s.hash } // Do evaluates the script. Under the covers, Do optimistically evaluates the // script using the EVALSHA command. If the command fails because the script is // not loaded, then Do evaluates the script using the EVAL command (thus // causing the script to load). func (s *Script) Do(c Conn, keysAndArgs ...interface{}) (interface{}, error) { v, err := c.Do("EVALSHA", s.args(s.hash, keysAndArgs)...) if e, ok := err.(Error); ok && strings.HasPrefix(string(e), "NOSCRIPT ") { v, err = c.Do("EVAL", s.args(s.src, keysAndArgs)...) } return v, err } // SendHash evaluates the script without waiting for the reply. The script is // evaluated with the EVALSHA command. The application must ensure that the // script is loaded by a previous call to Send, Do or Load methods. func (s *Script) SendHash(c Conn, keysAndArgs ...interface{}) error { return c.Send("EVALSHA", s.args(s.hash, keysAndArgs)...) } // Send evaluates the script without waiting for the reply. func (s *Script) Send(c Conn, keysAndArgs ...interface{}) error { return c.Send("EVAL", s.args(s.src, keysAndArgs)...) } // Load loads the script without evaluating it. func (s *Script) Load(c Conn) error { _, err := c.Do("SCRIPT", "LOAD", s.src) return err } ================================================ FILE: vendor/github.com/jinzhu/gorm/.codeclimate.yml ================================================ --- engines: gofmt: enabled: true govet: enabled: true golint: enabled: true ratings: paths: - "**.go" ================================================ FILE: vendor/github.com/jinzhu/gorm/.gitignore ================================================ documents _book ================================================ FILE: vendor/github.com/jinzhu/gorm/License ================================================ The MIT License (MIT) Copyright (c) 2013-NOW Jinzhu 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. ================================================ FILE: vendor/github.com/jinzhu/gorm/README.md ================================================ # GORM The fantastic ORM library for Golang, aims to be developer friendly. [![go report card](https://goreportcard.com/badge/github.com/jinzhu/gorm "go report card")](https://goreportcard.com/report/github.com/jinzhu/gorm) [![wercker status](https://app.wercker.com/status/8596cace912c9947dd9c8542ecc8cb8b/s/master "wercker status")](https://app.wercker.com/project/byKey/8596cace912c9947dd9c8542ecc8cb8b) [![Join the chat at https://gitter.im/jinzhu/gorm](https://img.shields.io/gitter/room/jinzhu/gorm.svg)](https://gitter.im/jinzhu/gorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Open Collective Backer](https://opencollective.com/gorm/tiers/backer/badge.svg?label=backer&color=brightgreen "Open Collective Backer")](https://opencollective.com/gorm) [![Open Collective Sponsor](https://opencollective.com/gorm/tiers/sponsor/badge.svg?label=sponsor&color=brightgreen "Open Collective Sponsor")](https://opencollective.com/gorm) [![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT) [![GoDoc](https://godoc.org/github.com/jinzhu/gorm?status.svg)](https://godoc.org/github.com/jinzhu/gorm) ## Overview * Full-Featured ORM (almost) * Associations (Has One, Has Many, Belongs To, Many To Many, Polymorphism) * Callbacks (Before/After Create/Save/Update/Delete/Find) * Preloading (eager loading) * Transactions * Composite Primary Key * SQL Builder * Auto Migrations * Logger * Extendable, write Plugins based on GORM callbacks * Every feature comes with tests * Developer Friendly ## Getting Started * GORM Guides [http://gorm.io](http://gorm.io) ## Contributing [Become a backer or sponsor on Open Collective](http://opencollective.com/gorm) [Become a backer or sponsor on Patreon](http://patreon.com/jinzhu) ## License © Jinzhu, 2013~time.Now Released under the [MIT License](https://github.com/jinzhu/gorm/blob/master/License) ================================================ FILE: vendor/github.com/jinzhu/gorm/association.go ================================================ package gorm import ( "errors" "fmt" "reflect" ) // Association Mode contains some helper methods to handle relationship things easily. type Association struct { Error error scope *Scope column string field *Field } // Find find out all related associations func (association *Association) Find(value interface{}) *Association { association.scope.related(value, association.column) return association.setErr(association.scope.db.Error) } // Append append new associations for many2many, has_many, replace current association for has_one, belongs_to func (association *Association) Append(values ...interface{}) *Association { if association.Error != nil { return association } if relationship := association.field.Relationship; relationship.Kind == "has_one" { return association.Replace(values...) } return association.saveAssociations(values...) } // Replace replace current associations with new one func (association *Association) Replace(values ...interface{}) *Association { if association.Error != nil { return association } var ( relationship = association.field.Relationship scope = association.scope field = association.field.Field newDB = scope.NewDB() ) // Append new values association.field.Set(reflect.Zero(association.field.Field.Type())) association.saveAssociations(values...) // Belongs To if relationship.Kind == "belongs_to" { // Set foreign key to be null when clearing value (length equals 0) if len(values) == 0 { // Set foreign key to be nil var foreignKeyMap = map[string]interface{}{} for _, foreignKey := range relationship.ForeignDBNames { foreignKeyMap[foreignKey] = nil } association.setErr(newDB.Model(scope.Value).UpdateColumn(foreignKeyMap).Error) } } else { // Polymorphic Relations if relationship.PolymorphicDBName != "" { newDB = newDB.Where(fmt.Sprintf("%v = ?", scope.Quote(relationship.PolymorphicDBName)), relationship.PolymorphicValue) } // Delete Relations except new created if len(values) > 0 { var associationForeignFieldNames, associationForeignDBNames []string if relationship.Kind == "many_to_many" { // if many to many relations, get association fields name from association foreign keys associationScope := scope.New(reflect.New(field.Type()).Interface()) for idx, dbName := range relationship.AssociationForeignFieldNames { if field, ok := associationScope.FieldByName(dbName); ok { associationForeignFieldNames = append(associationForeignFieldNames, field.Name) associationForeignDBNames = append(associationForeignDBNames, relationship.AssociationForeignDBNames[idx]) } } } else { // If has one/many relations, use primary keys for _, field := range scope.New(reflect.New(field.Type()).Interface()).PrimaryFields() { associationForeignFieldNames = append(associationForeignFieldNames, field.Name) associationForeignDBNames = append(associationForeignDBNames, field.DBName) } } newPrimaryKeys := scope.getColumnAsArray(associationForeignFieldNames, field.Interface()) if len(newPrimaryKeys) > 0 { sql := fmt.Sprintf("%v NOT IN (%v)", toQueryCondition(scope, associationForeignDBNames), toQueryMarks(newPrimaryKeys)) newDB = newDB.Where(sql, toQueryValues(newPrimaryKeys)...) } } if relationship.Kind == "many_to_many" { // if many to many relations, delete related relations from join table var sourceForeignFieldNames []string for _, dbName := range relationship.ForeignFieldNames { if field, ok := scope.FieldByName(dbName); ok { sourceForeignFieldNames = append(sourceForeignFieldNames, field.Name) } } if sourcePrimaryKeys := scope.getColumnAsArray(sourceForeignFieldNames, scope.Value); len(sourcePrimaryKeys) > 0 { newDB = newDB.Where(fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.ForeignDBNames), toQueryMarks(sourcePrimaryKeys)), toQueryValues(sourcePrimaryKeys)...) association.setErr(relationship.JoinTableHandler.Delete(relationship.JoinTableHandler, newDB)) } } else if relationship.Kind == "has_one" || relationship.Kind == "has_many" { // has_one or has_many relations, set foreign key to be nil (TODO or delete them?) var foreignKeyMap = map[string]interface{}{} for idx, foreignKey := range relationship.ForeignDBNames { foreignKeyMap[foreignKey] = nil if field, ok := scope.FieldByName(relationship.AssociationForeignFieldNames[idx]); ok { newDB = newDB.Where(fmt.Sprintf("%v = ?", scope.Quote(foreignKey)), field.Field.Interface()) } } fieldValue := reflect.New(association.field.Field.Type()).Interface() association.setErr(newDB.Model(fieldValue).UpdateColumn(foreignKeyMap).Error) } } return association } // Delete remove relationship between source & passed arguments, but won't delete those arguments func (association *Association) Delete(values ...interface{}) *Association { if association.Error != nil { return association } var ( relationship = association.field.Relationship scope = association.scope field = association.field.Field newDB = scope.NewDB() ) if len(values) == 0 { return association } var deletingResourcePrimaryFieldNames, deletingResourcePrimaryDBNames []string for _, field := range scope.New(reflect.New(field.Type()).Interface()).PrimaryFields() { deletingResourcePrimaryFieldNames = append(deletingResourcePrimaryFieldNames, field.Name) deletingResourcePrimaryDBNames = append(deletingResourcePrimaryDBNames, field.DBName) } deletingPrimaryKeys := scope.getColumnAsArray(deletingResourcePrimaryFieldNames, values...) if relationship.Kind == "many_to_many" { // source value's foreign keys for idx, foreignKey := range relationship.ForeignDBNames { if field, ok := scope.FieldByName(relationship.ForeignFieldNames[idx]); ok { newDB = newDB.Where(fmt.Sprintf("%v = ?", scope.Quote(foreignKey)), field.Field.Interface()) } } // get association's foreign fields name var associationScope = scope.New(reflect.New(field.Type()).Interface()) var associationForeignFieldNames []string for _, associationDBName := range relationship.AssociationForeignFieldNames { if field, ok := associationScope.FieldByName(associationDBName); ok { associationForeignFieldNames = append(associationForeignFieldNames, field.Name) } } // association value's foreign keys deletingPrimaryKeys := scope.getColumnAsArray(associationForeignFieldNames, values...) sql := fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.AssociationForeignDBNames), toQueryMarks(deletingPrimaryKeys)) newDB = newDB.Where(sql, toQueryValues(deletingPrimaryKeys)...) association.setErr(relationship.JoinTableHandler.Delete(relationship.JoinTableHandler, newDB)) } else { var foreignKeyMap = map[string]interface{}{} for _, foreignKey := range relationship.ForeignDBNames { foreignKeyMap[foreignKey] = nil } if relationship.Kind == "belongs_to" { // find with deleting relation's foreign keys primaryKeys := scope.getColumnAsArray(relationship.AssociationForeignFieldNames, values...) newDB = newDB.Where( fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.ForeignDBNames), toQueryMarks(primaryKeys)), toQueryValues(primaryKeys)..., ) // set foreign key to be null if there are some records affected modelValue := reflect.New(scope.GetModelStruct().ModelType).Interface() if results := newDB.Model(modelValue).UpdateColumn(foreignKeyMap); results.Error == nil { if results.RowsAffected > 0 { scope.updatedAttrsWithValues(foreignKeyMap) } } else { association.setErr(results.Error) } } else if relationship.Kind == "has_one" || relationship.Kind == "has_many" { // find all relations primaryKeys := scope.getColumnAsArray(relationship.AssociationForeignFieldNames, scope.Value) newDB = newDB.Where( fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.ForeignDBNames), toQueryMarks(primaryKeys)), toQueryValues(primaryKeys)..., ) // only include those deleting relations newDB = newDB.Where( fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, deletingResourcePrimaryDBNames), toQueryMarks(deletingPrimaryKeys)), toQueryValues(deletingPrimaryKeys)..., ) // set matched relation's foreign key to be null fieldValue := reflect.New(association.field.Field.Type()).Interface() association.setErr(newDB.Model(fieldValue).UpdateColumn(foreignKeyMap).Error) } } // Remove deleted records from source's field if association.Error == nil { if field.Kind() == reflect.Slice { leftValues := reflect.Zero(field.Type()) for i := 0; i < field.Len(); i++ { reflectValue := field.Index(i) primaryKey := scope.getColumnAsArray(deletingResourcePrimaryFieldNames, reflectValue.Interface())[0] var isDeleted = false for _, pk := range deletingPrimaryKeys { if equalAsString(primaryKey, pk) { isDeleted = true break } } if !isDeleted { leftValues = reflect.Append(leftValues, reflectValue) } } association.field.Set(leftValues) } else if field.Kind() == reflect.Struct { primaryKey := scope.getColumnAsArray(deletingResourcePrimaryFieldNames, field.Interface())[0] for _, pk := range deletingPrimaryKeys { if equalAsString(primaryKey, pk) { association.field.Set(reflect.Zero(field.Type())) break } } } } return association } // Clear remove relationship between source & current associations, won't delete those associations func (association *Association) Clear() *Association { return association.Replace() } // Count return the count of current associations func (association *Association) Count() int { var ( count = 0 relationship = association.field.Relationship scope = association.scope fieldValue = association.field.Field.Interface() query = scope.DB() ) if relationship.Kind == "many_to_many" { query = relationship.JoinTableHandler.JoinWith(relationship.JoinTableHandler, query, scope.Value) } else if relationship.Kind == "has_many" || relationship.Kind == "has_one" { primaryKeys := scope.getColumnAsArray(relationship.AssociationForeignFieldNames, scope.Value) query = query.Where( fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.ForeignDBNames), toQueryMarks(primaryKeys)), toQueryValues(primaryKeys)..., ) } else if relationship.Kind == "belongs_to" { primaryKeys := scope.getColumnAsArray(relationship.ForeignFieldNames, scope.Value) query = query.Where( fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.AssociationForeignDBNames), toQueryMarks(primaryKeys)), toQueryValues(primaryKeys)..., ) } if relationship.PolymorphicType != "" { query = query.Where( fmt.Sprintf("%v.%v = ?", scope.New(fieldValue).QuotedTableName(), scope.Quote(relationship.PolymorphicDBName)), relationship.PolymorphicValue, ) } if err := query.Model(fieldValue).Count(&count).Error; err != nil { association.Error = err } return count } // saveAssociations save passed values as associations func (association *Association) saveAssociations(values ...interface{}) *Association { var ( scope = association.scope field = association.field relationship = field.Relationship ) saveAssociation := func(reflectValue reflect.Value) { // value has to been pointer if reflectValue.Kind() != reflect.Ptr { reflectPtr := reflect.New(reflectValue.Type()) reflectPtr.Elem().Set(reflectValue) reflectValue = reflectPtr } // value has to been saved for many2many if relationship.Kind == "many_to_many" { if scope.New(reflectValue.Interface()).PrimaryKeyZero() { association.setErr(scope.NewDB().Save(reflectValue.Interface()).Error) } } // Assign Fields var fieldType = field.Field.Type() var setFieldBackToValue, setSliceFieldBackToValue bool if reflectValue.Type().AssignableTo(fieldType) { field.Set(reflectValue) } else if reflectValue.Type().Elem().AssignableTo(fieldType) { // if field's type is struct, then need to set value back to argument after save setFieldBackToValue = true field.Set(reflectValue.Elem()) } else if fieldType.Kind() == reflect.Slice { if reflectValue.Type().AssignableTo(fieldType.Elem()) { field.Set(reflect.Append(field.Field, reflectValue)) } else if reflectValue.Type().Elem().AssignableTo(fieldType.Elem()) { // if field's type is slice of struct, then need to set value back to argument after save setSliceFieldBackToValue = true field.Set(reflect.Append(field.Field, reflectValue.Elem())) } } if relationship.Kind == "many_to_many" { association.setErr(relationship.JoinTableHandler.Add(relationship.JoinTableHandler, scope.NewDB(), scope.Value, reflectValue.Interface())) } else { association.setErr(scope.NewDB().Select(field.Name).Save(scope.Value).Error) if setFieldBackToValue { reflectValue.Elem().Set(field.Field) } else if setSliceFieldBackToValue { reflectValue.Elem().Set(field.Field.Index(field.Field.Len() - 1)) } } } for _, value := range values { reflectValue := reflect.ValueOf(value) indirectReflectValue := reflect.Indirect(reflectValue) if indirectReflectValue.Kind() == reflect.Struct { saveAssociation(reflectValue) } else if indirectReflectValue.Kind() == reflect.Slice { for i := 0; i < indirectReflectValue.Len(); i++ { saveAssociation(indirectReflectValue.Index(i)) } } else { association.setErr(errors.New("invalid value type")) } } return association } func (association *Association) setErr(err error) *Association { if err != nil { association.Error = err } return association } ================================================ FILE: vendor/github.com/jinzhu/gorm/callback.go ================================================ package gorm import "log" // DefaultCallback default callbacks defined by gorm var DefaultCallback = &Callback{} // Callback is a struct that contains all CRUD callbacks // Field `creates` contains callbacks will be call when creating object // Field `updates` contains callbacks will be call when updating object // Field `deletes` contains callbacks will be call when deleting object // Field `queries` contains callbacks will be call when querying object with query methods like Find, First, Related, Association... // Field `rowQueries` contains callbacks will be call when querying object with Row, Rows... // Field `processors` contains all callback processors, will be used to generate above callbacks in order type Callback struct { creates []*func(scope *Scope) updates []*func(scope *Scope) deletes []*func(scope *Scope) queries []*func(scope *Scope) rowQueries []*func(scope *Scope) processors []*CallbackProcessor } // CallbackProcessor contains callback informations type CallbackProcessor struct { name string // current callback's name before string // register current callback before a callback after string // register current callback after a callback replace bool // replace callbacks with same name remove bool // delete callbacks with same name kind string // callback type: create, update, delete, query, row_query processor *func(scope *Scope) // callback handler parent *Callback } func (c *Callback) clone() *Callback { return &Callback{ creates: c.creates, updates: c.updates, deletes: c.deletes, queries: c.queries, rowQueries: c.rowQueries, processors: c.processors, } } // Create could be used to register callbacks for creating object // db.Callback().Create().After("gorm:create").Register("plugin:run_after_create", func(*Scope) { // // business logic // ... // // // set error if some thing wrong happened, will rollback the creating // scope.Err(errors.New("error")) // }) func (c *Callback) Create() *CallbackProcessor { return &CallbackProcessor{kind: "create", parent: c} } // Update could be used to register callbacks for updating object, refer `Create` for usage func (c *Callback) Update() *CallbackProcessor { return &CallbackProcessor{kind: "update", parent: c} } // Delete could be used to register callbacks for deleting object, refer `Create` for usage func (c *Callback) Delete() *CallbackProcessor { return &CallbackProcessor{kind: "delete", parent: c} } // Query could be used to register callbacks for querying objects with query methods like `Find`, `First`, `Related`, `Association`... // Refer `Create` for usage func (c *Callback) Query() *CallbackProcessor { return &CallbackProcessor{kind: "query", parent: c} } // RowQuery could be used to register callbacks for querying objects with `Row`, `Rows`, refer `Create` for usage func (c *Callback) RowQuery() *CallbackProcessor { return &CallbackProcessor{kind: "row_query", parent: c} } // After insert a new callback after callback `callbackName`, refer `Callbacks.Create` func (cp *CallbackProcessor) After(callbackName string) *CallbackProcessor { cp.after = callbackName return cp } // Before insert a new callback before callback `callbackName`, refer `Callbacks.Create` func (cp *CallbackProcessor) Before(callbackName string) *CallbackProcessor { cp.before = callbackName return cp } // Register a new callback, refer `Callbacks.Create` func (cp *CallbackProcessor) Register(callbackName string, callback func(scope *Scope)) { if cp.kind == "row_query" { if cp.before == "" && cp.after == "" && callbackName != "gorm:row_query" { log.Printf("Registing RowQuery callback %v without specify order with Before(), After(), applying Before('gorm:row_query') by default for compatibility...\n", callbackName) cp.before = "gorm:row_query" } } cp.name = callbackName cp.processor = &callback cp.parent.processors = append(cp.parent.processors, cp) cp.parent.reorder() } // Remove a registered callback // db.Callback().Create().Remove("gorm:update_time_stamp_when_create") func (cp *CallbackProcessor) Remove(callbackName string) { log.Printf("[info] removing callback `%v` from %v\n", callbackName, fileWithLineNum()) cp.name = callbackName cp.remove = true cp.parent.processors = append(cp.parent.processors, cp) cp.parent.reorder() } // Replace a registered callback with new callback // db.Callback().Create().Replace("gorm:update_time_stamp_when_create", func(*Scope) { // scope.SetColumn("Created", now) // scope.SetColumn("Updated", now) // }) func (cp *CallbackProcessor) Replace(callbackName string, callback func(scope *Scope)) { log.Printf("[info] replacing callback `%v` from %v\n", callbackName, fileWithLineNum()) cp.name = callbackName cp.processor = &callback cp.replace = true cp.parent.processors = append(cp.parent.processors, cp) cp.parent.reorder() } // Get registered callback // db.Callback().Create().Get("gorm:create") func (cp *CallbackProcessor) Get(callbackName string) (callback func(scope *Scope)) { for _, p := range cp.parent.processors { if p.name == callbackName && p.kind == cp.kind && !cp.remove { return *p.processor } } return nil } // getRIndex get right index from string slice func getRIndex(strs []string, str string) int { for i := len(strs) - 1; i >= 0; i-- { if strs[i] == str { return i } } return -1 } // sortProcessors sort callback processors based on its before, after, remove, replace func sortProcessors(cps []*CallbackProcessor) []*func(scope *Scope) { var ( allNames, sortedNames []string sortCallbackProcessor func(c *CallbackProcessor) ) for _, cp := range cps { // show warning message the callback name already exists if index := getRIndex(allNames, cp.name); index > -1 && !cp.replace && !cp.remove { log.Printf("[warning] duplicated callback `%v` from %v\n", cp.name, fileWithLineNum()) } allNames = append(allNames, cp.name) } sortCallbackProcessor = func(c *CallbackProcessor) { if getRIndex(sortedNames, c.name) == -1 { // if not sorted if c.before != "" { // if defined before callback if index := getRIndex(sortedNames, c.before); index != -1 { // if before callback already sorted, append current callback just after it sortedNames = append(sortedNames[:index], append([]string{c.name}, sortedNames[index:]...)...) } else if index := getRIndex(allNames, c.before); index != -1 { // if before callback exists but haven't sorted, append current callback to last sortedNames = append(sortedNames, c.name) sortCallbackProcessor(cps[index]) } } if c.after != "" { // if defined after callback if index := getRIndex(sortedNames, c.after); index != -1 { // if after callback already sorted, append current callback just before it sortedNames = append(sortedNames[:index+1], append([]string{c.name}, sortedNames[index+1:]...)...) } else if index := getRIndex(allNames, c.after); index != -1 { // if after callback exists but haven't sorted cp := cps[index] // set after callback's before callback to current callback if cp.before == "" { cp.before = c.name } sortCallbackProcessor(cp) } } // if current callback haven't been sorted, append it to last if getRIndex(sortedNames, c.name) == -1 { sortedNames = append(sortedNames, c.name) } } } for _, cp := range cps { sortCallbackProcessor(cp) } var sortedFuncs []*func(scope *Scope) for _, name := range sortedNames { if index := getRIndex(allNames, name); !cps[index].remove { sortedFuncs = append(sortedFuncs, cps[index].processor) } } return sortedFuncs } // reorder all registered processors, and reset CRUD callbacks func (c *Callback) reorder() { var creates, updates, deletes, queries, rowQueries []*CallbackProcessor for _, processor := range c.processors { if processor.name != "" { switch processor.kind { case "create": creates = append(creates, processor) case "update": updates = append(updates, processor) case "delete": deletes = append(deletes, processor) case "query": queries = append(queries, processor) case "row_query": rowQueries = append(rowQueries, processor) } } } c.creates = sortProcessors(creates) c.updates = sortProcessors(updates) c.deletes = sortProcessors(deletes) c.queries = sortProcessors(queries) c.rowQueries = sortProcessors(rowQueries) } ================================================ FILE: vendor/github.com/jinzhu/gorm/callback_create.go ================================================ package gorm import ( "fmt" "strings" ) // Define callbacks for creating func init() { DefaultCallback.Create().Register("gorm:begin_transaction", beginTransactionCallback) DefaultCallback.Create().Register("gorm:before_create", beforeCreateCallback) DefaultCallback.Create().Register("gorm:save_before_associations", saveBeforeAssociationsCallback) DefaultCallback.Create().Register("gorm:update_time_stamp", updateTimeStampForCreateCallback) DefaultCallback.Create().Register("gorm:create", createCallback) DefaultCallback.Create().Register("gorm:force_reload_after_create", forceReloadAfterCreateCallback) DefaultCallback.Create().Register("gorm:save_after_associations", saveAfterAssociationsCallback) DefaultCallback.Create().Register("gorm:after_create", afterCreateCallback) DefaultCallback.Create().Register("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback) } // beforeCreateCallback will invoke `BeforeSave`, `BeforeCreate` method before creating func beforeCreateCallback(scope *Scope) { if !scope.HasError() { scope.CallMethod("BeforeSave") } if !scope.HasError() { scope.CallMethod("BeforeCreate") } } // updateTimeStampForCreateCallback will set `CreatedAt`, `UpdatedAt` when creating func updateTimeStampForCreateCallback(scope *Scope) { if !scope.HasError() { now := NowFunc() if createdAtField, ok := scope.FieldByName("CreatedAt"); ok { if createdAtField.IsBlank { createdAtField.Set(now) } } if updatedAtField, ok := scope.FieldByName("UpdatedAt"); ok { if updatedAtField.IsBlank { updatedAtField.Set(now) } } } } // createCallback the callback used to insert data into database func createCallback(scope *Scope) { if !scope.HasError() { defer scope.trace(NowFunc()) var ( columns, placeholders []string blankColumnsWithDefaultValue []string ) for _, field := range scope.Fields() { if scope.changeableField(field) { if field.IsNormal { if field.IsBlank && field.HasDefaultValue { blankColumnsWithDefaultValue = append(blankColumnsWithDefaultValue, scope.Quote(field.DBName)) scope.InstanceSet("gorm:blank_columns_with_default_value", blankColumnsWithDefaultValue) } else if !field.IsPrimaryKey || !field.IsBlank { columns = append(columns, scope.Quote(field.DBName)) placeholders = append(placeholders, scope.AddToVars(field.Field.Interface())) } } else if field.Relationship != nil && field.Relationship.Kind == "belongs_to" { for _, foreignKey := range field.Relationship.ForeignDBNames { if foreignField, ok := scope.FieldByName(foreignKey); ok && !scope.changeableField(foreignField) { columns = append(columns, scope.Quote(foreignField.DBName)) placeholders = append(placeholders, scope.AddToVars(foreignField.Field.Interface())) } } } } } var ( returningColumn = "*" quotedTableName = scope.QuotedTableName() primaryField = scope.PrimaryField() extraOption string ) if str, ok := scope.Get("gorm:insert_option"); ok { extraOption = fmt.Sprint(str) } if primaryField != nil { returningColumn = scope.Quote(primaryField.DBName) } lastInsertIDReturningSuffix := scope.Dialect().LastInsertIDReturningSuffix(quotedTableName, returningColumn) if len(columns) == 0 { scope.Raw(fmt.Sprintf( "INSERT INTO %v %v%v%v", quotedTableName, scope.Dialect().DefaultValueStr(), addExtraSpaceIfExist(extraOption), addExtraSpaceIfExist(lastInsertIDReturningSuffix), )) } else { scope.Raw(fmt.Sprintf( "INSERT INTO %v (%v) VALUES (%v)%v%v", scope.QuotedTableName(), strings.Join(columns, ","), strings.Join(placeholders, ","), addExtraSpaceIfExist(extraOption), addExtraSpaceIfExist(lastInsertIDReturningSuffix), )) } // execute create sql if lastInsertIDReturningSuffix == "" || primaryField == nil { if result, err := scope.SQLDB().Exec(scope.SQL, scope.SQLVars...); scope.Err(err) == nil { // set rows affected count scope.db.RowsAffected, _ = result.RowsAffected() // set primary value to primary field if primaryField != nil && primaryField.IsBlank { if primaryValue, err := result.LastInsertId(); scope.Err(err) == nil { scope.Err(primaryField.Set(primaryValue)) } } } } else { if primaryField.Field.CanAddr() { if err := scope.SQLDB().QueryRow(scope.SQL, scope.SQLVars...).Scan(primaryField.Field.Addr().Interface()); scope.Err(err) == nil { primaryField.IsBlank = false scope.db.RowsAffected = 1 } } else { scope.Err(ErrUnaddressable) } } } } // forceReloadAfterCreateCallback will reload columns that having default value, and set it back to current object func forceReloadAfterCreateCallback(scope *Scope) { if blankColumnsWithDefaultValue, ok := scope.InstanceGet("gorm:blank_columns_with_default_value"); ok { db := scope.DB().New().Table(scope.TableName()).Select(blankColumnsWithDefaultValue.([]string)) for _, field := range scope.Fields() { if field.IsPrimaryKey && !field.IsBlank { db = db.Where(fmt.Sprintf("%v = ?", field.DBName), field.Field.Interface()) } } db.Scan(scope.Value) } } // afterCreateCallback will invoke `AfterCreate`, `AfterSave` method after creating func afterCreateCallback(scope *Scope) { if !scope.HasError() { scope.CallMethod("AfterCreate") } if !scope.HasError() { scope.CallMethod("AfterSave") } } ================================================ FILE: vendor/github.com/jinzhu/gorm/callback_delete.go ================================================ package gorm import ( "errors" "fmt" ) // Define callbacks for deleting func init() { DefaultCallback.Delete().Register("gorm:begin_transaction", beginTransactionCallback) DefaultCallback.Delete().Register("gorm:before_delete", beforeDeleteCallback) DefaultCallback.Delete().Register("gorm:delete", deleteCallback) DefaultCallback.Delete().Register("gorm:after_delete", afterDeleteCallback) DefaultCallback.Delete().Register("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback) } // beforeDeleteCallback will invoke `BeforeDelete` method before deleting func beforeDeleteCallback(scope *Scope) { if scope.DB().HasBlockGlobalUpdate() && !scope.hasConditions() { scope.Err(errors.New("Missing WHERE clause while deleting")) return } if !scope.HasError() { scope.CallMethod("BeforeDelete") } } // deleteCallback used to delete data from database or set deleted_at to current time (when using with soft delete) func deleteCallback(scope *Scope) { if !scope.HasError() { var extraOption string if str, ok := scope.Get("gorm:delete_option"); ok { extraOption = fmt.Sprint(str) } deletedAtField, hasDeletedAtField := scope.FieldByName("DeletedAt") if !scope.Search.Unscoped && hasDeletedAtField { scope.Raw(fmt.Sprintf( "UPDATE %v SET %v=%v%v%v", scope.QuotedTableName(), scope.Quote(deletedAtField.DBName), scope.AddToVars(NowFunc()), addExtraSpaceIfExist(scope.CombinedConditionSql()), addExtraSpaceIfExist(extraOption), )).Exec() } else { scope.Raw(fmt.Sprintf( "DELETE FROM %v%v%v", scope.QuotedTableName(), addExtraSpaceIfExist(scope.CombinedConditionSql()), addExtraSpaceIfExist(extraOption), )).Exec() } } } // afterDeleteCallback will invoke `AfterDelete` method after deleting func afterDeleteCallback(scope *Scope) { if !scope.HasError() { scope.CallMethod("AfterDelete") } } ================================================ FILE: vendor/github.com/jinzhu/gorm/callback_query.go ================================================ package gorm import ( "errors" "fmt" "reflect" ) // Define callbacks for querying func init() { DefaultCallback.Query().Register("gorm:query", queryCallback) DefaultCallback.Query().Register("gorm:preload", preloadCallback) DefaultCallback.Query().Register("gorm:after_query", afterQueryCallback) } // queryCallback used to query data from database func queryCallback(scope *Scope) { if _, skip := scope.InstanceGet("gorm:skip_query_callback"); skip { return } defer scope.trace(NowFunc()) var ( isSlice, isPtr bool resultType reflect.Type results = scope.IndirectValue() ) if orderBy, ok := scope.Get("gorm:order_by_primary_key"); ok { if primaryField := scope.PrimaryField(); primaryField != nil { scope.Search.Order(fmt.Sprintf("%v.%v %v", scope.QuotedTableName(), scope.Quote(primaryField.DBName), orderBy)) } } if value, ok := scope.Get("gorm:query_destination"); ok { results = indirect(reflect.ValueOf(value)) } if kind := results.Kind(); kind == reflect.Slice { isSlice = true resultType = results.Type().Elem() results.Set(reflect.MakeSlice(results.Type(), 0, 0)) if resultType.Kind() == reflect.Ptr { isPtr = true resultType = resultType.Elem() } } else if kind != reflect.Struct { scope.Err(errors.New("unsupported destination, should be slice or struct")) return } scope.prepareQuerySQL() if !scope.HasError() { scope.db.RowsAffected = 0 if str, ok := scope.Get("gorm:query_option"); ok { scope.SQL += addExtraSpaceIfExist(fmt.Sprint(str)) } if rows, err := scope.SQLDB().Query(scope.SQL, scope.SQLVars...); scope.Err(err) == nil { defer rows.Close() columns, _ := rows.Columns() for rows.Next() { scope.db.RowsAffected++ elem := results if isSlice { elem = reflect.New(resultType).Elem() } scope.scan(rows, columns, scope.New(elem.Addr().Interface()).Fields()) if isSlice { if isPtr { results.Set(reflect.Append(results, elem.Addr())) } else { results.Set(reflect.Append(results, elem)) } } } if err := rows.Err(); err != nil { scope.Err(err) } else if scope.db.RowsAffected == 0 && !isSlice { scope.Err(ErrRecordNotFound) } } } } // afterQueryCallback will invoke `AfterFind` method after querying func afterQueryCallback(scope *Scope) { if !scope.HasError() { scope.CallMethod("AfterFind") } } ================================================ FILE: vendor/github.com/jinzhu/gorm/callback_query_preload.go ================================================ package gorm import ( "errors" "fmt" "reflect" "strconv" "strings" ) // preloadCallback used to preload associations func preloadCallback(scope *Scope) { if _, skip := scope.InstanceGet("gorm:skip_query_callback"); skip { return } if _, ok := scope.Get("gorm:auto_preload"); ok { autoPreload(scope) } if scope.Search.preload == nil || scope.HasError() { return } var ( preloadedMap = map[string]bool{} fields = scope.Fields() ) for _, preload := range scope.Search.preload { var ( preloadFields = strings.Split(preload.schema, ".") currentScope = scope currentFields = fields ) for idx, preloadField := range preloadFields { var currentPreloadConditions []interface{} if currentScope == nil { continue } // if not preloaded if preloadKey := strings.Join(preloadFields[:idx+1], "."); !preloadedMap[preloadKey] { // assign search conditions to last preload if idx == len(preloadFields)-1 { currentPreloadConditions = preload.conditions } for _, field := range currentFields { if field.Name != preloadField || field.Relationship == nil { continue } switch field.Relationship.Kind { case "has_one": currentScope.handleHasOnePreload(field, currentPreloadConditions) case "has_many": currentScope.handleHasManyPreload(field, currentPreloadConditions) case "belongs_to": currentScope.handleBelongsToPreload(field, currentPreloadConditions) case "many_to_many": currentScope.handleManyToManyPreload(field, currentPreloadConditions) default: scope.Err(errors.New("unsupported relation")) } preloadedMap[preloadKey] = true break } if !preloadedMap[preloadKey] { scope.Err(fmt.Errorf("can't preload field %s for %s", preloadField, currentScope.GetModelStruct().ModelType)) return } } // preload next level if idx < len(preloadFields)-1 { currentScope = currentScope.getColumnAsScope(preloadField) if currentScope != nil { currentFields = currentScope.Fields() } } } } } func autoPreload(scope *Scope) { for _, field := range scope.Fields() { if field.Relationship == nil { continue } if val, ok := field.TagSettings["PRELOAD"]; ok { if preload, err := strconv.ParseBool(val); err != nil { scope.Err(errors.New("invalid preload option")) return } else if !preload { continue } } scope.Search.Preload(field.Name) } } func (scope *Scope) generatePreloadDBWithConditions(conditions []interface{}) (*DB, []interface{}) { var ( preloadDB = scope.NewDB() preloadConditions []interface{} ) for _, condition := range conditions { if scopes, ok := condition.(func(*DB) *DB); ok { preloadDB = scopes(preloadDB) } else { preloadConditions = append(preloadConditions, condition) } } return preloadDB, preloadConditions } // handleHasOnePreload used to preload has one associations func (scope *Scope) handleHasOnePreload(field *Field, conditions []interface{}) { relation := field.Relationship // get relations's primary keys primaryKeys := scope.getColumnAsArray(relation.AssociationForeignFieldNames, scope.Value) if len(primaryKeys) == 0 { return } // preload conditions preloadDB, preloadConditions := scope.generatePreloadDBWithConditions(conditions) // find relations query := fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relation.ForeignDBNames), toQueryMarks(primaryKeys)) values := toQueryValues(primaryKeys) if relation.PolymorphicType != "" { query += fmt.Sprintf(" AND %v = ?", scope.Quote(relation.PolymorphicDBName)) values = append(values, relation.PolymorphicValue) } results := makeSlice(field.Struct.Type) scope.Err(preloadDB.Where(query, values...).Find(results, preloadConditions...).Error) // assign find results var ( resultsValue = indirect(reflect.ValueOf(results)) indirectScopeValue = scope.IndirectValue() ) if indirectScopeValue.Kind() == reflect.Slice { for j := 0; j < indirectScopeValue.Len(); j++ { for i := 0; i < resultsValue.Len(); i++ { result := resultsValue.Index(i) foreignValues := getValueFromFields(result, relation.ForeignFieldNames) if indirectValue := indirect(indirectScopeValue.Index(j)); equalAsString(getValueFromFields(indirectValue, relation.AssociationForeignFieldNames), foreignValues) { indirectValue.FieldByName(field.Name).Set(result) break } } } } else { for i := 0; i < resultsValue.Len(); i++ { result := resultsValue.Index(i) scope.Err(field.Set(result)) } } } // handleHasManyPreload used to preload has many associations func (scope *Scope) handleHasManyPreload(field *Field, conditions []interface{}) { relation := field.Relationship // get relations's primary keys primaryKeys := scope.getColumnAsArray(relation.AssociationForeignFieldNames, scope.Value) if len(primaryKeys) == 0 { return } // preload conditions preloadDB, preloadConditions := scope.generatePreloadDBWithConditions(conditions) // find relations query := fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relation.ForeignDBNames), toQueryMarks(primaryKeys)) values := toQueryValues(primaryKeys) if relation.PolymorphicType != "" { query += fmt.Sprintf(" AND %v = ?", scope.Quote(relation.PolymorphicDBName)) values = append(values, relation.PolymorphicValue) } results := makeSlice(field.Struct.Type) scope.Err(preloadDB.Where(query, values...).Find(results, preloadConditions...).Error) // assign find results var ( resultsValue = indirect(reflect.ValueOf(results)) indirectScopeValue = scope.IndirectValue() ) if indirectScopeValue.Kind() == reflect.Slice { preloadMap := make(map[string][]reflect.Value) for i := 0; i < resultsValue.Len(); i++ { result := resultsValue.Index(i) foreignValues := getValueFromFields(result, relation.ForeignFieldNames) preloadMap[toString(foreignValues)] = append(preloadMap[toString(foreignValues)], result) } for j := 0; j < indirectScopeValue.Len(); j++ { object := indirect(indirectScopeValue.Index(j)) objectRealValue := getValueFromFields(object, relation.AssociationForeignFieldNames) f := object.FieldByName(field.Name) if results, ok := preloadMap[toString(objectRealValue)]; ok { f.Set(reflect.Append(f, results...)) } else { f.Set(reflect.MakeSlice(f.Type(), 0, 0)) } } } else { scope.Err(field.Set(resultsValue)) } } // handleBelongsToPreload used to preload belongs to associations func (scope *Scope) handleBelongsToPreload(field *Field, conditions []interface{}) { relation := field.Relationship // preload conditions preloadDB, preloadConditions := scope.generatePreloadDBWithConditions(conditions) // get relations's primary keys primaryKeys := scope.getColumnAsArray(relation.ForeignFieldNames, scope.Value) if len(primaryKeys) == 0 { return } // find relations results := makeSlice(field.Struct.Type) scope.Err(preloadDB.Where(fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relation.AssociationForeignDBNames), toQueryMarks(primaryKeys)), toQueryValues(primaryKeys)...).Find(results, preloadConditions...).Error) // assign find results var ( resultsValue = indirect(reflect.ValueOf(results)) indirectScopeValue = scope.IndirectValue() ) for i := 0; i < resultsValue.Len(); i++ { result := resultsValue.Index(i) if indirectScopeValue.Kind() == reflect.Slice { value := getValueFromFields(result, relation.AssociationForeignFieldNames) for j := 0; j < indirectScopeValue.Len(); j++ { object := indirect(indirectScopeValue.Index(j)) if equalAsString(getValueFromFields(object, relation.ForeignFieldNames), value) { object.FieldByName(field.Name).Set(result) } } } else { scope.Err(field.Set(result)) } } } // handleManyToManyPreload used to preload many to many associations func (scope *Scope) handleManyToManyPreload(field *Field, conditions []interface{}) { var ( relation = field.Relationship joinTableHandler = relation.JoinTableHandler fieldType = field.Struct.Type.Elem() foreignKeyValue interface{} foreignKeyType = reflect.ValueOf(&foreignKeyValue).Type() linkHash = map[string][]reflect.Value{} isPtr bool ) if fieldType.Kind() == reflect.Ptr { isPtr = true fieldType = fieldType.Elem() } var sourceKeys = []string{} for _, key := range joinTableHandler.SourceForeignKeys() { sourceKeys = append(sourceKeys, key.DBName) } // preload conditions preloadDB, preloadConditions := scope.generatePreloadDBWithConditions(conditions) // generate query with join table newScope := scope.New(reflect.New(fieldType).Interface()) preloadDB = preloadDB.Table(newScope.TableName()).Model(newScope.Value) if len(preloadDB.search.selects) == 0 { preloadDB = preloadDB.Select("*") } preloadDB = joinTableHandler.JoinWith(joinTableHandler, preloadDB, scope.Value) // preload inline conditions if len(preloadConditions) > 0 { preloadDB = preloadDB.Where(preloadConditions[0], preloadConditions[1:]...) } rows, err := preloadDB.Rows() if scope.Err(err) != nil { return } defer rows.Close() columns, _ := rows.Columns() for rows.Next() { var ( elem = reflect.New(fieldType).Elem() fields = scope.New(elem.Addr().Interface()).Fields() ) // register foreign keys in join tables var joinTableFields []*Field for _, sourceKey := range sourceKeys { joinTableFields = append(joinTableFields, &Field{StructField: &StructField{DBName: sourceKey, IsNormal: true}, Field: reflect.New(foreignKeyType).Elem()}) } scope.scan(rows, columns, append(fields, joinTableFields...)) scope.New(elem.Addr().Interface()). InstanceSet("gorm:skip_query_callback", true). callCallbacks(scope.db.parent.callbacks.queries) var foreignKeys = make([]interface{}, len(sourceKeys)) // generate hashed forkey keys in join table for idx, joinTableField := range joinTableFields { if !joinTableField.Field.IsNil() { foreignKeys[idx] = joinTableField.Field.Elem().Interface() } } hashedSourceKeys := toString(foreignKeys) if isPtr { linkHash[hashedSourceKeys] = append(linkHash[hashedSourceKeys], elem.Addr()) } else { linkHash[hashedSourceKeys] = append(linkHash[hashedSourceKeys], elem) } } if err := rows.Err(); err != nil { scope.Err(err) } // assign find results var ( indirectScopeValue = scope.IndirectValue() fieldsSourceMap = map[string][]reflect.Value{} foreignFieldNames = []string{} ) for _, dbName := range relation.ForeignFieldNames { if field, ok := scope.FieldByName(dbName); ok { foreignFieldNames = append(foreignFieldNames, field.Name) } } if indirectScopeValue.Kind() == reflect.Slice { for j := 0; j < indirectScopeValue.Len(); j++ { object := indirect(indirectScopeValue.Index(j)) key := toString(getValueFromFields(object, foreignFieldNames)) fieldsSourceMap[key] = append(fieldsSourceMap[key], object.FieldByName(field.Name)) } } else if indirectScopeValue.IsValid() { key := toString(getValueFromFields(indirectScopeValue, foreignFieldNames)) fieldsSourceMap[key] = append(fieldsSourceMap[key], indirectScopeValue.FieldByName(field.Name)) } for source, link := range linkHash { for i, field := range fieldsSourceMap[source] { //If not 0 this means Value is a pointer and we already added preloaded models to it if fieldsSourceMap[source][i].Len() != 0 { continue } field.Set(reflect.Append(fieldsSourceMap[source][i], link...)) } } } ================================================ FILE: vendor/github.com/jinzhu/gorm/callback_row_query.go ================================================ package gorm import "database/sql" // Define callbacks for row query func init() { DefaultCallback.RowQuery().Register("gorm:row_query", rowQueryCallback) } type RowQueryResult struct { Row *sql.Row } type RowsQueryResult struct { Rows *sql.Rows Error error } // queryCallback used to query data from database func rowQueryCallback(scope *Scope) { if result, ok := scope.InstanceGet("row_query_result"); ok { scope.prepareQuerySQL() if rowResult, ok := result.(*RowQueryResult); ok { rowResult.Row = scope.SQLDB().QueryRow(scope.SQL, scope.SQLVars...) } else if rowsResult, ok := result.(*RowsQueryResult); ok { rowsResult.Rows, rowsResult.Error = scope.SQLDB().Query(scope.SQL, scope.SQLVars...) } } } ================================================ FILE: vendor/github.com/jinzhu/gorm/callback_save.go ================================================ package gorm import ( "reflect" "strings" ) func beginTransactionCallback(scope *Scope) { scope.Begin() } func commitOrRollbackTransactionCallback(scope *Scope) { scope.CommitOrRollback() } func saveAssociationCheck(scope *Scope, field *Field) (autoUpdate bool, autoCreate bool, saveReference bool, r *Relationship) { checkTruth := func(value interface{}) bool { if v, ok := value.(bool); ok && !v { return false } if v, ok := value.(string); ok { v = strings.ToLower(v) if v == "false" || v != "skip" { return false } } return true } if scope.changeableField(field) && !field.IsBlank && !field.IsIgnored { if r = field.Relationship; r != nil { autoUpdate, autoCreate, saveReference = true, true, true if value, ok := scope.Get("gorm:save_associations"); ok { autoUpdate = checkTruth(value) autoCreate = autoUpdate } else if value, ok := field.TagSettings["SAVE_ASSOCIATIONS"]; ok { autoUpdate = checkTruth(value) autoCreate = autoUpdate } if value, ok := scope.Get("gorm:association_autoupdate"); ok { autoUpdate = checkTruth(value) } else if value, ok := field.TagSettings["ASSOCIATION_AUTOUPDATE"]; ok { autoUpdate = checkTruth(value) } if value, ok := scope.Get("gorm:association_autocreate"); ok { autoCreate = checkTruth(value) } else if value, ok := field.TagSettings["ASSOCIATION_AUTOCREATE"]; ok { autoCreate = checkTruth(value) } if value, ok := scope.Get("gorm:association_save_reference"); ok { saveReference = checkTruth(value) } else if value, ok := field.TagSettings["ASSOCIATION_SAVE_REFERENCE"]; ok { saveReference = checkTruth(value) } } } return } func saveBeforeAssociationsCallback(scope *Scope) { for _, field := range scope.Fields() { autoUpdate, autoCreate, saveReference, relationship := saveAssociationCheck(scope, field) if relationship != nil && relationship.Kind == "belongs_to" { fieldValue := field.Field.Addr().Interface() newScope := scope.New(fieldValue) if newScope.PrimaryKeyZero() { if autoCreate { scope.Err(scope.NewDB().Save(fieldValue).Error) } } else if autoUpdate { scope.Err(scope.NewDB().Save(fieldValue).Error) } if saveReference { if len(relationship.ForeignFieldNames) != 0 { // set value's foreign key for idx, fieldName := range relationship.ForeignFieldNames { associationForeignName := relationship.AssociationForeignDBNames[idx] if foreignField, ok := scope.New(fieldValue).FieldByName(associationForeignName); ok { scope.Err(scope.SetColumn(fieldName, foreignField.Field.Interface())) } } } } } } } func saveAfterAssociationsCallback(scope *Scope) { for _, field := range scope.Fields() { autoUpdate, autoCreate, saveReference, relationship := saveAssociationCheck(scope, field) if relationship != nil && (relationship.Kind == "has_one" || relationship.Kind == "has_many" || relationship.Kind == "many_to_many") { value := field.Field switch value.Kind() { case reflect.Slice: for i := 0; i < value.Len(); i++ { newDB := scope.NewDB() elem := value.Index(i).Addr().Interface() newScope := newDB.NewScope(elem) if saveReference { if relationship.JoinTableHandler == nil && len(relationship.ForeignFieldNames) != 0 { for idx, fieldName := range relationship.ForeignFieldNames { associationForeignName := relationship.AssociationForeignDBNames[idx] if f, ok := scope.FieldByName(associationForeignName); ok { scope.Err(newScope.SetColumn(fieldName, f.Field.Interface())) } } } if relationship.PolymorphicType != "" { scope.Err(newScope.SetColumn(relationship.PolymorphicType, relationship.PolymorphicValue)) } } if newScope.PrimaryKeyZero() { if autoCreate { scope.Err(newDB.Save(elem).Error) } } else if autoUpdate { scope.Err(newDB.Save(elem).Error) } if !scope.New(newScope.Value).PrimaryKeyZero() && saveReference { if joinTableHandler := relationship.JoinTableHandler; joinTableHandler != nil { scope.Err(joinTableHandler.Add(joinTableHandler, newDB, scope.Value, newScope.Value)) } } } default: elem := value.Addr().Interface() newScope := scope.New(elem) if saveReference { if len(relationship.ForeignFieldNames) != 0 { for idx, fieldName := range relationship.ForeignFieldNames { associationForeignName := relationship.AssociationForeignDBNames[idx] if f, ok := scope.FieldByName(associationForeignName); ok { scope.Err(newScope.SetColumn(fieldName, f.Field.Interface())) } } } if relationship.PolymorphicType != "" { scope.Err(newScope.SetColumn(relationship.PolymorphicType, relationship.PolymorphicValue)) } } if newScope.PrimaryKeyZero() { if autoCreate { scope.Err(scope.NewDB().Save(elem).Error) } } else if autoUpdate { scope.Err(scope.NewDB().Save(elem).Error) } } } } } ================================================ FILE: vendor/github.com/jinzhu/gorm/callback_update.go ================================================ package gorm import ( "errors" "fmt" "sort" "strings" ) // Define callbacks for updating func init() { DefaultCallback.Update().Register("gorm:assign_updating_attributes", assignUpdatingAttributesCallback) DefaultCallback.Update().Register("gorm:begin_transaction", beginTransactionCallback) DefaultCallback.Update().Register("gorm:before_update", beforeUpdateCallback) DefaultCallback.Update().Register("gorm:save_before_associations", saveBeforeAssociationsCallback) DefaultCallback.Update().Register("gorm:update_time_stamp", updateTimeStampForUpdateCallback) DefaultCallback.Update().Register("gorm:update", updateCallback) DefaultCallback.Update().Register("gorm:save_after_associations", saveAfterAssociationsCallback) DefaultCallback.Update().Register("gorm:after_update", afterUpdateCallback) DefaultCallback.Update().Register("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback) } // assignUpdatingAttributesCallback assign updating attributes to model func assignUpdatingAttributesCallback(scope *Scope) { if attrs, ok := scope.InstanceGet("gorm:update_interface"); ok { if updateMaps, hasUpdate := scope.updatedAttrsWithValues(attrs); hasUpdate { scope.InstanceSet("gorm:update_attrs", updateMaps) } else { scope.SkipLeft() } } } // beforeUpdateCallback will invoke `BeforeSave`, `BeforeUpdate` method before updating func beforeUpdateCallback(scope *Scope) { if scope.DB().HasBlockGlobalUpdate() && !scope.hasConditions() { scope.Err(errors.New("Missing WHERE clause while updating")) return } if _, ok := scope.Get("gorm:update_column"); !ok { if !scope.HasError() { scope.CallMethod("BeforeSave") } if !scope.HasError() { scope.CallMethod("BeforeUpdate") } } } // updateTimeStampForUpdateCallback will set `UpdatedAt` when updating func updateTimeStampForUpdateCallback(scope *Scope) { if _, ok := scope.Get("gorm:update_column"); !ok { scope.SetColumn("UpdatedAt", NowFunc()) } } // updateCallback the callback used to update data to database func updateCallback(scope *Scope) { if !scope.HasError() { var sqls []string if updateAttrs, ok := scope.InstanceGet("gorm:update_attrs"); ok { // Sort the column names so that the generated SQL is the same every time. updateMap := updateAttrs.(map[string]interface{}) var columns []string for c := range updateMap { columns = append(columns, c) } sort.Strings(columns) for _, column := range columns { value := updateMap[column] sqls = append(sqls, fmt.Sprintf("%v = %v", scope.Quote(column), scope.AddToVars(value))) } } else { for _, field := range scope.Fields() { if scope.changeableField(field) { if !field.IsPrimaryKey && field.IsNormal { sqls = append(sqls, fmt.Sprintf("%v = %v", scope.Quote(field.DBName), scope.AddToVars(field.Field.Interface()))) } else if relationship := field.Relationship; relationship != nil && relationship.Kind == "belongs_to" { for _, foreignKey := range relationship.ForeignDBNames { if foreignField, ok := scope.FieldByName(foreignKey); ok && !scope.changeableField(foreignField) { sqls = append(sqls, fmt.Sprintf("%v = %v", scope.Quote(foreignField.DBName), scope.AddToVars(foreignField.Field.Interface()))) } } } } } } var extraOption string if str, ok := scope.Get("gorm:update_option"); ok { extraOption = fmt.Sprint(str) } if len(sqls) > 0 { scope.Raw(fmt.Sprintf( "UPDATE %v SET %v%v%v", scope.QuotedTableName(), strings.Join(sqls, ", "), addExtraSpaceIfExist(scope.CombinedConditionSql()), addExtraSpaceIfExist(extraOption), )).Exec() } } } // afterUpdateCallback will invoke `AfterUpdate`, `AfterSave` method after updating func afterUpdateCallback(scope *Scope) { if _, ok := scope.Get("gorm:update_column"); !ok { if !scope.HasError() { scope.CallMethod("AfterUpdate") } if !scope.HasError() { scope.CallMethod("AfterSave") } } } ================================================ FILE: vendor/github.com/jinzhu/gorm/dialect.go ================================================ package gorm import ( "database/sql" "fmt" "reflect" "strconv" "strings" ) // Dialect interface contains behaviors that differ across SQL database type Dialect interface { // GetName get dialect's name GetName() string // SetDB set db for dialect SetDB(db SQLCommon) // BindVar return the placeholder for actual values in SQL statements, in many dbs it is "?", Postgres using $1 BindVar(i int) string // Quote quotes field name to avoid SQL parsing exceptions by using a reserved word as a field name Quote(key string) string // DataTypeOf return data's sql type DataTypeOf(field *StructField) string // HasIndex check has index or not HasIndex(tableName string, indexName string) bool // HasForeignKey check has foreign key or not HasForeignKey(tableName string, foreignKeyName string) bool // RemoveIndex remove index RemoveIndex(tableName string, indexName string) error // HasTable check has table or not HasTable(tableName string) bool // HasColumn check has column or not HasColumn(tableName string, columnName string) bool // ModifyColumn modify column's type ModifyColumn(tableName string, columnName string, typ string) error // LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case LimitAndOffsetSQL(limit, offset interface{}) string // SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL` SelectFromDummyTable() string // LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING` LastInsertIDReturningSuffix(tableName, columnName string) string // DefaultValueStr DefaultValueStr() string // BuildKeyName returns a valid key name (foreign key, index key) for the given table, field and reference BuildKeyName(kind, tableName string, fields ...string) string // CurrentDatabase return current database name CurrentDatabase() string } var dialectsMap = map[string]Dialect{} func newDialect(name string, db SQLCommon) Dialect { if value, ok := dialectsMap[name]; ok { dialect := reflect.New(reflect.TypeOf(value).Elem()).Interface().(Dialect) dialect.SetDB(db) return dialect } fmt.Printf("`%v` is not officially supported, running under compatibility mode.\n", name) commontDialect := &commonDialect{} commontDialect.SetDB(db) return commontDialect } // RegisterDialect register new dialect func RegisterDialect(name string, dialect Dialect) { dialectsMap[name] = dialect } // ParseFieldStructForDialect get field's sql data type var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fieldValue reflect.Value, sqlType string, size int, additionalType string) { // Get redirected field type var ( reflectType = field.Struct.Type dataType = field.TagSettings["TYPE"] ) for reflectType.Kind() == reflect.Ptr { reflectType = reflectType.Elem() } // Get redirected field value fieldValue = reflect.Indirect(reflect.New(reflectType)) if gormDataType, ok := fieldValue.Interface().(interface { GormDataType(Dialect) string }); ok { dataType = gormDataType.GormDataType(dialect) } // Get scanner's real value var getScannerValue func(reflect.Value) getScannerValue = func(value reflect.Value) { fieldValue = value if _, isScanner := reflect.New(fieldValue.Type()).Interface().(sql.Scanner); isScanner && fieldValue.Kind() == reflect.Struct { getScannerValue(fieldValue.Field(0)) } } getScannerValue(fieldValue) // Default Size if num, ok := field.TagSettings["SIZE"]; ok { size, _ = strconv.Atoi(num) } else { size = 255 } // Default type from tag setting additionalType = field.TagSettings["NOT NULL"] + " " + field.TagSettings["UNIQUE"] if value, ok := field.TagSettings["DEFAULT"]; ok { additionalType = additionalType + " DEFAULT " + value } return fieldValue, dataType, size, strings.TrimSpace(additionalType) } func currentDatabaseAndTable(dialect Dialect, tableName string) (string, string) { if strings.Contains(tableName, ".") { splitStrings := strings.SplitN(tableName, ".", 2) return splitStrings[0], splitStrings[1] } return dialect.CurrentDatabase(), tableName } ================================================ FILE: vendor/github.com/jinzhu/gorm/dialect_common.go ================================================ package gorm import ( "fmt" "reflect" "regexp" "strconv" "strings" "time" ) // DefaultForeignKeyNamer contains the default foreign key name generator method type DefaultForeignKeyNamer struct { } type commonDialect struct { db SQLCommon DefaultForeignKeyNamer } func init() { RegisterDialect("common", &commonDialect{}) } func (commonDialect) GetName() string { return "common" } func (s *commonDialect) SetDB(db SQLCommon) { s.db = db } func (commonDialect) BindVar(i int) string { return "$$$" // ? } func (commonDialect) Quote(key string) string { return fmt.Sprintf(`"%s"`, key) } func (s *commonDialect) fieldCanAutoIncrement(field *StructField) bool { if value, ok := field.TagSettings["AUTO_INCREMENT"]; ok { return strings.ToLower(value) != "false" } return field.IsPrimaryKey } func (s *commonDialect) DataTypeOf(field *StructField) string { var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s) if sqlType == "" { switch dataValue.Kind() { case reflect.Bool: sqlType = "BOOLEAN" case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr: if s.fieldCanAutoIncrement(field) { sqlType = "INTEGER AUTO_INCREMENT" } else { sqlType = "INTEGER" } case reflect.Int64, reflect.Uint64: if s.fieldCanAutoIncrement(field) { sqlType = "BIGINT AUTO_INCREMENT" } else { sqlType = "BIGINT" } case reflect.Float32, reflect.Float64: sqlType = "FLOAT" case reflect.String: if size > 0 && size < 65532 { sqlType = fmt.Sprintf("VARCHAR(%d)", size) } else { sqlType = "VARCHAR(65532)" } case reflect.Struct: if _, ok := dataValue.Interface().(time.Time); ok { sqlType = "TIMESTAMP" } default: if _, ok := dataValue.Interface().([]byte); ok { if size > 0 && size < 65532 { sqlType = fmt.Sprintf("BINARY(%d)", size) } else { sqlType = "BINARY(65532)" } } } } if sqlType == "" { panic(fmt.Sprintf("invalid sql type %s (%s) for commonDialect", dataValue.Type().Name(), dataValue.Kind().String())) } if strings.TrimSpace(additionalType) == "" { return sqlType } return fmt.Sprintf("%v %v", sqlType, additionalType) } func (s commonDialect) HasIndex(tableName string, indexName string) bool { var count int currentDatabase, tableName := currentDatabaseAndTable(&s, tableName) s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema = ? AND table_name = ? AND index_name = ?", currentDatabase, tableName, indexName).Scan(&count) return count > 0 } func (s commonDialect) RemoveIndex(tableName string, indexName string) error { _, err := s.db.Exec(fmt.Sprintf("DROP INDEX %v", indexName)) return err } func (s commonDialect) HasForeignKey(tableName string, foreignKeyName string) bool { return false } func (s commonDialect) HasTable(tableName string) bool { var count int currentDatabase, tableName := currentDatabaseAndTable(&s, tableName) s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = ? AND table_name = ?", currentDatabase, tableName).Scan(&count) return count > 0 } func (s commonDialect) HasColumn(tableName string, columnName string) bool { var count int currentDatabase, tableName := currentDatabaseAndTable(&s, tableName) s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = ? AND table_name = ? AND column_name = ?", currentDatabase, tableName, columnName).Scan(&count) return count > 0 } func (s commonDialect) ModifyColumn(tableName string, columnName string, typ string) error { _, err := s.db.Exec(fmt.Sprintf("ALTER TABLE %v ALTER COLUMN %v TYPE %v", tableName, columnName, typ)) return err } func (s commonDialect) CurrentDatabase() (name string) { s.db.QueryRow("SELECT DATABASE()").Scan(&name) return } func (commonDialect) LimitAndOffsetSQL(limit, offset interface{}) (sql string) { if limit != nil { if parsedLimit, err := strconv.ParseInt(fmt.Sprint(limit), 0, 0); err == nil && parsedLimit >= 0 { sql += fmt.Sprintf(" LIMIT %d", parsedLimit) } } if offset != nil { if parsedOffset, err := strconv.ParseInt(fmt.Sprint(offset), 0, 0); err == nil && parsedOffset >= 0 { sql += fmt.Sprintf(" OFFSET %d", parsedOffset) } } return } func (commonDialect) SelectFromDummyTable() string { return "" } func (commonDialect) LastInsertIDReturningSuffix(tableName, columnName string) string { return "" } func (commonDialect) DefaultValueStr() string { return "DEFAULT VALUES" } // BuildKeyName returns a valid key name (foreign key, index key) for the given table, field and reference func (DefaultForeignKeyNamer) BuildKeyName(kind, tableName string, fields ...string) string { keyName := fmt.Sprintf("%s_%s_%s", kind, tableName, strings.Join(fields, "_")) keyName = regexp.MustCompile("[^a-zA-Z0-9]+").ReplaceAllString(keyName, "_") return keyName } // IsByteArrayOrSlice returns true of the reflected value is an array or slice func IsByteArrayOrSlice(value reflect.Value) bool { return (value.Kind() == reflect.Array || value.Kind() == reflect.Slice) && value.Type().Elem() == reflect.TypeOf(uint8(0)) } ================================================ FILE: vendor/github.com/jinzhu/gorm/dialect_mysql.go ================================================ package gorm import ( "crypto/sha1" "fmt" "reflect" "regexp" "strconv" "strings" "time" "unicode/utf8" ) type mysql struct { commonDialect } func init() { RegisterDialect("mysql", &mysql{}) } func (mysql) GetName() string { return "mysql" } func (mysql) Quote(key string) string { return fmt.Sprintf("`%s`", key) } // Get Data Type for MySQL Dialect func (s *mysql) DataTypeOf(field *StructField) string { var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s) // MySQL allows only one auto increment column per table, and it must // be a KEY column. if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok { if _, ok = field.TagSettings["INDEX"]; !ok && !field.IsPrimaryKey { delete(field.TagSettings, "AUTO_INCREMENT") } } if sqlType == "" { switch dataValue.Kind() { case reflect.Bool: sqlType = "boolean" case reflect.Int8: if s.fieldCanAutoIncrement(field) { field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" sqlType = "tinyint AUTO_INCREMENT" } else { sqlType = "tinyint" } case reflect.Int, reflect.Int16, reflect.Int32: if s.fieldCanAutoIncrement(field) { field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" sqlType = "int AUTO_INCREMENT" } else { sqlType = "int" } case reflect.Uint8: if s.fieldCanAutoIncrement(field) { field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" sqlType = "tinyint unsigned AUTO_INCREMENT" } else { sqlType = "tinyint unsigned" } case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uintptr: if s.fieldCanAutoIncrement(field) { field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" sqlType = "int unsigned AUTO_INCREMENT" } else { sqlType = "int unsigned" } case reflect.Int64: if s.fieldCanAutoIncrement(field) { field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" sqlType = "bigint AUTO_INCREMENT" } else { sqlType = "bigint" } case reflect.Uint64: if s.fieldCanAutoIncrement(field) { field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" sqlType = "bigint unsigned AUTO_INCREMENT" } else { sqlType = "bigint unsigned" } case reflect.Float32, reflect.Float64: sqlType = "double" case reflect.String: if size > 0 && size < 65532 { sqlType = fmt.Sprintf("varchar(%d)", size) } else { sqlType = "longtext" } case reflect.Struct: if _, ok := dataValue.Interface().(time.Time); ok { precision := "" if p, ok := field.TagSettings["PRECISION"]; ok { precision = fmt.Sprintf("(%s)", p) } if _, ok := field.TagSettings["NOT NULL"]; ok { sqlType = fmt.Sprintf("timestamp%v", precision) } else { sqlType = fmt.Sprintf("timestamp%v NULL", precision) } } default: if IsByteArrayOrSlice(dataValue) { if size > 0 && size < 65532 { sqlType = fmt.Sprintf("varbinary(%d)", size) } else { sqlType = "longblob" } } } } if sqlType == "" { panic(fmt.Sprintf("invalid sql type %s (%s) for mysql", dataValue.Type().Name(), dataValue.Kind().String())) } if strings.TrimSpace(additionalType) == "" { return sqlType } return fmt.Sprintf("%v %v", sqlType, additionalType) } func (s mysql) RemoveIndex(tableName string, indexName string) error { _, err := s.db.Exec(fmt.Sprintf("DROP INDEX %v ON %v", indexName, s.Quote(tableName))) return err } func (s mysql) ModifyColumn(tableName string, columnName string, typ string) error { _, err := s.db.Exec(fmt.Sprintf("ALTER TABLE %v MODIFY COLUMN %v %v", tableName, columnName, typ)) return err } func (s mysql) LimitAndOffsetSQL(limit, offset interface{}) (sql string) { if limit != nil { if parsedLimit, err := strconv.ParseInt(fmt.Sprint(limit), 0, 0); err == nil && parsedLimit >= 0 { sql += fmt.Sprintf(" LIMIT %d", parsedLimit) if offset != nil { if parsedOffset, err := strconv.ParseInt(fmt.Sprint(offset), 0, 0); err == nil && parsedOffset >= 0 { sql += fmt.Sprintf(" OFFSET %d", parsedOffset) } } } } return } func (s mysql) HasForeignKey(tableName string, foreignKeyName string) bool { var count int currentDatabase, tableName := currentDatabaseAndTable(&s, tableName) s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_SCHEMA=? AND TABLE_NAME=? AND CONSTRAINT_NAME=? AND CONSTRAINT_TYPE='FOREIGN KEY'", currentDatabase, tableName, foreignKeyName).Scan(&count) return count > 0 } func (s mysql) CurrentDatabase() (name string) { s.db.QueryRow("SELECT DATABASE()").Scan(&name) return } func (mysql) SelectFromDummyTable() string { return "FROM DUAL" } func (s mysql) BuildKeyName(kind, tableName string, fields ...string) string { keyName := s.commonDialect.BuildKeyName(kind, tableName, fields...) if utf8.RuneCountInString(keyName) <= 64 { return keyName } h := sha1.New() h.Write([]byte(keyName)) bs := h.Sum(nil) // sha1 is 40 characters, keep first 24 characters of destination destRunes := []rune(regexp.MustCompile("[^a-zA-Z0-9]+").ReplaceAllString(fields[0], "_")) if len(destRunes) > 24 { destRunes = destRunes[:24] } return fmt.Sprintf("%s%x", string(destRunes), bs) } func (mysql) DefaultValueStr() string { return "VALUES()" } ================================================ FILE: vendor/github.com/jinzhu/gorm/dialect_postgres.go ================================================ package gorm import ( "encoding/json" "fmt" "reflect" "strings" "time" ) type postgres struct { commonDialect } func init() { RegisterDialect("postgres", &postgres{}) RegisterDialect("cloudsqlpostgres", &postgres{}) } func (postgres) GetName() string { return "postgres" } func (postgres) BindVar(i int) string { return fmt.Sprintf("$%v", i) } func (s *postgres) DataTypeOf(field *StructField) string { var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s) if sqlType == "" { switch dataValue.Kind() { case reflect.Bool: sqlType = "boolean" case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uintptr: if s.fieldCanAutoIncrement(field) { field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" sqlType = "serial" } else { sqlType = "integer" } case reflect.Int64, reflect.Uint32, reflect.Uint64: if s.fieldCanAutoIncrement(field) { field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" sqlType = "bigserial" } else { sqlType = "bigint" } case reflect.Float32, reflect.Float64: sqlType = "numeric" case reflect.String: if _, ok := field.TagSettings["SIZE"]; !ok { size = 0 // if SIZE haven't been set, use `text` as the default type, as there are no performance different } if size > 0 && size < 65532 { sqlType = fmt.Sprintf("varchar(%d)", size) } else { sqlType = "text" } case reflect.Struct: if _, ok := dataValue.Interface().(time.Time); ok { sqlType = "timestamp with time zone" } case reflect.Map: if dataValue.Type().Name() == "Hstore" { sqlType = "hstore" } default: if IsByteArrayOrSlice(dataValue) { sqlType = "bytea" if isUUID(dataValue) { sqlType = "uuid" } if isJSON(dataValue) { sqlType = "jsonb" } } } } if sqlType == "" { panic(fmt.Sprintf("invalid sql type %s (%s) for postgres", dataValue.Type().Name(), dataValue.Kind().String())) } if strings.TrimSpace(additionalType) == "" { return sqlType } return fmt.Sprintf("%v %v", sqlType, additionalType) } func (s postgres) HasIndex(tableName string, indexName string) bool { var count int s.db.QueryRow("SELECT count(*) FROM pg_indexes WHERE tablename = $1 AND indexname = $2 AND schemaname = CURRENT_SCHEMA()", tableName, indexName).Scan(&count) return count > 0 } func (s postgres) HasForeignKey(tableName string, foreignKeyName string) bool { var count int s.db.QueryRow("SELECT count(con.conname) FROM pg_constraint con WHERE $1::regclass::oid = con.conrelid AND con.conname = $2 AND con.contype='f'", tableName, foreignKeyName).Scan(&count) return count > 0 } func (s postgres) HasTable(tableName string) bool { var count int s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.tables WHERE table_name = $1 AND table_type = 'BASE TABLE' AND table_schema = CURRENT_SCHEMA()", tableName).Scan(&count) return count > 0 } func (s postgres) HasColumn(tableName string, columnName string) bool { var count int s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.columns WHERE table_name = $1 AND column_name = $2 AND table_schema = CURRENT_SCHEMA()", tableName, columnName).Scan(&count) return count > 0 } func (s postgres) CurrentDatabase() (name string) { s.db.QueryRow("SELECT CURRENT_DATABASE()").Scan(&name) return } func (s postgres) LastInsertIDReturningSuffix(tableName, key string) string { return fmt.Sprintf("RETURNING %v.%v", tableName, key) } func (postgres) SupportLastInsertID() bool { return false } func isUUID(value reflect.Value) bool { if value.Kind() != reflect.Array || value.Type().Len() != 16 { return false } typename := value.Type().Name() lower := strings.ToLower(typename) return "uuid" == lower || "guid" == lower } func isJSON(value reflect.Value) bool { _, ok := value.Interface().(json.RawMessage) return ok } ================================================ FILE: vendor/github.com/jinzhu/gorm/dialect_sqlite3.go ================================================ package gorm import ( "fmt" "reflect" "strings" "time" ) type sqlite3 struct { commonDialect } func init() { RegisterDialect("sqlite3", &sqlite3{}) } func (sqlite3) GetName() string { return "sqlite3" } // Get Data Type for Sqlite Dialect func (s *sqlite3) DataTypeOf(field *StructField) string { var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s) if sqlType == "" { switch dataValue.Kind() { case reflect.Bool: sqlType = "bool" case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr: if s.fieldCanAutoIncrement(field) { field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" sqlType = "integer primary key autoincrement" } else { sqlType = "integer" } case reflect.Int64, reflect.Uint64: if s.fieldCanAutoIncrement(field) { field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT" sqlType = "integer primary key autoincrement" } else { sqlType = "bigint" } case reflect.Float32, reflect.Float64: sqlType = "real" case reflect.String: if size > 0 && size < 65532 { sqlType = fmt.Sprintf("varchar(%d)", size) } else { sqlType = "text" } case reflect.Struct: if _, ok := dataValue.Interface().(time.Time); ok { sqlType = "datetime" } default: if IsByteArrayOrSlice(dataValue) { sqlType = "blob" } } } if sqlType == "" { panic(fmt.Sprintf("invalid sql type %s (%s) for sqlite3", dataValue.Type().Name(), dataValue.Kind().String())) } if strings.TrimSpace(additionalType) == "" { return sqlType } return fmt.Sprintf("%v %v", sqlType, additionalType) } func (s sqlite3) HasIndex(tableName string, indexName string) bool { var count int s.db.QueryRow(fmt.Sprintf("SELECT count(*) FROM sqlite_master WHERE tbl_name = ? AND sql LIKE '%%INDEX %v ON%%'", indexName), tableName).Scan(&count) return count > 0 } func (s sqlite3) HasTable(tableName string) bool { var count int s.db.QueryRow("SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?", tableName).Scan(&count) return count > 0 } func (s sqlite3) HasColumn(tableName string, columnName string) bool { var count int s.db.QueryRow(fmt.Sprintf("SELECT count(*) FROM sqlite_master WHERE tbl_name = ? AND (sql LIKE '%%\"%v\" %%' OR sql LIKE '%%%v %%');\n", columnName, columnName), tableName).Scan(&count) return count > 0 } func (s sqlite3) CurrentDatabase() (name string) { var ( ifaces = make([]interface{}, 3) pointers = make([]*string, 3) i int ) for i = 0; i < 3; i++ { ifaces[i] = &pointers[i] } if err := s.db.QueryRow("PRAGMA database_list").Scan(ifaces...); err != nil { return } if pointers[1] != nil { name = *pointers[1] } return } ================================================ FILE: vendor/github.com/jinzhu/gorm/dialects/mysql/mysql.go ================================================ package mysql import _ "github.com/go-sql-driver/mysql" ================================================ FILE: vendor/github.com/jinzhu/gorm/docker-compose.yml ================================================ version: '3' services: mysql: image: 'mysql:latest' ports: - 9910:3306 environment: - MYSQL_DATABASE=gorm - MYSQL_USER=gorm - MYSQL_PASSWORD=gorm - MYSQL_RANDOM_ROOT_PASSWORD="yes" postgres: image: 'postgres:latest' ports: - 9920:5432 environment: - POSTGRES_USER=gorm - POSTGRES_DB=gorm - POSTGRES_PASSWORD=gorm mssql: image: 'mcmoe/mssqldocker:latest' ports: - 9930:1433 environment: - ACCEPT_EULA=Y - SA_PASSWORD=LoremIpsum86 - MSSQL_DB=gorm - MSSQL_USER=gorm - MSSQL_PASSWORD=LoremIpsum86 ================================================ FILE: vendor/github.com/jinzhu/gorm/errors.go ================================================ package gorm import ( "errors" "strings" ) var ( // ErrRecordNotFound record not found error, happens when haven't find any matched data when looking up with a struct ErrRecordNotFound = errors.New("record not found") // ErrInvalidSQL invalid SQL error, happens when you passed invalid SQL ErrInvalidSQL = errors.New("invalid SQL") // ErrInvalidTransaction invalid transaction when you are trying to `Commit` or `Rollback` ErrInvalidTransaction = errors.New("no valid transaction") // ErrCantStartTransaction can't start transaction when you are trying to start one with `Begin` ErrCantStartTransaction = errors.New("can't start transaction") // ErrUnaddressable unaddressable value ErrUnaddressable = errors.New("using unaddressable value") ) // Errors contains all happened errors type Errors []error // IsRecordNotFoundError returns current error has record not found error or not func IsRecordNotFoundError(err error) bool { if errs, ok := err.(Errors); ok { for _, err := range errs { if err == ErrRecordNotFound { return true } } } return err == ErrRecordNotFound } // GetErrors gets all happened errors func (errs Errors) GetErrors() []error { return errs } // Add adds an error func (errs Errors) Add(newErrors ...error) Errors { for _, err := range newErrors { if err == nil { continue } if errors, ok := err.(Errors); ok { errs = errs.Add(errors...) } else { ok = true for _, e := range errs { if err == e { ok = false } } if ok { errs = append(errs, err) } } } return errs } // Error format happened errors func (errs Errors) Error() string { var errors = []string{} for _, e := range errs { errors = append(errors, e.Error()) } return strings.Join(errors, "; ") } ================================================ FILE: vendor/github.com/jinzhu/gorm/field.go ================================================ package gorm import ( "database/sql" "errors" "fmt" "reflect" ) // Field model field definition type Field struct { *StructField IsBlank bool Field reflect.Value } // Set set a value to the field func (field *Field) Set(value interface{}) (err error) { if !field.Field.IsValid() { return errors.New("field value not valid") } if !field.Field.CanAddr() { return ErrUnaddressable } reflectValue, ok := value.(reflect.Value) if !ok { reflectValue = reflect.ValueOf(value) } fieldValue := field.Field if reflectValue.IsValid() { if reflectValue.Type().ConvertibleTo(fieldValue.Type()) { fieldValue.Set(reflectValue.Convert(fieldValue.Type())) } else { if fieldValue.Kind() == reflect.Ptr { if fieldValue.IsNil() { fieldValue.Set(reflect.New(field.Struct.Type.Elem())) } fieldValue = fieldValue.Elem() } if reflectValue.Type().ConvertibleTo(fieldValue.Type()) { fieldValue.Set(reflectValue.Convert(fieldValue.Type())) } else if scanner, ok := fieldValue.Addr().Interface().(sql.Scanner); ok { err = scanner.Scan(reflectValue.Interface()) } else { err = fmt.Errorf("could not convert argument of field %s from %s to %s", field.Name, reflectValue.Type(), fieldValue.Type()) } } } else { field.Field.Set(reflect.Zero(field.Field.Type())) } field.IsBlank = isBlank(field.Field) return err } ================================================ FILE: vendor/github.com/jinzhu/gorm/interface.go ================================================ package gorm import "database/sql" // SQLCommon is the minimal database connection functionality gorm requires. Implemented by *sql.DB. type SQLCommon interface { Exec(query string, args ...interface{}) (sql.Result, error) Prepare(query string) (*sql.Stmt, error) Query(query string, args ...interface{}) (*sql.Rows, error) QueryRow(query string, args ...interface{}) *sql.Row } type sqlDb interface { Begin() (*sql.Tx, error) } type sqlTx interface { Commit() error Rollback() error } ================================================ FILE: vendor/github.com/jinzhu/gorm/join_table_handler.go ================================================ package gorm import ( "errors" "fmt" "reflect" "strings" ) // JoinTableHandlerInterface is an interface for how to handle many2many relations type JoinTableHandlerInterface interface { // initialize join table handler Setup(relationship *Relationship, tableName string, source reflect.Type, destination reflect.Type) // Table return join table's table name Table(db *DB) string // Add create relationship in join table for source and destination Add(handler JoinTableHandlerInterface, db *DB, source interface{}, destination interface{}) error // Delete delete relationship in join table for sources Delete(handler JoinTableHandlerInterface, db *DB, sources ...interface{}) error // JoinWith query with `Join` conditions JoinWith(handler JoinTableHandlerInterface, db *DB, source interface{}) *DB // SourceForeignKeys return source foreign keys SourceForeignKeys() []JoinTableForeignKey // DestinationForeignKeys return destination foreign keys DestinationForeignKeys() []JoinTableForeignKey } // JoinTableForeignKey join table foreign key struct type JoinTableForeignKey struct { DBName string AssociationDBName string } // JoinTableSource is a struct that contains model type and foreign keys type JoinTableSource struct { ModelType reflect.Type ForeignKeys []JoinTableForeignKey } // JoinTableHandler default join table handler type JoinTableHandler struct { TableName string `sql:"-"` Source JoinTableSource `sql:"-"` Destination JoinTableSource `sql:"-"` } // SourceForeignKeys return source foreign keys func (s *JoinTableHandler) SourceForeignKeys() []JoinTableForeignKey { return s.Source.ForeignKeys } // DestinationForeignKeys return destination foreign keys func (s *JoinTableHandler) DestinationForeignKeys() []JoinTableForeignKey { return s.Destination.ForeignKeys } // Setup initialize a default join table handler func (s *JoinTableHandler) Setup(relationship *Relationship, tableName string, source reflect.Type, destination reflect.Type) { s.TableName = tableName s.Source = JoinTableSource{ModelType: source} s.Source.ForeignKeys = []JoinTableForeignKey{} for idx, dbName := range relationship.ForeignFieldNames { s.Source.ForeignKeys = append(s.Source.ForeignKeys, JoinTableForeignKey{ DBName: relationship.ForeignDBNames[idx], AssociationDBName: dbName, }) } s.Destination = JoinTableSource{ModelType: destination} s.Destination.ForeignKeys = []JoinTableForeignKey{} for idx, dbName := range relationship.AssociationForeignFieldNames { s.Destination.ForeignKeys = append(s.Destination.ForeignKeys, JoinTableForeignKey{ DBName: relationship.AssociationForeignDBNames[idx], AssociationDBName: dbName, }) } } // Table return join table's table name func (s JoinTableHandler) Table(db *DB) string { return DefaultTableNameHandler(db, s.TableName) } func (s JoinTableHandler) updateConditionMap(conditionMap map[string]interface{}, db *DB, joinTableSources []JoinTableSource, sources ...interface{}) { for _, source := range sources { scope := db.NewScope(source) modelType := scope.GetModelStruct().ModelType for _, joinTableSource := range joinTableSources { if joinTableSource.ModelType == modelType { for _, foreignKey := range joinTableSource.ForeignKeys { if field, ok := scope.FieldByName(foreignKey.AssociationDBName); ok { conditionMap[foreignKey.DBName] = field.Field.Interface() } } break } } } } // Add create relationship in join table for source and destination func (s JoinTableHandler) Add(handler JoinTableHandlerInterface, db *DB, source interface{}, destination interface{}) error { var ( scope = db.NewScope("") conditionMap = map[string]interface{}{} ) // Update condition map for source s.updateConditionMap(conditionMap, db, []JoinTableSource{s.Source}, source) // Update condition map for destination s.updateConditionMap(conditionMap, db, []JoinTableSource{s.Destination}, destination) var assignColumns, binVars, conditions []string var values []interface{} for key, value := range conditionMap { assignColumns = append(assignColumns, scope.Quote(key)) binVars = append(binVars, `?`) conditions = append(conditions, fmt.Sprintf("%v = ?", scope.Quote(key))) values = append(values, value) } for _, value := range values { values = append(values, value) } quotedTable := scope.Quote(handler.Table(db)) sql := fmt.Sprintf( "INSERT INTO %v (%v) SELECT %v %v WHERE NOT EXISTS (SELECT * FROM %v WHERE %v)", quotedTable, strings.Join(assignColumns, ","), strings.Join(binVars, ","), scope.Dialect().SelectFromDummyTable(), quotedTable, strings.Join(conditions, " AND "), ) return db.Exec(sql, values...).Error } // Delete delete relationship in join table for sources func (s JoinTableHandler) Delete(handler JoinTableHandlerInterface, db *DB, sources ...interface{}) error { var ( scope = db.NewScope(nil) conditions []string values []interface{} conditionMap = map[string]interface{}{} ) s.updateConditionMap(conditionMap, db, []JoinTableSource{s.Source, s.Destination}, sources...) for key, value := range conditionMap { conditions = append(conditions, fmt.Sprintf("%v = ?", scope.Quote(key))) values = append(values, value) } return db.Table(handler.Table(db)).Where(strings.Join(conditions, " AND "), values...).Delete("").Error } // JoinWith query with `Join` conditions func (s JoinTableHandler) JoinWith(handler JoinTableHandlerInterface, db *DB, source interface{}) *DB { var ( scope = db.NewScope(source) tableName = handler.Table(db) quotedTableName = scope.Quote(tableName) joinConditions []string values []interface{} ) if s.Source.ModelType == scope.GetModelStruct().ModelType { destinationTableName := db.NewScope(reflect.New(s.Destination.ModelType).Interface()).QuotedTableName() for _, foreignKey := range s.Destination.ForeignKeys { joinConditions = append(joinConditions, fmt.Sprintf("%v.%v = %v.%v", quotedTableName, scope.Quote(foreignKey.DBName), destinationTableName, scope.Quote(foreignKey.AssociationDBName))) } var foreignDBNames []string var foreignFieldNames []string for _, foreignKey := range s.Source.ForeignKeys { foreignDBNames = append(foreignDBNames, foreignKey.DBName) if field, ok := scope.FieldByName(foreignKey.AssociationDBName); ok { foreignFieldNames = append(foreignFieldNames, field.Name) } } foreignFieldValues := scope.getColumnAsArray(foreignFieldNames, scope.Value) var condString string if len(foreignFieldValues) > 0 { var quotedForeignDBNames []string for _, dbName := range foreignDBNames { quotedForeignDBNames = append(quotedForeignDBNames, tableName+"."+dbName) } condString = fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, quotedForeignDBNames), toQueryMarks(foreignFieldValues)) keys := scope.getColumnAsArray(foreignFieldNames, scope.Value) values = append(values, toQueryValues(keys)) } else { condString = fmt.Sprintf("1 <> 1") } return db.Joins(fmt.Sprintf("INNER JOIN %v ON %v", quotedTableName, strings.Join(joinConditions, " AND "))). Where(condString, toQueryValues(foreignFieldValues)...) } db.Error = errors.New("wrong source type for join table handler") return db } ================================================ FILE: vendor/github.com/jinzhu/gorm/logger.go ================================================ package gorm import ( "database/sql/driver" "fmt" "log" "os" "reflect" "regexp" "strconv" "time" "unicode" ) var ( defaultLogger = Logger{log.New(os.Stdout, "\r\n", 0)} sqlRegexp = regexp.MustCompile(`\?`) numericPlaceHolderRegexp = regexp.MustCompile(`\$\d+`) ) func isPrintable(s string) bool { for _, r := range s { if !unicode.IsPrint(r) { return false } } return true } var LogFormatter = func(values ...interface{}) (messages []interface{}) { if len(values) > 1 { var ( sql string formattedValues []string level = values[0] currentTime = "\n\033[33m[" + NowFunc().Format("2006-01-02 15:04:05") + "]\033[0m" source = fmt.Sprintf("\033[35m(%v)\033[0m", values[1]) ) messages = []interface{}{source, currentTime} if level == "sql" { // duration messages = append(messages, fmt.Sprintf(" \033[36;1m[%.2fms]\033[0m ", float64(values[2].(time.Duration).Nanoseconds()/1e4)/100.0)) // sql for _, value := range values[4].([]interface{}) { indirectValue := reflect.Indirect(reflect.ValueOf(value)) if indirectValue.IsValid() { value = indirectValue.Interface() if t, ok := value.(time.Time); ok { formattedValues = append(formattedValues, fmt.Sprintf("'%v'", t.Format("2006-01-02 15:04:05"))) } else if b, ok := value.([]byte); ok { if str := string(b); isPrintable(str) { formattedValues = append(formattedValues, fmt.Sprintf("'%v'", str)) } else { formattedValues = append(formattedValues, "''") } } else if r, ok := value.(driver.Valuer); ok { if value, err := r.Value(); err == nil && value != nil { formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value)) } else { formattedValues = append(formattedValues, "NULL") } } else { formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value)) } } else { formattedValues = append(formattedValues, "NULL") } } // differentiate between $n placeholders or else treat like ? if numericPlaceHolderRegexp.MatchString(values[3].(string)) { sql = values[3].(string) for index, value := range formattedValues { placeholder := fmt.Sprintf(`\$%d([^\d]|$)`, index+1) sql = regexp.MustCompile(placeholder).ReplaceAllString(sql, value+"$1") } } else { formattedValuesLength := len(formattedValues) for index, value := range sqlRegexp.Split(values[3].(string), -1) { sql += value if index < formattedValuesLength { sql += formattedValues[index] } } } messages = append(messages, sql) messages = append(messages, fmt.Sprintf(" \n\033[36;31m[%v]\033[0m ", strconv.FormatInt(values[5].(int64), 10)+" rows affected or returned ")) } else { messages = append(messages, "\033[31;1m") messages = append(messages, values[2:]...) messages = append(messages, "\033[0m") } } return } type logger interface { Print(v ...interface{}) } // LogWriter log writer interface type LogWriter interface { Println(v ...interface{}) } // Logger default logger type Logger struct { LogWriter } // Print format & print log func (logger Logger) Print(values ...interface{}) { logger.Println(LogFormatter(values...)...) } ================================================ FILE: vendor/github.com/jinzhu/gorm/main.go ================================================ package gorm import ( "database/sql" "errors" "fmt" "reflect" "strings" "time" ) // DB contains information for current db connection type DB struct { Value interface{} Error error RowsAffected int64 // single db db SQLCommon blockGlobalUpdate bool logMode int logger logger search *search values map[string]interface{} // global db parent *DB callbacks *Callback dialect Dialect singularTable bool } // Open initialize a new db connection, need to import driver first, e.g: // // import _ "github.com/go-sql-driver/mysql" // func main() { // db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local") // } // GORM has wrapped some drivers, for easier to remember driver's import path, so you could import the mysql driver with // import _ "github.com/jinzhu/gorm/dialects/mysql" // // import _ "github.com/jinzhu/gorm/dialects/postgres" // // import _ "github.com/jinzhu/gorm/dialects/sqlite" // // import _ "github.com/jinzhu/gorm/dialects/mssql" func Open(dialect string, args ...interface{}) (db *DB, err error) { if len(args) == 0 { err = errors.New("invalid database source") return nil, err } var source string var dbSQL SQLCommon switch value := args[0].(type) { case string: var driver = dialect if len(args) == 1 { source = value } else if len(args) >= 2 { driver = value source = args[1].(string) } dbSQL, err = sql.Open(driver, source) case SQLCommon: dbSQL = value } db = &DB{ db: dbSQL, logger: defaultLogger, values: map[string]interface{}{}, callbacks: DefaultCallback, dialect: newDialect(dialect, dbSQL), } db.parent = db if err != nil { return } // Send a ping to make sure the database connection is alive. if d, ok := dbSQL.(*sql.DB); ok { if err = d.Ping(); err != nil { d.Close() } } return } // New clone a new db connection without search conditions func (s *DB) New() *DB { clone := s.clone() clone.search = nil clone.Value = nil return clone } type closer interface { Close() error } // Close close current db connection. If database connection is not an io.Closer, returns an error. func (s *DB) Close() error { if db, ok := s.parent.db.(closer); ok { return db.Close() } return errors.New("can't close current db") } // DB get `*sql.DB` from current connection // If the underlying database connection is not a *sql.DB, returns nil func (s *DB) DB() *sql.DB { db, _ := s.db.(*sql.DB) return db } // CommonDB return the underlying `*sql.DB` or `*sql.Tx` instance, mainly intended to allow coexistence with legacy non-GORM code. func (s *DB) CommonDB() SQLCommon { return s.db } // Dialect get dialect func (s *DB) Dialect() Dialect { return s.parent.dialect } // Callback return `Callbacks` container, you could add/change/delete callbacks with it // db.Callback().Create().Register("update_created_at", updateCreated) // Refer https://jinzhu.github.io/gorm/development.html#callbacks func (s *DB) Callback() *Callback { s.parent.callbacks = s.parent.callbacks.clone() return s.parent.callbacks } // SetLogger replace default logger func (s *DB) SetLogger(log logger) { s.logger = log } // LogMode set log mode, `true` for detailed logs, `false` for no log, default, will only print error logs func (s *DB) LogMode(enable bool) *DB { if enable { s.logMode = 2 } else { s.logMode = 1 } return s } // BlockGlobalUpdate if true, generates an error on update/delete without where clause. // This is to prevent eventual error with empty objects updates/deletions func (s *DB) BlockGlobalUpdate(enable bool) *DB { s.blockGlobalUpdate = enable return s } // HasBlockGlobalUpdate return state of block func (s *DB) HasBlockGlobalUpdate() bool { return s.blockGlobalUpdate } // SingularTable use singular table by default func (s *DB) SingularTable(enable bool) { modelStructsMap = newModelStructsMap() s.parent.singularTable = enable } // NewScope create a scope for current operation func (s *DB) NewScope(value interface{}) *Scope { dbClone := s.clone() dbClone.Value = value return &Scope{db: dbClone, Search: dbClone.search.clone(), Value: value} } // QueryExpr returns the query as expr object func (s *DB) QueryExpr() *expr { scope := s.NewScope(s.Value) scope.InstanceSet("skip_bindvar", true) scope.prepareQuerySQL() return Expr(scope.SQL, scope.SQLVars...) } // Where return a new relation, filter records with given conditions, accepts `map`, `struct` or `string` as conditions, refer http://jinzhu.github.io/gorm/crud.html#query func (s *DB) Where(query interface{}, args ...interface{}) *DB { return s.clone().search.Where(query, args...).db } // Or filter records that match before conditions or this one, similar to `Where` func (s *DB) Or(query interface{}, args ...interface{}) *DB { return s.clone().search.Or(query, args...).db } // Not filter records that don't match current conditions, similar to `Where` func (s *DB) Not(query interface{}, args ...interface{}) *DB { return s.clone().search.Not(query, args...).db } // Limit specify the number of records to be retrieved func (s *DB) Limit(limit interface{}) *DB { return s.clone().search.Limit(limit).db } // Offset specify the number of records to skip before starting to return the records func (s *DB) Offset(offset interface{}) *DB { return s.clone().search.Offset(offset).db } // Order specify order when retrieve records from database, set reorder to `true` to overwrite defined conditions // db.Order("name DESC") // db.Order("name DESC", true) // reorder // db.Order(gorm.Expr("name = ? DESC", "first")) // sql expression func (s *DB) Order(value interface{}, reorder ...bool) *DB { return s.clone().search.Order(value, reorder...).db } // Select specify fields that you want to retrieve from database when querying, by default, will select all fields; // When creating/updating, specify fields that you want to save to database func (s *DB) Select(query interface{}, args ...interface{}) *DB { return s.clone().search.Select(query, args...).db } // Omit specify fields that you want to ignore when saving to database for creating, updating func (s *DB) Omit(columns ...string) *DB { return s.clone().search.Omit(columns...).db } // Group specify the group method on the find func (s *DB) Group(query string) *DB { return s.clone().search.Group(query).db } // Having specify HAVING conditions for GROUP BY func (s *DB) Having(query interface{}, values ...interface{}) *DB { return s.clone().search.Having(query, values...).db } // Joins specify Joins conditions // db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Find(&user) func (s *DB) Joins(query string, args ...interface{}) *DB { return s.clone().search.Joins(query, args...).db } // Scopes pass current database connection to arguments `func(*DB) *DB`, which could be used to add conditions dynamically // func AmountGreaterThan1000(db *gorm.DB) *gorm.DB { // return db.Where("amount > ?", 1000) // } // // func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB { // return func (db *gorm.DB) *gorm.DB { // return db.Scopes(AmountGreaterThan1000).Where("status in (?)", status) // } // } // // db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders) // Refer https://jinzhu.github.io/gorm/crud.html#scopes func (s *DB) Scopes(funcs ...func(*DB) *DB) *DB { for _, f := range funcs { s = f(s) } return s } // Unscoped return all record including deleted record, refer Soft Delete https://jinzhu.github.io/gorm/crud.html#soft-delete func (s *DB) Unscoped() *DB { return s.clone().search.unscoped().db } // Attrs initialize struct with argument if record not found with `FirstOrInit` https://jinzhu.github.io/gorm/crud.html#firstorinit or `FirstOrCreate` https://jinzhu.github.io/gorm/crud.html#firstorcreate func (s *DB) Attrs(attrs ...interface{}) *DB { return s.clone().search.Attrs(attrs...).db } // Assign assign result with argument regardless it is found or not with `FirstOrInit` https://jinzhu.github.io/gorm/crud.html#firstorinit or `FirstOrCreate` https://jinzhu.github.io/gorm/crud.html#firstorcreate func (s *DB) Assign(attrs ...interface{}) *DB { return s.clone().search.Assign(attrs...).db } // First find first record that match given conditions, order by primary key func (s *DB) First(out interface{}, where ...interface{}) *DB { newScope := s.NewScope(out) newScope.Search.Limit(1) return newScope.Set("gorm:order_by_primary_key", "ASC"). inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db } // Take return a record that match given conditions, the order will depend on the database implementation func (s *DB) Take(out interface{}, where ...interface{}) *DB { newScope := s.NewScope(out) newScope.Search.Limit(1) return newScope.inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db } // Last find last record that match given conditions, order by primary key func (s *DB) Last(out interface{}, where ...interface{}) *DB { newScope := s.NewScope(out) newScope.Search.Limit(1) return newScope.Set("gorm:order_by_primary_key", "DESC"). inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db } // Find find records that match given conditions func (s *DB) Find(out interface{}, where ...interface{}) *DB { return s.NewScope(out).inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db } // Scan scan value to a struct func (s *DB) Scan(dest interface{}) *DB { return s.NewScope(s.Value).Set("gorm:query_destination", dest).callCallbacks(s.parent.callbacks.queries).db } // Row return `*sql.Row` with given conditions func (s *DB) Row() *sql.Row { return s.NewScope(s.Value).row() } // Rows return `*sql.Rows` with given conditions func (s *DB) Rows() (*sql.Rows, error) { return s.NewScope(s.Value).rows() } // ScanRows scan `*sql.Rows` to give struct func (s *DB) ScanRows(rows *sql.Rows, result interface{}) error { var ( scope = s.NewScope(result) clone = scope.db columns, err = rows.Columns() ) if clone.AddError(err) == nil { scope.scan(rows, columns, scope.Fields()) } return clone.Error } // Pluck used to query single column from a model as a map // var ages []int64 // db.Find(&users).Pluck("age", &ages) func (s *DB) Pluck(column string, value interface{}) *DB { return s.NewScope(s.Value).pluck(column, value).db } // Count get how many records for a model func (s *DB) Count(value interface{}) *DB { return s.NewScope(s.Value).count(value).db } // Related get related associations func (s *DB) Related(value interface{}, foreignKeys ...string) *DB { return s.NewScope(s.Value).related(value, foreignKeys...).db } // FirstOrInit find first matched record or initialize a new one with given conditions (only works with struct, map conditions) // https://jinzhu.github.io/gorm/crud.html#firstorinit func (s *DB) FirstOrInit(out interface{}, where ...interface{}) *DB { c := s.clone() if result := c.First(out, where...); result.Error != nil { if !result.RecordNotFound() { return result } c.NewScope(out).inlineCondition(where...).initialize() } else { c.NewScope(out).updatedAttrsWithValues(c.search.assignAttrs) } return c } // FirstOrCreate find first matched record or create a new one with given conditions (only works with struct, map conditions) // https://jinzhu.github.io/gorm/crud.html#firstorcreate func (s *DB) FirstOrCreate(out interface{}, where ...interface{}) *DB { c := s.clone() if result := s.First(out, where...); result.Error != nil { if !result.RecordNotFound() { return result } return c.NewScope(out).inlineCondition(where...).initialize().callCallbacks(c.parent.callbacks.creates).db } else if len(c.search.assignAttrs) > 0 { return c.NewScope(out).InstanceSet("gorm:update_interface", c.search.assignAttrs).callCallbacks(c.parent.callbacks.updates).db } return c } // Update update attributes with callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update func (s *DB) Update(attrs ...interface{}) *DB { return s.Updates(toSearchableMap(attrs...), true) } // Updates update attributes with callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update func (s *DB) Updates(values interface{}, ignoreProtectedAttrs ...bool) *DB { return s.NewScope(s.Value). Set("gorm:ignore_protected_attrs", len(ignoreProtectedAttrs) > 0). InstanceSet("gorm:update_interface", values). callCallbacks(s.parent.callbacks.updates).db } // UpdateColumn update attributes without callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update func (s *DB) UpdateColumn(attrs ...interface{}) *DB { return s.UpdateColumns(toSearchableMap(attrs...)) } // UpdateColumns update attributes without callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update func (s *DB) UpdateColumns(values interface{}) *DB { return s.NewScope(s.Value). Set("gorm:update_column", true). Set("gorm:save_associations", false). InstanceSet("gorm:update_interface", values). callCallbacks(s.parent.callbacks.updates).db } // Save update value in database, if the value doesn't have primary key, will insert it func (s *DB) Save(value interface{}) *DB { scope := s.NewScope(value) if !scope.PrimaryKeyZero() { newDB := scope.callCallbacks(s.parent.callbacks.updates).db if newDB.Error == nil && newDB.RowsAffected == 0 { return s.New().FirstOrCreate(value) } return newDB } return scope.callCallbacks(s.parent.callbacks.creates).db } // Create insert the value into database func (s *DB) Create(value interface{}) *DB { scope := s.NewScope(value) return scope.callCallbacks(s.parent.callbacks.creates).db } // Delete delete value match given conditions, if the value has primary key, then will including the primary key as condition func (s *DB) Delete(value interface{}, where ...interface{}) *DB { return s.NewScope(value).inlineCondition(where...).callCallbacks(s.parent.callbacks.deletes).db } // Raw use raw sql as conditions, won't run it unless invoked by other methods // db.Raw("SELECT name, age FROM users WHERE name = ?", 3).Scan(&result) func (s *DB) Raw(sql string, values ...interface{}) *DB { return s.clone().search.Raw(true).Where(sql, values...).db } // Exec execute raw sql func (s *DB) Exec(sql string, values ...interface{}) *DB { scope := s.NewScope(nil) generatedSQL := scope.buildCondition(map[string]interface{}{"query": sql, "args": values}, true) generatedSQL = strings.TrimSuffix(strings.TrimPrefix(generatedSQL, "("), ")") scope.Raw(generatedSQL) return scope.Exec().db } // Model specify the model you would like to run db operations // // update all users's name to `hello` // db.Model(&User{}).Update("name", "hello") // // if user's primary key is non-blank, will use it as condition, then will only update the user's name to `hello` // db.Model(&user).Update("name", "hello") func (s *DB) Model(value interface{}) *DB { c := s.clone() c.Value = value return c } // Table specify the table you would like to run db operations func (s *DB) Table(name string) *DB { clone := s.clone() clone.search.Table(name) clone.Value = nil return clone } // Debug start debug mode func (s *DB) Debug() *DB { return s.clone().LogMode(true) } // Begin begin a transaction func (s *DB) Begin() *DB { c := s.clone() if db, ok := c.db.(sqlDb); ok && db != nil { tx, err := db.Begin() c.db = interface{}(tx).(SQLCommon) c.AddError(err) } else { c.AddError(ErrCantStartTransaction) } return c } // Commit commit a transaction func (s *DB) Commit() *DB { if db, ok := s.db.(sqlTx); ok && db != nil { s.AddError(db.Commit()) } else { s.AddError(ErrInvalidTransaction) } return s } // Rollback rollback a transaction func (s *DB) Rollback() *DB { if db, ok := s.db.(sqlTx); ok && db != nil { s.AddError(db.Rollback()) } else { s.AddError(ErrInvalidTransaction) } return s } // NewRecord check if value's primary key is blank func (s *DB) NewRecord(value interface{}) bool { return s.NewScope(value).PrimaryKeyZero() } // RecordNotFound check if returning ErrRecordNotFound error func (s *DB) RecordNotFound() bool { for _, err := range s.GetErrors() { if err == ErrRecordNotFound { return true } } return false } // CreateTable create table for models func (s *DB) CreateTable(models ...interface{}) *DB { db := s.Unscoped() for _, model := range models { db = db.NewScope(model).createTable().db } return db } // DropTable drop table for models func (s *DB) DropTable(values ...interface{}) *DB { db := s.clone() for _, value := range values { if tableName, ok := value.(string); ok { db = db.Table(tableName) } db = db.NewScope(value).dropTable().db } return db } // DropTableIfExists drop table if it is exist func (s *DB) DropTableIfExists(values ...interface{}) *DB { db := s.clone() for _, value := range values { if s.HasTable(value) { db.AddError(s.DropTable(value).Error) } } return db } // HasTable check has table or not func (s *DB) HasTable(value interface{}) bool { var ( scope = s.NewScope(value) tableName string ) if name, ok := value.(string); ok { tableName = name } else { tableName = scope.TableName() } has := scope.Dialect().HasTable(tableName) s.AddError(scope.db.Error) return has } // AutoMigrate run auto migration for given models, will only add missing fields, won't delete/change current data func (s *DB) AutoMigrate(values ...interface{}) *DB { db := s.Unscoped() for _, value := range values { db = db.NewScope(value).autoMigrate().db } return db } // ModifyColumn modify column to type func (s *DB) ModifyColumn(column string, typ string) *DB { scope := s.NewScope(s.Value) scope.modifyColumn(column, typ) return scope.db } // DropColumn drop a column func (s *DB) DropColumn(column string) *DB { scope := s.NewScope(s.Value) scope.dropColumn(column) return scope.db } // AddIndex add index for columns with given name func (s *DB) AddIndex(indexName string, columns ...string) *DB { scope := s.Unscoped().NewScope(s.Value) scope.addIndex(false, indexName, columns...) return scope.db } // AddUniqueIndex add unique index for columns with given name func (s *DB) AddUniqueIndex(indexName string, columns ...string) *DB { scope := s.Unscoped().NewScope(s.Value) scope.addIndex(true, indexName, columns...) return scope.db } // RemoveIndex remove index with name func (s *DB) RemoveIndex(indexName string) *DB { scope := s.NewScope(s.Value) scope.removeIndex(indexName) return scope.db } // AddForeignKey Add foreign key to the given scope, e.g: // db.Model(&User{}).AddForeignKey("city_id", "cities(id)", "RESTRICT", "RESTRICT") func (s *DB) AddForeignKey(field string, dest string, onDelete string, onUpdate string) *DB { scope := s.NewScope(s.Value) scope.addForeignKey(field, dest, onDelete, onUpdate) return scope.db } // RemoveForeignKey Remove foreign key from the given scope, e.g: // db.Model(&User{}).RemoveForeignKey("city_id", "cities(id)") func (s *DB) RemoveForeignKey(field string, dest string) *DB { scope := s.clone().NewScope(s.Value) scope.removeForeignKey(field, dest) return scope.db } // Association start `Association Mode` to handler relations things easir in that mode, refer: https://jinzhu.github.io/gorm/associations.html#association-mode func (s *DB) Association(column string) *Association { var err error var scope = s.Set("gorm:association:source", s.Value).NewScope(s.Value) if primaryField := scope.PrimaryField(); primaryField.IsBlank { err = errors.New("primary key can't be nil") } else { if field, ok := scope.FieldByName(column); ok { if field.Relationship == nil || len(field.Relationship.ForeignFieldNames) == 0 { err = fmt.Errorf("invalid association %v for %v", column, scope.IndirectValue().Type()) } else { return &Association{scope: scope, column: column, field: field} } } else { err = fmt.Errorf("%v doesn't have column %v", scope.IndirectValue().Type(), column) } } return &Association{Error: err} } // Preload preload associations with given conditions // db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users) func (s *DB) Preload(column string, conditions ...interface{}) *DB { return s.clone().search.Preload(column, conditions...).db } // Set set setting by name, which could be used in callbacks, will clone a new db, and update its setting func (s *DB) Set(name string, value interface{}) *DB { return s.clone().InstantSet(name, value) } // InstantSet instant set setting, will affect current db func (s *DB) InstantSet(name string, value interface{}) *DB { s.values[name] = value return s } // Get get setting by name func (s *DB) Get(name string) (value interface{}, ok bool) { value, ok = s.values[name] return } // SetJoinTableHandler set a model's join table handler for a relation func (s *DB) SetJoinTableHandler(source interface{}, column string, handler JoinTableHandlerInterface) { scope := s.NewScope(source) for _, field := range scope.GetModelStruct().StructFields { if field.Name == column || field.DBName == column { if many2many := field.TagSettings["MANY2MANY"]; many2many != "" { source := (&Scope{Value: source}).GetModelStruct().ModelType destination := (&Scope{Value: reflect.New(field.Struct.Type).Interface()}).GetModelStruct().ModelType handler.Setup(field.Relationship, many2many, source, destination) field.Relationship.JoinTableHandler = handler if table := handler.Table(s); scope.Dialect().HasTable(table) { s.Table(table).AutoMigrate(handler) } } } } } // AddError add error to the db func (s *DB) AddError(err error) error { if err != nil { if err != ErrRecordNotFound { if s.logMode == 0 { go s.print(fileWithLineNum(), err) } else { s.log(err) } errors := Errors(s.GetErrors()) errors = errors.Add(err) if len(errors) > 1 { err = errors } } s.Error = err } return err } // GetErrors get happened errors from the db func (s *DB) GetErrors() []error { if errs, ok := s.Error.(Errors); ok { return errs } else if s.Error != nil { return []error{s.Error} } return []error{} } //////////////////////////////////////////////////////////////////////////////// // Private Methods For DB //////////////////////////////////////////////////////////////////////////////// func (s *DB) clone() *DB { db := &DB{ db: s.db, parent: s.parent, logger: s.logger, logMode: s.logMode, values: map[string]interface{}{}, Value: s.Value, Error: s.Error, blockGlobalUpdate: s.blockGlobalUpdate, } for key, value := range s.values { db.values[key] = value } if s.search == nil { db.search = &search{limit: -1, offset: -1} } else { db.search = s.search.clone() } db.search.db = db return db } func (s *DB) print(v ...interface{}) { s.logger.Print(v...) } func (s *DB) log(v ...interface{}) { if s != nil && s.logMode == 2 { s.print(append([]interface{}{"log", fileWithLineNum()}, v...)...) } } func (s *DB) slog(sql string, t time.Time, vars ...interface{}) { if s.logMode == 2 { s.print("sql", fileWithLineNum(), NowFunc().Sub(t), sql, vars, s.RowsAffected) } } ================================================ FILE: vendor/github.com/jinzhu/gorm/model.go ================================================ package gorm import "time" // Model base model definition, including fields `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt`, which could be embedded in your models // type User struct { // gorm.Model // } type Model struct { ID uint `gorm:"primary_key"` CreatedAt time.Time UpdatedAt time.Time DeletedAt *time.Time `sql:"index"` } ================================================ FILE: vendor/github.com/jinzhu/gorm/model_struct.go ================================================ package gorm import ( "database/sql" "errors" "go/ast" "reflect" "strings" "sync" "time" "github.com/jinzhu/inflection" ) // DefaultTableNameHandler default table name handler var DefaultTableNameHandler = func(db *DB, defaultTableName string) string { return defaultTableName } type safeModelStructsMap struct { m map[reflect.Type]*ModelStruct l *sync.RWMutex } func (s *safeModelStructsMap) Set(key reflect.Type, value *ModelStruct) { s.l.Lock() defer s.l.Unlock() s.m[key] = value } func (s *safeModelStructsMap) Get(key reflect.Type) *ModelStruct { s.l.RLock() defer s.l.RUnlock() return s.m[key] } func newModelStructsMap() *safeModelStructsMap { return &safeModelStructsMap{l: new(sync.RWMutex), m: make(map[reflect.Type]*ModelStruct)} } var modelStructsMap = newModelStructsMap() // ModelStruct model definition type ModelStruct struct { PrimaryFields []*StructField StructFields []*StructField ModelType reflect.Type defaultTableName string } // TableName get model's table name func (s *ModelStruct) TableName(db *DB) string { if s.defaultTableName == "" && db != nil && s.ModelType != nil { // Set default table name if tabler, ok := reflect.New(s.ModelType).Interface().(tabler); ok { s.defaultTableName = tabler.TableName() } else { tableName := ToDBName(s.ModelType.Name()) if db == nil || !db.parent.singularTable { tableName = inflection.Plural(tableName) } s.defaultTableName = tableName } } return DefaultTableNameHandler(db, s.defaultTableName) } // StructField model field's struct definition type StructField struct { DBName string Name string Names []string IsPrimaryKey bool IsNormal bool IsIgnored bool IsScanner bool HasDefaultValue bool Tag reflect.StructTag TagSettings map[string]string Struct reflect.StructField IsForeignKey bool Relationship *Relationship } func (structField *StructField) clone() *StructField { clone := &StructField{ DBName: structField.DBName, Name: structField.Name, Names: structField.Names, IsPrimaryKey: structField.IsPrimaryKey, IsNormal: structField.IsNormal, IsIgnored: structField.IsIgnored, IsScanner: structField.IsScanner, HasDefaultValue: structField.HasDefaultValue, Tag: structField.Tag, TagSettings: map[string]string{}, Struct: structField.Struct, IsForeignKey: structField.IsForeignKey, } if structField.Relationship != nil { relationship := *structField.Relationship clone.Relationship = &relationship } for key, value := range structField.TagSettings { clone.TagSettings[key] = value } return clone } // Relationship described the relationship between models type Relationship struct { Kind string PolymorphicType string PolymorphicDBName string PolymorphicValue string ForeignFieldNames []string ForeignDBNames []string AssociationForeignFieldNames []string AssociationForeignDBNames []string JoinTableHandler JoinTableHandlerInterface } func getForeignField(column string, fields []*StructField) *StructField { for _, field := range fields { if field.Name == column || field.DBName == column || field.DBName == ToDBName(column) { return field } } return nil } // GetModelStruct get value's model struct, relationships based on struct and tag definition func (scope *Scope) GetModelStruct() *ModelStruct { var modelStruct ModelStruct // Scope value can't be nil if scope.Value == nil { return &modelStruct } reflectType := reflect.ValueOf(scope.Value).Type() for reflectType.Kind() == reflect.Slice || reflectType.Kind() == reflect.Ptr { reflectType = reflectType.Elem() } // Scope value need to be a struct if reflectType.Kind() != reflect.Struct { return &modelStruct } // Get Cached model struct if value := modelStructsMap.Get(reflectType); value != nil { return value } modelStruct.ModelType = reflectType // Get all fields for i := 0; i < reflectType.NumField(); i++ { if fieldStruct := reflectType.Field(i); ast.IsExported(fieldStruct.Name) { field := &StructField{ Struct: fieldStruct, Name: fieldStruct.Name, Names: []string{fieldStruct.Name}, Tag: fieldStruct.Tag, TagSettings: parseTagSetting(fieldStruct.Tag), } // is ignored field if _, ok := field.TagSettings["-"]; ok { field.IsIgnored = true } else { if _, ok := field.TagSettings["PRIMARY_KEY"]; ok { field.IsPrimaryKey = true modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, field) } if _, ok := field.TagSettings["DEFAULT"]; ok { field.HasDefaultValue = true } if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok && !field.IsPrimaryKey { field.HasDefaultValue = true } indirectType := fieldStruct.Type for indirectType.Kind() == reflect.Ptr { indirectType = indirectType.Elem() } fieldValue := reflect.New(indirectType).Interface() if _, isScanner := fieldValue.(sql.Scanner); isScanner { // is scanner field.IsScanner, field.IsNormal = true, true if indirectType.Kind() == reflect.Struct { for i := 0; i < indirectType.NumField(); i++ { for key, value := range parseTagSetting(indirectType.Field(i).Tag) { if _, ok := field.TagSettings[key]; !ok { field.TagSettings[key] = value } } } } } else if _, isTime := fieldValue.(*time.Time); isTime { // is time field.IsNormal = true } else if _, ok := field.TagSettings["EMBEDDED"]; ok || fieldStruct.Anonymous { // is embedded struct for _, subField := range scope.New(fieldValue).GetModelStruct().StructFields { subField = subField.clone() subField.Names = append([]string{fieldStruct.Name}, subField.Names...) if prefix, ok := field.TagSettings["EMBEDDED_PREFIX"]; ok { subField.DBName = prefix + subField.DBName } if subField.IsPrimaryKey { if _, ok := subField.TagSettings["PRIMARY_KEY"]; ok { modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, subField) } else { subField.IsPrimaryKey = false } } if subField.Relationship != nil && subField.Relationship.JoinTableHandler != nil { if joinTableHandler, ok := subField.Relationship.JoinTableHandler.(*JoinTableHandler); ok { newJoinTableHandler := &JoinTableHandler{} newJoinTableHandler.Setup(subField.Relationship, joinTableHandler.TableName, reflectType, joinTableHandler.Destination.ModelType) subField.Relationship.JoinTableHandler = newJoinTableHandler } } modelStruct.StructFields = append(modelStruct.StructFields, subField) } continue } else { // build relationships switch indirectType.Kind() { case reflect.Slice: defer func(field *StructField) { var ( relationship = &Relationship{} toScope = scope.New(reflect.New(field.Struct.Type).Interface()) foreignKeys []string associationForeignKeys []string elemType = field.Struct.Type ) if foreignKey := field.TagSettings["FOREIGNKEY"]; foreignKey != "" { foreignKeys = strings.Split(foreignKey, ",") } if foreignKey := field.TagSettings["ASSOCIATION_FOREIGNKEY"]; foreignKey != "" { associationForeignKeys = strings.Split(foreignKey, ",") } else if foreignKey := field.TagSettings["ASSOCIATIONFOREIGNKEY"]; foreignKey != "" { associationForeignKeys = strings.Split(foreignKey, ",") } for elemType.Kind() == reflect.Slice || elemType.Kind() == reflect.Ptr { elemType = elemType.Elem() } if elemType.Kind() == reflect.Struct { if many2many := field.TagSettings["MANY2MANY"]; many2many != "" { relationship.Kind = "many_to_many" { // Foreign Keys for Source joinTableDBNames := []string{} if foreignKey := field.TagSettings["JOINTABLE_FOREIGNKEY"]; foreignKey != "" { joinTableDBNames = strings.Split(foreignKey, ",") } // if no foreign keys defined with tag if len(foreignKeys) == 0 { for _, field := range modelStruct.PrimaryFields { foreignKeys = append(foreignKeys, field.DBName) } } for idx, foreignKey := range foreignKeys { if foreignField := getForeignField(foreignKey, modelStruct.StructFields); foreignField != nil { // source foreign keys (db names) relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.DBName) // setup join table foreign keys for source if len(joinTableDBNames) > idx { // if defined join table's foreign key relationship.ForeignDBNames = append(relationship.ForeignDBNames, joinTableDBNames[idx]) } else { defaultJointableForeignKey := ToDBName(reflectType.Name()) + "_" + foreignField.DBName relationship.ForeignDBNames = append(relationship.ForeignDBNames, defaultJointableForeignKey) } } } } { // Foreign Keys for Association (Destination) associationJoinTableDBNames := []string{} if foreignKey := field.TagSettings["ASSOCIATION_JOINTABLE_FOREIGNKEY"]; foreignKey != "" { associationJoinTableDBNames = strings.Split(foreignKey, ",") } // if no association foreign keys defined with tag if len(associationForeignKeys) == 0 { for _, field := range toScope.PrimaryFields() { associationForeignKeys = append(associationForeignKeys, field.DBName) } } for idx, name := range associationForeignKeys { if field, ok := toScope.FieldByName(name); ok { // association foreign keys (db names) relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, field.DBName) // setup join table foreign keys for association if len(associationJoinTableDBNames) > idx { relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, associationJoinTableDBNames[idx]) } else { // join table foreign keys for association joinTableDBName := ToDBName(elemType.Name()) + "_" + field.DBName relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, joinTableDBName) } } } } joinTableHandler := JoinTableHandler{} joinTableHandler.Setup(relationship, many2many, reflectType, elemType) relationship.JoinTableHandler = &joinTableHandler field.Relationship = relationship } else { // User has many comments, associationType is User, comment use UserID as foreign key var associationType = reflectType.Name() var toFields = toScope.GetStructFields() relationship.Kind = "has_many" if polymorphic := field.TagSettings["POLYMORPHIC"]; polymorphic != "" { // Dog has many toys, tag polymorphic is Owner, then associationType is Owner // Toy use OwnerID, OwnerType ('dogs') as foreign key if polymorphicType := getForeignField(polymorphic+"Type", toFields); polymorphicType != nil { associationType = polymorphic relationship.PolymorphicType = polymorphicType.Name relationship.PolymorphicDBName = polymorphicType.DBName // if Dog has multiple set of toys set name of the set (instead of default 'dogs') if value, ok := field.TagSettings["POLYMORPHIC_VALUE"]; ok { relationship.PolymorphicValue = value } else { relationship.PolymorphicValue = scope.TableName() } polymorphicType.IsForeignKey = true } } // if no foreign keys defined with tag if len(foreignKeys) == 0 { // if no association foreign keys defined with tag if len(associationForeignKeys) == 0 { for _, field := range modelStruct.PrimaryFields { foreignKeys = append(foreignKeys, associationType+field.Name) associationForeignKeys = append(associationForeignKeys, field.Name) } } else { // generate foreign keys from defined association foreign keys for _, scopeFieldName := range associationForeignKeys { if foreignField := getForeignField(scopeFieldName, modelStruct.StructFields); foreignField != nil { foreignKeys = append(foreignKeys, associationType+foreignField.Name) associationForeignKeys = append(associationForeignKeys, foreignField.Name) } } } } else { // generate association foreign keys from foreign keys if len(associationForeignKeys) == 0 { for _, foreignKey := range foreignKeys { if strings.HasPrefix(foreignKey, associationType) { associationForeignKey := strings.TrimPrefix(foreignKey, associationType) if foreignField := getForeignField(associationForeignKey, modelStruct.StructFields); foreignField != nil { associationForeignKeys = append(associationForeignKeys, associationForeignKey) } } } if len(associationForeignKeys) == 0 && len(foreignKeys) == 1 { associationForeignKeys = []string{scope.PrimaryKey()} } } else if len(foreignKeys) != len(associationForeignKeys) { scope.Err(errors.New("invalid foreign keys, should have same length")) return } } for idx, foreignKey := range foreignKeys { if foreignField := getForeignField(foreignKey, toFields); foreignField != nil { if associationField := getForeignField(associationForeignKeys[idx], modelStruct.StructFields); associationField != nil { // source foreign keys foreignField.IsForeignKey = true relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, associationField.Name) relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, associationField.DBName) // association foreign keys relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name) relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName) } } } if len(relationship.ForeignFieldNames) != 0 { field.Relationship = relationship } } } else { field.IsNormal = true } }(field) case reflect.Struct: defer func(field *StructField) { var ( // user has one profile, associationType is User, profile use UserID as foreign key // user belongs to profile, associationType is Profile, user use ProfileID as foreign key associationType = reflectType.Name() relationship = &Relationship{} toScope = scope.New(reflect.New(field.Struct.Type).Interface()) toFields = toScope.GetStructFields() tagForeignKeys []string tagAssociationForeignKeys []string ) if foreignKey := field.TagSettings["FOREIGNKEY"]; foreignKey != "" { tagForeignKeys = strings.Split(foreignKey, ",") } if foreignKey := field.TagSettings["ASSOCIATION_FOREIGNKEY"]; foreignKey != "" { tagAssociationForeignKeys = strings.Split(foreignKey, ",") } else if foreignKey := field.TagSettings["ASSOCIATIONFOREIGNKEY"]; foreignKey != "" { tagAssociationForeignKeys = strings.Split(foreignKey, ",") } if polymorphic := field.TagSettings["POLYMORPHIC"]; polymorphic != "" { // Cat has one toy, tag polymorphic is Owner, then associationType is Owner // Toy use OwnerID, OwnerType ('cats') as foreign key if polymorphicType := getForeignField(polymorphic+"Type", toFields); polymorphicType != nil { associationType = polymorphic relationship.PolymorphicType = polymorphicType.Name relationship.PolymorphicDBName = polymorphicType.DBName // if Cat has several different types of toys set name for each (instead of default 'cats') if value, ok := field.TagSettings["POLYMORPHIC_VALUE"]; ok { relationship.PolymorphicValue = value } else { relationship.PolymorphicValue = scope.TableName() } polymorphicType.IsForeignKey = true } } // Has One { var foreignKeys = tagForeignKeys var associationForeignKeys = tagAssociationForeignKeys // if no foreign keys defined with tag if len(foreignKeys) == 0 { // if no association foreign keys defined with tag if len(associationForeignKeys) == 0 { for _, primaryField := range modelStruct.PrimaryFields { foreignKeys = append(foreignKeys, associationType+primaryField.Name) associationForeignKeys = append(associationForeignKeys, primaryField.Name) } } else { // generate foreign keys form association foreign keys for _, associationForeignKey := range tagAssociationForeignKeys { if foreignField := getForeignField(associationForeignKey, modelStruct.StructFields); foreignField != nil { foreignKeys = append(foreignKeys, associationType+foreignField.Name) associationForeignKeys = append(associationForeignKeys, foreignField.Name) } } } } else { // generate association foreign keys from foreign keys if len(associationForeignKeys) == 0 { for _, foreignKey := range foreignKeys { if strings.HasPrefix(foreignKey, associationType) { associationForeignKey := strings.TrimPrefix(foreignKey, associationType) if foreignField := getForeignField(associationForeignKey, modelStruct.StructFields); foreignField != nil { associationForeignKeys = append(associationForeignKeys, associationForeignKey) } } } if len(associationForeignKeys) == 0 && len(foreignKeys) == 1 { associationForeignKeys = []string{scope.PrimaryKey()} } } else if len(foreignKeys) != len(associationForeignKeys) { scope.Err(errors.New("invalid foreign keys, should have same length")) return } } for idx, foreignKey := range foreignKeys { if foreignField := getForeignField(foreignKey, toFields); foreignField != nil { if scopeField := getForeignField(associationForeignKeys[idx], modelStruct.StructFields); scopeField != nil { foreignField.IsForeignKey = true // source foreign keys relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, scopeField.Name) relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, scopeField.DBName) // association foreign keys relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name) relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName) } } } } if len(relationship.ForeignFieldNames) != 0 { relationship.Kind = "has_one" field.Relationship = relationship } else { var foreignKeys = tagForeignKeys var associationForeignKeys = tagAssociationForeignKeys if len(foreignKeys) == 0 { // generate foreign keys & association foreign keys if len(associationForeignKeys) == 0 { for _, primaryField := range toScope.PrimaryFields() { foreignKeys = append(foreignKeys, field.Name+primaryField.Name) associationForeignKeys = append(associationForeignKeys, primaryField.Name) } } else { // generate foreign keys with association foreign keys for _, associationForeignKey := range associationForeignKeys { if foreignField := getForeignField(associationForeignKey, toFields); foreignField != nil { foreignKeys = append(foreignKeys, field.Name+foreignField.Name) associationForeignKeys = append(associationForeignKeys, foreignField.Name) } } } } else { // generate foreign keys & association foreign keys if len(associationForeignKeys) == 0 { for _, foreignKey := range foreignKeys { if strings.HasPrefix(foreignKey, field.Name) { associationForeignKey := strings.TrimPrefix(foreignKey, field.Name) if foreignField := getForeignField(associationForeignKey, toFields); foreignField != nil { associationForeignKeys = append(associationForeignKeys, associationForeignKey) } } } if len(associationForeignKeys) == 0 && len(foreignKeys) == 1 { associationForeignKeys = []string{toScope.PrimaryKey()} } } else if len(foreignKeys) != len(associationForeignKeys) { scope.Err(errors.New("invalid foreign keys, should have same length")) return } } for idx, foreignKey := range foreignKeys { if foreignField := getForeignField(foreignKey, modelStruct.StructFields); foreignField != nil { if associationField := getForeignField(associationForeignKeys[idx], toFields); associationField != nil { foreignField.IsForeignKey = true // association foreign keys relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, associationField.Name) relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, associationField.DBName) // source foreign keys relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name) relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName) } } } if len(relationship.ForeignFieldNames) != 0 { relationship.Kind = "belongs_to" field.Relationship = relationship } } }(field) default: field.IsNormal = true } } } // Even it is ignored, also possible to decode db value into the field if value, ok := field.TagSettings["COLUMN"]; ok { field.DBName = value } else { field.DBName = ToDBName(fieldStruct.Name) } modelStruct.StructFields = append(modelStruct.StructFields, field) } } if len(modelStruct.PrimaryFields) == 0 { if field := getForeignField("id", modelStruct.StructFields); field != nil { field.IsPrimaryKey = true modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, field) } } modelStructsMap.Set(reflectType, &modelStruct) return &modelStruct } // GetStructFields get model's field structs func (scope *Scope) GetStructFields() (fields []*StructField) { return scope.GetModelStruct().StructFields } func parseTagSetting(tags reflect.StructTag) map[string]string { setting := map[string]string{} for _, str := range []string{tags.Get("sql"), tags.Get("gorm")} { tags := strings.Split(str, ";") for _, value := range tags { v := strings.Split(value, ":") k := strings.TrimSpace(strings.ToUpper(v[0])) if len(v) >= 2 { setting[k] = strings.Join(v[1:], ":") } else { setting[k] = k } } } return setting } ================================================ FILE: vendor/github.com/jinzhu/gorm/scope.go ================================================ package gorm import ( "bytes" "database/sql" "database/sql/driver" "errors" "fmt" "reflect" "regexp" "strings" "time" ) // Scope contain current operation's information when you perform any operation on the database type Scope struct { Search *search Value interface{} SQL string SQLVars []interface{} db *DB instanceID string primaryKeyField *Field skipLeft bool fields *[]*Field selectAttrs *[]string } // IndirectValue return scope's reflect value's indirect value func (scope *Scope) IndirectValue() reflect.Value { return indirect(reflect.ValueOf(scope.Value)) } // New create a new Scope without search information func (scope *Scope) New(value interface{}) *Scope { return &Scope{db: scope.NewDB(), Search: &search{}, Value: value} } //////////////////////////////////////////////////////////////////////////////// // Scope DB //////////////////////////////////////////////////////////////////////////////// // DB return scope's DB connection func (scope *Scope) DB() *DB { return scope.db } // NewDB create a new DB without search information func (scope *Scope) NewDB() *DB { if scope.db != nil { db := scope.db.clone() db.search = nil db.Value = nil return db } return nil } // SQLDB return *sql.DB func (scope *Scope) SQLDB() SQLCommon { return scope.db.db } // Dialect get dialect func (scope *Scope) Dialect() Dialect { return scope.db.parent.dialect } // Quote used to quote string to escape them for database func (scope *Scope) Quote(str string) string { if strings.Index(str, ".") != -1 { newStrs := []string{} for _, str := range strings.Split(str, ".") { newStrs = append(newStrs, scope.Dialect().Quote(str)) } return strings.Join(newStrs, ".") } return scope.Dialect().Quote(str) } // Err add error to Scope func (scope *Scope) Err(err error) error { if err != nil { scope.db.AddError(err) } return err } // HasError check if there are any error func (scope *Scope) HasError() bool { return scope.db.Error != nil } // Log print log message func (scope *Scope) Log(v ...interface{}) { scope.db.log(v...) } // SkipLeft skip remaining callbacks func (scope *Scope) SkipLeft() { scope.skipLeft = true } // Fields get value's fields func (scope *Scope) Fields() []*Field { if scope.fields == nil { var ( fields []*Field indirectScopeValue = scope.IndirectValue() isStruct = indirectScopeValue.Kind() == reflect.Struct ) for _, structField := range scope.GetModelStruct().StructFields { if isStruct { fieldValue := indirectScopeValue for _, name := range structField.Names { if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() { fieldValue.Set(reflect.New(fieldValue.Type().Elem())) } fieldValue = reflect.Indirect(fieldValue).FieldByName(name) } fields = append(fields, &Field{StructField: structField, Field: fieldValue, IsBlank: isBlank(fieldValue)}) } else { fields = append(fields, &Field{StructField: structField, IsBlank: true}) } } scope.fields = &fields } return *scope.fields } // FieldByName find `gorm.Field` with field name or db name func (scope *Scope) FieldByName(name string) (field *Field, ok bool) { var ( dbName = ToDBName(name) mostMatchedField *Field ) for _, field := range scope.Fields() { if field.Name == name || field.DBName == name { return field, true } if field.DBName == dbName { mostMatchedField = field } } return mostMatchedField, mostMatchedField != nil } // PrimaryFields return scope's primary fields func (scope *Scope) PrimaryFields() (fields []*Field) { for _, field := range scope.Fields() { if field.IsPrimaryKey { fields = append(fields, field) } } return fields } // PrimaryField return scope's main primary field, if defined more that one primary fields, will return the one having column name `id` or the first one func (scope *Scope) PrimaryField() *Field { if primaryFields := scope.GetModelStruct().PrimaryFields; len(primaryFields) > 0 { if len(primaryFields) > 1 { if field, ok := scope.FieldByName("id"); ok { return field } } return scope.PrimaryFields()[0] } return nil } // PrimaryKey get main primary field's db name func (scope *Scope) PrimaryKey() string { if field := scope.PrimaryField(); field != nil { return field.DBName } return "" } // PrimaryKeyZero check main primary field's value is blank or not func (scope *Scope) PrimaryKeyZero() bool { field := scope.PrimaryField() return field == nil || field.IsBlank } // PrimaryKeyValue get the primary key's value func (scope *Scope) PrimaryKeyValue() interface{} { if field := scope.PrimaryField(); field != nil && field.Field.IsValid() { return field.Field.Interface() } return 0 } // HasColumn to check if has column func (scope *Scope) HasColumn(column string) bool { for _, field := range scope.GetStructFields() { if field.IsNormal && (field.Name == column || field.DBName == column) { return true } } return false } // SetColumn to set the column's value, column could be field or field's name/dbname func (scope *Scope) SetColumn(column interface{}, value interface{}) error { var updateAttrs = map[string]interface{}{} if attrs, ok := scope.InstanceGet("gorm:update_attrs"); ok { updateAttrs = attrs.(map[string]interface{}) defer scope.InstanceSet("gorm:update_attrs", updateAttrs) } if field, ok := column.(*Field); ok { updateAttrs[field.DBName] = value return field.Set(value) } else if name, ok := column.(string); ok { var ( dbName = ToDBName(name) mostMatchedField *Field ) for _, field := range scope.Fields() { if field.DBName == value { updateAttrs[field.DBName] = value return field.Set(value) } if (field.DBName == dbName) || (field.Name == name && mostMatchedField == nil) { mostMatchedField = field } } if mostMatchedField != nil { updateAttrs[mostMatchedField.DBName] = value return mostMatchedField.Set(value) } } return errors.New("could not convert column to field") } // CallMethod call scope value's method, if it is a slice, will call its element's method one by one func (scope *Scope) CallMethod(methodName string) { if scope.Value == nil { return } if indirectScopeValue := scope.IndirectValue(); indirectScopeValue.Kind() == reflect.Slice { for i := 0; i < indirectScopeValue.Len(); i++ { scope.callMethod(methodName, indirectScopeValue.Index(i)) } } else { scope.callMethod(methodName, indirectScopeValue) } } // AddToVars add value as sql's vars, used to prevent SQL injection func (scope *Scope) AddToVars(value interface{}) string { _, skipBindVar := scope.InstanceGet("skip_bindvar") if expr, ok := value.(*expr); ok { exp := expr.expr for _, arg := range expr.args { if skipBindVar { scope.AddToVars(arg) } else { exp = strings.Replace(exp, "?", scope.AddToVars(arg), 1) } } return exp } scope.SQLVars = append(scope.SQLVars, value) if skipBindVar { return "?" } return scope.Dialect().BindVar(len(scope.SQLVars)) } // SelectAttrs return selected attributes func (scope *Scope) SelectAttrs() []string { if scope.selectAttrs == nil { attrs := []string{} for _, value := range scope.Search.selects { if str, ok := value.(string); ok { attrs = append(attrs, str) } else if strs, ok := value.([]string); ok { attrs = append(attrs, strs...) } else if strs, ok := value.([]interface{}); ok { for _, str := range strs { attrs = append(attrs, fmt.Sprintf("%v", str)) } } } scope.selectAttrs = &attrs } return *scope.selectAttrs } // OmitAttrs return omitted attributes func (scope *Scope) OmitAttrs() []string { return scope.Search.omits } type tabler interface { TableName() string } type dbTabler interface { TableName(*DB) string } // TableName return table name func (scope *Scope) TableName() string { if scope.Search != nil && len(scope.Search.tableName) > 0 { return scope.Search.tableName } if tabler, ok := scope.Value.(tabler); ok { return tabler.TableName() } if tabler, ok := scope.Value.(dbTabler); ok { return tabler.TableName(scope.db) } return scope.GetModelStruct().TableName(scope.db.Model(scope.Value)) } // QuotedTableName return quoted table name func (scope *Scope) QuotedTableName() (name string) { if scope.Search != nil && len(scope.Search.tableName) > 0 { if strings.Index(scope.Search.tableName, " ") != -1 { return scope.Search.tableName } return scope.Quote(scope.Search.tableName) } return scope.Quote(scope.TableName()) } // CombinedConditionSql return combined condition sql func (scope *Scope) CombinedConditionSql() string { joinSQL := scope.joinsSQL() whereSQL := scope.whereSQL() if scope.Search.raw { whereSQL = strings.TrimSuffix(strings.TrimPrefix(whereSQL, "WHERE ("), ")") } return joinSQL + whereSQL + scope.groupSQL() + scope.havingSQL() + scope.orderSQL() + scope.limitAndOffsetSQL() } // Raw set raw sql func (scope *Scope) Raw(sql string) *Scope { scope.SQL = strings.Replace(sql, "$$$", "?", -1) return scope } // Exec perform generated SQL func (scope *Scope) Exec() *Scope { defer scope.trace(NowFunc()) if !scope.HasError() { if result, err := scope.SQLDB().Exec(scope.SQL, scope.SQLVars...); scope.Err(err) == nil { if count, err := result.RowsAffected(); scope.Err(err) == nil { scope.db.RowsAffected = count } } } return scope } // Set set value by name func (scope *Scope) Set(name string, value interface{}) *Scope { scope.db.InstantSet(name, value) return scope } // Get get setting by name func (scope *Scope) Get(name string) (interface{}, bool) { return scope.db.Get(name) } // InstanceID get InstanceID for scope func (scope *Scope) InstanceID() string { if scope.instanceID == "" { scope.instanceID = fmt.Sprintf("%v%v", &scope, &scope.db) } return scope.instanceID } // InstanceSet set instance setting for current operation, but not for operations in callbacks, like saving associations callback func (scope *Scope) InstanceSet(name string, value interface{}) *Scope { return scope.Set(name+scope.InstanceID(), value) } // InstanceGet get instance setting from current operation func (scope *Scope) InstanceGet(name string) (interface{}, bool) { return scope.Get(name + scope.InstanceID()) } // Begin start a transaction func (scope *Scope) Begin() *Scope { if db, ok := scope.SQLDB().(sqlDb); ok { if tx, err := db.Begin(); err == nil { scope.db.db = interface{}(tx).(SQLCommon) scope.InstanceSet("gorm:started_transaction", true) } } return scope } // CommitOrRollback commit current transaction if no error happened, otherwise will rollback it func (scope *Scope) CommitOrRollback() *Scope { if _, ok := scope.InstanceGet("gorm:started_transaction"); ok { if db, ok := scope.db.db.(sqlTx); ok { if scope.HasError() { db.Rollback() } else { scope.Err(db.Commit()) } scope.db.db = scope.db.parent.db } } return scope } //////////////////////////////////////////////////////////////////////////////// // Private Methods For *gorm.Scope //////////////////////////////////////////////////////////////////////////////// func (scope *Scope) callMethod(methodName string, reflectValue reflect.Value) { // Only get address from non-pointer if reflectValue.CanAddr() && reflectValue.Kind() != reflect.Ptr { reflectValue = reflectValue.Addr() } if methodValue := reflectValue.MethodByName(methodName); methodValue.IsValid() { switch method := methodValue.Interface().(type) { case func(): method() case func(*Scope): method(scope) case func(*DB): newDB := scope.NewDB() method(newDB) scope.Err(newDB.Error) case func() error: scope.Err(method()) case func(*Scope) error: scope.Err(method(scope)) case func(*DB) error: newDB := scope.NewDB() scope.Err(method(newDB)) scope.Err(newDB.Error) default: scope.Err(fmt.Errorf("unsupported function %v", methodName)) } } } var ( columnRegexp = regexp.MustCompile("^[a-zA-Z\\d]+(\\.[a-zA-Z\\d]+)*$") // only match string like `name`, `users.name` isNumberRegexp = regexp.MustCompile("^\\s*\\d+\\s*$") // match if string is number comparisonRegexp = regexp.MustCompile("(?i) (=|<>|(>|<)(=?)|LIKE|IS|IN) ") countingQueryRegexp = regexp.MustCompile("(?i)^count(.+)$") ) func (scope *Scope) quoteIfPossible(str string) string { if columnRegexp.MatchString(str) { return scope.Quote(str) } return str } func (scope *Scope) scan(rows *sql.Rows, columns []string, fields []*Field) { var ( ignored interface{} values = make([]interface{}, len(columns)) selectFields []*Field selectedColumnsMap = map[string]int{} resetFields = map[int]*Field{} ) for index, column := range columns { values[index] = &ignored selectFields = fields if idx, ok := selectedColumnsMap[column]; ok { selectFields = selectFields[idx+1:] } for fieldIndex, field := range selectFields { if field.DBName == column { if field.Field.Kind() == reflect.Ptr { values[index] = field.Field.Addr().Interface() } else { reflectValue := reflect.New(reflect.PtrTo(field.Struct.Type)) reflectValue.Elem().Set(field.Field.Addr()) values[index] = reflectValue.Interface() resetFields[index] = field } selectedColumnsMap[column] = fieldIndex if field.IsNormal { break } } } } scope.Err(rows.Scan(values...)) for index, field := range resetFields { if v := reflect.ValueOf(values[index]).Elem().Elem(); v.IsValid() { field.Field.Set(v) } } } func (scope *Scope) primaryCondition(value interface{}) string { return fmt.Sprintf("(%v.%v = %v)", scope.QuotedTableName(), scope.Quote(scope.PrimaryKey()), value) } func (scope *Scope) buildCondition(clause map[string]interface{}, include bool) (str string) { var ( quotedTableName = scope.QuotedTableName() quotedPrimaryKey = scope.Quote(scope.PrimaryKey()) equalSQL = "=" inSQL = "IN" ) // If building not conditions if !include { equalSQL = "<>" inSQL = "NOT IN" } switch value := clause["query"].(type) { case sql.NullInt64: return fmt.Sprintf("(%v.%v %s %v)", quotedTableName, quotedPrimaryKey, equalSQL, value.Int64) case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: return fmt.Sprintf("(%v.%v %s %v)", quotedTableName, quotedPrimaryKey, equalSQL, value) case []int, []int8, []int16, []int32, []int64, []uint, []uint8, []uint16, []uint32, []uint64, []string, []interface{}: if !include && reflect.ValueOf(value).Len() == 0 { return } str = fmt.Sprintf("(%v.%v %s (?))", quotedTableName, quotedPrimaryKey, inSQL) clause["args"] = []interface{}{value} case string: if isNumberRegexp.MatchString(value) { return fmt.Sprintf("(%v.%v %s %v)", quotedTableName, quotedPrimaryKey, equalSQL, scope.AddToVars(value)) } if value != "" { if !include { if comparisonRegexp.MatchString(value) { str = fmt.Sprintf("NOT (%v)", value) } else { str = fmt.Sprintf("(%v.%v NOT IN (?))", quotedTableName, scope.Quote(value)) } } else { str = fmt.Sprintf("(%v)", value) } } case map[string]interface{}: var sqls []string for key, value := range value { if value != nil { sqls = append(sqls, fmt.Sprintf("(%v.%v %s %v)", quotedTableName, scope.Quote(key), equalSQL, scope.AddToVars(value))) } else { if !include { sqls = append(sqls, fmt.Sprintf("(%v.%v IS NOT NULL)", quotedTableName, scope.Quote(key))) } else { sqls = append(sqls, fmt.Sprintf("(%v.%v IS NULL)", quotedTableName, scope.Quote(key))) } } } return strings.Join(sqls, " AND ") case interface{}: var sqls []string newScope := scope.New(value) if len(newScope.Fields()) == 0 { scope.Err(fmt.Errorf("invalid query condition: %v", value)) return } for _, field := range newScope.Fields() { if !field.IsIgnored && !field.IsBlank { sqls = append(sqls, fmt.Sprintf("(%v.%v %s %v)", quotedTableName, scope.Quote(field.DBName), equalSQL, scope.AddToVars(field.Field.Interface()))) } } return strings.Join(sqls, " AND ") default: scope.Err(fmt.Errorf("invalid query condition: %v", value)) return } replacements := []string{} args := clause["args"].([]interface{}) for _, arg := range args { var err error switch reflect.ValueOf(arg).Kind() { case reflect.Slice: // For where("id in (?)", []int64{1,2}) if scanner, ok := interface{}(arg).(driver.Valuer); ok { arg, err = scanner.Value() replacements = append(replacements, scope.AddToVars(arg)) } else if b, ok := arg.([]byte); ok { replacements = append(replacements, scope.AddToVars(b)) } else if as, ok := arg.([][]interface{}); ok { var tempMarks []string for _, a := range as { var arrayMarks []string for _, v := range a { arrayMarks = append(arrayMarks, scope.AddToVars(v)) } if len(arrayMarks) > 0 { tempMarks = append(tempMarks, fmt.Sprintf("(%v)", strings.Join(arrayMarks, ","))) } } if len(tempMarks) > 0 { replacements = append(replacements, strings.Join(tempMarks, ",")) } } else if values := reflect.ValueOf(arg); values.Len() > 0 { var tempMarks []string for i := 0; i < values.Len(); i++ { tempMarks = append(tempMarks, scope.AddToVars(values.Index(i).Interface())) } replacements = append(replacements, strings.Join(tempMarks, ",")) } else { replacements = append(replacements, scope.AddToVars(Expr("NULL"))) } default: if valuer, ok := interface{}(arg).(driver.Valuer); ok { arg, err = valuer.Value() } replacements = append(replacements, scope.AddToVars(arg)) } if err != nil { scope.Err(err) } } buff := bytes.NewBuffer([]byte{}) i := 0 for _, s := range str { if s == '?' { buff.WriteString(replacements[i]) i++ } else { buff.WriteRune(s) } } str = buff.String() return } func (scope *Scope) buildSelectQuery(clause map[string]interface{}) (str string) { switch value := clause["query"].(type) { case string: str = value case []string: str = strings.Join(value, ", ") } args := clause["args"].([]interface{}) replacements := []string{} for _, arg := range args { switch reflect.ValueOf(arg).Kind() { case reflect.Slice: values := reflect.ValueOf(arg) var tempMarks []string for i := 0; i < values.Len(); i++ { tempMarks = append(tempMarks, scope.AddToVars(values.Index(i).Interface())) } replacements = append(replacements, strings.Join(tempMarks, ",")) default: if valuer, ok := interface{}(arg).(driver.Valuer); ok { arg, _ = valuer.Value() } replacements = append(replacements, scope.AddToVars(arg)) } } buff := bytes.NewBuffer([]byte{}) i := 0 for pos := range str { if str[pos] == '?' { buff.WriteString(replacements[i]) i++ } else { buff.WriteByte(str[pos]) } } str = buff.String() return } func (scope *Scope) whereSQL() (sql string) { var ( quotedTableName = scope.QuotedTableName() deletedAtField, hasDeletedAtField = scope.FieldByName("DeletedAt") primaryConditions, andConditions, orConditions []string ) if !scope.Search.Unscoped && hasDeletedAtField { sql := fmt.Sprintf("%v.%v IS NULL", quotedTableName, scope.Quote(deletedAtField.DBName)) primaryConditions = append(primaryConditions, sql) } if !scope.PrimaryKeyZero() { for _, field := range scope.PrimaryFields() { sql := fmt.Sprintf("%v.%v = %v", quotedTableName, scope.Quote(field.DBName), scope.AddToVars(field.Field.Interface())) primaryConditions = append(primaryConditions, sql) } } for _, clause := range scope.Search.whereConditions { if sql := scope.buildCondition(clause, true); sql != "" { andConditions = append(andConditions, sql) } } for _, clause := range scope.Search.orConditions { if sql := scope.buildCondition(clause, true); sql != "" { orConditions = append(orConditions, sql) } } for _, clause := range scope.Search.notConditions { if sql := scope.buildCondition(clause, false); sql != "" { andConditions = append(andConditions, sql) } } orSQL := strings.Join(orConditions, " OR ") combinedSQL := strings.Join(andConditions, " AND ") if len(combinedSQL) > 0 { if len(orSQL) > 0 { combinedSQL = combinedSQL + " OR " + orSQL } } else { combinedSQL = orSQL } if len(primaryConditions) > 0 { sql = "WHERE " + strings.Join(primaryConditions, " AND ") if len(combinedSQL) > 0 { sql = sql + " AND (" + combinedSQL + ")" } } else if len(combinedSQL) > 0 { sql = "WHERE " + combinedSQL } return } func (scope *Scope) selectSQL() string { if len(scope.Search.selects) == 0 { if len(scope.Search.joinConditions) > 0 { return fmt.Sprintf("%v.*", scope.QuotedTableName()) } return "*" } return scope.buildSelectQuery(scope.Search.selects) } func (scope *Scope) orderSQL() string { if len(scope.Search.orders) == 0 || scope.Search.ignoreOrderQuery { return "" } var orders []string for _, order := range scope.Search.orders { if str, ok := order.(string); ok { orders = append(orders, scope.quoteIfPossible(str)) } else if expr, ok := order.(*expr); ok { exp := expr.expr for _, arg := range expr.args { exp = strings.Replace(exp, "?", scope.AddToVars(arg), 1) } orders = append(orders, exp) } } return " ORDER BY " + strings.Join(orders, ",") } func (scope *Scope) limitAndOffsetSQL() string { return scope.Dialect().LimitAndOffsetSQL(scope.Search.limit, scope.Search.offset) } func (scope *Scope) groupSQL() string { if len(scope.Search.group) == 0 { return "" } return " GROUP BY " + scope.Search.group } func (scope *Scope) havingSQL() string { if len(scope.Search.havingConditions) == 0 { return "" } var andConditions []string for _, clause := range scope.Search.havingConditions { if sql := scope.buildCondition(clause, true); sql != "" { andConditions = append(andConditions, sql) } } combinedSQL := strings.Join(andConditions, " AND ") if len(combinedSQL) == 0 { return "" } return " HAVING " + combinedSQL } func (scope *Scope) joinsSQL() string { var joinConditions []string for _, clause := range scope.Search.joinConditions { if sql := scope.buildCondition(clause, true); sql != "" { joinConditions = append(joinConditions, strings.TrimSuffix(strings.TrimPrefix(sql, "("), ")")) } } return strings.Join(joinConditions, " ") + " " } func (scope *Scope) prepareQuerySQL() { if scope.Search.raw { scope.Raw(scope.CombinedConditionSql()) } else { scope.Raw(fmt.Sprintf("SELECT %v FROM %v %v", scope.selectSQL(), scope.QuotedTableName(), scope.CombinedConditionSql())) } return } func (scope *Scope) inlineCondition(values ...interface{}) *Scope { if len(values) > 0 { scope.Search.Where(values[0], values[1:]...) } return scope } func (scope *Scope) callCallbacks(funcs []*func(s *Scope)) *Scope { for _, f := range funcs { (*f)(scope) if scope.skipLeft { break } } return scope } func convertInterfaceToMap(values interface{}, withIgnoredField bool) map[string]interface{} { var attrs = map[string]interface{}{} switch value := values.(type) { case map[string]interface{}: return value case []interface{}: for _, v := range value { for key, value := range convertInterfaceToMap(v, withIgnoredField) { attrs[key] = value } } case interface{}: reflectValue := reflect.ValueOf(values) switch reflectValue.Kind() { case reflect.Map: for _, key := range reflectValue.MapKeys() { attrs[ToDBName(key.Interface().(string))] = reflectValue.MapIndex(key).Interface() } default: for _, field := range (&Scope{Value: values}).Fields() { if !field.IsBlank && (withIgnoredField || !field.IsIgnored) { attrs[field.DBName] = field.Field.Interface() } } } } return attrs } func (scope *Scope) updatedAttrsWithValues(value interface{}) (results map[string]interface{}, hasUpdate bool) { if scope.IndirectValue().Kind() != reflect.Struct { return convertInterfaceToMap(value, false), true } results = map[string]interface{}{} for key, value := range convertInterfaceToMap(value, true) { if field, ok := scope.FieldByName(key); ok && scope.changeableField(field) { if _, ok := value.(*expr); ok { hasUpdate = true results[field.DBName] = value } else { err := field.Set(value) if field.IsNormal { hasUpdate = true if err == ErrUnaddressable { results[field.DBName] = value } else { results[field.DBName] = field.Field.Interface() } } } } } return } func (scope *Scope) row() *sql.Row { defer scope.trace(NowFunc()) result := &RowQueryResult{} scope.InstanceSet("row_query_result", result) scope.callCallbacks(scope.db.parent.callbacks.rowQueries) return result.Row } func (scope *Scope) rows() (*sql.Rows, error) { defer scope.trace(NowFunc()) result := &RowsQueryResult{} scope.InstanceSet("row_query_result", result) scope.callCallbacks(scope.db.parent.callbacks.rowQueries) return result.Rows, result.Error } func (scope *Scope) initialize() *Scope { for _, clause := range scope.Search.whereConditions { scope.updatedAttrsWithValues(clause["query"]) } scope.updatedAttrsWithValues(scope.Search.initAttrs) scope.updatedAttrsWithValues(scope.Search.assignAttrs) return scope } func (scope *Scope) isQueryForColumn(query interface{}, column string) bool { queryStr := strings.ToLower(fmt.Sprint(query)) if queryStr == column { return true } if strings.HasSuffix(queryStr, "as "+column) { return true } if strings.HasSuffix(queryStr, "as "+scope.Quote(column)) { return true } return false } func (scope *Scope) pluck(column string, value interface{}) *Scope { dest := reflect.Indirect(reflect.ValueOf(value)) if dest.Kind() != reflect.Slice { scope.Err(fmt.Errorf("results should be a slice, not %s", dest.Kind())) return scope } if query, ok := scope.Search.selects["query"]; !ok || !scope.isQueryForColumn(query, column) { scope.Search.Select(column) } rows, err := scope.rows() if scope.Err(err) == nil { defer rows.Close() for rows.Next() { elem := reflect.New(dest.Type().Elem()).Interface() scope.Err(rows.Scan(elem)) dest.Set(reflect.Append(dest, reflect.ValueOf(elem).Elem())) } if err := rows.Err(); err != nil { scope.Err(err) } } return scope } func (scope *Scope) count(value interface{}) *Scope { if query, ok := scope.Search.selects["query"]; !ok || !countingQueryRegexp.MatchString(fmt.Sprint(query)) { if len(scope.Search.group) != 0 { scope.Search.Select("count(*) FROM ( SELECT count(*) as name ") scope.Search.group += " ) AS count_table" } else { scope.Search.Select("count(*)") } } scope.Search.ignoreOrderQuery = true scope.Err(scope.row().Scan(value)) return scope } func (scope *Scope) typeName() string { typ := scope.IndirectValue().Type() for typ.Kind() == reflect.Slice || typ.Kind() == reflect.Ptr { typ = typ.Elem() } return typ.Name() } // trace print sql log func (scope *Scope) trace(t time.Time) { if len(scope.SQL) > 0 { scope.db.slog(scope.SQL, t, scope.SQLVars...) } } func (scope *Scope) changeableField(field *Field) bool { if selectAttrs := scope.SelectAttrs(); len(selectAttrs) > 0 { for _, attr := range selectAttrs { if field.Name == attr || field.DBName == attr { return true } } return false } for _, attr := range scope.OmitAttrs() { if field.Name == attr || field.DBName == attr { return false } } return true } func (scope *Scope) related(value interface{}, foreignKeys ...string) *Scope { toScope := scope.db.NewScope(value) tx := scope.db.Set("gorm:association:source", scope.Value) for _, foreignKey := range append(foreignKeys, toScope.typeName()+"Id", scope.typeName()+"Id") { fromField, _ := scope.FieldByName(foreignKey) toField, _ := toScope.FieldByName(foreignKey) if fromField != nil { if relationship := fromField.Relationship; relationship != nil { if relationship.Kind == "many_to_many" { joinTableHandler := relationship.JoinTableHandler scope.Err(joinTableHandler.JoinWith(joinTableHandler, tx, scope.Value).Find(value).Error) } else if relationship.Kind == "belongs_to" { for idx, foreignKey := range relationship.ForeignDBNames { if field, ok := scope.FieldByName(foreignKey); ok { tx = tx.Where(fmt.Sprintf("%v = ?", scope.Quote(relationship.AssociationForeignDBNames[idx])), field.Field.Interface()) } } scope.Err(tx.Find(value).Error) } else if relationship.Kind == "has_many" || relationship.Kind == "has_one" { for idx, foreignKey := range relationship.ForeignDBNames { if field, ok := scope.FieldByName(relationship.AssociationForeignDBNames[idx]); ok { tx = tx.Where(fmt.Sprintf("%v = ?", scope.Quote(foreignKey)), field.Field.Interface()) } } if relationship.PolymorphicType != "" { tx = tx.Where(fmt.Sprintf("%v = ?", scope.Quote(relationship.PolymorphicDBName)), relationship.PolymorphicValue) } scope.Err(tx.Find(value).Error) } } else { sql := fmt.Sprintf("%v = ?", scope.Quote(toScope.PrimaryKey())) scope.Err(tx.Where(sql, fromField.Field.Interface()).Find(value).Error) } return scope } else if toField != nil { sql := fmt.Sprintf("%v = ?", scope.Quote(toField.DBName)) scope.Err(tx.Where(sql, scope.PrimaryKeyValue()).Find(value).Error) return scope } } scope.Err(fmt.Errorf("invalid association %v", foreignKeys)) return scope } // getTableOptions return the table options string or an empty string if the table options does not exist func (scope *Scope) getTableOptions() string { tableOptions, ok := scope.Get("gorm:table_options") if !ok { return "" } return " " + tableOptions.(string) } func (scope *Scope) createJoinTable(field *StructField) { if relationship := field.Relationship; relationship != nil && relationship.JoinTableHandler != nil { joinTableHandler := relationship.JoinTableHandler joinTable := joinTableHandler.Table(scope.db) if !scope.Dialect().HasTable(joinTable) { toScope := &Scope{Value: reflect.New(field.Struct.Type).Interface()} var sqlTypes, primaryKeys []string for idx, fieldName := range relationship.ForeignFieldNames { if field, ok := scope.FieldByName(fieldName); ok { foreignKeyStruct := field.clone() foreignKeyStruct.IsPrimaryKey = false foreignKeyStruct.TagSettings["IS_JOINTABLE_FOREIGNKEY"] = "true" delete(foreignKeyStruct.TagSettings, "AUTO_INCREMENT") sqlTypes = append(sqlTypes, scope.Quote(relationship.ForeignDBNames[idx])+" "+scope.Dialect().DataTypeOf(foreignKeyStruct)) primaryKeys = append(primaryKeys, scope.Quote(relationship.ForeignDBNames[idx])) } } for idx, fieldName := range relationship.AssociationForeignFieldNames { if field, ok := toScope.FieldByName(fieldName); ok { foreignKeyStruct := field.clone() foreignKeyStruct.IsPrimaryKey = false foreignKeyStruct.TagSettings["IS_JOINTABLE_FOREIGNKEY"] = "true" delete(foreignKeyStruct.TagSettings, "AUTO_INCREMENT") sqlTypes = append(sqlTypes, scope.Quote(relationship.AssociationForeignDBNames[idx])+" "+scope.Dialect().DataTypeOf(foreignKeyStruct)) primaryKeys = append(primaryKeys, scope.Quote(relationship.AssociationForeignDBNames[idx])) } } scope.Err(scope.NewDB().Exec(fmt.Sprintf("CREATE TABLE %v (%v, PRIMARY KEY (%v))%s", scope.Quote(joinTable), strings.Join(sqlTypes, ","), strings.Join(primaryKeys, ","), scope.getTableOptions())).Error) } scope.NewDB().Table(joinTable).AutoMigrate(joinTableHandler) } } func (scope *Scope) createTable() *Scope { var tags []string var primaryKeys []string var primaryKeyInColumnType = false for _, field := range scope.GetModelStruct().StructFields { if field.IsNormal { sqlTag := scope.Dialect().DataTypeOf(field) // Check if the primary key constraint was specified as // part of the column type. If so, we can only support // one column as the primary key. if strings.Contains(strings.ToLower(sqlTag), "primary key") { primaryKeyInColumnType = true } tags = append(tags, scope.Quote(field.DBName)+" "+sqlTag) } if field.IsPrimaryKey { primaryKeys = append(primaryKeys, scope.Quote(field.DBName)) } scope.createJoinTable(field) } var primaryKeyStr string if len(primaryKeys) > 0 && !primaryKeyInColumnType { primaryKeyStr = fmt.Sprintf(", PRIMARY KEY (%v)", strings.Join(primaryKeys, ",")) } scope.Raw(fmt.Sprintf("CREATE TABLE %v (%v %v)%s", scope.QuotedTableName(), strings.Join(tags, ","), primaryKeyStr, scope.getTableOptions())).Exec() scope.autoIndex() return scope } func (scope *Scope) dropTable() *Scope { scope.Raw(fmt.Sprintf("DROP TABLE %v%s", scope.QuotedTableName(), scope.getTableOptions())).Exec() return scope } func (scope *Scope) modifyColumn(column string, typ string) { scope.db.AddError(scope.Dialect().ModifyColumn(scope.QuotedTableName(), scope.Quote(column), typ)) } func (scope *Scope) dropColumn(column string) { scope.Raw(fmt.Sprintf("ALTER TABLE %v DROP COLUMN %v", scope.QuotedTableName(), scope.Quote(column))).Exec() } func (scope *Scope) addIndex(unique bool, indexName string, column ...string) { if scope.Dialect().HasIndex(scope.TableName(), indexName) { return } var columns []string for _, name := range column { columns = append(columns, scope.quoteIfPossible(name)) } sqlCreate := "CREATE INDEX" if unique { sqlCreate = "CREATE UNIQUE INDEX" } scope.Raw(fmt.Sprintf("%s %v ON %v(%v) %v", sqlCreate, indexName, scope.QuotedTableName(), strings.Join(columns, ", "), scope.whereSQL())).Exec() } func (scope *Scope) addForeignKey(field string, dest string, onDelete string, onUpdate string) { // Compatible with old generated key keyName := scope.Dialect().BuildKeyName(scope.TableName(), field, dest, "foreign") if scope.Dialect().HasForeignKey(scope.TableName(), keyName) { return } var query = `ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s ON DELETE %s ON UPDATE %s;` scope.Raw(fmt.Sprintf(query, scope.QuotedTableName(), scope.quoteIfPossible(keyName), scope.quoteIfPossible(field), dest, onDelete, onUpdate)).Exec() } func (scope *Scope) removeForeignKey(field string, dest string) { keyName := scope.Dialect().BuildKeyName(scope.TableName(), field, dest) if !scope.Dialect().HasForeignKey(scope.TableName(), keyName) { return } var query = `ALTER TABLE %s DROP CONSTRAINT %s;` scope.Raw(fmt.Sprintf(query, scope.QuotedTableName(), scope.quoteIfPossible(keyName))).Exec() } func (scope *Scope) removeIndex(indexName string) { scope.Dialect().RemoveIndex(scope.TableName(), indexName) } func (scope *Scope) autoMigrate() *Scope { tableName := scope.TableName() quotedTableName := scope.QuotedTableName() if !scope.Dialect().HasTable(tableName) { scope.createTable() } else { for _, field := range scope.GetModelStruct().StructFields { if !scope.Dialect().HasColumn(tableName, field.DBName) { if field.IsNormal { sqlTag := scope.Dialect().DataTypeOf(field) scope.Raw(fmt.Sprintf("ALTER TABLE %v ADD %v %v;", quotedTableName, scope.Quote(field.DBName), sqlTag)).Exec() } } scope.createJoinTable(field) } scope.autoIndex() } return scope } func (scope *Scope) autoIndex() *Scope { var indexes = map[string][]string{} var uniqueIndexes = map[string][]string{} for _, field := range scope.GetStructFields() { if name, ok := field.TagSettings["INDEX"]; ok { names := strings.Split(name, ",") for _, name := range names { if name == "INDEX" || name == "" { name = scope.Dialect().BuildKeyName("idx", scope.TableName(), field.DBName) } indexes[name] = append(indexes[name], field.DBName) } } if name, ok := field.TagSettings["UNIQUE_INDEX"]; ok { names := strings.Split(name, ",") for _, name := range names { if name == "UNIQUE_INDEX" || name == "" { name = scope.Dialect().BuildKeyName("uix", scope.TableName(), field.DBName) } uniqueIndexes[name] = append(uniqueIndexes[name], field.DBName) } } } for name, columns := range indexes { if db := scope.NewDB().Table(scope.TableName()).Model(scope.Value).AddIndex(name, columns...); db.Error != nil { scope.db.AddError(db.Error) } } for name, columns := range uniqueIndexes { if db := scope.NewDB().Table(scope.TableName()).Model(scope.Value).AddUniqueIndex(name, columns...); db.Error != nil { scope.db.AddError(db.Error) } } return scope } func (scope *Scope) getColumnAsArray(columns []string, values ...interface{}) (results [][]interface{}) { for _, value := range values { indirectValue := indirect(reflect.ValueOf(value)) switch indirectValue.Kind() { case reflect.Slice: for i := 0; i < indirectValue.Len(); i++ { var result []interface{} var object = indirect(indirectValue.Index(i)) var hasValue = false for _, column := range columns { field := object.FieldByName(column) if hasValue || !isBlank(field) { hasValue = true } result = append(result, field.Interface()) } if hasValue { results = append(results, result) } } case reflect.Struct: var result []interface{} var hasValue = false for _, column := range columns { field := indirectValue.FieldByName(column) if hasValue || !isBlank(field) { hasValue = true } result = append(result, field.Interface()) } if hasValue { results = append(results, result) } } } return } func (scope *Scope) getColumnAsScope(column string) *Scope { indirectScopeValue := scope.IndirectValue() switch indirectScopeValue.Kind() { case reflect.Slice: if fieldStruct, ok := scope.GetModelStruct().ModelType.FieldByName(column); ok { fieldType := fieldStruct.Type if fieldType.Kind() == reflect.Slice || fieldType.Kind() == reflect.Ptr { fieldType = fieldType.Elem() } resultsMap := map[interface{}]bool{} results := reflect.New(reflect.SliceOf(reflect.PtrTo(fieldType))).Elem() for i := 0; i < indirectScopeValue.Len(); i++ { result := indirect(indirect(indirectScopeValue.Index(i)).FieldByName(column)) if result.Kind() == reflect.Slice { for j := 0; j < result.Len(); j++ { if elem := result.Index(j); elem.CanAddr() && resultsMap[elem.Addr()] != true { resultsMap[elem.Addr()] = true results = reflect.Append(results, elem.Addr()) } } } else if result.CanAddr() && resultsMap[result.Addr()] != true { resultsMap[result.Addr()] = true results = reflect.Append(results, result.Addr()) } } return scope.New(results.Interface()) } case reflect.Struct: if field := indirectScopeValue.FieldByName(column); field.CanAddr() { return scope.New(field.Addr().Interface()) } } return nil } func (scope *Scope) hasConditions() bool { return !scope.PrimaryKeyZero() || len(scope.Search.whereConditions) > 0 || len(scope.Search.orConditions) > 0 || len(scope.Search.notConditions) > 0 } ================================================ FILE: vendor/github.com/jinzhu/gorm/search.go ================================================ package gorm import ( "fmt" ) type search struct { db *DB whereConditions []map[string]interface{} orConditions []map[string]interface{} notConditions []map[string]interface{} havingConditions []map[string]interface{} joinConditions []map[string]interface{} initAttrs []interface{} assignAttrs []interface{} selects map[string]interface{} omits []string orders []interface{} preload []searchPreload offset interface{} limit interface{} group string tableName string raw bool Unscoped bool ignoreOrderQuery bool } type searchPreload struct { schema string conditions []interface{} } func (s *search) clone() *search { clone := *s return &clone } func (s *search) Where(query interface{}, values ...interface{}) *search { s.whereConditions = append(s.whereConditions, map[string]interface{}{"query": query, "args": values}) return s } func (s *search) Not(query interface{}, values ...interface{}) *search { s.notConditions = append(s.notConditions, map[string]interface{}{"query": query, "args": values}) return s } func (s *search) Or(query interface{}, values ...interface{}) *search { s.orConditions = append(s.orConditions, map[string]interface{}{"query": query, "args": values}) return s } func (s *search) Attrs(attrs ...interface{}) *search { s.initAttrs = append(s.initAttrs, toSearchableMap(attrs...)) return s } func (s *search) Assign(attrs ...interface{}) *search { s.assignAttrs = append(s.assignAttrs, toSearchableMap(attrs...)) return s } func (s *search) Order(value interface{}, reorder ...bool) *search { if len(reorder) > 0 && reorder[0] { s.orders = []interface{}{} } if value != nil && value != "" { s.orders = append(s.orders, value) } return s } func (s *search) Select(query interface{}, args ...interface{}) *search { s.selects = map[string]interface{}{"query": query, "args": args} return s } func (s *search) Omit(columns ...string) *search { s.omits = columns return s } func (s *search) Limit(limit interface{}) *search { s.limit = limit return s } func (s *search) Offset(offset interface{}) *search { s.offset = offset return s } func (s *search) Group(query string) *search { s.group = s.getInterfaceAsSQL(query) return s } func (s *search) Having(query interface{}, values ...interface{}) *search { if val, ok := query.(*expr); ok { s.havingConditions = append(s.havingConditions, map[string]interface{}{"query": val.expr, "args": val.args}) } else { s.havingConditions = append(s.havingConditions, map[string]interface{}{"query": query, "args": values}) } return s } func (s *search) Joins(query string, values ...interface{}) *search { s.joinConditions = append(s.joinConditions, map[string]interface{}{"query": query, "args": values}) return s } func (s *search) Preload(schema string, values ...interface{}) *search { var preloads []searchPreload for _, preload := range s.preload { if preload.schema != schema { preloads = append(preloads, preload) } } preloads = append(preloads, searchPreload{schema, values}) s.preload = preloads return s } func (s *search) Raw(b bool) *search { s.raw = b return s } func (s *search) unscoped() *search { s.Unscoped = true return s } func (s *search) Table(name string) *search { s.tableName = name return s } func (s *search) getInterfaceAsSQL(value interface{}) (str string) { switch value.(type) { case string, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: str = fmt.Sprintf("%v", value) default: s.db.AddError(ErrInvalidSQL) } if str == "-1" { return "" } return } ================================================ FILE: vendor/github.com/jinzhu/gorm/test_all.sh ================================================ dialects=("postgres" "mysql" "mssql" "sqlite") for dialect in "${dialects[@]}" ; do DEBUG=false GORM_DIALECT=${dialect} go test done ================================================ FILE: vendor/github.com/jinzhu/gorm/utils.go ================================================ package gorm import ( "bytes" "database/sql/driver" "fmt" "reflect" "regexp" "runtime" "strings" "sync" "time" ) // NowFunc returns current time, this function is exported in order to be able // to give the flexibility to the developer to customize it according to their // needs, e.g: // gorm.NowFunc = func() time.Time { // return time.Now().UTC() // } var NowFunc = func() time.Time { return time.Now() } // Copied from golint var commonInitialisms = []string{"API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "LHS", "QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SSH", "TLS", "TTL", "UID", "UI", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XSRF", "XSS"} var commonInitialismsReplacer *strings.Replacer var goSrcRegexp = regexp.MustCompile(`jinzhu/gorm/.*.go`) var goTestRegexp = regexp.MustCompile(`jinzhu/gorm/.*test.go`) func init() { var commonInitialismsForReplacer []string for _, initialism := range commonInitialisms { commonInitialismsForReplacer = append(commonInitialismsForReplacer, initialism, strings.Title(strings.ToLower(initialism))) } commonInitialismsReplacer = strings.NewReplacer(commonInitialismsForReplacer...) } type safeMap struct { m map[string]string l *sync.RWMutex } func (s *safeMap) Set(key string, value string) { s.l.Lock() defer s.l.Unlock() s.m[key] = value } func (s *safeMap) Get(key string) string { s.l.RLock() defer s.l.RUnlock() return s.m[key] } func newSafeMap() *safeMap { return &safeMap{l: new(sync.RWMutex), m: make(map[string]string)} } var smap = newSafeMap() type strCase bool const ( lower strCase = false upper strCase = true ) // ToDBName convert string to db name func ToDBName(name string) string { if v := smap.Get(name); v != "" { return v } if name == "" { return "" } var ( value = commonInitialismsReplacer.Replace(name) buf = bytes.NewBufferString("") lastCase, currCase, nextCase strCase ) for i, v := range value[:len(value)-1] { nextCase = strCase(value[i+1] >= 'A' && value[i+1] <= 'Z') if i > 0 { if currCase == upper { if lastCase == upper && nextCase == upper { buf.WriteRune(v) } else { if value[i-1] != '_' && value[i+1] != '_' { buf.WriteRune('_') } buf.WriteRune(v) } } else { buf.WriteRune(v) if i == len(value)-2 && nextCase == upper { buf.WriteRune('_') } } } else { currCase = upper buf.WriteRune(v) } lastCase = currCase currCase = nextCase } buf.WriteByte(value[len(value)-1]) s := strings.ToLower(buf.String()) smap.Set(name, s) return s } // SQL expression type expr struct { expr string args []interface{} } // Expr generate raw SQL expression, for example: // DB.Model(&product).Update("price", gorm.Expr("price * ? + ?", 2, 100)) func Expr(expression string, args ...interface{}) *expr { return &expr{expr: expression, args: args} } func indirect(reflectValue reflect.Value) reflect.Value { for reflectValue.Kind() == reflect.Ptr { reflectValue = reflectValue.Elem() } return reflectValue } func toQueryMarks(primaryValues [][]interface{}) string { var results []string for _, primaryValue := range primaryValues { var marks []string for range primaryValue { marks = append(marks, "?") } if len(marks) > 1 { results = append(results, fmt.Sprintf("(%v)", strings.Join(marks, ","))) } else { results = append(results, strings.Join(marks, "")) } } return strings.Join(results, ",") } func toQueryCondition(scope *Scope, columns []string) string { var newColumns []string for _, column := range columns { newColumns = append(newColumns, scope.Quote(column)) } if len(columns) > 1 { return fmt.Sprintf("(%v)", strings.Join(newColumns, ",")) } return strings.Join(newColumns, ",") } func toQueryValues(values [][]interface{}) (results []interface{}) { for _, value := range values { for _, v := range value { results = append(results, v) } } return } func fileWithLineNum() string { for i := 2; i < 15; i++ { _, file, line, ok := runtime.Caller(i) if ok && (!goSrcRegexp.MatchString(file) || goTestRegexp.MatchString(file)) { return fmt.Sprintf("%v:%v", file, line) } } return "" } func isBlank(value reflect.Value) bool { switch value.Kind() { case reflect.String: return value.Len() == 0 case reflect.Bool: return !value.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return value.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return value.Uint() == 0 case reflect.Float32, reflect.Float64: return value.Float() == 0 case reflect.Interface, reflect.Ptr: return value.IsNil() } return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface()) } func toSearchableMap(attrs ...interface{}) (result interface{}) { if len(attrs) > 1 { if str, ok := attrs[0].(string); ok { result = map[string]interface{}{str: attrs[1]} } } else if len(attrs) == 1 { if attr, ok := attrs[0].(map[string]interface{}); ok { result = attr } if attr, ok := attrs[0].(interface{}); ok { result = attr } } return } func equalAsString(a interface{}, b interface{}) bool { return toString(a) == toString(b) } func toString(str interface{}) string { if values, ok := str.([]interface{}); ok { var results []string for _, value := range values { results = append(results, toString(value)) } return strings.Join(results, "_") } else if bytes, ok := str.([]byte); ok { return string(bytes) } else if reflectValue := reflect.Indirect(reflect.ValueOf(str)); reflectValue.IsValid() { return fmt.Sprintf("%v", reflectValue.Interface()) } return "" } func makeSlice(elemType reflect.Type) interface{} { if elemType.Kind() == reflect.Slice { elemType = elemType.Elem() } sliceType := reflect.SliceOf(elemType) slice := reflect.New(sliceType) slice.Elem().Set(reflect.MakeSlice(sliceType, 0, 0)) return slice.Interface() } func strInSlice(a string, list []string) bool { for _, b := range list { if b == a { return true } } return false } // getValueFromFields return given fields's value func getValueFromFields(value reflect.Value, fieldNames []string) (results []interface{}) { // If value is a nil pointer, Indirect returns a zero Value! // Therefor we need to check for a zero value, // as FieldByName could panic if indirectValue := reflect.Indirect(value); indirectValue.IsValid() { for _, fieldName := range fieldNames { if fieldValue := indirectValue.FieldByName(fieldName); fieldValue.IsValid() { result := fieldValue.Interface() if r, ok := result.(driver.Valuer); ok { result, _ = r.Value() } results = append(results, result) } } } return } func addExtraSpaceIfExist(str string) string { if str != "" { return " " + str } return "" } ================================================ FILE: vendor/github.com/jinzhu/gorm/wercker.yml ================================================ # use the default golang container from Docker Hub box: golang services: - name: mariadb id: mariadb:latest env: MYSQL_DATABASE: gorm MYSQL_USER: gorm MYSQL_PASSWORD: gorm MYSQL_RANDOM_ROOT_PASSWORD: "yes" - name: mysql id: mysql:8 env: MYSQL_DATABASE: gorm MYSQL_USER: gorm MYSQL_PASSWORD: gorm MYSQL_RANDOM_ROOT_PASSWORD: "yes" - name: mysql57 id: mysql:5.7 env: MYSQL_DATABASE: gorm MYSQL_USER: gorm MYSQL_PASSWORD: gorm MYSQL_RANDOM_ROOT_PASSWORD: "yes" - name: mysql56 id: mysql:5.6 env: MYSQL_DATABASE: gorm MYSQL_USER: gorm MYSQL_PASSWORD: gorm MYSQL_RANDOM_ROOT_PASSWORD: "yes" - name: mysql55 id: mysql:5.5 env: MYSQL_DATABASE: gorm MYSQL_USER: gorm MYSQL_PASSWORD: gorm MYSQL_RANDOM_ROOT_PASSWORD: "yes" - name: postgres id: postgres:latest env: POSTGRES_USER: gorm POSTGRES_PASSWORD: gorm POSTGRES_DB: gorm - name: postgres96 id: postgres:9.6 env: POSTGRES_USER: gorm POSTGRES_PASSWORD: gorm POSTGRES_DB: gorm - name: postgres95 id: postgres:9.5 env: POSTGRES_USER: gorm POSTGRES_PASSWORD: gorm POSTGRES_DB: gorm - name: postgres94 id: postgres:9.4 env: POSTGRES_USER: gorm POSTGRES_PASSWORD: gorm POSTGRES_DB: gorm - name: postgres93 id: postgres:9.3 env: POSTGRES_USER: gorm POSTGRES_PASSWORD: gorm POSTGRES_DB: gorm - name: mssql id: mcmoe/mssqldocker:latest env: ACCEPT_EULA: Y SA_PASSWORD: LoremIpsum86 MSSQL_DB: gorm MSSQL_USER: gorm MSSQL_PASSWORD: LoremIpsum86 # The steps that will be executed in the build pipeline build: # The steps that will be executed on build steps: # Sets the go workspace and places you package # at the right place in the workspace tree - setup-go-workspace # Gets the dependencies - script: name: go get code: | cd $WERCKER_SOURCE_DIR go version go get -t ./... # Build the project - script: name: go build code: | go build ./... # Test the project - script: name: test sqlite code: | go test ./... - script: name: test mariadb code: | GORM_DIALECT=mysql GORM_DSN="gorm:gorm@tcp(mariadb:3306)/gorm?charset=utf8&parseTime=True" go test ./... - script: name: test mysql code: | GORM_DIALECT=mysql GORM_DSN="gorm:gorm@tcp(mysql:3306)/gorm?charset=utf8&parseTime=True" go test ./... - script: name: test mysql5.7 code: | GORM_DIALECT=mysql GORM_DSN="gorm:gorm@tcp(mysql57:3306)/gorm?charset=utf8&parseTime=True" go test ./... - script: name: test mysql5.6 code: | GORM_DIALECT=mysql GORM_DSN="gorm:gorm@tcp(mysql56:3306)/gorm?charset=utf8&parseTime=True" go test ./... - script: name: test mysql5.5 code: | GORM_DIALECT=mysql GORM_DSN="gorm:gorm@tcp(mysql55:3306)/gorm?charset=utf8&parseTime=True" go test ./... - script: name: test postgres code: | GORM_DIALECT=postgres GORM_DSN="host=postgres user=gorm password=gorm DB.name=gorm port=5432 sslmode=disable" go test ./... - script: name: test postgres96 code: | GORM_DIALECT=postgres GORM_DSN="host=postgres96 user=gorm password=gorm DB.name=gorm port=5432 sslmode=disable" go test ./... - script: name: test postgres95 code: | GORM_DIALECT=postgres GORM_DSN="host=postgres95 user=gorm password=gorm DB.name=gorm port=5432 sslmode=disable" go test ./... - script: name: test postgres94 code: | GORM_DIALECT=postgres GORM_DSN="host=postgres94 user=gorm password=gorm DB.name=gorm port=5432 sslmode=disable" go test ./... - script: name: test postgres93 code: | GORM_DIALECT=postgres GORM_DSN="host=postgres93 user=gorm password=gorm DB.name=gorm port=5432 sslmode=disable" go test ./... - script: name: test mssql code: | GORM_DIALECT=mssql GORM_DSN="sqlserver://gorm:LoremIpsum86@mssql:1433?database=gorm" go test ./... ================================================ FILE: vendor/github.com/jinzhu/inflection/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 - Jinzhu 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. ================================================ FILE: vendor/github.com/jinzhu/inflection/README.md ================================================ Inflection ========= Inflection pluralizes and singularizes English nouns ## Basic Usage ```go inflection.Plural("person") => "people" inflection.Plural("Person") => "People" inflection.Plural("PERSON") => "PEOPLE" inflection.Plural("bus") => "buses" inflection.Plural("BUS") => "BUSES" inflection.Plural("Bus") => "Buses" inflection.Singular("people") => "person" inflection.Singular("People") => "Person" inflection.Singular("PEOPLE") => "PERSON" inflection.Singular("buses") => "bus" inflection.Singular("BUSES") => "BUS" inflection.Singular("Buses") => "Bus" inflection.Plural("FancyPerson") => "FancyPeople" inflection.Singular("FancyPeople") => "FancyPerson" ``` ## Register Rules Standard rules are from Rails's ActiveSupport (https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflections.rb) If you want to register more rules, follow: ``` inflection.AddUncountable("fish") inflection.AddIrregular("person", "people") inflection.AddPlural("(bu)s$", "${1}ses") # "bus" => "buses" / "BUS" => "BUSES" / "Bus" => "Buses" inflection.AddSingular("(bus)(es)?$", "${1}") # "buses" => "bus" / "Buses" => "Bus" / "BUSES" => "BUS" ``` ## Supporting the project [![http://patreon.com/jinzhu](http://patreon_public_assets.s3.amazonaws.com/sized/becomeAPatronBanner.png)](http://patreon.com/jinzhu) ## Author **jinzhu** * * * ## License Released under the [MIT License](http://www.opensource.org/licenses/MIT). ================================================ FILE: vendor/github.com/jinzhu/inflection/inflections.go ================================================ /* Package inflection pluralizes and singularizes English nouns. inflection.Plural("person") => "people" inflection.Plural("Person") => "People" inflection.Plural("PERSON") => "PEOPLE" inflection.Singular("people") => "person" inflection.Singular("People") => "Person" inflection.Singular("PEOPLE") => "PERSON" inflection.Plural("FancyPerson") => "FancydPeople" inflection.Singular("FancyPeople") => "FancydPerson" Standard rules are from Rails's ActiveSupport (https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflections.rb) If you want to register more rules, follow: inflection.AddUncountable("fish") inflection.AddIrregular("person", "people") inflection.AddPlural("(bu)s$", "${1}ses") # "bus" => "buses" / "BUS" => "BUSES" / "Bus" => "Buses" inflection.AddSingular("(bus)(es)?$", "${1}") # "buses" => "bus" / "Buses" => "Bus" / "BUSES" => "BUS" */ package inflection import ( "regexp" "strings" ) type inflection struct { regexp *regexp.Regexp replace string } // Regular is a regexp find replace inflection type Regular struct { find string replace string } // Irregular is a hard replace inflection, // containing both singular and plural forms type Irregular struct { singular string plural string } // RegularSlice is a slice of Regular inflections type RegularSlice []Regular // IrregularSlice is a slice of Irregular inflections type IrregularSlice []Irregular var pluralInflections = RegularSlice{ {"([a-z])$", "${1}s"}, {"s$", "s"}, {"^(ax|test)is$", "${1}es"}, {"(octop|vir)us$", "${1}i"}, {"(octop|vir)i$", "${1}i"}, {"(alias|status)$", "${1}es"}, {"(bu)s$", "${1}ses"}, {"(buffal|tomat)o$", "${1}oes"}, {"([ti])um$", "${1}a"}, {"([ti])a$", "${1}a"}, {"sis$", "ses"}, {"(?:([^f])fe|([lr])f)$", "${1}${2}ves"}, {"(hive)$", "${1}s"}, {"([^aeiouy]|qu)y$", "${1}ies"}, {"(x|ch|ss|sh)$", "${1}es"}, {"(matr|vert|ind)(?:ix|ex)$", "${1}ices"}, {"^(m|l)ouse$", "${1}ice"}, {"^(m|l)ice$", "${1}ice"}, {"^(ox)$", "${1}en"}, {"^(oxen)$", "${1}"}, {"(quiz)$", "${1}zes"}, } var singularInflections = RegularSlice{ {"s$", ""}, {"(ss)$", "${1}"}, {"(n)ews$", "${1}ews"}, {"([ti])a$", "${1}um"}, {"((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$", "${1}sis"}, {"(^analy)(sis|ses)$", "${1}sis"}, {"([^f])ves$", "${1}fe"}, {"(hive)s$", "${1}"}, {"(tive)s$", "${1}"}, {"([lr])ves$", "${1}f"}, {"([^aeiouy]|qu)ies$", "${1}y"}, {"(s)eries$", "${1}eries"}, {"(m)ovies$", "${1}ovie"}, {"(c)ookies$", "${1}ookie"}, {"(x|ch|ss|sh)es$", "${1}"}, {"^(m|l)ice$", "${1}ouse"}, {"(bus)(es)?$", "${1}"}, {"(o)es$", "${1}"}, {"(shoe)s$", "${1}"}, {"(cris|test)(is|es)$", "${1}is"}, {"^(a)x[ie]s$", "${1}xis"}, {"(octop|vir)(us|i)$", "${1}us"}, {"(alias|status)(es)?$", "${1}"}, {"^(ox)en", "${1}"}, {"(vert|ind)ices$", "${1}ex"}, {"(matr)ices$", "${1}ix"}, {"(quiz)zes$", "${1}"}, {"(database)s$", "${1}"}, } var irregularInflections = IrregularSlice{ {"person", "people"}, {"man", "men"}, {"child", "children"}, {"sex", "sexes"}, {"move", "moves"}, {"mombie", "mombies"}, } var uncountableInflections = []string{"equipment", "information", "rice", "money", "species", "series", "fish", "sheep", "jeans", "police"} var compiledPluralMaps []inflection var compiledSingularMaps []inflection func compile() { compiledPluralMaps = []inflection{} compiledSingularMaps = []inflection{} for _, uncountable := range uncountableInflections { inf := inflection{ regexp: regexp.MustCompile("^(?i)(" + uncountable + ")$"), replace: "${1}", } compiledPluralMaps = append(compiledPluralMaps, inf) compiledSingularMaps = append(compiledSingularMaps, inf) } for _, value := range irregularInflections { infs := []inflection{ inflection{regexp: regexp.MustCompile(strings.ToUpper(value.singular) + "$"), replace: strings.ToUpper(value.plural)}, inflection{regexp: regexp.MustCompile(strings.Title(value.singular) + "$"), replace: strings.Title(value.plural)}, inflection{regexp: regexp.MustCompile(value.singular + "$"), replace: value.plural}, } compiledPluralMaps = append(compiledPluralMaps, infs...) } for _, value := range irregularInflections { infs := []inflection{ inflection{regexp: regexp.MustCompile(strings.ToUpper(value.plural) + "$"), replace: strings.ToUpper(value.singular)}, inflection{regexp: regexp.MustCompile(strings.Title(value.plural) + "$"), replace: strings.Title(value.singular)}, inflection{regexp: regexp.MustCompile(value.plural + "$"), replace: value.singular}, } compiledSingularMaps = append(compiledSingularMaps, infs...) } for i := len(pluralInflections) - 1; i >= 0; i-- { value := pluralInflections[i] infs := []inflection{ inflection{regexp: regexp.MustCompile(strings.ToUpper(value.find)), replace: strings.ToUpper(value.replace)}, inflection{regexp: regexp.MustCompile(value.find), replace: value.replace}, inflection{regexp: regexp.MustCompile("(?i)" + value.find), replace: value.replace}, } compiledPluralMaps = append(compiledPluralMaps, infs...) } for i := len(singularInflections) - 1; i >= 0; i-- { value := singularInflections[i] infs := []inflection{ inflection{regexp: regexp.MustCompile(strings.ToUpper(value.find)), replace: strings.ToUpper(value.replace)}, inflection{regexp: regexp.MustCompile(value.find), replace: value.replace}, inflection{regexp: regexp.MustCompile("(?i)" + value.find), replace: value.replace}, } compiledSingularMaps = append(compiledSingularMaps, infs...) } } func init() { compile() } // AddPlural adds a plural inflection func AddPlural(find, replace string) { pluralInflections = append(pluralInflections, Regular{find, replace}) compile() } // AddSingular adds a singular inflection func AddSingular(find, replace string) { singularInflections = append(singularInflections, Regular{find, replace}) compile() } // AddIrregular adds an irregular inflection func AddIrregular(singular, plural string) { irregularInflections = append(irregularInflections, Irregular{singular, plural}) compile() } // AddUncountable adds an uncountable inflection func AddUncountable(values ...string) { uncountableInflections = append(uncountableInflections, values...) compile() } // GetPlural retrieves the plural inflection values func GetPlural() RegularSlice { plurals := make(RegularSlice, len(pluralInflections)) copy(plurals, pluralInflections) return plurals } // GetSingular retrieves the singular inflection values func GetSingular() RegularSlice { singulars := make(RegularSlice, len(singularInflections)) copy(singulars, singularInflections) return singulars } // GetIrregular retrieves the irregular inflection values func GetIrregular() IrregularSlice { irregular := make(IrregularSlice, len(irregularInflections)) copy(irregular, irregularInflections) return irregular } // GetUncountable retrieves the uncountable inflection values func GetUncountable() []string { uncountables := make([]string, len(uncountableInflections)) copy(uncountables, uncountableInflections) return uncountables } // SetPlural sets the plural inflections slice func SetPlural(inflections RegularSlice) { pluralInflections = inflections compile() } // SetSingular sets the singular inflections slice func SetSingular(inflections RegularSlice) { singularInflections = inflections compile() } // SetIrregular sets the irregular inflections slice func SetIrregular(inflections IrregularSlice) { irregularInflections = inflections compile() } // SetUncountable sets the uncountable inflections slice func SetUncountable(inflections []string) { uncountableInflections = inflections compile() } // Plural converts a word to its plural form func Plural(str string) string { for _, inflection := range compiledPluralMaps { if inflection.regexp.MatchString(str) { return inflection.regexp.ReplaceAllString(str, inflection.replace) } } return str } // Singular converts a word to its singular form func Singular(str string) string { for _, inflection := range compiledSingularMaps { if inflection.regexp.MatchString(str) { return inflection.regexp.ReplaceAllString(str, inflection.replace) } } return str } ================================================ FILE: vendor/github.com/mailru/easyjson/LICENSE ================================================ Copyright (c) 2016 Mail.Ru Group 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. ================================================ FILE: vendor/github.com/mailru/easyjson/buffer/pool.go ================================================ // Package buffer implements a buffer for serialization, consisting of a chain of []byte-s to // reduce copying and to allow reuse of individual chunks. package buffer import ( "io" "sync" ) // PoolConfig contains configuration for the allocation and reuse strategy. type PoolConfig struct { StartSize int // Minimum chunk size that is allocated. PooledSize int // Minimum chunk size that is reused, reusing chunks too small will result in overhead. MaxSize int // Maximum chunk size that will be allocated. } var config = PoolConfig{ StartSize: 128, PooledSize: 512, MaxSize: 32768, } // Reuse pool: chunk size -> pool. var buffers = map[int]*sync.Pool{} func initBuffers() { for l := config.PooledSize; l <= config.MaxSize; l *= 2 { buffers[l] = new(sync.Pool) } } func init() { initBuffers() } // Init sets up a non-default pooling and allocation strategy. Should be run before serialization is done. func Init(cfg PoolConfig) { config = cfg initBuffers() } // putBuf puts a chunk to reuse pool if it can be reused. func putBuf(buf []byte) { size := cap(buf) if size < config.PooledSize { return } if c := buffers[size]; c != nil { c.Put(buf[:0]) } } // getBuf gets a chunk from reuse pool or creates a new one if reuse failed. func getBuf(size int) []byte { if size < config.PooledSize { return make([]byte, 0, size) } if c := buffers[size]; c != nil { v := c.Get() if v != nil { return v.([]byte) } } return make([]byte, 0, size) } // Buffer is a buffer optimized for serialization without extra copying. type Buffer struct { // Buf is the current chunk that can be used for serialization. Buf []byte toPool []byte bufs [][]byte } // EnsureSpace makes sure that the current chunk contains at least s free bytes, // possibly creating a new chunk. func (b *Buffer) EnsureSpace(s int) { if cap(b.Buf)-len(b.Buf) >= s { return } l := len(b.Buf) if l > 0 { if cap(b.toPool) != cap(b.Buf) { // Chunk was reallocated, toPool can be pooled. putBuf(b.toPool) } if cap(b.bufs) == 0 { b.bufs = make([][]byte, 0, 8) } b.bufs = append(b.bufs, b.Buf) l = cap(b.toPool) * 2 } else { l = config.StartSize } if l > config.MaxSize { l = config.MaxSize } b.Buf = getBuf(l) b.toPool = b.Buf } // AppendByte appends a single byte to buffer. func (b *Buffer) AppendByte(data byte) { if cap(b.Buf) == len(b.Buf) { // EnsureSpace won't be inlined. b.EnsureSpace(1) } b.Buf = append(b.Buf, data) } // AppendBytes appends a byte slice to buffer. func (b *Buffer) AppendBytes(data []byte) { for len(data) > 0 { if cap(b.Buf) == len(b.Buf) { // EnsureSpace won't be inlined. b.EnsureSpace(1) } sz := cap(b.Buf) - len(b.Buf) if sz > len(data) { sz = len(data) } b.Buf = append(b.Buf, data[:sz]...) data = data[sz:] } } // AppendBytes appends a string to buffer. func (b *Buffer) AppendString(data string) { for len(data) > 0 { if cap(b.Buf) == len(b.Buf) { // EnsureSpace won't be inlined. b.EnsureSpace(1) } sz := cap(b.Buf) - len(b.Buf) if sz > len(data) { sz = len(data) } b.Buf = append(b.Buf, data[:sz]...) data = data[sz:] } } // Size computes the size of a buffer by adding sizes of every chunk. func (b *Buffer) Size() int { size := len(b.Buf) for _, buf := range b.bufs { size += len(buf) } return size } // DumpTo outputs the contents of a buffer to a writer and resets the buffer. func (b *Buffer) DumpTo(w io.Writer) (written int, err error) { var n int for _, buf := range b.bufs { if err == nil { n, err = w.Write(buf) written += n } putBuf(buf) } if err == nil { n, err = w.Write(b.Buf) written += n } putBuf(b.toPool) b.bufs = nil b.Buf = nil b.toPool = nil return } // BuildBytes creates a single byte slice with all the contents of the buffer. Data is // copied if it does not fit in a single chunk. You can optionally provide one byte // slice as argument that it will try to reuse. func (b *Buffer) BuildBytes(reuse ...[]byte) []byte { if len(b.bufs) == 0 { ret := b.Buf b.toPool = nil b.Buf = nil return ret } var ret []byte size := b.Size() // If we got a buffer as argument and it is big enought, reuse it. if len(reuse) == 1 && cap(reuse[0]) >= size { ret = reuse[0][:0] } else { ret = make([]byte, 0, size) } for _, buf := range b.bufs { ret = append(ret, buf...) putBuf(buf) } ret = append(ret, b.Buf...) putBuf(b.toPool) b.bufs = nil b.toPool = nil b.Buf = nil return ret } type readCloser struct { offset int bufs [][]byte } func (r *readCloser) Read(p []byte) (n int, err error) { for _, buf := range r.bufs { // Copy as much as we can. x := copy(p[n:], buf[r.offset:]) n += x // Increment how much we filled. // Did we empty the whole buffer? if r.offset+x == len(buf) { // On to the next buffer. r.offset = 0 r.bufs = r.bufs[1:] // We can release this buffer. putBuf(buf) } else { r.offset += x } if n == len(p) { break } } // No buffers left or nothing read? if len(r.bufs) == 0 { err = io.EOF } return } func (r *readCloser) Close() error { // Release all remaining buffers. for _, buf := range r.bufs { putBuf(buf) } // In case Close gets called multiple times. r.bufs = nil return nil } // ReadCloser creates an io.ReadCloser with all the contents of the buffer. func (b *Buffer) ReadCloser() io.ReadCloser { ret := &readCloser{0, append(b.bufs, b.Buf)} b.bufs = nil b.toPool = nil b.Buf = nil return ret } ================================================ FILE: vendor/github.com/mailru/easyjson/jlexer/bytestostr.go ================================================ // This file will only be included to the build if neither // easyjson_nounsafe nor appengine build tag is set. See README notes // for more details. //+build !easyjson_nounsafe //+build !appengine package jlexer import ( "reflect" "unsafe" ) // bytesToStr creates a string pointing at the slice to avoid copying. // // Warning: the string returned by the function should be used with care, as the whole input data // chunk may be either blocked from being freed by GC because of a single string or the buffer.Data // may be garbage-collected even when the string exists. func bytesToStr(data []byte) string { h := (*reflect.SliceHeader)(unsafe.Pointer(&data)) shdr := reflect.StringHeader{Data: h.Data, Len: h.Len} return *(*string)(unsafe.Pointer(&shdr)) } ================================================ FILE: vendor/github.com/mailru/easyjson/jlexer/bytestostr_nounsafe.go ================================================ // This file is included to the build if any of the buildtags below // are defined. Refer to README notes for more details. //+build easyjson_nounsafe appengine package jlexer // bytesToStr creates a string normally from []byte // // Note that this method is roughly 1.5x slower than using the 'unsafe' method. func bytesToStr(data []byte) string { return string(data) } ================================================ FILE: vendor/github.com/mailru/easyjson/jlexer/error.go ================================================ package jlexer import "fmt" // LexerError implements the error interface and represents all possible errors that can be // generated during parsing the JSON data. type LexerError struct { Reason string Offset int Data string } func (l *LexerError) Error() string { return fmt.Sprintf("parse error: %s near offset %d of '%s'", l.Reason, l.Offset, l.Data) } ================================================ FILE: vendor/github.com/mailru/easyjson/jlexer/lexer.go ================================================ // Package jlexer contains a JSON lexer implementation. // // It is expected that it is mostly used with generated parser code, so the interface is tuned // for a parser that knows what kind of data is expected. package jlexer import ( "encoding/base64" "encoding/json" "errors" "fmt" "io" "strconv" "unicode" "unicode/utf16" "unicode/utf8" ) // tokenKind determines type of a token. type tokenKind byte const ( tokenUndef tokenKind = iota // No token. tokenDelim // Delimiter: one of '{', '}', '[' or ']'. tokenString // A string literal, e.g. "abc\u1234" tokenNumber // Number literal, e.g. 1.5e5 tokenBool // Boolean literal: true or false. tokenNull // null keyword. ) // token describes a single token: type, position in the input and value. type token struct { kind tokenKind // Type of a token. boolValue bool // Value if a boolean literal token. byteValue []byte // Raw value of a token. delimValue byte } // Lexer is a JSON lexer: it iterates over JSON tokens in a byte slice. type Lexer struct { Data []byte // Input data given to the lexer. start int // Start of the current token. pos int // Current unscanned position in the input stream. token token // Last scanned token, if token.kind != tokenUndef. firstElement bool // Whether current element is the first in array or an object. wantSep byte // A comma or a colon character, which need to occur before a token. UseMultipleErrors bool // If we want to use multiple errors. fatalError error // Fatal error occurred during lexing. It is usually a syntax error. multipleErrors []*LexerError // Semantic errors occurred during lexing. Marshalling will be continued after finding this errors. } // FetchToken scans the input for the next token. func (r *Lexer) FetchToken() { r.token.kind = tokenUndef r.start = r.pos // Check if r.Data has r.pos element // If it doesn't, it mean corrupted input data if len(r.Data) < r.pos { r.errParse("Unexpected end of data") return } // Determine the type of a token by skipping whitespace and reading the // first character. for _, c := range r.Data[r.pos:] { switch c { case ':', ',': if r.wantSep == c { r.pos++ r.start++ r.wantSep = 0 } else { r.errSyntax() } case ' ', '\t', '\r', '\n': r.pos++ r.start++ case '"': if r.wantSep != 0 { r.errSyntax() } r.token.kind = tokenString r.fetchString() return case '{', '[': if r.wantSep != 0 { r.errSyntax() } r.firstElement = true r.token.kind = tokenDelim r.token.delimValue = r.Data[r.pos] r.pos++ return case '}', ']': if !r.firstElement && (r.wantSep != ',') { r.errSyntax() } r.wantSep = 0 r.token.kind = tokenDelim r.token.delimValue = r.Data[r.pos] r.pos++ return case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': if r.wantSep != 0 { r.errSyntax() } r.token.kind = tokenNumber r.fetchNumber() return case 'n': if r.wantSep != 0 { r.errSyntax() } r.token.kind = tokenNull r.fetchNull() return case 't': if r.wantSep != 0 { r.errSyntax() } r.token.kind = tokenBool r.token.boolValue = true r.fetchTrue() return case 'f': if r.wantSep != 0 { r.errSyntax() } r.token.kind = tokenBool r.token.boolValue = false r.fetchFalse() return default: r.errSyntax() return } } r.fatalError = io.EOF return } // isTokenEnd returns true if the char can follow a non-delimiter token func isTokenEnd(c byte) bool { return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '[' || c == ']' || c == '{' || c == '}' || c == ',' || c == ':' } // fetchNull fetches and checks remaining bytes of null keyword. func (r *Lexer) fetchNull() { r.pos += 4 if r.pos > len(r.Data) || r.Data[r.pos-3] != 'u' || r.Data[r.pos-2] != 'l' || r.Data[r.pos-1] != 'l' || (r.pos != len(r.Data) && !isTokenEnd(r.Data[r.pos])) { r.pos -= 4 r.errSyntax() } } // fetchTrue fetches and checks remaining bytes of true keyword. func (r *Lexer) fetchTrue() { r.pos += 4 if r.pos > len(r.Data) || r.Data[r.pos-3] != 'r' || r.Data[r.pos-2] != 'u' || r.Data[r.pos-1] != 'e' || (r.pos != len(r.Data) && !isTokenEnd(r.Data[r.pos])) { r.pos -= 4 r.errSyntax() } } // fetchFalse fetches and checks remaining bytes of false keyword. func (r *Lexer) fetchFalse() { r.pos += 5 if r.pos > len(r.Data) || r.Data[r.pos-4] != 'a' || r.Data[r.pos-3] != 'l' || r.Data[r.pos-2] != 's' || r.Data[r.pos-1] != 'e' || (r.pos != len(r.Data) && !isTokenEnd(r.Data[r.pos])) { r.pos -= 5 r.errSyntax() } } // fetchNumber scans a number literal token. func (r *Lexer) fetchNumber() { hasE := false afterE := false hasDot := false r.pos++ for i, c := range r.Data[r.pos:] { switch { case c >= '0' && c <= '9': afterE = false case c == '.' && !hasDot: hasDot = true case (c == 'e' || c == 'E') && !hasE: hasE = true hasDot = true afterE = true case (c == '+' || c == '-') && afterE: afterE = false default: r.pos += i if !isTokenEnd(c) { r.errSyntax() } else { r.token.byteValue = r.Data[r.start:r.pos] } return } } r.pos = len(r.Data) r.token.byteValue = r.Data[r.start:] } // findStringLen tries to scan into the string literal for ending quote char to determine required size. // The size will be exact if no escapes are present and may be inexact if there are escaped chars. func findStringLen(data []byte) (isValid, hasEscapes bool, length int) { delta := 0 for i := 0; i < len(data); i++ { switch data[i] { case '\\': i++ delta++ if i < len(data) && data[i] == 'u' { delta++ } case '"': return true, (delta > 0), (i - delta) } } return false, false, len(data) } // 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 } var val rune for i := 2; i < len(s) && i < 6; i++ { var v byte c := s[i] switch c { case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': v = c - '0' case 'a', 'b', 'c', 'd', 'e', 'f': v = c - 'a' + 10 case 'A', 'B', 'C', 'D', 'E', 'F': v = c - 'A' + 10 default: return -1 } val <<= 4 val |= rune(v) } return val } // processEscape processes a single escape sequence and returns number of bytes processed. func (r *Lexer) processEscape(data []byte) (int, error) { if len(data) < 2 { return 0, fmt.Errorf("syntax error at %v", string(data)) } c := data[1] switch c { case '"', '/', '\\': r.token.byteValue = append(r.token.byteValue, c) return 2, nil case 'b': r.token.byteValue = append(r.token.byteValue, '\b') return 2, nil case 'f': r.token.byteValue = append(r.token.byteValue, '\f') return 2, nil case 'n': r.token.byteValue = append(r.token.byteValue, '\n') return 2, nil case 'r': r.token.byteValue = append(r.token.byteValue, '\r') return 2, nil case 't': r.token.byteValue = append(r.token.byteValue, '\t') return 2, nil case 'u': rr := getu4(data) if rr < 0 { return 0, errors.New("syntax error") } read := 6 if utf16.IsSurrogate(rr) { rr1 := getu4(data[read:]) if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { read += 6 rr = dec } else { rr = unicode.ReplacementChar } } var d [4]byte s := utf8.EncodeRune(d[:], rr) r.token.byteValue = append(r.token.byteValue, d[:s]...) return read, nil } return 0, errors.New("syntax error") } // fetchString scans a string literal token. func (r *Lexer) fetchString() { r.pos++ data := r.Data[r.pos:] isValid, hasEscapes, length := findStringLen(data) if !isValid { r.pos += length r.errParse("unterminated string literal") return } if !hasEscapes { r.token.byteValue = data[:length] r.pos += length + 1 return } r.token.byteValue = make([]byte, 0, length) p := 0 for i := 0; i < len(data); { switch data[i] { case '"': r.pos += i + 1 r.token.byteValue = append(r.token.byteValue, data[p:i]...) i++ return case '\\': r.token.byteValue = append(r.token.byteValue, data[p:i]...) off, err := r.processEscape(data[i:]) if err != nil { r.errParse(err.Error()) return } i += off p = i default: i++ } } r.errParse("unterminated string literal") } // scanToken scans the next token if no token is currently available in the lexer. func (r *Lexer) scanToken() { if r.token.kind != tokenUndef || r.fatalError != nil { return } r.FetchToken() } // consume resets the current token to allow scanning the next one. func (r *Lexer) consume() { r.token.kind = tokenUndef r.token.delimValue = 0 } // Ok returns true if no error (including io.EOF) was encountered during scanning. func (r *Lexer) Ok() bool { return r.fatalError == nil } const maxErrorContextLen = 13 func (r *Lexer) errParse(what string) { if r.fatalError == nil { var str string if len(r.Data)-r.pos <= maxErrorContextLen { str = string(r.Data) } else { str = string(r.Data[r.pos:r.pos+maxErrorContextLen-3]) + "..." } r.fatalError = &LexerError{ Reason: what, Offset: r.pos, Data: str, } } } func (r *Lexer) errSyntax() { r.errParse("syntax error") } func (r *Lexer) errInvalidToken(expected string) { if r.fatalError != nil { return } if r.UseMultipleErrors { r.pos = r.start r.consume() r.SkipRecursive() switch expected { case "[": r.token.delimValue = ']' r.token.kind = tokenDelim case "{": r.token.delimValue = '}' r.token.kind = tokenDelim } r.addNonfatalError(&LexerError{ Reason: fmt.Sprintf("expected %s", expected), Offset: r.start, Data: string(r.Data[r.start:r.pos]), }) return } var str string if len(r.token.byteValue) <= maxErrorContextLen { str = string(r.token.byteValue) } else { str = string(r.token.byteValue[:maxErrorContextLen-3]) + "..." } r.fatalError = &LexerError{ Reason: fmt.Sprintf("expected %s", expected), Offset: r.pos, Data: str, } } func (r *Lexer) GetPos() int { return r.pos } // Delim consumes a token and verifies that it is the given delimiter. func (r *Lexer) Delim(c byte) { if r.token.kind == tokenUndef && r.Ok() { r.FetchToken() } if !r.Ok() || r.token.delimValue != c { r.consume() // errInvalidToken can change token if UseMultipleErrors is enabled. r.errInvalidToken(string([]byte{c})) } else { r.consume() } } // IsDelim returns true if there was no scanning error and next token is the given delimiter. func (r *Lexer) IsDelim(c byte) bool { if r.token.kind == tokenUndef && r.Ok() { r.FetchToken() } return !r.Ok() || r.token.delimValue == c } // Null verifies that the next token is null and consumes it. func (r *Lexer) Null() { if r.token.kind == tokenUndef && r.Ok() { r.FetchToken() } if !r.Ok() || r.token.kind != tokenNull { r.errInvalidToken("null") } r.consume() } // IsNull returns true if the next token is a null keyword. func (r *Lexer) IsNull() bool { if r.token.kind == tokenUndef && r.Ok() { r.FetchToken() } return r.Ok() && r.token.kind == tokenNull } // Skip skips a single token. func (r *Lexer) Skip() { if r.token.kind == tokenUndef && r.Ok() { r.FetchToken() } r.consume() } // SkipRecursive skips next array or object completely, or just skips a single token if not // an array/object. // // Note: no syntax validation is performed on the skipped data. func (r *Lexer) SkipRecursive() { r.scanToken() var start, end byte if r.token.delimValue == '{' { start, end = '{', '}' } else if r.token.delimValue == '[' { start, end = '[', ']' } else { r.consume() return } r.consume() level := 1 inQuotes := false wasEscape := false for i, c := range r.Data[r.pos:] { switch { case c == start && !inQuotes: level++ case c == end && !inQuotes: level-- if level == 0 { r.pos += i + 1 return } case c == '\\' && inQuotes: wasEscape = !wasEscape continue case c == '"' && inQuotes: inQuotes = wasEscape case c == '"': inQuotes = true } wasEscape = false } r.pos = len(r.Data) r.fatalError = &LexerError{ Reason: "EOF reached while skipping array/object or token", Offset: r.pos, Data: string(r.Data[r.pos:]), } } // Raw fetches the next item recursively as a data slice func (r *Lexer) Raw() []byte { r.SkipRecursive() if !r.Ok() { return nil } return r.Data[r.start:r.pos] } // IsStart returns whether the lexer is positioned at the start // of an input string. func (r *Lexer) IsStart() bool { return r.pos == 0 } // Consumed reads all remaining bytes from the input, publishing an error if // there is anything but whitespace remaining. func (r *Lexer) Consumed() { if r.pos > len(r.Data) || !r.Ok() { return } for _, c := range r.Data[r.pos:] { if c != ' ' && c != '\t' && c != '\r' && c != '\n' { r.AddError(&LexerError{ Reason: "invalid character '" + string(c) + "' after top-level value", Offset: r.pos, Data: string(r.Data[r.pos:]), }) return } r.pos++ r.start++ } } func (r *Lexer) unsafeString() (string, []byte) { if r.token.kind == tokenUndef && r.Ok() { r.FetchToken() } if !r.Ok() || r.token.kind != tokenString { r.errInvalidToken("string") return "", nil } bytes := r.token.byteValue ret := bytesToStr(r.token.byteValue) r.consume() return ret, bytes } // UnsafeString returns the string value if the token is a string literal. // // Warning: returned string may point to the input buffer, so the string should not outlive // the input buffer. Intended pattern of usage is as an argument to a switch statement. func (r *Lexer) UnsafeString() string { ret, _ := r.unsafeString() return ret } // UnsafeBytes returns the byte slice if the token is a string literal. func (r *Lexer) UnsafeBytes() []byte { _, ret := r.unsafeString() return ret } // String reads a string literal. func (r *Lexer) String() string { if r.token.kind == tokenUndef && r.Ok() { r.FetchToken() } if !r.Ok() || r.token.kind != tokenString { r.errInvalidToken("string") return "" } ret := string(r.token.byteValue) r.consume() return ret } // Bytes reads a string literal and base64 decodes it into a byte slice. func (r *Lexer) Bytes() []byte { if r.token.kind == tokenUndef && r.Ok() { r.FetchToken() } if !r.Ok() || r.token.kind != tokenString { r.errInvalidToken("string") return nil } ret := make([]byte, base64.StdEncoding.DecodedLen(len(r.token.byteValue))) n, err := base64.StdEncoding.Decode(ret, r.token.byteValue) if err != nil { r.fatalError = &LexerError{ Reason: err.Error(), } return nil } r.consume() return ret[:n] } // Bool reads a true or false boolean keyword. func (r *Lexer) Bool() bool { if r.token.kind == tokenUndef && r.Ok() { r.FetchToken() } if !r.Ok() || r.token.kind != tokenBool { r.errInvalidToken("bool") return false } ret := r.token.boolValue r.consume() return ret } func (r *Lexer) number() string { if r.token.kind == tokenUndef && r.Ok() { r.FetchToken() } if !r.Ok() || r.token.kind != tokenNumber { r.errInvalidToken("number") return "" } ret := bytesToStr(r.token.byteValue) r.consume() return ret } func (r *Lexer) Uint8() uint8 { s := r.number() if !r.Ok() { return 0 } n, err := strconv.ParseUint(s, 10, 8) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: s, }) } return uint8(n) } func (r *Lexer) Uint16() uint16 { s := r.number() if !r.Ok() { return 0 } n, err := strconv.ParseUint(s, 10, 16) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: s, }) } return uint16(n) } func (r *Lexer) Uint32() uint32 { s := r.number() if !r.Ok() { return 0 } n, err := strconv.ParseUint(s, 10, 32) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: s, }) } return uint32(n) } func (r *Lexer) Uint64() uint64 { s := r.number() if !r.Ok() { return 0 } n, err := strconv.ParseUint(s, 10, 64) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: s, }) } return n } func (r *Lexer) Uint() uint { return uint(r.Uint64()) } func (r *Lexer) Int8() int8 { s := r.number() if !r.Ok() { return 0 } n, err := strconv.ParseInt(s, 10, 8) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: s, }) } return int8(n) } func (r *Lexer) Int16() int16 { s := r.number() if !r.Ok() { return 0 } n, err := strconv.ParseInt(s, 10, 16) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: s, }) } return int16(n) } func (r *Lexer) Int32() int32 { s := r.number() if !r.Ok() { return 0 } n, err := strconv.ParseInt(s, 10, 32) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: s, }) } return int32(n) } func (r *Lexer) Int64() int64 { s := r.number() if !r.Ok() { return 0 } n, err := strconv.ParseInt(s, 10, 64) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: s, }) } return n } func (r *Lexer) Int() int { return int(r.Int64()) } func (r *Lexer) Uint8Str() uint8 { s, b := r.unsafeString() if !r.Ok() { return 0 } n, err := strconv.ParseUint(s, 10, 8) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: string(b), }) } return uint8(n) } func (r *Lexer) Uint16Str() uint16 { s, b := r.unsafeString() if !r.Ok() { return 0 } n, err := strconv.ParseUint(s, 10, 16) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: string(b), }) } return uint16(n) } func (r *Lexer) Uint32Str() uint32 { s, b := r.unsafeString() if !r.Ok() { return 0 } n, err := strconv.ParseUint(s, 10, 32) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: string(b), }) } return uint32(n) } func (r *Lexer) Uint64Str() uint64 { s, b := r.unsafeString() if !r.Ok() { return 0 } n, err := strconv.ParseUint(s, 10, 64) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: string(b), }) } return n } func (r *Lexer) UintStr() uint { return uint(r.Uint64Str()) } func (r *Lexer) UintptrStr() uintptr { return uintptr(r.Uint64Str()) } func (r *Lexer) Int8Str() int8 { s, b := r.unsafeString() if !r.Ok() { return 0 } n, err := strconv.ParseInt(s, 10, 8) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: string(b), }) } return int8(n) } func (r *Lexer) Int16Str() int16 { s, b := r.unsafeString() if !r.Ok() { return 0 } n, err := strconv.ParseInt(s, 10, 16) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: string(b), }) } return int16(n) } func (r *Lexer) Int32Str() int32 { s, b := r.unsafeString() if !r.Ok() { return 0 } n, err := strconv.ParseInt(s, 10, 32) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: string(b), }) } return int32(n) } func (r *Lexer) Int64Str() int64 { s, b := r.unsafeString() if !r.Ok() { return 0 } n, err := strconv.ParseInt(s, 10, 64) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: string(b), }) } return n } func (r *Lexer) IntStr() int { return int(r.Int64Str()) } func (r *Lexer) Float32() float32 { s := r.number() if !r.Ok() { return 0 } n, err := strconv.ParseFloat(s, 32) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: s, }) } return float32(n) } func (r *Lexer) Float32Str() float32 { s, b := r.unsafeString() if !r.Ok() { return 0 } n, err := strconv.ParseFloat(s, 32) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: string(b), }) } return float32(n) } func (r *Lexer) Float64() float64 { s := r.number() if !r.Ok() { return 0 } n, err := strconv.ParseFloat(s, 64) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: s, }) } return n } func (r *Lexer) Float64Str() float64 { s, b := r.unsafeString() if !r.Ok() { return 0 } n, err := strconv.ParseFloat(s, 64) if err != nil { r.addNonfatalError(&LexerError{ Offset: r.start, Reason: err.Error(), Data: string(b), }) } return n } func (r *Lexer) Error() error { return r.fatalError } func (r *Lexer) AddError(e error) { if r.fatalError == nil { r.fatalError = e } } func (r *Lexer) AddNonFatalError(e error) { r.addNonfatalError(&LexerError{ Offset: r.start, Data: string(r.Data[r.start:r.pos]), Reason: e.Error(), }) } func (r *Lexer) addNonfatalError(err *LexerError) { if r.UseMultipleErrors { // We don't want to add errors with the same offset. if len(r.multipleErrors) != 0 && r.multipleErrors[len(r.multipleErrors)-1].Offset == err.Offset { return } r.multipleErrors = append(r.multipleErrors, err) return } r.fatalError = err } func (r *Lexer) GetNonFatalErrors() []*LexerError { return r.multipleErrors } // JsonNumber fetches and json.Number from 'encoding/json' package. // Both int, float or string, contains them are valid values func (r *Lexer) JsonNumber() json.Number { if r.token.kind == tokenUndef && r.Ok() { r.FetchToken() } if !r.Ok() { r.errInvalidToken("json.Number") return json.Number("") } switch r.token.kind { case tokenString: return json.Number(r.String()) case tokenNumber: return json.Number(r.Raw()) case tokenNull: r.Null() return json.Number("") default: r.errSyntax() return json.Number("") } } // Interface fetches an interface{} analogous to the 'encoding/json' package. func (r *Lexer) Interface() interface{} { if r.token.kind == tokenUndef && r.Ok() { r.FetchToken() } if !r.Ok() { return nil } switch r.token.kind { case tokenString: return r.String() case tokenNumber: return r.Float64() case tokenBool: return r.Bool() case tokenNull: r.Null() return nil } if r.token.delimValue == '{' { r.consume() ret := map[string]interface{}{} for !r.IsDelim('}') { key := r.String() r.WantColon() ret[key] = r.Interface() r.WantComma() } r.Delim('}') if r.Ok() { return ret } else { return nil } } else if r.token.delimValue == '[' { r.consume() var ret []interface{} for !r.IsDelim(']') { ret = append(ret, r.Interface()) r.WantComma() } r.Delim(']') if r.Ok() { return ret } else { return nil } } r.errSyntax() return nil } // WantComma requires a comma to be present before fetching next token. func (r *Lexer) WantComma() { r.wantSep = ',' r.firstElement = false } // WantColon requires a colon to be present before fetching next token. func (r *Lexer) WantColon() { r.wantSep = ':' r.firstElement = false } ================================================ FILE: vendor/github.com/mailru/easyjson/jwriter/writer.go ================================================ // Package jwriter contains a JSON writer. package jwriter import ( "io" "strconv" "unicode/utf8" "github.com/mailru/easyjson/buffer" ) // Flags describe various encoding options. The behavior may be actually implemented in the encoder, but // Flags field in Writer is used to set and pass them around. type Flags int const ( NilMapAsEmpty Flags = 1 << iota // Encode nil map as '{}' rather than 'null'. NilSliceAsEmpty // Encode nil slice as '[]' rather than 'null'. ) // Writer is a JSON writer. type Writer struct { Flags Flags Error error Buffer buffer.Buffer NoEscapeHTML bool } // Size returns the size of the data that was written out. func (w *Writer) Size() int { return w.Buffer.Size() } // DumpTo outputs the data to given io.Writer, resetting the buffer. func (w *Writer) DumpTo(out io.Writer) (written int, err error) { return w.Buffer.DumpTo(out) } // BuildBytes returns writer data as a single byte slice. You can optionally provide one byte slice // as argument that it will try to reuse. func (w *Writer) BuildBytes(reuse ...[]byte) ([]byte, error) { if w.Error != nil { return nil, w.Error } return w.Buffer.BuildBytes(reuse...), nil } // ReadCloser returns an io.ReadCloser that can be used to read the data. // ReadCloser also resets the buffer. func (w *Writer) ReadCloser() (io.ReadCloser, error) { if w.Error != nil { return nil, w.Error } return w.Buffer.ReadCloser(), nil } // RawByte appends raw binary data to the buffer. func (w *Writer) RawByte(c byte) { w.Buffer.AppendByte(c) } // RawByte appends raw binary data to the buffer. func (w *Writer) RawString(s string) { w.Buffer.AppendString(s) } // Raw appends raw binary data to the buffer or sets the error if it is given. Useful for // calling with results of MarshalJSON-like functions. func (w *Writer) Raw(data []byte, err error) { switch { case w.Error != nil: return case err != nil: w.Error = err case len(data) > 0: w.Buffer.AppendBytes(data) default: w.RawString("null") } } // RawText encloses raw binary data in quotes and appends in to the buffer. // Useful for calling with results of MarshalText-like functions. func (w *Writer) RawText(data []byte, err error) { switch { case w.Error != nil: return case err != nil: w.Error = err case len(data) > 0: w.String(string(data)) default: w.RawString("null") } } // Base64Bytes appends data to the buffer after base64 encoding it func (w *Writer) Base64Bytes(data []byte) { if data == nil { w.Buffer.AppendString("null") return } w.Buffer.AppendByte('"') w.base64(data) w.Buffer.AppendByte('"') } func (w *Writer) Uint8(n uint8) { w.Buffer.EnsureSpace(3) w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10) } func (w *Writer) Uint16(n uint16) { w.Buffer.EnsureSpace(5) w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10) } func (w *Writer) Uint32(n uint32) { w.Buffer.EnsureSpace(10) w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10) } func (w *Writer) Uint(n uint) { w.Buffer.EnsureSpace(20) w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10) } func (w *Writer) Uint64(n uint64) { w.Buffer.EnsureSpace(20) w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, n, 10) } func (w *Writer) Int8(n int8) { w.Buffer.EnsureSpace(4) w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10) } func (w *Writer) Int16(n int16) { w.Buffer.EnsureSpace(6) w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10) } func (w *Writer) Int32(n int32) { w.Buffer.EnsureSpace(11) w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10) } func (w *Writer) Int(n int) { w.Buffer.EnsureSpace(21) w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10) } func (w *Writer) Int64(n int64) { w.Buffer.EnsureSpace(21) w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, n, 10) } func (w *Writer) Uint8Str(n uint8) { w.Buffer.EnsureSpace(3) w.Buffer.Buf = append(w.Buffer.Buf, '"') w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10) w.Buffer.Buf = append(w.Buffer.Buf, '"') } func (w *Writer) Uint16Str(n uint16) { w.Buffer.EnsureSpace(5) w.Buffer.Buf = append(w.Buffer.Buf, '"') w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10) w.Buffer.Buf = append(w.Buffer.Buf, '"') } func (w *Writer) Uint32Str(n uint32) { w.Buffer.EnsureSpace(10) w.Buffer.Buf = append(w.Buffer.Buf, '"') w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10) w.Buffer.Buf = append(w.Buffer.Buf, '"') } func (w *Writer) UintStr(n uint) { w.Buffer.EnsureSpace(20) w.Buffer.Buf = append(w.Buffer.Buf, '"') w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10) w.Buffer.Buf = append(w.Buffer.Buf, '"') } func (w *Writer) Uint64Str(n uint64) { w.Buffer.EnsureSpace(20) w.Buffer.Buf = append(w.Buffer.Buf, '"') w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, n, 10) w.Buffer.Buf = append(w.Buffer.Buf, '"') } func (w *Writer) UintptrStr(n uintptr) { w.Buffer.EnsureSpace(20) w.Buffer.Buf = append(w.Buffer.Buf, '"') w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10) w.Buffer.Buf = append(w.Buffer.Buf, '"') } func (w *Writer) Int8Str(n int8) { w.Buffer.EnsureSpace(4) w.Buffer.Buf = append(w.Buffer.Buf, '"') w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10) w.Buffer.Buf = append(w.Buffer.Buf, '"') } func (w *Writer) Int16Str(n int16) { w.Buffer.EnsureSpace(6) w.Buffer.Buf = append(w.Buffer.Buf, '"') w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10) w.Buffer.Buf = append(w.Buffer.Buf, '"') } func (w *Writer) Int32Str(n int32) { w.Buffer.EnsureSpace(11) w.Buffer.Buf = append(w.Buffer.Buf, '"') w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10) w.Buffer.Buf = append(w.Buffer.Buf, '"') } func (w *Writer) IntStr(n int) { w.Buffer.EnsureSpace(21) w.Buffer.Buf = append(w.Buffer.Buf, '"') w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10) w.Buffer.Buf = append(w.Buffer.Buf, '"') } func (w *Writer) Int64Str(n int64) { w.Buffer.EnsureSpace(21) w.Buffer.Buf = append(w.Buffer.Buf, '"') w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, n, 10) w.Buffer.Buf = append(w.Buffer.Buf, '"') } func (w *Writer) Float32(n float32) { w.Buffer.EnsureSpace(20) w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32) } func (w *Writer) Float32Str(n float32) { w.Buffer.EnsureSpace(20) w.Buffer.Buf = append(w.Buffer.Buf, '"') w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32) w.Buffer.Buf = append(w.Buffer.Buf, '"') } func (w *Writer) Float64(n float64) { w.Buffer.EnsureSpace(20) w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, n, 'g', -1, 64) } func (w *Writer) Float64Str(n float64) { w.Buffer.EnsureSpace(20) w.Buffer.Buf = append(w.Buffer.Buf, '"') w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 64) w.Buffer.Buf = append(w.Buffer.Buf, '"') } func (w *Writer) Bool(v bool) { w.Buffer.EnsureSpace(5) if v { w.Buffer.Buf = append(w.Buffer.Buf, "true"...) } else { w.Buffer.Buf = append(w.Buffer.Buf, "false"...) } } const chars = "0123456789abcdef" func isNotEscapedSingleChar(c byte, escapeHTML bool) bool { // Note: might make sense to use a table if there are more chars to escape. With 4 chars // it benchmarks the same. if escapeHTML { return c != '<' && c != '>' && c != '&' && c != '\\' && c != '"' && c >= 0x20 && c < utf8.RuneSelf } else { return c != '\\' && c != '"' && c >= 0x20 && c < utf8.RuneSelf } } func (w *Writer) String(s string) { w.Buffer.AppendByte('"') // Portions of the string that contain no escapes are appended as // byte slices. p := 0 // last non-escape symbol for i := 0; i < len(s); { c := s[i] if isNotEscapedSingleChar(c, !w.NoEscapeHTML) { // single-width character, no escaping is required i++ continue } else if c < utf8.RuneSelf { // single-with character, need to escape w.Buffer.AppendString(s[p:i]) switch c { case '\t': w.Buffer.AppendString(`\t`) case '\r': w.Buffer.AppendString(`\r`) case '\n': w.Buffer.AppendString(`\n`) case '\\': w.Buffer.AppendString(`\\`) case '"': w.Buffer.AppendString(`\"`) default: w.Buffer.AppendString(`\u00`) w.Buffer.AppendByte(chars[c>>4]) w.Buffer.AppendByte(chars[c&0xf]) } i++ p = i continue } // broken utf runeValue, runeWidth := utf8.DecodeRuneInString(s[i:]) if runeValue == utf8.RuneError && runeWidth == 1 { w.Buffer.AppendString(s[p:i]) w.Buffer.AppendString(`\ufffd`) i++ p = i continue } // jsonp stuff - tab separator and line separator if runeValue == '\u2028' || runeValue == '\u2029' { w.Buffer.AppendString(s[p:i]) w.Buffer.AppendString(`\u202`) w.Buffer.AppendByte(chars[runeValue&0xf]) i += runeWidth p = i continue } i += runeWidth } w.Buffer.AppendString(s[p:]) w.Buffer.AppendByte('"') } const encode = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" const padChar = '=' func (w *Writer) base64(in []byte) { if len(in) == 0 { return } w.Buffer.EnsureSpace(((len(in)-1)/3 + 1) * 4) si := 0 n := (len(in) / 3) * 3 for si < n { // Convert 3x 8bit source bytes into 4 bytes val := uint(in[si+0])<<16 | uint(in[si+1])<<8 | uint(in[si+2]) w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>18&0x3F], encode[val>>12&0x3F], encode[val>>6&0x3F], encode[val&0x3F]) si += 3 } remain := len(in) - si if remain == 0 { return } // Add the remaining small block val := uint(in[si+0]) << 16 if remain == 2 { val |= uint(in[si+1]) << 8 } w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>18&0x3F], encode[val>>12&0x3F]) switch remain { case 2: w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>6&0x3F], byte(padChar)) case 1: w.Buffer.Buf = append(w.Buffer.Buf, byte(padChar), byte(padChar)) } } ================================================ FILE: vendor/github.com/mattn/go-isatty/.travis.yml ================================================ language: go go: - tip os: - linux - osx before_install: - go get github.com/mattn/goveralls - go get golang.org/x/tools/cmd/cover script: - $HOME/gopath/bin/goveralls -repotoken 3gHdORO5k5ziZcWMBxnd9LrMZaJs8m9x5 ================================================ FILE: vendor/github.com/mattn/go-isatty/LICENSE ================================================ Copyright (c) Yasuhiro MATSUMOTO MIT License (Expat) 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. ================================================ FILE: vendor/github.com/mattn/go-isatty/README.md ================================================ # go-isatty [![Godoc Reference](https://godoc.org/github.com/mattn/go-isatty?status.svg)](http://godoc.org/github.com/mattn/go-isatty) [![Build Status](https://travis-ci.org/mattn/go-isatty.svg?branch=master)](https://travis-ci.org/mattn/go-isatty) [![Coverage Status](https://coveralls.io/repos/github/mattn/go-isatty/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-isatty?branch=master) [![Go Report Card](https://goreportcard.com/badge/mattn/go-isatty)](https://goreportcard.com/report/mattn/go-isatty) isatty for golang ## Usage ```go package main import ( "fmt" "github.com/mattn/go-isatty" "os" ) func main() { if isatty.IsTerminal(os.Stdout.Fd()) { fmt.Println("Is Terminal") } else if isatty.IsCygwinTerminal(os.Stdout.Fd()) { fmt.Println("Is Cygwin/MSYS2 Terminal") } else { fmt.Println("Is Not Terminal") } } ``` ## Installation ``` $ go get github.com/mattn/go-isatty ``` ## License MIT ## Author Yasuhiro Matsumoto (a.k.a mattn) ## Thanks * k-takata: base idea for IsCygwinTerminal https://github.com/k-takata/go-iscygpty ================================================ FILE: vendor/github.com/mattn/go-isatty/doc.go ================================================ // Package isatty implements interface to isatty package isatty ================================================ FILE: vendor/github.com/mattn/go-isatty/go.mod ================================================ module github.com/mattn/go-isatty require golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 ================================================ FILE: vendor/github.com/mattn/go-isatty/go.sum ================================================ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= ================================================ FILE: vendor/github.com/mattn/go-isatty/isatty_android.go ================================================ // +build android package isatty import ( "syscall" "unsafe" ) const ioctlReadTermios = syscall.TCGETS // IsTerminal return true if the file descriptor is terminal. func IsTerminal(fd uintptr) bool { var termios syscall.Termios _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) return err == 0 } // IsCygwinTerminal return true if the file descriptor is a cygwin or msys2 // terminal. This is also always false on this environment. func IsCygwinTerminal(fd uintptr) bool { return false } ================================================ FILE: vendor/github.com/mattn/go-isatty/isatty_bsd.go ================================================ // +build darwin freebsd openbsd netbsd dragonfly // +build !appengine package isatty import ( "syscall" "unsafe" ) const ioctlReadTermios = syscall.TIOCGETA // IsTerminal return true if the file descriptor is terminal. func IsTerminal(fd uintptr) bool { var termios syscall.Termios _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) return err == 0 } // IsCygwinTerminal return true if the file descriptor is a cygwin or msys2 // terminal. This is also always false on this environment. func IsCygwinTerminal(fd uintptr) bool { return false } ================================================ FILE: vendor/github.com/mattn/go-isatty/isatty_others.go ================================================ // +build appengine js nacl package isatty // IsTerminal returns true if the file descriptor is terminal which // is always false on js and appengine classic which is a sandboxed PaaS. func IsTerminal(fd uintptr) bool { return false } // IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2 // terminal. This is also always false on this environment. func IsCygwinTerminal(fd uintptr) bool { return false } ================================================ FILE: vendor/github.com/mattn/go-isatty/isatty_solaris.go ================================================ // +build solaris // +build !appengine package isatty import ( "golang.org/x/sys/unix" ) // IsTerminal returns true if the given file descriptor is a terminal. // see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c func IsTerminal(fd uintptr) bool { var termio unix.Termio err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio) return err == nil } // IsCygwinTerminal return true if the file descriptor is a cygwin or msys2 // terminal. This is also always false on this environment. func IsCygwinTerminal(fd uintptr) bool { return false } ================================================ FILE: vendor/github.com/mattn/go-isatty/isatty_tcgets.go ================================================ // +build linux aix // +build !appengine // +build !android package isatty import "golang.org/x/sys/unix" // IsTerminal return true if the file descriptor is terminal. func IsTerminal(fd uintptr) bool { _, err := unix.IoctlGetTermios(int(fd), unix.TCGETS) return err == nil } // IsCygwinTerminal return true if the file descriptor is a cygwin or msys2 // terminal. This is also always false on this environment. func IsCygwinTerminal(fd uintptr) bool { return false } ================================================ FILE: vendor/github.com/mattn/go-isatty/isatty_windows.go ================================================ // +build windows // +build !appengine package isatty import ( "strings" "syscall" "unicode/utf16" "unsafe" ) const ( fileNameInfo uintptr = 2 fileTypePipe = 3 ) var ( kernel32 = syscall.NewLazyDLL("kernel32.dll") procGetConsoleMode = kernel32.NewProc("GetConsoleMode") procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx") procGetFileType = kernel32.NewProc("GetFileType") ) func init() { // Check if GetFileInformationByHandleEx is available. if procGetFileInformationByHandleEx.Find() != nil { procGetFileInformationByHandleEx = nil } } // IsTerminal return true if the file descriptor is terminal. func IsTerminal(fd uintptr) bool { var st uint32 r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0) return r != 0 && e == 0 } // Check pipe name is used for cygwin/msys2 pty. // Cygwin/MSYS2 PTY has a name like: // \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master func isCygwinPipeName(name string) bool { token := strings.Split(name, "-") if len(token) < 5 { return false } if token[0] != `\msys` && token[0] != `\cygwin` { return false } if token[1] == "" { return false } if !strings.HasPrefix(token[2], "pty") { return false } if token[3] != `from` && token[3] != `to` { return false } if token[4] != "master" { return false } return true } // IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2 // terminal. func IsCygwinTerminal(fd uintptr) bool { if procGetFileInformationByHandleEx == nil { return false } // Cygwin/msys's pty is a pipe. ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0) if ft != fileTypePipe || e != 0 { return false } var buf [2 + syscall.MAX_PATH]uint16 r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)), uintptr(len(buf)*2), 0, 0) if r == 0 || e != 0 { return false } l := *(*uint32)(unsafe.Pointer(&buf)) return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2]))) } ================================================ FILE: vendor/github.com/modern-go/concurrent/.gitignore ================================================ /coverage.txt ================================================ FILE: vendor/github.com/modern-go/concurrent/.travis.yml ================================================ language: go go: - 1.8.x - 1.x before_install: - go get -t -v ./... script: - ./test.sh after_success: - bash <(curl -s https://codecov.io/bash) ================================================ FILE: vendor/github.com/modern-go/concurrent/LICENSE ================================================ 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. ================================================ FILE: vendor/github.com/modern-go/concurrent/README.md ================================================ # concurrent [![Sourcegraph](https://sourcegraph.com/github.com/modern-go/concurrent/-/badge.svg)](https://sourcegraph.com/github.com/modern-go/concurrent?badge) [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/modern-go/concurrent) [![Build Status](https://travis-ci.org/modern-go/concurrent.svg?branch=master)](https://travis-ci.org/modern-go/concurrent) [![codecov](https://codecov.io/gh/modern-go/concurrent/branch/master/graph/badge.svg)](https://codecov.io/gh/modern-go/concurrent) [![rcard](https://goreportcard.com/badge/github.com/modern-go/concurrent)](https://goreportcard.com/report/github.com/modern-go/concurrent) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://raw.githubusercontent.com/modern-go/concurrent/master/LICENSE) * concurrent.Map: backport sync.Map for go below 1.9 * concurrent.Executor: goroutine with explicit ownership and cancellable # concurrent.Map because sync.Map is only available in go 1.9, we can use concurrent.Map to make code portable ```go m := concurrent.NewMap() m.Store("hello", "world") elem, found := m.Load("hello") // elem will be "world" // found will be true ``` # concurrent.Executor ```go executor := concurrent.NewUnboundedExecutor() executor.Go(func(ctx context.Context) { everyMillisecond := time.NewTicker(time.Millisecond) for { select { case <-ctx.Done(): fmt.Println("goroutine exited") return case <-everyMillisecond.C: // do something } } }) time.Sleep(time.Second) executor.StopAndWaitForever() fmt.Println("executor stopped") ``` attach goroutine to executor instance, so that we can * cancel it by stop the executor with Stop/StopAndWait/StopAndWaitForever * handle panic by callback: the default behavior will no longer crash your application ================================================ FILE: vendor/github.com/modern-go/concurrent/executor.go ================================================ package concurrent import "context" // Executor replace go keyword to start a new goroutine // the goroutine should cancel itself if the context passed in has been cancelled // the goroutine started by the executor, is owned by the executor // we can cancel all executors owned by the executor just by stop the executor itself // however Executor interface does not Stop method, the one starting and owning executor // should use the concrete type of executor, instead of this interface. type Executor interface { // Go starts a new goroutine controlled by the context Go(handler func(ctx context.Context)) } ================================================ FILE: vendor/github.com/modern-go/concurrent/go_above_19.go ================================================ //+build go1.9 package concurrent import "sync" // Map is a wrapper for sync.Map introduced in go1.9 type Map struct { sync.Map } // NewMap creates a thread safe Map func NewMap() *Map { return &Map{} } ================================================ FILE: vendor/github.com/modern-go/concurrent/go_below_19.go ================================================ //+build !go1.9 package concurrent import "sync" // Map implements a thread safe map for go version below 1.9 using mutex type Map struct { lock sync.RWMutex data map[interface{}]interface{} } // NewMap creates a thread safe map func NewMap() *Map { return &Map{ data: make(map[interface{}]interface{}, 32), } } // Load is same as sync.Map Load func (m *Map) Load(key interface{}) (elem interface{}, found bool) { m.lock.RLock() elem, found = m.data[key] m.lock.RUnlock() return } // Load is same as sync.Map Store func (m *Map) Store(key interface{}, elem interface{}) { m.lock.Lock() m.data[key] = elem m.lock.Unlock() } ================================================ FILE: vendor/github.com/modern-go/concurrent/log.go ================================================ package concurrent import ( "os" "log" "io/ioutil" ) // ErrorLogger is used to print out error, can be set to writer other than stderr var ErrorLogger = log.New(os.Stderr, "", 0) // InfoLogger is used to print informational message, default to off var InfoLogger = log.New(ioutil.Discard, "", 0) ================================================ FILE: vendor/github.com/modern-go/concurrent/test.sh ================================================ #!/usr/bin/env bash set -e echo "" > coverage.txt for d in $(go list ./... | grep -v vendor); do go test -coverprofile=profile.out -coverpkg=github.com/modern-go/concurrent $d if [ -f profile.out ]; then cat profile.out >> coverage.txt rm profile.out fi done ================================================ FILE: vendor/github.com/modern-go/concurrent/unbounded_executor.go ================================================ package concurrent import ( "context" "fmt" "runtime" "runtime/debug" "sync" "time" "reflect" ) // HandlePanic logs goroutine panic by default var HandlePanic = func(recovered interface{}, funcName string) { ErrorLogger.Println(fmt.Sprintf("%s panic: %v", funcName, recovered)) ErrorLogger.Println(string(debug.Stack())) } // UnboundedExecutor is a executor without limits on counts of alive goroutines // it tracks the goroutine started by it, and can cancel them when shutdown type UnboundedExecutor struct { ctx context.Context cancel context.CancelFunc activeGoroutinesMutex *sync.Mutex activeGoroutines map[string]int HandlePanic func(recovered interface{}, funcName string) } // GlobalUnboundedExecutor has the life cycle of the program itself // any goroutine want to be shutdown before main exit can be started from this executor // GlobalUnboundedExecutor expects the main function to call stop // it does not magically knows the main function exits var GlobalUnboundedExecutor = NewUnboundedExecutor() // NewUnboundedExecutor creates a new UnboundedExecutor, // UnboundedExecutor can not be created by &UnboundedExecutor{} // HandlePanic can be set with a callback to override global HandlePanic func NewUnboundedExecutor() *UnboundedExecutor { ctx, cancel := context.WithCancel(context.TODO()) return &UnboundedExecutor{ ctx: ctx, cancel: cancel, activeGoroutinesMutex: &sync.Mutex{}, activeGoroutines: map[string]int{}, } } // Go starts a new goroutine and tracks its lifecycle. // Panic will be recovered and logged automatically, except for StopSignal func (executor *UnboundedExecutor) Go(handler func(ctx context.Context)) { pc := reflect.ValueOf(handler).Pointer() f := runtime.FuncForPC(pc) funcName := f.Name() file, line := f.FileLine(pc) executor.activeGoroutinesMutex.Lock() defer executor.activeGoroutinesMutex.Unlock() startFrom := fmt.Sprintf("%s:%d", file, line) executor.activeGoroutines[startFrom] += 1 go func() { defer func() { recovered := recover() // if you want to quit a goroutine without trigger HandlePanic // use runtime.Goexit() to quit if recovered != nil { if executor.HandlePanic == nil { HandlePanic(recovered, funcName) } else { executor.HandlePanic(recovered, funcName) } } executor.activeGoroutinesMutex.Lock() executor.activeGoroutines[startFrom] -= 1 executor.activeGoroutinesMutex.Unlock() }() handler(executor.ctx) }() } // Stop cancel all goroutines started by this executor without wait func (executor *UnboundedExecutor) Stop() { executor.cancel() } // StopAndWaitForever cancel all goroutines started by this executor and // wait until all goroutines exited func (executor *UnboundedExecutor) StopAndWaitForever() { executor.StopAndWait(context.Background()) } // StopAndWait cancel all goroutines started by this executor and wait. // Wait can be cancelled by the context passed in. func (executor *UnboundedExecutor) StopAndWait(ctx context.Context) { executor.cancel() for { oneHundredMilliseconds := time.NewTimer(time.Millisecond * 100) select { case <-oneHundredMilliseconds.C: if executor.checkNoActiveGoroutines() { return } case <-ctx.Done(): return } } } func (executor *UnboundedExecutor) checkNoActiveGoroutines() bool { executor.activeGoroutinesMutex.Lock() defer executor.activeGoroutinesMutex.Unlock() for startFrom, count := range executor.activeGoroutines { if count > 0 { InfoLogger.Println("UnboundedExecutor is still waiting goroutines to quit", "startFrom", startFrom, "count", count) return false } } return true } ================================================ FILE: vendor/github.com/pkg/errors/.gitignore ================================================ # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof ================================================ FILE: vendor/github.com/pkg/errors/.travis.yml ================================================ language: go go_import_path: github.com/pkg/errors go: - 1.4.x - 1.5.x - 1.6.x - 1.7.x - 1.8.x - 1.9.x - 1.10.x - 1.11.x - tip script: - go test -v ./... ================================================ FILE: vendor/github.com/pkg/errors/LICENSE ================================================ Copyright (c) 2015, Dave Cheney All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: vendor/github.com/pkg/errors/README.md ================================================ # errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge) Package errors provides simple error handling primitives. `go get github.com/pkg/errors` The traditional error handling idiom in Go is roughly akin to ```go if err != nil { return err } ``` which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error. ## Adding context to an error The errors.Wrap function returns a new error that adds context to the original error. For example ```go _, err := ioutil.ReadAll(r) if err != nil { return errors.Wrap(err, "read failed") } ``` ## Retrieving the cause of an error Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`. ```go type causer interface { Cause() error } ``` `errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example: ```go switch err := errors.Cause(err).(type) { case *MyError: // handle specifically default: // unknown error } ``` [Read the package documentation for more information](https://godoc.org/github.com/pkg/errors). ## Contributing We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high. Before proposing a change, please discuss your change by raising an issue. ## License BSD-2-Clause ================================================ FILE: vendor/github.com/pkg/errors/appveyor.yml ================================================ version: build-{build}.{branch} clone_folder: C:\gopath\src\github.com\pkg\errors shallow_clone: true # for startup speed environment: GOPATH: C:\gopath platform: - x64 # http://www.appveyor.com/docs/installed-software install: # some helpful output for debugging builds - go version - go env # pre-installed MinGW at C:\MinGW is 32bit only # but MSYS2 at C:\msys64 has mingw64 - set PATH=C:\msys64\mingw64\bin;%PATH% - gcc --version - g++ --version build_script: - go install -v ./... test_script: - set PATH=C:\gopath\bin;%PATH% - go test -v ./... #artifacts: # - path: '%GOPATH%\bin\*.exe' deploy: off ================================================ FILE: vendor/github.com/pkg/errors/errors.go ================================================ // Package errors provides simple error handling primitives. // // The traditional error handling idiom in Go is roughly akin to // // if err != nil { // return err // } // // which when applied recursively up the call stack results in error reports // without context or debugging information. The errors package allows // programmers to add context to the failure path in their code in a way // that does not destroy the original value of the error. // // Adding context to an error // // The errors.Wrap function returns a new error that adds context to the // original error by recording a stack trace at the point Wrap is called, // together with the supplied message. For example // // _, err := ioutil.ReadAll(r) // if err != nil { // return errors.Wrap(err, "read failed") // } // // If additional control is required, the errors.WithStack and // errors.WithMessage functions destructure errors.Wrap into its component // operations: annotating an error with a stack trace and with a message, // respectively. // // Retrieving the cause of an error // // Using errors.Wrap constructs a stack of errors, adding context to the // preceding error. Depending on the nature of the error it may be necessary // to reverse the operation of errors.Wrap to retrieve the original error // for inspection. Any error value which implements this interface // // type causer interface { // Cause() error // } // // can be inspected by errors.Cause. errors.Cause will recursively retrieve // the topmost error that does not implement causer, which is assumed to be // the original cause. For example: // // switch err := errors.Cause(err).(type) { // case *MyError: // // handle specifically // default: // // unknown error // } // // Although the causer interface is not exported by this package, it is // considered a part of its stable public interface. // // Formatted printing of errors // // All error values returned from this package implement fmt.Formatter and can // be formatted by the fmt package. The following verbs are supported: // // %s print the error. If the error has a Cause it will be // printed recursively. // %v see %s // %+v extended format. Each Frame of the error's StackTrace will // be printed in detail. // // Retrieving the stack trace of an error or wrapper // // New, Errorf, Wrap, and Wrapf record a stack trace at the point they are // invoked. This information can be retrieved with the following interface: // // type stackTracer interface { // StackTrace() errors.StackTrace // } // // The returned errors.StackTrace type is defined as // // type StackTrace []Frame // // The Frame type represents a call site in the stack trace. Frame supports // the fmt.Formatter interface that can be used for printing information about // the stack trace of this error. For example: // // if err, ok := err.(stackTracer); ok { // for _, f := range err.StackTrace() { // fmt.Printf("%+s:%d", f) // } // } // // Although the stackTracer interface is not exported by this package, it is // considered a part of its stable public interface. // // See the documentation for Frame.Format for more details. package errors import ( "fmt" "io" ) // New returns an error with the supplied message. // New also records the stack trace at the point it was called. func New(message string) error { return &fundamental{ msg: message, stack: callers(), } } // Errorf formats according to a format specifier and returns the string // as a value that satisfies error. // Errorf also records the stack trace at the point it was called. func Errorf(format string, args ...interface{}) error { return &fundamental{ msg: fmt.Sprintf(format, args...), stack: callers(), } } // fundamental is an error that has a message and a stack, but no caller. type fundamental struct { msg string *stack } func (f *fundamental) Error() string { return f.msg } func (f *fundamental) Format(s fmt.State, verb rune) { switch verb { case 'v': if s.Flag('+') { io.WriteString(s, f.msg) f.stack.Format(s, verb) return } fallthrough case 's': io.WriteString(s, f.msg) case 'q': fmt.Fprintf(s, "%q", f.msg) } } // WithStack annotates err with a stack trace at the point WithStack was called. // If err is nil, WithStack returns nil. func WithStack(err error) error { if err == nil { return nil } return &withStack{ err, callers(), } } type withStack struct { error *stack } func (w *withStack) Cause() error { return w.error } func (w *withStack) Format(s fmt.State, verb rune) { switch verb { case 'v': if s.Flag('+') { fmt.Fprintf(s, "%+v", w.Cause()) w.stack.Format(s, verb) return } fallthrough case 's': io.WriteString(s, w.Error()) case 'q': fmt.Fprintf(s, "%q", w.Error()) } } // Wrap returns an error annotating err with a stack trace // at the point Wrap is called, and the supplied message. // If err is nil, Wrap returns nil. func Wrap(err error, message string) error { if err == nil { return nil } err = &withMessage{ cause: err, msg: message, } return &withStack{ err, callers(), } } // Wrapf returns an error annotating err with a stack trace // at the point Wrapf is called, and the format specifier. // If err is nil, Wrapf returns nil. func Wrapf(err error, format string, args ...interface{}) error { if err == nil { return nil } err = &withMessage{ cause: err, msg: fmt.Sprintf(format, args...), } return &withStack{ err, callers(), } } // WithMessage annotates err with a new message. // If err is nil, WithMessage returns nil. func WithMessage(err error, message string) error { if err == nil { return nil } return &withMessage{ cause: err, msg: message, } } // WithMessagef annotates err with the format specifier. // If err is nil, WithMessagef returns nil. func WithMessagef(err error, format string, args ...interface{}) error { if err == nil { return nil } return &withMessage{ cause: err, msg: fmt.Sprintf(format, args...), } } type withMessage struct { cause error msg string } func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } func (w *withMessage) Cause() error { return w.cause } func (w *withMessage) Format(s fmt.State, verb rune) { switch verb { case 'v': if s.Flag('+') { fmt.Fprintf(s, "%+v\n", w.Cause()) io.WriteString(s, w.msg) return } fallthrough case 's', 'q': io.WriteString(s, w.Error()) } } // Cause returns the underlying cause of the error, if possible. // An error value has a cause if it implements the following // interface: // // type causer interface { // Cause() error // } // // If the error does not implement Cause, the original error will // be returned. If the error is nil, nil will be returned without further // investigation. func Cause(err error) error { type causer interface { Cause() error } for err != nil { cause, ok := err.(causer) if !ok { break } err = cause.Cause() } return err } ================================================ FILE: vendor/github.com/pkg/errors/stack.go ================================================ package errors import ( "fmt" "io" "path" "runtime" "strings" ) // Frame represents a program counter inside a stack frame. type Frame uintptr // pc returns the program counter for this frame; // multiple frames may have the same PC value. func (f Frame) pc() uintptr { return uintptr(f) - 1 } // file returns the full path to the file that contains the // function for this Frame's pc. func (f Frame) file() string { fn := runtime.FuncForPC(f.pc()) if fn == nil { return "unknown" } file, _ := fn.FileLine(f.pc()) return file } // line returns the line number of source code of the // function for this Frame's pc. func (f Frame) line() int { fn := runtime.FuncForPC(f.pc()) if fn == nil { return 0 } _, line := fn.FileLine(f.pc()) return line } // Format formats the frame according to the fmt.Formatter interface. // // %s source file // %d source line // %n function name // %v equivalent to %s:%d // // Format accepts flags that alter the printing of some verbs, as follows: // // %+s function name and path of source file relative to the compile time // GOPATH separated by \n\t (\n\t) // %+v equivalent to %+s:%d func (f Frame) Format(s fmt.State, verb rune) { switch verb { case 's': switch { case s.Flag('+'): pc := f.pc() fn := runtime.FuncForPC(pc) if fn == nil { io.WriteString(s, "unknown") } else { file, _ := fn.FileLine(pc) fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file) } default: io.WriteString(s, path.Base(f.file())) } case 'd': fmt.Fprintf(s, "%d", f.line()) case 'n': name := runtime.FuncForPC(f.pc()).Name() io.WriteString(s, funcname(name)) case 'v': f.Format(s, 's') io.WriteString(s, ":") f.Format(s, 'd') } } // StackTrace is stack of Frames from innermost (newest) to outermost (oldest). type StackTrace []Frame // Format formats the stack of Frames according to the fmt.Formatter interface. // // %s lists source files for each Frame in the stack // %v lists the source file and line number for each Frame in the stack // // Format accepts flags that alter the printing of some verbs, as follows: // // %+v Prints filename, function, and line number for each Frame in the stack. func (st StackTrace) Format(s fmt.State, verb rune) { switch verb { case 'v': switch { case s.Flag('+'): for _, f := range st { fmt.Fprintf(s, "\n%+v", f) } case s.Flag('#'): fmt.Fprintf(s, "%#v", []Frame(st)) default: fmt.Fprintf(s, "%v", []Frame(st)) } case 's': fmt.Fprintf(s, "%s", []Frame(st)) } } // stack represents a stack of program counters. type stack []uintptr func (s *stack) Format(st fmt.State, verb rune) { switch verb { case 'v': switch { case st.Flag('+'): for _, pc := range *s { f := Frame(pc) fmt.Fprintf(st, "\n%+v", f) } } } } func (s *stack) StackTrace() StackTrace { f := make([]Frame, len(*s)) for i := 0; i < len(f); i++ { f[i] = Frame((*s)[i]) } return f } func callers() *stack { const depth = 32 var pcs [depth]uintptr n := runtime.Callers(3, pcs[:]) var st stack = pcs[0:n] return &st } // funcname removes the path prefix component of a function's name reported by func.Name(). func funcname(name string) string { i := strings.LastIndex(name, "/") name = name[i+1:] i = strings.Index(name, ".") return name[i+1:] } ================================================ FILE: vendor/github.com/swaggo/swag/.gitignore ================================================ dist testdata/simple*/docs cover.out # Test binary, build with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out .idea .vscode # Etc .DS_Store ================================================ FILE: vendor/github.com/swaggo/swag/.goreleaser.yml ================================================ build: main: cmd/swag/main.go archive: replacements: darwin: Darwin linux: Linux windows: Windows 386: i386 amd64: x86_64 checksum: name_template: 'checksums.txt' snapshot: name_template: "{{ .Tag }}-next" changelog: sort: asc filters: exclude: - '^docs:' - '^test:' ================================================ FILE: vendor/github.com/swaggo/swag/.travis.yml ================================================ language: go sudo: false go: - 1.9.x - 1.10.x - 1.11.x - 1.12.x install: - make install script: - make fmt-check - make lint - make vet - make build - make test after_success: - bash <(curl -s https://codecov.io/bash) ================================================ FILE: vendor/github.com/swaggo/swag/CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [gitter.im/swaggo/swag](https://gitter.im/swaggo/swag).The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: vendor/github.com/swaggo/swag/CONTRIBUTING.md ================================================ # Contributing When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change. Please note we have a code of conduct, please follow it in all your interactions with the project. ## Pull Request Process 1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request Please make an issue first if the change is likely to increase. ================================================ FILE: vendor/github.com/swaggo/swag/Makefile ================================================ GOCMD:=$(shell which go) GOLINT:=$(shell which golint) GOIMPORT:=$(shell which goimports) GOFMT:=$(shell which gofmt) GOBUILD:=$(GOCMD) build GOCLEAN:=$(GOCMD) clean GOTEST:=$(GOCMD) test GOGET:=$(GOCMD) get GOLIST:=$(GOCMD) list GOVET:=$(GOCMD) vet BINARY_NAME:=swag PACKAGES:=$(shell $(GOLIST) github.com/swaggo/swag github.com/swaggo/swag/cmd/swag github.com/swaggo/swag/gen) GOFILES:=$(shell find . -name "*.go" -type f) export GO111MODULE := on all: test build .PHONY: build build: $(GOBUILD) -o $(BINARY_NAME) -v ./cmd/... .PHONY: test test: echo "mode: count" > coverage.out for PKG in $(PACKAGES); do \ $(GOCMD) test -v -covermode=count -coverprofile=profile.out $$PKG > tmp.out; \ cat tmp.out; \ if grep -q "^--- FAIL" tmp.out; then \ rm tmp.out; \ exit 1; \ elif grep -q "build failed" tmp.out; then \ rm tmp.out; \ exit; \ fi; \ if [ -f profile.out ]; then \ cat profile.out | grep -v "mode:" >> coverage.out; \ rm profile.out; \ fi; \ done .PHONY: clean clean: $(GOCLEAN) rm -f $(BINARY_NAME) .PHONY: install install: $(GOGET) -v github.com/swaggo/swag github.com/swaggo/swag/cmd/swag github.com/swaggo/swag/gen $(GOGET) github.com/stretchr/testify/assert .PHONY: lint lint: which golint || $(GOGET) -u golang.org/x/lint/golint for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done; .PHONY: vet vet: $(GOVET) $(PACKAGES) .PHONY: fmt fmt: $(GOFMT) -s -w $(GOFILES) .PHONY: fmt-check fmt-check: @diff=$$($(GOFMT) -s -d $(GOFILES)); \ if [ -n "$$diff" ]; then \ echo "Please run 'make fmt' and commit the result:"; \ echo "$${diff}"; \ exit 1; \ fi; .PHONY: view-covered view-covered: $(GOTEST) -coverprofile=cover.out $(TARGET) $(GOCMD) tool cover -html=cover.out ================================================ FILE: vendor/github.com/swaggo/swag/PULL_REQUEST_TEMPLATE.md ================================================ **Describe the PR** e.g. add cool parser. **Relation issue** e.g. https://github.com/swaggo/swag/pull/118/files **Additional context** Add any other context about the problem here. ================================================ FILE: vendor/github.com/swaggo/swag/README.md ================================================ # swag [![Travis Status](https://img.shields.io/travis/swaggo/swag/master.svg)](https://travis-ci.org/swaggo/swag) [![Coverage Status](https://img.shields.io/codecov/c/github/swaggo/swag/master.svg)](https://codecov.io/gh/swaggo/swag) [![Go Report Card](https://goreportcard.com/badge/github.com/swaggo/swag)](https://goreportcard.com/report/github.com/swaggo/swag) [![codebeat badge](https://codebeat.co/badges/71e2f5e5-9e6b-405d-baf9-7cc8b5037330)](https://codebeat.co/projects/github-com-swaggo-swag-master) [![Go Doc](https://godoc.org/github.com/swaggo/swagg?status.svg)](https://godoc.org/github.com/swaggo/swag) [![Backers on Open Collective](https://opencollective.com/swag/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/swag/sponsors/badge.svg)](#sponsors) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fswaggo%2Fswag.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fswaggo%2Fswag?ref=badge_shield) [![Release](https://img.shields.io/github/release/swaggo/swag.svg?style=flat-square)](https://github.com/swaggo/swag/releases) Swag converts Go annotations to Swagger Documentation 2.0. We've created a variety of plugins for popular [Go web frameworks](#supported-web-frameworks). This allows you to quickly integrate with an existing Go project (using Swagger UI). ## Contents - [Getting started](#getting-started) - [Supported Web Frameworks](#supported-web-frameworks) - [How to use it with Gin](#how-to-use-it-with-gin) - [Implementation Status](#implementation-status) - [Declarative Comments Format](#declarative-comments-format) - [General API Info](#general-api-info) - [API Operation](#api-operation) - [Security](#security) - [Examples](#examples) - [Descriptions over multiple lines](#descriptions-over-multiple-lines) - [User defined structure with an array type](#user-defined-structure-with-an-array-type) - [Add a headers in response](#add-a-headers-in-response) - [Use multiple path params](#use-multiple-path-params) - [Example value of struct](#example-value-of-struct) - [Description of struct](#description-of-struct) - [Use swaggertype tag to supported custom type](#use-swaggertype-tag-to-supported-custom-type) - [Add extension info to struct field](#add-extension-info-to-struct-field) - [How to using security annotations](#how-to-using-security-annotations) - [About the Project](#about-the-project) ## Getting started 1. Add comments to your API source code, See [Declarative Comments Format](#declarative-comments-format). 2. Download swag by using: ```sh $ go get -u github.com/swaggo/swag/cmd/swag ``` To build from source you need [Go](https://golang.org/dl/) (1.9 or newer). Or download the pre-compiled binaries binray form [release page](https://github.com/swaggo/swag/releases). 3. Run `swag init` in the project's root folder which contains the `main.go` file. This will parse your comments and generate the required files (`docs` folder and `docs/docs.go`). ```sh $ swag init ``` Make sure to import the generated `docs/docs.go` so that your specific configuration gets `init`'ed. If your General API annotations do not live in `main.go`, you can let swag know with `-g` flag. ```sh swag init -g http/api.go ``` ## swag cli ```sh $ swag init -h NAME: swag init - Create docs.go USAGE: swag init [command options] [arguments...] OPTIONS: --generalInfo value, -g value Go file path in which 'swagger general API Info' is written (default: "main.go") --dir value, -d value Directory you want to parse (default: "./") --propertyStrategy value, -p value Property Naming Strategy like snakecase,camelcase,pascalcase (default: "camelcase") --output value, -o value Output directory for al the generated files(swagger.json, swagger.yaml and doc.go) (default: "./docs") --parseVendor Parse go files in 'vendor' folder, disabled by default ``` ## Supported Web Frameworks - [gin](http://github.com/swaggo/gin-swagger) - [echo](http://github.com/swaggo/echo-swagger) - [buffalo](https://github.com/swaggo/buffalo-swagger) - [net/http](https://github.com/swaggo/http-swagger) ## How to use it with Gin Find the example source code [here](https://github.com/swaggo/swag/tree/master/example/celler). 1. After using `swag init` to generate Swagger 2.0 docs, import the following packages: ```go import "github.com/swaggo/gin-swagger" // gin-swagger middleware import "github.com/swaggo/gin-swagger/swaggerFiles" // swagger embed files ``` 2. Add [General API](#general-api-info) annotations in `main.go` code: ```go // @title Swagger Example API // @version 1.0 // @description This is a sample server celler server. // @termsOfService http://swagger.io/terms/ // @contact.name API Support // @contact.url http://www.swagger.io/support // @contact.email support@swagger.io // @license.name Apache 2.0 // @license.url http://www.apache.org/licenses/LICENSE-2.0.html // @host localhost:8080 // @BasePath /api/v1 // @securityDefinitions.basic BasicAuth // @securityDefinitions.apikey ApiKeyAuth // @in header // @name Authorization // @securitydefinitions.oauth2.application OAuth2Application // @tokenUrl https://example.com/oauth/token // @scope.write Grants write access // @scope.admin Grants read and write access to administrative information // @securitydefinitions.oauth2.implicit OAuth2Implicit // @authorizationurl https://example.com/oauth/authorize // @scope.write Grants write access // @scope.admin Grants read and write access to administrative information // @securitydefinitions.oauth2.password OAuth2Password // @tokenUrl https://example.com/oauth/token // @scope.read Grants read access // @scope.write Grants write access // @scope.admin Grants read and write access to administrative information // @securitydefinitions.oauth2.accessCode OAuth2AccessCode // @tokenUrl https://example.com/oauth/token // @authorizationurl https://example.com/oauth/authorize // @scope.admin Grants read and write access to administrative information func main() { r := gin.Default() c := controller.NewController() v1 := r.Group("/api/v1") { accounts := v1.Group("/accounts") { accounts.GET(":id", c.ShowAccount) accounts.GET("", c.ListAccounts) accounts.POST("", c.AddAccount) accounts.DELETE(":id", c.DeleteAccount) accounts.PATCH(":id", c.UpdateAccount) accounts.POST(":id/images", c.UploadAccountImage) } //... } r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) r.Run(":8080") } //... ``` Additionally some general API info can be set dynamically. The generated code package `docs` exports `SwaggerInfo` variable which we can use to set the title, description, version, host and base path programatically. Example using Gin: ```go package main import ( "github.com/gin-gonic/gin" "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" "./docs" // docs is generated by Swag CLI, you have to import it. ) // @contact.name API Support // @contact.url http://www.swagger.io/support // @contact.email support@swagger.io // @license.name Apache 2.0 // @license.url http://www.apache.org/licenses/LICENSE-2.0.html // @termsOfService http://swagger.io/terms/ func main() { // programatically set swagger info docs.SwaggerInfo.Title = "Swagger Example API" docs.SwaggerInfo.Description = "This is a sample server Petstore server." docs.SwaggerInfo.Version = "1.0" docs.SwaggerInfo.Host = "petstore.swagger.io" docs.SwaggerInfo.BasePath = "/v2" r := gin.New() // use ginSwagger middleware to serve the API docs r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) r.Run() } ``` 3. Add [API Operation](#api-operation) annotations in `controller` code ``` go package controller import ( "fmt" "net/http" "strconv" "github.com/gin-gonic/gin" "github.com/swaggo/swag/example/celler/httputil" "github.com/swaggo/swag/example/celler/model" ) // ShowAccount godoc // @Summary Show a account // @Description get string by ID // @ID get-string-by-int // @Accept json // @Produce json // @Param id path int true "Account ID" // @Success 200 {object} model.Account // @Header 200 {string} Token "qwerty" // @Failure 400 {object} httputil.HTTPError // @Failure 404 {object} httputil.HTTPError // @Failure 500 {object} httputil.HTTPError // @Router /accounts/{id} [get] func (c *Controller) ShowAccount(ctx *gin.Context) { id := ctx.Param("id") aid, err := strconv.Atoi(id) if err != nil { httputil.NewError(ctx, http.StatusBadRequest, err) return } account, err := model.AccountOne(aid) if err != nil { httputil.NewError(ctx, http.StatusNotFound, err) return } ctx.JSON(http.StatusOK, account) } // ListAccounts godoc // @Summary List accounts // @Description get accounts // @Accept json // @Produce json // @Param q query string false "name search by q" // @Success 200 {array} model.Account // @Header 200 {string} Token "qwerty" // @Failure 400 {object} httputil.HTTPError // @Failure 404 {object} httputil.HTTPError // @Failure 500 {object} httputil.HTTPError // @Router /accounts [get] func (c *Controller) ListAccounts(ctx *gin.Context) { q := ctx.Request.URL.Query().Get("q") accounts, err := model.AccountsAll(q) if err != nil { httputil.NewError(ctx, http.StatusNotFound, err) return } ctx.JSON(http.StatusOK, accounts) } //... ``` ```console $ swag init ``` 4.Run your app, and browse to http://localhost:8080/swagger/index.html. You will see Swagger 2.0 Api documents as shown below: ![swagger_index.html](https://raw.githubusercontent.com/swaggo/swag/master/assets/swagger-image.png) ## Implementation Status [Swagger 2.0 document](https://swagger.io/docs/specification/2-0/basic-structure/) - [x] Basic Structure - [x] API Host and Base Path - [x] Paths and Operations - [x] Describing Parameters - [x] Describing Request Body - [x] Describing Responses - [x] MIME Types - [x] Authentication - [x] Basic Authentication - [x] API Keys - [x] Adding Examples - [x] File Upload - [x] Enums - [x] Grouping Operations With Tags - [ ] Swagger Extensions # Declarative Comments Format ## General API Info **Example** [celler/main.go](https://github.com/swaggo/swag/blob/master/example/celler/main.go) | annotation | description | example | |-------------|--------------------------------------------|---------------------------------| | title | **Required.** The title of the application.| // @title Swagger Example API | | version | **Required.** Provides the version of the application API.| // @version 1.0 | | description | A short description of the application. |// @description This is a sample server celler server. | | tag.name | Name of a tag.| // @tag.name This is the name of the tag | | tag.description | Description of the tag | // @tag.description Cool Description | | tag.docs.url | Url of the external Documentation of the tag | // @tag.docs.url https://example.com| | tag.docs.descripiton | Description of the external Documentation of the tag| // @tag.docs.descirption Best example documentation | | termsOfService | The Terms of Service for the API.| // @termsOfService http://swagger.io/terms/ | | contact.name | The contact information for the exposed API.| // @contact.name API Support | | contact.url | The URL pointing to the contact information. MUST be in the format of a URL. | // @contact.url http://www.swagger.io/support| | contact.email| The email address of the contact person/organization. MUST be in the format of an email address.| // @contact.email support@swagger.io | | license.name | **Required.** The license name used for the API.|// @license.name Apache 2.0| | license.url | A URL to the license used for the API. MUST be in the format of a URL. | // @license.url http://www.apache.org/licenses/LICENSE-2.0.html | | host | The host (name or ip) serving the API. | // @host localhost:8080 | | BasePath | The base path on which the API is served. | // @BasePath /api/v1 | | schemes | The transfer protocol for the operation that separated by spaces. | // @schemes http https | ## API Operation **Example** [celler/controller](https://github.com/swaggo/swag/tree/master/example/celler/controller) | annotation | description | |--------------------|----------------------------------------------------------------------------------------------------------------------------| | description | A verbose explanation of the operation behavior. | | id | A unique string used to identify the operation. Must be unique among all API operations. | | tags | A list of tags to each API operation that separated by commas. | | summary | A short summary of what the operation does. | | accept | A list of MIME types the APIs can consume. Value MUST be as described under [Mime Types](#mime-types). | | produce | A list of MIME types the APIs can produce. Value MUST be as described under [Mime Types](#mime-types). | | param | Parameters that separated by spaces. `param name`,`param type`,`data type`,`is mandatory?`,`comment` `attribute(optional)` | | security | [Security](#security) to each API operation. | | success | Success response that separated by spaces. `return code`,`{param type}`,`data type`,`comment` | | failure | Failure response that separated by spaces. `return code`,`{param type}`,`data type`,`comment` | | header | Header in response that separated by spaces. `return code`,`{param type}`,`data type`,`comment` | | router | Path definition that separated by spaces. `path`,`[httpMethod]` | ## Mime Types `swag` accepts all MIME Types which are in the correct format, that is, match `*/*`. Besides that, `swag` also accepts aliases for some MIME Types as follows: | Alias | MIME Type | |-----------------------|-----------------------------------| | json | application/json | | xml | text/xml | | plain | text/plain | | html | text/html | | mpfd | multipart/form-data | | x-www-form-urlencoded | application/x-www-form-urlencoded | | json-api | application/vnd.api+json | | json-stream | application/x-json-stream | | octet-stream | application/octet-stream | | png | image/png | | jpeg | image/jpeg | | gif | image/gif | ## Param Type - query - path - header - body - formData ## Data Type - string (string) - integer (int, uint, uint32, uint64) - number (float32) - boolean (bool) - user defined struct ## Security | annotation | description | parameters | example | |------------|-------------|------------|---------| | securitydefinitions.basic | [Basic](https://swagger.io/docs/specification/2-0/authentication/basic-authentication/) auth. | | // @securityDefinitions.basic BasicAuth | | securitydefinitions.apikey | [API key](https://swagger.io/docs/specification/2-0/authentication/api-keys/) auth. | in, name | // @securityDefinitions.apikey ApiKeyAuth | | securitydefinitions.oauth2.application | [OAuth2 application](https://swagger.io/docs/specification/authentication/oauth2/) auth. | tokenUrl, scope | // @securitydefinitions.oauth2.application OAuth2Application | | securitydefinitions.oauth2.implicit | [OAuth2 implicit](https://swagger.io/docs/specification/authentication/oauth2/) auth. | authorizationUrl, scope | // @securitydefinitions.oauth2.implicit OAuth2Implicit | | securitydefinitions.oauth2.password | [OAuth2 password](https://swagger.io/docs/specification/authentication/oauth2/) auth. | tokenUrl, scope | // @securitydefinitions.oauth2.password OAuth2Password | | securitydefinitions.oauth2.accessCode | [OAuth2 access code](https://swagger.io/docs/specification/authentication/oauth2/) auth. | tokenUrl, authorizationUrl, scope | // @securitydefinitions.oauth2.accessCode OAuth2AccessCode | | parameters annotation | example | |-----------------------|----------------------------------------------------------| | in | // @in header | | name | // @name Authorization | | tokenUrl | // @tokenUrl https://example.com/oauth/token | | authorizationurl | // @authorizationurl https://example.com/oauth/authorize | | scope.hoge | // @scope.write Grants write access | ## Attribute ```go // @Param enumstring query string false "string enums" Enums(A, B, C) // @Param enumint query int false "int enums" Enums(1, 2, 3) // @Param enumnumber query number false "int enums" Enums(1.1, 1.2, 1.3) // @Param string query string false "string valid" minlength(5) maxlength(10) // @Param int query int false "int valid" mininum(1) maxinum(10) // @Param default query string false "string default" default(A) ``` It also works for the struct fields: ```go type Foo struct { Bar string `minLength:"4" maxLength:"16"` Baz int `minimum:"10" maximum:"20" default:"15"` Qux []string `enums:"foo,bar,baz"` } ``` ### Available Field Name | Type | Description ---|:---:|--- default | * | Declares the value of the parameter that the server will use if none is provided, for example a "count" to control the number of results per page might default to 100 if not supplied by the client in the request. (Note: "default" has no meaning for required parameters.) See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2. Unlike JSON Schema this value MUST conform to the defined [`type`](#parameterType) for this parameter. maximum | `number` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.2. minimum | `number` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.3. maxLength | `integer` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.1. minLength | `integer` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.2. enums | [\*] | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1. format | `string` | The extending format for the previously mentioned [`type`](#parameterType). See [Data Type Formats](#dataTypeFormat) for further details. ### Future Field Name | Type | Description ---|:---:|--- multipleOf | `number` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.1. pattern | `string` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3. maxItems | `integer` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.3.2. minItems | `integer` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.3.3. uniqueItems | `boolean` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.3.4. collectionFormat | `string` | Determines the format of the array if type array is used. Possible values are:
  • `csv` - comma separated values `foo,bar`.
  • `ssv` - space separated values `foo bar`.
  • `tsv` - tab separated values `foo\tbar`.
  • `pipes` - pipe separated values foo|bar.
  • `multi` - corresponds to multiple parameter instances instead of multiple values for a single instance `foo=bar&foo=baz`. This is valid only for parameters [`in`](#parameterIn) "query" or "formData".
Default value is `csv`. ## Examples ### Descriptions over multiple lines You can add descriptions spanning multiple lines in either the general api description or routes definitions like so: ```go // @description This is the first line // @description This is the second line // @description And so forth. ``` ### User defined structure with an array type ```go // @Success 200 {array} model.Account <-- This is a user defined struct. ``` ```go package model type Account struct { ID int `json:"id" example:"1"` Name string `json:"name" example:"account name"` } ``` ### Add a headers in response ```go // @Success 200 {string} string "ok" // @Header 200 {string} Location "/entity/1" // @Header 200 {string} Token "qwerty" ``` ### Use multiple path params ```go /// ... // @Param group_id path int true "Group ID" // @Param account_id path int true "Account ID" // ... // @Router /examples/groups/{group_id}/accounts/{account_id} [get] ``` ### Example value of struct ```go type Account struct { ID int `json:"id" example:"1"` Name string `json:"name" example:"account name"` PhotoUrls []string `json:"photo_urls" example:"http://test/image/1.jpg,http://test/image/2.jpg"` } ``` ### Description of struct ```go type Account struct { // ID this is userid ID int `json:"id"` Name string `json:"name"` // This is Name } ``` ### Use swaggertype tag to supported custom type [#201](https://github.com/swaggo/swag/issues/201#issuecomment-475479409) ```go type TimestampTime struct { time.Time } ///implement encoding.JSON.Marshaler interface func (t *TimestampTime) MarshalJSON() ([]byte, error) { bin := make([]byte, 16) bin = strconv.AppendInt(bin[:0], t.Time.Unix(), 10) return bin, nil } func (t *TimestampTime) UnmarshalJSON(bin []byte) error { v, err := strconv.ParseInt(string(bin), 10, 64) if err != nil { return err } t.Time = time.Unix(v, 0) return nil } /// type Account struct { // Override primitive type by simply specifying it via `swaggertype` tag ID sql.NullInt64 `json:"id" swaggertype:"integer"` // Override struct type to a primitive type 'integer' by specifying it via `swaggertype` tag RegisterTime TimestampTime `json:"register_time" swaggertype:"primitive,integer"` // Array types can be overridden using "array," format Coeffs []big.Float `json:"coeffs" swaggertype:"array,number"` } ``` ### Add extension info to struct field ```go type Account struct { ID int `json:"id" extensions:"x-nullable,x-abc=def"` // extensions fields must start with "x-" } ``` generate swagger doc as follows: ```go "Account": { "type": "object", "properties": { "id": { "type": "string", "x-nullable": true, "x-abc": "def" } } } ``` ### How to using security annotations General API info. ```go // @securityDefinitions.basic BasicAuth // @securitydefinitions.oauth2.application OAuth2Application // @tokenUrl https://example.com/oauth/token // @scope.write Grants write access // @scope.admin Grants read and write access to administrative information ``` Each API operation. ```go // @Security ApiKeyAuth ``` Make it AND condition ```go // @Security ApiKeyAuth // @Security OAuth2Application[write, admin] ``` ## About the Project This project was inspired by [yvasiyarov/swagger](https://github.com/yvasiyarov/swagger) but we simplified the usage and added support a variety of [web frameworks](#supported-web-frameworks). Gopher image source is [tenntenn/gopher-stickers](https://github.com/tenntenn/gopher-stickers). It has licenses [creative commons licensing](http://creativecommons.org/licenses/by/3.0/deed.en). ## Contributors This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. ## Backers Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/swag#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/swag#sponsor)] ## License [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fswaggo%2Fswag.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fswaggo%2Fswag?ref=badge_large) ================================================ FILE: vendor/github.com/swaggo/swag/debug.go ================================================ package swag import ( "log" ) const ( test = iota release ) var swagMode = release func isRelease() bool { return swagMode == release } // Println calls Output to print to the standard logger when release mode. func Println(v ...interface{}) { if isRelease() { log.Println(v...) } } // Printf calls Output to print to the standard logger when release mode. func Printf(format string, v ...interface{}) { if isRelease() { log.Printf(format, v...) } } ================================================ FILE: vendor/github.com/swaggo/swag/doc.go ================================================ /* Package swag converts Go annotations to Swagger Documentation 2.0. See https://github.com/swaggo/swag for more information about swag. */ package swag // import "github.com/swaggo/swag" ================================================ FILE: vendor/github.com/swaggo/swag/go.mod ================================================ module github.com/swaggo/swag require ( github.com/ghodss/yaml v1.0.0 github.com/go-openapi/jsonreference v0.19.0 github.com/go-openapi/spec v0.19.0 github.com/pkg/errors v0.8.1 github.com/urfave/cli v1.20.0 golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468 ) ================================================ FILE: vendor/github.com/swaggo/swag/go.sum ================================================ github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-openapi/jsonpointer v0.17.0 h1:nH6xp8XdXHx8dqveo0ZuJBluCO2qGrPbDNZ0dwoRHP0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.0 h1:BqWKpV1dFd+AuiKlgtddwVIFQsuMpxfBDBHGfM2yNpk= github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/spec v0.19.0 h1:A4SZ6IWh3lnjH0rG0Z5lkxazMGBECtrZcbyYQi+64k4= github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/swag v0.17.0 h1:iqrgMg7Q7SvtbWLlltPrkMs0UBJI6oTSs79JFRUi880= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468 h1:fTfk6GjmihJbK0mSUFgPPgYpsdmApQ86Mcd4GuKax9U= golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= ================================================ FILE: vendor/github.com/swaggo/swag/license ================================================ MIT License Copyright (c) 2017 Eason Lin 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. ================================================ FILE: vendor/github.com/swaggo/swag/operation.go ================================================ package swag import ( "fmt" "go/ast" goparser "go/parser" "go/token" "net/http" "os" "regexp" "strconv" "strings" "github.com/go-openapi/jsonreference" "github.com/go-openapi/spec" "github.com/pkg/errors" "golang.org/x/tools/go/loader" ) // Operation describes a single API operation on a path. // For more information: https://github.com/swaggo/swag#api-operation type Operation struct { HTTPMethod string Path string spec.Operation parser *Parser } var mimeTypeAliases = map[string]string{ "json": "application/json", "xml": "text/xml", "plain": "text/plain", "html": "text/html", "mpfd": "multipart/form-data", "x-www-form-urlencoded": "application/x-www-form-urlencoded", "json-api": "application/vnd.api+json", "json-stream": "application/x-json-stream", "octet-stream": "application/octet-stream", "png": "image/png", "jpeg": "image/jpeg", "gif": "image/gif", } var mimeTypePattern = regexp.MustCompile("^[^/]+/[^/]+$") // NewOperation creates a new Operation with default properties. // map[int]Response func NewOperation() *Operation { return &Operation{ HTTPMethod: "get", Operation: spec.Operation{ OperationProps: spec.OperationProps{}, }, } } // ParseComment parses comment for given comment string and returns error if error occurs. func (operation *Operation) ParseComment(comment string, astFile *ast.File) error { commentLine := strings.TrimSpace(strings.TrimLeft(comment, "//")) if len(commentLine) == 0 { return nil } attribute := strings.Fields(commentLine)[0] lineRemainder := strings.TrimSpace(commentLine[len(attribute):]) switch strings.ToLower(attribute) { case "@description": if operation.Description == "" { operation.Description = lineRemainder } else { operation.Description += "\n" + lineRemainder } case "@summary": operation.Summary = lineRemainder case "@id": operation.ID = lineRemainder case "@tags": operation.ParseTagsComment(lineRemainder) case "@accept": if err := operation.ParseAcceptComment(lineRemainder); err != nil { return err } case "@produce": if err := operation.ParseProduceComment(lineRemainder); err != nil { return err } case "@param": if err := operation.ParseParamComment(lineRemainder, astFile); err != nil { return err } case "@success", "@failure": if err := operation.ParseResponseComment(lineRemainder, astFile); err != nil { if err := operation.ParseEmptyResponseComment(lineRemainder); err != nil { if err := operation.ParseEmptyResponseOnly(lineRemainder); err != nil { return err } } } case "@header": if err := operation.ParseResponseHeaderComment(lineRemainder, astFile); err != nil { return err } case "@router": if err := operation.ParseRouterComment(lineRemainder); err != nil { return err } case "@security": if err := operation.ParseSecurityComment(lineRemainder); err != nil { return err } } return nil } var paramPattern = regexp.MustCompile(`(\S+)[\s]+([\w]+)[\s]+([\S.]+)[\s]+([\w]+)[\s]+"([^"]+)"`) // ParseParamComment parses params return []string of param properties // E.g. @Param queryText form string true "The email for login" // [param name] [paramType] [data type] [is mandatory?] [Comment] // E.g. @Param some_id path int true "Some ID" func (operation *Operation) ParseParamComment(commentLine string, astFile *ast.File) error { matches := paramPattern.FindStringSubmatch(commentLine) if len(matches) != 6 { return fmt.Errorf("missing required param comment parameters \"%s\"", commentLine) } name := matches[1] paramType := matches[2] schemaType := matches[3] requiredText := strings.ToLower(matches[4]) required := requiredText == "true" || requiredText == "required" description := matches[5] var param spec.Parameter //five possible parameter types. switch paramType { case "query", "path", "header": param = createParameter(paramType, description, name, TransToValidSchemeType(schemaType), required) case "body": param = createParameter(paramType, description, name, "object", required) // TODO: if Parameter types can be objects, but also primitives and arrays if err := operation.registerSchemaType(schemaType, astFile); err != nil { return err } param.Schema.Ref = spec.Ref{ Ref: jsonreference.MustCreateRef("#/definitions/" + schemaType), } case "formData": param = createParameter(paramType, description, name, TransToValidSchemeType(schemaType), required) default: return fmt.Errorf("%s is not supported paramType", paramType) } if err := operation.parseAndExtractionParamAttribute(commentLine, schemaType, ¶m); err != nil { return err } operation.Operation.Parameters = append(operation.Operation.Parameters, param) return nil } func (operation *Operation) registerSchemaType(schemaType string, astFile *ast.File) error { refSplit := strings.Split(schemaType, ".") if len(refSplit) != 2 { return nil } pkgName := refSplit[0] typeName := refSplit[1] if typeSpec, ok := operation.parser.TypeDefinitions[pkgName][typeName]; ok { operation.parser.registerTypes[schemaType] = typeSpec return nil } var typeSpec *ast.TypeSpec if astFile == nil { return fmt.Errorf("can not register schema type: %q reason: astFile == nil", schemaType) } for _, imp := range astFile.Imports { if imp.Name != nil && imp.Name.Name == pkgName { // the import had an alias that matched break } impPath := strings.Replace(imp.Path.Value, `"`, ``, -1) if strings.HasSuffix(impPath, "/"+pkgName) { var err error typeSpec, err = findTypeDef(impPath, typeName) if err != nil { return errors.Wrapf(err, "can not find type def: %q", schemaType) } break } } if typeSpec == nil { return fmt.Errorf("can not find schema type: %q", schemaType) } if _, ok := operation.parser.TypeDefinitions[pkgName]; !ok { operation.parser.TypeDefinitions[pkgName] = make(map[string]*ast.TypeSpec) } operation.parser.TypeDefinitions[pkgName][typeName] = typeSpec operation.parser.registerTypes[schemaType] = typeSpec return nil } var regexAttributes = map[string]*regexp.Regexp{ // for Enums(A, B) "enums": regexp.MustCompile(`(?i)enums\(.*\)`), // for Minimum(0) "maxinum": regexp.MustCompile(`(?i)maxinum\(.*\)`), // for Maximum(0) "mininum": regexp.MustCompile(`(?i)mininum\(.*\)`), // for Maximum(0) "default": regexp.MustCompile(`(?i)default\(.*\)`), // for minlength(0) "minlength": regexp.MustCompile(`(?i)minlength\(.*\)`), // for maxlength(0) "maxlength": regexp.MustCompile(`(?i)maxlength\(.*\)`), // for format(email) "format": regexp.MustCompile(`(?i)format\(.*\)`), } func (operation *Operation) parseAndExtractionParamAttribute(commentLine, schemaType string, param *spec.Parameter) error { schemaType = TransToValidSchemeType(schemaType) for attrKey, re := range regexAttributes { switch attrKey { case "enums": enums, err := findAttrList(re, commentLine) if err != nil { break } for _, e := range enums { e = strings.TrimSpace(e) value, err := defineType(schemaType, e) if err != nil { return err } param.Enum = append(param.Enum, value) } case "maxinum": attr, err := findAttr(re, commentLine) if err != nil { break } if schemaType != "integer" && schemaType != "number" { return fmt.Errorf("maxinum is attribute to set to a number. comment=%s got=%s", commentLine, schemaType) } n, err := strconv.ParseFloat(attr, 64) if err != nil { return fmt.Errorf("maximum is allow only a number. comment=%s got=%s", commentLine, attr) } param.Maximum = &n case "mininum": attr, err := findAttr(re, commentLine) if err != nil { break } if schemaType != "integer" && schemaType != "number" { return fmt.Errorf("mininum is attribute to set to a number. comment=%s got=%s", commentLine, schemaType) } n, err := strconv.ParseFloat(attr, 64) if err != nil { return fmt.Errorf("mininum is allow only a number got=%s", attr) } param.Minimum = &n case "default": attr, err := findAttr(re, commentLine) if err != nil { break } value, err := defineType(schemaType, attr) if err != nil { return nil } param.Default = value case "maxlength": attr, err := findAttr(re, commentLine) if err != nil { break } if schemaType != "string" { return fmt.Errorf("maxlength is attribute to set to a number. comment=%s got=%s", commentLine, schemaType) } n, err := strconv.ParseInt(attr, 10, 64) if err != nil { return fmt.Errorf("maxlength is allow only a number got=%s", attr) } param.MaxLength = &n case "minlength": attr, err := findAttr(re, commentLine) if err != nil { break } if schemaType != "string" { return fmt.Errorf("maxlength is attribute to set to a number. comment=%s got=%s", commentLine, schemaType) } n, err := strconv.ParseInt(attr, 10, 64) if err != nil { return fmt.Errorf("minlength is allow only a number got=%s", attr) } param.MinLength = &n case "format": attr, err := findAttr(re, commentLine) if err != nil { break } param.Format = attr } } return nil } func findAttr(re *regexp.Regexp, commentLine string) (string, error) { attr := re.FindString(commentLine) l := strings.Index(attr, "(") r := strings.Index(attr, ")") if l == -1 || r == -1 { return "", fmt.Errorf("can not find regex=%s, comment=%s", re.String(), commentLine) } return strings.TrimSpace(attr[l+1 : r]), nil } func findAttrList(re *regexp.Regexp, commentLine string) ([]string, error) { attr, err := findAttr(re, commentLine) if err != nil { return []string{""}, err } return strings.Split(attr, ","), nil } // defineType enum value define the type (object and array unsupported) func defineType(schemaType string, value string) (interface{}, error) { schemaType = TransToValidSchemeType(schemaType) switch schemaType { case "string": return value, nil case "number": v, err := strconv.ParseFloat(value, 64) if err != nil { return nil, fmt.Errorf("enum value %s can't convert to %s err: %s", value, schemaType, err) } return v, nil case "integer": v, err := strconv.Atoi(value) if err != nil { return nil, fmt.Errorf("enum value %s can't convert to %s err: %s", value, schemaType, err) } return v, nil case "boolean": v, err := strconv.ParseBool(value) if err != nil { return nil, fmt.Errorf("enum value %s can't convert to %s err: %s", value, schemaType, err) } return v, nil default: return nil, fmt.Errorf("%s is unsupported type in enum value", schemaType) } } // ParseTagsComment parses comment for given `tag` comment string. func (operation *Operation) ParseTagsComment(commentLine string) { tags := strings.Split(commentLine, ",") for _, tag := range tags { operation.Tags = append(operation.Tags, strings.TrimSpace(tag)) } } // ParseAcceptComment parses comment for given `accept` comment string. func (operation *Operation) ParseAcceptComment(commentLine string) error { return parseMimeTypeList(commentLine, &operation.Consumes, "%v accept type can't be accepted") } // ParseProduceComment parses comment for given `produce` comment string. func (operation *Operation) ParseProduceComment(commentLine string) error { return parseMimeTypeList(commentLine, &operation.Produces, "%v produce type can't be accepted") } // parseMimeTypeList parses a list of MIME Types for a comment like // `produce` (`Content-Type:` response header) or // `accept` (`Accept:` request header) func parseMimeTypeList(mimeTypeList string, typeList *[]string, format string) error { mimeTypes := strings.Split(mimeTypeList, ",") for _, typeName := range mimeTypes { if mimeTypePattern.MatchString(typeName) { *typeList = append(*typeList, typeName) continue } if aliasMimeType, ok := mimeTypeAliases[typeName]; ok { *typeList = append(*typeList, aliasMimeType) continue } return fmt.Errorf(format, typeName) } return nil } var routerPattern = regexp.MustCompile(`([\w\.\/\-{}\+]+)[^\[]+\[([^\]]+)`) // ParseRouterComment parses comment for gived `router` comment string. func (operation *Operation) ParseRouterComment(commentLine string) error { var matches []string if matches = routerPattern.FindStringSubmatch(commentLine); len(matches) != 3 { return fmt.Errorf("can not parse router comment \"%s\"", commentLine) } path := matches[1] httpMethod := matches[2] operation.Path = path operation.HTTPMethod = strings.ToUpper(httpMethod) return nil } // ParseSecurityComment parses comment for gived `security` comment string. func (operation *Operation) ParseSecurityComment(commentLine string) error { securitySource := commentLine[strings.Index(commentLine, "@Security")+1:] l := strings.Index(securitySource, "[") r := strings.Index(securitySource, "]") // exists scope if !(l == -1 && r == -1) { scopes := securitySource[l+1 : r] s := []string{} for _, scope := range strings.Split(scopes, ",") { scope = strings.TrimSpace(scope) s = append(s, scope) } securityKey := securitySource[0:l] securityMap := map[string][]string{} securityMap[securityKey] = append(securityMap[securityKey], s...) operation.Security = append(operation.Security, securityMap) } else { securityKey := strings.TrimSpace(securitySource) securityMap := map[string][]string{} securityMap[securityKey] = []string{} operation.Security = append(operation.Security, securityMap) } return nil } // findTypeDef attempts to find the *ast.TypeSpec for a specific type given the // type's name and the package's import path // TODO: improve finding external pkg func findTypeDef(importPath, typeName string) (*ast.TypeSpec, error) { cwd, err := os.Getwd() if err != nil { return nil, err } conf := loader.Config{ ParserMode: goparser.SpuriousErrors, Cwd: cwd, } conf.Import(importPath) lprog, err := conf.Load() if err != nil { return nil, err } // If the pkg is vendored, the actual pkg path is going to resemble // something like "{importPath}/vendor/{importPath}" for k := range lprog.AllPackages { realPkgPath := k.Path() if strings.Contains(realPkgPath, "vendor/"+importPath) { importPath = realPkgPath } } pkgInfo := lprog.Package(importPath) if pkgInfo == nil { return nil, errors.New("package was nil") } // TODO: possibly cache pkgInfo since it's an expensive operation for i := range pkgInfo.Files { for _, astDeclaration := range pkgInfo.Files[i].Decls { if generalDeclaration, ok := astDeclaration.(*ast.GenDecl); ok && generalDeclaration.Tok == token.TYPE { for _, astSpec := range generalDeclaration.Specs { if typeSpec, ok := astSpec.(*ast.TypeSpec); ok { if typeSpec.Name.String() == typeName { return typeSpec, nil } } } } } } return nil, errors.New("type spec not found") } var responsePattern = regexp.MustCompile(`([\d]+)[\s]+([\w\{\}]+)[\s]+([\w\-\.\/]+)[^"]*(.*)?`) // ParseResponseComment parses comment for gived `response` comment string. func (operation *Operation) ParseResponseComment(commentLine string, astFile *ast.File) error { var matches []string if matches = responsePattern.FindStringSubmatch(commentLine); len(matches) != 5 { return fmt.Errorf("can not parse response comment \"%s\"", commentLine) } response := spec.Response{} code, _ := strconv.Atoi(matches[1]) responseDescription := strings.Trim(matches[4], "\"") if responseDescription == "" { responseDescription = http.StatusText(code) } response.Description = responseDescription schemaType := strings.Trim(matches[2], "{}") refType := matches[3] if operation.parser != nil { // checking refType has existing in 'TypeDefinitions' if err := operation.registerSchemaType(refType, astFile); err != nil { return err } } // so we have to know all type in app //TODO: we might omitted schema.type if schemaType equals 'object' response.Schema = &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{schemaType}}} if schemaType == "object" { response.Schema.Ref = spec.Ref{ Ref: jsonreference.MustCreateRef("#/definitions/" + refType), } } if schemaType == "array" { refType = TransToValidSchemeType(refType) if IsPrimitiveType(refType) { response.Schema.Items = &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Type: spec.StringOrArray{refType}, }, }, } } else { response.Schema.Items = &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Ref: spec.Ref{Ref: jsonreference.MustCreateRef("#/definitions/" + refType)}, }, }, } } } if operation.Responses == nil { operation.Responses = &spec.Responses{ ResponsesProps: spec.ResponsesProps{ StatusCodeResponses: make(map[int]spec.Response), }, } } operation.Responses.StatusCodeResponses[code] = response return nil } // ParseResponseHeaderComment parses comment for gived `response header` comment string. func (operation *Operation) ParseResponseHeaderComment(commentLine string, astFile *ast.File) error { var matches []string if matches = responsePattern.FindStringSubmatch(commentLine); len(matches) != 5 { return fmt.Errorf("can not parse response comment \"%s\"", commentLine) } response := spec.Response{} code, _ := strconv.Atoi(matches[1]) responseDescription := strings.Trim(matches[4], "\"") if responseDescription == "" { responseDescription = http.StatusText(code) } response.Description = responseDescription schemaType := strings.Trim(matches[2], "{}") refType := matches[3] if operation.Responses == nil { operation.Responses = &spec.Responses{ ResponsesProps: spec.ResponsesProps{ StatusCodeResponses: make(map[int]spec.Response), }, } } response, responseExist := operation.Responses.StatusCodeResponses[code] if responseExist { header := spec.Header{} header.Description = responseDescription header.Type = schemaType if response.Headers == nil { response.Headers = make(map[string]spec.Header) } response.Headers[refType] = header operation.Responses.StatusCodeResponses[code] = response } return nil } var emptyResponsePattern = regexp.MustCompile(`([\d]+)[\s]+"(.*)"`) // ParseEmptyResponseComment parse only comment out status code and description,eg: @Success 200 "it's ok" func (operation *Operation) ParseEmptyResponseComment(commentLine string) error { var matches []string if matches = emptyResponsePattern.FindStringSubmatch(commentLine); len(matches) != 3 { return fmt.Errorf("can not parse response comment \"%s\"", commentLine) } response := spec.Response{} code, _ := strconv.Atoi(matches[1]) response.Description = strings.Trim(matches[2], "") if operation.Responses == nil { operation.Responses = &spec.Responses{ ResponsesProps: spec.ResponsesProps{ StatusCodeResponses: make(map[int]spec.Response), }, } } operation.Responses.StatusCodeResponses[code] = response return nil } //ParseEmptyResponseOnly parse only comment out status code ,eg: @Success 200 func (operation *Operation) ParseEmptyResponseOnly(commentLine string) error { response := spec.Response{} code, err := strconv.Atoi(commentLine) if err != nil { return fmt.Errorf("can not parse response comment \"%s\"", commentLine) } if operation.Responses == nil { operation.Responses = &spec.Responses{ ResponsesProps: spec.ResponsesProps{ StatusCodeResponses: make(map[int]spec.Response), }, } } operation.Responses.StatusCodeResponses[code] = response return nil } // createParameter returns swagger spec.Parameter for gived paramType, description, paramName, schemaType, required func createParameter(paramType, description, paramName, schemaType string, required bool) spec.Parameter { // //five possible parameter types. query, path, body, header, form paramProps := spec.ParamProps{ Name: paramName, Description: description, Required: required, In: paramType, } if paramType == "body" { paramProps.Schema = &spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{schemaType}, }, } parameter := spec.Parameter{ ParamProps: paramProps, } return parameter } parameter := spec.Parameter{ ParamProps: paramProps, SimpleSchema: spec.SimpleSchema{ Type: schemaType, }, } return parameter } ================================================ FILE: vendor/github.com/swaggo/swag/parser.go ================================================ package swag import ( "fmt" "go/ast" goparser "go/parser" "go/token" "net/http" "os" "path" "path/filepath" "reflect" "sort" "strconv" "strings" "unicode" "github.com/go-openapi/jsonreference" "github.com/go-openapi/spec" "github.com/pkg/errors" ) const ( // CamelCase indicates using CamelCase strategy for struct field. CamelCase = "camelcase" // PascalCase indicates using PascalCase strategy for struct field. PascalCase = "pascalcase" // SnakeCase indicates using SnakeCase strategy for struct field. SnakeCase = "snakecase" ) // Parser implements a parser for Go source files. type Parser struct { // swagger represents the root document object for the API specification swagger *spec.Swagger //files is a map that stores map[real_go_file_path][astFile] files map[string]*ast.File // TypeDefinitions is a map that stores [package name][type name][*ast.TypeSpec] TypeDefinitions map[string]map[string]*ast.TypeSpec // CustomPrimitiveTypes is a map that stores custom primitive types to actual golang types [type name][string] CustomPrimitiveTypes map[string]string //registerTypes is a map that stores [refTypeName][*ast.TypeSpec] registerTypes map[string]*ast.TypeSpec PropNamingStrategy string ParseVendor bool // structStack stores full names of the structures that were already parsed or are being parsed now structStack []string } // New creates a new Parser with default properties. func New() *Parser { parser := &Parser{ swagger: &spec.Swagger{ SwaggerProps: spec.SwaggerProps{ Info: &spec.Info{ InfoProps: spec.InfoProps{ Contact: &spec.ContactInfo{}, License: &spec.License{}, }, }, Paths: &spec.Paths{ Paths: make(map[string]spec.PathItem), }, Definitions: make(map[string]spec.Schema), }, }, files: make(map[string]*ast.File), TypeDefinitions: make(map[string]map[string]*ast.TypeSpec), CustomPrimitiveTypes: make(map[string]string), registerTypes: make(map[string]*ast.TypeSpec), } return parser } // ParseAPI parses general api info for gived searchDir and mainAPIFile func (parser *Parser) ParseAPI(searchDir string, mainAPIFile string) error { Println("Generate general API Info") if err := parser.getAllGoFileInfo(searchDir); err != nil { return err } parser.ParseGeneralAPIInfo(path.Join(searchDir, mainAPIFile)) for _, astFile := range parser.files { parser.ParseType(astFile) } for fileName, astFile := range parser.files { if err := parser.ParseRouterAPIInfo(fileName, astFile); err != nil { return err } } parser.ParseDefinitions() return nil } // ParseGeneralAPIInfo parses general api info for gived mainAPIFile path func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error { fileSet := token.NewFileSet() fileTree, err := goparser.ParseFile(fileSet, mainAPIFile, nil, goparser.ParseComments) if err != nil { return errors.Wrap(err, "cannot parse soure files") } parser.swagger.Swagger = "2.0" securityMap := map[string]*spec.SecurityScheme{} // templated defaults parser.swagger.Info.Version = "{{.Version}}" parser.swagger.Info.Title = "{{.Title}}" parser.swagger.Info.Description = "{{.Description}}" parser.swagger.Host = "{{.Host}}" parser.swagger.BasePath = "{{.BasePath}}" if fileTree.Comments != nil { for _, comment := range fileTree.Comments { comments := strings.Split(comment.Text(), "\n") previousAttribute := "" for _, commentLine := range comments { attribute := strings.ToLower(strings.Split(commentLine, " ")[0]) multilineBlock := false if previousAttribute == attribute { multilineBlock = true } switch attribute { case "@version": parser.swagger.Info.Version = strings.TrimSpace(commentLine[len(attribute):]) case "@title": parser.swagger.Info.Title = strings.TrimSpace(commentLine[len(attribute):]) case "@description": if parser.swagger.Info.Description == "{{.Description}}" { parser.swagger.Info.Description = strings.TrimSpace(commentLine[len(attribute):]) } else if multilineBlock { parser.swagger.Info.Description += "\n" + strings.TrimSpace(commentLine[len(attribute):]) } case "@termsofservice": parser.swagger.Info.TermsOfService = strings.TrimSpace(commentLine[len(attribute):]) case "@contact.name": parser.swagger.Info.Contact.Name = strings.TrimSpace(commentLine[len(attribute):]) case "@contact.email": parser.swagger.Info.Contact.Email = strings.TrimSpace(commentLine[len(attribute):]) case "@contact.url": parser.swagger.Info.Contact.URL = strings.TrimSpace(commentLine[len(attribute):]) case "@license.name": parser.swagger.Info.License.Name = strings.TrimSpace(commentLine[len(attribute):]) case "@license.url": parser.swagger.Info.License.URL = strings.TrimSpace(commentLine[len(attribute):]) case "@host": parser.swagger.Host = strings.TrimSpace(commentLine[len(attribute):]) case "@basepath": parser.swagger.BasePath = strings.TrimSpace(commentLine[len(attribute):]) case "@schemes": parser.swagger.Schemes = getSchemes(commentLine) case "@tag.name": commentInfo := strings.TrimSpace(commentLine[len(attribute):]) parser.swagger.Tags = append(parser.swagger.Tags, spec.Tag{ TagProps: spec.TagProps{ Name: strings.TrimSpace(commentInfo), }, }) case "@tag.description": commentInfo := strings.TrimSpace(commentLine[len(attribute):]) tag := parser.swagger.Tags[len(parser.swagger.Tags)-1] tag.TagProps.Description = commentInfo replaceLastTag(parser.swagger.Tags, tag) case "@tag.docs.url": commentInfo := strings.TrimSpace(commentLine[len(attribute):]) tag := parser.swagger.Tags[len(parser.swagger.Tags)-1] tag.TagProps.ExternalDocs = &spec.ExternalDocumentation{ URL: commentInfo, } replaceLastTag(parser.swagger.Tags, tag) case "@tag.docs.description": commentInfo := strings.TrimSpace(commentLine[len(attribute):]) tag := parser.swagger.Tags[len(parser.swagger.Tags)-1] if tag.TagProps.ExternalDocs == nil { return errors.New("@tag.docs.description needs to come after a @tags.docs.url") } tag.TagProps.ExternalDocs.Description = commentInfo replaceLastTag(parser.swagger.Tags, tag) } previousAttribute = attribute } for i := 0; i < len(comments); i++ { attribute := strings.ToLower(strings.Split(comments[i], " ")[0]) switch attribute { case "@securitydefinitions.basic": securityMap[strings.TrimSpace(comments[i][len(attribute):])] = spec.BasicAuth() case "@securitydefinitions.apikey": attrMap := map[string]string{} for _, v := range comments[i+1:] { securityAttr := strings.ToLower(strings.Split(v, " ")[0]) if securityAttr == "@in" || securityAttr == "@name" { attrMap[securityAttr] = strings.TrimSpace(v[len(securityAttr):]) } // next securityDefinitions if strings.Index(securityAttr, "@securitydefinitions.") == 0 { break } } if len(attrMap) != 2 { return errors.New("@securitydefinitions.apikey is @name and @in required") } securityMap[strings.TrimSpace(comments[i][len(attribute):])] = spec.APIKeyAuth(attrMap["@name"], attrMap["@in"]) case "@securitydefinitions.oauth2.application": attrMap := map[string]string{} scopes := map[string]string{} for _, v := range comments[i+1:] { securityAttr := strings.ToLower(strings.Split(v, " ")[0]) if securityAttr == "@tokenurl" { attrMap[securityAttr] = strings.TrimSpace(v[len(securityAttr):]) } else { isExists, err := isExistsScope(securityAttr) if err != nil { return err } if isExists { scopScheme, err := getScopeScheme(securityAttr) if err != nil { return err } scopes[scopScheme] = v[len(securityAttr):] } } // next securityDefinitions if strings.Index(securityAttr, "@securitydefinitions.") == 0 { break } } if len(attrMap) != 1 { return errors.New("@securitydefinitions.oauth2.application is @tokenUrl required") } securityScheme := spec.OAuth2Application(attrMap["@tokenurl"]) for scope, description := range scopes { securityScheme.AddScope(scope, description) } securityMap[strings.TrimSpace(comments[i][len(attribute):])] = securityScheme case "@securitydefinitions.oauth2.implicit": attrMap := map[string]string{} scopes := map[string]string{} for _, v := range comments[i+1:] { securityAttr := strings.ToLower(strings.Split(v, " ")[0]) if securityAttr == "@authorizationurl" { attrMap[securityAttr] = strings.TrimSpace(v[len(securityAttr):]) } else { isExists, err := isExistsScope(securityAttr) if err != nil { return err } if isExists { scopScheme, err := getScopeScheme(securityAttr) if err != nil { return err } scopes[scopScheme] = v[len(securityAttr):] } } // next securityDefinitions if strings.Index(securityAttr, "@securitydefinitions.") == 0 { break } } if len(attrMap) != 1 { return errors.New("@securitydefinitions.oauth2.implicit is @authorizationUrl required") } securityScheme := spec.OAuth2Implicit(attrMap["@authorizationurl"]) for scope, description := range scopes { securityScheme.AddScope(scope, description) } securityMap[strings.TrimSpace(comments[i][len(attribute):])] = securityScheme case "@securitydefinitions.oauth2.password": attrMap := map[string]string{} scopes := map[string]string{} for _, v := range comments[i+1:] { securityAttr := strings.ToLower(strings.Split(v, " ")[0]) if securityAttr == "@tokenurl" { attrMap[securityAttr] = strings.TrimSpace(v[len(securityAttr):]) } else { isExists, err := isExistsScope(securityAttr) if err != nil { return err } if isExists { scopScheme, err := getScopeScheme(securityAttr) if err != nil { return err } scopes[scopScheme] = v[len(securityAttr):] } } // next securityDefinitions if strings.Index(securityAttr, "@securitydefinitions.") == 0 { break } } if len(attrMap) != 1 { return errors.New("@securitydefinitions.oauth2.password is @tokenUrl required") } securityScheme := spec.OAuth2Password(attrMap["@tokenurl"]) for scope, description := range scopes { securityScheme.AddScope(scope, description) } securityMap[strings.TrimSpace(comments[i][len(attribute):])] = securityScheme case "@securitydefinitions.oauth2.accesscode": attrMap := map[string]string{} scopes := map[string]string{} for _, v := range comments[i+1:] { securityAttr := strings.ToLower(strings.Split(v, " ")[0]) if securityAttr == "@tokenurl" || securityAttr == "@authorizationurl" { attrMap[securityAttr] = strings.TrimSpace(v[len(securityAttr):]) } else { isExists, err := isExistsScope(securityAttr) if err != nil { return err } if isExists { scopScheme, err := getScopeScheme(securityAttr) if err != nil { return err } scopes[scopScheme] = v[len(securityAttr):] } } // next securityDefinitions if strings.Index(securityAttr, "@securitydefinitions.") == 0 { break } } if len(attrMap) != 2 { return errors.New("@securitydefinitions.oauth2.accessCode is @tokenUrl and @authorizationUrl required") } securityScheme := spec.OAuth2AccessToken(attrMap["@authorizationurl"], attrMap["@tokenurl"]) for scope, description := range scopes { securityScheme.AddScope(scope, description) } securityMap[strings.TrimSpace(comments[i][len(attribute):])] = securityScheme } } } } if len(securityMap) > 0 { parser.swagger.SecurityDefinitions = securityMap } return nil } func getScopeScheme(scope string) (string, error) { scopeValue := scope[strings.Index(scope, "@scope."):] if scopeValue == "" { return "", errors.New("@scope is empty") } return scope[len("@scope."):], nil } func isExistsScope(scope string) (bool, error) { s := strings.Fields(scope) for _, v := range s { if strings.Index(v, "@scope.") != -1 { if strings.Index(v, ",") != -1 { return false, fmt.Errorf("@scope can't use comma(,) get=" + v) } } } return strings.Index(scope, "@scope.") != -1, nil } // getSchemes parses swagger schemes for given commentLine func getSchemes(commentLine string) []string { attribute := strings.ToLower(strings.Split(commentLine, " ")[0]) return strings.Split(strings.TrimSpace(commentLine[len(attribute):]), " ") } // ParseRouterAPIInfo parses router api info for given astFile func (parser *Parser) ParseRouterAPIInfo(fileName string, astFile *ast.File) error { for _, astDescription := range astFile.Decls { switch astDeclaration := astDescription.(type) { case *ast.FuncDecl: if astDeclaration.Doc != nil && astDeclaration.Doc.List != nil { operation := NewOperation() //for per 'function' comment, create a new 'Operation' object operation.parser = parser for _, comment := range astDeclaration.Doc.List { if err := operation.ParseComment(comment.Text, astFile); err != nil { return fmt.Errorf("ParseComment error in file %s :%+v", fileName, err) } } var pathItem spec.PathItem var ok bool if pathItem, ok = parser.swagger.Paths.Paths[operation.Path]; !ok { pathItem = spec.PathItem{} } switch strings.ToUpper(operation.HTTPMethod) { case http.MethodGet: pathItem.Get = &operation.Operation case http.MethodPost: pathItem.Post = &operation.Operation case http.MethodDelete: pathItem.Delete = &operation.Operation case http.MethodPut: pathItem.Put = &operation.Operation case http.MethodPatch: pathItem.Patch = &operation.Operation case http.MethodHead: pathItem.Head = &operation.Operation case http.MethodOptions: pathItem.Options = &operation.Operation } parser.swagger.Paths.Paths[operation.Path] = pathItem } } } return nil } // ParseType parses type info for given astFile. func (parser *Parser) ParseType(astFile *ast.File) { if _, ok := parser.TypeDefinitions[astFile.Name.String()]; !ok { parser.TypeDefinitions[astFile.Name.String()] = make(map[string]*ast.TypeSpec) } for _, astDeclaration := range astFile.Decls { if generalDeclaration, ok := astDeclaration.(*ast.GenDecl); ok && generalDeclaration.Tok == token.TYPE { for _, astSpec := range generalDeclaration.Specs { if typeSpec, ok := astSpec.(*ast.TypeSpec); ok { typeName := fmt.Sprintf("%v", typeSpec.Type) // check if its a custom primitive type if IsGolangPrimitiveType(typeName) { parser.CustomPrimitiveTypes[typeSpec.Name.String()] = TransToValidSchemeType(typeName) } else { parser.TypeDefinitions[astFile.Name.String()][typeSpec.Name.String()] = typeSpec } } } } } } func (parser *Parser) isInStructStack(refTypeName string) bool { for _, structName := range parser.structStack { if refTypeName == structName { return true } } return false } // ParseDefinitions parses Swagger Api definitions. func (parser *Parser) ParseDefinitions() { // sort the typeNames so that parsing definitions is deterministic typeNames := make([]string, 0, len(parser.registerTypes)) for refTypeName := range parser.registerTypes { typeNames = append(typeNames, refTypeName) } sort.Strings(typeNames) for _, refTypeName := range typeNames { typeSpec := parser.registerTypes[refTypeName] ss := strings.Split(refTypeName, ".") pkgName := ss[0] parser.structStack = nil parser.ParseDefinition(pkgName, typeSpec.Name.Name, typeSpec) } } // ParseDefinition parses given type spec that corresponds to the type under // given name and package, and populates swagger schema definitions registry // with a schema for the given type func (parser *Parser) ParseDefinition(pkgName, typeName string, typeSpec *ast.TypeSpec) error { refTypeName := fullTypeName(pkgName, typeName) if _, isParsed := parser.swagger.Definitions[refTypeName]; isParsed { Println("Skipping '" + refTypeName + "', already parsed.") return nil } if parser.isInStructStack(refTypeName) { Println("Skipping '" + refTypeName + "', recursion detected.") return nil } parser.structStack = append(parser.structStack, refTypeName) Println("Generating " + refTypeName) schema, err := parser.parseTypeExpr(pkgName, typeName, typeSpec.Type) if err != nil { return err } parser.swagger.Definitions[refTypeName] = schema return nil } func (parser *Parser) collectRequiredFields(pkgName string, properties map[string]spec.Schema, extraRequired []string) (requiredFields []string) { // created sorted list of properties keys so when we iterate over them it's deterministic ks := make([]string, 0, len(properties)) for k := range properties { ks = append(ks, k) } sort.Strings(ks) requiredFields = make([]string, 0) // iterate over keys list instead of map to avoid the random shuffle of the order that go does for maps for _, k := range ks { prop := properties[k] // todo find the pkgName of the property type tname := prop.SchemaProps.Type[0] if _, ok := parser.TypeDefinitions[pkgName][tname]; ok { tspec := parser.TypeDefinitions[pkgName][tname] parser.ParseDefinition(pkgName, tname, tspec) } if tname != "object" { requiredFields = append(requiredFields, prop.SchemaProps.Required...) } properties[k] = prop } if extraRequired != nil { requiredFields = append(requiredFields, extraRequired...) } sort.Strings(requiredFields) return } func fullTypeName(pkgName, typeName string) string { if pkgName != "" { return pkgName + "." + typeName } return typeName } // parseTypeExpr parses given type expression that corresponds to the type under // given name and package, and returns swagger schema for it. func (parser *Parser) parseTypeExpr(pkgName, typeName string, typeExpr ast.Expr) (spec.Schema, error) { //TODO: return pointer to spec.Schema switch expr := typeExpr.(type) { // type Foo struct {...} case *ast.StructType: refTypeName := fullTypeName(pkgName, typeName) if schema, isParsed := parser.swagger.Definitions[refTypeName]; isParsed { return schema, nil } extraRequired := make([]string, 0) properties := make(map[string]spec.Schema) for _, field := range expr.Fields.List { var fieldProps map[string]spec.Schema var requiredFromAnon []string if field.Names == nil { var err error fieldProps, requiredFromAnon, err = parser.parseAnonymousField(pkgName, field) if err != nil { return spec.Schema{}, err } extraRequired = append(extraRequired, requiredFromAnon...) } else { var err error fieldProps, err = parser.parseStruct(pkgName, field) if err != nil { return spec.Schema{}, err } } for k, v := range fieldProps { properties[k] = v } } // collect requireds from our properties and anonymous fields required := parser.collectRequiredFields(pkgName, properties, extraRequired) // unset required from properties because we've collected them for k, prop := range properties { tname := prop.SchemaProps.Type[0] if tname != "object" { prop.SchemaProps.Required = make([]string, 0) } properties[k] = prop } return spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: properties, Required: required, }}, nil // type Foo Baz case *ast.Ident: refTypeName := fullTypeName(pkgName, expr.Name) if _, isParsed := parser.swagger.Definitions[refTypeName]; !isParsed { if typedef, ok := parser.TypeDefinitions[pkgName][expr.Name]; ok { parser.ParseDefinition(pkgName, expr.Name, typedef) } } return parser.swagger.Definitions[refTypeName], nil // type Foo *Baz case *ast.StarExpr: return parser.parseTypeExpr(pkgName, typeName, expr.X) // type Foo []Baz case *ast.ArrayType: itemSchema, err := parser.parseTypeExpr(pkgName, "", expr.Elt) if err != nil { return spec.Schema{}, err } return spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &itemSchema, }, }, }, nil // type Foo pkg.Bar case *ast.SelectorExpr: if xIdent, ok := expr.X.(*ast.Ident); ok { pkgName = xIdent.Name typeName = expr.Sel.Name refTypeName := fullTypeName(pkgName, typeName) if _, isParsed := parser.swagger.Definitions[refTypeName]; !isParsed { typedef := parser.TypeDefinitions[pkgName][typeName] parser.ParseDefinition(pkgName, typeName, typedef) } return parser.swagger.Definitions[refTypeName], nil } // type Foo map[string]Bar case *ast.MapType: itemSchema, err := parser.parseTypeExpr(pkgName, "", expr.Value) if err != nil { return spec.Schema{}, err } return spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, AdditionalProperties: &spec.SchemaOrBool{ Schema: &itemSchema, }, }, }, nil // ... default: Printf("Type definition of type '%T' is not supported yet. Using 'object' instead.\n", typeExpr) } return spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, }, }, nil } type structField struct { name string schemaType string arrayType string formatType string isRequired bool crossPkg string exampleValue interface{} maximum *float64 minimum *float64 maxLength *int64 minLength *int64 enums []interface{} defaultValue interface{} extensions map[string]interface{} } func (parser *Parser) parseStruct(pkgName string, field *ast.Field) (map[string]spec.Schema, error) { properties := map[string]spec.Schema{} structField, err := parser.parseField(field) if err != nil { return properties, nil } if structField.name == "" { return properties, nil } var desc string if field.Doc != nil { desc = strings.TrimSpace(field.Doc.Text()) } if desc == "" && field.Comment != nil { desc = strings.TrimSpace(field.Comment.Text()) } // TODO: find package of schemaType and/or arrayType if structField.crossPkg != "" { pkgName = structField.crossPkg } if _, ok := parser.TypeDefinitions[pkgName][structField.schemaType]; ok { // user type field // write definition if not yet present parser.ParseDefinition(pkgName, structField.schemaType, parser.TypeDefinitions[pkgName][structField.schemaType]) properties[structField.name] = spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, // to avoid swagger validation error Description: desc, Ref: spec.Ref{ Ref: jsonreference.MustCreateRef("#/definitions/" + pkgName + "." + structField.schemaType), }, }, } } else if structField.schemaType == "array" { // array field type // if defined -- ref it if _, ok := parser.TypeDefinitions[pkgName][structField.arrayType]; ok { // user type in array parser.ParseDefinition(pkgName, structField.arrayType, parser.TypeDefinitions[pkgName][structField.arrayType]) properties[structField.name] = spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{structField.schemaType}, Description: desc, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Ref: spec.Ref{ Ref: jsonreference.MustCreateRef("#/definitions/" + pkgName + "." + structField.arrayType), }, }, }, }, }, } } else { // standard type in array required := make([]string, 0) if structField.isRequired { required = append(required, structField.name) } properties[structField.name] = spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{structField.schemaType}, Description: desc, Format: structField.formatType, Required: required, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{structField.arrayType}, Maximum: structField.maximum, Minimum: structField.minimum, MaxLength: structField.maxLength, MinLength: structField.minLength, Enum: structField.enums, Default: structField.defaultValue, }, }, }, }, SwaggerSchemaProps: spec.SwaggerSchemaProps{ Example: structField.exampleValue, }, } } } else { required := make([]string, 0) if structField.isRequired { required = append(required, structField.name) } properties[structField.name] = spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{structField.schemaType}, Description: desc, Format: structField.formatType, Required: required, Maximum: structField.maximum, Minimum: structField.minimum, MaxLength: structField.maxLength, MinLength: structField.minLength, Enum: structField.enums, Default: structField.defaultValue, }, SwaggerSchemaProps: spec.SwaggerSchemaProps{ Example: structField.exampleValue, }, VendorExtensible: spec.VendorExtensible{ Extensions: structField.extensions, }, } nestStruct, ok := field.Type.(*ast.StructType) if ok { props := map[string]spec.Schema{} nestRequired := make([]string, 0) for _, v := range nestStruct.Fields.List { p, err := parser.parseStruct(pkgName, v) if err != nil { return properties, err } for k, v := range p { if v.SchemaProps.Type[0] != "object" { nestRequired = append(nestRequired, v.SchemaProps.Required...) v.SchemaProps.Required = make([]string, 0) } props[k] = v } } properties[structField.name] = spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{structField.schemaType}, Description: desc, Format: structField.formatType, Properties: props, Required: nestRequired, Maximum: structField.maximum, Minimum: structField.minimum, MaxLength: structField.maxLength, MinLength: structField.minLength, Enum: structField.enums, Default: structField.defaultValue, }, SwaggerSchemaProps: spec.SwaggerSchemaProps{ Example: structField.exampleValue, }, } } } return properties, nil } func (parser *Parser) parseAnonymousField(pkgName string, field *ast.Field) (map[string]spec.Schema, []string, error) { properties := make(map[string]spec.Schema) fullTypeName := "" switch ftype := field.Type.(type) { case *ast.Ident: fullTypeName = ftype.Name case *ast.StarExpr: if ftypeX, ok := ftype.X.(*ast.Ident); ok { fullTypeName = ftypeX.Name } else if ftypeX, ok := ftype.X.(*ast.SelectorExpr); ok { if packageX, ok := ftypeX.X.(*ast.Ident); ok { fullTypeName = fmt.Sprintf("%s.%s", packageX.Name, ftypeX.Sel.Name) } } else { Printf("Composite field type of '%T' is unhandle by parser. Skipping", ftype) return properties, []string{}, nil } default: Printf("Field type of '%T' is unsupported. Skipping", ftype) return properties, []string{}, nil } typeName := fullTypeName if splits := strings.Split(fullTypeName, "."); len(splits) > 1 { pkgName = splits[0] typeName = splits[1] } typeSpec := parser.TypeDefinitions[pkgName][typeName] schema, err := parser.parseTypeExpr(pkgName, typeName, typeSpec.Type) if err != nil { return properties, []string{}, err } schemaType := "unknown" if len(schema.SchemaProps.Type) > 0 { schemaType = schema.SchemaProps.Type[0] } switch schemaType { case "object": for k, v := range schema.SchemaProps.Properties { properties[k] = v } case "array": properties[typeName] = schema default: Printf("Can't extract properties from a schema of type '%s'", schemaType) } return properties, schema.SchemaProps.Required, nil } func (parser *Parser) parseField(field *ast.Field) (*structField, error) { prop, err := getPropertyName(field.Type, parser) if err != nil { return nil, err } if len(prop.ArrayType) == 0 { CheckSchemaType(prop.SchemaType) } else { CheckSchemaType("array") } structField := &structField{ name: field.Names[0].Name, schemaType: prop.SchemaType, arrayType: prop.ArrayType, crossPkg: prop.CrossPkg, } switch parser.PropNamingStrategy { case SnakeCase: structField.name = toSnakeCase(structField.name) case PascalCase: //use struct field name case CamelCase: structField.name = toLowerCamelCase(structField.name) default: structField.name = toLowerCamelCase(structField.name) } if field.Tag == nil { return structField, nil } // `json:"tag"` -> json:"tag" structTag := reflect.StructTag(strings.Replace(field.Tag.Value, "`", "", -1)) jsonTag := structTag.Get("json") // json:"tag,hoge" if strings.Contains(jsonTag, ",") { // json:",hoge" if strings.HasPrefix(jsonTag, ",") { jsonTag = "" } else { jsonTag = strings.SplitN(jsonTag, ",", 2)[0] } } if jsonTag == "-" { structField.name = "" } else if jsonTag != "" { structField.name = jsonTag } if typeTag := structTag.Get("swaggertype"); typeTag != "" { parts := strings.Split(typeTag, ",") if 0 < len(parts) && len(parts) <= 2 { newSchemaType := parts[0] newArrayType := structField.arrayType if len(parts) >= 2 { if newSchemaType == "array" { newArrayType = parts[1] } else if newSchemaType == "primitive" { newSchemaType = parts[1] newArrayType = parts[1] } } CheckSchemaType(newSchemaType) CheckSchemaType(newArrayType) structField.schemaType = newSchemaType structField.arrayType = newArrayType } } if exampleTag := structTag.Get("example"); exampleTag != "" { example, err := defineTypeOfExample(structField.schemaType, structField.arrayType, exampleTag) if err != nil { return nil, err } structField.exampleValue = example } if formatTag := structTag.Get("format"); formatTag != "" { structField.formatType = formatTag } if bindingTag := structTag.Get("binding"); bindingTag != "" { for _, val := range strings.Split(bindingTag, ",") { if val == "required" { structField.isRequired = true break } } } if validateTag := structTag.Get("validate"); validateTag != "" { for _, val := range strings.Split(validateTag, ",") { if val == "required" { structField.isRequired = true break } } } if extensionsTag := structTag.Get("extensions"); extensionsTag != "" { structField.extensions = map[string]interface{}{} for _, val := range strings.Split(extensionsTag, ",") { parts := strings.SplitN(val, "=", 2) if len(parts) == 2 { structField.extensions[parts[0]] = parts[1] } else { structField.extensions[parts[0]] = true } } } if enumsTag := structTag.Get("enums"); enumsTag != "" { enumType := structField.schemaType if structField.schemaType == "array" { enumType = structField.arrayType } for _, e := range strings.Split(enumsTag, ",") { value, err := defineType(enumType, e) if err != nil { return nil, err } structField.enums = append(structField.enums, value) } } if defaultTag := structTag.Get("default"); defaultTag != "" { value, err := defineType(structField.schemaType, defaultTag) if err != nil { return nil, err } structField.defaultValue = value } if IsNumericType(structField.schemaType) || IsNumericType(structField.arrayType) { maximum, err := getFloatTag(structTag, "maximum") if err != nil { return nil, err } structField.maximum = maximum minimum, err := getFloatTag(structTag, "minimum") if err != nil { return nil, err } structField.minimum = minimum } if structField.schemaType == "string" || structField.arrayType == "string" { maxLength, err := getIntTag(structTag, "maxLength") if err != nil { return nil, err } structField.maxLength = maxLength minLength, err := getIntTag(structTag, "minLength") if err != nil { return nil, err } structField.minLength = minLength } return structField, nil } func replaceLastTag(slice []spec.Tag, element spec.Tag) { slice = slice[:len(slice)-1] slice = append(slice, element) } func getFloatTag(structTag reflect.StructTag, tagName string) (*float64, error) { strValue := structTag.Get(tagName) if strValue == "" { return nil, nil } value, err := strconv.ParseFloat(strValue, 64) if err != nil { return nil, fmt.Errorf("can't parse numeric value of %q tag: %v", tagName, err) } return &value, nil } func getIntTag(structTag reflect.StructTag, tagName string) (*int64, error) { strValue := structTag.Get(tagName) if strValue == "" { return nil, nil } value, err := strconv.ParseInt(strValue, 10, 64) if err != nil { return nil, fmt.Errorf("can't parse numeric value of %q tag: %v", tagName, err) } return &value, nil } func toSnakeCase(in string) string { runes := []rune(in) length := len(runes) var out []rune for i := 0; i < length; i++ { if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) { out = append(out, '_') } out = append(out, unicode.ToLower(runes[i])) } return string(out) } func toLowerCamelCase(in string) string { runes := []rune(in) var out []rune flag := false for i, curr := range runes { if (i == 0 && unicode.IsUpper(curr)) || (flag && unicode.IsUpper(curr)) { out = append(out, unicode.ToLower(curr)) flag = true } else { out = append(out, curr) flag = false } } return string(out) } // defineTypeOfExample example value define the type (object and array unsupported) func defineTypeOfExample(schemaType, arrayType, exampleValue string) (interface{}, error) { switch schemaType { case "string": return exampleValue, nil case "number": v, err := strconv.ParseFloat(exampleValue, 64) if err != nil { return nil, fmt.Errorf("example value %s can't convert to %s err: %s", exampleValue, schemaType, err) } return v, nil case "integer": v, err := strconv.Atoi(exampleValue) if err != nil { return nil, fmt.Errorf("example value %s can't convert to %s err: %s", exampleValue, schemaType, err) } return v, nil case "boolean": v, err := strconv.ParseBool(exampleValue) if err != nil { return nil, fmt.Errorf("example value %s can't convert to %s err: %s", exampleValue, schemaType, err) } return v, nil case "array": values := strings.Split(exampleValue, ",") result := make([]interface{}, 0) for _, value := range values { v, err := defineTypeOfExample(arrayType, "", value) if err != nil { return nil, err } result = append(result, v) } return result, nil default: return nil, fmt.Errorf("%s is unsupported type in example value", schemaType) } } // GetAllGoFileInfo gets all Go source files information for given searchDir. func (parser *Parser) getAllGoFileInfo(searchDir string) error { return filepath.Walk(searchDir, parser.visit) } func (parser *Parser) visit(path string, f os.FileInfo, err error) error { if err := parser.Skip(path, f); err != nil { return err } if ext := filepath.Ext(path); ext == ".go" { fset := token.NewFileSet() // positions are relative to fset astFile, err := goparser.ParseFile(fset, path, nil, goparser.ParseComments) if err != nil { return fmt.Errorf("ParseFile error:%+v", err) } parser.files[path] = astFile } return nil } // Skip returns filepath.SkipDir error if match vendor and hidden folder func (parser *Parser) Skip(path string, f os.FileInfo) error { if !parser.ParseVendor { // ignore vendor if f.IsDir() && f.Name() == "vendor" { return filepath.SkipDir } } // exclude all hidden folder if f.IsDir() && len(f.Name()) > 1 && f.Name()[0] == '.' { return filepath.SkipDir } return nil } // GetSwagger returns *spec.Swagger which is the root document object for the API specification. func (parser *Parser) GetSwagger() *spec.Swagger { return parser.swagger } ================================================ FILE: vendor/github.com/swaggo/swag/property.go ================================================ package swag import ( "errors" "fmt" "go/ast" "strings" ) // ErrFailedConvertPrimitiveType Failed to convert for swag to interpretable type var ErrFailedConvertPrimitiveType = errors.New("swag property: failed convert primitive type") type propertyName struct { SchemaType string ArrayType string CrossPkg string } type propertyNewFunc func(schemeType string, crossPkg string) propertyName func newArrayProperty(schemeType string, crossPkg string) propertyName { return propertyName{ SchemaType: "array", ArrayType: schemeType, CrossPkg: crossPkg, } } func newProperty(schemeType string, crossPkg string) propertyName { return propertyName{ SchemaType: schemeType, ArrayType: "string", CrossPkg: crossPkg, } } func convertFromSpecificToPrimitive(typeName string) (string, error) { typeName = strings.ToUpper(typeName) switch typeName { case "TIME", "OBJECTID", "UUID": return "string", nil case "DECIMAL": return "number", nil } return "", ErrFailedConvertPrimitiveType } func parseFieldSelectorExpr(astTypeSelectorExpr *ast.SelectorExpr, parser *Parser, propertyNewFunc propertyNewFunc) propertyName { if primitiveType, err := convertFromSpecificToPrimitive(astTypeSelectorExpr.Sel.Name); err == nil { return propertyNewFunc(primitiveType, "") } if pkgName, ok := astTypeSelectorExpr.X.(*ast.Ident); ok { if typeDefinitions, ok := parser.TypeDefinitions[pkgName.Name][astTypeSelectorExpr.Sel.Name]; ok { if expr, ok := typeDefinitions.Type.(*ast.SelectorExpr); ok { if primitiveType, err := convertFromSpecificToPrimitive(expr.Sel.Name); err == nil { return propertyNewFunc(primitiveType, "") } } parser.ParseDefinition(pkgName.Name, astTypeSelectorExpr.Sel.Name, typeDefinitions) return propertyNewFunc(astTypeSelectorExpr.Sel.Name, pkgName.Name) } if actualPrimitiveType, isCustomType := parser.CustomPrimitiveTypes[astTypeSelectorExpr.Sel.Name]; isCustomType { return propertyName{SchemaType: actualPrimitiveType, ArrayType: actualPrimitiveType} } } return propertyName{SchemaType: "string", ArrayType: "string"} } // getPropertyName returns the string value for the given field if it exists // allowedValues: array, boolean, integer, null, number, object, string func getPropertyName(expr ast.Expr, parser *Parser) (propertyName, error) { if astTypeSelectorExpr, ok := expr.(*ast.SelectorExpr); ok { return parseFieldSelectorExpr(astTypeSelectorExpr, parser, newProperty), nil } // check if it is a custom type typeName := fmt.Sprintf("%v", expr) if actualPrimitiveType, isCustomType := parser.CustomPrimitiveTypes[typeName]; isCustomType { return propertyName{SchemaType: actualPrimitiveType, ArrayType: actualPrimitiveType}, nil } if astTypeIdent, ok := expr.(*ast.Ident); ok { name := astTypeIdent.Name schemeType := TransToValidSchemeType(name) return propertyName{SchemaType: schemeType, ArrayType: schemeType}, nil } if ptr, ok := expr.(*ast.StarExpr); ok { return getPropertyName(ptr.X, parser) } if astTypeArray, ok := expr.(*ast.ArrayType); ok { // if array return getArrayPropertyName(astTypeArray, parser), nil } if _, ok := expr.(*ast.MapType); ok { // if map return propertyName{SchemaType: "object", ArrayType: "object"}, nil } if _, ok := expr.(*ast.StructType); ok { // if struct return propertyName{SchemaType: "object", ArrayType: "object"}, nil } if _, ok := expr.(*ast.InterfaceType); ok { // if interface{} return propertyName{SchemaType: "object", ArrayType: "object"}, nil } return propertyName{}, errors.New("not supported" + fmt.Sprint(expr)) } func getArrayPropertyName(astTypeArray *ast.ArrayType, parser *Parser) propertyName { if astTypeArrayExpr, ok := astTypeArray.Elt.(*ast.SelectorExpr); ok { return parseFieldSelectorExpr(astTypeArrayExpr, parser, newArrayProperty) } if astTypeArrayExpr, ok := astTypeArray.Elt.(*ast.StarExpr); ok { if astTypeArraySel, ok := astTypeArrayExpr.X.(*ast.SelectorExpr); ok { return parseFieldSelectorExpr(astTypeArraySel, parser, newArrayProperty) } if astTypeArrayIdent, ok := astTypeArrayExpr.X.(*ast.Ident); ok { name := TransToValidSchemeType(astTypeArrayIdent.Name) return propertyName{SchemaType: "array", ArrayType: name} } } itemTypeName := TransToValidSchemeType(fmt.Sprintf("%s", astTypeArray.Elt)) if actualPrimitiveType, isCustomType := parser.CustomPrimitiveTypes[itemTypeName]; isCustomType { itemTypeName = actualPrimitiveType } return propertyName{SchemaType: "array", ArrayType: itemTypeName} } ================================================ FILE: vendor/github.com/swaggo/swag/schema.go ================================================ package swag import "fmt" // CheckSchemaType checks if typeName is not a name of primitive type func CheckSchemaType(typeName string) error { if !IsPrimitiveType(typeName) { return fmt.Errorf("%s is not basic types", typeName) } return nil } // IsPrimitiveType determine whether the type name is a primitive type func IsPrimitiveType(typeName string) bool { switch typeName { case "string", "number", "integer", "boolean", "array", "object": return true default: return false } } // IsNumericType determines whether the swagger type name is a numeric type func IsNumericType(typeName string) bool { return typeName == "integer" || typeName == "number" } // TransToValidSchemeType indicates type will transfer golang basic type to swagger supported type. func TransToValidSchemeType(typeName string) string { switch typeName { case "uint", "int", "uint8", "int8", "uint16", "int16", "byte": return "integer" case "uint32", "int32", "rune": return "integer" case "uint64", "int64": return "integer" case "float32", "float64": return "number" case "bool": return "boolean" case "string": return "string" default: return typeName // to support user defined types } } // IsGolangPrimitiveType determine whether the type name is a golang primitive type func IsGolangPrimitiveType(typeName string) bool { switch typeName { case "uint", "int", "uint8", "int8", "uint16", "int16", "byte", "uint32", "int32", "rune", "uint64", "int64", "float32", "float64", "bool", "string": return true default: return false } } ================================================ FILE: vendor/github.com/swaggo/swag/swagger.go ================================================ package swag import ( "errors" "sync" ) // Name is a unique name be used to register swag instance. const Name = "swagger" var ( swaggerMu sync.RWMutex swag Swagger ) // Swagger is a interface to read swagger document. type Swagger interface { ReadDoc() string } // Register registers swagger for given name. func Register(name string, swagger Swagger) { swaggerMu.Lock() defer swaggerMu.Unlock() if swagger == nil { panic("swagger is nil") } if swag != nil { panic("Register called twice for swag: " + name) } swag = swagger } // ReadDoc reads swagger document. func ReadDoc() (string, error) { if swag != nil { return swag.ReadDoc(), nil } return "", errors.New("not yet registered swag") } ================================================ FILE: vendor/github.com/swaggo/swag/version.go ================================================ package swag // Version of swag const Version = "v1.5.1" ================================================ FILE: vendor/github.com/tealeg/xlsx/.gitignore ================================================ .vscode .DS_Store xlsx.test *.swp coverage.txt ================================================ FILE: vendor/github.com/tealeg/xlsx/.travis.yml ================================================ language: go go: - 1.8.x - 1.9.x script: - go vet ./... - go test -v -coverprofile=coverage.txt -covermode=atomic . after_success: - bash <(curl -s https://codecov.io/bash) ================================================ FILE: vendor/github.com/tealeg/xlsx/AUTHORS.txt ================================================ ACHER Andrew Schwartz Artem Chernyak Artem Chernyak blackss2 Brandon Mulcahy Brian Smith bronze1man Bruno Bigras Chris Glass Colin Fox Colin Fox crahles Daniel Upton Daniel YC Lin DerLinkshaender Eric frogs fzerorubigd Geoffrey J. Teale Gyu-Ho Lee Herman Schaaf Hugh Gao Iain Lowe ivnivnch Jason Hall Joshua Baker Kaur Kuut Lunny Xiao magician1 Mathias Fredriksson Matt Aimonetti Moch. Lutfi Moch.Lutfi Neoin Nguyen Nguyen Nikita Danilov OneOfOne Peter Waller Philipp Klose richard bucker Shawn Milochik Shawn Smith Shawn Smith SHIMADA Koji Steven Degutis takuya sato Thieu Pham Tormod Erevik Lea trinchan U-NORTH_AMERICA\ACHER YAMADA Tsuyoshi Yoshiki Shibukawa zhcy ================================================ FILE: vendor/github.com/tealeg/xlsx/CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at tealeg@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: vendor/github.com/tealeg/xlsx/LICENSE ================================================ BSD 3-Clause License Copyright (c) 2011-2017, Geoffrey J. Teale 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. ================================================ FILE: vendor/github.com/tealeg/xlsx/README.org ================================================ * XLSX [[https://travis-ci.org/tealeg/xlsx][https://img.shields.io/travis/tealeg/xlsx/master.svg?style=flat-square]] [[https://codecov.io/gh/tealeg/xlsx][https://codecov.io/gh/tealeg/xlsx/branch/master/graph/badge.svg]] [[https://godoc.org/github.com/tealeg/xlsx][https://godoc.org/github.com/tealeg/xlsx?status.svg]] [[https://github.com/tealeg/xlsx#license][https://img.shields.io/badge/license-bsd-orange.svg]] ** Introduction xlsx is a library to simplify reading and writing the XML format used by recent version of Microsoft Excel in Go programs. The support for writing XLSX files is currently extremely minimal. It will expand slowly, but in the meantime patches are welcome! ** Full API docs The full API docs can be viewed using go's built in documentation tool, or online at [[http://godoc.org/github.com/tealeg/xlsx][godoc.org]]. ** Basic Usage *** Reading XLSX files Here is a minimal example usage that will dump all cell data in a given XLSX file. A more complete example of this kind of functionality is contained in [[https://github.com/tealeg/xlsx2csv][the XLSX2CSV program]]: #+BEGIN_SRC go package main import ( "fmt" "github.com/tealeg/xlsx" ) func main() { excelFileName := "/home/tealeg/foo.xlsx" xlFile, err := xlsx.OpenFile(excelFileName) if err != nil { ... } for _, sheet := range xlFile.Sheets { for _, row := range sheet.Rows { for _, cell := range row.Cells { text := cell.String() fmt.Printf("%s\n", text) } } } } #+END_SRC Some additional information is available from the cell (for example, style information). For more details see the godoc output for this package. *** Writing XLSX files The following constitutes the bare minimum required to write an XLSX document. #+BEGIN_SRC go package main import ( "fmt" "github.com/tealeg/xlsx" ) func main() { var file *xlsx.File var sheet *xlsx.Sheet var row *xlsx.Row var cell *xlsx.Cell var err error file = xlsx.NewFile() sheet, err = file.AddSheet("Sheet1") if err != nil { fmt.Printf(err.Error()) } row = sheet.AddRow() cell = row.AddCell() cell.Value = "I am a cell!" err = file.Save("MyXLSXFile.xlsx") if err != nil { fmt.Printf(err.Error()) } } #+END_SRC ** Contributing We're extremely happy to review pull requests. Please be patient, maintaining XLSX doesn't pay anyone's salary (to my knowledge). If you'd like to propose a change please ensure the following: - All existing tests are passing. - There are tests in the test suite that cover the changes you're making. - You have added documentation strings (in English) to (at least) the public functions you've added or modified. - Your use of, or creation of, XML is compliant with [[http://www.ecma-international.org/publications/standards/Ecma-376.htm][part 1 of the 4th edition of the ECMA-376 Standard for Office Open XML]]. Eat a peach - Geoff ================================================ FILE: vendor/github.com/tealeg/xlsx/cell.go ================================================ package xlsx import ( "fmt" "math" "strconv" "time" ) const ( maxNonScientificNumber = 1e11 minNonScientificNumber = 1e-9 ) // CellType is an int type for storing metadata about the data type in the cell. type CellType int // These are the cell types from the ST_CellType spec const ( CellTypeString CellType = iota // CellTypeStringFormula is a specific format for formulas that return string values. Formulas that return numbers // and booleans are stored as those types. CellTypeStringFormula CellTypeNumeric CellTypeBool // CellTypeInline is not respected on save, all inline string cells will be saved as SharedStrings // when saving to an XLSX file. This the same behavior as that found in Excel. CellTypeInline CellTypeError // d (Date): Cell contains a date in the ISO 8601 format. // That is the only mention of this format in the XLSX spec. // Date seems to be unused by the current version of Excel, it stores dates as Numeric cells with a date format string. // For now these cells will have their value output directly. It is unclear if the value is supposed to be parsed // into a number and then formatted using the formatting or not. CellTypeDate ) func (ct CellType) Ptr() *CellType { return &ct } // Cell is a high level structure intended to provide user access to // the contents of Cell within an xlsx.Row. type Cell struct { Row *Row Value string formula string style *Style NumFmt string parsedNumFmt *parsedNumberFormat date1904 bool Hidden bool HMerge int VMerge int cellType CellType } // CellInterface defines the public API of the Cell. type CellInterface interface { String() string FormattedValue() string } // NewCell creates a cell and adds it to a row. func NewCell(r *Row) *Cell { return &Cell{Row: r, NumFmt: "general"} } // Merge with other cells, horizontally and/or vertically. func (c *Cell) Merge(hcells, vcells int) { c.HMerge = hcells c.VMerge = vcells } // Type returns the CellType of a cell. See CellType constants for more details. func (c *Cell) Type() CellType { return c.cellType } // SetString sets the value of a cell to a string. func (c *Cell) SetString(s string) { c.Value = s c.formula = "" c.cellType = CellTypeString } // String returns the value of a Cell as a string. If you'd like to // see errors returned from formatting then please use // Cell.FormattedValue() instead. func (c *Cell) String() string { // To preserve the String() interface we'll throw away errors. // Not that using FormattedValue is therefore strongly // preferred. value, _ := c.FormattedValue() return value } // SetFloat sets the value of a cell to a float. func (c *Cell) SetFloat(n float64) { c.SetValue(n) } //GetTime returns the value of a Cell as a time.Time func (c *Cell) GetTime(date1904 bool) (t time.Time, err error) { f, err := c.Float() if err != nil { return t, err } return TimeFromExcelTime(f, date1904), nil } /* The following are samples of format samples. * "0.00e+00" * "0", "#,##0" * "0.00", "#,##0.00", "@" * "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)" * "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)" * "0%", "0.00%" * "0.00e+00", "##0.0e+0" */ // SetFloatWithFormat sets the value of a cell to a float and applies // formatting to the cell. func (c *Cell) SetFloatWithFormat(n float64, format string) { c.SetValue(n) c.NumFmt = format c.formula = "" } var timeLocationUTC, _ = time.LoadLocation("UTC") func TimeToUTCTime(t time.Time) time.Time { return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), timeLocationUTC) } func TimeToExcelTime(t time.Time) float64 { return float64(t.UnixNano())/8.64e13 + 25569.0 } // DateTimeOptions are additional options for exporting times type DateTimeOptions struct { // Location allows calculating times in other timezones/locations Location *time.Location // ExcelTimeFormat is the string you want excel to use to format the datetime ExcelTimeFormat string } var ( DefaultDateFormat = builtInNumFmt[14] DefaultDateTimeFormat = builtInNumFmt[22] DefaultDateOptions = DateTimeOptions{ Location: timeLocationUTC, ExcelTimeFormat: DefaultDateFormat, } DefaultDateTimeOptions = DateTimeOptions{ Location: timeLocationUTC, ExcelTimeFormat: DefaultDateTimeFormat, } ) // SetDate sets the value of a cell to a float. func (c *Cell) SetDate(t time.Time) { c.SetDateWithOptions(t, DefaultDateOptions) } func (c *Cell) SetDateTime(t time.Time) { c.SetDateWithOptions(t, DefaultDateTimeOptions) } // SetDateWithOptions allows for more granular control when exporting dates and times func (c *Cell) SetDateWithOptions(t time.Time, options DateTimeOptions) { _, offset := t.In(options.Location).Zone() t = time.Unix(t.Unix()+int64(offset), 0) c.SetDateTimeWithFormat(TimeToExcelTime(t.In(timeLocationUTC)), options.ExcelTimeFormat) } func (c *Cell) SetDateTimeWithFormat(n float64, format string) { c.Value = strconv.FormatFloat(n, 'f', -1, 64) c.NumFmt = format c.formula = "" c.cellType = CellTypeNumeric } // Float returns the value of cell as a number. func (c *Cell) Float() (float64, error) { f, err := strconv.ParseFloat(c.Value, 64) if err != nil { return math.NaN(), err } return f, nil } // SetInt64 sets a cell's value to a 64-bit integer. func (c *Cell) SetInt64(n int64) { c.SetValue(n) } // Int64 returns the value of cell as 64-bit integer. func (c *Cell) Int64() (int64, error) { f, err := strconv.ParseInt(c.Value, 10, 64) if err != nil { return -1, err } return f, nil } // GeneralNumeric returns the value of the cell as a string. It is formatted very closely to the the XLSX spec for how // to display values when the storage type is Number and the format type is General. It is not 100% identical to the // spec but is as close as you can get using the built in Go formatting tools. func (c *Cell) GeneralNumeric() (string, error) { return generalNumericScientific(c.Value, true) } // GeneralNumericWithoutScientific returns numbers that are always formatted as numbers, but it does not follow // the rules for when XLSX should switch to scientific notation, since sometimes scientific notation is not desired, // even if that is how the document is supposed to be formatted. func (c *Cell) GeneralNumericWithoutScientific() (string, error) { return generalNumericScientific(c.Value, false) } // SetInt sets a cell's value to an integer. func (c *Cell) SetInt(n int) { c.SetValue(n) } // SetInt sets a cell's value to an integer. func (c *Cell) SetValue(n interface{}) { switch t := n.(type) { case time.Time: c.SetDateTime(t) return case int, int8, int16, int32, int64: c.setNumeric(fmt.Sprintf("%d", n)) case float64: // When formatting floats, do not use fmt.Sprintf("%v", n), this will cause numbers below 1e-4 to be printed in // scientific notation. Scientific notation is not a valid way to store numbers in XML. // Also not not use fmt.Sprintf("%f", n), this will cause numbers to be stored as X.XXXXXX. Which means that // numbers will lose precision and numbers with fewer significant digits such as 0 will be stored as 0.000000 // which causes tests to fail. c.setNumeric(strconv.FormatFloat(t, 'f', -1, 64)) case float32: c.setNumeric(strconv.FormatFloat(float64(t), 'f', -1, 32)) case string: c.SetString(t) case []byte: c.SetString(string(t)) case nil: c.SetString("") default: c.SetString(fmt.Sprintf("%v", n)) } } // setNumeric sets a cell's value to a number func (c *Cell) setNumeric(s string) { c.Value = s c.NumFmt = builtInNumFmt[builtInNumFmtIndex_GENERAL] c.formula = "" c.cellType = CellTypeNumeric } // Int returns the value of cell as integer. // Has max 53 bits of precision // See: float64(int64(math.MaxInt)) func (c *Cell) Int() (int, error) { f, err := strconv.ParseFloat(c.Value, 64) if err != nil { return -1, err } return int(f), nil } // SetBool sets a cell's value to a boolean. func (c *Cell) SetBool(b bool) { if b { c.Value = "1" } else { c.Value = "0" } c.cellType = CellTypeBool } // Bool returns a boolean from a cell's value. // TODO: Determine if the current return value is // appropriate for types other than CellTypeBool. func (c *Cell) Bool() bool { // If bool, just return the value. if c.cellType == CellTypeBool { return c.Value == "1" } // If numeric, base it on a non-zero. if c.cellType == CellTypeNumeric { return c.Value != "0" } // Return whether there's an empty string. return c.Value != "" } // SetFormula sets the format string for a cell. func (c *Cell) SetFormula(formula string) { c.formula = formula c.cellType = CellTypeNumeric } func (c *Cell) SetStringFormula(formula string) { c.formula = formula c.cellType = CellTypeStringFormula } // Formula returns the formula string for the cell. func (c *Cell) Formula() string { return c.formula } // GetStyle returns the Style associated with a Cell func (c *Cell) GetStyle() *Style { if c.style == nil { c.style = NewStyle() } return c.style } // SetStyle sets the style of a cell. func (c *Cell) SetStyle(style *Style) { c.style = style } // GetNumberFormat returns the number format string for a cell. func (c *Cell) GetNumberFormat() string { return c.NumFmt } func (c *Cell) formatToFloat(format string) (string, error) { f, err := strconv.ParseFloat(c.Value, 64) if err != nil { return c.Value, err } return fmt.Sprintf(format, f), nil } func (c *Cell) formatToInt(format string) (string, error) { f, err := strconv.ParseFloat(c.Value, 64) if err != nil { return c.Value, err } return fmt.Sprintf(format, int(f)), nil } // getNumberFormat will update the parsedNumFmt struct if it has become out of date, since a cell's NumFmt string is a // public field that could be edited by clients. func (c *Cell) getNumberFormat() *parsedNumberFormat { if c.parsedNumFmt == nil || c.parsedNumFmt.numFmt != c.NumFmt { c.parsedNumFmt = parseFullNumberFormatString(c.NumFmt) } return c.parsedNumFmt } // FormattedValue returns a value, and possibly an error condition // from a Cell. If it is possible to apply a format to the cell // value, it will do so, if not then an error will be returned, along // with the raw value of the Cell. func (c *Cell) FormattedValue() (string, error) { fullFormat := c.getNumberFormat() returnVal, err := fullFormat.FormatValue(c) if fullFormat.parseEncounteredError != nil { return returnVal, *fullFormat.parseEncounteredError } return returnVal, err } ================================================ FILE: vendor/github.com/tealeg/xlsx/col.go ================================================ package xlsx // Default column width in excel const ColWidth = 9.5 type Col struct { Min int Max int Hidden bool Width float64 Collapsed bool OutlineLevel uint8 numFmt string parsedNumFmt *parsedNumberFormat style *Style } // SetType will set the format string of a column based on the type that you want to set it to. // This function does not really make a lot of sense. func (c *Col) SetType(cellType CellType) { switch cellType { case CellTypeString: c.numFmt = builtInNumFmt[builtInNumFmtIndex_STRING] case CellTypeNumeric: c.numFmt = builtInNumFmt[builtInNumFmtIndex_INT] case CellTypeBool: c.numFmt = builtInNumFmt[builtInNumFmtIndex_GENERAL] //TEMP case CellTypeInline: c.numFmt = builtInNumFmt[builtInNumFmtIndex_STRING] case CellTypeError: c.numFmt = builtInNumFmt[builtInNumFmtIndex_GENERAL] //TEMP case CellTypeDate: // Cells that are stored as dates are not properly supported in this library. // They should instead be stored as a Numeric with a date format. c.numFmt = builtInNumFmt[builtInNumFmtIndex_GENERAL] case CellTypeStringFormula: c.numFmt = builtInNumFmt[builtInNumFmtIndex_STRING] } } // GetStyle returns the Style associated with a Col func (c *Col) GetStyle() *Style { return c.style } // SetStyle sets the style of a Col func (c *Col) SetStyle(style *Style) { c.style = style } ================================================ FILE: vendor/github.com/tealeg/xlsx/date.go ================================================ package xlsx import ( "math" "time" ) const MJD_0 float64 = 2400000.5 const MJD_JD2000 float64 = 51544.5 func shiftJulianToNoon(julianDays, julianFraction float64) (float64, float64) { switch { case -0.5 < julianFraction && julianFraction < 0.5: julianFraction += 0.5 case julianFraction >= 0.5: julianDays += 1 julianFraction -= 0.5 case julianFraction <= -0.5: julianDays -= 1 julianFraction += 1.5 } return julianDays, julianFraction } // Return the integer values for hour, minutes, seconds and // nanoseconds that comprised a given fraction of a day. // values would round to 1 us. func fractionOfADay(fraction float64) (hours, minutes, seconds, nanoseconds int) { const ( c1us = 1e3 c1s = 1e9 c1day = 24 * 60 * 60 * c1s ) frac := int64(c1day*fraction + c1us/2) nanoseconds = int((frac%c1s)/c1us) * c1us frac /= c1s seconds = int(frac % 60) frac /= 60 minutes = int(frac % 60) hours = int(frac / 60) return } func julianDateToGregorianTime(part1, part2 float64) time.Time { part1I, part1F := math.Modf(part1) part2I, part2F := math.Modf(part2) julianDays := part1I + part2I julianFraction := part1F + part2F julianDays, julianFraction = shiftJulianToNoon(julianDays, julianFraction) day, month, year := doTheFliegelAndVanFlandernAlgorithm(int(julianDays)) hours, minutes, seconds, nanoseconds := fractionOfADay(julianFraction) return time.Date(year, time.Month(month), day, hours, minutes, seconds, nanoseconds, time.UTC) } // By this point generations of programmers have repeated the // algorithm sent to the editor of "Communications of the ACM" in 1968 // (published in CACM, volume 11, number 10, October 1968, p.657). // None of those programmers seems to have found it necessary to // explain the constants or variable names set out by Henry F. Fliegel // and Thomas C. Van Flandern. Maybe one day I'll buy that jounal and // expand an explanation here - that day is not today. func doTheFliegelAndVanFlandernAlgorithm(jd int) (day, month, year int) { l := jd + 68569 n := (4 * l) / 146097 l = l - (146097*n+3)/4 i := (4000 * (l + 1)) / 1461001 l = l - (1461*i)/4 + 31 j := (80 * l) / 2447 d := l - (2447*j)/80 l = j / 11 m := j + 2 - (12 * l) y := 100*(n-49) + i + l return d, m, y } // Convert an excelTime representation (stored as a floating point number) to a time.Time. func TimeFromExcelTime(excelTime float64, date1904 bool) time.Time { var date time.Time var intPart int64 = int64(excelTime) // Excel uses Julian dates prior to March 1st 1900, and // Gregorian thereafter. if intPart <= 61 { const OFFSET1900 = 15018.0 const OFFSET1904 = 16480.0 var date time.Time if date1904 { date = julianDateToGregorianTime(MJD_0, excelTime+OFFSET1904) } else { date = julianDateToGregorianTime(MJD_0, excelTime+OFFSET1900) } return date } var floatPart float64 = excelTime - float64(intPart) var dayNanoSeconds float64 = 24 * 60 * 60 * 1000 * 1000 * 1000 if date1904 { date = time.Date(1904, 1, 1, 0, 0, 0, 0, time.UTC) } else { date = time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC) } durationDays := time.Duration(intPart) * time.Hour * 24 durationPart := time.Duration(dayNanoSeconds * floatPart) return date.Add(durationDays).Add(durationPart) } ================================================ FILE: vendor/github.com/tealeg/xlsx/doc.go ================================================ // xslx is a package designed to help with reading data from // spreadsheets stored in the XLSX format used in recent versions of // Microsoft's Excel spreadsheet. // // Additionally, xlsx has started to grow some XLSX authoring // capabilities too. // // For a concise example of how to use this library why not check out // the source for xlsx2csv here: https://github.com/tealeg/xlsx2csv package xlsx ================================================ FILE: vendor/github.com/tealeg/xlsx/file.go ================================================ package xlsx import ( "archive/zip" "bytes" "encoding/xml" "errors" "fmt" "io" "os" "strconv" "strings" "unicode/utf8" ) // File is a high level structure providing a slice of Sheet structs // to the user. type File struct { worksheets map[string]*zip.File referenceTable *RefTable Date1904 bool styles *xlsxStyleSheet Sheets []*Sheet Sheet map[string]*Sheet theme *theme DefinedNames []*xlsxDefinedName } const NoRowLimit int = -1 // Create a new File func NewFile() *File { return &File{ Sheet: make(map[string]*Sheet), Sheets: make([]*Sheet, 0), DefinedNames: make([]*xlsxDefinedName, 0), } } // OpenFile() take the name of an XLSX file and returns a populated // xlsx.File struct for it. func OpenFile(fileName string) (file *File, err error) { return OpenFileWithRowLimit(fileName, NoRowLimit) } // OpenFileWithRowLimit() will open the file, but will only read the specified number of rows. // If you save this file, it will be truncated to the number of rows specified. func OpenFileWithRowLimit(fileName string, rowLimit int) (file *File, err error) { var z *zip.ReadCloser z, err = zip.OpenReader(fileName) if err != nil { return nil, err } return ReadZipWithRowLimit(z, rowLimit) } // OpenBinary() take bytes of an XLSX file and returns a populated // xlsx.File struct for it. func OpenBinary(bs []byte) (*File, error) { return OpenBinaryWithRowLimit(bs, NoRowLimit) } // OpenBinaryWithRowLimit() take bytes of an XLSX file and returns a populated // xlsx.File struct for it. func OpenBinaryWithRowLimit(bs []byte, rowLimit int) (*File, error) { r := bytes.NewReader(bs) return OpenReaderAtWithRowLimit(r, int64(r.Len()), rowLimit) } // OpenReaderAt() take io.ReaderAt of an XLSX file and returns a populated // xlsx.File struct for it. func OpenReaderAt(r io.ReaderAt, size int64) (*File, error) { return OpenReaderAtWithRowLimit(r, size, NoRowLimit) } // OpenReaderAtWithRowLimit() take io.ReaderAt of an XLSX file and returns a populated // xlsx.File struct for it. func OpenReaderAtWithRowLimit(r io.ReaderAt, size int64, rowLimit int) (*File, error) { file, err := zip.NewReader(r, size) if err != nil { return nil, err } return ReadZipReaderWithRowLimit(file, rowLimit) } // A convenient wrapper around File.ToSlice, FileToSlice will // return the raw data contained in an Excel XLSX file as three // dimensional slice. The first index represents the sheet number, // the second the row number, and the third the cell number. // // For example: // // var mySlice [][][]string // var value string // mySlice = xlsx.FileToSlice("myXLSX.xlsx") // value = mySlice[0][0][0] // // Here, value would be set to the raw value of the cell A1 in the // first sheet in the XLSX file. func FileToSlice(path string) ([][][]string, error) { f, err := OpenFile(path) if err != nil { return nil, err } return f.ToSlice() } // FileToSliceUnmerged is a wrapper around File.ToSliceUnmerged. // It returns the raw data contained in an Excel XLSX file as three // dimensional slice. Merged cells will be unmerged. Covered cells become the // values of theirs origins. func FileToSliceUnmerged(path string) ([][][]string, error) { f, err := OpenFile(path) if err != nil { return nil, err } return f.ToSliceUnmerged() } // Save the File to an xlsx file at the provided path. func (f *File) Save(path string) (err error) { target, err := os.Create(path) if err != nil { return err } err = f.Write(target) if err != nil { return err } return target.Close() } // Write the File to io.Writer as xlsx func (f *File) Write(writer io.Writer) (err error) { parts, err := f.MarshallParts() if err != nil { return } zipWriter := zip.NewWriter(writer) for partName, part := range parts { w, err := zipWriter.Create(partName) if err != nil { return err } _, err = w.Write([]byte(part)) if err != nil { return err } } return zipWriter.Close() } // Add a new Sheet, with the provided name, to a File func (f *File) AddSheet(sheetName string) (*Sheet, error) { if _, exists := f.Sheet[sheetName]; exists { return nil, fmt.Errorf("duplicate sheet name '%s'.", sheetName) } if utf8.RuneCountInString(sheetName) >= 31 { return nil, fmt.Errorf("sheet name must be less than 31 characters long. It is currently '%d' characters long", utf8.RuneCountInString(sheetName)) } sheet := &Sheet{ Name: sheetName, File: f, Selected: len(f.Sheets) == 0, } f.Sheet[sheetName] = sheet f.Sheets = append(f.Sheets, sheet) return sheet, nil } // Appends an existing Sheet, with the provided name, to a File func (f *File) AppendSheet(sheet Sheet, sheetName string) (*Sheet, error) { if _, exists := f.Sheet[sheetName]; exists { return nil, fmt.Errorf("duplicate sheet name '%s'.", sheetName) } sheet.Name = sheetName sheet.File = f sheet.Selected = len(f.Sheets) == 0 f.Sheet[sheetName] = &sheet f.Sheets = append(f.Sheets, &sheet) return &sheet, nil } func (f *File) makeWorkbook() xlsxWorkbook { return xlsxWorkbook{ FileVersion: xlsxFileVersion{AppName: "Go XLSX"}, WorkbookPr: xlsxWorkbookPr{ShowObjects: "all"}, BookViews: xlsxBookViews{ WorkBookView: []xlsxWorkBookView{ { ShowHorizontalScroll: true, ShowSheetTabs: true, ShowVerticalScroll: true, TabRatio: 204, WindowHeight: 8192, WindowWidth: 16384, XWindow: "0", YWindow: "0", }, }, }, Sheets: xlsxSheets{Sheet: make([]xlsxSheet, len(f.Sheets))}, CalcPr: xlsxCalcPr{ IterateCount: 100, RefMode: "A1", Iterate: false, IterateDelta: 0.001, }, } } // Some tools that read XLSX files have very strict requirements about // the structure of the input XML. In particular both Numbers on the Mac // and SAS dislike inline XML namespace declarations, or namespace // prefixes that don't match the ones that Excel itself uses. This is a // problem because the Go XML library doesn't multiple namespace // declarations in a single element of a document. This function is a // horrible hack to fix that after the XML marshalling is completed. func replaceRelationshipsNameSpace(workbookMarshal string) string { newWorkbook := strings.Replace(workbookMarshal, `xmlns:relationships="http://schemas.openxmlformats.org/officeDocument/2006/relationships" relationships:id`, `r:id`, -1) // Dirty hack to fix issues #63 and #91; encoding/xml currently // "doesn't allow for additional namespaces to be defined in the // root element of the document," as described by @tealeg in the // comments for #63. oldXmlns := `` newXmlns := `` return strings.Replace(newWorkbook, oldXmlns, newXmlns, 1) } // Construct a map of file name to XML content representing the file // in terms of the structure of an XLSX file. func (f *File) MarshallParts() (map[string]string, error) { var parts map[string]string var refTable *RefTable = NewSharedStringRefTable() refTable.isWrite = true var workbookRels WorkBookRels = make(WorkBookRels) var err error var workbook xlsxWorkbook var types xlsxTypes = MakeDefaultContentTypes() marshal := func(thing interface{}) (string, error) { body, err := xml.Marshal(thing) if err != nil { return "", err } return xml.Header + string(body), nil } parts = make(map[string]string) workbook = f.makeWorkbook() sheetIndex := 1 if f.styles == nil { f.styles = newXlsxStyleSheet(f.theme) } f.styles.reset() if len(f.Sheets) == 0 { err := errors.New("Workbook must contains atleast one worksheet") return nil, err } for _, sheet := range f.Sheets { xSheet := sheet.makeXLSXSheet(refTable, f.styles) rId := fmt.Sprintf("rId%d", sheetIndex) sheetId := strconv.Itoa(sheetIndex) sheetPath := fmt.Sprintf("worksheets/sheet%d.xml", sheetIndex) partName := "xl/" + sheetPath types.Overrides = append( types.Overrides, xlsxOverride{ PartName: "/" + partName, ContentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"}) workbookRels[rId] = sheetPath workbook.Sheets.Sheet[sheetIndex-1] = xlsxSheet{ Name: sheet.Name, SheetId: sheetId, Id: rId, State: "visible"} parts[partName], err = marshal(xSheet) if err != nil { return parts, err } sheetIndex++ } workbookMarshal, err := marshal(workbook) if err != nil { return parts, err } workbookMarshal = replaceRelationshipsNameSpace(workbookMarshal) parts["xl/workbook.xml"] = workbookMarshal if err != nil { return parts, err } parts["_rels/.rels"] = TEMPLATE__RELS_DOT_RELS parts["docProps/app.xml"] = TEMPLATE_DOCPROPS_APP // TODO - do this properly, modification and revision information parts["docProps/core.xml"] = TEMPLATE_DOCPROPS_CORE parts["xl/theme/theme1.xml"] = TEMPLATE_XL_THEME_THEME xSST := refTable.makeXLSXSST() parts["xl/sharedStrings.xml"], err = marshal(xSST) if err != nil { return parts, err } xWRel := workbookRels.MakeXLSXWorkbookRels() parts["xl/_rels/workbook.xml.rels"], err = marshal(xWRel) if err != nil { return parts, err } parts["[Content_Types].xml"], err = marshal(types) if err != nil { return parts, err } parts["xl/styles.xml"], err = f.styles.Marshal() if err != nil { return parts, err } return parts, nil } // Return the raw data contained in the File as three // dimensional slice. The first index represents the sheet number, // the second the row number, and the third the cell number. // // For example: // // var mySlice [][][]string // var value string // mySlice = xlsx.FileToSlice("myXLSX.xlsx") // value = mySlice[0][0][0] // // Here, value would be set to the raw value of the cell A1 in the // first sheet in the XLSX file. func (f *File) ToSlice() (output [][][]string, err error) { output = [][][]string{} for _, sheet := range f.Sheets { s := [][]string{} for _, row := range sheet.Rows { if row == nil { continue } r := []string{} for _, cell := range row.Cells { str, err := cell.FormattedValue() if err != nil { // Recover from strconv.NumError if the value is an empty string, // and insert an empty string in the output. if numErr, ok := err.(*strconv.NumError); ok && numErr.Num == "" { str = "" } else { return output, err } } r = append(r, str) } s = append(s, r) } output = append(output, s) } return output, nil } // ToSliceUnmerged returns the raw data contained in the File as three // dimensional slice (s. method ToSlice). // A covered cell become the value of its origin cell. // Example: table where A1:A2 merged. // | 01.01.2011 | Bread | 20 | // | | Fish | 70 | // This sheet will be converted to the slice: // [ [01.01.2011 Bread 20] // [01.01.2011 Fish 70] ] func (f *File) ToSliceUnmerged() (output [][][]string, err error) { output, err = f.ToSlice() if err != nil { return nil, err } for s, sheet := range f.Sheets { for r, row := range sheet.Rows { for c, cell := range row.Cells { if cell.HMerge > 0 { for i := c + 1; i <= c+cell.HMerge; i++ { output[s][r][i] = output[s][r][c] } } if cell.VMerge > 0 { for i := r + 1; i <= r+cell.VMerge; i++ { output[s][i][c] = output[s][r][c] } } } } } return output, nil } ================================================ FILE: vendor/github.com/tealeg/xlsx/format_code.go ================================================ package xlsx import ( "errors" "fmt" "math" "strconv" "strings" ) // Do not edit these attributes once this struct is created. This struct should only be created by // parseFullNumberFormatString() from a number format string. If the format for a cell needs to change, change // the number format string and getNumberFormat() will invalidate the old struct and re-parse the string. type parsedNumberFormat struct { numFmt string isTimeFormat bool negativeFormatExpectsPositive bool positiveFormat *formatOptions negativeFormat *formatOptions zeroFormat *formatOptions textFormat *formatOptions parseEncounteredError *error } type formatOptions struct { isTimeFormat bool showPercent bool fullFormatString string reducedFormatString string prefix string suffix string } // FormatValue returns a value, and possibly an error condition // from a Cell. If it is possible to apply a format to the cell // value, it will do so, if not then an error will be returned, along // with the raw value of the Cell. // // This is the documentation of the "General" Format in the Office Open XML spec: // // Numbers // The application shall attempt to display the full number up to 11 digits (inc. decimal point). If the number is too // large*, the application shall attempt to show exponential format. If the number has too many significant digits, the // display shall be truncated. The optimal method of display is based on the available cell width. If the number cannot // be displayed using any of these formats in the available width, the application shall show "#" across the width of // the cell. // // Conditions for switching to exponential format: // 1. The cell value shall have at least five digits for xE-xx // 2. If the exponent is bigger than the size allowed, a floating point number cannot fit, so try exponential notation. // 3. Similarly, for negative exponents, check if there is space for even one (non-zero) digit in floating point format**. // 4. Finally, if there isn't room for all of the significant digits in floating point format (for a negative exponent), // exponential format shall display more digits if the exponent is less than -3. (The 3 is because E-xx takes 4 // characters, and the leading 0 in floating point takes only 1 character. Thus, for an exponent less than -3, there is // more than 3 additional leading 0's, more than enough to compensate for the size of the E-xx.) // // Floating point rule: // For general formatting in cells, max overall length for cell display is 11, not including negative sign, but includes // leading zeros and decimal separator.*** // // Added Notes: // * "If the number is too large" can also mean "if the number has more than 11 digits", so greater than or equal to // 1e11 and less than 1e-9. // ** Means that you should switch to scientific if there would be 9 zeros after the decimal (the decimal and first zero // count against the 11 character limit), so less than 1e9. // *** The way this is written, you can get numbers that are more than 11 characters because the golang Float fmt // does not support adjusting the precision while not padding with zeros, while also not switching to scientific // notation too early. func (fullFormat *parsedNumberFormat) FormatValue(cell *Cell) (string, error) { switch cell.cellType { case CellTypeError: // The error type is what XLSX uses in error cases such as when formulas are invalid. // There will be text in the cell's value that can be shown, something ugly like #NAME? or ####### return cell.Value, nil case CellTypeBool: if cell.Value == "0" { return "FALSE", nil } else if cell.Value == "1" { return "TRUE", nil } else { return cell.Value, errors.New("invalid value in bool cell") } case CellTypeString: fallthrough case CellTypeInline: fallthrough case CellTypeStringFormula: textFormat := cell.parsedNumFmt.textFormat // This switch statement is only for String formats switch textFormat.reducedFormatString { case builtInNumFmt[builtInNumFmtIndex_GENERAL]: // General is literally "general" return cell.Value, nil case builtInNumFmt[builtInNumFmtIndex_STRING]: // String is "@" return textFormat.prefix + cell.Value + textFormat.suffix, nil case "": // If cell is not "General" and there is not an "@" symbol in the format, then the cell's value is not // used when determining what to display. It would be completely legal to have a format of "Error" // for strings, and all values that are not numbers would show up as "Error". In that case, this code would // have a prefix of "Error" and a reduced format string of "" (empty string). return textFormat.prefix + textFormat.suffix, nil default: return cell.Value, errors.New("invalid or unsupported format, unsupported string format") } case CellTypeDate: // These are dates that are stored in date format instead of being stored as numbers with a format to turn them // into a date string. return cell.Value, nil case CellTypeNumeric: return fullFormat.formatNumericCell(cell) default: return cell.Value, errors.New("unknown cell type") } } func (fullFormat *parsedNumberFormat) formatNumericCell(cell *Cell) (string, error) { rawValue := strings.TrimSpace(cell.Value) // If there wasn't a value in the cell, it shouldn't have been marked as Numeric. // It's better to support this case though. if rawValue == "" { return "", nil } if fullFormat.isTimeFormat { return fullFormat.parseTime(rawValue, cell.date1904) } var numberFormat *formatOptions floatVal, floatErr := strconv.ParseFloat(rawValue, 64) if floatErr != nil { return rawValue, floatErr } // Choose the correct format. There can be different formats for positive, negative, and zero numbers. // Excel only uses the zero format if the value is literally zero, even if the number is so small that it shows // up as "0" when the positive format is used. if floatVal > 0 { numberFormat = fullFormat.positiveFormat } else if floatVal < 0 { // If format string specified a different format for negative numbers, then the number should be made positive // before getting formatted. The format string itself will contain formatting that denotes a negative number and // this formatting will end up in the prefix or suffix. Commonly if there is a negative format specified, the // number will get surrounded by parenthesis instead of showing it with a minus sign. if fullFormat.negativeFormatExpectsPositive { floatVal = math.Abs(floatVal) } numberFormat = fullFormat.negativeFormat } else { numberFormat = fullFormat.zeroFormat } // When showPercent is true, multiply the number by 100. // The percent sign will be in the prefix or suffix already, so it does not need to be added in this function. // The number format itself will be the same as any other number format once the value is multiplied by 100. if numberFormat.showPercent { floatVal = 100 * floatVal } // Only the most common format strings are supported here. // Eventually this switch needs to be replaced with a more general solution. // Some of these "supported" formats should have thousand separators, but don't get them since Go fmt // doesn't have a way to request thousands separators. // The only things that should be supported here are in the array formattingCharacters, // everything else has been stripped out before and will be placed in the prefix or suffix. // The formatting characters can have non-formatting characters mixed in with them and those should be maintained. // However, at this time we fail to parse those formatting codes and they get replaced with "General" var formattedNum string switch numberFormat.reducedFormatString { case builtInNumFmt[builtInNumFmtIndex_GENERAL]: // General is literally "general" // prefix, showPercent, and suffix cannot apply to the general format // The logic for showing numbers when the format is "general" is much more complicated than the rest of these. generalFormatted, err := generalNumericScientific(cell.Value, true) if err != nil { return rawValue, nil } return generalFormatted, nil case builtInNumFmt[builtInNumFmtIndex_STRING]: // String is "@" formattedNum = cell.Value case builtInNumFmt[builtInNumFmtIndex_INT], "#,##0": // Int is "0" // Previously this case would cast to int and print with %d, but that will not round the value correctly. formattedNum = fmt.Sprintf("%.0f", floatVal) case "0.0", "#,##0.0": formattedNum = fmt.Sprintf("%.1f", floatVal) case builtInNumFmt[builtInNumFmtIndex_FLOAT], "#,##0.00": // Float is "0.00" formattedNum = fmt.Sprintf("%.2f", floatVal) case "0.000", "#,##0.000": formattedNum = fmt.Sprintf("%.3f", floatVal) case "0.0000", "#,##0.0000": formattedNum = fmt.Sprintf("%.4f", floatVal) case "0.00e+00", "##0.0e+0": formattedNum = fmt.Sprintf("%e", floatVal) case "": // Do nothing. default: return rawValue, nil } return numberFormat.prefix + formattedNum + numberFormat.suffix, nil } func generalNumericScientific(value string, allowScientific bool) (string, error) { if strings.TrimSpace(value) == "" { return "", nil } f, err := strconv.ParseFloat(value, 64) if err != nil { return value, err } if allowScientific { absF := math.Abs(f) // When using General format, numbers that are less than 1e-9 (0.000000001) and greater than or equal to // 1e11 (100,000,000,000) should be shown in scientific notation. // Numbers less than the number after zero, are assumed to be zero. if (absF >= math.SmallestNonzeroFloat64 && absF < minNonScientificNumber) || absF >= maxNonScientificNumber { return strconv.FormatFloat(f, 'E', -1, 64), nil } } // This format (fmt="f", prec=-1) will prevent padding with zeros and will never switch to scientific notation. // However, it will show more than 11 characters for very precise numbers, and this cannot be changed. // You could also use fmt="g", prec=11, which doesn't pad with zeros and allows the correct precision, // but it will use scientific notation on numbers less than 1e-4. That value is hardcoded in Go and cannot be // configured or disabled. return strconv.FormatFloat(f, 'f', -1, 64), nil } // Format strings are a little strange to compare because empty string needs to be taken as general, and general needs // to be compared case insensitively. func compareFormatString(fmt1, fmt2 string) bool { if fmt1 == fmt2 { return true } if fmt1 == "" || strings.EqualFold(fmt1, "general") { fmt1 = "general" } if fmt2 == "" || strings.EqualFold(fmt2, "general") { fmt2 = "general" } return fmt1 == fmt2 } func parseFullNumberFormatString(numFmt string) *parsedNumberFormat { parsedNumFmt := &parsedNumberFormat{ numFmt: numFmt, } if isTimeFormat(numFmt) { // Time formats cannot have multiple groups separated by semicolons, there is only one format. // Strings are unaffected by the time format. parsedNumFmt.isTimeFormat = true parsedNumFmt.textFormat, _ = parseNumberFormatSection("general") return parsedNumFmt } var fmtOptions []*formatOptions formats, err := splitFormatOnSemicolon(numFmt) if err == nil { for _, formatSection := range formats { parsedFormat, err := parseNumberFormatSection(formatSection) if err != nil { // If an invalid number section is found, fall back to general parsedFormat = fallbackErrorFormat parsedNumFmt.parseEncounteredError = &err } fmtOptions = append(fmtOptions, parsedFormat) } } else { fmtOptions = append(fmtOptions, fallbackErrorFormat) parsedNumFmt.parseEncounteredError = &err } if len(fmtOptions) > 4 { fmtOptions = []*formatOptions{fallbackErrorFormat} err = errors.New("invalid number format, too many format sections") parsedNumFmt.parseEncounteredError = &err } if len(fmtOptions) == 1 { // If there is only one option, it is used for all parsedNumFmt.positiveFormat = fmtOptions[0] parsedNumFmt.negativeFormat = fmtOptions[0] parsedNumFmt.zeroFormat = fmtOptions[0] if strings.Contains(fmtOptions[0].fullFormatString, "@") { parsedNumFmt.textFormat = fmtOptions[0] } else { parsedNumFmt.textFormat, _ = parseNumberFormatSection("general") } } else if len(fmtOptions) == 2 { // If there are two formats, the first is used for positive and zeros, the second gets used as a negative format, // and strings are not formatted. // When negative numbers now have their own format, they should become positive before having the format applied. // The format will contain a negative sign if it is desired, but they may be colored red or wrapped in // parenthesis instead. parsedNumFmt.negativeFormatExpectsPositive = true parsedNumFmt.positiveFormat = fmtOptions[0] parsedNumFmt.negativeFormat = fmtOptions[1] parsedNumFmt.zeroFormat = fmtOptions[0] parsedNumFmt.textFormat, _ = parseNumberFormatSection("general") } else if len(fmtOptions) == 3 { // If there are three formats, the first is used for positive, the second gets used as a negative format, // the third is for negative, and strings are not formatted. parsedNumFmt.negativeFormatExpectsPositive = true parsedNumFmt.positiveFormat = fmtOptions[0] parsedNumFmt.negativeFormat = fmtOptions[1] parsedNumFmt.zeroFormat = fmtOptions[2] parsedNumFmt.textFormat, _ = parseNumberFormatSection("general") } else { // With four options, the first is positive, the second is negative, the third is zero, and the fourth is strings // Negative numbers should be still become positive before having the negative formatting applied. parsedNumFmt.negativeFormatExpectsPositive = true parsedNumFmt.positiveFormat = fmtOptions[0] parsedNumFmt.negativeFormat = fmtOptions[1] parsedNumFmt.zeroFormat = fmtOptions[2] parsedNumFmt.textFormat = fmtOptions[3] } return parsedNumFmt } // splitFormatOnSemicolon will split the format string into the format sections // This logic to split the different formats on semicolon is fully correct, and will skip all literal semicolons, // and will catch all breaking semicolons. func splitFormatOnSemicolon(format string) ([]string, error) { var formats []string prevIndex := 0 for i := 0; i < len(format); i++ { if format[i] == ';' { formats = append(formats, format[prevIndex:i]) prevIndex = i + 1 } else if format[i] == '\\' { i++ } else if format[i] == '"' { endQuoteIndex := strings.Index(format[i+1:], "\"") if endQuoteIndex == -1 { // This is an invalid format string, fall back to general return nil, errors.New("invalid format string, unmatched double quote") } i += endQuoteIndex + 1 } } return append(formats, format[prevIndex:]), nil } var fallbackErrorFormat = &formatOptions{ fullFormatString: "general", reducedFormatString: "general", } // parseNumberFormatSection takes in individual format and parses out most of the options. // Some options are parsed, removed from the string, and set as settings on formatOptions. // There remainder of the format string is put in the reducedFormatString attribute, and supported values for these // are handled in a switch in the Cell.FormattedValue() function. // Ideally more and more of the format string would be parsed out here into settings until there is no remainder string // at all. // Features that this supports: // - Time formats are detected, and marked in the options. Time format strings are handled when doing the formatting. // The logic to detect time formats is currently not correct, and can catch formats that are not time formats as well // as miss formats that are time formats. // - Color formats are detected and removed. // - Currency annotations are handled properly. // - Literal strings wrapped in quotes are handled and put into prefix or suffix. // - Numbers that should be percent are detected and marked in the options. // - Conditionals are detected and removed, but they are not obeyed. The conditional groups will be used just like the // positive;negative;zero;string format groups. Here is an example of a conditional format: "[Red][<=100];[Blue][>100]" // Decoding the actual number formatting portion is out of scope, that is placed into reducedFormatString and is used // when formatting the string. The string there will be reduced to only the things in the formattingCharacters array. // Everything not in that array has been parsed out and put into formatOptions. func parseNumberFormatSection(fullFormat string) (*formatOptions, error) { reducedFormat := strings.TrimSpace(fullFormat) // general is the only format that does not use the normal format symbols notations if compareFormatString(reducedFormat, "general") { return &formatOptions{ fullFormatString: "general", reducedFormatString: "general", }, nil } prefix, reducedFormat, showPercent1, err := parseLiterals(reducedFormat) if err != nil { return nil, err } reducedFormat, suffixFormat := splitFormatAndSuffixFormat(reducedFormat) suffix, remaining, showPercent2, err := parseLiterals(suffixFormat) if err != nil { return nil, err } if len(remaining) > 0 { // This paradigm of codes consisting of literals, number formats, then more literals is not always correct, they can // actually be intertwined. Though 99% of the time number formats will not do this. // Excel uses this format string for Social Security Numbers: 000\-00\-0000 // and this for US phone numbers: [<=9999999]###\-####;\(###\)\ ###\-#### return nil, errors.New("invalid or unsupported format string") } return &formatOptions{ fullFormatString: fullFormat, isTimeFormat: false, reducedFormatString: reducedFormat, prefix: prefix, suffix: suffix, showPercent: showPercent1 || showPercent2, }, nil } // formattingCharacters will be left in the reducedNumberFormat // It is important that these be looked for in order so that the slash cases are handled correctly. // / (slash) is a fraction format if preceded by 0, #, or ?, otherwise it is not a formatting character // E- E+ e- e+ are scientific notation, but E, e, -, + are not formatting characters independently // \ (back slash) makes the next character a literal (not formatting) // " Anything in double quotes is not a formatting character // _ (underscore) skips the width of the next character, so the next character cannot be formatting var formattingCharacters = []string{"0/", "#/", "?/", "E-", "E+", "e-", "e+", "0", "#", "?", ".", ",", "@", "*"} // The following are also time format characters, but since this is only used for detecting, not decoding, they are // redundant here: ee, gg, ggg, rr, ss, mm, hh, yyyy, dd, ddd, dddd, mm, mmm, mmmm, mmmmm, ss.0000, ss.000, ss.00, ss.0 // The .00 type format is very tricky, because it only counts if it comes after ss or s or [ss] or [s] // .00 is actually a valid number format by itself. var timeFormatCharacters = []string{"m", "d", "yy", "h", "m", "AM/PM", "A/P", "am/pm", "a/p", "r", "g", "e", "b1", "b2", "[hh]", "[h]", "[mm]", "[m]", "s.0000", "s.000", "s.00", "s.0", "s", "[ss].0000", "[ss].000", "[ss].00", "[ss].0", "[ss]", "[s].0000", "[s].000", "[s].00", "[s].0", "[s]"} func splitFormatAndSuffixFormat(format string) (string, string) { var i int for ; i < len(format); i++ { curReducedFormat := format[i:] var found bool for _, special := range formattingCharacters { if strings.HasPrefix(curReducedFormat, special) { // Skip ahead if the special character was longer than length 1 i += len(special) - 1 found = true break } } if !found { break } } suffixFormat := format[i:] format = format[:i] return format, suffixFormat } func parseLiterals(format string) (string, string, bool, error) { var prefix string showPercent := false for i := 0; i < len(format); i++ { curReducedFormat := format[i:] switch curReducedFormat[0] { case '\\': // If there is a slash, skip the next character, and add it to the prefix if len(curReducedFormat) > 1 { i++ prefix += curReducedFormat[1:2] } case '_': // If there is an underscore, skip the next character, but don't add it to the prefix if len(curReducedFormat) > 1 { i++ } case '*': // Asterisks are used to repeat the next character to fill the full cell width. // There isn't really a cell size in this context, so this will be ignored. case '"': // If there is a quote skip to the next quote, and add the quoted characters to the prefix endQuoteIndex := strings.Index(curReducedFormat[1:], "\"") if endQuoteIndex == -1 { return "", "", false, errors.New("invalid formatting code, unmatched double quote") } prefix = prefix + curReducedFormat[1:endQuoteIndex+1] i += endQuoteIndex + 1 case '%': showPercent = true prefix += "%" case '[': // Brackets can be currency annotations (e.g. [$$-409]) // color formats (e.g. [color1] through [color56], as well as [red] etc.) // conditionals (e.g. [>100], the valid conditionals are =, >, <, >=, <=, <>) bracketIndex := strings.Index(curReducedFormat, "]") if bracketIndex == -1 { return "", "", false, errors.New("invalid formatting code, invalid brackets") } // Currencies in Excel are annotated with this format: [$-] // Currency String is something like $, ¥, €, or £ // Language Info is three hexadecimal characters if len(curReducedFormat) > 2 && curReducedFormat[1] == '$' { dashIndex := strings.Index(curReducedFormat, "-") if dashIndex != -1 && dashIndex < bracketIndex { // Get the currency symbol, and skip to the end of the currency format prefix += curReducedFormat[2:dashIndex] } else { return "", "", false, errors.New("invalid formatting code, invalid currency annotation") } } i += bracketIndex case '$', '-', '+', '/', '(', ')', ':', '!', '^', '&', '\'', '~', '{', '}', '<', '>', '=', ' ': // These symbols are allowed to be used as literal without escaping prefix += curReducedFormat[0:1] default: for _, special := range formattingCharacters { if strings.HasPrefix(curReducedFormat, special) { // This means we found the start of the actual number formatting portion, and should return. return prefix, format[i:], showPercent, nil } } // Symbols that don't have meaning and aren't in the exempt literal characters and are not escaped. return "", "", false, errors.New("invalid formatting code: unsupported or unescaped characters") } } return prefix, "", showPercent, nil } // parseTime returns a string parsed using time.Time func (fullFormat *parsedNumberFormat) parseTime(value string, date1904 bool) (string, error) { f, err := strconv.ParseFloat(value, 64) if err != nil { return value, err } val := TimeFromExcelTime(f, date1904) format := fullFormat.numFmt // Replace Excel placeholders with Go time placeholders. // For example, replace yyyy with 2006. These are in a specific order, // due to the fact that m is used in month, minute, and am/pm. It would // be easier to fix that with regular expressions, but if it's possible // to keep this simple it would be easier to maintain. // Full-length month and days (e.g. March, Tuesday) have letters in them that would be replaced // by other characters below (such as the 'h' in March, or the 'd' in Tuesday) below. // First we convert them to arbitrary characters unused in Excel Date formats, and then at the end, // turn them to what they should actually be. // Based off: http://www.ozgrid.com/Excel/CustomFormats.htm replacements := []struct{ xltime, gotime string }{ {"yyyy", "2006"}, {"yy", "06"}, {"mmmm", "%%%%"}, {"dddd", "&&&&"}, {"dd", "02"}, {"d", "2"}, {"mmm", "Jan"}, {"mmss", "0405"}, {"ss", "05"}, {"mm:", "04:"}, {":mm", ":04"}, {"mm", "01"}, {"am/pm", "pm"}, {"m/", "1/"}, {"%%%%", "January"}, {"&&&&", "Monday"}, } // It is the presence of the "am/pm" indicator that determins // if this is a 12 hour or 24 hours time format, not the // number of 'h' characters. if is12HourTime(format) { format = strings.Replace(format, "hh", "03", 1) format = strings.Replace(format, "h", "3", 1) } else { format = strings.Replace(format, "hh", "15", 1) format = strings.Replace(format, "h", "15", 1) } for _, repl := range replacements { format = strings.Replace(format, repl.xltime, repl.gotime, 1) } // If the hour is optional, strip it out, along with the // possible dangling colon that would remain. if val.Hour() < 1 { format = strings.Replace(format, "]:", "]", 1) format = strings.Replace(format, "[03]", "", 1) format = strings.Replace(format, "[3]", "", 1) format = strings.Replace(format, "[15]", "", 1) } else { format = strings.Replace(format, "[3]", "3", 1) format = strings.Replace(format, "[15]", "15", 1) } return val.Format(format), nil } // isTimeFormat checks whether an Excel format string represents a time.Time. // This function is now correct, but it can detect time format strings that cannot be correctly handled by parseTime() func isTimeFormat(format string) bool { var foundTimeFormatCharacters bool for i := 0; i < len(format); i++ { curReducedFormat := format[i:] switch curReducedFormat[0] { case '\\', '_': // If there is a slash, skip the next character, and add it to the prefix // If there is an underscore, skip the next character, but don't add it to the prefix if len(curReducedFormat) > 1 { i++ } case '*': // Asterisks are used to repeat the next character to fill the full cell width. // There isn't really a cell size in this context, so this will be ignored. case '"': // If there is a quote skip to the next quote, and add the quoted characters to the prefix endQuoteIndex := strings.Index(curReducedFormat[1:], "\"") if endQuoteIndex == -1 { // This is not any type of valid format. return false } i += endQuoteIndex + 1 case '$', '-', '+', '/', '(', ')', ':', '!', '^', '&', '\'', '~', '{', '}', '<', '>', '=', ' ': // These symbols are allowed to be used as literal without escaping case ',': // This is not documented in the XLSX spec as far as I can tell, but Excel and Numbers will include // commas in number formats without escaping them, so this should be supported. default: foundInThisLoop := false for _, special := range timeFormatCharacters { if strings.HasPrefix(curReducedFormat, special) { foundTimeFormatCharacters = true foundInThisLoop = true i += len(special) - 1 break } } if foundInThisLoop { continue } if curReducedFormat[0] == '[' { // For number formats, this code would happen above in a case '[': section. // However, for time formats it must happen after looking for occurrences in timeFormatCharacters // because there are a few time formats that can be wrapped in brackets. // Brackets can be currency annotations (e.g. [$$-409]) // color formats (e.g. [color1] through [color56], as well as [red] etc.) // conditionals (e.g. [>100], the valid conditionals are =, >, <, >=, <=, <>) bracketIndex := strings.Index(curReducedFormat, "]") if bracketIndex == -1 { // This is not any type of valid format. return false } i += bracketIndex continue } // Symbols that don't have meaning, aren't in the exempt literal characters, and aren't escaped are invalid. // The string could still be a valid number format string. return false } } // If the string doesn't have any time formatting characters, it could technically be a time format, but it // would be a pretty weak time format. A valid time format with no time formatting symbols will also be a number // format with no number formatting symbols, which is essentially a constant string that does not depend on the // cell's value in anyway. The downstream logic will do the right thing in that case if this returns false. return foundTimeFormatCharacters } // is12HourTime checks whether an Excel time format string is a 12 // hours form. func is12HourTime(format string) bool { return strings.Contains(format, "am/pm") || strings.Contains(format, "AM/PM") || strings.Contains(format, "a/p") || strings.Contains(format, "A/P") } ================================================ FILE: vendor/github.com/tealeg/xlsx/hsl.go ================================================ /* Copyright (c) 2012 Rodrigo Moraes. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package xlsx import ( "image/color" "math" ) // HSLModel converts any color.Color to a HSL color. var HSLModel = color.ModelFunc(hslModel) // HSL represents a cylindrical coordinate of points in an RGB color model. // // Values are in the range 0 to 1. type HSL struct { H, S, L float64 } // RGBA returns the alpha-premultiplied red, green, blue and alpha values // for the HSL. func (c HSL) RGBA() (uint32, uint32, uint32, uint32) { r, g, b := HSLToRGB(c.H, c.S, c.L) return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff } // hslModel converts a color.Color to HSL. func hslModel(c color.Color) color.Color { if _, ok := c.(HSL); ok { return c } r, g, b, _ := c.RGBA() h, s, l := RGBToHSL(uint8(r>>8), uint8(g>>8), uint8(b>>8)) return HSL{h, s, l} } // RGBToHSL converts an RGB triple to a HSL triple. // // Ported from http://goo.gl/Vg1h9 func RGBToHSL(r, g, b uint8) (h, s, l float64) { fR := float64(r) / 255 fG := float64(g) / 255 fB := float64(b) / 255 max := math.Max(math.Max(fR, fG), fB) min := math.Min(math.Min(fR, fG), fB) l = (max + min) / 2 if max == min { // Achromatic. h, s = 0, 0 } else { // Chromatic. d := max - min if l > 0.5 { s = d / (2.0 - max - min) } else { s = d / (max + min) } switch max { case fR: h = (fG - fB) / d if fG < fB { h += 6 } case fG: h = (fB-fR)/d + 2 case fB: h = (fR-fG)/d + 4 } h /= 6 } return } // HSLToRGB converts an HSL triple to a RGB triple. // // Ported from http://goo.gl/Vg1h9 func HSLToRGB(h, s, l float64) (r, g, b uint8) { var fR, fG, fB float64 if s == 0 { fR, fG, fB = l, l, l } else { var q float64 if l < 0.5 { q = l * (1 + s) } else { q = l + s - s*l } p := 2*l - q fR = hueToRGB(p, q, h+1.0/3) fG = hueToRGB(p, q, h) fB = hueToRGB(p, q, h-1.0/3) } r = uint8((fR * 255) + 0.5) g = uint8((fG * 255) + 0.5) b = uint8((fB * 255) + 0.5) return } // hueToRGB is a helper function for HSLToRGB. func hueToRGB(p, q, t float64) float64 { if t < 0 { t += 1 } if t > 1 { t -= 1 } if t < 1.0/6 { return p + (q-p)*6*t } if t < 0.5 { return q } if t < 2.0/3 { return p + (q-p)*(2.0/3-t)*6 } return p } ================================================ FILE: vendor/github.com/tealeg/xlsx/lib.go ================================================ package xlsx import ( "archive/zip" "bytes" "encoding/xml" "errors" "fmt" "io" "path" "strconv" "strings" ) const ( sheetEnding = `` ) // XLSXReaderError is the standard error type for otherwise undefined // errors in the XSLX reading process. type XLSXReaderError struct { Err string } // Error returns a string value from an XLSXReaderError struct in order // that it might comply with the builtin.error interface. func (e *XLSXReaderError) Error() string { return e.Err } // getRangeFromString is an internal helper function that converts // XLSX internal range syntax to a pair of integers. For example, // the range string "1:3" yield the upper and lower integers 1 and 3. func getRangeFromString(rangeString string) (lower int, upper int, error error) { var parts []string parts = strings.SplitN(rangeString, ":", 2) if parts[0] == "" { error = errors.New(fmt.Sprintf("Invalid range '%s'\n", rangeString)) } if parts[1] == "" { error = errors.New(fmt.Sprintf("Invalid range '%s'\n", rangeString)) } lower, error = strconv.Atoi(parts[0]) if error != nil { error = errors.New(fmt.Sprintf("Invalid range (not integer in lower bound) %s\n", rangeString)) } upper, error = strconv.Atoi(parts[1]) if error != nil { error = errors.New(fmt.Sprintf("Invalid range (not integer in upper bound) %s\n", rangeString)) } return lower, upper, error } // ColLettersToIndex is used to convert a character based column // reference to a zero based numeric column identifier. func ColLettersToIndex(letters string) int { sum, mul, n := 0, 1, 0 for i := len(letters) - 1; i >= 0; i, mul, n = i-1, mul*26, 1 { c := letters[i] switch { case 'A' <= c && c <= 'Z': n += int(c - 'A') case 'a' <= c && c <= 'z': n += int(c - 'a') } sum += n * mul } return sum } // Get the largestDenominator that is a multiple of a basedDenominator // and fits at least once into a given numerator. func getLargestDenominator(numerator, multiple, baseDenominator, power int) (int, int) { if numerator/multiple == 0 { return 1, power } next, nextPower := getLargestDenominator( numerator, multiple*baseDenominator, baseDenominator, power+1) if next > multiple { return next, nextPower } return multiple, power } // Convers a list of numbers representing a column into a alphabetic // representation, as used in the spreadsheet. func formatColumnName(colId []int) string { lastPart := len(colId) - 1 result := "" for n, part := range colId { if n == lastPart { // The least significant number is in the // range 0-25, all other numbers are 1-26, // hence we use a differente offset for the // last part. result += string(part + 65) } else { // Don't output leading 0s, as there is no // representation of 0 in this format. if part > 0 { result += string(part + 64) } } } return result } func smooshBase26Slice(b26 []int) []int { // Smoosh values together, eliminating 0s from all but the // least significant part. lastButOnePart := len(b26) - 2 for i := lastButOnePart; i > 0; i-- { part := b26[i] if part == 0 { greaterPart := b26[i-1] if greaterPart > 0 { b26[i-1] = greaterPart - 1 b26[i] = 26 } } } return b26 } func intToBase26(x int) (parts []int) { // Excel column codes are pure evil - in essence they're just // base26, but they don't represent the number 0. b26Denominator, _ := getLargestDenominator(x, 1, 26, 0) // This loop terminates because integer division of 1 / 26 // returns 0. for d := b26Denominator; d > 0; d = d / 26 { value := x / d remainder := x % d parts = append(parts, value) x = remainder } return parts } // ColIndexToLetters is used to convert a zero based, numeric column // indentifier into a character code. func ColIndexToLetters(colRef int) string { parts := intToBase26(colRef) return formatColumnName(smooshBase26Slice(parts)) } // letterOnlyMapF is used in conjunction with strings.Map to return // only the characters A-Z and a-z in a string func letterOnlyMapF(rune rune) rune { switch { case 'A' <= rune && rune <= 'Z': return rune case 'a' <= rune && rune <= 'z': return rune - 32 } return -1 } // intOnlyMapF is used in conjunction with strings.Map to return only // the numeric portions of a string. func intOnlyMapF(rune rune) rune { if rune >= 48 && rune < 58 { return rune } return -1 } // GetCoordsFromCellIDString returns the zero based cartesian // coordinates from a cell name in Excel format, e.g. the cellIDString // "A1" returns 0, 0 and the "B3" return 1, 2. func GetCoordsFromCellIDString(cellIDString string) (x, y int, error error) { var letterPart string = strings.Map(letterOnlyMapF, cellIDString) y, error = strconv.Atoi(strings.Map(intOnlyMapF, cellIDString)) if error != nil { return x, y, error } y -= 1 // Zero based x = ColLettersToIndex(letterPart) return x, y, error } // GetCellIDStringFromCoords returns the Excel format cell name that // represents a pair of zero based cartesian coordinates. func GetCellIDStringFromCoords(x, y int) string { letterPart := ColIndexToLetters(x) numericPart := y + 1 return fmt.Sprintf("%s%d", letterPart, numericPart) } // getMaxMinFromDimensionRef return the zero based cartesian maximum // and minimum coordinates from the dimension reference embedded in a // XLSX worksheet. For example, the dimension reference "A1:B2" // returns "0,0", "1,1". func getMaxMinFromDimensionRef(ref string) (minx, miny, maxx, maxy int, err error) { var parts []string parts = strings.Split(ref, ":") minx, miny, err = GetCoordsFromCellIDString(parts[0]) if err != nil { return -1, -1, -1, -1, err } maxx, maxy, err = GetCoordsFromCellIDString(parts[1]) if err != nil { return -1, -1, -1, -1, err } return } // calculateMaxMinFromWorkSheet works out the dimensions of a spreadsheet // that doesn't have a DimensionRef set. The only case currently // known where this is true is with XLSX exported from Google Docs. // This is also true for XLSX files created through the streaming APIs. func calculateMaxMinFromWorksheet(worksheet *xlsxWorksheet) (minx, miny, maxx, maxy int, err error) { // Note, this method could be very slow for large spreadsheets. var x, y int var maxVal int maxVal = int(^uint(0) >> 1) minx = maxVal miny = maxVal maxy = 0 maxx = 0 for _, row := range worksheet.SheetData.Row { for _, cell := range row.C { x, y, err = GetCoordsFromCellIDString(cell.R) if err != nil { return -1, -1, -1, -1, err } if x < minx { minx = x } if x > maxx { maxx = x } if y < miny { miny = y } if y > maxy { maxy = y } } } if minx == maxVal { minx = 0 } if miny == maxVal { miny = 0 } return } // makeRowFromSpan will, when given a span expressed as a string, // return an empty Row large enough to encompass that span and // populate it with empty cells. All rows start from cell 1 - // regardless of the lower bound of the span. func makeRowFromSpan(spans string, sheet *Sheet) *Row { var error error var upper int var row *Row var cell *Cell row = new(Row) row.Sheet = sheet _, upper, error = getRangeFromString(spans) if error != nil { panic(error) } error = nil row.Cells = make([]*Cell, upper) for i := 0; i < upper; i++ { cell = new(Cell) cell.Value = "" row.Cells[i] = cell } return row } // makeRowFromRaw returns the Row representation of the xlsxRow. func makeRowFromRaw(rawrow xlsxRow, sheet *Sheet) *Row { var upper int var row *Row var cell *Cell row = new(Row) row.Sheet = sheet upper = -1 for _, rawcell := range rawrow.C { if rawcell.R != "" { x, _, error := GetCoordsFromCellIDString(rawcell.R) if error != nil { panic(fmt.Sprintf("Invalid Cell Coord, %s\n", rawcell.R)) } if x > upper { upper = x } continue } upper++ } upper++ row.OutlineLevel = rawrow.OutlineLevel row.Cells = make([]*Cell, upper) for i := 0; i < upper; i++ { cell = new(Cell) cell.Value = "" row.Cells[i] = cell } return row } func makeEmptyRow(sheet *Sheet) *Row { row := new(Row) row.Cells = make([]*Cell, 0) row.Sheet = sheet return row } type sharedFormula struct { x, y int formula string } func formulaForCell(rawcell xlsxC, sharedFormulas map[int]sharedFormula) string { var res string f := rawcell.F if f == nil { return "" } if f.T == "shared" { x, y, err := GetCoordsFromCellIDString(rawcell.R) if err != nil { res = f.Content } else { if f.Ref != "" { res = f.Content sharedFormulas[f.Si] = sharedFormula{x, y, res} } else { sharedFormula := sharedFormulas[f.Si] dx := x - sharedFormula.x dy := y - sharedFormula.y orig := []byte(sharedFormula.formula) var start, end int var stringLiteral bool for end = 0; end < len(orig); end++ { c := orig[end] if c == '"' { stringLiteral = !stringLiteral } if stringLiteral { continue // Skip characters in quotes } if c >= 'A' && c <= 'Z' || c == '$' { res += string(orig[start:end]) start = end end++ foundNum := false for ; end < len(orig); end++ { idc := orig[end] if idc >= '0' && idc <= '9' || idc == '$' { foundNum = true } else if idc >= 'A' && idc <= 'Z' { if foundNum { break } } else { break } } if foundNum { cellID := string(orig[start:end]) res += shiftCell(cellID, dx, dy) start = end } } } if start < len(orig) { res += string(orig[start:]) } } } } else { res = f.Content } return strings.Trim(res, " \t\n\r") } // shiftCell returns the cell shifted according to dx and dy taking into consideration of absolute // references with dollar sign ($) func shiftCell(cellID string, dx, dy int) string { fx, fy, _ := GetCoordsFromCellIDString(cellID) // Is fixed column? fixedCol := strings.Index(cellID, "$") == 0 // Is fixed row? fixedRow := strings.LastIndex(cellID, "$") > 0 if !fixedCol { // Shift column fx += dx } if !fixedRow { // Shift row fy += dy } // New shifted cell shiftedCellID := GetCellIDStringFromCoords(fx, fy) if !fixedCol && !fixedRow { return shiftedCellID } // There are absolute references, need to put the $ back into the formula. letterPart := strings.Map(letterOnlyMapF, shiftedCellID) numberPart := strings.Map(intOnlyMapF, shiftedCellID) result := "" if fixedCol { result += "$" } result += letterPart if fixedRow { result += "$" } result += numberPart return result } // fillCellData attempts to extract a valid value, usable in // CSV form from the raw cell value. Note - this is not actually // general enough - we should support retaining tabs and newlines. func fillCellData(rawCell xlsxC, refTable *RefTable, sharedFormulas map[int]sharedFormula, cell *Cell) { val := strings.Trim(rawCell.V, " \t\n\r") cell.formula = formulaForCell(rawCell, sharedFormulas) switch rawCell.T { case "s": // Shared String cell.cellType = CellTypeString if val != "" { ref, err := strconv.Atoi(val) if err != nil { panic(err) } cell.Value = refTable.ResolveSharedString(ref) } case "inlineStr": cell.cellType = CellTypeInline fillCellDataFromInlineString(rawCell, cell) case "b": // Boolean cell.Value = val cell.cellType = CellTypeBool case "e": // Error cell.Value = val cell.cellType = CellTypeError case "str": // String Formula (special type for cells with formulas that return a string value) // Unlike the other string cell types, the string is stored directly in the value. cell.Value = val cell.cellType = CellTypeStringFormula case "d": // Date: Cell contains a date in the ISO 8601 format. cell.Value = val cell.cellType = CellTypeDate case "": // Numeric is the default fallthrough case "n": // Numeric cell.Value = val cell.cellType = CellTypeNumeric default: panic(errors.New("invalid cell type")) } } // fillCellDataFromInlineString attempts to get inline string data and put it into a Cell. func fillCellDataFromInlineString(rawcell xlsxC, cell *Cell) { cell.Value = "" if rawcell.Is != nil { if rawcell.Is.T != "" { cell.Value = strings.Trim(rawcell.Is.T, " \t\n\r") } else { for _, r := range rawcell.Is.R { cell.Value += r.T } } } } // readRowsFromSheet is an internal helper function that extracts the // rows from a XSLXWorksheet, populates them with Cells and resolves // the value references from the reference table and stores them in // the rows and columns. func readRowsFromSheet(Worksheet *xlsxWorksheet, file *File, sheet *Sheet, rowLimit int) ([]*Row, []*Col, int, int) { var rows []*Row var cols []*Col var row *Row var minCol, maxCol, maxRow, colCount, rowCount int var reftable *RefTable var err error var insertRowIndex, insertColIndex int sharedFormulas := map[int]sharedFormula{} if len(Worksheet.SheetData.Row) == 0 { return nil, nil, 0, 0 } reftable = file.referenceTable if len(Worksheet.Dimension.Ref) > 0 && len(strings.Split(Worksheet.Dimension.Ref, ":")) == 2 && rowLimit == NoRowLimit { minCol, _, maxCol, maxRow, err = getMaxMinFromDimensionRef(Worksheet.Dimension.Ref) } else { minCol, _, maxCol, maxRow, err = calculateMaxMinFromWorksheet(Worksheet) } if err != nil { panic(err.Error()) } rowCount = maxRow + 1 colCount = maxCol + 1 rows = make([]*Row, rowCount) cols = make([]*Col, colCount) for i := range cols { cols[i] = &Col{ Hidden: false, } } if Worksheet.Cols != nil { // Columns can apply to a range, for convenience we expand the // ranges out into individual column definitions. for _, rawcol := range Worksheet.Cols.Col { // Note, below, that sometimes column definitions can // exist outside the defined dimensions of the // spreadsheet - we deliberately exclude these // columns. for i := rawcol.Min; i <= rawcol.Max && i <= colCount; i++ { col := &Col{ Min: rawcol.Min, Max: rawcol.Max, Hidden: rawcol.Hidden, Width: rawcol.Width, OutlineLevel: rawcol.OutlineLevel} cols[i-1] = col if file.styles != nil { col.style = file.styles.getStyle(rawcol.Style) col.numFmt, col.parsedNumFmt = file.styles.getNumberFormat(rawcol.Style) } } } } numRows := len(rows) for rowIndex := 0; rowIndex < len(Worksheet.SheetData.Row); rowIndex++ { rawrow := Worksheet.SheetData.Row[rowIndex] // Some spreadsheets will omit blank rows from the // stored data for rawrow.R > (insertRowIndex + 1) { // Put an empty Row into the array if insertRowIndex < numRows { rows[insertRowIndex] = makeEmptyRow(sheet) } insertRowIndex++ } // range is not empty and only one range exist if len(rawrow.Spans) != 0 && strings.Count(rawrow.Spans, ":") == 1 { row = makeRowFromSpan(rawrow.Spans, sheet) } else { row = makeRowFromRaw(rawrow, sheet) } row.Hidden = rawrow.Hidden height, err := strconv.ParseFloat(rawrow.Ht, 64) if err == nil { row.Height = height } row.isCustom = rawrow.CustomHeight row.OutlineLevel = rawrow.OutlineLevel insertColIndex = minCol for _, rawcell := range rawrow.C { h, v, err := Worksheet.MergeCells.getExtent(rawcell.R) if err != nil { panic(err.Error()) } x, _, _ := GetCoordsFromCellIDString(rawcell.R) // K1000000: Prevent panic when the range specified in the spreadsheet // view exceeds the actual number of columns in the dataset. // Some spreadsheets will omit blank cells // from the data. for x > insertColIndex { // Put an empty Cell into the array if insertColIndex < len(row.Cells) { row.Cells[insertColIndex] = new(Cell) } insertColIndex++ } cellX := insertColIndex if cellX < len(row.Cells) { cell := row.Cells[cellX] cell.HMerge = h cell.VMerge = v fillCellData(rawcell, reftable, sharedFormulas, cell) if file.styles != nil { cell.style = file.styles.getStyle(rawcell.S) cell.NumFmt, cell.parsedNumFmt = file.styles.getNumberFormat(rawcell.S) } cell.date1904 = file.Date1904 // Cell is considered hidden if the row or the column of this cell is hidden cell.Hidden = rawrow.Hidden || (len(cols) > cellX && cols[cellX].Hidden) insertColIndex++ } } if len(rows) > insertRowIndex { rows[insertRowIndex] = row } insertRowIndex++ } // insert trailing empty rows for the rest of the file for ; insertRowIndex < rowCount; insertRowIndex++ { rows[insertRowIndex] = makeEmptyRow(sheet) } return rows, cols, colCount, rowCount } type indexedSheet struct { Index int Sheet *Sheet Error error } func readSheetViews(xSheetViews xlsxSheetViews) []SheetView { if xSheetViews.SheetView == nil || len(xSheetViews.SheetView) == 0 { return nil } sheetViews := []SheetView{} for _, xSheetView := range xSheetViews.SheetView { sheetView := SheetView{} if xSheetView.Pane != nil { xlsxPane := xSheetView.Pane pane := &Pane{} pane.XSplit = xlsxPane.XSplit pane.YSplit = xlsxPane.YSplit pane.TopLeftCell = xlsxPane.TopLeftCell pane.ActivePane = xlsxPane.ActivePane pane.State = xlsxPane.State sheetView.Pane = pane } sheetViews = append(sheetViews, sheetView) } return sheetViews } // readSheetFromFile is the logic of converting a xlsxSheet struct // into a Sheet struct. This work can be done in parallel and so // readSheetsFromZipFile will spawn an instance of this function per // sheet and get the results back on the provided channel. func readSheetFromFile(sc chan *indexedSheet, index int, rsheet xlsxSheet, fi *File, sheetXMLMap map[string]string, rowLimit int) (errRes error) { result := &indexedSheet{Index: index, Sheet: nil, Error: nil} defer func() { if e := recover(); e != nil { switch e.(type) { case error: result.Error = e.(error) errRes = e.(error) default: result.Error = errors.New("unexpected error") } // The only thing here, is if one close the channel. but its not the case sc <- result } }() worksheet, err := getWorksheetFromSheet(rsheet, fi.worksheets, sheetXMLMap, rowLimit) if err != nil { result.Error = err sc <- result return err } sheet := new(Sheet) sheet.File = fi sheet.Rows, sheet.Cols, sheet.MaxCol, sheet.MaxRow = readRowsFromSheet(worksheet, fi, sheet, rowLimit) sheet.Hidden = rsheet.State == sheetStateHidden || rsheet.State == sheetStateVeryHidden sheet.SheetViews = readSheetViews(worksheet.SheetViews) sheet.SheetFormat.DefaultColWidth = worksheet.SheetFormatPr.DefaultColWidth sheet.SheetFormat.DefaultRowHeight = worksheet.SheetFormatPr.DefaultRowHeight sheet.SheetFormat.OutlineLevelCol = worksheet.SheetFormatPr.OutlineLevelCol sheet.SheetFormat.OutlineLevelRow = worksheet.SheetFormatPr.OutlineLevelRow result.Sheet = sheet sc <- result return nil } // readSheetsFromZipFile is an internal helper function that loops // over the Worksheets defined in the XSLXWorkbook and loads them into // Sheet objects stored in the Sheets slice of a xlsx.File struct. func readSheetsFromZipFile(f *zip.File, file *File, sheetXMLMap map[string]string, rowLimit int) (map[string]*Sheet, []*Sheet, error) { var workbook *xlsxWorkbook var err error var rc io.ReadCloser var decoder *xml.Decoder var sheetCount int workbook = new(xlsxWorkbook) rc, err = f.Open() if err != nil { return nil, nil, err } decoder = xml.NewDecoder(rc) err = decoder.Decode(workbook) if err != nil { return nil, nil, err } file.Date1904 = workbook.WorkbookPr.Date1904 for entryNum := range workbook.DefinedNames.DefinedName { file.DefinedNames = append(file.DefinedNames, &workbook.DefinedNames.DefinedName[entryNum]) } // Only try and read sheets that have corresponding files. // Notably this excludes chartsheets don't right now var workbookSheets []xlsxSheet for _, sheet := range workbook.Sheets.Sheet { if f := worksheetFileForSheet(sheet, file.worksheets, sheetXMLMap); f != nil { workbookSheets = append(workbookSheets, sheet) } } sheetCount = len(workbookSheets) sheetsByName := make(map[string]*Sheet, sheetCount) sheets := make([]*Sheet, sheetCount) sheetChan := make(chan *indexedSheet, sheetCount) go func() { defer close(sheetChan) err = nil for i, rawsheet := range workbookSheets { if err := readSheetFromFile(sheetChan, i, rawsheet, file, sheetXMLMap, rowLimit); err != nil { return } } }() for j := 0; j < sheetCount; j++ { sheet := <-sheetChan if sheet.Error != nil { return nil, nil, sheet.Error } sheetName := workbookSheets[sheet.Index].Name sheetsByName[sheetName] = sheet.Sheet sheet.Sheet.Name = sheetName sheets[sheet.Index] = sheet.Sheet } return sheetsByName, sheets, nil } // readSharedStringsFromZipFile() is an internal helper function to // extract a reference table from the sharedStrings.xml file within // the XLSX zip file. func readSharedStringsFromZipFile(f *zip.File) (*RefTable, error) { var sst *xlsxSST var error error var rc io.ReadCloser var decoder *xml.Decoder var reftable *RefTable // In a file with no strings it's possible that // sharedStrings.xml doesn't exist. In this case the value // passed as f will be nil. if f == nil { return nil, nil } rc, error = f.Open() if error != nil { return nil, error } sst = new(xlsxSST) decoder = xml.NewDecoder(rc) error = decoder.Decode(sst) if error != nil { return nil, error } reftable = MakeSharedStringRefTable(sst) return reftable, nil } // readStylesFromZipFile() is an internal helper function to // extract a style table from the style.xml file within // the XLSX zip file. func readStylesFromZipFile(f *zip.File, theme *theme) (*xlsxStyleSheet, error) { var style *xlsxStyleSheet var error error var rc io.ReadCloser var decoder *xml.Decoder rc, error = f.Open() if error != nil { return nil, error } style = newXlsxStyleSheet(theme) decoder = xml.NewDecoder(rc) error = decoder.Decode(style) if error != nil { return nil, error } buildNumFmtRefTable(style) return style, nil } func buildNumFmtRefTable(style *xlsxStyleSheet) { for _, numFmt := range style.NumFmts.NumFmt { // We do this for the side effect of populating the NumFmtRefTable. style.addNumFmt(numFmt) } } func readThemeFromZipFile(f *zip.File) (*theme, error) { rc, err := f.Open() if err != nil { return nil, err } var themeXml xlsxTheme err = xml.NewDecoder(rc).Decode(&themeXml) if err != nil { return nil, err } return newTheme(themeXml), nil } type WorkBookRels map[string]string func (w *WorkBookRels) MakeXLSXWorkbookRels() xlsxWorkbookRels { relCount := len(*w) xWorkbookRels := xlsxWorkbookRels{} xWorkbookRels.Relationships = make([]xlsxWorkbookRelation, relCount+3) for k, v := range *w { index, err := strconv.Atoi(k[3:]) if err != nil { panic(err.Error()) } xWorkbookRels.Relationships[index-1] = xlsxWorkbookRelation{ Id: k, Target: v, Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"} } relCount++ sheetId := fmt.Sprintf("rId%d", relCount) xWorkbookRels.Relationships[relCount-1] = xlsxWorkbookRelation{ Id: sheetId, Target: "sharedStrings.xml", Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"} relCount++ sheetId = fmt.Sprintf("rId%d", relCount) xWorkbookRels.Relationships[relCount-1] = xlsxWorkbookRelation{ Id: sheetId, Target: "theme/theme1.xml", Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"} relCount++ sheetId = fmt.Sprintf("rId%d", relCount) xWorkbookRels.Relationships[relCount-1] = xlsxWorkbookRelation{ Id: sheetId, Target: "styles.xml", Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"} return xWorkbookRels } // readWorkbookRelationsFromZipFile is an internal helper function to // extract a map of relationship ID strings to the name of the // worksheet.xml file they refer to. The resulting map can be used to // reliably derefence the worksheets in the XLSX file. func readWorkbookRelationsFromZipFile(workbookRels *zip.File) (WorkBookRels, error) { var sheetXMLMap WorkBookRels var wbRelationships *xlsxWorkbookRels var rc io.ReadCloser var decoder *xml.Decoder var err error rc, err = workbookRels.Open() if err != nil { return nil, err } decoder = xml.NewDecoder(rc) wbRelationships = new(xlsxWorkbookRels) err = decoder.Decode(wbRelationships) if err != nil { return nil, err } sheetXMLMap = make(WorkBookRels) for _, rel := range wbRelationships.Relationships { if strings.HasSuffix(rel.Target, ".xml") && rel.Type == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" { _, filename := path.Split(rel.Target) sheetXMLMap[rel.Id] = strings.Replace(filename, ".xml", "", 1) } } return sheetXMLMap, nil } // ReadZip() takes a pointer to a zip.ReadCloser and returns a // xlsx.File struct populated with its contents. In most cases // ReadZip is not used directly, but is called internally by OpenFile. func ReadZip(f *zip.ReadCloser) (*File, error) { return ReadZipWithRowLimit(f, NoRowLimit) } // ReadZipWithRowLimit() takes a pointer to a zip.ReadCloser and returns a // xlsx.File struct populated with its contents. In most cases // ReadZip is not used directly, but is called internally by OpenFile. func ReadZipWithRowLimit(f *zip.ReadCloser, rowLimit int) (*File, error) { defer f.Close() return ReadZipReaderWithRowLimit(&f.Reader, rowLimit) } // ReadZipReader() can be used to read an XLSX in memory without // touching the filesystem. func ReadZipReader(r *zip.Reader) (*File, error) { return ReadZipReaderWithRowLimit(r, NoRowLimit) } // ReadZipReaderWithRowLimit() can be used to read an XLSX in memory without // touching the filesystem. // rowLimit is the number of rows that should be read from the file. If rowLimit is -1, no limit is applied. // You can specify this with the constant NoRowLimit. func ReadZipReaderWithRowLimit(r *zip.Reader, rowLimit int) (*File, error) { var err error var file *File var reftable *RefTable var sharedStrings *zip.File var sheetXMLMap map[string]string var sheetsByName map[string]*Sheet var sheets []*Sheet var style *xlsxStyleSheet var styles *zip.File var themeFile *zip.File var v *zip.File var workbook *zip.File var workbookRels *zip.File var worksheets map[string]*zip.File file = NewFile() // file.numFmtRefTable = make(map[int]xlsxNumFmt, 1) worksheets = make(map[string]*zip.File, len(r.File)) for _, v = range r.File { switch v.Name { case "xl/sharedStrings.xml": sharedStrings = v case "xl/workbook.xml": workbook = v case "xl/_rels/workbook.xml.rels": workbookRels = v case "xl/styles.xml": styles = v case "xl/theme/theme1.xml": themeFile = v default: if len(v.Name) > 17 { if v.Name[0:13] == "xl/worksheets" { worksheets[v.Name[14:len(v.Name)-4]] = v } } } } if workbookRels == nil { return nil, fmt.Errorf("xl/_rels/workbook.xml.rels not found in input xlsx.") } sheetXMLMap, err = readWorkbookRelationsFromZipFile(workbookRels) if err != nil { return nil, err } if len(worksheets) == 0 { return nil, fmt.Errorf("Input xlsx contains no worksheets.") } file.worksheets = worksheets reftable, err = readSharedStringsFromZipFile(sharedStrings) if err != nil { return nil, err } file.referenceTable = reftable if themeFile != nil { theme, err := readThemeFromZipFile(themeFile) if err != nil { return nil, err } file.theme = theme } if styles != nil { style, err = readStylesFromZipFile(styles, file.theme) if err != nil { return nil, err } file.styles = style } sheetsByName, sheets, err = readSheetsFromZipFile(workbook, file, sheetXMLMap, rowLimit) if err != nil { return nil, err } if sheets == nil { readerErr := new(XLSXReaderError) readerErr.Err = "No sheets found in XLSX File" return nil, readerErr } file.Sheet = sheetsByName file.Sheets = sheets return file, nil } // truncateSheetXML will take in a reader to an XML sheet file and will return a reader that will read an equivalent // XML sheet file with only the number of rows specified. This greatly speeds up XML unmarshalling when only // a few rows need to be read from a large sheet. // When sheets are truncated, all formatting present after the sheetData tag will be lost, but all of this formatting // is related to printing and visibility, and is out of scope for most purposes of this library. func truncateSheetXML(r io.Reader, rowLimit int) (io.Reader, error) { var rowCount int var token xml.Token var readErr error output := new(bytes.Buffer) r = io.TeeReader(r, output) decoder := xml.NewDecoder(r) for { token, readErr = decoder.Token() if readErr == io.EOF { break } else if readErr != nil { return nil, readErr } end, ok := token.(xml.EndElement) if ok && end.Name.Local == "row" { rowCount++ if rowCount >= rowLimit { break } } } offset := decoder.InputOffset() output.Truncate(int(offset)) if readErr != io.EOF { _, err := output.Write([]byte(sheetEnding)) if err != nil { return nil, err } } return output, nil } ================================================ FILE: vendor/github.com/tealeg/xlsx/read.go ================================================ package xlsx import ( "errors" "reflect" "strconv" "time" ) var ( errNilInterface = errors.New("nil pointer is not a valid argument") errNotStructPointer = errors.New("argument must be a pointer to struct") errInvalidTag = errors.New(`invalid tag: must have the format xlsx:idx`) ) //XLSXUnmarshaler is the interface implemented for types that can unmarshal a Row //as a representation of themselves. type XLSXUnmarshaler interface { Unmarshal(*Row) error } //ReadStruct reads a struct from r to ptr. Accepts a ptr //to struct. This code expects a tag xlsx:"N", where N is the index //of the cell to be used. Basic types like int,string,float64 and bool //are supported func (r *Row) ReadStruct(ptr interface{}) error { if ptr == nil { return errNilInterface } //check if the type implements XLSXUnmarshaler. If so, //just let it do the work. unmarshaller, ok := ptr.(XLSXUnmarshaler) if ok { return unmarshaller.Unmarshal(r) } v := reflect.ValueOf(ptr) if v.Kind() != reflect.Ptr { return errNotStructPointer } v = v.Elem() if v.Kind() != reflect.Struct { return errNotStructPointer } n := v.NumField() for i := 0; i < n; i++ { field := v.Type().Field(i) idx := field.Tag.Get("xlsx") //do a recursive check for the field if it is a struct or a pointer //even if it doesn't have a tag //ignore if it has a - or empty tag isTime := false switch { case idx == "-": continue case field.Type.Kind() == reflect.Ptr || field.Type.Kind() == reflect.Struct: var structPtr interface{} if !v.Field(i).CanSet() { continue } if field.Type.Kind() == reflect.Struct { structPtr = v.Field(i).Addr().Interface() } else { structPtr = v.Field(i).Interface() } //check if the container is a time.Time _, isTime = structPtr.(*time.Time) if isTime { break } err := r.ReadStruct(structPtr) if err != nil { return err } continue case len(idx) == 0: continue } pos, err := strconv.Atoi(idx) if err != nil { return errInvalidTag } //check if desired position is not out of bounds if pos > len(r.Cells)-1 { continue } cell := r.Cells[pos] fieldV := v.Field(i) //continue if the field is not settable if !fieldV.CanSet() { continue } if isTime { t, err := cell.GetTime(false) if err != nil { return err } if field.Type.Kind() == reflect.Ptr { fieldV.Set(reflect.ValueOf(&t)) } else { fieldV.Set(reflect.ValueOf(t)) } continue } switch field.Type.Kind() { case reflect.String: value, err := cell.FormattedValue() if err != nil { return err } fieldV.SetString(value) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: value, err := cell.Int64() if err != nil { return err } fieldV.SetInt(value) case reflect.Float64: value, err := cell.Float() if err != nil { return err } fieldV.SetFloat(value) case reflect.Bool: value := cell.Bool() fieldV.SetBool(value) } } value := v.Interface() ptr = &value return nil } ================================================ FILE: vendor/github.com/tealeg/xlsx/reftable.go ================================================ package xlsx type RefTable struct { indexedStrings []string knownStrings map[string]int isWrite bool } // NewSharedStringRefTable() creates a new, empty RefTable. func NewSharedStringRefTable() *RefTable { rt := RefTable{} rt.knownStrings = make(map[string]int) return &rt } // MakeSharedStringRefTable() takes an xlsxSST struct and converts // it's contents to an slice of strings used to refer to string values // by numeric index - this is the model used within XLSX worksheet (a // numeric reference is stored to a shared cell value). func MakeSharedStringRefTable(source *xlsxSST) *RefTable { reftable := NewSharedStringRefTable() reftable.isWrite = false for _, si := range source.SI { if len(si.R) > 0 { newString := "" for j := 0; j < len(si.R); j++ { newString = newString + si.R[j].T } reftable.AddString(newString) } else { reftable.AddString(si.T) } } return reftable } // makeXlsxSST() takes a RefTable and returns and // equivalent xlsxSST representation. func (rt *RefTable) makeXLSXSST() xlsxSST { sst := xlsxSST{} sst.Count = len(rt.indexedStrings) sst.UniqueCount = sst.Count for _, ref := range rt.indexedStrings { si := xlsxSI{} si.T = ref sst.SI = append(sst.SI, si) } return sst } // Resolvesharedstring() looks up a string value by numeric index from // a provided reference table (just a slice of strings in the correct // order). This function only exists to provide clarity or purpose // via it's name. func (rt *RefTable) ResolveSharedString(index int) string { return rt.indexedStrings[index] } // AddString adds a string to the reference table and return it's // numeric index. If the string already exists then it simply returns // the existing index. func (rt *RefTable) AddString(str string) int { if rt.isWrite { index, ok := rt.knownStrings[str] if ok { return index } } rt.indexedStrings = append(rt.indexedStrings, str) index := len(rt.indexedStrings) - 1 rt.knownStrings[str] = index return index } func (rt *RefTable) Length() int { return len(rt.indexedStrings) } ================================================ FILE: vendor/github.com/tealeg/xlsx/row.go ================================================ package xlsx type Row struct { Cells []*Cell Hidden bool Sheet *Sheet Height float64 OutlineLevel uint8 isCustom bool } func (r *Row) SetHeight(ht float64) { r.Height = ht r.isCustom = true } func (r *Row) SetHeightCM(ht float64) { r.Height = ht * 28.3464567 // Convert CM to postscript points r.isCustom = true } func (r *Row) AddCell() *Cell { cell := NewCell(r) r.Cells = append(r.Cells, cell) r.Sheet.maybeAddCol(len(r.Cells)) return cell } ================================================ FILE: vendor/github.com/tealeg/xlsx/sheet.go ================================================ package xlsx import ( "errors" "fmt" "strconv" ) // Sheet is a high level structure intended to provide user access to // the contents of a particular sheet within an XLSX file. type Sheet struct { Name string File *File Rows []*Row Cols []*Col MaxRow int MaxCol int Hidden bool Selected bool SheetViews []SheetView SheetFormat SheetFormat AutoFilter *AutoFilter } type SheetView struct { Pane *Pane } type Pane struct { XSplit float64 YSplit float64 TopLeftCell string ActivePane string State string // Either "split" or "frozen" } type SheetFormat struct { DefaultColWidth float64 DefaultRowHeight float64 OutlineLevelCol uint8 OutlineLevelRow uint8 } type AutoFilter struct { TopLeftCell string BottomRightCell string } // Add a new Row to a Sheet func (s *Sheet) AddRow() *Row { row := &Row{Sheet: s} s.Rows = append(s.Rows, row) if len(s.Rows) > s.MaxRow { s.MaxRow = len(s.Rows) } return row } // Make sure we always have as many Cols as we do cells. func (s *Sheet) maybeAddCol(cellCount int) { if cellCount > s.MaxCol { col := &Col{ style: NewStyle(), Min: cellCount, Max: cellCount, Hidden: false, Collapsed: false} s.Cols = append(s.Cols, col) s.MaxCol = cellCount } } // Make sure we always have as many Cols as we do cells. func (s *Sheet) Col(idx int) *Col { s.maybeAddCol(idx + 1) return s.Cols[idx] } // Get a Cell by passing it's cartesian coordinates (zero based) as // row and column integer indexes. // // For example: // // cell := sheet.Cell(0,0) // // ... would set the variable "cell" to contain a Cell struct // containing the data from the field "A1" on the spreadsheet. func (sh *Sheet) Cell(row, col int) *Cell { // If the user requests a row beyond what we have, then extend. for len(sh.Rows) <= row { sh.AddRow() } r := sh.Rows[row] for len(r.Cells) <= col { r.AddCell() } return r.Cells[col] } //Set the width of a single column or multiple columns. func (s *Sheet) SetColWidth(startcol, endcol int, width float64) error { if startcol > endcol { return fmt.Errorf("Could not set width for range %d-%d: startcol must be less than endcol.", startcol, endcol) } col := &Col{ style: NewStyle(), Min: startcol + 1, Max: endcol + 1, Hidden: false, Collapsed: false, Width: width} s.Cols = append(s.Cols, col) if endcol+1 > s.MaxCol { s.MaxCol = endcol + 1 } return nil } // When merging cells, the cell may be the 'original' or the 'covered'. // First, figure out which cells are merge starting points. Then create // the necessary cells underlying the merge area. // Then go through all the underlying cells and apply the appropriate // border, based on the original cell. func (s *Sheet) handleMerged() { merged := make(map[string]*Cell) for r, row := range s.Rows { for c, cell := range row.Cells { if cell.HMerge > 0 || cell.VMerge > 0 { coord := GetCellIDStringFromCoords(c, r) merged[coord] = cell } } } // This loop iterates over all cells that should be merged and applies the correct // borders to them depending on their position. If any cells required by the merge // are missing, they will be allocated by s.Cell(). for key, cell := range merged { mainstyle := cell.GetStyle() top := mainstyle.Border.Top left := mainstyle.Border.Left right := mainstyle.Border.Right bottom := mainstyle.Border.Bottom // When merging cells, the upper left cell does not maintain // the original borders mainstyle.Border.Top = "none" mainstyle.Border.Left = "none" mainstyle.Border.Right = "none" mainstyle.Border.Bottom = "none" maincol, mainrow, _ := GetCoordsFromCellIDString(key) for rownum := 0; rownum <= cell.VMerge; rownum++ { for colnum := 0; colnum <= cell.HMerge; colnum++ { tmpcell := s.Cell(mainrow+rownum, maincol+colnum) style := tmpcell.GetStyle() style.ApplyBorder = true if rownum == 0 { style.Border.Top = top } if rownum == (cell.VMerge) { style.Border.Bottom = bottom } if colnum == 0 { style.Border.Left = left } if colnum == (cell.HMerge) { style.Border.Right = right } } } } } // Dump sheet to its XML representation, intended for internal use only func (s *Sheet) makeXLSXSheet(refTable *RefTable, styles *xlsxStyleSheet) *xlsxWorksheet { worksheet := newXlsxWorksheet() xSheet := xlsxSheetData{} maxRow := 0 maxCell := 0 var maxLevelCol, maxLevelRow uint8 // Scan through the sheet and see if there are any merged cells. If there // are, we may need to extend the size of the sheet. There needs to be // phantom cells underlying the area covered by the merged cell s.handleMerged() for index, sheetView := range s.SheetViews { if sheetView.Pane != nil { worksheet.SheetViews.SheetView[index].Pane = &xlsxPane{ XSplit: sheetView.Pane.XSplit, YSplit: sheetView.Pane.YSplit, TopLeftCell: sheetView.Pane.TopLeftCell, ActivePane: sheetView.Pane.ActivePane, State: sheetView.Pane.State, } } } if s.Selected { worksheet.SheetViews.SheetView[0].TabSelected = true } if s.SheetFormat.DefaultRowHeight != 0 { worksheet.SheetFormatPr.DefaultRowHeight = s.SheetFormat.DefaultRowHeight } worksheet.SheetFormatPr.DefaultColWidth = s.SheetFormat.DefaultColWidth colsXfIdList := make([]int, len(s.Cols)) worksheet.Cols = &xlsxCols{Col: []xlsxCol{}} for c, col := range s.Cols { XfId := 0 if col.Min == 0 { col.Min = 1 } if col.Max == 0 { col.Max = 1 } style := col.GetStyle() //col's style always not nil if style != nil { xNumFmt := styles.newNumFmt(col.numFmt) XfId = handleStyleForXLSX(style, xNumFmt.NumFmtId, styles) } colsXfIdList[c] = XfId var customWidth bool if col.Width == 0 { col.Width = ColWidth customWidth = false } else { customWidth = true } worksheet.Cols.Col = append(worksheet.Cols.Col, xlsxCol{Min: col.Min, Max: col.Max, Hidden: col.Hidden, Width: col.Width, CustomWidth: customWidth, Collapsed: col.Collapsed, OutlineLevel: col.OutlineLevel, Style: XfId, }) if col.OutlineLevel > maxLevelCol { maxLevelCol = col.OutlineLevel } } for r, row := range s.Rows { if r > maxRow { maxRow = r } xRow := xlsxRow{} xRow.R = r + 1 if row.isCustom { xRow.CustomHeight = true xRow.Ht = fmt.Sprintf("%g", row.Height) } xRow.OutlineLevel = row.OutlineLevel if row.OutlineLevel > maxLevelRow { maxLevelRow = row.OutlineLevel } for c, cell := range row.Cells { XfId := colsXfIdList[c] // generate NumFmtId and add new NumFmt xNumFmt := styles.newNumFmt(cell.NumFmt) style := cell.style if style != nil { XfId = handleStyleForXLSX(style, xNumFmt.NumFmtId, styles) } else if len(cell.NumFmt) > 0 && !compareFormatString(s.Cols[c].numFmt, cell.NumFmt) { XfId = handleNumFmtIdForXLSX(xNumFmt.NumFmtId, styles) } if c > maxCell { maxCell = c } xC := xlsxC{ S: XfId, R: GetCellIDStringFromCoords(c, r), } if cell.formula != "" { xC.F = &xlsxF{Content: cell.formula} } switch cell.cellType { case CellTypeInline: // Inline strings are turned into shared strings since they are more efficient. // This is what Excel does as well. fallthrough case CellTypeString: if len(cell.Value) > 0 { xC.V = strconv.Itoa(refTable.AddString(cell.Value)) } xC.T = "s" case CellTypeNumeric: // Numeric is the default, so the type can be left blank xC.V = cell.Value case CellTypeBool: xC.V = cell.Value xC.T = "b" case CellTypeError: xC.V = cell.Value xC.T = "e" case CellTypeDate: xC.V = cell.Value xC.T = "d" case CellTypeStringFormula: xC.V = cell.Value xC.T = "str" default: panic(errors.New("unknown cell type cannot be marshaled")) } xRow.C = append(xRow.C, xC) if cell.HMerge > 0 || cell.VMerge > 0 { // r == rownum, c == colnum mc := xlsxMergeCell{} start := GetCellIDStringFromCoords(c, r) endCol := c + cell.HMerge endRow := r + cell.VMerge end := GetCellIDStringFromCoords(endCol, endRow) mc.Ref = start + ":" + end if worksheet.MergeCells == nil { worksheet.MergeCells = &xlsxMergeCells{} } worksheet.MergeCells.Cells = append(worksheet.MergeCells.Cells, mc) } } xSheet.Row = append(xSheet.Row, xRow) } // Update sheet format with the freshly determined max levels s.SheetFormat.OutlineLevelCol = maxLevelCol s.SheetFormat.OutlineLevelRow = maxLevelRow // .. and then also apply this to the xml worksheet worksheet.SheetFormatPr.OutlineLevelCol = s.SheetFormat.OutlineLevelCol worksheet.SheetFormatPr.OutlineLevelRow = s.SheetFormat.OutlineLevelRow if worksheet.MergeCells != nil { worksheet.MergeCells.Count = len(worksheet.MergeCells.Cells) } if s.AutoFilter != nil { worksheet.AutoFilter = &xlsxAutoFilter{Ref: fmt.Sprintf("%v:%v", s.AutoFilter.TopLeftCell, s.AutoFilter.BottomRightCell)} } worksheet.SheetData = xSheet dimension := xlsxDimension{} dimension.Ref = "A1:" + GetCellIDStringFromCoords(maxCell, maxRow) if dimension.Ref == "A1:A1" { dimension.Ref = "A1" } worksheet.Dimension = dimension return worksheet } func handleStyleForXLSX(style *Style, NumFmtId int, styles *xlsxStyleSheet) (XfId int) { xFont, xFill, xBorder, xCellXf := style.makeXLSXStyleElements() fontId := styles.addFont(xFont) fillId := styles.addFill(xFill) // HACK - adding light grey fill, as in OO and Google greyfill := xlsxFill{} greyfill.PatternFill.PatternType = "lightGray" styles.addFill(greyfill) borderId := styles.addBorder(xBorder) xCellXf.FontId = fontId xCellXf.FillId = fillId xCellXf.BorderId = borderId xCellXf.NumFmtId = NumFmtId // apply the numFmtId when it is not the default cellxf if xCellXf.NumFmtId > 0 { xCellXf.ApplyNumberFormat = true } xCellXf.Alignment.Horizontal = style.Alignment.Horizontal xCellXf.Alignment.Indent = style.Alignment.Indent xCellXf.Alignment.ShrinkToFit = style.Alignment.ShrinkToFit xCellXf.Alignment.TextRotation = style.Alignment.TextRotation xCellXf.Alignment.Vertical = style.Alignment.Vertical xCellXf.Alignment.WrapText = style.Alignment.WrapText XfId = styles.addCellXf(xCellXf) return } func handleNumFmtIdForXLSX(NumFmtId int, styles *xlsxStyleSheet) (XfId int) { xCellXf := makeXLSXCellElement() xCellXf.NumFmtId = NumFmtId if xCellXf.NumFmtId > 0 { xCellXf.ApplyNumberFormat = true } XfId = styles.addCellXf(xCellXf) return } ================================================ FILE: vendor/github.com/tealeg/xlsx/stream_file.go ================================================ package xlsx import ( "archive/zip" "encoding/xml" "errors" "io" "strconv" ) type StreamFile struct { xlsxFile *File sheetXmlPrefix []string sheetXmlSuffix []string zipWriter *zip.Writer currentSheet *streamSheet styleIds [][]int err error } type streamSheet struct { // sheetIndex is the XLSX sheet index, which starts at 1 index int // The number of rows that have been written to the sheet so far rowCount int // The number of columns in the sheet columnCount int // The writer to write to this sheet's file in the XLSX Zip file writer io.Writer styleIds []int } var ( NoCurrentSheetError = errors.New("no Current Sheet") WrongNumberOfRowsError = errors.New("invalid number of cells passed to Write. All calls to Write on the same sheet must have the same number of cells") AlreadyOnLastSheetError = errors.New("NextSheet() called, but already on last sheet") ) // Write will write a row of cells to the current sheet. Every call to Write on the same sheet must contain the // same number of cells as the header provided when the sheet was created or an error will be returned. This function // will always trigger a flush on success. Currently the only supported data type is string data. func (sf *StreamFile) Write(cells []string) error { if sf.err != nil { return sf.err } err := sf.write(cells) if err != nil { sf.err = err return err } return sf.zipWriter.Flush() } func (sf *StreamFile) WriteAll(records [][]string) error { if sf.err != nil { return sf.err } for _, row := range records { err := sf.write(row) if err != nil { sf.err = err return err } } return sf.zipWriter.Flush() } func (sf *StreamFile) write(cells []string) error { if sf.currentSheet == nil { return NoCurrentSheetError } if len(cells) != sf.currentSheet.columnCount { return WrongNumberOfRowsError } sf.currentSheet.rowCount++ if err := sf.currentSheet.write(``); err != nil { return err } for colIndex, cellData := range cells { // documentation for the c.t (cell.Type) attribute: // b (Boolean): Cell containing a boolean. // d (Date): Cell contains a date in the ISO 8601 format. // e (Error): Cell containing an error. // inlineStr (Inline String): Cell containing an (inline) rich string, i.e., one not in the shared string table. // If this cell type is used, then the cell value is in the is element rather than the v element in the cell (c element). // n (Number): Cell containing a number. // s (Shared String): Cell containing a shared string. // str (String): Cell containing a formula string. cellCoordinate := GetCellIDStringFromCoords(colIndex, sf.currentSheet.rowCount-1) cellType := "inlineStr" cellOpen := `` cellClose := `` if err := sf.currentSheet.write(cellOpen); err != nil { return err } if err := xml.EscapeText(sf.currentSheet.writer, []byte(cellData)); err != nil { return err } if err := sf.currentSheet.write(cellClose); err != nil { return err } } if err := sf.currentSheet.write(``); err != nil { return err } return sf.zipWriter.Flush() } // Error reports any error that has occurred during a previous Write or Flush. func (sf *StreamFile) Error() error { return sf.err } func (sf *StreamFile) Flush() { if sf.err != nil { sf.err = sf.zipWriter.Flush() } } // NextSheet will switch to the next sheet. Sheets are selected in the same order they were added. // Once you leave a sheet, you cannot return to it. func (sf *StreamFile) NextSheet() error { if sf.err != nil { return sf.err } var sheetIndex int if sf.currentSheet != nil { if sf.currentSheet.index >= len(sf.xlsxFile.Sheets) { sf.err = AlreadyOnLastSheetError return AlreadyOnLastSheetError } if err := sf.writeSheetEnd(); err != nil { sf.currentSheet = nil sf.err = err return err } sheetIndex = sf.currentSheet.index } sheetIndex++ sf.currentSheet = &streamSheet{ index: sheetIndex, columnCount: len(sf.xlsxFile.Sheets[sheetIndex-1].Cols), styleIds: sf.styleIds[sheetIndex-1], rowCount: 1, } sheetPath := sheetFilePathPrefix + strconv.Itoa(sf.currentSheet.index) + sheetFilePathSuffix fileWriter, err := sf.zipWriter.Create(sheetPath) if err != nil { sf.err = err return err } sf.currentSheet.writer = fileWriter if err := sf.writeSheetStart(); err != nil { sf.err = err return err } return nil } // Close closes the Stream File. // Any sheets that have not yet been written to will have an empty sheet created for them. func (sf *StreamFile) Close() error { if sf.err != nil { return sf.err } // If there are sheets that have not been written yet, call NextSheet() which will add files to the zip for them. // XLSX readers may error if the sheets registered in the metadata are not present in the file. if sf.currentSheet != nil { for sf.currentSheet.index < len(sf.xlsxFile.Sheets) { if err := sf.NextSheet(); err != nil { sf.err = err return err } } // Write the end of the last sheet. if err := sf.writeSheetEnd(); err != nil { sf.err = err return err } } err := sf.zipWriter.Close() if err != nil { sf.err = err } return err } // writeSheetStart will write the start of the Sheet's XML func (sf *StreamFile) writeSheetStart() error { if sf.currentSheet == nil { return NoCurrentSheetError } return sf.currentSheet.write(sf.sheetXmlPrefix[sf.currentSheet.index-1]) } // writeSheetEnd will write the end of the Sheet's XML func (sf *StreamFile) writeSheetEnd() error { if sf.currentSheet == nil { return NoCurrentSheetError } if err := sf.currentSheet.write(endSheetDataTag); err != nil { return err } return sf.currentSheet.write(sf.sheetXmlSuffix[sf.currentSheet.index-1]) } func (ss *streamSheet) write(data string) error { _, err := ss.writer.Write([]byte(data)) return err } ================================================ FILE: vendor/github.com/tealeg/xlsx/stream_file_builder.go ================================================ // Authors: Ryan Hollis (ryanh@) // The purpose of StreamFileBuilder and StreamFile is to allow streamed writing of XLSX files. // Directions: // 1. Create a StreamFileBuilder with NewStreamFileBuilder() or NewStreamFileBuilderForPath(). // 2. Add the sheets and their first row of data by calling AddSheet(). // 3. Call Build() to get a StreamFile. Once built, all functions on the builder will return an error. // 4. Write to the StreamFile with Write(). Writes begin on the first sheet. New rows are always written and flushed // to the io. All rows written to the same sheet must have the same number of cells as the header provided when the sheet // was created or an error will be returned. // 5. Call NextSheet() to proceed to the next sheet. Once NextSheet() is called, the previous sheet can not be edited. // 6. Call Close() to finish. // Future work suggestions: // Currently the only supported cell type is string, since the main reason this library was written was to prevent // strings from being interpreted as numbers. It would be nice to have support for numbers and money so that the exported // files could better take advantage of XLSX's features. // All text is written with the same text style. Support for additional text styles could be added to highlight certain // data in the file. // The current default style uses fonts that are not on Macs by default so opening the XLSX files in Numbers causes a // pop up that says there are missing fonts. The font could be changed to something that is usually found on Mac and PC. package xlsx import ( "archive/zip" "errors" "fmt" "io" "os" "strconv" "strings" ) type StreamFileBuilder struct { built bool xlsxFile *File zipWriter *zip.Writer cellTypeToStyleIds map[CellType]int maxStyleId int styleIds [][]int } const ( sheetFilePathPrefix = "xl/worksheets/sheet" sheetFilePathSuffix = ".xml" endSheetDataTag = "" dimensionTag = `` // This is the index of the max style that this library will insert into XLSX sheets by default. // This allows us to predict what the style id of styles that we add will be. // TestXlsxStyleBehavior tests that this behavior continues to be what we expect. initMaxStyleId = 1 ) var BuiltStreamFileBuilderError = errors.New("StreamFileBuilder has already been built, functions may no longer be used") // NewStreamFileBuilder creates an StreamFileBuilder that will write to the the provided io.writer func NewStreamFileBuilder(writer io.Writer) *StreamFileBuilder { return &StreamFileBuilder{ zipWriter: zip.NewWriter(writer), xlsxFile: NewFile(), cellTypeToStyleIds: make(map[CellType]int), maxStyleId: initMaxStyleId, } } // NewStreamFileBuilderForPath takes the name of an XLSX file and returns a builder for it. // The file will be created if it does not exist, or truncated if it does. func NewStreamFileBuilderForPath(path string) (*StreamFileBuilder, error) { file, err := os.Create(path) if err != nil { return nil, err } return NewStreamFileBuilder(file), nil } // AddSheet will add sheets with the given name with the provided headers. The headers cannot be edited later, and all // rows written to the sheet must contain the same number of cells as the header. Sheet names must be unique, or an // error will be thrown. func (sb *StreamFileBuilder) AddSheet(name string, headers []string, cellTypes []*CellType) error { if sb.built { return BuiltStreamFileBuilderError } if len(cellTypes) > len(headers) { return errors.New("cellTypes is longer than headers") } sheet, err := sb.xlsxFile.AddSheet(name) if err != nil { // Set built on error so that all subsequent calls to the builder will also fail. sb.built = true return err } sb.styleIds = append(sb.styleIds, []int{}) row := sheet.AddRow() if count := row.WriteSlice(&headers, -1); count != len(headers) { // Set built on error so that all subsequent calls to the builder will also fail. sb.built = true return errors.New("failed to write headers") } for i, cellType := range cellTypes { var cellStyleIndex int var ok bool if cellType != nil { // The cell type is one of the attributes of a Style. // Since it is the only attribute of Style that we use, we can assume that cell types // map one to one with Styles and their Style ID. // If a new cell type is used, a new style gets created with an increased id, if an existing cell type is // used, the pre-existing style will also be used. cellStyleIndex, ok = sb.cellTypeToStyleIds[*cellType] if !ok { sb.maxStyleId++ cellStyleIndex = sb.maxStyleId sb.cellTypeToStyleIds[*cellType] = sb.maxStyleId } sheet.Cols[i].SetType(*cellType) } sb.styleIds[len(sb.styleIds)-1] = append(sb.styleIds[len(sb.styleIds)-1], cellStyleIndex) } return nil } // Build begins streaming the XLSX file to the io, by writing all the XLSX metadata. It creates a StreamFile struct // that can be used to write the rows to the sheets. func (sb *StreamFileBuilder) Build() (*StreamFile, error) { if sb.built { return nil, BuiltStreamFileBuilderError } sb.built = true parts, err := sb.xlsxFile.MarshallParts() if err != nil { return nil, err } es := &StreamFile{ zipWriter: sb.zipWriter, xlsxFile: sb.xlsxFile, sheetXmlPrefix: make([]string, len(sb.xlsxFile.Sheets)), sheetXmlSuffix: make([]string, len(sb.xlsxFile.Sheets)), styleIds: sb.styleIds, } for path, data := range parts { // If the part is a sheet, don't write it yet. We only want to write the XLSX metadata files, since at this // point the sheets are still empty. The sheet files will be written later as their rows come in. if strings.HasPrefix(path, sheetFilePathPrefix) { if err := sb.processEmptySheetXML(es, path, data); err != nil { return nil, err } continue } metadataFile, err := sb.zipWriter.Create(path) if err != nil { return nil, err } _, err = metadataFile.Write([]byte(data)) if err != nil { return nil, err } } if err := es.NextSheet(); err != nil { return nil, err } return es, nil } // processEmptySheetXML will take in the path and XML data of an empty sheet, and will save the beginning and end of the // XML file so that these can be written at the right time. func (sb *StreamFileBuilder) processEmptySheetXML(sf *StreamFile, path, data string) error { // Get the sheet index from the path sheetIndex, err := getSheetIndex(sf, path) if err != nil { return err } // Remove the Dimension tag. Since more rows are going to be written to the sheet, it will be wrong. // It is valid to for a sheet to be missing a Dimension tag, but it is not valid for it to be wrong. data, err = removeDimensionTag(data, sf.xlsxFile.Sheets[sheetIndex]) if err != nil { return err } // Split the sheet at the end of its SheetData tag so that more rows can be added inside. prefix, suffix, err := splitSheetIntoPrefixAndSuffix(data) if err != nil { return err } sf.sheetXmlPrefix[sheetIndex] = prefix sf.sheetXmlSuffix[sheetIndex] = suffix return nil } // getSheetIndex parses the path to the XLSX sheet data and returns the index // The files that store the data for each sheet must have the format: // xl/worksheets/sheet123.xml // where 123 is the index of the sheet. This file path format is part of the XLSX file standard. func getSheetIndex(sf *StreamFile, path string) (int, error) { indexString := path[len(sheetFilePathPrefix) : len(path)-len(sheetFilePathSuffix)] sheetXLSXIndex, err := strconv.Atoi(indexString) if err != nil { return -1, errors.New("Unexpected sheet file name from xlsx package") } if sheetXLSXIndex < 1 || len(sf.sheetXmlPrefix) < sheetXLSXIndex || len(sf.sheetXmlSuffix) < sheetXLSXIndex || len(sf.xlsxFile.Sheets) < sheetXLSXIndex { return -1, errors.New("Unexpected sheet index") } sheetArrayIndex := sheetXLSXIndex - 1 return sheetArrayIndex, nil } // removeDimensionTag will return the passed in XLSX Spreadsheet XML with the dimension tag removed. // data is the XML data for the sheet // sheet is the Sheet struct that the XML was created from. // Can return an error if the XML's dimension tag does not match was is expected based on the provided Sheet func removeDimensionTag(data string, sheet *Sheet) (string, error) { x := len(sheet.Cols) - 1 y := len(sheet.Rows) - 1 if x < 0 { x = 0 } if y < 0 { y = 0 } var dimensionRef string if x == 0 && y == 0 { dimensionRef = "A1" } else { endCoordinate := GetCellIDStringFromCoords(x, y) dimensionRef = "A1:" + endCoordinate } dataParts := strings.Split(data, fmt.Sprintf(dimensionTag, dimensionRef)) if len(dataParts) != 2 { return "", errors.New("unexpected Sheet XML: dimension tag not found") } return dataParts[0] + dataParts[1], nil } // splitSheetIntoPrefixAndSuffix will split the provided XML sheet into a prefix and a suffix so that // more spreadsheet rows can be inserted in between. func splitSheetIntoPrefixAndSuffix(data string) (string, string, error) { // Split the sheet at the end of its SheetData tag so that more rows can be added inside. sheetParts := strings.Split(data, endSheetDataTag) if len(sheetParts) != 2 { return "", "", errors.New("unexpected Sheet XML: SheetData close tag not found") } return sheetParts[0], sheetParts[1], nil } ================================================ FILE: vendor/github.com/tealeg/xlsx/style.go ================================================ package xlsx import "strconv" // Style is a high level structure intended to provide user access to // the contents of Style within an XLSX file. type Style struct { Border Border Fill Fill Font Font ApplyBorder bool ApplyFill bool ApplyFont bool ApplyAlignment bool Alignment Alignment NamedStyleIndex *int } // Return a new Style structure initialised with the default values. func NewStyle() *Style { return &Style{ Alignment: *DefaultAlignment(), Border: *DefaultBorder(), Fill: *DefaultFill(), Font: *DefaultFont(), } } // Generate the underlying XLSX style elements that correspond to the Style. func (style *Style) makeXLSXStyleElements() (xFont xlsxFont, xFill xlsxFill, xBorder xlsxBorder, xCellXf xlsxXf) { xFont = xlsxFont{} xFill = xlsxFill{} xBorder = xlsxBorder{} xCellXf = xlsxXf{} xFont.Sz.Val = strconv.Itoa(style.Font.Size) xFont.Name.Val = style.Font.Name xFont.Family.Val = strconv.Itoa(style.Font.Family) xFont.Charset.Val = strconv.Itoa(style.Font.Charset) xFont.Color.RGB = style.Font.Color if style.Font.Bold { xFont.B = &xlsxVal{} } else { xFont.B = nil } if style.Font.Italic { xFont.I = &xlsxVal{} } else { xFont.I = nil } if style.Font.Underline { xFont.U = &xlsxVal{} } else { xFont.U = nil } xPatternFill := xlsxPatternFill{} xPatternFill.PatternType = style.Fill.PatternType xPatternFill.FgColor.RGB = style.Fill.FgColor xPatternFill.BgColor.RGB = style.Fill.BgColor xFill.PatternFill = xPatternFill xBorder.Left = xlsxLine{ Style: style.Border.Left, Color: xlsxColor{RGB: style.Border.LeftColor}, } xBorder.Right = xlsxLine{ Style: style.Border.Right, Color: xlsxColor{RGB: style.Border.RightColor}, } xBorder.Top = xlsxLine{ Style: style.Border.Top, Color: xlsxColor{RGB: style.Border.TopColor}, } xBorder.Bottom = xlsxLine{ Style: style.Border.Bottom, Color: xlsxColor{RGB: style.Border.BottomColor}, } xCellXf = makeXLSXCellElement() xCellXf.ApplyBorder = style.ApplyBorder xCellXf.ApplyFill = style.ApplyFill xCellXf.ApplyFont = style.ApplyFont xCellXf.ApplyAlignment = style.ApplyAlignment if style.NamedStyleIndex != nil { xCellXf.XfId = style.NamedStyleIndex } return } func makeXLSXCellElement() (xCellXf xlsxXf) { xCellXf.NumFmtId = 0 return } // Border is a high level structure intended to provide user access to // the contents of Border Style within an Sheet. type Border struct { Left string LeftColor string Right string RightColor string Top string TopColor string Bottom string BottomColor string } func NewBorder(left, right, top, bottom string) *Border { return &Border{ Left: left, Right: right, Top: top, Bottom: bottom, } } // Fill is a high level structure intended to provide user access to // the contents of background and foreground color index within an Sheet. type Fill struct { PatternType string BgColor string FgColor string } func NewFill(patternType, fgColor, bgColor string) *Fill { return &Fill{ PatternType: patternType, FgColor: fgColor, BgColor: bgColor, } } type Font struct { Size int Name string Family int Charset int Color string Bold bool Italic bool Underline bool } func NewFont(size int, name string) *Font { return &Font{Size: size, Name: name} } type Alignment struct { Horizontal string Indent int ShrinkToFit bool TextRotation int Vertical string WrapText bool } var defaultFontSize = 12 var defaultFontName = "Verdana" func SetDefaultFont(size int, name string) { defaultFontSize = size defaultFontName = name } func DefaultFont() *Font { return NewFont(defaultFontSize, defaultFontName) } func DefaultFill() *Fill { return NewFill("none", "FFFFFFFF", "00000000") } func DefaultBorder() *Border { return NewBorder("none", "none", "none", "none") } func DefaultAlignment() *Alignment { return &Alignment{ Horizontal: "general", Vertical: "bottom", } } ================================================ FILE: vendor/github.com/tealeg/xlsx/templates.go ================================================ // This file contains default templates for XML files we don't yet // populated based on content. package xlsx const TEMPLATE__RELS_DOT_RELS = ` ` const TEMPLATE_DOCPROPS_APP = ` 0 Go XLSX ` const TEMPLATE_DOCPROPS_CORE = ` ` const TEMPLATE_XL_THEME_THEME = ` ` ================================================ FILE: vendor/github.com/tealeg/xlsx/theme.go ================================================ package xlsx import ( "fmt" "strconv" ) type theme struct { colors []string } func newTheme(themeXml xlsxTheme) *theme { clrMap := map[string]string{} clrSchemes := themeXml.ThemeElements.ClrScheme.Children for _, scheme := range clrSchemes { var rgbColor string if scheme.SysClr != nil { rgbColor = scheme.SysClr.LastClr } else { rgbColor = scheme.SrgbClr.Val } clrMap[scheme.XMLName.Local] = rgbColor } colors := []string{clrMap["lt1"], clrMap["dk1"], clrMap["lt2"], clrMap["dk2"], clrMap["accent1"], clrMap["accent2"], clrMap["accent3"], clrMap["accent4"], clrMap["accent5"], clrMap["accent6"], clrMap["hlink"], clrMap["folHlink"]} return &theme{colors} } func (t *theme) themeColor(index int64, tint float64) string { baseColor := t.colors[index] if tint == 0 { return "FF" + baseColor } else { r, _ := strconv.ParseInt(baseColor[0:2], 16, 64) g, _ := strconv.ParseInt(baseColor[2:4], 16, 64) b, _ := strconv.ParseInt(baseColor[4:6], 16, 64) h, s, l := RGBToHSL(uint8(r), uint8(g), uint8(b)) if tint < 0 { l *= (1 + tint) } else { l = l*(1-tint) + (1 - (1 - tint)) } br, bg, bb := HSLToRGB(h, s, l) return fmt.Sprintf("FF%02X%02X%02X", br, bg, bb) } } ================================================ FILE: vendor/github.com/tealeg/xlsx/write.go ================================================ package xlsx import ( "fmt" "reflect" "time" ) // Writes an array to row r. Accepts a pointer to array type 'e', // and writes the number of columns to write, 'cols'. If 'cols' is < 0, // the entire array will be written if possible. Returns -1 if the 'e' // doesn't point to an array, otherwise the number of columns written. func (r *Row) WriteSlice(e interface{}, cols int) int { if cols == 0 { return cols } // make sure 'e' is a Ptr to Slice v := reflect.ValueOf(e) if v.Kind() != reflect.Ptr { return -1 } v = v.Elem() if v.Kind() != reflect.Slice { return -1 } // it's a slice, so open up its values n := v.Len() if cols < n && cols > 0 { n = cols } var setCell func(reflect.Value) setCell = func(val reflect.Value) { switch t := val.Interface().(type) { case time.Time: cell := r.AddCell() cell.SetValue(t) case fmt.Stringer: // check Stringer first cell := r.AddCell() cell.SetString(t.String()) default: switch val.Kind() { // underlying type of slice case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64, reflect.Float32: cell := r.AddCell() cell.SetValue(val.Interface()) case reflect.Bool: cell := r.AddCell() cell.SetBool(t.(bool)) case reflect.Interface: setCell(reflect.ValueOf(t)) } } } var i int for i = 0; i < n; i++ { setCell(v.Index(i)) } return i } // Writes a struct to row r. Accepts a pointer to struct type 'e', // and the number of columns to write, `cols`. If 'cols' is < 0, // the entire struct will be written if possible. Returns -1 if the 'e' // doesn't point to a struct, otherwise the number of columns written func (r *Row) WriteStruct(e interface{}, cols int) int { if cols == 0 { return cols } v := reflect.ValueOf(e).Elem() if v.Kind() != reflect.Struct { return -1 // bail if it's not a struct } n := v.NumField() // number of fields in struct if cols < n && cols > 0 { n = cols } var k int for i := 0; i < n; i, k = i+1, k+1 { f := v.Field(i) switch t := f.Interface().(type) { case time.Time: cell := r.AddCell() cell.SetValue(t) case fmt.Stringer: // check Stringer first cell := r.AddCell() cell.SetString(t.String()) default: switch f.Kind() { case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64, reflect.Float32: cell := r.AddCell() cell.SetValue(f.Interface()) case reflect.Bool: cell := r.AddCell() cell.SetBool(t.(bool)) default: k-- // nothing set so reset to previous } } } return k } ================================================ FILE: vendor/github.com/tealeg/xlsx/xmlContentTypes.go ================================================ package xlsx import ( "encoding/xml" ) type xlsxTypes struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/content-types Types"` Overrides []xlsxOverride `xml:"Override"` Defaults []xlsxDefault `xml:"Default"` } type xlsxOverride struct { PartName string `xml:",attr"` ContentType string `xml:",attr"` } type xlsxDefault struct { Extension string `xml:",attr"` ContentType string `xml:",attr"` } func MakeDefaultContentTypes() (types xlsxTypes) { types.Overrides = make([]xlsxOverride, 8) types.Defaults = make([]xlsxDefault, 2) types.Overrides[0].PartName = "/_rels/.rels" types.Overrides[0].ContentType = "application/vnd.openxmlformats-package.relationships+xml" types.Overrides[1].PartName = "/docProps/app.xml" types.Overrides[1].ContentType = "application/vnd.openxmlformats-officedocument.extended-properties+xml" types.Overrides[2].PartName = "/docProps/core.xml" types.Overrides[2].ContentType = "application/vnd.openxmlformats-package.core-properties+xml" types.Overrides[3].PartName = "/xl/_rels/workbook.xml.rels" types.Overrides[3].ContentType = "application/vnd.openxmlformats-package.relationships+xml" types.Overrides[4].PartName = "/xl/sharedStrings.xml" types.Overrides[4].ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml" types.Overrides[5].PartName = "/xl/styles.xml" types.Overrides[5].ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml" types.Overrides[6].PartName = "/xl/workbook.xml" types.Overrides[6].ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" types.Overrides[7].PartName = "/xl/theme/theme1.xml" types.Overrides[7].ContentType = "application/vnd.openxmlformats-officedocument.theme+xml" types.Defaults[0].Extension = "rels" types.Defaults[0].ContentType = "application/vnd.openxmlformats-package.relationships+xml" types.Defaults[1].Extension = "xml" types.Defaults[1].ContentType = "application/xml" return } ================================================ FILE: vendor/github.com/tealeg/xlsx/xmlSharedStrings.go ================================================ package xlsx import ( "encoding/xml" ) // xlsxSST directly maps the sst element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main currently // I have not checked this for completeness - it does as much as I need. type xlsxSST struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main sst"` Count int `xml:"count,attr"` UniqueCount int `xml:"uniqueCount,attr"` SI []xlsxSI `xml:"si"` } // xlsxSI directly maps the si element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked this for completeness - it does as // much as I need. type xlsxSI struct { T string `xml:"t"` R []xlsxR `xml:"r"` } // xlsxR directly maps the r element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked this for completeness - it does as // much as I need. type xlsxR struct { T string `xml:"t"` } ================================================ FILE: vendor/github.com/tealeg/xlsx/xmlStyle.go ================================================ // xslx is a package designed to help with reading data from // spreadsheets stored in the XLSX format used in recent versions of // Microsoft's Excel spreadsheet. // // For a concise example of how to use this library why not check out // the source for xlsx2csv here: https://github.com/tealeg/xlsx2csv package xlsx import ( "bytes" "encoding/xml" "fmt" "strconv" "sync" ) // Excel styles can reference number formats that are built-in, all of which // have an id less than 164. const builtinNumFmtsCount = 163 // Excel styles can reference number formats that are built-in, all of which // have an id less than 164. This is a possibly incomplete list comprised of as // many of them as I could find. var builtInNumFmt = map[int]string{ 0: "general", 1: "0", 2: "0.00", 3: "#,##0", 4: "#,##0.00", 9: "0%", 10: "0.00%", 11: "0.00e+00", 12: "# ?/?", 13: "# ??/??", 14: "mm-dd-yy", 15: "d-mmm-yy", 16: "d-mmm", 17: "mmm-yy", 18: "h:mm am/pm", 19: "h:mm:ss am/pm", 20: "h:mm", 21: "h:mm:ss", 22: "m/d/yy h:mm", 37: "#,##0 ;(#,##0)", 38: "#,##0 ;[red](#,##0)", 39: "#,##0.00;(#,##0.00)", 40: "#,##0.00;[red](#,##0.00)", 41: `_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)`, 42: `_("$"* #,##0_);_("$* \(#,##0\);_("$"* "-"_);_(@_)`, 43: `_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)`, 44: `_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)`, 45: "mm:ss", 46: "[h]:mm:ss", 47: "mmss.0", 48: "##0.0e+0", 49: "@", } // These are the color annotations from number format codes that contain color names. // Also possible are [color1] through [color56] var numFmtColorCodes = []string{ "[red]", "[black]", "[green]", "[white]", "[blue]", "[magenta]", "[yellow]", "[cyan]", } var builtInNumFmtInv = make(map[string]int, 40) func init() { for k, v := range builtInNumFmt { builtInNumFmtInv[v] = k } } const ( builtInNumFmtIndex_GENERAL = int(0) builtInNumFmtIndex_INT = int(1) builtInNumFmtIndex_FLOAT = int(2) builtInNumFmtIndex_DATE = int(14) builtInNumFmtIndex_STRING = int(49) ) // xlsxStyle directly maps the styleSheet element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxStyleSheet struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main styleSheet"` Fonts xlsxFonts `xml:"fonts,omitempty"` Fills xlsxFills `xml:"fills,omitempty"` Borders xlsxBorders `xml:"borders,omitempty"` CellStyles *xlsxCellStyles `xml:"cellStyles,omitempty"` CellStyleXfs *xlsxCellStyleXfs `xml:"cellStyleXfs,omitempty"` CellXfs xlsxCellXfs `xml:"cellXfs,omitempty"` NumFmts xlsxNumFmts `xml:"numFmts,omitempty"` theme *theme sync.RWMutex // protects the following styleCache map[int]*Style numFmtRefTable map[int]xlsxNumFmt parsedNumFmtTable map[string]*parsedNumberFormat } func newXlsxStyleSheet(t *theme) *xlsxStyleSheet { return &xlsxStyleSheet{ theme: t, styleCache: make(map[int]*Style), } } func (styles *xlsxStyleSheet) reset() { styles.Fonts = xlsxFonts{} styles.Fills = xlsxFills{} styles.Borders = xlsxBorders{} // Microsoft seems to want an emtpy border to start with styles.addBorder( xlsxBorder{ Left: xlsxLine{Style: "none"}, Right: xlsxLine{Style: "none"}, Top: xlsxLine{Style: "none"}, Bottom: xlsxLine{Style: "none"}, }) styles.CellStyleXfs = &xlsxCellStyleXfs{} // add default xf styles.CellXfs = xlsxCellXfs{Count: 1, Xf: []xlsxXf{{}}} styles.NumFmts = xlsxNumFmts{} } func (styles *xlsxStyleSheet) getStyle(styleIndex int) *Style { styles.RLock() style, ok := styles.styleCache[styleIndex] styles.RUnlock() if ok { return style } style = new(Style) var namedStyleXf xlsxXf xfCount := styles.CellXfs.Count if styleIndex > -1 && xfCount > 0 && styleIndex <= xfCount { xf := styles.CellXfs.Xf[styleIndex] if xf.XfId != nil && styles.CellStyleXfs != nil { namedStyleXf = styles.CellStyleXfs.Xf[*xf.XfId] style.NamedStyleIndex = xf.XfId } else { namedStyleXf = xlsxXf{} } style.ApplyBorder = xf.ApplyBorder || namedStyleXf.ApplyBorder style.ApplyFill = xf.ApplyFill || namedStyleXf.ApplyFill style.ApplyFont = xf.ApplyFont || namedStyleXf.ApplyFont style.ApplyAlignment = xf.ApplyAlignment || namedStyleXf.ApplyAlignment if xf.BorderId > -1 && xf.BorderId < styles.Borders.Count { var border xlsxBorder border = styles.Borders.Border[xf.BorderId] style.Border.Left = border.Left.Style style.Border.LeftColor = border.Left.Color.RGB style.Border.Right = border.Right.Style style.Border.RightColor = border.Right.Color.RGB style.Border.Top = border.Top.Style style.Border.TopColor = border.Top.Color.RGB style.Border.Bottom = border.Bottom.Style style.Border.BottomColor = border.Bottom.Color.RGB } if xf.FillId > -1 && xf.FillId < styles.Fills.Count { xFill := styles.Fills.Fill[xf.FillId] style.Fill.PatternType = xFill.PatternFill.PatternType style.Fill.FgColor = styles.argbValue(xFill.PatternFill.FgColor) style.Fill.BgColor = styles.argbValue(xFill.PatternFill.BgColor) } if xf.FontId > -1 && xf.FontId < styles.Fonts.Count { xfont := styles.Fonts.Font[xf.FontId] style.Font.Size, _ = strconv.Atoi(xfont.Sz.Val) style.Font.Name = xfont.Name.Val style.Font.Family, _ = strconv.Atoi(xfont.Family.Val) style.Font.Charset, _ = strconv.Atoi(xfont.Charset.Val) style.Font.Color = styles.argbValue(xfont.Color) if bold := xfont.B; bold != nil && bold.Val != "0" { style.Font.Bold = true } if italic := xfont.I; italic != nil && italic.Val != "0" { style.Font.Italic = true } if underline := xfont.U; underline != nil && underline.Val != "0" { style.Font.Underline = true } } if xf.Alignment.Horizontal != "" { style.Alignment.Horizontal = xf.Alignment.Horizontal } if xf.Alignment.Vertical != "" { style.Alignment.Vertical = xf.Alignment.Vertical } style.Alignment.WrapText = xf.Alignment.WrapText style.Alignment.TextRotation = xf.Alignment.TextRotation styles.Lock() styles.styleCache[styleIndex] = style styles.Unlock() } return style } func (styles *xlsxStyleSheet) argbValue(color xlsxColor) string { if color.Theme != nil && styles.theme != nil { return styles.theme.themeColor(int64(*color.Theme), color.Tint) } return color.RGB } // Excel styles can reference number formats that are built-in, all of which // have an id less than 164. This is a possibly incomplete list comprised of as // many of them as I could find. func getBuiltinNumberFormat(numFmtId int) string { return builtInNumFmt[numFmtId] } func (styles *xlsxStyleSheet) getNumberFormat(styleIndex int) (string, *parsedNumberFormat) { var numberFormat string = "general" if styles.CellXfs.Xf != nil { if styleIndex > -1 && styleIndex <= styles.CellXfs.Count { xf := styles.CellXfs.Xf[styleIndex] if builtin := getBuiltinNumberFormat(xf.NumFmtId); builtin != "" { numberFormat = builtin } else { if styles.numFmtRefTable != nil { numFmt := styles.numFmtRefTable[xf.NumFmtId] numberFormat = numFmt.FormatCode } } } } parsedFmt, ok := styles.parsedNumFmtTable[numberFormat] if !ok { if styles.parsedNumFmtTable == nil { styles.parsedNumFmtTable = map[string]*parsedNumberFormat{} } parsedFmt = parseFullNumberFormatString(numberFormat) styles.parsedNumFmtTable[numberFormat] = parsedFmt } return numberFormat, parsedFmt } func (styles *xlsxStyleSheet) addFont(xFont xlsxFont) (index int) { var font xlsxFont if xFont.Name.Val == "" { return 0 } for index, font = range styles.Fonts.Font { if font.Equals(xFont) { return index } } styles.Fonts.Font = append(styles.Fonts.Font, xFont) index = styles.Fonts.Count styles.Fonts.Count++ return } func (styles *xlsxStyleSheet) addFill(xFill xlsxFill) (index int) { var fill xlsxFill for index, fill = range styles.Fills.Fill { if fill.Equals(xFill) { return index } } styles.Fills.Fill = append(styles.Fills.Fill, xFill) index = styles.Fills.Count styles.Fills.Count++ return } func (styles *xlsxStyleSheet) addBorder(xBorder xlsxBorder) (index int) { var border xlsxBorder for index, border = range styles.Borders.Border { if border.Equals(xBorder) { return index } } styles.Borders.Border = append(styles.Borders.Border, xBorder) index = styles.Borders.Count styles.Borders.Count++ return } func (styles *xlsxStyleSheet) addCellStyleXf(xCellStyleXf xlsxXf) (index int) { var cellStyleXf xlsxXf if styles.CellStyleXfs == nil { styles.CellStyleXfs = &xlsxCellStyleXfs{Count: 0} } for index, cellStyleXf = range styles.CellStyleXfs.Xf { if cellStyleXf.Equals(xCellStyleXf) { return index } } styles.CellStyleXfs.Xf = append(styles.CellStyleXfs.Xf, xCellStyleXf) index = styles.CellStyleXfs.Count styles.CellStyleXfs.Count++ return } func (styles *xlsxStyleSheet) addCellXf(xCellXf xlsxXf) (index int) { var cellXf xlsxXf for index, cellXf = range styles.CellXfs.Xf { if cellXf.Equals(xCellXf) { return index } } styles.CellXfs.Xf = append(styles.CellXfs.Xf, xCellXf) index = styles.CellXfs.Count styles.CellXfs.Count++ return } // newNumFmt generate a xlsxNumFmt according the format code. When the FormatCode is built in, it will return a xlsxNumFmt with the NumFmtId defined in ECMA document, otherwise it will generate a new NumFmtId greater than 164. func (styles *xlsxStyleSheet) newNumFmt(formatCode string) xlsxNumFmt { if compareFormatString(formatCode, "general") { return xlsxNumFmt{NumFmtId: 0, FormatCode: "general"} } // built in NumFmts in xmlStyle.go, traverse from the const. numFmtId, ok := builtInNumFmtInv[formatCode] if ok { return xlsxNumFmt{NumFmtId: numFmtId, FormatCode: formatCode} } // find the exist xlsxNumFmt for _, numFmt := range styles.NumFmts.NumFmt { if formatCode == numFmt.FormatCode { return numFmt } } // The user define NumFmtId. The one less than 164 in built in. numFmtId = builtinNumFmtsCount + 1 styles.Lock() defer styles.Unlock() for { // get a unused NumFmtId if _, ok = styles.numFmtRefTable[numFmtId]; ok { numFmtId++ } else { styles.addNumFmt(xlsxNumFmt{NumFmtId: numFmtId, FormatCode: formatCode}) break } } return xlsxNumFmt{NumFmtId: numFmtId, FormatCode: formatCode} } // addNumFmt add xlsxNumFmt if its not exist. func (styles *xlsxStyleSheet) addNumFmt(xNumFmt xlsxNumFmt) { // don't add built in NumFmt if xNumFmt.NumFmtId <= builtinNumFmtsCount { return } _, ok := styles.numFmtRefTable[xNumFmt.NumFmtId] if !ok { if styles.numFmtRefTable == nil { styles.numFmtRefTable = make(map[int]xlsxNumFmt) } styles.NumFmts.NumFmt = append(styles.NumFmts.NumFmt, xNumFmt) styles.numFmtRefTable[xNumFmt.NumFmtId] = xNumFmt styles.NumFmts.Count++ } } func (styles *xlsxStyleSheet) Marshal() (string, error) { result := xml.Header + `` xNumFmts, err := styles.NumFmts.Marshal() if err != nil { return "", err } result += xNumFmts outputFontMap := make(map[int]int) xfonts, err := styles.Fonts.Marshal(outputFontMap) if err != nil { return "", err } result += xfonts outputFillMap := make(map[int]int) xfills, err := styles.Fills.Marshal(outputFillMap) if err != nil { return "", err } result += xfills outputBorderMap := make(map[int]int) xborders, err := styles.Borders.Marshal(outputBorderMap) if err != nil { return "", err } result += xborders if styles.CellStyleXfs != nil { xcellStyleXfs, err := styles.CellStyleXfs.Marshal(outputBorderMap, outputFillMap, outputFontMap) if err != nil { return "", err } result += xcellStyleXfs } xcellXfs, err := styles.CellXfs.Marshal(outputBorderMap, outputFillMap, outputFontMap) if err != nil { return "", err } result += xcellXfs if styles.CellStyles != nil { xcellStyles, err := styles.CellStyles.Marshal() if err != nil { return "", err } result += xcellStyles } return result + "", nil } // xlsxNumFmts directly maps the numFmts element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxNumFmts struct { Count int `xml:"count,attr"` NumFmt []xlsxNumFmt `xml:"numFmt,omitempty"` } func (numFmts *xlsxNumFmts) Marshal() (result string, err error) { if numFmts.Count > 0 { result = fmt.Sprintf(``, numFmts.Count) for _, numFmt := range numFmts.NumFmt { var xNumFmt string xNumFmt, err = numFmt.Marshal() if err != nil { return } result += xNumFmt } result += `` } return } // xlsxNumFmt directly maps the numFmt element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxNumFmt struct { NumFmtId int `xml:"numFmtId,attr,omitempty"` FormatCode string `xml:"formatCode,attr,omitempty"` } func (numFmt *xlsxNumFmt) Marshal() (result string, err error) { formatCode := &bytes.Buffer{} if err := xml.EscapeText(formatCode, []byte(numFmt.FormatCode)); err != nil { return "", err } return fmt.Sprintf(``, numFmt.NumFmtId, formatCode), nil } // xlsxFonts directly maps the fonts element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxFonts struct { XMLName xml.Name `xml:"fonts"` Count int `xml:"count,attr"` Font []xlsxFont `xml:"font,omitempty"` } func (fonts *xlsxFonts) Marshal(outputFontMap map[int]int) (result string, err error) { emittedCount := 0 subparts := "" for i, font := range fonts.Font { var xfont string xfont, err = font.Marshal() if err != nil { return } if xfont != "" { outputFontMap[i] = emittedCount emittedCount++ subparts += xfont } } if emittedCount > 0 { result = fmt.Sprintf(``, fonts.Count) result += subparts result += `` } return } // xlsxFont directly maps the font element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxFont struct { Sz xlsxVal `xml:"sz,omitempty"` Name xlsxVal `xml:"name,omitempty"` Family xlsxVal `xml:"family,omitempty"` Charset xlsxVal `xml:"charset,omitempty"` Color xlsxColor `xml:"color,omitempty"` B *xlsxVal `xml:"b,omitempty"` I *xlsxVal `xml:"i,omitempty"` U *xlsxVal `xml:"u,omitempty"` } func (font *xlsxFont) Equals(other xlsxFont) bool { if (font.B == nil && other.B != nil) || (font.B != nil && other.B == nil) { return false } if (font.I == nil && other.I != nil) || (font.I != nil && other.I == nil) { return false } if (font.U == nil && other.U != nil) || (font.U != nil && other.U == nil) { return false } return font.Sz.Equals(other.Sz) && font.Name.Equals(other.Name) && font.Family.Equals(other.Family) && font.Charset.Equals(other.Charset) && font.Color.Equals(other.Color) } func (font *xlsxFont) Marshal() (result string, err error) { result = "" if font.Sz.Val != "" { result += fmt.Sprintf(``, font.Sz.Val) } if font.Name.Val != "" { result += fmt.Sprintf(``, font.Name.Val) } if font.Family.Val != "" { result += fmt.Sprintf(``, font.Family.Val) } if font.Charset.Val != "" { result += fmt.Sprintf(``, font.Charset.Val) } if font.Color.RGB != "" { result += fmt.Sprintf(``, font.Color.RGB) } if font.B != nil { result += "" } if font.I != nil { result += "" } if font.U != nil { result += "" } return result + "", nil } // xlsxVal directly maps the val element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxVal struct { Val string `xml:"val,attr,omitempty"` } func (val *xlsxVal) Equals(other xlsxVal) bool { return val.Val == other.Val } // xlsxFills directly maps the fills element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxFills struct { Count int `xml:"count,attr"` Fill []xlsxFill `xml:"fill,omitempty"` } func (fills *xlsxFills) Marshal(outputFillMap map[int]int) (string, error) { var subparts string var emittedCount int for i, fill := range fills.Fill { xfill, err := fill.Marshal() if err != nil { return "", err } if xfill != "" { outputFillMap[i] = emittedCount emittedCount++ subparts += xfill } } var result string if emittedCount > 0 { result = fmt.Sprintf(``, emittedCount) result += subparts result += `` } return result, nil } // xlsxFill directly maps the fill element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxFill struct { PatternFill xlsxPatternFill `xml:"patternFill,omitempty"` } func (fill *xlsxFill) Equals(other xlsxFill) bool { return fill.PatternFill.Equals(other.PatternFill) } func (fill *xlsxFill) Marshal() (result string, err error) { if fill.PatternFill.PatternType != "" { var xpatternFill string result = `` xpatternFill, err = fill.PatternFill.Marshal() if err != nil { return } result += xpatternFill result += `` } return } // xlsxPatternFill directly maps the patternFill element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxPatternFill struct { PatternType string `xml:"patternType,attr,omitempty"` FgColor xlsxColor `xml:"fgColor,omitempty"` BgColor xlsxColor `xml:"bgColor,omitempty"` } func (patternFill *xlsxPatternFill) Equals(other xlsxPatternFill) bool { return patternFill.PatternType == other.PatternType && patternFill.FgColor.Equals(other.FgColor) && patternFill.BgColor.Equals(other.BgColor) } func (patternFill *xlsxPatternFill) Marshal() (result string, err error) { result = fmt.Sprintf(`` terminator := "" subparts := "" if patternFill.FgColor.RGB != "" { ending = `>` terminator = "" subparts += fmt.Sprintf(``, patternFill.FgColor.RGB) } if patternFill.BgColor.RGB != "" { ending = `>` terminator = "" subparts += fmt.Sprintf(``, patternFill.BgColor.RGB) } result += ending result += subparts result += terminator return } // xlsxColor is a common mapping used for both the fgColor and bgColor // elements in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxColor struct { RGB string `xml:"rgb,attr,omitempty"` Theme *int `xml:"theme,attr,omitempty"` Tint float64 `xml:"tint,attr,omitempty"` } func (color *xlsxColor) Equals(other xlsxColor) bool { return color.RGB == other.RGB } // xlsxBorders directly maps the borders element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxBorders struct { Count int `xml:"count,attr"` Border []xlsxBorder `xml:"border"` } func (borders *xlsxBorders) Marshal(outputBorderMap map[int]int) (result string, err error) { result = "" emittedCount := 0 subparts := "" for i, border := range borders.Border { var xborder string xborder, err = border.Marshal() if err != nil { return } if xborder != "" { outputBorderMap[i] = emittedCount emittedCount++ subparts += xborder } } if emittedCount > 0 { result += fmt.Sprintf(``, emittedCount) result += subparts result += `` } return } // xlsxBorder directly maps the border element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxBorder struct { Left xlsxLine `xml:"left,omitempty"` Right xlsxLine `xml:"right,omitempty"` Top xlsxLine `xml:"top,omitempty"` Bottom xlsxLine `xml:"bottom,omitempty"` } func (border *xlsxBorder) Equals(other xlsxBorder) bool { return border.Left.Equals(other.Left) && border.Right.Equals(other.Right) && border.Top.Equals(other.Top) && border.Bottom.Equals(other.Bottom) } // To get borders to work correctly in Excel, you have to always start with an // empty set of borders. There was logic in this function that would strip out // empty elements, but unfortunately that would cause the border to fail. func (border *xlsxBorder) Marshal() (result string, err error) { subparts := "" subparts += fmt.Sprintf(``, border.Left.Style) if border.Left.Color.RGB != "" { subparts += fmt.Sprintf(``, border.Left.Color.RGB) } subparts += `` subparts += fmt.Sprintf(``, border.Right.Style) if border.Right.Color.RGB != "" { subparts += fmt.Sprintf(``, border.Right.Color.RGB) } subparts += `` subparts += fmt.Sprintf(``, border.Top.Style) if border.Top.Color.RGB != "" { subparts += fmt.Sprintf(``, border.Top.Color.RGB) } subparts += `` subparts += fmt.Sprintf(``, border.Bottom.Style) if border.Bottom.Color.RGB != "" { subparts += fmt.Sprintf(``, border.Bottom.Color.RGB) } subparts += `` result += `` result += subparts result += `` return } // xlsxLine directly maps the line style element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxLine struct { Style string `xml:"style,attr,omitempty"` Color xlsxColor `xml:"color,omitempty"` } func (line *xlsxLine) Equals(other xlsxLine) bool { return line.Style == other.Style && line.Color.Equals(other.Color) } type xlsxCellStyles struct { XMLName xml.Name `xml:"cellStyles"` Count int `xml:"count,attr"` CellStyle []xlsxCellStyle `xml:"cellStyle,omitempty"` } func (cellStyles *xlsxCellStyles) Marshal() (result string, err error) { if cellStyles.Count > 0 { result = fmt.Sprintf(``, cellStyles.Count) for _, cellStyle := range cellStyles.CellStyle { var xCellStyle []byte xCellStyle, err = xml.Marshal(cellStyle) if err != nil { return } result += string(xCellStyle) } result += `` } return } type xlsxCellStyle struct { XMLName xml.Name `xml:"cellStyle"` BuiltInId *int `xml:"builtInId,attr,omitempty"` CustomBuiltIn *bool `xml:"customBuiltIn,attr,omitempty"` Hidden *bool `xml:"hidden,attr,omitempty"` ILevel *bool `xml:"iLevel,attr,omitempty"` Name string `xml:"name,attr"` XfId int `xml:"xfId,attr"` } // xlsxCellStyleXfs directly maps the cellStyleXfs element in the // namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main // - currently I have not checked it for completeness - it does as // much as I need. type xlsxCellStyleXfs struct { Count int `xml:"count,attr"` Xf []xlsxXf `xml:"xf,omitempty"` } func (cellStyleXfs *xlsxCellStyleXfs) Marshal(outputBorderMap, outputFillMap, outputFontMap map[int]int) (result string, err error) { if cellStyleXfs.Count > 0 { result = fmt.Sprintf(``, cellStyleXfs.Count) for _, xf := range cellStyleXfs.Xf { var xxf string xxf, err = xf.Marshal(outputBorderMap, outputFillMap, outputFontMap) if err != nil { return } result += xxf } result += `` } return } // xlsxCellXfs directly maps the cellXfs element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxCellXfs struct { Count int `xml:"count,attr"` Xf []xlsxXf `xml:"xf,omitempty"` } func (cellXfs *xlsxCellXfs) Marshal(outputBorderMap, outputFillMap, outputFontMap map[int]int) (result string, err error) { if cellXfs.Count > 0 { result = fmt.Sprintf(``, cellXfs.Count) for _, xf := range cellXfs.Xf { var xxf string xxf, err = xf.Marshal(outputBorderMap, outputFillMap, outputFontMap) if err != nil { return } result += xxf } result += `` } return } // xlsxXf directly maps the xf element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxXf struct { ApplyAlignment bool `xml:"applyAlignment,attr"` ApplyBorder bool `xml:"applyBorder,attr"` ApplyFont bool `xml:"applyFont,attr"` ApplyFill bool `xml:"applyFill,attr"` ApplyNumberFormat bool `xml:"applyNumberFormat,attr"` ApplyProtection bool `xml:"applyProtection,attr"` BorderId int `xml:"borderId,attr"` FillId int `xml:"fillId,attr"` FontId int `xml:"fontId,attr"` NumFmtId int `xml:"numFmtId,attr"` XfId *int `xml:"xfId,attr,omitempty"` Alignment xlsxAlignment `xml:"alignment"` } func (xf *xlsxXf) Equals(other xlsxXf) bool { return xf.ApplyAlignment == other.ApplyAlignment && xf.ApplyBorder == other.ApplyBorder && xf.ApplyFont == other.ApplyFont && xf.ApplyFill == other.ApplyFill && xf.ApplyProtection == other.ApplyProtection && xf.BorderId == other.BorderId && xf.FillId == other.FillId && xf.FontId == other.FontId && xf.NumFmtId == other.NumFmtId && (xf.XfId == other.XfId || ((xf.XfId != nil && other.XfId != nil) && *xf.XfId == *other.XfId)) && xf.Alignment.Equals(other.Alignment) } func (xf *xlsxXf) Marshal(outputBorderMap, outputFillMap, outputFontMap map[int]int) (result string, err error) { result = fmt.Sprintf(`", nil } type xlsxAlignment struct { Horizontal string `xml:"horizontal,attr"` Indent int `xml:"indent,attr"` ShrinkToFit bool `xml:"shrinkToFit,attr"` TextRotation int `xml:"textRotation,attr"` Vertical string `xml:"vertical,attr"` WrapText bool `xml:"wrapText,attr"` } func (alignment *xlsxAlignment) Equals(other xlsxAlignment) bool { return alignment.Horizontal == other.Horizontal && alignment.Indent == other.Indent && alignment.ShrinkToFit == other.ShrinkToFit && alignment.TextRotation == other.TextRotation && alignment.Vertical == other.Vertical && alignment.WrapText == other.WrapText } func (alignment *xlsxAlignment) Marshal() (result string, err error) { if alignment.Horizontal == "" { alignment.Horizontal = "general" } if alignment.Vertical == "" { alignment.Vertical = "bottom" } return fmt.Sprintf(``, alignment.Horizontal, alignment.Indent, bool2Int(alignment.ShrinkToFit), alignment.TextRotation, alignment.Vertical, bool2Int(alignment.WrapText)), nil } func bool2Int(b bool) int { if b { return 1 } return 0 } ================================================ FILE: vendor/github.com/tealeg/xlsx/xmlTheme.go ================================================ package xlsx import "encoding/xml" // xlsxTheme directly maps the theme element in the namespace // http://schemas.openxmlformats.org/drawingml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxTheme struct { ThemeElements xlsxThemeElements `xml:"themeElements"` } // xlsxThemeElements directly maps the themeElements element in the namespace // http://schemas.openxmlformats.org/drawingml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxThemeElements struct { ClrScheme xlsxClrScheme `xml:"clrScheme"` } // xlsxClrScheme directly maps the clrScheme element in the namespace // http://schemas.openxmlformats.org/drawingml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxClrScheme struct { Name string `xml:"name,attr"` Children []xlsxClrSchemeEl `xml:",any"` } // xlsxClrScheme maps to children of the clrScheme element in the namespace // http://schemas.openxmlformats.org/drawingml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxClrSchemeEl struct { XMLName xml.Name SysClr *xlsxSysClr `xml:"sysClr"` SrgbClr *xlsxSrgbClr `xml:"srgbClr"` } // xlsxSysClr directly maps the sysClr element in the namespace // http://schemas.openxmlformats.org/drawingml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxSysClr struct { Val string `xml:"val,attr"` LastClr string `xml:"lastClr,attr"` } // xlsxSrgbClr directly maps the srgbClr element in the namespace // http://schemas.openxmlformats.org/drawingml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxSrgbClr struct { Val string `xml:"val,attr"` } ================================================ FILE: vendor/github.com/tealeg/xlsx/xmlWorkbook.go ================================================ package xlsx import ( "archive/zip" "encoding/xml" "fmt" "io" ) const ( // sheet state values as defined by // http://msdn.microsoft.com/en-us/library/office/documentformat.openxml.spreadsheet.sheetstatevalues.aspx sheetStateVisible = "visible" sheetStateHidden = "hidden" sheetStateVeryHidden = "veryHidden" ) // xmlxWorkbookRels contains xmlxWorkbookRelations // which maps sheet id and sheet XML type xlsxWorkbookRels struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/relationships Relationships"` Relationships []xlsxWorkbookRelation `xml:"Relationship"` } // xmlxWorkbookRelation maps sheet id and xl/worksheets/sheet%d.xml type xlsxWorkbookRelation struct { Id string `xml:",attr"` Target string `xml:",attr"` Type string `xml:",attr"` } // xlsxWorkbook directly maps the workbook element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxWorkbook struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main workbook"` FileVersion xlsxFileVersion `xml:"fileVersion"` WorkbookPr xlsxWorkbookPr `xml:"workbookPr"` WorkbookProtection xlsxWorkbookProtection `xml:"workbookProtection"` BookViews xlsxBookViews `xml:"bookViews"` Sheets xlsxSheets `xml:"sheets"` DefinedNames xlsxDefinedNames `xml:"definedNames"` CalcPr xlsxCalcPr `xml:"calcPr"` } // xlsxWorkbookProtection directly maps the workbookProtection element from the // namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main // - currently I have not checked it for completeness - it does as // much as I need. type xlsxWorkbookProtection struct { // We don't need this, yet. } // xlsxFileVersion directly maps the fileVersion element from the // namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main // - currently I have not checked it for completeness - it does as // much as I need. type xlsxFileVersion struct { AppName string `xml:"appName,attr,omitempty"` LastEdited string `xml:"lastEdited,attr,omitempty"` LowestEdited string `xml:"lowestEdited,attr,omitempty"` RupBuild string `xml:"rupBuild,attr,omitempty"` } // xlsxWorkbookPr directly maps the workbookPr element from the // namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main // - currently I have not checked it for completeness - it does as // much as I need. type xlsxWorkbookPr struct { DefaultThemeVersion string `xml:"defaultThemeVersion,attr,omitempty"` BackupFile bool `xml:"backupFile,attr,omitempty"` ShowObjects string `xml:"showObjects,attr,omitempty"` Date1904 bool `xml:"date1904,attr"` } // xlsxBookViews directly maps the bookViews element from the // namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main // - currently I have not checked it for completeness - it does as // much as I need. type xlsxBookViews struct { WorkBookView []xlsxWorkBookView `xml:"workbookView"` } // xlsxWorkBookView directly maps the workbookView element from the // namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main // - currently I have not checked it for completeness - it does as // much as I need. type xlsxWorkBookView struct { ActiveTab int `xml:"activeTab,attr,omitempty"` FirstSheet int `xml:"firstSheet,attr,omitempty"` ShowHorizontalScroll bool `xml:"showHorizontalScroll,attr,omitempty"` ShowVerticalScroll bool `xml:"showVerticalScroll,attr,omitempty"` ShowSheetTabs bool `xml:"showSheetTabs,attr,omitempty"` TabRatio int `xml:"tabRatio,attr,omitempty"` WindowHeight int `xml:"windowHeight,attr,omitempty"` WindowWidth int `xml:"windowWidth,attr,omitempty"` XWindow string `xml:"xWindow,attr,omitempty"` YWindow string `xml:"yWindow,attr,omitempty"` } // xlsxSheets directly maps the sheets element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxSheets struct { Sheet []xlsxSheet `xml:"sheet"` } // xlsxSheet directly maps the sheet element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxSheet struct { Name string `xml:"name,attr,omitempty"` SheetId string `xml:"sheetId,attr,omitempty"` Id string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` State string `xml:"state,attr,omitempty"` } // xlsxDefinedNames directly maps the definedNames element from the // namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main // - currently I have not checked it for completeness - it does as // much as I need. type xlsxDefinedNames struct { DefinedName []xlsxDefinedName `xml:"definedName"` } // xlsxDefinedName directly maps the definedName element from the // namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main // - currently I have not checked it for completeness - it does as // much as I need. // for a descriptions of the attributes see // https://msdn.microsoft.com/en-us/library/office/documentformat.openxml.spreadsheet.definedname.aspx type xlsxDefinedName struct { Data string `xml:",chardata"` Name string `xml:"name,attr"` Comment string `xml:"comment,attr,omitempty"` CustomMenu string `xml:"customMenu,attr,omitempty"` Description string `xml:"description,attr,omitempty"` Help string `xml:"help,attr,omitempty"` ShortcutKey string `xml:"shortcutKey,attr,omitempty"` StatusBar string `xml:"statusBar,attr,omitempty"` LocalSheetID int `xml:"localSheetId,attr,omitempty"` FunctionGroupID int `xml:"functionGroupId,attr,omitempty"` Function bool `xml:"function,attr,omitempty"` Hidden bool `xml:"hidden,attr,omitempty"` VbProcedure bool `xml:"vbProcedure,attr,omitempty"` PublishToServer bool `xml:"publishToServer,attr,omitempty"` WorkbookParameter bool `xml:"workbookParameter,attr,omitempty"` Xlm bool `xml:"xml,attr,omitempty"` } // xlsxCalcPr directly maps the calcPr element from the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxCalcPr struct { CalcId string `xml:"calcId,attr,omitempty"` IterateCount int `xml:"iterateCount,attr,omitempty"` RefMode string `xml:"refMode,attr,omitempty"` Iterate bool `xml:"iterate,attr,omitempty"` IterateDelta float64 `xml:"iterateDelta,attr,omitempty"` } // Helper function to lookup the file corresponding to a xlsxSheet object in the worksheets map func worksheetFileForSheet(sheet xlsxSheet, worksheets map[string]*zip.File, sheetXMLMap map[string]string) *zip.File { sheetName, ok := sheetXMLMap[sheet.Id] if !ok { if sheet.SheetId != "" { sheetName = fmt.Sprintf("sheet%s", sheet.SheetId) } else { sheetName = fmt.Sprintf("sheet%s", sheet.Id) } } return worksheets[sheetName] } // getWorksheetFromSheet() is an internal helper function to open a // sheetN.xml file, referred to by an xlsx.xlsxSheet struct, from the XLSX // file and unmarshal it an xlsx.xlsxWorksheet struct func getWorksheetFromSheet(sheet xlsxSheet, worksheets map[string]*zip.File, sheetXMLMap map[string]string, rowLimit int) (*xlsxWorksheet, error) { var r io.Reader var decoder *xml.Decoder var worksheet *xlsxWorksheet var err error worksheet = new(xlsxWorksheet) f := worksheetFileForSheet(sheet, worksheets, sheetXMLMap) if f == nil { return nil, fmt.Errorf("Unable to find sheet '%s'", sheet) } if rc, err := f.Open(); err != nil { return nil, err } else { defer rc.Close() r = rc } if rowLimit != NoRowLimit { r, err = truncateSheetXML(r, rowLimit) if err != nil { return nil, err } } decoder = xml.NewDecoder(r) err = decoder.Decode(worksheet) if err != nil { return nil, err } return worksheet, nil } ================================================ FILE: vendor/github.com/tealeg/xlsx/xmlWorksheet.go ================================================ package xlsx import ( "encoding/xml" "strings" ) // xlsxWorksheet directly maps the worksheet element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxWorksheet struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main worksheet"` SheetPr xlsxSheetPr `xml:"sheetPr"` Dimension xlsxDimension `xml:"dimension"` SheetViews xlsxSheetViews `xml:"sheetViews"` SheetFormatPr xlsxSheetFormatPr `xml:"sheetFormatPr"` Cols *xlsxCols `xml:"cols,omitempty"` SheetData xlsxSheetData `xml:"sheetData"` AutoFilter *xlsxAutoFilter `xml:"autoFilter,omitempty"` MergeCells *xlsxMergeCells `xml:"mergeCells,omitempty"` PrintOptions xlsxPrintOptions `xml:"printOptions"` PageMargins xlsxPageMargins `xml:"pageMargins"` PageSetUp xlsxPageSetUp `xml:"pageSetup"` HeaderFooter xlsxHeaderFooter `xml:"headerFooter"` } // xlsxHeaderFooter directly maps the headerFooter element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxHeaderFooter struct { DifferentFirst bool `xml:"differentFirst,attr"` DifferentOddEven bool `xml:"differentOddEven,attr"` OddHeader []xlsxOddHeader `xml:"oddHeader"` OddFooter []xlsxOddFooter `xml:"oddFooter"` } // xlsxOddHeader directly maps the oddHeader element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxOddHeader struct { Content string `xml:",chardata"` } // xlsxOddFooter directly maps the oddFooter element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxOddFooter struct { Content string `xml:",chardata"` } // xlsxPageSetUp directly maps the pageSetup element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxPageSetUp struct { PaperSize string `xml:"paperSize,attr"` Scale int `xml:"scale,attr"` FirstPageNumber int `xml:"firstPageNumber,attr"` FitToWidth int `xml:"fitToWidth,attr"` FitToHeight int `xml:"fitToHeight,attr"` PageOrder string `xml:"pageOrder,attr"` Orientation string `xml:"orientation,attr"` UsePrinterDefaults bool `xml:"usePrinterDefaults,attr"` BlackAndWhite bool `xml:"blackAndWhite,attr"` Draft bool `xml:"draft,attr"` CellComments string `xml:"cellComments,attr"` UseFirstPageNumber bool `xml:"useFirstPageNumber,attr"` HorizontalDPI float32 `xml:"horizontalDpi,attr"` VerticalDPI float32 `xml:"verticalDpi,attr"` Copies int `xml:"copies,attr"` } // xlsxPrintOptions directly maps the printOptions element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxPrintOptions struct { Headings bool `xml:"headings,attr"` GridLines bool `xml:"gridLines,attr"` GridLinesSet bool `xml:"gridLinesSet,attr"` HorizontalCentered bool `xml:"horizontalCentered,attr"` VerticalCentered bool `xml:"verticalCentered,attr"` } // xlsxPageMargins directly maps the pageMargins element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxPageMargins struct { Left float64 `xml:"left,attr"` Right float64 `xml:"right,attr"` Top float64 `xml:"top,attr"` Bottom float64 `xml:"bottom,attr"` Header float64 `xml:"header,attr"` Footer float64 `xml:"footer,attr"` } // xlsxSheetFormatPr directly maps the sheetFormatPr element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxSheetFormatPr struct { DefaultColWidth float64 `xml:"defaultColWidth,attr,omitempty"` DefaultRowHeight float64 `xml:"defaultRowHeight,attr"` OutlineLevelCol uint8 `xml:"outlineLevelCol,attr,omitempty"` OutlineLevelRow uint8 `xml:"outlineLevelRow,attr,omitempty"` } // xlsxSheetViews directly maps the sheetViews element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxSheetViews struct { SheetView []xlsxSheetView `xml:"sheetView"` } // xlsxSheetView directly maps the sheetView element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxSheetView struct { WindowProtection bool `xml:"windowProtection,attr"` ShowFormulas bool `xml:"showFormulas,attr"` ShowGridLines bool `xml:"showGridLines,attr"` ShowRowColHeaders bool `xml:"showRowColHeaders,attr"` ShowZeros bool `xml:"showZeros,attr"` RightToLeft bool `xml:"rightToLeft,attr"` TabSelected bool `xml:"tabSelected,attr"` ShowOutlineSymbols bool `xml:"showOutlineSymbols,attr"` DefaultGridColor bool `xml:"defaultGridColor,attr"` View string `xml:"view,attr"` TopLeftCell string `xml:"topLeftCell,attr"` ColorId int `xml:"colorId,attr"` ZoomScale float64 `xml:"zoomScale,attr"` ZoomScaleNormal float64 `xml:"zoomScaleNormal,attr"` ZoomScalePageLayoutView float64 `xml:"zoomScalePageLayoutView,attr"` WorkbookViewId int `xml:"workbookViewId,attr"` Pane *xlsxPane `xml:"pane"` Selection []xlsxSelection `xml:"selection"` } // xlsxSelection directly maps the selection element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxSelection struct { Pane string `xml:"pane,attr"` ActiveCell string `xml:"activeCell,attr"` ActiveCellId int `xml:"activeCellId,attr"` SQRef string `xml:"sqref,attr"` } // xlsxSelection directly maps the selection element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxPane struct { XSplit float64 `xml:"xSplit,attr"` YSplit float64 `xml:"ySplit,attr"` TopLeftCell string `xml:"topLeftCell,attr"` ActivePane string `xml:"activePane,attr"` State string `xml:"state,attr"` // Either "split" or "frozen" } // xlsxSheetPr directly maps the sheetPr element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxSheetPr struct { FilterMode bool `xml:"filterMode,attr"` PageSetUpPr []xlsxPageSetUpPr `xml:"pageSetUpPr"` } // xlsxPageSetUpPr directly maps the pageSetupPr element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxPageSetUpPr struct { FitToPage bool `xml:"fitToPage,attr"` } // xlsxCols directly maps the cols element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxCols struct { Col []xlsxCol `xml:"col"` } // xlsxCol directly maps the col element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxCol struct { Collapsed bool `xml:"collapsed,attr"` Hidden bool `xml:"hidden,attr"` Max int `xml:"max,attr"` Min int `xml:"min,attr"` Style int `xml:"style,attr"` Width float64 `xml:"width,attr"` CustomWidth bool `xml:"customWidth,attr,omitempty"` OutlineLevel uint8 `xml:"outlineLevel,attr,omitempty"` } // xlsxDimension directly maps the dimension element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxDimension struct { Ref string `xml:"ref,attr"` } // xlsxSheetData directly maps the sheetData element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxSheetData struct { XMLName xml.Name `xml:"sheetData"` Row []xlsxRow `xml:"row"` } // xlsxRow directly maps the row element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxRow struct { R int `xml:"r,attr"` Spans string `xml:"spans,attr,omitempty"` Hidden bool `xml:"hidden,attr,omitempty"` C []xlsxC `xml:"c"` Ht string `xml:"ht,attr,omitempty"` CustomHeight bool `xml:"customHeight,attr,omitempty"` OutlineLevel uint8 `xml:"outlineLevel,attr,omitempty"` } type xlsxAutoFilter struct { Ref string `xml:"ref,attr"` } type xlsxMergeCell struct { Ref string `xml:"ref,attr"` // ref: horiz "A1:C1", vert "B3:B6", both "D3:G4" } type xlsxMergeCells struct { XMLName xml.Name //`xml:"mergeCells,omitempty"` Count int `xml:"count,attr,omitempty"` Cells []xlsxMergeCell `xml:"mergeCell,omitempty"` } // Return the cartesian extent of a merged cell range from its origin // cell (the closest merged cell to the to left of the sheet. func (mc *xlsxMergeCells) getExtent(cellRef string) (int, int, error) { if mc == nil { return 0, 0, nil } for _, cell := range mc.Cells { if strings.HasPrefix(cell.Ref, cellRef+":") { parts := strings.Split(cell.Ref, ":") startx, starty, err := GetCoordsFromCellIDString(parts[0]) if err != nil { return -1, -1, err } endx, endy, err := GetCoordsFromCellIDString(parts[1]) if err != nil { return -2, -2, err } return endx - startx, endy - starty, nil } } return 0, 0, nil } // xlsxC directly maps the c element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxC struct { R string `xml:"r,attr"` // Cell ID, e.g. A1 S int `xml:"s,attr,omitempty"` // Style reference. T string `xml:"t,attr,omitempty"` // Type. F *xlsxF `xml:"f,omitempty"` // Formula V string `xml:"v,omitempty"` // Value Is *xlsxSI `xml:"is,omitempty"` // Inline String. } // xlsxF directly maps the f element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - // currently I have not checked it for completeness - it does as much // as I need. type xlsxF struct { Content string `xml:",chardata"` T string `xml:"t,attr,omitempty"` // Formula type Ref string `xml:"ref,attr,omitempty"` // Shared formula ref Si int `xml:"si,attr,omitempty"` // Shared formula index } // Create a new XLSX Worksheet with default values populated. // Strictly for internal use only! func newXlsxWorksheet() (worksheet *xlsxWorksheet) { worksheet = &xlsxWorksheet{} worksheet.SheetPr.FilterMode = false worksheet.SheetPr.PageSetUpPr = make([]xlsxPageSetUpPr, 1) worksheet.SheetPr.PageSetUpPr[0] = xlsxPageSetUpPr{FitToPage: false} worksheet.SheetViews.SheetView = make([]xlsxSheetView, 1) worksheet.SheetViews.SheetView[0] = xlsxSheetView{ ColorId: 64, DefaultGridColor: true, RightToLeft: false, Selection: make([]xlsxSelection, 1), ShowFormulas: false, ShowGridLines: true, ShowOutlineSymbols: true, ShowRowColHeaders: true, ShowZeros: true, TabSelected: false, TopLeftCell: "A1", View: "normal", WindowProtection: false, WorkbookViewId: 0, ZoomScale: 100, ZoomScaleNormal: 100, ZoomScalePageLayoutView: 100} worksheet.SheetViews.SheetView[0].Selection[0] = xlsxSelection{ Pane: "topLeft", ActiveCell: "A1", ActiveCellId: 0, SQRef: "A1"} worksheet.SheetFormatPr.DefaultRowHeight = 12.85 worksheet.PrintOptions.Headings = false worksheet.PrintOptions.GridLines = false worksheet.PrintOptions.GridLinesSet = true worksheet.PrintOptions.HorizontalCentered = false worksheet.PrintOptions.VerticalCentered = false worksheet.PageMargins.Left = 0.7875 worksheet.PageMargins.Right = 0.7875 worksheet.PageMargins.Top = 1.05277777777778 worksheet.PageMargins.Bottom = 1.05277777777778 worksheet.PageMargins.Header = 0.7875 worksheet.PageMargins.Footer = 0.7875 worksheet.PageSetUp.PaperSize = "9" worksheet.PageSetUp.Scale = 100 worksheet.PageSetUp.FirstPageNumber = 1 worksheet.PageSetUp.FitToWidth = 1 worksheet.PageSetUp.FitToHeight = 1 worksheet.PageSetUp.PageOrder = "downThenOver" worksheet.PageSetUp.Orientation = "portrait" worksheet.PageSetUp.UsePrinterDefaults = false worksheet.PageSetUp.BlackAndWhite = false worksheet.PageSetUp.Draft = false worksheet.PageSetUp.CellComments = "none" worksheet.PageSetUp.UseFirstPageNumber = true worksheet.PageSetUp.HorizontalDPI = 300 worksheet.PageSetUp.VerticalDPI = 300 worksheet.PageSetUp.Copies = 1 worksheet.HeaderFooter.OddHeader = make([]xlsxOddHeader, 1) worksheet.HeaderFooter.OddHeader[0] = xlsxOddHeader{Content: `&C&"Times New Roman,Regular"&12&A`} worksheet.HeaderFooter.OddFooter = make([]xlsxOddFooter, 1) worksheet.HeaderFooter.OddFooter[0] = xlsxOddFooter{Content: `&C&"Times New Roman,Regular"&12Page &P`} return } ================================================ FILE: vendor/github.com/ugorji/go/codec/0_importpath.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. package codec // import "github.com/ugorji/go/codec" // This establishes that this package must be imported as github.com/ugorji/go/codec. // It makes forking easier, and plays well with pre-module releases of go. ================================================ FILE: vendor/github.com/ugorji/go/codec/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. 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. ================================================ FILE: vendor/github.com/ugorji/go/codec/binc.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. package codec import ( "math" "reflect" "time" ) const bincDoPrune = true // No longer needed. Needed before as C lib did not support pruning. // vd as low 4 bits (there are 16 slots) const ( bincVdSpecial byte = iota bincVdPosInt bincVdNegInt bincVdFloat bincVdString bincVdByteArray bincVdArray bincVdMap bincVdTimestamp bincVdSmallInt bincVdUnicodeOther bincVdSymbol bincVdDecimal _ // open slot _ // open slot bincVdCustomExt = 0x0f ) const ( bincSpNil byte = iota bincSpFalse bincSpTrue bincSpNan bincSpPosInf bincSpNegInf bincSpZeroFloat bincSpZero bincSpNegOne ) const ( bincFlBin16 byte = iota bincFlBin32 _ // bincFlBin32e bincFlBin64 _ // bincFlBin64e // others not currently supported ) func bincdesc(vd, vs byte) string { switch vd { case bincVdSpecial: switch vs { case bincSpNil: return "nil" case bincSpFalse: return "false" case bincSpTrue: return "true" case bincSpNan, bincSpPosInf, bincSpNegInf, bincSpZeroFloat: return "float" case bincSpZero: return "uint" case bincSpNegOne: return "int" default: return "unknown" } case bincVdSmallInt, bincVdPosInt: return "uint" case bincVdNegInt: return "int" case bincVdFloat: return "float" case bincVdSymbol: return "string" case bincVdString: return "string" case bincVdByteArray: return "bytes" case bincVdTimestamp: return "time" case bincVdCustomExt: return "ext" case bincVdArray: return "array" case bincVdMap: return "map" default: return "unknown" } } type bincEncDriver struct { encDriverNoopContainerWriter e *Encoder h *BincHandle w *encWriterSwitch m map[string]uint16 // symbols b [16]byte // scratch, used for encoding numbers - bigendian style s uint16 // symbols sequencer // c containerState // encDriverTrackContainerWriter noBuiltInTypes // encNoSeparator // _ [1]uint64 // padding } func (e *bincEncDriver) EncodeNil() { e.w.writen1(bincVdSpecial<<4 | bincSpNil) } func (e *bincEncDriver) EncodeTime(t time.Time) { if t.IsZero() { e.EncodeNil() } else { bs := bincEncodeTime(t) e.w.writen1(bincVdTimestamp<<4 | uint8(len(bs))) e.w.writeb(bs) } } func (e *bincEncDriver) EncodeBool(b bool) { if b { e.w.writen1(bincVdSpecial<<4 | bincSpTrue) } else { e.w.writen1(bincVdSpecial<<4 | bincSpFalse) } } func (e *bincEncDriver) EncodeFloat32(f float32) { if f == 0 { e.w.writen1(bincVdSpecial<<4 | bincSpZeroFloat) return } e.w.writen1(bincVdFloat<<4 | bincFlBin32) bigenHelper{e.b[:4], e.w}.writeUint32(math.Float32bits(f)) } func (e *bincEncDriver) EncodeFloat64(f float64) { if f == 0 { e.w.writen1(bincVdSpecial<<4 | bincSpZeroFloat) return } bigen.PutUint64(e.b[:8], math.Float64bits(f)) if bincDoPrune { i := 7 for ; i >= 0 && (e.b[i] == 0); i-- { } i++ if i <= 6 { e.w.writen1(bincVdFloat<<4 | 0x8 | bincFlBin64) e.w.writen1(byte(i)) e.w.writeb(e.b[:i]) return } } e.w.writen1(bincVdFloat<<4 | bincFlBin64) e.w.writeb(e.b[:8]) } func (e *bincEncDriver) encIntegerPrune(bd byte, pos bool, v uint64, lim uint8) { if lim == 4 { bigen.PutUint32(e.b[:lim], uint32(v)) } else { bigen.PutUint64(e.b[:lim], v) } if bincDoPrune { i := pruneSignExt(e.b[:lim], pos) e.w.writen1(bd | lim - 1 - byte(i)) e.w.writeb(e.b[i:lim]) } else { e.w.writen1(bd | lim - 1) e.w.writeb(e.b[:lim]) } } func (e *bincEncDriver) EncodeInt(v int64) { // const nbd byte = bincVdNegInt << 4 if v >= 0 { e.encUint(bincVdPosInt<<4, true, uint64(v)) } else if v == -1 { e.w.writen1(bincVdSpecial<<4 | bincSpNegOne) } else { e.encUint(bincVdNegInt<<4, false, uint64(-v)) } } func (e *bincEncDriver) EncodeUint(v uint64) { e.encUint(bincVdPosInt<<4, true, v) } func (e *bincEncDriver) encUint(bd byte, pos bool, v uint64) { if v == 0 { e.w.writen1(bincVdSpecial<<4 | bincSpZero) } else if pos && v >= 1 && v <= 16 { e.w.writen1(bincVdSmallInt<<4 | byte(v-1)) } else if v <= math.MaxUint8 { e.w.writen2(bd|0x0, byte(v)) } else if v <= math.MaxUint16 { e.w.writen1(bd | 0x01) bigenHelper{e.b[:2], e.w}.writeUint16(uint16(v)) } else if v <= math.MaxUint32 { e.encIntegerPrune(bd, pos, v, 4) } else { e.encIntegerPrune(bd, pos, v, 8) } } func (e *bincEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext, _ *Encoder) { bs := ext.WriteExt(rv) if bs == nil { e.EncodeNil() return } e.encodeExtPreamble(uint8(xtag), len(bs)) e.w.writeb(bs) } func (e *bincEncDriver) EncodeRawExt(re *RawExt, _ *Encoder) { e.encodeExtPreamble(uint8(re.Tag), len(re.Data)) e.w.writeb(re.Data) } func (e *bincEncDriver) encodeExtPreamble(xtag byte, length int) { e.encLen(bincVdCustomExt<<4, uint64(length)) e.w.writen1(xtag) } func (e *bincEncDriver) WriteArrayStart(length int) { e.encLen(bincVdArray<<4, uint64(length)) } func (e *bincEncDriver) WriteMapStart(length int) { e.encLen(bincVdMap<<4, uint64(length)) } func (e *bincEncDriver) EncodeSymbol(v string) { // if WriteSymbolsNoRefs { // e.encodeString(cUTF8, v) // return // } //symbols only offer benefit when string length > 1. //This is because strings with length 1 take only 2 bytes to store //(bd with embedded length, and single byte for string val). l := len(v) if l == 0 { e.encBytesLen(cUTF8, 0) return } else if l == 1 { e.encBytesLen(cUTF8, 1) e.w.writen1(v[0]) return } if e.m == nil { e.m = make(map[string]uint16, 16) } ui, ok := e.m[v] if ok { if ui <= math.MaxUint8 { e.w.writen2(bincVdSymbol<<4, byte(ui)) } else { e.w.writen1(bincVdSymbol<<4 | 0x8) bigenHelper{e.b[:2], e.w}.writeUint16(ui) } } else { e.s++ ui = e.s //ui = uint16(atomic.AddUint32(&e.s, 1)) e.m[v] = ui var lenprec uint8 if l <= math.MaxUint8 { // lenprec = 0 } else if l <= math.MaxUint16 { lenprec = 1 } else if int64(l) <= math.MaxUint32 { lenprec = 2 } else { lenprec = 3 } if ui <= math.MaxUint8 { e.w.writen2(bincVdSymbol<<4|0x0|0x4|lenprec, byte(ui)) } else { e.w.writen1(bincVdSymbol<<4 | 0x8 | 0x4 | lenprec) bigenHelper{e.b[:2], e.w}.writeUint16(ui) } if lenprec == 0 { e.w.writen1(byte(l)) } else if lenprec == 1 { bigenHelper{e.b[:2], e.w}.writeUint16(uint16(l)) } else if lenprec == 2 { bigenHelper{e.b[:4], e.w}.writeUint32(uint32(l)) } else { bigenHelper{e.b[:8], e.w}.writeUint64(uint64(l)) } e.w.writestr(v) } } func (e *bincEncDriver) EncodeStringEnc(c charEncoding, v string) { if e.e.c == containerMapKey && c == cUTF8 && (e.h.AsSymbols == 0 || e.h.AsSymbols == 1) { e.EncodeSymbol(v) return } l := uint64(len(v)) e.encLen(bincVdString<<4, l) // e.encBytesLen(c, l) if l > 0 { e.w.writestr(v) } } func (e *bincEncDriver) EncodeStringBytesRaw(v []byte) { if v == nil { e.EncodeNil() return } l := uint64(len(v)) e.encLen(bincVdByteArray<<4, l) // e.encBytesLen(c, l) if l > 0 { e.w.writeb(v) } } func (e *bincEncDriver) encBytesLen(c charEncoding, length uint64) { //TODO: support bincUnicodeOther (for now, just use string or bytearray) if c == cRAW { e.encLen(bincVdByteArray<<4, length) } else { e.encLen(bincVdString<<4, length) } } func (e *bincEncDriver) encLen(bd byte, l uint64) { if l < 12 { e.w.writen1(bd | uint8(l+4)) } else { e.encLenNumber(bd, l) } } func (e *bincEncDriver) encLenNumber(bd byte, v uint64) { if v <= math.MaxUint8 { e.w.writen2(bd, byte(v)) } else if v <= math.MaxUint16 { e.w.writen1(bd | 0x01) bigenHelper{e.b[:2], e.w}.writeUint16(uint16(v)) } else if v <= math.MaxUint32 { e.w.writen1(bd | 0x02) bigenHelper{e.b[:4], e.w}.writeUint32(uint32(v)) } else { e.w.writen1(bd | 0x03) bigenHelper{e.b[:8], e.w}.writeUint64(uint64(v)) } } //------------------------------------ type bincDecSymbol struct { s string b []byte i uint16 } type bincDecDriver struct { decDriverNoopContainerReader noBuiltInTypes d *Decoder h *BincHandle r *decReaderSwitch br bool // bytes reader bdRead bool bd byte vd byte vs byte // _ [3]byte // padding // linear searching on this slice is ok, // because we typically expect < 32 symbols in each stream. s []bincDecSymbol // noStreamingCodec // decNoSeparator b [(8 + 1) * 8]byte // scratch } func (d *bincDecDriver) readNextBd() { d.bd = d.r.readn1() d.vd = d.bd >> 4 d.vs = d.bd & 0x0f d.bdRead = true } func (d *bincDecDriver) uncacheRead() { if d.bdRead { d.r.unreadn1() d.bdRead = false } } func (d *bincDecDriver) ContainerType() (vt valueType) { if !d.bdRead { d.readNextBd() } if d.vd == bincVdSpecial && d.vs == bincSpNil { return valueTypeNil } else if d.vd == bincVdByteArray { return valueTypeBytes } else if d.vd == bincVdString { return valueTypeString } else if d.vd == bincVdArray { return valueTypeArray } else if d.vd == bincVdMap { return valueTypeMap } // else { // d.d.errorf("isContainerType: unsupported parameter: %v", vt) // } return valueTypeUnset } func (d *bincDecDriver) TryDecodeAsNil() bool { if !d.bdRead { d.readNextBd() } if d.bd == bincVdSpecial<<4|bincSpNil { d.bdRead = false return true } return false } func (d *bincDecDriver) DecodeTime() (t time.Time) { if !d.bdRead { d.readNextBd() } if d.bd == bincVdSpecial<<4|bincSpNil { d.bdRead = false return } if d.vd != bincVdTimestamp { d.d.errorf("cannot decode time - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs)) return } t, err := bincDecodeTime(d.r.readx(uint(d.vs))) if err != nil { panic(err) } d.bdRead = false return } func (d *bincDecDriver) decFloatPre(vs, defaultLen byte) { if vs&0x8 == 0 { d.r.readb(d.b[0:defaultLen]) } else { l := d.r.readn1() if l > 8 { d.d.errorf("cannot read float - at most 8 bytes used to represent float - received %v bytes", l) return } for i := l; i < 8; i++ { d.b[i] = 0 } d.r.readb(d.b[0:l]) } } func (d *bincDecDriver) decFloat() (f float64) { //if true { f = math.Float64frombits(bigen.Uint64(d.r.readx(8))); break; } if x := d.vs & 0x7; x == bincFlBin32 { d.decFloatPre(d.vs, 4) f = float64(math.Float32frombits(bigen.Uint32(d.b[0:4]))) } else if x == bincFlBin64 { d.decFloatPre(d.vs, 8) f = math.Float64frombits(bigen.Uint64(d.b[0:8])) } else { d.d.errorf("read float - only float32 and float64 are supported - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs)) return } return } func (d *bincDecDriver) decUint() (v uint64) { // need to inline the code (interface conversion and type assertion expensive) switch d.vs { case 0: v = uint64(d.r.readn1()) case 1: d.r.readb(d.b[6:8]) v = uint64(bigen.Uint16(d.b[6:8])) case 2: d.b[4] = 0 d.r.readb(d.b[5:8]) v = uint64(bigen.Uint32(d.b[4:8])) case 3: d.r.readb(d.b[4:8]) v = uint64(bigen.Uint32(d.b[4:8])) case 4, 5, 6: lim := 7 - d.vs d.r.readb(d.b[lim:8]) for i := uint8(0); i < lim; i++ { d.b[i] = 0 } v = uint64(bigen.Uint64(d.b[:8])) case 7: d.r.readb(d.b[:8]) v = uint64(bigen.Uint64(d.b[:8])) default: d.d.errorf("unsigned integers with greater than 64 bits of precision not supported") return } return } func (d *bincDecDriver) decCheckInteger() (ui uint64, neg bool) { if !d.bdRead { d.readNextBd() } vd, vs := d.vd, d.vs if vd == bincVdPosInt { ui = d.decUint() } else if vd == bincVdNegInt { ui = d.decUint() neg = true } else if vd == bincVdSmallInt { ui = uint64(d.vs) + 1 } else if vd == bincVdSpecial { if vs == bincSpZero { //i = 0 } else if vs == bincSpNegOne { neg = true ui = 1 } else { d.d.errorf("integer decode fails - invalid special value from descriptor %x-%x/%s", d.vd, d.vs, bincdesc(d.vd, d.vs)) return } } else { d.d.errorf("integer can only be decoded from int/uint. d.bd: 0x%x, d.vd: 0x%x", d.bd, d.vd) return } return } func (d *bincDecDriver) DecodeInt64() (i int64) { ui, neg := d.decCheckInteger() i = chkOvf.SignedIntV(ui) if neg { i = -i } d.bdRead = false return } func (d *bincDecDriver) DecodeUint64() (ui uint64) { ui, neg := d.decCheckInteger() if neg { d.d.errorf("assigning negative signed value to unsigned integer type") return } d.bdRead = false return } func (d *bincDecDriver) DecodeFloat64() (f float64) { if !d.bdRead { d.readNextBd() } vd, vs := d.vd, d.vs if vd == bincVdSpecial { d.bdRead = false if vs == bincSpNan { return math.NaN() } else if vs == bincSpPosInf { return math.Inf(1) } else if vs == bincSpZeroFloat || vs == bincSpZero { return } else if vs == bincSpNegInf { return math.Inf(-1) } else { d.d.errorf("float - invalid special value from descriptor %x-%x/%s", d.vd, d.vs, bincdesc(d.vd, d.vs)) return } } else if vd == bincVdFloat { f = d.decFloat() } else { f = float64(d.DecodeInt64()) } d.bdRead = false return } // bool can be decoded from bool only (single byte). func (d *bincDecDriver) DecodeBool() (b bool) { if !d.bdRead { d.readNextBd() } if bd := d.bd; bd == (bincVdSpecial | bincSpFalse) { // b = false } else if bd == (bincVdSpecial | bincSpTrue) { b = true } else { d.d.errorf("bool - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs)) return } d.bdRead = false return } func (d *bincDecDriver) ReadMapStart() (length int) { if !d.bdRead { d.readNextBd() } if d.vd != bincVdMap { d.d.errorf("map - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs)) return } length = d.decLen() d.bdRead = false return } func (d *bincDecDriver) ReadArrayStart() (length int) { if !d.bdRead { d.readNextBd() } if d.vd != bincVdArray { d.d.errorf("array - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs)) return } length = d.decLen() d.bdRead = false return } func (d *bincDecDriver) decLen() int { if d.vs > 3 { return int(d.vs - 4) } return int(d.decLenNumber()) } func (d *bincDecDriver) decLenNumber() (v uint64) { if x := d.vs; x == 0 { v = uint64(d.r.readn1()) } else if x == 1 { d.r.readb(d.b[6:8]) v = uint64(bigen.Uint16(d.b[6:8])) } else if x == 2 { d.r.readb(d.b[4:8]) v = uint64(bigen.Uint32(d.b[4:8])) } else { d.r.readb(d.b[:8]) v = bigen.Uint64(d.b[:8]) } return } func (d *bincDecDriver) decStringAndBytes(bs []byte, withString, zerocopy bool) ( bs2 []byte, s string) { if !d.bdRead { d.readNextBd() } if d.bd == bincVdSpecial<<4|bincSpNil { d.bdRead = false return } var slen = -1 // var ok bool switch d.vd { case bincVdString, bincVdByteArray: slen = d.decLen() if zerocopy { if d.br { bs2 = d.r.readx(uint(slen)) } else if len(bs) == 0 { bs2 = decByteSlice(d.r, slen, d.d.h.MaxInitLen, d.b[:]) } else { bs2 = decByteSlice(d.r, slen, d.d.h.MaxInitLen, bs) } } else { bs2 = decByteSlice(d.r, slen, d.d.h.MaxInitLen, bs) } if withString { s = string(bs2) } case bincVdSymbol: // zerocopy doesn't apply for symbols, // as the values must be stored in a table for later use. // //from vs: extract numSymbolBytes, containsStringVal, strLenPrecision, //extract symbol //if containsStringVal, read it and put in map //else look in map for string value var symbol uint16 vs := d.vs if vs&0x8 == 0 { symbol = uint16(d.r.readn1()) } else { symbol = uint16(bigen.Uint16(d.r.readx(2))) } if d.s == nil { d.s = make([]bincDecSymbol, 0, 16) } if vs&0x4 == 0 { for i := range d.s { j := &d.s[i] if j.i == symbol { bs2 = j.b if withString { if j.s == "" && bs2 != nil { j.s = string(bs2) } s = j.s } break } } } else { switch vs & 0x3 { case 0: slen = int(d.r.readn1()) case 1: slen = int(bigen.Uint16(d.r.readx(2))) case 2: slen = int(bigen.Uint32(d.r.readx(4))) case 3: slen = int(bigen.Uint64(d.r.readx(8))) } // since using symbols, do not store any part of // the parameter bs in the map, as it might be a shared buffer. // bs2 = decByteSlice(d.r, slen, bs) bs2 = decByteSlice(d.r, slen, d.d.h.MaxInitLen, nil) if withString { s = string(bs2) } d.s = append(d.s, bincDecSymbol{i: symbol, s: s, b: bs2}) } default: d.d.errorf("string/bytes - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs)) return } d.bdRead = false return } func (d *bincDecDriver) DecodeString() (s string) { // DecodeBytes does not accommodate symbols, whose impl stores string version in map. // Use decStringAndBytes directly. // return string(d.DecodeBytes(d.b[:], true, true)) _, s = d.decStringAndBytes(d.b[:], true, true) return } func (d *bincDecDriver) DecodeStringAsBytes() (s []byte) { s, _ = d.decStringAndBytes(d.b[:], false, true) return } func (d *bincDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) { if !d.bdRead { d.readNextBd() } if d.bd == bincVdSpecial<<4|bincSpNil { d.bdRead = false return nil } // check if an "array" of uint8's (see ContainerType for how to infer if an array) if d.vd == bincVdArray { bsOut, _ = fastpathTV.DecSliceUint8V(bs, true, d.d) return } var clen int if d.vd == bincVdString || d.vd == bincVdByteArray { clen = d.decLen() } else { d.d.errorf("bytes - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs)) return } d.bdRead = false if zerocopy { if d.br { return d.r.readx(uint(clen)) } else if len(bs) == 0 { bs = d.b[:] } } return decByteSlice(d.r, clen, d.d.h.MaxInitLen, bs) } func (d *bincDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) { if xtag > 0xff { d.d.errorf("ext: tag must be <= 0xff; got: %v", xtag) return } realxtag1, xbs := d.decodeExtV(ext != nil, uint8(xtag)) realxtag = uint64(realxtag1) if ext == nil { re := rv.(*RawExt) re.Tag = realxtag re.Data = detachZeroCopyBytes(d.br, re.Data, xbs) } else { ext.ReadExt(rv, xbs) } return } func (d *bincDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs []byte) { if !d.bdRead { d.readNextBd() } if d.vd == bincVdCustomExt { l := d.decLen() xtag = d.r.readn1() if verifyTag && xtag != tag { d.d.errorf("wrong extension tag - got %b, expecting: %v", xtag, tag) return } if d.br { xbs = d.r.readx(uint(l)) } else { xbs = decByteSlice(d.r, l, d.d.h.MaxInitLen, d.d.b[:]) } } else if d.vd == bincVdByteArray { xbs = d.DecodeBytes(nil, true) } else { d.d.errorf("ext - expecting extensions or byte array - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs)) return } d.bdRead = false return } func (d *bincDecDriver) DecodeNaked() { if !d.bdRead { d.readNextBd() } n := d.d.naked() var decodeFurther bool switch d.vd { case bincVdSpecial: switch d.vs { case bincSpNil: n.v = valueTypeNil case bincSpFalse: n.v = valueTypeBool n.b = false case bincSpTrue: n.v = valueTypeBool n.b = true case bincSpNan: n.v = valueTypeFloat n.f = math.NaN() case bincSpPosInf: n.v = valueTypeFloat n.f = math.Inf(1) case bincSpNegInf: n.v = valueTypeFloat n.f = math.Inf(-1) case bincSpZeroFloat: n.v = valueTypeFloat n.f = float64(0) case bincSpZero: n.v = valueTypeUint n.u = uint64(0) // int8(0) case bincSpNegOne: n.v = valueTypeInt n.i = int64(-1) // int8(-1) default: d.d.errorf("cannot infer value - unrecognized special value from descriptor %x-%x/%s", d.vd, d.vs, bincdesc(d.vd, d.vs)) } case bincVdSmallInt: n.v = valueTypeUint n.u = uint64(int8(d.vs)) + 1 // int8(d.vs) + 1 case bincVdPosInt: n.v = valueTypeUint n.u = d.decUint() case bincVdNegInt: n.v = valueTypeInt n.i = -(int64(d.decUint())) case bincVdFloat: n.v = valueTypeFloat n.f = d.decFloat() case bincVdSymbol: n.v = valueTypeSymbol n.s = d.DecodeString() case bincVdString: n.v = valueTypeString n.s = d.DecodeString() case bincVdByteArray: decNakedReadRawBytes(d, d.d, n, d.h.RawToString) case bincVdTimestamp: n.v = valueTypeTime tt, err := bincDecodeTime(d.r.readx(uint(d.vs))) if err != nil { panic(err) } n.t = tt case bincVdCustomExt: n.v = valueTypeExt l := d.decLen() n.u = uint64(d.r.readn1()) if d.br { n.l = d.r.readx(uint(l)) } else { n.l = decByteSlice(d.r, l, d.d.h.MaxInitLen, d.d.b[:]) } case bincVdArray: n.v = valueTypeArray decodeFurther = true case bincVdMap: n.v = valueTypeMap decodeFurther = true default: d.d.errorf("cannot infer value - %s %x-%x/%s", msgBadDesc, d.vd, d.vs, bincdesc(d.vd, d.vs)) } if !decodeFurther { d.bdRead = false } if n.v == valueTypeUint && d.h.SignedInteger { n.v = valueTypeInt n.i = int64(n.u) } } //------------------------------------ //BincHandle is a Handle for the Binc Schema-Free Encoding Format //defined at https://github.com/ugorji/binc . // //BincHandle currently supports all Binc features with the following EXCEPTIONS: // - only integers up to 64 bits of precision are supported. // big integers are unsupported. // - Only IEEE 754 binary32 and binary64 floats are supported (ie Go float32 and float64 types). // extended precision and decimal IEEE 754 floats are unsupported. // - Only UTF-8 strings supported. // Unicode_Other Binc types (UTF16, UTF32) are currently unsupported. // //Note that these EXCEPTIONS are temporary and full support is possible and may happen soon. type BincHandle struct { BasicHandle binaryEncodingType noElemSeparators // AsSymbols defines what should be encoded as symbols. // // Encoding as symbols can reduce the encoded size significantly. // // However, during decoding, each string to be encoded as a symbol must // be checked to see if it has been seen before. Consequently, encoding time // will increase if using symbols, because string comparisons has a clear cost. // // Values: // - 0: default: library uses best judgement // - 1: use symbols // - 2: do not use symbols AsSymbols uint8 // AsSymbols: may later on introduce more options ... // - m: map keys // - s: struct fields // - n: none // - a: all: same as m, s, ... _ [1]uint64 // padding (cache-aligned) } // Name returns the name of the handle: binc func (h *BincHandle) Name() string { return "binc" } // SetBytesExt sets an extension func (h *BincHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) { return h.SetExt(rt, tag, &bytesExtWrapper{BytesExt: ext}) } func (h *BincHandle) newEncDriver(e *Encoder) encDriver { return &bincEncDriver{e: e, h: h, w: e.w()} } func (h *BincHandle) newDecDriver(d *Decoder) decDriver { return &bincDecDriver{d: d, h: h, r: d.r(), br: d.bytes} } func (e *bincEncDriver) reset() { e.w = e.e.w() e.s = 0 e.m = nil } func (d *bincDecDriver) reset() { d.r, d.br = d.d.r(), d.d.bytes d.s = nil d.bd, d.bdRead, d.vd, d.vs = 0, false, 0, 0 } // var timeDigits = [...]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'} // EncodeTime encodes a time.Time as a []byte, including // information on the instant in time and UTC offset. // // Format Description // // A timestamp is composed of 3 components: // // - secs: signed integer representing seconds since unix epoch // - nsces: unsigned integer representing fractional seconds as a // nanosecond offset within secs, in the range 0 <= nsecs < 1e9 // - tz: signed integer representing timezone offset in minutes east of UTC, // and a dst (daylight savings time) flag // // When encoding a timestamp, the first byte is the descriptor, which // defines which components are encoded and how many bytes are used to // encode secs and nsecs components. *If secs/nsecs is 0 or tz is UTC, it // is not encoded in the byte array explicitly*. // // Descriptor 8 bits are of the form `A B C DDD EE`: // A: Is secs component encoded? 1 = true // B: Is nsecs component encoded? 1 = true // C: Is tz component encoded? 1 = true // DDD: Number of extra bytes for secs (range 0-7). // If A = 1, secs encoded in DDD+1 bytes. // If A = 0, secs is not encoded, and is assumed to be 0. // If A = 1, then we need at least 1 byte to encode secs. // DDD says the number of extra bytes beyond that 1. // E.g. if DDD=0, then secs is represented in 1 byte. // if DDD=2, then secs is represented in 3 bytes. // EE: Number of extra bytes for nsecs (range 0-3). // If B = 1, nsecs encoded in EE+1 bytes (similar to secs/DDD above) // // Following the descriptor bytes, subsequent bytes are: // // secs component encoded in `DDD + 1` bytes (if A == 1) // nsecs component encoded in `EE + 1` bytes (if B == 1) // tz component encoded in 2 bytes (if C == 1) // // secs and nsecs components are integers encoded in a BigEndian // 2-complement encoding format. // // tz component is encoded as 2 bytes (16 bits). Most significant bit 15 to // Least significant bit 0 are described below: // // Timezone offset has a range of -12:00 to +14:00 (ie -720 to +840 minutes). // Bit 15 = have\_dst: set to 1 if we set the dst flag. // Bit 14 = dst\_on: set to 1 if dst is in effect at the time, or 0 if not. // Bits 13..0 = timezone offset in minutes. It is a signed integer in Big Endian format. // func bincEncodeTime(t time.Time) []byte { //t := rv.Interface().(time.Time) tsecs, tnsecs := t.Unix(), t.Nanosecond() var ( bd byte btmp [8]byte bs [16]byte i int = 1 ) l := t.Location() if l == time.UTC { l = nil } if tsecs != 0 { bd = bd | 0x80 bigen.PutUint64(btmp[:], uint64(tsecs)) f := pruneSignExt(btmp[:], tsecs >= 0) bd = bd | (byte(7-f) << 2) copy(bs[i:], btmp[f:]) i = i + (8 - f) } if tnsecs != 0 { bd = bd | 0x40 bigen.PutUint32(btmp[:4], uint32(tnsecs)) f := pruneSignExt(btmp[:4], true) bd = bd | byte(3-f) copy(bs[i:], btmp[f:4]) i = i + (4 - f) } if l != nil { bd = bd | 0x20 // Note that Go Libs do not give access to dst flag. _, zoneOffset := t.Zone() //zoneName, zoneOffset := t.Zone() zoneOffset /= 60 z := uint16(zoneOffset) bigen.PutUint16(btmp[:2], z) // clear dst flags bs[i] = btmp[0] & 0x3f bs[i+1] = btmp[1] i = i + 2 } bs[0] = bd return bs[0:i] } // bincDecodeTime decodes a []byte into a time.Time. func bincDecodeTime(bs []byte) (tt time.Time, err error) { bd := bs[0] var ( tsec int64 tnsec uint32 tz uint16 i byte = 1 i2 byte n byte ) if bd&(1<<7) != 0 { var btmp [8]byte n = ((bd >> 2) & 0x7) + 1 i2 = i + n copy(btmp[8-n:], bs[i:i2]) //if first bit of bs[i] is set, then fill btmp[0..8-n] with 0xff (ie sign extend it) if bs[i]&(1<<7) != 0 { copy(btmp[0:8-n], bsAll0xff) //for j,k := byte(0), 8-n; j < k; j++ { btmp[j] = 0xff } } i = i2 tsec = int64(bigen.Uint64(btmp[:])) } if bd&(1<<6) != 0 { var btmp [4]byte n = (bd & 0x3) + 1 i2 = i + n copy(btmp[4-n:], bs[i:i2]) i = i2 tnsec = bigen.Uint32(btmp[:]) } if bd&(1<<5) == 0 { tt = time.Unix(tsec, int64(tnsec)).UTC() return } // In stdlib time.Parse, when a date is parsed without a zone name, it uses "" as zone name. // However, we need name here, so it can be shown when time is printf.d. // Zone name is in form: UTC-08:00. // Note that Go Libs do not give access to dst flag, so we ignore dst bits i2 = i + 2 tz = bigen.Uint16(bs[i:i2]) // i = i2 // sign extend sign bit into top 2 MSB (which were dst bits): if tz&(1<<13) == 0 { // positive tz = tz & 0x3fff //clear 2 MSBs: dst bits } else { // negative tz = tz | 0xc000 //set 2 MSBs: dst bits } tzint := int16(tz) if tzint == 0 { tt = time.Unix(tsec, int64(tnsec)).UTC() } else { // For Go Time, do not use a descriptive timezone. // It's unnecessary, and makes it harder to do a reflect.DeepEqual. // The Offset already tells what the offset should be, if not on UTC and unknown zone name. // var zoneName = timeLocUTCName(tzint) tt = time.Unix(tsec, int64(tnsec)).In(time.FixedZone("", int(tzint)*60)) } return } var _ decDriver = (*bincDecDriver)(nil) var _ encDriver = (*bincEncDriver)(nil) ================================================ FILE: vendor/github.com/ugorji/go/codec/build.sh ================================================ #!/bin/bash # Run all the different permutations of all the tests and other things # This helps ensure that nothing gets broken. _tests() { local gover=$( go version | cut -f 3 -d ' ' ) # note that codecgen requires fastpath, so you cannot do "codecgen notfastpath" local a=( "" "safe" "notfastpath" "notfastpath safe" "codecgen" "codecgen safe" ) for i in "${a[@]}" do echo ">>>> TAGS: $i" local i2=${i:-default} case $gover in go1.[0-6]*) go vet -printfuncs "errorf" "$@" && go test ${zargs[*]} -vet off -tags "$i" "$@" ;; *) go vet -printfuncs "errorf" "$@" && go test ${zargs[*]} -vet off -tags "alltests $i" -run "Suite" -coverprofile "${i2// /-}.cov.out" "$@" ;; esac if [[ "$?" != 0 ]]; then return 1; fi done echo "++++++++ TEST SUITES ALL PASSED ++++++++" } # is a generation needed? _ng() { local a="$1" if [[ ! -e "$a" ]]; then echo 1; return; fi for i in `ls -1 *.go.tmpl gen.go values_test.go` do if [[ "$a" -ot "$i" ]]; then echo 1; return; fi done } _prependbt() { cat > ${2} <> ${2} rm -f ${1} } # _build generates fast-path.go and gen-helper.go. _build() { if ! [[ "${zforce}" || $(_ng "fast-path.generated.go") || $(_ng "gen-helper.generated.go") || $(_ng "gen.generated.go") ]]; then return 0; fi if [ "${zbak}" ]; then _zts=`date '+%m%d%Y_%H%M%S'` _gg=".generated.go" [ -e "gen-helper${_gg}" ] && mv gen-helper${_gg} gen-helper${_gg}__${_zts}.bak [ -e "fast-path${_gg}" ] && mv fast-path${_gg} fast-path${_gg}__${_zts}.bak [ -e "gen${_gg}" ] && mv gen${_gg} gen${_gg}__${_zts}.bak fi rm -f gen-helper.generated.go fast-path.generated.go gen.generated.go \ *safe.generated.go *_generated_test.go *.generated_ffjson_expose.go cat > gen.generated.go <> gen.generated.go < gen-dec-map.go.tmpl cat >> gen.generated.go <> gen.generated.go < gen-dec-array.go.tmpl cat >> gen.generated.go <> gen.generated.go < gen-enc-chan.go.tmpl cat >> gen.generated.go < gen-from-tmpl.codec.generated.go < gen-from-tmpl.generated.go < " + fnameOut + " ______") fin, err := os.Open(fnameIn) if err != nil { panic(err) } defer fin.Close() fout, err := os.Create(fnameOut) if err != nil { panic(err) } defer fout.Close() err = codec.GenInternalGoFile(fin, fout) if err != nil { panic(err) } } func main() { run("fast-path.go.tmpl", "fast-path.generated.go") run("gen-helper.go.tmpl", "gen-helper.generated.go") run("mammoth-test.go.tmpl", "mammoth_generated_test.go") run("mammoth2-test.go.tmpl", "mammoth2_generated_test.go") // run("sort-slice.go.tmpl", "sort-slice.generated.go") } EOF sed -e 's+// __DO_NOT_REMOVE__NEEDED_FOR_REPLACING__IMPORT_PATH__FOR_CODEC_BENCH__+import . "github.com/ugorji/go/codec"+' \ shared_test.go > bench/shared_test.go # explicitly return 0 if this passes, else return 1 go run -tags "prebuild" prebuild.go || return 1 go run -tags "notfastpath safe codecgen.exec" gen-from-tmpl.generated.go || return 1 rm -f gen-from-tmpl.*generated.go return 0 } _codegenerators() { local c5="_generated_test.go" local c7="$PWD/codecgen" local c8="$c7/__codecgen" local c9="codecgen-scratch.go" if ! [[ $zforce || $(_ng "values_codecgen${c5}") ]]; then return 0; fi # Note: ensure you run the codecgen for this codebase/directory i.e. ./codecgen/codecgen true && echo "codecgen ... " && if [[ $zforce || ! -f "$c8" || "$c7/gen.go" -nt "$c8" ]]; then echo "rebuilding codecgen ... " && ( cd codecgen && go build -o $c8 ${zargs[*]} . ) fi && $c8 -rt codecgen -t 'codecgen generated' -o values_codecgen${c5} -d 19780 $zfin $zfin2 && cp mammoth2_generated_test.go $c9 && $c8 -t 'codecgen,!notfastpath generated,!notfastpath' -o mammoth2_codecgen${c5} -d 19781 mammoth2_generated_test.go && rm -f $c9 && echo "generators done!" } _prebuild() { echo "prebuild: zforce: $zforce" local d="$PWD" local zfin="test_values.generated.go" local zfin2="test_values_flex.generated.go" local zpkg="github.com/ugorji/go/codec" # zpkg=${d##*/src/} # zgobase=${d%%/src/*} # rm -f *_generated_test.go rm -f codecgen-*.go && _build && cp $d/values_test.go $d/$zfin && cp $d/values_flex_test.go $d/$zfin2 && _codegenerators && if [[ "$(type -t _codegenerators_external )" = "function" ]]; then _codegenerators_external ; fi && if [[ $zforce ]]; then go install ${zargs[*]} .; fi && echo "prebuild done successfully" rm -f $d/$zfin $d/$zfin2 # unset zfin zfin2 zpkg } _make() { local makeforce=${zforce} zforce=1 (cd codecgen && go install ${zargs[*]} .) && _prebuild && go install ${zargs[*]} . zforce=${makeforce} } _clean() { rm -f gen-from-tmpl.*generated.go \ codecgen-*.go \ test_values.generated.go test_values_flex.generated.go } _release() { local reply read -p "Pre-release validation takes a few minutes and MUST be run from within GOPATH/src. Confirm y/n? " -n 1 -r reply echo if [[ ! $reply =~ ^[Yy]$ ]]; then return 1; fi # expects GOROOT, GOROOT_BOOTSTRAP to have been set. if [[ -z "${GOROOT// }" || -z "${GOROOT_BOOTSTRAP// }" ]]; then return 1; fi # (cd $GOROOT && git checkout -f master && git pull && git reset --hard) (cd $GOROOT && git pull) local f=`pwd`/make.release.out cat > $f <>$f if [[ "$i" != "master" ]]; then i="release-branch.go$i"; fi (false || (echo "===== BUILDING GO SDK for branch: $i ... =====" && cd $GOROOT && git checkout -f $i && git reset --hard && git clean -f . && cd src && ./make.bash >>$f 2>&1 && sleep 1 ) ) && echo "===== GO SDK BUILD DONE =====" && _prebuild && echo "===== PREBUILD DONE with exit: $? =====" && _tests "$@" if [[ "$?" != 0 ]]; then return 1; fi done zforce=${makeforce} echo "++++++++ RELEASE TEST SUITES ALL PASSED ++++++++" } _usage() { cat < [tests, make, prebuild (force) (external), inlining diagnostics, mid-stack inlining, race detector] -v -> verbose EOF if [[ "$(type -t _usage_run)" = "function" ]]; then _usage_run ; fi } _main() { if [[ -z "$1" ]]; then _usage; return 1; fi local x local zforce local zargs=() local zverbose=() local zbenchflags # unset zforce zargs=() zbenchflags="" OPTIND=1 while getopts ":ctmnrgpfvlzdb:" flag do case "x$flag" in 'xf') zforce=1 ;; 'xv') zverbose+=(1) ;; 'xl') zargs+=("-gcflags"); zargs+=("-l=4") ;; 'xn') zargs+=("-gcflags"); zargs+=("-m=2") ;; 'xd') zargs+=("-race") ;; 'xb') x='b'; zbenchflags=${OPTARG} ;; x\?) _usage; return 1 ;; *) x=$flag ;; esac done shift $((OPTIND-1)) # echo ">>>> _main: extra args: $@" case "x$x" in 'xt') _tests "$@" ;; 'xm') _make "$@" ;; 'xr') _release "$@" ;; 'xg') _go ;; 'xp') _prebuild "$@" ;; 'xc') _clean "$@" ;; 'xz') _analyze "$@" ;; 'xb') _bench "$@" ;; esac # unset zforce zargs zbenchflags } [ "." = `dirname $0` ] && _main "$@" ================================================ FILE: vendor/github.com/ugorji/go/codec/cbor.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. package codec import ( "math" "reflect" "time" ) const ( cborMajorUint byte = iota cborMajorNegInt cborMajorBytes cborMajorText cborMajorArray cborMajorMap cborMajorTag cborMajorOther ) const ( cborBdFalse byte = 0xf4 + iota cborBdTrue cborBdNil cborBdUndefined cborBdExt cborBdFloat16 cborBdFloat32 cborBdFloat64 ) const ( cborBdIndefiniteBytes byte = 0x5f cborBdIndefiniteString byte = 0x7f cborBdIndefiniteArray byte = 0x9f cborBdIndefiniteMap byte = 0xbf cborBdBreak byte = 0xff ) // These define some in-stream descriptors for // manual encoding e.g. when doing explicit indefinite-length const ( CborStreamBytes byte = 0x5f CborStreamString byte = 0x7f CborStreamArray byte = 0x9f CborStreamMap byte = 0xbf CborStreamBreak byte = 0xff ) const ( cborBaseUint byte = 0x00 cborBaseNegInt byte = 0x20 cborBaseBytes byte = 0x40 cborBaseString byte = 0x60 cborBaseArray byte = 0x80 cborBaseMap byte = 0xa0 cborBaseTag byte = 0xc0 cborBaseSimple byte = 0xe0 ) func cbordesc(bd byte) string { switch bd { case cborBdNil: return "nil" case cborBdFalse: return "false" case cborBdTrue: return "true" case cborBdFloat16, cborBdFloat32, cborBdFloat64: return "float" case cborBdIndefiniteBytes: return "bytes*" case cborBdIndefiniteString: return "string*" case cborBdIndefiniteArray: return "array*" case cborBdIndefiniteMap: return "map*" default: switch { case bd >= cborBaseUint && bd < cborBaseNegInt: return "(u)int" case bd >= cborBaseNegInt && bd < cborBaseBytes: return "int" case bd >= cborBaseBytes && bd < cborBaseString: return "bytes" case bd >= cborBaseString && bd < cborBaseArray: return "string" case bd >= cborBaseArray && bd < cborBaseMap: return "array" case bd >= cborBaseMap && bd < cborBaseTag: return "map" case bd >= cborBaseTag && bd < cborBaseSimple: return "ext" default: return "unknown" } } } // ------------------- type cborEncDriver struct { noBuiltInTypes encDriverNoopContainerWriter e *Encoder w *encWriterSwitch h *CborHandle x [8]byte // _ [3]uint64 // padding } func (e *cborEncDriver) EncodeNil() { e.w.writen1(cborBdNil) } func (e *cborEncDriver) EncodeBool(b bool) { if b { e.w.writen1(cborBdTrue) } else { e.w.writen1(cborBdFalse) } } func (e *cborEncDriver) EncodeFloat32(f float32) { e.w.writen1(cborBdFloat32) bigenHelper{e.x[:4], e.w}.writeUint32(math.Float32bits(f)) } func (e *cborEncDriver) EncodeFloat64(f float64) { e.w.writen1(cborBdFloat64) bigenHelper{e.x[:8], e.w}.writeUint64(math.Float64bits(f)) } func (e *cborEncDriver) encUint(v uint64, bd byte) { if v <= 0x17 { e.w.writen1(byte(v) + bd) } else if v <= math.MaxUint8 { e.w.writen2(bd+0x18, uint8(v)) } else if v <= math.MaxUint16 { e.w.writen1(bd + 0x19) bigenHelper{e.x[:2], e.w}.writeUint16(uint16(v)) } else if v <= math.MaxUint32 { e.w.writen1(bd + 0x1a) bigenHelper{e.x[:4], e.w}.writeUint32(uint32(v)) } else { // if v <= math.MaxUint64 { e.w.writen1(bd + 0x1b) bigenHelper{e.x[:8], e.w}.writeUint64(v) } } func (e *cborEncDriver) EncodeInt(v int64) { if v < 0 { e.encUint(uint64(-1-v), cborBaseNegInt) } else { e.encUint(uint64(v), cborBaseUint) } } func (e *cborEncDriver) EncodeUint(v uint64) { e.encUint(v, cborBaseUint) } func (e *cborEncDriver) encLen(bd byte, length int) { e.encUint(uint64(length), bd) } func (e *cborEncDriver) EncodeTime(t time.Time) { if t.IsZero() { e.EncodeNil() } else if e.h.TimeRFC3339 { e.encUint(0, cborBaseTag) e.EncodeStringEnc(cUTF8, t.Format(time.RFC3339Nano)) } else { e.encUint(1, cborBaseTag) t = t.UTC().Round(time.Microsecond) sec, nsec := t.Unix(), uint64(t.Nanosecond()) if nsec == 0 { e.EncodeInt(sec) } else { e.EncodeFloat64(float64(sec) + float64(nsec)/1e9) } } } func (e *cborEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext, en *Encoder) { e.encUint(uint64(xtag), cborBaseTag) if v := ext.ConvertExt(rv); v == nil { e.EncodeNil() } else { en.encode(v) } } func (e *cborEncDriver) EncodeRawExt(re *RawExt, en *Encoder) { e.encUint(uint64(re.Tag), cborBaseTag) // only encodes re.Value (never re.Data) // if false && re.Data != nil { // en.encode(re.Data) // } else if re.Value != nil { if re.Value != nil { en.encode(re.Value) } else { e.EncodeNil() } } func (e *cborEncDriver) WriteArrayStart(length int) { if e.h.IndefiniteLength { e.w.writen1(cborBdIndefiniteArray) } else { e.encLen(cborBaseArray, length) } } func (e *cborEncDriver) WriteMapStart(length int) { if e.h.IndefiniteLength { e.w.writen1(cborBdIndefiniteMap) } else { e.encLen(cborBaseMap, length) } } func (e *cborEncDriver) WriteMapEnd() { if e.h.IndefiniteLength { e.w.writen1(cborBdBreak) } } func (e *cborEncDriver) WriteArrayEnd() { if e.h.IndefiniteLength { e.w.writen1(cborBdBreak) } } func (e *cborEncDriver) EncodeStringEnc(c charEncoding, v string) { e.encStringBytesS(cborBaseString, v) } func (e *cborEncDriver) EncodeStringBytesRaw(v []byte) { if v == nil { e.EncodeNil() } else { e.encStringBytesS(cborBaseBytes, stringView(v)) } } func (e *cborEncDriver) encStringBytesS(bb byte, v string) { if e.h.IndefiniteLength { if bb == cborBaseBytes { e.w.writen1(cborBdIndefiniteBytes) } else { e.w.writen1(cborBdIndefiniteString) } var vlen uint = uint(len(v)) blen := vlen / 4 if blen == 0 { blen = 64 } else if blen > 1024 { blen = 1024 } for i := uint(0); i < vlen; { var v2 string i2 := i + blen if i2 < vlen { v2 = v[i:i2] } else { v2 = v[i:] } e.encLen(bb, len(v2)) e.w.writestr(v2) i = i2 } e.w.writen1(cborBdBreak) } else { e.encLen(bb, len(v)) e.w.writestr(v) } } // ---------------------- type cborDecDriver struct { d *Decoder h *CborHandle r *decReaderSwitch br bool // bytes reader bdRead bool bd byte noBuiltInTypes // decNoSeparator decDriverNoopContainerReader // _ [3]uint64 // padding } func (d *cborDecDriver) readNextBd() { d.bd = d.r.readn1() d.bdRead = true } func (d *cborDecDriver) uncacheRead() { if d.bdRead { d.r.unreadn1() d.bdRead = false } } func (d *cborDecDriver) ContainerType() (vt valueType) { if !d.bdRead { d.readNextBd() } if d.bd == cborBdNil { return valueTypeNil } else if d.bd == cborBdIndefiniteBytes || (d.bd >= cborBaseBytes && d.bd < cborBaseString) { return valueTypeBytes } else if d.bd == cborBdIndefiniteString || (d.bd >= cborBaseString && d.bd < cborBaseArray) { return valueTypeString } else if d.bd == cborBdIndefiniteArray || (d.bd >= cborBaseArray && d.bd < cborBaseMap) { return valueTypeArray } else if d.bd == cborBdIndefiniteMap || (d.bd >= cborBaseMap && d.bd < cborBaseTag) { return valueTypeMap } // else { // d.d.errorf("isContainerType: unsupported parameter: %v", vt) // } return valueTypeUnset } func (d *cborDecDriver) TryDecodeAsNil() bool { if !d.bdRead { d.readNextBd() } // treat Nil and Undefined as nil values if d.bd == cborBdNil || d.bd == cborBdUndefined { d.bdRead = false return true } return false } func (d *cborDecDriver) CheckBreak() bool { if !d.bdRead { d.readNextBd() } if d.bd == cborBdBreak { d.bdRead = false return true } return false } func (d *cborDecDriver) decUint() (ui uint64) { v := d.bd & 0x1f if v <= 0x17 { ui = uint64(v) } else { if v == 0x18 { ui = uint64(d.r.readn1()) } else if v == 0x19 { ui = uint64(bigen.Uint16(d.r.readx(2))) } else if v == 0x1a { ui = uint64(bigen.Uint32(d.r.readx(4))) } else if v == 0x1b { ui = uint64(bigen.Uint64(d.r.readx(8))) } else { d.d.errorf("invalid descriptor decoding uint: %x/%s", d.bd, cbordesc(d.bd)) return } } return } func (d *cborDecDriver) decCheckInteger() (neg bool) { if !d.bdRead { d.readNextBd() } major := d.bd >> 5 if major == cborMajorUint { } else if major == cborMajorNegInt { neg = true } else { d.d.errorf("not an integer - invalid major %v from descriptor %x/%s", major, d.bd, cbordesc(d.bd)) return } return } func (d *cborDecDriver) DecodeInt64() (i int64) { neg := d.decCheckInteger() ui := d.decUint() // check if this number can be converted to an int without overflow if neg { i = -(chkOvf.SignedIntV(ui + 1)) } else { i = chkOvf.SignedIntV(ui) } d.bdRead = false return } func (d *cborDecDriver) DecodeUint64() (ui uint64) { if d.decCheckInteger() { d.d.errorf("assigning negative signed value to unsigned type") return } ui = d.decUint() d.bdRead = false return } func (d *cborDecDriver) DecodeFloat64() (f float64) { if !d.bdRead { d.readNextBd() } if bd := d.bd; bd == cborBdFloat16 { f = float64(math.Float32frombits(halfFloatToFloatBits(bigen.Uint16(d.r.readx(2))))) } else if bd == cborBdFloat32 { f = float64(math.Float32frombits(bigen.Uint32(d.r.readx(4)))) } else if bd == cborBdFloat64 { f = math.Float64frombits(bigen.Uint64(d.r.readx(8))) } else if bd >= cborBaseUint && bd < cborBaseBytes { f = float64(d.DecodeInt64()) } else { d.d.errorf("float only valid from float16/32/64 - invalid descriptor %x/%s", bd, cbordesc(bd)) return } d.bdRead = false return } // bool can be decoded from bool only (single byte). func (d *cborDecDriver) DecodeBool() (b bool) { if !d.bdRead { d.readNextBd() } if bd := d.bd; bd == cborBdTrue { b = true } else if bd == cborBdFalse { } else { d.d.errorf("not bool - %s %x/%s", msgBadDesc, d.bd, cbordesc(d.bd)) return } d.bdRead = false return } func (d *cborDecDriver) ReadMapStart() (length int) { if !d.bdRead { d.readNextBd() } d.bdRead = false if d.bd == cborBdIndefiniteMap { return -1 } return d.decLen() } func (d *cborDecDriver) ReadArrayStart() (length int) { if !d.bdRead { d.readNextBd() } d.bdRead = false if d.bd == cborBdIndefiniteArray { return -1 } return d.decLen() } func (d *cborDecDriver) decLen() int { return int(d.decUint()) } func (d *cborDecDriver) decAppendIndefiniteBytes(bs []byte) []byte { d.bdRead = false for { if d.CheckBreak() { break } if major := d.bd >> 5; major != cborMajorBytes && major != cborMajorText { d.d.errorf("expect bytes/string major type in indefinite string/bytes;"+ " got major %v from descriptor %x/%x", major, d.bd, cbordesc(d.bd)) return nil } n := d.decLen() oldLen := len(bs) newLen := oldLen + n if newLen > cap(bs) { bs2 := make([]byte, newLen, 2*cap(bs)+n) copy(bs2, bs) bs = bs2 } else { bs = bs[:newLen] } d.r.readb(bs[oldLen:newLen]) // bs = append(bs, d.r.readn()...) d.bdRead = false } d.bdRead = false return bs } func (d *cborDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) { if !d.bdRead { d.readNextBd() } if d.bd == cborBdNil || d.bd == cborBdUndefined { d.bdRead = false return nil } if d.bd == cborBdIndefiniteBytes || d.bd == cborBdIndefiniteString { d.bdRead = false if bs == nil { if zerocopy { return d.decAppendIndefiniteBytes(d.d.b[:0]) } return d.decAppendIndefiniteBytes(zeroByteSlice) } return d.decAppendIndefiniteBytes(bs[:0]) } // check if an "array" of uint8's (see ContainerType for how to infer if an array) if d.bd == cborBdIndefiniteArray || (d.bd >= cborBaseArray && d.bd < cborBaseMap) { bsOut, _ = fastpathTV.DecSliceUint8V(bs, true, d.d) return } clen := d.decLen() d.bdRead = false if zerocopy { if d.br { return d.r.readx(uint(clen)) } else if len(bs) == 0 { bs = d.d.b[:] } } return decByteSlice(d.r, clen, d.h.MaxInitLen, bs) } func (d *cborDecDriver) DecodeString() (s string) { return string(d.DecodeBytes(d.d.b[:], true)) } func (d *cborDecDriver) DecodeStringAsBytes() (s []byte) { return d.DecodeBytes(d.d.b[:], true) } func (d *cborDecDriver) DecodeTime() (t time.Time) { if !d.bdRead { d.readNextBd() } if d.bd == cborBdNil || d.bd == cborBdUndefined { d.bdRead = false return } xtag := d.decUint() d.bdRead = false return d.decodeTime(xtag) } func (d *cborDecDriver) decodeTime(xtag uint64) (t time.Time) { if !d.bdRead { d.readNextBd() } switch xtag { case 0: var err error if t, err = time.Parse(time.RFC3339, stringView(d.DecodeStringAsBytes())); err != nil { d.d.errorv(err) } case 1: // decode an int64 or a float, and infer time.Time from there. // for floats, round to microseconds, as that is what is guaranteed to fit well. switch { case d.bd == cborBdFloat16, d.bd == cborBdFloat32: f1, f2 := math.Modf(d.DecodeFloat64()) t = time.Unix(int64(f1), int64(f2*1e9)) case d.bd == cborBdFloat64: f1, f2 := math.Modf(d.DecodeFloat64()) t = time.Unix(int64(f1), int64(f2*1e9)) case d.bd >= cborBaseUint && d.bd < cborBaseNegInt, d.bd >= cborBaseNegInt && d.bd < cborBaseBytes: t = time.Unix(d.DecodeInt64(), 0) default: d.d.errorf("time.Time can only be decoded from a number (or RFC3339 string)") } default: d.d.errorf("invalid tag for time.Time - expecting 0 or 1, got 0x%x", xtag) } t = t.UTC().Round(time.Microsecond) return } func (d *cborDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) { if !d.bdRead { d.readNextBd() } u := d.decUint() d.bdRead = false realxtag = u if ext == nil { re := rv.(*RawExt) re.Tag = realxtag d.d.decode(&re.Value) } else if xtag != realxtag { d.d.errorf("Wrong extension tag. Got %b. Expecting: %v", realxtag, xtag) return } else { var v interface{} d.d.decode(&v) ext.UpdateExt(rv, v) } d.bdRead = false return } func (d *cborDecDriver) DecodeNaked() { if !d.bdRead { d.readNextBd() } n := d.d.naked() var decodeFurther bool switch d.bd { case cborBdNil: n.v = valueTypeNil case cborBdFalse: n.v = valueTypeBool n.b = false case cborBdTrue: n.v = valueTypeBool n.b = true case cborBdFloat16, cborBdFloat32, cborBdFloat64: n.v = valueTypeFloat n.f = d.DecodeFloat64() case cborBdIndefiniteBytes: decNakedReadRawBytes(d, d.d, n, d.h.RawToString) case cborBdIndefiniteString: n.v = valueTypeString n.s = d.DecodeString() case cborBdIndefiniteArray: n.v = valueTypeArray decodeFurther = true case cborBdIndefiniteMap: n.v = valueTypeMap decodeFurther = true default: switch { case d.bd >= cborBaseUint && d.bd < cborBaseNegInt: if d.h.SignedInteger { n.v = valueTypeInt n.i = d.DecodeInt64() } else { n.v = valueTypeUint n.u = d.DecodeUint64() } case d.bd >= cborBaseNegInt && d.bd < cborBaseBytes: n.v = valueTypeInt n.i = d.DecodeInt64() case d.bd >= cborBaseBytes && d.bd < cborBaseString: decNakedReadRawBytes(d, d.d, n, d.h.RawToString) case d.bd >= cborBaseString && d.bd < cborBaseArray: n.v = valueTypeString n.s = d.DecodeString() case d.bd >= cborBaseArray && d.bd < cborBaseMap: n.v = valueTypeArray decodeFurther = true case d.bd >= cborBaseMap && d.bd < cborBaseTag: n.v = valueTypeMap decodeFurther = true case d.bd >= cborBaseTag && d.bd < cborBaseSimple: n.v = valueTypeExt n.u = d.decUint() n.l = nil if n.u == 0 || n.u == 1 { d.bdRead = false n.v = valueTypeTime n.t = d.decodeTime(n.u) } // d.bdRead = false // d.d.decode(&re.Value) // handled by decode itself. // decodeFurther = true default: d.d.errorf("decodeNaked: Unrecognized d.bd: 0x%x", d.bd) return } } if !decodeFurther { d.bdRead = false } } // ------------------------- // CborHandle is a Handle for the CBOR encoding format, // defined at http://tools.ietf.org/html/rfc7049 and documented further at http://cbor.io . // // CBOR is comprehensively supported, including support for: // - indefinite-length arrays/maps/bytes/strings // - (extension) tags in range 0..0xffff (0 .. 65535) // - half, single and double-precision floats // - all numbers (1, 2, 4 and 8-byte signed and unsigned integers) // - nil, true, false, ... // - arrays and maps, bytes and text strings // // None of the optional extensions (with tags) defined in the spec are supported out-of-the-box. // Users can implement them as needed (using SetExt), including spec-documented ones: // - timestamp, BigNum, BigFloat, Decimals, // - Encoded Text (e.g. URL, regexp, base64, MIME Message), etc. type CborHandle struct { binaryEncodingType noElemSeparators BasicHandle // IndefiniteLength=true, means that we encode using indefinitelength IndefiniteLength bool // TimeRFC3339 says to encode time.Time using RFC3339 format. // If unset, we encode time.Time using seconds past epoch. TimeRFC3339 bool _ [1]uint64 // padding (cache-aligned) } // Name returns the name of the handle: cbor func (h *CborHandle) Name() string { return "cbor" } // SetInterfaceExt sets an extension func (h *CborHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) { return h.SetExt(rt, tag, &interfaceExtWrapper{InterfaceExt: ext}) } func (h *CborHandle) newEncDriver(e *Encoder) encDriver { return &cborEncDriver{e: e, w: e.w(), h: h} } func (h *CborHandle) newDecDriver(d *Decoder) decDriver { return &cborDecDriver{d: d, h: h, r: d.r(), br: d.bytes} } func (e *cborEncDriver) reset() { e.w = e.e.w() } func (d *cborDecDriver) reset() { d.r, d.br = d.d.r(), d.d.bytes d.bd, d.bdRead = 0, false } var _ decDriver = (*cborDecDriver)(nil) var _ encDriver = (*cborEncDriver)(nil) ================================================ FILE: vendor/github.com/ugorji/go/codec/codecgen.go ================================================ // +build codecgen generated package codec // this file is here, to set the codecgen variable to true // when the build tag codecgen is set. // // this allows us do specific things e.g. skip missing fields tests, // when running in codecgen mode. func init() { codecgen = true } ================================================ FILE: vendor/github.com/ugorji/go/codec/decode.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. package codec import ( "encoding" "errors" "fmt" "io" "reflect" "runtime" "strconv" "time" ) // Some tagging information for error messages. const ( msgBadDesc = "unrecognized descriptor byte" // msgDecCannotExpandArr = "cannot expand go array from %v to stream length: %v" ) const ( decDefMaxDepth = 1024 // maximum depth decDefSliceCap = 8 decDefChanCap = 64 // should be large, as cap cannot be expanded decScratchByteArrayLen = cacheLineSize // - 5 // + (8 * 2) // - (8 * 1) ) var ( errstrOnlyMapOrArrayCanDecodeIntoStruct = "only encoded map or array can be decoded into a struct" errstrCannotDecodeIntoNil = "cannot decode into nil" errmsgExpandSliceOverflow = "expand slice: slice overflow" errmsgExpandSliceCannotChange = "expand slice: cannot change" errDecoderNotInitialized = errors.New("Decoder not initialized") errDecUnreadByteNothingToRead = errors.New("cannot unread - nothing has been read") errDecUnreadByteLastByteNotRead = errors.New("cannot unread - last byte has not been read") errDecUnreadByteUnknown = errors.New("cannot unread - reason unknown") errMaxDepthExceeded = errors.New("maximum decoding depth exceeded") ) /* // decReader abstracts the reading source, allowing implementations that can // read from an io.Reader or directly off a byte slice with zero-copying. // // Deprecated: Use decReaderSwitch instead. type decReader interface { unreadn1() // readx will use the implementation scratch buffer if possible i.e. n < len(scratchbuf), OR // just return a view of the []byte being decoded from. // Ensure you call detachZeroCopyBytes later if this needs to be sent outside codec control. readx(n int) []byte readb([]byte) readn1() uint8 numread() uint // number of bytes read track() stopTrack() []byte // skip will skip any byte that matches, and return the first non-matching byte skip(accept *bitset256) (token byte) // readTo will read any byte that matches, stopping once no-longer matching. readTo(in []byte, accept *bitset256) (out []byte) // readUntil will read, only stopping once it matches the 'stop' byte. readUntil(in []byte, stop byte) (out []byte) } */ type decDriver interface { // this will check if the next token is a break. CheckBreak() bool // TryDecodeAsNil tries to decode as nil. // Note: TryDecodeAsNil should be careful not to share any temporary []byte with // the rest of the decDriver. This is because sometimes, we optimize by holding onto // a transient []byte, and ensuring the only other call we make to the decDriver // during that time is maybe a TryDecodeAsNil() call. TryDecodeAsNil() bool // ContainerType returns one of: Bytes, String, Nil, Slice or Map. Return unSet if not known. ContainerType() (vt valueType) // IsBuiltinType(rt uintptr) bool // DecodeNaked will decode primitives (number, bool, string, []byte) and RawExt. // For maps and arrays, it will not do the decoding in-band, but will signal // the decoder, so that is done later, by setting the decNaked.valueType field. // // Note: Numbers are decoded as int64, uint64, float64 only (no smaller sized number types). // for extensions, DecodeNaked must read the tag and the []byte if it exists. // if the []byte is not read, then kInterfaceNaked will treat it as a Handle // that stores the subsequent value in-band, and complete reading the RawExt. // // extensions should also use readx to decode them, for efficiency. // kInterface will extract the detached byte slice if it has to pass it outside its realm. DecodeNaked() DecodeInt64() (i int64) DecodeUint64() (ui uint64) DecodeFloat64() (f float64) DecodeBool() (b bool) // DecodeString can also decode symbols. // It looks redundant as DecodeBytes is available. // However, some codecs (e.g. binc) support symbols and can // return a pre-stored string value, meaning that it can bypass // the cost of []byte->string conversion. DecodeString() (s string) DecodeStringAsBytes() (v []byte) // DecodeBytes may be called directly, without going through reflection. // Consequently, it must be designed to handle possible nil. DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) // DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte) // decodeExt will decode into a *RawExt or into an extension. DecodeExt(v interface{}, xtag uint64, ext Ext) (realxtag uint64) // decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte) DecodeTime() (t time.Time) ReadArrayStart() int ReadArrayEnd() ReadMapStart() int ReadMapEnd() reset() uncacheRead() } type decDriverContainerTracker interface { ReadArrayElem() ReadMapElemKey() ReadMapElemValue() } type decodeError struct { codecError pos int } func (d decodeError) Error() string { return fmt.Sprintf("%s decode error [pos %d]: %v", d.name, d.pos, d.err) } type decDriverNoopContainerReader struct{} func (x decDriverNoopContainerReader) ReadArrayStart() (v int) { return } func (x decDriverNoopContainerReader) ReadArrayEnd() {} func (x decDriverNoopContainerReader) ReadMapStart() (v int) { return } func (x decDriverNoopContainerReader) ReadMapEnd() {} func (x decDriverNoopContainerReader) CheckBreak() (v bool) { return } // func (x decDriverNoopContainerReader) ReadArrayElem() {} // func (x decDriverNoopContainerReader) ReadMapElemKey() {} // func (x decDriverNoopContainerReader) ReadMapElemValue() {} // func (x decNoSeparator) uncacheRead() {} // DecodeOptions captures configuration options during decode. type DecodeOptions struct { // MapType specifies type to use during schema-less decoding of a map in the stream. // If nil (unset), we default to map[string]interface{} iff json handle and MapStringAsKey=true, // else map[interface{}]interface{}. MapType reflect.Type // SliceType specifies type to use during schema-less decoding of an array in the stream. // If nil (unset), we default to []interface{} for all formats. SliceType reflect.Type // MaxInitLen defines the maxinum initial length that we "make" a collection // (string, slice, map, chan). If 0 or negative, we default to a sensible value // based on the size of an element in the collection. // // For example, when decoding, a stream may say that it has 2^64 elements. // We should not auto-matically provision a slice of that size, to prevent Out-Of-Memory crash. // Instead, we provision up to MaxInitLen, fill that up, and start appending after that. MaxInitLen int // ReaderBufferSize is the size of the buffer used when reading. // // if > 0, we use a smart buffer internally for performance purposes. ReaderBufferSize int // MaxDepth defines the maximum depth when decoding nested // maps and slices. If 0 or negative, we default to a suitably large number (currently 1024). MaxDepth int16 // If ErrorIfNoField, return an error when decoding a map // from a codec stream into a struct, and no matching struct field is found. ErrorIfNoField bool // If ErrorIfNoArrayExpand, return an error when decoding a slice/array that cannot be expanded. // For example, the stream contains an array of 8 items, but you are decoding into a [4]T array, // or you are decoding into a slice of length 4 which is non-addressable (and so cannot be set). ErrorIfNoArrayExpand bool // If SignedInteger, use the int64 during schema-less decoding of unsigned values (not uint64). SignedInteger bool // MapValueReset controls how we decode into a map value. // // By default, we MAY retrieve the mapping for a key, and then decode into that. // However, especially with big maps, that retrieval may be expensive and unnecessary // if the stream already contains all that is necessary to recreate the value. // // If true, we will never retrieve the previous mapping, // but rather decode into a new value and set that in the map. // // If false, we will retrieve the previous mapping if necessary e.g. // the previous mapping is a pointer, or is a struct or array with pre-set state, // or is an interface. MapValueReset bool // SliceElementReset: on decoding a slice, reset the element to a zero value first. // // concern: if the slice already contained some garbage, we will decode into that garbage. SliceElementReset bool // InterfaceReset controls how we decode into an interface. // // By default, when we see a field that is an interface{...}, // or a map with interface{...} value, we will attempt decoding into the // "contained" value. // // However, this prevents us from reading a string into an interface{} // that formerly contained a number. // // If true, we will decode into a new "blank" value, and set that in the interface. // If false, we will decode into whatever is contained in the interface. InterfaceReset bool // InternString controls interning of strings during decoding. // // Some handles, e.g. json, typically will read map keys as strings. // If the set of keys are finite, it may help reduce allocation to // look them up from a map (than to allocate them afresh). // // Note: Handles will be smart when using the intern functionality. // Every string should not be interned. // An excellent use-case for interning is struct field names, // or map keys where key type is string. InternString bool // PreferArrayOverSlice controls whether to decode to an array or a slice. // // This only impacts decoding into a nil interface{}. // Consequently, it has no effect on codecgen. // // *Note*: This only applies if using go1.5 and above, // as it requires reflect.ArrayOf support which was absent before go1.5. PreferArrayOverSlice bool // DeleteOnNilMapValue controls how to decode a nil value in the stream. // // If true, we will delete the mapping of the key. // Else, just set the mapping to the zero value of the type. DeleteOnNilMapValue bool // RawToString controls how raw bytes in a stream are decoded into a nil interface{}. // By default, they are decoded as []byte, but can be decoded as string (if configured). RawToString bool } // ------------------------------------------------ type unreadByteStatus uint8 // unreadByteStatus goes from // undefined (when initialized) -- (read) --> canUnread -- (unread) --> canRead ... const ( unreadByteUndefined unreadByteStatus = iota unreadByteCanRead unreadByteCanUnread ) type ioDecReaderCommon struct { r io.Reader // the reader passed in n uint // num read l byte // last byte ls unreadByteStatus // last byte status trb bool // tracking bytes turned on _ bool b [4]byte // tiny buffer for reading single bytes tr []byte // tracking bytes read } func (z *ioDecReaderCommon) reset(r io.Reader) { z.r = r z.ls = unreadByteUndefined z.l, z.n = 0, 0 z.trb = false if z.tr != nil { z.tr = z.tr[:0] } } func (z *ioDecReaderCommon) numread() uint { return z.n } func (z *ioDecReaderCommon) track() { if z.tr != nil { z.tr = z.tr[:0] } z.trb = true } func (z *ioDecReaderCommon) stopTrack() (bs []byte) { z.trb = false return z.tr } // ------------------------------------------ // ioDecReader is a decReader that reads off an io.Reader. // // It also has a fallback implementation of ByteScanner if needed. type ioDecReader struct { ioDecReaderCommon rr io.Reader br io.ByteScanner x [scratchByteArrayLen + 8]byte // for: get struct field name, swallow valueTypeBytes, etc // _ [1]uint64 // padding } func (z *ioDecReader) reset(r io.Reader) { z.ioDecReaderCommon.reset(r) var ok bool z.rr = r z.br, ok = r.(io.ByteScanner) if !ok { z.br = z z.rr = z } } func (z *ioDecReader) Read(p []byte) (n int, err error) { if len(p) == 0 { return } var firstByte bool if z.ls == unreadByteCanRead { z.ls = unreadByteCanUnread p[0] = z.l if len(p) == 1 { n = 1 return } firstByte = true p = p[1:] } n, err = z.r.Read(p) if n > 0 { if err == io.EOF && n == len(p) { err = nil // read was successful, so postpone EOF (till next time) } z.l = p[n-1] z.ls = unreadByteCanUnread } if firstByte { n++ } return } func (z *ioDecReader) ReadByte() (c byte, err error) { n, err := z.Read(z.b[:1]) if n == 1 { c = z.b[0] if err == io.EOF { err = nil // read was successful, so postpone EOF (till next time) } } return } func (z *ioDecReader) UnreadByte() (err error) { switch z.ls { case unreadByteCanUnread: z.ls = unreadByteCanRead case unreadByteCanRead: err = errDecUnreadByteLastByteNotRead case unreadByteUndefined: err = errDecUnreadByteNothingToRead default: err = errDecUnreadByteUnknown } return } func (z *ioDecReader) readx(n uint) (bs []byte) { if n == 0 { return } if n < uint(len(z.x)) { bs = z.x[:n] } else { bs = make([]byte, n) } if _, err := decReadFull(z.rr, bs); err != nil { panic(err) } z.n += uint(len(bs)) if z.trb { z.tr = append(z.tr, bs...) } return } func (z *ioDecReader) readb(bs []byte) { if len(bs) == 0 { return } if _, err := decReadFull(z.rr, bs); err != nil { panic(err) } z.n += uint(len(bs)) if z.trb { z.tr = append(z.tr, bs...) } } func (z *ioDecReader) readn1eof() (b uint8, eof bool) { b, err := z.br.ReadByte() if err == nil { z.n++ if z.trb { z.tr = append(z.tr, b) } } else if err == io.EOF { eof = true } else { panic(err) } return } func (z *ioDecReader) readn1() (b uint8) { b, err := z.br.ReadByte() if err == nil { z.n++ if z.trb { z.tr = append(z.tr, b) } return } panic(err) } func (z *ioDecReader) skip(accept *bitset256) (token byte) { var eof bool // for { // token, eof = z.readn1eof() // if eof { // return // } // if accept.isset(token) { // continue // } // return // } LOOP: token, eof = z.readn1eof() if eof { return } if accept.isset(token) { goto LOOP } return } func (z *ioDecReader) readTo(in []byte, accept *bitset256) []byte { // out = in // for { // token, eof := z.readn1eof() // if eof { // return // } // if accept.isset(token) { // out = append(out, token) // } else { // z.unreadn1() // return // } // } LOOP: token, eof := z.readn1eof() if eof { return in } if accept.isset(token) { // out = append(out, token) in = append(in, token) goto LOOP } z.unreadn1() return in } func (z *ioDecReader) readUntil(in []byte, stop byte) (out []byte) { out = in // for { // token, eof := z.readn1eof() // if eof { // panic(io.EOF) // } // out = append(out, token) // if token == stop { // return // } // } LOOP: token, eof := z.readn1eof() if eof { panic(io.EOF) } out = append(out, token) if token == stop { return } goto LOOP } //go:noinline func (z *ioDecReader) unreadn1() { err := z.br.UnreadByte() if err != nil { panic(err) } z.n-- if z.trb { if l := len(z.tr) - 1; l >= 0 { z.tr = z.tr[:l] } } } // ------------------------------------ type bufioDecReader struct { ioDecReaderCommon _ uint64 // padding (cache-aligned) c uint // cursor buf []byte bytesBufPooler // err error // Extensions can call Decode() within a current Decode() call. // We need to know when the top level Decode() call returns, // so we can decide whether to Release() or not. calls uint16 // what depth in mustDecode are we in now. _ [6]uint8 // padding } func (z *bufioDecReader) reset(r io.Reader, bufsize int) { z.ioDecReaderCommon.reset(r) z.c = 0 z.calls = 0 if cap(z.buf) >= bufsize { z.buf = z.buf[:0] } else { z.buf = z.bytesBufPooler.get(bufsize)[:0] // z.buf = make([]byte, 0, bufsize) } } func (z *bufioDecReader) release() { z.buf = nil z.bytesBufPooler.end() } func (z *bufioDecReader) readb(p []byte) { var n = uint(copy(p, z.buf[z.c:])) z.n += n z.c += n if len(p) == int(n) { if z.trb { z.tr = append(z.tr, p...) // cost=9 } } else { z.readbFill(p, n) } } //go:noinline - fallback when z.buf is consumed func (z *bufioDecReader) readbFill(p0 []byte, n uint) { // at this point, there's nothing in z.buf to read (z.buf is fully consumed) p := p0[n:] var n2 uint var err error if len(p) > cap(z.buf) { n2, err = decReadFull(z.r, p) if err != nil { panic(err) } n += n2 z.n += n2 // always keep last byte in z.buf z.buf = z.buf[:1] z.buf[0] = p[len(p)-1] z.c = 1 if z.trb { z.tr = append(z.tr, p0[:n]...) } return } // z.c is now 0, and len(p) <= cap(z.buf) LOOP: // for len(p) > 0 && z.err == nil { if len(p) > 0 { z.buf = z.buf[0:cap(z.buf)] var n1 int n1, err = z.r.Read(z.buf) n2 = uint(n1) if n2 == 0 && err != nil { panic(err) } z.buf = z.buf[:n2] n2 = uint(copy(p, z.buf)) z.c = n2 n += n2 z.n += n2 p = p[n2:] goto LOOP } if z.c == 0 { z.buf = z.buf[:1] z.buf[0] = p[len(p)-1] z.c = 1 } if z.trb { z.tr = append(z.tr, p0[:n]...) } } func (z *bufioDecReader) readn1() (b byte) { // fast-path, so we elide calling into Read() most of the time if z.c < uint(len(z.buf)) { b = z.buf[z.c] z.c++ z.n++ if z.trb { z.tr = append(z.tr, b) } } else { // meaning z.c == len(z.buf) or greater ... so need to fill z.readbFill(z.b[:1], 0) b = z.b[0] } return } func (z *bufioDecReader) unreadn1() { if z.c == 0 { panic(errDecUnreadByteNothingToRead) } z.c-- z.n-- if z.trb { z.tr = z.tr[:len(z.tr)-1] } } func (z *bufioDecReader) readx(n uint) (bs []byte) { if n == 0 { // return } else if z.c+n <= uint(len(z.buf)) { bs = z.buf[z.c : z.c+n] z.n += n z.c += n if z.trb { z.tr = append(z.tr, bs...) } } else { bs = make([]byte, n) // n no longer used - can reuse n = uint(copy(bs, z.buf[z.c:])) z.n += n z.c += n z.readbFill(bs, n) } return } //go:noinline - track called by Decoder.nextValueBytes() (called by jsonUnmarshal,rawBytes) func (z *bufioDecReader) doTrack(y uint) { z.tr = append(z.tr, z.buf[z.c:y]...) // cost=14??? } func (z *bufioDecReader) skipLoopFn(i uint) { z.n += (i - z.c) - 1 i++ if z.trb { // z.tr = append(z.tr, z.buf[z.c:i]...) z.doTrack(i) } z.c = i } func (z *bufioDecReader) skip(accept *bitset256) (token byte) { // token, _ = z.search(nil, accept, 0, 1); return // for i := z.c; i < len(z.buf); i++ { // if token = z.buf[i]; !accept.isset(token) { // z.skipLoopFn(i) // return // } // } i := z.c LOOP: if i < uint(len(z.buf)) { // inline z.skipLoopFn(i) and refactor, so cost is within inline budget token = z.buf[i] i++ if accept.isset(token) { goto LOOP } z.n += i - 2 - z.c if z.trb { z.doTrack(i) } z.c = i return } return z.skipFill(accept) } func (z *bufioDecReader) skipFill(accept *bitset256) (token byte) { z.n += uint(len(z.buf)) - z.c if z.trb { z.tr = append(z.tr, z.buf[z.c:]...) } var n2 int var err error for { z.c = 0 z.buf = z.buf[0:cap(z.buf)] n2, err = z.r.Read(z.buf) if n2 == 0 && err != nil { panic(err) } z.buf = z.buf[:n2] var i int for i, token = range z.buf { if !accept.isset(token) { z.skipLoopFn(uint(i)) return } } // for i := 0; i < n2; i++ { // if token = z.buf[i]; !accept.isset(token) { // z.skipLoopFn(i) // return // } // } z.n += uint(n2) if z.trb { z.tr = append(z.tr, z.buf...) } } } func (z *bufioDecReader) readToLoopFn(i uint, out0 []byte) (out []byte) { // out0 is never nil z.n += (i - z.c) - 1 out = append(out0, z.buf[z.c:i]...) if z.trb { z.doTrack(i) } z.c = i return } func (z *bufioDecReader) readTo(in []byte, accept *bitset256) (out []byte) { // _, out = z.search(in, accept, 0, 2); return // for i := z.c; i < len(z.buf); i++ { // if !accept.isset(z.buf[i]) { // return z.readToLoopFn(i, nil) // } // } i := z.c LOOP: if i < uint(len(z.buf)) { if !accept.isset(z.buf[i]) { // return z.readToLoopFn(i, nil) // inline readToLoopFn here (for performance) z.n += (i - z.c) - 1 out = z.buf[z.c:i] if z.trb { z.doTrack(i) } z.c = i return } i++ goto LOOP } return z.readToFill(in, accept) } func (z *bufioDecReader) readToFill(in []byte, accept *bitset256) (out []byte) { z.n += uint(len(z.buf)) - z.c out = append(in, z.buf[z.c:]...) if z.trb { z.tr = append(z.tr, z.buf[z.c:]...) } var n2 int var err error for { z.c = 0 z.buf = z.buf[0:cap(z.buf)] n2, err = z.r.Read(z.buf) if n2 == 0 && err != nil { if err == io.EOF { return // readTo should read until it matches or end is reached } panic(err) } z.buf = z.buf[:n2] for i, token := range z.buf { if !accept.isset(token) { return z.readToLoopFn(uint(i), out) } } // for i := 0; i < n2; i++ { // if !accept.isset(z.buf[i]) { // return z.readToLoopFn(i, out) // } // } out = append(out, z.buf...) z.n += uint(n2) if z.trb { z.tr = append(z.tr, z.buf...) } } } func (z *bufioDecReader) readUntilLoopFn(i uint, out0 []byte) (out []byte) { z.n += (i - z.c) - 1 i++ out = append(out0, z.buf[z.c:i]...) if z.trb { // z.tr = append(z.tr, z.buf[z.c:i]...) z.doTrack(i) } z.c = i return } func (z *bufioDecReader) readUntil(in []byte, stop byte) (out []byte) { // _, out = z.search(in, nil, stop, 4); return // for i := z.c; i < len(z.buf); i++ { // if z.buf[i] == stop { // return z.readUntilLoopFn(i, nil) // } // } i := z.c LOOP: if i < uint(len(z.buf)) { if z.buf[i] == stop { // inline readUntilLoopFn // return z.readUntilLoopFn(i, nil) z.n += (i - z.c) - 1 i++ out = z.buf[z.c:i] if z.trb { z.doTrack(i) } z.c = i return } i++ goto LOOP } return z.readUntilFill(in, stop) } func (z *bufioDecReader) readUntilFill(in []byte, stop byte) (out []byte) { z.n += uint(len(z.buf)) - z.c out = append(in, z.buf[z.c:]...) if z.trb { z.tr = append(z.tr, z.buf[z.c:]...) } var n1 int var n2 uint var err error for { z.c = 0 z.buf = z.buf[0:cap(z.buf)] n1, err = z.r.Read(z.buf) n2 = uint(n1) if n2 == 0 && err != nil { panic(err) } z.buf = z.buf[:n2] for i, token := range z.buf { if token == stop { return z.readUntilLoopFn(uint(i), out) } } // for i := 0; i < n2; i++ { // if z.buf[i] == stop { // return z.readUntilLoopFn(i, out) // } // } out = append(out, z.buf...) z.n += n2 if z.trb { z.tr = append(z.tr, z.buf...) } } } // ------------------------------------ var errBytesDecReaderCannotUnread = errors.New("cannot unread last byte read") // bytesDecReader is a decReader that reads off a byte slice with zero copying type bytesDecReader struct { b []byte // data c uint // cursor t uint // track start // a int // available } func (z *bytesDecReader) reset(in []byte) { z.b = in // z.a = len(in) z.c = 0 z.t = 0 } func (z *bytesDecReader) numread() uint { return z.c } func (z *bytesDecReader) unreadn1() { if z.c == 0 || len(z.b) == 0 { panic(errBytesDecReaderCannotUnread) } z.c-- // z.a++ } func (z *bytesDecReader) readx(n uint) (bs []byte) { // slicing from a non-constant start position is more expensive, // as more computation is required to decipher the pointer start position. // However, we do it only once, and it's better than reslicing both z.b and return value. // if n <= 0 { // } else if z.a == 0 { // panic(io.EOF) // } else if n > z.a { // panic(io.ErrUnexpectedEOF) // } else { // c0 := z.c // z.c = c0 + n // z.a = z.a - n // bs = z.b[c0:z.c] // } // return if n != 0 { z.c += n if z.c > uint(len(z.b)) { z.c = uint(len(z.b)) panic(io.EOF) } bs = z.b[z.c-n : z.c] } return // if n == 0 { // } else if z.c+n > uint(len(z.b)) { // z.c = uint(len(z.b)) // panic(io.EOF) // } else { // z.c += n // bs = z.b[z.c-n : z.c] // } // return // if n == 0 { // return // } // if z.c == uint(len(z.b)) { // panic(io.EOF) // } // if z.c+n > uint(len(z.b)) { // panic(io.ErrUnexpectedEOF) // } // // z.a -= n // z.c += n // return z.b[z.c-n : z.c] } func (z *bytesDecReader) readb(bs []byte) { copy(bs, z.readx(uint(len(bs)))) } func (z *bytesDecReader) readn1() (v uint8) { if z.c == uint(len(z.b)) { panic(io.EOF) } v = z.b[z.c] z.c++ // z.a-- return } // func (z *bytesDecReader) readn1eof() (v uint8, eof bool) { // if z.a == 0 { // eof = true // return // } // v = z.b[z.c] // z.c++ // z.a-- // return // } func (z *bytesDecReader) skip(accept *bitset256) (token byte) { i := z.c // if i == len(z.b) { // goto END // // panic(io.EOF) // } // Replace loop with goto construct, so that this can be inlined // for i := z.c; i < blen; i++ { // if !accept.isset(z.b[i]) { // token = z.b[i] // i++ // z.a -= (i - z.c) // z.c = i // return // } // } // i := z.c LOOP: if i < uint(len(z.b)) { token = z.b[i] i++ if accept.isset(token) { goto LOOP } // z.a -= (i - z.c) z.c = i return } // END: panic(io.EOF) // // z.a = 0 // z.c = blen // return } func (z *bytesDecReader) readTo(_ []byte, accept *bitset256) (out []byte) { return z.readToNoInput(accept) } func (z *bytesDecReader) readToNoInput(accept *bitset256) (out []byte) { i := z.c if i == uint(len(z.b)) { panic(io.EOF) } // Replace loop with goto construct, so that this can be inlined // for i := z.c; i < blen; i++ { // if !accept.isset(z.b[i]) { // out = z.b[z.c:i] // z.a -= (i - z.c) // z.c = i // return // } // } // out = z.b[z.c:] // z.a, z.c = 0, blen // return // i := z.c // LOOP: // if i < blen { // if accept.isset(z.b[i]) { // i++ // goto LOOP // } // out = z.b[z.c:i] // z.a -= (i - z.c) // z.c = i // return // } // out = z.b[z.c:] // // z.a, z.c = 0, blen // z.a = 0 // z.c = blen // return // c := i LOOP: if i < uint(len(z.b)) { if accept.isset(z.b[i]) { i++ goto LOOP } } out = z.b[z.c:i] // z.a -= (i - z.c) z.c = i return // z.b[c:i] // z.c, i = i, z.c // return z.b[i:z.c] } func (z *bytesDecReader) readUntil(_ []byte, stop byte) (out []byte) { return z.readUntilNoInput(stop) } func (z *bytesDecReader) readUntilNoInput(stop byte) (out []byte) { i := z.c // if i == len(z.b) { // panic(io.EOF) // } // Replace loop with goto construct, so that this can be inlined // for i := z.c; i < blen; i++ { // if z.b[i] == stop { // i++ // out = z.b[z.c:i] // z.a -= (i - z.c) // z.c = i // return // } // } LOOP: if i < uint(len(z.b)) { if z.b[i] == stop { i++ out = z.b[z.c:i] // z.a -= (i - z.c) z.c = i return } i++ goto LOOP } // z.a = 0 // z.c = blen panic(io.EOF) } func (z *bytesDecReader) track() { z.t = z.c } func (z *bytesDecReader) stopTrack() (bs []byte) { return z.b[z.t:z.c] } // ---------------------------------------- // func (d *Decoder) builtin(f *codecFnInfo, rv reflect.Value) { // d.d.DecodeBuiltin(f.ti.rtid, rv2i(rv)) // } func (d *Decoder) rawExt(f *codecFnInfo, rv reflect.Value) { d.d.DecodeExt(rv2i(rv), 0, nil) } func (d *Decoder) ext(f *codecFnInfo, rv reflect.Value) { d.d.DecodeExt(rv2i(rv), f.xfTag, f.xfFn) } func (d *Decoder) selferUnmarshal(f *codecFnInfo, rv reflect.Value) { rv2i(rv).(Selfer).CodecDecodeSelf(d) } func (d *Decoder) binaryUnmarshal(f *codecFnInfo, rv reflect.Value) { bm := rv2i(rv).(encoding.BinaryUnmarshaler) xbs := d.d.DecodeBytes(nil, true) if fnerr := bm.UnmarshalBinary(xbs); fnerr != nil { panic(fnerr) } } func (d *Decoder) textUnmarshal(f *codecFnInfo, rv reflect.Value) { tm := rv2i(rv).(encoding.TextUnmarshaler) fnerr := tm.UnmarshalText(d.d.DecodeStringAsBytes()) if fnerr != nil { panic(fnerr) } } func (d *Decoder) jsonUnmarshal(f *codecFnInfo, rv reflect.Value) { tm := rv2i(rv).(jsonUnmarshaler) // bs := d.d.DecodeBytes(d.b[:], true, true) // grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself. fnerr := tm.UnmarshalJSON(d.nextValueBytes()) if fnerr != nil { panic(fnerr) } } func (d *Decoder) kErr(f *codecFnInfo, rv reflect.Value) { d.errorf("no decoding function defined for kind %v", rv.Kind()) } // var kIntfCtr uint64 func (d *Decoder) kInterfaceNaked(f *codecFnInfo) (rvn reflect.Value) { // nil interface: // use some hieristics to decode it appropriately // based on the detected next value in the stream. n := d.naked() d.d.DecodeNaked() if n.v == valueTypeNil { return } // We cannot decode non-nil stream value into nil interface with methods (e.g. io.Reader). if f.ti.numMeth > 0 { d.errorf("cannot decode non-nil codec value into nil %v (%v methods)", f.ti.rt, f.ti.numMeth) return } // var useRvn bool switch n.v { case valueTypeMap: // if json, default to a map type with string keys mtid := d.mtid if mtid == 0 { if d.jsms { mtid = mapStrIntfTypId } else { mtid = mapIntfIntfTypId } } if mtid == mapIntfIntfTypId { var v2 map[interface{}]interface{} d.decode(&v2) rvn = reflect.ValueOf(&v2).Elem() } else if mtid == mapStrIntfTypId { // for json performance var v2 map[string]interface{} d.decode(&v2) rvn = reflect.ValueOf(&v2).Elem() } else { if d.mtr { rvn = reflect.New(d.h.MapType) d.decode(rv2i(rvn)) rvn = rvn.Elem() } else { rvn = reflect.New(d.h.MapType).Elem() d.decodeValue(rvn, nil, true) } } case valueTypeArray: if d.stid == 0 || d.stid == intfSliceTypId { var v2 []interface{} d.decode(&v2) rvn = reflect.ValueOf(&v2).Elem() if reflectArrayOfSupported && d.stid == 0 && d.h.PreferArrayOverSlice { rvn2 := reflect.New(reflectArrayOf(rvn.Len(), intfTyp)).Elem() reflect.Copy(rvn2, rvn) rvn = rvn2 } } else { if d.str { rvn = reflect.New(d.h.SliceType) d.decode(rv2i(rvn)) rvn = rvn.Elem() } else { rvn = reflect.New(d.h.SliceType).Elem() d.decodeValue(rvn, nil, true) } } case valueTypeExt: var v interface{} tag, bytes := n.u, n.l // calling decode below might taint the values if bytes == nil { d.decode(&v) } bfn := d.h.getExtForTag(tag) if bfn == nil { var re RawExt re.Tag = tag re.Data = detachZeroCopyBytes(d.bytes, nil, bytes) re.Value = v rvn = reflect.ValueOf(&re).Elem() } else { rvnA := reflect.New(bfn.rt) if bytes != nil { bfn.ext.ReadExt(rv2i(rvnA), bytes) } else { bfn.ext.UpdateExt(rv2i(rvnA), v) } rvn = rvnA.Elem() } case valueTypeNil: // no-op case valueTypeInt: rvn = n.ri() case valueTypeUint: rvn = n.ru() case valueTypeFloat: rvn = n.rf() case valueTypeBool: rvn = n.rb() case valueTypeString, valueTypeSymbol: rvn = n.rs() case valueTypeBytes: rvn = n.rl() case valueTypeTime: rvn = n.rt() default: panicv.errorf("kInterfaceNaked: unexpected valueType: %d", n.v) } return } func (d *Decoder) kInterface(f *codecFnInfo, rv reflect.Value) { // Note: // A consequence of how kInterface works, is that // if an interface already contains something, we try // to decode into what was there before. // We do not replace with a generic value (as got from decodeNaked). // every interface passed here MUST be settable. var rvn reflect.Value if rv.IsNil() || d.h.InterfaceReset { // check if mapping to a type: if so, initialize it and move on rvn = d.h.intf2impl(f.ti.rtid) if rvn.IsValid() { rv.Set(rvn) } else { rvn = d.kInterfaceNaked(f) if rvn.IsValid() { rv.Set(rvn) } else if d.h.InterfaceReset { // reset to zero value based on current type in there. rv.Set(reflect.Zero(rv.Elem().Type())) } return } } else { // now we have a non-nil interface value, meaning it contains a type rvn = rv.Elem() } if d.d.TryDecodeAsNil() { rv.Set(reflect.Zero(rvn.Type())) return } // Note: interface{} is settable, but underlying type may not be. // Consequently, we MAY have to create a decodable value out of the underlying value, // decode into it, and reset the interface itself. // fmt.Printf(">>>> kInterface: rvn type: %v, rv type: %v\n", rvn.Type(), rv.Type()) rvn2, canDecode := isDecodeable(rvn) if canDecode { d.decodeValue(rvn2, nil, true) return } rvn2 = reflect.New(rvn.Type()).Elem() rvn2.Set(rvn) d.decodeValue(rvn2, nil, true) rv.Set(rvn2) } func decStructFieldKey(dd decDriver, keyType valueType, b *[decScratchByteArrayLen]byte) (rvkencname []byte) { // use if-else-if, not switch (which compiles to binary-search) // since keyType is typically valueTypeString, branch prediction is pretty good. if keyType == valueTypeString { rvkencname = dd.DecodeStringAsBytes() } else if keyType == valueTypeInt { rvkencname = strconv.AppendInt(b[:0], dd.DecodeInt64(), 10) } else if keyType == valueTypeUint { rvkencname = strconv.AppendUint(b[:0], dd.DecodeUint64(), 10) } else if keyType == valueTypeFloat { rvkencname = strconv.AppendFloat(b[:0], dd.DecodeFloat64(), 'f', -1, 64) } else { rvkencname = dd.DecodeStringAsBytes() } return rvkencname } func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) { fti := f.ti dd := d.d sfn := structFieldNode{v: rv, update: true} ctyp := dd.ContainerType() var mf MissingFielder if fti.mf { mf = rv2i(rv).(MissingFielder) } else if fti.mfp { mf = rv2i(rv.Addr()).(MissingFielder) } if ctyp == valueTypeMap { containerLen := d.mapStart() if containerLen == 0 { d.mapEnd() return } tisfi := fti.sfiSort hasLen := containerLen >= 0 var rvkencname []byte for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ { d.mapElemKey() rvkencname = decStructFieldKey(dd, fti.keyType, &d.b) d.mapElemValue() if k := fti.indexForEncName(rvkencname); k > -1 { si := tisfi[k] if dd.TryDecodeAsNil() { si.setToZeroValue(rv) } else { d.decodeValue(sfn.field(si), nil, true) } } else if mf != nil { // store rvkencname in new []byte, as it previously shares Decoder.b, which is used in decode name2 := rvkencname rvkencname = make([]byte, len(rvkencname)) copy(rvkencname, name2) var f interface{} // xdebugf("kStruct: mf != nil: before decode: rvkencname: %s", rvkencname) d.decode(&f) // xdebugf("kStruct: mf != nil: after decode: rvkencname: %s", rvkencname) if !mf.CodecMissingField(rvkencname, f) && d.h.ErrorIfNoField { d.errorf("no matching struct field found when decoding stream map with key: %s ", stringView(rvkencname)) } } else { d.structFieldNotFound(-1, stringView(rvkencname)) } // keepAlive4StringView(rvkencnameB) // not needed, as reference is outside loop } d.mapEnd() } else if ctyp == valueTypeArray { containerLen := d.arrayStart() if containerLen == 0 { d.arrayEnd() return } // Not much gain from doing it two ways for array. // Arrays are not used as much for structs. hasLen := containerLen >= 0 var checkbreak bool for j, si := range fti.sfiSrc { if hasLen && j == containerLen { break } if !hasLen && dd.CheckBreak() { checkbreak = true break } d.arrayElem() if dd.TryDecodeAsNil() { si.setToZeroValue(rv) } else { d.decodeValue(sfn.field(si), nil, true) } } if (hasLen && containerLen > len(fti.sfiSrc)) || (!hasLen && !checkbreak) { // read remaining values and throw away for j := len(fti.sfiSrc); ; j++ { if (hasLen && j == containerLen) || (!hasLen && dd.CheckBreak()) { break } d.arrayElem() d.structFieldNotFound(j, "") } } d.arrayEnd() } else { d.errorstr(errstrOnlyMapOrArrayCanDecodeIntoStruct) return } } func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) { // A slice can be set from a map or array in stream. // This way, the order can be kept (as order is lost with map). frt := f.ti.rt if f.seq == seqTypeChan && f.ti.chandir&uint8(reflect.SendDir) == 0 { d.errorf("receive-only channel cannot be decoded") } dd := d.d rtelem0 := f.ti.elem ctyp := dd.ContainerType() if ctyp == valueTypeBytes || ctyp == valueTypeString { // you can only decode bytes or string in the stream into a slice or array of bytes if !(f.ti.rtid == uint8SliceTypId || rtelem0.Kind() == reflect.Uint8) { d.errorf("bytes/string in stream must decode into slice/array of bytes, not %v", frt) } if f.seq == seqTypeChan { bs2 := dd.DecodeBytes(nil, true) irv := rv2i(rv) ch, ok := irv.(chan<- byte) if !ok { ch = irv.(chan byte) } for _, b := range bs2 { ch <- b } } else { rvbs := rv.Bytes() bs2 := dd.DecodeBytes(rvbs, false) // if rvbs == nil && bs2 != nil || rvbs != nil && bs2 == nil || len(bs2) != len(rvbs) { if !(len(bs2) > 0 && len(bs2) == len(rvbs) && &bs2[0] == &rvbs[0]) { if rv.CanSet() { rv.SetBytes(bs2) } else if len(rvbs) > 0 && len(bs2) > 0 { copy(rvbs, bs2) } } } return } // array := f.seq == seqTypeChan slh, containerLenS := d.decSliceHelperStart() // only expects valueType(Array|Map) // an array can never return a nil slice. so no need to check f.array here. if containerLenS == 0 { if rv.CanSet() { if f.seq == seqTypeSlice { if rv.IsNil() { rv.Set(reflect.MakeSlice(frt, 0, 0)) } else { rv.SetLen(0) } } else if f.seq == seqTypeChan { if rv.IsNil() { rv.Set(reflect.MakeChan(frt, 0)) } } } slh.End() return } rtelem0Size := int(rtelem0.Size()) rtElem0Kind := rtelem0.Kind() rtelem0Mut := !isImmutableKind(rtElem0Kind) rtelem := rtelem0 rtelemkind := rtelem.Kind() for rtelemkind == reflect.Ptr { rtelem = rtelem.Elem() rtelemkind = rtelem.Kind() } var fn *codecFn var rvCanset = rv.CanSet() var rvChanged bool var rv0 = rv var rv9 reflect.Value rvlen := rv.Len() rvcap := rv.Cap() hasLen := containerLenS > 0 if hasLen && f.seq == seqTypeSlice { if containerLenS > rvcap { oldRvlenGtZero := rvlen > 0 rvlen = decInferLen(containerLenS, d.h.MaxInitLen, int(rtelem0.Size())) if rvlen <= rvcap { if rvCanset { rv.SetLen(rvlen) } } else if rvCanset { rv = reflect.MakeSlice(frt, rvlen, rvlen) rvcap = rvlen rvChanged = true } else { d.errorf("cannot decode into non-settable slice") } if rvChanged && oldRvlenGtZero && !isImmutableKind(rtelem0.Kind()) { reflect.Copy(rv, rv0) // only copy up to length NOT cap i.e. rv0.Slice(0, rvcap) } } else if containerLenS != rvlen { rvlen = containerLenS if rvCanset { rv.SetLen(rvlen) } // else { // rv = rv.Slice(0, rvlen) // rvChanged = true // d.errorf("cannot decode into non-settable slice") // } } } // consider creating new element once, and just decoding into it. var rtelem0Zero reflect.Value var rtelem0ZeroValid bool var decodeAsNil bool var j int for ; (hasLen && j < containerLenS) || !(hasLen || dd.CheckBreak()); j++ { if j == 0 && (f.seq == seqTypeSlice || f.seq == seqTypeChan) && rv.IsNil() { if hasLen { rvlen = decInferLen(containerLenS, d.h.MaxInitLen, rtelem0Size) } else if f.seq == seqTypeSlice { rvlen = decDefSliceCap } else { rvlen = decDefChanCap } if rvCanset { if f.seq == seqTypeSlice { rv = reflect.MakeSlice(frt, rvlen, rvlen) rvChanged = true } else { // chan rv = reflect.MakeChan(frt, rvlen) rvChanged = true } } else { d.errorf("cannot decode into non-settable slice") } } slh.ElemContainerState(j) decodeAsNil = dd.TryDecodeAsNil() if f.seq == seqTypeChan { if decodeAsNil { rv.Send(reflect.Zero(rtelem0)) continue } if rtelem0Mut || !rv9.IsValid() { // || (rtElem0Kind == reflect.Ptr && rv9.IsNil()) { rv9 = reflect.New(rtelem0).Elem() } if fn == nil { fn = d.h.fn(rtelem, true, true) } d.decodeValue(rv9, fn, true) rv.Send(rv9) } else { // if indefinite, etc, then expand the slice if necessary var decodeIntoBlank bool if j >= rvlen { if f.seq == seqTypeArray { d.arrayCannotExpand(rvlen, j+1) decodeIntoBlank = true } else { // if f.seq == seqTypeSlice // rv = reflect.Append(rv, reflect.Zero(rtelem0)) // append logic + varargs var rvcap2 int var rvErrmsg2 string rv9, rvcap2, rvChanged, rvErrmsg2 = expandSliceRV(rv, frt, rvCanset, rtelem0Size, 1, rvlen, rvcap) if rvErrmsg2 != "" { d.errorf(rvErrmsg2) } rvlen++ if rvChanged { rv = rv9 rvcap = rvcap2 } } } if decodeIntoBlank { if !decodeAsNil { d.swallow() } } else { rv9 = rv.Index(j) if d.h.SliceElementReset || decodeAsNil { if !rtelem0ZeroValid { rtelem0ZeroValid = true rtelem0Zero = reflect.Zero(rtelem0) } rv9.Set(rtelem0Zero) if decodeAsNil { continue } } if fn == nil { fn = d.h.fn(rtelem, true, true) } d.decodeValue(rv9, fn, true) } } } if f.seq == seqTypeSlice { if j < rvlen { if rv.CanSet() { rv.SetLen(j) } else if rvCanset { rv = rv.Slice(0, j) rvChanged = true } // else { d.errorf("kSlice: cannot change non-settable slice") } rvlen = j } else if j == 0 && rv.IsNil() { if rvCanset { rv = reflect.MakeSlice(frt, 0, 0) rvChanged = true } // else { d.errorf("kSlice: cannot change non-settable slice") } } } slh.End() if rvChanged { // infers rvCanset=true, so it can be reset rv0.Set(rv) } } // func (d *Decoder) kArray(f *codecFnInfo, rv reflect.Value) { // // d.decodeValueFn(rv.Slice(0, rv.Len())) // f.kSlice(rv.Slice(0, rv.Len())) // } func (d *Decoder) kMap(f *codecFnInfo, rv reflect.Value) { dd := d.d containerLen := d.mapStart() ti := f.ti if rv.IsNil() { rvlen := decInferLen(containerLen, d.h.MaxInitLen, int(ti.key.Size()+ti.elem.Size())) rv.Set(makeMapReflect(ti.rt, rvlen)) } if containerLen == 0 { d.mapEnd() return } ktype, vtype := ti.key, ti.elem ktypeId := rt2id(ktype) vtypeKind := vtype.Kind() var keyFn, valFn *codecFn var ktypeLo, vtypeLo reflect.Type for ktypeLo = ktype; ktypeLo.Kind() == reflect.Ptr; ktypeLo = ktypeLo.Elem() { } for vtypeLo = vtype; vtypeLo.Kind() == reflect.Ptr; vtypeLo = vtypeLo.Elem() { } var mapGet, mapSet bool rvvImmut := isImmutableKind(vtypeKind) if !d.h.MapValueReset { // if pointer, mapGet = true // if interface, mapGet = true if !DecodeNakedAlways (else false) // if builtin, mapGet = false // else mapGet = true if vtypeKind == reflect.Ptr { mapGet = true } else if vtypeKind == reflect.Interface { if !d.h.InterfaceReset { mapGet = true } } else if !rvvImmut { mapGet = true } } var rvk, rvkp, rvv, rvz reflect.Value rvkMut := !isImmutableKind(ktype.Kind()) // if ktype is immutable, then re-use the same rvk. ktypeIsString := ktypeId == stringTypId ktypeIsIntf := ktypeId == intfTypId hasLen := containerLen > 0 var kstrbs []byte for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ { if rvkMut || !rvkp.IsValid() { rvkp = reflect.New(ktype) rvk = rvkp.Elem() } d.mapElemKey() // if false && dd.TryDecodeAsNil() { // nil cannot be a map key, so disregard this block // // Previously, if a nil key, we just ignored the mapped value and continued. // // However, that makes the result of encoding and then decoding map[intf]intf{nil:nil} // // to be an empty map. // // Instead, we treat a nil key as the zero value of the type. // rvk.Set(reflect.Zero(ktype)) // } else if ktypeIsString { if ktypeIsString { kstrbs = dd.DecodeStringAsBytes() rvk.SetString(stringView(kstrbs)) // NOTE: if doing an insert, you MUST use a real string (not stringview) } else { if keyFn == nil { keyFn = d.h.fn(ktypeLo, true, true) } d.decodeValue(rvk, keyFn, true) } // special case if a byte array. if ktypeIsIntf { if rvk2 := rvk.Elem(); rvk2.IsValid() { if rvk2.Type() == uint8SliceTyp { rvk = reflect.ValueOf(d.string(rvk2.Bytes())) } else { rvk = rvk2 } } } d.mapElemValue() // Brittle, but OK per TryDecodeAsNil() contract. // i.e. TryDecodeAsNil never shares slices with other decDriver procedures if dd.TryDecodeAsNil() { if ktypeIsString { rvk.SetString(d.string(kstrbs)) } if d.h.DeleteOnNilMapValue { rv.SetMapIndex(rvk, reflect.Value{}) } else { rv.SetMapIndex(rvk, reflect.Zero(vtype)) } continue } mapSet = true // set to false if u do a get, and its a non-nil pointer if mapGet { // mapGet true only in case where kind=Ptr|Interface or kind is otherwise mutable. rvv = rv.MapIndex(rvk) if !rvv.IsValid() { rvv = reflect.New(vtype).Elem() } else if vtypeKind == reflect.Ptr { if rvv.IsNil() { rvv = reflect.New(vtype).Elem() } else { mapSet = false } } else if vtypeKind == reflect.Interface { // not addressable, and thus not settable. // e MUST create a settable/addressable variant rvv2 := reflect.New(rvv.Type()).Elem() if !rvv.IsNil() { rvv2.Set(rvv) } rvv = rvv2 } // else it is ~mutable, and we can just decode into it directly } else if rvvImmut { if !rvz.IsValid() { rvz = reflect.New(vtype).Elem() } rvv = rvz } else { rvv = reflect.New(vtype).Elem() } // We MUST be done with the stringview of the key, before decoding the value // so that we don't bastardize the reused byte array. if mapSet && ktypeIsString { rvk.SetString(d.string(kstrbs)) } if valFn == nil { valFn = d.h.fn(vtypeLo, true, true) } d.decodeValue(rvv, valFn, true) // d.decodeValueFn(rvv, valFn) if mapSet { rv.SetMapIndex(rvk, rvv) } // if ktypeIsString { // // keepAlive4StringView(kstrbs) // not needed, as reference is outside loop // } } d.mapEnd() } // decNaked is used to keep track of the primitives decoded. // Without it, we would have to decode each primitive and wrap it // in an interface{}, causing an allocation. // In this model, the primitives are decoded in a "pseudo-atomic" fashion, // so we can rest assured that no other decoding happens while these // primitives are being decoded. // // maps and arrays are not handled by this mechanism. // However, RawExt is, and we accommodate for extensions that decode // RawExt from DecodeNaked, but need to decode the value subsequently. // kInterfaceNaked and swallow, which call DecodeNaked, handle this caveat. // // However, decNaked also keeps some arrays of default maps and slices // used in DecodeNaked. This way, we can get a pointer to it // without causing a new heap allocation. // // kInterfaceNaked will ensure that there is no allocation for the common // uses. type decNaked struct { // r RawExt // used for RawExt, uint, []byte. // primitives below u uint64 i int64 f float64 l []byte s string // ---- cpu cache line boundary? t time.Time b bool // state v valueType // _ [6]bool // padding // ru, ri, rf, rl, rs, rb, rt reflect.Value // mapping to the primitives above // // _ [3]uint64 // padding } // func (n *decNaked) init() { // n.ru = reflect.ValueOf(&n.u).Elem() // n.ri = reflect.ValueOf(&n.i).Elem() // n.rf = reflect.ValueOf(&n.f).Elem() // n.rl = reflect.ValueOf(&n.l).Elem() // n.rs = reflect.ValueOf(&n.s).Elem() // n.rt = reflect.ValueOf(&n.t).Elem() // n.rb = reflect.ValueOf(&n.b).Elem() // // n.rr[] = reflect.ValueOf(&n.) // } // type decNakedPooler struct { // n *decNaked // nsp *sync.Pool // } // // naked must be called before each call to .DecodeNaked, as they will use it. // func (d *decNakedPooler) naked() *decNaked { // if d.n == nil { // // consider one of: // // - get from sync.Pool (if GC is frequent, there's no value here) // // - new alloc (safest. only init'ed if it a naked decode will be done) // // - field in Decoder (makes the Decoder struct very big) // // To support using a decoder where a DecodeNaked is not needed, // // we prefer #1 or #2. // // d.n = new(decNaked) // &d.nv // new(decNaked) // grab from a sync.Pool // // d.n.init() // var v interface{} // d.nsp, v = pool.decNaked() // d.n = v.(*decNaked) // } // return d.n // } // func (d *decNakedPooler) end() { // if d.n != nil { // // if n != nil, then nsp != nil (they are always set together) // d.nsp.Put(d.n) // d.n, d.nsp = nil, nil // } // } // type rtid2rv struct { // rtid uintptr // rv reflect.Value // } // -------------- type decReaderSwitch struct { esep bool // has elem separators mtr, str bool // whether maptype or slicetype are known types be bool // is binary encoding js bool // is json handle jsms bool // is json handle, and MapKeyAsString // typ entryType bytes bool // is bytes reader bufio bool // is this a bufioDecReader? rb bytesDecReader ri *ioDecReader bi *bufioDecReader } // numread, track and stopTrack are always inlined, as they just check int fields, etc. /* func (z *decReaderSwitch) numread() int { switch z.typ { case entryTypeBytes: return z.rb.numread() case entryTypeIo: return z.ri.numread() default: return z.bi.numread() } } func (z *decReaderSwitch) track() { switch z.typ { case entryTypeBytes: z.rb.track() case entryTypeIo: z.ri.track() default: z.bi.track() } } func (z *decReaderSwitch) stopTrack() []byte { switch z.typ { case entryTypeBytes: return z.rb.stopTrack() case entryTypeIo: return z.ri.stopTrack() default: return z.bi.stopTrack() } } func (z *decReaderSwitch) unreadn1() { switch z.typ { case entryTypeBytes: z.rb.unreadn1() case entryTypeIo: z.ri.unreadn1() default: z.bi.unreadn1() } } func (z *decReaderSwitch) readx(n int) []byte { switch z.typ { case entryTypeBytes: return z.rb.readx(n) case entryTypeIo: return z.ri.readx(n) default: return z.bi.readx(n) } } func (z *decReaderSwitch) readb(s []byte) { switch z.typ { case entryTypeBytes: z.rb.readb(s) case entryTypeIo: z.ri.readb(s) default: z.bi.readb(s) } } func (z *decReaderSwitch) readn1() uint8 { switch z.typ { case entryTypeBytes: return z.rb.readn1() case entryTypeIo: return z.ri.readn1() default: return z.bi.readn1() } } func (z *decReaderSwitch) skip(accept *bitset256) (token byte) { switch z.typ { case entryTypeBytes: return z.rb.skip(accept) case entryTypeIo: return z.ri.skip(accept) default: return z.bi.skip(accept) } } func (z *decReaderSwitch) readTo(in []byte, accept *bitset256) (out []byte) { switch z.typ { case entryTypeBytes: return z.rb.readTo(in, accept) case entryTypeIo: return z.ri.readTo(in, accept) default: return z.bi.readTo(in, accept) } } func (z *decReaderSwitch) readUntil(in []byte, stop byte) (out []byte) { switch z.typ { case entryTypeBytes: return z.rb.readUntil(in, stop) case entryTypeIo: return z.ri.readUntil(in, stop) default: return z.bi.readUntil(in, stop) } } */ // the if/else-if/else block is expensive to inline. // Each node of this construct costs a lot and dominates the budget. // Best to only do an if fast-path else block (so fast-path is inlined). // This is irrespective of inlineExtraCallCost set in $GOROOT/src/cmd/compile/internal/gc/inl.go // // In decReaderSwitch methods below, we delegate all IO functions into their own methods. // This allows for the inlining of the common path when z.bytes=true. // Go 1.12+ supports inlining methods with up to 1 inlined function (or 2 if no other constructs). func (z *decReaderSwitch) numread() uint { if z.bytes { return z.rb.numread() } else if z.bufio { return z.bi.numread() } else { return z.ri.numread() } } func (z *decReaderSwitch) track() { if z.bytes { z.rb.track() } else if z.bufio { z.bi.track() } else { z.ri.track() } } func (z *decReaderSwitch) stopTrack() []byte { if z.bytes { return z.rb.stopTrack() } else if z.bufio { return z.bi.stopTrack() } else { return z.ri.stopTrack() } } // func (z *decReaderSwitch) unreadn1() { // if z.bytes { // z.rb.unreadn1() // } else { // z.unreadn1IO() // } // } // func (z *decReaderSwitch) unreadn1IO() { // if z.bufio { // z.bi.unreadn1() // } else { // z.ri.unreadn1() // } // } func (z *decReaderSwitch) unreadn1() { if z.bytes { z.rb.unreadn1() } else if z.bufio { z.bi.unreadn1() } else { z.ri.unreadn1() // not inlined } } func (z *decReaderSwitch) readx(n uint) []byte { if z.bytes { return z.rb.readx(n) } return z.readxIO(n) } func (z *decReaderSwitch) readxIO(n uint) []byte { if z.bufio { return z.bi.readx(n) } return z.ri.readx(n) } func (z *decReaderSwitch) readb(s []byte) { if z.bytes { z.rb.readb(s) } else { z.readbIO(s) } } //go:noinline - fallback for io, ensures z.bytes path is inlined func (z *decReaderSwitch) readbIO(s []byte) { if z.bufio { z.bi.readb(s) } else { z.ri.readb(s) } } func (z *decReaderSwitch) readn1() uint8 { if z.bytes { return z.rb.readn1() } return z.readn1IO() } func (z *decReaderSwitch) readn1IO() uint8 { if z.bufio { return z.bi.readn1() } return z.ri.readn1() } func (z *decReaderSwitch) skip(accept *bitset256) (token byte) { if z.bytes { return z.rb.skip(accept) } return z.skipIO(accept) } func (z *decReaderSwitch) skipIO(accept *bitset256) (token byte) { if z.bufio { return z.bi.skip(accept) } return z.ri.skip(accept) } func (z *decReaderSwitch) readTo(in []byte, accept *bitset256) (out []byte) { if z.bytes { return z.rb.readToNoInput(accept) // z.rb.readTo(in, accept) } return z.readToIO(in, accept) } //go:noinline - fallback for io, ensures z.bytes path is inlined func (z *decReaderSwitch) readToIO(in []byte, accept *bitset256) (out []byte) { if z.bufio { return z.bi.readTo(in, accept) } return z.ri.readTo(in, accept) } func (z *decReaderSwitch) readUntil(in []byte, stop byte) (out []byte) { if z.bytes { return z.rb.readUntilNoInput(stop) } return z.readUntilIO(in, stop) } func (z *decReaderSwitch) readUntilIO(in []byte, stop byte) (out []byte) { if z.bufio { return z.bi.readUntil(in, stop) } return z.ri.readUntil(in, stop) } // Decoder reads and decodes an object from an input stream in a supported format. // // Decoder is NOT safe for concurrent use i.e. a Decoder cannot be used // concurrently in multiple goroutines. // // However, as Decoder could be allocation heavy to initialize, a Reset method is provided // so its state can be reused to decode new input streams repeatedly. // This is the idiomatic way to use. type Decoder struct { panicHdl // hopefully, reduce derefencing cost by laying the decReader inside the Decoder. // Try to put things that go together to fit within a cache line (8 words). d decDriver // NOTE: Decoder shouldn't call its read methods, // as the handler MAY need to do some coordination. // r *decReaderSwitch // bi *bufioDecReader // cache the mapTypeId and sliceTypeId for faster comparisons mtid uintptr stid uintptr jdec *jsonDecDriver h *BasicHandle hh Handle // ---- cpu cache line boundary? decReaderSwitch // ---- cpu cache line boundary? n decNaked // cr containerStateRecv // _ [4]uint8 // padding is map[string]string // used for interning strings err error // ---- cpu cache line boundary? // ---- writable fields during execution --- *try* to keep in sep cache line maxdepth int16 depth int16 c containerState _ [3]byte // padding b [decScratchByteArrayLen]byte // scratch buffer, used by Decoder and xxxEncDrivers // padding - false sharing help // modify 232 if Decoder struct changes. // _ [cacheLineSize - 232%cacheLineSize]byte } // NewDecoder returns a Decoder for decoding a stream of bytes from an io.Reader. // // For efficiency, Users are encouraged to configure ReaderBufferSize on the handle // OR pass in a memory buffered reader (eg bufio.Reader, bytes.Buffer). func NewDecoder(r io.Reader, h Handle) *Decoder { d := newDecoder(h) d.Reset(r) return d } // NewDecoderBytes returns a Decoder which efficiently decodes directly // from a byte slice with zero copying. func NewDecoderBytes(in []byte, h Handle) *Decoder { d := newDecoder(h) d.ResetBytes(in) return d } // var defaultDecNaked decNaked func newDecoder(h Handle) *Decoder { d := &Decoder{h: basicHandle(h), err: errDecoderNotInitialized} d.bytes = true if useFinalizers { runtime.SetFinalizer(d, (*Decoder).finalize) // xdebugf(">>>> new(Decoder) with finalizer") } // d.r = &d.decReaderSwitch d.hh = h d.be = h.isBinary() // NOTE: do not initialize d.n here. It is lazily initialized in d.naked() var jh *JsonHandle jh, d.js = h.(*JsonHandle) d.jdec = nil if d.js { d.jsms = jh.MapKeyAsString } d.esep = d.hh.hasElemSeparators() if d.h.InternString { d.is = make(map[string]string, 32) } d.d = h.newDecDriver(d) if d.js { d.jdec = d.d.(*jsonDecDriver) } // d.cr, _ = d.d.(containerStateRecv) return d } func (d *Decoder) r() *decReaderSwitch { return &d.decReaderSwitch } func (d *Decoder) resetCommon() { // d.r = &d.decReaderSwitch d.d.reset() d.err = nil d.depth = 0 d.maxdepth = d.h.MaxDepth if d.maxdepth <= 0 { d.maxdepth = decDefMaxDepth } // reset all things which were cached from the Handle, but could change d.mtid, d.stid = 0, 0 d.mtr, d.str = false, false if d.h.MapType != nil { d.mtid = rt2id(d.h.MapType) d.mtr = fastpathAV.index(d.mtid) != -1 } if d.h.SliceType != nil { d.stid = rt2id(d.h.SliceType) d.str = fastpathAV.index(d.stid) != -1 } } // Reset the Decoder with a new Reader to decode from, // clearing all state from last run(s). func (d *Decoder) Reset(r io.Reader) { if r == nil { return } d.bytes = false // d.typ = entryTypeUnset if d.h.ReaderBufferSize > 0 { if d.bi == nil { d.bi = new(bufioDecReader) } d.bi.reset(r, d.h.ReaderBufferSize) // d.r = d.bi // d.typ = entryTypeBufio d.bufio = true } else { // d.ri.x = &d.b // d.s = d.sa[:0] if d.ri == nil { d.ri = new(ioDecReader) } d.ri.reset(r) // d.r = d.ri // d.typ = entryTypeIo d.bufio = false } d.resetCommon() } // ResetBytes resets the Decoder with a new []byte to decode from, // clearing all state from last run(s). func (d *Decoder) ResetBytes(in []byte) { if in == nil { return } d.bytes = true d.bufio = false // d.typ = entryTypeBytes d.rb.reset(in) // d.r = &d.rb d.resetCommon() } func (d *Decoder) naked() *decNaked { return &d.n } // Decode decodes the stream from reader and stores the result in the // value pointed to by v. v cannot be a nil pointer. v can also be // a reflect.Value of a pointer. // // Note that a pointer to a nil interface is not a nil pointer. // If you do not know what type of stream it is, pass in a pointer to a nil interface. // We will decode and store a value in that nil interface. // // Sample usages: // // Decoding into a non-nil typed value // var f float32 // err = codec.NewDecoder(r, handle).Decode(&f) // // // Decoding into nil interface // var v interface{} // dec := codec.NewDecoder(r, handle) // err = dec.Decode(&v) // // When decoding into a nil interface{}, we will decode into an appropriate value based // on the contents of the stream: // - Numbers are decoded as float64, int64 or uint64. // - Other values are decoded appropriately depending on the type: // bool, string, []byte, time.Time, etc // - Extensions are decoded as RawExt (if no ext function registered for the tag) // Configurations exist on the Handle to override defaults // (e.g. for MapType, SliceType and how to decode raw bytes). // // When decoding into a non-nil interface{} value, the mode of encoding is based on the // type of the value. When a value is seen: // - If an extension is registered for it, call that extension function // - If it implements BinaryUnmarshaler, call its UnmarshalBinary(data []byte) error // - Else decode it based on its reflect.Kind // // There are some special rules when decoding into containers (slice/array/map/struct). // Decode will typically use the stream contents to UPDATE the container i.e. the values // in these containers will not be zero'ed before decoding. // - A map can be decoded from a stream map, by updating matching keys. // - A slice can be decoded from a stream array, // by updating the first n elements, where n is length of the stream. // - A slice can be decoded from a stream map, by decoding as if // it contains a sequence of key-value pairs. // - A struct can be decoded from a stream map, by updating matching fields. // - A struct can be decoded from a stream array, // by updating fields as they occur in the struct (by index). // // This in-place update maintains consistency in the decoding philosophy (i.e. we ALWAYS update // in place by default). However, the consequence of this is that values in slices or maps // which are not zero'ed before hand, will have part of the prior values in place after decode // if the stream doesn't contain an update for those parts. // // This in-place update can be disabled by configuring the MapValueReset and SliceElementReset // decode options available on every handle. // // Furthermore, when decoding a stream map or array with length of 0 into a nil map or slice, // we reset the destination map or slice to a zero-length value. // // However, when decoding a stream nil, we reset the destination container // to its "zero" value (e.g. nil for slice/map, etc). // // Note: we allow nil values in the stream anywhere except for map keys. // A nil value in the encoded stream where a map key is expected is treated as an error. func (d *Decoder) Decode(v interface{}) (err error) { // tried to use closure, as runtime optimizes defer with no params. // This seemed to be causing weird issues (like circular reference found, unexpected panic, etc). // Also, see https://github.com/golang/go/issues/14939#issuecomment-417836139 // defer func() { d.deferred(&err) }() // { x, y := d, &err; defer func() { x.deferred(y) }() } if d.err != nil { return d.err } if recoverPanicToErr { defer func() { if x := recover(); x != nil { panicValToErr(d, x, &d.err) if d.err != err { err = d.err } } }() } // defer d.deferred(&err) d.mustDecode(v) return } // MustDecode is like Decode, but panics if unable to Decode. // This provides insight to the code location that triggered the error. func (d *Decoder) MustDecode(v interface{}) { if d.err != nil { panic(d.err) } d.mustDecode(v) } // MustDecode is like Decode, but panics if unable to Decode. // This provides insight to the code location that triggered the error. func (d *Decoder) mustDecode(v interface{}) { // TODO: Top-level: ensure that v is a pointer and not nil. if d.d.TryDecodeAsNil() { setZero(v) return } if d.bi == nil { d.decode(v) return } d.bi.calls++ d.decode(v) // xprintf.(">>>>>>>> >>>>>>>> num decFns: %v\n", d.cf.sn) d.bi.calls-- if !d.h.ExplicitRelease && d.bi.calls == 0 { d.bi.release() } } // func (d *Decoder) deferred(err1 *error) { // if recoverPanicToErr { // if x := recover(); x != nil { // panicValToErr(d, x, err1) // panicValToErr(d, x, &d.err) // } // } // } //go:noinline -- as it is run by finalizer func (d *Decoder) finalize() { // xdebugf("finalizing Decoder") d.Release() } // Release releases shared (pooled) resources. // // It is important to call Release() when done with a Decoder, so those resources // are released instantly for use by subsequently created Decoders. // // By default, Release() is automatically called unless the option ExplicitRelease is set. func (d *Decoder) Release() { if d.bi != nil { d.bi.release() } // d.decNakedPooler.end() } // // this is not a smart swallow, as it allocates objects and does unnecessary work. // func (d *Decoder) swallowViaHammer() { // var blank interface{} // d.decodeValueNoFn(reflect.ValueOf(&blank).Elem()) // } func (d *Decoder) swallow() { // smarter decode that just swallows the content dd := d.d if dd.TryDecodeAsNil() { return } switch dd.ContainerType() { case valueTypeMap: containerLen := d.mapStart() hasLen := containerLen >= 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ { // if clenGtEqualZero {if j >= containerLen {break} } else if dd.CheckBreak() {break} d.mapElemKey() d.swallow() d.mapElemValue() d.swallow() } d.mapEnd() case valueTypeArray: containerLen := d.arrayStart() hasLen := containerLen >= 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ { d.arrayElem() d.swallow() } d.arrayEnd() case valueTypeBytes: dd.DecodeBytes(d.b[:], true) case valueTypeString: dd.DecodeStringAsBytes() default: // these are all primitives, which we can get from decodeNaked // if RawExt using Value, complete the processing. n := d.naked() dd.DecodeNaked() if n.v == valueTypeExt && n.l == nil { var v2 interface{} d.decode(&v2) } } } func setZero(iv interface{}) { if iv == nil || definitelyNil(iv) { return } var canDecode bool switch v := iv.(type) { case *string: *v = "" case *bool: *v = false case *int: *v = 0 case *int8: *v = 0 case *int16: *v = 0 case *int32: *v = 0 case *int64: *v = 0 case *uint: *v = 0 case *uint8: *v = 0 case *uint16: *v = 0 case *uint32: *v = 0 case *uint64: *v = 0 case *float32: *v = 0 case *float64: *v = 0 case *[]uint8: *v = nil case *Raw: *v = nil case *time.Time: *v = time.Time{} case reflect.Value: if v, canDecode = isDecodeable(v); canDecode && v.CanSet() { v.Set(reflect.Zero(v.Type())) } // TODO: else drain if chan, clear if map, set all to nil if slice??? default: if !fastpathDecodeSetZeroTypeSwitch(iv) { v := reflect.ValueOf(iv) if v, canDecode = isDecodeable(v); canDecode && v.CanSet() { v.Set(reflect.Zero(v.Type())) } // TODO: else drain if chan, clear if map, set all to nil if slice??? } } } func (d *Decoder) decode(iv interface{}) { // a switch with only concrete types can be optimized. // consequently, we deal with nil and interfaces outside the switch. if iv == nil { d.errorstr(errstrCannotDecodeIntoNil) return } switch v := iv.(type) { // case nil: // case Selfer: case reflect.Value: v = d.ensureDecodeable(v) d.decodeValue(v, nil, true) case *string: *v = d.d.DecodeString() case *bool: *v = d.d.DecodeBool() case *int: *v = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) case *int8: *v = int8(chkOvf.IntV(d.d.DecodeInt64(), 8)) case *int16: *v = int16(chkOvf.IntV(d.d.DecodeInt64(), 16)) case *int32: *v = int32(chkOvf.IntV(d.d.DecodeInt64(), 32)) case *int64: *v = d.d.DecodeInt64() case *uint: *v = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) case *uint8: *v = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) case *uint16: *v = uint16(chkOvf.UintV(d.d.DecodeUint64(), 16)) case *uint32: *v = uint32(chkOvf.UintV(d.d.DecodeUint64(), 32)) case *uint64: *v = d.d.DecodeUint64() case *float32: *v = float32(d.decodeFloat32()) case *float64: *v = d.d.DecodeFloat64() case *[]uint8: *v = d.d.DecodeBytes(*v, false) case []uint8: b := d.d.DecodeBytes(v, false) if !(len(b) > 0 && len(b) == len(v) && &b[0] == &v[0]) { copy(v, b) } case *time.Time: *v = d.d.DecodeTime() case *Raw: *v = d.rawBytes() case *interface{}: d.decodeValue(reflect.ValueOf(iv).Elem(), nil, true) // d.decodeValueNotNil(reflect.ValueOf(iv).Elem()) default: if v, ok := iv.(Selfer); ok { v.CodecDecodeSelf(d) } else if !fastpathDecodeTypeSwitch(iv, d) { v := reflect.ValueOf(iv) v = d.ensureDecodeable(v) d.decodeValue(v, nil, false) // d.decodeValueFallback(v) } } } func (d *Decoder) decodeValue(rv reflect.Value, fn *codecFn, chkAll bool) { // If stream is not containing a nil value, then we can deref to the base // non-pointer value, and decode into that. var rvp reflect.Value var rvpValid bool if rv.Kind() == reflect.Ptr { rvpValid = true for { if rv.IsNil() { rv.Set(reflect.New(rv.Type().Elem())) } rvp = rv rv = rv.Elem() if rv.Kind() != reflect.Ptr { break } } } if fn == nil { // always pass checkCodecSelfer=true, in case T or ****T is passed, where *T is a Selfer fn = d.h.fn(rv.Type(), chkAll, true) // chkAll, chkAll) } if fn.i.addrD { if rvpValid { fn.fd(d, &fn.i, rvp) } else if rv.CanAddr() { fn.fd(d, &fn.i, rv.Addr()) } else if !fn.i.addrF { fn.fd(d, &fn.i, rv) } else { d.errorf("cannot decode into a non-pointer value") } } else { fn.fd(d, &fn.i, rv) } // return rv } func (d *Decoder) structFieldNotFound(index int, rvkencname string) { // NOTE: rvkencname may be a stringView, so don't pass it to another function. if d.h.ErrorIfNoField { if index >= 0 { d.errorf("no matching struct field found when decoding stream array at index %v", index) return } else if rvkencname != "" { d.errorf("no matching struct field found when decoding stream map with key " + rvkencname) return } } d.swallow() } func (d *Decoder) arrayCannotExpand(sliceLen, streamLen int) { if d.h.ErrorIfNoArrayExpand { d.errorf("cannot expand array len during decode from %v to %v", sliceLen, streamLen) } } func isDecodeable(rv reflect.Value) (rv2 reflect.Value, canDecode bool) { switch rv.Kind() { case reflect.Array: return rv, rv.CanAddr() case reflect.Ptr: if !rv.IsNil() { return rv.Elem(), true } case reflect.Slice, reflect.Chan, reflect.Map: if !rv.IsNil() { return rv, true } } return } func (d *Decoder) ensureDecodeable(rv reflect.Value) (rv2 reflect.Value) { // decode can take any reflect.Value that is a inherently addressable i.e. // - array // - non-nil chan (we will SEND to it) // - non-nil slice (we will set its elements) // - non-nil map (we will put into it) // - non-nil pointer (we can "update" it) rv2, canDecode := isDecodeable(rv) if canDecode { return } if !rv.IsValid() { d.errorstr(errstrCannotDecodeIntoNil) return } if !rv.CanInterface() { d.errorf("cannot decode into a value without an interface: %v", rv) return } rvi := rv2i(rv) rvk := rv.Kind() d.errorf("cannot decode into value of kind: %v, type: %T, %v", rvk, rvi, rvi) return } func (d *Decoder) depthIncr() { d.depth++ if d.depth >= d.maxdepth { panic(errMaxDepthExceeded) } } func (d *Decoder) depthDecr() { d.depth-- } // Possibly get an interned version of a string // // This should mostly be used for map keys, where the key type is string. // This is because keys of a map/struct are typically reused across many objects. func (d *Decoder) string(v []byte) (s string) { if d.is == nil { return string(v) // don't return stringView, as we need a real string here. } s, ok := d.is[string(v)] // no allocation here, per go implementation if !ok { s = string(v) // new allocation here d.is[s] = s } return s } // nextValueBytes returns the next value in the stream as a set of bytes. func (d *Decoder) nextValueBytes() (bs []byte) { d.d.uncacheRead() d.r().track() d.swallow() bs = d.r().stopTrack() return } func (d *Decoder) rawBytes() []byte { // ensure that this is not a view into the bytes // i.e. make new copy always. bs := d.nextValueBytes() bs2 := make([]byte, len(bs)) copy(bs2, bs) return bs2 } func (d *Decoder) wrapErr(v interface{}, err *error) { *err = decodeError{codecError: codecError{name: d.hh.Name(), err: v}, pos: int(d.r().numread())} } // NumBytesRead returns the number of bytes read func (d *Decoder) NumBytesRead() int { return int(d.r().numread()) } // decodeFloat32 will delegate to an appropriate DecodeFloat32 implementation (if exists), // else if will call DecodeFloat64 and ensure the value doesn't overflow. // // Note that we return float64 to reduce unnecessary conversions func (d *Decoder) decodeFloat32() float64 { if d.js { return d.jdec.DecodeFloat32() // custom implementation for 32-bit } return chkOvf.Float32V(d.d.DecodeFloat64()) } // ---- container tracking // Note: We update the .c after calling the callback. // This way, the callback can know what the last status was. func (d *Decoder) mapStart() (v int) { v = d.d.ReadMapStart() d.depthIncr() d.c = containerMapStart return } func (d *Decoder) mapElemKey() { if d.js { d.jdec.ReadMapElemKey() } d.c = containerMapKey } func (d *Decoder) mapElemValue() { if d.js { d.jdec.ReadMapElemValue() } d.c = containerMapValue } func (d *Decoder) mapEnd() { d.d.ReadMapEnd() d.depthDecr() d.c = containerMapEnd d.c = 0 } func (d *Decoder) arrayStart() (v int) { v = d.d.ReadArrayStart() d.depthIncr() d.c = containerArrayStart return } func (d *Decoder) arrayElem() { if d.js { d.jdec.ReadArrayElem() } d.c = containerArrayElem } func (d *Decoder) arrayEnd() { d.d.ReadArrayEnd() d.depthDecr() d.c = containerArrayEnd d.c = 0 } // -------------------------------------------------- // decSliceHelper assists when decoding into a slice, from a map or an array in the stream. // A slice can be set from a map or array in stream. This supports the MapBySlice interface. type decSliceHelper struct { d *Decoder ct valueType array bool } func (d *Decoder) decSliceHelperStart() (x decSliceHelper, clen int) { x.ct = d.d.ContainerType() x.d = d switch x.ct { case valueTypeArray: x.array = true clen = d.arrayStart() case valueTypeMap: clen = d.mapStart() * 2 default: d.errorf("only encoded map or array can be decoded into a slice (%d)", x.ct) } return } func (x decSliceHelper) End() { if x.array { x.d.arrayEnd() } else { x.d.mapEnd() } } func (x decSliceHelper) ElemContainerState(index int) { if x.array { x.d.arrayElem() } else if index%2 == 0 { x.d.mapElemKey() } else { x.d.mapElemValue() } } func decByteSlice(r *decReaderSwitch, clen, maxInitLen int, bs []byte) (bsOut []byte) { if clen == 0 { return zeroByteSlice } if len(bs) == clen { bsOut = bs r.readb(bsOut) } else if cap(bs) >= clen { bsOut = bs[:clen] r.readb(bsOut) } else { // bsOut = make([]byte, clen) len2 := decInferLen(clen, maxInitLen, 1) bsOut = make([]byte, len2) r.readb(bsOut) for len2 < clen { len3 := decInferLen(clen-len2, maxInitLen, 1) bs3 := bsOut bsOut = make([]byte, len2+len3) copy(bsOut, bs3) r.readb(bsOut[len2:]) len2 += len3 } } return } // func decByteSliceZeroCopy(r decReader, clen, maxInitLen int, bs []byte) (bsOut []byte) { // if _, ok := r.(*bytesDecReader); ok && clen <= maxInitLen { // return r.readx(clen) // } // return decByteSlice(r, clen, maxInitLen, bs) // } func detachZeroCopyBytes(isBytesReader bool, dest []byte, in []byte) (out []byte) { if xlen := len(in); xlen > 0 { if isBytesReader || xlen <= scratchByteArrayLen { if cap(dest) >= xlen { out = dest[:xlen] } else { out = make([]byte, xlen) } copy(out, in) return } } return in } // decInferLen will infer a sensible length, given the following: // - clen: length wanted. // - maxlen: max length to be returned. // if <= 0, it is unset, and we infer it based on the unit size // - unit: number of bytes for each element of the collection func decInferLen(clen, maxlen, unit int) (rvlen int) { // handle when maxlen is not set i.e. <= 0 if clen <= 0 { return } if unit == 0 { return clen } if maxlen <= 0 { // no maxlen defined. Use maximum of 256K memory, with a floor of 4K items. // maxlen = 256 * 1024 / unit // if maxlen < (4 * 1024) { // maxlen = 4 * 1024 // } if unit < (256 / 4) { maxlen = 256 * 1024 / unit } else { maxlen = 4 * 1024 } } if clen > maxlen { rvlen = maxlen } else { rvlen = clen } return } func expandSliceRV(s reflect.Value, st reflect.Type, canChange bool, stElemSize, num, slen, scap int) ( s2 reflect.Value, scap2 int, changed bool, err string) { l1 := slen + num // new slice length if l1 < slen { err = errmsgExpandSliceOverflow return } if l1 <= scap { if s.CanSet() { s.SetLen(l1) } else if canChange { s2 = s.Slice(0, l1) scap2 = scap changed = true } else { err = errmsgExpandSliceCannotChange return } return } if !canChange { err = errmsgExpandSliceCannotChange return } scap2 = growCap(scap, stElemSize, num) s2 = reflect.MakeSlice(st, l1, scap2) changed = true reflect.Copy(s2, s) return } func decReadFull(r io.Reader, bs []byte) (n uint, err error) { var nn int for n < uint(len(bs)) && err == nil { nn, err = r.Read(bs[n:]) if nn > 0 { if err == io.EOF { // leave EOF for next time err = nil } n += uint(nn) } } // xdebugf("decReadFull: len(bs): %v, n: %v, err: %v", len(bs), n, err) // do not do this - it serves no purpose // if n != len(bs) && err == io.EOF { err = io.ErrUnexpectedEOF } return } func decNakedReadRawBytes(dr decDriver, d *Decoder, n *decNaked, rawToString bool) { if rawToString { n.v = valueTypeString n.s = string(dr.DecodeBytes(d.b[:], true)) } else { n.v = valueTypeBytes n.l = dr.DecodeBytes(nil, false) } } ================================================ FILE: vendor/github.com/ugorji/go/codec/doc.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. /* Package codec provides a High Performance, Feature-Rich Idiomatic Go 1.4+ codec/encoding library for binc, msgpack, cbor, json. Supported Serialization formats are: - msgpack: https://github.com/msgpack/msgpack - binc: http://github.com/ugorji/binc - cbor: http://cbor.io http://tools.ietf.org/html/rfc7049 - json: http://json.org http://tools.ietf.org/html/rfc7159 - simple: This package will carefully use 'package unsafe' for performance reasons in specific places. You can build without unsafe use by passing the safe or appengine tag i.e. 'go install -tags=safe ...'. Note that unsafe is only supported for the last 4 go releases e.g. current go release is go 1.12, so we support unsafe use only from go 1.9+ . This is because supporting unsafe requires knowledge of implementation details. For detailed usage information, read the primer at http://ugorji.net/blog/go-codec-primer . The idiomatic Go support is as seen in other encoding packages in the standard library (ie json, xml, gob, etc). Rich Feature Set includes: - Simple but extremely powerful and feature-rich API - Support for go1.4 and above, while selectively using newer APIs for later releases - Excellent code coverage ( > 90% ) - Very High Performance. Our extensive benchmarks show us outperforming Gob, Json, Bson, etc by 2-4X. - Careful selected use of 'unsafe' for targeted performance gains. 100% mode exists where 'unsafe' is not used at all. - Lock-free (sans mutex) concurrency for scaling to 100's of cores - In-place updates during decode, with option to zero value in maps and slices prior to decode - Coerce types where appropriate e.g. decode an int in the stream into a float, decode numbers from formatted strings, etc - Corner Cases: Overflows, nil maps/slices, nil values in streams are handled correctly - Standard field renaming via tags - Support for omitting empty fields during an encoding - Encoding from any value and decoding into pointer to any value (struct, slice, map, primitives, pointers, interface{}, etc) - Extensions to support efficient encoding/decoding of any named types - Support encoding.(Binary|Text)(M|Unm)arshaler interfaces - Support IsZero() bool to determine if a value is a zero value. Analogous to time.Time.IsZero() bool. - Decoding without a schema (into a interface{}). Includes Options to configure what specific map or slice type to use when decoding an encoded list or map into a nil interface{} - Mapping a non-interface type to an interface, so we can decode appropriately into any interface type with a correctly configured non-interface value. - Encode a struct as an array, and decode struct from an array in the data stream - Option to encode struct keys as numbers (instead of strings) (to support structured streams with fields encoded as numeric codes) - Comprehensive support for anonymous fields - Fast (no-reflection) encoding/decoding of common maps and slices - Code-generation for faster performance. - Support binary (e.g. messagepack, cbor) and text (e.g. json) formats - Support indefinite-length formats to enable true streaming (for formats which support it e.g. json, cbor) - Support canonical encoding, where a value is ALWAYS encoded as same sequence of bytes. This mostly applies to maps, where iteration order is non-deterministic. - NIL in data stream decoded as zero value - Never silently skip data when decoding. User decides whether to return an error or silently skip data when keys or indexes in the data stream do not map to fields in the struct. - Detect and error when encoding a cyclic reference (instead of stack overflow shutdown) - Encode/Decode from/to chan types (for iterative streaming support) - Drop-in replacement for encoding/json. `json:` key in struct tag supported. - Provides a RPC Server and Client Codec for net/rpc communication protocol. - Handle unique idiosyncrasies of codecs e.g. - For messagepack, configure how ambiguities in handling raw bytes are resolved - For messagepack, provide rpc server/client codec to support msgpack-rpc protocol defined at: https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md Extension Support Users can register a function to handle the encoding or decoding of their custom types. There are no restrictions on what the custom type can be. Some examples: type BisSet []int type BitSet64 uint64 type UUID string type MyStructWithUnexportedFields struct { a int; b bool; c []int; } type GifImage struct { ... } As an illustration, MyStructWithUnexportedFields would normally be encoded as an empty map because it has no exported fields, while UUID would be encoded as a string. However, with extension support, you can encode any of these however you like. Custom Encoding and Decoding This package maintains symmetry in the encoding and decoding halfs. We determine how to encode or decode by walking this decision tree - is type a codec.Selfer? - is there an extension registered for the type? - is format binary, and is type a encoding.BinaryMarshaler and BinaryUnmarshaler? - is format specifically json, and is type a encoding/json.Marshaler and Unmarshaler? - is format text-based, and type an encoding.TextMarshaler and TextUnmarshaler? - else we use a pair of functions based on the "kind" of the type e.g. map, slice, int64, etc This symmetry is important to reduce chances of issues happening because the encoding and decoding sides are out of sync e.g. decoded via very specific encoding.TextUnmarshaler but encoded via kind-specific generalized mode. Consequently, if a type only defines one-half of the symmetry (e.g. it implements UnmarshalJSON() but not MarshalJSON() ), then that type doesn't satisfy the check and we will continue walking down the decision tree. RPC RPC Client and Server Codecs are implemented, so the codecs can be used with the standard net/rpc package. Usage The Handle is SAFE for concurrent READ, but NOT SAFE for concurrent modification. The Encoder and Decoder are NOT safe for concurrent use. Consequently, the usage model is basically: - Create and initialize the Handle before any use. Once created, DO NOT modify it. - Multiple Encoders or Decoders can now use the Handle concurrently. They only read information off the Handle (never write). - However, each Encoder or Decoder MUST not be used concurrently - To re-use an Encoder/Decoder, call Reset(...) on it first. This allows you use state maintained on the Encoder/Decoder. Sample usage model: // create and configure Handle var ( bh codec.BincHandle mh codec.MsgpackHandle ch codec.CborHandle ) mh.MapType = reflect.TypeOf(map[string]interface{}(nil)) // configure extensions // e.g. for msgpack, define functions and enable Time support for tag 1 // mh.SetExt(reflect.TypeOf(time.Time{}), 1, myExt) // create and use decoder/encoder var ( r io.Reader w io.Writer b []byte h = &bh // or mh to use msgpack ) dec = codec.NewDecoder(r, h) dec = codec.NewDecoderBytes(b, h) err = dec.Decode(&v) enc = codec.NewEncoder(w, h) enc = codec.NewEncoderBytes(&b, h) err = enc.Encode(v) //RPC Server go func() { for { conn, err := listener.Accept() rpcCodec := codec.GoRpc.ServerCodec(conn, h) //OR rpcCodec := codec.MsgpackSpecRpc.ServerCodec(conn, h) rpc.ServeCodec(rpcCodec) } }() //RPC Communication (client side) conn, err = net.Dial("tcp", "localhost:5555") rpcCodec := codec.GoRpc.ClientCodec(conn, h) //OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h) client := rpc.NewClientWithCodec(rpcCodec) Running Tests To run tests, use the following: go test To run the full suite of tests, use the following: go test -tags alltests -run Suite You can run the tag 'safe' to run tests or build in safe mode. e.g. go test -tags safe -run Json go test -tags "alltests safe" -run Suite Running Benchmarks cd bench go test -bench . -benchmem -benchtime 1s Please see http://github.com/ugorji/go-codec-bench . Managing Binary Size This package adds some size to any binary that depends on it. This is because we include an auto-generated file: `fast-path.generated.go` to help with performance when encoding/decoding slices and maps of built in numeric, boolean, string and interface{} types. Prior to 2019-05-16, this package could add about 11MB to the size of your binaries. We have now trimmed that in half, and the package contributes about 5.5MB. You can override this by building (or running tests and benchmarks) with the tag: `notfastpath`. go install -tags notfastpath go build -tags notfastpath go test -tags notfastpath With the tag `notfastpath`, we trim that size to about 2.9MB. Be aware that, at least in our representative microbenchmarks for cbor (for example), passing `notfastpath` tag causes up to 33% increase in decoding and 50% increase in encoding speeds. YMMV. Caveats Struct fields matching the following are ignored during encoding and decoding - struct tag value set to - - func, complex numbers, unsafe pointers - unexported and not embedded - unexported and embedded and not struct kind - unexported and embedded pointers (from go1.10) Every other field in a struct will be encoded/decoded. Embedded fields are encoded as if they exist in the top-level struct, with some caveats. See Encode documentation. */ package codec ================================================ FILE: vendor/github.com/ugorji/go/codec/encode.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. package codec import ( "encoding" "errors" "fmt" "io" "reflect" "runtime" "sort" "strconv" "time" ) // defEncByteBufSize is the default size of []byte used // for bufio buffer or []byte (when nil passed) const defEncByteBufSize = 1 << 10 // 4:16, 6:64, 8:256, 10:1024 var errEncoderNotInitialized = errors.New("Encoder not initialized") /* // encWriter abstracts writing to a byte array or to an io.Writer. // // // Deprecated: Use encWriterSwitch instead. type encWriter interface { writeb([]byte) writestr(string) writeqstr(string) // write string wrapped in quotes ie "..." writen1(byte) writen2(byte, byte) end() } */ // encDriver abstracts the actual codec (binc vs msgpack, etc) type encDriver interface { EncodeNil() EncodeInt(i int64) EncodeUint(i uint64) EncodeBool(b bool) EncodeFloat32(f float32) EncodeFloat64(f float64) // encodeExtPreamble(xtag byte, length int) EncodeRawExt(re *RawExt, e *Encoder) EncodeExt(v interface{}, xtag uint64, ext Ext, e *Encoder) EncodeStringEnc(c charEncoding, v string) // c cannot be cRAW // EncodeSymbol(v string) EncodeStringBytesRaw(v []byte) EncodeTime(time.Time) //encBignum(f *big.Int) //encStringRunes(c charEncoding, v []rune) WriteArrayStart(length int) WriteArrayEnd() WriteMapStart(length int) WriteMapEnd() reset() atEndOfEncode() } type encDriverContainerTracker interface { WriteArrayElem() WriteMapElemKey() WriteMapElemValue() } type encDriverAsis interface { EncodeAsis(v []byte) } type encodeError struct { codecError } func (e encodeError) Error() string { return fmt.Sprintf("%s encode error: %v", e.name, e.err) } type encDriverNoopContainerWriter struct{} func (encDriverNoopContainerWriter) WriteArrayStart(length int) {} func (encDriverNoopContainerWriter) WriteArrayEnd() {} func (encDriverNoopContainerWriter) WriteMapStart(length int) {} func (encDriverNoopContainerWriter) WriteMapEnd() {} func (encDriverNoopContainerWriter) atEndOfEncode() {} // func (encDriverNoopContainerWriter) WriteArrayElem() {} // func (encDriverNoopContainerWriter) WriteMapElemKey() {} // func (encDriverNoopContainerWriter) WriteMapElemValue() {} // type encDriverTrackContainerWriter struct { // c containerState // } // func (e *encDriverTrackContainerWriter) WriteArrayStart(length int) { e.c = containerArrayStart } // func (e *encDriverTrackContainerWriter) WriteArrayElem() { e.c = containerArrayElem } // func (e *encDriverTrackContainerWriter) WriteArrayEnd() { e.c = containerArrayEnd } // func (e *encDriverTrackContainerWriter) WriteMapStart(length int) { e.c = containerMapStart } // func (e *encDriverTrackContainerWriter) WriteMapElemKey() { e.c = containerMapKey } // func (e *encDriverTrackContainerWriter) WriteMapElemValue() { e.c = containerMapValue } // func (e *encDriverTrackContainerWriter) WriteMapEnd() { e.c = containerMapEnd } // func (e *encDriverTrackContainerWriter) atEndOfEncode() {} // type ioEncWriterWriter interface { // WriteByte(c byte) error // WriteString(s string) (n int, err error) // Write(p []byte) (n int, err error) // } // EncodeOptions captures configuration options during encode. type EncodeOptions struct { // WriterBufferSize is the size of the buffer used when writing. // // if > 0, we use a smart buffer internally for performance purposes. WriterBufferSize int // ChanRecvTimeout is the timeout used when selecting from a chan. // // Configuring this controls how we receive from a chan during the encoding process. // - If ==0, we only consume the elements currently available in the chan. // - if <0, we consume until the chan is closed. // - If >0, we consume until this timeout. ChanRecvTimeout time.Duration // StructToArray specifies to encode a struct as an array, and not as a map StructToArray bool // Canonical representation means that encoding a value will always result in the same // sequence of bytes. // // This only affects maps, as the iteration order for maps is random. // // The implementation MAY use the natural sort order for the map keys if possible: // // - If there is a natural sort order (ie for number, bool, string or []byte keys), // then the map keys are first sorted in natural order and then written // with corresponding map values to the strema. // - If there is no natural sort order, then the map keys will first be // encoded into []byte, and then sorted, // before writing the sorted keys and the corresponding map values to the stream. // Canonical bool // CheckCircularRef controls whether we check for circular references // and error fast during an encode. // // If enabled, an error is received if a pointer to a struct // references itself either directly or through one of its fields (iteratively). // // This is opt-in, as there may be a performance hit to checking circular references. CheckCircularRef bool // RecursiveEmptyCheck controls whether we descend into interfaces, structs and pointers // when checking if a value is empty. // // Note that this may make OmitEmpty more expensive, as it incurs a lot more reflect calls. RecursiveEmptyCheck bool // Raw controls whether we encode Raw values. // This is a "dangerous" option and must be explicitly set. // If set, we blindly encode Raw values as-is, without checking // if they are a correct representation of a value in that format. // If unset, we error out. Raw bool // StringToRaw controls how strings are encoded. // // As a go string is just an (immutable) sequence of bytes, // it can be encoded either as raw bytes or as a UTF string. // // By default, strings are encoded as UTF-8. // but can be treated as []byte during an encode. // // Note that things which we know (by definition) to be UTF-8 // are ALWAYS encoded as UTF-8 strings. // These include encoding.TextMarshaler, time.Format calls, struct field names, etc. StringToRaw bool // // AsSymbols defines what should be encoded as symbols. // // // // Encoding as symbols can reduce the encoded size significantly. // // // // However, during decoding, each string to be encoded as a symbol must // // be checked to see if it has been seen before. Consequently, encoding time // // will increase if using symbols, because string comparisons has a clear cost. // // // // Sample values: // // AsSymbolNone // // AsSymbolAll // // AsSymbolMapStringKeys // // AsSymbolMapStringKeysFlag | AsSymbolStructFieldNameFlag // AsSymbols AsSymbolFlag } // --------------------------------------------- /* type ioEncStringWriter interface { WriteString(s string) (n int, err error) } // ioEncWriter implements encWriter and can write to an io.Writer implementation type ioEncWriter struct { w io.Writer ww io.Writer bw io.ByteWriter sw ioEncStringWriter fw ioFlusher b [8]byte } func (z *ioEncWriter) reset(w io.Writer) { z.w = w var ok bool if z.bw, ok = w.(io.ByteWriter); !ok { z.bw = z } if z.sw, ok = w.(ioEncStringWriter); !ok { z.sw = z } z.fw, _ = w.(ioFlusher) z.ww = w } func (z *ioEncWriter) WriteByte(b byte) (err error) { z.b[0] = b _, err = z.w.Write(z.b[:1]) return } func (z *ioEncWriter) WriteString(s string) (n int, err error) { return z.w.Write(bytesView(s)) } func (z *ioEncWriter) writeb(bs []byte) { if _, err := z.ww.Write(bs); err != nil { panic(err) } } func (z *ioEncWriter) writestr(s string) { if _, err := z.sw.WriteString(s); err != nil { panic(err) } } func (z *ioEncWriter) writeqstr(s string) { writestr("\"" + s + "\"") } func (z *ioEncWriter) writen1(b byte) { if err := z.bw.WriteByte(b); err != nil { panic(err) } } func (z *ioEncWriter) writen2(b1, b2 byte) { var err error if err = z.bw.WriteByte(b1); err == nil { if err = z.bw.WriteByte(b2); err == nil { return } } panic(err) } // func (z *ioEncWriter) writen5(b1, b2, b3, b4, b5 byte) { // z.b[0], z.b[1], z.b[2], z.b[3], z.b[4] = b1, b2, b3, b4, b5 // if _, err := z.ww.Write(z.b[:5]); err != nil { // panic(err) // } // } //go:noinline - so *encWriterSwitch.XXX has the bytesEncAppender.XXX inlined func (z *ioEncWriter) end() { if z.fw != nil { if err := z.fw.Flush(); err != nil { panic(err) } } } */ // --------------------------------------------- // bufioEncWriter type bufioEncWriter struct { w io.Writer buf []byte n int // Extensions can call Encode() within a current Encode() call. // We need to know when the top level Encode() call returns, // so we can decide whether to Release() or not. calls uint16 // what depth in mustDecode are we in now. sz int // buf size // _ uint64 // padding (cache-aligned) // ---- cache line // write-most fields below // less used fields bytesBufPooler b [40]byte // scratch buffer and padding (cache-aligned) // a int // b [4]byte // err } func (z *bufioEncWriter) reset(w io.Writer, bufsize int) { z.w = w z.n = 0 z.calls = 0 if bufsize <= 0 { bufsize = defEncByteBufSize } z.sz = bufsize if cap(z.buf) >= bufsize { z.buf = z.buf[:cap(z.buf)] } else if bufsize <= len(z.b) { z.buf = z.b[:] } else { z.buf = z.bytesBufPooler.get(bufsize) // z.buf = make([]byte, bufsize) } } func (z *bufioEncWriter) release() { z.buf = nil z.bytesBufPooler.end() } //go:noinline - flush only called intermittently func (z *bufioEncWriter) flushErr() (err error) { n, err := z.w.Write(z.buf[:z.n]) z.n -= n if z.n > 0 && err == nil { err = io.ErrShortWrite } if n > 0 && z.n > 0 { copy(z.buf, z.buf[n:z.n+n]) } return err } func (z *bufioEncWriter) flush() { if err := z.flushErr(); err != nil { panic(err) } } func (z *bufioEncWriter) writeb(s []byte) { LOOP: a := len(z.buf) - z.n if len(s) > a { z.n += copy(z.buf[z.n:], s[:a]) s = s[a:] z.flush() goto LOOP } z.n += copy(z.buf[z.n:], s) } func (z *bufioEncWriter) writestr(s string) { // z.writeb(bytesView(s)) // inlined below LOOP: a := len(z.buf) - z.n if len(s) > a { z.n += copy(z.buf[z.n:], s[:a]) s = s[a:] z.flush() goto LOOP } z.n += copy(z.buf[z.n:], s) } func (z *bufioEncWriter) writeqstr(s string) { // z.writen1('"') // z.writestr(s) // z.writen1('"') if z.n+len(s)+2 > len(z.buf) { z.flush() } z.buf[z.n] = '"' z.n++ LOOP: a := len(z.buf) - z.n if len(s)+1 > a { z.n += copy(z.buf[z.n:], s[:a]) s = s[a:] z.flush() goto LOOP } z.n += copy(z.buf[z.n:], s) z.buf[z.n] = '"' z.n++ } func (z *bufioEncWriter) writen1(b1 byte) { if 1 > len(z.buf)-z.n { z.flush() } z.buf[z.n] = b1 z.n++ } func (z *bufioEncWriter) writen2(b1, b2 byte) { if 2 > len(z.buf)-z.n { z.flush() } z.buf[z.n+1] = b2 z.buf[z.n] = b1 z.n += 2 } func (z *bufioEncWriter) endErr() (err error) { if z.n > 0 { err = z.flushErr() } return } // --------------------------------------------- // bytesEncAppender implements encWriter and can write to an byte slice. type bytesEncAppender struct { b []byte out *[]byte } func (z *bytesEncAppender) writeb(s []byte) { z.b = append(z.b, s...) } func (z *bytesEncAppender) writestr(s string) { z.b = append(z.b, s...) } func (z *bytesEncAppender) writeqstr(s string) { // z.writen1('"') // z.writestr(s) // z.writen1('"') z.b = append(append(append(z.b, '"'), s...), '"') // z.b = append(z.b, '"') // z.b = append(z.b, s...) // z.b = append(z.b, '"') } func (z *bytesEncAppender) writen1(b1 byte) { z.b = append(z.b, b1) } func (z *bytesEncAppender) writen2(b1, b2 byte) { z.b = append(z.b, b1, b2) } func (z *bytesEncAppender) endErr() error { *(z.out) = z.b return nil } func (z *bytesEncAppender) reset(in []byte, out *[]byte) { z.b = in[:0] z.out = out } // --------------------------------------------- func (e *Encoder) rawExt(f *codecFnInfo, rv reflect.Value) { e.e.EncodeRawExt(rv2i(rv).(*RawExt), e) } func (e *Encoder) ext(f *codecFnInfo, rv reflect.Value) { e.e.EncodeExt(rv2i(rv), f.xfTag, f.xfFn, e) } func (e *Encoder) selferMarshal(f *codecFnInfo, rv reflect.Value) { rv2i(rv).(Selfer).CodecEncodeSelf(e) } func (e *Encoder) binaryMarshal(f *codecFnInfo, rv reflect.Value) { bs, fnerr := rv2i(rv).(encoding.BinaryMarshaler).MarshalBinary() e.marshalRaw(bs, fnerr) } func (e *Encoder) textMarshal(f *codecFnInfo, rv reflect.Value) { bs, fnerr := rv2i(rv).(encoding.TextMarshaler).MarshalText() e.marshalUtf8(bs, fnerr) } func (e *Encoder) jsonMarshal(f *codecFnInfo, rv reflect.Value) { bs, fnerr := rv2i(rv).(jsonMarshaler).MarshalJSON() e.marshalAsis(bs, fnerr) } func (e *Encoder) raw(f *codecFnInfo, rv reflect.Value) { e.rawBytes(rv2i(rv).(Raw)) } func (e *Encoder) kInvalid(f *codecFnInfo, rv reflect.Value) { e.e.EncodeNil() } func (e *Encoder) kErr(f *codecFnInfo, rv reflect.Value) { e.errorf("unsupported kind %s, for %#v", rv.Kind(), rv) } func (e *Encoder) kSlice(f *codecFnInfo, rv reflect.Value) { // array may be non-addressable, so we have to manage with care // (don't call rv.Bytes, rv.Slice, etc). // E.g. type struct S{B [2]byte}; // Encode(S{}) will bomb on "panic: slice of unaddressable array". if f.seq != seqTypeArray { if rv.IsNil() { e.e.EncodeNil() return } // If in this method, then there was no extension function defined. // So it's okay to treat as []byte. if f.ti.rtid == uint8SliceTypId { e.e.EncodeStringBytesRaw(rv.Bytes()) return } } if f.seq == seqTypeChan && f.ti.chandir&uint8(reflect.RecvDir) == 0 { e.errorf("send-only channel cannot be encoded") } mbs := f.ti.mbs rtelem := f.ti.elem // if a slice, array or chan of bytes, treat specially if !mbs && uint8TypId == rt2id(rtelem) { // NOT rtelem.Kind() == reflect.Uint8 e.kSliceBytes(rv, f.seq) return } // if chan, consume chan into a slice, and work off that slice. if f.seq == seqTypeChan { rvcs := reflect.Zero(reflect.SliceOf(rtelem)) timeout := e.h.ChanRecvTimeout if timeout < 0 { // consume until close for { recv, recvOk := rv.Recv() if !recvOk { break } rvcs = reflect.Append(rvcs, recv) } } else { cases := make([]reflect.SelectCase, 2) cases[0] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: rv} if timeout == 0 { cases[1] = reflect.SelectCase{Dir: reflect.SelectDefault} } else { tt := time.NewTimer(timeout) cases[1] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(tt.C)} } for { chosen, recv, recvOk := reflect.Select(cases) if chosen == 1 || !recvOk { break } rvcs = reflect.Append(rvcs, recv) } } rv = rvcs // TODO: ensure this doesn't mess up anywhere that rv of kind chan is expected } var l = rv.Len() if mbs { if l%2 == 1 { e.errorf("mapBySlice requires even slice length, but got %v", l) return } e.mapStart(l / 2) } else { e.arrayStart(l) } if l > 0 { var fn *codecFn for rtelem.Kind() == reflect.Ptr { rtelem = rtelem.Elem() } // if kind is reflect.Interface, do not pre-determine the // encoding type, because preEncodeValue may break it down to // a concrete type and kInterface will bomb. if rtelem.Kind() != reflect.Interface { fn = e.h.fn(rtelem, true, true) } for j := 0; j < l; j++ { if mbs { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } } else { e.arrayElem() } e.encodeValue(rv.Index(j), fn, true) } } if mbs { e.mapEnd() } else { e.arrayEnd() } } func (e *Encoder) kSliceBytes(rv reflect.Value, seq seqType) { // xdebugf("kSliceBytes: seq: %d, rvType: %v", seq, rv.Type()) switch seq { case seqTypeSlice: e.e.EncodeStringBytesRaw(rv.Bytes()) case seqTypeArray: var l = rv.Len() if rv.CanAddr() { e.e.EncodeStringBytesRaw(rv.Slice(0, l).Bytes()) } else { var bs []byte if l <= cap(e.b) { bs = e.b[:l] } else { bs = make([]byte, l) } reflect.Copy(reflect.ValueOf(bs), rv) e.e.EncodeStringBytesRaw(bs) } case seqTypeChan: // do not use range, so that the number of elements encoded // does not change, and encoding does not hang waiting on someone to close chan. // for b := range rv2i(rv).(<-chan byte) { bs = append(bs, b) } // ch := rv2i(rv).(<-chan byte) // fix error - that this is a chan byte, not a <-chan byte. if rv.IsNil() { e.e.EncodeNil() break } bs := e.b[:0] irv := rv2i(rv) ch, ok := irv.(<-chan byte) if !ok { ch = irv.(chan byte) } L1: switch timeout := e.h.ChanRecvTimeout; { case timeout == 0: // only consume available for { select { case b := <-ch: bs = append(bs, b) default: break L1 } } case timeout > 0: // consume until timeout tt := time.NewTimer(timeout) for { select { case b := <-ch: bs = append(bs, b) case <-tt.C: // close(tt.C) break L1 } } default: // consume until close for b := range ch { bs = append(bs, b) } } e.e.EncodeStringBytesRaw(bs) } } func (e *Encoder) kStructNoOmitempty(f *codecFnInfo, rv reflect.Value) { sfn := structFieldNode{v: rv, update: false} if f.ti.toArray || e.h.StructToArray { // toArray e.arrayStart(len(f.ti.sfiSrc)) for _, si := range f.ti.sfiSrc { e.arrayElem() e.encodeValue(sfn.field(si), nil, true) } e.arrayEnd() } else { e.mapStart(len(f.ti.sfiSort)) for _, si := range f.ti.sfiSort { e.mapElemKey() e.kStructFieldKey(f.ti.keyType, si.encNameAsciiAlphaNum, si.encName) e.mapElemValue() e.encodeValue(sfn.field(si), nil, true) } e.mapEnd() } } func (e *Encoder) kStructFieldKey(keyType valueType, encNameAsciiAlphaNum bool, encName string) { encStructFieldKey(encName, e.e, e.w(), keyType, encNameAsciiAlphaNum, e.js) } func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) { var newlen int toMap := !(f.ti.toArray || e.h.StructToArray) var mf map[string]interface{} if f.ti.mf { mf = rv2i(rv).(MissingFielder).CodecMissingFields() toMap = true newlen += len(mf) } else if f.ti.mfp { if rv.CanAddr() { mf = rv2i(rv.Addr()).(MissingFielder).CodecMissingFields() } else { // make a new addressable value of same one, and use it rv2 := reflect.New(rv.Type()) rv2.Elem().Set(rv) mf = rv2i(rv2).(MissingFielder).CodecMissingFields() } toMap = true newlen += len(mf) } newlen += len(f.ti.sfiSrc) // Use sync.Pool to reduce allocating slices unnecessarily. // The cost of sync.Pool is less than the cost of new allocation. // // Each element of the array pools one of encStructPool(8|16|32|64). // It allows the re-use of slices up to 64 in length. // A performance cost of encoding structs was collecting // which values were empty and should be omitted. // We needed slices of reflect.Value and string to collect them. // This shared pool reduces the amount of unnecessary creation we do. // The cost is that of locking sometimes, but sync.Pool is efficient // enough to reduce thread contention. // fmt.Printf(">>>>>>>>>>>>>> encode.kStruct: newlen: %d\n", newlen) var spool sfiRvPooler var fkvs = spool.get(newlen) recur := e.h.RecursiveEmptyCheck sfn := structFieldNode{v: rv, update: false} var kv sfiRv var j int if toMap { newlen = 0 for _, si := range f.ti.sfiSort { // use sorted array // kv.r = si.field(rv, false) kv.r = sfn.field(si) if si.omitEmpty() && isEmptyValue(kv.r, e.h.TypeInfos, recur, recur) { continue } kv.v = si // si.encName fkvs[newlen] = kv newlen++ } var mflen int for k, v := range mf { if k == "" { delete(mf, k) continue } if f.ti.infoFieldOmitempty && isEmptyValue(reflect.ValueOf(v), e.h.TypeInfos, recur, recur) { delete(mf, k) continue } mflen++ } // encode it all e.mapStart(newlen + mflen) for j = 0; j < newlen; j++ { kv = fkvs[j] e.mapElemKey() e.kStructFieldKey(f.ti.keyType, kv.v.encNameAsciiAlphaNum, kv.v.encName) e.mapElemValue() e.encodeValue(kv.r, nil, true) } // now, add the others for k, v := range mf { e.mapElemKey() e.kStructFieldKey(f.ti.keyType, false, k) e.mapElemValue() e.encode(v) } e.mapEnd() } else { newlen = len(f.ti.sfiSrc) // kv.v = nil for i, si := range f.ti.sfiSrc { // use unsorted array (to match sequence in struct) // kv.r = si.field(rv, false) kv.r = sfn.field(si) // use the zero value. // if a reference or struct, set to nil (so you do not output too much) if si.omitEmpty() && isEmptyValue(kv.r, e.h.TypeInfos, recur, recur) { switch kv.r.Kind() { case reflect.Struct, reflect.Interface, reflect.Ptr, reflect.Array, reflect.Map, reflect.Slice: kv.r = reflect.Value{} //encode as nil } } fkvs[i] = kv } // encode it all e.arrayStart(newlen) for j = 0; j < newlen; j++ { e.arrayElem() e.encodeValue(fkvs[j].r, nil, true) } e.arrayEnd() } // do not use defer. Instead, use explicit pool return at end of function. // defer has a cost we are trying to avoid. // If there is a panic and these slices are not returned, it is ok. spool.end() } func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) { if rv.IsNil() { e.e.EncodeNil() return } l := rv.Len() e.mapStart(l) if l == 0 { e.mapEnd() return } // var asSymbols bool // determine the underlying key and val encFn's for the map. // This eliminates some work which is done for each loop iteration i.e. // rv.Type(), ref.ValueOf(rt).Pointer(), then check map/list for fn. // // However, if kind is reflect.Interface, do not pre-determine the // encoding type, because preEncodeValue may break it down to // a concrete type and kInterface will bomb. var keyFn, valFn *codecFn rtval := f.ti.elem // rtkeyid := rt2id(f.ti.key) for rtval.Kind() == reflect.Ptr { rtval = rtval.Elem() } if rtval.Kind() != reflect.Interface { valFn = e.h.fn(rtval, true, true) } mks := rv.MapKeys() if e.h.Canonical { e.kMapCanonical(f.ti.key, rv, mks, valFn) e.mapEnd() return } rtkey := f.ti.key var keyTypeIsString = stringTypId == rt2id(rtkey) // rtkeyid if !keyTypeIsString { for rtkey.Kind() == reflect.Ptr { rtkey = rtkey.Elem() } if rtkey.Kind() != reflect.Interface { // rtkeyid = rt2id(rtkey) keyFn = e.h.fn(rtkey, true, true) } } // for j, lmks := 0, len(mks); j < lmks; j++ { for j := range mks { e.mapElemKey() if keyTypeIsString { if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(mks[j].String())) } else { e.e.EncodeStringEnc(cUTF8, mks[j].String()) } } else { e.encodeValue(mks[j], keyFn, true) } e.mapElemValue() e.encodeValue(rv.MapIndex(mks[j]), valFn, true) } e.mapEnd() } func (e *Encoder) kMapCanonical(rtkey reflect.Type, rv reflect.Value, mks []reflect.Value, valFn *codecFn) { // we previously did out-of-band if an extension was registered. // This is not necessary, as the natural kind is sufficient for ordering. switch rtkey.Kind() { case reflect.Bool: mksv := make([]boolRv, len(mks)) for i, k := range mks { v := &mksv[i] v.r = k v.v = k.Bool() } sort.Sort(boolRvSlice(mksv)) for i := range mksv { e.mapElemKey() e.e.EncodeBool(mksv[i].v) e.mapElemValue() e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true) } case reflect.String: mksv := make([]stringRv, len(mks)) for i, k := range mks { v := &mksv[i] v.r = k v.v = k.String() } sort.Sort(stringRvSlice(mksv)) for i := range mksv { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(mksv[i].v)) } else { e.e.EncodeStringEnc(cUTF8, mksv[i].v) } e.mapElemValue() e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true) } case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr: mksv := make([]uint64Rv, len(mks)) for i, k := range mks { v := &mksv[i] v.r = k v.v = k.Uint() } sort.Sort(uint64RvSlice(mksv)) for i := range mksv { e.mapElemKey() e.e.EncodeUint(mksv[i].v) e.mapElemValue() e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true) } case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: mksv := make([]int64Rv, len(mks)) for i, k := range mks { v := &mksv[i] v.r = k v.v = k.Int() } sort.Sort(int64RvSlice(mksv)) for i := range mksv { e.mapElemKey() e.e.EncodeInt(mksv[i].v) e.mapElemValue() e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true) } case reflect.Float32: mksv := make([]float64Rv, len(mks)) for i, k := range mks { v := &mksv[i] v.r = k v.v = k.Float() } sort.Sort(float64RvSlice(mksv)) for i := range mksv { e.mapElemKey() e.e.EncodeFloat32(float32(mksv[i].v)) e.mapElemValue() e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true) } case reflect.Float64: mksv := make([]float64Rv, len(mks)) for i, k := range mks { v := &mksv[i] v.r = k v.v = k.Float() } sort.Sort(float64RvSlice(mksv)) for i := range mksv { e.mapElemKey() e.e.EncodeFloat64(mksv[i].v) e.mapElemValue() e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true) } case reflect.Struct: if rv.Type() == timeTyp { mksv := make([]timeRv, len(mks)) for i, k := range mks { v := &mksv[i] v.r = k v.v = rv2i(k).(time.Time) } sort.Sort(timeRvSlice(mksv)) for i := range mksv { e.mapElemKey() e.e.EncodeTime(mksv[i].v) e.mapElemValue() e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true) } break } fallthrough default: // out-of-band // first encode each key to a []byte first, then sort them, then record var mksv []byte = make([]byte, 0, len(mks)*16) // temporary byte slice for the encoding e2 := NewEncoderBytes(&mksv, e.hh) mksbv := make([]bytesRv, len(mks)) for i, k := range mks { v := &mksbv[i] l := len(mksv) e2.MustEncode(k) v.r = k v.v = mksv[l:] } sort.Sort(bytesRvSlice(mksbv)) for j := range mksbv { e.mapElemKey() e.asis(mksbv[j].v) e.mapElemValue() e.encodeValue(rv.MapIndex(mksbv[j].r), valFn, true) } } } // // -------------------------------------------------- type encWriterSwitch struct { esep bool // whether it has elem separators bytes bool // encoding to []byte isas bool // whether e.as != nil js bool // is json encoder? be bool // is binary encoder? c containerState // _ [3]byte // padding // _ [2]uint64 // padding // _ uint64 // padding // wi *ioEncWriter wb bytesEncAppender wf *bufioEncWriter // typ entryType } func (z *encWriterSwitch) writeb(s []byte) { if z.bytes { z.wb.writeb(s) } else { z.wf.writeb(s) } } func (z *encWriterSwitch) writeqstr(s string) { if z.bytes { z.wb.writeqstr(s) } else { z.wf.writeqstr(s) } } func (z *encWriterSwitch) writestr(s string) { if z.bytes { z.wb.writestr(s) } else { z.wf.writestr(s) } } func (z *encWriterSwitch) writen1(b1 byte) { if z.bytes { z.wb.writen1(b1) } else { z.wf.writen1(b1) } } func (z *encWriterSwitch) writen2(b1, b2 byte) { if z.bytes { z.wb.writen2(b1, b2) } else { z.wf.writen2(b1, b2) } } func (z *encWriterSwitch) endErr() error { if z.bytes { return z.wb.endErr() } return z.wf.endErr() } func (z *encWriterSwitch) end() { if err := z.endErr(); err != nil { panic(err) } } /* // ------------------------------------------ func (z *encWriterSwitch) writeb(s []byte) { switch z.typ { case entryTypeBytes: z.wb.writeb(s) case entryTypeIo: z.wi.writeb(s) default: z.wf.writeb(s) } } func (z *encWriterSwitch) writestr(s string) { switch z.typ { case entryTypeBytes: z.wb.writestr(s) case entryTypeIo: z.wi.writestr(s) default: z.wf.writestr(s) } } func (z *encWriterSwitch) writen1(b1 byte) { switch z.typ { case entryTypeBytes: z.wb.writen1(b1) case entryTypeIo: z.wi.writen1(b1) default: z.wf.writen1(b1) } } func (z *encWriterSwitch) writen2(b1, b2 byte) { switch z.typ { case entryTypeBytes: z.wb.writen2(b1, b2) case entryTypeIo: z.wi.writen2(b1, b2) default: z.wf.writen2(b1, b2) } } func (z *encWriterSwitch) end() { switch z.typ { case entryTypeBytes: z.wb.end() case entryTypeIo: z.wi.end() default: z.wf.end() } } // ------------------------------------------ func (z *encWriterSwitch) writeb(s []byte) { if z.bytes { z.wb.writeb(s) } else { z.wi.writeb(s) } } func (z *encWriterSwitch) writestr(s string) { if z.bytes { z.wb.writestr(s) } else { z.wi.writestr(s) } } func (z *encWriterSwitch) writen1(b1 byte) { if z.bytes { z.wb.writen1(b1) } else { z.wi.writen1(b1) } } func (z *encWriterSwitch) writen2(b1, b2 byte) { if z.bytes { z.wb.writen2(b1, b2) } else { z.wi.writen2(b1, b2) } } func (z *encWriterSwitch) end() { if z.bytes { z.wb.end() } else { z.wi.end() } } */ // Encoder writes an object to an output stream in a supported format. // // Encoder is NOT safe for concurrent use i.e. a Encoder cannot be used // concurrently in multiple goroutines. // // However, as Encoder could be allocation heavy to initialize, a Reset method is provided // so its state can be reused to decode new input streams repeatedly. // This is the idiomatic way to use. type Encoder struct { panicHdl // hopefully, reduce derefencing cost by laying the encWriter inside the Encoder e encDriver // NOTE: Encoder shouldn't call it's write methods, // as the handler MAY need to do some coordination. // w *encWriterSwitch // bw *bufio.Writer as encDriverAsis jenc *jsonEncDriver h *BasicHandle hh Handle // ---- cpu cache line boundary encWriterSwitch err error // ---- cpu cache line boundary // ---- writable fields during execution --- *try* to keep in sep cache line ci set // holds set of addresses found during an encoding (if CheckCircularRef=true) cidef [1]uintptr // default ci b [(4 * 8)]byte // for encoding chan byte, (non-addressable) [N]byte, etc // ---- cpu cache line boundary? // b [scratchByteArrayLen]byte // _ [cacheLineSize - scratchByteArrayLen]byte // padding // b [cacheLineSize - (8 * 0)]byte // used for encoding a chan or (non-addressable) array of bytes } // NewEncoder returns an Encoder for encoding into an io.Writer. // // For efficiency, Users are encouraged to configure WriterBufferSize on the handle // OR pass in a memory buffered writer (eg bufio.Writer, bytes.Buffer). func NewEncoder(w io.Writer, h Handle) *Encoder { e := newEncoder(h) e.Reset(w) return e } // NewEncoderBytes returns an encoder for encoding directly and efficiently // into a byte slice, using zero-copying to temporary slices. // // It will potentially replace the output byte slice pointed to. // After encoding, the out parameter contains the encoded contents. func NewEncoderBytes(out *[]byte, h Handle) *Encoder { e := newEncoder(h) e.ResetBytes(out) return e } func newEncoder(h Handle) *Encoder { e := &Encoder{h: basicHandle(h), err: errEncoderNotInitialized} e.bytes = true if useFinalizers { runtime.SetFinalizer(e, (*Encoder).finalize) // xdebugf(">>>> new(Encoder) with finalizer") } // e.w = &e.encWriterSwitch e.hh = h e.esep = h.hasElemSeparators() return e } func (e *Encoder) w() *encWriterSwitch { return &e.encWriterSwitch } func (e *Encoder) resetCommon() { // e.w = &e.encWriterSwitch if e.e == nil || e.hh.recreateEncDriver(e.e) { e.e = e.hh.newEncDriver(e) e.as, e.isas = e.e.(encDriverAsis) // e.cr, _ = e.e.(containerStateRecv) } if e.ci == nil { e.ci = (set)(e.cidef[:0]) } else { e.ci = e.ci[:0] } e.be = e.hh.isBinary() e.jenc = nil _, e.js = e.hh.(*JsonHandle) if e.js { e.jenc = e.e.(interface{ getJsonEncDriver() *jsonEncDriver }).getJsonEncDriver() } e.e.reset() e.c = 0 e.err = nil } // Reset resets the Encoder with a new output stream. // // This accommodates using the state of the Encoder, // where it has "cached" information about sub-engines. func (e *Encoder) Reset(w io.Writer) { if w == nil { return } // var ok bool e.bytes = false if e.wf == nil { e.wf = new(bufioEncWriter) } // e.typ = entryTypeUnset // if e.h.WriterBufferSize > 0 { // // bw := bufio.NewWriterSize(w, e.h.WriterBufferSize) // // e.wi.bw = bw // // e.wi.sw = bw // // e.wi.fw = bw // // e.wi.ww = bw // if e.wf == nil { // e.wf = new(bufioEncWriter) // } // e.wf.reset(w, e.h.WriterBufferSize) // e.typ = entryTypeBufio // } else { // if e.wi == nil { // e.wi = new(ioEncWriter) // } // e.wi.reset(w) // e.typ = entryTypeIo // } e.wf.reset(w, e.h.WriterBufferSize) // e.typ = entryTypeBufio // e.w = e.wi e.resetCommon() } // ResetBytes resets the Encoder with a new destination output []byte. func (e *Encoder) ResetBytes(out *[]byte) { if out == nil { return } var in []byte = *out if in == nil { in = make([]byte, defEncByteBufSize) } e.bytes = true // e.typ = entryTypeBytes e.wb.reset(in, out) // e.w = &e.wb e.resetCommon() } // Encode writes an object into a stream. // // Encoding can be configured via the struct tag for the fields. // The key (in the struct tags) that we look at is configurable. // // By default, we look up the "codec" key in the struct field's tags, // and fall bak to the "json" key if "codec" is absent. // That key in struct field's tag value is the key name, // followed by an optional comma and options. // // To set an option on all fields (e.g. omitempty on all fields), you // can create a field called _struct, and set flags on it. The options // which can be set on _struct are: // - omitempty: so all fields are omitted if empty // - toarray: so struct is encoded as an array // - int: so struct key names are encoded as signed integers (instead of strings) // - uint: so struct key names are encoded as unsigned integers (instead of strings) // - float: so struct key names are encoded as floats (instead of strings) // More details on these below. // // Struct values "usually" encode as maps. Each exported struct field is encoded unless: // - the field's tag is "-", OR // - the field is empty (empty or the zero value) and its tag specifies the "omitempty" option. // // When encoding as a map, the first string in the tag (before the comma) // is the map key string to use when encoding. // ... // This key is typically encoded as a string. // However, there are instances where the encoded stream has mapping keys encoded as numbers. // For example, some cbor streams have keys as integer codes in the stream, but they should map // to fields in a structured object. Consequently, a struct is the natural representation in code. // For these, configure the struct to encode/decode the keys as numbers (instead of string). // This is done with the int,uint or float option on the _struct field (see above). // // However, struct values may encode as arrays. This happens when: // - StructToArray Encode option is set, OR // - the tag on the _struct field sets the "toarray" option // Note that omitempty is ignored when encoding struct values as arrays, // as an entry must be encoded for each field, to maintain its position. // // Values with types that implement MapBySlice are encoded as stream maps. // // The empty values (for omitempty option) are false, 0, any nil pointer // or interface value, and any array, slice, map, or string of length zero. // // Anonymous fields are encoded inline except: // - the struct tag specifies a replacement name (first value) // - the field is of an interface type // // Examples: // // // NOTE: 'json:' can be used as struct tag key, in place 'codec:' below. // type MyStruct struct { // _struct bool `codec:",omitempty"` //set omitempty for every field // Field1 string `codec:"-"` //skip this field // Field2 int `codec:"myName"` //Use key "myName" in encode stream // Field3 int32 `codec:",omitempty"` //use key "Field3". Omit if empty. // Field4 bool `codec:"f4,omitempty"` //use key "f4". Omit if empty. // io.Reader //use key "Reader". // MyStruct `codec:"my1" //use key "my1". // MyStruct //inline it // ... // } // // type MyStruct struct { // _struct bool `codec:",toarray"` //encode struct as an array // } // // type MyStruct struct { // _struct bool `codec:",uint"` //encode struct with "unsigned integer" keys // Field1 string `codec:"1"` //encode Field1 key using: EncodeInt(1) // Field2 string `codec:"2"` //encode Field2 key using: EncodeInt(2) // } // // The mode of encoding is based on the type of the value. When a value is seen: // - If a Selfer, call its CodecEncodeSelf method // - If an extension is registered for it, call that extension function // - If implements encoding.(Binary|Text|JSON)Marshaler, call Marshal(Binary|Text|JSON) method // - Else encode it based on its reflect.Kind // // Note that struct field names and keys in map[string]XXX will be treated as symbols. // Some formats support symbols (e.g. binc) and will properly encode the string // only once in the stream, and use a tag to refer to it thereafter. func (e *Encoder) Encode(v interface{}) (err error) { // tried to use closure, as runtime optimizes defer with no params. // This seemed to be causing weird issues (like circular reference found, unexpected panic, etc). // Also, see https://github.com/golang/go/issues/14939#issuecomment-417836139 // defer func() { e.deferred(&err) }() } // { x, y := e, &err; defer func() { x.deferred(y) }() } if e.err != nil { return e.err } if recoverPanicToErr { defer func() { // if error occurred during encoding, return that error; // else if error occurred on end'ing (i.e. during flush), return that error. err = e.w().endErr() x := recover() if x == nil { if e.err != err { e.err = err } } else { panicValToErr(e, x, &e.err) if e.err != err { err = e.err } } }() } // defer e.deferred(&err) e.mustEncode(v) return } // MustEncode is like Encode, but panics if unable to Encode. // This provides insight to the code location that triggered the error. func (e *Encoder) MustEncode(v interface{}) { if e.err != nil { panic(e.err) } e.mustEncode(v) } func (e *Encoder) mustEncode(v interface{}) { if e.wf == nil { e.encode(v) e.e.atEndOfEncode() e.w().end() return } if e.wf.buf == nil { e.wf.buf = e.wf.bytesBufPooler.get(e.wf.sz) } e.wf.calls++ e.encode(v) e.wf.calls-- if e.wf.calls == 0 { e.e.atEndOfEncode() e.w().end() if !e.h.ExplicitRelease { e.wf.release() } } } // func (e *Encoder) deferred(err1 *error) { // e.w().end() // if recoverPanicToErr { // if x := recover(); x != nil { // panicValToErr(e, x, err1) // panicValToErr(e, x, &e.err) // } // } // } //go:noinline -- as it is run by finalizer func (e *Encoder) finalize() { // xdebugf("finalizing Encoder") e.Release() } // Release releases shared (pooled) resources. // // It is important to call Release() when done with an Encoder, so those resources // are released instantly for use by subsequently created Encoders. func (e *Encoder) Release() { if e.wf != nil { e.wf.release() } } func (e *Encoder) encode(iv interface{}) { // a switch with only concrete types can be optimized. // consequently, we deal with nil and interfaces outside the switch. if iv == nil || definitelyNil(iv) { e.e.EncodeNil() return } switch v := iv.(type) { // case nil: // case Selfer: case Raw: e.rawBytes(v) case reflect.Value: e.encodeValue(v, nil, true) case string: if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(v)) } else { e.e.EncodeStringEnc(cUTF8, v) } case bool: e.e.EncodeBool(v) case int: e.e.EncodeInt(int64(v)) case int8: e.e.EncodeInt(int64(v)) case int16: e.e.EncodeInt(int64(v)) case int32: e.e.EncodeInt(int64(v)) case int64: e.e.EncodeInt(v) case uint: e.e.EncodeUint(uint64(v)) case uint8: e.e.EncodeUint(uint64(v)) case uint16: e.e.EncodeUint(uint64(v)) case uint32: e.e.EncodeUint(uint64(v)) case uint64: e.e.EncodeUint(v) case uintptr: e.e.EncodeUint(uint64(v)) case float32: e.e.EncodeFloat32(v) case float64: e.e.EncodeFloat64(v) case time.Time: e.e.EncodeTime(v) case []uint8: e.e.EncodeStringBytesRaw(v) case *Raw: e.rawBytes(*v) case *string: if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(*v)) } else { e.e.EncodeStringEnc(cUTF8, *v) } case *bool: e.e.EncodeBool(*v) case *int: e.e.EncodeInt(int64(*v)) case *int8: e.e.EncodeInt(int64(*v)) case *int16: e.e.EncodeInt(int64(*v)) case *int32: e.e.EncodeInt(int64(*v)) case *int64: e.e.EncodeInt(*v) case *uint: e.e.EncodeUint(uint64(*v)) case *uint8: e.e.EncodeUint(uint64(*v)) case *uint16: e.e.EncodeUint(uint64(*v)) case *uint32: e.e.EncodeUint(uint64(*v)) case *uint64: e.e.EncodeUint(*v) case *uintptr: e.e.EncodeUint(uint64(*v)) case *float32: e.e.EncodeFloat32(*v) case *float64: e.e.EncodeFloat64(*v) case *time.Time: e.e.EncodeTime(*v) case *[]uint8: e.e.EncodeStringBytesRaw(*v) default: if v, ok := iv.(Selfer); ok { v.CodecEncodeSelf(e) } else if !fastpathEncodeTypeSwitch(iv, e) { // checkfastpath=true (not false), as underlying slice/map type may be fast-path e.encodeValue(reflect.ValueOf(iv), nil, true) } } } func (e *Encoder) encodeValue(rv reflect.Value, fn *codecFn, checkFastpath bool) { // if a valid fn is passed, it MUST BE for the dereferenced type of rv var sptr uintptr var rvp reflect.Value var rvpValid bool TOP: switch rv.Kind() { case reflect.Ptr: if rv.IsNil() { e.e.EncodeNil() return } rvpValid = true rvp = rv rv = rv.Elem() if e.h.CheckCircularRef && rv.Kind() == reflect.Struct { // TODO: Movable pointers will be an issue here. Future problem. sptr = rv.UnsafeAddr() break TOP } goto TOP case reflect.Interface: if rv.IsNil() { e.e.EncodeNil() return } rv = rv.Elem() goto TOP case reflect.Slice, reflect.Map: if rv.IsNil() { e.e.EncodeNil() return } case reflect.Invalid, reflect.Func: e.e.EncodeNil() return } if sptr != 0 && (&e.ci).add(sptr) { e.errorf("circular reference found: # %d", sptr) } if fn == nil { rt := rv.Type() // always pass checkCodecSelfer=true, in case T or ****T is passed, where *T is a Selfer fn = e.h.fn(rt, checkFastpath, true) } if fn.i.addrE { if rvpValid { fn.fe(e, &fn.i, rvp) } else if rv.CanAddr() { fn.fe(e, &fn.i, rv.Addr()) } else { rv2 := reflect.New(rv.Type()) rv2.Elem().Set(rv) fn.fe(e, &fn.i, rv2) } } else { fn.fe(e, &fn.i, rv) } if sptr != 0 { (&e.ci).remove(sptr) } } // func (e *Encoder) marshal(bs []byte, fnerr error, asis bool, c charEncoding) { // if fnerr != nil { // panic(fnerr) // } // if bs == nil { // e.e.EncodeNil() // } else if asis { // e.asis(bs) // } else { // e.e.EncodeStringBytesRaw(bs) // } // } func (e *Encoder) marshalUtf8(bs []byte, fnerr error) { if fnerr != nil { panic(fnerr) } if bs == nil { e.e.EncodeNil() } else { e.e.EncodeStringEnc(cUTF8, stringView(bs)) } } func (e *Encoder) marshalAsis(bs []byte, fnerr error) { if fnerr != nil { panic(fnerr) } if bs == nil { e.e.EncodeNil() } else { e.asis(bs) } } func (e *Encoder) marshalRaw(bs []byte, fnerr error) { if fnerr != nil { panic(fnerr) } if bs == nil { e.e.EncodeNil() } else { e.e.EncodeStringBytesRaw(bs) } } func (e *Encoder) asis(v []byte) { if e.isas { e.as.EncodeAsis(v) } else { e.w().writeb(v) } } func (e *Encoder) rawBytes(vv Raw) { v := []byte(vv) if !e.h.Raw { e.errorf("Raw values cannot be encoded: %v", v) } e.asis(v) } func (e *Encoder) wrapErr(v interface{}, err *error) { *err = encodeError{codecError{name: e.hh.Name(), err: v}} } // ---- container tracker methods // Note: We update the .c after calling the callback. // This way, the callback can know what the last status was. func (e *Encoder) mapStart(length int) { e.e.WriteMapStart(length) e.c = containerMapStart } func (e *Encoder) mapElemKey() { if e.js { e.jenc.WriteMapElemKey() } e.c = containerMapKey } func (e *Encoder) mapElemValue() { if e.js { e.jenc.WriteMapElemValue() } e.c = containerMapValue } func (e *Encoder) mapEnd() { e.e.WriteMapEnd() e.c = containerMapEnd e.c = 0 } func (e *Encoder) arrayStart(length int) { e.e.WriteArrayStart(length) e.c = containerArrayStart } func (e *Encoder) arrayElem() { if e.js { e.jenc.WriteArrayElem() } e.c = containerArrayElem } func (e *Encoder) arrayEnd() { e.e.WriteArrayEnd() e.c = 0 e.c = containerArrayEnd } func encStructFieldKey(encName string, ee encDriver, w *encWriterSwitch, keyType valueType, encNameAsciiAlphaNum bool, js bool) { var m must // use if-else-if, not switch (which compiles to binary-search) // since keyType is typically valueTypeString, branch prediction is pretty good. if keyType == valueTypeString { if js && encNameAsciiAlphaNum { // keyType == valueTypeString w.writeqstr(encName) // ---- // w.writen1('"') // w.writestr(encName) // w.writen1('"') // ---- // w.writestr(`"` + encName + `"`) // ---- // // do concat myself, so it is faster than the generic string concat // b := make([]byte, len(encName)+2) // copy(b[1:], encName) // b[0] = '"' // b[len(b)-1] = '"' // w.writeb(b) } else { // keyType == valueTypeString ee.EncodeStringEnc(cUTF8, encName) } } else if keyType == valueTypeInt { ee.EncodeInt(m.Int(strconv.ParseInt(encName, 10, 64))) } else if keyType == valueTypeUint { ee.EncodeUint(m.Uint(strconv.ParseUint(encName, 10, 64))) } else if keyType == valueTypeFloat { ee.EncodeFloat64(m.Float(strconv.ParseFloat(encName, 64))) } } // func encStringAsRawBytesMaybe(ee encDriver, s string, stringToRaw bool) { // if stringToRaw { // ee.EncodeStringBytesRaw(bytesView(s)) // } else { // ee.EncodeStringEnc(cUTF8, s) // } // } ================================================ FILE: vendor/github.com/ugorji/go/codec/fast-path.generated.go ================================================ // +build !notfastpath // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // Code generated from fast-path.go.tmpl - DO NOT EDIT. package codec // Fast path functions try to create a fast path encode or decode implementation // for common maps and slices. // // We define the functions and register them in this single file // so as not to pollute the encode.go and decode.go, and create a dependency in there. // This file can be omitted without causing a build failure. // // The advantage of fast paths is: // - Many calls bypass reflection altogether // // Currently support // - slice of all builtin types (numeric, bool, string, []byte) // - maps of builtin types to builtin or interface{} type, EXCEPT FOR // keys of type uintptr, int8/16/32, uint16/32, float32/64, bool, interface{} // AND values of type type int8/16/32, uint16/32 // This should provide adequate "typical" implementations. // // Note that fast track decode functions must handle values for which an address cannot be obtained. // For example: // m2 := map[string]int{} // p2 := []interface{}{m2} // // decoding into p2 will bomb if fast track functions do not treat like unaddressable. // import ( "reflect" "sort" ) const fastpathEnabled = true const fastpathMapBySliceErrMsg = "mapBySlice requires even slice length, but got %v" type fastpathT struct{} var fastpathTV fastpathT type fastpathE struct { rtid uintptr rt reflect.Type encfn func(*Encoder, *codecFnInfo, reflect.Value) decfn func(*Decoder, *codecFnInfo, reflect.Value) } type fastpathA [88]fastpathE func (x *fastpathA) index(rtid uintptr) int { // use binary search to grab the index (adapted from sort/search.go) // Note: we use goto (instead of for loop) so this can be inlined. // h, i, j := 0, 0, len(x) var h, i uint var j = uint(len(x)) LOOP: if i < j { h = i + (j-i)/2 if x[h].rtid < rtid { i = h + 1 } else { j = h } goto LOOP } if i < uint(len(x)) && x[i].rtid == rtid { return int(i) } return -1 } type fastpathAslice []fastpathE func (x fastpathAslice) Len() int { return len(x) } func (x fastpathAslice) Less(i, j int) bool { return x[uint(i)].rtid < x[uint(j)].rtid } func (x fastpathAslice) Swap(i, j int) { x[uint(i)], x[uint(j)] = x[uint(j)], x[uint(i)] } var fastpathAV fastpathA // due to possible initialization loop error, make fastpath in an init() func init() { var i uint = 0 fn := func(v interface{}, fe func(*Encoder, *codecFnInfo, reflect.Value), fd func(*Decoder, *codecFnInfo, reflect.Value)) { xrt := reflect.TypeOf(v) xptr := rt2id(xrt) fastpathAV[i] = fastpathE{xptr, xrt, fe, fd} i++ } fn([]interface{}(nil), (*Encoder).fastpathEncSliceIntfR, (*Decoder).fastpathDecSliceIntfR) fn([]string(nil), (*Encoder).fastpathEncSliceStringR, (*Decoder).fastpathDecSliceStringR) fn([][]byte(nil), (*Encoder).fastpathEncSliceBytesR, (*Decoder).fastpathDecSliceBytesR) fn([]float32(nil), (*Encoder).fastpathEncSliceFloat32R, (*Decoder).fastpathDecSliceFloat32R) fn([]float64(nil), (*Encoder).fastpathEncSliceFloat64R, (*Decoder).fastpathDecSliceFloat64R) fn([]uint(nil), (*Encoder).fastpathEncSliceUintR, (*Decoder).fastpathDecSliceUintR) fn([]uint16(nil), (*Encoder).fastpathEncSliceUint16R, (*Decoder).fastpathDecSliceUint16R) fn([]uint32(nil), (*Encoder).fastpathEncSliceUint32R, (*Decoder).fastpathDecSliceUint32R) fn([]uint64(nil), (*Encoder).fastpathEncSliceUint64R, (*Decoder).fastpathDecSliceUint64R) fn([]uintptr(nil), (*Encoder).fastpathEncSliceUintptrR, (*Decoder).fastpathDecSliceUintptrR) fn([]int(nil), (*Encoder).fastpathEncSliceIntR, (*Decoder).fastpathDecSliceIntR) fn([]int8(nil), (*Encoder).fastpathEncSliceInt8R, (*Decoder).fastpathDecSliceInt8R) fn([]int16(nil), (*Encoder).fastpathEncSliceInt16R, (*Decoder).fastpathDecSliceInt16R) fn([]int32(nil), (*Encoder).fastpathEncSliceInt32R, (*Decoder).fastpathDecSliceInt32R) fn([]int64(nil), (*Encoder).fastpathEncSliceInt64R, (*Decoder).fastpathDecSliceInt64R) fn([]bool(nil), (*Encoder).fastpathEncSliceBoolR, (*Decoder).fastpathDecSliceBoolR) fn(map[string]interface{}(nil), (*Encoder).fastpathEncMapStringIntfR, (*Decoder).fastpathDecMapStringIntfR) fn(map[string]string(nil), (*Encoder).fastpathEncMapStringStringR, (*Decoder).fastpathDecMapStringStringR) fn(map[string][]byte(nil), (*Encoder).fastpathEncMapStringBytesR, (*Decoder).fastpathDecMapStringBytesR) fn(map[string]uint(nil), (*Encoder).fastpathEncMapStringUintR, (*Decoder).fastpathDecMapStringUintR) fn(map[string]uint8(nil), (*Encoder).fastpathEncMapStringUint8R, (*Decoder).fastpathDecMapStringUint8R) fn(map[string]uint64(nil), (*Encoder).fastpathEncMapStringUint64R, (*Decoder).fastpathDecMapStringUint64R) fn(map[string]uintptr(nil), (*Encoder).fastpathEncMapStringUintptrR, (*Decoder).fastpathDecMapStringUintptrR) fn(map[string]int(nil), (*Encoder).fastpathEncMapStringIntR, (*Decoder).fastpathDecMapStringIntR) fn(map[string]int64(nil), (*Encoder).fastpathEncMapStringInt64R, (*Decoder).fastpathDecMapStringInt64R) fn(map[string]float32(nil), (*Encoder).fastpathEncMapStringFloat32R, (*Decoder).fastpathDecMapStringFloat32R) fn(map[string]float64(nil), (*Encoder).fastpathEncMapStringFloat64R, (*Decoder).fastpathDecMapStringFloat64R) fn(map[string]bool(nil), (*Encoder).fastpathEncMapStringBoolR, (*Decoder).fastpathDecMapStringBoolR) fn(map[uint]interface{}(nil), (*Encoder).fastpathEncMapUintIntfR, (*Decoder).fastpathDecMapUintIntfR) fn(map[uint]string(nil), (*Encoder).fastpathEncMapUintStringR, (*Decoder).fastpathDecMapUintStringR) fn(map[uint][]byte(nil), (*Encoder).fastpathEncMapUintBytesR, (*Decoder).fastpathDecMapUintBytesR) fn(map[uint]uint(nil), (*Encoder).fastpathEncMapUintUintR, (*Decoder).fastpathDecMapUintUintR) fn(map[uint]uint8(nil), (*Encoder).fastpathEncMapUintUint8R, (*Decoder).fastpathDecMapUintUint8R) fn(map[uint]uint64(nil), (*Encoder).fastpathEncMapUintUint64R, (*Decoder).fastpathDecMapUintUint64R) fn(map[uint]uintptr(nil), (*Encoder).fastpathEncMapUintUintptrR, (*Decoder).fastpathDecMapUintUintptrR) fn(map[uint]int(nil), (*Encoder).fastpathEncMapUintIntR, (*Decoder).fastpathDecMapUintIntR) fn(map[uint]int64(nil), (*Encoder).fastpathEncMapUintInt64R, (*Decoder).fastpathDecMapUintInt64R) fn(map[uint]float32(nil), (*Encoder).fastpathEncMapUintFloat32R, (*Decoder).fastpathDecMapUintFloat32R) fn(map[uint]float64(nil), (*Encoder).fastpathEncMapUintFloat64R, (*Decoder).fastpathDecMapUintFloat64R) fn(map[uint]bool(nil), (*Encoder).fastpathEncMapUintBoolR, (*Decoder).fastpathDecMapUintBoolR) fn(map[uint8]interface{}(nil), (*Encoder).fastpathEncMapUint8IntfR, (*Decoder).fastpathDecMapUint8IntfR) fn(map[uint8]string(nil), (*Encoder).fastpathEncMapUint8StringR, (*Decoder).fastpathDecMapUint8StringR) fn(map[uint8][]byte(nil), (*Encoder).fastpathEncMapUint8BytesR, (*Decoder).fastpathDecMapUint8BytesR) fn(map[uint8]uint(nil), (*Encoder).fastpathEncMapUint8UintR, (*Decoder).fastpathDecMapUint8UintR) fn(map[uint8]uint8(nil), (*Encoder).fastpathEncMapUint8Uint8R, (*Decoder).fastpathDecMapUint8Uint8R) fn(map[uint8]uint64(nil), (*Encoder).fastpathEncMapUint8Uint64R, (*Decoder).fastpathDecMapUint8Uint64R) fn(map[uint8]uintptr(nil), (*Encoder).fastpathEncMapUint8UintptrR, (*Decoder).fastpathDecMapUint8UintptrR) fn(map[uint8]int(nil), (*Encoder).fastpathEncMapUint8IntR, (*Decoder).fastpathDecMapUint8IntR) fn(map[uint8]int64(nil), (*Encoder).fastpathEncMapUint8Int64R, (*Decoder).fastpathDecMapUint8Int64R) fn(map[uint8]float32(nil), (*Encoder).fastpathEncMapUint8Float32R, (*Decoder).fastpathDecMapUint8Float32R) fn(map[uint8]float64(nil), (*Encoder).fastpathEncMapUint8Float64R, (*Decoder).fastpathDecMapUint8Float64R) fn(map[uint8]bool(nil), (*Encoder).fastpathEncMapUint8BoolR, (*Decoder).fastpathDecMapUint8BoolR) fn(map[uint64]interface{}(nil), (*Encoder).fastpathEncMapUint64IntfR, (*Decoder).fastpathDecMapUint64IntfR) fn(map[uint64]string(nil), (*Encoder).fastpathEncMapUint64StringR, (*Decoder).fastpathDecMapUint64StringR) fn(map[uint64][]byte(nil), (*Encoder).fastpathEncMapUint64BytesR, (*Decoder).fastpathDecMapUint64BytesR) fn(map[uint64]uint(nil), (*Encoder).fastpathEncMapUint64UintR, (*Decoder).fastpathDecMapUint64UintR) fn(map[uint64]uint8(nil), (*Encoder).fastpathEncMapUint64Uint8R, (*Decoder).fastpathDecMapUint64Uint8R) fn(map[uint64]uint64(nil), (*Encoder).fastpathEncMapUint64Uint64R, (*Decoder).fastpathDecMapUint64Uint64R) fn(map[uint64]uintptr(nil), (*Encoder).fastpathEncMapUint64UintptrR, (*Decoder).fastpathDecMapUint64UintptrR) fn(map[uint64]int(nil), (*Encoder).fastpathEncMapUint64IntR, (*Decoder).fastpathDecMapUint64IntR) fn(map[uint64]int64(nil), (*Encoder).fastpathEncMapUint64Int64R, (*Decoder).fastpathDecMapUint64Int64R) fn(map[uint64]float32(nil), (*Encoder).fastpathEncMapUint64Float32R, (*Decoder).fastpathDecMapUint64Float32R) fn(map[uint64]float64(nil), (*Encoder).fastpathEncMapUint64Float64R, (*Decoder).fastpathDecMapUint64Float64R) fn(map[uint64]bool(nil), (*Encoder).fastpathEncMapUint64BoolR, (*Decoder).fastpathDecMapUint64BoolR) fn(map[int]interface{}(nil), (*Encoder).fastpathEncMapIntIntfR, (*Decoder).fastpathDecMapIntIntfR) fn(map[int]string(nil), (*Encoder).fastpathEncMapIntStringR, (*Decoder).fastpathDecMapIntStringR) fn(map[int][]byte(nil), (*Encoder).fastpathEncMapIntBytesR, (*Decoder).fastpathDecMapIntBytesR) fn(map[int]uint(nil), (*Encoder).fastpathEncMapIntUintR, (*Decoder).fastpathDecMapIntUintR) fn(map[int]uint8(nil), (*Encoder).fastpathEncMapIntUint8R, (*Decoder).fastpathDecMapIntUint8R) fn(map[int]uint64(nil), (*Encoder).fastpathEncMapIntUint64R, (*Decoder).fastpathDecMapIntUint64R) fn(map[int]uintptr(nil), (*Encoder).fastpathEncMapIntUintptrR, (*Decoder).fastpathDecMapIntUintptrR) fn(map[int]int(nil), (*Encoder).fastpathEncMapIntIntR, (*Decoder).fastpathDecMapIntIntR) fn(map[int]int64(nil), (*Encoder).fastpathEncMapIntInt64R, (*Decoder).fastpathDecMapIntInt64R) fn(map[int]float32(nil), (*Encoder).fastpathEncMapIntFloat32R, (*Decoder).fastpathDecMapIntFloat32R) fn(map[int]float64(nil), (*Encoder).fastpathEncMapIntFloat64R, (*Decoder).fastpathDecMapIntFloat64R) fn(map[int]bool(nil), (*Encoder).fastpathEncMapIntBoolR, (*Decoder).fastpathDecMapIntBoolR) fn(map[int64]interface{}(nil), (*Encoder).fastpathEncMapInt64IntfR, (*Decoder).fastpathDecMapInt64IntfR) fn(map[int64]string(nil), (*Encoder).fastpathEncMapInt64StringR, (*Decoder).fastpathDecMapInt64StringR) fn(map[int64][]byte(nil), (*Encoder).fastpathEncMapInt64BytesR, (*Decoder).fastpathDecMapInt64BytesR) fn(map[int64]uint(nil), (*Encoder).fastpathEncMapInt64UintR, (*Decoder).fastpathDecMapInt64UintR) fn(map[int64]uint8(nil), (*Encoder).fastpathEncMapInt64Uint8R, (*Decoder).fastpathDecMapInt64Uint8R) fn(map[int64]uint64(nil), (*Encoder).fastpathEncMapInt64Uint64R, (*Decoder).fastpathDecMapInt64Uint64R) fn(map[int64]uintptr(nil), (*Encoder).fastpathEncMapInt64UintptrR, (*Decoder).fastpathDecMapInt64UintptrR) fn(map[int64]int(nil), (*Encoder).fastpathEncMapInt64IntR, (*Decoder).fastpathDecMapInt64IntR) fn(map[int64]int64(nil), (*Encoder).fastpathEncMapInt64Int64R, (*Decoder).fastpathDecMapInt64Int64R) fn(map[int64]float32(nil), (*Encoder).fastpathEncMapInt64Float32R, (*Decoder).fastpathDecMapInt64Float32R) fn(map[int64]float64(nil), (*Encoder).fastpathEncMapInt64Float64R, (*Decoder).fastpathDecMapInt64Float64R) fn(map[int64]bool(nil), (*Encoder).fastpathEncMapInt64BoolR, (*Decoder).fastpathDecMapInt64BoolR) sort.Sort(fastpathAslice(fastpathAV[:])) } // -- encode // -- -- fast path type switch func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { switch v := iv.(type) { case []interface{}: fastpathTV.EncSliceIntfV(v, e) case *[]interface{}: fastpathTV.EncSliceIntfV(*v, e) case []string: fastpathTV.EncSliceStringV(v, e) case *[]string: fastpathTV.EncSliceStringV(*v, e) case [][]byte: fastpathTV.EncSliceBytesV(v, e) case *[][]byte: fastpathTV.EncSliceBytesV(*v, e) case []float32: fastpathTV.EncSliceFloat32V(v, e) case *[]float32: fastpathTV.EncSliceFloat32V(*v, e) case []float64: fastpathTV.EncSliceFloat64V(v, e) case *[]float64: fastpathTV.EncSliceFloat64V(*v, e) case []uint: fastpathTV.EncSliceUintV(v, e) case *[]uint: fastpathTV.EncSliceUintV(*v, e) case []uint16: fastpathTV.EncSliceUint16V(v, e) case *[]uint16: fastpathTV.EncSliceUint16V(*v, e) case []uint32: fastpathTV.EncSliceUint32V(v, e) case *[]uint32: fastpathTV.EncSliceUint32V(*v, e) case []uint64: fastpathTV.EncSliceUint64V(v, e) case *[]uint64: fastpathTV.EncSliceUint64V(*v, e) case []uintptr: fastpathTV.EncSliceUintptrV(v, e) case *[]uintptr: fastpathTV.EncSliceUintptrV(*v, e) case []int: fastpathTV.EncSliceIntV(v, e) case *[]int: fastpathTV.EncSliceIntV(*v, e) case []int8: fastpathTV.EncSliceInt8V(v, e) case *[]int8: fastpathTV.EncSliceInt8V(*v, e) case []int16: fastpathTV.EncSliceInt16V(v, e) case *[]int16: fastpathTV.EncSliceInt16V(*v, e) case []int32: fastpathTV.EncSliceInt32V(v, e) case *[]int32: fastpathTV.EncSliceInt32V(*v, e) case []int64: fastpathTV.EncSliceInt64V(v, e) case *[]int64: fastpathTV.EncSliceInt64V(*v, e) case []bool: fastpathTV.EncSliceBoolV(v, e) case *[]bool: fastpathTV.EncSliceBoolV(*v, e) case map[string]interface{}: fastpathTV.EncMapStringIntfV(v, e) case *map[string]interface{}: fastpathTV.EncMapStringIntfV(*v, e) case map[string]string: fastpathTV.EncMapStringStringV(v, e) case *map[string]string: fastpathTV.EncMapStringStringV(*v, e) case map[string][]byte: fastpathTV.EncMapStringBytesV(v, e) case *map[string][]byte: fastpathTV.EncMapStringBytesV(*v, e) case map[string]uint: fastpathTV.EncMapStringUintV(v, e) case *map[string]uint: fastpathTV.EncMapStringUintV(*v, e) case map[string]uint8: fastpathTV.EncMapStringUint8V(v, e) case *map[string]uint8: fastpathTV.EncMapStringUint8V(*v, e) case map[string]uint64: fastpathTV.EncMapStringUint64V(v, e) case *map[string]uint64: fastpathTV.EncMapStringUint64V(*v, e) case map[string]uintptr: fastpathTV.EncMapStringUintptrV(v, e) case *map[string]uintptr: fastpathTV.EncMapStringUintptrV(*v, e) case map[string]int: fastpathTV.EncMapStringIntV(v, e) case *map[string]int: fastpathTV.EncMapStringIntV(*v, e) case map[string]int64: fastpathTV.EncMapStringInt64V(v, e) case *map[string]int64: fastpathTV.EncMapStringInt64V(*v, e) case map[string]float32: fastpathTV.EncMapStringFloat32V(v, e) case *map[string]float32: fastpathTV.EncMapStringFloat32V(*v, e) case map[string]float64: fastpathTV.EncMapStringFloat64V(v, e) case *map[string]float64: fastpathTV.EncMapStringFloat64V(*v, e) case map[string]bool: fastpathTV.EncMapStringBoolV(v, e) case *map[string]bool: fastpathTV.EncMapStringBoolV(*v, e) case map[uint]interface{}: fastpathTV.EncMapUintIntfV(v, e) case *map[uint]interface{}: fastpathTV.EncMapUintIntfV(*v, e) case map[uint]string: fastpathTV.EncMapUintStringV(v, e) case *map[uint]string: fastpathTV.EncMapUintStringV(*v, e) case map[uint][]byte: fastpathTV.EncMapUintBytesV(v, e) case *map[uint][]byte: fastpathTV.EncMapUintBytesV(*v, e) case map[uint]uint: fastpathTV.EncMapUintUintV(v, e) case *map[uint]uint: fastpathTV.EncMapUintUintV(*v, e) case map[uint]uint8: fastpathTV.EncMapUintUint8V(v, e) case *map[uint]uint8: fastpathTV.EncMapUintUint8V(*v, e) case map[uint]uint64: fastpathTV.EncMapUintUint64V(v, e) case *map[uint]uint64: fastpathTV.EncMapUintUint64V(*v, e) case map[uint]uintptr: fastpathTV.EncMapUintUintptrV(v, e) case *map[uint]uintptr: fastpathTV.EncMapUintUintptrV(*v, e) case map[uint]int: fastpathTV.EncMapUintIntV(v, e) case *map[uint]int: fastpathTV.EncMapUintIntV(*v, e) case map[uint]int64: fastpathTV.EncMapUintInt64V(v, e) case *map[uint]int64: fastpathTV.EncMapUintInt64V(*v, e) case map[uint]float32: fastpathTV.EncMapUintFloat32V(v, e) case *map[uint]float32: fastpathTV.EncMapUintFloat32V(*v, e) case map[uint]float64: fastpathTV.EncMapUintFloat64V(v, e) case *map[uint]float64: fastpathTV.EncMapUintFloat64V(*v, e) case map[uint]bool: fastpathTV.EncMapUintBoolV(v, e) case *map[uint]bool: fastpathTV.EncMapUintBoolV(*v, e) case map[uint8]interface{}: fastpathTV.EncMapUint8IntfV(v, e) case *map[uint8]interface{}: fastpathTV.EncMapUint8IntfV(*v, e) case map[uint8]string: fastpathTV.EncMapUint8StringV(v, e) case *map[uint8]string: fastpathTV.EncMapUint8StringV(*v, e) case map[uint8][]byte: fastpathTV.EncMapUint8BytesV(v, e) case *map[uint8][]byte: fastpathTV.EncMapUint8BytesV(*v, e) case map[uint8]uint: fastpathTV.EncMapUint8UintV(v, e) case *map[uint8]uint: fastpathTV.EncMapUint8UintV(*v, e) case map[uint8]uint8: fastpathTV.EncMapUint8Uint8V(v, e) case *map[uint8]uint8: fastpathTV.EncMapUint8Uint8V(*v, e) case map[uint8]uint64: fastpathTV.EncMapUint8Uint64V(v, e) case *map[uint8]uint64: fastpathTV.EncMapUint8Uint64V(*v, e) case map[uint8]uintptr: fastpathTV.EncMapUint8UintptrV(v, e) case *map[uint8]uintptr: fastpathTV.EncMapUint8UintptrV(*v, e) case map[uint8]int: fastpathTV.EncMapUint8IntV(v, e) case *map[uint8]int: fastpathTV.EncMapUint8IntV(*v, e) case map[uint8]int64: fastpathTV.EncMapUint8Int64V(v, e) case *map[uint8]int64: fastpathTV.EncMapUint8Int64V(*v, e) case map[uint8]float32: fastpathTV.EncMapUint8Float32V(v, e) case *map[uint8]float32: fastpathTV.EncMapUint8Float32V(*v, e) case map[uint8]float64: fastpathTV.EncMapUint8Float64V(v, e) case *map[uint8]float64: fastpathTV.EncMapUint8Float64V(*v, e) case map[uint8]bool: fastpathTV.EncMapUint8BoolV(v, e) case *map[uint8]bool: fastpathTV.EncMapUint8BoolV(*v, e) case map[uint64]interface{}: fastpathTV.EncMapUint64IntfV(v, e) case *map[uint64]interface{}: fastpathTV.EncMapUint64IntfV(*v, e) case map[uint64]string: fastpathTV.EncMapUint64StringV(v, e) case *map[uint64]string: fastpathTV.EncMapUint64StringV(*v, e) case map[uint64][]byte: fastpathTV.EncMapUint64BytesV(v, e) case *map[uint64][]byte: fastpathTV.EncMapUint64BytesV(*v, e) case map[uint64]uint: fastpathTV.EncMapUint64UintV(v, e) case *map[uint64]uint: fastpathTV.EncMapUint64UintV(*v, e) case map[uint64]uint8: fastpathTV.EncMapUint64Uint8V(v, e) case *map[uint64]uint8: fastpathTV.EncMapUint64Uint8V(*v, e) case map[uint64]uint64: fastpathTV.EncMapUint64Uint64V(v, e) case *map[uint64]uint64: fastpathTV.EncMapUint64Uint64V(*v, e) case map[uint64]uintptr: fastpathTV.EncMapUint64UintptrV(v, e) case *map[uint64]uintptr: fastpathTV.EncMapUint64UintptrV(*v, e) case map[uint64]int: fastpathTV.EncMapUint64IntV(v, e) case *map[uint64]int: fastpathTV.EncMapUint64IntV(*v, e) case map[uint64]int64: fastpathTV.EncMapUint64Int64V(v, e) case *map[uint64]int64: fastpathTV.EncMapUint64Int64V(*v, e) case map[uint64]float32: fastpathTV.EncMapUint64Float32V(v, e) case *map[uint64]float32: fastpathTV.EncMapUint64Float32V(*v, e) case map[uint64]float64: fastpathTV.EncMapUint64Float64V(v, e) case *map[uint64]float64: fastpathTV.EncMapUint64Float64V(*v, e) case map[uint64]bool: fastpathTV.EncMapUint64BoolV(v, e) case *map[uint64]bool: fastpathTV.EncMapUint64BoolV(*v, e) case map[int]interface{}: fastpathTV.EncMapIntIntfV(v, e) case *map[int]interface{}: fastpathTV.EncMapIntIntfV(*v, e) case map[int]string: fastpathTV.EncMapIntStringV(v, e) case *map[int]string: fastpathTV.EncMapIntStringV(*v, e) case map[int][]byte: fastpathTV.EncMapIntBytesV(v, e) case *map[int][]byte: fastpathTV.EncMapIntBytesV(*v, e) case map[int]uint: fastpathTV.EncMapIntUintV(v, e) case *map[int]uint: fastpathTV.EncMapIntUintV(*v, e) case map[int]uint8: fastpathTV.EncMapIntUint8V(v, e) case *map[int]uint8: fastpathTV.EncMapIntUint8V(*v, e) case map[int]uint64: fastpathTV.EncMapIntUint64V(v, e) case *map[int]uint64: fastpathTV.EncMapIntUint64V(*v, e) case map[int]uintptr: fastpathTV.EncMapIntUintptrV(v, e) case *map[int]uintptr: fastpathTV.EncMapIntUintptrV(*v, e) case map[int]int: fastpathTV.EncMapIntIntV(v, e) case *map[int]int: fastpathTV.EncMapIntIntV(*v, e) case map[int]int64: fastpathTV.EncMapIntInt64V(v, e) case *map[int]int64: fastpathTV.EncMapIntInt64V(*v, e) case map[int]float32: fastpathTV.EncMapIntFloat32V(v, e) case *map[int]float32: fastpathTV.EncMapIntFloat32V(*v, e) case map[int]float64: fastpathTV.EncMapIntFloat64V(v, e) case *map[int]float64: fastpathTV.EncMapIntFloat64V(*v, e) case map[int]bool: fastpathTV.EncMapIntBoolV(v, e) case *map[int]bool: fastpathTV.EncMapIntBoolV(*v, e) case map[int64]interface{}: fastpathTV.EncMapInt64IntfV(v, e) case *map[int64]interface{}: fastpathTV.EncMapInt64IntfV(*v, e) case map[int64]string: fastpathTV.EncMapInt64StringV(v, e) case *map[int64]string: fastpathTV.EncMapInt64StringV(*v, e) case map[int64][]byte: fastpathTV.EncMapInt64BytesV(v, e) case *map[int64][]byte: fastpathTV.EncMapInt64BytesV(*v, e) case map[int64]uint: fastpathTV.EncMapInt64UintV(v, e) case *map[int64]uint: fastpathTV.EncMapInt64UintV(*v, e) case map[int64]uint8: fastpathTV.EncMapInt64Uint8V(v, e) case *map[int64]uint8: fastpathTV.EncMapInt64Uint8V(*v, e) case map[int64]uint64: fastpathTV.EncMapInt64Uint64V(v, e) case *map[int64]uint64: fastpathTV.EncMapInt64Uint64V(*v, e) case map[int64]uintptr: fastpathTV.EncMapInt64UintptrV(v, e) case *map[int64]uintptr: fastpathTV.EncMapInt64UintptrV(*v, e) case map[int64]int: fastpathTV.EncMapInt64IntV(v, e) case *map[int64]int: fastpathTV.EncMapInt64IntV(*v, e) case map[int64]int64: fastpathTV.EncMapInt64Int64V(v, e) case *map[int64]int64: fastpathTV.EncMapInt64Int64V(*v, e) case map[int64]float32: fastpathTV.EncMapInt64Float32V(v, e) case *map[int64]float32: fastpathTV.EncMapInt64Float32V(*v, e) case map[int64]float64: fastpathTV.EncMapInt64Float64V(v, e) case *map[int64]float64: fastpathTV.EncMapInt64Float64V(*v, e) case map[int64]bool: fastpathTV.EncMapInt64BoolV(v, e) case *map[int64]bool: fastpathTV.EncMapInt64BoolV(*v, e) default: _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4 return false } return true } // -- -- fast path functions func (e *Encoder) fastpathEncSliceIntfR(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceIntfV(rv2i(rv).([]interface{}), e) } else { fastpathTV.EncSliceIntfV(rv2i(rv).([]interface{}), e) } } func (fastpathT) EncSliceIntfV(v []interface{}, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.encode(v[j]) } e.arrayEnd() } func (fastpathT) EncAsMapSliceIntfV(v []interface{}, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.encode(v[j]) } e.mapEnd() } } func (e *Encoder) fastpathEncSliceStringR(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceStringV(rv2i(rv).([]string), e) } else { fastpathTV.EncSliceStringV(rv2i(rv).([]string), e) } } func (fastpathT) EncSliceStringV(v []string, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(v[j])) } else { e.e.EncodeStringEnc(cUTF8, v[j]) } } e.arrayEnd() } func (fastpathT) EncAsMapSliceStringV(v []string, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(v[j])) } else { e.e.EncodeStringEnc(cUTF8, v[j]) } } e.mapEnd() } } func (e *Encoder) fastpathEncSliceBytesR(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceBytesV(rv2i(rv).([][]byte), e) } else { fastpathTV.EncSliceBytesV(rv2i(rv).([][]byte), e) } } func (fastpathT) EncSliceBytesV(v [][]byte, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.e.EncodeStringBytesRaw(v[j]) } e.arrayEnd() } func (fastpathT) EncAsMapSliceBytesV(v [][]byte, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.e.EncodeStringBytesRaw(v[j]) } e.mapEnd() } } func (e *Encoder) fastpathEncSliceFloat32R(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceFloat32V(rv2i(rv).([]float32), e) } else { fastpathTV.EncSliceFloat32V(rv2i(rv).([]float32), e) } } func (fastpathT) EncSliceFloat32V(v []float32, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.e.EncodeFloat32(v[j]) } e.arrayEnd() } func (fastpathT) EncAsMapSliceFloat32V(v []float32, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.e.EncodeFloat32(v[j]) } e.mapEnd() } } func (e *Encoder) fastpathEncSliceFloat64R(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceFloat64V(rv2i(rv).([]float64), e) } else { fastpathTV.EncSliceFloat64V(rv2i(rv).([]float64), e) } } func (fastpathT) EncSliceFloat64V(v []float64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.e.EncodeFloat64(v[j]) } e.arrayEnd() } func (fastpathT) EncAsMapSliceFloat64V(v []float64, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.e.EncodeFloat64(v[j]) } e.mapEnd() } } func (e *Encoder) fastpathEncSliceUintR(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceUintV(rv2i(rv).([]uint), e) } else { fastpathTV.EncSliceUintV(rv2i(rv).([]uint), e) } } func (fastpathT) EncSliceUintV(v []uint, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.e.EncodeUint(uint64(v[j])) } e.arrayEnd() } func (fastpathT) EncAsMapSliceUintV(v []uint, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.e.EncodeUint(uint64(v[j])) } e.mapEnd() } } func (e *Encoder) fastpathEncSliceUint8R(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceUint8V(rv2i(rv).([]uint8), e) } else { fastpathTV.EncSliceUint8V(rv2i(rv).([]uint8), e) } } func (fastpathT) EncSliceUint8V(v []uint8, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.e.EncodeUint(uint64(v[j])) } e.arrayEnd() } func (fastpathT) EncAsMapSliceUint8V(v []uint8, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.e.EncodeUint(uint64(v[j])) } e.mapEnd() } } func (e *Encoder) fastpathEncSliceUint16R(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceUint16V(rv2i(rv).([]uint16), e) } else { fastpathTV.EncSliceUint16V(rv2i(rv).([]uint16), e) } } func (fastpathT) EncSliceUint16V(v []uint16, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.e.EncodeUint(uint64(v[j])) } e.arrayEnd() } func (fastpathT) EncAsMapSliceUint16V(v []uint16, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.e.EncodeUint(uint64(v[j])) } e.mapEnd() } } func (e *Encoder) fastpathEncSliceUint32R(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceUint32V(rv2i(rv).([]uint32), e) } else { fastpathTV.EncSliceUint32V(rv2i(rv).([]uint32), e) } } func (fastpathT) EncSliceUint32V(v []uint32, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.e.EncodeUint(uint64(v[j])) } e.arrayEnd() } func (fastpathT) EncAsMapSliceUint32V(v []uint32, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.e.EncodeUint(uint64(v[j])) } e.mapEnd() } } func (e *Encoder) fastpathEncSliceUint64R(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceUint64V(rv2i(rv).([]uint64), e) } else { fastpathTV.EncSliceUint64V(rv2i(rv).([]uint64), e) } } func (fastpathT) EncSliceUint64V(v []uint64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.e.EncodeUint(v[j]) } e.arrayEnd() } func (fastpathT) EncAsMapSliceUint64V(v []uint64, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.e.EncodeUint(v[j]) } e.mapEnd() } } func (e *Encoder) fastpathEncSliceUintptrR(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceUintptrV(rv2i(rv).([]uintptr), e) } else { fastpathTV.EncSliceUintptrV(rv2i(rv).([]uintptr), e) } } func (fastpathT) EncSliceUintptrV(v []uintptr, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.encode(v[j]) } e.arrayEnd() } func (fastpathT) EncAsMapSliceUintptrV(v []uintptr, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.encode(v[j]) } e.mapEnd() } } func (e *Encoder) fastpathEncSliceIntR(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceIntV(rv2i(rv).([]int), e) } else { fastpathTV.EncSliceIntV(rv2i(rv).([]int), e) } } func (fastpathT) EncSliceIntV(v []int, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.e.EncodeInt(int64(v[j])) } e.arrayEnd() } func (fastpathT) EncAsMapSliceIntV(v []int, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.e.EncodeInt(int64(v[j])) } e.mapEnd() } } func (e *Encoder) fastpathEncSliceInt8R(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceInt8V(rv2i(rv).([]int8), e) } else { fastpathTV.EncSliceInt8V(rv2i(rv).([]int8), e) } } func (fastpathT) EncSliceInt8V(v []int8, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.e.EncodeInt(int64(v[j])) } e.arrayEnd() } func (fastpathT) EncAsMapSliceInt8V(v []int8, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.e.EncodeInt(int64(v[j])) } e.mapEnd() } } func (e *Encoder) fastpathEncSliceInt16R(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceInt16V(rv2i(rv).([]int16), e) } else { fastpathTV.EncSliceInt16V(rv2i(rv).([]int16), e) } } func (fastpathT) EncSliceInt16V(v []int16, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.e.EncodeInt(int64(v[j])) } e.arrayEnd() } func (fastpathT) EncAsMapSliceInt16V(v []int16, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.e.EncodeInt(int64(v[j])) } e.mapEnd() } } func (e *Encoder) fastpathEncSliceInt32R(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceInt32V(rv2i(rv).([]int32), e) } else { fastpathTV.EncSliceInt32V(rv2i(rv).([]int32), e) } } func (fastpathT) EncSliceInt32V(v []int32, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.e.EncodeInt(int64(v[j])) } e.arrayEnd() } func (fastpathT) EncAsMapSliceInt32V(v []int32, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.e.EncodeInt(int64(v[j])) } e.mapEnd() } } func (e *Encoder) fastpathEncSliceInt64R(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceInt64V(rv2i(rv).([]int64), e) } else { fastpathTV.EncSliceInt64V(rv2i(rv).([]int64), e) } } func (fastpathT) EncSliceInt64V(v []int64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.e.EncodeInt(v[j]) } e.arrayEnd() } func (fastpathT) EncAsMapSliceInt64V(v []int64, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.e.EncodeInt(v[j]) } e.mapEnd() } } func (e *Encoder) fastpathEncSliceBoolR(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.EncAsMapSliceBoolV(rv2i(rv).([]bool), e) } else { fastpathTV.EncSliceBoolV(rv2i(rv).([]bool), e) } } func (fastpathT) EncSliceBoolV(v []bool, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() e.e.EncodeBool(v[j]) } e.arrayEnd() } func (fastpathT) EncAsMapSliceBoolV(v []bool, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } e.e.EncodeBool(v[j]) } e.mapEnd() } } func (e *Encoder) fastpathEncMapStringIntfR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapStringIntfV(rv2i(rv).(map[string]interface{}), e) } func (fastpathT) EncMapStringIntfV(v map[string]interface{}, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]string, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(stringSlice(v2)) for _, k2 := range v2 { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.encode(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.encode(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapStringStringR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapStringStringV(rv2i(rv).(map[string]string), e) } func (fastpathT) EncMapStringStringV(v map[string]string, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]string, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(stringSlice(v2)) for _, k2 := range v2 { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(v[k2])) } else { e.e.EncodeStringEnc(cUTF8, v[k2]) } } } else { for k2, v2 := range v { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(v2)) } else { e.e.EncodeStringEnc(cUTF8, v2) } } } e.mapEnd() } func (e *Encoder) fastpathEncMapStringBytesR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapStringBytesV(rv2i(rv).(map[string][]byte), e) } func (fastpathT) EncMapStringBytesV(v map[string][]byte, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]string, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(stringSlice(v2)) for _, k2 := range v2 { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeStringBytesRaw(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeStringBytesRaw(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapStringUintR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapStringUintV(rv2i(rv).(map[string]uint), e) } func (fastpathT) EncMapStringUintV(v map[string]uint, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]string, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(stringSlice(v2)) for _, k2 := range v2 { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeUint(uint64(v[k2])) } } else { for k2, v2 := range v { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeUint(uint64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapStringUint8R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapStringUint8V(rv2i(rv).(map[string]uint8), e) } func (fastpathT) EncMapStringUint8V(v map[string]uint8, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]string, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(stringSlice(v2)) for _, k2 := range v2 { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeUint(uint64(v[k2])) } } else { for k2, v2 := range v { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeUint(uint64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapStringUint64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapStringUint64V(rv2i(rv).(map[string]uint64), e) } func (fastpathT) EncMapStringUint64V(v map[string]uint64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]string, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(stringSlice(v2)) for _, k2 := range v2 { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeUint(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeUint(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapStringUintptrR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapStringUintptrV(rv2i(rv).(map[string]uintptr), e) } func (fastpathT) EncMapStringUintptrV(v map[string]uintptr, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]string, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(stringSlice(v2)) for _, k2 := range v2 { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.encode(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.encode(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapStringIntR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapStringIntV(rv2i(rv).(map[string]int), e) } func (fastpathT) EncMapStringIntV(v map[string]int, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]string, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(stringSlice(v2)) for _, k2 := range v2 { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeInt(int64(v[k2])) } } else { for k2, v2 := range v { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeInt(int64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapStringInt64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapStringInt64V(rv2i(rv).(map[string]int64), e) } func (fastpathT) EncMapStringInt64V(v map[string]int64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]string, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(stringSlice(v2)) for _, k2 := range v2 { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeInt(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeInt(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapStringFloat32R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapStringFloat32V(rv2i(rv).(map[string]float32), e) } func (fastpathT) EncMapStringFloat32V(v map[string]float32, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]string, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(stringSlice(v2)) for _, k2 := range v2 { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeFloat32(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeFloat32(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapStringFloat64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapStringFloat64V(rv2i(rv).(map[string]float64), e) } func (fastpathT) EncMapStringFloat64V(v map[string]float64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]string, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(stringSlice(v2)) for _, k2 := range v2 { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeFloat64(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeFloat64(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapStringBoolR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapStringBoolV(rv2i(rv).(map[string]bool), e) } func (fastpathT) EncMapStringBoolV(v map[string]bool, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]string, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(stringSlice(v2)) for _, k2 := range v2 { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeBool(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(k2)) } else { e.e.EncodeStringEnc(cUTF8, k2) } e.mapElemValue() e.e.EncodeBool(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUintIntfR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUintIntfV(rv2i(rv).(map[uint]interface{}), e) } func (fastpathT) EncMapUintIntfV(v map[uint]interface{}, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint(k2))) e.mapElemValue() e.encode(v[uint(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.encode(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUintStringR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUintStringV(rv2i(rv).(map[uint]string), e) } func (fastpathT) EncMapUintStringV(v map[uint]string, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint(k2))) e.mapElemValue() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(v[uint(k2)])) } else { e.e.EncodeStringEnc(cUTF8, v[uint(k2)]) } } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(v2)) } else { e.e.EncodeStringEnc(cUTF8, v2) } } } e.mapEnd() } func (e *Encoder) fastpathEncMapUintBytesR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUintBytesV(rv2i(rv).(map[uint][]byte), e) } func (fastpathT) EncMapUintBytesV(v map[uint][]byte, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint(k2))) e.mapElemValue() e.e.EncodeStringBytesRaw(v[uint(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeStringBytesRaw(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUintUintR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUintUintV(rv2i(rv).(map[uint]uint), e) } func (fastpathT) EncMapUintUintV(v map[uint]uint, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint(k2))) e.mapElemValue() e.e.EncodeUint(uint64(v[uint(k2)])) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeUint(uint64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUintUint8R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUintUint8V(rv2i(rv).(map[uint]uint8), e) } func (fastpathT) EncMapUintUint8V(v map[uint]uint8, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint(k2))) e.mapElemValue() e.e.EncodeUint(uint64(v[uint(k2)])) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeUint(uint64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUintUint64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUintUint64V(rv2i(rv).(map[uint]uint64), e) } func (fastpathT) EncMapUintUint64V(v map[uint]uint64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint(k2))) e.mapElemValue() e.e.EncodeUint(v[uint(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeUint(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUintUintptrR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUintUintptrV(rv2i(rv).(map[uint]uintptr), e) } func (fastpathT) EncMapUintUintptrV(v map[uint]uintptr, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint(k2))) e.mapElemValue() e.encode(v[uint(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.encode(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUintIntR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUintIntV(rv2i(rv).(map[uint]int), e) } func (fastpathT) EncMapUintIntV(v map[uint]int, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint(k2))) e.mapElemValue() e.e.EncodeInt(int64(v[uint(k2)])) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeInt(int64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUintInt64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUintInt64V(rv2i(rv).(map[uint]int64), e) } func (fastpathT) EncMapUintInt64V(v map[uint]int64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint(k2))) e.mapElemValue() e.e.EncodeInt(v[uint(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeInt(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUintFloat32R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUintFloat32V(rv2i(rv).(map[uint]float32), e) } func (fastpathT) EncMapUintFloat32V(v map[uint]float32, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint(k2))) e.mapElemValue() e.e.EncodeFloat32(v[uint(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeFloat32(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUintFloat64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUintFloat64V(rv2i(rv).(map[uint]float64), e) } func (fastpathT) EncMapUintFloat64V(v map[uint]float64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint(k2))) e.mapElemValue() e.e.EncodeFloat64(v[uint(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeFloat64(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUintBoolR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUintBoolV(rv2i(rv).(map[uint]bool), e) } func (fastpathT) EncMapUintBoolV(v map[uint]bool, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint(k2))) e.mapElemValue() e.e.EncodeBool(v[uint(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeBool(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint8IntfR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint8IntfV(rv2i(rv).(map[uint8]interface{}), e) } func (fastpathT) EncMapUint8IntfV(v map[uint8]interface{}, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint8(k2))) e.mapElemValue() e.encode(v[uint8(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.encode(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint8StringR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint8StringV(rv2i(rv).(map[uint8]string), e) } func (fastpathT) EncMapUint8StringV(v map[uint8]string, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint8(k2))) e.mapElemValue() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(v[uint8(k2)])) } else { e.e.EncodeStringEnc(cUTF8, v[uint8(k2)]) } } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(v2)) } else { e.e.EncodeStringEnc(cUTF8, v2) } } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint8BytesR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint8BytesV(rv2i(rv).(map[uint8][]byte), e) } func (fastpathT) EncMapUint8BytesV(v map[uint8][]byte, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint8(k2))) e.mapElemValue() e.e.EncodeStringBytesRaw(v[uint8(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeStringBytesRaw(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint8UintR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint8UintV(rv2i(rv).(map[uint8]uint), e) } func (fastpathT) EncMapUint8UintV(v map[uint8]uint, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint8(k2))) e.mapElemValue() e.e.EncodeUint(uint64(v[uint8(k2)])) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeUint(uint64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint8Uint8R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint8Uint8V(rv2i(rv).(map[uint8]uint8), e) } func (fastpathT) EncMapUint8Uint8V(v map[uint8]uint8, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint8(k2))) e.mapElemValue() e.e.EncodeUint(uint64(v[uint8(k2)])) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeUint(uint64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint8Uint64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint8Uint64V(rv2i(rv).(map[uint8]uint64), e) } func (fastpathT) EncMapUint8Uint64V(v map[uint8]uint64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint8(k2))) e.mapElemValue() e.e.EncodeUint(v[uint8(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeUint(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint8UintptrR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint8UintptrV(rv2i(rv).(map[uint8]uintptr), e) } func (fastpathT) EncMapUint8UintptrV(v map[uint8]uintptr, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint8(k2))) e.mapElemValue() e.encode(v[uint8(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.encode(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint8IntR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint8IntV(rv2i(rv).(map[uint8]int), e) } func (fastpathT) EncMapUint8IntV(v map[uint8]int, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint8(k2))) e.mapElemValue() e.e.EncodeInt(int64(v[uint8(k2)])) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeInt(int64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint8Int64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint8Int64V(rv2i(rv).(map[uint8]int64), e) } func (fastpathT) EncMapUint8Int64V(v map[uint8]int64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint8(k2))) e.mapElemValue() e.e.EncodeInt(v[uint8(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeInt(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint8Float32R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint8Float32V(rv2i(rv).(map[uint8]float32), e) } func (fastpathT) EncMapUint8Float32V(v map[uint8]float32, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint8(k2))) e.mapElemValue() e.e.EncodeFloat32(v[uint8(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeFloat32(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint8Float64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint8Float64V(rv2i(rv).(map[uint8]float64), e) } func (fastpathT) EncMapUint8Float64V(v map[uint8]float64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint8(k2))) e.mapElemValue() e.e.EncodeFloat64(v[uint8(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeFloat64(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint8BoolR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint8BoolV(rv2i(rv).(map[uint8]bool), e) } func (fastpathT) EncMapUint8BoolV(v map[uint8]bool, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = uint64(k) i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(uint64(uint8(k2))) e.mapElemValue() e.e.EncodeBool(v[uint8(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(uint64(k2)) e.mapElemValue() e.e.EncodeBool(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint64IntfR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint64IntfV(rv2i(rv).(map[uint64]interface{}), e) } func (fastpathT) EncMapUint64IntfV(v map[uint64]interface{}, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.encode(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.encode(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint64StringR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint64StringV(rv2i(rv).(map[uint64]string), e) } func (fastpathT) EncMapUint64StringV(v map[uint64]string, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(v[k2])) } else { e.e.EncodeStringEnc(cUTF8, v[k2]) } } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(v2)) } else { e.e.EncodeStringEnc(cUTF8, v2) } } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint64BytesR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint64BytesV(rv2i(rv).(map[uint64][]byte), e) } func (fastpathT) EncMapUint64BytesV(v map[uint64][]byte, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeStringBytesRaw(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeStringBytesRaw(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint64UintR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint64UintV(rv2i(rv).(map[uint64]uint), e) } func (fastpathT) EncMapUint64UintV(v map[uint64]uint, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeUint(uint64(v[k2])) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeUint(uint64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint64Uint8R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint64Uint8V(rv2i(rv).(map[uint64]uint8), e) } func (fastpathT) EncMapUint64Uint8V(v map[uint64]uint8, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeUint(uint64(v[k2])) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeUint(uint64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint64Uint64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint64Uint64V(rv2i(rv).(map[uint64]uint64), e) } func (fastpathT) EncMapUint64Uint64V(v map[uint64]uint64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeUint(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeUint(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint64UintptrR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint64UintptrV(rv2i(rv).(map[uint64]uintptr), e) } func (fastpathT) EncMapUint64UintptrV(v map[uint64]uintptr, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.encode(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.encode(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint64IntR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint64IntV(rv2i(rv).(map[uint64]int), e) } func (fastpathT) EncMapUint64IntV(v map[uint64]int, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeInt(int64(v[k2])) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeInt(int64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint64Int64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint64Int64V(rv2i(rv).(map[uint64]int64), e) } func (fastpathT) EncMapUint64Int64V(v map[uint64]int64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeInt(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeInt(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint64Float32R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint64Float32V(rv2i(rv).(map[uint64]float32), e) } func (fastpathT) EncMapUint64Float32V(v map[uint64]float32, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeFloat32(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeFloat32(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint64Float64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint64Float64V(rv2i(rv).(map[uint64]float64), e) } func (fastpathT) EncMapUint64Float64V(v map[uint64]float64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeFloat64(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeFloat64(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapUint64BoolR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapUint64BoolV(rv2i(rv).(map[uint64]bool), e) } func (fastpathT) EncMapUint64BoolV(v map[uint64]bool, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]uint64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(uint64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeBool(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeUint(k2) e.mapElemValue() e.e.EncodeBool(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapIntIntfR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapIntIntfV(rv2i(rv).(map[int]interface{}), e) } func (fastpathT) EncMapIntIntfV(v map[int]interface{}, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = int64(k) i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(int64(int(k2))) e.mapElemValue() e.encode(v[int(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(int64(k2)) e.mapElemValue() e.encode(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapIntStringR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapIntStringV(rv2i(rv).(map[int]string), e) } func (fastpathT) EncMapIntStringV(v map[int]string, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = int64(k) i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(int64(int(k2))) e.mapElemValue() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(v[int(k2)])) } else { e.e.EncodeStringEnc(cUTF8, v[int(k2)]) } } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(int64(k2)) e.mapElemValue() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(v2)) } else { e.e.EncodeStringEnc(cUTF8, v2) } } } e.mapEnd() } func (e *Encoder) fastpathEncMapIntBytesR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapIntBytesV(rv2i(rv).(map[int][]byte), e) } func (fastpathT) EncMapIntBytesV(v map[int][]byte, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = int64(k) i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(int64(int(k2))) e.mapElemValue() e.e.EncodeStringBytesRaw(v[int(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(int64(k2)) e.mapElemValue() e.e.EncodeStringBytesRaw(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapIntUintR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapIntUintV(rv2i(rv).(map[int]uint), e) } func (fastpathT) EncMapIntUintV(v map[int]uint, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = int64(k) i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(int64(int(k2))) e.mapElemValue() e.e.EncodeUint(uint64(v[int(k2)])) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(int64(k2)) e.mapElemValue() e.e.EncodeUint(uint64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapIntUint8R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapIntUint8V(rv2i(rv).(map[int]uint8), e) } func (fastpathT) EncMapIntUint8V(v map[int]uint8, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = int64(k) i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(int64(int(k2))) e.mapElemValue() e.e.EncodeUint(uint64(v[int(k2)])) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(int64(k2)) e.mapElemValue() e.e.EncodeUint(uint64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapIntUint64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapIntUint64V(rv2i(rv).(map[int]uint64), e) } func (fastpathT) EncMapIntUint64V(v map[int]uint64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = int64(k) i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(int64(int(k2))) e.mapElemValue() e.e.EncodeUint(v[int(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(int64(k2)) e.mapElemValue() e.e.EncodeUint(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapIntUintptrR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapIntUintptrV(rv2i(rv).(map[int]uintptr), e) } func (fastpathT) EncMapIntUintptrV(v map[int]uintptr, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = int64(k) i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(int64(int(k2))) e.mapElemValue() e.encode(v[int(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(int64(k2)) e.mapElemValue() e.encode(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapIntIntR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapIntIntV(rv2i(rv).(map[int]int), e) } func (fastpathT) EncMapIntIntV(v map[int]int, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = int64(k) i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(int64(int(k2))) e.mapElemValue() e.e.EncodeInt(int64(v[int(k2)])) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(int64(k2)) e.mapElemValue() e.e.EncodeInt(int64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapIntInt64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapIntInt64V(rv2i(rv).(map[int]int64), e) } func (fastpathT) EncMapIntInt64V(v map[int]int64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = int64(k) i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(int64(int(k2))) e.mapElemValue() e.e.EncodeInt(v[int(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(int64(k2)) e.mapElemValue() e.e.EncodeInt(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapIntFloat32R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapIntFloat32V(rv2i(rv).(map[int]float32), e) } func (fastpathT) EncMapIntFloat32V(v map[int]float32, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = int64(k) i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(int64(int(k2))) e.mapElemValue() e.e.EncodeFloat32(v[int(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(int64(k2)) e.mapElemValue() e.e.EncodeFloat32(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapIntFloat64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapIntFloat64V(rv2i(rv).(map[int]float64), e) } func (fastpathT) EncMapIntFloat64V(v map[int]float64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = int64(k) i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(int64(int(k2))) e.mapElemValue() e.e.EncodeFloat64(v[int(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(int64(k2)) e.mapElemValue() e.e.EncodeFloat64(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapIntBoolR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapIntBoolV(rv2i(rv).(map[int]bool), e) } func (fastpathT) EncMapIntBoolV(v map[int]bool, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = int64(k) i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(int64(int(k2))) e.mapElemValue() e.e.EncodeBool(v[int(k2)]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(int64(k2)) e.mapElemValue() e.e.EncodeBool(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapInt64IntfR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapInt64IntfV(rv2i(rv).(map[int64]interface{}), e) } func (fastpathT) EncMapInt64IntfV(v map[int64]interface{}, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.encode(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.encode(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapInt64StringR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapInt64StringV(rv2i(rv).(map[int64]string), e) } func (fastpathT) EncMapInt64StringV(v map[int64]string, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(v[k2])) } else { e.e.EncodeStringEnc(cUTF8, v[k2]) } } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(v2)) } else { e.e.EncodeStringEnc(cUTF8, v2) } } } e.mapEnd() } func (e *Encoder) fastpathEncMapInt64BytesR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapInt64BytesV(rv2i(rv).(map[int64][]byte), e) } func (fastpathT) EncMapInt64BytesV(v map[int64][]byte, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeStringBytesRaw(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeStringBytesRaw(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapInt64UintR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapInt64UintV(rv2i(rv).(map[int64]uint), e) } func (fastpathT) EncMapInt64UintV(v map[int64]uint, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeUint(uint64(v[k2])) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeUint(uint64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapInt64Uint8R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapInt64Uint8V(rv2i(rv).(map[int64]uint8), e) } func (fastpathT) EncMapInt64Uint8V(v map[int64]uint8, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeUint(uint64(v[k2])) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeUint(uint64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapInt64Uint64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapInt64Uint64V(rv2i(rv).(map[int64]uint64), e) } func (fastpathT) EncMapInt64Uint64V(v map[int64]uint64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeUint(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeUint(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapInt64UintptrR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapInt64UintptrV(rv2i(rv).(map[int64]uintptr), e) } func (fastpathT) EncMapInt64UintptrV(v map[int64]uintptr, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.encode(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.encode(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapInt64IntR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapInt64IntV(rv2i(rv).(map[int64]int), e) } func (fastpathT) EncMapInt64IntV(v map[int64]int, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeInt(int64(v[k2])) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeInt(int64(v2)) } } e.mapEnd() } func (e *Encoder) fastpathEncMapInt64Int64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapInt64Int64V(rv2i(rv).(map[int64]int64), e) } func (fastpathT) EncMapInt64Int64V(v map[int64]int64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeInt(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeInt(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapInt64Float32R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapInt64Float32V(rv2i(rv).(map[int64]float32), e) } func (fastpathT) EncMapInt64Float32V(v map[int64]float32, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeFloat32(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeFloat32(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapInt64Float64R(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapInt64Float64V(rv2i(rv).(map[int64]float64), e) } func (fastpathT) EncMapInt64Float64V(v map[int64]float64, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeFloat64(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeFloat64(v2) } } e.mapEnd() } func (e *Encoder) fastpathEncMapInt64BoolR(f *codecFnInfo, rv reflect.Value) { fastpathTV.EncMapInt64BoolV(rv2i(rv).(map[int64]bool), e) } func (fastpathT) EncMapInt64BoolV(v map[int64]bool, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.mapStart(len(v)) if e.h.Canonical { v2 := make([]int64, len(v)) var i uint for k := range v { v2[i] = k i++ } sort.Sort(int64Slice(v2)) for _, k2 := range v2 { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeBool(v[k2]) } } else { for k2, v2 := range v { e.mapElemKey() e.e.EncodeInt(k2) e.mapElemValue() e.e.EncodeBool(v2) } } e.mapEnd() } // -- decode // -- -- fast path type switch func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool { var changed bool switch v := iv.(type) { case []interface{}: var v2 []interface{} v2, changed = fastpathTV.DecSliceIntfV(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]interface{}: var v2 []interface{} v2, changed = fastpathTV.DecSliceIntfV(*v, true, d) if changed { *v = v2 } case []string: var v2 []string v2, changed = fastpathTV.DecSliceStringV(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]string: var v2 []string v2, changed = fastpathTV.DecSliceStringV(*v, true, d) if changed { *v = v2 } case [][]byte: var v2 [][]byte v2, changed = fastpathTV.DecSliceBytesV(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[][]byte: var v2 [][]byte v2, changed = fastpathTV.DecSliceBytesV(*v, true, d) if changed { *v = v2 } case []float32: var v2 []float32 v2, changed = fastpathTV.DecSliceFloat32V(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]float32: var v2 []float32 v2, changed = fastpathTV.DecSliceFloat32V(*v, true, d) if changed { *v = v2 } case []float64: var v2 []float64 v2, changed = fastpathTV.DecSliceFloat64V(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]float64: var v2 []float64 v2, changed = fastpathTV.DecSliceFloat64V(*v, true, d) if changed { *v = v2 } case []uint: var v2 []uint v2, changed = fastpathTV.DecSliceUintV(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]uint: var v2 []uint v2, changed = fastpathTV.DecSliceUintV(*v, true, d) if changed { *v = v2 } case []uint16: var v2 []uint16 v2, changed = fastpathTV.DecSliceUint16V(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]uint16: var v2 []uint16 v2, changed = fastpathTV.DecSliceUint16V(*v, true, d) if changed { *v = v2 } case []uint32: var v2 []uint32 v2, changed = fastpathTV.DecSliceUint32V(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]uint32: var v2 []uint32 v2, changed = fastpathTV.DecSliceUint32V(*v, true, d) if changed { *v = v2 } case []uint64: var v2 []uint64 v2, changed = fastpathTV.DecSliceUint64V(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]uint64: var v2 []uint64 v2, changed = fastpathTV.DecSliceUint64V(*v, true, d) if changed { *v = v2 } case []uintptr: var v2 []uintptr v2, changed = fastpathTV.DecSliceUintptrV(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]uintptr: var v2 []uintptr v2, changed = fastpathTV.DecSliceUintptrV(*v, true, d) if changed { *v = v2 } case []int: var v2 []int v2, changed = fastpathTV.DecSliceIntV(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]int: var v2 []int v2, changed = fastpathTV.DecSliceIntV(*v, true, d) if changed { *v = v2 } case []int8: var v2 []int8 v2, changed = fastpathTV.DecSliceInt8V(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]int8: var v2 []int8 v2, changed = fastpathTV.DecSliceInt8V(*v, true, d) if changed { *v = v2 } case []int16: var v2 []int16 v2, changed = fastpathTV.DecSliceInt16V(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]int16: var v2 []int16 v2, changed = fastpathTV.DecSliceInt16V(*v, true, d) if changed { *v = v2 } case []int32: var v2 []int32 v2, changed = fastpathTV.DecSliceInt32V(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]int32: var v2 []int32 v2, changed = fastpathTV.DecSliceInt32V(*v, true, d) if changed { *v = v2 } case []int64: var v2 []int64 v2, changed = fastpathTV.DecSliceInt64V(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]int64: var v2 []int64 v2, changed = fastpathTV.DecSliceInt64V(*v, true, d) if changed { *v = v2 } case []bool: var v2 []bool v2, changed = fastpathTV.DecSliceBoolV(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]bool: var v2 []bool v2, changed = fastpathTV.DecSliceBoolV(*v, true, d) if changed { *v = v2 } case map[string]interface{}: fastpathTV.DecMapStringIntfV(v, false, d) case *map[string]interface{}: var v2 map[string]interface{} v2, changed = fastpathTV.DecMapStringIntfV(*v, true, d) if changed { *v = v2 } case map[string]string: fastpathTV.DecMapStringStringV(v, false, d) case *map[string]string: var v2 map[string]string v2, changed = fastpathTV.DecMapStringStringV(*v, true, d) if changed { *v = v2 } case map[string][]byte: fastpathTV.DecMapStringBytesV(v, false, d) case *map[string][]byte: var v2 map[string][]byte v2, changed = fastpathTV.DecMapStringBytesV(*v, true, d) if changed { *v = v2 } case map[string]uint: fastpathTV.DecMapStringUintV(v, false, d) case *map[string]uint: var v2 map[string]uint v2, changed = fastpathTV.DecMapStringUintV(*v, true, d) if changed { *v = v2 } case map[string]uint8: fastpathTV.DecMapStringUint8V(v, false, d) case *map[string]uint8: var v2 map[string]uint8 v2, changed = fastpathTV.DecMapStringUint8V(*v, true, d) if changed { *v = v2 } case map[string]uint64: fastpathTV.DecMapStringUint64V(v, false, d) case *map[string]uint64: var v2 map[string]uint64 v2, changed = fastpathTV.DecMapStringUint64V(*v, true, d) if changed { *v = v2 } case map[string]uintptr: fastpathTV.DecMapStringUintptrV(v, false, d) case *map[string]uintptr: var v2 map[string]uintptr v2, changed = fastpathTV.DecMapStringUintptrV(*v, true, d) if changed { *v = v2 } case map[string]int: fastpathTV.DecMapStringIntV(v, false, d) case *map[string]int: var v2 map[string]int v2, changed = fastpathTV.DecMapStringIntV(*v, true, d) if changed { *v = v2 } case map[string]int64: fastpathTV.DecMapStringInt64V(v, false, d) case *map[string]int64: var v2 map[string]int64 v2, changed = fastpathTV.DecMapStringInt64V(*v, true, d) if changed { *v = v2 } case map[string]float32: fastpathTV.DecMapStringFloat32V(v, false, d) case *map[string]float32: var v2 map[string]float32 v2, changed = fastpathTV.DecMapStringFloat32V(*v, true, d) if changed { *v = v2 } case map[string]float64: fastpathTV.DecMapStringFloat64V(v, false, d) case *map[string]float64: var v2 map[string]float64 v2, changed = fastpathTV.DecMapStringFloat64V(*v, true, d) if changed { *v = v2 } case map[string]bool: fastpathTV.DecMapStringBoolV(v, false, d) case *map[string]bool: var v2 map[string]bool v2, changed = fastpathTV.DecMapStringBoolV(*v, true, d) if changed { *v = v2 } case map[uint]interface{}: fastpathTV.DecMapUintIntfV(v, false, d) case *map[uint]interface{}: var v2 map[uint]interface{} v2, changed = fastpathTV.DecMapUintIntfV(*v, true, d) if changed { *v = v2 } case map[uint]string: fastpathTV.DecMapUintStringV(v, false, d) case *map[uint]string: var v2 map[uint]string v2, changed = fastpathTV.DecMapUintStringV(*v, true, d) if changed { *v = v2 } case map[uint][]byte: fastpathTV.DecMapUintBytesV(v, false, d) case *map[uint][]byte: var v2 map[uint][]byte v2, changed = fastpathTV.DecMapUintBytesV(*v, true, d) if changed { *v = v2 } case map[uint]uint: fastpathTV.DecMapUintUintV(v, false, d) case *map[uint]uint: var v2 map[uint]uint v2, changed = fastpathTV.DecMapUintUintV(*v, true, d) if changed { *v = v2 } case map[uint]uint8: fastpathTV.DecMapUintUint8V(v, false, d) case *map[uint]uint8: var v2 map[uint]uint8 v2, changed = fastpathTV.DecMapUintUint8V(*v, true, d) if changed { *v = v2 } case map[uint]uint64: fastpathTV.DecMapUintUint64V(v, false, d) case *map[uint]uint64: var v2 map[uint]uint64 v2, changed = fastpathTV.DecMapUintUint64V(*v, true, d) if changed { *v = v2 } case map[uint]uintptr: fastpathTV.DecMapUintUintptrV(v, false, d) case *map[uint]uintptr: var v2 map[uint]uintptr v2, changed = fastpathTV.DecMapUintUintptrV(*v, true, d) if changed { *v = v2 } case map[uint]int: fastpathTV.DecMapUintIntV(v, false, d) case *map[uint]int: var v2 map[uint]int v2, changed = fastpathTV.DecMapUintIntV(*v, true, d) if changed { *v = v2 } case map[uint]int64: fastpathTV.DecMapUintInt64V(v, false, d) case *map[uint]int64: var v2 map[uint]int64 v2, changed = fastpathTV.DecMapUintInt64V(*v, true, d) if changed { *v = v2 } case map[uint]float32: fastpathTV.DecMapUintFloat32V(v, false, d) case *map[uint]float32: var v2 map[uint]float32 v2, changed = fastpathTV.DecMapUintFloat32V(*v, true, d) if changed { *v = v2 } case map[uint]float64: fastpathTV.DecMapUintFloat64V(v, false, d) case *map[uint]float64: var v2 map[uint]float64 v2, changed = fastpathTV.DecMapUintFloat64V(*v, true, d) if changed { *v = v2 } case map[uint]bool: fastpathTV.DecMapUintBoolV(v, false, d) case *map[uint]bool: var v2 map[uint]bool v2, changed = fastpathTV.DecMapUintBoolV(*v, true, d) if changed { *v = v2 } case map[uint8]interface{}: fastpathTV.DecMapUint8IntfV(v, false, d) case *map[uint8]interface{}: var v2 map[uint8]interface{} v2, changed = fastpathTV.DecMapUint8IntfV(*v, true, d) if changed { *v = v2 } case map[uint8]string: fastpathTV.DecMapUint8StringV(v, false, d) case *map[uint8]string: var v2 map[uint8]string v2, changed = fastpathTV.DecMapUint8StringV(*v, true, d) if changed { *v = v2 } case map[uint8][]byte: fastpathTV.DecMapUint8BytesV(v, false, d) case *map[uint8][]byte: var v2 map[uint8][]byte v2, changed = fastpathTV.DecMapUint8BytesV(*v, true, d) if changed { *v = v2 } case map[uint8]uint: fastpathTV.DecMapUint8UintV(v, false, d) case *map[uint8]uint: var v2 map[uint8]uint v2, changed = fastpathTV.DecMapUint8UintV(*v, true, d) if changed { *v = v2 } case map[uint8]uint8: fastpathTV.DecMapUint8Uint8V(v, false, d) case *map[uint8]uint8: var v2 map[uint8]uint8 v2, changed = fastpathTV.DecMapUint8Uint8V(*v, true, d) if changed { *v = v2 } case map[uint8]uint64: fastpathTV.DecMapUint8Uint64V(v, false, d) case *map[uint8]uint64: var v2 map[uint8]uint64 v2, changed = fastpathTV.DecMapUint8Uint64V(*v, true, d) if changed { *v = v2 } case map[uint8]uintptr: fastpathTV.DecMapUint8UintptrV(v, false, d) case *map[uint8]uintptr: var v2 map[uint8]uintptr v2, changed = fastpathTV.DecMapUint8UintptrV(*v, true, d) if changed { *v = v2 } case map[uint8]int: fastpathTV.DecMapUint8IntV(v, false, d) case *map[uint8]int: var v2 map[uint8]int v2, changed = fastpathTV.DecMapUint8IntV(*v, true, d) if changed { *v = v2 } case map[uint8]int64: fastpathTV.DecMapUint8Int64V(v, false, d) case *map[uint8]int64: var v2 map[uint8]int64 v2, changed = fastpathTV.DecMapUint8Int64V(*v, true, d) if changed { *v = v2 } case map[uint8]float32: fastpathTV.DecMapUint8Float32V(v, false, d) case *map[uint8]float32: var v2 map[uint8]float32 v2, changed = fastpathTV.DecMapUint8Float32V(*v, true, d) if changed { *v = v2 } case map[uint8]float64: fastpathTV.DecMapUint8Float64V(v, false, d) case *map[uint8]float64: var v2 map[uint8]float64 v2, changed = fastpathTV.DecMapUint8Float64V(*v, true, d) if changed { *v = v2 } case map[uint8]bool: fastpathTV.DecMapUint8BoolV(v, false, d) case *map[uint8]bool: var v2 map[uint8]bool v2, changed = fastpathTV.DecMapUint8BoolV(*v, true, d) if changed { *v = v2 } case map[uint64]interface{}: fastpathTV.DecMapUint64IntfV(v, false, d) case *map[uint64]interface{}: var v2 map[uint64]interface{} v2, changed = fastpathTV.DecMapUint64IntfV(*v, true, d) if changed { *v = v2 } case map[uint64]string: fastpathTV.DecMapUint64StringV(v, false, d) case *map[uint64]string: var v2 map[uint64]string v2, changed = fastpathTV.DecMapUint64StringV(*v, true, d) if changed { *v = v2 } case map[uint64][]byte: fastpathTV.DecMapUint64BytesV(v, false, d) case *map[uint64][]byte: var v2 map[uint64][]byte v2, changed = fastpathTV.DecMapUint64BytesV(*v, true, d) if changed { *v = v2 } case map[uint64]uint: fastpathTV.DecMapUint64UintV(v, false, d) case *map[uint64]uint: var v2 map[uint64]uint v2, changed = fastpathTV.DecMapUint64UintV(*v, true, d) if changed { *v = v2 } case map[uint64]uint8: fastpathTV.DecMapUint64Uint8V(v, false, d) case *map[uint64]uint8: var v2 map[uint64]uint8 v2, changed = fastpathTV.DecMapUint64Uint8V(*v, true, d) if changed { *v = v2 } case map[uint64]uint64: fastpathTV.DecMapUint64Uint64V(v, false, d) case *map[uint64]uint64: var v2 map[uint64]uint64 v2, changed = fastpathTV.DecMapUint64Uint64V(*v, true, d) if changed { *v = v2 } case map[uint64]uintptr: fastpathTV.DecMapUint64UintptrV(v, false, d) case *map[uint64]uintptr: var v2 map[uint64]uintptr v2, changed = fastpathTV.DecMapUint64UintptrV(*v, true, d) if changed { *v = v2 } case map[uint64]int: fastpathTV.DecMapUint64IntV(v, false, d) case *map[uint64]int: var v2 map[uint64]int v2, changed = fastpathTV.DecMapUint64IntV(*v, true, d) if changed { *v = v2 } case map[uint64]int64: fastpathTV.DecMapUint64Int64V(v, false, d) case *map[uint64]int64: var v2 map[uint64]int64 v2, changed = fastpathTV.DecMapUint64Int64V(*v, true, d) if changed { *v = v2 } case map[uint64]float32: fastpathTV.DecMapUint64Float32V(v, false, d) case *map[uint64]float32: var v2 map[uint64]float32 v2, changed = fastpathTV.DecMapUint64Float32V(*v, true, d) if changed { *v = v2 } case map[uint64]float64: fastpathTV.DecMapUint64Float64V(v, false, d) case *map[uint64]float64: var v2 map[uint64]float64 v2, changed = fastpathTV.DecMapUint64Float64V(*v, true, d) if changed { *v = v2 } case map[uint64]bool: fastpathTV.DecMapUint64BoolV(v, false, d) case *map[uint64]bool: var v2 map[uint64]bool v2, changed = fastpathTV.DecMapUint64BoolV(*v, true, d) if changed { *v = v2 } case map[int]interface{}: fastpathTV.DecMapIntIntfV(v, false, d) case *map[int]interface{}: var v2 map[int]interface{} v2, changed = fastpathTV.DecMapIntIntfV(*v, true, d) if changed { *v = v2 } case map[int]string: fastpathTV.DecMapIntStringV(v, false, d) case *map[int]string: var v2 map[int]string v2, changed = fastpathTV.DecMapIntStringV(*v, true, d) if changed { *v = v2 } case map[int][]byte: fastpathTV.DecMapIntBytesV(v, false, d) case *map[int][]byte: var v2 map[int][]byte v2, changed = fastpathTV.DecMapIntBytesV(*v, true, d) if changed { *v = v2 } case map[int]uint: fastpathTV.DecMapIntUintV(v, false, d) case *map[int]uint: var v2 map[int]uint v2, changed = fastpathTV.DecMapIntUintV(*v, true, d) if changed { *v = v2 } case map[int]uint8: fastpathTV.DecMapIntUint8V(v, false, d) case *map[int]uint8: var v2 map[int]uint8 v2, changed = fastpathTV.DecMapIntUint8V(*v, true, d) if changed { *v = v2 } case map[int]uint64: fastpathTV.DecMapIntUint64V(v, false, d) case *map[int]uint64: var v2 map[int]uint64 v2, changed = fastpathTV.DecMapIntUint64V(*v, true, d) if changed { *v = v2 } case map[int]uintptr: fastpathTV.DecMapIntUintptrV(v, false, d) case *map[int]uintptr: var v2 map[int]uintptr v2, changed = fastpathTV.DecMapIntUintptrV(*v, true, d) if changed { *v = v2 } case map[int]int: fastpathTV.DecMapIntIntV(v, false, d) case *map[int]int: var v2 map[int]int v2, changed = fastpathTV.DecMapIntIntV(*v, true, d) if changed { *v = v2 } case map[int]int64: fastpathTV.DecMapIntInt64V(v, false, d) case *map[int]int64: var v2 map[int]int64 v2, changed = fastpathTV.DecMapIntInt64V(*v, true, d) if changed { *v = v2 } case map[int]float32: fastpathTV.DecMapIntFloat32V(v, false, d) case *map[int]float32: var v2 map[int]float32 v2, changed = fastpathTV.DecMapIntFloat32V(*v, true, d) if changed { *v = v2 } case map[int]float64: fastpathTV.DecMapIntFloat64V(v, false, d) case *map[int]float64: var v2 map[int]float64 v2, changed = fastpathTV.DecMapIntFloat64V(*v, true, d) if changed { *v = v2 } case map[int]bool: fastpathTV.DecMapIntBoolV(v, false, d) case *map[int]bool: var v2 map[int]bool v2, changed = fastpathTV.DecMapIntBoolV(*v, true, d) if changed { *v = v2 } case map[int64]interface{}: fastpathTV.DecMapInt64IntfV(v, false, d) case *map[int64]interface{}: var v2 map[int64]interface{} v2, changed = fastpathTV.DecMapInt64IntfV(*v, true, d) if changed { *v = v2 } case map[int64]string: fastpathTV.DecMapInt64StringV(v, false, d) case *map[int64]string: var v2 map[int64]string v2, changed = fastpathTV.DecMapInt64StringV(*v, true, d) if changed { *v = v2 } case map[int64][]byte: fastpathTV.DecMapInt64BytesV(v, false, d) case *map[int64][]byte: var v2 map[int64][]byte v2, changed = fastpathTV.DecMapInt64BytesV(*v, true, d) if changed { *v = v2 } case map[int64]uint: fastpathTV.DecMapInt64UintV(v, false, d) case *map[int64]uint: var v2 map[int64]uint v2, changed = fastpathTV.DecMapInt64UintV(*v, true, d) if changed { *v = v2 } case map[int64]uint8: fastpathTV.DecMapInt64Uint8V(v, false, d) case *map[int64]uint8: var v2 map[int64]uint8 v2, changed = fastpathTV.DecMapInt64Uint8V(*v, true, d) if changed { *v = v2 } case map[int64]uint64: fastpathTV.DecMapInt64Uint64V(v, false, d) case *map[int64]uint64: var v2 map[int64]uint64 v2, changed = fastpathTV.DecMapInt64Uint64V(*v, true, d) if changed { *v = v2 } case map[int64]uintptr: fastpathTV.DecMapInt64UintptrV(v, false, d) case *map[int64]uintptr: var v2 map[int64]uintptr v2, changed = fastpathTV.DecMapInt64UintptrV(*v, true, d) if changed { *v = v2 } case map[int64]int: fastpathTV.DecMapInt64IntV(v, false, d) case *map[int64]int: var v2 map[int64]int v2, changed = fastpathTV.DecMapInt64IntV(*v, true, d) if changed { *v = v2 } case map[int64]int64: fastpathTV.DecMapInt64Int64V(v, false, d) case *map[int64]int64: var v2 map[int64]int64 v2, changed = fastpathTV.DecMapInt64Int64V(*v, true, d) if changed { *v = v2 } case map[int64]float32: fastpathTV.DecMapInt64Float32V(v, false, d) case *map[int64]float32: var v2 map[int64]float32 v2, changed = fastpathTV.DecMapInt64Float32V(*v, true, d) if changed { *v = v2 } case map[int64]float64: fastpathTV.DecMapInt64Float64V(v, false, d) case *map[int64]float64: var v2 map[int64]float64 v2, changed = fastpathTV.DecMapInt64Float64V(*v, true, d) if changed { *v = v2 } case map[int64]bool: fastpathTV.DecMapInt64BoolV(v, false, d) case *map[int64]bool: var v2 map[int64]bool v2, changed = fastpathTV.DecMapInt64BoolV(*v, true, d) if changed { *v = v2 } default: _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4 return false } return true } func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool { switch v := iv.(type) { case *[]interface{}: *v = nil case *[]string: *v = nil case *[][]byte: *v = nil case *[]float32: *v = nil case *[]float64: *v = nil case *[]uint: *v = nil case *[]uint8: *v = nil case *[]uint16: *v = nil case *[]uint32: *v = nil case *[]uint64: *v = nil case *[]uintptr: *v = nil case *[]int: *v = nil case *[]int8: *v = nil case *[]int16: *v = nil case *[]int32: *v = nil case *[]int64: *v = nil case *[]bool: *v = nil case *map[string]interface{}: *v = nil case *map[string]string: *v = nil case *map[string][]byte: *v = nil case *map[string]uint: *v = nil case *map[string]uint8: *v = nil case *map[string]uint64: *v = nil case *map[string]uintptr: *v = nil case *map[string]int: *v = nil case *map[string]int64: *v = nil case *map[string]float32: *v = nil case *map[string]float64: *v = nil case *map[string]bool: *v = nil case *map[uint]interface{}: *v = nil case *map[uint]string: *v = nil case *map[uint][]byte: *v = nil case *map[uint]uint: *v = nil case *map[uint]uint8: *v = nil case *map[uint]uint64: *v = nil case *map[uint]uintptr: *v = nil case *map[uint]int: *v = nil case *map[uint]int64: *v = nil case *map[uint]float32: *v = nil case *map[uint]float64: *v = nil case *map[uint]bool: *v = nil case *map[uint8]interface{}: *v = nil case *map[uint8]string: *v = nil case *map[uint8][]byte: *v = nil case *map[uint8]uint: *v = nil case *map[uint8]uint8: *v = nil case *map[uint8]uint64: *v = nil case *map[uint8]uintptr: *v = nil case *map[uint8]int: *v = nil case *map[uint8]int64: *v = nil case *map[uint8]float32: *v = nil case *map[uint8]float64: *v = nil case *map[uint8]bool: *v = nil case *map[uint64]interface{}: *v = nil case *map[uint64]string: *v = nil case *map[uint64][]byte: *v = nil case *map[uint64]uint: *v = nil case *map[uint64]uint8: *v = nil case *map[uint64]uint64: *v = nil case *map[uint64]uintptr: *v = nil case *map[uint64]int: *v = nil case *map[uint64]int64: *v = nil case *map[uint64]float32: *v = nil case *map[uint64]float64: *v = nil case *map[uint64]bool: *v = nil case *map[int]interface{}: *v = nil case *map[int]string: *v = nil case *map[int][]byte: *v = nil case *map[int]uint: *v = nil case *map[int]uint8: *v = nil case *map[int]uint64: *v = nil case *map[int]uintptr: *v = nil case *map[int]int: *v = nil case *map[int]int64: *v = nil case *map[int]float32: *v = nil case *map[int]float64: *v = nil case *map[int]bool: *v = nil case *map[int64]interface{}: *v = nil case *map[int64]string: *v = nil case *map[int64][]byte: *v = nil case *map[int64]uint: *v = nil case *map[int64]uint8: *v = nil case *map[int64]uint64: *v = nil case *map[int64]uintptr: *v = nil case *map[int64]int: *v = nil case *map[int64]int64: *v = nil case *map[int64]float32: *v = nil case *map[int64]float64: *v = nil case *map[int64]bool: *v = nil default: _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4 return false } return true } // -- -- fast path functions func (d *Decoder) fastpathDecSliceIntfR(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]interface{}) if v, changed := fastpathTV.DecSliceIntfV(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]interface{}) v2, changed := fastpathTV.DecSliceIntfV(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceIntfX(vp *[]interface{}, d *Decoder) { if v, changed := f.DecSliceIntfV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceIntfV(v []interface{}, canChange bool, d *Decoder) (_ []interface{}, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []interface{}{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 16) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]interface{}, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 16) } else { xlen = 8 } v = make([]interface{}, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, nil) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = nil } else { d.decode(&v[uint(j)]) } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]interface{}, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceStringR(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]string) if v, changed := fastpathTV.DecSliceStringV(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]string) v2, changed := fastpathTV.DecSliceStringV(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceStringX(vp *[]string, d *Decoder) { if v, changed := f.DecSliceStringV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceStringV(v []string, canChange bool, d *Decoder) (_ []string, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []string{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 16) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]string, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 16) } else { xlen = 8 } v = make([]string, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, "") changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = "" } else { v[uint(j)] = d.d.DecodeString() } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]string, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceBytesR(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[][]byte) if v, changed := fastpathTV.DecSliceBytesV(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([][]byte) v2, changed := fastpathTV.DecSliceBytesV(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceBytesX(vp *[][]byte, d *Decoder) { if v, changed := f.DecSliceBytesV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceBytesV(v [][]byte, canChange bool, d *Decoder) (_ [][]byte, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = [][]byte{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 24) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([][]byte, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 24) } else { xlen = 8 } v = make([][]byte, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, nil) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = nil } else { v[uint(j)] = d.d.DecodeBytes(nil, false) } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([][]byte, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceFloat32R(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]float32) if v, changed := fastpathTV.DecSliceFloat32V(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]float32) v2, changed := fastpathTV.DecSliceFloat32V(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceFloat32X(vp *[]float32, d *Decoder) { if v, changed := f.DecSliceFloat32V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceFloat32V(v []float32, canChange bool, d *Decoder) (_ []float32, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []float32{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 4) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]float32, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 4) } else { xlen = 8 } v = make([]float32, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, 0) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = 0 } else { v[uint(j)] = float32(d.decodeFloat32()) } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]float32, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceFloat64R(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]float64) if v, changed := fastpathTV.DecSliceFloat64V(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]float64) v2, changed := fastpathTV.DecSliceFloat64V(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceFloat64X(vp *[]float64, d *Decoder) { if v, changed := f.DecSliceFloat64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceFloat64V(v []float64, canChange bool, d *Decoder) (_ []float64, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []float64{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]float64, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) } else { xlen = 8 } v = make([]float64, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, 0) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = 0 } else { v[uint(j)] = d.d.DecodeFloat64() } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]float64, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceUintR(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]uint) if v, changed := fastpathTV.DecSliceUintV(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]uint) v2, changed := fastpathTV.DecSliceUintV(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceUintX(vp *[]uint, d *Decoder) { if v, changed := f.DecSliceUintV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceUintV(v []uint, canChange bool, d *Decoder) (_ []uint, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []uint{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]uint, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) } else { xlen = 8 } v = make([]uint, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, 0) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = 0 } else { v[uint(j)] = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]uint, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceUint8R(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]uint8) if v, changed := fastpathTV.DecSliceUint8V(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]uint8) v2, changed := fastpathTV.DecSliceUint8V(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceUint8X(vp *[]uint8, d *Decoder) { if v, changed := f.DecSliceUint8V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceUint8V(v []uint8, canChange bool, d *Decoder) (_ []uint8, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []uint8{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 1) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]uint8, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 1) } else { xlen = 8 } v = make([]uint8, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, 0) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = 0 } else { v[uint(j)] = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]uint8, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceUint16R(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]uint16) if v, changed := fastpathTV.DecSliceUint16V(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]uint16) v2, changed := fastpathTV.DecSliceUint16V(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceUint16X(vp *[]uint16, d *Decoder) { if v, changed := f.DecSliceUint16V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceUint16V(v []uint16, canChange bool, d *Decoder) (_ []uint16, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []uint16{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 2) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]uint16, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 2) } else { xlen = 8 } v = make([]uint16, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, 0) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = 0 } else { v[uint(j)] = uint16(chkOvf.UintV(d.d.DecodeUint64(), 16)) } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]uint16, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceUint32R(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]uint32) if v, changed := fastpathTV.DecSliceUint32V(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]uint32) v2, changed := fastpathTV.DecSliceUint32V(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceUint32X(vp *[]uint32, d *Decoder) { if v, changed := f.DecSliceUint32V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceUint32V(v []uint32, canChange bool, d *Decoder) (_ []uint32, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []uint32{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 4) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]uint32, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 4) } else { xlen = 8 } v = make([]uint32, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, 0) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = 0 } else { v[uint(j)] = uint32(chkOvf.UintV(d.d.DecodeUint64(), 32)) } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]uint32, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceUint64R(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]uint64) if v, changed := fastpathTV.DecSliceUint64V(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]uint64) v2, changed := fastpathTV.DecSliceUint64V(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceUint64X(vp *[]uint64, d *Decoder) { if v, changed := f.DecSliceUint64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceUint64V(v []uint64, canChange bool, d *Decoder) (_ []uint64, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []uint64{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]uint64, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) } else { xlen = 8 } v = make([]uint64, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, 0) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = 0 } else { v[uint(j)] = d.d.DecodeUint64() } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]uint64, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceUintptrR(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]uintptr) if v, changed := fastpathTV.DecSliceUintptrV(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]uintptr) v2, changed := fastpathTV.DecSliceUintptrV(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceUintptrX(vp *[]uintptr, d *Decoder) { if v, changed := f.DecSliceUintptrV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceUintptrV(v []uintptr, canChange bool, d *Decoder) (_ []uintptr, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []uintptr{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]uintptr, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) } else { xlen = 8 } v = make([]uintptr, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, 0) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = 0 } else { v[uint(j)] = uintptr(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]uintptr, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceIntR(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]int) if v, changed := fastpathTV.DecSliceIntV(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]int) v2, changed := fastpathTV.DecSliceIntV(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceIntX(vp *[]int, d *Decoder) { if v, changed := f.DecSliceIntV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceIntV(v []int, canChange bool, d *Decoder) (_ []int, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []int{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]int, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) } else { xlen = 8 } v = make([]int, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, 0) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = 0 } else { v[uint(j)] = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]int, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceInt8R(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]int8) if v, changed := fastpathTV.DecSliceInt8V(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]int8) v2, changed := fastpathTV.DecSliceInt8V(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceInt8X(vp *[]int8, d *Decoder) { if v, changed := f.DecSliceInt8V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceInt8V(v []int8, canChange bool, d *Decoder) (_ []int8, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []int8{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 1) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]int8, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 1) } else { xlen = 8 } v = make([]int8, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, 0) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = 0 } else { v[uint(j)] = int8(chkOvf.IntV(d.d.DecodeInt64(), 8)) } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]int8, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceInt16R(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]int16) if v, changed := fastpathTV.DecSliceInt16V(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]int16) v2, changed := fastpathTV.DecSliceInt16V(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceInt16X(vp *[]int16, d *Decoder) { if v, changed := f.DecSliceInt16V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceInt16V(v []int16, canChange bool, d *Decoder) (_ []int16, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []int16{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 2) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]int16, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 2) } else { xlen = 8 } v = make([]int16, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, 0) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = 0 } else { v[uint(j)] = int16(chkOvf.IntV(d.d.DecodeInt64(), 16)) } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]int16, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceInt32R(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]int32) if v, changed := fastpathTV.DecSliceInt32V(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]int32) v2, changed := fastpathTV.DecSliceInt32V(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceInt32X(vp *[]int32, d *Decoder) { if v, changed := f.DecSliceInt32V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceInt32V(v []int32, canChange bool, d *Decoder) (_ []int32, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []int32{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 4) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]int32, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 4) } else { xlen = 8 } v = make([]int32, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, 0) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = 0 } else { v[uint(j)] = int32(chkOvf.IntV(d.d.DecodeInt64(), 32)) } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]int32, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceInt64R(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]int64) if v, changed := fastpathTV.DecSliceInt64V(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]int64) v2, changed := fastpathTV.DecSliceInt64V(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceInt64X(vp *[]int64, d *Decoder) { if v, changed := f.DecSliceInt64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceInt64V(v []int64, canChange bool, d *Decoder) (_ []int64, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []int64{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]int64, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 8) } else { xlen = 8 } v = make([]int64, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, 0) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = 0 } else { v[uint(j)] = d.d.DecodeInt64() } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]int64, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecSliceBoolR(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]bool) if v, changed := fastpathTV.DecSliceBoolV(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]bool) v2, changed := fastpathTV.DecSliceBoolV(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) DecSliceBoolX(vp *[]bool, d *Decoder) { if v, changed := f.DecSliceBoolV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecSliceBoolV(v []bool, canChange bool, d *Decoder) (_ []bool, changed bool) { slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []bool{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 1) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]bool, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, 1) } else { xlen = 8 } v = make([]bool, uint(xlen)) changed = true } var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, false) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = false } else { v[uint(j)] = d.d.DecodeBool() } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]bool, 0) changed = true } } slh.End() return v, changed } func (d *Decoder) fastpathDecMapStringIntfR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[string]interface{}) if v, changed := fastpathTV.DecMapStringIntfV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapStringIntfV(rv2i(rv).(map[string]interface{}), false, d) } } func (f fastpathT) DecMapStringIntfX(vp *map[string]interface{}, d *Decoder) { if v, changed := f.DecMapStringIntfV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapStringIntfV(v map[string]interface{}, canChange bool, d *Decoder) (_ map[string]interface{}, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[string]interface{}, decInferLen(containerLen, d.h.MaxInitLen, 32)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } mapGet := v != nil && !d.h.MapValueReset && !d.h.InterfaceReset var mk string var mv interface{} hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeString() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = nil } continue } if mapGet { mv = v[mk] } else { mv = nil } d.decode(&mv) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapStringStringR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[string]string) if v, changed := fastpathTV.DecMapStringStringV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapStringStringV(rv2i(rv).(map[string]string), false, d) } } func (f fastpathT) DecMapStringStringX(vp *map[string]string, d *Decoder) { if v, changed := f.DecMapStringStringV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapStringStringV(v map[string]string, canChange bool, d *Decoder) (_ map[string]string, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[string]string, decInferLen(containerLen, d.h.MaxInitLen, 32)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk string var mv string hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeString() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = "" } continue } mv = d.d.DecodeString() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapStringBytesR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[string][]byte) if v, changed := fastpathTV.DecMapStringBytesV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapStringBytesV(rv2i(rv).(map[string][]byte), false, d) } } func (f fastpathT) DecMapStringBytesX(vp *map[string][]byte, d *Decoder) { if v, changed := f.DecMapStringBytesV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapStringBytesV(v map[string][]byte, canChange bool, d *Decoder) (_ map[string][]byte, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[string][]byte, decInferLen(containerLen, d.h.MaxInitLen, 40)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } mapGet := v != nil && !d.h.MapValueReset var mk string var mv []byte hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeString() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = nil } continue } if mapGet { mv = v[mk] } else { mv = nil } mv = d.d.DecodeBytes(mv, false) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapStringUintR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[string]uint) if v, changed := fastpathTV.DecMapStringUintV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapStringUintV(rv2i(rv).(map[string]uint), false, d) } } func (f fastpathT) DecMapStringUintX(vp *map[string]uint, d *Decoder) { if v, changed := f.DecMapStringUintV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapStringUintV(v map[string]uint, canChange bool, d *Decoder) (_ map[string]uint, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[string]uint, decInferLen(containerLen, d.h.MaxInitLen, 24)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk string var mv uint hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeString() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapStringUint8R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[string]uint8) if v, changed := fastpathTV.DecMapStringUint8V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapStringUint8V(rv2i(rv).(map[string]uint8), false, d) } } func (f fastpathT) DecMapStringUint8X(vp *map[string]uint8, d *Decoder) { if v, changed := f.DecMapStringUint8V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapStringUint8V(v map[string]uint8, canChange bool, d *Decoder) (_ map[string]uint8, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[string]uint8, decInferLen(containerLen, d.h.MaxInitLen, 17)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk string var mv uint8 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeString() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapStringUint64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[string]uint64) if v, changed := fastpathTV.DecMapStringUint64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapStringUint64V(rv2i(rv).(map[string]uint64), false, d) } } func (f fastpathT) DecMapStringUint64X(vp *map[string]uint64, d *Decoder) { if v, changed := f.DecMapStringUint64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapStringUint64V(v map[string]uint64, canChange bool, d *Decoder) (_ map[string]uint64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[string]uint64, decInferLen(containerLen, d.h.MaxInitLen, 24)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk string var mv uint64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeString() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeUint64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapStringUintptrR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[string]uintptr) if v, changed := fastpathTV.DecMapStringUintptrV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapStringUintptrV(rv2i(rv).(map[string]uintptr), false, d) } } func (f fastpathT) DecMapStringUintptrX(vp *map[string]uintptr, d *Decoder) { if v, changed := f.DecMapStringUintptrV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapStringUintptrV(v map[string]uintptr, canChange bool, d *Decoder) (_ map[string]uintptr, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[string]uintptr, decInferLen(containerLen, d.h.MaxInitLen, 24)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk string var mv uintptr hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeString() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uintptr(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapStringIntR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[string]int) if v, changed := fastpathTV.DecMapStringIntV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapStringIntV(rv2i(rv).(map[string]int), false, d) } } func (f fastpathT) DecMapStringIntX(vp *map[string]int, d *Decoder) { if v, changed := f.DecMapStringIntV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapStringIntV(v map[string]int, canChange bool, d *Decoder) (_ map[string]int, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[string]int, decInferLen(containerLen, d.h.MaxInitLen, 24)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk string var mv int hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeString() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapStringInt64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[string]int64) if v, changed := fastpathTV.DecMapStringInt64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapStringInt64V(rv2i(rv).(map[string]int64), false, d) } } func (f fastpathT) DecMapStringInt64X(vp *map[string]int64, d *Decoder) { if v, changed := f.DecMapStringInt64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapStringInt64V(v map[string]int64, canChange bool, d *Decoder) (_ map[string]int64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[string]int64, decInferLen(containerLen, d.h.MaxInitLen, 24)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk string var mv int64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeString() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeInt64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapStringFloat32R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[string]float32) if v, changed := fastpathTV.DecMapStringFloat32V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapStringFloat32V(rv2i(rv).(map[string]float32), false, d) } } func (f fastpathT) DecMapStringFloat32X(vp *map[string]float32, d *Decoder) { if v, changed := f.DecMapStringFloat32V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapStringFloat32V(v map[string]float32, canChange bool, d *Decoder) (_ map[string]float32, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[string]float32, decInferLen(containerLen, d.h.MaxInitLen, 20)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk string var mv float32 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeString() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = float32(d.decodeFloat32()) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapStringFloat64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[string]float64) if v, changed := fastpathTV.DecMapStringFloat64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapStringFloat64V(rv2i(rv).(map[string]float64), false, d) } } func (f fastpathT) DecMapStringFloat64X(vp *map[string]float64, d *Decoder) { if v, changed := f.DecMapStringFloat64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapStringFloat64V(v map[string]float64, canChange bool, d *Decoder) (_ map[string]float64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[string]float64, decInferLen(containerLen, d.h.MaxInitLen, 24)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk string var mv float64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeString() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeFloat64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapStringBoolR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[string]bool) if v, changed := fastpathTV.DecMapStringBoolV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapStringBoolV(rv2i(rv).(map[string]bool), false, d) } } func (f fastpathT) DecMapStringBoolX(vp *map[string]bool, d *Decoder) { if v, changed := f.DecMapStringBoolV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapStringBoolV(v map[string]bool, canChange bool, d *Decoder) (_ map[string]bool, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[string]bool, decInferLen(containerLen, d.h.MaxInitLen, 17)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk string var mv bool hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeString() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = false } continue } mv = d.d.DecodeBool() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUintIntfR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint]interface{}) if v, changed := fastpathTV.DecMapUintIntfV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUintIntfV(rv2i(rv).(map[uint]interface{}), false, d) } } func (f fastpathT) DecMapUintIntfX(vp *map[uint]interface{}, d *Decoder) { if v, changed := f.DecMapUintIntfV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUintIntfV(v map[uint]interface{}, canChange bool, d *Decoder) (_ map[uint]interface{}, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint]interface{}, decInferLen(containerLen, d.h.MaxInitLen, 24)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } mapGet := v != nil && !d.h.MapValueReset && !d.h.InterfaceReset var mk uint var mv interface{} hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = nil } continue } if mapGet { mv = v[mk] } else { mv = nil } d.decode(&mv) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUintStringR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint]string) if v, changed := fastpathTV.DecMapUintStringV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUintStringV(rv2i(rv).(map[uint]string), false, d) } } func (f fastpathT) DecMapUintStringX(vp *map[uint]string, d *Decoder) { if v, changed := f.DecMapUintStringV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUintStringV(v map[uint]string, canChange bool, d *Decoder) (_ map[uint]string, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint]string, decInferLen(containerLen, d.h.MaxInitLen, 24)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint var mv string hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = "" } continue } mv = d.d.DecodeString() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUintBytesR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint][]byte) if v, changed := fastpathTV.DecMapUintBytesV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUintBytesV(rv2i(rv).(map[uint][]byte), false, d) } } func (f fastpathT) DecMapUintBytesX(vp *map[uint][]byte, d *Decoder) { if v, changed := f.DecMapUintBytesV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUintBytesV(v map[uint][]byte, canChange bool, d *Decoder) (_ map[uint][]byte, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint][]byte, decInferLen(containerLen, d.h.MaxInitLen, 32)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } mapGet := v != nil && !d.h.MapValueReset var mk uint var mv []byte hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = nil } continue } if mapGet { mv = v[mk] } else { mv = nil } mv = d.d.DecodeBytes(mv, false) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUintUintR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint]uint) if v, changed := fastpathTV.DecMapUintUintV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUintUintV(rv2i(rv).(map[uint]uint), false, d) } } func (f fastpathT) DecMapUintUintX(vp *map[uint]uint, d *Decoder) { if v, changed := f.DecMapUintUintV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUintUintV(v map[uint]uint, canChange bool, d *Decoder) (_ map[uint]uint, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint]uint, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint var mv uint hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUintUint8R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint]uint8) if v, changed := fastpathTV.DecMapUintUint8V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUintUint8V(rv2i(rv).(map[uint]uint8), false, d) } } func (f fastpathT) DecMapUintUint8X(vp *map[uint]uint8, d *Decoder) { if v, changed := f.DecMapUintUint8V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUintUint8V(v map[uint]uint8, canChange bool, d *Decoder) (_ map[uint]uint8, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint]uint8, decInferLen(containerLen, d.h.MaxInitLen, 9)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint var mv uint8 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUintUint64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint]uint64) if v, changed := fastpathTV.DecMapUintUint64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUintUint64V(rv2i(rv).(map[uint]uint64), false, d) } } func (f fastpathT) DecMapUintUint64X(vp *map[uint]uint64, d *Decoder) { if v, changed := f.DecMapUintUint64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUintUint64V(v map[uint]uint64, canChange bool, d *Decoder) (_ map[uint]uint64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint]uint64, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint var mv uint64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeUint64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUintUintptrR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint]uintptr) if v, changed := fastpathTV.DecMapUintUintptrV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUintUintptrV(rv2i(rv).(map[uint]uintptr), false, d) } } func (f fastpathT) DecMapUintUintptrX(vp *map[uint]uintptr, d *Decoder) { if v, changed := f.DecMapUintUintptrV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUintUintptrV(v map[uint]uintptr, canChange bool, d *Decoder) (_ map[uint]uintptr, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint]uintptr, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint var mv uintptr hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uintptr(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUintIntR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint]int) if v, changed := fastpathTV.DecMapUintIntV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUintIntV(rv2i(rv).(map[uint]int), false, d) } } func (f fastpathT) DecMapUintIntX(vp *map[uint]int, d *Decoder) { if v, changed := f.DecMapUintIntV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUintIntV(v map[uint]int, canChange bool, d *Decoder) (_ map[uint]int, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint]int, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint var mv int hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUintInt64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint]int64) if v, changed := fastpathTV.DecMapUintInt64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUintInt64V(rv2i(rv).(map[uint]int64), false, d) } } func (f fastpathT) DecMapUintInt64X(vp *map[uint]int64, d *Decoder) { if v, changed := f.DecMapUintInt64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUintInt64V(v map[uint]int64, canChange bool, d *Decoder) (_ map[uint]int64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint]int64, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint var mv int64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeInt64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUintFloat32R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint]float32) if v, changed := fastpathTV.DecMapUintFloat32V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUintFloat32V(rv2i(rv).(map[uint]float32), false, d) } } func (f fastpathT) DecMapUintFloat32X(vp *map[uint]float32, d *Decoder) { if v, changed := f.DecMapUintFloat32V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUintFloat32V(v map[uint]float32, canChange bool, d *Decoder) (_ map[uint]float32, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint]float32, decInferLen(containerLen, d.h.MaxInitLen, 12)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint var mv float32 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = float32(d.decodeFloat32()) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUintFloat64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint]float64) if v, changed := fastpathTV.DecMapUintFloat64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUintFloat64V(rv2i(rv).(map[uint]float64), false, d) } } func (f fastpathT) DecMapUintFloat64X(vp *map[uint]float64, d *Decoder) { if v, changed := f.DecMapUintFloat64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUintFloat64V(v map[uint]float64, canChange bool, d *Decoder) (_ map[uint]float64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint]float64, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint var mv float64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeFloat64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUintBoolR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint]bool) if v, changed := fastpathTV.DecMapUintBoolV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUintBoolV(rv2i(rv).(map[uint]bool), false, d) } } func (f fastpathT) DecMapUintBoolX(vp *map[uint]bool, d *Decoder) { if v, changed := f.DecMapUintBoolV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUintBoolV(v map[uint]bool, canChange bool, d *Decoder) (_ map[uint]bool, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint]bool, decInferLen(containerLen, d.h.MaxInitLen, 9)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint var mv bool hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = false } continue } mv = d.d.DecodeBool() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint8IntfR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint8]interface{}) if v, changed := fastpathTV.DecMapUint8IntfV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint8IntfV(rv2i(rv).(map[uint8]interface{}), false, d) } } func (f fastpathT) DecMapUint8IntfX(vp *map[uint8]interface{}, d *Decoder) { if v, changed := f.DecMapUint8IntfV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint8IntfV(v map[uint8]interface{}, canChange bool, d *Decoder) (_ map[uint8]interface{}, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint8]interface{}, decInferLen(containerLen, d.h.MaxInitLen, 17)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } mapGet := v != nil && !d.h.MapValueReset && !d.h.InterfaceReset var mk uint8 var mv interface{} hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = nil } continue } if mapGet { mv = v[mk] } else { mv = nil } d.decode(&mv) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint8StringR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint8]string) if v, changed := fastpathTV.DecMapUint8StringV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint8StringV(rv2i(rv).(map[uint8]string), false, d) } } func (f fastpathT) DecMapUint8StringX(vp *map[uint8]string, d *Decoder) { if v, changed := f.DecMapUint8StringV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint8StringV(v map[uint8]string, canChange bool, d *Decoder) (_ map[uint8]string, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint8]string, decInferLen(containerLen, d.h.MaxInitLen, 17)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint8 var mv string hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = "" } continue } mv = d.d.DecodeString() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint8BytesR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint8][]byte) if v, changed := fastpathTV.DecMapUint8BytesV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint8BytesV(rv2i(rv).(map[uint8][]byte), false, d) } } func (f fastpathT) DecMapUint8BytesX(vp *map[uint8][]byte, d *Decoder) { if v, changed := f.DecMapUint8BytesV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint8BytesV(v map[uint8][]byte, canChange bool, d *Decoder) (_ map[uint8][]byte, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint8][]byte, decInferLen(containerLen, d.h.MaxInitLen, 25)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } mapGet := v != nil && !d.h.MapValueReset var mk uint8 var mv []byte hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = nil } continue } if mapGet { mv = v[mk] } else { mv = nil } mv = d.d.DecodeBytes(mv, false) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint8UintR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint8]uint) if v, changed := fastpathTV.DecMapUint8UintV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint8UintV(rv2i(rv).(map[uint8]uint), false, d) } } func (f fastpathT) DecMapUint8UintX(vp *map[uint8]uint, d *Decoder) { if v, changed := f.DecMapUint8UintV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint8UintV(v map[uint8]uint, canChange bool, d *Decoder) (_ map[uint8]uint, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint8]uint, decInferLen(containerLen, d.h.MaxInitLen, 9)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint8 var mv uint hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint8Uint8R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint8]uint8) if v, changed := fastpathTV.DecMapUint8Uint8V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint8Uint8V(rv2i(rv).(map[uint8]uint8), false, d) } } func (f fastpathT) DecMapUint8Uint8X(vp *map[uint8]uint8, d *Decoder) { if v, changed := f.DecMapUint8Uint8V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint8Uint8V(v map[uint8]uint8, canChange bool, d *Decoder) (_ map[uint8]uint8, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint8]uint8, decInferLen(containerLen, d.h.MaxInitLen, 2)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint8 var mv uint8 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint8Uint64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint8]uint64) if v, changed := fastpathTV.DecMapUint8Uint64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint8Uint64V(rv2i(rv).(map[uint8]uint64), false, d) } } func (f fastpathT) DecMapUint8Uint64X(vp *map[uint8]uint64, d *Decoder) { if v, changed := f.DecMapUint8Uint64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint8Uint64V(v map[uint8]uint64, canChange bool, d *Decoder) (_ map[uint8]uint64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint8]uint64, decInferLen(containerLen, d.h.MaxInitLen, 9)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint8 var mv uint64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeUint64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint8UintptrR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint8]uintptr) if v, changed := fastpathTV.DecMapUint8UintptrV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint8UintptrV(rv2i(rv).(map[uint8]uintptr), false, d) } } func (f fastpathT) DecMapUint8UintptrX(vp *map[uint8]uintptr, d *Decoder) { if v, changed := f.DecMapUint8UintptrV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint8UintptrV(v map[uint8]uintptr, canChange bool, d *Decoder) (_ map[uint8]uintptr, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint8]uintptr, decInferLen(containerLen, d.h.MaxInitLen, 9)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint8 var mv uintptr hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uintptr(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint8IntR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint8]int) if v, changed := fastpathTV.DecMapUint8IntV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint8IntV(rv2i(rv).(map[uint8]int), false, d) } } func (f fastpathT) DecMapUint8IntX(vp *map[uint8]int, d *Decoder) { if v, changed := f.DecMapUint8IntV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint8IntV(v map[uint8]int, canChange bool, d *Decoder) (_ map[uint8]int, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint8]int, decInferLen(containerLen, d.h.MaxInitLen, 9)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint8 var mv int hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint8Int64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint8]int64) if v, changed := fastpathTV.DecMapUint8Int64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint8Int64V(rv2i(rv).(map[uint8]int64), false, d) } } func (f fastpathT) DecMapUint8Int64X(vp *map[uint8]int64, d *Decoder) { if v, changed := f.DecMapUint8Int64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint8Int64V(v map[uint8]int64, canChange bool, d *Decoder) (_ map[uint8]int64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint8]int64, decInferLen(containerLen, d.h.MaxInitLen, 9)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint8 var mv int64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeInt64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint8Float32R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint8]float32) if v, changed := fastpathTV.DecMapUint8Float32V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint8Float32V(rv2i(rv).(map[uint8]float32), false, d) } } func (f fastpathT) DecMapUint8Float32X(vp *map[uint8]float32, d *Decoder) { if v, changed := f.DecMapUint8Float32V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint8Float32V(v map[uint8]float32, canChange bool, d *Decoder) (_ map[uint8]float32, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint8]float32, decInferLen(containerLen, d.h.MaxInitLen, 5)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint8 var mv float32 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = float32(d.decodeFloat32()) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint8Float64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint8]float64) if v, changed := fastpathTV.DecMapUint8Float64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint8Float64V(rv2i(rv).(map[uint8]float64), false, d) } } func (f fastpathT) DecMapUint8Float64X(vp *map[uint8]float64, d *Decoder) { if v, changed := f.DecMapUint8Float64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint8Float64V(v map[uint8]float64, canChange bool, d *Decoder) (_ map[uint8]float64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint8]float64, decInferLen(containerLen, d.h.MaxInitLen, 9)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint8 var mv float64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeFloat64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint8BoolR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint8]bool) if v, changed := fastpathTV.DecMapUint8BoolV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint8BoolV(rv2i(rv).(map[uint8]bool), false, d) } } func (f fastpathT) DecMapUint8BoolX(vp *map[uint8]bool, d *Decoder) { if v, changed := f.DecMapUint8BoolV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint8BoolV(v map[uint8]bool, canChange bool, d *Decoder) (_ map[uint8]bool, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint8]bool, decInferLen(containerLen, d.h.MaxInitLen, 2)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint8 var mv bool hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = false } continue } mv = d.d.DecodeBool() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint64IntfR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint64]interface{}) if v, changed := fastpathTV.DecMapUint64IntfV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint64IntfV(rv2i(rv).(map[uint64]interface{}), false, d) } } func (f fastpathT) DecMapUint64IntfX(vp *map[uint64]interface{}, d *Decoder) { if v, changed := f.DecMapUint64IntfV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint64IntfV(v map[uint64]interface{}, canChange bool, d *Decoder) (_ map[uint64]interface{}, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint64]interface{}, decInferLen(containerLen, d.h.MaxInitLen, 24)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } mapGet := v != nil && !d.h.MapValueReset && !d.h.InterfaceReset var mk uint64 var mv interface{} hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = nil } continue } if mapGet { mv = v[mk] } else { mv = nil } d.decode(&mv) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint64StringR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint64]string) if v, changed := fastpathTV.DecMapUint64StringV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint64StringV(rv2i(rv).(map[uint64]string), false, d) } } func (f fastpathT) DecMapUint64StringX(vp *map[uint64]string, d *Decoder) { if v, changed := f.DecMapUint64StringV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint64StringV(v map[uint64]string, canChange bool, d *Decoder) (_ map[uint64]string, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint64]string, decInferLen(containerLen, d.h.MaxInitLen, 24)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint64 var mv string hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = "" } continue } mv = d.d.DecodeString() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint64BytesR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint64][]byte) if v, changed := fastpathTV.DecMapUint64BytesV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint64BytesV(rv2i(rv).(map[uint64][]byte), false, d) } } func (f fastpathT) DecMapUint64BytesX(vp *map[uint64][]byte, d *Decoder) { if v, changed := f.DecMapUint64BytesV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint64BytesV(v map[uint64][]byte, canChange bool, d *Decoder) (_ map[uint64][]byte, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint64][]byte, decInferLen(containerLen, d.h.MaxInitLen, 32)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } mapGet := v != nil && !d.h.MapValueReset var mk uint64 var mv []byte hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = nil } continue } if mapGet { mv = v[mk] } else { mv = nil } mv = d.d.DecodeBytes(mv, false) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint64UintR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint64]uint) if v, changed := fastpathTV.DecMapUint64UintV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint64UintV(rv2i(rv).(map[uint64]uint), false, d) } } func (f fastpathT) DecMapUint64UintX(vp *map[uint64]uint, d *Decoder) { if v, changed := f.DecMapUint64UintV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint64UintV(v map[uint64]uint, canChange bool, d *Decoder) (_ map[uint64]uint, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint64]uint, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint64 var mv uint hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint64Uint8R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint64]uint8) if v, changed := fastpathTV.DecMapUint64Uint8V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint64Uint8V(rv2i(rv).(map[uint64]uint8), false, d) } } func (f fastpathT) DecMapUint64Uint8X(vp *map[uint64]uint8, d *Decoder) { if v, changed := f.DecMapUint64Uint8V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint64Uint8V(v map[uint64]uint8, canChange bool, d *Decoder) (_ map[uint64]uint8, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint64]uint8, decInferLen(containerLen, d.h.MaxInitLen, 9)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint64 var mv uint8 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint64Uint64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint64]uint64) if v, changed := fastpathTV.DecMapUint64Uint64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint64Uint64V(rv2i(rv).(map[uint64]uint64), false, d) } } func (f fastpathT) DecMapUint64Uint64X(vp *map[uint64]uint64, d *Decoder) { if v, changed := f.DecMapUint64Uint64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint64Uint64V(v map[uint64]uint64, canChange bool, d *Decoder) (_ map[uint64]uint64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint64]uint64, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint64 var mv uint64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeUint64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint64UintptrR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint64]uintptr) if v, changed := fastpathTV.DecMapUint64UintptrV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint64UintptrV(rv2i(rv).(map[uint64]uintptr), false, d) } } func (f fastpathT) DecMapUint64UintptrX(vp *map[uint64]uintptr, d *Decoder) { if v, changed := f.DecMapUint64UintptrV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint64UintptrV(v map[uint64]uintptr, canChange bool, d *Decoder) (_ map[uint64]uintptr, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint64]uintptr, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint64 var mv uintptr hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uintptr(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint64IntR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint64]int) if v, changed := fastpathTV.DecMapUint64IntV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint64IntV(rv2i(rv).(map[uint64]int), false, d) } } func (f fastpathT) DecMapUint64IntX(vp *map[uint64]int, d *Decoder) { if v, changed := f.DecMapUint64IntV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint64IntV(v map[uint64]int, canChange bool, d *Decoder) (_ map[uint64]int, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint64]int, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint64 var mv int hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint64Int64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint64]int64) if v, changed := fastpathTV.DecMapUint64Int64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint64Int64V(rv2i(rv).(map[uint64]int64), false, d) } } func (f fastpathT) DecMapUint64Int64X(vp *map[uint64]int64, d *Decoder) { if v, changed := f.DecMapUint64Int64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint64Int64V(v map[uint64]int64, canChange bool, d *Decoder) (_ map[uint64]int64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint64]int64, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint64 var mv int64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeInt64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint64Float32R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint64]float32) if v, changed := fastpathTV.DecMapUint64Float32V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint64Float32V(rv2i(rv).(map[uint64]float32), false, d) } } func (f fastpathT) DecMapUint64Float32X(vp *map[uint64]float32, d *Decoder) { if v, changed := f.DecMapUint64Float32V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint64Float32V(v map[uint64]float32, canChange bool, d *Decoder) (_ map[uint64]float32, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint64]float32, decInferLen(containerLen, d.h.MaxInitLen, 12)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint64 var mv float32 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = float32(d.decodeFloat32()) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint64Float64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint64]float64) if v, changed := fastpathTV.DecMapUint64Float64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint64Float64V(rv2i(rv).(map[uint64]float64), false, d) } } func (f fastpathT) DecMapUint64Float64X(vp *map[uint64]float64, d *Decoder) { if v, changed := f.DecMapUint64Float64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint64Float64V(v map[uint64]float64, canChange bool, d *Decoder) (_ map[uint64]float64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint64]float64, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint64 var mv float64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeFloat64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapUint64BoolR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[uint64]bool) if v, changed := fastpathTV.DecMapUint64BoolV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapUint64BoolV(rv2i(rv).(map[uint64]bool), false, d) } } func (f fastpathT) DecMapUint64BoolX(vp *map[uint64]bool, d *Decoder) { if v, changed := f.DecMapUint64BoolV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapUint64BoolV(v map[uint64]bool, canChange bool, d *Decoder) (_ map[uint64]bool, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[uint64]bool, decInferLen(containerLen, d.h.MaxInitLen, 9)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk uint64 var mv bool hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeUint64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = false } continue } mv = d.d.DecodeBool() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapIntIntfR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int]interface{}) if v, changed := fastpathTV.DecMapIntIntfV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapIntIntfV(rv2i(rv).(map[int]interface{}), false, d) } } func (f fastpathT) DecMapIntIntfX(vp *map[int]interface{}, d *Decoder) { if v, changed := f.DecMapIntIntfV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapIntIntfV(v map[int]interface{}, canChange bool, d *Decoder) (_ map[int]interface{}, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int]interface{}, decInferLen(containerLen, d.h.MaxInitLen, 24)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } mapGet := v != nil && !d.h.MapValueReset && !d.h.InterfaceReset var mk int var mv interface{} hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = nil } continue } if mapGet { mv = v[mk] } else { mv = nil } d.decode(&mv) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapIntStringR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int]string) if v, changed := fastpathTV.DecMapIntStringV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapIntStringV(rv2i(rv).(map[int]string), false, d) } } func (f fastpathT) DecMapIntStringX(vp *map[int]string, d *Decoder) { if v, changed := f.DecMapIntStringV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapIntStringV(v map[int]string, canChange bool, d *Decoder) (_ map[int]string, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int]string, decInferLen(containerLen, d.h.MaxInitLen, 24)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int var mv string hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = "" } continue } mv = d.d.DecodeString() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapIntBytesR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int][]byte) if v, changed := fastpathTV.DecMapIntBytesV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapIntBytesV(rv2i(rv).(map[int][]byte), false, d) } } func (f fastpathT) DecMapIntBytesX(vp *map[int][]byte, d *Decoder) { if v, changed := f.DecMapIntBytesV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapIntBytesV(v map[int][]byte, canChange bool, d *Decoder) (_ map[int][]byte, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int][]byte, decInferLen(containerLen, d.h.MaxInitLen, 32)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } mapGet := v != nil && !d.h.MapValueReset var mk int var mv []byte hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = nil } continue } if mapGet { mv = v[mk] } else { mv = nil } mv = d.d.DecodeBytes(mv, false) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapIntUintR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int]uint) if v, changed := fastpathTV.DecMapIntUintV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapIntUintV(rv2i(rv).(map[int]uint), false, d) } } func (f fastpathT) DecMapIntUintX(vp *map[int]uint, d *Decoder) { if v, changed := f.DecMapIntUintV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapIntUintV(v map[int]uint, canChange bool, d *Decoder) (_ map[int]uint, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int]uint, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int var mv uint hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapIntUint8R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int]uint8) if v, changed := fastpathTV.DecMapIntUint8V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapIntUint8V(rv2i(rv).(map[int]uint8), false, d) } } func (f fastpathT) DecMapIntUint8X(vp *map[int]uint8, d *Decoder) { if v, changed := f.DecMapIntUint8V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapIntUint8V(v map[int]uint8, canChange bool, d *Decoder) (_ map[int]uint8, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int]uint8, decInferLen(containerLen, d.h.MaxInitLen, 9)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int var mv uint8 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapIntUint64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int]uint64) if v, changed := fastpathTV.DecMapIntUint64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapIntUint64V(rv2i(rv).(map[int]uint64), false, d) } } func (f fastpathT) DecMapIntUint64X(vp *map[int]uint64, d *Decoder) { if v, changed := f.DecMapIntUint64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapIntUint64V(v map[int]uint64, canChange bool, d *Decoder) (_ map[int]uint64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int]uint64, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int var mv uint64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeUint64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapIntUintptrR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int]uintptr) if v, changed := fastpathTV.DecMapIntUintptrV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapIntUintptrV(rv2i(rv).(map[int]uintptr), false, d) } } func (f fastpathT) DecMapIntUintptrX(vp *map[int]uintptr, d *Decoder) { if v, changed := f.DecMapIntUintptrV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapIntUintptrV(v map[int]uintptr, canChange bool, d *Decoder) (_ map[int]uintptr, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int]uintptr, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int var mv uintptr hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uintptr(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapIntIntR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int]int) if v, changed := fastpathTV.DecMapIntIntV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapIntIntV(rv2i(rv).(map[int]int), false, d) } } func (f fastpathT) DecMapIntIntX(vp *map[int]int, d *Decoder) { if v, changed := f.DecMapIntIntV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapIntIntV(v map[int]int, canChange bool, d *Decoder) (_ map[int]int, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int]int, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int var mv int hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapIntInt64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int]int64) if v, changed := fastpathTV.DecMapIntInt64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapIntInt64V(rv2i(rv).(map[int]int64), false, d) } } func (f fastpathT) DecMapIntInt64X(vp *map[int]int64, d *Decoder) { if v, changed := f.DecMapIntInt64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapIntInt64V(v map[int]int64, canChange bool, d *Decoder) (_ map[int]int64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int]int64, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int var mv int64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeInt64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapIntFloat32R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int]float32) if v, changed := fastpathTV.DecMapIntFloat32V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapIntFloat32V(rv2i(rv).(map[int]float32), false, d) } } func (f fastpathT) DecMapIntFloat32X(vp *map[int]float32, d *Decoder) { if v, changed := f.DecMapIntFloat32V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapIntFloat32V(v map[int]float32, canChange bool, d *Decoder) (_ map[int]float32, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int]float32, decInferLen(containerLen, d.h.MaxInitLen, 12)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int var mv float32 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = float32(d.decodeFloat32()) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapIntFloat64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int]float64) if v, changed := fastpathTV.DecMapIntFloat64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapIntFloat64V(rv2i(rv).(map[int]float64), false, d) } } func (f fastpathT) DecMapIntFloat64X(vp *map[int]float64, d *Decoder) { if v, changed := f.DecMapIntFloat64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapIntFloat64V(v map[int]float64, canChange bool, d *Decoder) (_ map[int]float64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int]float64, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int var mv float64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeFloat64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapIntBoolR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int]bool) if v, changed := fastpathTV.DecMapIntBoolV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapIntBoolV(rv2i(rv).(map[int]bool), false, d) } } func (f fastpathT) DecMapIntBoolX(vp *map[int]bool, d *Decoder) { if v, changed := f.DecMapIntBoolV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapIntBoolV(v map[int]bool, canChange bool, d *Decoder) (_ map[int]bool, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int]bool, decInferLen(containerLen, d.h.MaxInitLen, 9)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int var mv bool hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = false } continue } mv = d.d.DecodeBool() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapInt64IntfR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int64]interface{}) if v, changed := fastpathTV.DecMapInt64IntfV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapInt64IntfV(rv2i(rv).(map[int64]interface{}), false, d) } } func (f fastpathT) DecMapInt64IntfX(vp *map[int64]interface{}, d *Decoder) { if v, changed := f.DecMapInt64IntfV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapInt64IntfV(v map[int64]interface{}, canChange bool, d *Decoder) (_ map[int64]interface{}, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int64]interface{}, decInferLen(containerLen, d.h.MaxInitLen, 24)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } mapGet := v != nil && !d.h.MapValueReset && !d.h.InterfaceReset var mk int64 var mv interface{} hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeInt64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = nil } continue } if mapGet { mv = v[mk] } else { mv = nil } d.decode(&mv) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapInt64StringR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int64]string) if v, changed := fastpathTV.DecMapInt64StringV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapInt64StringV(rv2i(rv).(map[int64]string), false, d) } } func (f fastpathT) DecMapInt64StringX(vp *map[int64]string, d *Decoder) { if v, changed := f.DecMapInt64StringV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapInt64StringV(v map[int64]string, canChange bool, d *Decoder) (_ map[int64]string, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int64]string, decInferLen(containerLen, d.h.MaxInitLen, 24)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int64 var mv string hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeInt64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = "" } continue } mv = d.d.DecodeString() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapInt64BytesR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int64][]byte) if v, changed := fastpathTV.DecMapInt64BytesV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapInt64BytesV(rv2i(rv).(map[int64][]byte), false, d) } } func (f fastpathT) DecMapInt64BytesX(vp *map[int64][]byte, d *Decoder) { if v, changed := f.DecMapInt64BytesV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapInt64BytesV(v map[int64][]byte, canChange bool, d *Decoder) (_ map[int64][]byte, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int64][]byte, decInferLen(containerLen, d.h.MaxInitLen, 32)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } mapGet := v != nil && !d.h.MapValueReset var mk int64 var mv []byte hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeInt64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = nil } continue } if mapGet { mv = v[mk] } else { mv = nil } mv = d.d.DecodeBytes(mv, false) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapInt64UintR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int64]uint) if v, changed := fastpathTV.DecMapInt64UintV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapInt64UintV(rv2i(rv).(map[int64]uint), false, d) } } func (f fastpathT) DecMapInt64UintX(vp *map[int64]uint, d *Decoder) { if v, changed := f.DecMapInt64UintV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapInt64UintV(v map[int64]uint, canChange bool, d *Decoder) (_ map[int64]uint, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int64]uint, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int64 var mv uint hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeInt64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapInt64Uint8R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int64]uint8) if v, changed := fastpathTV.DecMapInt64Uint8V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapInt64Uint8V(rv2i(rv).(map[int64]uint8), false, d) } } func (f fastpathT) DecMapInt64Uint8X(vp *map[int64]uint8, d *Decoder) { if v, changed := f.DecMapInt64Uint8V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapInt64Uint8V(v map[int64]uint8, canChange bool, d *Decoder) (_ map[int64]uint8, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int64]uint8, decInferLen(containerLen, d.h.MaxInitLen, 9)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int64 var mv uint8 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeInt64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapInt64Uint64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int64]uint64) if v, changed := fastpathTV.DecMapInt64Uint64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapInt64Uint64V(rv2i(rv).(map[int64]uint64), false, d) } } func (f fastpathT) DecMapInt64Uint64X(vp *map[int64]uint64, d *Decoder) { if v, changed := f.DecMapInt64Uint64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapInt64Uint64V(v map[int64]uint64, canChange bool, d *Decoder) (_ map[int64]uint64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int64]uint64, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int64 var mv uint64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeInt64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeUint64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapInt64UintptrR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int64]uintptr) if v, changed := fastpathTV.DecMapInt64UintptrV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapInt64UintptrV(rv2i(rv).(map[int64]uintptr), false, d) } } func (f fastpathT) DecMapInt64UintptrX(vp *map[int64]uintptr, d *Decoder) { if v, changed := f.DecMapInt64UintptrV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapInt64UintptrV(v map[int64]uintptr, canChange bool, d *Decoder) (_ map[int64]uintptr, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int64]uintptr, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int64 var mv uintptr hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeInt64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = uintptr(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapInt64IntR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int64]int) if v, changed := fastpathTV.DecMapInt64IntV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapInt64IntV(rv2i(rv).(map[int64]int), false, d) } } func (f fastpathT) DecMapInt64IntX(vp *map[int64]int, d *Decoder) { if v, changed := f.DecMapInt64IntV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapInt64IntV(v map[int64]int, canChange bool, d *Decoder) (_ map[int64]int, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int64]int, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int64 var mv int hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeInt64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapInt64Int64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int64]int64) if v, changed := fastpathTV.DecMapInt64Int64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapInt64Int64V(rv2i(rv).(map[int64]int64), false, d) } } func (f fastpathT) DecMapInt64Int64X(vp *map[int64]int64, d *Decoder) { if v, changed := f.DecMapInt64Int64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapInt64Int64V(v map[int64]int64, canChange bool, d *Decoder) (_ map[int64]int64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int64]int64, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int64 var mv int64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeInt64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeInt64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapInt64Float32R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int64]float32) if v, changed := fastpathTV.DecMapInt64Float32V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapInt64Float32V(rv2i(rv).(map[int64]float32), false, d) } } func (f fastpathT) DecMapInt64Float32X(vp *map[int64]float32, d *Decoder) { if v, changed := f.DecMapInt64Float32V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapInt64Float32V(v map[int64]float32, canChange bool, d *Decoder) (_ map[int64]float32, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int64]float32, decInferLen(containerLen, d.h.MaxInitLen, 12)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int64 var mv float32 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeInt64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = float32(d.decodeFloat32()) if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapInt64Float64R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int64]float64) if v, changed := fastpathTV.DecMapInt64Float64V(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapInt64Float64V(rv2i(rv).(map[int64]float64), false, d) } } func (f fastpathT) DecMapInt64Float64X(vp *map[int64]float64, d *Decoder) { if v, changed := f.DecMapInt64Float64V(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapInt64Float64V(v map[int64]float64, canChange bool, d *Decoder) (_ map[int64]float64, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int64]float64, decInferLen(containerLen, d.h.MaxInitLen, 16)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int64 var mv float64 hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeInt64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = 0 } continue } mv = d.d.DecodeFloat64() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } func (d *Decoder) fastpathDecMapInt64BoolR(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[int64]bool) if v, changed := fastpathTV.DecMapInt64BoolV(*vp, true, d); changed { *vp = v } } else { fastpathTV.DecMapInt64BoolV(rv2i(rv).(map[int64]bool), false, d) } } func (f fastpathT) DecMapInt64BoolX(vp *map[int64]bool, d *Decoder) { if v, changed := f.DecMapInt64BoolV(*vp, true, d); changed { *vp = v } } func (fastpathT) DecMapInt64BoolV(v map[int64]bool, canChange bool, d *Decoder) (_ map[int64]bool, changed bool) { containerLen := d.mapStart() if canChange && v == nil { v = make(map[int64]bool, decInferLen(containerLen, d.h.MaxInitLen, 9)) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } var mk int64 var mv bool hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() mk = d.d.DecodeInt64() d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil { } else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = false } continue } mv = d.d.DecodeBool() if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } ================================================ FILE: vendor/github.com/ugorji/go/codec/fast-path.go.tmpl ================================================ // +build !notfastpath // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // Code generated from fast-path.go.tmpl - DO NOT EDIT. package codec // Fast path functions try to create a fast path encode or decode implementation // for common maps and slices. // // We define the functions and register them in this single file // so as not to pollute the encode.go and decode.go, and create a dependency in there. // This file can be omitted without causing a build failure. // // The advantage of fast paths is: // - Many calls bypass reflection altogether // // Currently support // - slice of all builtin types (numeric, bool, string, []byte) // - maps of builtin types to builtin or interface{} type, EXCEPT FOR // keys of type uintptr, int8/16/32, uint16/32, float32/64, bool, interface{} // AND values of type type int8/16/32, uint16/32 // This should provide adequate "typical" implementations. // // Note that fast track decode functions must handle values for which an address cannot be obtained. // For example: // m2 := map[string]int{} // p2 := []interface{}{m2} // // decoding into p2 will bomb if fast track functions do not treat like unaddressable. // import ( "reflect" "sort" ) const fastpathEnabled = true const fastpathMapBySliceErrMsg = "mapBySlice requires even slice length, but got %v" type fastpathT struct {} var fastpathTV fastpathT type fastpathE struct { rtid uintptr rt reflect.Type encfn func(*Encoder, *codecFnInfo, reflect.Value) decfn func(*Decoder, *codecFnInfo, reflect.Value) } type fastpathA [{{ .FastpathLen }}]fastpathE func (x *fastpathA) index(rtid uintptr) int { // use binary search to grab the index (adapted from sort/search.go) // Note: we use goto (instead of for loop) so this can be inlined. // h, i, j := 0, 0, len(x) var h, i uint var j = uint(len(x)) LOOP: if i < j { h = i + (j-i)/2 if x[h].rtid < rtid { i = h + 1 } else { j = h } goto LOOP } if i < uint(len(x)) && x[i].rtid == rtid { return int(i) } return -1 } type fastpathAslice []fastpathE func (x fastpathAslice) Len() int { return len(x) } func (x fastpathAslice) Less(i, j int) bool { return x[uint(i)].rtid < x[uint(j)].rtid } func (x fastpathAslice) Swap(i, j int) { x[uint(i)], x[uint(j)] = x[uint(j)], x[uint(i)] } var fastpathAV fastpathA // due to possible initialization loop error, make fastpath in an init() func init() { var i uint = 0 fn := func(v interface{}, fe func(*Encoder, *codecFnInfo, reflect.Value), fd func(*Decoder, *codecFnInfo, reflect.Value)) { xrt := reflect.TypeOf(v) xptr := rt2id(xrt) fastpathAV[i] = fastpathE{xptr, xrt, fe, fd} i++ } {{/* do not register []uint8 in fast-path */}} {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8"}} fn([]{{ .Elem }}(nil), (*Encoder).{{ .MethodNamePfx "fastpathEnc" false }}R, (*Decoder).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}{{end}} {{range .Values}}{{if not .Primitive}}{{if .MapKey }} fn(map[{{ .MapKey }}]{{ .Elem }}(nil), (*Encoder).{{ .MethodNamePfx "fastpathEnc" false }}R, (*Decoder).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}} sort.Sort(fastpathAslice(fastpathAV[:])) } // -- encode // -- -- fast path type switch func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { switch v := iv.(type) { {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8"}} case []{{ .Elem }}: fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e) case *[]{{ .Elem }}: fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e){{/* */}}{{end}}{{end}}{{end}}{{end}} {{range .Values}}{{if not .Primitive}}{{if .MapKey }} case map[{{ .MapKey }}]{{ .Elem }}: fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e) case *map[{{ .MapKey }}]{{ .Elem }}: fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e){{/* */}}{{end}}{{end}}{{end}} default: _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4 return false } return true } {{/* **** removing this block, as they are never called directly **** **** removing this block, as they are never called directly **** func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool { switch v := iv.(type) { {{range .Values}}{{if not .Primitive}}{{if not .MapKey }} case []{{ .Elem }}: fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e) case *[]{{ .Elem }}: fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e) {{end}}{{end}}{{end}} default: _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4 return false } return true } func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { switch v := iv.(type) { {{range .Values}}{{if not .Primitive}}{{if .MapKey }} case map[{{ .MapKey }}]{{ .Elem }}: fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e) case *map[{{ .MapKey }}]{{ .Elem }}: fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e) {{end}}{{end}}{{end}} default: _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4 return false } return true } **** removing this block, as they are never called directly **** **** removing this block, as they are never called directly **** */}} // -- -- fast path functions {{range .Values}}{{if not .Primitive}}{{if not .MapKey }} func (e *Encoder) {{ .MethodNamePfx "fastpathEnc" false }}R(f *codecFnInfo, rv reflect.Value) { if f.ti.mbs { fastpathTV.{{ .MethodNamePfx "EncAsMap" false }}V(rv2i(rv).([]{{ .Elem }}), e) } else { fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv2i(rv).([]{{ .Elem }}), e) } } func (fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, e *Encoder) { if v == nil { e.e.EncodeNil() return } e.arrayStart(len(v)) for j := range v { e.arrayElem() {{ encmd .Elem "v[j]"}} } e.arrayEnd() } func (fastpathT) {{ .MethodNamePfx "EncAsMap" false }}V(v []{{ .Elem }}, e *Encoder) { if v == nil { e.e.EncodeNil() } else if len(v)%2 == 1 { e.errorf(fastpathMapBySliceErrMsg, len(v)) } else { e.mapStart(len(v) / 2) for j := range v { if j%2 == 0 { e.mapElemKey() } else { e.mapElemValue() } {{ encmd .Elem "v[j]"}} } e.mapEnd() } } {{end}}{{end}}{{end}} {{range .Values}}{{if not .Primitive}}{{if .MapKey }} func (e *Encoder) {{ .MethodNamePfx "fastpathEnc" false }}R(f *codecFnInfo, rv reflect.Value) { fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv2i(rv).(map[{{ .MapKey }}]{{ .Elem }}), e) } func (fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, e *Encoder) { if v == nil { e.e.EncodeNil(); return } e.mapStart(len(v)) if e.h.Canonical { {{/* need to figure out .NoCanonical */}} {{if eq .MapKey "interface{}"}}{{/* out of band */ -}} var mksv []byte = make([]byte, 0, len(v)*16) // temporary byte slice for the encoding e2 := NewEncoderBytes(&mksv, e.hh) v2 := make([]bytesIntf, len(v)) var i, l uint var vp *bytesIntf {{/* put loop variables outside. seems currently needed for better perf */}} for k2 := range v { l = uint(len(mksv)) e2.MustEncode(k2) vp = &v2[i] vp.v = mksv[l:] vp.i = k2 i++ } sort.Sort(bytesIntfSlice(v2)) for j := range v2 { e.mapElemKey() e.asis(v2[j].v) e.mapElemValue() e.encode(v[v2[j].i]) } {{else}}{{ $x := sorttype .MapKey true}}v2 := make([]{{ $x }}, len(v)) var i uint for k := range v { v2[i] = {{if eq $x .MapKey}}k{{else}}{{ $x }}(k){{end}} i++ } sort.Sort({{ sorttype .MapKey false}}(v2)) for _, k2 := range v2 { e.mapElemKey() {{if eq .MapKey "string"}} if e.h.StringToRaw {e.e.EncodeStringBytesRaw(bytesView(k2))} else {e.e.EncodeStringEnc(cUTF8, k2)} {{else}}{{ $y := printf "%s(k2)" .MapKey }}{{if eq $x .MapKey }}{{ $y = "k2" }}{{end}}{{ encmd .MapKey $y }}{{end}} e.mapElemValue() {{ $y := printf "v[%s(k2)]" .MapKey }}{{if eq $x .MapKey }}{{ $y = "v[k2]" }}{{end}}{{ encmd .Elem $y }} } {{end}} } else { for k2, v2 := range v { e.mapElemKey() {{if eq .MapKey "string"}} if e.h.StringToRaw {e.e.EncodeStringBytesRaw(bytesView(k2))} else {e.e.EncodeStringEnc(cUTF8, k2)} {{else}}{{ encmd .MapKey "k2"}}{{end}} e.mapElemValue() {{ encmd .Elem "v2"}} } } e.mapEnd() } {{end}}{{end}}{{end}} // -- decode // -- -- fast path type switch func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool { var changed bool switch v := iv.(type) { {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8"}} case []{{ .Elem }}: var v2 []{{ .Elem }} v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, false, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } case *[]{{ .Elem }}: var v2 []{{ .Elem }} v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, true, d) if changed { *v = v2 }{{/* */}}{{end}}{{end}}{{end}}{{end}} {{range .Values}}{{if not .Primitive}}{{if .MapKey }}{{/* // maps only change if nil, and in that case, there's no point copying */}} case map[{{ .MapKey }}]{{ .Elem }}: fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, false, d) case *map[{{ .MapKey }}]{{ .Elem }}: var v2 map[{{ .MapKey }}]{{ .Elem }} v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, true, d) if changed { *v = v2 }{{/* */}}{{end}}{{end}}{{end}} default: _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4 return false } return true } func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool { switch v := iv.(type) { {{range .Values}}{{if not .Primitive}}{{if not .MapKey }} case *[]{{ .Elem }}: *v = nil {{/* */}}{{end}}{{end}}{{end}} {{range .Values}}{{if not .Primitive}}{{if .MapKey }} case *map[{{ .MapKey }}]{{ .Elem }}: *v = nil {{/* */}}{{end}}{{end}}{{end}} default: _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4 return false } return true } // -- -- fast path functions {{range .Values}}{{if not .Primitive}}{{if not .MapKey }} {{/* Slices can change if they - did not come from an array - are addressable (from a ptr) - are settable (e.g. contained in an interface{}) */}} func (d *Decoder) {{ .MethodNamePfx "fastpathDec" false }}R(f *codecFnInfo, rv reflect.Value) { if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*[]{{ .Elem }}) if v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, !array, d); changed { *vp = v } } else { v := rv2i(rv).([]{{ .Elem }}) v2, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, !array, d) if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) { copy(v, v2) } } } func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *[]{{ .Elem }}, d *Decoder) { if v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d); changed { *vp = v } } func (fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, canChange bool, d *Decoder) (_ []{{ .Elem }}, changed bool) { {{/* dd := d.d // if d.d.isContainerType(valueTypeNil) { d.d.TryDecodeAsNil() } */ -}} slh, containerLenS := d.decSliceHelperStart() if containerLenS == 0 { if canChange { if v == nil { v = []{{ .Elem }}{} } else if len(v) != 0 { v = v[:0] } changed = true } slh.End() return v, changed } hasLen := containerLenS > 0 var xlen int if hasLen && canChange { if containerLenS > cap(v) { xlen = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }}) if xlen <= cap(v) { v = v[:uint(xlen)] } else { v = make([]{{ .Elem }}, uint(xlen)) } changed = true } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } } var j int for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ { if j == 0 && len(v) == 0 && canChange { if hasLen { xlen = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }}) } else { xlen = 8 } v = make([]{{ .Elem }}, uint(xlen)) changed = true } {{/* // if indefinite, etc, then expand the slice if necessary */ -}} var decodeIntoBlank bool if j >= len(v) { if canChange { v = append(v, {{ zerocmd .Elem }}) changed = true } else { d.arrayCannotExpand(len(v), j+1) decodeIntoBlank = true } } slh.ElemContainerState(j) if decodeIntoBlank { d.swallow() } else if d.d.TryDecodeAsNil() { v[uint(j)] = {{ zerocmd .Elem }} } else { {{ if eq .Elem "interface{}" }}d.decode(&v[uint(j)]){{ else }}v[uint(j)] = {{ decmd .Elem }}{{ end }} } } if canChange { if j < len(v) { v = v[:uint(j)] changed = true } else if j == 0 && v == nil { v = make([]{{ .Elem }}, 0) changed = true } } slh.End() return v, changed } {{end}}{{end}}{{end}} {{range .Values}}{{if not .Primitive}}{{if .MapKey }} {{/* Maps can change if they are - addressable (from a ptr) - settable (e.g. contained in an interface{}) */}} func (d *Decoder) {{ .MethodNamePfx "fastpathDec" false }}R(f *codecFnInfo, rv reflect.Value) { if rv.Kind() == reflect.Ptr { vp := rv2i(rv).(*map[{{ .MapKey }}]{{ .Elem }}) if v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d); changed { *vp = v } } else { fastpathTV.{{ .MethodNamePfx "Dec" false }}V(rv2i(rv).(map[{{ .MapKey }}]{{ .Elem }}), false, d) } } func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *map[{{ .MapKey }}]{{ .Elem }}, d *Decoder) { if v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d); changed { *vp = v } } func (fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, canChange bool, d *Decoder) (_ map[{{ .MapKey }}]{{ .Elem }}, changed bool) { {{/* // if d.d.isContainerType(valueTypeNil) {d.d.TryDecodeAsNil() */ -}} containerLen := d.mapStart() if canChange && v == nil { v = make(map[{{ .MapKey }}]{{ .Elem }}, decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }})) changed = true } if containerLen == 0 { d.mapEnd() return v, changed } {{if eq .Elem "interface{}" }}mapGet := v != nil && !d.h.MapValueReset && !d.h.InterfaceReset {{else if eq .Elem "bytes" "[]byte" }}mapGet := v != nil && !d.h.MapValueReset {{end -}} var mk {{ .MapKey }} var mv {{ .Elem }} hasLen := containerLen > 0 for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ { d.mapElemKey() {{ if eq .MapKey "interface{}" }}mk = nil d.decode(&mk) if bv, bok := mk.([]byte); bok { mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}} }{{ else }}mk = {{ decmd .MapKey }}{{ end }} d.mapElemValue() if d.d.TryDecodeAsNil() { if v == nil {} else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = {{ zerocmd .Elem }} } continue } {{ if eq .Elem "interface{}" "[]byte" "bytes" -}} if mapGet { mv = v[mk] } else { mv = nil } {{ end -}} {{ if eq .Elem "interface{}" -}} d.decode(&mv) {{ else if eq .Elem "[]byte" "bytes" -}} mv = d.d.DecodeBytes(mv, false) {{ else -}} mv = {{ decmd .Elem }} {{ end -}} if v != nil { v[mk] = mv } } d.mapEnd() return v, changed } {{end}}{{end}}{{end}} ================================================ FILE: vendor/github.com/ugorji/go/codec/fast-path.not.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // +build notfastpath package codec import "reflect" const fastpathEnabled = false // The generated fast-path code is very large, and adds a few seconds to the build time. // This causes test execution, execution of small tools which use codec, etc // to take a long time. // // To mitigate, we now support the notfastpath tag. // This tag disables fastpath during build, allowing for faster build, test execution, // short-program runs, etc. func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool { return false } func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { return false } func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool { return false } func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { return false } func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool { return false } type fastpathT struct{} type fastpathE struct { rtid uintptr rt reflect.Type encfn func(*Encoder, *codecFnInfo, reflect.Value) decfn func(*Decoder, *codecFnInfo, reflect.Value) } type fastpathA [0]fastpathE func (x fastpathA) index(rtid uintptr) int { return -1 } func (_ fastpathT) DecSliceUint8V(v []uint8, canChange bool, d *Decoder) (_ []uint8, changed bool) { fn := d.h.fn(uint8SliceTyp, true, true) d.kSlice(&fn.i, reflect.ValueOf(&v).Elem()) return v, true } var fastpathAV fastpathA var fastpathTV fastpathT // ---- type TestMammoth2Wrapper struct{} // to allow testMammoth work in notfastpath mode ================================================ FILE: vendor/github.com/ugorji/go/codec/gen-dec-array.go.tmpl ================================================ {{var "v"}} := {{if not isArray}}*{{end}}{{ .Varname }} {{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}}{{if not isArray}} var {{var "c"}} bool {{/* // changed */}} _ = {{var "c"}}{{end}} if {{var "l"}} == 0 { {{if isSlice }}if {{var "v"}} == nil { {{var "v"}} = []{{ .Typ }}{} {{var "c"}} = true } else if len({{var "v"}}) != 0 { {{var "v"}} = {{var "v"}}[:0] {{var "c"}} = true } {{else if isChan }}if {{var "v"}} == nil { {{var "v"}} = make({{ .CTyp }}, 0) {{var "c"}} = true } {{end -}} } else { {{var "hl"}} := {{var "l"}} > 0 var {{var "rl"}} int _ = {{var "rl"}} {{if isSlice }} if {{var "hl"}} { if {{var "l"}} > cap({{var "v"}}) { {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}) if {{var "rl"}} <= cap({{var "v"}}) { {{var "v"}} = {{var "v"}}[:{{var "rl"}}] } else { {{var "v"}} = make([]{{ .Typ }}, {{var "rl"}}) } {{var "c"}} = true } else if {{var "l"}} != len({{var "v"}}) { {{var "v"}} = {{var "v"}}[:{{var "l"}}] {{var "c"}} = true } } {{end -}} var {{var "j"}} int {{/* // var {{var "dn"}} bool */ -}} for {{var "j"}} = 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ { // bounds-check-elimination {{if not isArray}} if {{var "j"}} == 0 && {{var "v"}} == nil { if {{var "hl"}} { {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}) } else { {{var "rl"}} = {{if isSlice}}8{{else if isChan}}64{{end}} } {{var "v"}} = make({{if isSlice}}[]{{ .Typ }}{{else if isChan}}{{.CTyp}}{{end}}, {{var "rl"}}) {{var "c"}} = true } {{end -}} {{var "h"}}.ElemContainerState({{var "j"}}) {{/* {{var "dn"}} = r.TryDecodeAsNil() */}}{{/* commented out, as decLineVar handles this already each time */ -}} {{if isChan}}{{ $x := printf "%[1]vvcx%[2]v" .TempVar .Rand }}var {{$x}} {{ .Typ }} {{ decLineVar $x -}} {{var "v"}} <- {{ $x }} // println(">>>> sending ", {{ $x }}, " into ", {{var "v"}}) // TODO: remove this {{else}}{{/* // if indefinite, etc, then expand the slice if necessary */ -}} var {{var "db"}} bool if {{var "j"}} >= len({{var "v"}}) { {{if isSlice }} {{var "v"}} = append({{var "v"}}, {{ zero }}) {{var "c"}} = true {{else}} z.DecArrayCannotExpand(len(v), {{var "j"}}+1); {{var "db"}} = true {{end -}} } if {{var "db"}} { z.DecSwallow() } else { {{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x -}} } {{end -}} } {{if isSlice}} if {{var "j"}} < len({{var "v"}}) { {{var "v"}} = {{var "v"}}[:{{var "j"}}] {{var "c"}} = true } else if {{var "j"}} == 0 && {{var "v"}} == nil { {{var "v"}} = make([]{{ .Typ }}, 0) {{var "c"}} = true } {{end -}} } {{var "h"}}.End() {{if not isArray }}if {{var "c"}} { *{{ .Varname }} = {{var "v"}} } {{end -}} ================================================ FILE: vendor/github.com/ugorji/go/codec/gen-dec-map.go.tmpl ================================================ {{var "v"}} := *{{ .Varname }} {{var "l"}} := z.DecReadMapStart() {{var "bh"}} := z.DecBasicHandle() if {{var "v"}} == nil { {{var "rl"}} := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }}) {{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}}) *{{ .Varname }} = {{var "v"}} } var {{var "mk"}} {{ .KTyp }} var {{var "mv"}} {{ .Typ }} var {{var "mg"}}, {{var "mdn"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool if {{var "bh"}}.MapValueReset { {{if decElemKindPtr}}{{var "mg"}} = true {{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true } {{else if not decElemKindImmutable}}{{var "mg"}} = true {{end}} } if {{var "l"}} != 0 { {{var "hl"}} := {{var "l"}} > 0 for {{var "j"}} := 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ { z.DecReadMapElemKey() {{/* z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }}) */}} {{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x -}} {{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */ -}} if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} { {{var "mk"}} = string({{var "bv"}}) } {{ end -}} {{if decElemKindPtr -}} {{var "ms"}} = true {{end -}} if {{var "mg"}} { {{if decElemKindPtr -}} {{var "mv"}}, {{var "mok"}} = {{var "v"}}[{{var "mk"}}] if {{var "mok"}} { {{var "ms"}} = false } {{else -}} {{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end -}} } {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}} z.DecReadMapElemValue() {{/* z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }}) */}} {{var "mdn"}} = false {{ $x := printf "%vmv%v" .TempVar .Rand }}{{ $y := printf "%vmdn%v" .TempVar .Rand }}{{ decLineVar $x $y -}} if {{var "mdn"}} { if {{ var "bh" }}.DeleteOnNilMapValue { delete({{var "v"}}, {{var "mk"}}) } else { {{var "v"}}[{{var "mk"}}] = {{decElemZero}} } } else if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil { {{var "v"}}[{{var "mk"}}] = {{var "mv"}} } } } // else len==0: TODO: Should we clear map entries? z.DecReadMapEnd() {{/* z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }}) */}} ================================================ FILE: vendor/github.com/ugorji/go/codec/gen-enc-chan.go.tmpl ================================================ {{.Label}}: switch timeout{{.Sfx}} := z.EncBasicHandle().ChanRecvTimeout; { case timeout{{.Sfx}} == 0: // only consume available for { select { case b{{.Sfx}} := <-{{.Chan}}: {{ .Slice }} = append({{.Slice}}, b{{.Sfx}}) default: break {{.Label}} } } case timeout{{.Sfx}} > 0: // consume until timeout tt{{.Sfx}} := time.NewTimer(timeout{{.Sfx}}) for { select { case b{{.Sfx}} := <-{{.Chan}}: {{.Slice}} = append({{.Slice}}, b{{.Sfx}}) case <-tt{{.Sfx}}.C: // close(tt.C) break {{.Label}} } } default: // consume until close for b{{.Sfx}} := range {{.Chan}} { {{.Slice}} = append({{.Slice}}, b{{.Sfx}}) } } ================================================ FILE: vendor/github.com/ugorji/go/codec/gen-helper.generated.go ================================================ // comment this out // + build ignore // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // Code generated from gen-helper.go.tmpl - DO NOT EDIT. package codec import ( "encoding" "reflect" ) // GenVersion is the current version of codecgen. const GenVersion = 12 // This file is used to generate helper code for codecgen. // The values here i.e. genHelper(En|De)coder are not to be used directly by // library users. They WILL change continuously and without notice. // GenHelperEncoder is exported so that it can be used externally by codecgen. // // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE. func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee genHelperEncDriver) { ge = genHelperEncoder{e: e} ee = genHelperEncDriver{encDriver: e.e} return } // GenHelperDecoder is exported so that it can be used externally by codecgen. // // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE. func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd genHelperDecDriver) { gd = genHelperDecoder{d: d} dd = genHelperDecDriver{decDriver: d.d} return } type genHelperEncDriver struct { encDriver } type genHelperDecDriver struct { decDriver } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* type genHelperEncoder struct { M must F fastpathT e *Encoder } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* type genHelperDecoder struct { C checkOverflow F fastpathT d *Decoder } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncBasicHandle() *BasicHandle { return f.e.h } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncBinary() bool { return f.e.be // f.e.hh.isBinaryEncoding() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) IsJSONHandle() bool { return f.e.js } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncFallback(iv interface{}) { // f.e.encodeI(iv, false, false) f.e.encodeValue(reflect.ValueOf(iv), nil, false) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) { bs, fnerr := iv.MarshalText() f.e.marshalUtf8(bs, fnerr) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) { bs, fnerr := iv.MarshalJSON() f.e.marshalAsis(bs, fnerr) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) { bs, fnerr := iv.MarshalBinary() f.e.marshalRaw(bs, fnerr) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncRaw(iv Raw) { f.e.rawBytes(iv) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) I2Rtid(v interface{}) uintptr { return i2rtid(v) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) Extension(rtid uintptr) (xfn *extTypeTagFn) { return f.e.h.getExt(rtid) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncExtension(v interface{}, xfFn *extTypeTagFn) { f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) WriteStr(s string) { f.e.w().writestr(s) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) BytesView(v string) []byte { return bytesView(v) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteMapStart(length int) { f.e.mapStart(length) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteMapEnd() { f.e.mapEnd() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteArrayStart(length int) { f.e.arrayStart(length) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteArrayEnd() { f.e.arrayEnd() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteArrayElem() { f.e.arrayElem() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteMapElemKey() { f.e.mapElemKey() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteMapElemValue() { f.e.mapElemValue() } // ---------------- DECODER FOLLOWS ----------------- // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecBasicHandle() *BasicHandle { return f.d.h } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecBinary() bool { return f.d.be // f.d.hh.isBinaryEncoding() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecSwallow() { f.d.swallow() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecScratchBuffer() []byte { return f.d.b[:] } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecScratchArrayBuffer() *[decScratchByteArrayLen]byte { return &f.d.b } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) { rv := reflect.ValueOf(iv) if chkPtr { rv = f.d.ensureDecodeable(rv) } f.d.decodeValue(rv, nil, false) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecSliceHelperStart() (decSliceHelper, int) { return f.d.decSliceHelperStart() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecStructFieldNotFound(index int, name string) { f.d.structFieldNotFound(index, name) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecArrayCannotExpand(sliceLen, streamLen int) { f.d.arrayCannotExpand(sliceLen, streamLen) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) { if fnerr := tm.UnmarshalText(f.d.d.DecodeStringAsBytes()); fnerr != nil { panic(fnerr) } } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) { // bs := f.dd.DecodeStringAsBytes() // grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself. if fnerr := tm.UnmarshalJSON(f.d.nextValueBytes()); fnerr != nil { panic(fnerr) } } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) { if fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, true)); fnerr != nil { panic(fnerr) } } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecRaw() []byte { return f.d.rawBytes() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) IsJSONHandle() bool { return f.d.js } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) I2Rtid(v interface{}) uintptr { return i2rtid(v) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) Extension(rtid uintptr) (xfn *extTypeTagFn) { return f.d.h.getExt(rtid) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecExtension(v interface{}, xfFn *extTypeTagFn) { f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int) { return decInferLen(clen, maxlen, unit) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) StringView(v []byte) string { return stringView(v) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecReadMapStart() int { return f.d.mapStart() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecReadMapEnd() { f.d.mapEnd() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecReadArrayStart() int { return f.d.arrayStart() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecReadArrayEnd() { f.d.arrayEnd() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecReadArrayElem() { f.d.arrayElem() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecReadMapElemKey() { f.d.mapElemKey() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecReadMapElemValue() { f.d.mapElemValue() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecDecodeFloat32() float64 { return f.d.decodeFloat32() } ================================================ FILE: vendor/github.com/ugorji/go/codec/gen-helper.go.tmpl ================================================ // comment this out // + build ignore // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // Code generated from gen-helper.go.tmpl - DO NOT EDIT. package codec import ( "encoding" "reflect" ) // GenVersion is the current version of codecgen. const GenVersion = {{ .Version }} // This file is used to generate helper code for codecgen. // The values here i.e. genHelper(En|De)coder are not to be used directly by // library users. They WILL change continuously and without notice. {{/* // To help enforce this, we create an unexported type with exported members. // The only way to get the type is via the one exported type that we control (somewhat). // // When static codecs are created for types, they will use this value // to perform encoding or decoding of primitives or known slice or map types. */ -}} // GenHelperEncoder is exported so that it can be used externally by codecgen. // // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE. func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee genHelperEncDriver) { ge = genHelperEncoder{e: e} ee = genHelperEncDriver{encDriver: e.e} return } // GenHelperDecoder is exported so that it can be used externally by codecgen. // // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE. func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd genHelperDecDriver) { gd = genHelperDecoder{d: d} dd = genHelperDecDriver{decDriver: d.d} return } type genHelperEncDriver struct { encDriver } type genHelperDecDriver struct { decDriver } {{/* // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) { encStructFieldKey(s, x.encDriver, nil, keyType, false, false) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (x genHelperDecDriver) DecStructFieldKey(keyType valueType, buf *[decScratchByteArrayLen]byte) []byte { return decStructFieldKey(x.decDriver, keyType, buf) } */ -}} // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* type genHelperEncoder struct { M must F fastpathT e *Encoder } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* type genHelperDecoder struct { C checkOverflow F fastpathT d *Decoder } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncBasicHandle() *BasicHandle { return f.e.h } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncBinary() bool { return f.e.be // f.e.hh.isBinaryEncoding() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) IsJSONHandle() bool { return f.e.js } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncFallback(iv interface{}) { // f.e.encodeI(iv, false, false) f.e.encodeValue(reflect.ValueOf(iv), nil, false) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) { bs, fnerr := iv.MarshalText() f.e.marshalUtf8(bs, fnerr) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) { bs, fnerr := iv.MarshalJSON() f.e.marshalAsis(bs, fnerr) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) { bs, fnerr := iv.MarshalBinary() f.e.marshalRaw(bs, fnerr) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncRaw(iv Raw) { f.e.rawBytes(iv) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) I2Rtid(v interface{}) uintptr { return i2rtid(v) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) Extension(rtid uintptr) (xfn *extTypeTagFn) { return f.e.h.getExt(rtid) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncExtension(v interface{}, xfFn *extTypeTagFn) { f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) WriteStr(s string) { f.e.w().writestr(s) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) BytesView(v string) []byte { return bytesView(v) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteMapStart(length int) { f.e.mapStart(length) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteMapEnd() { f.e.mapEnd() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteArrayStart(length int) { f.e.arrayStart(length) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteArrayEnd() { f.e.arrayEnd() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteArrayElem() { f.e.arrayElem() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteMapElemKey() { f.e.mapElemKey() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperEncoder) EncWriteMapElemValue() { f.e.mapElemValue() } // ---------------- DECODER FOLLOWS ----------------- // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecBasicHandle() *BasicHandle { return f.d.h } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecBinary() bool { return f.d.be // f.d.hh.isBinaryEncoding() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecSwallow() { f.d.swallow() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecScratchBuffer() []byte { return f.d.b[:] } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecScratchArrayBuffer() *[decScratchByteArrayLen]byte { return &f.d.b } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) { rv := reflect.ValueOf(iv) if chkPtr { rv = f.d.ensureDecodeable(rv) } f.d.decodeValue(rv, nil, false) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecSliceHelperStart() (decSliceHelper, int) { return f.d.decSliceHelperStart() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecStructFieldNotFound(index int, name string) { f.d.structFieldNotFound(index, name) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecArrayCannotExpand(sliceLen, streamLen int) { f.d.arrayCannotExpand(sliceLen, streamLen) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) { if fnerr := tm.UnmarshalText(f.d.d.DecodeStringAsBytes()); fnerr != nil { panic(fnerr) } } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) { // bs := f.dd.DecodeStringAsBytes() // grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself. if fnerr := tm.UnmarshalJSON(f.d.nextValueBytes()); fnerr != nil { panic(fnerr) } } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) { if fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, true)); fnerr != nil { panic(fnerr) } } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecRaw() []byte { return f.d.rawBytes() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) IsJSONHandle() bool { return f.d.js } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) I2Rtid(v interface{}) uintptr { return i2rtid(v) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) Extension(rtid uintptr) (xfn *extTypeTagFn) { return f.d.h.getExt(rtid) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecExtension(v interface{}, xfFn *extTypeTagFn) { f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int) { return decInferLen(clen, maxlen, unit) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) StringView(v []byte) string { return stringView(v) } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecReadMapStart() int { return f.d.mapStart() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecReadMapEnd() { f.d.mapEnd() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecReadArrayStart() int { return f.d.arrayStart() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecReadArrayEnd() { f.d.arrayEnd() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecReadArrayElem() { f.d.arrayElem() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecReadMapElemKey() { f.d.mapElemKey() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecReadMapElemValue() { f.d.mapElemValue() } // FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* func (f genHelperDecoder) DecDecodeFloat32() float64 { return f.d.decodeFloat32() } ================================================ FILE: vendor/github.com/ugorji/go/codec/gen.generated.go ================================================ // +build codecgen.exec // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. package codec // DO NOT EDIT. THIS FILE IS AUTO-GENERATED FROM gen-dec-(map|array).go.tmpl const genDecMapTmpl = ` {{var "v"}} := *{{ .Varname }} {{var "l"}} := z.DecReadMapStart() {{var "bh"}} := z.DecBasicHandle() if {{var "v"}} == nil { {{var "rl"}} := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }}) {{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}}) *{{ .Varname }} = {{var "v"}} } var {{var "mk"}} {{ .KTyp }} var {{var "mv"}} {{ .Typ }} var {{var "mg"}}, {{var "mdn"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool if {{var "bh"}}.MapValueReset { {{if decElemKindPtr}}{{var "mg"}} = true {{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true } {{else if not decElemKindImmutable}}{{var "mg"}} = true {{end}} } if {{var "l"}} != 0 { {{var "hl"}} := {{var "l"}} > 0 for {{var "j"}} := 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ { z.DecReadMapElemKey() {{/* z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }}) */}} {{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x -}} {{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */ -}} if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} { {{var "mk"}} = string({{var "bv"}}) } {{ end -}} {{if decElemKindPtr -}} {{var "ms"}} = true {{end -}} if {{var "mg"}} { {{if decElemKindPtr -}} {{var "mv"}}, {{var "mok"}} = {{var "v"}}[{{var "mk"}}] if {{var "mok"}} { {{var "ms"}} = false } {{else -}} {{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end -}} } {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}} z.DecReadMapElemValue() {{/* z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }}) */}} {{var "mdn"}} = false {{ $x := printf "%vmv%v" .TempVar .Rand }}{{ $y := printf "%vmdn%v" .TempVar .Rand }}{{ decLineVar $x $y -}} if {{var "mdn"}} { if {{ var "bh" }}.DeleteOnNilMapValue { delete({{var "v"}}, {{var "mk"}}) } else { {{var "v"}}[{{var "mk"}}] = {{decElemZero}} } } else if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil { {{var "v"}}[{{var "mk"}}] = {{var "mv"}} } } } // else len==0: TODO: Should we clear map entries? z.DecReadMapEnd() {{/* z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }}) */}} ` const genDecListTmpl = ` {{var "v"}} := {{if not isArray}}*{{end}}{{ .Varname }} {{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}}{{if not isArray}} var {{var "c"}} bool {{/* // changed */}} _ = {{var "c"}}{{end}} if {{var "l"}} == 0 { {{if isSlice }}if {{var "v"}} == nil { {{var "v"}} = []{{ .Typ }}{} {{var "c"}} = true } else if len({{var "v"}}) != 0 { {{var "v"}} = {{var "v"}}[:0] {{var "c"}} = true } {{else if isChan }}if {{var "v"}} == nil { {{var "v"}} = make({{ .CTyp }}, 0) {{var "c"}} = true } {{end -}} } else { {{var "hl"}} := {{var "l"}} > 0 var {{var "rl"}} int _ = {{var "rl"}} {{if isSlice }} if {{var "hl"}} { if {{var "l"}} > cap({{var "v"}}) { {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}) if {{var "rl"}} <= cap({{var "v"}}) { {{var "v"}} = {{var "v"}}[:{{var "rl"}}] } else { {{var "v"}} = make([]{{ .Typ }}, {{var "rl"}}) } {{var "c"}} = true } else if {{var "l"}} != len({{var "v"}}) { {{var "v"}} = {{var "v"}}[:{{var "l"}}] {{var "c"}} = true } } {{end -}} var {{var "j"}} int {{/* // var {{var "dn"}} bool */ -}} for {{var "j"}} = 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ { // bounds-check-elimination {{if not isArray}} if {{var "j"}} == 0 && {{var "v"}} == nil { if {{var "hl"}} { {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}) } else { {{var "rl"}} = {{if isSlice}}8{{else if isChan}}64{{end}} } {{var "v"}} = make({{if isSlice}}[]{{ .Typ }}{{else if isChan}}{{.CTyp}}{{end}}, {{var "rl"}}) {{var "c"}} = true } {{end -}} {{var "h"}}.ElemContainerState({{var "j"}}) {{/* {{var "dn"}} = r.TryDecodeAsNil() */}}{{/* commented out, as decLineVar handles this already each time */ -}} {{if isChan}}{{ $x := printf "%[1]vvcx%[2]v" .TempVar .Rand }}var {{$x}} {{ .Typ }} {{ decLineVar $x -}} {{var "v"}} <- {{ $x }} // println(">>>> sending ", {{ $x }}, " into ", {{var "v"}}) // TODO: remove this {{else}}{{/* // if indefinite, etc, then expand the slice if necessary */ -}} var {{var "db"}} bool if {{var "j"}} >= len({{var "v"}}) { {{if isSlice }} {{var "v"}} = append({{var "v"}}, {{ zero }}) {{var "c"}} = true {{else}} z.DecArrayCannotExpand(len(v), {{var "j"}}+1); {{var "db"}} = true {{end -}} } if {{var "db"}} { z.DecSwallow() } else { {{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x -}} } {{end -}} } {{if isSlice}} if {{var "j"}} < len({{var "v"}}) { {{var "v"}} = {{var "v"}}[:{{var "j"}}] {{var "c"}} = true } else if {{var "j"}} == 0 && {{var "v"}} == nil { {{var "v"}} = make([]{{ .Typ }}, 0) {{var "c"}} = true } {{end -}} } {{var "h"}}.End() {{if not isArray }}if {{var "c"}} { *{{ .Varname }} = {{var "v"}} } {{end -}} ` const genEncChanTmpl = ` {{.Label}}: switch timeout{{.Sfx}} := z.EncBasicHandle().ChanRecvTimeout; { case timeout{{.Sfx}} == 0: // only consume available for { select { case b{{.Sfx}} := <-{{.Chan}}: {{ .Slice }} = append({{.Slice}}, b{{.Sfx}}) default: break {{.Label}} } } case timeout{{.Sfx}} > 0: // consume until timeout tt{{.Sfx}} := time.NewTimer(timeout{{.Sfx}}) for { select { case b{{.Sfx}} := <-{{.Chan}}: {{.Slice}} = append({{.Slice}}, b{{.Sfx}}) case <-tt{{.Sfx}}.C: // close(tt.C) break {{.Label}} } } default: // consume until close for b{{.Sfx}} := range {{.Chan}} { {{.Slice}} = append({{.Slice}}, b{{.Sfx}}) } } ` ================================================ FILE: vendor/github.com/ugorji/go/codec/gen.go ================================================ // +build codecgen.exec // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. package codec import ( "bytes" "encoding/base64" "errors" "fmt" "go/format" "io" "io/ioutil" "math/rand" "reflect" "regexp" "sort" "strconv" "strings" "sync" "text/template" "time" "unicode" "unicode/utf8" ) // --------------------------------------------------- // codecgen supports the full cycle of reflection-based codec: // - RawExt // - Raw // - Extensions // - (Binary|Text|JSON)(Unm|M)arshal // - generic by-kind // // This means that, for dynamic things, we MUST use reflection to at least get the reflect.Type. // In those areas, we try to only do reflection or interface-conversion when NECESSARY: // - Extensions, only if Extensions are configured. // // However, codecgen doesn't support the following: // - Canonical option. (codecgen IGNORES it currently) // This is just because it has not been implemented. // - MissingFielder implementation. // If a type implements MissingFielder, it is completely ignored by codecgen. // // During encode/decode, Selfer takes precedence. // A type implementing Selfer will know how to encode/decode itself statically. // // The following field types are supported: // array: [n]T // slice: []T // map: map[K]V // primitive: [u]int[n], float(32|64), bool, string // struct // // --------------------------------------------------- // Note that a Selfer cannot call (e|d).(En|De)code on itself, // as this will cause a circular reference, as (En|De)code will call Selfer methods. // Any type that implements Selfer must implement completely and not fallback to (En|De)code. // // In addition, code in this file manages the generation of fast-path implementations of // encode/decode of slices/maps of primitive keys/values. // // Users MUST re-generate their implementations whenever the code shape changes. // The generated code will panic if it was generated with a version older than the supporting library. // --------------------------------------------------- // // codec framework is very feature rich. // When encoding or decoding into an interface, it depends on the runtime type of the interface. // The type of the interface may be a named type, an extension, etc. // Consequently, we fallback to runtime codec for encoding/decoding interfaces. // In addition, we fallback for any value which cannot be guaranteed at runtime. // This allows us support ANY value, including any named types, specifically those which // do not implement our interfaces (e.g. Selfer). // // This explains some slowness compared to other code generation codecs (e.g. msgp). // This reduction in speed is only seen when your refers to interfaces, // e.g. type T struct { A interface{}; B []interface{}; C map[string]interface{} } // // codecgen will panic if the file was generated with an old version of the library in use. // // Note: // It was a conscious decision to have gen.go always explicitly call EncodeNil or TryDecodeAsNil. // This way, there isn't a function call overhead just to see that we should not enter a block of code. // // Note: // codecgen-generated code depends on the variables defined by fast-path.generated.go. // consequently, you cannot run with tags "codecgen notfastpath". // GenVersion is the current version of codecgen. // // NOTE: Increment this value each time codecgen changes fundamentally. // Fundamental changes are: // - helper methods change (signature change, new ones added, some removed, etc) // - codecgen command line changes // // v1: Initial Version // v2: // v3: Changes for Kubernetes: // changes in signature of some unpublished helper methods and codecgen cmdline arguments. // v4: Removed separator support from (en|de)cDriver, and refactored codec(gen) // v5: changes to support faster json decoding. Let encoder/decoder maintain state of collections. // v6: removed unsafe from gen, and now uses codecgen.exec tag // v7: // v8: current - we now maintain compatibility with old generated code. // v9: skipped // v10: modified encDriver and decDriver interfaces. // v11: remove deprecated methods of encDriver and decDriver. // v12: removed deprecated methods from genHelper and changed container tracking logic const genVersion = 12 const ( genCodecPkg = "codec1978" genTempVarPfx = "yy" genTopLevelVarName = "x" // ignore canBeNil parameter, and always set to true. // This is because nil can appear anywhere, so we should always check. genAnythingCanBeNil = true // if genUseOneFunctionForDecStructMap, make a single codecDecodeSelferFromMap function; // else make codecDecodeSelferFromMap{LenPrefix,CheckBreak} so that conditionals // are not executed a lot. // // From testing, it didn't make much difference in runtime, so keep as true (one function only) genUseOneFunctionForDecStructMap = true // genFastpathCanonical configures whether we support Canonical in fast path. // The savings is not much. // // NOTE: This MUST ALWAYS BE TRUE. fast-path.go.tmp doesn't handle it being false. genFastpathCanonical = true // MUST be true // genFastpathTrimTypes configures whether we trim uncommon fastpath types. genFastpathTrimTypes = true ) type genStructMapStyle uint8 const ( genStructMapStyleConsolidated genStructMapStyle = iota genStructMapStyleLenPrefix genStructMapStyleCheckBreak ) var ( errGenAllTypesSamePkg = errors.New("All types must be in the same package") errGenExpectArrayOrMap = errors.New("unexpected type. Expecting array/map/slice") genBase64enc = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789__") genQNameRegex = regexp.MustCompile(`[A-Za-z_.]+`) ) type genBuf struct { buf []byte } func (x *genBuf) s(s string) *genBuf { x.buf = append(x.buf, s...); return x } func (x *genBuf) b(s []byte) *genBuf { x.buf = append(x.buf, s...); return x } func (x *genBuf) v() string { return string(x.buf) } func (x *genBuf) f(s string, args ...interface{}) { x.s(fmt.Sprintf(s, args...)) } func (x *genBuf) reset() { if x.buf != nil { x.buf = x.buf[:0] } } // genRunner holds some state used during a Gen run. type genRunner struct { w io.Writer // output c uint64 // counter used for generating varsfx f uint64 // counter used for saying false t []reflect.Type // list of types to run selfer on tc reflect.Type // currently running selfer on this type te map[uintptr]bool // types for which the encoder has been created td map[uintptr]bool // types for which the decoder has been created cp string // codec import path im map[string]reflect.Type // imports to add imn map[string]string // package names of imports to add imc uint64 // counter for import numbers is map[reflect.Type]struct{} // types seen during import search bp string // base PkgPath, for which we are generating for cpfx string // codec package prefix tm map[reflect.Type]struct{} // types for which enc/dec must be generated ts []reflect.Type // types for which enc/dec must be generated xs string // top level variable/constant suffix hn string // fn helper type name ti *TypeInfos // rr *rand.Rand // random generator for file-specific types nx bool // no extensions } type genIfClause struct { hasIf bool } func (g *genIfClause) end(x *genRunner) { if g.hasIf { x.line("}") } } func (g *genIfClause) c(last bool) (v string) { if last { if g.hasIf { v = " } else { " } } else if g.hasIf { v = " } else if " } else { v = "if " g.hasIf = true } return } // Gen will write a complete go file containing Selfer implementations for each // type passed. All the types must be in the same package. // // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINUOUSLY WITHOUT NOTICE. func Gen(w io.Writer, buildTags, pkgName, uid string, noExtensions bool, ti *TypeInfos, typ ...reflect.Type) { // All types passed to this method do not have a codec.Selfer method implemented directly. // codecgen already checks the AST and skips any types that define the codec.Selfer methods. // Consequently, there's no need to check and trim them if they implement codec.Selfer if len(typ) == 0 { return } x := genRunner{ w: w, t: typ, te: make(map[uintptr]bool), td: make(map[uintptr]bool), im: make(map[string]reflect.Type), imn: make(map[string]string), is: make(map[reflect.Type]struct{}), tm: make(map[reflect.Type]struct{}), ts: []reflect.Type{}, bp: genImportPath(typ[0]), xs: uid, ti: ti, nx: noExtensions, } if x.ti == nil { x.ti = defTypeInfos } if x.xs == "" { rr := rand.New(rand.NewSource(time.Now().UnixNano())) x.xs = strconv.FormatInt(rr.Int63n(9999), 10) } // gather imports first: x.cp = genImportPath(reflect.TypeOf(x)) x.imn[x.cp] = genCodecPkg for _, t := range typ { // fmt.Printf("###########: PkgPath: '%v', Name: '%s'\n", genImportPath(t), t.Name()) if genImportPath(t) != x.bp { panic(errGenAllTypesSamePkg) } x.genRefPkgs(t) } if buildTags != "" { x.line("// +build " + buildTags) x.line("") } x.line(` // Code generated by codecgen - DO NOT EDIT. `) x.line("package " + pkgName) x.line("") x.line("import (") if x.cp != x.bp { x.cpfx = genCodecPkg + "." x.linef("%s \"%s\"", genCodecPkg, x.cp) } // use a sorted set of im keys, so that we can get consistent output imKeys := make([]string, 0, len(x.im)) for k := range x.im { imKeys = append(imKeys, k) } sort.Strings(imKeys) for _, k := range imKeys { // for k, _ := range x.im { if k == x.imn[k] { x.linef("\"%s\"", k) } else { x.linef("%s \"%s\"", x.imn[k], k) } } // add required packages for _, k := range [...]string{"runtime", "errors", "strconv"} { // "reflect", "fmt" if _, ok := x.im[k]; !ok { x.line("\"" + k + "\"") } } x.line(")") x.line("") x.line("const (") x.linef("// ----- content types ----") x.linef("codecSelferCcUTF8%s = %v", x.xs, int64(cUTF8)) x.linef("codecSelferCcRAW%s = %v", x.xs, int64(cRAW)) x.linef("// ----- value types used ----") for _, vt := range [...]valueType{ valueTypeArray, valueTypeMap, valueTypeString, valueTypeInt, valueTypeUint, valueTypeFloat} { x.linef("codecSelferValueType%s%s = %v", vt.String(), x.xs, int64(vt)) } x.linef("codecSelferBitsize%s = uint8(32 << (^uint(0) >> 63))", x.xs) x.line(")") x.line("var (") x.line("errCodecSelferOnlyMapOrArrayEncodeToStruct" + x.xs + " = " + "\nerrors.New(`only encoded map or array can be decoded into a struct`)") x.line(")") x.line("") x.hn = "codecSelfer" + x.xs x.line("type " + x.hn + " struct{}") x.line("") x.linef("func %sFalse() bool { return false }", x.hn) x.line("") x.varsfxreset() x.line("func init() {") x.linef("if %sGenVersion != %v {", x.cpfx, genVersion) x.line("_, file, _, _ := runtime.Caller(0)") x.linef("ver := strconv.FormatInt(int64(%sGenVersion), 10)", x.cpfx) x.outf(`panic("codecgen version mismatch: current: %v, need " + ver + ". Re-generate file: " + file)`, genVersion) // x.out(`panic(fmt.Errorf("codecgen version mismatch: current: %v, need %v. Re-generate file: %v", `) // x.linef(`%v, %sGenVersion, file))`, genVersion, x.cpfx) x.linef("}") if len(imKeys) > 0 { x.line("if false { // reference the types, but skip this branch at build/run time") x.line("var _ byte") // x.line("_ = strconv.ParseInt") // var n int // for k, t := range x.im { for _, k := range imKeys { t := x.im[k] // x.linef("var v%v %s.%s", n, x.imn[k], t.Name()) // n++ x.linef("var _ %s.%s", x.imn[k], t.Name()) } // if n > 0 { // x.out("_") // for i := 1; i < n; i++ { // x.out(", _") // } // x.out(" = v0") // for i := 1; i < n; i++ { // x.outf(", v%v", i) // } // } x.line("} ") // close if false } x.line("}") // close init x.line("") // generate rest of type info for _, t := range typ { x.tc = t x.selfer(true) x.selfer(false) } for _, t := range x.ts { rtid := rt2id(t) // generate enc functions for all these slice/map types. x.varsfxreset() x.linef("func (x %s) enc%s(v %s%s, e *%sEncoder) {", x.hn, x.genMethodNameT(t), x.arr2str(t, "*"), x.genTypeName(t), x.cpfx) x.genRequiredMethodVars(true) switch t.Kind() { case reflect.Array, reflect.Slice, reflect.Chan: x.encListFallback("v", t) case reflect.Map: x.encMapFallback("v", t) default: panic(errGenExpectArrayOrMap) } x.line("}") x.line("") // generate dec functions for all these slice/map types. x.varsfxreset() x.linef("func (x %s) dec%s(v *%s, d *%sDecoder) {", x.hn, x.genMethodNameT(t), x.genTypeName(t), x.cpfx) x.genRequiredMethodVars(false) switch t.Kind() { case reflect.Array, reflect.Slice, reflect.Chan: x.decListFallback("v", rtid, t) case reflect.Map: x.decMapFallback("v", rtid, t) default: panic(errGenExpectArrayOrMap) } x.line("}") x.line("") } x.line("") } func (x *genRunner) checkForSelfer(t reflect.Type, varname string) bool { // return varname != genTopLevelVarName && t != x.tc // the only time we checkForSelfer is if we are not at the TOP of the generated code. return varname != genTopLevelVarName } func (x *genRunner) arr2str(t reflect.Type, s string) string { if t.Kind() == reflect.Array { return s } return "" } func (x *genRunner) genRequiredMethodVars(encode bool) { x.line("var h " + x.hn) if encode { x.line("z, r := " + x.cpfx + "GenHelperEncoder(e)") } else { x.line("z, r := " + x.cpfx + "GenHelperDecoder(d)") } x.line("_, _, _ = h, z, r") } func (x *genRunner) genRefPkgs(t reflect.Type) { if _, ok := x.is[t]; ok { return } x.is[t] = struct{}{} tpkg, tname := genImportPath(t), t.Name() if tpkg != "" && tpkg != x.bp && tpkg != x.cp && tname != "" && tname[0] >= 'A' && tname[0] <= 'Z' { if _, ok := x.im[tpkg]; !ok { x.im[tpkg] = t if idx := strings.LastIndex(tpkg, "/"); idx < 0 { x.imn[tpkg] = tpkg } else { x.imc++ x.imn[tpkg] = "pkg" + strconv.FormatUint(x.imc, 10) + "_" + genGoIdentifier(tpkg[idx+1:], false) } } } switch t.Kind() { case reflect.Array, reflect.Slice, reflect.Ptr, reflect.Chan: x.genRefPkgs(t.Elem()) case reflect.Map: x.genRefPkgs(t.Elem()) x.genRefPkgs(t.Key()) case reflect.Struct: for i := 0; i < t.NumField(); i++ { if fname := t.Field(i).Name; fname != "" && fname[0] >= 'A' && fname[0] <= 'Z' { x.genRefPkgs(t.Field(i).Type) } } } } // sayFalse will either say "false" or use a function call that returns false. func (x *genRunner) sayFalse() string { x.f++ if x.f%2 == 0 { return x.hn + "False()" } return "false" } func (x *genRunner) varsfx() string { x.c++ return strconv.FormatUint(x.c, 10) } func (x *genRunner) varsfxreset() { x.c = 0 } func (x *genRunner) out(s string) { _, err := io.WriteString(x.w, s) if err != nil { panic(err) } } func (x *genRunner) outf(s string, params ...interface{}) { _, err := fmt.Fprintf(x.w, s, params...) if err != nil { panic(err) } } func (x *genRunner) line(s string) { x.out(s) if len(s) == 0 || s[len(s)-1] != '\n' { x.out("\n") } } func (x *genRunner) lineIf(s string) { if s != "" { x.line(s) } } func (x *genRunner) linef(s string, params ...interface{}) { x.outf(s, params...) if len(s) == 0 || s[len(s)-1] != '\n' { x.out("\n") } } func (x *genRunner) genTypeName(t reflect.Type) (n string) { // defer func() { fmt.Printf(">>>> ####: genTypeName: t: %v, name: '%s'\n", t, n) }() // if the type has a PkgPath, which doesn't match the current package, // then include it. // We cannot depend on t.String() because it includes current package, // or t.PkgPath because it includes full import path, // var ptrPfx string for t.Kind() == reflect.Ptr { ptrPfx += "*" t = t.Elem() } if tn := t.Name(); tn != "" { return ptrPfx + x.genTypeNamePrim(t) } switch t.Kind() { case reflect.Map: return ptrPfx + "map[" + x.genTypeName(t.Key()) + "]" + x.genTypeName(t.Elem()) case reflect.Slice: return ptrPfx + "[]" + x.genTypeName(t.Elem()) case reflect.Array: return ptrPfx + "[" + strconv.FormatInt(int64(t.Len()), 10) + "]" + x.genTypeName(t.Elem()) case reflect.Chan: return ptrPfx + t.ChanDir().String() + " " + x.genTypeName(t.Elem()) default: if t == intfTyp { return ptrPfx + "interface{}" } else { return ptrPfx + x.genTypeNamePrim(t) } } } func (x *genRunner) genTypeNamePrim(t reflect.Type) (n string) { if t.Name() == "" { return t.String() } else if genImportPath(t) == "" || genImportPath(t) == genImportPath(x.tc) { return t.Name() } else { return x.imn[genImportPath(t)] + "." + t.Name() // return t.String() // best way to get the package name inclusive } } func (x *genRunner) genZeroValueR(t reflect.Type) string { // if t is a named type, w switch t.Kind() { case reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func, reflect.Slice, reflect.Map, reflect.Invalid: return "nil" case reflect.Bool: return "false" case reflect.String: return `""` case reflect.Struct, reflect.Array: return x.genTypeName(t) + "{}" default: // all numbers return "0" } } func (x *genRunner) genMethodNameT(t reflect.Type) (s string) { return genMethodNameT(t, x.tc) } func (x *genRunner) selfer(encode bool) { t := x.tc t0 := t // always make decode use a pointer receiver, // and structs/arrays always use a ptr receiver (encode|decode) isptr := !encode || t.Kind() == reflect.Array || (t.Kind() == reflect.Struct && t != timeTyp) x.varsfxreset() fnSigPfx := "func (" + genTopLevelVarName + " " if isptr { fnSigPfx += "*" } fnSigPfx += x.genTypeName(t) x.out(fnSigPfx) if isptr { t = reflect.PtrTo(t) } if encode { x.line(") CodecEncodeSelf(e *" + x.cpfx + "Encoder) {") x.genRequiredMethodVars(true) x.encVar(genTopLevelVarName, t) } else { x.line(") CodecDecodeSelf(d *" + x.cpfx + "Decoder) {") x.genRequiredMethodVars(false) // do not use decVar, as there is no need to check TryDecodeAsNil // or way to elegantly handle that, and also setting it to a // non-nil value doesn't affect the pointer passed. // x.decVar(genTopLevelVarName, t, false) x.dec(genTopLevelVarName, t0, true) } x.line("}") x.line("") if encode || t0.Kind() != reflect.Struct { return } // write is containerMap if genUseOneFunctionForDecStructMap { x.out(fnSigPfx) x.line(") codecDecodeSelfFromMap(l int, d *" + x.cpfx + "Decoder) {") x.genRequiredMethodVars(false) x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0, genStructMapStyleConsolidated) x.line("}") x.line("") } else { x.out(fnSigPfx) x.line(") codecDecodeSelfFromMapLenPrefix(l int, d *" + x.cpfx + "Decoder) {") x.genRequiredMethodVars(false) x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0, genStructMapStyleLenPrefix) x.line("}") x.line("") x.out(fnSigPfx) x.line(") codecDecodeSelfFromMapCheckBreak(l int, d *" + x.cpfx + "Decoder) {") x.genRequiredMethodVars(false) x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0, genStructMapStyleCheckBreak) x.line("}") x.line("") } // write containerArray x.out(fnSigPfx) x.line(") codecDecodeSelfFromArray(l int, d *" + x.cpfx + "Decoder) {") x.genRequiredMethodVars(false) x.decStructArray(genTopLevelVarName, "l", "return", rt2id(t0), t0) x.line("}") x.line("") } // used for chan, array, slice, map func (x *genRunner) xtraSM(varname string, t reflect.Type, encode, isptr bool) { var ptrPfx, addrPfx string if isptr { ptrPfx = "*" } else { addrPfx = "&" } if encode { x.linef("h.enc%s((%s%s)(%s), e)", x.genMethodNameT(t), ptrPfx, x.genTypeName(t), varname) } else { x.linef("h.dec%s((*%s)(%s%s), d)", x.genMethodNameT(t), x.genTypeName(t), addrPfx, varname) } x.registerXtraT(t) } func (x *genRunner) registerXtraT(t reflect.Type) { // recursively register the types if _, ok := x.tm[t]; ok { return } var tkey reflect.Type switch t.Kind() { case reflect.Chan, reflect.Slice, reflect.Array: case reflect.Map: tkey = t.Key() default: return } x.tm[t] = struct{}{} x.ts = append(x.ts, t) // check if this refers to any xtra types eg. a slice of array: add the array x.registerXtraT(t.Elem()) if tkey != nil { x.registerXtraT(tkey) } } // encVar will encode a variable. // The parameter, t, is the reflect.Type of the variable itself func (x *genRunner) encVar(varname string, t reflect.Type) { // xdebugf("varname: %s, t: %v", varname, t) var checkNil bool switch t.Kind() { case reflect.Ptr, reflect.Interface, reflect.Slice, reflect.Map, reflect.Chan: checkNil = true } x.encVarChkNil(varname, t, checkNil) } func (x *genRunner) encVarChkNil(varname string, t reflect.Type, checkNil bool) { if checkNil { x.linef("if %s == nil { r.EncodeNil() } else { ", varname) } switch t.Kind() { case reflect.Ptr: telem := t.Elem() tek := telem.Kind() if tek == reflect.Array || (tek == reflect.Struct && telem != timeTyp) { x.enc(varname, genNonPtr(t)) break } i := x.varsfx() x.line(genTempVarPfx + i + " := *" + varname) x.enc(genTempVarPfx+i, genNonPtr(t)) case reflect.Struct, reflect.Array: if t == timeTyp { x.enc(varname, t) break } i := x.varsfx() x.line(genTempVarPfx + i + " := &" + varname) x.enc(genTempVarPfx+i, t) default: x.enc(varname, t) } if checkNil { x.line("}") } } // enc will encode a variable (varname) of type t, where t represents T. // if t is !time.Time and t is of kind reflect.Struct or reflect.Array, varname is of type *T // (to prevent copying), // else t is of type T func (x *genRunner) enc(varname string, t reflect.Type) { rtid := rt2id(t) ti2 := x.ti.get(rtid, t) // We call CodecEncodeSelf if one of the following are honored: // - the type already implements Selfer, call that // - the type has a Selfer implementation just created, use that // - the type is in the list of the ones we will generate for, but it is not currently being generated mi := x.varsfx() // tptr := reflect.PtrTo(t) tk := t.Kind() if x.checkForSelfer(t, varname) { if tk == reflect.Array || (tk == reflect.Struct && rtid != timeTypId) { // varname is of type *T // if tptr.Implements(selferTyp) || t.Implements(selferTyp) { if ti2.isFlag(typeInfoFlagIsZeroerPtr) || ti2.isFlag(typeInfoFlagIsZeroer) { x.line(varname + ".CodecEncodeSelf(e)") return } } else { // varname is of type T if ti2.cs { // t.Implements(selferTyp) { x.line(varname + ".CodecEncodeSelf(e)") return } else if ti2.csp { // tptr.Implements(selferTyp) { x.linef("%ssf%s := &%s", genTempVarPfx, mi, varname) x.linef("%ssf%s.CodecEncodeSelf(e)", genTempVarPfx, mi) return } } if _, ok := x.te[rtid]; ok { x.line(varname + ".CodecEncodeSelf(e)") return } } inlist := false for _, t0 := range x.t { if t == t0 { inlist = true if x.checkForSelfer(t, varname) { x.line(varname + ".CodecEncodeSelf(e)") return } break } } var rtidAdded bool if t == x.tc { x.te[rtid] = true rtidAdded = true } // check if // - type is time.Time, RawExt, Raw // - the type implements (Text|JSON|Binary)(Unm|M)arshal var hasIf genIfClause defer hasIf.end(x) // end if block (if necessary) if t == timeTyp { x.linef("%s !z.EncBasicHandle().TimeNotBuiltin { r.EncodeTime(%s)", hasIf.c(false), varname) // return } if t == rawTyp { x.linef("%s z.EncRaw(%s)", hasIf.c(true), varname) return } if t == rawExtTyp { x.linef("%s r.EncodeRawExt(%s, e)", hasIf.c(true), varname) return } // only check for extensions if the type is named, and has a packagePath. var arrayOrStruct = tk == reflect.Array || tk == reflect.Struct // meaning varname if of type *T if !x.nx && genImportPath(t) != "" && t.Name() != "" { yy := fmt.Sprintf("%sxt%s", genTempVarPfx, mi) x.linef("%s %s := z.Extension(z.I2Rtid(%s)); %s != nil { z.EncExtension(%s, %s) ", hasIf.c(false), yy, varname, yy, varname, yy) } if arrayOrStruct { // varname is of type *T if ti2.bm || ti2.bmp { // t.Implements(binaryMarshalerTyp) || tptr.Implements(binaryMarshalerTyp) { x.linef("%s z.EncBinary() { z.EncBinaryMarshal(%v) ", hasIf.c(false), varname) } if ti2.jm || ti2.jmp { // t.Implements(jsonMarshalerTyp) || tptr.Implements(jsonMarshalerTyp) { x.linef("%s !z.EncBinary() && z.IsJSONHandle() { z.EncJSONMarshal(%v) ", hasIf.c(false), varname) } else if ti2.tm || ti2.tmp { // t.Implements(textMarshalerTyp) || tptr.Implements(textMarshalerTyp) { x.linef("%s !z.EncBinary() { z.EncTextMarshal(%v) ", hasIf.c(false), varname) } } else { // varname is of type T if ti2.bm { // t.Implements(binaryMarshalerTyp) { x.linef("%s z.EncBinary() { z.EncBinaryMarshal(%v) ", hasIf.c(false), varname) } else if ti2.bmp { // tptr.Implements(binaryMarshalerTyp) { x.linef("%s z.EncBinary() { z.EncBinaryMarshal(&%v) ", hasIf.c(false), varname) } if ti2.jm { // t.Implements(jsonMarshalerTyp) { x.linef("%s !z.EncBinary() && z.IsJSONHandle() { z.EncJSONMarshal(%v) ", hasIf.c(false), varname) } else if ti2.jmp { // tptr.Implements(jsonMarshalerTyp) { x.linef("%s !z.EncBinary() && z.IsJSONHandle() { z.EncJSONMarshal(&%v) ", hasIf.c(false), varname) } else if ti2.tm { // t.Implements(textMarshalerTyp) { x.linef("%s !z.EncBinary() { z.EncTextMarshal(%v) ", hasIf.c(false), varname) } else if ti2.tmp { // tptr.Implements(textMarshalerTyp) { x.linef("%s !z.EncBinary() { z.EncTextMarshal(&%v) ", hasIf.c(false), varname) } } x.lineIf(hasIf.c(true)) switch t.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: x.line("r.EncodeInt(int64(" + varname + "))") case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: x.line("r.EncodeUint(uint64(" + varname + "))") case reflect.Float32: x.line("r.EncodeFloat32(float32(" + varname + "))") case reflect.Float64: x.line("r.EncodeFloat64(float64(" + varname + "))") case reflect.Bool: x.line("r.EncodeBool(bool(" + varname + "))") case reflect.String: x.linef("if z.EncBasicHandle().StringToRaw { r.EncodeStringBytesRaw(z.BytesView(string(%s))) } else { r.EncodeStringEnc(codecSelferCcUTF8%s, string(%s)) }", varname, x.xs, varname) case reflect.Chan: x.xtraSM(varname, t, true, false) // x.encListFallback(varname, rtid, t) case reflect.Array: x.xtraSM(varname, t, true, true) case reflect.Slice: // if nil, call dedicated function // if a []uint8, call dedicated function // if a known fastpath slice, call dedicated function // else write encode function in-line. // - if elements are primitives or Selfers, call dedicated function on each member. // - else call Encoder.encode(XXX) on it. if rtid == uint8SliceTypId { x.line("r.EncodeStringBytesRaw([]byte(" + varname + "))") } else if fastpathAV.index(rtid) != -1 { g := x.newFastpathGenV(t) x.line("z.F." + g.MethodNamePfx("Enc", false) + "V(" + varname + ", e)") } else { x.xtraSM(varname, t, true, false) // x.encListFallback(varname, rtid, t) } case reflect.Map: // if nil, call dedicated function // if a known fastpath map, call dedicated function // else write encode function in-line. // - if elements are primitives or Selfers, call dedicated function on each member. // - else call Encoder.encode(XXX) on it. // x.line("if " + varname + " == nil { \nr.EncodeNil()\n } else { ") if fastpathAV.index(rtid) != -1 { g := x.newFastpathGenV(t) x.line("z.F." + g.MethodNamePfx("Enc", false) + "V(" + varname + ", e)") } else { x.xtraSM(varname, t, true, false) // x.encMapFallback(varname, rtid, t) } case reflect.Struct: if !inlist { delete(x.te, rtid) x.line("z.EncFallback(" + varname + ")") break } x.encStruct(varname, rtid, t) default: if rtidAdded { delete(x.te, rtid) } x.line("z.EncFallback(" + varname + ")") } } func (x *genRunner) encZero(t reflect.Type) { switch t.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: x.line("r.EncodeInt(0)") case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: x.line("r.EncodeUint(0)") case reflect.Float32: x.line("r.EncodeFloat32(0)") case reflect.Float64: x.line("r.EncodeFloat64(0)") case reflect.Bool: x.line("r.EncodeBool(false)") case reflect.String: x.linef(`if z.EncBasicHandle().StringToRaw { r.EncodeStringBytesRaw([]byte{}) } else { r.EncodeStringEnc(codecSelferCcUTF8%s, "") }`, x.xs) default: x.line("r.EncodeNil()") } } func (x *genRunner) doEncOmitEmptyLine(t2 reflect.StructField, varname string, buf *genBuf) { x.f = 0 x.encOmitEmptyLine(t2, varname, buf) } func (x *genRunner) encOmitEmptyLine(t2 reflect.StructField, varname string, buf *genBuf) { // smartly check omitEmpty on a struct type, as it may contain uncomparable map/slice/etc. // also, for maps/slices/arrays, check if len ! 0 (not if == zero value) varname2 := varname + "." + t2.Name switch t2.Type.Kind() { case reflect.Struct: rtid2 := rt2id(t2.Type) ti2 := x.ti.get(rtid2, t2.Type) // fmt.Printf(">>>> structfield: omitempty: type: %s, field: %s\n", t2.Type.Name(), t2.Name) if ti2.rtid == timeTypId { buf.s("!(").s(varname2).s(".IsZero())") break } if ti2.isFlag(typeInfoFlagIsZeroerPtr) || ti2.isFlag(typeInfoFlagIsZeroer) { buf.s("!(").s(varname2).s(".IsZero())") break } if ti2.isFlag(typeInfoFlagComparable) { buf.s(varname2).s(" != ").s(x.genZeroValueR(t2.Type)) break } // buf.s("(") buf.s(x.sayFalse()) // buf.s("false") for i, n := 0, t2.Type.NumField(); i < n; i++ { f := t2.Type.Field(i) if f.PkgPath != "" { // unexported continue } buf.s(" || ") x.encOmitEmptyLine(f, varname2, buf) } //buf.s(")") case reflect.Bool: buf.s(varname2) case reflect.Map, reflect.Slice, reflect.Array, reflect.Chan: buf.s("len(").s(varname2).s(") != 0") default: buf.s(varname2).s(" != ").s(x.genZeroValueR(t2.Type)) } } func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) { // xdebug2f("encStruct, varname: %s, t: %s", varname, t) // Use knowledge from structfieldinfo (mbs, encodable fields. Ignore omitempty. ) // replicate code in kStruct i.e. for each field, deref type to non-pointer, and call x.enc on it // if t === type currently running selfer on, do for all ti := x.ti.get(rtid, t) i := x.varsfx() sepVarname := genTempVarPfx + "sep" + i numfieldsvar := genTempVarPfx + "q" + i ti2arrayvar := genTempVarPfx + "r" + i struct2arrvar := genTempVarPfx + "2arr" + i // firstvar := genTempVarPfx + "2first" + i x.line(sepVarname + " := !z.EncBinary()") x.linef("%s := z.EncBasicHandle().StructToArray", struct2arrvar) x.linef("_, _ = %s, %s", sepVarname, struct2arrvar) x.linef("const %s bool = %v // struct tag has 'toArray'", ti2arrayvar, ti.toArray) // x.linef("var %s bool = true", firstvar) tisfi := ti.sfiSrc // always use sequence from file. decStruct expects same thing. // var nn int // due to omitEmpty, we need to calculate the // number of non-empty things we write out first. // This is required as we need to pre-determine the size of the container, // to support length-prefixing. if ti.anyOmitEmpty { x.linef("var %s = [%v]bool{ // should field at this index be written?", numfieldsvar, len(tisfi)) for j, si := range tisfi { _ = j if !si.omitEmpty() { // x.linef("%s[%v] = true // %s", numfieldsvar, j, si.fieldName) x.linef("true, // %s", si.fieldName) // nn++ continue } var t2 reflect.StructField var omitline genBuf { t2typ := t varname3 := varname // go through the loop, record the t2 field explicitly, // and gather the omit line if embedded in pointers. for ij, ix := range si.is { if uint8(ij) == si.nis { break } for t2typ.Kind() == reflect.Ptr { t2typ = t2typ.Elem() } t2 = t2typ.Field(int(ix)) t2typ = t2.Type varname3 = varname3 + "." + t2.Name // do not include actual field in the omit line. // that is done subsequently (right after - below). if uint8(ij+1) < si.nis && t2typ.Kind() == reflect.Ptr { omitline.s(varname3).s(" != nil && ") } } } x.doEncOmitEmptyLine(t2, varname, &omitline) x.linef("%s, // %s", omitline.v(), si.fieldName) } x.line("}") x.linef("_ = %s", numfieldsvar) } // x.linef("var %snn%s int", genTempVarPfx, i) type genFQN struct { i string fqname string nilLine genBuf nilVar string canNil bool sf reflect.StructField } genFQNs := make([]genFQN, len(tisfi)) for j, si := range tisfi { q := &genFQNs[j] q.i = x.varsfx() q.nilVar = genTempVarPfx + "n" + q.i q.canNil = false q.fqname = varname { t2typ := t for ij, ix := range si.is { if uint8(ij) == si.nis { break } for t2typ.Kind() == reflect.Ptr { t2typ = t2typ.Elem() } q.sf = t2typ.Field(int(ix)) t2typ = q.sf.Type q.fqname += "." + q.sf.Name if t2typ.Kind() == reflect.Ptr { if !q.canNil { q.nilLine.f("%s == nil", q.fqname) q.canNil = true } else { q.nilLine.f(" || %s == nil", q.fqname) } // x.linef("if %s == nil { %s = true; goto LABEL%d }", varname3, isNilVarName, i) // "varname3 = new(" + x.genTypeName(t3.Elem()) + ") }") } } // t2 = t.FieldByIndex(si.is) } } for j := range genFQNs { q := &genFQNs[j] if q.canNil { x.linef("var %s bool = %s", q.nilVar, q.nilLine.v()) // x.linef("if %s { %s = true }", q.nilLine.v(), q.nilVar) } } x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray x.linef("z.EncWriteArrayStart(%d)", len(tisfi)) for j, si := range tisfi { q := &genFQNs[j] // if the type of the field is a Selfer, or one of the ones if q.canNil { x.linef("if %s { z.EncWriteArrayElem(); r.EncodeNil() } else { ", q.nilVar) } x.linef("z.EncWriteArrayElem()") if si.omitEmpty() { x.linef("if %s[%v] {", numfieldsvar, j) } // xdebug2f("varname: %s, t2.Type: %s", varname3, t2.Type) x.encVarChkNil(q.fqname, q.sf.Type, false) if si.omitEmpty() { x.linef("} else {") x.encZero(q.sf.Type) x.linef("}") } if q.canNil { x.line("}") } } x.line("z.EncWriteArrayEnd()") x.linef("} else {") // if not ti.toArray if ti.anyOmitEmpty { // nn = 0 // x.linef("var %snn%s = %v", genTempVarPfx, i, nn) x.linef("var %snn%s int", genTempVarPfx, i) x.linef("for _, b := range %s { if b { %snn%s++ } }", numfieldsvar, genTempVarPfx, i) x.linef("z.EncWriteMapStart(%snn%s)", genTempVarPfx, i) x.linef("%snn%s = %v", genTempVarPfx, i, 0) } else { x.linef("z.EncWriteMapStart(%d)", len(tisfi)) } for j, si := range tisfi { q := &genFQNs[j] if si.omitEmpty() { x.linef("if %s[%v] {", numfieldsvar, j) } x.linef("z.EncWriteMapElemKey()") // emulate EncStructFieldKey switch ti.keyType { case valueTypeInt: x.linef("r.EncodeInt(z.M.Int(strconv.ParseInt(`%s`, 10, 64)))", si.encName) case valueTypeUint: x.linef("r.EncodeUint(z.M.Uint(strconv.ParseUint(`%s`, 10, 64)))", si.encName) case valueTypeFloat: x.linef("r.EncodeFloat64(z.M.Float(strconv.ParseFloat(`%s`, 64)))", si.encName) default: // string if si.encNameAsciiAlphaNum { x.linef(`if z.IsJSONHandle() { z.WriteStr("\"%s\"") } else { `, si.encName) } x.linef("r.EncodeStringEnc(codecSelferCcUTF8%s, `%s`)", x.xs, si.encName) if si.encNameAsciiAlphaNum { x.linef("}") } } // x.linef("r.EncStructFieldKey(codecSelferValueType%s%s, `%s`)", ti.keyType.String(), x.xs, si.encName) x.line("z.EncWriteMapElemValue()") if q.canNil { x.line("if " + q.nilVar + " { r.EncodeNil() } else { ") x.encVarChkNil(q.fqname, q.sf.Type, false) x.line("}") } else { x.encVarChkNil(q.fqname, q.sf.Type, false) } if si.omitEmpty() { x.line("}") } } x.line("z.EncWriteMapEnd()") x.linef("} ") // end if/else ti.toArray } func (x *genRunner) encListFallback(varname string, t reflect.Type) { elemBytes := t.Elem().Kind() == reflect.Uint8 if t.AssignableTo(uint8SliceTyp) { x.linef("r.EncodeStringBytesRaw([]byte(%s))", varname) return } if t.Kind() == reflect.Array && elemBytes { x.linef("r.EncodeStringBytesRaw(((*[%d]byte)(%s))[:])", t.Len(), varname) return } i := x.varsfx() if t.Kind() == reflect.Chan { type ts struct { Label, Chan, Slice, Sfx string } tm, err := template.New("").Parse(genEncChanTmpl) if err != nil { panic(err) } x.linef("if %s == nil { r.EncodeNil() } else { ", varname) x.linef("var sch%s []%s", i, x.genTypeName(t.Elem())) err = tm.Execute(x.w, &ts{"Lsch" + i, varname, "sch" + i, i}) if err != nil { panic(err) } // x.linef("%s = sch%s", varname, i) if elemBytes { x.linef("r.EncodeStringBytesRaw([]byte(%s))", "sch"+i) x.line("}") return } varname = "sch" + i } x.line("z.EncWriteArrayStart(len(" + varname + "))") x.linef("for _, %sv%s := range %s {", genTempVarPfx, i, varname) x.linef("z.EncWriteArrayElem()") x.encVar(genTempVarPfx+"v"+i, t.Elem()) x.line("}") x.line("z.EncWriteArrayEnd()") if t.Kind() == reflect.Chan { x.line("}") } } func (x *genRunner) encMapFallback(varname string, t reflect.Type) { // TODO: expand this to handle canonical. i := x.varsfx() x.line("z.EncWriteMapStart(len(" + varname + "))") // x.linef("var %sfirst%s = true", genTempVarPfx, i) x.linef("for %sk%s, %sv%s := range %s {", genTempVarPfx, i, genTempVarPfx, i, varname) x.linef("z.EncWriteMapElemKey()") // x.linef("%sfirst%s = false", genTempVarPfx, i) x.encVar(genTempVarPfx+"k"+i, t.Key()) x.line("z.EncWriteMapElemValue()") x.encVar(genTempVarPfx+"v"+i, t.Elem()) x.line("}") x.line("z.EncWriteMapEnd()") } func (x *genRunner) decVarInitPtr(varname, nilvar string, t reflect.Type, si *structFieldInfo, newbuf, nilbuf *genBuf) (varname3 string, t2 reflect.StructField) { //we must accommodate anonymous fields, where the embedded field is a nil pointer in the value. // t2 = t.FieldByIndex(si.is) varname3 = varname t2typ := t t2kind := t2typ.Kind() var nilbufed bool if si != nil { for ij, ix := range si.is { if uint8(ij) == si.nis { break } for t2typ.Kind() == reflect.Ptr { t2typ = t2typ.Elem() } t2 = t2typ.Field(int(ix)) t2typ = t2.Type varname3 = varname3 + "." + t2.Name t2kind = t2typ.Kind() if t2kind != reflect.Ptr { continue } if newbuf != nil { newbuf.f("if %s == nil { %s = new(%s) }\n", varname3, varname3, x.genTypeName(t2typ.Elem())) } if nilbuf != nil { if !nilbufed { nilbuf.s("if ").s(varname3).s(" != nil") nilbufed = true } else { nilbuf.s(" && ").s(varname3).s(" != nil") } } } } // if t2typ.Kind() == reflect.Ptr { // varname3 = varname3 + t2.Name // } if nilbuf != nil { if nilbufed { nilbuf.s(" { ").s("// remove the if-true\n") } if nilvar != "" { nilbuf.s(nilvar).s(" = true") } else if tk := t2typ.Kind(); tk == reflect.Ptr { if strings.IndexByte(varname3, '.') != -1 || strings.IndexByte(varname3, '[') != -1 { nilbuf.s(varname3).s(" = nil") } else { nilbuf.s("*").s(varname3).s(" = ").s(x.genZeroValueR(t2typ.Elem())) } } else { nilbuf.s(varname3).s(" = ").s(x.genZeroValueR(t2typ)) } if nilbufed { nilbuf.s("}") } } return } // decVar takes a variable called varname, of type t func (x *genRunner) decVarMain(varname, rand string, t reflect.Type, checkNotNil bool) { // We only encode as nil if a nillable value. // This removes some of the wasted checks for TryDecodeAsNil. // We need to think about this more, to see what happens if omitempty, etc // cause a nil value to be stored when something is expected. // This could happen when decoding from a struct encoded as an array. // For that, decVar should be called with canNil=true, to force true as its value. var varname2 string if t.Kind() != reflect.Ptr { if t.PkgPath() != "" || !x.decTryAssignPrimitive(varname, t, false) { x.dec(varname, t, false) } } else { if checkNotNil { x.linef("if %s == nil { %s = new(%s) }", varname, varname, x.genTypeName(t.Elem())) } // Ensure we set underlying ptr to a non-nil value (so we can deref to it later). // There's a chance of a **T in here which is nil. var ptrPfx string for t = t.Elem(); t.Kind() == reflect.Ptr; t = t.Elem() { ptrPfx += "*" if checkNotNil { x.linef("if %s%s == nil { %s%s = new(%s)}", ptrPfx, varname, ptrPfx, varname, x.genTypeName(t)) } } // Should we create temp var if a slice/map indexing? No. dec(...) can now handle it. if ptrPfx == "" { x.dec(varname, t, true) } else { varname2 = genTempVarPfx + "z" + rand x.line(varname2 + " := " + ptrPfx + varname) x.dec(varname2, t, true) } } } // decVar takes a variable called varname, of type t func (x *genRunner) decVar(varname, nilvar string, t reflect.Type, canBeNil, checkNotNil bool) { i := x.varsfx() // We only encode as nil if a nillable value. // This removes some of the wasted checks for TryDecodeAsNil. // We need to think about this more, to see what happens if omitempty, etc // cause a nil value to be stored when something is expected. // This could happen when decoding from a struct encoded as an array. // For that, decVar should be called with canNil=true, to force true as its value. if !canBeNil { canBeNil = genAnythingCanBeNil || !genIsImmutable(t) } if canBeNil { var buf genBuf x.decVarInitPtr(varname, nilvar, t, nil, nil, &buf) x.linef("if r.TryDecodeAsNil() { %s } else {", buf.buf) } else { x.line("// cannot be nil") } x.decVarMain(varname, i, t, checkNotNil) if canBeNil { x.line("} ") } } // dec will decode a variable (varname) of type t or ptrTo(t) if isptr==true. // t is always a basetype (i.e. not of kind reflect.Ptr). func (x *genRunner) dec(varname string, t reflect.Type, isptr bool) { // assumptions: // - the varname is to a pointer already. No need to take address of it // - t is always a baseType T (not a *T, etc). rtid := rt2id(t) ti2 := x.ti.get(rtid, t) // tptr := reflect.PtrTo(t) if x.checkForSelfer(t, varname) { if ti2.cs || ti2.csp { // t.Implements(selferTyp) || tptr.Implements(selferTyp) { x.line(varname + ".CodecDecodeSelf(d)") return } if _, ok := x.td[rtid]; ok { x.line(varname + ".CodecDecodeSelf(d)") return } } inlist := false for _, t0 := range x.t { if t == t0 { inlist = true if x.checkForSelfer(t, varname) { x.line(varname + ".CodecDecodeSelf(d)") return } break } } var rtidAdded bool if t == x.tc { x.td[rtid] = true rtidAdded = true } // check if // - type is time.Time, Raw, RawExt // - the type implements (Text|JSON|Binary)(Unm|M)arshal mi := x.varsfx() // x.linef("%sm%s := z.DecBinary()", genTempVarPfx, mi) // x.linef("_ = %sm%s", genTempVarPfx, mi) var hasIf genIfClause defer hasIf.end(x) var ptrPfx, addrPfx string if isptr { ptrPfx = "*" } else { addrPfx = "&" } if t == timeTyp { x.linef("%s !z.DecBasicHandle().TimeNotBuiltin { %s%v = r.DecodeTime()", hasIf.c(false), ptrPfx, varname) // return } if t == rawTyp { x.linef("%s %s%v = z.DecRaw()", hasIf.c(true), ptrPfx, varname) return } if t == rawExtTyp { x.linef("%s r.DecodeExt(%s%v, 0, nil)", hasIf.c(true), addrPfx, varname) return } // only check for extensions if the type is named, and has a packagePath. if !x.nx && genImportPath(t) != "" && t.Name() != "" { // first check if extensions are configued, before doing the interface conversion // x.linef("} else if z.HasExtensions() && z.DecExt(%s) {", varname) yy := fmt.Sprintf("%sxt%s", genTempVarPfx, mi) x.linef("%s %s := z.Extension(z.I2Rtid(%s)); %s != nil { z.DecExtension(%s, %s) ", hasIf.c(false), yy, varname, yy, varname, yy) } if ti2.bu || ti2.bup { // t.Implements(binaryUnmarshalerTyp) || tptr.Implements(binaryUnmarshalerTyp) { x.linef("%s z.DecBinary() { z.DecBinaryUnmarshal(%s%v) ", hasIf.c(false), addrPfx, varname) } if ti2.ju || ti2.jup { // t.Implements(jsonUnmarshalerTyp) || tptr.Implements(jsonUnmarshalerTyp) { x.linef("%s !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(%s%v)", hasIf.c(false), addrPfx, varname) } else if ti2.tu || ti2.tup { // t.Implements(textUnmarshalerTyp) || tptr.Implements(textUnmarshalerTyp) { x.linef("%s !z.DecBinary() { z.DecTextUnmarshal(%s%v)", hasIf.c(false), addrPfx, varname) } x.lineIf(hasIf.c(true)) if x.decTryAssignPrimitive(varname, t, isptr) { return } switch t.Kind() { case reflect.Array, reflect.Chan: x.xtraSM(varname, t, false, isptr) case reflect.Slice: // if a []uint8, call dedicated function // if a known fastpath slice, call dedicated function // else write encode function in-line. // - if elements are primitives or Selfers, call dedicated function on each member. // - else call Encoder.encode(XXX) on it. if rtid == uint8SliceTypId { x.linef("%s%s = r.DecodeBytes(%s(%s[]byte)(%s), false)", ptrPfx, varname, ptrPfx, ptrPfx, varname) } else if fastpathAV.index(rtid) != -1 { g := x.newFastpathGenV(t) x.linef("z.F.%sX(%s%s, d)", g.MethodNamePfx("Dec", false), addrPfx, varname) } else { x.xtraSM(varname, t, false, isptr) // x.decListFallback(varname, rtid, false, t) } case reflect.Map: // if a known fastpath map, call dedicated function // else write encode function in-line. // - if elements are primitives or Selfers, call dedicated function on each member. // - else call Encoder.encode(XXX) on it. if fastpathAV.index(rtid) != -1 { g := x.newFastpathGenV(t) x.linef("z.F.%sX(%s%s, d)", g.MethodNamePfx("Dec", false), addrPfx, varname) } else { x.xtraSM(varname, t, false, isptr) // x.decMapFallback(varname, rtid, t) } case reflect.Struct: if inlist { // no need to create temp variable if isptr, or x.F or x[F] if isptr || strings.IndexByte(varname, '.') != -1 || strings.IndexByte(varname, '[') != -1 { x.decStruct(varname, rtid, t) } else { varname2 := genTempVarPfx + "j" + mi x.line(varname2 + " := &" + varname) x.decStruct(varname2, rtid, t) } } else { // delete(x.td, rtid) x.line("z.DecFallback(" + addrPfx + varname + ", false)") } default: if rtidAdded { delete(x.te, rtid) } x.line("z.DecFallback(" + addrPfx + varname + ", true)") } } func (x *genRunner) decTryAssignPrimitive(varname string, t reflect.Type, isptr bool) (done bool) { // This should only be used for exact primitives (ie un-named types). // Named types may be implementations of Selfer, Unmarshaler, etc. // They should be handled by dec(...) var ptr string if isptr { ptr = "*" } switch t.Kind() { case reflect.Int: x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs) case reflect.Int8: x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 8))", ptr, varname, x.genTypeName(t)) case reflect.Int16: x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 16))", ptr, varname, x.genTypeName(t)) case reflect.Int32: x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 32))", ptr, varname, x.genTypeName(t)) case reflect.Int64: x.linef("%s%s = (%s)(r.DecodeInt64())", ptr, varname, x.genTypeName(t)) case reflect.Uint: x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs) case reflect.Uint8: x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 8))", ptr, varname, x.genTypeName(t)) case reflect.Uint16: x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 16))", ptr, varname, x.genTypeName(t)) case reflect.Uint32: x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 32))", ptr, varname, x.genTypeName(t)) case reflect.Uint64: x.linef("%s%s = (%s)(r.DecodeUint64())", ptr, varname, x.genTypeName(t)) case reflect.Uintptr: x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs) case reflect.Float32: x.linef("%s%s = (%s)(z.DecDecodeFloat32())", ptr, varname, x.genTypeName(t)) case reflect.Float64: x.linef("%s%s = (%s)(r.DecodeFloat64())", ptr, varname, x.genTypeName(t)) case reflect.Bool: x.linef("%s%s = (%s)(r.DecodeBool())", ptr, varname, x.genTypeName(t)) case reflect.String: x.linef("%s%s = (%s)(r.DecodeString())", ptr, varname, x.genTypeName(t)) default: return false } return true } func (x *genRunner) decListFallback(varname string, rtid uintptr, t reflect.Type) { if t.AssignableTo(uint8SliceTyp) { x.line("*" + varname + " = r.DecodeBytes(*((*[]byte)(" + varname + ")), false)") return } if t.Kind() == reflect.Array && t.Elem().Kind() == reflect.Uint8 { x.linef("r.DecodeBytes( ((*[%d]byte)(%s))[:], true)", t.Len(), varname) return } type tstruc struct { TempVar string Rand string Varname string CTyp string Typ string Immutable bool Size int } telem := t.Elem() ts := tstruc{genTempVarPfx, x.varsfx(), varname, x.genTypeName(t), x.genTypeName(telem), genIsImmutable(telem), int(telem.Size())} funcs := make(template.FuncMap) funcs["decLineVar"] = func(varname string) string { x.decVar(varname, "", telem, false, true) return "" } funcs["var"] = func(s string) string { return ts.TempVar + s + ts.Rand } funcs["zero"] = func() string { return x.genZeroValueR(telem) } funcs["isArray"] = func() bool { return t.Kind() == reflect.Array } funcs["isSlice"] = func() bool { return t.Kind() == reflect.Slice } funcs["isChan"] = func() bool { return t.Kind() == reflect.Chan } tm, err := template.New("").Funcs(funcs).Parse(genDecListTmpl) if err != nil { panic(err) } if err = tm.Execute(x.w, &ts); err != nil { panic(err) } } func (x *genRunner) decMapFallback(varname string, rtid uintptr, t reflect.Type) { type tstruc struct { TempVar string Sfx string Rand string Varname string KTyp string Typ string Size int } telem := t.Elem() tkey := t.Key() ts := tstruc{ genTempVarPfx, x.xs, x.varsfx(), varname, x.genTypeName(tkey), x.genTypeName(telem), int(telem.Size() + tkey.Size()), } funcs := make(template.FuncMap) funcs["decElemZero"] = func() string { return x.genZeroValueR(telem) } funcs["decElemKindImmutable"] = func() bool { return genIsImmutable(telem) } funcs["decElemKindPtr"] = func() bool { return telem.Kind() == reflect.Ptr } funcs["decElemKindIntf"] = func() bool { return telem.Kind() == reflect.Interface } funcs["decLineVarK"] = func(varname string) string { x.decVar(varname, "", tkey, false, true) return "" } funcs["decLineVar"] = func(varname, decodedNilVarname string) string { x.decVar(varname, decodedNilVarname, telem, false, true) return "" } funcs["var"] = func(s string) string { return ts.TempVar + s + ts.Rand } tm, err := template.New("").Funcs(funcs).Parse(genDecMapTmpl) if err != nil { panic(err) } if err = tm.Execute(x.w, &ts); err != nil { panic(err) } } func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintptr, t reflect.Type) { ti := x.ti.get(rtid, t) tisfi := ti.sfiSrc // always use sequence from file. decStruct expects same thing. x.line("switch (" + kName + ") {") var newbuf, nilbuf genBuf for _, si := range tisfi { x.line("case \"" + si.encName + "\":") newbuf.reset() nilbuf.reset() varname3, t2 := x.decVarInitPtr(varname, "", t, si, &newbuf, &nilbuf) x.linef("if r.TryDecodeAsNil() { %s } else { %s", nilbuf.buf, newbuf.buf) x.decVarMain(varname3, x.varsfx(), t2.Type, false) x.line("}") } x.line("default:") // pass the slice here, so that the string will not escape, and maybe save allocation x.line("z.DecStructFieldNotFound(-1, " + kName + ")") x.line("} // end switch " + kName) } func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t reflect.Type, style genStructMapStyle) { tpfx := genTempVarPfx ti := x.ti.get(rtid, t) i := x.varsfx() kName := tpfx + "s" + i switch style { case genStructMapStyleLenPrefix: x.linef("for %sj%s := 0; %sj%s < %s; %sj%s++ {", tpfx, i, tpfx, i, lenvarname, tpfx, i) case genStructMapStyleCheckBreak: x.linef("for %sj%s := 0; !r.CheckBreak(); %sj%s++ {", tpfx, i, tpfx, i) default: // 0, otherwise. x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length x.linef("for %sj%s := 0; ; %sj%s++ {", tpfx, i, tpfx, i) x.linef("if %shl%s { if %sj%s >= %s { break }", tpfx, i, tpfx, i, lenvarname) x.line("} else { if r.CheckBreak() { break }; }") } x.line("z.DecReadMapElemKey()") // emulate decstructfieldkey switch ti.keyType { case valueTypeInt: x.linef("%s := z.StringView(strconv.AppendInt(z.DecScratchArrayBuffer()[:0], r.DecodeInt64(), 10))", kName) case valueTypeUint: x.linef("%s := z.StringView(strconv.AppendUint(z.DecScratchArrayBuffer()[:0], r.DecodeUint64(), 10))", kName) case valueTypeFloat: x.linef("%s := z.StringView(strconv.AppendFloat(z.DecScratchArrayBuffer()[:0], r.DecodeFloat64(), 'f', -1, 64))", kName) default: // string x.linef("%s := z.StringView(r.DecodeStringAsBytes())", kName) } // x.linef("%s := z.StringView(r.DecStructFieldKey(codecSelferValueType%s%s, z.DecScratchArrayBuffer()))", kName, ti.keyType.String(), x.xs) x.line("z.DecReadMapElemValue()") x.decStructMapSwitch(kName, varname, rtid, t) x.line("} // end for " + tpfx + "j" + i) x.line("z.DecReadMapEnd()") } func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid uintptr, t reflect.Type) { tpfx := genTempVarPfx i := x.varsfx() ti := x.ti.get(rtid, t) tisfi := ti.sfiSrc // always use sequence from file. decStruct expects same thing. x.linef("var %sj%s int", tpfx, i) x.linef("var %sb%s bool", tpfx, i) // break x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length var newbuf, nilbuf genBuf for _, si := range tisfi { x.linef("%sj%s++; if %shl%s { %sb%s = %sj%s > %s } else { %sb%s = r.CheckBreak() }", tpfx, i, tpfx, i, tpfx, i, tpfx, i, lenvarname, tpfx, i) x.linef("if %sb%s { z.DecReadArrayEnd(); %s }", tpfx, i, breakString) x.line("z.DecReadArrayElem()") newbuf.reset() nilbuf.reset() varname3, t2 := x.decVarInitPtr(varname, "", t, si, &newbuf, &nilbuf) x.linef("if r.TryDecodeAsNil() { %s } else { %s", nilbuf.buf, newbuf.buf) x.decVarMain(varname3, x.varsfx(), t2.Type, false) x.line("}") } // read remaining values and throw away. x.line("for {") x.linef("%sj%s++; if %shl%s { %sb%s = %sj%s > %s } else { %sb%s = r.CheckBreak() }", tpfx, i, tpfx, i, tpfx, i, tpfx, i, lenvarname, tpfx, i) x.linef("if %sb%s { break }", tpfx, i) x.line("z.DecReadArrayElem()") x.linef(`z.DecStructFieldNotFound(%sj%s - 1, "")`, tpfx, i) x.line("}") x.line("z.DecReadArrayEnd()") } func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) { // varname MUST be a ptr, or a struct field or a slice element. i := x.varsfx() x.linef("%sct%s := r.ContainerType()", genTempVarPfx, i) x.linef("if %sct%s == codecSelferValueTypeMap%s {", genTempVarPfx, i, x.xs) x.line(genTempVarPfx + "l" + i + " := z.DecReadMapStart()") x.linef("if %sl%s == 0 {", genTempVarPfx, i) x.line("z.DecReadMapEnd()") if genUseOneFunctionForDecStructMap { x.line("} else { ") x.linef("%s.codecDecodeSelfFromMap(%sl%s, d)", varname, genTempVarPfx, i) } else { x.line("} else if " + genTempVarPfx + "l" + i + " > 0 { ") x.line(varname + ".codecDecodeSelfFromMapLenPrefix(" + genTempVarPfx + "l" + i + ", d)") x.line("} else {") x.line(varname + ".codecDecodeSelfFromMapCheckBreak(" + genTempVarPfx + "l" + i + ", d)") } x.line("}") // else if container is array x.linef("} else if %sct%s == codecSelferValueTypeArray%s {", genTempVarPfx, i, x.xs) x.line(genTempVarPfx + "l" + i + " := z.DecReadArrayStart()") x.linef("if %sl%s == 0 {", genTempVarPfx, i) x.line("z.DecReadArrayEnd()") x.line("} else { ") x.linef("%s.codecDecodeSelfFromArray(%sl%s, d)", varname, genTempVarPfx, i) x.line("}") // else panic x.line("} else { ") x.line("panic(errCodecSelferOnlyMapOrArrayEncodeToStruct" + x.xs + ")") x.line("} ") } // -------- type fastpathGenV struct { // fastpathGenV is either a primitive (Primitive != "") or a map (MapKey != "") or a slice MapKey string Elem string Primitive string Size int NoCanonical bool } func (x *genRunner) newFastpathGenV(t reflect.Type) (v fastpathGenV) { v.NoCanonical = !genFastpathCanonical switch t.Kind() { case reflect.Slice, reflect.Array: te := t.Elem() v.Elem = x.genTypeName(te) v.Size = int(te.Size()) case reflect.Map: te, tk := t.Elem(), t.Key() v.Elem = x.genTypeName(te) v.MapKey = x.genTypeName(tk) v.Size = int(te.Size() + tk.Size()) default: panic("unexpected type for newFastpathGenV. Requires map or slice type") } return } func (x *fastpathGenV) MethodNamePfx(prefix string, prim bool) string { var name []byte if prefix != "" { name = append(name, prefix...) } if prim { name = append(name, genTitleCaseName(x.Primitive)...) } else { if x.MapKey == "" { name = append(name, "Slice"...) } else { name = append(name, "Map"...) name = append(name, genTitleCaseName(x.MapKey)...) } name = append(name, genTitleCaseName(x.Elem)...) } return string(name) } // genImportPath returns import path of a non-predeclared named typed, or an empty string otherwise. // // This handles the misbehaviour that occurs when 1.5-style vendoring is enabled, // where PkgPath returns the full path, including the vendoring pre-fix that should have been stripped. // We strip it here. func genImportPath(t reflect.Type) (s string) { s = t.PkgPath() if genCheckVendor { // HACK: always handle vendoring. It should be typically on in go 1.6, 1.7 s = genStripVendor(s) } return } // A go identifier is (letter|_)[letter|number|_]* func genGoIdentifier(s string, checkFirstChar bool) string { b := make([]byte, 0, len(s)) t := make([]byte, 4) var n int for i, r := range s { if checkFirstChar && i == 0 && !unicode.IsLetter(r) { b = append(b, '_') } // r must be unicode_letter, unicode_digit or _ if unicode.IsLetter(r) || unicode.IsDigit(r) { n = utf8.EncodeRune(t, r) b = append(b, t[:n]...) } else { b = append(b, '_') } } return string(b) } func genNonPtr(t reflect.Type) reflect.Type { for t.Kind() == reflect.Ptr { t = t.Elem() } return t } func genTitleCaseName(s string) string { switch s { case "interface{}", "interface {}": return "Intf" case "[]byte", "[]uint8", "bytes": return "Bytes" default: return strings.ToUpper(s[0:1]) + s[1:] } } func genMethodNameT(t reflect.Type, tRef reflect.Type) (n string) { var ptrPfx string for t.Kind() == reflect.Ptr { ptrPfx += "Ptrto" t = t.Elem() } tstr := t.String() if tn := t.Name(); tn != "" { if tRef != nil && genImportPath(t) == genImportPath(tRef) { return ptrPfx + tn } else { if genQNameRegex.MatchString(tstr) { return ptrPfx + strings.Replace(tstr, ".", "_", 1000) } else { return ptrPfx + genCustomTypeName(tstr) } } } switch t.Kind() { case reflect.Map: return ptrPfx + "Map" + genMethodNameT(t.Key(), tRef) + genMethodNameT(t.Elem(), tRef) case reflect.Slice: return ptrPfx + "Slice" + genMethodNameT(t.Elem(), tRef) case reflect.Array: return ptrPfx + "Array" + strconv.FormatInt(int64(t.Len()), 10) + genMethodNameT(t.Elem(), tRef) case reflect.Chan: var cx string switch t.ChanDir() { case reflect.SendDir: cx = "ChanSend" case reflect.RecvDir: cx = "ChanRecv" default: cx = "Chan" } return ptrPfx + cx + genMethodNameT(t.Elem(), tRef) default: if t == intfTyp { return ptrPfx + "Interface" } else { if tRef != nil && genImportPath(t) == genImportPath(tRef) { if t.Name() != "" { return ptrPfx + t.Name() } else { return ptrPfx + genCustomTypeName(tstr) } } else { // best way to get the package name inclusive // return ptrPfx + strings.Replace(tstr, ".", "_", 1000) // return ptrPfx + genBase64enc.EncodeToString([]byte(tstr)) if t.Name() != "" && genQNameRegex.MatchString(tstr) { return ptrPfx + strings.Replace(tstr, ".", "_", 1000) } else { return ptrPfx + genCustomTypeName(tstr) } } } } } // genCustomNameForType base64encodes the t.String() value in such a way // that it can be used within a function name. func genCustomTypeName(tstr string) string { len2 := genBase64enc.EncodedLen(len(tstr)) bufx := make([]byte, len2) genBase64enc.Encode(bufx, []byte(tstr)) for i := len2 - 1; i >= 0; i-- { if bufx[i] == '=' { len2-- } else { break } } return string(bufx[:len2]) } func genIsImmutable(t reflect.Type) (v bool) { return isImmutableKind(t.Kind()) } type genInternal struct { Version int Values []fastpathGenV } func (x genInternal) FastpathLen() (l int) { for _, v := range x.Values { if v.Primitive == "" && !(v.MapKey == "" && v.Elem == "uint8") { l++ } } return } func genInternalZeroValue(s string) string { switch s { case "interface{}", "interface {}": return "nil" case "[]byte", "[]uint8", "bytes": return "nil" case "bool": return "false" case "string": return `""` default: return "0" } } var genInternalNonZeroValueIdx [6]uint64 var genInternalNonZeroValueStrs = [2][6]string{ {`"string-is-an-interface"`, "true", `"some-string"`, `[]byte("some-string")`, "11.1", "33"}, {`"string-is-an-interface-2"`, "true", `"some-string-2"`, `[]byte("some-string-2")`, "22.2", "44"}, } func genInternalNonZeroValue(s string) string { var i int switch s { case "interface{}", "interface {}": i = 0 case "bool": i = 1 case "string": i = 2 case "bytes", "[]byte", "[]uint8": i = 3 case "float32", "float64", "float", "double": i = 4 default: i = 5 } genInternalNonZeroValueIdx[i]++ return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[i]%2][i] // return string, to remove ambiguity } func genInternalEncCommandAsString(s string, vname string) string { switch s { case "uint64": return "e.e.EncodeUint(" + vname + ")" case "uint", "uint8", "uint16", "uint32": return "e.e.EncodeUint(uint64(" + vname + "))" case "int64": return "e.e.EncodeInt(" + vname + ")" case "int", "int8", "int16", "int32": return "e.e.EncodeInt(int64(" + vname + "))" case "[]byte", "[]uint8", "bytes": return "e.e.EncodeStringBytesRaw(" + vname + ")" case "string": return "if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(" + vname + ")) " + "} else { e.e.EncodeStringEnc(cUTF8, " + vname + ") }" case "float32": return "e.e.EncodeFloat32(" + vname + ")" case "float64": return "e.e.EncodeFloat64(" + vname + ")" case "bool": return "e.e.EncodeBool(" + vname + ")" // case "symbol": // return "e.e.EncodeSymbol(" + vname + ")" default: return "e.encode(" + vname + ")" } } func genInternalDecCommandAsString(s string) string { switch s { case "uint": return "uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))" case "uint8": return "uint8(chkOvf.UintV(d.d.DecodeUint64(), 8))" case "uint16": return "uint16(chkOvf.UintV(d.d.DecodeUint64(), 16))" case "uint32": return "uint32(chkOvf.UintV(d.d.DecodeUint64(), 32))" case "uint64": return "d.d.DecodeUint64()" case "uintptr": return "uintptr(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))" case "int": return "int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize))" case "int8": return "int8(chkOvf.IntV(d.d.DecodeInt64(), 8))" case "int16": return "int16(chkOvf.IntV(d.d.DecodeInt64(), 16))" case "int32": return "int32(chkOvf.IntV(d.d.DecodeInt64(), 32))" case "int64": return "d.d.DecodeInt64()" case "string": return "d.d.DecodeString()" case "[]byte", "[]uint8", "bytes": return "d.d.DecodeBytes(nil, false)" case "float32": return "float32(d.decodeFloat32())" case "float64": return "d.d.DecodeFloat64()" case "bool": return "d.d.DecodeBool()" default: panic(errors.New("gen internal: unknown type for decode: " + s)) } } func genInternalSortType(s string, elem bool) string { for _, v := range [...]string{ "int", "uint", "float", "bool", "string", "bytes", "[]uint8", "[]byte", } { if v == "[]byte" || v == "[]uint8" { v = "bytes" } if strings.HasPrefix(s, v) { if v == "int" || v == "uint" || v == "float" { v += "64" } if elem { return v } return v + "Slice" } } panic("sorttype: unexpected type: " + s) } func genStripVendor(s string) string { // HACK: Misbehaviour occurs in go 1.5. May have to re-visit this later. // if s contains /vendor/ OR startsWith vendor/, then return everything after it. const vendorStart = "vendor/" const vendorInline = "/vendor/" if i := strings.LastIndex(s, vendorInline); i >= 0 { s = s[i+len(vendorInline):] } else if strings.HasPrefix(s, vendorStart) { s = s[len(vendorStart):] } return s } // var genInternalMu sync.Mutex var genInternalV = genInternal{Version: genVersion} var genInternalTmplFuncs template.FuncMap var genInternalOnce sync.Once func genInternalInit() { wordSizeBytes := int(intBitsize) / 8 typesizes := map[string]int{ "interface{}": 2 * wordSizeBytes, "string": 2 * wordSizeBytes, "[]byte": 3 * wordSizeBytes, "uint": 1 * wordSizeBytes, "uint8": 1, "uint16": 2, "uint32": 4, "uint64": 8, "uintptr": 1 * wordSizeBytes, "int": 1 * wordSizeBytes, "int8": 1, "int16": 2, "int32": 4, "int64": 8, "float32": 4, "float64": 8, "bool": 1, } // keep as slice, so it is in specific iteration order. // Initial order was uint64, string, interface{}, int, int64, ... var types = [...]string{ "interface{}", "string", "[]byte", "float32", "float64", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", "int", "int8", "int16", "int32", "int64", "bool", } var primitivetypes, slicetypes, mapkeytypes, mapvaltypes []string primitivetypes = types[:] slicetypes = types[:] mapkeytypes = types[:] mapvaltypes = types[:] if genFastpathTrimTypes { mapkeytypes = []string{ //"interface{}", "string", //"[]byte", //"float32", //"float64", "uint", "uint8", //"uint16", //"uint32", "uint64", //"uintptr", "int", //"int8", //"int16", //"int32", "int64", // "bool", } mapvaltypes = []string{ "interface{}", "string", "[]byte", "uint", "uint8", //"uint16", //"uint32", "uint64", "uintptr", "int", //"int8", //"int16", //"int32", "int64", "float32", "float64", "bool", } } // var mapkeytypes [len(&types) - 1]string // skip bool // copy(mapkeytypes[:], types[:]) // var mb []byte // mb = append(mb, '|') // for _, s := range mapkeytypes { // mb = append(mb, s...) // mb = append(mb, '|') // } // var mapkeytypestr = string(mb) var gt = genInternal{Version: genVersion} // For each slice or map type, there must be a (symmetrical) Encode and Decode fast-path function for _, s := range primitivetypes { gt.Values = append(gt.Values, fastpathGenV{Primitive: s, Size: typesizes[s], NoCanonical: !genFastpathCanonical}) } for _, s := range slicetypes { // if s != "uint8" { // do not generate fast path for slice of bytes. Treat specially already. // gt.Values = append(gt.Values, fastpathGenV{Elem: s, Size: typesizes[s]}) // } gt.Values = append(gt.Values, fastpathGenV{Elem: s, Size: typesizes[s], NoCanonical: !genFastpathCanonical}) } for _, s := range mapkeytypes { // if _, ok := typesizes[s]; !ok { // if strings.Contains(mapkeytypestr, "|"+s+"|") { // gt.Values = append(gt.Values, fastpathGenV{MapKey: s, Elem: s, Size: 2 * typesizes[s]}) // } for _, ms := range mapvaltypes { gt.Values = append(gt.Values, fastpathGenV{MapKey: s, Elem: ms, Size: typesizes[s] + typesizes[ms], NoCanonical: !genFastpathCanonical}) } } funcs := make(template.FuncMap) // funcs["haspfx"] = strings.HasPrefix funcs["encmd"] = genInternalEncCommandAsString funcs["decmd"] = genInternalDecCommandAsString funcs["zerocmd"] = genInternalZeroValue funcs["nonzerocmd"] = genInternalNonZeroValue funcs["hasprefix"] = strings.HasPrefix funcs["sorttype"] = genInternalSortType genInternalV = gt genInternalTmplFuncs = funcs } // genInternalGoFile is used to generate source files from templates. // It is run by the program author alone. // Unfortunately, it has to be exported so that it can be called from a command line tool. // *** DO NOT USE *** func genInternalGoFile(r io.Reader, w io.Writer) (err error) { genInternalOnce.Do(genInternalInit) gt := genInternalV t := template.New("").Funcs(genInternalTmplFuncs) tmplstr, err := ioutil.ReadAll(r) if err != nil { return } if t, err = t.Parse(string(tmplstr)); err != nil { return } var out bytes.Buffer err = t.Execute(&out, gt) if err != nil { return } bout, err := format.Source(out.Bytes()) if err != nil { w.Write(out.Bytes()) // write out if error, so we can still see. // w.Write(bout) // write out if error, as much as possible, so we can still see. return } w.Write(bout) return } ================================================ FILE: vendor/github.com/ugorji/go/codec/go.mod ================================================ module github.com/ugorji/go/codec require ( github.com/ugorji/go v1.1.5-pre ) ================================================ FILE: vendor/github.com/ugorji/go/codec/goversion_arrayof_gte_go15.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // +build go1.5 package codec import "reflect" const reflectArrayOfSupported = true func reflectArrayOf(count int, elem reflect.Type) reflect.Type { return reflect.ArrayOf(count, elem) } ================================================ FILE: vendor/github.com/ugorji/go/codec/goversion_arrayof_lt_go15.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // +build !go1.5 package codec import "reflect" const reflectArrayOfSupported = false func reflectArrayOf(count int, elem reflect.Type) reflect.Type { panic("codec: reflect.ArrayOf unsupported in this go version") } ================================================ FILE: vendor/github.com/ugorji/go/codec/goversion_makemap_gte_go19.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // +build go1.9 package codec import "reflect" func makeMapReflect(t reflect.Type, size int) reflect.Value { if size < 0 { return reflect.MakeMapWithSize(t, 4) } return reflect.MakeMapWithSize(t, size) } ================================================ FILE: vendor/github.com/ugorji/go/codec/goversion_makemap_lt_go19.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // +build !go1.9 package codec import "reflect" func makeMapReflect(t reflect.Type, size int) reflect.Value { return reflect.MakeMap(t) } ================================================ FILE: vendor/github.com/ugorji/go/codec/goversion_unexportedembeddedptr_gte_go110.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // +build go1.10 package codec const allowSetUnexportedEmbeddedPtr = false ================================================ FILE: vendor/github.com/ugorji/go/codec/goversion_unexportedembeddedptr_lt_go110.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // +build !go1.10 package codec const allowSetUnexportedEmbeddedPtr = true ================================================ FILE: vendor/github.com/ugorji/go/codec/goversion_unsupported_lt_go14.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // +build !go1.4 package codec // This codec package will only work for go1.4 and above. // This is for the following reasons: // - go 1.4 was released in 2014 // - go runtime is written fully in go // - interface only holds pointers // - reflect.Value is stabilized as 3 words func init() { panic("codec: go 1.3 and below are not supported") } ================================================ FILE: vendor/github.com/ugorji/go/codec/goversion_vendor_eq_go15.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // +build go1.5,!go1.6 package codec import "os" var genCheckVendor = os.Getenv("GO15VENDOREXPERIMENT") == "1" ================================================ FILE: vendor/github.com/ugorji/go/codec/goversion_vendor_eq_go16.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // +build go1.6,!go1.7 package codec import "os" var genCheckVendor = os.Getenv("GO15VENDOREXPERIMENT") != "0" ================================================ FILE: vendor/github.com/ugorji/go/codec/goversion_vendor_gte_go17.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // +build go1.7 package codec const genCheckVendor = true ================================================ FILE: vendor/github.com/ugorji/go/codec/goversion_vendor_lt_go15.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // +build !go1.5 package codec var genCheckVendor = false ================================================ FILE: vendor/github.com/ugorji/go/codec/helper.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. package codec // Contains code shared by both encode and decode. // Some shared ideas around encoding/decoding // ------------------------------------------ // // If an interface{} is passed, we first do a type assertion to see if it is // a primitive type or a map/slice of primitive types, and use a fastpath to handle it. // // If we start with a reflect.Value, we are already in reflect.Value land and // will try to grab the function for the underlying Type and directly call that function. // This is more performant than calling reflect.Value.Interface(). // // This still helps us bypass many layers of reflection, and give best performance. // // Containers // ------------ // Containers in the stream are either associative arrays (key-value pairs) or // regular arrays (indexed by incrementing integers). // // Some streams support indefinite-length containers, and use a breaking // byte-sequence to denote that the container has come to an end. // // Some streams also are text-based, and use explicit separators to denote the // end/beginning of different values. // // During encode, we use a high-level condition to determine how to iterate through // the container. That decision is based on whether the container is text-based (with // separators) or binary (without separators). If binary, we do not even call the // encoding of separators. // // During decode, we use a different high-level condition to determine how to iterate // through the containers. That decision is based on whether the stream contained // a length prefix, or if it used explicit breaks. If length-prefixed, we assume that // it has to be binary, and we do not even try to read separators. // // Philosophy // ------------ // On decode, this codec will update containers appropriately: // - If struct, update fields from stream into fields of struct. // If field in stream not found in struct, handle appropriately (based on option). // If a struct field has no corresponding value in the stream, leave it AS IS. // If nil in stream, set value to nil/zero value. // - If map, update map from stream. // If the stream value is NIL, set the map to nil. // - if slice, try to update up to length of array in stream. // if container len is less than stream array length, // and container cannot be expanded, handled (based on option). // This means you can decode 4-element stream array into 1-element array. // // ------------------------------------ // On encode, user can specify omitEmpty. This means that the value will be omitted // if the zero value. The problem may occur during decode, where omitted values do not affect // the value being decoded into. This means that if decoding into a struct with an // int field with current value=5, and the field is omitted in the stream, then after // decoding, the value will still be 5 (not 0). // omitEmpty only works if you guarantee that you always decode into zero-values. // // ------------------------------------ // We could have truncated a map to remove keys not available in the stream, // or set values in the struct which are not in the stream to their zero values. // We decided against it because there is no efficient way to do it. // We may introduce it as an option later. // However, that will require enabling it for both runtime and code generation modes. // // To support truncate, we need to do 2 passes over the container: // map // - first collect all keys (e.g. in k1) // - for each key in stream, mark k1 that the key should not be removed // - after updating map, do second pass and call delete for all keys in k1 which are not marked // struct: // - for each field, track the *typeInfo s1 // - iterate through all s1, and for each one not marked, set value to zero // - this involves checking the possible anonymous fields which are nil ptrs. // too much work. // // ------------------------------------------ // Error Handling is done within the library using panic. // // This way, the code doesn't have to keep checking if an error has happened, // and we don't have to keep sending the error value along with each call // or storing it in the En|Decoder and checking it constantly along the way. // // The disadvantage is that small functions which use panics cannot be inlined. // The code accounts for that by only using panics behind an interface; // since interface calls cannot be inlined, this is irrelevant. // // We considered storing the error is En|Decoder. // - once it has its err field set, it cannot be used again. // - panicing will be optional, controlled by const flag. // - code should always check error first and return early. // We eventually decided against it as it makes the code clumsier to always // check for these error conditions. import ( "bytes" "encoding" "encoding/binary" "errors" "fmt" "io" "math" "reflect" "sort" "strconv" "strings" "sync" "sync/atomic" "time" ) const ( scratchByteArrayLen = 32 // initCollectionCap = 16 // 32 is defensive. 16 is preferred. // Support encoding.(Binary|Text)(Unm|M)arshaler. // This constant flag will enable or disable it. supportMarshalInterfaces = true // for debugging, set this to false, to catch panic traces. // Note that this will always cause rpc tests to fail, since they need io.EOF sent via panic. recoverPanicToErr = true // arrayCacheLen is the length of the cache used in encoder or decoder for // allowing zero-alloc initialization. // arrayCacheLen = 8 // size of the cacheline: defaulting to value for archs: amd64, arm64, 386 // should use "runtime/internal/sys".CacheLineSize, but that is not exposed. cacheLineSize = 64 wordSizeBits = 32 << (^uint(0) >> 63) // strconv.IntSize wordSize = wordSizeBits / 8 // so structFieldInfo fits into 8 bytes maxLevelsEmbedding = 14 // useFinalizers=true configures finalizers to release pool'ed resources // acquired by Encoder/Decoder during their GC. // // Note that calling SetFinalizer is always expensive, // as code must be run on the systemstack even for SetFinalizer(t, nil). // // We document that folks SHOULD call Release() when done, or they can // explicitly call SetFinalizer themselves e.g. // runtime.SetFinalizer(e, (*Encoder).Release) // runtime.SetFinalizer(d, (*Decoder).Release) useFinalizers = false ) var oneByteArr [1]byte var zeroByteSlice = oneByteArr[:0:0] var codecgen bool var refBitset bitset256 var pool pooler var panicv panicHdl func init() { pool.init() refBitset.set(byte(reflect.Map)) refBitset.set(byte(reflect.Ptr)) refBitset.set(byte(reflect.Func)) refBitset.set(byte(reflect.Chan)) } type handleFlag uint8 const ( initedHandleFlag handleFlag = 1 << iota binaryHandleFlag jsonHandleFlag ) type clsErr struct { closed bool // is it closed? errClosed error // error on closing } // type entryType uint8 // const ( // entryTypeBytes entryType = iota // make this 0, so a comparison is cheap // entryTypeIo // entryTypeBufio // entryTypeUnset = 255 // ) type charEncoding uint8 const ( _ charEncoding = iota // make 0 unset cUTF8 cUTF16LE cUTF16BE cUTF32LE cUTF32BE // Deprecated: not a true char encoding value cRAW charEncoding = 255 ) // valueType is the stream type type valueType uint8 const ( valueTypeUnset valueType = iota valueTypeNil valueTypeInt valueTypeUint valueTypeFloat valueTypeBool valueTypeString valueTypeSymbol valueTypeBytes valueTypeMap valueTypeArray valueTypeTime valueTypeExt // valueTypeInvalid = 0xff ) var valueTypeStrings = [...]string{ "Unset", "Nil", "Int", "Uint", "Float", "Bool", "String", "Symbol", "Bytes", "Map", "Array", "Timestamp", "Ext", } func (x valueType) String() string { if int(x) < len(valueTypeStrings) { return valueTypeStrings[x] } return strconv.FormatInt(int64(x), 10) } type seqType uint8 const ( _ seqType = iota seqTypeArray seqTypeSlice seqTypeChan ) // note that containerMapStart and containerArraySend are not sent. // This is because the ReadXXXStart and EncodeXXXStart already does these. type containerState uint8 const ( _ containerState = iota containerMapStart containerMapKey containerMapValue containerMapEnd containerArrayStart containerArrayElem containerArrayEnd ) // // sfiIdx used for tracking where a (field/enc)Name is seen in a []*structFieldInfo // type sfiIdx struct { // name string // index int // } // do not recurse if a containing type refers to an embedded type // which refers back to its containing type (via a pointer). // The second time this back-reference happens, break out, // so as not to cause an infinite loop. const rgetMaxRecursion = 2 // Anecdotally, we believe most types have <= 12 fields. // - even Java's PMD rules set TooManyFields threshold to 15. // However, go has embedded fields, which should be regarded as // top level, allowing structs to possibly double or triple. // In addition, we don't want to keep creating transient arrays, // especially for the sfi index tracking, and the evtypes tracking. // // So - try to keep typeInfoLoadArray within 2K bytes const ( typeInfoLoadArraySfisLen = 16 typeInfoLoadArraySfiidxLen = 8 * 112 typeInfoLoadArrayEtypesLen = 12 typeInfoLoadArrayBLen = 8 * 4 ) // typeInfoLoad is a transient object used while loading up a typeInfo. type typeInfoLoad struct { // fNames []string // encNames []string etypes []uintptr sfis []structFieldInfo } // typeInfoLoadArray is a cache object used to efficiently load up a typeInfo without // much allocation. type typeInfoLoadArray struct { // fNames [typeInfoLoadArrayLen]string // encNames [typeInfoLoadArrayLen]string sfis [typeInfoLoadArraySfisLen]structFieldInfo sfiidx [typeInfoLoadArraySfiidxLen]byte etypes [typeInfoLoadArrayEtypesLen]uintptr b [typeInfoLoadArrayBLen]byte // scratch - used for struct field names } // // cacheLineSafer denotes that a type is safe for cache-line access. // // This could mean that // type cacheLineSafer interface { // cacheLineSafe() // } // mirror json.Marshaler and json.Unmarshaler here, // so we don't import the encoding/json package type jsonMarshaler interface { MarshalJSON() ([]byte, error) } type jsonUnmarshaler interface { UnmarshalJSON([]byte) error } type isZeroer interface { IsZero() bool } type codecError struct { name string err interface{} } func (e codecError) Cause() error { switch xerr := e.err.(type) { case nil: return nil case error: return xerr case string: return errors.New(xerr) case fmt.Stringer: return errors.New(xerr.String()) default: return fmt.Errorf("%v", e.err) } } func (e codecError) Error() string { return fmt.Sprintf("%s error: %v", e.name, e.err) } // type byteAccepter func(byte) bool var ( bigen = binary.BigEndian structInfoFieldName = "_struct" mapStrIntfTyp = reflect.TypeOf(map[string]interface{}(nil)) mapIntfIntfTyp = reflect.TypeOf(map[interface{}]interface{}(nil)) intfSliceTyp = reflect.TypeOf([]interface{}(nil)) intfTyp = intfSliceTyp.Elem() reflectValTyp = reflect.TypeOf((*reflect.Value)(nil)).Elem() stringTyp = reflect.TypeOf("") timeTyp = reflect.TypeOf(time.Time{}) rawExtTyp = reflect.TypeOf(RawExt{}) rawTyp = reflect.TypeOf(Raw{}) uintptrTyp = reflect.TypeOf(uintptr(0)) uint8Typ = reflect.TypeOf(uint8(0)) uint8SliceTyp = reflect.TypeOf([]uint8(nil)) uintTyp = reflect.TypeOf(uint(0)) intTyp = reflect.TypeOf(int(0)) mapBySliceTyp = reflect.TypeOf((*MapBySlice)(nil)).Elem() binaryMarshalerTyp = reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem() binaryUnmarshalerTyp = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem() textMarshalerTyp = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() textUnmarshalerTyp = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() jsonMarshalerTyp = reflect.TypeOf((*jsonMarshaler)(nil)).Elem() jsonUnmarshalerTyp = reflect.TypeOf((*jsonUnmarshaler)(nil)).Elem() selferTyp = reflect.TypeOf((*Selfer)(nil)).Elem() missingFielderTyp = reflect.TypeOf((*MissingFielder)(nil)).Elem() iszeroTyp = reflect.TypeOf((*isZeroer)(nil)).Elem() uint8TypId = rt2id(uint8Typ) uint8SliceTypId = rt2id(uint8SliceTyp) rawExtTypId = rt2id(rawExtTyp) rawTypId = rt2id(rawTyp) intfTypId = rt2id(intfTyp) timeTypId = rt2id(timeTyp) stringTypId = rt2id(stringTyp) mapStrIntfTypId = rt2id(mapStrIntfTyp) mapIntfIntfTypId = rt2id(mapIntfIntfTyp) intfSliceTypId = rt2id(intfSliceTyp) // mapBySliceTypId = rt2id(mapBySliceTyp) intBitsize = uint8(intTyp.Bits()) uintBitsize = uint8(uintTyp.Bits()) // bsAll0x00 = []byte{0, 0, 0, 0, 0, 0, 0, 0} bsAll0xff = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} chkOvf checkOverflow errNoFieldNameToStructFieldInfo = errors.New("no field name passed to parseStructFieldInfo") ) var defTypeInfos = NewTypeInfos([]string{"codec", "json"}) var immutableKindsSet = [32]bool{ // reflect.Invalid: , reflect.Bool: true, reflect.Int: true, reflect.Int8: true, reflect.Int16: true, reflect.Int32: true, reflect.Int64: true, reflect.Uint: true, reflect.Uint8: true, reflect.Uint16: true, reflect.Uint32: true, reflect.Uint64: true, reflect.Uintptr: true, reflect.Float32: true, reflect.Float64: true, reflect.Complex64: true, reflect.Complex128: true, // reflect.Array // reflect.Chan // reflect.Func: true, // reflect.Interface // reflect.Map // reflect.Ptr // reflect.Slice reflect.String: true, // reflect.Struct // reflect.UnsafePointer } // Selfer defines methods by which a value can encode or decode itself. // // Any type which implements Selfer will be able to encode or decode itself. // Consequently, during (en|de)code, this takes precedence over // (text|binary)(M|Unm)arshal or extension support. // // By definition, it is not allowed for a Selfer to directly call Encode or Decode on itself. // If that is done, Encode/Decode will rightfully fail with a Stack Overflow style error. // For example, the snippet below will cause such an error. // type testSelferRecur struct{} // func (s *testSelferRecur) CodecEncodeSelf(e *Encoder) { e.MustEncode(s) } // func (s *testSelferRecur) CodecDecodeSelf(d *Decoder) { d.MustDecode(s) } // // Note: *the first set of bytes of any value MUST NOT represent nil in the format*. // This is because, during each decode, we first check the the next set of bytes // represent nil, and if so, we just set the value to nil. type Selfer interface { CodecEncodeSelf(*Encoder) CodecDecodeSelf(*Decoder) } // MissingFielder defines the interface allowing structs to internally decode or encode // values which do not map to struct fields. // // We expect that this interface is bound to a pointer type (so the mutation function works). // // A use-case is if a version of a type unexports a field, but you want compatibility between // both versions during encoding and decoding. // // Note that the interface is completely ignored during codecgen. type MissingFielder interface { // CodecMissingField is called to set a missing field and value pair. // // It returns true if the missing field was set on the struct. CodecMissingField(field []byte, value interface{}) bool // CodecMissingFields returns the set of fields which are not struct fields CodecMissingFields() map[string]interface{} } // MapBySlice is a tag interface that denotes wrapped slice should encode as a map in the stream. // The slice contains a sequence of key-value pairs. // This affords storing a map in a specific sequence in the stream. // // Example usage: // type T1 []string // or []int or []Point or any other "slice" type // func (_ T1) MapBySlice{} // T1 now implements MapBySlice, and will be encoded as a map // type T2 struct { KeyValues T1 } // // var kvs = []string{"one", "1", "two", "2", "three", "3"} // var v2 = T2{ KeyValues: T1(kvs) } // // v2 will be encoded like the map: {"KeyValues": {"one": "1", "two": "2", "three": "3"} } // // The support of MapBySlice affords the following: // - A slice type which implements MapBySlice will be encoded as a map // - A slice can be decoded from a map in the stream // - It MUST be a slice type (not a pointer receiver) that implements MapBySlice type MapBySlice interface { MapBySlice() } // BasicHandle encapsulates the common options and extension functions. // // Deprecated: DO NOT USE DIRECTLY. EXPORTED FOR GODOC BENEFIT. WILL BE REMOVED. type BasicHandle struct { // BasicHandle is always a part of a different type. // It doesn't have to fit into it own cache lines. // TypeInfos is used to get the type info for any type. // // If not configured, the default TypeInfos is used, which uses struct tag keys: codec, json TypeInfos *TypeInfos // Note: BasicHandle is not comparable, due to these slices here (extHandle, intf2impls). // If *[]T is used instead, this becomes comparable, at the cost of extra indirection. // Thses slices are used all the time, so keep as slices (not pointers). extHandle intf2impls EncodeOptions DecodeOptions RPCOptions // TimeNotBuiltin configures whether time.Time should be treated as a builtin type. // // All Handlers should know how to encode/decode time.Time as part of the core // format specification, or as a standard extension defined by the format. // // However, users can elect to handle time.Time as a custom extension, or via the // standard library's encoding.Binary(M|Unm)arshaler or Text(M|Unm)arshaler interface. // To elect this behavior, users can set TimeNotBuiltin=true. // Note: Setting TimeNotBuiltin=true can be used to enable the legacy behavior // (for Cbor and Msgpack), where time.Time was not a builtin supported type. TimeNotBuiltin bool // ExplicitRelease configures whether Release() is implicitly called after an encode or // decode call. // // If you will hold onto an Encoder or Decoder for re-use, by calling Reset(...) // on it or calling (Must)Encode repeatedly into a given []byte or io.Writer, // then you do not want it to be implicitly closed after each Encode/Decode call. // Doing so will unnecessarily return resources to the shared pool, only for you to // grab them right after again to do another Encode/Decode call. // // Instead, you configure ExplicitRelease=true, and you explicitly call Release() when // you are truly done. // // As an alternative, you can explicitly set a finalizer - so its resources // are returned to the shared pool before it is garbage-collected. Do it as below: // runtime.SetFinalizer(e, (*Encoder).Release) // runtime.SetFinalizer(d, (*Decoder).Release) ExplicitRelease bool // flags handleFlag // holds flag for if binaryEncoding, jsonHandler, etc // be bool // is handle a binary encoding? // js bool // is handle javascript handler? // n byte // first letter of handle name // _ uint16 // padding // ---- cache line // noBuiltInTypeChecker inited uint32 // holds if inited, and also handle flags (binary encoding, json handler, etc) mu sync.Mutex // _ uint32 // padding rtidFns atomicRtidFnSlice // r []uintptr // rtids mapped to s above } // basicHandle returns an initialized BasicHandle from the Handle. func basicHandle(hh Handle) (x *BasicHandle) { x = hh.getBasicHandle() // ** We need to simulate once.Do, to ensure no data race within the block. // ** Consequently, below would not work. // if atomic.CompareAndSwapUint32(&x.inited, 0, 1) { // x.be = hh.isBinary() // _, x.js = hh.(*JsonHandle) // x.n = hh.Name()[0] // } // simulate once.Do using our own stored flag and mutex as a CompareAndSwap // is not sufficient, since a race condition can occur within init(Handle) function. // init is made noinline, so that this function can be inlined by its caller. if atomic.LoadUint32(&x.inited) == 0 { x.init(hh) } return } func (x *BasicHandle) isJs() bool { return handleFlag(x.inited)&jsonHandleFlag != 0 } func (x *BasicHandle) isBe() bool { return handleFlag(x.inited)&binaryHandleFlag != 0 } //go:noinline func (x *BasicHandle) init(hh Handle) { // make it uninlineable, as it is called at most once x.mu.Lock() if x.inited == 0 { var f = initedHandleFlag if hh.isBinary() { f |= binaryHandleFlag } if _, b := hh.(*JsonHandle); b { f |= jsonHandleFlag } // _, x.js = hh.(*JsonHandle) // x.n = hh.Name()[0] atomic.StoreUint32(&x.inited, uint32(f)) } x.mu.Unlock() } func (x *BasicHandle) getBasicHandle() *BasicHandle { return x } func (x *BasicHandle) getTypeInfo(rtid uintptr, rt reflect.Type) (pti *typeInfo) { if x.TypeInfos == nil { return defTypeInfos.get(rtid, rt) } return x.TypeInfos.get(rtid, rt) } func findFn(s []codecRtidFn, rtid uintptr) (i uint, fn *codecFn) { // binary search. adapted from sort/search.go. // Note: we use goto (instead of for loop) so this can be inlined. // h, i, j := 0, 0, len(s) var h uint // var h, i uint var j = uint(len(s)) LOOP: if i < j { h = i + (j-i)/2 if s[h].rtid < rtid { i = h + 1 } else { j = h } goto LOOP } if i < uint(len(s)) && s[i].rtid == rtid { fn = s[i].fn } return } func (x *BasicHandle) fn(rt reflect.Type, checkFastpath, checkCodecSelfer bool) (fn *codecFn) { rtid := rt2id(rt) sp := x.rtidFns.load() if sp != nil { if _, fn = findFn(sp, rtid); fn != nil { // xdebugf("<<<< %c: found fn for %v in rtidfns of size: %v", c.n, rt, len(sp)) return } } c := x // xdebugf("#### for %c: load fn for %v in rtidfns of size: %v", c.n, rt, len(sp)) fn = new(codecFn) fi := &(fn.i) ti := c.getTypeInfo(rtid, rt) fi.ti = ti rk := reflect.Kind(ti.kind) if checkCodecSelfer && (ti.cs || ti.csp) { fn.fe = (*Encoder).selferMarshal fn.fd = (*Decoder).selferUnmarshal fi.addrF = true fi.addrD = ti.csp fi.addrE = ti.csp } else if rtid == timeTypId && !c.TimeNotBuiltin { fn.fe = (*Encoder).kTime fn.fd = (*Decoder).kTime } else if rtid == rawTypId { fn.fe = (*Encoder).raw fn.fd = (*Decoder).raw } else if rtid == rawExtTypId { fn.fe = (*Encoder).rawExt fn.fd = (*Decoder).rawExt fi.addrF = true fi.addrD = true fi.addrE = true } else if xfFn := c.getExt(rtid); xfFn != nil { fi.xfTag, fi.xfFn = xfFn.tag, xfFn.ext fn.fe = (*Encoder).ext fn.fd = (*Decoder).ext fi.addrF = true fi.addrD = true if rk == reflect.Struct || rk == reflect.Array { fi.addrE = true } } else if supportMarshalInterfaces && c.isBe() && (ti.bm || ti.bmp) && (ti.bu || ti.bup) { fn.fe = (*Encoder).binaryMarshal fn.fd = (*Decoder).binaryUnmarshal fi.addrF = true fi.addrD = ti.bup fi.addrE = ti.bmp } else if supportMarshalInterfaces && !c.isBe() && c.isJs() && (ti.jm || ti.jmp) && (ti.ju || ti.jup) { //If JSON, we should check JSONMarshal before textMarshal fn.fe = (*Encoder).jsonMarshal fn.fd = (*Decoder).jsonUnmarshal fi.addrF = true fi.addrD = ti.jup fi.addrE = ti.jmp } else if supportMarshalInterfaces && !c.isBe() && (ti.tm || ti.tmp) && (ti.tu || ti.tup) { fn.fe = (*Encoder).textMarshal fn.fd = (*Decoder).textUnmarshal fi.addrF = true fi.addrD = ti.tup fi.addrE = ti.tmp } else { if fastpathEnabled && checkFastpath && (rk == reflect.Map || rk == reflect.Slice) { if ti.pkgpath == "" { // un-named slice or map if idx := fastpathAV.index(rtid); idx != -1 { fn.fe = fastpathAV[idx].encfn fn.fd = fastpathAV[idx].decfn fi.addrD = true fi.addrF = false } } else { // use mapping for underlying type if there var rtu reflect.Type if rk == reflect.Map { rtu = reflect.MapOf(ti.key, ti.elem) } else { rtu = reflect.SliceOf(ti.elem) } rtuid := rt2id(rtu) if idx := fastpathAV.index(rtuid); idx != -1 { xfnf := fastpathAV[idx].encfn xrt := fastpathAV[idx].rt fn.fe = func(e *Encoder, xf *codecFnInfo, xrv reflect.Value) { xfnf(e, xf, xrv.Convert(xrt)) } fi.addrD = true fi.addrF = false // meaning it can be an address(ptr) or a value xfnf2 := fastpathAV[idx].decfn fn.fd = func(d *Decoder, xf *codecFnInfo, xrv reflect.Value) { if xrv.Kind() == reflect.Ptr { xfnf2(d, xf, xrv.Convert(reflect.PtrTo(xrt))) } else { xfnf2(d, xf, xrv.Convert(xrt)) } } } } } if fn.fe == nil && fn.fd == nil { switch rk { case reflect.Bool: fn.fe = (*Encoder).kBool fn.fd = (*Decoder).kBool case reflect.String: fn.fe = (*Encoder).kString fn.fd = (*Decoder).kString case reflect.Int: fn.fd = (*Decoder).kInt fn.fe = (*Encoder).kInt case reflect.Int8: fn.fe = (*Encoder).kInt8 fn.fd = (*Decoder).kInt8 case reflect.Int16: fn.fe = (*Encoder).kInt16 fn.fd = (*Decoder).kInt16 case reflect.Int32: fn.fe = (*Encoder).kInt32 fn.fd = (*Decoder).kInt32 case reflect.Int64: fn.fe = (*Encoder).kInt64 fn.fd = (*Decoder).kInt64 case reflect.Uint: fn.fd = (*Decoder).kUint fn.fe = (*Encoder).kUint case reflect.Uint8: fn.fe = (*Encoder).kUint8 fn.fd = (*Decoder).kUint8 case reflect.Uint16: fn.fe = (*Encoder).kUint16 fn.fd = (*Decoder).kUint16 case reflect.Uint32: fn.fe = (*Encoder).kUint32 fn.fd = (*Decoder).kUint32 case reflect.Uint64: fn.fe = (*Encoder).kUint64 fn.fd = (*Decoder).kUint64 case reflect.Uintptr: fn.fe = (*Encoder).kUintptr fn.fd = (*Decoder).kUintptr case reflect.Float32: fn.fe = (*Encoder).kFloat32 fn.fd = (*Decoder).kFloat32 case reflect.Float64: fn.fe = (*Encoder).kFloat64 fn.fd = (*Decoder).kFloat64 case reflect.Invalid: fn.fe = (*Encoder).kInvalid fn.fd = (*Decoder).kErr case reflect.Chan: fi.seq = seqTypeChan fn.fe = (*Encoder).kSlice fn.fd = (*Decoder).kSlice case reflect.Slice: fi.seq = seqTypeSlice fn.fe = (*Encoder).kSlice fn.fd = (*Decoder).kSlice case reflect.Array: fi.seq = seqTypeArray fn.fe = (*Encoder).kSlice fi.addrF = false fi.addrD = false rt2 := reflect.SliceOf(ti.elem) fn.fd = func(d *Decoder, xf *codecFnInfo, xrv reflect.Value) { d.h.fn(rt2, true, false).fd(d, xf, xrv.Slice(0, xrv.Len())) } // fn.fd = (*Decoder).kArray case reflect.Struct: if ti.anyOmitEmpty || ti.mf || ti.mfp { fn.fe = (*Encoder).kStruct } else { fn.fe = (*Encoder).kStructNoOmitempty } fn.fd = (*Decoder).kStruct case reflect.Map: fn.fe = (*Encoder).kMap fn.fd = (*Decoder).kMap case reflect.Interface: // encode: reflect.Interface are handled already by preEncodeValue fn.fd = (*Decoder).kInterface fn.fe = (*Encoder).kErr default: // reflect.Ptr and reflect.Interface are handled already by preEncodeValue fn.fe = (*Encoder).kErr fn.fd = (*Decoder).kErr } } } c.mu.Lock() var sp2 []codecRtidFn sp = c.rtidFns.load() if sp == nil { sp2 = []codecRtidFn{{rtid, fn}} c.rtidFns.store(sp2) // xdebugf(">>>> adding rt: %v to rtidfns of size: %v", rt, len(sp2)) // xdebugf(">>>> loading stored rtidfns of size: %v", len(c.rtidFns.load())) } else { idx, fn2 := findFn(sp, rtid) if fn2 == nil { sp2 = make([]codecRtidFn, len(sp)+1) copy(sp2, sp[:idx]) copy(sp2[idx+1:], sp[idx:]) sp2[idx] = codecRtidFn{rtid, fn} c.rtidFns.store(sp2) // xdebugf(">>>> adding rt: %v to rtidfns of size: %v", rt, len(sp2)) } } c.mu.Unlock() return } // Handle defines a specific encoding format. It also stores any runtime state // used during an Encoding or Decoding session e.g. stored state about Types, etc. // // Once a handle is configured, it can be shared across multiple Encoders and Decoders. // // Note that a Handle is NOT safe for concurrent modification. // Consequently, do not modify it after it is configured if shared among // multiple Encoders and Decoders in different goroutines. // // Consequently, the typical usage model is that a Handle is pre-configured // before first time use, and not modified while in use. // Such a pre-configured Handle is safe for concurrent access. type Handle interface { Name() string // return the basic handle. It may not have been inited. // Prefer to use basicHandle() helper function that ensures it has been inited. getBasicHandle() *BasicHandle recreateEncDriver(encDriver) bool newEncDriver(w *Encoder) encDriver newDecDriver(r *Decoder) decDriver isBinary() bool hasElemSeparators() bool // IsBuiltinType(rtid uintptr) bool } // Raw represents raw formatted bytes. // We "blindly" store it during encode and retrieve the raw bytes during decode. // Note: it is dangerous during encode, so we may gate the behaviour // behind an Encode flag which must be explicitly set. type Raw []byte // RawExt represents raw unprocessed extension data. // Some codecs will decode extension data as a *RawExt // if there is no registered extension for the tag. // // Only one of Data or Value is nil. // If Data is nil, then the content of the RawExt is in the Value. type RawExt struct { Tag uint64 // Data is the []byte which represents the raw ext. If nil, ext is exposed in Value. // Data is used by codecs (e.g. binc, msgpack, simple) which do custom serialization of types Data []byte // Value represents the extension, if Data is nil. // Value is used by codecs (e.g. cbor, json) which leverage the format to do // custom serialization of the types. Value interface{} } // BytesExt handles custom (de)serialization of types to/from []byte. // It is used by codecs (e.g. binc, msgpack, simple) which do custom serialization of the types. type BytesExt interface { // WriteExt converts a value to a []byte. // // Note: v is a pointer iff the registered extension type is a struct or array kind. WriteExt(v interface{}) []byte // ReadExt updates a value from a []byte. // // Note: dst is always a pointer kind to the registered extension type. ReadExt(dst interface{}, src []byte) } // InterfaceExt handles custom (de)serialization of types to/from another interface{} value. // The Encoder or Decoder will then handle the further (de)serialization of that known type. // // It is used by codecs (e.g. cbor, json) which use the format to do custom serialization of types. type InterfaceExt interface { // ConvertExt converts a value into a simpler interface for easy encoding // e.g. convert time.Time to int64. // // Note: v is a pointer iff the registered extension type is a struct or array kind. ConvertExt(v interface{}) interface{} // UpdateExt updates a value from a simpler interface for easy decoding // e.g. convert int64 to time.Time. // // Note: dst is always a pointer kind to the registered extension type. UpdateExt(dst interface{}, src interface{}) } // Ext handles custom (de)serialization of custom types / extensions. type Ext interface { BytesExt InterfaceExt } // addExtWrapper is a wrapper implementation to support former AddExt exported method. type addExtWrapper struct { encFn func(reflect.Value) ([]byte, error) decFn func(reflect.Value, []byte) error } func (x addExtWrapper) WriteExt(v interface{}) []byte { bs, err := x.encFn(reflect.ValueOf(v)) if err != nil { panic(err) } return bs } func (x addExtWrapper) ReadExt(v interface{}, bs []byte) { if err := x.decFn(reflect.ValueOf(v), bs); err != nil { panic(err) } } func (x addExtWrapper) ConvertExt(v interface{}) interface{} { return x.WriteExt(v) } func (x addExtWrapper) UpdateExt(dest interface{}, v interface{}) { x.ReadExt(dest, v.([]byte)) } type bytesExtFailer struct{} func (bytesExtFailer) WriteExt(v interface{}) []byte { panicv.errorstr("BytesExt.WriteExt is not supported") return nil } func (bytesExtFailer) ReadExt(v interface{}, bs []byte) { panicv.errorstr("BytesExt.ReadExt is not supported") } type interfaceExtFailer struct{} func (interfaceExtFailer) ConvertExt(v interface{}) interface{} { panicv.errorstr("InterfaceExt.ConvertExt is not supported") return nil } func (interfaceExtFailer) UpdateExt(dest interface{}, v interface{}) { panicv.errorstr("InterfaceExt.UpdateExt is not supported") } // type extWrapper struct { // BytesExt // InterfaceExt // } type bytesExtWrapper struct { interfaceExtFailer BytesExt } type interfaceExtWrapper struct { bytesExtFailer InterfaceExt } type binaryEncodingType struct{} func (binaryEncodingType) isBinary() bool { return true } type textEncodingType struct{} func (textEncodingType) isBinary() bool { return false } // noBuiltInTypes is embedded into many types which do not support builtins // e.g. msgpack, simple, cbor. // type noBuiltInTypeChecker struct{} // func (noBuiltInTypeChecker) IsBuiltinType(rt uintptr) bool { return false } // type noBuiltInTypes struct{ noBuiltInTypeChecker } type noBuiltInTypes struct{} func (noBuiltInTypes) EncodeBuiltin(rt uintptr, v interface{}) {} func (noBuiltInTypes) DecodeBuiltin(rt uintptr, v interface{}) {} // type noStreamingCodec struct{} // func (noStreamingCodec) CheckBreak() bool { return false } // func (noStreamingCodec) hasElemSeparators() bool { return false } type noElemSeparators struct{} func (noElemSeparators) hasElemSeparators() (v bool) { return } func (noElemSeparators) recreateEncDriver(e encDriver) (v bool) { return } // bigenHelper. // Users must already slice the x completely, because we will not reslice. type bigenHelper struct { x []byte // must be correctly sliced to appropriate len. slicing is a cost. w *encWriterSwitch } func (z bigenHelper) writeUint16(v uint16) { bigen.PutUint16(z.x, v) z.w.writeb(z.x) } func (z bigenHelper) writeUint32(v uint32) { bigen.PutUint32(z.x, v) z.w.writeb(z.x) } func (z bigenHelper) writeUint64(v uint64) { bigen.PutUint64(z.x, v) z.w.writeb(z.x) } type extTypeTagFn struct { rtid uintptr rtidptr uintptr rt reflect.Type tag uint64 ext Ext // _ [1]uint64 // padding } type extHandle []extTypeTagFn // AddExt registes an encode and decode function for a reflect.Type. // To deregister an Ext, call AddExt with nil encfn and/or nil decfn. // // Deprecated: Use SetBytesExt or SetInterfaceExt on the Handle instead. func (o *extHandle) AddExt(rt reflect.Type, tag byte, encfn func(reflect.Value) ([]byte, error), decfn func(reflect.Value, []byte) error) (err error) { if encfn == nil || decfn == nil { return o.SetExt(rt, uint64(tag), nil) } return o.SetExt(rt, uint64(tag), addExtWrapper{encfn, decfn}) } // SetExt will set the extension for a tag and reflect.Type. // Note that the type must be a named type, and specifically not a pointer or Interface. // An error is returned if that is not honored. // To Deregister an ext, call SetExt with nil Ext. // // Deprecated: Use SetBytesExt or SetInterfaceExt on the Handle instead. func (o *extHandle) SetExt(rt reflect.Type, tag uint64, ext Ext) (err error) { // o is a pointer, because we may need to initialize it rk := rt.Kind() for rk == reflect.Ptr { rt = rt.Elem() rk = rt.Kind() } if rt.PkgPath() == "" || rk == reflect.Interface { // || rk == reflect.Ptr { return fmt.Errorf("codec.Handle.SetExt: Takes named type, not a pointer or interface: %v", rt) } rtid := rt2id(rt) switch rtid { case timeTypId, rawTypId, rawExtTypId: // all natively supported type, so cannot have an extension return // TODO: should we silently ignore, or return an error??? } // if o == nil { // return errors.New("codec.Handle.SetExt: extHandle not initialized") // } o2 := *o // if o2 == nil { // return errors.New("codec.Handle.SetExt: extHandle not initialized") // } for i := range o2 { v := &o2[i] if v.rtid == rtid { v.tag, v.ext = tag, ext return } } rtidptr := rt2id(reflect.PtrTo(rt)) *o = append(o2, extTypeTagFn{rtid, rtidptr, rt, tag, ext}) // , [1]uint64{}}) return } func (o extHandle) getExt(rtid uintptr) (v *extTypeTagFn) { for i := range o { v = &o[i] if v.rtid == rtid || v.rtidptr == rtid { return } } return nil } func (o extHandle) getExtForTag(tag uint64) (v *extTypeTagFn) { for i := range o { v = &o[i] if v.tag == tag { return } } return nil } type intf2impl struct { rtid uintptr // for intf impl reflect.Type // _ [1]uint64 // padding // not-needed, as *intf2impl is never returned. } type intf2impls []intf2impl // Intf2Impl maps an interface to an implementing type. // This allows us support infering the concrete type // and populating it when passed an interface. // e.g. var v io.Reader can be decoded as a bytes.Buffer, etc. // // Passing a nil impl will clear the mapping. func (o *intf2impls) Intf2Impl(intf, impl reflect.Type) (err error) { if impl != nil && !impl.Implements(intf) { return fmt.Errorf("Intf2Impl: %v does not implement %v", impl, intf) } rtid := rt2id(intf) o2 := *o for i := range o2 { v := &o2[i] if v.rtid == rtid { v.impl = impl return } } *o = append(o2, intf2impl{rtid, impl}) return } func (o intf2impls) intf2impl(rtid uintptr) (rv reflect.Value) { for i := range o { v := &o[i] if v.rtid == rtid { if v.impl == nil { return } if v.impl.Kind() == reflect.Ptr { return reflect.New(v.impl.Elem()) } return reflect.New(v.impl).Elem() } } return } type structFieldInfoFlag uint8 const ( _ structFieldInfoFlag = 1 << iota structFieldInfoFlagReady structFieldInfoFlagOmitEmpty ) func (x *structFieldInfoFlag) flagSet(f structFieldInfoFlag) { *x = *x | f } func (x *structFieldInfoFlag) flagClr(f structFieldInfoFlag) { *x = *x &^ f } func (x structFieldInfoFlag) flagGet(f structFieldInfoFlag) bool { return x&f != 0 } func (x structFieldInfoFlag) omitEmpty() bool { return x.flagGet(structFieldInfoFlagOmitEmpty) } func (x structFieldInfoFlag) ready() bool { return x.flagGet(structFieldInfoFlagReady) } type structFieldInfo struct { encName string // encode name fieldName string // field name is [maxLevelsEmbedding]uint16 // (recursive/embedded) field index in struct nis uint8 // num levels of embedding. if 1, then it's not embedded. encNameAsciiAlphaNum bool // the encName only contains ascii alphabet and numbers structFieldInfoFlag // _ [1]byte // padding } func (si *structFieldInfo) setToZeroValue(v reflect.Value) { if v, valid := si.field(v, false); valid { v.Set(reflect.Zero(v.Type())) } } // rv returns the field of the struct. // If anonymous, it returns an Invalid func (si *structFieldInfo) field(v reflect.Value, update bool) (rv2 reflect.Value, valid bool) { // replicate FieldByIndex for i, x := range si.is { if uint8(i) == si.nis { break } if v, valid = baseStructRv(v, update); !valid { return } v = v.Field(int(x)) } return v, true } // func (si *structFieldInfo) fieldval(v reflect.Value, update bool) reflect.Value { // v, _ = si.field(v, update) // return v // } func parseStructInfo(stag string) (toArray, omitEmpty bool, keytype valueType) { keytype = valueTypeString // default if stag == "" { return } for i, s := range strings.Split(stag, ",") { if i == 0 { } else { switch s { case "omitempty": omitEmpty = true case "toarray": toArray = true case "int": keytype = valueTypeInt case "uint": keytype = valueTypeUint case "float": keytype = valueTypeFloat // case "bool": // keytype = valueTypeBool case "string": keytype = valueTypeString } } } return } func (si *structFieldInfo) parseTag(stag string) { // if fname == "" { // panic(errNoFieldNameToStructFieldInfo) // } if stag == "" { return } for i, s := range strings.Split(stag, ",") { if i == 0 { if s != "" { si.encName = s } } else { switch s { case "omitempty": si.flagSet(structFieldInfoFlagOmitEmpty) // si.omitEmpty = true // case "toarray": // si.toArray = true } } } } type sfiSortedByEncName []*structFieldInfo func (p sfiSortedByEncName) Len() int { return len(p) } func (p sfiSortedByEncName) Less(i, j int) bool { return p[uint(i)].encName < p[uint(j)].encName } func (p sfiSortedByEncName) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } const structFieldNodeNumToCache = 4 type structFieldNodeCache struct { rv [structFieldNodeNumToCache]reflect.Value idx [structFieldNodeNumToCache]uint32 num uint8 } func (x *structFieldNodeCache) get(key uint32) (fv reflect.Value, valid bool) { for i, k := range &x.idx { if uint8(i) == x.num { return // break } if key == k { return x.rv[i], true } } return } func (x *structFieldNodeCache) tryAdd(fv reflect.Value, key uint32) { if x.num < structFieldNodeNumToCache { x.rv[x.num] = fv x.idx[x.num] = key x.num++ return } } type structFieldNode struct { v reflect.Value cache2 structFieldNodeCache cache3 structFieldNodeCache update bool } func (x *structFieldNode) field(si *structFieldInfo) (fv reflect.Value) { // return si.fieldval(x.v, x.update) // Note: we only cache if nis=2 or nis=3 i.e. up to 2 levels of embedding // This mostly saves us time on the repeated calls to v.Elem, v.Field, etc. var valid bool switch si.nis { case 1: fv = x.v.Field(int(si.is[0])) case 2: if fv, valid = x.cache2.get(uint32(si.is[0])); valid { fv = fv.Field(int(si.is[1])) return } fv = x.v.Field(int(si.is[0])) if fv, valid = baseStructRv(fv, x.update); !valid { return } x.cache2.tryAdd(fv, uint32(si.is[0])) fv = fv.Field(int(si.is[1])) case 3: var key uint32 = uint32(si.is[0])<<16 | uint32(si.is[1]) if fv, valid = x.cache3.get(key); valid { fv = fv.Field(int(si.is[2])) return } fv = x.v.Field(int(si.is[0])) if fv, valid = baseStructRv(fv, x.update); !valid { return } fv = fv.Field(int(si.is[1])) if fv, valid = baseStructRv(fv, x.update); !valid { return } x.cache3.tryAdd(fv, key) fv = fv.Field(int(si.is[2])) default: fv, _ = si.field(x.v, x.update) } return } func baseStructRv(v reflect.Value, update bool) (v2 reflect.Value, valid bool) { for v.Kind() == reflect.Ptr { if v.IsNil() { if !update { return } v.Set(reflect.New(v.Type().Elem())) } v = v.Elem() } return v, true } type typeInfoFlag uint8 const ( typeInfoFlagComparable = 1 << iota typeInfoFlagIsZeroer typeInfoFlagIsZeroerPtr ) // typeInfo keeps static (non-changing readonly)information // about each (non-ptr) type referenced in the encode/decode sequence. // // During an encode/decode sequence, we work as below: // - If base is a built in type, en/decode base value // - If base is registered as an extension, en/decode base value // - If type is binary(M/Unm)arshaler, call Binary(M/Unm)arshal method // - If type is text(M/Unm)arshaler, call Text(M/Unm)arshal method // - Else decode appropriately based on the reflect.Kind type typeInfo struct { rt reflect.Type elem reflect.Type pkgpath string rtid uintptr // rv0 reflect.Value // saved zero value, used if immutableKind numMeth uint16 // number of methods kind uint8 chandir uint8 anyOmitEmpty bool // true if a struct, and any of the fields are tagged "omitempty" toArray bool // whether this (struct) type should be encoded as an array keyType valueType // if struct, how is the field name stored in a stream? default is string mbs bool // base type (T or *T) is a MapBySlice // ---- cpu cache line boundary? sfiSort []*structFieldInfo // sorted. Used when enc/dec struct to map. sfiSrc []*structFieldInfo // unsorted. Used when enc/dec struct to array. key reflect.Type // ---- cpu cache line boundary? // sfis []structFieldInfo // all sfi, in src order, as created. sfiNamesSort []byte // all names, with indexes into the sfiSort // format of marshal type fields below: [btj][mu]p? OR csp? bm bool // T is a binaryMarshaler bmp bool // *T is a binaryMarshaler bu bool // T is a binaryUnmarshaler bup bool // *T is a binaryUnmarshaler tm bool // T is a textMarshaler tmp bool // *T is a textMarshaler tu bool // T is a textUnmarshaler tup bool // *T is a textUnmarshaler jm bool // T is a jsonMarshaler jmp bool // *T is a jsonMarshaler ju bool // T is a jsonUnmarshaler jup bool // *T is a jsonUnmarshaler cs bool // T is a Selfer csp bool // *T is a Selfer mf bool // T is a MissingFielder mfp bool // *T is a MissingFielder // other flags, with individual bits representing if set. flags typeInfoFlag infoFieldOmitempty bool // _ [6]byte // padding // _ [2]uint64 // padding } func (ti *typeInfo) isFlag(f typeInfoFlag) bool { return ti.flags&f != 0 } func (ti *typeInfo) indexForEncName(name []byte) (index int16) { var sn []byte if len(name)+2 <= 32 { var buf [32]byte // should not escape to heap sn = buf[:len(name)+2] } else { sn = make([]byte, len(name)+2) } copy(sn[1:], name) sn[0], sn[len(sn)-1] = tiSep2(name), 0xff j := bytes.Index(ti.sfiNamesSort, sn) if j < 0 { return -1 } index = int16(uint16(ti.sfiNamesSort[j+len(sn)+1]) | uint16(ti.sfiNamesSort[j+len(sn)])<<8) return } type rtid2ti struct { rtid uintptr ti *typeInfo } // TypeInfos caches typeInfo for each type on first inspection. // // It is configured with a set of tag keys, which are used to get // configuration for the type. type TypeInfos struct { // infos: formerly map[uintptr]*typeInfo, now *[]rtid2ti, 2 words expected infos atomicTypeInfoSlice mu sync.Mutex _ uint64 // padding (cache-aligned) tags []string _ uint64 // padding (cache-aligned) } // NewTypeInfos creates a TypeInfos given a set of struct tags keys. // // This allows users customize the struct tag keys which contain configuration // of their types. func NewTypeInfos(tags []string) *TypeInfos { return &TypeInfos{tags: tags} } func (x *TypeInfos) structTag(t reflect.StructTag) (s string) { // check for tags: codec, json, in that order. // this allows seamless support for many configured structs. for _, x := range x.tags { s = t.Get(x) if s != "" { return s } } return } func findTypeInfo(s []rtid2ti, rtid uintptr) (i uint, ti *typeInfo) { // binary search. adapted from sort/search.go. // Note: we use goto (instead of for loop) so this can be inlined. // if sp == nil { // return -1, nil // } // s := *sp // h, i, j := 0, 0, len(s) var h uint // var h, i uint var j = uint(len(s)) LOOP: if i < j { h = i + (j-i)/2 if s[h].rtid < rtid { i = h + 1 } else { j = h } goto LOOP } if i < uint(len(s)) && s[i].rtid == rtid { ti = s[i].ti } return } func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) { sp := x.infos.load() if sp != nil { _, pti = findTypeInfo(sp, rtid) if pti != nil { return } } rk := rt.Kind() if rk == reflect.Ptr { // || (rk == reflect.Interface && rtid != intfTypId) { panicv.errorf("invalid kind passed to TypeInfos.get: %v - %v", rk, rt) } // do not hold lock while computing this. // it may lead to duplication, but that's ok. ti := typeInfo{ rt: rt, rtid: rtid, kind: uint8(rk), pkgpath: rt.PkgPath(), keyType: valueTypeString, // default it - so it's never 0 } // ti.rv0 = reflect.Zero(rt) // ti.comparable = rt.Comparable() ti.numMeth = uint16(rt.NumMethod()) ti.bm, ti.bmp = implIntf(rt, binaryMarshalerTyp) ti.bu, ti.bup = implIntf(rt, binaryUnmarshalerTyp) ti.tm, ti.tmp = implIntf(rt, textMarshalerTyp) ti.tu, ti.tup = implIntf(rt, textUnmarshalerTyp) ti.jm, ti.jmp = implIntf(rt, jsonMarshalerTyp) ti.ju, ti.jup = implIntf(rt, jsonUnmarshalerTyp) ti.cs, ti.csp = implIntf(rt, selferTyp) ti.mf, ti.mfp = implIntf(rt, missingFielderTyp) b1, b2 := implIntf(rt, iszeroTyp) if b1 { ti.flags |= typeInfoFlagIsZeroer } if b2 { ti.flags |= typeInfoFlagIsZeroerPtr } if rt.Comparable() { ti.flags |= typeInfoFlagComparable } switch rk { case reflect.Struct: var omitEmpty bool if f, ok := rt.FieldByName(structInfoFieldName); ok { ti.toArray, omitEmpty, ti.keyType = parseStructInfo(x.structTag(f.Tag)) ti.infoFieldOmitempty = omitEmpty } else { ti.keyType = valueTypeString } pp, pi := &pool.tiload, pool.tiload.Get() // pool.tiLoad() pv := pi.(*typeInfoLoadArray) pv.etypes[0] = ti.rtid // vv := typeInfoLoad{pv.fNames[:0], pv.encNames[:0], pv.etypes[:1], pv.sfis[:0]} vv := typeInfoLoad{pv.etypes[:1], pv.sfis[:0]} x.rget(rt, rtid, omitEmpty, nil, &vv) // ti.sfis = vv.sfis ti.sfiSrc, ti.sfiSort, ti.sfiNamesSort, ti.anyOmitEmpty = rgetResolveSFI(rt, vv.sfis, pv) pp.Put(pi) case reflect.Map: ti.elem = rt.Elem() ti.key = rt.Key() case reflect.Slice: ti.mbs, _ = implIntf(rt, mapBySliceTyp) ti.elem = rt.Elem() case reflect.Chan: ti.elem = rt.Elem() ti.chandir = uint8(rt.ChanDir()) case reflect.Array, reflect.Ptr: ti.elem = rt.Elem() } // sfi = sfiSrc x.mu.Lock() sp = x.infos.load() var sp2 []rtid2ti if sp == nil { pti = &ti sp2 = []rtid2ti{{rtid, pti}} x.infos.store(sp2) } else { var idx uint idx, pti = findTypeInfo(sp, rtid) if pti == nil { pti = &ti sp2 = make([]rtid2ti, len(sp)+1) copy(sp2, sp[:idx]) copy(sp2[idx+1:], sp[idx:]) sp2[idx] = rtid2ti{rtid, pti} x.infos.store(sp2) } } x.mu.Unlock() return } func (x *TypeInfos) rget(rt reflect.Type, rtid uintptr, omitEmpty bool, indexstack []uint16, pv *typeInfoLoad) { // Read up fields and store how to access the value. // // It uses go's rules for message selectors, // which say that the field with the shallowest depth is selected. // // Note: we consciously use slices, not a map, to simulate a set. // Typically, types have < 16 fields, // and iteration using equals is faster than maps there flen := rt.NumField() if flen > (1< %v fields are not supported - has %v fields", (1<= 0; i-- { // bounds-check elimination b := si.encName[i] if (b >= '0' && b <= '9') || (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') { continue } si.encNameAsciiAlphaNum = false break } si.fieldName = f.Name si.flagSet(structFieldInfoFlagReady) // pv.encNames = append(pv.encNames, si.encName) // si.ikind = int(f.Type.Kind()) if len(indexstack) > maxLevelsEmbedding-1 { panicv.errorf("codec: only supports up to %v depth of embedding - type has %v depth", maxLevelsEmbedding-1, len(indexstack)) } si.nis = uint8(len(indexstack)) + 1 copy(si.is[:], indexstack) si.is[len(indexstack)] = j if omitEmpty { si.flagSet(structFieldInfoFlagOmitEmpty) } pv.sfis = append(pv.sfis, si) } } func tiSep(name string) uint8 { // (xn[0]%64) // (between 192-255 - outside ascii BMP) // return 0xfe - (name[0] & 63) // return 0xfe - (name[0] & 63) - uint8(len(name)) // return 0xfe - (name[0] & 63) - uint8(len(name)&63) // return ((0xfe - (name[0] & 63)) & 0xf8) | (uint8(len(name) & 0x07)) return 0xfe - (name[0] & 63) - uint8(len(name)&63) } func tiSep2(name []byte) uint8 { return 0xfe - (name[0] & 63) - uint8(len(name)&63) } // resolves the struct field info got from a call to rget. // Returns a trimmed, unsorted and sorted []*structFieldInfo. func rgetResolveSFI(rt reflect.Type, x []structFieldInfo, pv *typeInfoLoadArray) ( y, z []*structFieldInfo, ss []byte, anyOmitEmpty bool) { sa := pv.sfiidx[:0] sn := pv.b[:] n := len(x) var xn string var ui uint16 var sep byte for i := range x { ui = uint16(i) xn = x[i].encName // fieldName or encName? use encName for now. if len(xn)+2 > cap(sn) { sn = make([]byte, len(xn)+2) } else { sn = sn[:len(xn)+2] } // use a custom sep, so that misses are less frequent, // since the sep (first char in search) is as unique as first char in field name. sep = tiSep(xn) sn[0], sn[len(sn)-1] = sep, 0xff copy(sn[1:], xn) j := bytes.Index(sa, sn) if j == -1 { sa = append(sa, sep) sa = append(sa, xn...) sa = append(sa, 0xff, byte(ui>>8), byte(ui)) } else { index := uint16(sa[j+len(sn)+1]) | uint16(sa[j+len(sn)])<<8 // one of them must be cleared (reset to nil), // and the index updated appropriately i2clear := ui // index to be cleared if x[i].nis < x[index].nis { // this one is shallower // update the index to point to this later one. sa[j+len(sn)], sa[j+len(sn)+1] = byte(ui>>8), byte(ui) // clear the earlier one, as this later one is shallower. i2clear = index } if x[i2clear].ready() { x[i2clear].flagClr(structFieldInfoFlagReady) n-- } } } var w []structFieldInfo sharingArray := len(x) <= typeInfoLoadArraySfisLen // sharing array with typeInfoLoadArray if sharingArray { w = make([]structFieldInfo, n) } // remove all the nils (non-ready) y = make([]*structFieldInfo, n) n = 0 var sslen int for i := range x { if !x[i].ready() { continue } if !anyOmitEmpty && x[i].omitEmpty() { anyOmitEmpty = true } if sharingArray { w[n] = x[i] y[n] = &w[n] } else { y[n] = &x[i] } sslen = sslen + len(x[i].encName) + 4 n++ } if n != len(y) { panicv.errorf("failure reading struct %v - expecting %d of %d valid fields, got %d", rt, len(y), len(x), n) } z = make([]*structFieldInfo, len(y)) copy(z, y) sort.Sort(sfiSortedByEncName(z)) sharingArray = len(sa) <= typeInfoLoadArraySfiidxLen if sharingArray { ss = make([]byte, 0, sslen) } else { ss = sa[:0] // reuse the newly made sa array if necessary } for i := range z { xn = z[i].encName sep = tiSep(xn) ui = uint16(i) ss = append(ss, sep) ss = append(ss, xn...) ss = append(ss, 0xff, byte(ui>>8), byte(ui)) } return } func implIntf(rt, iTyp reflect.Type) (base bool, indir bool) { return rt.Implements(iTyp), reflect.PtrTo(rt).Implements(iTyp) } // isEmptyStruct is only called from isEmptyValue, and checks if a struct is empty: // - does it implement IsZero() bool // - is it comparable, and can i compare directly using == // - if checkStruct, then walk through the encodable fields // and check if they are empty or not. func isEmptyStruct(v reflect.Value, tinfos *TypeInfos, deref, checkStruct bool) bool { // v is a struct kind - no need to check again. // We only check isZero on a struct kind, to reduce the amount of times // that we lookup the rtid and typeInfo for each type as we walk the tree. vt := v.Type() rtid := rt2id(vt) if tinfos == nil { tinfos = defTypeInfos } ti := tinfos.get(rtid, vt) if ti.rtid == timeTypId { return rv2i(v).(time.Time).IsZero() } if ti.isFlag(typeInfoFlagIsZeroerPtr) && v.CanAddr() { return rv2i(v.Addr()).(isZeroer).IsZero() } if ti.isFlag(typeInfoFlagIsZeroer) { return rv2i(v).(isZeroer).IsZero() } if ti.isFlag(typeInfoFlagComparable) { return rv2i(v) == rv2i(reflect.Zero(vt)) } if !checkStruct { return false } // We only care about what we can encode/decode, // so that is what we use to check omitEmpty. for _, si := range ti.sfiSrc { sfv, valid := si.field(v, false) if valid && !isEmptyValue(sfv, tinfos, deref, checkStruct) { return false } } return true } // func roundFloat(x float64) float64 { // t := math.Trunc(x) // if math.Abs(x-t) >= 0.5 { // return t + math.Copysign(1, x) // } // return t // } func panicToErr(h errDecorator, err *error) { // Note: This method MUST be called directly from defer i.e. defer panicToErr ... // else it seems the recover is not fully handled if recoverPanicToErr { if x := recover(); x != nil { // fmt.Printf("panic'ing with: %v\n", x) // debug.PrintStack() panicValToErr(h, x, err) } } } func panicValToErr(h errDecorator, v interface{}, err *error) { switch xerr := v.(type) { case nil: case error: switch xerr { case nil: case io.EOF, io.ErrUnexpectedEOF, errEncoderNotInitialized, errDecoderNotInitialized: // treat as special (bubble up) *err = xerr default: h.wrapErr(xerr, err) } case string: if xerr != "" { h.wrapErr(xerr, err) } case fmt.Stringer: if xerr != nil { h.wrapErr(xerr, err) } default: h.wrapErr(v, err) } } func isImmutableKind(k reflect.Kind) (v bool) { // return immutableKindsSet[k] // since we know reflect.Kind is in range 0..31, then use the k%32 == k constraint return immutableKindsSet[k%reflect.Kind(len(immutableKindsSet))] // bounds-check-elimination } // ---- type codecFnInfo struct { ti *typeInfo xfFn Ext xfTag uint64 seq seqType addrD bool addrF bool // if addrD, this says whether decode function can take a value or a ptr addrE bool } // codecFn encapsulates the captured variables and the encode function. // This way, we only do some calculations one times, and pass to the // code block that should be called (encapsulated in a function) // instead of executing the checks every time. type codecFn struct { i codecFnInfo fe func(*Encoder, *codecFnInfo, reflect.Value) fd func(*Decoder, *codecFnInfo, reflect.Value) _ [1]uint64 // padding (cache-aligned) } type codecRtidFn struct { rtid uintptr fn *codecFn } // ---- // these "checkOverflow" functions must be inlinable, and not call anybody. // Overflow means that the value cannot be represented without wrapping/overflow. // Overflow=false does not mean that the value can be represented without losing precision // (especially for floating point). type checkOverflow struct{} // func (checkOverflow) Float16(f float64) (overflow bool) { // panicv.errorf("unimplemented") // if f < 0 { // f = -f // } // return math.MaxFloat32 < f && f <= math.MaxFloat64 // } func (checkOverflow) Float32(v float64) (overflow bool) { if v < 0 { v = -v } return math.MaxFloat32 < v && v <= math.MaxFloat64 } func (checkOverflow) Uint(v uint64, bitsize uint8) (overflow bool) { if bitsize == 0 || bitsize >= 64 || v == 0 { return } if trunc := (v << (64 - bitsize)) >> (64 - bitsize); v != trunc { overflow = true } return } func (checkOverflow) Int(v int64, bitsize uint8) (overflow bool) { if bitsize == 0 || bitsize >= 64 || v == 0 { return } if trunc := (v << (64 - bitsize)) >> (64 - bitsize); v != trunc { overflow = true } return } func (checkOverflow) SignedInt(v uint64) (overflow bool) { //e.g. -127 to 128 for int8 pos := (v >> 63) == 0 ui2 := v & 0x7fffffffffffffff if pos { if ui2 > math.MaxInt64 { overflow = true } } else { if ui2 > math.MaxInt64-1 { overflow = true } } return } func (x checkOverflow) Float32V(v float64) float64 { if x.Float32(v) { panicv.errorf("float32 overflow: %v", v) } return v } func (x checkOverflow) UintV(v uint64, bitsize uint8) uint64 { if x.Uint(v, bitsize) { panicv.errorf("uint64 overflow: %v", v) } return v } func (x checkOverflow) IntV(v int64, bitsize uint8) int64 { if x.Int(v, bitsize) { panicv.errorf("int64 overflow: %v", v) } return v } func (x checkOverflow) SignedIntV(v uint64) int64 { if x.SignedInt(v) { panicv.errorf("uint64 to int64 overflow: %v", v) } return int64(v) } // ------------------ FLOATING POINT ----------------- func isNaN64(f float64) bool { return f != f } func isNaN32(f float32) bool { return f != f } func abs32(f float32) float32 { return math.Float32frombits(math.Float32bits(f) &^ (1 << 31)) } // Per go spec, floats are represented in memory as // IEEE single or double precision floating point values. // // We also looked at the source for stdlib math/modf.go, // reviewed https://github.com/chewxy/math32 // and read wikipedia documents describing the formats. // // It became clear that we could easily look at the bits to determine // whether any fraction exists. // // This is all we need for now. func noFrac64(f float64) (v bool) { x := math.Float64bits(f) e := uint64(x>>52)&0x7FF - 1023 // uint(x>>shift)&mask - bias // clear top 12+e bits, the integer part; if the rest is 0, then no fraction. if e < 52 { // return x&((1<<64-1)>>(12+e)) == 0 return x<<(12+e) == 0 } return } func noFrac32(f float32) (v bool) { x := math.Float32bits(f) e := uint32(x>>23)&0xFF - 127 // uint(x>>shift)&mask - bias // clear top 9+e bits, the integer part; if the rest is 0, then no fraction. if e < 23 { // return x&((1<<32-1)>>(9+e)) == 0 return x<<(9+e) == 0 } return } // func noFrac(f float64) bool { // _, frac := math.Modf(float64(f)) // return frac == 0 // } // ----------------------- type ioFlusher interface { Flush() error } type ioPeeker interface { Peek(int) ([]byte, error) } type ioBuffered interface { Buffered() int } // ----------------------- type sfiRv struct { v *structFieldInfo r reflect.Value } // ----------------- type set []uintptr func (s *set) add(v uintptr) (exists bool) { // e.ci is always nil, or len >= 1 x := *s // defer func() { xdebugf("set.add: len: %d", len(x)) }() if x == nil { x = make([]uintptr, 1, 8) x[0] = v *s = x return } // typically, length will be 1. make this perform. if len(x) == 1 { if j := x[0]; j == 0 { x[0] = v } else if j == v { exists = true } else { x = append(x, v) *s = x } return } // check if it exists for _, j := range x { if j == v { exists = true return } } // try to replace a "deleted" slot for i, j := range x { if j == 0 { x[i] = v return } } // if unable to replace deleted slot, just append it. x = append(x, v) *s = x return } func (s *set) remove(v uintptr) (exists bool) { x := *s if len(x) == 0 { return } if len(x) == 1 { if x[0] == v { x[0] = 0 } return } for i, j := range x { if j == v { exists = true x[i] = 0 // set it to 0, as way to delete it. // copy(x[i:], x[i+1:]) // x = x[:len(x)-1] return } } return } // ------ // bitset types are better than [256]bool, because they permit the whole // bitset array being on a single cache line and use less memory. // // Also, since pos is a byte (0-255), there's no bounds checks on indexing (cheap). // // We previously had bitset128 [16]byte, and bitset32 [4]byte, but those introduces // bounds checking, so we discarded them, and everyone uses bitset256. // // given x > 0 and n > 0 and x is exactly 2^n, then pos/x === pos>>n AND pos%x === pos&(x-1). // consequently, pos/32 === pos>>5, pos/16 === pos>>4, pos/8 === pos>>3, pos%8 == pos&7 type bitset256 [32]byte func (x *bitset256) isset(pos byte) bool { return x[pos>>3]&(1<<(pos&7)) != 0 } // func (x *bitset256) issetv(pos byte) byte { // return x[pos>>3] & (1 << (pos & 7)) // } func (x *bitset256) set(pos byte) { x[pos>>3] |= (1 << (pos & 7)) } // func (x *bitset256) unset(pos byte) { // x[pos>>3] &^= (1 << (pos & 7)) // } // type bit2set256 [64]byte // func (x *bit2set256) set(pos byte, v1, v2 bool) { // var pos2 uint8 = (pos & 3) << 1 // returning 0, 2, 4 or 6 // if v1 { // x[pos>>2] |= 1 << (pos2 + 1) // } // if v2 { // x[pos>>2] |= 1 << pos2 // } // } // func (x *bit2set256) get(pos byte) uint8 { // var pos2 uint8 = (pos & 3) << 1 // returning 0, 2, 4 or 6 // return x[pos>>2] << (6 - pos2) >> 6 // 11000000 -> 00000011 // } // ------------ type pooler struct { // function-scoped pooled resources tiload sync.Pool // for type info loading sfiRv8, sfiRv16, sfiRv32, sfiRv64, sfiRv128 sync.Pool // for struct encoding // lifetime-scoped pooled resources // dn sync.Pool // for decNaked buf1k, buf2k, buf4k, buf8k, buf16k, buf32k, buf64k sync.Pool // for [N]byte } func (p *pooler) init() { p.tiload.New = func() interface{} { return new(typeInfoLoadArray) } p.sfiRv8.New = func() interface{} { return new([8]sfiRv) } p.sfiRv16.New = func() interface{} { return new([16]sfiRv) } p.sfiRv32.New = func() interface{} { return new([32]sfiRv) } p.sfiRv64.New = func() interface{} { return new([64]sfiRv) } p.sfiRv128.New = func() interface{} { return new([128]sfiRv) } // p.dn.New = func() interface{} { x := new(decNaked); x.init(); return x } p.buf1k.New = func() interface{} { return new([1 * 1024]byte) } p.buf2k.New = func() interface{} { return new([2 * 1024]byte) } p.buf4k.New = func() interface{} { return new([4 * 1024]byte) } p.buf8k.New = func() interface{} { return new([8 * 1024]byte) } p.buf16k.New = func() interface{} { return new([16 * 1024]byte) } p.buf32k.New = func() interface{} { return new([32 * 1024]byte) } p.buf64k.New = func() interface{} { return new([64 * 1024]byte) } } // func (p *pooler) sfiRv8() (sp *sync.Pool, v interface{}) { // return &p.strRv8, p.strRv8.Get() // } // func (p *pooler) sfiRv16() (sp *sync.Pool, v interface{}) { // return &p.strRv16, p.strRv16.Get() // } // func (p *pooler) sfiRv32() (sp *sync.Pool, v interface{}) { // return &p.strRv32, p.strRv32.Get() // } // func (p *pooler) sfiRv64() (sp *sync.Pool, v interface{}) { // return &p.strRv64, p.strRv64.Get() // } // func (p *pooler) sfiRv128() (sp *sync.Pool, v interface{}) { // return &p.strRv128, p.strRv128.Get() // } // func (p *pooler) bytes1k() (sp *sync.Pool, v interface{}) { // return &p.buf1k, p.buf1k.Get() // } // func (p *pooler) bytes2k() (sp *sync.Pool, v interface{}) { // return &p.buf2k, p.buf2k.Get() // } // func (p *pooler) bytes4k() (sp *sync.Pool, v interface{}) { // return &p.buf4k, p.buf4k.Get() // } // func (p *pooler) bytes8k() (sp *sync.Pool, v interface{}) { // return &p.buf8k, p.buf8k.Get() // } // func (p *pooler) bytes16k() (sp *sync.Pool, v interface{}) { // return &p.buf16k, p.buf16k.Get() // } // func (p *pooler) bytes32k() (sp *sync.Pool, v interface{}) { // return &p.buf32k, p.buf32k.Get() // } // func (p *pooler) bytes64k() (sp *sync.Pool, v interface{}) { // return &p.buf64k, p.buf64k.Get() // } // func (p *pooler) tiLoad() (sp *sync.Pool, v interface{}) { // return &p.tiload, p.tiload.Get() // } // func (p *pooler) decNaked() (sp *sync.Pool, v interface{}) { // return &p.dn, p.dn.Get() // } // func (p *pooler) decNaked() (v *decNaked, f func(*decNaked) ) { // sp := &(p.dn) // vv := sp.Get() // return vv.(*decNaked), func(x *decNaked) { sp.Put(vv) } // } // func (p *pooler) decNakedGet() (v interface{}) { // return p.dn.Get() // } // func (p *pooler) tiLoadGet() (v interface{}) { // return p.tiload.Get() // } // func (p *pooler) decNakedPut(v interface{}) { // p.dn.Put(v) // } // func (p *pooler) tiLoadPut(v interface{}) { // p.tiload.Put(v) // } // ---------------------------------------------------- type panicHdl struct{} func (panicHdl) errorv(err error) { if err != nil { panic(err) } } func (panicHdl) errorstr(message string) { if message != "" { panic(message) } } func (panicHdl) errorf(format string, params ...interface{}) { if format == "" { } else if len(params) == 0 { panic(format) } else { panic(fmt.Sprintf(format, params...)) } } // ---------------------------------------------------- type errDecorator interface { wrapErr(in interface{}, out *error) } type errDecoratorDef struct{} func (errDecoratorDef) wrapErr(v interface{}, e *error) { *e = fmt.Errorf("%v", v) } // ---------------------------------------------------- type must struct{} func (must) String(s string, err error) string { if err != nil { panicv.errorv(err) } return s } func (must) Int(s int64, err error) int64 { if err != nil { panicv.errorv(err) } return s } func (must) Uint(s uint64, err error) uint64 { if err != nil { panicv.errorv(err) } return s } func (must) Float(s float64, err error) float64 { if err != nil { panicv.errorv(err) } return s } // ------------------- type bytesBufPooler struct { pool *sync.Pool poolbuf interface{} } func (z *bytesBufPooler) end() { if z.pool != nil { z.pool.Put(z.poolbuf) z.pool, z.poolbuf = nil, nil } } func (z *bytesBufPooler) get(bufsize int) (buf []byte) { // ensure an end is called first (if necessary) if z.pool != nil { z.pool.Put(z.poolbuf) z.pool, z.poolbuf = nil, nil } // // Try to use binary search. // // This is not optimal, as most folks select 1k or 2k buffers // // so a linear search is better (sequence of if/else blocks) // if bufsize < 1 { // bufsize = 0 // } else { // bufsize-- // bufsize /= 1024 // } // switch bufsize { // case 0: // z.pool, z.poolbuf = pool.bytes1k() // buf = z.poolbuf.(*[1 * 1024]byte)[:] // case 1: // z.pool, z.poolbuf = pool.bytes2k() // buf = z.poolbuf.(*[2 * 1024]byte)[:] // case 2, 3: // z.pool, z.poolbuf = pool.bytes4k() // buf = z.poolbuf.(*[4 * 1024]byte)[:] // case 4, 5, 6, 7: // z.pool, z.poolbuf = pool.bytes8k() // buf = z.poolbuf.(*[8 * 1024]byte)[:] // case 8, 9, 10, 11, 12, 13, 14, 15: // z.pool, z.poolbuf = pool.bytes16k() // buf = z.poolbuf.(*[16 * 1024]byte)[:] // case 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31: // z.pool, z.poolbuf = pool.bytes32k() // buf = z.poolbuf.(*[32 * 1024]byte)[:] // default: // z.pool, z.poolbuf = pool.bytes64k() // buf = z.poolbuf.(*[64 * 1024]byte)[:] // } // return if bufsize <= 1*1024 { z.pool, z.poolbuf = &pool.buf1k, pool.buf1k.Get() // pool.bytes1k() buf = z.poolbuf.(*[1 * 1024]byte)[:] } else if bufsize <= 2*1024 { z.pool, z.poolbuf = &pool.buf2k, pool.buf2k.Get() // pool.bytes2k() buf = z.poolbuf.(*[2 * 1024]byte)[:] } else if bufsize <= 4*1024 { z.pool, z.poolbuf = &pool.buf4k, pool.buf4k.Get() // pool.bytes4k() buf = z.poolbuf.(*[4 * 1024]byte)[:] } else if bufsize <= 8*1024 { z.pool, z.poolbuf = &pool.buf8k, pool.buf8k.Get() // pool.bytes8k() buf = z.poolbuf.(*[8 * 1024]byte)[:] } else if bufsize <= 16*1024 { z.pool, z.poolbuf = &pool.buf16k, pool.buf16k.Get() // pool.bytes16k() buf = z.poolbuf.(*[16 * 1024]byte)[:] } else if bufsize <= 32*1024 { z.pool, z.poolbuf = &pool.buf32k, pool.buf32k.Get() // pool.bytes32k() buf = z.poolbuf.(*[32 * 1024]byte)[:] } else { z.pool, z.poolbuf = &pool.buf64k, pool.buf64k.Get() // pool.bytes64k() buf = z.poolbuf.(*[64 * 1024]byte)[:] } return } // ---------------- type sfiRvPooler struct { pool *sync.Pool poolv interface{} } func (z *sfiRvPooler) end() { if z.pool != nil { z.pool.Put(z.poolv) z.pool, z.poolv = nil, nil } } func (z *sfiRvPooler) get(newlen int) (fkvs []sfiRv) { if newlen < 0 { // bounds-check-elimination // cannot happen // here for bounds-check-elimination } else if newlen <= 8 { z.pool, z.poolv = &pool.sfiRv8, pool.sfiRv8.Get() // pool.sfiRv8() fkvs = z.poolv.(*[8]sfiRv)[:newlen] } else if newlen <= 16 { z.pool, z.poolv = &pool.sfiRv16, pool.sfiRv16.Get() // pool.sfiRv16() fkvs = z.poolv.(*[16]sfiRv)[:newlen] } else if newlen <= 32 { z.pool, z.poolv = &pool.sfiRv32, pool.sfiRv32.Get() // pool.sfiRv32() fkvs = z.poolv.(*[32]sfiRv)[:newlen] } else if newlen <= 64 { z.pool, z.poolv = &pool.sfiRv64, pool.sfiRv64.Get() // pool.sfiRv64() fkvs = z.poolv.(*[64]sfiRv)[:newlen] } else if newlen <= 128 { z.pool, z.poolv = &pool.sfiRv128, pool.sfiRv128.Get() // pool.sfiRv128() fkvs = z.poolv.(*[128]sfiRv)[:newlen] } else { fkvs = make([]sfiRv, newlen) } return } // xdebugf printf. the message in red on the terminal. // Use it in place of fmt.Printf (which it calls internally) func xdebugf(pattern string, args ...interface{}) { var delim string if len(pattern) > 0 && pattern[len(pattern)-1] != '\n' { delim = "\n" } fmt.Printf("\033[1;31m"+pattern+delim+"\033[0m", args...) } // xdebug2f printf. the message in blue on the terminal. // Use it in place of fmt.Printf (which it calls internally) func xdebug2f(pattern string, args ...interface{}) { var delim string if len(pattern) > 0 && pattern[len(pattern)-1] != '\n' { delim = "\n" } fmt.Printf("\033[1;34m"+pattern+delim+"\033[0m", args...) } // func isImmutableKind(k reflect.Kind) (v bool) { // return false || // k == reflect.Int || // k == reflect.Int8 || // k == reflect.Int16 || // k == reflect.Int32 || // k == reflect.Int64 || // k == reflect.Uint || // k == reflect.Uint8 || // k == reflect.Uint16 || // k == reflect.Uint32 || // k == reflect.Uint64 || // k == reflect.Uintptr || // k == reflect.Float32 || // k == reflect.Float64 || // k == reflect.Bool || // k == reflect.String // } // func timeLocUTCName(tzint int16) string { // if tzint == 0 { // return "UTC" // } // var tzname = []byte("UTC+00:00") // //tzname := fmt.Sprintf("UTC%s%02d:%02d", tzsign, tz/60, tz%60) //perf issue using Sprintf.. inline below. // //tzhr, tzmin := tz/60, tz%60 //faster if u convert to int first // var tzhr, tzmin int16 // if tzint < 0 { // tzname[3] = '-' // (TODO: verify. this works here) // tzhr, tzmin = -tzint/60, (-tzint)%60 // } else { // tzhr, tzmin = tzint/60, tzint%60 // } // tzname[4] = timeDigits[tzhr/10] // tzname[5] = timeDigits[tzhr%10] // tzname[7] = timeDigits[tzmin/10] // tzname[8] = timeDigits[tzmin%10] // return string(tzname) // //return time.FixedZone(string(tzname), int(tzint)*60) // } ================================================ FILE: vendor/github.com/ugorji/go/codec/helper_internal.go ================================================ // Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. package codec // All non-std package dependencies live in this file, // so porting to different environment is easy (just update functions). func pruneSignExt(v []byte, pos bool) (n int) { if len(v) < 2 { } else if pos && v[0] == 0 { for ; v[n] == 0 && n+1 < len(v) && (v[n+1]&(1<<7) == 0); n++ { } } else if !pos && v[0] == 0xff { for ; v[n] == 0xff && n+1 < len(v) && (v[n+1]&(1<<7) != 0); n++ { } } return } // validate that this function is correct ... // culled from OGRE (Object-Oriented Graphics Rendering Engine) // function: halfToFloatI (http://stderr.org/doc/ogre-doc/api/OgreBitwise_8h-source.html) func halfFloatToFloatBits(yy uint16) (d uint32) { y := uint32(yy) s := (y >> 15) & 0x01 e := (y >> 10) & 0x1f m := y & 0x03ff if e == 0 { if m == 0 { // plu or minus 0 return s << 31 } // Denormalized number -- renormalize it for (m & 0x00000400) == 0 { m <<= 1 e -= 1 } e += 1 const zz uint32 = 0x0400 m &= ^zz } else if e == 31 { if m == 0 { // Inf return (s << 31) | 0x7f800000 } return (s << 31) | 0x7f800000 | (m << 13) // NaN } e = e + (127 - 15) m = m << 13 return (s << 31) | (e << 23) | m } // GrowCap will return a new capacity for a slice, given the following: // - oldCap: current capacity // - unit: in-memory size of an element // - num: number of elements to add func growCap(oldCap, unit, num int) (newCap int) { // appendslice logic (if cap < 1024, *2, else *1.25): // leads to many copy calls, especially when copying bytes. // bytes.Buffer model (2*cap + n): much better for bytes. // smarter way is to take the byte-size of the appended element(type) into account // maintain 3 thresholds: // t1: if cap <= t1, newcap = 2x // t2: if cap <= t2, newcap = 1.75x // t3: if cap <= t3, newcap = 1.5x // else newcap = 1.25x // // t1, t2, t3 >= 1024 always. // i.e. if unit size >= 16, then always do 2x or 1.25x (ie t1, t2, t3 are all same) // // With this, appending for bytes increase by: // 100% up to 4K // 75% up to 8K // 50% up to 16K // 25% beyond that // unit can be 0 e.g. for struct{}{}; handle that appropriately var t1, t2, t3 int // thresholds if unit <= 1 { t1, t2, t3 = 4*1024, 8*1024, 16*1024 } else if unit < 16 { t3 = 16 / unit * 1024 t1 = t3 * 1 / 4 t2 = t3 * 2 / 4 } else { t1, t2, t3 = 1024, 1024, 1024 } var x int // temporary variable // x is multiplier here: one of 5, 6, 7 or 8; incr of 25%, 50%, 75% or 100% respectively if oldCap <= t1 { // [0,t1] x = 8 } else if oldCap > t3 { // (t3,infinity] x = 5 } else if oldCap <= t2 { // (t1,t2] x = 7 } else { // (t2,t3] x = 6 } newCap = x * oldCap / 4 if num > 0 { newCap += num } // ensure newCap is a multiple of 64 (if it is > 64) or 16. if newCap > 64 { if x = newCap % 64; x != 0 { x = newCap / 64 newCap = 64 * (x + 1) } } else { if x = newCap % 16; x != 0 { x = newCap / 16 newCap = 16 * (x + 1) } } return } ================================================ FILE: vendor/github.com/ugorji/go/codec/helper_not_unsafe.go ================================================ // +build !go1.7 safe appengine // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. package codec import ( "reflect" "sync/atomic" "time" ) const safeMode = true // stringView returns a view of the []byte as a string. // In unsafe mode, it doesn't incur allocation and copying caused by conversion. // In regular safe mode, it is an allocation and copy. // // Usage: Always maintain a reference to v while result of this call is in use, // and call keepAlive4BytesView(v) at point where done with view. func stringView(v []byte) string { return string(v) } // bytesView returns a view of the string as a []byte. // In unsafe mode, it doesn't incur allocation and copying caused by conversion. // In regular safe mode, it is an allocation and copy. // // Usage: Always maintain a reference to v while result of this call is in use, // and call keepAlive4BytesView(v) at point where done with view. func bytesView(v string) []byte { return []byte(v) } func definitelyNil(v interface{}) bool { // this is a best-effort option. // We just return false, so we don't unnecessarily incur the cost of reflection this early. return false } func rv2i(rv reflect.Value) interface{} { return rv.Interface() } func rt2id(rt reflect.Type) uintptr { return reflect.ValueOf(rt).Pointer() } // func rv2rtid(rv reflect.Value) uintptr { // return reflect.ValueOf(rv.Type()).Pointer() // } func i2rtid(i interface{}) uintptr { return reflect.ValueOf(reflect.TypeOf(i)).Pointer() } // -------------------------- func isEmptyValue(v reflect.Value, tinfos *TypeInfos, deref, checkStruct bool) bool { switch v.Kind() { case reflect.Invalid: return true case reflect.Array, reflect.Map, reflect.Slice, reflect.String: return v.Len() == 0 case reflect.Bool: return !v.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflect.Interface, reflect.Ptr: if deref { if v.IsNil() { return true } return isEmptyValue(v.Elem(), tinfos, deref, checkStruct) } return v.IsNil() case reflect.Struct: return isEmptyStruct(v, tinfos, deref, checkStruct) } return false } // -------------------------- // type ptrToRvMap struct{} // func (*ptrToRvMap) init() {} // func (*ptrToRvMap) get(i interface{}) reflect.Value { // return reflect.ValueOf(i).Elem() // } // -------------------------- type atomicClsErr struct { v atomic.Value } func (x *atomicClsErr) load() (e clsErr) { if i := x.v.Load(); i != nil { e = i.(clsErr) } return } func (x *atomicClsErr) store(p clsErr) { x.v.Store(p) } // -------------------------- type atomicTypeInfoSlice struct { // expected to be 2 words v atomic.Value } func (x *atomicTypeInfoSlice) load() (e []rtid2ti) { if i := x.v.Load(); i != nil { e = i.([]rtid2ti) } return } func (x *atomicTypeInfoSlice) store(p []rtid2ti) { x.v.Store(p) } // -------------------------- type atomicRtidFnSlice struct { // expected to be 2 words v atomic.Value } func (x *atomicRtidFnSlice) load() (e []codecRtidFn) { if i := x.v.Load(); i != nil { e = i.([]codecRtidFn) } return } func (x *atomicRtidFnSlice) store(p []codecRtidFn) { x.v.Store(p) } // -------------------------- func (n *decNaked) ru() reflect.Value { return reflect.ValueOf(&n.u).Elem() } func (n *decNaked) ri() reflect.Value { return reflect.ValueOf(&n.i).Elem() } func (n *decNaked) rf() reflect.Value { return reflect.ValueOf(&n.f).Elem() } func (n *decNaked) rl() reflect.Value { return reflect.ValueOf(&n.l).Elem() } func (n *decNaked) rs() reflect.Value { return reflect.ValueOf(&n.s).Elem() } func (n *decNaked) rt() reflect.Value { return reflect.ValueOf(&n.t).Elem() } func (n *decNaked) rb() reflect.Value { return reflect.ValueOf(&n.b).Elem() } // -------------------------- func (d *Decoder) raw(f *codecFnInfo, rv reflect.Value) { rv.SetBytes(d.rawBytes()) } func (d *Decoder) kString(f *codecFnInfo, rv reflect.Value) { rv.SetString(d.d.DecodeString()) } func (d *Decoder) kBool(f *codecFnInfo, rv reflect.Value) { rv.SetBool(d.d.DecodeBool()) } func (d *Decoder) kTime(f *codecFnInfo, rv reflect.Value) { rv.Set(reflect.ValueOf(d.d.DecodeTime())) } func (d *Decoder) kFloat32(f *codecFnInfo, rv reflect.Value) { rv.SetFloat(d.decodeFloat32()) } func (d *Decoder) kFloat64(f *codecFnInfo, rv reflect.Value) { rv.SetFloat(d.d.DecodeFloat64()) } func (d *Decoder) kInt(f *codecFnInfo, rv reflect.Value) { rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) } func (d *Decoder) kInt8(f *codecFnInfo, rv reflect.Value) { rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), 8)) } func (d *Decoder) kInt16(f *codecFnInfo, rv reflect.Value) { rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), 16)) } func (d *Decoder) kInt32(f *codecFnInfo, rv reflect.Value) { rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), 32)) } func (d *Decoder) kInt64(f *codecFnInfo, rv reflect.Value) { rv.SetInt(d.d.DecodeInt64()) } func (d *Decoder) kUint(f *codecFnInfo, rv reflect.Value) { rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) } func (d *Decoder) kUintptr(f *codecFnInfo, rv reflect.Value) { rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) } func (d *Decoder) kUint8(f *codecFnInfo, rv reflect.Value) { rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), 8)) } func (d *Decoder) kUint16(f *codecFnInfo, rv reflect.Value) { rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), 16)) } func (d *Decoder) kUint32(f *codecFnInfo, rv reflect.Value) { rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), 32)) } func (d *Decoder) kUint64(f *codecFnInfo, rv reflect.Value) { rv.SetUint(d.d.DecodeUint64()) } // ---------------- func (e *Encoder) kBool(f *codecFnInfo, rv reflect.Value) { e.e.EncodeBool(rv.Bool()) } func (e *Encoder) kTime(f *codecFnInfo, rv reflect.Value) { e.e.EncodeTime(rv2i(rv).(time.Time)) } func (e *Encoder) kString(f *codecFnInfo, rv reflect.Value) { s := rv.String() if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(s)) } else { e.e.EncodeStringEnc(cUTF8, s) } } func (e *Encoder) kFloat64(f *codecFnInfo, rv reflect.Value) { e.e.EncodeFloat64(rv.Float()) } func (e *Encoder) kFloat32(f *codecFnInfo, rv reflect.Value) { e.e.EncodeFloat32(float32(rv.Float())) } func (e *Encoder) kInt(f *codecFnInfo, rv reflect.Value) { e.e.EncodeInt(rv.Int()) } func (e *Encoder) kInt8(f *codecFnInfo, rv reflect.Value) { e.e.EncodeInt(rv.Int()) } func (e *Encoder) kInt16(f *codecFnInfo, rv reflect.Value) { e.e.EncodeInt(rv.Int()) } func (e *Encoder) kInt32(f *codecFnInfo, rv reflect.Value) { e.e.EncodeInt(rv.Int()) } func (e *Encoder) kInt64(f *codecFnInfo, rv reflect.Value) { e.e.EncodeInt(rv.Int()) } func (e *Encoder) kUint(f *codecFnInfo, rv reflect.Value) { e.e.EncodeUint(rv.Uint()) } func (e *Encoder) kUint8(f *codecFnInfo, rv reflect.Value) { e.e.EncodeUint(rv.Uint()) } func (e *Encoder) kUint16(f *codecFnInfo, rv reflect.Value) { e.e.EncodeUint(rv.Uint()) } func (e *Encoder) kUint32(f *codecFnInfo, rv reflect.Value) { e.e.EncodeUint(rv.Uint()) } func (e *Encoder) kUint64(f *codecFnInfo, rv reflect.Value) { e.e.EncodeUint(rv.Uint()) } func (e *Encoder) kUintptr(f *codecFnInfo, rv reflect.Value) { e.e.EncodeUint(rv.Uint()) } // // keepAlive4BytesView maintains a reference to the input parameter for bytesView. // // // // Usage: call this at point where done with the bytes view. // func keepAlive4BytesView(v string) {} // // keepAlive4BytesView maintains a reference to the input parameter for stringView. // // // // Usage: call this at point where done with the string view. // func keepAlive4StringView(v []byte) {} // func definitelyNil(v interface{}) bool { // rv := reflect.ValueOf(v) // switch rv.Kind() { // case reflect.Invalid: // return true // case reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Slice, reflect.Map, reflect.Func: // return rv.IsNil() // default: // return false // } // } ================================================ FILE: vendor/github.com/ugorji/go/codec/helper_unsafe.go ================================================ // +build !safe // +build !appengine // +build go1.7 // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. package codec import ( "reflect" "sync/atomic" "time" "unsafe" ) // This file has unsafe variants of some helper methods. // NOTE: See helper_not_unsafe.go for the usage information. // var zeroRTv [4]uintptr const safeMode = false const unsafeFlagIndir = 1 << 7 // keep in sync with GO_ROOT/src/reflect/value.go type unsafeString struct { Data unsafe.Pointer Len int } type unsafeSlice struct { Data unsafe.Pointer Len int Cap int } type unsafeIntf struct { typ unsafe.Pointer word unsafe.Pointer } type unsafeReflectValue struct { typ unsafe.Pointer ptr unsafe.Pointer flag uintptr } func stringView(v []byte) string { if len(v) == 0 { return "" } bx := (*unsafeSlice)(unsafe.Pointer(&v)) return *(*string)(unsafe.Pointer(&unsafeString{bx.Data, bx.Len})) } func bytesView(v string) []byte { if len(v) == 0 { return zeroByteSlice } sx := (*unsafeString)(unsafe.Pointer(&v)) return *(*[]byte)(unsafe.Pointer(&unsafeSlice{sx.Data, sx.Len, sx.Len})) } func definitelyNil(v interface{}) bool { // There is no global way of checking if an interface is nil. // For true references (map, ptr, func, chan), you can just look // at the word of the interface. However, for slices, you have to dereference // the word, and get a pointer to the 3-word interface value. // // However, the following are cheap calls // - TypeOf(interface): cheap 2-line call. // - ValueOf(interface{}): expensive // - type.Kind: cheap call through an interface // - Value.Type(): cheap call // except it's a method value (e.g. r.Read, which implies that it is a Func) return ((*unsafeIntf)(unsafe.Pointer(&v))).word == nil } func rv2i(rv reflect.Value) interface{} { // TODO: consider a more generally-known optimization for reflect.Value ==> Interface // // Currently, we use this fragile method that taps into implememtation details from // the source go stdlib reflect/value.go, and trims the implementation. urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) // true references (map, func, chan, ptr - NOT slice) may be double-referenced as flagIndir var ptr unsafe.Pointer if refBitset.isset(byte(urv.flag&(1<<5-1))) && urv.flag&unsafeFlagIndir != 0 { ptr = *(*unsafe.Pointer)(urv.ptr) } else { ptr = urv.ptr } return *(*interface{})(unsafe.Pointer(&unsafeIntf{typ: urv.typ, word: ptr})) } func rt2id(rt reflect.Type) uintptr { return uintptr(((*unsafeIntf)(unsafe.Pointer(&rt))).word) } // func rv2rtid(rv reflect.Value) uintptr { // return uintptr((*unsafeReflectValue)(unsafe.Pointer(&rv)).typ) // } func i2rtid(i interface{}) uintptr { return uintptr(((*unsafeIntf)(unsafe.Pointer(&i))).typ) } // -------------------------- func isEmptyValue(v reflect.Value, tinfos *TypeInfos, deref, checkStruct bool) bool { urv := (*unsafeReflectValue)(unsafe.Pointer(&v)) if urv.flag == 0 { return true } switch v.Kind() { case reflect.Invalid: return true case reflect.String: return (*unsafeString)(urv.ptr).Len == 0 case reflect.Slice: return (*unsafeSlice)(urv.ptr).Len == 0 case reflect.Bool: return !*(*bool)(urv.ptr) case reflect.Int: return *(*int)(urv.ptr) == 0 case reflect.Int8: return *(*int8)(urv.ptr) == 0 case reflect.Int16: return *(*int16)(urv.ptr) == 0 case reflect.Int32: return *(*int32)(urv.ptr) == 0 case reflect.Int64: return *(*int64)(urv.ptr) == 0 case reflect.Uint: return *(*uint)(urv.ptr) == 0 case reflect.Uint8: return *(*uint8)(urv.ptr) == 0 case reflect.Uint16: return *(*uint16)(urv.ptr) == 0 case reflect.Uint32: return *(*uint32)(urv.ptr) == 0 case reflect.Uint64: return *(*uint64)(urv.ptr) == 0 case reflect.Uintptr: return *(*uintptr)(urv.ptr) == 0 case reflect.Float32: return *(*float32)(urv.ptr) == 0 case reflect.Float64: return *(*float64)(urv.ptr) == 0 case reflect.Interface: isnil := urv.ptr == nil || *(*unsafe.Pointer)(urv.ptr) == nil if deref { if isnil { return true } return isEmptyValue(v.Elem(), tinfos, deref, checkStruct) } return isnil case reflect.Ptr: // isnil := urv.ptr == nil (not sufficient, as a pointer value encodes the type) isnil := urv.ptr == nil || *(*unsafe.Pointer)(urv.ptr) == nil if deref { if isnil { return true } return isEmptyValue(v.Elem(), tinfos, deref, checkStruct) } return isnil case reflect.Struct: return isEmptyStruct(v, tinfos, deref, checkStruct) case reflect.Map, reflect.Array, reflect.Chan: return v.Len() == 0 } return false } // -------------------------- // atomicXXX is expected to be 2 words (for symmetry with atomic.Value) // // Note that we do not atomically load/store length and data pointer separately, // as this could lead to some races. Instead, we atomically load/store cappedSlice. // // Note: with atomic.(Load|Store)Pointer, we MUST work with an unsafe.Pointer directly. // ---------------------- type atomicTypeInfoSlice struct { v unsafe.Pointer // *[]rtid2ti _ uint64 // padding (atomicXXX expected to be 2 words) } func (x *atomicTypeInfoSlice) load() (s []rtid2ti) { x2 := atomic.LoadPointer(&x.v) if x2 != nil { s = *(*[]rtid2ti)(x2) } return } func (x *atomicTypeInfoSlice) store(p []rtid2ti) { atomic.StorePointer(&x.v, unsafe.Pointer(&p)) } // -------------------------- type atomicRtidFnSlice struct { v unsafe.Pointer // *[]codecRtidFn // _ uint64 // padding (atomicXXX expected to be 2 words) (make 1 word so JsonHandle fits) } func (x *atomicRtidFnSlice) load() (s []codecRtidFn) { x2 := atomic.LoadPointer(&x.v) if x2 != nil { s = *(*[]codecRtidFn)(x2) } return } func (x *atomicRtidFnSlice) store(p []codecRtidFn) { atomic.StorePointer(&x.v, unsafe.Pointer(&p)) } // -------------------------- type atomicClsErr struct { v unsafe.Pointer // *clsErr _ uint64 // padding (atomicXXX expected to be 2 words) } func (x *atomicClsErr) load() (e clsErr) { x2 := (*clsErr)(atomic.LoadPointer(&x.v)) if x2 != nil { e = *x2 } return } func (x *atomicClsErr) store(p clsErr) { atomic.StorePointer(&x.v, unsafe.Pointer(&p)) } // -------------------------- // to create a reflect.Value for each member field of decNaked, // we first create a global decNaked, and create reflect.Value // for them all. // This way, we have the flags and type in the reflect.Value. // Then, when a reflect.Value is called, we just copy it, // update the ptr to the decNaked's, and return it. type unsafeDecNakedWrapper struct { decNaked ru, ri, rf, rl, rs, rb, rt reflect.Value // mapping to the primitives above } func (n *unsafeDecNakedWrapper) init() { n.ru = reflect.ValueOf(&n.u).Elem() n.ri = reflect.ValueOf(&n.i).Elem() n.rf = reflect.ValueOf(&n.f).Elem() n.rl = reflect.ValueOf(&n.l).Elem() n.rs = reflect.ValueOf(&n.s).Elem() n.rt = reflect.ValueOf(&n.t).Elem() n.rb = reflect.ValueOf(&n.b).Elem() // n.rr[] = reflect.ValueOf(&n.) } var defUnsafeDecNakedWrapper unsafeDecNakedWrapper func init() { defUnsafeDecNakedWrapper.init() } func (n *decNaked) ru() (v reflect.Value) { v = defUnsafeDecNakedWrapper.ru ((*unsafeReflectValue)(unsafe.Pointer(&v))).ptr = unsafe.Pointer(&n.u) return } func (n *decNaked) ri() (v reflect.Value) { v = defUnsafeDecNakedWrapper.ri ((*unsafeReflectValue)(unsafe.Pointer(&v))).ptr = unsafe.Pointer(&n.i) return } func (n *decNaked) rf() (v reflect.Value) { v = defUnsafeDecNakedWrapper.rf ((*unsafeReflectValue)(unsafe.Pointer(&v))).ptr = unsafe.Pointer(&n.f) return } func (n *decNaked) rl() (v reflect.Value) { v = defUnsafeDecNakedWrapper.rl ((*unsafeReflectValue)(unsafe.Pointer(&v))).ptr = unsafe.Pointer(&n.l) return } func (n *decNaked) rs() (v reflect.Value) { v = defUnsafeDecNakedWrapper.rs ((*unsafeReflectValue)(unsafe.Pointer(&v))).ptr = unsafe.Pointer(&n.s) return } func (n *decNaked) rt() (v reflect.Value) { v = defUnsafeDecNakedWrapper.rt ((*unsafeReflectValue)(unsafe.Pointer(&v))).ptr = unsafe.Pointer(&n.t) return } func (n *decNaked) rb() (v reflect.Value) { v = defUnsafeDecNakedWrapper.rb ((*unsafeReflectValue)(unsafe.Pointer(&v))).ptr = unsafe.Pointer(&n.b) return } // -------------------------- func (d *Decoder) raw(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*[]byte)(urv.ptr) = d.rawBytes() } func (d *Decoder) kString(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*string)(urv.ptr) = d.d.DecodeString() } func (d *Decoder) kBool(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*bool)(urv.ptr) = d.d.DecodeBool() } func (d *Decoder) kTime(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*time.Time)(urv.ptr) = d.d.DecodeTime() } func (d *Decoder) kFloat32(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*float32)(urv.ptr) = float32(d.decodeFloat32()) } func (d *Decoder) kFloat64(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*float64)(urv.ptr) = d.d.DecodeFloat64() } func (d *Decoder) kInt(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*int)(urv.ptr) = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) } func (d *Decoder) kInt8(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*int8)(urv.ptr) = int8(chkOvf.IntV(d.d.DecodeInt64(), 8)) } func (d *Decoder) kInt16(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*int16)(urv.ptr) = int16(chkOvf.IntV(d.d.DecodeInt64(), 16)) } func (d *Decoder) kInt32(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*int32)(urv.ptr) = int32(chkOvf.IntV(d.d.DecodeInt64(), 32)) } func (d *Decoder) kInt64(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*int64)(urv.ptr) = d.d.DecodeInt64() } func (d *Decoder) kUint(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*uint)(urv.ptr) = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) } func (d *Decoder) kUintptr(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*uintptr)(urv.ptr) = uintptr(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) } func (d *Decoder) kUint8(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*uint8)(urv.ptr) = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) } func (d *Decoder) kUint16(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*uint16)(urv.ptr) = uint16(chkOvf.UintV(d.d.DecodeUint64(), 16)) } func (d *Decoder) kUint32(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*uint32)(urv.ptr) = uint32(chkOvf.UintV(d.d.DecodeUint64(), 32)) } func (d *Decoder) kUint64(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*uint64)(urv.ptr) = d.d.DecodeUint64() } // ------------ func (e *Encoder) kBool(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeBool(*(*bool)(v.ptr)) } func (e *Encoder) kTime(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeTime(*(*time.Time)(v.ptr)) } func (e *Encoder) kString(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) s := *(*string)(v.ptr) if e.h.StringToRaw { e.e.EncodeStringBytesRaw(bytesView(s)) } else { e.e.EncodeStringEnc(cUTF8, s) } } func (e *Encoder) kFloat64(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeFloat64(*(*float64)(v.ptr)) } func (e *Encoder) kFloat32(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeFloat32(*(*float32)(v.ptr)) } func (e *Encoder) kInt(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeInt(int64(*(*int)(v.ptr))) } func (e *Encoder) kInt8(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeInt(int64(*(*int8)(v.ptr))) } func (e *Encoder) kInt16(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeInt(int64(*(*int16)(v.ptr))) } func (e *Encoder) kInt32(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeInt(int64(*(*int32)(v.ptr))) } func (e *Encoder) kInt64(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeInt(int64(*(*int64)(v.ptr))) } func (e *Encoder) kUint(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeUint(uint64(*(*uint)(v.ptr))) } func (e *Encoder) kUint8(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeUint(uint64(*(*uint8)(v.ptr))) } func (e *Encoder) kUint16(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeUint(uint64(*(*uint16)(v.ptr))) } func (e *Encoder) kUint32(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeUint(uint64(*(*uint32)(v.ptr))) } func (e *Encoder) kUint64(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeUint(uint64(*(*uint64)(v.ptr))) } func (e *Encoder) kUintptr(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeUint(uint64(*(*uintptr)(v.ptr))) } // ------------ // func (d *Decoder) raw(f *codecFnInfo, rv reflect.Value) { // urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) // // if urv.flag&unsafeFlagIndir != 0 { // // urv.ptr = *(*unsafe.Pointer)(urv.ptr) // // } // *(*[]byte)(urv.ptr) = d.rawBytes() // } // func rv0t(rt reflect.Type) reflect.Value { // ut := (*unsafeIntf)(unsafe.Pointer(&rt)) // // we need to determine whether ifaceIndir, and then whether to just pass 0 as the ptr // uv := unsafeReflectValue{ut.word, &zeroRTv, flag(rt.Kind())} // return *(*reflect.Value)(unsafe.Pointer(&uv}) // } // func rv2i(rv reflect.Value) interface{} { // urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) // // true references (map, func, chan, ptr - NOT slice) may be double-referenced as flagIndir // var ptr unsafe.Pointer // // kk := reflect.Kind(urv.flag & (1<<5 - 1)) // // if (kk == reflect.Map || kk == reflect.Ptr || kk == reflect.Chan || kk == reflect.Func) && urv.flag&unsafeFlagIndir != 0 { // if refBitset.isset(byte(urv.flag&(1<<5-1))) && urv.flag&unsafeFlagIndir != 0 { // ptr = *(*unsafe.Pointer)(urv.ptr) // } else { // ptr = urv.ptr // } // return *(*interface{})(unsafe.Pointer(&unsafeIntf{typ: urv.typ, word: ptr})) // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ})) // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ})) // } // func definitelyNil(v interface{}) bool { // var ui *unsafeIntf = (*unsafeIntf)(unsafe.Pointer(&v)) // if ui.word == nil { // return true // } // var tk = reflect.TypeOf(v).Kind() // return (tk == reflect.Interface || tk == reflect.Slice) && *(*unsafe.Pointer)(ui.word) == nil // fmt.Printf(">>>> definitely nil: isnil: %v, TYPE: \t%T, word: %v, *word: %v, type: %v, nil: %v\n", // v == nil, v, word, *((*unsafe.Pointer)(word)), ui.typ, nil) // } // func keepAlive4BytesView(v string) { // runtime.KeepAlive(v) // } // func keepAlive4StringView(v []byte) { // runtime.KeepAlive(v) // } // func rt2id(rt reflect.Type) uintptr { // return uintptr(((*unsafeIntf)(unsafe.Pointer(&rt))).word) // // var i interface{} = rt // // // ui := (*unsafeIntf)(unsafe.Pointer(&i)) // // return ((*unsafeIntf)(unsafe.Pointer(&i))).word // } // func rv2i(rv reflect.Value) interface{} { // urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) // // non-reference type: already indir // // reference type: depend on flagIndir property ('cos maybe was double-referenced) // // const (unsafeRvFlagKindMask = 1<<5 - 1 , unsafeRvFlagIndir = 1 << 7 ) // // rvk := reflect.Kind(urv.flag & (1<<5 - 1)) // // if (rvk == reflect.Chan || // // rvk == reflect.Func || // // rvk == reflect.Interface || // // rvk == reflect.Map || // // rvk == reflect.Ptr || // // rvk == reflect.UnsafePointer) && urv.flag&(1<<8) != 0 { // // fmt.Printf(">>>>> ---- double indirect reference: %v, %v\n", rvk, rv.Type()) // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ})) // // } // if urv.flag&(1<<5-1) == uintptr(reflect.Map) && urv.flag&(1<<7) != 0 { // // fmt.Printf(">>>>> ---- double indirect reference: %v, %v\n", rvk, rv.Type()) // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ})) // } // // fmt.Printf(">>>>> ++++ direct reference: %v, %v\n", rvk, rv.Type()) // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ})) // } // const ( // unsafeRvFlagKindMask = 1<<5 - 1 // unsafeRvKindDirectIface = 1 << 5 // unsafeRvFlagIndir = 1 << 7 // unsafeRvFlagAddr = 1 << 8 // unsafeRvFlagMethod = 1 << 9 // _USE_RV_INTERFACE bool = false // _UNSAFE_RV_DEBUG = true // ) // type unsafeRtype struct { // _ [2]uintptr // _ uint32 // _ uint8 // _ uint8 // _ uint8 // kind uint8 // _ [2]uintptr // _ int32 // } // func _rv2i(rv reflect.Value) interface{} { // // Note: From use, // // - it's never an interface // // - the only calls here are for ifaceIndir types. // // (though that conditional is wrong) // // To know for sure, we need the value of t.kind (which is not exposed). // // // // Need to validate the path: type is indirect ==> only value is indirect ==> default (value is direct) // // - Type indirect, Value indirect: ==> numbers, boolean, slice, struct, array, string // // - Type Direct, Value indirect: ==> map??? // // - Type Direct, Value direct: ==> pointers, unsafe.Pointer, func, chan, map // // // // TRANSLATES TO: // // if typeIndirect { } else if valueIndirect { } else { } // // // // Since we don't deal with funcs, then "flagNethod" is unset, and can be ignored. // if _USE_RV_INTERFACE { // return rv.Interface() // } // urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) // // if urv.flag&unsafeRvFlagMethod != 0 || urv.flag&unsafeRvFlagKindMask == uintptr(reflect.Interface) { // // println("***** IS flag method or interface: delegating to rv.Interface()") // // return rv.Interface() // // } // // if urv.flag&unsafeRvFlagKindMask == uintptr(reflect.Interface) { // // println("***** IS Interface: delegate to rv.Interface") // // return rv.Interface() // // } // // if urv.flag&unsafeRvFlagKindMask&unsafeRvKindDirectIface == 0 { // // if urv.flag&unsafeRvFlagAddr == 0 { // // println("***** IS ifaceIndir typ") // // // ui := unsafeIntf{word: urv.ptr, typ: urv.typ} // // // return *(*interface{})(unsafe.Pointer(&ui)) // // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ})) // // } // // } else if urv.flag&unsafeRvFlagIndir != 0 { // // println("***** IS flagindir") // // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ})) // // } else { // // println("***** NOT flagindir") // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ})) // // } // // println("***** default: delegate to rv.Interface") // urt := (*unsafeRtype)(unsafe.Pointer(urv.typ)) // if _UNSAFE_RV_DEBUG { // fmt.Printf(">>>> start: %v: ", rv.Type()) // fmt.Printf("%v - %v\n", *urv, *urt) // } // if urt.kind&unsafeRvKindDirectIface == 0 { // if _UNSAFE_RV_DEBUG { // fmt.Printf("**** +ifaceIndir type: %v\n", rv.Type()) // } // // println("***** IS ifaceIndir typ") // // if true || urv.flag&unsafeRvFlagAddr == 0 { // // // println(" ***** IS NOT addr") // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ})) // // } // } else if urv.flag&unsafeRvFlagIndir != 0 { // if _UNSAFE_RV_DEBUG { // fmt.Printf("**** +flagIndir type: %v\n", rv.Type()) // } // // println("***** IS flagindir") // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ})) // } else { // if _UNSAFE_RV_DEBUG { // fmt.Printf("**** -flagIndir type: %v\n", rv.Type()) // } // // println("***** NOT flagindir") // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ})) // } // // println("***** default: delegating to rv.Interface()") // // return rv.Interface() // } // var staticM0 = make(map[string]uint64) // var staticI0 = (int32)(-5) // func staticRv2iTest() { // i0 := (int32)(-5) // m0 := make(map[string]uint16) // m0["1"] = 1 // for _, i := range []interface{}{ // (int)(7), // (uint)(8), // (int16)(-9), // (uint16)(19), // (uintptr)(77), // (bool)(true), // float32(-32.7), // float64(64.9), // complex(float32(19), 5), // complex(float64(-32), 7), // [4]uint64{1, 2, 3, 4}, // (chan<- int)(nil), // chan, // rv2i, // func // io.Writer(ioutil.Discard), // make(map[string]uint), // (map[string]uint)(nil), // staticM0, // m0, // &m0, // i0, // &i0, // &staticI0, // &staticM0, // []uint32{6, 7, 8}, // "abc", // Raw{}, // RawExt{}, // &Raw{}, // &RawExt{}, // unsafe.Pointer(&i0), // } { // i2 := rv2i(reflect.ValueOf(i)) // eq := reflect.DeepEqual(i, i2) // fmt.Printf(">>>> %v == %v? %v\n", i, i2, eq) // } // // os.Exit(0) // } // func init() { // staticRv2iTest() // } // func rv2i(rv reflect.Value) interface{} { // if _USE_RV_INTERFACE || rv.Kind() == reflect.Interface || rv.CanAddr() { // return rv.Interface() // } // // var i interface{} // // ui := (*unsafeIntf)(unsafe.Pointer(&i)) // var ui unsafeIntf // urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) // // fmt.Printf("urv: flag: %b, typ: %b, ptr: %b\n", urv.flag, uintptr(urv.typ), uintptr(urv.ptr)) // if (urv.flag&unsafeRvFlagKindMask)&unsafeRvKindDirectIface == 0 { // if urv.flag&unsafeRvFlagAddr != 0 { // println("***** indirect and addressable! Needs typed move - delegate to rv.Interface()") // return rv.Interface() // } // println("****** indirect type/kind") // ui.word = urv.ptr // } else if urv.flag&unsafeRvFlagIndir != 0 { // println("****** unsafe rv flag indir") // ui.word = *(*unsafe.Pointer)(urv.ptr) // } else { // println("****** default: assign prt to word directly") // ui.word = urv.ptr // } // // ui.word = urv.ptr // ui.typ = urv.typ // // fmt.Printf("(pointers) ui.typ: %p, word: %p\n", ui.typ, ui.word) // // fmt.Printf("(binary) ui.typ: %b, word: %b\n", uintptr(ui.typ), uintptr(ui.word)) // return *(*interface{})(unsafe.Pointer(&ui)) // // return i // } ================================================ FILE: vendor/github.com/ugorji/go/codec/json.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. package codec // By default, this json support uses base64 encoding for bytes, because you cannot // store and read any arbitrary string in json (only unicode). // However, the user can configre how to encode/decode bytes. // // This library specifically supports UTF-8 for encoding and decoding only. // // Note that the library will happily encode/decode things which are not valid // json e.g. a map[int64]string. We do it for consistency. With valid json, // we will encode and decode appropriately. // Users can specify their map type if necessary to force it. // // Note: // - we cannot use strconv.Quote and strconv.Unquote because json quotes/unquotes differently. // We implement it here. // Top-level methods of json(End|Dec)Driver (which are implementations of (en|de)cDriver // MUST not call one-another. import ( "bytes" "encoding/base64" "math" "reflect" "strconv" "time" "unicode" "unicode/utf16" "unicode/utf8" ) //-------------------------------- var jsonLiterals = [...]byte{ '"', 't', 'r', 'u', 'e', '"', '"', 'f', 'a', 'l', 's', 'e', '"', '"', 'n', 'u', 'l', 'l', '"', } const ( jsonLitTrueQ = 0 jsonLitTrue = 1 jsonLitFalseQ = 6 jsonLitFalse = 7 // jsonLitNullQ = 13 jsonLitNull = 14 ) var ( jsonLiteral4True = jsonLiterals[jsonLitTrue+1 : jsonLitTrue+4] jsonLiteral4False = jsonLiterals[jsonLitFalse+1 : jsonLitFalse+5] jsonLiteral4Null = jsonLiterals[jsonLitNull+1 : jsonLitNull+4] ) const ( jsonU4Chk2 = '0' jsonU4Chk1 = 'a' - 10 jsonU4Chk0 = 'A' - 10 jsonScratchArrayLen = cacheLineSize // 64 ) const ( // If !jsonValidateSymbols, decoding will be faster, by skipping some checks: // - If we see first character of null, false or true, // do not validate subsequent characters. // - e.g. if we see a n, assume null and skip next 3 characters, // and do not validate they are ull. // P.S. Do not expect a significant decoding boost from this. jsonValidateSymbols = true jsonSpacesOrTabsLen = 128 jsonAlwaysReturnInternString = false ) var ( // jsonTabs and jsonSpaces are used as caches for indents jsonTabs, jsonSpaces [jsonSpacesOrTabsLen]byte jsonCharHtmlSafeSet bitset256 jsonCharSafeSet bitset256 jsonCharWhitespaceSet bitset256 jsonNumSet bitset256 ) func init() { var i byte for i = 0; i < jsonSpacesOrTabsLen; i++ { jsonSpaces[i] = ' ' jsonTabs[i] = '\t' } // populate the safe values as true: note: ASCII control characters are (0-31) // jsonCharSafeSet: all true except (0-31) " \ // jsonCharHtmlSafeSet: all true except (0-31) " \ < > & for i = 32; i < utf8.RuneSelf; i++ { switch i { case '"', '\\': case '<', '>', '&': jsonCharSafeSet.set(i) // = true default: jsonCharSafeSet.set(i) jsonCharHtmlSafeSet.set(i) } } for i = 0; i <= utf8.RuneSelf; i++ { switch i { case ' ', '\t', '\r', '\n': jsonCharWhitespaceSet.set(i) case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'e', 'E', '.', '+', '-': jsonNumSet.set(i) } } } // ---------------- type jsonEncDriverTypical struct { jsonEncDriver } func (e *jsonEncDriverTypical) WriteArrayStart(length int) { e.w.writen1('[') } func (e *jsonEncDriverTypical) WriteArrayElem() { if e.e.c != containerArrayStart { e.w.writen1(',') } } func (e *jsonEncDriverTypical) WriteArrayEnd() { e.w.writen1(']') } func (e *jsonEncDriverTypical) WriteMapStart(length int) { e.w.writen1('{') } func (e *jsonEncDriverTypical) WriteMapElemKey() { if e.e.c != containerMapStart { e.w.writen1(',') } } func (e *jsonEncDriverTypical) WriteMapElemValue() { e.w.writen1(':') } func (e *jsonEncDriverTypical) WriteMapEnd() { e.w.writen1('}') } func (e *jsonEncDriverTypical) EncodeBool(b bool) { if b { e.w.writeb(jsonLiterals[jsonLitTrue : jsonLitTrue+4]) } else { e.w.writeb(jsonLiterals[jsonLitFalse : jsonLitFalse+5]) } } func (e *jsonEncDriverTypical) EncodeInt(v int64) { e.w.writeb(strconv.AppendInt(e.b[:0], v, 10)) } func (e *jsonEncDriverTypical) EncodeUint(v uint64) { e.w.writeb(strconv.AppendUint(e.b[:0], v, 10)) } func (e *jsonEncDriverTypical) EncodeFloat64(f float64) { fmt, prec := jsonFloatStrconvFmtPrec64(f) e.w.writeb(strconv.AppendFloat(e.b[:0], f, fmt, int(prec), 64)) // e.w.writeb(strconv.AppendFloat(e.b[:0], f, jsonFloatStrconvFmtPrec64(f), 64)) } func (e *jsonEncDriverTypical) EncodeFloat32(f float32) { fmt, prec := jsonFloatStrconvFmtPrec32(f) e.w.writeb(strconv.AppendFloat(e.b[:0], float64(f), fmt, int(prec), 32)) } // func (e *jsonEncDriverTypical) encodeFloat(f float64, bitsize uint8) { // fmt, prec := jsonFloatStrconvFmtPrec(f, bitsize == 32) // e.w.writeb(strconv.AppendFloat(e.b[:0], f, fmt, prec, int(bitsize))) // } // func (e *jsonEncDriverTypical) atEndOfEncode() { // if e.tw { // e.w.writen1(' ') // } // } // ---------------- type jsonEncDriverGeneric struct { jsonEncDriver } // indent is done as below: // - newline and indent are added before each mapKey or arrayElem // - newline and indent are added before each ending, // except there was no entry (so we can have {} or []) func (e *jsonEncDriverGeneric) reset() { e.jsonEncDriver.reset() e.d, e.dl, e.di = false, 0, 0 if e.h.Indent != 0 { e.d = true e.di = int8(e.h.Indent) } // if e.h.Indent > 0 { // e.d = true // e.di = int8(e.h.Indent) // } else if e.h.Indent < 0 { // e.d = true // // e.dt = true // e.di = int8(-e.h.Indent) // } e.ks = e.h.MapKeyAsString e.is = e.h.IntegerAsString } func (e *jsonEncDriverGeneric) WriteArrayStart(length int) { if e.d { e.dl++ } e.w.writen1('[') } func (e *jsonEncDriverGeneric) WriteArrayEnd() { if e.d { e.dl-- e.writeIndent() } e.w.writen1(']') } func (e *jsonEncDriverGeneric) WriteMapStart(length int) { if e.d { e.dl++ } e.w.writen1('{') } func (e *jsonEncDriverGeneric) WriteMapEnd() { if e.d { e.dl-- if e.e.c != containerMapStart { e.writeIndent() } } e.w.writen1('}') } func (e *jsonEncDriverGeneric) EncodeBool(b bool) { if e.ks && e.e.c == containerMapKey { if b { e.w.writeb(jsonLiterals[jsonLitTrueQ : jsonLitTrueQ+6]) } else { e.w.writeb(jsonLiterals[jsonLitFalseQ : jsonLitFalseQ+7]) } } else { if b { e.w.writeb(jsonLiterals[jsonLitTrue : jsonLitTrue+4]) } else { e.w.writeb(jsonLiterals[jsonLitFalse : jsonLitFalse+5]) } } } func (e *jsonEncDriverGeneric) encodeFloat(f float64, bitsize, fmt byte, prec int8) { var blen int if e.ks && e.e.c == containerMapKey { blen = 2 + len(strconv.AppendFloat(e.b[1:1], f, fmt, int(prec), int(bitsize))) e.b[0] = '"' e.b[blen-1] = '"' } else { blen = len(strconv.AppendFloat(e.b[:0], f, fmt, int(prec), int(bitsize))) } e.w.writeb(e.b[:blen]) } func (e *jsonEncDriverGeneric) EncodeFloat64(f float64) { fmt, prec := jsonFloatStrconvFmtPrec64(f) e.encodeFloat(f, 64, fmt, prec) } func (e *jsonEncDriverGeneric) EncodeFloat32(f float32) { fmt, prec := jsonFloatStrconvFmtPrec32(f) e.encodeFloat(float64(f), 32, fmt, prec) } func (e *jsonEncDriverGeneric) EncodeInt(v int64) { x := e.is if x == 'A' || x == 'L' && (v > 1<<53 || v < -(1<<53)) || (e.ks && e.e.c == containerMapKey) { blen := 2 + len(strconv.AppendInt(e.b[1:1], v, 10)) e.b[0] = '"' e.b[blen-1] = '"' e.w.writeb(e.b[:blen]) return } e.w.writeb(strconv.AppendInt(e.b[:0], v, 10)) } func (e *jsonEncDriverGeneric) EncodeUint(v uint64) { x := e.is if x == 'A' || x == 'L' && v > 1<<53 || (e.ks && e.e.c == containerMapKey) { blen := 2 + len(strconv.AppendUint(e.b[1:1], v, 10)) e.b[0] = '"' e.b[blen-1] = '"' e.w.writeb(e.b[:blen]) return } e.w.writeb(strconv.AppendUint(e.b[:0], v, 10)) } // func (e *jsonEncDriverGeneric) EncodeFloat32(f float32) { // // e.encodeFloat(float64(f), 32) // // always encode all floats as IEEE 64-bit floating point. // // It also ensures that we can decode in full precision even if into a float32, // // as what is written is always to float64 precision. // e.EncodeFloat64(float64(f)) // } // func (e *jsonEncDriverGeneric) atEndOfEncode() { // if e.tw { // if e.d { // e.w.writen1('\n') // } else { // e.w.writen1(' ') // } // } // } // -------------------- type jsonEncDriver struct { noBuiltInTypes w *encWriterSwitch e *Encoder h *JsonHandle bs []byte // for encoding strings se interfaceExtWrapper // ---- cpu cache line boundary? // ds string // indent string di int8 // indent per: if negative, use tabs d bool // indenting? // dt bool // indent using tabs dl uint16 // indent level ks bool // map key as string is byte // integer as string s *bitset256 // safe set for characters (taking h.HTMLAsIs into consideration) // scratch: encode time, numbers, etc. Note: leave 1 byte for containerState b [jsonScratchArrayLen - 16]byte // leave space for bs(len,cap), containerState } // Keep writeIndent, WriteArrayElem, WriteMapElemKey, WriteMapElemValue // in jsonEncDriver, so that *Encoder can directly call them func (e *jsonEncDriver) getJsonEncDriver() *jsonEncDriver { return e } func (e *jsonEncDriver) writeIndent() { e.w.writen1('\n') x := int(e.di) * int(e.dl) if e.di < 0 { x = -x for x > jsonSpacesOrTabsLen { e.w.writeb(jsonTabs[:]) x -= jsonSpacesOrTabsLen } e.w.writeb(jsonTabs[:x]) } else { for x > jsonSpacesOrTabsLen { e.w.writeb(jsonSpaces[:]) x -= jsonSpacesOrTabsLen } e.w.writeb(jsonSpaces[:x]) } } func (e *jsonEncDriver) WriteArrayElem() { // xdebugf("WriteArrayElem: e.e.c: %d", e.e.c) if e.e.c != containerArrayStart { e.w.writen1(',') } if e.d { e.writeIndent() } } func (e *jsonEncDriver) WriteMapElemKey() { if e.e.c != containerMapStart { e.w.writen1(',') } if e.d { e.writeIndent() } } func (e *jsonEncDriver) WriteMapElemValue() { if e.d { e.w.writen2(':', ' ') } else { e.w.writen1(':') } } func (e *jsonEncDriver) EncodeNil() { // We always encode nil as just null (never in quotes) // This allows us to easily decode if a nil in the json stream // ie if initial token is n. e.w.writeb(jsonLiterals[jsonLitNull : jsonLitNull+4]) // if e.h.MapKeyAsString && e.e.c == containerMapKey { // e.w.writeb(jsonLiterals[jsonLitNullQ : jsonLitNullQ+6]) // } else { // e.w.writeb(jsonLiterals[jsonLitNull : jsonLitNull+4]) // } } func (e *jsonEncDriver) EncodeTime(t time.Time) { // Do NOT use MarshalJSON, as it allocates internally. // instead, we call AppendFormat directly, using our scratch buffer (e.b) if t.IsZero() { e.EncodeNil() } else { e.b[0] = '"' b := t.AppendFormat(e.b[1:1], time.RFC3339Nano) e.b[len(b)+1] = '"' e.w.writeb(e.b[:len(b)+2]) } // v, err := t.MarshalJSON(); if err != nil { e.e.error(err) } e.w.writeb(v) } func (e *jsonEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext, en *Encoder) { if v := ext.ConvertExt(rv); v == nil { e.EncodeNil() } else { en.encode(v) } } func (e *jsonEncDriver) EncodeRawExt(re *RawExt, en *Encoder) { // only encodes re.Value (never re.Data) if re.Value == nil { e.EncodeNil() } else { en.encode(re.Value) } } func (e *jsonEncDriver) EncodeStringEnc(c charEncoding, v string) { e.quoteStr(v) } func (e *jsonEncDriver) EncodeStringBytesRaw(v []byte) { // if encoding raw bytes and RawBytesExt is configured, use it to encode if v == nil { e.EncodeNil() return } if e.se.InterfaceExt != nil { e.EncodeExt(v, 0, &e.se, e.e) return } slen := base64.StdEncoding.EncodedLen(len(v)) + 2 if cap(e.bs) >= slen { e.bs = e.bs[:slen] } else { e.bs = make([]byte, slen) } e.bs[0] = '"' base64.StdEncoding.Encode(e.bs[1:], v) e.bs[slen-1] = '"' e.w.writeb(e.bs) } func (e *jsonEncDriver) EncodeAsis(v []byte) { e.w.writeb(v) } func (e *jsonEncDriver) quoteStr(s string) { // adapted from std pkg encoding/json const hex = "0123456789abcdef" w := e.w w.writen1('"') var start int for i := 0; i < len(s); { // encode all bytes < 0x20 (except \r, \n). // also encode < > & to prevent security holes when served to some browsers. // We optimize for ascii, by assumining that most characters are in the BMP // and natively consumed by json without much computation. // if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' { // if (htmlasis && jsonCharSafeSet.isset(b)) || jsonCharHtmlSafeSet.isset(b) { if e.s.isset(s[i]) { i++ continue } if b := s[i]; b < utf8.RuneSelf { if start < i { w.writestr(s[start:i]) } switch b { case '\\', '"': w.writen2('\\', b) case '\n': w.writen2('\\', 'n') case '\r': w.writen2('\\', 'r') case '\b': w.writen2('\\', 'b') case '\f': w.writen2('\\', 'f') case '\t': w.writen2('\\', 't') default: w.writestr(`\u00`) w.writen2(hex[b>>4], hex[b&0xF]) } i++ start = i continue } c, size := utf8.DecodeRuneInString(s[i:]) if c == utf8.RuneError { if size == 1 { if start < i { w.writestr(s[start:i]) } w.writestr(`\ufffd`) i++ start = i } continue } // U+2028 is LINE SEPARATOR. U+2029 is PARAGRAPH SEPARATOR. // Both technically valid JSON, but bomb on JSONP, so fix here unconditionally. if c == '\u2028' || c == '\u2029' { if start < i { w.writestr(s[start:i]) } w.writestr(`\u202`) w.writen1(hex[c&0xF]) i += size start = i continue } i += size } if start < len(s) { w.writestr(s[start:]) } w.writen1('"') } func (e *jsonEncDriver) atEndOfEncode() { // if e.e.c == 0 { // scalar written, output space // e.w.writen1(' ') // } else if e.h.TermWhitespace { // container written, output new-line // e.w.writen1('\n') // } if e.h.TermWhitespace { if e.e.c == 0 { // scalar written, output space e.w.writen1(' ') } else { // container written, output new-line e.w.writen1('\n') } } } type jsonDecDriver struct { noBuiltInTypes d *Decoder h *JsonHandle r *decReaderSwitch se interfaceExtWrapper bs []byte // scratch, initialized from b. For parsing strings or numbers. // ---- writable fields during execution --- *try* to keep in sep cache line // ---- cpu cache line boundary? b [jsonScratchArrayLen]byte // scratch 1, used for parsing strings or numbers or time.Time // ---- cpu cache line boundary? // c containerState tok uint8 // used to store the token read right after skipWhiteSpace fnull bool // found null from appendStringAsBytes _ [2]byte // padding bstr [4]byte // scratch used for string \UXXX parsing b2 [jsonScratchArrayLen - 8]byte // scratch 2, used only for readUntil, decNumBytes // _ [3]uint64 // padding // n jsonNum } // func jsonIsWS(b byte) bool { // // return b == ' ' || b == '\t' || b == '\r' || b == '\n' // return jsonCharWhitespaceSet.isset(b) // } func (d *jsonDecDriver) uncacheRead() { if d.tok != 0 { d.r.unreadn1() d.tok = 0 } } func (d *jsonDecDriver) ReadMapStart() int { if d.tok == 0 { d.tok = d.r.skip(&jsonCharWhitespaceSet) } const xc uint8 = '{' if d.tok != xc { d.d.errorf("read map - expect char '%c' but got char '%c'", xc, d.tok) } d.tok = 0 return -1 } func (d *jsonDecDriver) ReadArrayStart() int { if d.tok == 0 { d.tok = d.r.skip(&jsonCharWhitespaceSet) } const xc uint8 = '[' if d.tok != xc { d.d.errorf("read array - expect char '%c' but got char '%c'", xc, d.tok) } d.tok = 0 return -1 } func (d *jsonDecDriver) CheckBreak() bool { if d.tok == 0 { d.tok = d.r.skip(&jsonCharWhitespaceSet) } return d.tok == '}' || d.tok == ']' } // For the ReadXXX methods below, we could just delegate to helper functions // readContainerState(c containerState, xc uint8, check bool) // - ReadArrayElem would become: // readContainerState(containerArrayElem, ',', d.d.c != containerArrayStart) // // However, until mid-stack inlining comes in go1.11 which supports inlining of // one-liners, we explicitly write them all 5 out to elide the extra func call. // // TODO: For Go 1.11, if inlined, consider consolidating these. func (d *jsonDecDriver) ReadArrayElem() { const xc uint8 = ',' if d.tok == 0 { d.tok = d.r.skip(&jsonCharWhitespaceSet) } // xdebugf("ReadArrayElem: d.d.c: %d, token: %c", d.d.c, d.tok) if d.d.c != containerArrayStart { if d.tok != xc { d.d.errorf("read array element - expect char '%c' but got char '%c'", xc, d.tok) } d.tok = 0 } } func (d *jsonDecDriver) ReadArrayEnd() { const xc uint8 = ']' if d.tok == 0 { d.tok = d.r.skip(&jsonCharWhitespaceSet) } if d.tok != xc { d.d.errorf("read array end - expect char '%c' but got char '%c'", xc, d.tok) } d.tok = 0 } func (d *jsonDecDriver) ReadMapElemKey() { const xc uint8 = ',' if d.tok == 0 { d.tok = d.r.skip(&jsonCharWhitespaceSet) } if d.d.c != containerMapStart { if d.tok != xc { d.d.errorf("read map key - expect char '%c' but got char '%c'", xc, d.tok) } d.tok = 0 } } func (d *jsonDecDriver) ReadMapElemValue() { const xc uint8 = ':' if d.tok == 0 { d.tok = d.r.skip(&jsonCharWhitespaceSet) } if d.tok != xc { d.d.errorf("read map value - expect char '%c' but got char '%c'", xc, d.tok) } d.tok = 0 } func (d *jsonDecDriver) ReadMapEnd() { const xc uint8 = '}' if d.tok == 0 { d.tok = d.r.skip(&jsonCharWhitespaceSet) } if d.tok != xc { d.d.errorf("read map end - expect char '%c' but got char '%c'", xc, d.tok) } d.tok = 0 } // func (d *jsonDecDriver) readLit(length, fromIdx uint8) { // // length here is always less than 8 (literals are: null, true, false) // bs := d.r.readx(int(length)) // d.tok = 0 // if jsonValidateSymbols && !bytes.Equal(bs, jsonLiterals[fromIdx:fromIdx+length]) { // d.d.errorf("expecting %s: got %s", jsonLiterals[fromIdx:fromIdx+length], bs) // } // } func (d *jsonDecDriver) readLit4True() { bs := d.r.readx(3) d.tok = 0 if jsonValidateSymbols && !bytes.Equal(bs, jsonLiteral4True) { d.d.errorf("expecting %s: got %s", jsonLiteral4True, bs) } } func (d *jsonDecDriver) readLit4False() { bs := d.r.readx(4) d.tok = 0 if jsonValidateSymbols && !bytes.Equal(bs, jsonLiteral4False) { d.d.errorf("expecting %s: got %s", jsonLiteral4False, bs) } } func (d *jsonDecDriver) readLit4Null() { bs := d.r.readx(3) d.tok = 0 if jsonValidateSymbols && !bytes.Equal(bs, jsonLiteral4Null) { d.d.errorf("expecting %s: got %s", jsonLiteral4Null, bs) } } func (d *jsonDecDriver) TryDecodeAsNil() bool { if d.tok == 0 { d.tok = d.r.skip(&jsonCharWhitespaceSet) } // we shouldn't try to see if "null" was here, right? // only the plain string: `null` denotes a nil (ie not quotes) if d.tok == 'n' { d.readLit4Null() return true } return false } func (d *jsonDecDriver) DecodeBool() (v bool) { if d.tok == 0 { d.tok = d.r.skip(&jsonCharWhitespaceSet) } fquot := d.d.c == containerMapKey && d.tok == '"' if fquot { d.tok = d.r.readn1() } switch d.tok { case 'f': d.readLit4False() // v = false case 't': d.readLit4True() v = true default: d.d.errorf("decode bool: got first char %c", d.tok) // v = false // "unreachable" } if fquot { d.r.readn1() } return } func (d *jsonDecDriver) DecodeTime() (t time.Time) { // read string, and pass the string into json.unmarshal d.appendStringAsBytes() if d.fnull { return } t, err := time.Parse(time.RFC3339, stringView(d.bs)) if err != nil { d.d.errorv(err) } return } func (d *jsonDecDriver) ContainerType() (vt valueType) { // check container type by checking the first char if d.tok == 0 { d.tok = d.r.skip(&jsonCharWhitespaceSet) } // optimize this, so we don't do 4 checks but do one computation. // return jsonContainerSet[d.tok] // ContainerType is mostly called for Map and Array, // so this conditional is good enough (max 2 checks typically) if b := d.tok; b == '{' { return valueTypeMap } else if b == '[' { return valueTypeArray } else if b == 'n' { return valueTypeNil } else if b == '"' { return valueTypeString } return valueTypeUnset } func (d *jsonDecDriver) decNumBytes() (bs []byte) { // stores num bytes in d.bs if d.tok == 0 { d.tok = d.r.skip(&jsonCharWhitespaceSet) } if d.tok == '"' { bs = d.r.readUntil(d.b2[:0], '"') bs = bs[:len(bs)-1] } else { d.r.unreadn1() bs = d.r.readTo(d.bs[:0], &jsonNumSet) } d.tok = 0 return bs } func (d *jsonDecDriver) DecodeUint64() (u uint64) { bs := d.decNumBytes() if len(bs) == 0 { return } n, neg, badsyntax, overflow := jsonParseInteger(bs) if overflow { d.d.errorf("overflow parsing unsigned integer: %s", bs) } else if neg { d.d.errorf("minus found parsing unsigned integer: %s", bs) } else if badsyntax { // fallback: try to decode as float, and cast n = d.decUint64ViaFloat(stringView(bs)) } return n } func (d *jsonDecDriver) DecodeInt64() (i int64) { const cutoff = uint64(1 << uint(64-1)) bs := d.decNumBytes() if len(bs) == 0 { return } n, neg, badsyntax, overflow := jsonParseInteger(bs) if overflow { d.d.errorf("overflow parsing integer: %s", bs) } else if badsyntax { // d.d.errorf("invalid syntax for integer: %s", bs) // fallback: try to decode as float, and cast if neg { n = d.decUint64ViaFloat(stringView(bs[1:])) } else { n = d.decUint64ViaFloat(stringView(bs)) } } if neg { if n > cutoff { d.d.errorf("overflow parsing integer: %s", bs) } i = -(int64(n)) } else { if n >= cutoff { d.d.errorf("overflow parsing integer: %s", bs) } i = int64(n) } return } func (d *jsonDecDriver) decUint64ViaFloat(s string) (u uint64) { if len(s) == 0 { return } f, err := strconv.ParseFloat(s, 64) if err != nil { d.d.errorf("invalid syntax for integer: %s", s) // d.d.errorv(err) } fi, ff := math.Modf(f) if ff > 0 { d.d.errorf("fractional part found parsing integer: %s", s) } else if fi > float64(math.MaxUint64) { d.d.errorf("overflow parsing integer: %s", s) } return uint64(fi) } func (d *jsonDecDriver) decodeFloat(bitsize int) (f float64) { bs := d.decNumBytes() if len(bs) == 0 { return } f, err := strconv.ParseFloat(stringView(bs), bitsize) if err != nil { d.d.errorv(err) } return } func (d *jsonDecDriver) DecodeFloat64() (f float64) { return d.decodeFloat(64) } func (d *jsonDecDriver) DecodeFloat32() (f float64) { return d.decodeFloat(32) } func (d *jsonDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) { if ext == nil { re := rv.(*RawExt) re.Tag = xtag d.d.decode(&re.Value) } else { var v interface{} d.d.decode(&v) ext.UpdateExt(rv, v) } return } func (d *jsonDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) { // if decoding into raw bytes, and the RawBytesExt is configured, use it to decode. if d.se.InterfaceExt != nil { bsOut = bs d.DecodeExt(&bsOut, 0, &d.se) return } if d.tok == 0 { d.tok = d.r.skip(&jsonCharWhitespaceSet) } // check if an "array" of uint8's (see ContainerType for how to infer if an array) if d.tok == '[' { bsOut, _ = fastpathTV.DecSliceUint8V(bs, true, d.d) return } d.appendStringAsBytes() // base64 encodes []byte{} as "", and we encode nil []byte as null. // Consequently, base64 should decode null as a nil []byte, and "" as an empty []byte{}. // appendStringAsBytes returns a zero-len slice for both, so as not to reset d.bs. // However, it sets a fnull field to true, so we can check if a null was found. if len(d.bs) == 0 { if d.fnull { return nil } return []byte{} } bs0 := d.bs slen := base64.StdEncoding.DecodedLen(len(bs0)) if slen <= cap(bs) { bsOut = bs[:slen] } else if zerocopy && slen <= cap(d.b2) { bsOut = d.b2[:slen] } else { bsOut = make([]byte, slen) } slen2, err := base64.StdEncoding.Decode(bsOut, bs0) if err != nil { d.d.errorf("error decoding base64 binary '%s': %v", bs0, err) return nil } if slen != slen2 { bsOut = bsOut[:slen2] } return } func (d *jsonDecDriver) DecodeString() (s string) { d.appendStringAsBytes() return d.bsToString() } func (d *jsonDecDriver) DecodeStringAsBytes() (s []byte) { d.appendStringAsBytes() return d.bs } func (d *jsonDecDriver) appendStringAsBytes() { if d.tok == 0 { d.tok = d.r.skip(&jsonCharWhitespaceSet) } d.fnull = false if d.tok != '"' { // d.d.errorf("expect char '%c' but got char '%c'", '"', d.tok) // handle non-string scalar: null, true, false or a number switch d.tok { case 'n': d.readLit4Null() d.bs = d.bs[:0] d.fnull = true case 'f': d.readLit4False() d.bs = d.bs[:5] copy(d.bs, "false") case 't': d.readLit4True() d.bs = d.bs[:4] copy(d.bs, "true") default: // try to parse a valid number bs := d.decNumBytes() if len(bs) <= cap(d.bs) { d.bs = d.bs[:len(bs)] } else { d.bs = make([]byte, len(bs)) } copy(d.bs, bs) } return } d.tok = 0 r := d.r var cs = r.readUntil(d.b2[:0], '"') var cslen = uint(len(cs)) var c uint8 v := d.bs[:0] // append on each byte seen can be expensive, so we just // keep track of where we last read a contiguous set of // non-special bytes (using cursor variable), // and when we see a special byte // e.g. end-of-slice, " or \, // we will append the full range into the v slice before proceeding var i, cursor uint for { if i == cslen { v = append(v, cs[cursor:]...) cs = r.readUntil(d.b2[:0], '"') cslen = uint(len(cs)) i, cursor = 0, 0 } c = cs[i] if c == '"' { v = append(v, cs[cursor:i]...) break } if c != '\\' { i++ continue } v = append(v, cs[cursor:i]...) i++ c = cs[i] switch c { case '"', '\\', '/', '\'': v = append(v, c) case 'b': v = append(v, '\b') case 'f': v = append(v, '\f') case 'n': v = append(v, '\n') case 'r': v = append(v, '\r') case 't': v = append(v, '\t') case 'u': var r rune var rr uint32 if cslen < i+4 { d.d.errorf("need at least 4 more bytes for unicode sequence") } var j uint for _, c = range cs[i+1 : i+5] { // bounds-check-elimination // best to use explicit if-else // - not a table, etc which involve memory loads, array lookup with bounds checks, etc if c >= '0' && c <= '9' { rr = rr*16 + uint32(c-jsonU4Chk2) } else if c >= 'a' && c <= 'f' { rr = rr*16 + uint32(c-jsonU4Chk1) } else if c >= 'A' && c <= 'F' { rr = rr*16 + uint32(c-jsonU4Chk0) } else { r = unicode.ReplacementChar i += 4 goto encode_rune } } r = rune(rr) i += 4 if utf16.IsSurrogate(r) { if len(cs) >= int(i+6) { var cx = cs[i+1:][:6:6] // [:6] affords bounds-check-elimination if cx[0] == '\\' && cx[1] == 'u' { i += 2 var rr1 uint32 for j = 2; j < 6; j++ { c = cx[j] if c >= '0' && c <= '9' { rr = rr*16 + uint32(c-jsonU4Chk2) } else if c >= 'a' && c <= 'f' { rr = rr*16 + uint32(c-jsonU4Chk1) } else if c >= 'A' && c <= 'F' { rr = rr*16 + uint32(c-jsonU4Chk0) } else { r = unicode.ReplacementChar i += 4 goto encode_rune } } r = utf16.DecodeRune(r, rune(rr1)) i += 4 goto encode_rune } } r = unicode.ReplacementChar } encode_rune: w2 := utf8.EncodeRune(d.bstr[:], r) v = append(v, d.bstr[:w2]...) default: d.d.errorf("unsupported escaped value: %c", c) } i++ cursor = i } d.bs = v } func (d *jsonDecDriver) nakedNum(z *decNaked, bs []byte) (err error) { const cutoff = uint64(1 << uint(64-1)) var n uint64 var neg, badsyntax, overflow bool if len(bs) == 0 { if d.h.PreferFloat { z.v = valueTypeFloat z.f = 0 } else if d.h.SignedInteger { z.v = valueTypeInt z.i = 0 } else { z.v = valueTypeUint z.u = 0 } return } if d.h.PreferFloat { goto F } n, neg, badsyntax, overflow = jsonParseInteger(bs) if badsyntax || overflow { goto F } if neg { if n > cutoff { goto F } z.v = valueTypeInt z.i = -(int64(n)) } else if d.h.SignedInteger { if n >= cutoff { goto F } z.v = valueTypeInt z.i = int64(n) } else { z.v = valueTypeUint z.u = n } return F: z.v = valueTypeFloat z.f, err = strconv.ParseFloat(stringView(bs), 64) return } func (d *jsonDecDriver) bsToString() string { // if x := d.s.sc; x != nil && x.so && x.st == '}' { // map key if jsonAlwaysReturnInternString || d.d.c == containerMapKey { return d.d.string(d.bs) } return string(d.bs) } func (d *jsonDecDriver) DecodeNaked() { z := d.d.naked() // var decodeFurther bool if d.tok == 0 { d.tok = d.r.skip(&jsonCharWhitespaceSet) } switch d.tok { case 'n': d.readLit4Null() z.v = valueTypeNil case 'f': d.readLit4False() z.v = valueTypeBool z.b = false case 't': d.readLit4True() z.v = valueTypeBool z.b = true case '{': z.v = valueTypeMap // don't consume. kInterfaceNaked will call ReadMapStart case '[': z.v = valueTypeArray // don't consume. kInterfaceNaked will call ReadArrayStart case '"': // if a string, and MapKeyAsString, then try to decode it as a nil, bool or number first d.appendStringAsBytes() if len(d.bs) > 0 && d.d.c == containerMapKey && d.h.MapKeyAsString { switch stringView(d.bs) { case "null": z.v = valueTypeNil case "true": z.v = valueTypeBool z.b = true case "false": z.v = valueTypeBool z.b = false default: // check if a number: float, int or uint if err := d.nakedNum(z, d.bs); err != nil { z.v = valueTypeString z.s = d.bsToString() } } } else { z.v = valueTypeString z.s = d.bsToString() } default: // number bs := d.decNumBytes() if len(bs) == 0 { d.d.errorf("decode number from empty string") return } if err := d.nakedNum(z, bs); err != nil { d.d.errorf("decode number from %s: %v", bs, err) return } } // if decodeFurther { // d.s.sc.retryRead() // } } //---------------------- // JsonHandle is a handle for JSON encoding format. // // Json is comprehensively supported: // - decodes numbers into interface{} as int, uint or float64 // based on how the number looks and some config parameters e.g. PreferFloat, SignedInt, etc. // - decode integers from float formatted numbers e.g. 1.27e+8 // - decode any json value (numbers, bool, etc) from quoted strings // - configurable way to encode/decode []byte . // by default, encodes and decodes []byte using base64 Std Encoding // - UTF-8 support for encoding and decoding // // It has better performance than the json library in the standard library, // by leveraging the performance improvements of the codec library. // // In addition, it doesn't read more bytes than necessary during a decode, which allows // reading multiple values from a stream containing json and non-json content. // For example, a user can read a json value, then a cbor value, then a msgpack value, // all from the same stream in sequence. // // Note that, when decoding 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. type JsonHandle struct { textEncodingType BasicHandle // Indent indicates how a value is encoded. // - If positive, indent by that number of spaces. // - If negative, indent by that number of tabs. Indent int8 // IntegerAsString controls how integers (signed and unsigned) are encoded. // // Per the JSON Spec, JSON numbers are 64-bit floating point numbers. // Consequently, integers > 2^53 cannot be represented as a JSON number without losing precision. // This can be mitigated by configuring how to encode integers. // // IntegerAsString interpretes the following values: // - if 'L', then encode integers > 2^53 as a json string. // - if 'A', then encode all integers as a json string // containing the exact integer representation as a decimal. // - else encode all integers as a json number (default) IntegerAsString byte // HTMLCharsAsIs controls how to encode some special characters to html: < > & // // By default, we encode them as \uXXX // to prevent security holes when served from some browsers. HTMLCharsAsIs bool // PreferFloat says that we will default to decoding a number as a float. // If not set, we will examine the characters of the number and decode as an // integer type if it doesn't have any of the characters [.eE]. PreferFloat bool // TermWhitespace says that we add a whitespace character // at the end of an encoding. // // The whitespace is important, especially if using numbers in a context // where multiple items are written to a stream. TermWhitespace bool // MapKeyAsString says to encode all map keys as strings. // // Use this to enforce strict json output. // The only caveat is that nil value is ALWAYS written as null (never as "null") MapKeyAsString bool // _ uint64 // padding (cache line) // Note: below, we store hardly-used items // e.g. RawBytesExt (which is already cached in the (en|de)cDriver). // RawBytesExt, if configured, is used to encode and decode raw bytes in a custom way. // If not configured, raw bytes are encoded to/from base64 text. RawBytesExt InterfaceExt // _ [2]uint64 // padding } // Name returns the name of the handle: json func (h *JsonHandle) Name() string { return "json" } func (h *JsonHandle) hasElemSeparators() bool { return true } func (h *JsonHandle) typical() bool { return h.Indent == 0 && !h.MapKeyAsString && h.IntegerAsString != 'A' && h.IntegerAsString != 'L' } func (h *JsonHandle) recreateEncDriver(ed encDriver) (v bool) { _, v = ed.(*jsonEncDriverTypical) return v != h.typical() } // SetInterfaceExt sets an extension func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) { return h.SetExt(rt, tag, &interfaceExtWrapper{InterfaceExt: ext}) } func (h *JsonHandle) newEncDriver(e *Encoder) (ee encDriver) { var hd *jsonEncDriver if h.typical() { var v jsonEncDriverTypical ee = &v hd = &v.jsonEncDriver } else { var v jsonEncDriverGeneric ee = &v hd = &v.jsonEncDriver } hd.e, hd.h, hd.bs = e, h, hd.b[:0] ee.reset() return } func (h *JsonHandle) newDecDriver(d *Decoder) decDriver { // d := jsonDecDriver{r: r.(*bytesDecReader), h: h} hd := jsonDecDriver{d: d, h: h} hd.bs = hd.b[:0] hd.reset() return &hd } func (e *jsonEncDriver) reset() { e.w = e.e.w() // (htmlasis && jsonCharSafeSet.isset(b)) || jsonCharHtmlSafeSet.isset(b) if e.h.HTMLCharsAsIs { e.s = &jsonCharSafeSet } else { e.s = &jsonCharHtmlSafeSet } e.se.InterfaceExt = e.h.RawBytesExt if e.bs == nil { e.bs = e.b[:0] } else { e.bs = e.bs[:0] } } func (d *jsonDecDriver) reset() { d.r = d.d.r() d.se.InterfaceExt = d.h.RawBytesExt if d.bs != nil { d.bs = d.bs[:0] } d.tok = 0 // d.n.reset() } // jsonFloatStrconvFmtPrec ... // // ensure that every float has an 'e' or '.' in it,/ for easy differentiation from integers. // this is better/faster than checking if encoded value has [e.] and appending if needed. // func jsonFloatStrconvFmtPrec(f float64, bits32 bool) (fmt byte, prec int) { // fmt = 'f' // prec = -1 // var abs = math.Abs(f) // if abs == 0 || abs == 1 { // prec = 1 // } else if !bits32 && (abs < 1e-6 || abs >= 1e21) || // bits32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) { // fmt = 'e' // } else if _, frac := math.Modf(abs); frac == 0 { // // ensure that floats have a .0 at the end, for easy identification as floats // prec = 1 // } // return // } func jsonFloatStrconvFmtPrec64(f float64) (fmt byte, prec int8) { fmt = 'f' prec = -1 var abs = math.Abs(f) if abs == 0 || abs == 1 { prec = 1 } else if abs < 1e-6 || abs >= 1e21 { fmt = 'e' } else if noFrac64(abs) { // _, frac := math.Modf(abs); frac == 0 { prec = 1 } return } func jsonFloatStrconvFmtPrec32(f float32) (fmt byte, prec int8) { fmt = 'f' prec = -1 var abs = abs32(f) if abs == 0 || abs == 1 { prec = 1 } else if abs < 1e-6 || abs >= 1e21 { fmt = 'e' } else if noFrac32(abs) { // _, frac := math.Modf(abs); frac == 0 { prec = 1 } return } // custom-fitted version of strconv.Parse(Ui|I)nt. // Also ensures we don't have to search for .eE to determine if a float or not. // Note: s CANNOT be a zero-length slice. func jsonParseInteger(s []byte) (n uint64, neg, badSyntax, overflow bool) { const maxUint64 = (1<<64 - 1) const cutoff = maxUint64/10 + 1 if len(s) == 0 { // bounds-check-elimination // treat empty string as zero value // badSyntax = true return } switch s[0] { case '+': s = s[1:] case '-': s = s[1:] neg = true } for _, c := range s { if c < '0' || c > '9' { badSyntax = true return } // unsigned integers don't overflow well on multiplication, so check cutoff here // e.g. (maxUint64-5)*10 doesn't overflow well ... if n >= cutoff { overflow = true return } n *= 10 n1 := n + uint64(c-'0') if n1 < n || n1 > maxUint64 { overflow = true return } n = n1 } return } var _ decDriverContainerTracker = (*jsonDecDriver)(nil) var _ encDriverContainerTracker = (*jsonEncDriver)(nil) var _ decDriver = (*jsonDecDriver)(nil) var _ encDriver = (*jsonEncDriverGeneric)(nil) var _ encDriver = (*jsonEncDriverTypical)(nil) var _ (interface{ getJsonEncDriver() *jsonEncDriver }) = (*jsonEncDriverTypical)(nil) var _ (interface{ getJsonEncDriver() *jsonEncDriver }) = (*jsonEncDriverGeneric)(nil) var _ (interface{ getJsonEncDriver() *jsonEncDriver }) = (*jsonEncDriver)(nil) // var _ encDriver = (*jsonEncDriver)(nil) ================================================ FILE: vendor/github.com/ugorji/go/codec/mammoth-test.go.tmpl ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // Code generated from mammoth-test.go.tmpl - DO NOT EDIT. package codec import "testing" import "fmt" import "reflect" // TestMammoth has all the different paths optimized in fast-path // It has all the primitives, slices and maps. // // For each of those types, it has a pointer and a non-pointer field. func init() { _ = fmt.Printf } // so we can include fmt as needed type TestMammoth struct { {{range .Values }}{{if .Primitive }}{{/* */}}{{ .MethodNamePfx "F" true }} {{ .Primitive }} {{ .MethodNamePfx "Fptr" true }} *{{ .Primitive }} {{end}}{{end}} {{range .Values }}{{if not .Primitive }}{{if not .MapKey }}{{/* */}}{{ .MethodNamePfx "F" false }} []{{ .Elem }} {{ .MethodNamePfx "Fptr" false }} *[]{{ .Elem }} {{end}}{{end}}{{end}} {{range .Values }}{{if not .Primitive }}{{if .MapKey }}{{/* */}}{{ .MethodNamePfx "F" false }} map[{{ .MapKey }}]{{ .Elem }} {{ .MethodNamePfx "Fptr" false }} *map[{{ .MapKey }}]{{ .Elem }} {{end}}{{end}}{{end}} } {{range .Values }}{{if not .Primitive }}{{if not .MapKey }}{{/* */}} type {{ .MethodNamePfx "typMbs" false }} []{{ .Elem }} func (_ {{ .MethodNamePfx "typMbs" false }}) MapBySlice() { } {{end}}{{end}}{{end}} {{range .Values }}{{if not .Primitive }}{{if .MapKey }}{{/* */}} type {{ .MethodNamePfx "typMap" false }} map[{{ .MapKey }}]{{ .Elem }} {{end}}{{end}}{{end}} func doTestMammothSlices(t *testing.T, h Handle) { {{range $i, $e := .Values }}{{if not .Primitive }}{{if not .MapKey }}{{/* */}} var v{{$i}}va [8]{{ .Elem }} for _, v := range [][]{{ .Elem }}{ nil, {}, { {{ nonzerocmd .Elem }}, {{ zerocmd .Elem }}, {{ zerocmd .Elem }}, {{ nonzerocmd .Elem }} } } { {{/* // fmt.Printf(">>>> running mammoth slice v{{$i}}: %v\n", v) // - encode value to some []byte // - decode into a length-wise-equal []byte // - check if equal to initial slice // - encode ptr to the value // - check if encode bytes are same // - decode into ptrs to: nil, then 1-elem slice, equal-length, then large len slice // - decode into non-addressable slice of equal length, then larger len // - for each decode, compare elem-by-elem to the original slice // - // - rinse and repeat for a MapBySlice version // - */}} var v{{$i}}v1, v{{$i}}v2 []{{ .Elem }} v{{$i}}v1 = v bs{{$i}} := testMarshalErr(v{{$i}}v1, h, t, "enc-slice-v{{$i}}") if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make([]{{ .Elem }}, len(v)) } testUnmarshalErr(v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}") testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}") if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make([]{{ .Elem }}, len(v)) } testUnmarshalErr(reflect.ValueOf(v{{$i}}v2), bs{{$i}}, h, t, "dec-slice-v{{$i}}-noaddr") // non-addressable value testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-noaddr") // ... bs{{$i}} = testMarshalErr(&v{{$i}}v1, h, t, "enc-slice-v{{$i}}-p") v{{$i}}v2 = nil testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}-p") testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-p") v{{$i}}va = [8]{{ .Elem }}{} // clear the array v{{$i}}v2 = v{{$i}}va[:1:1] testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}-p-1") testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-p-1") v{{$i}}va = [8]{{ .Elem }}{} // clear the array v{{$i}}v2 = v{{$i}}va[:len(v{{$i}}v1):len(v{{$i}}v1)] testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}-p-len") testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-p-len") v{{$i}}va = [8]{{ .Elem }}{} // clear the array v{{$i}}v2 = v{{$i}}va[:] testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}-p-cap") testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-p-cap") if len(v{{$i}}v1) > 1 { v{{$i}}va = [8]{{ .Elem }}{} // clear the array testUnmarshalErr((&v{{$i}}va)[:len(v{{$i}}v1)], bs{{$i}}, h, t, "dec-slice-v{{$i}}-p-len-noaddr") testDeepEqualErr(v{{$i}}v1, v{{$i}}va[:len(v{{$i}}v1)], t, "equal-slice-v{{$i}}-p-len-noaddr") v{{$i}}va = [8]{{ .Elem }}{} // clear the array testUnmarshalErr((&v{{$i}}va)[:], bs{{$i}}, h, t, "dec-slice-v{{$i}}-p-cap-noaddr") testDeepEqualErr(v{{$i}}v1, v{{$i}}va[:len(v{{$i}}v1)], t, "equal-slice-v{{$i}}-p-cap-noaddr") } // ... var v{{$i}}v3, v{{$i}}v4 {{ .MethodNamePfx "typMbs" false }} v{{$i}}v2 = nil if v != nil { v{{$i}}v2 = make([]{{ .Elem }}, len(v)) } v{{$i}}v3 = {{ .MethodNamePfx "typMbs" false }}(v{{$i}}v1) v{{$i}}v4 = {{ .MethodNamePfx "typMbs" false }}(v{{$i}}v2) bs{{$i}} = testMarshalErr(v{{$i}}v3, h, t, "enc-slice-v{{$i}}-custom") testUnmarshalErr(v{{$i}}v4, bs{{$i}}, h, t, "dec-slice-v{{$i}}-custom") testDeepEqualErr(v{{$i}}v3, v{{$i}}v4, t, "equal-slice-v{{$i}}-custom") bs{{$i}} = testMarshalErr(&v{{$i}}v3, h, t, "enc-slice-v{{$i}}-custom-p") v{{$i}}v2 = nil v{{$i}}v4 = {{ .MethodNamePfx "typMbs" false }}(v{{$i}}v2) testUnmarshalErr(&v{{$i}}v4, bs{{$i}}, h, t, "dec-slice-v{{$i}}-custom-p") testDeepEqualErr(v{{$i}}v3, v{{$i}}v4, t, "equal-slice-v{{$i}}-custom-p") } {{end}}{{end}}{{end}} } func doTestMammothMaps(t *testing.T, h Handle) { {{range $i, $e := .Values }}{{if not .Primitive }}{{if .MapKey }}{{/* */}} for _, v := range []map[{{ .MapKey }}]{{ .Elem }}{ nil, {}, { {{ nonzerocmd .MapKey }}:{{ zerocmd .Elem }} {{if ne "bool" .MapKey}}, {{ nonzerocmd .MapKey }}:{{ nonzerocmd .Elem }} {{end}} } } { // fmt.Printf(">>>> running mammoth map v{{$i}}: %v\n", v) var v{{$i}}v1, v{{$i}}v2 map[{{ .MapKey }}]{{ .Elem }} v{{$i}}v1 = v bs{{$i}} := testMarshalErr(v{{$i}}v1, h, t, "enc-map-v{{$i}}") if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make(map[{{ .MapKey }}]{{ .Elem }}, len(v)) } // reset map testUnmarshalErr(v{{$i}}v2, bs{{$i}}, h, t, "dec-map-v{{$i}}") testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-map-v{{$i}}") if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make(map[{{ .MapKey }}]{{ .Elem }}, len(v)) } // reset map testUnmarshalErr(reflect.ValueOf(v{{$i}}v2), bs{{$i}}, h, t, "dec-map-v{{$i}}-noaddr") // decode into non-addressable map value testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-map-v{{$i}}-noaddr") if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make(map[{{ .MapKey }}]{{ .Elem }}, len(v)) } // reset map testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-map-v{{$i}}-p-len") testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-map-v{{$i}}-p-len") bs{{$i}} = testMarshalErr(&v{{$i}}v1, h, t, "enc-map-v{{$i}}-p") v{{$i}}v2 = nil testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-map-v{{$i}}-p-nil") testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-map-v{{$i}}-p-nil") // ... if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make(map[{{ .MapKey }}]{{ .Elem }}, len(v)) } // reset map var v{{$i}}v3, v{{$i}}v4 {{ .MethodNamePfx "typMap" false }} v{{$i}}v3 = {{ .MethodNamePfx "typMap" false }}(v{{$i}}v1) v{{$i}}v4 = {{ .MethodNamePfx "typMap" false }}(v{{$i}}v2) bs{{$i}} = testMarshalErr(v{{$i}}v3, h, t, "enc-map-v{{$i}}-custom") testUnmarshalErr(v{{$i}}v4, bs{{$i}}, h, t, "dec-map-v{{$i}}-p-len") testDeepEqualErr(v{{$i}}v3, v{{$i}}v4, t, "equal-map-v{{$i}}-p-len") } {{end}}{{end}}{{end}} } func doTestMammothMapsAndSlices(t *testing.T, h Handle) { doTestMammothSlices(t, h) doTestMammothMaps(t, h) } ================================================ FILE: vendor/github.com/ugorji/go/codec/mammoth2-test.go.tmpl ================================================ // +build !notfastpath // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // Code generated from mammoth2-test.go.tmpl - DO NOT EDIT. package codec // Increase codecoverage by covering all the codecgen paths, in fast-path and gen-helper.go.... // // Add: // - test file for creating a mammoth generated file as _mammoth_generated.go // - generate a second mammoth files in a different file: mammoth2_generated_test.go // - mammoth-test.go.tmpl will do this // - run codecgen on it, into mammoth2_codecgen_generated_test.go (no build tags) // - as part of TestMammoth, run it also // - this will cover all the codecgen, gen-helper, etc in one full run // - check in mammoth* files into github also // - then // // Now, add some types: // - some that implement BinaryMarshal, TextMarshal, JSONMarshal, and one that implements none of it // - create a wrapper type that includes TestMammoth2, with it in slices, and maps, and the custom types // - this wrapper object is what we work encode/decode (so that the codecgen methods are called) // import "encoding/binary" import "fmt" type TestMammoth2 struct { {{range .Values }}{{if .Primitive }}{{/* */}}{{ .MethodNamePfx "F" true }} {{ .Primitive }} {{ .MethodNamePfx "Fptr" true }} *{{ .Primitive }} {{end}}{{end}} {{range .Values }}{{if not .Primitive }}{{if not .MapKey }}{{/* */}}{{ .MethodNamePfx "F" false }} []{{ .Elem }} {{ .MethodNamePfx "Fptr" false }} *[]{{ .Elem }} {{end}}{{end}}{{end}} {{range .Values }}{{if not .Primitive }}{{if .MapKey }}{{/* */}}{{ .MethodNamePfx "F" false }} map[{{ .MapKey }}]{{ .Elem }} {{ .MethodNamePfx "Fptr" false }} *map[{{ .MapKey }}]{{ .Elem }} {{end}}{{end}}{{end}} } // ----------- type testMammoth2Binary uint64 func (x testMammoth2Binary) MarshalBinary() (data []byte, err error) { data = make([]byte, 8) bigen.PutUint64(data, uint64(x)) return } func (x *testMammoth2Binary) UnmarshalBinary(data []byte) (err error) { *x = testMammoth2Binary(bigen.Uint64(data)) return } type testMammoth2Text uint64 func (x testMammoth2Text) MarshalText() (data []byte, err error) { data = []byte(fmt.Sprintf("%b", uint64(x))) return } func (x *testMammoth2Text) UnmarshalText(data []byte) (err error) { _, err = fmt.Sscanf(string(data), "%b", (*uint64)(x)) return } type testMammoth2Json uint64 func (x testMammoth2Json) MarshalJSON() (data []byte, err error) { data = []byte(fmt.Sprintf("%v", uint64(x))) return } func (x *testMammoth2Json) UnmarshalJSON(data []byte) (err error) { _, err = fmt.Sscanf(string(data), "%v", (*uint64)(x)) return } type testMammoth2Basic [4]uint64 type TestMammoth2Wrapper struct { V TestMammoth2 T testMammoth2Text B testMammoth2Binary J testMammoth2Json C testMammoth2Basic M map[testMammoth2Basic]TestMammoth2 L []TestMammoth2 A [4]int64 } ================================================ FILE: vendor/github.com/ugorji/go/codec/msgpack.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. /* MSGPACK Msgpack-c implementation powers the c, c++, python, ruby, etc libraries. We need to maintain compatibility with it and how it encodes integer values without caring about the type. For compatibility with behaviour of msgpack-c reference implementation: - Go intX (>0) and uintX IS ENCODED AS msgpack +ve fixnum, unsigned - Go intX (<0) IS ENCODED AS msgpack -ve fixnum, signed */ package codec import ( "fmt" "io" "math" "net/rpc" "reflect" "time" ) const ( mpPosFixNumMin byte = 0x00 mpPosFixNumMax byte = 0x7f mpFixMapMin byte = 0x80 mpFixMapMax byte = 0x8f mpFixArrayMin byte = 0x90 mpFixArrayMax byte = 0x9f mpFixStrMin byte = 0xa0 mpFixStrMax byte = 0xbf mpNil byte = 0xc0 _ byte = 0xc1 mpFalse byte = 0xc2 mpTrue byte = 0xc3 mpFloat byte = 0xca mpDouble byte = 0xcb mpUint8 byte = 0xcc mpUint16 byte = 0xcd mpUint32 byte = 0xce mpUint64 byte = 0xcf mpInt8 byte = 0xd0 mpInt16 byte = 0xd1 mpInt32 byte = 0xd2 mpInt64 byte = 0xd3 // extensions below mpBin8 byte = 0xc4 mpBin16 byte = 0xc5 mpBin32 byte = 0xc6 mpExt8 byte = 0xc7 mpExt16 byte = 0xc8 mpExt32 byte = 0xc9 mpFixExt1 byte = 0xd4 mpFixExt2 byte = 0xd5 mpFixExt4 byte = 0xd6 mpFixExt8 byte = 0xd7 mpFixExt16 byte = 0xd8 mpStr8 byte = 0xd9 // new mpStr16 byte = 0xda mpStr32 byte = 0xdb mpArray16 byte = 0xdc mpArray32 byte = 0xdd mpMap16 byte = 0xde mpMap32 byte = 0xdf mpNegFixNumMin byte = 0xe0 mpNegFixNumMax byte = 0xff ) var mpTimeExtTag int8 = -1 var mpTimeExtTagU = uint8(mpTimeExtTag) // var mpdesc = map[byte]string{ // mpPosFixNumMin: "PosFixNumMin", // mpPosFixNumMax: "PosFixNumMax", // mpFixMapMin: "FixMapMin", // mpFixMapMax: "FixMapMax", // mpFixArrayMin: "FixArrayMin", // mpFixArrayMax: "FixArrayMax", // mpFixStrMin: "FixStrMin", // mpFixStrMax: "FixStrMax", // mpNil: "Nil", // mpFalse: "False", // mpTrue: "True", // mpFloat: "Float", // mpDouble: "Double", // mpUint8: "Uint8", // mpUint16: "Uint16", // mpUint32: "Uint32", // mpUint64: "Uint64", // mpInt8: "Int8", // mpInt16: "Int16", // mpInt32: "Int32", // mpInt64: "Int64", // mpBin8: "Bin8", // mpBin16: "Bin16", // mpBin32: "Bin32", // mpExt8: "Ext8", // mpExt16: "Ext16", // mpExt32: "Ext32", // mpFixExt1: "FixExt1", // mpFixExt2: "FixExt2", // mpFixExt4: "FixExt4", // mpFixExt8: "FixExt8", // mpFixExt16: "FixExt16", // mpStr8: "Str8", // mpStr16: "Str16", // mpStr32: "Str32", // mpArray16: "Array16", // mpArray32: "Array32", // mpMap16: "Map16", // mpMap32: "Map32", // mpNegFixNumMin: "NegFixNumMin", // mpNegFixNumMax: "NegFixNumMax", // } func mpdesc(bd byte) string { switch bd { case mpNil: return "nil" case mpFalse: return "false" case mpTrue: return "true" case mpFloat, mpDouble: return "float" case mpUint8, mpUint16, mpUint32, mpUint64: return "uint" case mpInt8, mpInt16, mpInt32, mpInt64: return "int" default: switch { case bd >= mpPosFixNumMin && bd <= mpPosFixNumMax: return "int" case bd >= mpNegFixNumMin && bd <= mpNegFixNumMax: return "int" case bd == mpStr8, bd == mpStr16, bd == mpStr32, bd >= mpFixStrMin && bd <= mpFixStrMax: return "string|bytes" case bd == mpBin8, bd == mpBin16, bd == mpBin32: return "bytes" case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax: return "array" case bd == mpMap16, bd == mpMap32, bd >= mpFixMapMin && bd <= mpFixMapMax: return "map" case bd >= mpFixExt1 && bd <= mpFixExt16, bd >= mpExt8 && bd <= mpExt32: return "ext" default: return "unknown" } } } // MsgpackSpecRpcMultiArgs is a special type which signifies to the MsgpackSpecRpcCodec // that the backend RPC service takes multiple arguments, which have been arranged // in sequence in the slice. // // The Codec then passes it AS-IS to the rpc service (without wrapping it in an // array of 1 element). type MsgpackSpecRpcMultiArgs []interface{} // A MsgpackContainer type specifies the different types of msgpackContainers. type msgpackContainerType struct { fixCutoff uint8 bFixMin, b8, b16, b32 byte // hasFixMin, has8, has8Always bool } var ( msgpackContainerRawLegacy = msgpackContainerType{ 32, mpFixStrMin, 0, mpStr16, mpStr32, } msgpackContainerStr = msgpackContainerType{ 32, mpFixStrMin, mpStr8, mpStr16, mpStr32, // true, true, false, } msgpackContainerBin = msgpackContainerType{ 0, 0, mpBin8, mpBin16, mpBin32, // false, true, true, } msgpackContainerList = msgpackContainerType{ 16, mpFixArrayMin, 0, mpArray16, mpArray32, // true, false, false, } msgpackContainerMap = msgpackContainerType{ 16, mpFixMapMin, 0, mpMap16, mpMap32, // true, false, false, } ) //--------------------------------------------- type msgpackEncDriver struct { noBuiltInTypes encDriverNoopContainerWriter // encNoSeparator e *Encoder w *encWriterSwitch h *MsgpackHandle x [8]byte // _ [3]uint64 // padding } func (e *msgpackEncDriver) EncodeNil() { e.w.writen1(mpNil) } func (e *msgpackEncDriver) EncodeInt(i int64) { if e.h.PositiveIntUnsigned && i >= 0 { e.EncodeUint(uint64(i)) } else if i > math.MaxInt8 { if i <= math.MaxInt16 { e.w.writen1(mpInt16) bigenHelper{e.x[:2], e.w}.writeUint16(uint16(i)) } else if i <= math.MaxInt32 { e.w.writen1(mpInt32) bigenHelper{e.x[:4], e.w}.writeUint32(uint32(i)) } else { e.w.writen1(mpInt64) bigenHelper{e.x[:8], e.w}.writeUint64(uint64(i)) } } else if i >= -32 { if e.h.NoFixedNum { e.w.writen2(mpInt8, byte(i)) } else { e.w.writen1(byte(i)) } } else if i >= math.MinInt8 { e.w.writen2(mpInt8, byte(i)) } else if i >= math.MinInt16 { e.w.writen1(mpInt16) bigenHelper{e.x[:2], e.w}.writeUint16(uint16(i)) } else if i >= math.MinInt32 { e.w.writen1(mpInt32) bigenHelper{e.x[:4], e.w}.writeUint32(uint32(i)) } else { e.w.writen1(mpInt64) bigenHelper{e.x[:8], e.w}.writeUint64(uint64(i)) } } func (e *msgpackEncDriver) EncodeUint(i uint64) { if i <= math.MaxInt8 { if e.h.NoFixedNum { e.w.writen2(mpUint8, byte(i)) } else { e.w.writen1(byte(i)) } } else if i <= math.MaxUint8 { e.w.writen2(mpUint8, byte(i)) } else if i <= math.MaxUint16 { e.w.writen1(mpUint16) bigenHelper{e.x[:2], e.w}.writeUint16(uint16(i)) } else if i <= math.MaxUint32 { e.w.writen1(mpUint32) bigenHelper{e.x[:4], e.w}.writeUint32(uint32(i)) } else { e.w.writen1(mpUint64) bigenHelper{e.x[:8], e.w}.writeUint64(uint64(i)) } } func (e *msgpackEncDriver) EncodeBool(b bool) { if b { e.w.writen1(mpTrue) } else { e.w.writen1(mpFalse) } } func (e *msgpackEncDriver) EncodeFloat32(f float32) { e.w.writen1(mpFloat) bigenHelper{e.x[:4], e.w}.writeUint32(math.Float32bits(f)) } func (e *msgpackEncDriver) EncodeFloat64(f float64) { e.w.writen1(mpDouble) bigenHelper{e.x[:8], e.w}.writeUint64(math.Float64bits(f)) } func (e *msgpackEncDriver) EncodeTime(t time.Time) { if t.IsZero() { e.EncodeNil() return } t = t.UTC() sec, nsec := t.Unix(), uint64(t.Nanosecond()) var data64 uint64 var l = 4 if sec >= 0 && sec>>34 == 0 { data64 = (nsec << 34) | uint64(sec) if data64&0xffffffff00000000 != 0 { l = 8 } } else { l = 12 } if e.h.WriteExt { e.encodeExtPreamble(mpTimeExtTagU, l) } else { e.writeContainerLen(msgpackContainerRawLegacy, l) } switch l { case 4: bigenHelper{e.x[:4], e.w}.writeUint32(uint32(data64)) case 8: bigenHelper{e.x[:8], e.w}.writeUint64(data64) case 12: bigenHelper{e.x[:4], e.w}.writeUint32(uint32(nsec)) bigenHelper{e.x[:8], e.w}.writeUint64(uint64(sec)) } } func (e *msgpackEncDriver) EncodeExt(v interface{}, xtag uint64, ext Ext, _ *Encoder) { bs := ext.WriteExt(v) if bs == nil { e.EncodeNil() return } if e.h.WriteExt { e.encodeExtPreamble(uint8(xtag), len(bs)) e.w.writeb(bs) } else { e.EncodeStringBytesRaw(bs) } } func (e *msgpackEncDriver) EncodeRawExt(re *RawExt, _ *Encoder) { e.encodeExtPreamble(uint8(re.Tag), len(re.Data)) e.w.writeb(re.Data) } func (e *msgpackEncDriver) encodeExtPreamble(xtag byte, l int) { if l == 1 { e.w.writen2(mpFixExt1, xtag) } else if l == 2 { e.w.writen2(mpFixExt2, xtag) } else if l == 4 { e.w.writen2(mpFixExt4, xtag) } else if l == 8 { e.w.writen2(mpFixExt8, xtag) } else if l == 16 { e.w.writen2(mpFixExt16, xtag) } else if l < 256 { e.w.writen2(mpExt8, byte(l)) e.w.writen1(xtag) } else if l < 65536 { e.w.writen1(mpExt16) bigenHelper{e.x[:2], e.w}.writeUint16(uint16(l)) e.w.writen1(xtag) } else { e.w.writen1(mpExt32) bigenHelper{e.x[:4], e.w}.writeUint32(uint32(l)) e.w.writen1(xtag) } } func (e *msgpackEncDriver) WriteArrayStart(length int) { e.writeContainerLen(msgpackContainerList, length) } func (e *msgpackEncDriver) WriteMapStart(length int) { e.writeContainerLen(msgpackContainerMap, length) } func (e *msgpackEncDriver) EncodeStringEnc(c charEncoding, s string) { slen := len(s) if e.h.WriteExt { e.writeContainerLen(msgpackContainerStr, slen) } else { e.writeContainerLen(msgpackContainerRawLegacy, slen) } if slen > 0 { e.w.writestr(s) } } func (e *msgpackEncDriver) EncodeStringBytesRaw(bs []byte) { if bs == nil { e.EncodeNil() return } slen := len(bs) if e.h.WriteExt { e.writeContainerLen(msgpackContainerBin, slen) } else { e.writeContainerLen(msgpackContainerRawLegacy, slen) } if slen > 0 { e.w.writeb(bs) } } func (e *msgpackEncDriver) writeContainerLen(ct msgpackContainerType, l int) { if ct.fixCutoff > 0 && l < int(ct.fixCutoff) { e.w.writen1(ct.bFixMin | byte(l)) } else if ct.b8 > 0 && l < 256 { e.w.writen2(ct.b8, uint8(l)) } else if l < 65536 { e.w.writen1(ct.b16) bigenHelper{e.x[:2], e.w}.writeUint16(uint16(l)) } else { e.w.writen1(ct.b32) bigenHelper{e.x[:4], e.w}.writeUint32(uint32(l)) } } //--------------------------------------------- type msgpackDecDriver struct { d *Decoder r *decReaderSwitch h *MsgpackHandle // b [scratchByteArrayLen]byte bd byte bdRead bool br bool // bytes reader noBuiltInTypes // noStreamingCodec // decNoSeparator decDriverNoopContainerReader // _ [3]uint64 // padding } // Note: This returns either a primitive (int, bool, etc) for non-containers, // or a containerType, or a specific type denoting nil or extension. // It is called when a nil interface{} is passed, leaving it up to the DecDriver // to introspect the stream and decide how best to decode. // It deciphers the value by looking at the stream first. func (d *msgpackDecDriver) DecodeNaked() { if !d.bdRead { d.readNextBd() } bd := d.bd n := d.d.naked() var decodeFurther bool switch bd { case mpNil: n.v = valueTypeNil d.bdRead = false case mpFalse: n.v = valueTypeBool n.b = false case mpTrue: n.v = valueTypeBool n.b = true case mpFloat: n.v = valueTypeFloat n.f = float64(math.Float32frombits(bigen.Uint32(d.r.readx(4)))) case mpDouble: n.v = valueTypeFloat n.f = math.Float64frombits(bigen.Uint64(d.r.readx(8))) case mpUint8: n.v = valueTypeUint n.u = uint64(d.r.readn1()) case mpUint16: n.v = valueTypeUint n.u = uint64(bigen.Uint16(d.r.readx(2))) case mpUint32: n.v = valueTypeUint n.u = uint64(bigen.Uint32(d.r.readx(4))) case mpUint64: n.v = valueTypeUint n.u = uint64(bigen.Uint64(d.r.readx(8))) case mpInt8: n.v = valueTypeInt n.i = int64(int8(d.r.readn1())) case mpInt16: n.v = valueTypeInt n.i = int64(int16(bigen.Uint16(d.r.readx(2)))) case mpInt32: n.v = valueTypeInt n.i = int64(int32(bigen.Uint32(d.r.readx(4)))) case mpInt64: n.v = valueTypeInt n.i = int64(int64(bigen.Uint64(d.r.readx(8)))) default: switch { case bd >= mpPosFixNumMin && bd <= mpPosFixNumMax: // positive fixnum (always signed) n.v = valueTypeInt n.i = int64(int8(bd)) case bd >= mpNegFixNumMin && bd <= mpNegFixNumMax: // negative fixnum n.v = valueTypeInt n.i = int64(int8(bd)) case bd == mpStr8, bd == mpStr16, bd == mpStr32, bd >= mpFixStrMin && bd <= mpFixStrMax: if d.h.WriteExt || d.h.RawToString { n.v = valueTypeString n.s = d.DecodeString() } else { n.v = valueTypeBytes n.l = d.DecodeBytes(nil, false) } case bd == mpBin8, bd == mpBin16, bd == mpBin32: decNakedReadRawBytes(d, d.d, n, d.h.RawToString) case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax: n.v = valueTypeArray decodeFurther = true case bd == mpMap16, bd == mpMap32, bd >= mpFixMapMin && bd <= mpFixMapMax: n.v = valueTypeMap decodeFurther = true case bd >= mpFixExt1 && bd <= mpFixExt16, bd >= mpExt8 && bd <= mpExt32: n.v = valueTypeExt clen := d.readExtLen() n.u = uint64(d.r.readn1()) if n.u == uint64(mpTimeExtTagU) { n.v = valueTypeTime n.t = d.decodeTime(clen) } else if d.br { n.l = d.r.readx(uint(clen)) } else { n.l = decByteSlice(d.r, clen, d.d.h.MaxInitLen, d.d.b[:]) } default: d.d.errorf("cannot infer value: %s: Ox%x/%d/%s", msgBadDesc, bd, bd, mpdesc(bd)) } } if !decodeFurther { d.bdRead = false } if n.v == valueTypeUint && d.h.SignedInteger { n.v = valueTypeInt n.i = int64(n.u) } } // int can be decoded from msgpack type: intXXX or uintXXX func (d *msgpackDecDriver) DecodeInt64() (i int64) { if !d.bdRead { d.readNextBd() } switch d.bd { case mpUint8: i = int64(uint64(d.r.readn1())) case mpUint16: i = int64(uint64(bigen.Uint16(d.r.readx(2)))) case mpUint32: i = int64(uint64(bigen.Uint32(d.r.readx(4)))) case mpUint64: i = int64(bigen.Uint64(d.r.readx(8))) case mpInt8: i = int64(int8(d.r.readn1())) case mpInt16: i = int64(int16(bigen.Uint16(d.r.readx(2)))) case mpInt32: i = int64(int32(bigen.Uint32(d.r.readx(4)))) case mpInt64: i = int64(bigen.Uint64(d.r.readx(8))) default: switch { case d.bd >= mpPosFixNumMin && d.bd <= mpPosFixNumMax: i = int64(int8(d.bd)) case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax: i = int64(int8(d.bd)) default: d.d.errorf("cannot decode signed integer: %s: %x/%s", msgBadDesc, d.bd, mpdesc(d.bd)) return } } d.bdRead = false return } // uint can be decoded from msgpack type: intXXX or uintXXX func (d *msgpackDecDriver) DecodeUint64() (ui uint64) { if !d.bdRead { d.readNextBd() } switch d.bd { case mpUint8: ui = uint64(d.r.readn1()) case mpUint16: ui = uint64(bigen.Uint16(d.r.readx(2))) case mpUint32: ui = uint64(bigen.Uint32(d.r.readx(4))) case mpUint64: ui = bigen.Uint64(d.r.readx(8)) case mpInt8: if i := int64(int8(d.r.readn1())); i >= 0 { ui = uint64(i) } else { d.d.errorf("assigning negative signed value: %v, to unsigned type", i) return } case mpInt16: if i := int64(int16(bigen.Uint16(d.r.readx(2)))); i >= 0 { ui = uint64(i) } else { d.d.errorf("assigning negative signed value: %v, to unsigned type", i) return } case mpInt32: if i := int64(int32(bigen.Uint32(d.r.readx(4)))); i >= 0 { ui = uint64(i) } else { d.d.errorf("assigning negative signed value: %v, to unsigned type", i) return } case mpInt64: if i := int64(bigen.Uint64(d.r.readx(8))); i >= 0 { ui = uint64(i) } else { d.d.errorf("assigning negative signed value: %v, to unsigned type", i) return } default: switch { case d.bd >= mpPosFixNumMin && d.bd <= mpPosFixNumMax: ui = uint64(d.bd) case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax: d.d.errorf("assigning negative signed value: %v, to unsigned type", int(d.bd)) return default: d.d.errorf("cannot decode unsigned integer: %s: %x/%s", msgBadDesc, d.bd, mpdesc(d.bd)) return } } d.bdRead = false return } // float can either be decoded from msgpack type: float, double or intX func (d *msgpackDecDriver) DecodeFloat64() (f float64) { if !d.bdRead { d.readNextBd() } if d.bd == mpFloat { f = float64(math.Float32frombits(bigen.Uint32(d.r.readx(4)))) } else if d.bd == mpDouble { f = math.Float64frombits(bigen.Uint64(d.r.readx(8))) } else { f = float64(d.DecodeInt64()) } d.bdRead = false return } // bool can be decoded from bool, fixnum 0 or 1. func (d *msgpackDecDriver) DecodeBool() (b bool) { if !d.bdRead { d.readNextBd() } if d.bd == mpFalse || d.bd == 0 { // b = false } else if d.bd == mpTrue || d.bd == 1 { b = true } else { d.d.errorf("cannot decode bool: %s: %x/%s", msgBadDesc, d.bd, mpdesc(d.bd)) return } d.bdRead = false return } func (d *msgpackDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) { if !d.bdRead { d.readNextBd() } bd := d.bd var clen int if bd == mpNil { d.bdRead = false return } else if bd == mpBin8 || bd == mpBin16 || bd == mpBin32 { clen = d.readContainerLen(msgpackContainerBin) // binary } else if bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || (bd >= mpFixStrMin && bd <= mpFixStrMax) { clen = d.readContainerLen(msgpackContainerStr) // string/raw } else if bd == mpArray16 || bd == mpArray32 || (bd >= mpFixArrayMin && bd <= mpFixArrayMax) { // check if an "array" of uint8's if zerocopy && len(bs) == 0 { bs = d.d.b[:] } bsOut, _ = fastpathTV.DecSliceUint8V(bs, true, d.d) return } else { d.d.errorf("invalid byte descriptor for decoding bytes, got: 0x%x", d.bd) return } d.bdRead = false if zerocopy { if d.br { return d.r.readx(uint(clen)) } else if len(bs) == 0 { bs = d.d.b[:] } } return decByteSlice(d.r, clen, d.h.MaxInitLen, bs) } func (d *msgpackDecDriver) DecodeString() (s string) { return string(d.DecodeBytes(d.d.b[:], true)) } func (d *msgpackDecDriver) DecodeStringAsBytes() (s []byte) { return d.DecodeBytes(d.d.b[:], true) } func (d *msgpackDecDriver) readNextBd() { d.bd = d.r.readn1() d.bdRead = true } func (d *msgpackDecDriver) uncacheRead() { if d.bdRead { d.r.unreadn1() d.bdRead = false } } func (d *msgpackDecDriver) ContainerType() (vt valueType) { if !d.bdRead { d.readNextBd() } bd := d.bd // if bd == mpNil { // // nil // } else if bd == mpBin8 || bd == mpBin16 || bd == mpBin32 { // // binary // } else if bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || // (bd >= mpFixStrMin && bd <= mpFixStrMax) { // // string/raw // } else if bd == mpArray16 || bd == mpArray32 || // (bd >= mpFixArrayMin && bd <= mpFixArrayMax) { // // array // } else if bd == mpMap16 || bd == mpMap32 || (bd >= mpFixMapMin && bd <= mpFixMapMax) { // // map // } if bd == mpNil { return valueTypeNil } else if bd == mpBin8 || bd == mpBin16 || bd == mpBin32 { return valueTypeBytes } else if bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || (bd >= mpFixStrMin && bd <= mpFixStrMax) { if d.h.WriteExt || d.h.RawToString { // UTF-8 string (new spec) return valueTypeString } return valueTypeBytes // raw (old spec) } else if bd == mpArray16 || bd == mpArray32 || (bd >= mpFixArrayMin && bd <= mpFixArrayMax) { return valueTypeArray } else if bd == mpMap16 || bd == mpMap32 || (bd >= mpFixMapMin && bd <= mpFixMapMax) { return valueTypeMap } // else { // d.d.errorf("isContainerType: unsupported parameter: %v", vt) // } return valueTypeUnset } func (d *msgpackDecDriver) TryDecodeAsNil() (v bool) { if !d.bdRead { d.readNextBd() } if d.bd == mpNil { d.bdRead = false return true } return } func (d *msgpackDecDriver) readContainerLen(ct msgpackContainerType) (clen int) { bd := d.bd if bd == mpNil { clen = -1 // to represent nil } else if bd == ct.b8 { clen = int(d.r.readn1()) } else if bd == ct.b16 { clen = int(bigen.Uint16(d.r.readx(2))) } else if bd == ct.b32 { clen = int(bigen.Uint32(d.r.readx(4))) } else if (ct.bFixMin & bd) == ct.bFixMin { clen = int(ct.bFixMin ^ bd) } else { d.d.errorf("cannot read container length: %s: hex: %x, decimal: %d", msgBadDesc, bd, bd) return } d.bdRead = false return } func (d *msgpackDecDriver) ReadMapStart() int { if !d.bdRead { d.readNextBd() } return d.readContainerLen(msgpackContainerMap) } func (d *msgpackDecDriver) ReadArrayStart() int { if !d.bdRead { d.readNextBd() } return d.readContainerLen(msgpackContainerList) } func (d *msgpackDecDriver) readExtLen() (clen int) { switch d.bd { case mpNil: clen = -1 // to represent nil case mpFixExt1: clen = 1 case mpFixExt2: clen = 2 case mpFixExt4: clen = 4 case mpFixExt8: clen = 8 case mpFixExt16: clen = 16 case mpExt8: clen = int(d.r.readn1()) case mpExt16: clen = int(bigen.Uint16(d.r.readx(2))) case mpExt32: clen = int(bigen.Uint32(d.r.readx(4))) default: d.d.errorf("decoding ext bytes: found unexpected byte: %x", d.bd) return } return } func (d *msgpackDecDriver) DecodeTime() (t time.Time) { // decode time from string bytes or ext if !d.bdRead { d.readNextBd() } bd := d.bd var clen int if bd == mpNil { d.bdRead = false return } else if bd == mpBin8 || bd == mpBin16 || bd == mpBin32 { clen = d.readContainerLen(msgpackContainerBin) // binary } else if bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || (bd >= mpFixStrMin && bd <= mpFixStrMax) { clen = d.readContainerLen(msgpackContainerStr) // string/raw } else { // expect to see mpFixExt4,-1 OR mpFixExt8,-1 OR mpExt8,12,-1 d.bdRead = false b2 := d.r.readn1() if d.bd == mpFixExt4 && b2 == mpTimeExtTagU { clen = 4 } else if d.bd == mpFixExt8 && b2 == mpTimeExtTagU { clen = 8 } else if d.bd == mpExt8 && b2 == 12 && d.r.readn1() == mpTimeExtTagU { clen = 12 } else { d.d.errorf("invalid stream for decoding time as extension: got 0x%x, 0x%x", d.bd, b2) return } } return d.decodeTime(clen) } func (d *msgpackDecDriver) decodeTime(clen int) (t time.Time) { // bs = d.r.readx(clen) d.bdRead = false switch clen { case 4: t = time.Unix(int64(bigen.Uint32(d.r.readx(4))), 0).UTC() case 8: tv := bigen.Uint64(d.r.readx(8)) t = time.Unix(int64(tv&0x00000003ffffffff), int64(tv>>34)).UTC() case 12: nsec := bigen.Uint32(d.r.readx(4)) sec := bigen.Uint64(d.r.readx(8)) t = time.Unix(int64(sec), int64(nsec)).UTC() default: d.d.errorf("invalid length of bytes for decoding time - expecting 4 or 8 or 12, got %d", clen) return } return } func (d *msgpackDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) { if xtag > 0xff { d.d.errorf("ext: tag must be <= 0xff; got: %v", xtag) return } realxtag1, xbs := d.decodeExtV(ext != nil, uint8(xtag)) realxtag = uint64(realxtag1) if ext == nil { re := rv.(*RawExt) re.Tag = realxtag re.Data = detachZeroCopyBytes(d.br, re.Data, xbs) } else { ext.ReadExt(rv, xbs) } return } func (d *msgpackDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs []byte) { if !d.bdRead { d.readNextBd() } xbd := d.bd if xbd == mpBin8 || xbd == mpBin16 || xbd == mpBin32 { xbs = d.DecodeBytes(nil, true) } else if xbd == mpStr8 || xbd == mpStr16 || xbd == mpStr32 || (xbd >= mpFixStrMin && xbd <= mpFixStrMax) { xbs = d.DecodeStringAsBytes() } else { clen := d.readExtLen() xtag = d.r.readn1() if verifyTag && xtag != tag { d.d.errorf("wrong extension tag - got %b, expecting %v", xtag, tag) return } if d.br { xbs = d.r.readx(uint(clen)) } else { xbs = decByteSlice(d.r, clen, d.d.h.MaxInitLen, d.d.b[:]) } } d.bdRead = false return } //-------------------------------------------------- //MsgpackHandle is a Handle for the Msgpack Schema-Free Encoding Format. type MsgpackHandle struct { BasicHandle // NoFixedNum says to output all signed integers as 2-bytes, never as 1-byte fixednum. NoFixedNum bool // WriteExt controls whether the new spec is honored. // // With WriteExt=true, we can encode configured extensions with extension tags // and encode string/[]byte/extensions in a way compatible with the new spec // but incompatible with the old spec. // // For compatibility with the old spec, set WriteExt=false. // // With WriteExt=false: // configured extensions are serialized as raw bytes (not msgpack extensions). // reserved byte descriptors like Str8 and those enabling the new msgpack Binary type // are not encoded. WriteExt bool // PositiveIntUnsigned says to encode positive integers as unsigned. PositiveIntUnsigned bool binaryEncodingType noElemSeparators _ [1]uint64 // padding (cache-aligned) } // Name returns the name of the handle: msgpack func (h *MsgpackHandle) Name() string { return "msgpack" } // SetBytesExt sets an extension func (h *MsgpackHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) { return h.SetExt(rt, tag, &bytesExtWrapper{BytesExt: ext}) } func (h *MsgpackHandle) newEncDriver(e *Encoder) encDriver { return &msgpackEncDriver{e: e, w: e.w(), h: h} } func (h *MsgpackHandle) newDecDriver(d *Decoder) decDriver { return &msgpackDecDriver{d: d, h: h, r: d.r(), br: d.bytes} } func (e *msgpackEncDriver) reset() { e.w = e.e.w() } func (d *msgpackDecDriver) reset() { d.r, d.br = d.d.r(), d.d.bytes d.bd, d.bdRead = 0, false } //-------------------------------------------------- type msgpackSpecRpcCodec struct { rpcCodec } // /////////////// Spec RPC Codec /////////////////// func (c *msgpackSpecRpcCodec) WriteRequest(r *rpc.Request, body interface{}) error { // WriteRequest can write to both a Go service, and other services that do // not abide by the 1 argument rule of a Go service. // We discriminate based on if the body is a MsgpackSpecRpcMultiArgs var bodyArr []interface{} if m, ok := body.(MsgpackSpecRpcMultiArgs); ok { bodyArr = ([]interface{})(m) } else { bodyArr = []interface{}{body} } r2 := []interface{}{0, uint32(r.Seq), r.ServiceMethod, bodyArr} return c.write(r2, nil, false) } func (c *msgpackSpecRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error { var moe interface{} if r.Error != "" { moe = r.Error } if moe != nil && body != nil { body = nil } r2 := []interface{}{1, uint32(r.Seq), moe, body} return c.write(r2, nil, false) } func (c *msgpackSpecRpcCodec) ReadResponseHeader(r *rpc.Response) error { return c.parseCustomHeader(1, &r.Seq, &r.Error) } func (c *msgpackSpecRpcCodec) ReadRequestHeader(r *rpc.Request) error { return c.parseCustomHeader(0, &r.Seq, &r.ServiceMethod) } func (c *msgpackSpecRpcCodec) ReadRequestBody(body interface{}) error { if body == nil { // read and discard return c.read(nil) } bodyArr := []interface{}{body} return c.read(&bodyArr) } func (c *msgpackSpecRpcCodec) parseCustomHeader(expectTypeByte byte, msgid *uint64, methodOrError *string) (err error) { if cls := c.cls.load(); cls.closed { return io.EOF } // We read the response header by hand // so that the body can be decoded on its own from the stream at a later time. const fia byte = 0x94 //four item array descriptor value // Not sure why the panic of EOF is swallowed above. // if bs1 := c.dec.r.readn1(); bs1 != fia { // err = fmt.Errorf("Unexpected value for array descriptor: Expecting %v. Received %v", fia, bs1) // return // } var ba [1]byte var n int for { n, err = c.r.Read(ba[:]) if err != nil { return } if n == 1 { break } } var b = ba[0] if b != fia { err = fmt.Errorf("not array - %s %x/%s", msgBadDesc, b, mpdesc(b)) } else { err = c.read(&b) if err == nil { if b != expectTypeByte { err = fmt.Errorf("%s - expecting %v but got %x/%s", msgBadDesc, expectTypeByte, b, mpdesc(b)) } else { err = c.read(msgid) if err == nil { err = c.read(methodOrError) } } } } return } //-------------------------------------------------- // msgpackSpecRpc is the implementation of Rpc that uses custom communication protocol // as defined in the msgpack spec at https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md type msgpackSpecRpc struct{} // MsgpackSpecRpc implements Rpc using the communication protocol defined in // the msgpack spec at https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md . // // See GoRpc documentation, for information on buffering for better performance. var MsgpackSpecRpc msgpackSpecRpc func (x msgpackSpecRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec { return &msgpackSpecRpcCodec{newRPCCodec(conn, h)} } func (x msgpackSpecRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec { return &msgpackSpecRpcCodec{newRPCCodec(conn, h)} } var _ decDriver = (*msgpackDecDriver)(nil) var _ encDriver = (*msgpackEncDriver)(nil) ================================================ FILE: vendor/github.com/ugorji/go/codec/prebuild.go ================================================ // +build prebuild package main import ( "bytes" "go/format" "io/ioutil" "os" "strings" "text/template" ) func genInternalSortableTypes() []string { return []string{ "string", "float32", "float64", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", "int", "int8", "int16", "int32", "int64", "bool", "time", "bytes", } } func genInternalSortablePlusTypes() []string { return []string{ "string", "float64", "uint64", "uintptr", "int64", "bool", "time", "bytes", } } func genTypeForShortName(s string) string { switch s { case "time": return "time.Time" case "bytes": return "[]byte" } return s } func genArgs(args ...interface{}) map[string]interface{} { m := make(map[string]interface{}, len(args)/2) for i := 0; i < len(args); { m[args[i].(string)] = args[i+1] i += 2 } return m } func genEndsWith(s0 string, sn ...string) bool { for _, s := range sn { if strings.HasSuffix(s0, s) { return true } } return false } func chkerr(err error) { if err != nil { panic(err) } } func run(fnameIn, fnameOut string) { var err error funcs := make(template.FuncMap) funcs["sortables"] = genInternalSortableTypes funcs["sortablesplus"] = genInternalSortablePlusTypes funcs["tshort"] = genTypeForShortName funcs["endswith"] = genEndsWith funcs["args"] = genArgs t := template.New("").Funcs(funcs) fin, err := os.Open(fnameIn) chkerr(err) defer fin.Close() fout, err := os.Create(fnameOut) chkerr(err) defer fout.Close() tmplstr, err := ioutil.ReadAll(fin) chkerr(err) t, err = t.Parse(string(tmplstr)) chkerr(err) var out bytes.Buffer err = t.Execute(&out, 0) chkerr(err) bout, err := format.Source(out.Bytes()) if err != nil { fout.Write(out.Bytes()) // write out if error, so we can still see. // w.Write(bout) // write out if error, as much as possible, so we can still see. } chkerr(err) _, err = fout.Write(bout) chkerr(err) } func main() { run("sort-slice.go.tmpl", "sort-slice.generated.go") } ================================================ FILE: vendor/github.com/ugorji/go/codec/rpc.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. package codec import ( "bufio" "errors" "io" "net/rpc" ) var errRpcJsonNeedsTermWhitespace = errors.New("rpc requires JsonHandle with TermWhitespace=true") // Rpc provides a rpc Server or Client Codec for rpc communication. type Rpc interface { ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec } // RPCOptions holds options specific to rpc functionality type RPCOptions struct { // RPCNoBuffer configures whether we attempt to buffer reads and writes during RPC calls. // // Set RPCNoBuffer=true to turn buffering off. // Buffering can still be done if buffered connections are passed in, or // buffering is configured on the handle. RPCNoBuffer bool } // rpcCodec defines the struct members and common methods. type rpcCodec struct { c io.Closer r io.Reader w io.Writer f ioFlusher dec *Decoder enc *Encoder // bw *bufio.Writer // br *bufio.Reader h Handle cls atomicClsErr } func newRPCCodec(conn io.ReadWriteCloser, h Handle) rpcCodec { // return newRPCCodec2(bufio.NewReader(conn), bufio.NewWriter(conn), conn, h) return newRPCCodec2(conn, conn, conn, h) } func newRPCCodec2(r io.Reader, w io.Writer, c io.Closer, h Handle) rpcCodec { // defensive: ensure that jsonH has TermWhitespace turned on. if jsonH, ok := h.(*JsonHandle); ok && !jsonH.TermWhitespace { panic(errRpcJsonNeedsTermWhitespace) } // always ensure that we use a flusher, and always flush what was written to the connection. // we lose nothing by using a buffered writer internally. f, ok := w.(ioFlusher) bh := basicHandle(h) if !bh.RPCNoBuffer { if bh.WriterBufferSize <= 0 { if !ok { bw := bufio.NewWriter(w) f, w = bw, bw } } if bh.ReaderBufferSize <= 0 { if _, ok = w.(ioPeeker); !ok { if _, ok = w.(ioBuffered); !ok { br := bufio.NewReader(r) r = br } } } } return rpcCodec{ c: c, w: w, r: r, f: f, h: h, enc: NewEncoder(w, h), dec: NewDecoder(r, h), } } func (c *rpcCodec) write(obj1, obj2 interface{}, writeObj2 bool) (err error) { if c.c != nil { cls := c.cls.load() if cls.closed { return cls.errClosed } } err = c.enc.Encode(obj1) if err == nil { if writeObj2 { err = c.enc.Encode(obj2) } // if err == nil && c.f != nil { // err = c.f.Flush() // } } if c.f != nil { if err == nil { err = c.f.Flush() } else { _ = c.f.Flush() // swallow flush error, so we maintain prior error on write } } return } func (c *rpcCodec) swallow(err *error) { defer panicToErr(c.dec, err) c.dec.swallow() } func (c *rpcCodec) read(obj interface{}) (err error) { if c.c != nil { cls := c.cls.load() if cls.closed { return cls.errClosed } } //If nil is passed in, we should read and discard if obj == nil { // var obj2 interface{} // return c.dec.Decode(&obj2) c.swallow(&err) return } return c.dec.Decode(obj) } func (c *rpcCodec) Close() error { if c.c == nil { return nil } cls := c.cls.load() if cls.closed { return cls.errClosed } cls.errClosed = c.c.Close() cls.closed = true c.cls.store(cls) return cls.errClosed } func (c *rpcCodec) ReadResponseBody(body interface{}) error { return c.read(body) } // ------------------------------------- type goRpcCodec struct { rpcCodec } func (c *goRpcCodec) WriteRequest(r *rpc.Request, body interface{}) error { return c.write(r, body, true) } func (c *goRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error { return c.write(r, body, true) } func (c *goRpcCodec) ReadResponseHeader(r *rpc.Response) error { return c.read(r) } func (c *goRpcCodec) ReadRequestHeader(r *rpc.Request) error { return c.read(r) } func (c *goRpcCodec) ReadRequestBody(body interface{}) error { return c.read(body) } // ------------------------------------- // goRpc is the implementation of Rpc that uses the communication protocol // as defined in net/rpc package. type goRpc struct{} // GoRpc implements Rpc using the communication protocol defined in net/rpc package. // // Note: network connection (from net.Dial, of type io.ReadWriteCloser) is not buffered. // // For performance, you should configure WriterBufferSize and ReaderBufferSize on the handle. // This ensures we use an adequate buffer during reading and writing. // If not configured, we will internally initialize and use a buffer during reads and writes. // This can be turned off via the RPCNoBuffer option on the Handle. // var handle codec.JsonHandle // handle.RPCNoBuffer = true // turns off attempt by rpc module to initialize a buffer // // Example 1: one way of configuring buffering explicitly: // var handle codec.JsonHandle // codec handle // handle.ReaderBufferSize = 1024 // handle.WriterBufferSize = 1024 // var conn io.ReadWriteCloser // connection got from a socket // var serverCodec = GoRpc.ServerCodec(conn, handle) // var clientCodec = GoRpc.ClientCodec(conn, handle) // // Example 2: you can also explicitly create a buffered connection yourself, // and not worry about configuring the buffer sizes in the Handle. // var handle codec.Handle // codec handle // var conn io.ReadWriteCloser // connection got from a socket // var bufconn = struct { // bufconn here is a buffered io.ReadWriteCloser // io.Closer // *bufio.Reader // *bufio.Writer // }{conn, bufio.NewReader(conn), bufio.NewWriter(conn)} // var serverCodec = GoRpc.ServerCodec(bufconn, handle) // var clientCodec = GoRpc.ClientCodec(bufconn, handle) // var GoRpc goRpc func (x goRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec { return &goRpcCodec{newRPCCodec(conn, h)} } func (x goRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec { return &goRpcCodec{newRPCCodec(conn, h)} } ================================================ FILE: vendor/github.com/ugorji/go/codec/simple.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. package codec import ( "math" "reflect" "time" ) const ( _ uint8 = iota simpleVdNil = 1 simpleVdFalse = 2 simpleVdTrue = 3 simpleVdFloat32 = 4 simpleVdFloat64 = 5 // each lasts for 4 (ie n, n+1, n+2, n+3) simpleVdPosInt = 8 simpleVdNegInt = 12 simpleVdTime = 24 // containers: each lasts for 4 (ie n, n+1, n+2, ... n+7) simpleVdString = 216 simpleVdByteArray = 224 simpleVdArray = 232 simpleVdMap = 240 simpleVdExt = 248 ) type simpleEncDriver struct { noBuiltInTypes encDriverNoopContainerWriter // encNoSeparator e *Encoder h *SimpleHandle w *encWriterSwitch b [8]byte // c containerState // encDriverTrackContainerWriter _ [2]uint64 // padding (cache-aligned) } func (e *simpleEncDriver) EncodeNil() { e.w.writen1(simpleVdNil) } func (e *simpleEncDriver) EncodeBool(b bool) { if e.h.EncZeroValuesAsNil && e.e.c != containerMapKey && !b { e.EncodeNil() return } if b { e.w.writen1(simpleVdTrue) } else { e.w.writen1(simpleVdFalse) } } func (e *simpleEncDriver) EncodeFloat32(f float32) { if e.h.EncZeroValuesAsNil && e.e.c != containerMapKey && f == 0.0 { e.EncodeNil() return } e.w.writen1(simpleVdFloat32) bigenHelper{e.b[:4], e.w}.writeUint32(math.Float32bits(f)) } func (e *simpleEncDriver) EncodeFloat64(f float64) { if e.h.EncZeroValuesAsNil && e.e.c != containerMapKey && f == 0.0 { e.EncodeNil() return } e.w.writen1(simpleVdFloat64) bigenHelper{e.b[:8], e.w}.writeUint64(math.Float64bits(f)) } func (e *simpleEncDriver) EncodeInt(v int64) { if v < 0 { e.encUint(uint64(-v), simpleVdNegInt) } else { e.encUint(uint64(v), simpleVdPosInt) } } func (e *simpleEncDriver) EncodeUint(v uint64) { e.encUint(v, simpleVdPosInt) } func (e *simpleEncDriver) encUint(v uint64, bd uint8) { if e.h.EncZeroValuesAsNil && e.e.c != containerMapKey && v == 0 { e.EncodeNil() return } if v <= math.MaxUint8 { e.w.writen2(bd, uint8(v)) } else if v <= math.MaxUint16 { e.w.writen1(bd + 1) bigenHelper{e.b[:2], e.w}.writeUint16(uint16(v)) } else if v <= math.MaxUint32 { e.w.writen1(bd + 2) bigenHelper{e.b[:4], e.w}.writeUint32(uint32(v)) } else { // if v <= math.MaxUint64 { e.w.writen1(bd + 3) bigenHelper{e.b[:8], e.w}.writeUint64(v) } } func (e *simpleEncDriver) encLen(bd byte, length int) { if length == 0 { e.w.writen1(bd) } else if length <= math.MaxUint8 { e.w.writen1(bd + 1) e.w.writen1(uint8(length)) } else if length <= math.MaxUint16 { e.w.writen1(bd + 2) bigenHelper{e.b[:2], e.w}.writeUint16(uint16(length)) } else if int64(length) <= math.MaxUint32 { e.w.writen1(bd + 3) bigenHelper{e.b[:4], e.w}.writeUint32(uint32(length)) } else { e.w.writen1(bd + 4) bigenHelper{e.b[:8], e.w}.writeUint64(uint64(length)) } } func (e *simpleEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext, _ *Encoder) { bs := ext.WriteExt(rv) if bs == nil { e.EncodeNil() return } e.encodeExtPreamble(uint8(xtag), len(bs)) e.w.writeb(bs) } func (e *simpleEncDriver) EncodeRawExt(re *RawExt, _ *Encoder) { e.encodeExtPreamble(uint8(re.Tag), len(re.Data)) e.w.writeb(re.Data) } func (e *simpleEncDriver) encodeExtPreamble(xtag byte, length int) { e.encLen(simpleVdExt, length) e.w.writen1(xtag) } func (e *simpleEncDriver) WriteArrayStart(length int) { e.encLen(simpleVdArray, length) } func (e *simpleEncDriver) WriteMapStart(length int) { e.encLen(simpleVdMap, length) } // func (e *simpleEncDriver) EncodeSymbol(v string) { // e.EncodeStringEnc(cUTF8, v) // } func (e *simpleEncDriver) EncodeStringEnc(c charEncoding, v string) { if false && e.h.EncZeroValuesAsNil && e.e.c != containerMapKey && v == "" { e.EncodeNil() return } e.encLen(simpleVdString, len(v)) e.w.writestr(v) } func (e *simpleEncDriver) EncodeStringBytesRaw(v []byte) { // if e.h.EncZeroValuesAsNil && e.c != containerMapKey && v == nil { if v == nil { e.EncodeNil() return } e.encLen(simpleVdByteArray, len(v)) e.w.writeb(v) } func (e *simpleEncDriver) EncodeTime(t time.Time) { // if e.h.EncZeroValuesAsNil && e.c != containerMapKey && t.IsZero() { if t.IsZero() { e.EncodeNil() return } v, err := t.MarshalBinary() if err != nil { e.e.errorv(err) return } // time.Time marshalbinary takes about 14 bytes. e.w.writen2(simpleVdTime, uint8(len(v))) e.w.writeb(v) } //------------------------------------ type simpleDecDriver struct { d *Decoder h *SimpleHandle r *decReaderSwitch bdRead bool bd byte br bool // a bytes reader? // c containerState // b [scratchByteArrayLen]byte noBuiltInTypes // noStreamingCodec decDriverNoopContainerReader // _ [3]uint64 // padding } func (d *simpleDecDriver) readNextBd() { d.bd = d.r.readn1() d.bdRead = true } func (d *simpleDecDriver) uncacheRead() { if d.bdRead { d.r.unreadn1() d.bdRead = false } } func (d *simpleDecDriver) ContainerType() (vt valueType) { if !d.bdRead { d.readNextBd() } switch d.bd { case simpleVdNil: return valueTypeNil case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4: return valueTypeBytes case simpleVdString, simpleVdString + 1, simpleVdString + 2, simpleVdString + 3, simpleVdString + 4: return valueTypeString case simpleVdArray, simpleVdArray + 1, simpleVdArray + 2, simpleVdArray + 3, simpleVdArray + 4: return valueTypeArray case simpleVdMap, simpleVdMap + 1, simpleVdMap + 2, simpleVdMap + 3, simpleVdMap + 4: return valueTypeMap // case simpleVdTime: // return valueTypeTime } // else { // d.d.errorf("isContainerType: unsupported parameter: %v", vt) // } return valueTypeUnset } func (d *simpleDecDriver) TryDecodeAsNil() bool { if !d.bdRead { d.readNextBd() } if d.bd == simpleVdNil { d.bdRead = false return true } return false } func (d *simpleDecDriver) decCheckInteger() (ui uint64, neg bool) { if !d.bdRead { d.readNextBd() } switch d.bd { case simpleVdPosInt: ui = uint64(d.r.readn1()) case simpleVdPosInt + 1: ui = uint64(bigen.Uint16(d.r.readx(2))) case simpleVdPosInt + 2: ui = uint64(bigen.Uint32(d.r.readx(4))) case simpleVdPosInt + 3: ui = uint64(bigen.Uint64(d.r.readx(8))) case simpleVdNegInt: ui = uint64(d.r.readn1()) neg = true case simpleVdNegInt + 1: ui = uint64(bigen.Uint16(d.r.readx(2))) neg = true case simpleVdNegInt + 2: ui = uint64(bigen.Uint32(d.r.readx(4))) neg = true case simpleVdNegInt + 3: ui = uint64(bigen.Uint64(d.r.readx(8))) neg = true default: d.d.errorf("integer only valid from pos/neg integer1..8. Invalid descriptor: %v", d.bd) return } // don't do this check, because callers may only want the unsigned value. // if ui > math.MaxInt64 { // d.d.errorf("decIntAny: Integer out of range for signed int64: %v", ui) // return // } return } func (d *simpleDecDriver) DecodeInt64() (i int64) { ui, neg := d.decCheckInteger() i = chkOvf.SignedIntV(ui) if neg { i = -i } d.bdRead = false return } func (d *simpleDecDriver) DecodeUint64() (ui uint64) { ui, neg := d.decCheckInteger() if neg { d.d.errorf("assigning negative signed value to unsigned type") return } d.bdRead = false return } func (d *simpleDecDriver) DecodeFloat64() (f float64) { if !d.bdRead { d.readNextBd() } if d.bd == simpleVdFloat32 { f = float64(math.Float32frombits(bigen.Uint32(d.r.readx(4)))) } else if d.bd == simpleVdFloat64 { f = math.Float64frombits(bigen.Uint64(d.r.readx(8))) } else { if d.bd >= simpleVdPosInt && d.bd <= simpleVdNegInt+3 { f = float64(d.DecodeInt64()) } else { d.d.errorf("float only valid from float32/64: Invalid descriptor: %v", d.bd) return } } d.bdRead = false return } // bool can be decoded from bool only (single byte). func (d *simpleDecDriver) DecodeBool() (b bool) { if !d.bdRead { d.readNextBd() } if d.bd == simpleVdTrue { b = true } else if d.bd == simpleVdFalse { } else { d.d.errorf("cannot decode bool - %s: %x", msgBadDesc, d.bd) return } d.bdRead = false return } func (d *simpleDecDriver) ReadMapStart() (length int) { if !d.bdRead { d.readNextBd() } d.bdRead = false return d.decLen() } func (d *simpleDecDriver) ReadArrayStart() (length int) { if !d.bdRead { d.readNextBd() } d.bdRead = false return d.decLen() } func (d *simpleDecDriver) decLen() int { switch d.bd % 8 { case 0: return 0 case 1: return int(d.r.readn1()) case 2: return int(bigen.Uint16(d.r.readx(2))) case 3: ui := uint64(bigen.Uint32(d.r.readx(4))) if chkOvf.Uint(ui, intBitsize) { d.d.errorf("overflow integer: %v", ui) return 0 } return int(ui) case 4: ui := bigen.Uint64(d.r.readx(8)) if chkOvf.Uint(ui, intBitsize) { d.d.errorf("overflow integer: %v", ui) return 0 } return int(ui) } d.d.errorf("cannot read length: bd%%8 must be in range 0..4. Got: %d", d.bd%8) return -1 } func (d *simpleDecDriver) DecodeString() (s string) { return string(d.DecodeBytes(d.d.b[:], true)) } func (d *simpleDecDriver) DecodeStringAsBytes() (s []byte) { return d.DecodeBytes(d.d.b[:], true) } func (d *simpleDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) { if !d.bdRead { d.readNextBd() } if d.bd == simpleVdNil { d.bdRead = false return } // check if an "array" of uint8's (see ContainerType for how to infer if an array) if d.bd >= simpleVdArray && d.bd <= simpleVdMap+4 { if len(bs) == 0 && zerocopy { bs = d.d.b[:] } bsOut, _ = fastpathTV.DecSliceUint8V(bs, true, d.d) return } clen := d.decLen() d.bdRead = false if zerocopy { if d.br { return d.r.readx(uint(clen)) } else if len(bs) == 0 { bs = d.d.b[:] } } return decByteSlice(d.r, clen, d.d.h.MaxInitLen, bs) } func (d *simpleDecDriver) DecodeTime() (t time.Time) { if !d.bdRead { d.readNextBd() } if d.bd == simpleVdNil { d.bdRead = false return } if d.bd != simpleVdTime { d.d.errorf("invalid descriptor for time.Time - expect 0x%x, received 0x%x", simpleVdTime, d.bd) return } d.bdRead = false clen := int(d.r.readn1()) b := d.r.readx(uint(clen)) if err := (&t).UnmarshalBinary(b); err != nil { d.d.errorv(err) } return } func (d *simpleDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) { if xtag > 0xff { d.d.errorf("ext: tag must be <= 0xff; got: %v", xtag) return } realxtag1, xbs := d.decodeExtV(ext != nil, uint8(xtag)) realxtag = uint64(realxtag1) if ext == nil { re := rv.(*RawExt) re.Tag = realxtag re.Data = detachZeroCopyBytes(d.br, re.Data, xbs) } else { ext.ReadExt(rv, xbs) } return } func (d *simpleDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs []byte) { if !d.bdRead { d.readNextBd() } switch d.bd { case simpleVdExt, simpleVdExt + 1, simpleVdExt + 2, simpleVdExt + 3, simpleVdExt + 4: l := d.decLen() xtag = d.r.readn1() if verifyTag && xtag != tag { d.d.errorf("wrong extension tag. Got %b. Expecting: %v", xtag, tag) return } if d.br { xbs = d.r.readx(uint(l)) } else { xbs = decByteSlice(d.r, l, d.d.h.MaxInitLen, d.d.b[:]) } case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4: xbs = d.DecodeBytes(nil, true) default: d.d.errorf("ext - %s - expecting extensions/bytearray, got: 0x%x", msgBadDesc, d.bd) return } d.bdRead = false return } func (d *simpleDecDriver) DecodeNaked() { if !d.bdRead { d.readNextBd() } n := d.d.naked() var decodeFurther bool switch d.bd { case simpleVdNil: n.v = valueTypeNil case simpleVdFalse: n.v = valueTypeBool n.b = false case simpleVdTrue: n.v = valueTypeBool n.b = true case simpleVdPosInt, simpleVdPosInt + 1, simpleVdPosInt + 2, simpleVdPosInt + 3: if d.h.SignedInteger { n.v = valueTypeInt n.i = d.DecodeInt64() } else { n.v = valueTypeUint n.u = d.DecodeUint64() } case simpleVdNegInt, simpleVdNegInt + 1, simpleVdNegInt + 2, simpleVdNegInt + 3: n.v = valueTypeInt n.i = d.DecodeInt64() case simpleVdFloat32: n.v = valueTypeFloat n.f = d.DecodeFloat64() case simpleVdFloat64: n.v = valueTypeFloat n.f = d.DecodeFloat64() case simpleVdTime: n.v = valueTypeTime n.t = d.DecodeTime() case simpleVdString, simpleVdString + 1, simpleVdString + 2, simpleVdString + 3, simpleVdString + 4: n.v = valueTypeString n.s = d.DecodeString() case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4: decNakedReadRawBytes(d, d.d, n, d.h.RawToString) case simpleVdExt, simpleVdExt + 1, simpleVdExt + 2, simpleVdExt + 3, simpleVdExt + 4: n.v = valueTypeExt l := d.decLen() n.u = uint64(d.r.readn1()) if d.br { n.l = d.r.readx(uint(l)) } else { n.l = decByteSlice(d.r, l, d.d.h.MaxInitLen, d.d.b[:]) } case simpleVdArray, simpleVdArray + 1, simpleVdArray + 2, simpleVdArray + 3, simpleVdArray + 4: n.v = valueTypeArray decodeFurther = true case simpleVdMap, simpleVdMap + 1, simpleVdMap + 2, simpleVdMap + 3, simpleVdMap + 4: n.v = valueTypeMap decodeFurther = true default: d.d.errorf("cannot infer value - %s 0x%x", msgBadDesc, d.bd) } if !decodeFurther { d.bdRead = false } } //------------------------------------ // SimpleHandle is a Handle for a very simple encoding format. // // simple is a simplistic codec similar to binc, but not as compact. // - Encoding of a value is always preceded by the descriptor byte (bd) // - True, false, nil are encoded fully in 1 byte (the descriptor) // - Integers (intXXX, uintXXX) are encoded in 1, 2, 4 or 8 bytes (plus a descriptor byte). // There are positive (uintXXX and intXXX >= 0) and negative (intXXX < 0) integers. // - Floats are encoded in 4 or 8 bytes (plus a descriptor byte) // - Length of containers (strings, bytes, array, map, extensions) // are encoded in 0, 1, 2, 4 or 8 bytes. // Zero-length containers have no length encoded. // For others, the number of bytes is given by pow(2, bd%3) // - maps are encoded as [bd] [length] [[key][value]]... // - arrays are encoded as [bd] [length] [value]... // - extensions are encoded as [bd] [length] [tag] [byte]... // - strings/bytearrays are encoded as [bd] [length] [byte]... // - time.Time are encoded as [bd] [length] [byte]... // // The full spec will be published soon. type SimpleHandle struct { BasicHandle binaryEncodingType noElemSeparators // EncZeroValuesAsNil says to encode zero values for numbers, bool, string, etc as nil EncZeroValuesAsNil bool _ [1]uint64 // padding (cache-aligned) } // Name returns the name of the handle: simple func (h *SimpleHandle) Name() string { return "simple" } // SetBytesExt sets an extension func (h *SimpleHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) { return h.SetExt(rt, tag, &bytesExtWrapper{BytesExt: ext}) } // func (h *SimpleHandle) hasElemSeparators() bool { return true } // as it implements Write(Map|Array)XXX func (h *SimpleHandle) newEncDriver(e *Encoder) encDriver { return &simpleEncDriver{e: e, w: e.w(), h: h} } func (h *SimpleHandle) newDecDriver(d *Decoder) decDriver { return &simpleDecDriver{d: d, h: h, r: d.r(), br: d.bytes} } func (e *simpleEncDriver) reset() { e.w = e.e.w() } func (d *simpleDecDriver) reset() { d.r, d.br = d.d.r(), d.d.bytes d.bd, d.bdRead = 0, false } var _ decDriver = (*simpleDecDriver)(nil) var _ encDriver = (*simpleEncDriver)(nil) ================================================ FILE: vendor/github.com/ugorji/go/codec/sort-slice.generated.go ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // Code generated from sort-slice.go.tmpl - DO NOT EDIT. package codec import "time" import "reflect" import "bytes" type stringSlice []string func (p stringSlice) Len() int { return len(p) } func (p stringSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p stringSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } type float32Slice []float32 func (p float32Slice) Len() int { return len(p) } func (p float32Slice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p float32Slice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] || isNaN32(p[uint(i)]) && !isNaN32(p[uint(j)]) } type float64Slice []float64 func (p float64Slice) Len() int { return len(p) } func (p float64Slice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p float64Slice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] || isNaN64(p[uint(i)]) && !isNaN64(p[uint(j)]) } type uintSlice []uint func (p uintSlice) Len() int { return len(p) } func (p uintSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p uintSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } type uint8Slice []uint8 func (p uint8Slice) Len() int { return len(p) } func (p uint8Slice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p uint8Slice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } type uint16Slice []uint16 func (p uint16Slice) Len() int { return len(p) } func (p uint16Slice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p uint16Slice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } type uint32Slice []uint32 func (p uint32Slice) Len() int { return len(p) } func (p uint32Slice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p uint32Slice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } type uint64Slice []uint64 func (p uint64Slice) Len() int { return len(p) } func (p uint64Slice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p uint64Slice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } type uintptrSlice []uintptr func (p uintptrSlice) Len() int { return len(p) } func (p uintptrSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p uintptrSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } type intSlice []int func (p intSlice) Len() int { return len(p) } func (p intSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p intSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } type int8Slice []int8 func (p int8Slice) Len() int { return len(p) } func (p int8Slice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p int8Slice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } type int16Slice []int16 func (p int16Slice) Len() int { return len(p) } func (p int16Slice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p int16Slice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } type int32Slice []int32 func (p int32Slice) Len() int { return len(p) } func (p int32Slice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p int32Slice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } type int64Slice []int64 func (p int64Slice) Len() int { return len(p) } func (p int64Slice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p int64Slice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } type boolSlice []bool func (p boolSlice) Len() int { return len(p) } func (p boolSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p boolSlice) Less(i, j int) bool { return !p[uint(i)] && p[uint(j)] } type timeSlice []time.Time func (p timeSlice) Len() int { return len(p) } func (p timeSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p timeSlice) Less(i, j int) bool { return p[uint(i)].Before(p[uint(j)]) } type bytesSlice [][]byte func (p bytesSlice) Len() int { return len(p) } func (p bytesSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p bytesSlice) Less(i, j int) bool { return bytes.Compare(p[uint(i)], p[uint(j)]) == -1 } type stringRv struct { v string r reflect.Value } type stringRvSlice []stringRv func (p stringRvSlice) Len() int { return len(p) } func (p stringRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p stringRvSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v } type stringIntf struct { v string i interface{} } type stringIntfSlice []stringIntf func (p stringIntfSlice) Len() int { return len(p) } func (p stringIntfSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p stringIntfSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v } type float64Rv struct { v float64 r reflect.Value } type float64RvSlice []float64Rv func (p float64RvSlice) Len() int { return len(p) } func (p float64RvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p float64RvSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v || isNaN64(p[uint(i)].v) && !isNaN64(p[uint(j)].v) } type float64Intf struct { v float64 i interface{} } type float64IntfSlice []float64Intf func (p float64IntfSlice) Len() int { return len(p) } func (p float64IntfSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p float64IntfSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v || isNaN64(p[uint(i)].v) && !isNaN64(p[uint(j)].v) } type uint64Rv struct { v uint64 r reflect.Value } type uint64RvSlice []uint64Rv func (p uint64RvSlice) Len() int { return len(p) } func (p uint64RvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p uint64RvSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v } type uint64Intf struct { v uint64 i interface{} } type uint64IntfSlice []uint64Intf func (p uint64IntfSlice) Len() int { return len(p) } func (p uint64IntfSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p uint64IntfSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v } type uintptrRv struct { v uintptr r reflect.Value } type uintptrRvSlice []uintptrRv func (p uintptrRvSlice) Len() int { return len(p) } func (p uintptrRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p uintptrRvSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v } type uintptrIntf struct { v uintptr i interface{} } type uintptrIntfSlice []uintptrIntf func (p uintptrIntfSlice) Len() int { return len(p) } func (p uintptrIntfSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p uintptrIntfSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v } type int64Rv struct { v int64 r reflect.Value } type int64RvSlice []int64Rv func (p int64RvSlice) Len() int { return len(p) } func (p int64RvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p int64RvSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v } type int64Intf struct { v int64 i interface{} } type int64IntfSlice []int64Intf func (p int64IntfSlice) Len() int { return len(p) } func (p int64IntfSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p int64IntfSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v } type boolRv struct { v bool r reflect.Value } type boolRvSlice []boolRv func (p boolRvSlice) Len() int { return len(p) } func (p boolRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p boolRvSlice) Less(i, j int) bool { return !p[uint(i)].v && p[uint(j)].v } type boolIntf struct { v bool i interface{} } type boolIntfSlice []boolIntf func (p boolIntfSlice) Len() int { return len(p) } func (p boolIntfSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p boolIntfSlice) Less(i, j int) bool { return !p[uint(i)].v && p[uint(j)].v } type timeRv struct { v time.Time r reflect.Value } type timeRvSlice []timeRv func (p timeRvSlice) Len() int { return len(p) } func (p timeRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p timeRvSlice) Less(i, j int) bool { return p[uint(i)].v.Before(p[uint(j)].v) } type timeIntf struct { v time.Time i interface{} } type timeIntfSlice []timeIntf func (p timeIntfSlice) Len() int { return len(p) } func (p timeIntfSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p timeIntfSlice) Less(i, j int) bool { return p[uint(i)].v.Before(p[uint(j)].v) } type bytesRv struct { v []byte r reflect.Value } type bytesRvSlice []bytesRv func (p bytesRvSlice) Len() int { return len(p) } func (p bytesRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p bytesRvSlice) Less(i, j int) bool { return bytes.Compare(p[uint(i)].v, p[uint(j)].v) == -1 } type bytesIntf struct { v []byte i interface{} } type bytesIntfSlice []bytesIntf func (p bytesIntfSlice) Len() int { return len(p) } func (p bytesIntfSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p bytesIntfSlice) Less(i, j int) bool { return bytes.Compare(p[uint(i)].v, p[uint(j)].v) == -1 } ================================================ FILE: vendor/github.com/ugorji/go/codec/sort-slice.go.tmpl ================================================ // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // Code generated from sort-slice.go.tmpl - DO NOT EDIT. {{/* xxxSlice xxxIntf xxxIntfSlice xxxRv xxxRvSlice I'm not going to create them for - sortables - sortablesplus With the parameters passed in sortables or sortablesplus, 'time, 'bytes' are special, and correspond to time.Time and []byte respectively. */}} package codec import "time" import "reflect" import "bytes" {{/* func init() { _ = time.Unix } */}} {{define "T"}} func (p {{ .Type }}) Len() int { return len(p) } func (p {{ .Type }}) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } func (p {{ .Type }}) Less(i, j int) bool { {{ if eq .Kind "bool" }} return !p[uint(i)]{{.V}} && p[uint(j)]{{.V}} {{ else if eq .Kind "float32" }} return p[uint(i)]{{.V}} < p[uint(j)]{{.V}} || isNaN32(p[uint(i)]{{.V}}) && !isNaN32(p[uint(j)]{{.V}}) {{ else if eq .Kind "float64" }} return p[uint(i)]{{.V}} < p[uint(j)]{{.V}} || isNaN64(p[uint(i)]{{.V}}) && !isNaN64(p[uint(j)]{{.V}}) {{ else if eq .Kind "time" }} return p[uint(i)]{{.V}}.Before(p[uint(j)]{{.V}}) {{ else if eq .Kind "bytes" }} return bytes.Compare(p[uint(i)]{{.V}}, p[uint(j)]{{.V}}) == -1 {{ else }} return p[uint(i)]{{.V}} < p[uint(j)]{{.V}} {{ end -}} } {{end}} {{range $i, $v := sortables }}{{ $t := tshort $v }} type {{ $v }}Slice []{{ $t }} {{template "T" args "Kind" $v "Type" (print $v "Slice") "V" ""}} {{end}} {{range $i, $v := sortablesplus }}{{ $t := tshort $v }} type {{ $v }}Rv struct { v {{ $t }} r reflect.Value } type {{ $v }}RvSlice []{{ $v }}Rv {{template "T" args "Kind" $v "Type" (print $v "RvSlice") "V" ".v"}} type {{ $v }}Intf struct { v {{ $t }} i interface{} } type {{ $v }}IntfSlice []{{ $v }}Intf {{template "T" args "Kind" $v "Type" (print $v "IntfSlice") "V" ".v"}} {{end}} ================================================ FILE: vendor/github.com/ugorji/go/codec/test-cbor-goldens.json ================================================ [ { "cbor": "AA==", "hex": "00", "roundtrip": true, "decoded": 0 }, { "cbor": "AQ==", "hex": "01", "roundtrip": true, "decoded": 1 }, { "cbor": "Cg==", "hex": "0a", "roundtrip": true, "decoded": 10 }, { "cbor": "Fw==", "hex": "17", "roundtrip": true, "decoded": 23 }, { "cbor": "GBg=", "hex": "1818", "roundtrip": true, "decoded": 24 }, { "cbor": "GBk=", "hex": "1819", "roundtrip": true, "decoded": 25 }, { "cbor": "GGQ=", "hex": "1864", "roundtrip": true, "decoded": 100 }, { "cbor": "GQPo", "hex": "1903e8", "roundtrip": true, "decoded": 1000 }, { "cbor": "GgAPQkA=", "hex": "1a000f4240", "roundtrip": true, "decoded": 1000000 }, { "cbor": "GwAAAOjUpRAA", "hex": "1b000000e8d4a51000", "roundtrip": true, "decoded": 1000000000000 }, { "cbor": "G///////////", "hex": "1bffffffffffffffff", "roundtrip": true, "decoded": 18446744073709551615 }, { "cbor": "wkkBAAAAAAAAAAA=", "hex": "c249010000000000000000", "roundtrip": true, "decoded": 18446744073709551616 }, { "cbor": "O///////////", "hex": "3bffffffffffffffff", "roundtrip": true, "decoded": -18446744073709551616, "skip": true }, { "cbor": "w0kBAAAAAAAAAAA=", "hex": "c349010000000000000000", "roundtrip": true, "decoded": -18446744073709551617 }, { "cbor": "IA==", "hex": "20", "roundtrip": true, "decoded": -1 }, { "cbor": "KQ==", "hex": "29", "roundtrip": true, "decoded": -10 }, { "cbor": "OGM=", "hex": "3863", "roundtrip": true, "decoded": -100 }, { "cbor": "OQPn", "hex": "3903e7", "roundtrip": true, "decoded": -1000 }, { "cbor": "+QAA", "hex": "f90000", "roundtrip": true, "decoded": 0.0 }, { "cbor": "+YAA", "hex": "f98000", "roundtrip": true, "decoded": -0.0 }, { "cbor": "+TwA", "hex": "f93c00", "roundtrip": true, "decoded": 1.0 }, { "cbor": "+z/xmZmZmZma", "hex": "fb3ff199999999999a", "roundtrip": true, "decoded": 1.1 }, { "cbor": "+T4A", "hex": "f93e00", "roundtrip": true, "decoded": 1.5 }, { "cbor": "+Xv/", "hex": "f97bff", "roundtrip": true, "decoded": 65504.0 }, { "cbor": "+kfDUAA=", "hex": "fa47c35000", "roundtrip": true, "decoded": 100000.0 }, { "cbor": "+n9///8=", "hex": "fa7f7fffff", "roundtrip": true, "decoded": 3.4028234663852886e+38 }, { "cbor": "+3435DyIAHWc", "hex": "fb7e37e43c8800759c", "roundtrip": true, "decoded": 1.0e+300 }, { "cbor": "+QAB", "hex": "f90001", "roundtrip": true, "decoded": 5.960464477539063e-08 }, { "cbor": "+QQA", "hex": "f90400", "roundtrip": true, "decoded": 6.103515625e-05 }, { "cbor": "+cQA", "hex": "f9c400", "roundtrip": true, "decoded": -4.0 }, { "cbor": "+8AQZmZmZmZm", "hex": "fbc010666666666666", "roundtrip": true, "decoded": -4.1 }, { "cbor": "+XwA", "hex": "f97c00", "roundtrip": true, "diagnostic": "Infinity" }, { "cbor": "+X4A", "hex": "f97e00", "roundtrip": true, "diagnostic": "NaN" }, { "cbor": "+fwA", "hex": "f9fc00", "roundtrip": true, "diagnostic": "-Infinity" }, { "cbor": "+n+AAAA=", "hex": "fa7f800000", "roundtrip": false, "diagnostic": "Infinity" }, { "cbor": "+n/AAAA=", "hex": "fa7fc00000", "roundtrip": false, "diagnostic": "NaN" }, { "cbor": "+v+AAAA=", "hex": "faff800000", "roundtrip": false, "diagnostic": "-Infinity" }, { "cbor": "+3/wAAAAAAAA", "hex": "fb7ff0000000000000", "roundtrip": false, "diagnostic": "Infinity" }, { "cbor": "+3/4AAAAAAAA", "hex": "fb7ff8000000000000", "roundtrip": false, "diagnostic": "NaN" }, { "cbor": "+//wAAAAAAAA", "hex": "fbfff0000000000000", "roundtrip": false, "diagnostic": "-Infinity" }, { "cbor": "9A==", "hex": "f4", "roundtrip": true, "decoded": false }, { "cbor": "9Q==", "hex": "f5", "roundtrip": true, "decoded": true }, { "cbor": "9g==", "hex": "f6", "roundtrip": true, "decoded": null }, { "cbor": "9w==", "hex": "f7", "roundtrip": true, "diagnostic": "undefined" }, { "cbor": "8A==", "hex": "f0", "roundtrip": true, "diagnostic": "simple(16)" }, { "cbor": "+Bg=", "hex": "f818", "roundtrip": true, "diagnostic": "simple(24)" }, { "cbor": "+P8=", "hex": "f8ff", "roundtrip": true, "diagnostic": "simple(255)" }, { "cbor": "wHQyMDEzLTAzLTIxVDIwOjA0OjAwWg==", "hex": "c074323031332d30332d32315432303a30343a30305a", "roundtrip": true, "diagnostic": "0(\"2013-03-21T20:04:00Z\")" }, { "cbor": "wRpRS2ew", "hex": "c11a514b67b0", "roundtrip": true, "diagnostic": "1(1363896240)" }, { "cbor": "wftB1FLZ7CAAAA==", "hex": "c1fb41d452d9ec200000", "roundtrip": true, "diagnostic": "1(1363896240.5)" }, { "cbor": "10QBAgME", "hex": "d74401020304", "roundtrip": true, "diagnostic": "23(h'01020304')" }, { "cbor": "2BhFZElFVEY=", "hex": "d818456449455446", "roundtrip": true, "diagnostic": "24(h'6449455446')" }, { "cbor": "2CB2aHR0cDovL3d3dy5leGFtcGxlLmNvbQ==", "hex": "d82076687474703a2f2f7777772e6578616d706c652e636f6d", "roundtrip": true, "diagnostic": "32(\"http://www.example.com\")" }, { "cbor": "QA==", "hex": "40", "roundtrip": true, "diagnostic": "h''" }, { "cbor": "RAECAwQ=", "hex": "4401020304", "roundtrip": true, "diagnostic": "h'01020304'" }, { "cbor": "YA==", "hex": "60", "roundtrip": true, "decoded": "" }, { "cbor": "YWE=", "hex": "6161", "roundtrip": true, "decoded": "a" }, { "cbor": "ZElFVEY=", "hex": "6449455446", "roundtrip": true, "decoded": "IETF" }, { "cbor": "YiJc", "hex": "62225c", "roundtrip": true, "decoded": "\"\\" }, { "cbor": "YsO8", "hex": "62c3bc", "roundtrip": true, "decoded": "ü" }, { "cbor": "Y+awtA==", "hex": "63e6b0b4", "roundtrip": true, "decoded": "水" }, { "cbor": "ZPCQhZE=", "hex": "64f0908591", "roundtrip": true, "decoded": "𐅑" }, { "cbor": "gA==", "hex": "80", "roundtrip": true, "decoded": [ ] }, { "cbor": "gwECAw==", "hex": "83010203", "roundtrip": true, "decoded": [ 1, 2, 3 ] }, { "cbor": "gwGCAgOCBAU=", "hex": "8301820203820405", "roundtrip": true, "decoded": [ 1, [ 2, 3 ], [ 4, 5 ] ] }, { "cbor": "mBkBAgMEBQYHCAkKCwwNDg8QERITFBUWFxgYGBk=", "hex": "98190102030405060708090a0b0c0d0e0f101112131415161718181819", "roundtrip": true, "decoded": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 ] }, { "cbor": "oA==", "hex": "a0", "roundtrip": true, "decoded": { } }, { "cbor": "ogECAwQ=", "hex": "a201020304", "roundtrip": true, "skip": true, "diagnostic": "{1: 2, 3: 4}" }, { "cbor": "omFhAWFiggID", "hex": "a26161016162820203", "roundtrip": true, "decoded": { "a": 1, "b": [ 2, 3 ] } }, { "cbor": "gmFhoWFiYWM=", "hex": "826161a161626163", "roundtrip": true, "decoded": [ "a", { "b": "c" } ] }, { "cbor": "pWFhYUFhYmFCYWNhQ2FkYURhZWFF", "hex": "a56161614161626142616361436164614461656145", "roundtrip": true, "decoded": { "a": "A", "b": "B", "c": "C", "d": "D", "e": "E" } }, { "cbor": "X0IBAkMDBAX/", "hex": "5f42010243030405ff", "roundtrip": false, "skip": true, "diagnostic": "(_ h'0102', h'030405')" }, { "cbor": "f2VzdHJlYWRtaW5n/w==", "hex": "7f657374726561646d696e67ff", "roundtrip": false, "decoded": "streaming" }, { "cbor": "n/8=", "hex": "9fff", "roundtrip": false, "decoded": [ ] }, { "cbor": "nwGCAgOfBAX//w==", "hex": "9f018202039f0405ffff", "roundtrip": false, "decoded": [ 1, [ 2, 3 ], [ 4, 5 ] ] }, { "cbor": "nwGCAgOCBAX/", "hex": "9f01820203820405ff", "roundtrip": false, "decoded": [ 1, [ 2, 3 ], [ 4, 5 ] ] }, { "cbor": "gwGCAgOfBAX/", "hex": "83018202039f0405ff", "roundtrip": false, "decoded": [ 1, [ 2, 3 ], [ 4, 5 ] ] }, { "cbor": "gwGfAgP/ggQF", "hex": "83019f0203ff820405", "roundtrip": false, "decoded": [ 1, [ 2, 3 ], [ 4, 5 ] ] }, { "cbor": "nwECAwQFBgcICQoLDA0ODxAREhMUFRYXGBgYGf8=", "hex": "9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff", "roundtrip": false, "decoded": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 ] }, { "cbor": "v2FhAWFinwID//8=", "hex": "bf61610161629f0203ffff", "roundtrip": false, "decoded": { "a": 1, "b": [ 2, 3 ] } }, { "cbor": "gmFhv2FiYWP/", "hex": "826161bf61626163ff", "roundtrip": false, "decoded": [ "a", { "b": "c" } ] }, { "cbor": "v2NGdW71Y0FtdCH/", "hex": "bf6346756ef563416d7421ff", "roundtrip": false, "decoded": { "Fun": true, "Amt": -2 } } ] ================================================ FILE: vendor/github.com/ugorji/go/codec/test.py ================================================ #!/usr/bin/env python # This will create golden files in a directory passed to it. # A Test calls this internally to create the golden files # So it can process them (so we don't have to checkin the files). # Ensure msgpack-python and cbor are installed first, using: # sudo apt-get install python-dev # sudo apt-get install python-pip # pip install --user msgpack-python msgpack-rpc-python cbor # Ensure all "string" keys are utf strings (else encoded as bytes) import cbor, msgpack, msgpackrpc, sys, os, threading def get_test_data_list(): # get list with all primitive types, and a combo type l0 = [ -8, -1616, -32323232, -6464646464646464, 192, 1616, 32323232, 6464646464646464, 192, -3232.0, -6464646464.0, 3232.0, 6464.0, 6464646464.0, False, True, u"null", None, u"some&day>some 0 if stopTimeSec > 0: def myStopRpcServer(): server.stop() t = threading.Timer(stopTimeSec, myStopRpcServer) t.start() server.start() def doRpcClientToPythonSvc(port): address = msgpackrpc.Address('127.0.0.1', port) client = msgpackrpc.Client(address, unpack_encoding='utf-8') print client.call("Echo123", "A1", "B2", "C3") print client.call("EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"}) def doRpcClientToGoSvc(port): # print ">>>> port: ", port, " <<<<<" address = msgpackrpc.Address('127.0.0.1', port) client = msgpackrpc.Client(address, unpack_encoding='utf-8') print client.call("TestRpcInt.Echo123", ["A1", "B2", "C3"]) print client.call("TestRpcInt.EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"}) def doMain(args): if len(args) == 2 and args[0] == "testdata": build_test_data(args[1]) elif len(args) == 3 and args[0] == "rpc-server": doRpcServer(int(args[1]), int(args[2])) elif len(args) == 2 and args[0] == "rpc-client-python-service": doRpcClientToPythonSvc(int(args[1])) elif len(args) == 2 and args[0] == "rpc-client-go-service": doRpcClientToGoSvc(int(args[1])) else: print("Usage: test.py " + "[testdata|rpc-server|rpc-client-python-service|rpc-client-go-service] ...") if __name__ == "__main__": doMain(sys.argv[1:]) ================================================ FILE: vendor/github.com/unknwon/com/go.mod ================================================ module github.com/unknwon/com require ( github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect github.com/jtolds/gls v4.2.1+incompatible // indirect github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 // indirect github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c ) ================================================ FILE: vendor/github.com/unknwon/com/go.sum ================================================ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= ================================================ FILE: vendor/golang.org/x/image/AUTHORS ================================================ # This source code refers to The Go Authors for copyright purposes. # The master list of authors is in the main Go distribution, # visible at http://tip.golang.org/AUTHORS. ================================================ FILE: vendor/golang.org/x/image/CONTRIBUTORS ================================================ # This source code was written by the Go contributors. # The master list of contributors is in the main Go distribution, # visible at http://tip.golang.org/CONTRIBUTORS. ================================================ FILE: vendor/golang.org/x/image/LICENSE ================================================ 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. ================================================ FILE: vendor/golang.org/x/image/PATENTS ================================================ 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. ================================================ FILE: vendor/golang.org/x/image/font/font.go ================================================ // Copyright 2015 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 font defines an interface for font faces, for drawing text on an // image. // // Other packages provide font face implementations. For example, a truetype // package would provide one based on .ttf font files. package font // import "golang.org/x/image/font" import ( "image" "image/draw" "io" "unicode/utf8" "golang.org/x/image/math/fixed" ) // TODO: who is responsible for caches (glyph images, glyph indices, kerns)? // The Drawer or the Face? // Face is a font face. Its glyphs are often derived from a font file, such as // "Comic_Sans_MS.ttf", but a face has a specific size, style, weight and // hinting. For example, the 12pt and 18pt versions of Comic Sans are two // different faces, even if derived from the same font file. // // A Face is not safe for concurrent use by multiple goroutines, as its methods // may re-use implementation-specific caches and mask image buffers. // // To create a Face, look to other packages that implement specific font file // formats. type Face interface { io.Closer // Glyph returns the draw.DrawMask parameters (dr, mask, maskp) to draw r's // glyph at the sub-pixel destination location dot, and that glyph's // advance width. // // It returns !ok if the face does not contain a glyph for r. // // The contents of the mask image returned by one Glyph call may change // after the next Glyph call. Callers that want to cache the mask must make // a copy. Glyph(dot fixed.Point26_6, r rune) ( dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) // GlyphBounds returns the bounding box of r's glyph, drawn at a dot equal // to the origin, and that glyph's advance width. // // It returns !ok if the face does not contain a glyph for r. // // The glyph's ascent and descent equal -bounds.Min.Y and +bounds.Max.Y. A // visual depiction of what these metrics are is at // https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) // GlyphAdvance returns the advance width of r's glyph. // // It returns !ok if the face does not contain a glyph for r. GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) // Kern returns the horizontal adjustment for the kerning pair (r0, r1). A // positive kern means to move the glyphs further apart. Kern(r0, r1 rune) fixed.Int26_6 // Metrics returns the metrics for this Face. Metrics() Metrics // TODO: ColoredGlyph for various emoji? // TODO: Ligatures? Shaping? } // Metrics holds the metrics for a Face. A visual depiction is at // https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png type Metrics struct { // Height is the recommended amount of vertical space between two lines of // text. Height fixed.Int26_6 // Ascent is the distance from the top of a line to its baseline. Ascent fixed.Int26_6 // Descent is the distance from the bottom of a line to its baseline. The // value is typically positive, even though a descender goes below the // baseline. Descent fixed.Int26_6 } // Drawer draws text on a destination image. // // A Drawer is not safe for concurrent use by multiple goroutines, since its // Face is not. type Drawer struct { // Dst is the destination image. Dst draw.Image // Src is the source image. Src image.Image // Face provides the glyph mask images. Face Face // Dot is the baseline location to draw the next glyph. The majority of the // affected pixels will be above and to the right of the dot, but some may // be below or to the left. For example, drawing a 'j' in an italic face // may affect pixels below and to the left of the dot. Dot fixed.Point26_6 // TODO: Clip image.Image? // TODO: SrcP image.Point for Src images other than *image.Uniform? How // does it get updated during DrawString? } // TODO: should DrawString return the last rune drawn, so the next DrawString // call can kern beforehand? Or should that be the responsibility of the caller // if they really want to do that, since they have to explicitly shift d.Dot // anyway? What if ligatures span more than two runes? What if grapheme // clusters span multiple runes? // // TODO: do we assume that the input is in any particular Unicode Normalization // Form? // // TODO: have DrawRunes(s []rune)? DrawRuneReader(io.RuneReader)?? If we take // io.RuneReader, we can't assume that we can rewind the stream. // // TODO: how does this work with line breaking: drawing text up until a // vertical line? Should DrawString return the number of runes drawn? // DrawBytes draws s at the dot and advances the dot's location. // // It is equivalent to DrawString(string(s)) but may be more efficient. func (d *Drawer) DrawBytes(s []byte) { prevC := rune(-1) for len(s) > 0 { c, size := utf8.DecodeRune(s) s = s[size:] if prevC >= 0 { d.Dot.X += d.Face.Kern(prevC, c) } dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c) if !ok { // TODO: is falling back on the U+FFFD glyph the responsibility of // the Drawer or the Face? // TODO: set prevC = '\ufffd'? continue } draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over) d.Dot.X += advance prevC = c } } // DrawString draws s at the dot and advances the dot's location. func (d *Drawer) DrawString(s string) { prevC := rune(-1) for _, c := range s { if prevC >= 0 { d.Dot.X += d.Face.Kern(prevC, c) } dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c) if !ok { // TODO: is falling back on the U+FFFD glyph the responsibility of // the Drawer or the Face? // TODO: set prevC = '\ufffd'? continue } draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over) d.Dot.X += advance prevC = c } } // BoundBytes returns the bounding box of s, drawn at the drawer dot, as well as // the advance. // // It is equivalent to BoundBytes(string(s)) but may be more efficient. func (d *Drawer) BoundBytes(s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) { bounds, advance = BoundBytes(d.Face, s) bounds.Min = bounds.Min.Add(d.Dot) bounds.Max = bounds.Max.Add(d.Dot) return } // BoundString returns the bounding box of s, drawn at the drawer dot, as well // as the advance. func (d *Drawer) BoundString(s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) { bounds, advance = BoundString(d.Face, s) bounds.Min = bounds.Min.Add(d.Dot) bounds.Max = bounds.Max.Add(d.Dot) return } // MeasureBytes returns how far dot would advance by drawing s. // // It is equivalent to MeasureString(string(s)) but may be more efficient. func (d *Drawer) MeasureBytes(s []byte) (advance fixed.Int26_6) { return MeasureBytes(d.Face, s) } // MeasureString returns how far dot would advance by drawing s. func (d *Drawer) MeasureString(s string) (advance fixed.Int26_6) { return MeasureString(d.Face, s) } // BoundBytes returns the bounding box of s with f, drawn at a dot equal to the // origin, as well as the advance. // // It is equivalent to BoundString(string(s)) but may be more efficient. func BoundBytes(f Face, s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) { prevC := rune(-1) for len(s) > 0 { c, size := utf8.DecodeRune(s) s = s[size:] if prevC >= 0 { advance += f.Kern(prevC, c) } b, a, ok := f.GlyphBounds(c) if !ok { // TODO: is falling back on the U+FFFD glyph the responsibility of // the Drawer or the Face? // TODO: set prevC = '\ufffd'? continue } b.Min.X += advance b.Max.X += advance bounds = bounds.Union(b) advance += a prevC = c } return } // BoundString returns the bounding box of s with f, drawn at a dot equal to the // origin, as well as the advance. func BoundString(f Face, s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) { prevC := rune(-1) for _, c := range s { if prevC >= 0 { advance += f.Kern(prevC, c) } b, a, ok := f.GlyphBounds(c) if !ok { // TODO: is falling back on the U+FFFD glyph the responsibility of // the Drawer or the Face? // TODO: set prevC = '\ufffd'? continue } b.Min.X += advance b.Max.X += advance bounds = bounds.Union(b) advance += a prevC = c } return } // MeasureBytes returns how far dot would advance by drawing s with f. // // It is equivalent to MeasureString(string(s)) but may be more efficient. func MeasureBytes(f Face, s []byte) (advance fixed.Int26_6) { prevC := rune(-1) for len(s) > 0 { c, size := utf8.DecodeRune(s) s = s[size:] if prevC >= 0 { advance += f.Kern(prevC, c) } a, ok := f.GlyphAdvance(c) if !ok { // TODO: is falling back on the U+FFFD glyph the responsibility of // the Drawer or the Face? // TODO: set prevC = '\ufffd'? continue } advance += a prevC = c } return advance } // MeasureString returns how far dot would advance by drawing s with f. func MeasureString(f Face, s string) (advance fixed.Int26_6) { prevC := rune(-1) for _, c := range s { if prevC >= 0 { advance += f.Kern(prevC, c) } a, ok := f.GlyphAdvance(c) if !ok { // TODO: is falling back on the U+FFFD glyph the responsibility of // the Drawer or the Face? // TODO: set prevC = '\ufffd'? continue } advance += a prevC = c } return advance } // Hinting selects how to quantize a vector font's glyph nodes. // // Not all fonts support hinting. type Hinting int const ( HintingNone Hinting = iota HintingVertical HintingFull ) // Stretch selects a normal, condensed, or expanded face. // // Not all fonts support stretches. type Stretch int const ( StretchUltraCondensed Stretch = -4 StretchExtraCondensed Stretch = -3 StretchCondensed Stretch = -2 StretchSemiCondensed Stretch = -1 StretchNormal Stretch = +0 StretchSemiExpanded Stretch = +1 StretchExpanded Stretch = +2 StretchExtraExpanded Stretch = +3 StretchUltraExpanded Stretch = +4 ) // Style selects a normal, italic, or oblique face. // // Not all fonts support styles. type Style int const ( StyleNormal Style = iota StyleItalic StyleOblique ) // Weight selects a normal, light or bold face. // // Not all fonts support weights. // // The named Weight constants (e.g. WeightBold) correspond to CSS' common // weight names (e.g. "Bold"), but the numerical values differ, so that in Go, // the zero value means to use a normal weight. For the CSS names and values, // see https://developer.mozilla.org/en/docs/Web/CSS/font-weight type Weight int const ( WeightThin Weight = -3 // CSS font-weight value 100. WeightExtraLight Weight = -2 // CSS font-weight value 200. WeightLight Weight = -1 // CSS font-weight value 300. WeightNormal Weight = +0 // CSS font-weight value 400. WeightMedium Weight = +1 // CSS font-weight value 500. WeightSemiBold Weight = +2 // CSS font-weight value 600. WeightBold Weight = +3 // CSS font-weight value 700. WeightExtraBold Weight = +4 // CSS font-weight value 800. WeightBlack Weight = +5 // CSS font-weight value 900. ) ================================================ FILE: vendor/golang.org/x/image/math/fixed/fixed.go ================================================ // Copyright 2015 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 fixed implements fixed-point integer types. package fixed // import "golang.org/x/image/math/fixed" import ( "fmt" ) // TODO: implement fmt.Formatter for %f and %g. // I returns the integer value i as an Int26_6. // // For example, passing the integer value 2 yields Int26_6(128). func I(i int) Int26_6 { return Int26_6(i << 6) } // Int26_6 is a signed 26.6 fixed-point number. // // The integer part ranges from -33554432 to 33554431, inclusive. The // fractional part has 6 bits of precision. // // For example, the number one-and-a-quarter is Int26_6(1<<6 + 1<<4). type Int26_6 int32 // String returns a human-readable representation of a 26.6 fixed-point number. // // For example, the number one-and-a-quarter becomes "1:16". func (x Int26_6) String() string { const shift, mask = 6, 1<<6 - 1 if x >= 0 { return fmt.Sprintf("%d:%02d", int32(x>>shift), int32(x&mask)) } x = -x if x >= 0 { return fmt.Sprintf("-%d:%02d", int32(x>>shift), int32(x&mask)) } return "-33554432:00" // The minimum value is -(1<<25). } // Floor returns the greatest integer value less than or equal to x. // // Its return type is int, not Int26_6. func (x Int26_6) Floor() int { return int((x + 0x00) >> 6) } // Round returns the nearest integer value to x. Ties are rounded up. // // Its return type is int, not Int26_6. func (x Int26_6) Round() int { return int((x + 0x20) >> 6) } // Ceil returns the least integer value greater than or equal to x. // // Its return type is int, not Int26_6. func (x Int26_6) Ceil() int { return int((x + 0x3f) >> 6) } // Mul returns x*y in 26.6 fixed-point arithmetic. func (x Int26_6) Mul(y Int26_6) Int26_6 { return Int26_6((int64(x)*int64(y) + 1<<5) >> 6) } // Int52_12 is a signed 52.12 fixed-point number. // // The integer part ranges from -2251799813685248 to 2251799813685247, // inclusive. The fractional part has 12 bits of precision. // // For example, the number one-and-a-quarter is Int52_12(1<<12 + 1<<10). type Int52_12 int64 // String returns a human-readable representation of a 52.12 fixed-point // number. // // For example, the number one-and-a-quarter becomes "1:1024". func (x Int52_12) String() string { const shift, mask = 12, 1<<12 - 1 if x >= 0 { return fmt.Sprintf("%d:%04d", int64(x>>shift), int64(x&mask)) } x = -x if x >= 0 { return fmt.Sprintf("-%d:%04d", int64(x>>shift), int64(x&mask)) } return "-2251799813685248:0000" // The minimum value is -(1<<51). } // Floor returns the greatest integer value less than or equal to x. // // Its return type is int, not Int52_12. func (x Int52_12) Floor() int { return int((x + 0x000) >> 12) } // Round returns the nearest integer value to x. Ties are rounded up. // // Its return type is int, not Int52_12. func (x Int52_12) Round() int { return int((x + 0x800) >> 12) } // Ceil returns the least integer value greater than or equal to x. // // Its return type is int, not Int52_12. func (x Int52_12) Ceil() int { return int((x + 0xfff) >> 12) } // Mul returns x*y in 52.12 fixed-point arithmetic. func (x Int52_12) Mul(y Int52_12) Int52_12 { const M, N = 52, 12 lo, hi := muli64(int64(x), int64(y)) ret := Int52_12(hi<>N) ret += Int52_12((lo >> (N - 1)) & 1) // Round to nearest, instead of rounding down. return ret } // muli64 multiplies two int64 values, returning the 128-bit signed integer // result as two uint64 values. // // This implementation is similar to $GOROOT/src/runtime/softfloat64.go's mullu // function, which is in turn adapted from Hacker's Delight. func muli64(u, v int64) (lo, hi uint64) { const ( s = 32 mask = 1<> s) u0 := uint64(u & mask) v1 := uint64(v >> s) v0 := uint64(v & mask) w0 := u0 * v0 t := u1*v0 + w0>>s w1 := t & mask w2 := uint64(int64(t) >> s) w1 += u0 * v1 return uint64(u) * uint64(v), u1*v1 + w2 + uint64(int64(w1)>>s) } // P returns the integer values x and y as a Point26_6. // // For example, passing the integer values (2, -3) yields Point26_6{128, -192}. func P(x, y int) Point26_6 { return Point26_6{Int26_6(x << 6), Int26_6(y << 6)} } // Point26_6 is a 26.6 fixed-point coordinate pair. // // It is analogous to the image.Point type in the standard library. type Point26_6 struct { X, Y Int26_6 } // Add returns the vector p+q. func (p Point26_6) Add(q Point26_6) Point26_6 { return Point26_6{p.X + q.X, p.Y + q.Y} } // Sub returns the vector p-q. func (p Point26_6) Sub(q Point26_6) Point26_6 { return Point26_6{p.X - q.X, p.Y - q.Y} } // Mul returns the vector p*k. func (p Point26_6) Mul(k Int26_6) Point26_6 { return Point26_6{p.X * k / 64, p.Y * k / 64} } // Div returns the vector p/k. func (p Point26_6) Div(k Int26_6) Point26_6 { return Point26_6{p.X * 64 / k, p.Y * 64 / k} } // In returns whether p is in r. func (p Point26_6) In(r Rectangle26_6) bool { return r.Min.X <= p.X && p.X < r.Max.X && r.Min.Y <= p.Y && p.Y < r.Max.Y } // Point52_12 is a 52.12 fixed-point coordinate pair. // // It is analogous to the image.Point type in the standard library. type Point52_12 struct { X, Y Int52_12 } // Add returns the vector p+q. func (p Point52_12) Add(q Point52_12) Point52_12 { return Point52_12{p.X + q.X, p.Y + q.Y} } // Sub returns the vector p-q. func (p Point52_12) Sub(q Point52_12) Point52_12 { return Point52_12{p.X - q.X, p.Y - q.Y} } // Mul returns the vector p*k. func (p Point52_12) Mul(k Int52_12) Point52_12 { return Point52_12{p.X * k / 4096, p.Y * k / 4096} } // Div returns the vector p/k. func (p Point52_12) Div(k Int52_12) Point52_12 { return Point52_12{p.X * 4096 / k, p.Y * 4096 / k} } // In returns whether p is in r. func (p Point52_12) In(r Rectangle52_12) bool { return r.Min.X <= p.X && p.X < r.Max.X && r.Min.Y <= p.Y && p.Y < r.Max.Y } // R returns the integer values minX, minY, maxX, maxY as a Rectangle26_6. // // For example, passing the integer values (0, 1, 2, 3) yields // Rectangle26_6{Point26_6{0, 64}, Point26_6{128, 192}}. // // Like the image.Rect function in the standard library, the returned rectangle // has minimum and maximum coordinates swapped if necessary so that it is // well-formed. func R(minX, minY, maxX, maxY int) Rectangle26_6 { if minX > maxX { minX, maxX = maxX, minX } if minY > maxY { minY, maxY = maxY, minY } return Rectangle26_6{ Point26_6{ Int26_6(minX << 6), Int26_6(minY << 6), }, Point26_6{ Int26_6(maxX << 6), Int26_6(maxY << 6), }, } } // Rectangle26_6 is a 26.6 fixed-point coordinate rectangle. The Min bound is // inclusive and the Max bound is exclusive. It is well-formed if Min.X <= // Max.X and likewise for Y. // // It is analogous to the image.Rectangle type in the standard library. type Rectangle26_6 struct { Min, Max Point26_6 } // Add returns the rectangle r translated by p. func (r Rectangle26_6) Add(p Point26_6) Rectangle26_6 { return Rectangle26_6{ Point26_6{r.Min.X + p.X, r.Min.Y + p.Y}, Point26_6{r.Max.X + p.X, r.Max.Y + p.Y}, } } // Sub returns the rectangle r translated by -p. func (r Rectangle26_6) Sub(p Point26_6) Rectangle26_6 { return Rectangle26_6{ Point26_6{r.Min.X - p.X, r.Min.Y - p.Y}, Point26_6{r.Max.X - p.X, r.Max.Y - p.Y}, } } // Intersect returns the largest rectangle contained by both r and s. If the // two rectangles do not overlap then the zero rectangle will be returned. func (r Rectangle26_6) Intersect(s Rectangle26_6) Rectangle26_6 { if r.Min.X < s.Min.X { r.Min.X = s.Min.X } if r.Min.Y < s.Min.Y { r.Min.Y = s.Min.Y } if r.Max.X > s.Max.X { r.Max.X = s.Max.X } if r.Max.Y > s.Max.Y { r.Max.Y = s.Max.Y } // Letting r0 and s0 be the values of r and s at the time that the method // is called, this next line is equivalent to: // // if max(r0.Min.X, s0.Min.X) >= min(r0.Max.X, s0.Max.X) || likewiseForY { etc } if r.Empty() { return Rectangle26_6{} } return r } // Union returns the smallest rectangle that contains both r and s. func (r Rectangle26_6) Union(s Rectangle26_6) Rectangle26_6 { if r.Empty() { return s } if s.Empty() { return r } if r.Min.X > s.Min.X { r.Min.X = s.Min.X } if r.Min.Y > s.Min.Y { r.Min.Y = s.Min.Y } if r.Max.X < s.Max.X { r.Max.X = s.Max.X } if r.Max.Y < s.Max.Y { r.Max.Y = s.Max.Y } return r } // Empty returns whether the rectangle contains no points. func (r Rectangle26_6) Empty() bool { return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y } // In returns whether every point in r is in s. func (r Rectangle26_6) In(s Rectangle26_6) bool { if r.Empty() { return true } // Note that r.Max is an exclusive bound for r, so that r.In(s) // does not require that r.Max.In(s). return s.Min.X <= r.Min.X && r.Max.X <= s.Max.X && s.Min.Y <= r.Min.Y && r.Max.Y <= s.Max.Y } // Rectangle52_12 is a 52.12 fixed-point coordinate rectangle. The Min bound is // inclusive and the Max bound is exclusive. It is well-formed if Min.X <= // Max.X and likewise for Y. // // It is analogous to the image.Rectangle type in the standard library. type Rectangle52_12 struct { Min, Max Point52_12 } // Add returns the rectangle r translated by p. func (r Rectangle52_12) Add(p Point52_12) Rectangle52_12 { return Rectangle52_12{ Point52_12{r.Min.X + p.X, r.Min.Y + p.Y}, Point52_12{r.Max.X + p.X, r.Max.Y + p.Y}, } } // Sub returns the rectangle r translated by -p. func (r Rectangle52_12) Sub(p Point52_12) Rectangle52_12 { return Rectangle52_12{ Point52_12{r.Min.X - p.X, r.Min.Y - p.Y}, Point52_12{r.Max.X - p.X, r.Max.Y - p.Y}, } } // Intersect returns the largest rectangle contained by both r and s. If the // two rectangles do not overlap then the zero rectangle will be returned. func (r Rectangle52_12) Intersect(s Rectangle52_12) Rectangle52_12 { if r.Min.X < s.Min.X { r.Min.X = s.Min.X } if r.Min.Y < s.Min.Y { r.Min.Y = s.Min.Y } if r.Max.X > s.Max.X { r.Max.X = s.Max.X } if r.Max.Y > s.Max.Y { r.Max.Y = s.Max.Y } // Letting r0 and s0 be the values of r and s at the time that the method // is called, this next line is equivalent to: // // if max(r0.Min.X, s0.Min.X) >= min(r0.Max.X, s0.Max.X) || likewiseForY { etc } if r.Empty() { return Rectangle52_12{} } return r } // Union returns the smallest rectangle that contains both r and s. func (r Rectangle52_12) Union(s Rectangle52_12) Rectangle52_12 { if r.Empty() { return s } if s.Empty() { return r } if r.Min.X > s.Min.X { r.Min.X = s.Min.X } if r.Min.Y > s.Min.Y { r.Min.Y = s.Min.Y } if r.Max.X < s.Max.X { r.Max.X = s.Max.X } if r.Max.Y < s.Max.Y { r.Max.Y = s.Max.Y } return r } // Empty returns whether the rectangle contains no points. func (r Rectangle52_12) Empty() bool { return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y } // In returns whether every point in r is in s. func (r Rectangle52_12) In(s Rectangle52_12) bool { if r.Empty() { return true } // Note that r.Max is an exclusive bound for r, so that r.In(s) // does not require that r.Max.In(s). return s.Min.X <= r.Min.X && r.Max.X <= s.Max.X && s.Min.Y <= r.Min.Y && r.Max.Y <= s.Max.Y } ================================================ FILE: vendor/golang.org/x/net/AUTHORS ================================================ # This source code refers to The Go Authors for copyright purposes. # The master list of authors is in the main Go distribution, # visible at http://tip.golang.org/AUTHORS. ================================================ FILE: vendor/golang.org/x/net/CONTRIBUTORS ================================================ # This source code was written by the Go contributors. # The master list of contributors is in the main Go distribution, # visible at http://tip.golang.org/CONTRIBUTORS. ================================================ FILE: vendor/golang.org/x/net/LICENSE ================================================ 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. ================================================ FILE: vendor/golang.org/x/net/PATENTS ================================================ 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. ================================================ FILE: vendor/golang.org/x/net/context/context.go ================================================ // 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 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 // propagate the Context, optionally replacing it with a modified copy created // using WithDeadline, WithTimeout, WithCancel, or WithValue. // // Programs that use Contexts should follow these rules to keep interfaces // consistent across packages and enable static analysis tools to check context // 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 // 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 // if you are unsure about which Context to use. // // Use context Values only for request-scoped data that transits processes and // APIs, not for passing optional parameters to functions. // // The same Context may be passed to functions running in different goroutines; // Contexts are safe for simultaneous use by multiple goroutines. // // See http://blog.golang.org/context for example code for a server that uses // Contexts. package context // import "golang.org/x/net/context" // 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, // 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 // 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 // whether Contexts are propagated correctly in a program. func TODO() Context { return todo } ================================================ FILE: vendor/golang.org/x/net/context/go17.go ================================================ // 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 package context import ( "context" // standard library's context, as of Go 1.7 "time" ) var ( todo = context.TODO() background = context.Background() ) // Canceled is the error returned by Context.Err when the context is canceled. var Canceled = context.Canceled // DeadlineExceeded is the error returned by Context.Err when the context's // deadline passes. var DeadlineExceeded = context.DeadlineExceeded // WithCancel returns a copy of parent with a new Done channel. The returned // context's Done channel is closed when the returned cancel function is called // or when the parent context's Done channel is closed, whichever happens first. // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete. func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { ctx, f := context.WithCancel(parent) return ctx, CancelFunc(f) } // 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 // 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. // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete. func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { ctx, f := context.WithDeadline(parent, deadline) return ctx, CancelFunc(f) } // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete: // // func slowOperationWithTimeout(ctx context.Context) (Result, error) { // ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) // defer cancel() // releases resources if slowOperation completes before timeout elapses // return slowOperation(ctx) // } func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { return WithDeadline(parent, time.Now().Add(timeout)) } // WithValue returns a copy of parent in which the value associated with key is // val. // // Use context Values only for request-scoped data that transits processes and // APIs, not for passing optional parameters to functions. func WithValue(parent Context, key interface{}, val interface{}) Context { return context.WithValue(parent, key, val) } ================================================ FILE: vendor/golang.org/x/net/context/go19.go ================================================ // 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 ================================================ FILE: vendor/golang.org/x/net/context/pre_go17.go ================================================ // 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.7 package context import ( "errors" "fmt" "sync" "time" ) // 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 func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { return } func (*emptyCtx) Done() <-chan struct{} { return nil } func (*emptyCtx) Err() error { return nil } func (*emptyCtx) Value(key interface{}) interface{} { return nil } func (e *emptyCtx) String() string { switch e { case background: return "context.Background" case todo: return "context.TODO" } return "unknown empty Context" } var ( background = new(emptyCtx) todo = new(emptyCtx) ) // Canceled is the error returned by Context.Err when the context is canceled. var Canceled = errors.New("context canceled") // DeadlineExceeded is the error returned by Context.Err when the context's // deadline passes. var DeadlineExceeded = errors.New("context deadline exceeded") // WithCancel returns a copy of parent with a new Done channel. The returned // context's Done channel is closed when the returned cancel function is called // or when the parent context's Done channel is closed, whichever happens first. // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete. func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { c := newCancelCtx(parent) propagateCancel(parent, c) return c, func() { c.cancel(true, Canceled) } } // newCancelCtx returns an initialized cancelCtx. func newCancelCtx(parent Context) *cancelCtx { return &cancelCtx{ Context: parent, done: make(chan struct{}), } } // propagateCancel arranges for child to be canceled when parent is. func propagateCancel(parent Context, child canceler) { if parent.Done() == nil { return // parent is never canceled } if p, ok := parentCancelCtx(parent); ok { p.mu.Lock() if p.err != nil { // parent has already been canceled child.cancel(false, p.err) } else { if p.children == nil { p.children = make(map[canceler]bool) } p.children[child] = true } p.mu.Unlock() } else { go func() { select { case <-parent.Done(): child.cancel(false, parent.Err()) case <-child.Done(): } }() } } // parentCancelCtx follows a chain of parent references until it finds a // *cancelCtx. This function understands how each of the concrete types in this // package represents its parent. func parentCancelCtx(parent Context) (*cancelCtx, bool) { for { switch c := parent.(type) { case *cancelCtx: return c, true case *timerCtx: return c.cancelCtx, true case *valueCtx: parent = c.Context default: return nil, false } } } // removeChild removes a context from its parent. func removeChild(parent Context, child canceler) { p, ok := parentCancelCtx(parent) if !ok { return } p.mu.Lock() if p.children != nil { delete(p.children, child) } p.mu.Unlock() } // 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 // that implement canceler. type cancelCtx struct { Context done chan struct{} // closed by the first cancel call. mu sync.Mutex children map[canceler]bool // set to nil by the first cancel call err error // set to non-nil by the first cancel call } func (c *cancelCtx) Done() <-chan struct{} { return c.done } func (c *cancelCtx) Err() error { c.mu.Lock() defer c.mu.Unlock() return c.err } func (c *cancelCtx) String() string { return fmt.Sprintf("%v.WithCancel", c.Context) } // cancel closes c.done, cancels each of c's children, and, if // removeFromParent is true, removes c from its parent's children. func (c *cancelCtx) cancel(removeFromParent bool, err error) { if err == nil { panic("context: internal error: missing cancel error") } c.mu.Lock() if c.err != nil { c.mu.Unlock() return // already canceled } c.err = err close(c.done) for child := range c.children { // NOTE: acquiring the child's lock while holding parent's lock. child.cancel(false, err) } c.children = nil c.mu.Unlock() if removeFromParent { removeChild(c.Context, c) } } // 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 // 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. // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete. func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { if cur, ok := parent.Deadline(); ok && cur.Before(deadline) { // The current deadline is already sooner than the new one. return WithCancel(parent) } c := &timerCtx{ cancelCtx: newCancelCtx(parent), deadline: deadline, } propagateCancel(parent, c) d := deadline.Sub(time.Now()) if d <= 0 { c.cancel(true, DeadlineExceeded) // deadline has already passed return c, func() { c.cancel(true, Canceled) } } c.mu.Lock() defer c.mu.Unlock() if c.err == nil { c.timer = time.AfterFunc(d, func() { c.cancel(true, DeadlineExceeded) }) } 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 // delegating to cancelCtx.cancel. type timerCtx struct { *cancelCtx timer *time.Timer // Under cancelCtx.mu. deadline time.Time } func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { return c.deadline, true } func (c *timerCtx) String() string { return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now())) } func (c *timerCtx) cancel(removeFromParent bool, err error) { c.cancelCtx.cancel(false, err) if removeFromParent { // Remove this timerCtx from its parent cancelCtx's children. removeChild(c.cancelCtx.Context, c) } c.mu.Lock() if c.timer != nil { c.timer.Stop() c.timer = nil } c.mu.Unlock() } // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete: // // func slowOperationWithTimeout(ctx context.Context) (Result, error) { // ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) // defer cancel() // releases resources if slowOperation completes before timeout elapses // return slowOperation(ctx) // } func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { return WithDeadline(parent, time.Now().Add(timeout)) } // WithValue returns a copy of parent in which the value associated with key is // val. // // Use context Values only for request-scoped data that transits processes and // APIs, not for passing optional parameters to functions. 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 // delegates all other calls to the embedded Context. type valueCtx struct { Context key, val interface{} } func (c *valueCtx) String() string { return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) } func (c *valueCtx) Value(key interface{}) interface{} { if c.key == key { return c.val } return c.Context.Value(key) } ================================================ FILE: vendor/golang.org/x/net/context/pre_go19.go ================================================ // 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() ================================================ FILE: vendor/golang.org/x/net/idna/idna10.0.0.go ================================================ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // 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.10 // Package idna implements IDNA2008 using the compatibility processing // defined by UTS (Unicode Technical Standard) #46, which defines a standard to // deal with the transition from IDNA2003. // // IDNA2008 (Internationalized Domain Names for Applications), is defined in RFC // 5890, RFC 5891, RFC 5892, RFC 5893 and RFC 5894. // UTS #46 is defined in https://www.unicode.org/reports/tr46. // See https://unicode.org/cldr/utility/idna.jsp for a visualization of the // differences between these two standards. package idna // import "golang.org/x/net/idna" import ( "fmt" "strings" "unicode/utf8" "golang.org/x/text/secure/bidirule" "golang.org/x/text/unicode/bidi" "golang.org/x/text/unicode/norm" ) // NOTE: Unlike common practice in Go APIs, the functions will return a // sanitized domain name in case of errors. Browsers sometimes use a partially // evaluated string as lookup. // TODO: the current error handling is, in my opinion, the least opinionated. // Other strategies are also viable, though: // Option 1) Return an empty string in case of error, but allow the user to // specify explicitly which errors to ignore. // Option 2) Return the partially evaluated string if it is itself a valid // string, otherwise return the empty string in case of error. // Option 3) Option 1 and 2. // Option 4) Always return an empty string for now and implement Option 1 as // needed, and document that the return string may not be empty in case of // error in the future. // I think Option 1 is best, but it is quite opinionated. // ToASCII is a wrapper for Punycode.ToASCII. func ToASCII(s string) (string, error) { return Punycode.process(s, true) } // ToUnicode is a wrapper for Punycode.ToUnicode. func ToUnicode(s string) (string, error) { return Punycode.process(s, false) } // An Option configures a Profile at creation time. type Option func(*options) // Transitional sets a Profile to use the Transitional mapping as defined in UTS // #46. This will cause, for example, "ß" to be mapped to "ss". Using the // transitional mapping provides a compromise between IDNA2003 and IDNA2008 // compatibility. It is used by most browsers when resolving domain names. This // option is only meaningful if combined with MapForLookup. func Transitional(transitional bool) Option { return func(o *options) { o.transitional = true } } // VerifyDNSLength sets whether a Profile should fail if any of the IDN parts // are longer than allowed by the RFC. func VerifyDNSLength(verify bool) Option { return func(o *options) { o.verifyDNSLength = verify } } // RemoveLeadingDots removes leading label separators. Leading runes that map to // dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well. // // This is the behavior suggested by the UTS #46 and is adopted by some // browsers. func RemoveLeadingDots(remove bool) Option { return func(o *options) { o.removeLeadingDots = remove } } // ValidateLabels sets whether to check the mandatory label validation criteria // as defined in Section 5.4 of RFC 5891. This includes testing for correct use // of hyphens ('-'), normalization, validity of runes, and the context rules. func ValidateLabels(enable bool) Option { return func(o *options) { // Don't override existing mappings, but set one that at least checks // normalization if it is not set. if o.mapping == nil && enable { o.mapping = normalize } o.trie = trie o.validateLabels = enable o.fromPuny = validateFromPunycode } } // StrictDomainName limits the set of permissible ASCII characters to those // allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the // hyphen). This is set by default for MapForLookup and ValidateForRegistration. // // This option is useful, for instance, for browsers that allow characters // outside this range, for example a '_' (U+005F LOW LINE). See // http://www.rfc-editor.org/std/std3.txt for more details This option // corresponds to the UseSTD3ASCIIRules option in UTS #46. func StrictDomainName(use bool) Option { return func(o *options) { o.trie = trie o.useSTD3Rules = use o.fromPuny = validateFromPunycode } } // NOTE: the following options pull in tables. The tables should not be linked // in as long as the options are not used. // BidiRule enables the Bidi rule as defined in RFC 5893. Any application // that relies on proper validation of labels should include this rule. func BidiRule() Option { return func(o *options) { o.bidirule = bidirule.ValidString } } // ValidateForRegistration sets validation options to verify that a given IDN is // properly formatted for registration as defined by Section 4 of RFC 5891. func ValidateForRegistration() Option { return func(o *options) { o.mapping = validateRegistration StrictDomainName(true)(o) ValidateLabels(true)(o) VerifyDNSLength(true)(o) BidiRule()(o) } } // MapForLookup sets validation and mapping options such that a given IDN is // transformed for domain name lookup according to the requirements set out in // Section 5 of RFC 5891. The mappings follow the recommendations of RFC 5894, // RFC 5895 and UTS 46. It does not add the Bidi Rule. Use the BidiRule option // to add this check. // // The mappings include normalization and mapping case, width and other // compatibility mappings. func MapForLookup() Option { return func(o *options) { o.mapping = validateAndMap StrictDomainName(true)(o) ValidateLabels(true)(o) } } type options struct { transitional bool useSTD3Rules bool validateLabels bool verifyDNSLength bool removeLeadingDots bool trie *idnaTrie // fromPuny calls validation rules when converting A-labels to U-labels. fromPuny func(p *Profile, s string) error // mapping implements a validation and mapping step as defined in RFC 5895 // or UTS 46, tailored to, for example, domain registration or lookup. mapping func(p *Profile, s string) (mapped string, isBidi bool, err error) // bidirule, if specified, checks whether s conforms to the Bidi Rule // defined in RFC 5893. bidirule func(s string) bool } // A Profile defines the configuration of an IDNA mapper. type Profile struct { options } func apply(o *options, opts []Option) { for _, f := range opts { f(o) } } // New creates a new Profile. // // With no options, the returned Profile is the most permissive and equals the // Punycode Profile. Options can be passed to further restrict the Profile. The // MapForLookup and ValidateForRegistration options set a collection of options, // for lookup and registration purposes respectively, which can be tailored by // adding more fine-grained options, where later options override earlier // options. func New(o ...Option) *Profile { p := &Profile{} apply(&p.options, o) return p } // ToASCII converts a domain or domain label to its ASCII form. For example, // ToASCII("bücher.example.com") is "xn--bcher-kva.example.com", and // ToASCII("golang") is "golang". If an error is encountered it will return // an error and a (partially) processed result. func (p *Profile) ToASCII(s string) (string, error) { return p.process(s, true) } // ToUnicode converts a domain or domain label to its Unicode form. For example, // ToUnicode("xn--bcher-kva.example.com") is "bücher.example.com", and // ToUnicode("golang") is "golang". If an error is encountered it will return // an error and a (partially) processed result. func (p *Profile) ToUnicode(s string) (string, error) { pp := *p pp.transitional = false return pp.process(s, false) } // String reports a string with a description of the profile for debugging // purposes. The string format may change with different versions. func (p *Profile) String() string { s := "" if p.transitional { s = "Transitional" } else { s = "NonTransitional" } if p.useSTD3Rules { s += ":UseSTD3Rules" } if p.validateLabels { s += ":ValidateLabels" } if p.verifyDNSLength { s += ":VerifyDNSLength" } return s } var ( // Punycode is a Profile that does raw punycode processing with a minimum // of validation. Punycode *Profile = punycode // Lookup is the recommended profile for looking up domain names, according // to Section 5 of RFC 5891. The exact configuration of this profile may // change over time. Lookup *Profile = lookup // Display is the recommended profile for displaying domain names. // The configuration of this profile may change over time. Display *Profile = display // Registration is the recommended profile for checking whether a given // IDN is valid for registration, according to Section 4 of RFC 5891. Registration *Profile = registration punycode = &Profile{} lookup = &Profile{options{ transitional: true, useSTD3Rules: true, validateLabels: true, trie: trie, fromPuny: validateFromPunycode, mapping: validateAndMap, bidirule: bidirule.ValidString, }} display = &Profile{options{ useSTD3Rules: true, validateLabels: true, trie: trie, fromPuny: validateFromPunycode, mapping: validateAndMap, bidirule: bidirule.ValidString, }} registration = &Profile{options{ useSTD3Rules: true, validateLabels: true, verifyDNSLength: true, trie: trie, fromPuny: validateFromPunycode, mapping: validateRegistration, bidirule: bidirule.ValidString, }} // TODO: profiles // Register: recommended for approving domain names: don't do any mappings // but rather reject on invalid input. Bundle or block deviation characters. ) type labelError struct{ label, code_ string } func (e labelError) code() string { return e.code_ } func (e labelError) Error() string { return fmt.Sprintf("idna: invalid label %q", e.label) } type runeError rune func (e runeError) code() string { return "P1" } func (e runeError) Error() string { return fmt.Sprintf("idna: disallowed rune %U", e) } // process implements the algorithm described in section 4 of UTS #46, // see https://www.unicode.org/reports/tr46. func (p *Profile) process(s string, toASCII bool) (string, error) { var err error var isBidi bool if p.mapping != nil { s, isBidi, err = p.mapping(p, s) } // Remove leading empty labels. if p.removeLeadingDots { for ; len(s) > 0 && s[0] == '.'; s = s[1:] { } } // TODO: allow for a quick check of the tables data. // It seems like we should only create this error on ToASCII, but the // UTS 46 conformance tests suggests we should always check this. if err == nil && p.verifyDNSLength && s == "" { err = &labelError{s, "A4"} } labels := labelIter{orig: s} for ; !labels.done(); labels.next() { label := labels.label() if label == "" { // Empty labels are not okay. The label iterator skips the last // label if it is empty. if err == nil && p.verifyDNSLength { err = &labelError{s, "A4"} } continue } if strings.HasPrefix(label, acePrefix) { u, err2 := decode(label[len(acePrefix):]) if err2 != nil { if err == nil { err = err2 } // Spec says keep the old label. continue } isBidi = isBidi || bidirule.DirectionString(u) != bidi.LeftToRight labels.set(u) if err == nil && p.validateLabels { err = p.fromPuny(p, u) } if err == nil { // This should be called on NonTransitional, according to the // spec, but that currently does not have any effect. Use the // original profile to preserve options. err = p.validateLabel(u) } } else if err == nil { err = p.validateLabel(label) } } if isBidi && p.bidirule != nil && err == nil { for labels.reset(); !labels.done(); labels.next() { if !p.bidirule(labels.label()) { err = &labelError{s, "B"} break } } } if toASCII { for labels.reset(); !labels.done(); labels.next() { label := labels.label() if !ascii(label) { a, err2 := encode(acePrefix, label) if err == nil { err = err2 } label = a labels.set(a) } n := len(label) if p.verifyDNSLength && err == nil && (n == 0 || n > 63) { err = &labelError{label, "A4"} } } } s = labels.result() if toASCII && p.verifyDNSLength && err == nil { // Compute the length of the domain name minus the root label and its dot. n := len(s) if n > 0 && s[n-1] == '.' { n-- } if len(s) < 1 || n > 253 { err = &labelError{s, "A4"} } } return s, err } func normalize(p *Profile, s string) (mapped string, isBidi bool, err error) { // TODO: consider first doing a quick check to see if any of these checks // need to be done. This will make it slower in the general case, but // faster in the common case. mapped = norm.NFC.String(s) isBidi = bidirule.DirectionString(mapped) == bidi.RightToLeft return mapped, isBidi, nil } func validateRegistration(p *Profile, s string) (idem string, bidi bool, err error) { // TODO: filter need for normalization in loop below. if !norm.NFC.IsNormalString(s) { return s, false, &labelError{s, "V1"} } for i := 0; i < len(s); { v, sz := trie.lookupString(s[i:]) if sz == 0 { return s, bidi, runeError(utf8.RuneError) } bidi = bidi || info(v).isBidi(s[i:]) // Copy bytes not copied so far. switch p.simplify(info(v).category()) { // TODO: handle the NV8 defined in the Unicode idna data set to allow // for strict conformance to IDNA2008. case valid, deviation: case disallowed, mapped, unknown, ignored: r, _ := utf8.DecodeRuneInString(s[i:]) return s, bidi, runeError(r) } i += sz } return s, bidi, nil } func (c info) isBidi(s string) bool { if !c.isMapped() { return c&attributesMask == rtl } // TODO: also store bidi info for mapped data. This is possible, but a bit // cumbersome and not for the common case. p, _ := bidi.LookupString(s) switch p.Class() { case bidi.R, bidi.AL, bidi.AN: return true } return false } func validateAndMap(p *Profile, s string) (vm string, bidi bool, err error) { var ( b []byte k int ) // combinedInfoBits contains the or-ed bits of all runes. We use this // to derive the mayNeedNorm bit later. This may trigger normalization // overeagerly, but it will not do so in the common case. The end result // is another 10% saving on BenchmarkProfile for the common case. var combinedInfoBits info for i := 0; i < len(s); { v, sz := trie.lookupString(s[i:]) if sz == 0 { b = append(b, s[k:i]...) b = append(b, "\ufffd"...) k = len(s) if err == nil { err = runeError(utf8.RuneError) } break } combinedInfoBits |= info(v) bidi = bidi || info(v).isBidi(s[i:]) start := i i += sz // Copy bytes not copied so far. switch p.simplify(info(v).category()) { case valid: continue case disallowed: if err == nil { r, _ := utf8.DecodeRuneInString(s[start:]) err = runeError(r) } continue case mapped, deviation: b = append(b, s[k:start]...) b = info(v).appendMapping(b, s[start:i]) case ignored: b = append(b, s[k:start]...) // drop the rune case unknown: b = append(b, s[k:start]...) b = append(b, "\ufffd"...) } k = i } if k == 0 { // No changes so far. if combinedInfoBits&mayNeedNorm != 0 { s = norm.NFC.String(s) } } else { b = append(b, s[k:]...) if norm.NFC.QuickSpan(b) != len(b) { b = norm.NFC.Bytes(b) } // TODO: the punycode converters require strings as input. s = string(b) } return s, bidi, err } // A labelIter allows iterating over domain name labels. type labelIter struct { orig string slice []string curStart int curEnd int i int } func (l *labelIter) reset() { l.curStart = 0 l.curEnd = 0 l.i = 0 } func (l *labelIter) done() bool { return l.curStart >= len(l.orig) } func (l *labelIter) result() string { if l.slice != nil { return strings.Join(l.slice, ".") } return l.orig } func (l *labelIter) label() string { if l.slice != nil { return l.slice[l.i] } p := strings.IndexByte(l.orig[l.curStart:], '.') l.curEnd = l.curStart + p if p == -1 { l.curEnd = len(l.orig) } return l.orig[l.curStart:l.curEnd] } // next sets the value to the next label. It skips the last label if it is empty. func (l *labelIter) next() { l.i++ if l.slice != nil { if l.i >= len(l.slice) || l.i == len(l.slice)-1 && l.slice[l.i] == "" { l.curStart = len(l.orig) } } else { l.curStart = l.curEnd + 1 if l.curStart == len(l.orig)-1 && l.orig[l.curStart] == '.' { l.curStart = len(l.orig) } } } func (l *labelIter) set(s string) { if l.slice == nil { l.slice = strings.Split(l.orig, ".") } l.slice[l.i] = s } // acePrefix is the ASCII Compatible Encoding prefix. const acePrefix = "xn--" func (p *Profile) simplify(cat category) category { switch cat { case disallowedSTD3Mapped: if p.useSTD3Rules { cat = disallowed } else { cat = mapped } case disallowedSTD3Valid: if p.useSTD3Rules { cat = disallowed } else { cat = valid } case deviation: if !p.transitional { cat = valid } case validNV8, validXV8: // TODO: handle V2008 cat = valid } return cat } func validateFromPunycode(p *Profile, s string) error { if !norm.NFC.IsNormalString(s) { return &labelError{s, "V1"} } // TODO: detect whether string may have to be normalized in the following // loop. for i := 0; i < len(s); { v, sz := trie.lookupString(s[i:]) if sz == 0 { return runeError(utf8.RuneError) } if c := p.simplify(info(v).category()); c != valid && c != deviation { return &labelError{s, "V6"} } i += sz } return nil } const ( zwnj = "\u200c" zwj = "\u200d" ) type joinState int8 const ( stateStart joinState = iota stateVirama stateBefore stateBeforeVirama stateAfter stateFAIL ) var joinStates = [][numJoinTypes]joinState{ stateStart: { joiningL: stateBefore, joiningD: stateBefore, joinZWNJ: stateFAIL, joinZWJ: stateFAIL, joinVirama: stateVirama, }, stateVirama: { joiningL: stateBefore, joiningD: stateBefore, }, stateBefore: { joiningL: stateBefore, joiningD: stateBefore, joiningT: stateBefore, joinZWNJ: stateAfter, joinZWJ: stateFAIL, joinVirama: stateBeforeVirama, }, stateBeforeVirama: { joiningL: stateBefore, joiningD: stateBefore, joiningT: stateBefore, }, stateAfter: { joiningL: stateFAIL, joiningD: stateBefore, joiningT: stateAfter, joiningR: stateStart, joinZWNJ: stateFAIL, joinZWJ: stateFAIL, joinVirama: stateAfter, // no-op as we can't accept joiners here }, stateFAIL: { 0: stateFAIL, joiningL: stateFAIL, joiningD: stateFAIL, joiningT: stateFAIL, joiningR: stateFAIL, joinZWNJ: stateFAIL, joinZWJ: stateFAIL, joinVirama: stateFAIL, }, } // validateLabel validates the criteria from Section 4.1. Item 1, 4, and 6 are // already implicitly satisfied by the overall implementation. func (p *Profile) validateLabel(s string) (err error) { if s == "" { if p.verifyDNSLength { return &labelError{s, "A4"} } return nil } if !p.validateLabels { return nil } trie := p.trie // p.validateLabels is only set if trie is set. if len(s) > 4 && s[2] == '-' && s[3] == '-' { return &labelError{s, "V2"} } if s[0] == '-' || s[len(s)-1] == '-' { return &labelError{s, "V3"} } // TODO: merge the use of this in the trie. v, sz := trie.lookupString(s) x := info(v) if x.isModifier() { return &labelError{s, "V5"} } // Quickly return in the absence of zero-width (non) joiners. if strings.Index(s, zwj) == -1 && strings.Index(s, zwnj) == -1 { return nil } st := stateStart for i := 0; ; { jt := x.joinType() if s[i:i+sz] == zwj { jt = joinZWJ } else if s[i:i+sz] == zwnj { jt = joinZWNJ } st = joinStates[st][jt] if x.isViramaModifier() { st = joinStates[st][joinVirama] } if i += sz; i == len(s) { break } v, sz = trie.lookupString(s[i:]) x = info(v) } if st == stateFAIL || st == stateAfter { return &labelError{s, "C"} } return nil } func ascii(s string) bool { for i := 0; i < len(s); i++ { if s[i] >= utf8.RuneSelf { return false } } return true } ================================================ FILE: vendor/golang.org/x/net/idna/idna9.0.0.go ================================================ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // 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.10 // Package idna implements IDNA2008 using the compatibility processing // defined by UTS (Unicode Technical Standard) #46, which defines a standard to // deal with the transition from IDNA2003. // // IDNA2008 (Internationalized Domain Names for Applications), is defined in RFC // 5890, RFC 5891, RFC 5892, RFC 5893 and RFC 5894. // UTS #46 is defined in https://www.unicode.org/reports/tr46. // See https://unicode.org/cldr/utility/idna.jsp for a visualization of the // differences between these two standards. package idna // import "golang.org/x/net/idna" import ( "fmt" "strings" "unicode/utf8" "golang.org/x/text/secure/bidirule" "golang.org/x/text/unicode/norm" ) // NOTE: Unlike common practice in Go APIs, the functions will return a // sanitized domain name in case of errors. Browsers sometimes use a partially // evaluated string as lookup. // TODO: the current error handling is, in my opinion, the least opinionated. // Other strategies are also viable, though: // Option 1) Return an empty string in case of error, but allow the user to // specify explicitly which errors to ignore. // Option 2) Return the partially evaluated string if it is itself a valid // string, otherwise return the empty string in case of error. // Option 3) Option 1 and 2. // Option 4) Always return an empty string for now and implement Option 1 as // needed, and document that the return string may not be empty in case of // error in the future. // I think Option 1 is best, but it is quite opinionated. // ToASCII is a wrapper for Punycode.ToASCII. func ToASCII(s string) (string, error) { return Punycode.process(s, true) } // ToUnicode is a wrapper for Punycode.ToUnicode. func ToUnicode(s string) (string, error) { return Punycode.process(s, false) } // An Option configures a Profile at creation time. type Option func(*options) // Transitional sets a Profile to use the Transitional mapping as defined in UTS // #46. This will cause, for example, "ß" to be mapped to "ss". Using the // transitional mapping provides a compromise between IDNA2003 and IDNA2008 // compatibility. It is used by most browsers when resolving domain names. This // option is only meaningful if combined with MapForLookup. func Transitional(transitional bool) Option { return func(o *options) { o.transitional = true } } // VerifyDNSLength sets whether a Profile should fail if any of the IDN parts // are longer than allowed by the RFC. func VerifyDNSLength(verify bool) Option { return func(o *options) { o.verifyDNSLength = verify } } // RemoveLeadingDots removes leading label separators. Leading runes that map to // dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well. // // This is the behavior suggested by the UTS #46 and is adopted by some // browsers. func RemoveLeadingDots(remove bool) Option { return func(o *options) { o.removeLeadingDots = remove } } // ValidateLabels sets whether to check the mandatory label validation criteria // as defined in Section 5.4 of RFC 5891. This includes testing for correct use // of hyphens ('-'), normalization, validity of runes, and the context rules. func ValidateLabels(enable bool) Option { return func(o *options) { // Don't override existing mappings, but set one that at least checks // normalization if it is not set. if o.mapping == nil && enable { o.mapping = normalize } o.trie = trie o.validateLabels = enable o.fromPuny = validateFromPunycode } } // StrictDomainName limits the set of permissable ASCII characters to those // allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the // hyphen). This is set by default for MapForLookup and ValidateForRegistration. // // This option is useful, for instance, for browsers that allow characters // outside this range, for example a '_' (U+005F LOW LINE). See // http://www.rfc-editor.org/std/std3.txt for more details This option // corresponds to the UseSTD3ASCIIRules option in UTS #46. func StrictDomainName(use bool) Option { return func(o *options) { o.trie = trie o.useSTD3Rules = use o.fromPuny = validateFromPunycode } } // NOTE: the following options pull in tables. The tables should not be linked // in as long as the options are not used. // BidiRule enables the Bidi rule as defined in RFC 5893. Any application // that relies on proper validation of labels should include this rule. func BidiRule() Option { return func(o *options) { o.bidirule = bidirule.ValidString } } // ValidateForRegistration sets validation options to verify that a given IDN is // properly formatted for registration as defined by Section 4 of RFC 5891. func ValidateForRegistration() Option { return func(o *options) { o.mapping = validateRegistration StrictDomainName(true)(o) ValidateLabels(true)(o) VerifyDNSLength(true)(o) BidiRule()(o) } } // MapForLookup sets validation and mapping options such that a given IDN is // transformed for domain name lookup according to the requirements set out in // Section 5 of RFC 5891. The mappings follow the recommendations of RFC 5894, // RFC 5895 and UTS 46. It does not add the Bidi Rule. Use the BidiRule option // to add this check. // // The mappings include normalization and mapping case, width and other // compatibility mappings. func MapForLookup() Option { return func(o *options) { o.mapping = validateAndMap StrictDomainName(true)(o) ValidateLabels(true)(o) RemoveLeadingDots(true)(o) } } type options struct { transitional bool useSTD3Rules bool validateLabels bool verifyDNSLength bool removeLeadingDots bool trie *idnaTrie // fromPuny calls validation rules when converting A-labels to U-labels. fromPuny func(p *Profile, s string) error // mapping implements a validation and mapping step as defined in RFC 5895 // or UTS 46, tailored to, for example, domain registration or lookup. mapping func(p *Profile, s string) (string, error) // bidirule, if specified, checks whether s conforms to the Bidi Rule // defined in RFC 5893. bidirule func(s string) bool } // A Profile defines the configuration of a IDNA mapper. type Profile struct { options } func apply(o *options, opts []Option) { for _, f := range opts { f(o) } } // New creates a new Profile. // // With no options, the returned Profile is the most permissive and equals the // Punycode Profile. Options can be passed to further restrict the Profile. The // MapForLookup and ValidateForRegistration options set a collection of options, // for lookup and registration purposes respectively, which can be tailored by // adding more fine-grained options, where later options override earlier // options. func New(o ...Option) *Profile { p := &Profile{} apply(&p.options, o) return p } // ToASCII converts a domain or domain label to its ASCII form. For example, // ToASCII("bücher.example.com") is "xn--bcher-kva.example.com", and // ToASCII("golang") is "golang". If an error is encountered it will return // an error and a (partially) processed result. func (p *Profile) ToASCII(s string) (string, error) { return p.process(s, true) } // ToUnicode converts a domain or domain label to its Unicode form. For example, // ToUnicode("xn--bcher-kva.example.com") is "bücher.example.com", and // ToUnicode("golang") is "golang". If an error is encountered it will return // an error and a (partially) processed result. func (p *Profile) ToUnicode(s string) (string, error) { pp := *p pp.transitional = false return pp.process(s, false) } // String reports a string with a description of the profile for debugging // purposes. The string format may change with different versions. func (p *Profile) String() string { s := "" if p.transitional { s = "Transitional" } else { s = "NonTransitional" } if p.useSTD3Rules { s += ":UseSTD3Rules" } if p.validateLabels { s += ":ValidateLabels" } if p.verifyDNSLength { s += ":VerifyDNSLength" } return s } var ( // Punycode is a Profile that does raw punycode processing with a minimum // of validation. Punycode *Profile = punycode // Lookup is the recommended profile for looking up domain names, according // to Section 5 of RFC 5891. The exact configuration of this profile may // change over time. Lookup *Profile = lookup // Display is the recommended profile for displaying domain names. // The configuration of this profile may change over time. Display *Profile = display // Registration is the recommended profile for checking whether a given // IDN is valid for registration, according to Section 4 of RFC 5891. Registration *Profile = registration punycode = &Profile{} lookup = &Profile{options{ transitional: true, useSTD3Rules: true, validateLabels: true, removeLeadingDots: true, trie: trie, fromPuny: validateFromPunycode, mapping: validateAndMap, bidirule: bidirule.ValidString, }} display = &Profile{options{ useSTD3Rules: true, validateLabels: true, removeLeadingDots: true, trie: trie, fromPuny: validateFromPunycode, mapping: validateAndMap, bidirule: bidirule.ValidString, }} registration = &Profile{options{ useSTD3Rules: true, validateLabels: true, verifyDNSLength: true, trie: trie, fromPuny: validateFromPunycode, mapping: validateRegistration, bidirule: bidirule.ValidString, }} // TODO: profiles // Register: recommended for approving domain names: don't do any mappings // but rather reject on invalid input. Bundle or block deviation characters. ) type labelError struct{ label, code_ string } func (e labelError) code() string { return e.code_ } func (e labelError) Error() string { return fmt.Sprintf("idna: invalid label %q", e.label) } type runeError rune func (e runeError) code() string { return "P1" } func (e runeError) Error() string { return fmt.Sprintf("idna: disallowed rune %U", e) } // process implements the algorithm described in section 4 of UTS #46, // see https://www.unicode.org/reports/tr46. func (p *Profile) process(s string, toASCII bool) (string, error) { var err error if p.mapping != nil { s, err = p.mapping(p, s) } // Remove leading empty labels. if p.removeLeadingDots { for ; len(s) > 0 && s[0] == '.'; s = s[1:] { } } // It seems like we should only create this error on ToASCII, but the // UTS 46 conformance tests suggests we should always check this. if err == nil && p.verifyDNSLength && s == "" { err = &labelError{s, "A4"} } labels := labelIter{orig: s} for ; !labels.done(); labels.next() { label := labels.label() if label == "" { // Empty labels are not okay. The label iterator skips the last // label if it is empty. if err == nil && p.verifyDNSLength { err = &labelError{s, "A4"} } continue } if strings.HasPrefix(label, acePrefix) { u, err2 := decode(label[len(acePrefix):]) if err2 != nil { if err == nil { err = err2 } // Spec says keep the old label. continue } labels.set(u) if err == nil && p.validateLabels { err = p.fromPuny(p, u) } if err == nil { // This should be called on NonTransitional, according to the // spec, but that currently does not have any effect. Use the // original profile to preserve options. err = p.validateLabel(u) } } else if err == nil { err = p.validateLabel(label) } } if toASCII { for labels.reset(); !labels.done(); labels.next() { label := labels.label() if !ascii(label) { a, err2 := encode(acePrefix, label) if err == nil { err = err2 } label = a labels.set(a) } n := len(label) if p.verifyDNSLength && err == nil && (n == 0 || n > 63) { err = &labelError{label, "A4"} } } } s = labels.result() if toASCII && p.verifyDNSLength && err == nil { // Compute the length of the domain name minus the root label and its dot. n := len(s) if n > 0 && s[n-1] == '.' { n-- } if len(s) < 1 || n > 253 { err = &labelError{s, "A4"} } } return s, err } func normalize(p *Profile, s string) (string, error) { return norm.NFC.String(s), nil } func validateRegistration(p *Profile, s string) (string, error) { if !norm.NFC.IsNormalString(s) { return s, &labelError{s, "V1"} } for i := 0; i < len(s); { v, sz := trie.lookupString(s[i:]) // Copy bytes not copied so far. switch p.simplify(info(v).category()) { // TODO: handle the NV8 defined in the Unicode idna data set to allow // for strict conformance to IDNA2008. case valid, deviation: case disallowed, mapped, unknown, ignored: r, _ := utf8.DecodeRuneInString(s[i:]) return s, runeError(r) } i += sz } return s, nil } func validateAndMap(p *Profile, s string) (string, error) { var ( err error b []byte k int ) for i := 0; i < len(s); { v, sz := trie.lookupString(s[i:]) start := i i += sz // Copy bytes not copied so far. switch p.simplify(info(v).category()) { case valid: continue case disallowed: if err == nil { r, _ := utf8.DecodeRuneInString(s[start:]) err = runeError(r) } continue case mapped, deviation: b = append(b, s[k:start]...) b = info(v).appendMapping(b, s[start:i]) case ignored: b = append(b, s[k:start]...) // drop the rune case unknown: b = append(b, s[k:start]...) b = append(b, "\ufffd"...) } k = i } if k == 0 { // No changes so far. s = norm.NFC.String(s) } else { b = append(b, s[k:]...) if norm.NFC.QuickSpan(b) != len(b) { b = norm.NFC.Bytes(b) } // TODO: the punycode converters require strings as input. s = string(b) } return s, err } // A labelIter allows iterating over domain name labels. type labelIter struct { orig string slice []string curStart int curEnd int i int } func (l *labelIter) reset() { l.curStart = 0 l.curEnd = 0 l.i = 0 } func (l *labelIter) done() bool { return l.curStart >= len(l.orig) } func (l *labelIter) result() string { if l.slice != nil { return strings.Join(l.slice, ".") } return l.orig } func (l *labelIter) label() string { if l.slice != nil { return l.slice[l.i] } p := strings.IndexByte(l.orig[l.curStart:], '.') l.curEnd = l.curStart + p if p == -1 { l.curEnd = len(l.orig) } return l.orig[l.curStart:l.curEnd] } // next sets the value to the next label. It skips the last label if it is empty. func (l *labelIter) next() { l.i++ if l.slice != nil { if l.i >= len(l.slice) || l.i == len(l.slice)-1 && l.slice[l.i] == "" { l.curStart = len(l.orig) } } else { l.curStart = l.curEnd + 1 if l.curStart == len(l.orig)-1 && l.orig[l.curStart] == '.' { l.curStart = len(l.orig) } } } func (l *labelIter) set(s string) { if l.slice == nil { l.slice = strings.Split(l.orig, ".") } l.slice[l.i] = s } // acePrefix is the ASCII Compatible Encoding prefix. const acePrefix = "xn--" func (p *Profile) simplify(cat category) category { switch cat { case disallowedSTD3Mapped: if p.useSTD3Rules { cat = disallowed } else { cat = mapped } case disallowedSTD3Valid: if p.useSTD3Rules { cat = disallowed } else { cat = valid } case deviation: if !p.transitional { cat = valid } case validNV8, validXV8: // TODO: handle V2008 cat = valid } return cat } func validateFromPunycode(p *Profile, s string) error { if !norm.NFC.IsNormalString(s) { return &labelError{s, "V1"} } for i := 0; i < len(s); { v, sz := trie.lookupString(s[i:]) if c := p.simplify(info(v).category()); c != valid && c != deviation { return &labelError{s, "V6"} } i += sz } return nil } const ( zwnj = "\u200c" zwj = "\u200d" ) type joinState int8 const ( stateStart joinState = iota stateVirama stateBefore stateBeforeVirama stateAfter stateFAIL ) var joinStates = [][numJoinTypes]joinState{ stateStart: { joiningL: stateBefore, joiningD: stateBefore, joinZWNJ: stateFAIL, joinZWJ: stateFAIL, joinVirama: stateVirama, }, stateVirama: { joiningL: stateBefore, joiningD: stateBefore, }, stateBefore: { joiningL: stateBefore, joiningD: stateBefore, joiningT: stateBefore, joinZWNJ: stateAfter, joinZWJ: stateFAIL, joinVirama: stateBeforeVirama, }, stateBeforeVirama: { joiningL: stateBefore, joiningD: stateBefore, joiningT: stateBefore, }, stateAfter: { joiningL: stateFAIL, joiningD: stateBefore, joiningT: stateAfter, joiningR: stateStart, joinZWNJ: stateFAIL, joinZWJ: stateFAIL, joinVirama: stateAfter, // no-op as we can't accept joiners here }, stateFAIL: { 0: stateFAIL, joiningL: stateFAIL, joiningD: stateFAIL, joiningT: stateFAIL, joiningR: stateFAIL, joinZWNJ: stateFAIL, joinZWJ: stateFAIL, joinVirama: stateFAIL, }, } // validateLabel validates the criteria from Section 4.1. Item 1, 4, and 6 are // already implicitly satisfied by the overall implementation. func (p *Profile) validateLabel(s string) error { if s == "" { if p.verifyDNSLength { return &labelError{s, "A4"} } return nil } if p.bidirule != nil && !p.bidirule(s) { return &labelError{s, "B"} } if !p.validateLabels { return nil } trie := p.trie // p.validateLabels is only set if trie is set. if len(s) > 4 && s[2] == '-' && s[3] == '-' { return &labelError{s, "V2"} } if s[0] == '-' || s[len(s)-1] == '-' { return &labelError{s, "V3"} } // TODO: merge the use of this in the trie. v, sz := trie.lookupString(s) x := info(v) if x.isModifier() { return &labelError{s, "V5"} } // Quickly return in the absence of zero-width (non) joiners. if strings.Index(s, zwj) == -1 && strings.Index(s, zwnj) == -1 { return nil } st := stateStart for i := 0; ; { jt := x.joinType() if s[i:i+sz] == zwj { jt = joinZWJ } else if s[i:i+sz] == zwnj { jt = joinZWNJ } st = joinStates[st][jt] if x.isViramaModifier() { st = joinStates[st][joinVirama] } if i += sz; i == len(s) { break } v, sz = trie.lookupString(s[i:]) x = info(v) } if st == stateFAIL || st == stateAfter { return &labelError{s, "C"} } return nil } func ascii(s string) bool { for i := 0; i < len(s); i++ { if s[i] >= utf8.RuneSelf { return false } } return true } ================================================ FILE: vendor/golang.org/x/net/idna/punycode.go ================================================ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // 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 idna // This file implements the Punycode algorithm from RFC 3492. import ( "math" "strings" "unicode/utf8" ) // These parameter values are specified in section 5. // // All computation is done with int32s, so that overflow behavior is identical // regardless of whether int is 32-bit or 64-bit. const ( base int32 = 36 damp int32 = 700 initialBias int32 = 72 initialN int32 = 128 skew int32 = 38 tmax int32 = 26 tmin int32 = 1 ) func punyError(s string) error { return &labelError{s, "A3"} } // decode decodes a string as specified in section 6.2. func decode(encoded string) (string, error) { if encoded == "" { return "", nil } pos := 1 + strings.LastIndex(encoded, "-") if pos == 1 { return "", punyError(encoded) } if pos == len(encoded) { return encoded[:len(encoded)-1], nil } output := make([]rune, 0, len(encoded)) if pos != 0 { for _, r := range encoded[:pos-1] { output = append(output, r) } } i, n, bias := int32(0), initialN, initialBias for pos < len(encoded) { oldI, w := i, int32(1) for k := base; ; k += base { if pos == len(encoded) { return "", punyError(encoded) } digit, ok := decodeDigit(encoded[pos]) if !ok { return "", punyError(encoded) } pos++ i += digit * w if i < 0 { return "", punyError(encoded) } t := k - bias if t < tmin { t = tmin } else if t > tmax { t = tmax } if digit < t { break } w *= base - t if w >= math.MaxInt32/base { return "", punyError(encoded) } } x := int32(len(output) + 1) bias = adapt(i-oldI, x, oldI == 0) n += i / x i %= x if n > utf8.MaxRune || len(output) >= 1024 { return "", punyError(encoded) } output = append(output, 0) copy(output[i+1:], output[i:]) output[i] = n i++ } return string(output), nil } // encode encodes a string as specified in section 6.3 and prepends prefix to // the result. // // The "while h < length(input)" line in the specification becomes "for // remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes. func encode(prefix, s string) (string, error) { output := make([]byte, len(prefix), len(prefix)+1+2*len(s)) copy(output, prefix) delta, n, bias := int32(0), initialN, initialBias b, remaining := int32(0), int32(0) for _, r := range s { if r < 0x80 { b++ output = append(output, byte(r)) } else { remaining++ } } h := b if b > 0 { output = append(output, '-') } for remaining != 0 { m := int32(0x7fffffff) for _, r := range s { if m > r && r >= n { m = r } } delta += (m - n) * (h + 1) if delta < 0 { return "", punyError(s) } n = m for _, r := range s { if r < n { delta++ if delta < 0 { return "", punyError(s) } continue } if r > n { continue } q := delta for k := base; ; k += base { t := k - bias if t < tmin { t = tmin } else if t > tmax { t = tmax } if q < t { break } output = append(output, encodeDigit(t+(q-t)%(base-t))) q = (q - t) / (base - t) } output = append(output, encodeDigit(q)) bias = adapt(delta, h+1, h == b) delta = 0 h++ remaining-- } delta++ n++ } return string(output), nil } func decodeDigit(x byte) (digit int32, ok bool) { switch { case '0' <= x && x <= '9': return int32(x - ('0' - 26)), true case 'A' <= x && x <= 'Z': return int32(x - 'A'), true case 'a' <= x && x <= 'z': return int32(x - 'a'), true } return 0, false } func encodeDigit(digit int32) byte { switch { case 0 <= digit && digit < 26: return byte(digit + 'a') case 26 <= digit && digit < 36: return byte(digit + ('0' - 26)) } panic("idna: internal error in punycode encoding") } // adapt is the bias adaptation function specified in section 6.1. func adapt(delta, numPoints int32, firstTime bool) int32 { if firstTime { delta /= damp } else { delta /= 2 } delta += delta / numPoints k := int32(0) for delta > ((base-tmin)*tmax)/2 { delta /= base - tmin k += base } return k + (base-tmin+1)*delta/(delta+skew) } ================================================ FILE: vendor/golang.org/x/net/idna/tables10.0.0.go ================================================ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // +build go1.10,!go1.13 package idna // UnicodeVersion is the Unicode version from which the tables in this package are derived. const UnicodeVersion = "10.0.0" var mappings string = "" + // Size: 8175 bytes "\x00\x01 \x03 ̈\x01a\x03 ̄\x012\x013\x03 ́\x03 ̧\x011\x01o\x051⁄4\x051⁄2" + "\x053⁄4\x03i̇\x03l·\x03ʼn\x01s\x03dž\x03ⱥ\x03ⱦ\x01h\x01j\x01r\x01w\x01y" + "\x03 ̆\x03 ̇\x03 ̊\x03 ̨\x03 ̃\x03 ̋\x01l\x01x\x04̈́\x03 ι\x01;\x05 ̈́" + "\x04եւ\x04اٴ\x04وٴ\x04ۇٴ\x04يٴ\x06क़\x06ख़\x06ग़\x06ज़\x06ड़\x06ढ़\x06फ़" + "\x06य़\x06ড়\x06ঢ়\x06য়\x06ਲ਼\x06ਸ਼\x06ਖ਼\x06ਗ਼\x06ਜ਼\x06ਫ਼\x06ଡ଼\x06ଢ଼" + "\x06ํา\x06ໍາ\x06ຫນ\x06ຫມ\x06གྷ\x06ཌྷ\x06དྷ\x06བྷ\x06ཛྷ\x06ཀྵ\x06ཱི\x06ཱུ" + "\x06ྲྀ\x09ྲཱྀ\x06ླྀ\x09ླཱྀ\x06ཱྀ\x06ྒྷ\x06ྜྷ\x06ྡྷ\x06ྦྷ\x06ྫྷ\x06ྐྵ\x02" + "в\x02д\x02о\x02с\x02т\x02ъ\x02ѣ\x02æ\x01b\x01d\x01e\x02ǝ\x01g\x01i\x01k" + "\x01m\x01n\x02ȣ\x01p\x01t\x01u\x02ɐ\x02ɑ\x02ə\x02ɛ\x02ɜ\x02ŋ\x02ɔ\x02ɯ" + "\x01v\x02β\x02γ\x02δ\x02φ\x02χ\x02ρ\x02н\x02ɒ\x01c\x02ɕ\x02ð\x01f\x02ɟ" + "\x02ɡ\x02ɥ\x02ɨ\x02ɩ\x02ɪ\x02ʝ\x02ɭ\x02ʟ\x02ɱ\x02ɰ\x02ɲ\x02ɳ\x02ɴ\x02ɵ" + "\x02ɸ\x02ʂ\x02ʃ\x02ƫ\x02ʉ\x02ʊ\x02ʋ\x02ʌ\x01z\x02ʐ\x02ʑ\x02ʒ\x02θ\x02ss" + "\x02ά\x02έ\x02ή\x02ί\x02ό\x02ύ\x02ώ\x05ἀι\x05ἁι\x05ἂι\x05ἃι\x05ἄι\x05ἅι" + "\x05ἆι\x05ἇι\x05ἠι\x05ἡι\x05ἢι\x05ἣι\x05ἤι\x05ἥι\x05ἦι\x05ἧι\x05ὠι\x05ὡι" + "\x05ὢι\x05ὣι\x05ὤι\x05ὥι\x05ὦι\x05ὧι\x05ὰι\x04αι\x04άι\x05ᾶι\x02ι\x05 ̈͂" + "\x05ὴι\x04ηι\x04ήι\x05ῆι\x05 ̓̀\x05 ̓́\x05 ̓͂\x02ΐ\x05 ̔̀\x05 ̔́\x05 ̔͂" + "\x02ΰ\x05 ̈̀\x01`\x05ὼι\x04ωι\x04ώι\x05ῶι\x06′′\x09′′′\x06‵‵\x09‵‵‵\x02!" + "!\x02??\x02?!\x02!?\x0c′′′′\x010\x014\x015\x016\x017\x018\x019\x01+\x01=" + "\x01(\x01)\x02rs\x02ħ\x02no\x01q\x02sm\x02tm\x02ω\x02å\x02א\x02ב\x02ג" + "\x02ד\x02π\x051⁄7\x051⁄9\x061⁄10\x051⁄3\x052⁄3\x051⁄5\x052⁄5\x053⁄5\x054" + "⁄5\x051⁄6\x055⁄6\x051⁄8\x053⁄8\x055⁄8\x057⁄8\x041⁄\x02ii\x02iv\x02vi" + "\x04viii\x02ix\x02xi\x050⁄3\x06∫∫\x09∫∫∫\x06∮∮\x09∮∮∮\x0210\x0211\x0212" + "\x0213\x0214\x0215\x0216\x0217\x0218\x0219\x0220\x04(10)\x04(11)\x04(12)" + "\x04(13)\x04(14)\x04(15)\x04(16)\x04(17)\x04(18)\x04(19)\x04(20)\x0c∫∫∫∫" + "\x02==\x05⫝̸\x02ɫ\x02ɽ\x02ȿ\x02ɀ\x01.\x04 ゙\x04 ゚\x06より\x06コト\x05(ᄀ)\x05" + "(ᄂ)\x05(ᄃ)\x05(ᄅ)\x05(ᄆ)\x05(ᄇ)\x05(ᄉ)\x05(ᄋ)\x05(ᄌ)\x05(ᄎ)\x05(ᄏ)\x05(ᄐ" + ")\x05(ᄑ)\x05(ᄒ)\x05(가)\x05(나)\x05(다)\x05(라)\x05(마)\x05(바)\x05(사)\x05(아)" + "\x05(자)\x05(차)\x05(카)\x05(타)\x05(파)\x05(하)\x05(주)\x08(오전)\x08(오후)\x05(一)" + "\x05(二)\x05(三)\x05(四)\x05(五)\x05(六)\x05(七)\x05(八)\x05(九)\x05(十)\x05(月)" + "\x05(火)\x05(水)\x05(木)\x05(金)\x05(土)\x05(日)\x05(株)\x05(有)\x05(社)\x05(名)" + "\x05(特)\x05(財)\x05(祝)\x05(労)\x05(代)\x05(呼)\x05(学)\x05(監)\x05(企)\x05(資)" + "\x05(協)\x05(祭)\x05(休)\x05(自)\x05(至)\x0221\x0222\x0223\x0224\x0225\x0226" + "\x0227\x0228\x0229\x0230\x0231\x0232\x0233\x0234\x0235\x06참고\x06주의\x0236" + "\x0237\x0238\x0239\x0240\x0241\x0242\x0243\x0244\x0245\x0246\x0247\x0248" + "\x0249\x0250\x041月\x042月\x043月\x044月\x045月\x046月\x047月\x048月\x049月\x0510" + "月\x0511月\x0512月\x02hg\x02ev\x0cアパート\x0cアルファ\x0cアンペア\x09アール\x0cイニング\x09" + "インチ\x09ウォン\x0fエスクード\x0cエーカー\x09オンス\x09オーム\x09カイリ\x0cカラット\x0cカロリー\x09ガロ" + "ン\x09ガンマ\x06ギガ\x09ギニー\x0cキュリー\x0cギルダー\x06キロ\x0fキログラム\x12キロメートル\x0fキロワッ" + "ト\x09グラム\x0fグラムトン\x0fクルゼイロ\x0cクローネ\x09ケース\x09コルナ\x09コーポ\x0cサイクル\x0fサンチ" + "ーム\x0cシリング\x09センチ\x09セント\x09ダース\x06デシ\x06ドル\x06トン\x06ナノ\x09ノット\x09ハイツ" + "\x0fパーセント\x09パーツ\x0cバーレル\x0fピアストル\x09ピクル\x06ピコ\x06ビル\x0fファラッド\x0cフィート" + "\x0fブッシェル\x09フラン\x0fヘクタール\x06ペソ\x09ペニヒ\x09ヘルツ\x09ペンス\x09ページ\x09ベータ\x0cポイ" + "ント\x09ボルト\x06ホン\x09ポンド\x09ホール\x09ホーン\x0cマイクロ\x09マイル\x09マッハ\x09マルク\x0fマ" + "ンション\x0cミクロン\x06ミリ\x0fミリバール\x06メガ\x0cメガトン\x0cメートル\x09ヤード\x09ヤール\x09ユアン" + "\x0cリットル\x06リラ\x09ルピー\x0cルーブル\x06レム\x0fレントゲン\x09ワット\x040点\x041点\x042点" + "\x043点\x044点\x045点\x046点\x047点\x048点\x049点\x0510点\x0511点\x0512点\x0513点" + "\x0514点\x0515点\x0516点\x0517点\x0518点\x0519点\x0520点\x0521点\x0522点\x0523点" + "\x0524点\x02da\x02au\x02ov\x02pc\x02dm\x02iu\x06平成\x06昭和\x06大正\x06明治\x0c株" + "式会社\x02pa\x02na\x02ma\x02ka\x02kb\x02mb\x02gb\x04kcal\x02pf\x02nf\x02m" + "g\x02kg\x02hz\x02ml\x02dl\x02kl\x02fm\x02nm\x02mm\x02cm\x02km\x02m2\x02m" + "3\x05m∕s\x06m∕s2\x07rad∕s\x08rad∕s2\x02ps\x02ns\x02ms\x02pv\x02nv\x02mv" + "\x02kv\x02pw\x02nw\x02mw\x02kw\x02bq\x02cc\x02cd\x06c∕kg\x02db\x02gy\x02" + "ha\x02hp\x02in\x02kk\x02kt\x02lm\x02ln\x02lx\x02ph\x02pr\x02sr\x02sv\x02" + "wb\x05v∕m\x05a∕m\x041日\x042日\x043日\x044日\x045日\x046日\x047日\x048日\x049日" + "\x0510日\x0511日\x0512日\x0513日\x0514日\x0515日\x0516日\x0517日\x0518日\x0519日" + "\x0520日\x0521日\x0522日\x0523日\x0524日\x0525日\x0526日\x0527日\x0528日\x0529日" + "\x0530日\x0531日\x02ь\x02ɦ\x02ɬ\x02ʞ\x02ʇ\x02œ\x04𤋮\x04𢡊\x04𢡄\x04𣏕\x04𥉉" + "\x04𥳐\x04𧻓\x02ff\x02fi\x02fl\x02st\x04մն\x04մե\x04մի\x04վն\x04մխ\x04יִ" + "\x04ײַ\x02ע\x02ה\x02כ\x02ל\x02ם\x02ר\x02ת\x04שׁ\x04שׂ\x06שּׁ\x06שּׂ\x04א" + "ַ\x04אָ\x04אּ\x04בּ\x04גּ\x04דּ\x04הּ\x04וּ\x04זּ\x04טּ\x04יּ\x04ךּ\x04" + "כּ\x04לּ\x04מּ\x04נּ\x04סּ\x04ףּ\x04פּ\x04צּ\x04קּ\x04רּ\x04שּ\x04תּ" + "\x04וֹ\x04בֿ\x04כֿ\x04פֿ\x04אל\x02ٱ\x02ٻ\x02پ\x02ڀ\x02ٺ\x02ٿ\x02ٹ\x02ڤ" + "\x02ڦ\x02ڄ\x02ڃ\x02چ\x02ڇ\x02ڍ\x02ڌ\x02ڎ\x02ڈ\x02ژ\x02ڑ\x02ک\x02گ\x02ڳ" + "\x02ڱ\x02ں\x02ڻ\x02ۀ\x02ہ\x02ھ\x02ے\x02ۓ\x02ڭ\x02ۇ\x02ۆ\x02ۈ\x02ۋ\x02ۅ" + "\x02ۉ\x02ې\x02ى\x04ئا\x04ئە\x04ئو\x04ئۇ\x04ئۆ\x04ئۈ\x04ئې\x04ئى\x02ی\x04" + "ئج\x04ئح\x04ئم\x04ئي\x04بج\x04بح\x04بخ\x04بم\x04بى\x04بي\x04تج\x04تح" + "\x04تخ\x04تم\x04تى\x04تي\x04ثج\x04ثم\x04ثى\x04ثي\x04جح\x04جم\x04حج\x04حم" + "\x04خج\x04خح\x04خم\x04سج\x04سح\x04سخ\x04سم\x04صح\x04صم\x04ضج\x04ضح\x04ضخ" + "\x04ضم\x04طح\x04طم\x04ظم\x04عج\x04عم\x04غج\x04غم\x04فج\x04فح\x04فخ\x04فم" + "\x04فى\x04في\x04قح\x04قم\x04قى\x04قي\x04كا\x04كج\x04كح\x04كخ\x04كل\x04كم" + "\x04كى\x04كي\x04لج\x04لح\x04لخ\x04لم\x04لى\x04لي\x04مج\x04مح\x04مخ\x04مم" + "\x04مى\x04مي\x04نج\x04نح\x04نخ\x04نم\x04نى\x04ني\x04هج\x04هم\x04هى\x04هي" + "\x04يج\x04يح\x04يخ\x04يم\x04يى\x04يي\x04ذٰ\x04رٰ\x04ىٰ\x05 ٌّ\x05 ٍّ\x05" + " َّ\x05 ُّ\x05 ِّ\x05 ّٰ\x04ئر\x04ئز\x04ئن\x04بر\x04بز\x04بن\x04تر\x04تز" + "\x04تن\x04ثر\x04ثز\x04ثن\x04ما\x04نر\x04نز\x04نن\x04ير\x04يز\x04ين\x04ئخ" + "\x04ئه\x04به\x04ته\x04صخ\x04له\x04نه\x04هٰ\x04يه\x04ثه\x04سه\x04شم\x04شه" + "\x06ـَّ\x06ـُّ\x06ـِّ\x04طى\x04طي\x04عى\x04عي\x04غى\x04غي\x04سى\x04سي" + "\x04شى\x04شي\x04حى\x04حي\x04جى\x04جي\x04خى\x04خي\x04صى\x04صي\x04ضى\x04ضي" + "\x04شج\x04شح\x04شخ\x04شر\x04سر\x04صر\x04ضر\x04اً\x06تجم\x06تحج\x06تحم" + "\x06تخم\x06تمج\x06تمح\x06تمخ\x06جمح\x06حمي\x06حمى\x06سحج\x06سجح\x06سجى" + "\x06سمح\x06سمج\x06سمم\x06صحح\x06صمم\x06شحم\x06شجي\x06شمخ\x06شمم\x06ضحى" + "\x06ضخم\x06طمح\x06طمم\x06طمي\x06عجم\x06عمم\x06عمى\x06غمم\x06غمي\x06غمى" + "\x06فخم\x06قمح\x06قمم\x06لحم\x06لحي\x06لحى\x06لجج\x06لخم\x06لمح\x06محج" + "\x06محم\x06محي\x06مجح\x06مجم\x06مخج\x06مخم\x06مجخ\x06همج\x06همم\x06نحم" + "\x06نحى\x06نجم\x06نجى\x06نمي\x06نمى\x06يمم\x06بخي\x06تجي\x06تجى\x06تخي" + "\x06تخى\x06تمي\x06تمى\x06جمي\x06جحى\x06جمى\x06سخى\x06صحي\x06شحي\x06ضحي" + "\x06لجي\x06لمي\x06يحي\x06يجي\x06يمي\x06ممي\x06قمي\x06نحي\x06عمي\x06كمي" + "\x06نجح\x06مخي\x06لجم\x06كمم\x06جحي\x06حجي\x06مجي\x06فمي\x06بحي\x06سخي" + "\x06نجي\x06صلے\x06قلے\x08الله\x08اكبر\x08محمد\x08صلعم\x08رسول\x08عليه" + "\x08وسلم\x06صلى!صلى الله عليه وسلم\x0fجل جلاله\x08ریال\x01,\x01:\x01!" + "\x01?\x01_\x01{\x01}\x01[\x01]\x01#\x01&\x01*\x01-\x01<\x01>\x01\\\x01$" + "\x01%\x01@\x04ـً\x04ـَ\x04ـُ\x04ـِ\x04ـّ\x04ـْ\x02ء\x02آ\x02أ\x02ؤ\x02إ" + "\x02ئ\x02ا\x02ب\x02ة\x02ت\x02ث\x02ج\x02ح\x02خ\x02د\x02ذ\x02ر\x02ز\x02س" + "\x02ش\x02ص\x02ض\x02ط\x02ظ\x02ع\x02غ\x02ف\x02ق\x02ك\x02ل\x02م\x02ن\x02ه" + "\x02و\x02ي\x04لآ\x04لأ\x04لإ\x04لا\x01\x22\x01'\x01/\x01^\x01|\x01~\x02¢" + "\x02£\x02¬\x02¦\x02¥\x08𝅗𝅥\x08𝅘𝅥\x0c𝅘𝅥𝅮\x0c𝅘𝅥𝅯\x0c𝅘𝅥𝅰\x0c𝅘𝅥𝅱\x0c𝅘𝅥𝅲\x08𝆹" + "𝅥\x08𝆺𝅥\x0c𝆹𝅥𝅮\x0c𝆺𝅥𝅮\x0c𝆹𝅥𝅯\x0c𝆺𝅥𝅯\x02ı\x02ȷ\x02α\x02ε\x02ζ\x02η\x02" + "κ\x02λ\x02μ\x02ν\x02ξ\x02ο\x02σ\x02τ\x02υ\x02ψ\x03∇\x03∂\x02ϝ\x02ٮ\x02ڡ" + "\x02ٯ\x020,\x021,\x022,\x023,\x024,\x025,\x026,\x027,\x028,\x029,\x03(a)" + "\x03(b)\x03(c)\x03(d)\x03(e)\x03(f)\x03(g)\x03(h)\x03(i)\x03(j)\x03(k)" + "\x03(l)\x03(m)\x03(n)\x03(o)\x03(p)\x03(q)\x03(r)\x03(s)\x03(t)\x03(u)" + "\x03(v)\x03(w)\x03(x)\x03(y)\x03(z)\x07〔s〕\x02wz\x02hv\x02sd\x03ppv\x02w" + "c\x02mc\x02md\x02dj\x06ほか\x06ココ\x03サ\x03手\x03字\x03双\x03デ\x03二\x03多\x03解" + "\x03天\x03交\x03映\x03無\x03料\x03前\x03後\x03再\x03新\x03初\x03終\x03生\x03販\x03声" + "\x03吹\x03演\x03投\x03捕\x03一\x03三\x03遊\x03左\x03中\x03右\x03指\x03走\x03打\x03禁" + "\x03空\x03合\x03満\x03有\x03月\x03申\x03割\x03営\x03配\x09〔本〕\x09〔三〕\x09〔二〕\x09〔安" + "〕\x09〔点〕\x09〔打〕\x09〔盗〕\x09〔勝〕\x09〔敗〕\x03得\x03可\x03丽\x03丸\x03乁\x03你\x03" + "侮\x03侻\x03倂\x03偺\x03備\x03僧\x03像\x03㒞\x03免\x03兔\x03兤\x03具\x03㒹\x03內\x03" + "冗\x03冤\x03仌\x03冬\x03况\x03凵\x03刃\x03㓟\x03刻\x03剆\x03剷\x03㔕\x03勇\x03勉\x03" + "勤\x03勺\x03包\x03匆\x03北\x03卉\x03卑\x03博\x03即\x03卽\x03卿\x03灰\x03及\x03叟\x03" + "叫\x03叱\x03吆\x03咞\x03吸\x03呈\x03周\x03咢\x03哶\x03唐\x03啓\x03啣\x03善\x03喙\x03" + "喫\x03喳\x03嗂\x03圖\x03嘆\x03圗\x03噑\x03噴\x03切\x03壮\x03城\x03埴\x03堍\x03型\x03" + "堲\x03報\x03墬\x03売\x03壷\x03夆\x03夢\x03奢\x03姬\x03娛\x03娧\x03姘\x03婦\x03㛮\x03" + "嬈\x03嬾\x03寃\x03寘\x03寧\x03寳\x03寿\x03将\x03尢\x03㞁\x03屠\x03屮\x03峀\x03岍\x03" + "嵃\x03嵮\x03嵫\x03嵼\x03巡\x03巢\x03㠯\x03巽\x03帨\x03帽\x03幩\x03㡢\x03㡼\x03庰\x03" + "庳\x03庶\x03廊\x03廾\x03舁\x03弢\x03㣇\x03形\x03彫\x03㣣\x03徚\x03忍\x03志\x03忹\x03" + "悁\x03㤺\x03㤜\x03悔\x03惇\x03慈\x03慌\x03慎\x03慺\x03憎\x03憲\x03憤\x03憯\x03懞\x03" + "懲\x03懶\x03成\x03戛\x03扝\x03抱\x03拔\x03捐\x03挽\x03拼\x03捨\x03掃\x03揤\x03搢\x03" + "揅\x03掩\x03㨮\x03摩\x03摾\x03撝\x03摷\x03㩬\x03敏\x03敬\x03旣\x03書\x03晉\x03㬙\x03" + "暑\x03㬈\x03㫤\x03冒\x03冕\x03最\x03暜\x03肭\x03䏙\x03朗\x03望\x03朡\x03杞\x03杓\x03" + "㭉\x03柺\x03枅\x03桒\x03梅\x03梎\x03栟\x03椔\x03㮝\x03楂\x03榣\x03槪\x03檨\x03櫛\x03" + "㰘\x03次\x03歔\x03㱎\x03歲\x03殟\x03殺\x03殻\x03汎\x03沿\x03泍\x03汧\x03洖\x03派\x03" + "海\x03流\x03浩\x03浸\x03涅\x03洴\x03港\x03湮\x03㴳\x03滋\x03滇\x03淹\x03潮\x03濆\x03" + "瀹\x03瀞\x03瀛\x03㶖\x03灊\x03災\x03灷\x03炭\x03煅\x03熜\x03爨\x03爵\x03牐\x03犀\x03" + "犕\x03獺\x03王\x03㺬\x03玥\x03㺸\x03瑇\x03瑜\x03瑱\x03璅\x03瓊\x03㼛\x03甤\x03甾\x03" + "異\x03瘐\x03㿼\x03䀈\x03直\x03眞\x03真\x03睊\x03䀹\x03瞋\x03䁆\x03䂖\x03硎\x03碌\x03" + "磌\x03䃣\x03祖\x03福\x03秫\x03䄯\x03穀\x03穊\x03穏\x03䈂\x03篆\x03築\x03䈧\x03糒\x03" + "䊠\x03糨\x03糣\x03紀\x03絣\x03䌁\x03緇\x03縂\x03繅\x03䌴\x03䍙\x03罺\x03羕\x03翺\x03" + "者\x03聠\x03聰\x03䏕\x03育\x03脃\x03䐋\x03脾\x03媵\x03舄\x03辞\x03䑫\x03芑\x03芋\x03" + "芝\x03劳\x03花\x03芳\x03芽\x03苦\x03若\x03茝\x03荣\x03莭\x03茣\x03莽\x03菧\x03著\x03" + "荓\x03菊\x03菌\x03菜\x03䔫\x03蓱\x03蓳\x03蔖\x03蕤\x03䕝\x03䕡\x03䕫\x03虐\x03虜\x03" + "虧\x03虩\x03蚩\x03蚈\x03蜎\x03蛢\x03蝹\x03蜨\x03蝫\x03螆\x03蟡\x03蠁\x03䗹\x03衠\x03" + "衣\x03裗\x03裞\x03䘵\x03裺\x03㒻\x03䚾\x03䛇\x03誠\x03諭\x03變\x03豕\x03貫\x03賁\x03" + "贛\x03起\x03跋\x03趼\x03跰\x03軔\x03輸\x03邔\x03郱\x03鄑\x03鄛\x03鈸\x03鋗\x03鋘\x03" + "鉼\x03鏹\x03鐕\x03開\x03䦕\x03閷\x03䧦\x03雃\x03嶲\x03霣\x03䩮\x03䩶\x03韠\x03䪲\x03" + "頋\x03頩\x03飢\x03䬳\x03餩\x03馧\x03駂\x03駾\x03䯎\x03鬒\x03鱀\x03鳽\x03䳎\x03䳭\x03" + "鵧\x03䳸\x03麻\x03䵖\x03黹\x03黾\x03鼅\x03鼏\x03鼖\x03鼻" var xorData string = "" + // Size: 4855 bytes "\x02\x0c\x09\x02\xb0\xec\x02\xad\xd8\x02\xad\xd9\x02\x06\x07\x02\x0f\x12" + "\x02\x0f\x1f\x02\x0f\x1d\x02\x01\x13\x02\x0f\x16\x02\x0f\x0b\x02\x0f3" + "\x02\x0f7\x02\x0f?\x02\x0f/\x02\x0f*\x02\x0c&\x02\x0c*\x02\x0c;\x02\x0c9" + "\x02\x0c%\x02\xab\xed\x02\xab\xe2\x02\xab\xe3\x02\xa9\xe0\x02\xa9\xe1" + "\x02\xa9\xe6\x02\xa3\xcb\x02\xa3\xc8\x02\xa3\xc9\x02\x01#\x02\x01\x08" + "\x02\x0e>\x02\x0e'\x02\x0f\x03\x02\x03\x0d\x02\x03\x09\x02\x03\x17\x02" + "\x03\x0e\x02\x02\x03\x02\x011\x02\x01\x00\x02\x01\x10\x02\x03<\x02\x07" + "\x0d\x02\x02\x0c\x02\x0c0\x02\x01\x03\x02\x01\x01\x02\x01 \x02\x01\x22" + "\x02\x01)\x02\x01\x0a\x02\x01\x0c\x02\x02\x06\x02\x02\x02\x02\x03\x10" + "\x03\x037 \x03\x0b+\x03\x02\x01\x04\x02\x01\x02\x02\x019\x02\x03\x1c\x02" + "\x02$\x03\x80p$\x02\x03:\x02\x03\x0a\x03\xc1r.\x03\xc1r,\x03\xc1r\x02" + "\x02\x02:\x02\x02>\x02\x02,\x02\x02\x10\x02\x02\x00\x03\xc1s<\x03\xc1s*" + "\x03\xc2L$\x03\xc2L;\x02\x09)\x02\x0a\x19\x03\x83\xab\xe3\x03\x83\xab" + "\xf2\x03 4\xe0\x03\x81\xab\xea\x03\x81\xab\xf3\x03 4\xef\x03\x96\xe1\xcd" + "\x03\x84\xe5\xc3\x02\x0d\x11\x03\x8b\xec\xcb\x03\x94\xec\xcf\x03\x9a\xec" + "\xc2\x03\x8b\xec\xdb\x03\x94\xec\xdf\x03\x9a\xec\xd2\x03\x01\x0c!\x03" + "\x01\x0c#\x03ʠ\x9d\x03ʣ\x9c\x03ʢ\x9f\x03ʥ\x9e\x03ʤ\x91\x03ʧ\x90\x03ʦ\x93" + "\x03ʩ\x92\x03ʨ\x95\x03\xca\xf3\xb5\x03\xca\xf0\xb4\x03\xca\xf1\xb7\x03" + "\xca\xf6\xb6\x03\xca\xf7\x89\x03\xca\xf4\x88\x03\xca\xf5\x8b\x03\xca\xfa" + "\x8a\x03\xca\xfb\x8d\x03\xca\xf8\x8c\x03\xca\xf9\x8f\x03\xca\xfe\x8e\x03" + "\xca\xff\x81\x03\xca\xfc\x80\x03\xca\xfd\x83\x03\xca\xe2\x82\x03\xca\xe3" + "\x85\x03\xca\xe0\x84\x03\xca\xe1\x87\x03\xca\xe6\x86\x03\xca\xe7\x99\x03" + "\xca\xe4\x98\x03\xca\xe5\x9b\x03\xca\xea\x9a\x03\xca\xeb\x9d\x03\xca\xe8" + "\x9c\x03ؓ\x89\x03ߔ\x8b\x02\x010\x03\x03\x04\x1e\x03\x04\x15\x12\x03\x0b" + "\x05,\x03\x06\x04\x00\x03\x06\x04)\x03\x06\x044\x03\x06\x04<\x03\x06\x05" + "\x1d\x03\x06\x06\x00\x03\x06\x06\x0a\x03\x06\x06'\x03\x06\x062\x03\x0786" + "\x03\x079/\x03\x079 \x03\x07:\x0e\x03\x07:\x1b\x03\x07:%\x03\x07;/\x03" + "\x07;%\x03\x074\x11\x03\x076\x09\x03\x077*\x03\x070\x01\x03\x070\x0f\x03" + "\x070.\x03\x071\x16\x03\x071\x04\x03\x0710\x03\x072\x18\x03\x072-\x03" + "\x073\x14\x03\x073>\x03\x07'\x09\x03\x07 \x00\x03\x07\x1f\x0b\x03\x07" + "\x18#\x03\x07\x18(\x03\x07\x186\x03\x07\x18\x03\x03\x07\x19\x16\x03\x07" + "\x116\x03\x07\x12'\x03\x07\x13\x10\x03\x07\x0c&\x03\x07\x0c\x08\x03\x07" + "\x0c\x13\x03\x07\x0d\x02\x03\x07\x0d\x1c\x03\x07\x0b5\x03\x07\x0b\x0a" + "\x03\x07\x0b\x01\x03\x07\x0b\x0f\x03\x07\x05\x00\x03\x07\x05\x09\x03\x07" + "\x05\x0b\x03\x07\x07\x01\x03\x07\x07\x08\x03\x07\x00<\x03\x07\x00+\x03" + "\x07\x01)\x03\x07\x01\x1b\x03\x07\x01\x08\x03\x07\x03?\x03\x0445\x03\x04" + "4\x08\x03\x0454\x03\x04)/\x03\x04)5\x03\x04+\x05\x03\x04+\x14\x03\x04+ " + "\x03\x04+<\x03\x04*&\x03\x04*\x22\x03\x04&8\x03\x04!\x01\x03\x04!\x22" + "\x03\x04\x11+\x03\x04\x10.\x03\x04\x104\x03\x04\x13=\x03\x04\x12\x04\x03" + "\x04\x12\x0a\x03\x04\x0d\x1d\x03\x04\x0d\x07\x03\x04\x0d \x03\x05<>\x03" + "\x055<\x03\x055!\x03\x055#\x03\x055&\x03\x054\x1d\x03\x054\x02\x03\x054" + "\x07\x03\x0571\x03\x053\x1a\x03\x053\x16\x03\x05.<\x03\x05.\x07\x03\x05)" + ":\x03\x05)<\x03\x05)\x0c\x03\x05)\x15\x03\x05+-\x03\x05+5\x03\x05$\x1e" + "\x03\x05$\x14\x03\x05'\x04\x03\x05'\x14\x03\x05&\x02\x03\x05\x226\x03" + "\x05\x22\x0c\x03\x05\x22\x1c\x03\x05\x19\x0a\x03\x05\x1b\x09\x03\x05\x1b" + "\x0c\x03\x05\x14\x07\x03\x05\x16?\x03\x05\x16\x0c\x03\x05\x0c\x05\x03" + "\x05\x0e\x0f\x03\x05\x01\x0e\x03\x05\x00(\x03\x05\x030\x03\x05\x03\x06" + "\x03\x0a==\x03\x0a=1\x03\x0a=,\x03\x0a=\x0c\x03\x0a??\x03\x0a<\x08\x03" + "\x0a9!\x03\x0a9)\x03\x0a97\x03\x0a99\x03\x0a6\x0a\x03\x0a6\x1c\x03\x0a6" + "\x17\x03\x0a7'\x03\x0a78\x03\x0a73\x03\x0a'\x01\x03\x0a'&\x03\x0a\x1f" + "\x0e\x03\x0a\x1f\x03\x03\x0a\x1f3\x03\x0a\x1b/\x03\x0a\x18\x19\x03\x0a" + "\x19\x01\x03\x0a\x16\x14\x03\x0a\x0e\x22\x03\x0a\x0f\x10\x03\x0a\x0f\x02" + "\x03\x0a\x0f \x03\x0a\x0c\x04\x03\x0a\x0b>\x03\x0a\x0b+\x03\x0a\x08/\x03" + "\x0a\x046\x03\x0a\x05\x14\x03\x0a\x00\x04\x03\x0a\x00\x10\x03\x0a\x00" + "\x14\x03\x0b<3\x03\x0b;*\x03\x0b9\x22\x03\x0b9)\x03\x0b97\x03\x0b+\x10" + "\x03\x0b((\x03\x0b&5\x03\x0b$\x1c\x03\x0b$\x12\x03\x0b%\x04\x03\x0b#<" + "\x03\x0b#0\x03\x0b#\x0d\x03\x0b#\x19\x03\x0b!:\x03\x0b!\x1f\x03\x0b!\x00" + "\x03\x0b\x1e5\x03\x0b\x1c\x1d\x03\x0b\x1d-\x03\x0b\x1d(\x03\x0b\x18.\x03" + "\x0b\x18 \x03\x0b\x18\x16\x03\x0b\x14\x13\x03\x0b\x15$\x03\x0b\x15\x22" + "\x03\x0b\x12\x1b\x03\x0b\x12\x10\x03\x0b\x132\x03\x0b\x13=\x03\x0b\x12" + "\x18\x03\x0b\x0c&\x03\x0b\x061\x03\x0b\x06:\x03\x0b\x05#\x03\x0b\x05<" + "\x03\x0b\x04\x0b\x03\x0b\x04\x04\x03\x0b\x04\x1b\x03\x0b\x042\x03\x0b" + "\x041\x03\x0b\x03\x03\x03\x0b\x03\x1d\x03\x0b\x03/\x03\x0b\x03+\x03\x0b" + "\x02\x1b\x03\x0b\x02\x00\x03\x0b\x01\x1e\x03\x0b\x01\x08\x03\x0b\x015" + "\x03\x06\x0d9\x03\x06\x0d=\x03\x06\x0d?\x03\x02\x001\x03\x02\x003\x03" + "\x02\x02\x19\x03\x02\x006\x03\x02\x02\x1b\x03\x02\x004\x03\x02\x00<\x03" + "\x02\x02\x0a\x03\x02\x02\x0e\x03\x02\x01\x1a\x03\x02\x01\x07\x03\x02\x01" + "\x05\x03\x02\x01\x0b\x03\x02\x01%\x03\x02\x01\x0c\x03\x02\x01\x04\x03" + "\x02\x01\x1c\x03\x02\x00.\x03\x02\x002\x03\x02\x00>\x03\x02\x00\x12\x03" + "\x02\x00\x16\x03\x02\x011\x03\x02\x013\x03\x02\x02 \x03\x02\x02%\x03\x02" + "\x02$\x03\x02\x028\x03\x02\x02;\x03\x02\x024\x03\x02\x012\x03\x02\x022" + "\x03\x02\x02/\x03\x02\x01,\x03\x02\x01\x13\x03\x02\x01\x16\x03\x02\x01" + "\x11\x03\x02\x01\x1e\x03\x02\x01\x15\x03\x02\x01\x17\x03\x02\x01\x0f\x03" + "\x02\x01\x08\x03\x02\x00?\x03\x02\x03\x07\x03\x02\x03\x0d\x03\x02\x03" + "\x13\x03\x02\x03\x1d\x03\x02\x03\x1f\x03\x02\x00\x03\x03\x02\x00\x0d\x03" + "\x02\x00\x01\x03\x02\x00\x1b\x03\x02\x00\x19\x03\x02\x00\x18\x03\x02\x00" + "\x13\x03\x02\x00/\x03\x07>\x12\x03\x07<\x1f\x03\x07>\x1d\x03\x06\x1d\x0e" + "\x03\x07>\x1c\x03\x07>:\x03\x07>\x13\x03\x04\x12+\x03\x07?\x03\x03\x07>" + "\x02\x03\x06\x224\x03\x06\x1a.\x03\x07<%\x03\x06\x1c\x0b\x03\x0609\x03" + "\x05\x1f\x01\x03\x04'\x08\x03\x93\xfd\xf5\x03\x02\x0d \x03\x02\x0d#\x03" + "\x02\x0d!\x03\x02\x0d&\x03\x02\x0d\x22\x03\x02\x0d/\x03\x02\x0d,\x03\x02" + "\x0d$\x03\x02\x0d'\x03\x02\x0d%\x03\x02\x0d;\x03\x02\x0d=\x03\x02\x0d?" + "\x03\x099.\x03\x08\x0b7\x03\x08\x02\x14\x03\x08\x14\x0d\x03\x08.:\x03" + "\x089'\x03\x0f\x0b\x18\x03\x0f\x1c1\x03\x0f\x17&\x03\x0f9\x1f\x03\x0f0" + "\x0c\x03\x0e\x0a9\x03\x0e\x056\x03\x0e\x1c#\x03\x0f\x13\x0e\x03\x072\x00" + "\x03\x070\x0d\x03\x072\x0b\x03\x06\x11\x18\x03\x070\x10\x03\x06\x0f(\x03" + "\x072\x05\x03\x06\x0f,\x03\x073\x15\x03\x06\x07\x08\x03\x05\x16\x02\x03" + "\x04\x0b \x03\x05:8\x03\x05\x16%\x03\x0a\x0d\x1f\x03\x06\x16\x10\x03\x05" + "\x1d5\x03\x05*;\x03\x05\x16\x1b\x03\x04.-\x03\x06\x1a\x19\x03\x04\x03," + "\x03\x0b87\x03\x04/\x0a\x03\x06\x00,\x03\x04-\x01\x03\x04\x1e-\x03\x06/(" + "\x03\x0a\x0b5\x03\x06\x0e7\x03\x06\x07.\x03\x0597\x03\x0a*%\x03\x0760" + "\x03\x06\x0c;\x03\x05'\x00\x03\x072.\x03\x072\x08\x03\x06=\x01\x03\x06" + "\x05\x1b\x03\x06\x06\x12\x03\x06$=\x03\x06'\x0d\x03\x04\x11\x0f\x03\x076" + ",\x03\x06\x07;\x03\x06.,\x03\x86\xf9\xea\x03\x8f\xff\xeb\x02\x092\x02" + "\x095\x02\x094\x02\x09;\x02\x09>\x02\x098\x02\x09*\x02\x09/\x02\x09,\x02" + "\x09%\x02\x09&\x02\x09#\x02\x09 \x02\x08!\x02\x08%\x02\x08$\x02\x08+\x02" + "\x08.\x02\x08*\x02\x08&\x02\x088\x02\x08>\x02\x084\x02\x086\x02\x080\x02" + "\x08\x10\x02\x08\x17\x02\x08\x12\x02\x08\x1d\x02\x08\x1f\x02\x08\x13\x02" + "\x08\x15\x02\x08\x14\x02\x08\x0c\x03\x8b\xfd\xd0\x03\x81\xec\xc6\x03\x87" + "\xe0\x8a\x03-2\xe3\x03\x80\xef\xe4\x03-2\xea\x03\x88\xe6\xeb\x03\x8e\xe6" + "\xe8\x03\x84\xe6\xe9\x03\x97\xe6\xee\x03-2\xf9\x03-2\xf6\x03\x8e\xe3\xad" + "\x03\x80\xe3\x92\x03\x88\xe3\x90\x03\x8e\xe3\x90\x03\x80\xe3\x97\x03\x88" + "\xe3\x95\x03\x88\xfe\xcb\x03\x8e\xfe\xca\x03\x84\xfe\xcd\x03\x91\xef\xc9" + "\x03-2\xc1\x03-2\xc0\x03-2\xcb\x03\x88@\x09\x03\x8e@\x08\x03\x8f\xe0\xf5" + "\x03\x8e\xe6\xf9\x03\x8e\xe0\xfa\x03\x93\xff\xf4\x03\x84\xee\xd3\x03\x0b" + "(\x04\x023 \x021;\x02\x01*\x03\x0b#\x10\x03\x0b 0\x03\x0b!\x10\x03\x0b!0" + "\x03\x07\x15\x08\x03\x09?5\x03\x07\x1f\x08\x03\x07\x17\x0b\x03\x09\x1f" + "\x15\x03\x0b\x1c7\x03\x0a+#\x03\x06\x1a\x1b\x03\x06\x1a\x14\x03\x0a\x01" + "\x18\x03\x06#\x1b\x03\x0a2\x0c\x03\x0a\x01\x04\x03\x09#;\x03\x08='\x03" + "\x08\x1a\x0a\x03\x07\x03\x0a\x111\x03\x09\x1b\x09\x03\x073.\x03\x07\x01\x00" + "\x03\x09/,\x03\x07#>\x03\x07\x048\x03\x0a\x1f\x22\x03\x098>\x03\x09\x11" + "\x00\x03\x08/\x17\x03\x06'\x22\x03\x0b\x1a+\x03\x0a\x22\x19\x03\x0a/1" + "\x03\x0974\x03\x09\x0f\x22\x03\x08,\x22\x03\x08?\x14\x03\x07$5\x03\x07<3" + "\x03\x07=*\x03\x07\x13\x18\x03\x068\x0a\x03\x06\x09\x16\x03\x06\x13\x00" + "\x03\x08\x067\x03\x08\x01\x03\x03\x08\x12\x1d\x03\x07+7\x03\x06(;\x03" + "\x06\x1c?\x03\x07\x0e\x17\x03\x0a\x06\x1d\x03\x0a\x19\x07\x03\x08\x14$" + "\x03\x07$;\x03\x08,$\x03\x08\x06\x0d\x03\x07\x16\x0a\x03\x06>>\x03\x0a" + "\x06\x12\x03\x0a\x14)\x03\x09\x0d\x1f\x03\x09\x12\x17\x03\x09\x19\x01" + "\x03\x08\x11 \x03\x08\x1d'\x03\x06<\x1a\x03\x0a.\x00\x03\x07'\x18\x03" + "\x0a\x22\x08\x03\x08\x0d\x0a\x03\x08\x13)\x03\x07*)\x03\x06<,\x03\x07" + "\x0b\x1a\x03\x09.\x14\x03\x09\x0d\x1e\x03\x07\x0e#\x03\x0b\x1d'\x03\x0a" + "\x0a8\x03\x09%2\x03\x08+&\x03\x080\x12\x03\x0a)4\x03\x08\x06\x1f\x03\x0b" + "\x1b\x1a\x03\x0a\x1b\x0f\x03\x0b\x1d*\x03\x09\x16$\x03\x090\x11\x03\x08" + "\x11\x08\x03\x0a*(\x03\x0a\x042\x03\x089,\x03\x074'\x03\x07\x0f\x05\x03" + "\x09\x0b\x0a\x03\x07\x1b\x01\x03\x09\x17:\x03\x09.\x0d\x03\x07.\x11\x03" + "\x09+\x15\x03\x080\x13\x03\x0b\x1f\x19\x03\x0a \x11\x03\x0a\x220\x03\x09" + "\x07;\x03\x08\x16\x1c\x03\x07,\x13\x03\x07\x0e/\x03\x06\x221\x03\x0a." + "\x0a\x03\x0a7\x02\x03\x0a\x032\x03\x0a\x1d.\x03\x091\x06\x03\x09\x19:" + "\x03\x08\x02/\x03\x060+\x03\x06\x0f-\x03\x06\x1c\x1f\x03\x06\x1d\x07\x03" + "\x0a,\x11\x03\x09=\x0d\x03\x09\x0b;\x03\x07\x1b/\x03\x0a\x1f:\x03\x09 " + "\x1f\x03\x09.\x10\x03\x094\x0b\x03\x09\x1a1\x03\x08#\x1a\x03\x084\x1d" + "\x03\x08\x01\x1f\x03\x08\x11\x22\x03\x07'8\x03\x07\x1a>\x03\x0757\x03" + "\x06&9\x03\x06+\x11\x03\x0a.\x0b\x03\x0a,>\x03\x0a4#\x03\x08%\x17\x03" + "\x07\x05\x22\x03\x07\x0c\x0b\x03\x0a\x1d+\x03\x0a\x19\x16\x03\x09+\x1f" + "\x03\x09\x08\x0b\x03\x08\x16\x18\x03\x08+\x12\x03\x0b\x1d\x0c\x03\x0a=" + "\x10\x03\x0a\x09\x0d\x03\x0a\x10\x11\x03\x09&0\x03\x08(\x1f\x03\x087\x07" + "\x03\x08\x185\x03\x07'6\x03\x06.\x05\x03\x06=\x04\x03\x06;;\x03\x06\x06," + "\x03\x0b\x18>\x03\x08\x00\x18\x03\x06 \x03\x03\x06<\x00\x03\x09%\x18\x03" + "\x0b\x1c<\x03\x0a%!\x03\x0a\x09\x12\x03\x0a\x16\x02\x03\x090'\x03\x09" + "\x0e=\x03\x08 \x0e\x03\x08>\x03\x03\x074>\x03\x06&?\x03\x06\x19\x09\x03" + "\x06?(\x03\x0a-\x0e\x03\x09:3\x03\x098:\x03\x09\x12\x0b\x03\x09\x1d\x17" + "\x03\x087\x05\x03\x082\x14\x03\x08\x06%\x03\x08\x13\x1f\x03\x06\x06\x0e" + "\x03\x0a\x22<\x03\x09/<\x03\x06>+\x03\x0a'?\x03\x0a\x13\x0c\x03\x09\x10<" + "\x03\x07\x1b=\x03\x0a\x19\x13\x03\x09\x22\x1d\x03\x09\x07\x0d\x03\x08)" + "\x1c\x03\x06=\x1a\x03\x0a/4\x03\x0a7\x11\x03\x0a\x16:\x03\x09?3\x03\x09:" + "/\x03\x09\x05\x0a\x03\x09\x14\x06\x03\x087\x22\x03\x080\x07\x03\x08\x1a" + "\x1f\x03\x07\x04(\x03\x07\x04\x09\x03\x06 %\x03\x06<\x08\x03\x0a+\x14" + "\x03\x09\x1d\x16\x03\x0a70\x03\x08 >\x03\x0857\x03\x070\x0a\x03\x06=\x12" + "\x03\x06\x16%\x03\x06\x1d,\x03\x099#\x03\x09\x10>\x03\x07 \x1e\x03\x08" + "\x0c<\x03\x08\x0b\x18\x03\x08\x15+\x03\x08,:\x03\x08%\x22\x03\x07\x0a$" + "\x03\x0b\x1c=\x03\x07+\x08\x03\x0a/\x05\x03\x0a \x07\x03\x0a\x12'\x03" + "\x09#\x11\x03\x08\x1b\x15\x03\x0a\x06\x01\x03\x09\x1c\x1b\x03\x0922\x03" + "\x07\x14<\x03\x07\x09\x04\x03\x061\x04\x03\x07\x0e\x01\x03\x0a\x13\x18" + "\x03\x0a-\x0c\x03\x0a?\x0d\x03\x0a\x09\x0a\x03\x091&\x03\x0a/\x0b\x03" + "\x08$<\x03\x083\x1d\x03\x08\x0c$\x03\x08\x0d\x07\x03\x08\x0d?\x03\x08" + "\x0e\x14\x03\x065\x0a\x03\x08\x1a#\x03\x08\x16#\x03\x0702\x03\x07\x03" + "\x1a\x03\x06(\x1d\x03\x06+\x1b\x03\x06\x0b\x05\x03\x06\x0b\x17\x03\x06" + "\x0c\x04\x03\x06\x1e\x19\x03\x06+0\x03\x062\x18\x03\x0b\x16\x1e\x03\x0a+" + "\x16\x03\x0a-?\x03\x0a#:\x03\x0a#\x10\x03\x0a%$\x03\x0a>+\x03\x0a01\x03" + "\x0a1\x10\x03\x0a\x099\x03\x0a\x0a\x12\x03\x0a\x19\x1f\x03\x0a\x19\x12" + "\x03\x09*)\x03\x09-\x16\x03\x09.1\x03\x09.2\x03\x09<\x0e\x03\x09> \x03" + "\x093\x12\x03\x09\x0b\x01\x03\x09\x1c2\x03\x09\x11\x1c\x03\x09\x15%\x03" + "\x08,&\x03\x08!\x22\x03\x089(\x03\x08\x0b\x1a\x03\x08\x0d2\x03\x08\x0c" + "\x04\x03\x08\x0c\x06\x03\x08\x0c\x1f\x03\x08\x0c\x0c\x03\x08\x0f\x1f\x03" + "\x08\x0f\x1d\x03\x08\x00\x14\x03\x08\x03\x14\x03\x08\x06\x16\x03\x08\x1e" + "#\x03\x08\x11\x11\x03\x08\x10\x18\x03\x08\x14(\x03\x07)\x1e\x03\x07.1" + "\x03\x07 $\x03\x07 '\x03\x078\x08\x03\x07\x0d0\x03\x07\x0f7\x03\x07\x05#" + "\x03\x07\x05\x1a\x03\x07\x1a7\x03\x07\x1d-\x03\x07\x17\x10\x03\x06)\x1f" + "\x03\x062\x0b\x03\x066\x16\x03\x06\x09\x11\x03\x09(\x1e\x03\x07!5\x03" + "\x0b\x11\x16\x03\x0a/\x04\x03\x0a,\x1a\x03\x0b\x173\x03\x0a,1\x03\x0a/5" + "\x03\x0a\x221\x03\x0a\x22\x0d\x03\x0a?%\x03\x0a<,\x03\x0a?#\x03\x0a>\x19" + "\x03\x0a\x08&\x03\x0a\x0b\x0e\x03\x0a\x0c:\x03\x0a\x0c+\x03\x0a\x03\x22" + "\x03\x0a\x06)\x03\x0a\x11\x10\x03\x0a\x11\x1a\x03\x0a\x17-\x03\x0a\x14(" + "\x03\x09)\x1e\x03\x09/\x09\x03\x09.\x00\x03\x09,\x07\x03\x09/*\x03\x09-9" + "\x03\x09\x228\x03\x09%\x09\x03\x09:\x12\x03\x09;\x1d\x03\x09?\x06\x03" + "\x093%\x03\x096\x05\x03\x096\x08\x03\x097\x02\x03\x09\x07,\x03\x09\x04," + "\x03\x09\x1f\x16\x03\x09\x11\x03\x03\x09\x11\x12\x03\x09\x168\x03\x08*" + "\x05\x03\x08/2\x03\x084:\x03\x08\x22+\x03\x08 0\x03\x08&\x0a\x03\x08;" + "\x10\x03\x08>$\x03\x08>\x18\x03\x0829\x03\x082:\x03\x081,\x03\x081<\x03" + "\x081\x1c\x03\x087#\x03\x087*\x03\x08\x09'\x03\x08\x00\x1d\x03\x08\x05-" + "\x03\x08\x1f4\x03\x08\x1d\x04\x03\x08\x16\x0f\x03\x07*7\x03\x07'!\x03" + "\x07%\x1b\x03\x077\x0c\x03\x07\x0c1\x03\x07\x0c.\x03\x07\x00\x06\x03\x07" + "\x01\x02\x03\x07\x010\x03\x07\x06=\x03\x07\x01\x03\x03\x07\x01\x13\x03" + "\x07\x06\x06\x03\x07\x05\x0a\x03\x07\x1f\x09\x03\x07\x17:\x03\x06*1\x03" + "\x06-\x1d\x03\x06\x223\x03\x062:\x03\x060$\x03\x066\x1e\x03\x064\x12\x03" + "\x0645\x03\x06\x0b\x00\x03\x06\x0b7\x03\x06\x07\x1f\x03\x06\x15\x12\x03" + "\x0c\x05\x0f\x03\x0b+\x0b\x03\x0b+-\x03\x06\x16\x1b\x03\x06\x15\x17\x03" + "\x89\xca\xea\x03\x89\xca\xe8\x03\x0c8\x10\x03\x0c8\x01\x03\x0c8\x0f\x03" + "\x0d8%\x03\x0d8!\x03\x0c8-\x03\x0c8/\x03\x0c8+\x03\x0c87\x03\x0c85\x03" + "\x0c9\x09\x03\x0c9\x0d\x03\x0c9\x0f\x03\x0c9\x0b\x03\xcfu\x0c\x03\xcfu" + "\x0f\x03\xcfu\x0e\x03\xcfu\x09\x03\x0c9\x10\x03\x0d9\x0c\x03\xcf`;\x03" + "\xcf`>\x03\xcf`9\x03\xcf`8\x03\xcf`7\x03\xcf`*\x03\xcf`-\x03\xcf`,\x03" + "\x0d\x1b\x1a\x03\x0d\x1b&\x03\x0c=.\x03\x0c=%\x03\x0c>\x1e\x03\x0c>\x14" + "\x03\x0c?\x06\x03\x0c?\x0b\x03\x0c?\x0c\x03\x0c?\x0d\x03\x0c?\x02\x03" + "\x0c>\x0f\x03\x0c>\x08\x03\x0c>\x09\x03\x0c>,\x03\x0c>\x0c\x03\x0c?\x13" + "\x03\x0c?\x16\x03\x0c?\x15\x03\x0c?\x1c\x03\x0c?\x1f\x03\x0c?\x1d\x03" + "\x0c?\x1a\x03\x0c?\x17\x03\x0c?\x08\x03\x0c?\x09\x03\x0c?\x0e\x03\x0c?" + "\x04\x03\x0c?\x05\x03\x0c" + "\x03\x0c=2\x03\x0c=6\x03\x0c<\x07\x03\x0c<\x05\x03\x0e:!\x03\x0e:#\x03" + "\x0e8\x09\x03\x0e:&\x03\x0e8\x0b\x03\x0e:$\x03\x0e:,\x03\x0e8\x1a\x03" + "\x0e8\x1e\x03\x0e:*\x03\x0e:7\x03\x0e:5\x03\x0e:;\x03\x0e:\x15\x03\x0e:<" + "\x03\x0e:4\x03\x0e:'\x03\x0e:-\x03\x0e:%\x03\x0e:?\x03\x0e:=\x03\x0e:)" + "\x03\x0e:/\x03\xcfs'\x03\x0d=\x0f\x03\x0d+*\x03\x0d99\x03\x0d9;\x03\x0d9" + "?\x03\x0d)\x0d\x03\x0d(%\x02\x01\x18\x02\x01(\x02\x01\x1e\x03\x0f$!\x03" + "\x0f87\x03\x0f4\x0e\x03\x0f5\x1d\x03\x06'\x03\x03\x0f\x08\x18\x03\x0f" + "\x0d\x1b\x03\x0e2=\x03\x0e;\x08\x03\x0e:\x0b\x03\x0e\x06$\x03\x0e\x0d)" + "\x03\x0e\x16\x1f\x03\x0e\x16\x1b\x03\x0d$\x0a\x03\x05,\x1d\x03\x0d. \x03" + "\x0d.#\x03\x0c(/\x03\x09%\x02\x03\x0d90\x03\x0d\x0e4\x03\x0d\x0d\x0f\x03" + "\x0c#\x00\x03\x0c,\x1e\x03\x0c2\x0e\x03\x0c\x01\x17\x03\x0c\x09:\x03\x0e" + "\x173\x03\x0c\x08\x03\x03\x0c\x11\x07\x03\x0c\x10\x18\x03\x0c\x1f\x1c" + "\x03\x0c\x19\x0e\x03\x0c\x1a\x1f\x03\x0f0>\x03\x0b->\x03\x0b<+\x03\x0b8" + "\x13\x03\x0b\x043\x03\x0b\x14\x03\x03\x0b\x16%\x03\x0d\x22&\x03\x0b\x1a" + "\x1a\x03\x0b\x1a\x04\x03\x0a%9\x03\x0a&2\x03\x0a&0\x03\x0a!\x1a\x03\x0a!" + "7\x03\x0a5\x10\x03\x0a=4\x03\x0a?\x0e\x03\x0a>\x10\x03\x0a\x00 \x03\x0a" + "\x0f:\x03\x0a\x0f9\x03\x0a\x0b\x0a\x03\x0a\x17%\x03\x0a\x1b-\x03\x09-" + "\x1a\x03\x09,4\x03\x09.,\x03\x09)\x09\x03\x096!\x03\x091\x1f\x03\x093" + "\x16\x03\x0c+\x1f\x03\x098 \x03\x098=\x03\x0c(\x1a\x03\x0c(\x16\x03\x09" + "\x0a+\x03\x09\x16\x12\x03\x09\x13\x0e\x03\x09\x153\x03\x08)!\x03\x09\x1a" + "\x01\x03\x09\x18\x01\x03\x08%#\x03\x08>\x22\x03\x08\x05%\x03\x08\x02*" + "\x03\x08\x15;\x03\x08\x1b7\x03\x0f\x07\x1d\x03\x0f\x04\x03\x03\x070\x0c" + "\x03\x07;\x0b\x03\x07\x08\x17\x03\x07\x12\x06\x03\x06/-\x03\x0671\x03" + "\x065+\x03\x06>7\x03\x06\x049\x03\x05+\x1e\x03\x05,\x17\x03\x05 \x1d\x03" + "\x05\x22\x05\x03\x050\x1d" // lookup returns the trie value for the first UTF-8 encoding in s and // the width in bytes of this encoding. The size will be 0 if s does not // hold enough bytes to complete the encoding. len(s) must be greater than 0. func (t *idnaTrie) lookup(s []byte) (v uint16, sz int) { c0 := s[0] switch { case c0 < 0x80: // is ASCII return idnaValues[c0], 1 case c0 < 0xC2: return 0, 1 // Illegal UTF-8: not a starter, not ASCII. case c0 < 0xE0: // 2-byte UTF-8 if len(s) < 2 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c1), 2 case c0 < 0xF0: // 3-byte UTF-8 if len(s) < 3 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } o := uint32(i)<<6 + uint32(c1) i = idnaIndex[o] c2 := s[2] if c2 < 0x80 || 0xC0 <= c2 { return 0, 2 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c2), 3 case c0 < 0xF8: // 4-byte UTF-8 if len(s) < 4 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } o := uint32(i)<<6 + uint32(c1) i = idnaIndex[o] c2 := s[2] if c2 < 0x80 || 0xC0 <= c2 { return 0, 2 // Illegal UTF-8: not a continuation byte. } o = uint32(i)<<6 + uint32(c2) i = idnaIndex[o] c3 := s[3] if c3 < 0x80 || 0xC0 <= c3 { return 0, 3 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c3), 4 } // Illegal rune return 0, 1 } // lookupUnsafe returns the trie value for the first UTF-8 encoding in s. // s must start with a full and valid UTF-8 encoded rune. func (t *idnaTrie) lookupUnsafe(s []byte) uint16 { c0 := s[0] if c0 < 0x80 { // is ASCII return idnaValues[c0] } i := idnaIndex[c0] if c0 < 0xE0 { // 2-byte UTF-8 return t.lookupValue(uint32(i), s[1]) } i = idnaIndex[uint32(i)<<6+uint32(s[1])] if c0 < 0xF0 { // 3-byte UTF-8 return t.lookupValue(uint32(i), s[2]) } i = idnaIndex[uint32(i)<<6+uint32(s[2])] if c0 < 0xF8 { // 4-byte UTF-8 return t.lookupValue(uint32(i), s[3]) } return 0 } // lookupString returns the trie value for the first UTF-8 encoding in s and // the width in bytes of this encoding. The size will be 0 if s does not // hold enough bytes to complete the encoding. len(s) must be greater than 0. func (t *idnaTrie) lookupString(s string) (v uint16, sz int) { c0 := s[0] switch { case c0 < 0x80: // is ASCII return idnaValues[c0], 1 case c0 < 0xC2: return 0, 1 // Illegal UTF-8: not a starter, not ASCII. case c0 < 0xE0: // 2-byte UTF-8 if len(s) < 2 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c1), 2 case c0 < 0xF0: // 3-byte UTF-8 if len(s) < 3 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } o := uint32(i)<<6 + uint32(c1) i = idnaIndex[o] c2 := s[2] if c2 < 0x80 || 0xC0 <= c2 { return 0, 2 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c2), 3 case c0 < 0xF8: // 4-byte UTF-8 if len(s) < 4 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } o := uint32(i)<<6 + uint32(c1) i = idnaIndex[o] c2 := s[2] if c2 < 0x80 || 0xC0 <= c2 { return 0, 2 // Illegal UTF-8: not a continuation byte. } o = uint32(i)<<6 + uint32(c2) i = idnaIndex[o] c3 := s[3] if c3 < 0x80 || 0xC0 <= c3 { return 0, 3 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c3), 4 } // Illegal rune return 0, 1 } // lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. // s must start with a full and valid UTF-8 encoded rune. func (t *idnaTrie) lookupStringUnsafe(s string) uint16 { c0 := s[0] if c0 < 0x80 { // is ASCII return idnaValues[c0] } i := idnaIndex[c0] if c0 < 0xE0 { // 2-byte UTF-8 return t.lookupValue(uint32(i), s[1]) } i = idnaIndex[uint32(i)<<6+uint32(s[1])] if c0 < 0xF0 { // 3-byte UTF-8 return t.lookupValue(uint32(i), s[2]) } i = idnaIndex[uint32(i)<<6+uint32(s[2])] if c0 < 0xF8 { // 4-byte UTF-8 return t.lookupValue(uint32(i), s[3]) } return 0 } // idnaTrie. Total size: 29052 bytes (28.37 KiB). Checksum: ef06e7ecc26f36dd. type idnaTrie struct{} func newIdnaTrie(i int) *idnaTrie { return &idnaTrie{} } // lookupValue determines the type of block n and looks up the value for b. func (t *idnaTrie) lookupValue(n uint32, b byte) uint16 { switch { case n < 125: return uint16(idnaValues[n<<6+uint32(b)]) default: n -= 125 return uint16(idnaSparse.lookup(n, b)) } } // idnaValues: 127 blocks, 8128 entries, 16256 bytes // The third block is the zero block. var idnaValues = [8128]uint16{ // Block 0x0, offset 0x0 0x00: 0x0080, 0x01: 0x0080, 0x02: 0x0080, 0x03: 0x0080, 0x04: 0x0080, 0x05: 0x0080, 0x06: 0x0080, 0x07: 0x0080, 0x08: 0x0080, 0x09: 0x0080, 0x0a: 0x0080, 0x0b: 0x0080, 0x0c: 0x0080, 0x0d: 0x0080, 0x0e: 0x0080, 0x0f: 0x0080, 0x10: 0x0080, 0x11: 0x0080, 0x12: 0x0080, 0x13: 0x0080, 0x14: 0x0080, 0x15: 0x0080, 0x16: 0x0080, 0x17: 0x0080, 0x18: 0x0080, 0x19: 0x0080, 0x1a: 0x0080, 0x1b: 0x0080, 0x1c: 0x0080, 0x1d: 0x0080, 0x1e: 0x0080, 0x1f: 0x0080, 0x20: 0x0080, 0x21: 0x0080, 0x22: 0x0080, 0x23: 0x0080, 0x24: 0x0080, 0x25: 0x0080, 0x26: 0x0080, 0x27: 0x0080, 0x28: 0x0080, 0x29: 0x0080, 0x2a: 0x0080, 0x2b: 0x0080, 0x2c: 0x0080, 0x2d: 0x0008, 0x2e: 0x0008, 0x2f: 0x0080, 0x30: 0x0008, 0x31: 0x0008, 0x32: 0x0008, 0x33: 0x0008, 0x34: 0x0008, 0x35: 0x0008, 0x36: 0x0008, 0x37: 0x0008, 0x38: 0x0008, 0x39: 0x0008, 0x3a: 0x0080, 0x3b: 0x0080, 0x3c: 0x0080, 0x3d: 0x0080, 0x3e: 0x0080, 0x3f: 0x0080, // Block 0x1, offset 0x40 0x40: 0x0080, 0x41: 0xe105, 0x42: 0xe105, 0x43: 0xe105, 0x44: 0xe105, 0x45: 0xe105, 0x46: 0xe105, 0x47: 0xe105, 0x48: 0xe105, 0x49: 0xe105, 0x4a: 0xe105, 0x4b: 0xe105, 0x4c: 0xe105, 0x4d: 0xe105, 0x4e: 0xe105, 0x4f: 0xe105, 0x50: 0xe105, 0x51: 0xe105, 0x52: 0xe105, 0x53: 0xe105, 0x54: 0xe105, 0x55: 0xe105, 0x56: 0xe105, 0x57: 0xe105, 0x58: 0xe105, 0x59: 0xe105, 0x5a: 0xe105, 0x5b: 0x0080, 0x5c: 0x0080, 0x5d: 0x0080, 0x5e: 0x0080, 0x5f: 0x0080, 0x60: 0x0080, 0x61: 0x0008, 0x62: 0x0008, 0x63: 0x0008, 0x64: 0x0008, 0x65: 0x0008, 0x66: 0x0008, 0x67: 0x0008, 0x68: 0x0008, 0x69: 0x0008, 0x6a: 0x0008, 0x6b: 0x0008, 0x6c: 0x0008, 0x6d: 0x0008, 0x6e: 0x0008, 0x6f: 0x0008, 0x70: 0x0008, 0x71: 0x0008, 0x72: 0x0008, 0x73: 0x0008, 0x74: 0x0008, 0x75: 0x0008, 0x76: 0x0008, 0x77: 0x0008, 0x78: 0x0008, 0x79: 0x0008, 0x7a: 0x0008, 0x7b: 0x0080, 0x7c: 0x0080, 0x7d: 0x0080, 0x7e: 0x0080, 0x7f: 0x0080, // Block 0x2, offset 0x80 // Block 0x3, offset 0xc0 0xc0: 0x0040, 0xc1: 0x0040, 0xc2: 0x0040, 0xc3: 0x0040, 0xc4: 0x0040, 0xc5: 0x0040, 0xc6: 0x0040, 0xc7: 0x0040, 0xc8: 0x0040, 0xc9: 0x0040, 0xca: 0x0040, 0xcb: 0x0040, 0xcc: 0x0040, 0xcd: 0x0040, 0xce: 0x0040, 0xcf: 0x0040, 0xd0: 0x0040, 0xd1: 0x0040, 0xd2: 0x0040, 0xd3: 0x0040, 0xd4: 0x0040, 0xd5: 0x0040, 0xd6: 0x0040, 0xd7: 0x0040, 0xd8: 0x0040, 0xd9: 0x0040, 0xda: 0x0040, 0xdb: 0x0040, 0xdc: 0x0040, 0xdd: 0x0040, 0xde: 0x0040, 0xdf: 0x0040, 0xe0: 0x000a, 0xe1: 0x0018, 0xe2: 0x0018, 0xe3: 0x0018, 0xe4: 0x0018, 0xe5: 0x0018, 0xe6: 0x0018, 0xe7: 0x0018, 0xe8: 0x001a, 0xe9: 0x0018, 0xea: 0x0039, 0xeb: 0x0018, 0xec: 0x0018, 0xed: 0x03c0, 0xee: 0x0018, 0xef: 0x004a, 0xf0: 0x0018, 0xf1: 0x0018, 0xf2: 0x0069, 0xf3: 0x0079, 0xf4: 0x008a, 0xf5: 0x0005, 0xf6: 0x0018, 0xf7: 0x0008, 0xf8: 0x00aa, 0xf9: 0x00c9, 0xfa: 0x00d9, 0xfb: 0x0018, 0xfc: 0x00e9, 0xfd: 0x0119, 0xfe: 0x0149, 0xff: 0x0018, // Block 0x4, offset 0x100 0x100: 0xe00d, 0x101: 0x0008, 0x102: 0xe00d, 0x103: 0x0008, 0x104: 0xe00d, 0x105: 0x0008, 0x106: 0xe00d, 0x107: 0x0008, 0x108: 0xe00d, 0x109: 0x0008, 0x10a: 0xe00d, 0x10b: 0x0008, 0x10c: 0xe00d, 0x10d: 0x0008, 0x10e: 0xe00d, 0x10f: 0x0008, 0x110: 0xe00d, 0x111: 0x0008, 0x112: 0xe00d, 0x113: 0x0008, 0x114: 0xe00d, 0x115: 0x0008, 0x116: 0xe00d, 0x117: 0x0008, 0x118: 0xe00d, 0x119: 0x0008, 0x11a: 0xe00d, 0x11b: 0x0008, 0x11c: 0xe00d, 0x11d: 0x0008, 0x11e: 0xe00d, 0x11f: 0x0008, 0x120: 0xe00d, 0x121: 0x0008, 0x122: 0xe00d, 0x123: 0x0008, 0x124: 0xe00d, 0x125: 0x0008, 0x126: 0xe00d, 0x127: 0x0008, 0x128: 0xe00d, 0x129: 0x0008, 0x12a: 0xe00d, 0x12b: 0x0008, 0x12c: 0xe00d, 0x12d: 0x0008, 0x12e: 0xe00d, 0x12f: 0x0008, 0x130: 0x0179, 0x131: 0x0008, 0x132: 0x0035, 0x133: 0x004d, 0x134: 0xe00d, 0x135: 0x0008, 0x136: 0xe00d, 0x137: 0x0008, 0x138: 0x0008, 0x139: 0xe01d, 0x13a: 0x0008, 0x13b: 0xe03d, 0x13c: 0x0008, 0x13d: 0xe01d, 0x13e: 0x0008, 0x13f: 0x0199, // Block 0x5, offset 0x140 0x140: 0x0199, 0x141: 0xe01d, 0x142: 0x0008, 0x143: 0xe03d, 0x144: 0x0008, 0x145: 0xe01d, 0x146: 0x0008, 0x147: 0xe07d, 0x148: 0x0008, 0x149: 0x01b9, 0x14a: 0xe00d, 0x14b: 0x0008, 0x14c: 0xe00d, 0x14d: 0x0008, 0x14e: 0xe00d, 0x14f: 0x0008, 0x150: 0xe00d, 0x151: 0x0008, 0x152: 0xe00d, 0x153: 0x0008, 0x154: 0xe00d, 0x155: 0x0008, 0x156: 0xe00d, 0x157: 0x0008, 0x158: 0xe00d, 0x159: 0x0008, 0x15a: 0xe00d, 0x15b: 0x0008, 0x15c: 0xe00d, 0x15d: 0x0008, 0x15e: 0xe00d, 0x15f: 0x0008, 0x160: 0xe00d, 0x161: 0x0008, 0x162: 0xe00d, 0x163: 0x0008, 0x164: 0xe00d, 0x165: 0x0008, 0x166: 0xe00d, 0x167: 0x0008, 0x168: 0xe00d, 0x169: 0x0008, 0x16a: 0xe00d, 0x16b: 0x0008, 0x16c: 0xe00d, 0x16d: 0x0008, 0x16e: 0xe00d, 0x16f: 0x0008, 0x170: 0xe00d, 0x171: 0x0008, 0x172: 0xe00d, 0x173: 0x0008, 0x174: 0xe00d, 0x175: 0x0008, 0x176: 0xe00d, 0x177: 0x0008, 0x178: 0x0065, 0x179: 0xe01d, 0x17a: 0x0008, 0x17b: 0xe03d, 0x17c: 0x0008, 0x17d: 0xe01d, 0x17e: 0x0008, 0x17f: 0x01d9, // Block 0x6, offset 0x180 0x180: 0x0008, 0x181: 0x007d, 0x182: 0xe00d, 0x183: 0x0008, 0x184: 0xe00d, 0x185: 0x0008, 0x186: 0x007d, 0x187: 0xe07d, 0x188: 0x0008, 0x189: 0x0095, 0x18a: 0x00ad, 0x18b: 0xe03d, 0x18c: 0x0008, 0x18d: 0x0008, 0x18e: 0x00c5, 0x18f: 0x00dd, 0x190: 0x00f5, 0x191: 0xe01d, 0x192: 0x0008, 0x193: 0x010d, 0x194: 0x0125, 0x195: 0x0008, 0x196: 0x013d, 0x197: 0x013d, 0x198: 0xe00d, 0x199: 0x0008, 0x19a: 0x0008, 0x19b: 0x0008, 0x19c: 0x010d, 0x19d: 0x0155, 0x19e: 0x0008, 0x19f: 0x016d, 0x1a0: 0xe00d, 0x1a1: 0x0008, 0x1a2: 0xe00d, 0x1a3: 0x0008, 0x1a4: 0xe00d, 0x1a5: 0x0008, 0x1a6: 0x0185, 0x1a7: 0xe07d, 0x1a8: 0x0008, 0x1a9: 0x019d, 0x1aa: 0x0008, 0x1ab: 0x0008, 0x1ac: 0xe00d, 0x1ad: 0x0008, 0x1ae: 0x0185, 0x1af: 0xe0fd, 0x1b0: 0x0008, 0x1b1: 0x01b5, 0x1b2: 0x01cd, 0x1b3: 0xe03d, 0x1b4: 0x0008, 0x1b5: 0xe01d, 0x1b6: 0x0008, 0x1b7: 0x01e5, 0x1b8: 0xe00d, 0x1b9: 0x0008, 0x1ba: 0x0008, 0x1bb: 0x0008, 0x1bc: 0xe00d, 0x1bd: 0x0008, 0x1be: 0x0008, 0x1bf: 0x0008, // Block 0x7, offset 0x1c0 0x1c0: 0x0008, 0x1c1: 0x0008, 0x1c2: 0x0008, 0x1c3: 0x0008, 0x1c4: 0x01e9, 0x1c5: 0x01e9, 0x1c6: 0x01e9, 0x1c7: 0x01fd, 0x1c8: 0x0215, 0x1c9: 0x022d, 0x1ca: 0x0245, 0x1cb: 0x025d, 0x1cc: 0x0275, 0x1cd: 0xe01d, 0x1ce: 0x0008, 0x1cf: 0xe0fd, 0x1d0: 0x0008, 0x1d1: 0xe01d, 0x1d2: 0x0008, 0x1d3: 0xe03d, 0x1d4: 0x0008, 0x1d5: 0xe01d, 0x1d6: 0x0008, 0x1d7: 0xe07d, 0x1d8: 0x0008, 0x1d9: 0xe01d, 0x1da: 0x0008, 0x1db: 0xe03d, 0x1dc: 0x0008, 0x1dd: 0x0008, 0x1de: 0xe00d, 0x1df: 0x0008, 0x1e0: 0xe00d, 0x1e1: 0x0008, 0x1e2: 0xe00d, 0x1e3: 0x0008, 0x1e4: 0xe00d, 0x1e5: 0x0008, 0x1e6: 0xe00d, 0x1e7: 0x0008, 0x1e8: 0xe00d, 0x1e9: 0x0008, 0x1ea: 0xe00d, 0x1eb: 0x0008, 0x1ec: 0xe00d, 0x1ed: 0x0008, 0x1ee: 0xe00d, 0x1ef: 0x0008, 0x1f0: 0x0008, 0x1f1: 0x028d, 0x1f2: 0x02a5, 0x1f3: 0x02bd, 0x1f4: 0xe00d, 0x1f5: 0x0008, 0x1f6: 0x02d5, 0x1f7: 0x02ed, 0x1f8: 0xe00d, 0x1f9: 0x0008, 0x1fa: 0xe00d, 0x1fb: 0x0008, 0x1fc: 0xe00d, 0x1fd: 0x0008, 0x1fe: 0xe00d, 0x1ff: 0x0008, // Block 0x8, offset 0x200 0x200: 0xe00d, 0x201: 0x0008, 0x202: 0xe00d, 0x203: 0x0008, 0x204: 0xe00d, 0x205: 0x0008, 0x206: 0xe00d, 0x207: 0x0008, 0x208: 0xe00d, 0x209: 0x0008, 0x20a: 0xe00d, 0x20b: 0x0008, 0x20c: 0xe00d, 0x20d: 0x0008, 0x20e: 0xe00d, 0x20f: 0x0008, 0x210: 0xe00d, 0x211: 0x0008, 0x212: 0xe00d, 0x213: 0x0008, 0x214: 0xe00d, 0x215: 0x0008, 0x216: 0xe00d, 0x217: 0x0008, 0x218: 0xe00d, 0x219: 0x0008, 0x21a: 0xe00d, 0x21b: 0x0008, 0x21c: 0xe00d, 0x21d: 0x0008, 0x21e: 0xe00d, 0x21f: 0x0008, 0x220: 0x0305, 0x221: 0x0008, 0x222: 0xe00d, 0x223: 0x0008, 0x224: 0xe00d, 0x225: 0x0008, 0x226: 0xe00d, 0x227: 0x0008, 0x228: 0xe00d, 0x229: 0x0008, 0x22a: 0xe00d, 0x22b: 0x0008, 0x22c: 0xe00d, 0x22d: 0x0008, 0x22e: 0xe00d, 0x22f: 0x0008, 0x230: 0xe00d, 0x231: 0x0008, 0x232: 0xe00d, 0x233: 0x0008, 0x234: 0x0008, 0x235: 0x0008, 0x236: 0x0008, 0x237: 0x0008, 0x238: 0x0008, 0x239: 0x0008, 0x23a: 0x0209, 0x23b: 0xe03d, 0x23c: 0x0008, 0x23d: 0x031d, 0x23e: 0x0229, 0x23f: 0x0008, // Block 0x9, offset 0x240 0x240: 0x0008, 0x241: 0x0008, 0x242: 0x0018, 0x243: 0x0018, 0x244: 0x0018, 0x245: 0x0018, 0x246: 0x0008, 0x247: 0x0008, 0x248: 0x0008, 0x249: 0x0008, 0x24a: 0x0008, 0x24b: 0x0008, 0x24c: 0x0008, 0x24d: 0x0008, 0x24e: 0x0008, 0x24f: 0x0008, 0x250: 0x0008, 0x251: 0x0008, 0x252: 0x0018, 0x253: 0x0018, 0x254: 0x0018, 0x255: 0x0018, 0x256: 0x0018, 0x257: 0x0018, 0x258: 0x029a, 0x259: 0x02ba, 0x25a: 0x02da, 0x25b: 0x02fa, 0x25c: 0x031a, 0x25d: 0x033a, 0x25e: 0x0018, 0x25f: 0x0018, 0x260: 0x03ad, 0x261: 0x0359, 0x262: 0x01d9, 0x263: 0x0369, 0x264: 0x03c5, 0x265: 0x0018, 0x266: 0x0018, 0x267: 0x0018, 0x268: 0x0018, 0x269: 0x0018, 0x26a: 0x0018, 0x26b: 0x0018, 0x26c: 0x0008, 0x26d: 0x0018, 0x26e: 0x0008, 0x26f: 0x0018, 0x270: 0x0018, 0x271: 0x0018, 0x272: 0x0018, 0x273: 0x0018, 0x274: 0x0018, 0x275: 0x0018, 0x276: 0x0018, 0x277: 0x0018, 0x278: 0x0018, 0x279: 0x0018, 0x27a: 0x0018, 0x27b: 0x0018, 0x27c: 0x0018, 0x27d: 0x0018, 0x27e: 0x0018, 0x27f: 0x0018, // Block 0xa, offset 0x280 0x280: 0x03dd, 0x281: 0x03dd, 0x282: 0x3308, 0x283: 0x03f5, 0x284: 0x0379, 0x285: 0x040d, 0x286: 0x3308, 0x287: 0x3308, 0x288: 0x3308, 0x289: 0x3308, 0x28a: 0x3308, 0x28b: 0x3308, 0x28c: 0x3308, 0x28d: 0x3308, 0x28e: 0x3308, 0x28f: 0x33c0, 0x290: 0x3308, 0x291: 0x3308, 0x292: 0x3308, 0x293: 0x3308, 0x294: 0x3308, 0x295: 0x3308, 0x296: 0x3308, 0x297: 0x3308, 0x298: 0x3308, 0x299: 0x3308, 0x29a: 0x3308, 0x29b: 0x3308, 0x29c: 0x3308, 0x29d: 0x3308, 0x29e: 0x3308, 0x29f: 0x3308, 0x2a0: 0x3308, 0x2a1: 0x3308, 0x2a2: 0x3308, 0x2a3: 0x3308, 0x2a4: 0x3308, 0x2a5: 0x3308, 0x2a6: 0x3308, 0x2a7: 0x3308, 0x2a8: 0x3308, 0x2a9: 0x3308, 0x2aa: 0x3308, 0x2ab: 0x3308, 0x2ac: 0x3308, 0x2ad: 0x3308, 0x2ae: 0x3308, 0x2af: 0x3308, 0x2b0: 0xe00d, 0x2b1: 0x0008, 0x2b2: 0xe00d, 0x2b3: 0x0008, 0x2b4: 0x0425, 0x2b5: 0x0008, 0x2b6: 0xe00d, 0x2b7: 0x0008, 0x2b8: 0x0040, 0x2b9: 0x0040, 0x2ba: 0x03a2, 0x2bb: 0x0008, 0x2bc: 0x0008, 0x2bd: 0x0008, 0x2be: 0x03c2, 0x2bf: 0x043d, // Block 0xb, offset 0x2c0 0x2c0: 0x0040, 0x2c1: 0x0040, 0x2c2: 0x0040, 0x2c3: 0x0040, 0x2c4: 0x008a, 0x2c5: 0x03d2, 0x2c6: 0xe155, 0x2c7: 0x0455, 0x2c8: 0xe12d, 0x2c9: 0xe13d, 0x2ca: 0xe12d, 0x2cb: 0x0040, 0x2cc: 0x03dd, 0x2cd: 0x0040, 0x2ce: 0x046d, 0x2cf: 0x0485, 0x2d0: 0x0008, 0x2d1: 0xe105, 0x2d2: 0xe105, 0x2d3: 0xe105, 0x2d4: 0xe105, 0x2d5: 0xe105, 0x2d6: 0xe105, 0x2d7: 0xe105, 0x2d8: 0xe105, 0x2d9: 0xe105, 0x2da: 0xe105, 0x2db: 0xe105, 0x2dc: 0xe105, 0x2dd: 0xe105, 0x2de: 0xe105, 0x2df: 0xe105, 0x2e0: 0x049d, 0x2e1: 0x049d, 0x2e2: 0x0040, 0x2e3: 0x049d, 0x2e4: 0x049d, 0x2e5: 0x049d, 0x2e6: 0x049d, 0x2e7: 0x049d, 0x2e8: 0x049d, 0x2e9: 0x049d, 0x2ea: 0x049d, 0x2eb: 0x049d, 0x2ec: 0x0008, 0x2ed: 0x0008, 0x2ee: 0x0008, 0x2ef: 0x0008, 0x2f0: 0x0008, 0x2f1: 0x0008, 0x2f2: 0x0008, 0x2f3: 0x0008, 0x2f4: 0x0008, 0x2f5: 0x0008, 0x2f6: 0x0008, 0x2f7: 0x0008, 0x2f8: 0x0008, 0x2f9: 0x0008, 0x2fa: 0x0008, 0x2fb: 0x0008, 0x2fc: 0x0008, 0x2fd: 0x0008, 0x2fe: 0x0008, 0x2ff: 0x0008, // Block 0xc, offset 0x300 0x300: 0x0008, 0x301: 0x0008, 0x302: 0xe00f, 0x303: 0x0008, 0x304: 0x0008, 0x305: 0x0008, 0x306: 0x0008, 0x307: 0x0008, 0x308: 0x0008, 0x309: 0x0008, 0x30a: 0x0008, 0x30b: 0x0008, 0x30c: 0x0008, 0x30d: 0x0008, 0x30e: 0x0008, 0x30f: 0xe0c5, 0x310: 0x04b5, 0x311: 0x04cd, 0x312: 0xe0bd, 0x313: 0xe0f5, 0x314: 0xe0fd, 0x315: 0xe09d, 0x316: 0xe0b5, 0x317: 0x0008, 0x318: 0xe00d, 0x319: 0x0008, 0x31a: 0xe00d, 0x31b: 0x0008, 0x31c: 0xe00d, 0x31d: 0x0008, 0x31e: 0xe00d, 0x31f: 0x0008, 0x320: 0xe00d, 0x321: 0x0008, 0x322: 0xe00d, 0x323: 0x0008, 0x324: 0xe00d, 0x325: 0x0008, 0x326: 0xe00d, 0x327: 0x0008, 0x328: 0xe00d, 0x329: 0x0008, 0x32a: 0xe00d, 0x32b: 0x0008, 0x32c: 0xe00d, 0x32d: 0x0008, 0x32e: 0xe00d, 0x32f: 0x0008, 0x330: 0x04e5, 0x331: 0xe185, 0x332: 0xe18d, 0x333: 0x0008, 0x334: 0x04fd, 0x335: 0x03dd, 0x336: 0x0018, 0x337: 0xe07d, 0x338: 0x0008, 0x339: 0xe1d5, 0x33a: 0xe00d, 0x33b: 0x0008, 0x33c: 0x0008, 0x33d: 0x0515, 0x33e: 0x052d, 0x33f: 0x052d, // Block 0xd, offset 0x340 0x340: 0x0008, 0x341: 0x0008, 0x342: 0x0008, 0x343: 0x0008, 0x344: 0x0008, 0x345: 0x0008, 0x346: 0x0008, 0x347: 0x0008, 0x348: 0x0008, 0x349: 0x0008, 0x34a: 0x0008, 0x34b: 0x0008, 0x34c: 0x0008, 0x34d: 0x0008, 0x34e: 0x0008, 0x34f: 0x0008, 0x350: 0x0008, 0x351: 0x0008, 0x352: 0x0008, 0x353: 0x0008, 0x354: 0x0008, 0x355: 0x0008, 0x356: 0x0008, 0x357: 0x0008, 0x358: 0x0008, 0x359: 0x0008, 0x35a: 0x0008, 0x35b: 0x0008, 0x35c: 0x0008, 0x35d: 0x0008, 0x35e: 0x0008, 0x35f: 0x0008, 0x360: 0xe00d, 0x361: 0x0008, 0x362: 0xe00d, 0x363: 0x0008, 0x364: 0xe00d, 0x365: 0x0008, 0x366: 0xe00d, 0x367: 0x0008, 0x368: 0xe00d, 0x369: 0x0008, 0x36a: 0xe00d, 0x36b: 0x0008, 0x36c: 0xe00d, 0x36d: 0x0008, 0x36e: 0xe00d, 0x36f: 0x0008, 0x370: 0xe00d, 0x371: 0x0008, 0x372: 0xe00d, 0x373: 0x0008, 0x374: 0xe00d, 0x375: 0x0008, 0x376: 0xe00d, 0x377: 0x0008, 0x378: 0xe00d, 0x379: 0x0008, 0x37a: 0xe00d, 0x37b: 0x0008, 0x37c: 0xe00d, 0x37d: 0x0008, 0x37e: 0xe00d, 0x37f: 0x0008, // Block 0xe, offset 0x380 0x380: 0xe00d, 0x381: 0x0008, 0x382: 0x0018, 0x383: 0x3308, 0x384: 0x3308, 0x385: 0x3308, 0x386: 0x3308, 0x387: 0x3308, 0x388: 0x3318, 0x389: 0x3318, 0x38a: 0xe00d, 0x38b: 0x0008, 0x38c: 0xe00d, 0x38d: 0x0008, 0x38e: 0xe00d, 0x38f: 0x0008, 0x390: 0xe00d, 0x391: 0x0008, 0x392: 0xe00d, 0x393: 0x0008, 0x394: 0xe00d, 0x395: 0x0008, 0x396: 0xe00d, 0x397: 0x0008, 0x398: 0xe00d, 0x399: 0x0008, 0x39a: 0xe00d, 0x39b: 0x0008, 0x39c: 0xe00d, 0x39d: 0x0008, 0x39e: 0xe00d, 0x39f: 0x0008, 0x3a0: 0xe00d, 0x3a1: 0x0008, 0x3a2: 0xe00d, 0x3a3: 0x0008, 0x3a4: 0xe00d, 0x3a5: 0x0008, 0x3a6: 0xe00d, 0x3a7: 0x0008, 0x3a8: 0xe00d, 0x3a9: 0x0008, 0x3aa: 0xe00d, 0x3ab: 0x0008, 0x3ac: 0xe00d, 0x3ad: 0x0008, 0x3ae: 0xe00d, 0x3af: 0x0008, 0x3b0: 0xe00d, 0x3b1: 0x0008, 0x3b2: 0xe00d, 0x3b3: 0x0008, 0x3b4: 0xe00d, 0x3b5: 0x0008, 0x3b6: 0xe00d, 0x3b7: 0x0008, 0x3b8: 0xe00d, 0x3b9: 0x0008, 0x3ba: 0xe00d, 0x3bb: 0x0008, 0x3bc: 0xe00d, 0x3bd: 0x0008, 0x3be: 0xe00d, 0x3bf: 0x0008, // Block 0xf, offset 0x3c0 0x3c0: 0x0040, 0x3c1: 0xe01d, 0x3c2: 0x0008, 0x3c3: 0xe03d, 0x3c4: 0x0008, 0x3c5: 0xe01d, 0x3c6: 0x0008, 0x3c7: 0xe07d, 0x3c8: 0x0008, 0x3c9: 0xe01d, 0x3ca: 0x0008, 0x3cb: 0xe03d, 0x3cc: 0x0008, 0x3cd: 0xe01d, 0x3ce: 0x0008, 0x3cf: 0x0008, 0x3d0: 0xe00d, 0x3d1: 0x0008, 0x3d2: 0xe00d, 0x3d3: 0x0008, 0x3d4: 0xe00d, 0x3d5: 0x0008, 0x3d6: 0xe00d, 0x3d7: 0x0008, 0x3d8: 0xe00d, 0x3d9: 0x0008, 0x3da: 0xe00d, 0x3db: 0x0008, 0x3dc: 0xe00d, 0x3dd: 0x0008, 0x3de: 0xe00d, 0x3df: 0x0008, 0x3e0: 0xe00d, 0x3e1: 0x0008, 0x3e2: 0xe00d, 0x3e3: 0x0008, 0x3e4: 0xe00d, 0x3e5: 0x0008, 0x3e6: 0xe00d, 0x3e7: 0x0008, 0x3e8: 0xe00d, 0x3e9: 0x0008, 0x3ea: 0xe00d, 0x3eb: 0x0008, 0x3ec: 0xe00d, 0x3ed: 0x0008, 0x3ee: 0xe00d, 0x3ef: 0x0008, 0x3f0: 0xe00d, 0x3f1: 0x0008, 0x3f2: 0xe00d, 0x3f3: 0x0008, 0x3f4: 0xe00d, 0x3f5: 0x0008, 0x3f6: 0xe00d, 0x3f7: 0x0008, 0x3f8: 0xe00d, 0x3f9: 0x0008, 0x3fa: 0xe00d, 0x3fb: 0x0008, 0x3fc: 0xe00d, 0x3fd: 0x0008, 0x3fe: 0xe00d, 0x3ff: 0x0008, // Block 0x10, offset 0x400 0x400: 0xe00d, 0x401: 0x0008, 0x402: 0xe00d, 0x403: 0x0008, 0x404: 0xe00d, 0x405: 0x0008, 0x406: 0xe00d, 0x407: 0x0008, 0x408: 0xe00d, 0x409: 0x0008, 0x40a: 0xe00d, 0x40b: 0x0008, 0x40c: 0xe00d, 0x40d: 0x0008, 0x40e: 0xe00d, 0x40f: 0x0008, 0x410: 0xe00d, 0x411: 0x0008, 0x412: 0xe00d, 0x413: 0x0008, 0x414: 0xe00d, 0x415: 0x0008, 0x416: 0xe00d, 0x417: 0x0008, 0x418: 0xe00d, 0x419: 0x0008, 0x41a: 0xe00d, 0x41b: 0x0008, 0x41c: 0xe00d, 0x41d: 0x0008, 0x41e: 0xe00d, 0x41f: 0x0008, 0x420: 0xe00d, 0x421: 0x0008, 0x422: 0xe00d, 0x423: 0x0008, 0x424: 0xe00d, 0x425: 0x0008, 0x426: 0xe00d, 0x427: 0x0008, 0x428: 0xe00d, 0x429: 0x0008, 0x42a: 0xe00d, 0x42b: 0x0008, 0x42c: 0xe00d, 0x42d: 0x0008, 0x42e: 0xe00d, 0x42f: 0x0008, 0x430: 0x0040, 0x431: 0x03f5, 0x432: 0x03f5, 0x433: 0x03f5, 0x434: 0x03f5, 0x435: 0x03f5, 0x436: 0x03f5, 0x437: 0x03f5, 0x438: 0x03f5, 0x439: 0x03f5, 0x43a: 0x03f5, 0x43b: 0x03f5, 0x43c: 0x03f5, 0x43d: 0x03f5, 0x43e: 0x03f5, 0x43f: 0x03f5, // Block 0x11, offset 0x440 0x440: 0x0840, 0x441: 0x0840, 0x442: 0x0840, 0x443: 0x0840, 0x444: 0x0840, 0x445: 0x0840, 0x446: 0x0018, 0x447: 0x0018, 0x448: 0x0818, 0x449: 0x0018, 0x44a: 0x0018, 0x44b: 0x0818, 0x44c: 0x0018, 0x44d: 0x0818, 0x44e: 0x0018, 0x44f: 0x0018, 0x450: 0x3308, 0x451: 0x3308, 0x452: 0x3308, 0x453: 0x3308, 0x454: 0x3308, 0x455: 0x3308, 0x456: 0x3308, 0x457: 0x3308, 0x458: 0x3308, 0x459: 0x3308, 0x45a: 0x3308, 0x45b: 0x0818, 0x45c: 0x0b40, 0x45d: 0x0040, 0x45e: 0x0818, 0x45f: 0x0818, 0x460: 0x0a08, 0x461: 0x0808, 0x462: 0x0c08, 0x463: 0x0c08, 0x464: 0x0c08, 0x465: 0x0c08, 0x466: 0x0a08, 0x467: 0x0c08, 0x468: 0x0a08, 0x469: 0x0c08, 0x46a: 0x0a08, 0x46b: 0x0a08, 0x46c: 0x0a08, 0x46d: 0x0a08, 0x46e: 0x0a08, 0x46f: 0x0c08, 0x470: 0x0c08, 0x471: 0x0c08, 0x472: 0x0c08, 0x473: 0x0a08, 0x474: 0x0a08, 0x475: 0x0a08, 0x476: 0x0a08, 0x477: 0x0a08, 0x478: 0x0a08, 0x479: 0x0a08, 0x47a: 0x0a08, 0x47b: 0x0a08, 0x47c: 0x0a08, 0x47d: 0x0a08, 0x47e: 0x0a08, 0x47f: 0x0a08, // Block 0x12, offset 0x480 0x480: 0x0818, 0x481: 0x0a08, 0x482: 0x0a08, 0x483: 0x0a08, 0x484: 0x0a08, 0x485: 0x0a08, 0x486: 0x0a08, 0x487: 0x0a08, 0x488: 0x0c08, 0x489: 0x0a08, 0x48a: 0x0a08, 0x48b: 0x3308, 0x48c: 0x3308, 0x48d: 0x3308, 0x48e: 0x3308, 0x48f: 0x3308, 0x490: 0x3308, 0x491: 0x3308, 0x492: 0x3308, 0x493: 0x3308, 0x494: 0x3308, 0x495: 0x3308, 0x496: 0x3308, 0x497: 0x3308, 0x498: 0x3308, 0x499: 0x3308, 0x49a: 0x3308, 0x49b: 0x3308, 0x49c: 0x3308, 0x49d: 0x3308, 0x49e: 0x3308, 0x49f: 0x3308, 0x4a0: 0x0808, 0x4a1: 0x0808, 0x4a2: 0x0808, 0x4a3: 0x0808, 0x4a4: 0x0808, 0x4a5: 0x0808, 0x4a6: 0x0808, 0x4a7: 0x0808, 0x4a8: 0x0808, 0x4a9: 0x0808, 0x4aa: 0x0018, 0x4ab: 0x0818, 0x4ac: 0x0818, 0x4ad: 0x0818, 0x4ae: 0x0a08, 0x4af: 0x0a08, 0x4b0: 0x3308, 0x4b1: 0x0c08, 0x4b2: 0x0c08, 0x4b3: 0x0c08, 0x4b4: 0x0808, 0x4b5: 0x0429, 0x4b6: 0x0451, 0x4b7: 0x0479, 0x4b8: 0x04a1, 0x4b9: 0x0a08, 0x4ba: 0x0a08, 0x4bb: 0x0a08, 0x4bc: 0x0a08, 0x4bd: 0x0a08, 0x4be: 0x0a08, 0x4bf: 0x0a08, // Block 0x13, offset 0x4c0 0x4c0: 0x0c08, 0x4c1: 0x0a08, 0x4c2: 0x0a08, 0x4c3: 0x0c08, 0x4c4: 0x0c08, 0x4c5: 0x0c08, 0x4c6: 0x0c08, 0x4c7: 0x0c08, 0x4c8: 0x0c08, 0x4c9: 0x0c08, 0x4ca: 0x0c08, 0x4cb: 0x0c08, 0x4cc: 0x0a08, 0x4cd: 0x0c08, 0x4ce: 0x0a08, 0x4cf: 0x0c08, 0x4d0: 0x0a08, 0x4d1: 0x0a08, 0x4d2: 0x0c08, 0x4d3: 0x0c08, 0x4d4: 0x0818, 0x4d5: 0x0c08, 0x4d6: 0x3308, 0x4d7: 0x3308, 0x4d8: 0x3308, 0x4d9: 0x3308, 0x4da: 0x3308, 0x4db: 0x3308, 0x4dc: 0x3308, 0x4dd: 0x0840, 0x4de: 0x0018, 0x4df: 0x3308, 0x4e0: 0x3308, 0x4e1: 0x3308, 0x4e2: 0x3308, 0x4e3: 0x3308, 0x4e4: 0x3308, 0x4e5: 0x0808, 0x4e6: 0x0808, 0x4e7: 0x3308, 0x4e8: 0x3308, 0x4e9: 0x0018, 0x4ea: 0x3308, 0x4eb: 0x3308, 0x4ec: 0x3308, 0x4ed: 0x3308, 0x4ee: 0x0c08, 0x4ef: 0x0c08, 0x4f0: 0x0008, 0x4f1: 0x0008, 0x4f2: 0x0008, 0x4f3: 0x0008, 0x4f4: 0x0008, 0x4f5: 0x0008, 0x4f6: 0x0008, 0x4f7: 0x0008, 0x4f8: 0x0008, 0x4f9: 0x0008, 0x4fa: 0x0a08, 0x4fb: 0x0a08, 0x4fc: 0x0a08, 0x4fd: 0x0808, 0x4fe: 0x0808, 0x4ff: 0x0a08, // Block 0x14, offset 0x500 0x500: 0x0818, 0x501: 0x0818, 0x502: 0x0818, 0x503: 0x0818, 0x504: 0x0818, 0x505: 0x0818, 0x506: 0x0818, 0x507: 0x0818, 0x508: 0x0818, 0x509: 0x0818, 0x50a: 0x0818, 0x50b: 0x0818, 0x50c: 0x0818, 0x50d: 0x0818, 0x50e: 0x0040, 0x50f: 0x0b40, 0x510: 0x0c08, 0x511: 0x3308, 0x512: 0x0a08, 0x513: 0x0a08, 0x514: 0x0a08, 0x515: 0x0c08, 0x516: 0x0c08, 0x517: 0x0c08, 0x518: 0x0c08, 0x519: 0x0c08, 0x51a: 0x0a08, 0x51b: 0x0a08, 0x51c: 0x0a08, 0x51d: 0x0a08, 0x51e: 0x0c08, 0x51f: 0x0a08, 0x520: 0x0a08, 0x521: 0x0a08, 0x522: 0x0a08, 0x523: 0x0a08, 0x524: 0x0a08, 0x525: 0x0a08, 0x526: 0x0a08, 0x527: 0x0a08, 0x528: 0x0c08, 0x529: 0x0a08, 0x52a: 0x0c08, 0x52b: 0x0a08, 0x52c: 0x0c08, 0x52d: 0x0a08, 0x52e: 0x0a08, 0x52f: 0x0c08, 0x530: 0x3308, 0x531: 0x3308, 0x532: 0x3308, 0x533: 0x3308, 0x534: 0x3308, 0x535: 0x3308, 0x536: 0x3308, 0x537: 0x3308, 0x538: 0x3308, 0x539: 0x3308, 0x53a: 0x3308, 0x53b: 0x3308, 0x53c: 0x3308, 0x53d: 0x3308, 0x53e: 0x3308, 0x53f: 0x3308, // Block 0x15, offset 0x540 0x540: 0x0c08, 0x541: 0x0a08, 0x542: 0x0a08, 0x543: 0x0a08, 0x544: 0x0a08, 0x545: 0x0a08, 0x546: 0x0c08, 0x547: 0x0c08, 0x548: 0x0a08, 0x549: 0x0c08, 0x54a: 0x0a08, 0x54b: 0x0a08, 0x54c: 0x0a08, 0x54d: 0x0a08, 0x54e: 0x0a08, 0x54f: 0x0a08, 0x550: 0x0a08, 0x551: 0x0a08, 0x552: 0x0a08, 0x553: 0x0a08, 0x554: 0x0c08, 0x555: 0x0a08, 0x556: 0x0808, 0x557: 0x0808, 0x558: 0x0808, 0x559: 0x3308, 0x55a: 0x3308, 0x55b: 0x3308, 0x55c: 0x0040, 0x55d: 0x0040, 0x55e: 0x0818, 0x55f: 0x0040, 0x560: 0x0a08, 0x561: 0x0808, 0x562: 0x0a08, 0x563: 0x0a08, 0x564: 0x0a08, 0x565: 0x0a08, 0x566: 0x0808, 0x567: 0x0c08, 0x568: 0x0a08, 0x569: 0x0c08, 0x56a: 0x0c08, 0x56b: 0x0040, 0x56c: 0x0040, 0x56d: 0x0040, 0x56e: 0x0040, 0x56f: 0x0040, 0x570: 0x0040, 0x571: 0x0040, 0x572: 0x0040, 0x573: 0x0040, 0x574: 0x0040, 0x575: 0x0040, 0x576: 0x0040, 0x577: 0x0040, 0x578: 0x0040, 0x579: 0x0040, 0x57a: 0x0040, 0x57b: 0x0040, 0x57c: 0x0040, 0x57d: 0x0040, 0x57e: 0x0040, 0x57f: 0x0040, // Block 0x16, offset 0x580 0x580: 0x3008, 0x581: 0x3308, 0x582: 0x3308, 0x583: 0x3308, 0x584: 0x3308, 0x585: 0x3308, 0x586: 0x3308, 0x587: 0x3308, 0x588: 0x3308, 0x589: 0x3008, 0x58a: 0x3008, 0x58b: 0x3008, 0x58c: 0x3008, 0x58d: 0x3b08, 0x58e: 0x3008, 0x58f: 0x3008, 0x590: 0x0008, 0x591: 0x3308, 0x592: 0x3308, 0x593: 0x3308, 0x594: 0x3308, 0x595: 0x3308, 0x596: 0x3308, 0x597: 0x3308, 0x598: 0x04c9, 0x599: 0x0501, 0x59a: 0x0539, 0x59b: 0x0571, 0x59c: 0x05a9, 0x59d: 0x05e1, 0x59e: 0x0619, 0x59f: 0x0651, 0x5a0: 0x0008, 0x5a1: 0x0008, 0x5a2: 0x3308, 0x5a3: 0x3308, 0x5a4: 0x0018, 0x5a5: 0x0018, 0x5a6: 0x0008, 0x5a7: 0x0008, 0x5a8: 0x0008, 0x5a9: 0x0008, 0x5aa: 0x0008, 0x5ab: 0x0008, 0x5ac: 0x0008, 0x5ad: 0x0008, 0x5ae: 0x0008, 0x5af: 0x0008, 0x5b0: 0x0018, 0x5b1: 0x0008, 0x5b2: 0x0008, 0x5b3: 0x0008, 0x5b4: 0x0008, 0x5b5: 0x0008, 0x5b6: 0x0008, 0x5b7: 0x0008, 0x5b8: 0x0008, 0x5b9: 0x0008, 0x5ba: 0x0008, 0x5bb: 0x0008, 0x5bc: 0x0008, 0x5bd: 0x0008, 0x5be: 0x0008, 0x5bf: 0x0008, // Block 0x17, offset 0x5c0 0x5c0: 0x0008, 0x5c1: 0x3308, 0x5c2: 0x3008, 0x5c3: 0x3008, 0x5c4: 0x0040, 0x5c5: 0x0008, 0x5c6: 0x0008, 0x5c7: 0x0008, 0x5c8: 0x0008, 0x5c9: 0x0008, 0x5ca: 0x0008, 0x5cb: 0x0008, 0x5cc: 0x0008, 0x5cd: 0x0040, 0x5ce: 0x0040, 0x5cf: 0x0008, 0x5d0: 0x0008, 0x5d1: 0x0040, 0x5d2: 0x0040, 0x5d3: 0x0008, 0x5d4: 0x0008, 0x5d5: 0x0008, 0x5d6: 0x0008, 0x5d7: 0x0008, 0x5d8: 0x0008, 0x5d9: 0x0008, 0x5da: 0x0008, 0x5db: 0x0008, 0x5dc: 0x0008, 0x5dd: 0x0008, 0x5de: 0x0008, 0x5df: 0x0008, 0x5e0: 0x0008, 0x5e1: 0x0008, 0x5e2: 0x0008, 0x5e3: 0x0008, 0x5e4: 0x0008, 0x5e5: 0x0008, 0x5e6: 0x0008, 0x5e7: 0x0008, 0x5e8: 0x0008, 0x5e9: 0x0040, 0x5ea: 0x0008, 0x5eb: 0x0008, 0x5ec: 0x0008, 0x5ed: 0x0008, 0x5ee: 0x0008, 0x5ef: 0x0008, 0x5f0: 0x0008, 0x5f1: 0x0040, 0x5f2: 0x0008, 0x5f3: 0x0040, 0x5f4: 0x0040, 0x5f5: 0x0040, 0x5f6: 0x0008, 0x5f7: 0x0008, 0x5f8: 0x0008, 0x5f9: 0x0008, 0x5fa: 0x0040, 0x5fb: 0x0040, 0x5fc: 0x3308, 0x5fd: 0x0008, 0x5fe: 0x3008, 0x5ff: 0x3008, // Block 0x18, offset 0x600 0x600: 0x3008, 0x601: 0x3308, 0x602: 0x3308, 0x603: 0x3308, 0x604: 0x3308, 0x605: 0x0040, 0x606: 0x0040, 0x607: 0x3008, 0x608: 0x3008, 0x609: 0x0040, 0x60a: 0x0040, 0x60b: 0x3008, 0x60c: 0x3008, 0x60d: 0x3b08, 0x60e: 0x0008, 0x60f: 0x0040, 0x610: 0x0040, 0x611: 0x0040, 0x612: 0x0040, 0x613: 0x0040, 0x614: 0x0040, 0x615: 0x0040, 0x616: 0x0040, 0x617: 0x3008, 0x618: 0x0040, 0x619: 0x0040, 0x61a: 0x0040, 0x61b: 0x0040, 0x61c: 0x0689, 0x61d: 0x06c1, 0x61e: 0x0040, 0x61f: 0x06f9, 0x620: 0x0008, 0x621: 0x0008, 0x622: 0x3308, 0x623: 0x3308, 0x624: 0x0040, 0x625: 0x0040, 0x626: 0x0008, 0x627: 0x0008, 0x628: 0x0008, 0x629: 0x0008, 0x62a: 0x0008, 0x62b: 0x0008, 0x62c: 0x0008, 0x62d: 0x0008, 0x62e: 0x0008, 0x62f: 0x0008, 0x630: 0x0008, 0x631: 0x0008, 0x632: 0x0018, 0x633: 0x0018, 0x634: 0x0018, 0x635: 0x0018, 0x636: 0x0018, 0x637: 0x0018, 0x638: 0x0018, 0x639: 0x0018, 0x63a: 0x0018, 0x63b: 0x0018, 0x63c: 0x0008, 0x63d: 0x0018, 0x63e: 0x0040, 0x63f: 0x0040, // Block 0x19, offset 0x640 0x640: 0x0040, 0x641: 0x3308, 0x642: 0x3308, 0x643: 0x3008, 0x644: 0x0040, 0x645: 0x0008, 0x646: 0x0008, 0x647: 0x0008, 0x648: 0x0008, 0x649: 0x0008, 0x64a: 0x0008, 0x64b: 0x0040, 0x64c: 0x0040, 0x64d: 0x0040, 0x64e: 0x0040, 0x64f: 0x0008, 0x650: 0x0008, 0x651: 0x0040, 0x652: 0x0040, 0x653: 0x0008, 0x654: 0x0008, 0x655: 0x0008, 0x656: 0x0008, 0x657: 0x0008, 0x658: 0x0008, 0x659: 0x0008, 0x65a: 0x0008, 0x65b: 0x0008, 0x65c: 0x0008, 0x65d: 0x0008, 0x65e: 0x0008, 0x65f: 0x0008, 0x660: 0x0008, 0x661: 0x0008, 0x662: 0x0008, 0x663: 0x0008, 0x664: 0x0008, 0x665: 0x0008, 0x666: 0x0008, 0x667: 0x0008, 0x668: 0x0008, 0x669: 0x0040, 0x66a: 0x0008, 0x66b: 0x0008, 0x66c: 0x0008, 0x66d: 0x0008, 0x66e: 0x0008, 0x66f: 0x0008, 0x670: 0x0008, 0x671: 0x0040, 0x672: 0x0008, 0x673: 0x0731, 0x674: 0x0040, 0x675: 0x0008, 0x676: 0x0769, 0x677: 0x0040, 0x678: 0x0008, 0x679: 0x0008, 0x67a: 0x0040, 0x67b: 0x0040, 0x67c: 0x3308, 0x67d: 0x0040, 0x67e: 0x3008, 0x67f: 0x3008, // Block 0x1a, offset 0x680 0x680: 0x3008, 0x681: 0x3308, 0x682: 0x3308, 0x683: 0x0040, 0x684: 0x0040, 0x685: 0x0040, 0x686: 0x0040, 0x687: 0x3308, 0x688: 0x3308, 0x689: 0x0040, 0x68a: 0x0040, 0x68b: 0x3308, 0x68c: 0x3308, 0x68d: 0x3b08, 0x68e: 0x0040, 0x68f: 0x0040, 0x690: 0x0040, 0x691: 0x3308, 0x692: 0x0040, 0x693: 0x0040, 0x694: 0x0040, 0x695: 0x0040, 0x696: 0x0040, 0x697: 0x0040, 0x698: 0x0040, 0x699: 0x07a1, 0x69a: 0x07d9, 0x69b: 0x0811, 0x69c: 0x0008, 0x69d: 0x0040, 0x69e: 0x0849, 0x69f: 0x0040, 0x6a0: 0x0040, 0x6a1: 0x0040, 0x6a2: 0x0040, 0x6a3: 0x0040, 0x6a4: 0x0040, 0x6a5: 0x0040, 0x6a6: 0x0008, 0x6a7: 0x0008, 0x6a8: 0x0008, 0x6a9: 0x0008, 0x6aa: 0x0008, 0x6ab: 0x0008, 0x6ac: 0x0008, 0x6ad: 0x0008, 0x6ae: 0x0008, 0x6af: 0x0008, 0x6b0: 0x3308, 0x6b1: 0x3308, 0x6b2: 0x0008, 0x6b3: 0x0008, 0x6b4: 0x0008, 0x6b5: 0x3308, 0x6b6: 0x0040, 0x6b7: 0x0040, 0x6b8: 0x0040, 0x6b9: 0x0040, 0x6ba: 0x0040, 0x6bb: 0x0040, 0x6bc: 0x0040, 0x6bd: 0x0040, 0x6be: 0x0040, 0x6bf: 0x0040, // Block 0x1b, offset 0x6c0 0x6c0: 0x0040, 0x6c1: 0x3308, 0x6c2: 0x3308, 0x6c3: 0x3008, 0x6c4: 0x0040, 0x6c5: 0x0008, 0x6c6: 0x0008, 0x6c7: 0x0008, 0x6c8: 0x0008, 0x6c9: 0x0008, 0x6ca: 0x0008, 0x6cb: 0x0008, 0x6cc: 0x0008, 0x6cd: 0x0008, 0x6ce: 0x0040, 0x6cf: 0x0008, 0x6d0: 0x0008, 0x6d1: 0x0008, 0x6d2: 0x0040, 0x6d3: 0x0008, 0x6d4: 0x0008, 0x6d5: 0x0008, 0x6d6: 0x0008, 0x6d7: 0x0008, 0x6d8: 0x0008, 0x6d9: 0x0008, 0x6da: 0x0008, 0x6db: 0x0008, 0x6dc: 0x0008, 0x6dd: 0x0008, 0x6de: 0x0008, 0x6df: 0x0008, 0x6e0: 0x0008, 0x6e1: 0x0008, 0x6e2: 0x0008, 0x6e3: 0x0008, 0x6e4: 0x0008, 0x6e5: 0x0008, 0x6e6: 0x0008, 0x6e7: 0x0008, 0x6e8: 0x0008, 0x6e9: 0x0040, 0x6ea: 0x0008, 0x6eb: 0x0008, 0x6ec: 0x0008, 0x6ed: 0x0008, 0x6ee: 0x0008, 0x6ef: 0x0008, 0x6f0: 0x0008, 0x6f1: 0x0040, 0x6f2: 0x0008, 0x6f3: 0x0008, 0x6f4: 0x0040, 0x6f5: 0x0008, 0x6f6: 0x0008, 0x6f7: 0x0008, 0x6f8: 0x0008, 0x6f9: 0x0008, 0x6fa: 0x0040, 0x6fb: 0x0040, 0x6fc: 0x3308, 0x6fd: 0x0008, 0x6fe: 0x3008, 0x6ff: 0x3008, // Block 0x1c, offset 0x700 0x700: 0x3008, 0x701: 0x3308, 0x702: 0x3308, 0x703: 0x3308, 0x704: 0x3308, 0x705: 0x3308, 0x706: 0x0040, 0x707: 0x3308, 0x708: 0x3308, 0x709: 0x3008, 0x70a: 0x0040, 0x70b: 0x3008, 0x70c: 0x3008, 0x70d: 0x3b08, 0x70e: 0x0040, 0x70f: 0x0040, 0x710: 0x0008, 0x711: 0x0040, 0x712: 0x0040, 0x713: 0x0040, 0x714: 0x0040, 0x715: 0x0040, 0x716: 0x0040, 0x717: 0x0040, 0x718: 0x0040, 0x719: 0x0040, 0x71a: 0x0040, 0x71b: 0x0040, 0x71c: 0x0040, 0x71d: 0x0040, 0x71e: 0x0040, 0x71f: 0x0040, 0x720: 0x0008, 0x721: 0x0008, 0x722: 0x3308, 0x723: 0x3308, 0x724: 0x0040, 0x725: 0x0040, 0x726: 0x0008, 0x727: 0x0008, 0x728: 0x0008, 0x729: 0x0008, 0x72a: 0x0008, 0x72b: 0x0008, 0x72c: 0x0008, 0x72d: 0x0008, 0x72e: 0x0008, 0x72f: 0x0008, 0x730: 0x0018, 0x731: 0x0018, 0x732: 0x0040, 0x733: 0x0040, 0x734: 0x0040, 0x735: 0x0040, 0x736: 0x0040, 0x737: 0x0040, 0x738: 0x0040, 0x739: 0x0008, 0x73a: 0x3308, 0x73b: 0x3308, 0x73c: 0x3308, 0x73d: 0x3308, 0x73e: 0x3308, 0x73f: 0x3308, // Block 0x1d, offset 0x740 0x740: 0x0040, 0x741: 0x3308, 0x742: 0x3008, 0x743: 0x3008, 0x744: 0x0040, 0x745: 0x0008, 0x746: 0x0008, 0x747: 0x0008, 0x748: 0x0008, 0x749: 0x0008, 0x74a: 0x0008, 0x74b: 0x0008, 0x74c: 0x0008, 0x74d: 0x0040, 0x74e: 0x0040, 0x74f: 0x0008, 0x750: 0x0008, 0x751: 0x0040, 0x752: 0x0040, 0x753: 0x0008, 0x754: 0x0008, 0x755: 0x0008, 0x756: 0x0008, 0x757: 0x0008, 0x758: 0x0008, 0x759: 0x0008, 0x75a: 0x0008, 0x75b: 0x0008, 0x75c: 0x0008, 0x75d: 0x0008, 0x75e: 0x0008, 0x75f: 0x0008, 0x760: 0x0008, 0x761: 0x0008, 0x762: 0x0008, 0x763: 0x0008, 0x764: 0x0008, 0x765: 0x0008, 0x766: 0x0008, 0x767: 0x0008, 0x768: 0x0008, 0x769: 0x0040, 0x76a: 0x0008, 0x76b: 0x0008, 0x76c: 0x0008, 0x76d: 0x0008, 0x76e: 0x0008, 0x76f: 0x0008, 0x770: 0x0008, 0x771: 0x0040, 0x772: 0x0008, 0x773: 0x0008, 0x774: 0x0040, 0x775: 0x0008, 0x776: 0x0008, 0x777: 0x0008, 0x778: 0x0008, 0x779: 0x0008, 0x77a: 0x0040, 0x77b: 0x0040, 0x77c: 0x3308, 0x77d: 0x0008, 0x77e: 0x3008, 0x77f: 0x3308, // Block 0x1e, offset 0x780 0x780: 0x3008, 0x781: 0x3308, 0x782: 0x3308, 0x783: 0x3308, 0x784: 0x3308, 0x785: 0x0040, 0x786: 0x0040, 0x787: 0x3008, 0x788: 0x3008, 0x789: 0x0040, 0x78a: 0x0040, 0x78b: 0x3008, 0x78c: 0x3008, 0x78d: 0x3b08, 0x78e: 0x0040, 0x78f: 0x0040, 0x790: 0x0040, 0x791: 0x0040, 0x792: 0x0040, 0x793: 0x0040, 0x794: 0x0040, 0x795: 0x0040, 0x796: 0x3308, 0x797: 0x3008, 0x798: 0x0040, 0x799: 0x0040, 0x79a: 0x0040, 0x79b: 0x0040, 0x79c: 0x0881, 0x79d: 0x08b9, 0x79e: 0x0040, 0x79f: 0x0008, 0x7a0: 0x0008, 0x7a1: 0x0008, 0x7a2: 0x3308, 0x7a3: 0x3308, 0x7a4: 0x0040, 0x7a5: 0x0040, 0x7a6: 0x0008, 0x7a7: 0x0008, 0x7a8: 0x0008, 0x7a9: 0x0008, 0x7aa: 0x0008, 0x7ab: 0x0008, 0x7ac: 0x0008, 0x7ad: 0x0008, 0x7ae: 0x0008, 0x7af: 0x0008, 0x7b0: 0x0018, 0x7b1: 0x0008, 0x7b2: 0x0018, 0x7b3: 0x0018, 0x7b4: 0x0018, 0x7b5: 0x0018, 0x7b6: 0x0018, 0x7b7: 0x0018, 0x7b8: 0x0040, 0x7b9: 0x0040, 0x7ba: 0x0040, 0x7bb: 0x0040, 0x7bc: 0x0040, 0x7bd: 0x0040, 0x7be: 0x0040, 0x7bf: 0x0040, // Block 0x1f, offset 0x7c0 0x7c0: 0x0040, 0x7c1: 0x0040, 0x7c2: 0x3308, 0x7c3: 0x0008, 0x7c4: 0x0040, 0x7c5: 0x0008, 0x7c6: 0x0008, 0x7c7: 0x0008, 0x7c8: 0x0008, 0x7c9: 0x0008, 0x7ca: 0x0008, 0x7cb: 0x0040, 0x7cc: 0x0040, 0x7cd: 0x0040, 0x7ce: 0x0008, 0x7cf: 0x0008, 0x7d0: 0x0008, 0x7d1: 0x0040, 0x7d2: 0x0008, 0x7d3: 0x0008, 0x7d4: 0x0008, 0x7d5: 0x0008, 0x7d6: 0x0040, 0x7d7: 0x0040, 0x7d8: 0x0040, 0x7d9: 0x0008, 0x7da: 0x0008, 0x7db: 0x0040, 0x7dc: 0x0008, 0x7dd: 0x0040, 0x7de: 0x0008, 0x7df: 0x0008, 0x7e0: 0x0040, 0x7e1: 0x0040, 0x7e2: 0x0040, 0x7e3: 0x0008, 0x7e4: 0x0008, 0x7e5: 0x0040, 0x7e6: 0x0040, 0x7e7: 0x0040, 0x7e8: 0x0008, 0x7e9: 0x0008, 0x7ea: 0x0008, 0x7eb: 0x0040, 0x7ec: 0x0040, 0x7ed: 0x0040, 0x7ee: 0x0008, 0x7ef: 0x0008, 0x7f0: 0x0008, 0x7f1: 0x0008, 0x7f2: 0x0008, 0x7f3: 0x0008, 0x7f4: 0x0008, 0x7f5: 0x0008, 0x7f6: 0x0008, 0x7f7: 0x0008, 0x7f8: 0x0008, 0x7f9: 0x0008, 0x7fa: 0x0040, 0x7fb: 0x0040, 0x7fc: 0x0040, 0x7fd: 0x0040, 0x7fe: 0x3008, 0x7ff: 0x3008, // Block 0x20, offset 0x800 0x800: 0x3308, 0x801: 0x3008, 0x802: 0x3008, 0x803: 0x3008, 0x804: 0x3008, 0x805: 0x0040, 0x806: 0x3308, 0x807: 0x3308, 0x808: 0x3308, 0x809: 0x0040, 0x80a: 0x3308, 0x80b: 0x3308, 0x80c: 0x3308, 0x80d: 0x3b08, 0x80e: 0x0040, 0x80f: 0x0040, 0x810: 0x0040, 0x811: 0x0040, 0x812: 0x0040, 0x813: 0x0040, 0x814: 0x0040, 0x815: 0x3308, 0x816: 0x3308, 0x817: 0x0040, 0x818: 0x0008, 0x819: 0x0008, 0x81a: 0x0008, 0x81b: 0x0040, 0x81c: 0x0040, 0x81d: 0x0040, 0x81e: 0x0040, 0x81f: 0x0040, 0x820: 0x0008, 0x821: 0x0008, 0x822: 0x3308, 0x823: 0x3308, 0x824: 0x0040, 0x825: 0x0040, 0x826: 0x0008, 0x827: 0x0008, 0x828: 0x0008, 0x829: 0x0008, 0x82a: 0x0008, 0x82b: 0x0008, 0x82c: 0x0008, 0x82d: 0x0008, 0x82e: 0x0008, 0x82f: 0x0008, 0x830: 0x0040, 0x831: 0x0040, 0x832: 0x0040, 0x833: 0x0040, 0x834: 0x0040, 0x835: 0x0040, 0x836: 0x0040, 0x837: 0x0040, 0x838: 0x0018, 0x839: 0x0018, 0x83a: 0x0018, 0x83b: 0x0018, 0x83c: 0x0018, 0x83d: 0x0018, 0x83e: 0x0018, 0x83f: 0x0018, // Block 0x21, offset 0x840 0x840: 0x0008, 0x841: 0x3308, 0x842: 0x3008, 0x843: 0x3008, 0x844: 0x0040, 0x845: 0x0008, 0x846: 0x0008, 0x847: 0x0008, 0x848: 0x0008, 0x849: 0x0008, 0x84a: 0x0008, 0x84b: 0x0008, 0x84c: 0x0008, 0x84d: 0x0040, 0x84e: 0x0008, 0x84f: 0x0008, 0x850: 0x0008, 0x851: 0x0040, 0x852: 0x0008, 0x853: 0x0008, 0x854: 0x0008, 0x855: 0x0008, 0x856: 0x0008, 0x857: 0x0008, 0x858: 0x0008, 0x859: 0x0008, 0x85a: 0x0008, 0x85b: 0x0008, 0x85c: 0x0008, 0x85d: 0x0008, 0x85e: 0x0008, 0x85f: 0x0008, 0x860: 0x0008, 0x861: 0x0008, 0x862: 0x0008, 0x863: 0x0008, 0x864: 0x0008, 0x865: 0x0008, 0x866: 0x0008, 0x867: 0x0008, 0x868: 0x0008, 0x869: 0x0040, 0x86a: 0x0008, 0x86b: 0x0008, 0x86c: 0x0008, 0x86d: 0x0008, 0x86e: 0x0008, 0x86f: 0x0008, 0x870: 0x0008, 0x871: 0x0008, 0x872: 0x0008, 0x873: 0x0008, 0x874: 0x0040, 0x875: 0x0008, 0x876: 0x0008, 0x877: 0x0008, 0x878: 0x0008, 0x879: 0x0008, 0x87a: 0x0040, 0x87b: 0x0040, 0x87c: 0x3308, 0x87d: 0x0008, 0x87e: 0x3008, 0x87f: 0x3308, // Block 0x22, offset 0x880 0x880: 0x3008, 0x881: 0x3008, 0x882: 0x3008, 0x883: 0x3008, 0x884: 0x3008, 0x885: 0x0040, 0x886: 0x3308, 0x887: 0x3008, 0x888: 0x3008, 0x889: 0x0040, 0x88a: 0x3008, 0x88b: 0x3008, 0x88c: 0x3308, 0x88d: 0x3b08, 0x88e: 0x0040, 0x88f: 0x0040, 0x890: 0x0040, 0x891: 0x0040, 0x892: 0x0040, 0x893: 0x0040, 0x894: 0x0040, 0x895: 0x3008, 0x896: 0x3008, 0x897: 0x0040, 0x898: 0x0040, 0x899: 0x0040, 0x89a: 0x0040, 0x89b: 0x0040, 0x89c: 0x0040, 0x89d: 0x0040, 0x89e: 0x0008, 0x89f: 0x0040, 0x8a0: 0x0008, 0x8a1: 0x0008, 0x8a2: 0x3308, 0x8a3: 0x3308, 0x8a4: 0x0040, 0x8a5: 0x0040, 0x8a6: 0x0008, 0x8a7: 0x0008, 0x8a8: 0x0008, 0x8a9: 0x0008, 0x8aa: 0x0008, 0x8ab: 0x0008, 0x8ac: 0x0008, 0x8ad: 0x0008, 0x8ae: 0x0008, 0x8af: 0x0008, 0x8b0: 0x0040, 0x8b1: 0x0008, 0x8b2: 0x0008, 0x8b3: 0x0040, 0x8b4: 0x0040, 0x8b5: 0x0040, 0x8b6: 0x0040, 0x8b7: 0x0040, 0x8b8: 0x0040, 0x8b9: 0x0040, 0x8ba: 0x0040, 0x8bb: 0x0040, 0x8bc: 0x0040, 0x8bd: 0x0040, 0x8be: 0x0040, 0x8bf: 0x0040, // Block 0x23, offset 0x8c0 0x8c0: 0x3008, 0x8c1: 0x3308, 0x8c2: 0x3308, 0x8c3: 0x3308, 0x8c4: 0x3308, 0x8c5: 0x0040, 0x8c6: 0x3008, 0x8c7: 0x3008, 0x8c8: 0x3008, 0x8c9: 0x0040, 0x8ca: 0x3008, 0x8cb: 0x3008, 0x8cc: 0x3008, 0x8cd: 0x3b08, 0x8ce: 0x0008, 0x8cf: 0x0018, 0x8d0: 0x0040, 0x8d1: 0x0040, 0x8d2: 0x0040, 0x8d3: 0x0040, 0x8d4: 0x0008, 0x8d5: 0x0008, 0x8d6: 0x0008, 0x8d7: 0x3008, 0x8d8: 0x0018, 0x8d9: 0x0018, 0x8da: 0x0018, 0x8db: 0x0018, 0x8dc: 0x0018, 0x8dd: 0x0018, 0x8de: 0x0018, 0x8df: 0x0008, 0x8e0: 0x0008, 0x8e1: 0x0008, 0x8e2: 0x3308, 0x8e3: 0x3308, 0x8e4: 0x0040, 0x8e5: 0x0040, 0x8e6: 0x0008, 0x8e7: 0x0008, 0x8e8: 0x0008, 0x8e9: 0x0008, 0x8ea: 0x0008, 0x8eb: 0x0008, 0x8ec: 0x0008, 0x8ed: 0x0008, 0x8ee: 0x0008, 0x8ef: 0x0008, 0x8f0: 0x0018, 0x8f1: 0x0018, 0x8f2: 0x0018, 0x8f3: 0x0018, 0x8f4: 0x0018, 0x8f5: 0x0018, 0x8f6: 0x0018, 0x8f7: 0x0018, 0x8f8: 0x0018, 0x8f9: 0x0018, 0x8fa: 0x0008, 0x8fb: 0x0008, 0x8fc: 0x0008, 0x8fd: 0x0008, 0x8fe: 0x0008, 0x8ff: 0x0008, // Block 0x24, offset 0x900 0x900: 0x0040, 0x901: 0x0008, 0x902: 0x0008, 0x903: 0x0040, 0x904: 0x0008, 0x905: 0x0040, 0x906: 0x0040, 0x907: 0x0008, 0x908: 0x0008, 0x909: 0x0040, 0x90a: 0x0008, 0x90b: 0x0040, 0x90c: 0x0040, 0x90d: 0x0008, 0x90e: 0x0040, 0x90f: 0x0040, 0x910: 0x0040, 0x911: 0x0040, 0x912: 0x0040, 0x913: 0x0040, 0x914: 0x0008, 0x915: 0x0008, 0x916: 0x0008, 0x917: 0x0008, 0x918: 0x0040, 0x919: 0x0008, 0x91a: 0x0008, 0x91b: 0x0008, 0x91c: 0x0008, 0x91d: 0x0008, 0x91e: 0x0008, 0x91f: 0x0008, 0x920: 0x0040, 0x921: 0x0008, 0x922: 0x0008, 0x923: 0x0008, 0x924: 0x0040, 0x925: 0x0008, 0x926: 0x0040, 0x927: 0x0008, 0x928: 0x0040, 0x929: 0x0040, 0x92a: 0x0008, 0x92b: 0x0008, 0x92c: 0x0040, 0x92d: 0x0008, 0x92e: 0x0008, 0x92f: 0x0008, 0x930: 0x0008, 0x931: 0x3308, 0x932: 0x0008, 0x933: 0x0929, 0x934: 0x3308, 0x935: 0x3308, 0x936: 0x3308, 0x937: 0x3308, 0x938: 0x3308, 0x939: 0x3308, 0x93a: 0x0040, 0x93b: 0x3308, 0x93c: 0x3308, 0x93d: 0x0008, 0x93e: 0x0040, 0x93f: 0x0040, // Block 0x25, offset 0x940 0x940: 0x0008, 0x941: 0x0008, 0x942: 0x0008, 0x943: 0x09d1, 0x944: 0x0008, 0x945: 0x0008, 0x946: 0x0008, 0x947: 0x0008, 0x948: 0x0040, 0x949: 0x0008, 0x94a: 0x0008, 0x94b: 0x0008, 0x94c: 0x0008, 0x94d: 0x0a09, 0x94e: 0x0008, 0x94f: 0x0008, 0x950: 0x0008, 0x951: 0x0008, 0x952: 0x0a41, 0x953: 0x0008, 0x954: 0x0008, 0x955: 0x0008, 0x956: 0x0008, 0x957: 0x0a79, 0x958: 0x0008, 0x959: 0x0008, 0x95a: 0x0008, 0x95b: 0x0008, 0x95c: 0x0ab1, 0x95d: 0x0008, 0x95e: 0x0008, 0x95f: 0x0008, 0x960: 0x0008, 0x961: 0x0008, 0x962: 0x0008, 0x963: 0x0008, 0x964: 0x0008, 0x965: 0x0008, 0x966: 0x0008, 0x967: 0x0008, 0x968: 0x0008, 0x969: 0x0ae9, 0x96a: 0x0008, 0x96b: 0x0008, 0x96c: 0x0008, 0x96d: 0x0040, 0x96e: 0x0040, 0x96f: 0x0040, 0x970: 0x0040, 0x971: 0x3308, 0x972: 0x3308, 0x973: 0x0b21, 0x974: 0x3308, 0x975: 0x0b59, 0x976: 0x0b91, 0x977: 0x0bc9, 0x978: 0x0c19, 0x979: 0x0c51, 0x97a: 0x3308, 0x97b: 0x3308, 0x97c: 0x3308, 0x97d: 0x3308, 0x97e: 0x3308, 0x97f: 0x3008, // Block 0x26, offset 0x980 0x980: 0x3308, 0x981: 0x0ca1, 0x982: 0x3308, 0x983: 0x3308, 0x984: 0x3b08, 0x985: 0x0018, 0x986: 0x3308, 0x987: 0x3308, 0x988: 0x0008, 0x989: 0x0008, 0x98a: 0x0008, 0x98b: 0x0008, 0x98c: 0x0008, 0x98d: 0x3308, 0x98e: 0x3308, 0x98f: 0x3308, 0x990: 0x3308, 0x991: 0x3308, 0x992: 0x3308, 0x993: 0x0cd9, 0x994: 0x3308, 0x995: 0x3308, 0x996: 0x3308, 0x997: 0x3308, 0x998: 0x0040, 0x999: 0x3308, 0x99a: 0x3308, 0x99b: 0x3308, 0x99c: 0x3308, 0x99d: 0x0d11, 0x99e: 0x3308, 0x99f: 0x3308, 0x9a0: 0x3308, 0x9a1: 0x3308, 0x9a2: 0x0d49, 0x9a3: 0x3308, 0x9a4: 0x3308, 0x9a5: 0x3308, 0x9a6: 0x3308, 0x9a7: 0x0d81, 0x9a8: 0x3308, 0x9a9: 0x3308, 0x9aa: 0x3308, 0x9ab: 0x3308, 0x9ac: 0x0db9, 0x9ad: 0x3308, 0x9ae: 0x3308, 0x9af: 0x3308, 0x9b0: 0x3308, 0x9b1: 0x3308, 0x9b2: 0x3308, 0x9b3: 0x3308, 0x9b4: 0x3308, 0x9b5: 0x3308, 0x9b6: 0x3308, 0x9b7: 0x3308, 0x9b8: 0x3308, 0x9b9: 0x0df1, 0x9ba: 0x3308, 0x9bb: 0x3308, 0x9bc: 0x3308, 0x9bd: 0x0040, 0x9be: 0x0018, 0x9bf: 0x0018, // Block 0x27, offset 0x9c0 0x9c0: 0x0008, 0x9c1: 0x0008, 0x9c2: 0x0008, 0x9c3: 0x0008, 0x9c4: 0x0008, 0x9c5: 0x0008, 0x9c6: 0x0008, 0x9c7: 0x0008, 0x9c8: 0x0008, 0x9c9: 0x0008, 0x9ca: 0x0008, 0x9cb: 0x0008, 0x9cc: 0x0008, 0x9cd: 0x0008, 0x9ce: 0x0008, 0x9cf: 0x0008, 0x9d0: 0x0008, 0x9d1: 0x0008, 0x9d2: 0x0008, 0x9d3: 0x0008, 0x9d4: 0x0008, 0x9d5: 0x0008, 0x9d6: 0x0008, 0x9d7: 0x0008, 0x9d8: 0x0008, 0x9d9: 0x0008, 0x9da: 0x0008, 0x9db: 0x0008, 0x9dc: 0x0008, 0x9dd: 0x0008, 0x9de: 0x0008, 0x9df: 0x0008, 0x9e0: 0x0008, 0x9e1: 0x0008, 0x9e2: 0x0008, 0x9e3: 0x0008, 0x9e4: 0x0008, 0x9e5: 0x0008, 0x9e6: 0x0008, 0x9e7: 0x0008, 0x9e8: 0x0008, 0x9e9: 0x0008, 0x9ea: 0x0008, 0x9eb: 0x0008, 0x9ec: 0x0039, 0x9ed: 0x0ed1, 0x9ee: 0x0ee9, 0x9ef: 0x0008, 0x9f0: 0x0ef9, 0x9f1: 0x0f09, 0x9f2: 0x0f19, 0x9f3: 0x0f31, 0x9f4: 0x0249, 0x9f5: 0x0f41, 0x9f6: 0x0259, 0x9f7: 0x0f51, 0x9f8: 0x0359, 0x9f9: 0x0f61, 0x9fa: 0x0f71, 0x9fb: 0x0008, 0x9fc: 0x00d9, 0x9fd: 0x0f81, 0x9fe: 0x0f99, 0x9ff: 0x0269, // Block 0x28, offset 0xa00 0xa00: 0x0fa9, 0xa01: 0x0fb9, 0xa02: 0x0279, 0xa03: 0x0039, 0xa04: 0x0fc9, 0xa05: 0x0fe1, 0xa06: 0x059d, 0xa07: 0x0ee9, 0xa08: 0x0ef9, 0xa09: 0x0f09, 0xa0a: 0x0ff9, 0xa0b: 0x1011, 0xa0c: 0x1029, 0xa0d: 0x0f31, 0xa0e: 0x0008, 0xa0f: 0x0f51, 0xa10: 0x0f61, 0xa11: 0x1041, 0xa12: 0x00d9, 0xa13: 0x1059, 0xa14: 0x05b5, 0xa15: 0x05b5, 0xa16: 0x0f99, 0xa17: 0x0fa9, 0xa18: 0x0fb9, 0xa19: 0x059d, 0xa1a: 0x1071, 0xa1b: 0x1089, 0xa1c: 0x05cd, 0xa1d: 0x1099, 0xa1e: 0x10b1, 0xa1f: 0x10c9, 0xa20: 0x10e1, 0xa21: 0x10f9, 0xa22: 0x0f41, 0xa23: 0x0269, 0xa24: 0x0fb9, 0xa25: 0x1089, 0xa26: 0x1099, 0xa27: 0x10b1, 0xa28: 0x1111, 0xa29: 0x10e1, 0xa2a: 0x10f9, 0xa2b: 0x0008, 0xa2c: 0x0008, 0xa2d: 0x0008, 0xa2e: 0x0008, 0xa2f: 0x0008, 0xa30: 0x0008, 0xa31: 0x0008, 0xa32: 0x0008, 0xa33: 0x0008, 0xa34: 0x0008, 0xa35: 0x0008, 0xa36: 0x0008, 0xa37: 0x0008, 0xa38: 0x1129, 0xa39: 0x0008, 0xa3a: 0x0008, 0xa3b: 0x0008, 0xa3c: 0x0008, 0xa3d: 0x0008, 0xa3e: 0x0008, 0xa3f: 0x0008, // Block 0x29, offset 0xa40 0xa40: 0x0008, 0xa41: 0x0008, 0xa42: 0x0008, 0xa43: 0x0008, 0xa44: 0x0008, 0xa45: 0x0008, 0xa46: 0x0008, 0xa47: 0x0008, 0xa48: 0x0008, 0xa49: 0x0008, 0xa4a: 0x0008, 0xa4b: 0x0008, 0xa4c: 0x0008, 0xa4d: 0x0008, 0xa4e: 0x0008, 0xa4f: 0x0008, 0xa50: 0x0008, 0xa51: 0x0008, 0xa52: 0x0008, 0xa53: 0x0008, 0xa54: 0x0008, 0xa55: 0x0008, 0xa56: 0x0008, 0xa57: 0x0008, 0xa58: 0x0008, 0xa59: 0x0008, 0xa5a: 0x0008, 0xa5b: 0x1141, 0xa5c: 0x1159, 0xa5d: 0x1169, 0xa5e: 0x1181, 0xa5f: 0x1029, 0xa60: 0x1199, 0xa61: 0x11a9, 0xa62: 0x11c1, 0xa63: 0x11d9, 0xa64: 0x11f1, 0xa65: 0x1209, 0xa66: 0x1221, 0xa67: 0x05e5, 0xa68: 0x1239, 0xa69: 0x1251, 0xa6a: 0xe17d, 0xa6b: 0x1269, 0xa6c: 0x1281, 0xa6d: 0x1299, 0xa6e: 0x12b1, 0xa6f: 0x12c9, 0xa70: 0x12e1, 0xa71: 0x12f9, 0xa72: 0x1311, 0xa73: 0x1329, 0xa74: 0x1341, 0xa75: 0x1359, 0xa76: 0x1371, 0xa77: 0x1389, 0xa78: 0x05fd, 0xa79: 0x13a1, 0xa7a: 0x13b9, 0xa7b: 0x13d1, 0xa7c: 0x13e1, 0xa7d: 0x13f9, 0xa7e: 0x1411, 0xa7f: 0x1429, // Block 0x2a, offset 0xa80 0xa80: 0xe00d, 0xa81: 0x0008, 0xa82: 0xe00d, 0xa83: 0x0008, 0xa84: 0xe00d, 0xa85: 0x0008, 0xa86: 0xe00d, 0xa87: 0x0008, 0xa88: 0xe00d, 0xa89: 0x0008, 0xa8a: 0xe00d, 0xa8b: 0x0008, 0xa8c: 0xe00d, 0xa8d: 0x0008, 0xa8e: 0xe00d, 0xa8f: 0x0008, 0xa90: 0xe00d, 0xa91: 0x0008, 0xa92: 0xe00d, 0xa93: 0x0008, 0xa94: 0xe00d, 0xa95: 0x0008, 0xa96: 0xe00d, 0xa97: 0x0008, 0xa98: 0xe00d, 0xa99: 0x0008, 0xa9a: 0xe00d, 0xa9b: 0x0008, 0xa9c: 0xe00d, 0xa9d: 0x0008, 0xa9e: 0xe00d, 0xa9f: 0x0008, 0xaa0: 0xe00d, 0xaa1: 0x0008, 0xaa2: 0xe00d, 0xaa3: 0x0008, 0xaa4: 0xe00d, 0xaa5: 0x0008, 0xaa6: 0xe00d, 0xaa7: 0x0008, 0xaa8: 0xe00d, 0xaa9: 0x0008, 0xaaa: 0xe00d, 0xaab: 0x0008, 0xaac: 0xe00d, 0xaad: 0x0008, 0xaae: 0xe00d, 0xaaf: 0x0008, 0xab0: 0xe00d, 0xab1: 0x0008, 0xab2: 0xe00d, 0xab3: 0x0008, 0xab4: 0xe00d, 0xab5: 0x0008, 0xab6: 0xe00d, 0xab7: 0x0008, 0xab8: 0xe00d, 0xab9: 0x0008, 0xaba: 0xe00d, 0xabb: 0x0008, 0xabc: 0xe00d, 0xabd: 0x0008, 0xabe: 0xe00d, 0xabf: 0x0008, // Block 0x2b, offset 0xac0 0xac0: 0xe00d, 0xac1: 0x0008, 0xac2: 0xe00d, 0xac3: 0x0008, 0xac4: 0xe00d, 0xac5: 0x0008, 0xac6: 0xe00d, 0xac7: 0x0008, 0xac8: 0xe00d, 0xac9: 0x0008, 0xaca: 0xe00d, 0xacb: 0x0008, 0xacc: 0xe00d, 0xacd: 0x0008, 0xace: 0xe00d, 0xacf: 0x0008, 0xad0: 0xe00d, 0xad1: 0x0008, 0xad2: 0xe00d, 0xad3: 0x0008, 0xad4: 0xe00d, 0xad5: 0x0008, 0xad6: 0x0008, 0xad7: 0x0008, 0xad8: 0x0008, 0xad9: 0x0008, 0xada: 0x0615, 0xadb: 0x0635, 0xadc: 0x0008, 0xadd: 0x0008, 0xade: 0x1441, 0xadf: 0x0008, 0xae0: 0xe00d, 0xae1: 0x0008, 0xae2: 0xe00d, 0xae3: 0x0008, 0xae4: 0xe00d, 0xae5: 0x0008, 0xae6: 0xe00d, 0xae7: 0x0008, 0xae8: 0xe00d, 0xae9: 0x0008, 0xaea: 0xe00d, 0xaeb: 0x0008, 0xaec: 0xe00d, 0xaed: 0x0008, 0xaee: 0xe00d, 0xaef: 0x0008, 0xaf0: 0xe00d, 0xaf1: 0x0008, 0xaf2: 0xe00d, 0xaf3: 0x0008, 0xaf4: 0xe00d, 0xaf5: 0x0008, 0xaf6: 0xe00d, 0xaf7: 0x0008, 0xaf8: 0xe00d, 0xaf9: 0x0008, 0xafa: 0xe00d, 0xafb: 0x0008, 0xafc: 0xe00d, 0xafd: 0x0008, 0xafe: 0xe00d, 0xaff: 0x0008, // Block 0x2c, offset 0xb00 0xb00: 0x0008, 0xb01: 0x0008, 0xb02: 0x0008, 0xb03: 0x0008, 0xb04: 0x0008, 0xb05: 0x0008, 0xb06: 0x0040, 0xb07: 0x0040, 0xb08: 0xe045, 0xb09: 0xe045, 0xb0a: 0xe045, 0xb0b: 0xe045, 0xb0c: 0xe045, 0xb0d: 0xe045, 0xb0e: 0x0040, 0xb0f: 0x0040, 0xb10: 0x0008, 0xb11: 0x0008, 0xb12: 0x0008, 0xb13: 0x0008, 0xb14: 0x0008, 0xb15: 0x0008, 0xb16: 0x0008, 0xb17: 0x0008, 0xb18: 0x0040, 0xb19: 0xe045, 0xb1a: 0x0040, 0xb1b: 0xe045, 0xb1c: 0x0040, 0xb1d: 0xe045, 0xb1e: 0x0040, 0xb1f: 0xe045, 0xb20: 0x0008, 0xb21: 0x0008, 0xb22: 0x0008, 0xb23: 0x0008, 0xb24: 0x0008, 0xb25: 0x0008, 0xb26: 0x0008, 0xb27: 0x0008, 0xb28: 0xe045, 0xb29: 0xe045, 0xb2a: 0xe045, 0xb2b: 0xe045, 0xb2c: 0xe045, 0xb2d: 0xe045, 0xb2e: 0xe045, 0xb2f: 0xe045, 0xb30: 0x0008, 0xb31: 0x1459, 0xb32: 0x0008, 0xb33: 0x1471, 0xb34: 0x0008, 0xb35: 0x1489, 0xb36: 0x0008, 0xb37: 0x14a1, 0xb38: 0x0008, 0xb39: 0x14b9, 0xb3a: 0x0008, 0xb3b: 0x14d1, 0xb3c: 0x0008, 0xb3d: 0x14e9, 0xb3e: 0x0040, 0xb3f: 0x0040, // Block 0x2d, offset 0xb40 0xb40: 0x1501, 0xb41: 0x1531, 0xb42: 0x1561, 0xb43: 0x1591, 0xb44: 0x15c1, 0xb45: 0x15f1, 0xb46: 0x1621, 0xb47: 0x1651, 0xb48: 0x1501, 0xb49: 0x1531, 0xb4a: 0x1561, 0xb4b: 0x1591, 0xb4c: 0x15c1, 0xb4d: 0x15f1, 0xb4e: 0x1621, 0xb4f: 0x1651, 0xb50: 0x1681, 0xb51: 0x16b1, 0xb52: 0x16e1, 0xb53: 0x1711, 0xb54: 0x1741, 0xb55: 0x1771, 0xb56: 0x17a1, 0xb57: 0x17d1, 0xb58: 0x1681, 0xb59: 0x16b1, 0xb5a: 0x16e1, 0xb5b: 0x1711, 0xb5c: 0x1741, 0xb5d: 0x1771, 0xb5e: 0x17a1, 0xb5f: 0x17d1, 0xb60: 0x1801, 0xb61: 0x1831, 0xb62: 0x1861, 0xb63: 0x1891, 0xb64: 0x18c1, 0xb65: 0x18f1, 0xb66: 0x1921, 0xb67: 0x1951, 0xb68: 0x1801, 0xb69: 0x1831, 0xb6a: 0x1861, 0xb6b: 0x1891, 0xb6c: 0x18c1, 0xb6d: 0x18f1, 0xb6e: 0x1921, 0xb6f: 0x1951, 0xb70: 0x0008, 0xb71: 0x0008, 0xb72: 0x1981, 0xb73: 0x19b1, 0xb74: 0x19d9, 0xb75: 0x0040, 0xb76: 0x0008, 0xb77: 0x1a01, 0xb78: 0xe045, 0xb79: 0xe045, 0xb7a: 0x064d, 0xb7b: 0x1459, 0xb7c: 0x19b1, 0xb7d: 0x0666, 0xb7e: 0x1a31, 0xb7f: 0x0686, // Block 0x2e, offset 0xb80 0xb80: 0x06a6, 0xb81: 0x1a4a, 0xb82: 0x1a79, 0xb83: 0x1aa9, 0xb84: 0x1ad1, 0xb85: 0x0040, 0xb86: 0x0008, 0xb87: 0x1af9, 0xb88: 0x06c5, 0xb89: 0x1471, 0xb8a: 0x06dd, 0xb8b: 0x1489, 0xb8c: 0x1aa9, 0xb8d: 0x1b2a, 0xb8e: 0x1b5a, 0xb8f: 0x1b8a, 0xb90: 0x0008, 0xb91: 0x0008, 0xb92: 0x0008, 0xb93: 0x1bb9, 0xb94: 0x0040, 0xb95: 0x0040, 0xb96: 0x0008, 0xb97: 0x0008, 0xb98: 0xe045, 0xb99: 0xe045, 0xb9a: 0x06f5, 0xb9b: 0x14a1, 0xb9c: 0x0040, 0xb9d: 0x1bd2, 0xb9e: 0x1c02, 0xb9f: 0x1c32, 0xba0: 0x0008, 0xba1: 0x0008, 0xba2: 0x0008, 0xba3: 0x1c61, 0xba4: 0x0008, 0xba5: 0x0008, 0xba6: 0x0008, 0xba7: 0x0008, 0xba8: 0xe045, 0xba9: 0xe045, 0xbaa: 0x070d, 0xbab: 0x14d1, 0xbac: 0xe04d, 0xbad: 0x1c7a, 0xbae: 0x03d2, 0xbaf: 0x1caa, 0xbb0: 0x0040, 0xbb1: 0x0040, 0xbb2: 0x1cb9, 0xbb3: 0x1ce9, 0xbb4: 0x1d11, 0xbb5: 0x0040, 0xbb6: 0x0008, 0xbb7: 0x1d39, 0xbb8: 0x0725, 0xbb9: 0x14b9, 0xbba: 0x0515, 0xbbb: 0x14e9, 0xbbc: 0x1ce9, 0xbbd: 0x073e, 0xbbe: 0x075e, 0xbbf: 0x0040, // Block 0x2f, offset 0xbc0 0xbc0: 0x000a, 0xbc1: 0x000a, 0xbc2: 0x000a, 0xbc3: 0x000a, 0xbc4: 0x000a, 0xbc5: 0x000a, 0xbc6: 0x000a, 0xbc7: 0x000a, 0xbc8: 0x000a, 0xbc9: 0x000a, 0xbca: 0x000a, 0xbcb: 0x03c0, 0xbcc: 0x0003, 0xbcd: 0x0003, 0xbce: 0x0340, 0xbcf: 0x0b40, 0xbd0: 0x0018, 0xbd1: 0xe00d, 0xbd2: 0x0018, 0xbd3: 0x0018, 0xbd4: 0x0018, 0xbd5: 0x0018, 0xbd6: 0x0018, 0xbd7: 0x077e, 0xbd8: 0x0018, 0xbd9: 0x0018, 0xbda: 0x0018, 0xbdb: 0x0018, 0xbdc: 0x0018, 0xbdd: 0x0018, 0xbde: 0x0018, 0xbdf: 0x0018, 0xbe0: 0x0018, 0xbe1: 0x0018, 0xbe2: 0x0018, 0xbe3: 0x0018, 0xbe4: 0x0040, 0xbe5: 0x0040, 0xbe6: 0x0040, 0xbe7: 0x0018, 0xbe8: 0x0040, 0xbe9: 0x0040, 0xbea: 0x0340, 0xbeb: 0x0340, 0xbec: 0x0340, 0xbed: 0x0340, 0xbee: 0x0340, 0xbef: 0x000a, 0xbf0: 0x0018, 0xbf1: 0x0018, 0xbf2: 0x0018, 0xbf3: 0x1d69, 0xbf4: 0x1da1, 0xbf5: 0x0018, 0xbf6: 0x1df1, 0xbf7: 0x1e29, 0xbf8: 0x0018, 0xbf9: 0x0018, 0xbfa: 0x0018, 0xbfb: 0x0018, 0xbfc: 0x1e7a, 0xbfd: 0x0018, 0xbfe: 0x079e, 0xbff: 0x0018, // Block 0x30, offset 0xc00 0xc00: 0x0018, 0xc01: 0x0018, 0xc02: 0x0018, 0xc03: 0x0018, 0xc04: 0x0018, 0xc05: 0x0018, 0xc06: 0x0018, 0xc07: 0x1e92, 0xc08: 0x1eaa, 0xc09: 0x1ec2, 0xc0a: 0x0018, 0xc0b: 0x0018, 0xc0c: 0x0018, 0xc0d: 0x0018, 0xc0e: 0x0018, 0xc0f: 0x0018, 0xc10: 0x0018, 0xc11: 0x0018, 0xc12: 0x0018, 0xc13: 0x0018, 0xc14: 0x0018, 0xc15: 0x0018, 0xc16: 0x0018, 0xc17: 0x1ed9, 0xc18: 0x0018, 0xc19: 0x0018, 0xc1a: 0x0018, 0xc1b: 0x0018, 0xc1c: 0x0018, 0xc1d: 0x0018, 0xc1e: 0x0018, 0xc1f: 0x000a, 0xc20: 0x03c0, 0xc21: 0x0340, 0xc22: 0x0340, 0xc23: 0x0340, 0xc24: 0x03c0, 0xc25: 0x0040, 0xc26: 0x0040, 0xc27: 0x0040, 0xc28: 0x0040, 0xc29: 0x0040, 0xc2a: 0x0340, 0xc2b: 0x0340, 0xc2c: 0x0340, 0xc2d: 0x0340, 0xc2e: 0x0340, 0xc2f: 0x0340, 0xc30: 0x1f41, 0xc31: 0x0f41, 0xc32: 0x0040, 0xc33: 0x0040, 0xc34: 0x1f51, 0xc35: 0x1f61, 0xc36: 0x1f71, 0xc37: 0x1f81, 0xc38: 0x1f91, 0xc39: 0x1fa1, 0xc3a: 0x1fb2, 0xc3b: 0x07bd, 0xc3c: 0x1fc2, 0xc3d: 0x1fd2, 0xc3e: 0x1fe2, 0xc3f: 0x0f71, // Block 0x31, offset 0xc40 0xc40: 0x1f41, 0xc41: 0x00c9, 0xc42: 0x0069, 0xc43: 0x0079, 0xc44: 0x1f51, 0xc45: 0x1f61, 0xc46: 0x1f71, 0xc47: 0x1f81, 0xc48: 0x1f91, 0xc49: 0x1fa1, 0xc4a: 0x1fb2, 0xc4b: 0x07d5, 0xc4c: 0x1fc2, 0xc4d: 0x1fd2, 0xc4e: 0x1fe2, 0xc4f: 0x0040, 0xc50: 0x0039, 0xc51: 0x0f09, 0xc52: 0x00d9, 0xc53: 0x0369, 0xc54: 0x0ff9, 0xc55: 0x0249, 0xc56: 0x0f51, 0xc57: 0x0359, 0xc58: 0x0f61, 0xc59: 0x0f71, 0xc5a: 0x0f99, 0xc5b: 0x01d9, 0xc5c: 0x0fa9, 0xc5d: 0x0040, 0xc5e: 0x0040, 0xc5f: 0x0040, 0xc60: 0x0018, 0xc61: 0x0018, 0xc62: 0x0018, 0xc63: 0x0018, 0xc64: 0x0018, 0xc65: 0x0018, 0xc66: 0x0018, 0xc67: 0x0018, 0xc68: 0x1ff1, 0xc69: 0x0018, 0xc6a: 0x0018, 0xc6b: 0x0018, 0xc6c: 0x0018, 0xc6d: 0x0018, 0xc6e: 0x0018, 0xc6f: 0x0018, 0xc70: 0x0018, 0xc71: 0x0018, 0xc72: 0x0018, 0xc73: 0x0018, 0xc74: 0x0018, 0xc75: 0x0018, 0xc76: 0x0018, 0xc77: 0x0018, 0xc78: 0x0018, 0xc79: 0x0018, 0xc7a: 0x0018, 0xc7b: 0x0018, 0xc7c: 0x0018, 0xc7d: 0x0018, 0xc7e: 0x0018, 0xc7f: 0x0018, // Block 0x32, offset 0xc80 0xc80: 0x07ee, 0xc81: 0x080e, 0xc82: 0x1159, 0xc83: 0x082d, 0xc84: 0x0018, 0xc85: 0x084e, 0xc86: 0x086e, 0xc87: 0x1011, 0xc88: 0x0018, 0xc89: 0x088d, 0xc8a: 0x0f31, 0xc8b: 0x0249, 0xc8c: 0x0249, 0xc8d: 0x0249, 0xc8e: 0x0249, 0xc8f: 0x2009, 0xc90: 0x0f41, 0xc91: 0x0f41, 0xc92: 0x0359, 0xc93: 0x0359, 0xc94: 0x0018, 0xc95: 0x0f71, 0xc96: 0x2021, 0xc97: 0x0018, 0xc98: 0x0018, 0xc99: 0x0f99, 0xc9a: 0x2039, 0xc9b: 0x0269, 0xc9c: 0x0269, 0xc9d: 0x0269, 0xc9e: 0x0018, 0xc9f: 0x0018, 0xca0: 0x2049, 0xca1: 0x08ad, 0xca2: 0x2061, 0xca3: 0x0018, 0xca4: 0x13d1, 0xca5: 0x0018, 0xca6: 0x2079, 0xca7: 0x0018, 0xca8: 0x13d1, 0xca9: 0x0018, 0xcaa: 0x0f51, 0xcab: 0x2091, 0xcac: 0x0ee9, 0xcad: 0x1159, 0xcae: 0x0018, 0xcaf: 0x0f09, 0xcb0: 0x0f09, 0xcb1: 0x1199, 0xcb2: 0x0040, 0xcb3: 0x0f61, 0xcb4: 0x00d9, 0xcb5: 0x20a9, 0xcb6: 0x20c1, 0xcb7: 0x20d9, 0xcb8: 0x20f1, 0xcb9: 0x0f41, 0xcba: 0x0018, 0xcbb: 0x08cd, 0xcbc: 0x2109, 0xcbd: 0x10b1, 0xcbe: 0x10b1, 0xcbf: 0x2109, // Block 0x33, offset 0xcc0 0xcc0: 0x08ed, 0xcc1: 0x0018, 0xcc2: 0x0018, 0xcc3: 0x0018, 0xcc4: 0x0018, 0xcc5: 0x0ef9, 0xcc6: 0x0ef9, 0xcc7: 0x0f09, 0xcc8: 0x0f41, 0xcc9: 0x0259, 0xcca: 0x0018, 0xccb: 0x0018, 0xccc: 0x0018, 0xccd: 0x0018, 0xcce: 0x0008, 0xccf: 0x0018, 0xcd0: 0x2121, 0xcd1: 0x2151, 0xcd2: 0x2181, 0xcd3: 0x21b9, 0xcd4: 0x21e9, 0xcd5: 0x2219, 0xcd6: 0x2249, 0xcd7: 0x2279, 0xcd8: 0x22a9, 0xcd9: 0x22d9, 0xcda: 0x2309, 0xcdb: 0x2339, 0xcdc: 0x2369, 0xcdd: 0x2399, 0xcde: 0x23c9, 0xcdf: 0x23f9, 0xce0: 0x0f41, 0xce1: 0x2421, 0xce2: 0x0905, 0xce3: 0x2439, 0xce4: 0x1089, 0xce5: 0x2451, 0xce6: 0x0925, 0xce7: 0x2469, 0xce8: 0x2491, 0xce9: 0x0369, 0xcea: 0x24a9, 0xceb: 0x0945, 0xcec: 0x0359, 0xced: 0x1159, 0xcee: 0x0ef9, 0xcef: 0x0f61, 0xcf0: 0x0f41, 0xcf1: 0x2421, 0xcf2: 0x0965, 0xcf3: 0x2439, 0xcf4: 0x1089, 0xcf5: 0x2451, 0xcf6: 0x0985, 0xcf7: 0x2469, 0xcf8: 0x2491, 0xcf9: 0x0369, 0xcfa: 0x24a9, 0xcfb: 0x09a5, 0xcfc: 0x0359, 0xcfd: 0x1159, 0xcfe: 0x0ef9, 0xcff: 0x0f61, // Block 0x34, offset 0xd00 0xd00: 0x0018, 0xd01: 0x0018, 0xd02: 0x0018, 0xd03: 0x0018, 0xd04: 0x0018, 0xd05: 0x0018, 0xd06: 0x0018, 0xd07: 0x0018, 0xd08: 0x0018, 0xd09: 0x0018, 0xd0a: 0x0018, 0xd0b: 0x0040, 0xd0c: 0x0040, 0xd0d: 0x0040, 0xd0e: 0x0040, 0xd0f: 0x0040, 0xd10: 0x0040, 0xd11: 0x0040, 0xd12: 0x0040, 0xd13: 0x0040, 0xd14: 0x0040, 0xd15: 0x0040, 0xd16: 0x0040, 0xd17: 0x0040, 0xd18: 0x0040, 0xd19: 0x0040, 0xd1a: 0x0040, 0xd1b: 0x0040, 0xd1c: 0x0040, 0xd1d: 0x0040, 0xd1e: 0x0040, 0xd1f: 0x0040, 0xd20: 0x00c9, 0xd21: 0x0069, 0xd22: 0x0079, 0xd23: 0x1f51, 0xd24: 0x1f61, 0xd25: 0x1f71, 0xd26: 0x1f81, 0xd27: 0x1f91, 0xd28: 0x1fa1, 0xd29: 0x2601, 0xd2a: 0x2619, 0xd2b: 0x2631, 0xd2c: 0x2649, 0xd2d: 0x2661, 0xd2e: 0x2679, 0xd2f: 0x2691, 0xd30: 0x26a9, 0xd31: 0x26c1, 0xd32: 0x26d9, 0xd33: 0x26f1, 0xd34: 0x0a06, 0xd35: 0x0a26, 0xd36: 0x0a46, 0xd37: 0x0a66, 0xd38: 0x0a86, 0xd39: 0x0aa6, 0xd3a: 0x0ac6, 0xd3b: 0x0ae6, 0xd3c: 0x0b06, 0xd3d: 0x270a, 0xd3e: 0x2732, 0xd3f: 0x275a, // Block 0x35, offset 0xd40 0xd40: 0x2782, 0xd41: 0x27aa, 0xd42: 0x27d2, 0xd43: 0x27fa, 0xd44: 0x2822, 0xd45: 0x284a, 0xd46: 0x2872, 0xd47: 0x289a, 0xd48: 0x0040, 0xd49: 0x0040, 0xd4a: 0x0040, 0xd4b: 0x0040, 0xd4c: 0x0040, 0xd4d: 0x0040, 0xd4e: 0x0040, 0xd4f: 0x0040, 0xd50: 0x0040, 0xd51: 0x0040, 0xd52: 0x0040, 0xd53: 0x0040, 0xd54: 0x0040, 0xd55: 0x0040, 0xd56: 0x0040, 0xd57: 0x0040, 0xd58: 0x0040, 0xd59: 0x0040, 0xd5a: 0x0040, 0xd5b: 0x0040, 0xd5c: 0x0b26, 0xd5d: 0x0b46, 0xd5e: 0x0b66, 0xd5f: 0x0b86, 0xd60: 0x0ba6, 0xd61: 0x0bc6, 0xd62: 0x0be6, 0xd63: 0x0c06, 0xd64: 0x0c26, 0xd65: 0x0c46, 0xd66: 0x0c66, 0xd67: 0x0c86, 0xd68: 0x0ca6, 0xd69: 0x0cc6, 0xd6a: 0x0ce6, 0xd6b: 0x0d06, 0xd6c: 0x0d26, 0xd6d: 0x0d46, 0xd6e: 0x0d66, 0xd6f: 0x0d86, 0xd70: 0x0da6, 0xd71: 0x0dc6, 0xd72: 0x0de6, 0xd73: 0x0e06, 0xd74: 0x0e26, 0xd75: 0x0e46, 0xd76: 0x0039, 0xd77: 0x0ee9, 0xd78: 0x1159, 0xd79: 0x0ef9, 0xd7a: 0x0f09, 0xd7b: 0x1199, 0xd7c: 0x0f31, 0xd7d: 0x0249, 0xd7e: 0x0f41, 0xd7f: 0x0259, // Block 0x36, offset 0xd80 0xd80: 0x0f51, 0xd81: 0x0359, 0xd82: 0x0f61, 0xd83: 0x0f71, 0xd84: 0x00d9, 0xd85: 0x0f99, 0xd86: 0x2039, 0xd87: 0x0269, 0xd88: 0x01d9, 0xd89: 0x0fa9, 0xd8a: 0x0fb9, 0xd8b: 0x1089, 0xd8c: 0x0279, 0xd8d: 0x0369, 0xd8e: 0x0289, 0xd8f: 0x13d1, 0xd90: 0x0039, 0xd91: 0x0ee9, 0xd92: 0x1159, 0xd93: 0x0ef9, 0xd94: 0x0f09, 0xd95: 0x1199, 0xd96: 0x0f31, 0xd97: 0x0249, 0xd98: 0x0f41, 0xd99: 0x0259, 0xd9a: 0x0f51, 0xd9b: 0x0359, 0xd9c: 0x0f61, 0xd9d: 0x0f71, 0xd9e: 0x00d9, 0xd9f: 0x0f99, 0xda0: 0x2039, 0xda1: 0x0269, 0xda2: 0x01d9, 0xda3: 0x0fa9, 0xda4: 0x0fb9, 0xda5: 0x1089, 0xda6: 0x0279, 0xda7: 0x0369, 0xda8: 0x0289, 0xda9: 0x13d1, 0xdaa: 0x1f41, 0xdab: 0x0018, 0xdac: 0x0018, 0xdad: 0x0018, 0xdae: 0x0018, 0xdaf: 0x0018, 0xdb0: 0x0018, 0xdb1: 0x0018, 0xdb2: 0x0018, 0xdb3: 0x0018, 0xdb4: 0x0018, 0xdb5: 0x0018, 0xdb6: 0x0018, 0xdb7: 0x0018, 0xdb8: 0x0018, 0xdb9: 0x0018, 0xdba: 0x0018, 0xdbb: 0x0018, 0xdbc: 0x0018, 0xdbd: 0x0018, 0xdbe: 0x0018, 0xdbf: 0x0018, // Block 0x37, offset 0xdc0 0xdc0: 0x0008, 0xdc1: 0x0008, 0xdc2: 0x0008, 0xdc3: 0x0008, 0xdc4: 0x0008, 0xdc5: 0x0008, 0xdc6: 0x0008, 0xdc7: 0x0008, 0xdc8: 0x0008, 0xdc9: 0x0008, 0xdca: 0x0008, 0xdcb: 0x0008, 0xdcc: 0x0008, 0xdcd: 0x0008, 0xdce: 0x0008, 0xdcf: 0x0008, 0xdd0: 0x0008, 0xdd1: 0x0008, 0xdd2: 0x0008, 0xdd3: 0x0008, 0xdd4: 0x0008, 0xdd5: 0x0008, 0xdd6: 0x0008, 0xdd7: 0x0008, 0xdd8: 0x0008, 0xdd9: 0x0008, 0xdda: 0x0008, 0xddb: 0x0008, 0xddc: 0x0008, 0xddd: 0x0008, 0xdde: 0x0008, 0xddf: 0x0040, 0xde0: 0xe00d, 0xde1: 0x0008, 0xde2: 0x2971, 0xde3: 0x0ebd, 0xde4: 0x2989, 0xde5: 0x0008, 0xde6: 0x0008, 0xde7: 0xe07d, 0xde8: 0x0008, 0xde9: 0xe01d, 0xdea: 0x0008, 0xdeb: 0xe03d, 0xdec: 0x0008, 0xded: 0x0fe1, 0xdee: 0x1281, 0xdef: 0x0fc9, 0xdf0: 0x1141, 0xdf1: 0x0008, 0xdf2: 0xe00d, 0xdf3: 0x0008, 0xdf4: 0x0008, 0xdf5: 0xe01d, 0xdf6: 0x0008, 0xdf7: 0x0008, 0xdf8: 0x0008, 0xdf9: 0x0008, 0xdfa: 0x0008, 0xdfb: 0x0008, 0xdfc: 0x0259, 0xdfd: 0x1089, 0xdfe: 0x29a1, 0xdff: 0x29b9, // Block 0x38, offset 0xe00 0xe00: 0xe00d, 0xe01: 0x0008, 0xe02: 0xe00d, 0xe03: 0x0008, 0xe04: 0xe00d, 0xe05: 0x0008, 0xe06: 0xe00d, 0xe07: 0x0008, 0xe08: 0xe00d, 0xe09: 0x0008, 0xe0a: 0xe00d, 0xe0b: 0x0008, 0xe0c: 0xe00d, 0xe0d: 0x0008, 0xe0e: 0xe00d, 0xe0f: 0x0008, 0xe10: 0xe00d, 0xe11: 0x0008, 0xe12: 0xe00d, 0xe13: 0x0008, 0xe14: 0xe00d, 0xe15: 0x0008, 0xe16: 0xe00d, 0xe17: 0x0008, 0xe18: 0xe00d, 0xe19: 0x0008, 0xe1a: 0xe00d, 0xe1b: 0x0008, 0xe1c: 0xe00d, 0xe1d: 0x0008, 0xe1e: 0xe00d, 0xe1f: 0x0008, 0xe20: 0xe00d, 0xe21: 0x0008, 0xe22: 0xe00d, 0xe23: 0x0008, 0xe24: 0x0008, 0xe25: 0x0018, 0xe26: 0x0018, 0xe27: 0x0018, 0xe28: 0x0018, 0xe29: 0x0018, 0xe2a: 0x0018, 0xe2b: 0xe03d, 0xe2c: 0x0008, 0xe2d: 0xe01d, 0xe2e: 0x0008, 0xe2f: 0x3308, 0xe30: 0x3308, 0xe31: 0x3308, 0xe32: 0xe00d, 0xe33: 0x0008, 0xe34: 0x0040, 0xe35: 0x0040, 0xe36: 0x0040, 0xe37: 0x0040, 0xe38: 0x0040, 0xe39: 0x0018, 0xe3a: 0x0018, 0xe3b: 0x0018, 0xe3c: 0x0018, 0xe3d: 0x0018, 0xe3e: 0x0018, 0xe3f: 0x0018, // Block 0x39, offset 0xe40 0xe40: 0x26fd, 0xe41: 0x271d, 0xe42: 0x273d, 0xe43: 0x275d, 0xe44: 0x277d, 0xe45: 0x279d, 0xe46: 0x27bd, 0xe47: 0x27dd, 0xe48: 0x27fd, 0xe49: 0x281d, 0xe4a: 0x283d, 0xe4b: 0x285d, 0xe4c: 0x287d, 0xe4d: 0x289d, 0xe4e: 0x28bd, 0xe4f: 0x28dd, 0xe50: 0x28fd, 0xe51: 0x291d, 0xe52: 0x293d, 0xe53: 0x295d, 0xe54: 0x297d, 0xe55: 0x299d, 0xe56: 0x0040, 0xe57: 0x0040, 0xe58: 0x0040, 0xe59: 0x0040, 0xe5a: 0x0040, 0xe5b: 0x0040, 0xe5c: 0x0040, 0xe5d: 0x0040, 0xe5e: 0x0040, 0xe5f: 0x0040, 0xe60: 0x0040, 0xe61: 0x0040, 0xe62: 0x0040, 0xe63: 0x0040, 0xe64: 0x0040, 0xe65: 0x0040, 0xe66: 0x0040, 0xe67: 0x0040, 0xe68: 0x0040, 0xe69: 0x0040, 0xe6a: 0x0040, 0xe6b: 0x0040, 0xe6c: 0x0040, 0xe6d: 0x0040, 0xe6e: 0x0040, 0xe6f: 0x0040, 0xe70: 0x0040, 0xe71: 0x0040, 0xe72: 0x0040, 0xe73: 0x0040, 0xe74: 0x0040, 0xe75: 0x0040, 0xe76: 0x0040, 0xe77: 0x0040, 0xe78: 0x0040, 0xe79: 0x0040, 0xe7a: 0x0040, 0xe7b: 0x0040, 0xe7c: 0x0040, 0xe7d: 0x0040, 0xe7e: 0x0040, 0xe7f: 0x0040, // Block 0x3a, offset 0xe80 0xe80: 0x000a, 0xe81: 0x0018, 0xe82: 0x29d1, 0xe83: 0x0018, 0xe84: 0x0018, 0xe85: 0x0008, 0xe86: 0x0008, 0xe87: 0x0008, 0xe88: 0x0018, 0xe89: 0x0018, 0xe8a: 0x0018, 0xe8b: 0x0018, 0xe8c: 0x0018, 0xe8d: 0x0018, 0xe8e: 0x0018, 0xe8f: 0x0018, 0xe90: 0x0018, 0xe91: 0x0018, 0xe92: 0x0018, 0xe93: 0x0018, 0xe94: 0x0018, 0xe95: 0x0018, 0xe96: 0x0018, 0xe97: 0x0018, 0xe98: 0x0018, 0xe99: 0x0018, 0xe9a: 0x0018, 0xe9b: 0x0018, 0xe9c: 0x0018, 0xe9d: 0x0018, 0xe9e: 0x0018, 0xe9f: 0x0018, 0xea0: 0x0018, 0xea1: 0x0018, 0xea2: 0x0018, 0xea3: 0x0018, 0xea4: 0x0018, 0xea5: 0x0018, 0xea6: 0x0018, 0xea7: 0x0018, 0xea8: 0x0018, 0xea9: 0x0018, 0xeaa: 0x3308, 0xeab: 0x3308, 0xeac: 0x3308, 0xead: 0x3308, 0xeae: 0x3018, 0xeaf: 0x3018, 0xeb0: 0x0018, 0xeb1: 0x0018, 0xeb2: 0x0018, 0xeb3: 0x0018, 0xeb4: 0x0018, 0xeb5: 0x0018, 0xeb6: 0xe125, 0xeb7: 0x0018, 0xeb8: 0x29bd, 0xeb9: 0x29dd, 0xeba: 0x29fd, 0xebb: 0x0018, 0xebc: 0x0008, 0xebd: 0x0018, 0xebe: 0x0018, 0xebf: 0x0018, // Block 0x3b, offset 0xec0 0xec0: 0x2b3d, 0xec1: 0x2b5d, 0xec2: 0x2b7d, 0xec3: 0x2b9d, 0xec4: 0x2bbd, 0xec5: 0x2bdd, 0xec6: 0x2bdd, 0xec7: 0x2bdd, 0xec8: 0x2bfd, 0xec9: 0x2bfd, 0xeca: 0x2bfd, 0xecb: 0x2bfd, 0xecc: 0x2c1d, 0xecd: 0x2c1d, 0xece: 0x2c1d, 0xecf: 0x2c3d, 0xed0: 0x2c5d, 0xed1: 0x2c5d, 0xed2: 0x2a7d, 0xed3: 0x2a7d, 0xed4: 0x2c5d, 0xed5: 0x2c5d, 0xed6: 0x2c7d, 0xed7: 0x2c7d, 0xed8: 0x2c5d, 0xed9: 0x2c5d, 0xeda: 0x2a7d, 0xedb: 0x2a7d, 0xedc: 0x2c5d, 0xedd: 0x2c5d, 0xede: 0x2c3d, 0xedf: 0x2c3d, 0xee0: 0x2c9d, 0xee1: 0x2c9d, 0xee2: 0x2cbd, 0xee3: 0x2cbd, 0xee4: 0x0040, 0xee5: 0x2cdd, 0xee6: 0x2cfd, 0xee7: 0x2d1d, 0xee8: 0x2d1d, 0xee9: 0x2d3d, 0xeea: 0x2d5d, 0xeeb: 0x2d7d, 0xeec: 0x2d9d, 0xeed: 0x2dbd, 0xeee: 0x2ddd, 0xeef: 0x2dfd, 0xef0: 0x2e1d, 0xef1: 0x2e3d, 0xef2: 0x2e3d, 0xef3: 0x2e5d, 0xef4: 0x2e7d, 0xef5: 0x2e7d, 0xef6: 0x2e9d, 0xef7: 0x2ebd, 0xef8: 0x2e5d, 0xef9: 0x2edd, 0xefa: 0x2efd, 0xefb: 0x2edd, 0xefc: 0x2e5d, 0xefd: 0x2f1d, 0xefe: 0x2f3d, 0xeff: 0x2f5d, // Block 0x3c, offset 0xf00 0xf00: 0x2f7d, 0xf01: 0x2f9d, 0xf02: 0x2cfd, 0xf03: 0x2cdd, 0xf04: 0x2fbd, 0xf05: 0x2fdd, 0xf06: 0x2ffd, 0xf07: 0x301d, 0xf08: 0x303d, 0xf09: 0x305d, 0xf0a: 0x307d, 0xf0b: 0x309d, 0xf0c: 0x30bd, 0xf0d: 0x30dd, 0xf0e: 0x30fd, 0xf0f: 0x0040, 0xf10: 0x0018, 0xf11: 0x0018, 0xf12: 0x311d, 0xf13: 0x313d, 0xf14: 0x315d, 0xf15: 0x317d, 0xf16: 0x319d, 0xf17: 0x31bd, 0xf18: 0x31dd, 0xf19: 0x31fd, 0xf1a: 0x321d, 0xf1b: 0x323d, 0xf1c: 0x315d, 0xf1d: 0x325d, 0xf1e: 0x327d, 0xf1f: 0x329d, 0xf20: 0x0008, 0xf21: 0x0008, 0xf22: 0x0008, 0xf23: 0x0008, 0xf24: 0x0008, 0xf25: 0x0008, 0xf26: 0x0008, 0xf27: 0x0008, 0xf28: 0x0008, 0xf29: 0x0008, 0xf2a: 0x0008, 0xf2b: 0x0008, 0xf2c: 0x0008, 0xf2d: 0x0008, 0xf2e: 0x0008, 0xf2f: 0x0008, 0xf30: 0x0008, 0xf31: 0x0008, 0xf32: 0x0008, 0xf33: 0x0008, 0xf34: 0x0008, 0xf35: 0x0008, 0xf36: 0x0008, 0xf37: 0x0008, 0xf38: 0x0008, 0xf39: 0x0008, 0xf3a: 0x0008, 0xf3b: 0x0040, 0xf3c: 0x0040, 0xf3d: 0x0040, 0xf3e: 0x0040, 0xf3f: 0x0040, // Block 0x3d, offset 0xf40 0xf40: 0x36a2, 0xf41: 0x36d2, 0xf42: 0x3702, 0xf43: 0x3732, 0xf44: 0x32bd, 0xf45: 0x32dd, 0xf46: 0x32fd, 0xf47: 0x331d, 0xf48: 0x0018, 0xf49: 0x0018, 0xf4a: 0x0018, 0xf4b: 0x0018, 0xf4c: 0x0018, 0xf4d: 0x0018, 0xf4e: 0x0018, 0xf4f: 0x0018, 0xf50: 0x333d, 0xf51: 0x3761, 0xf52: 0x3779, 0xf53: 0x3791, 0xf54: 0x37a9, 0xf55: 0x37c1, 0xf56: 0x37d9, 0xf57: 0x37f1, 0xf58: 0x3809, 0xf59: 0x3821, 0xf5a: 0x3839, 0xf5b: 0x3851, 0xf5c: 0x3869, 0xf5d: 0x3881, 0xf5e: 0x3899, 0xf5f: 0x38b1, 0xf60: 0x335d, 0xf61: 0x337d, 0xf62: 0x339d, 0xf63: 0x33bd, 0xf64: 0x33dd, 0xf65: 0x33dd, 0xf66: 0x33fd, 0xf67: 0x341d, 0xf68: 0x343d, 0xf69: 0x345d, 0xf6a: 0x347d, 0xf6b: 0x349d, 0xf6c: 0x34bd, 0xf6d: 0x34dd, 0xf6e: 0x34fd, 0xf6f: 0x351d, 0xf70: 0x353d, 0xf71: 0x355d, 0xf72: 0x357d, 0xf73: 0x359d, 0xf74: 0x35bd, 0xf75: 0x35dd, 0xf76: 0x35fd, 0xf77: 0x361d, 0xf78: 0x363d, 0xf79: 0x365d, 0xf7a: 0x367d, 0xf7b: 0x369d, 0xf7c: 0x38c9, 0xf7d: 0x3901, 0xf7e: 0x36bd, 0xf7f: 0x0018, // Block 0x3e, offset 0xf80 0xf80: 0x36dd, 0xf81: 0x36fd, 0xf82: 0x371d, 0xf83: 0x373d, 0xf84: 0x375d, 0xf85: 0x377d, 0xf86: 0x379d, 0xf87: 0x37bd, 0xf88: 0x37dd, 0xf89: 0x37fd, 0xf8a: 0x381d, 0xf8b: 0x383d, 0xf8c: 0x385d, 0xf8d: 0x387d, 0xf8e: 0x389d, 0xf8f: 0x38bd, 0xf90: 0x38dd, 0xf91: 0x38fd, 0xf92: 0x391d, 0xf93: 0x393d, 0xf94: 0x395d, 0xf95: 0x397d, 0xf96: 0x399d, 0xf97: 0x39bd, 0xf98: 0x39dd, 0xf99: 0x39fd, 0xf9a: 0x3a1d, 0xf9b: 0x3a3d, 0xf9c: 0x3a5d, 0xf9d: 0x3a7d, 0xf9e: 0x3a9d, 0xf9f: 0x3abd, 0xfa0: 0x3add, 0xfa1: 0x3afd, 0xfa2: 0x3b1d, 0xfa3: 0x3b3d, 0xfa4: 0x3b5d, 0xfa5: 0x3b7d, 0xfa6: 0x127d, 0xfa7: 0x3b9d, 0xfa8: 0x3bbd, 0xfa9: 0x3bdd, 0xfaa: 0x3bfd, 0xfab: 0x3c1d, 0xfac: 0x3c3d, 0xfad: 0x3c5d, 0xfae: 0x239d, 0xfaf: 0x3c7d, 0xfb0: 0x3c9d, 0xfb1: 0x3939, 0xfb2: 0x3951, 0xfb3: 0x3969, 0xfb4: 0x3981, 0xfb5: 0x3999, 0xfb6: 0x39b1, 0xfb7: 0x39c9, 0xfb8: 0x39e1, 0xfb9: 0x39f9, 0xfba: 0x3a11, 0xfbb: 0x3a29, 0xfbc: 0x3a41, 0xfbd: 0x3a59, 0xfbe: 0x3a71, 0xfbf: 0x3a89, // Block 0x3f, offset 0xfc0 0xfc0: 0x3aa1, 0xfc1: 0x3ac9, 0xfc2: 0x3af1, 0xfc3: 0x3b19, 0xfc4: 0x3b41, 0xfc5: 0x3b69, 0xfc6: 0x3b91, 0xfc7: 0x3bb9, 0xfc8: 0x3be1, 0xfc9: 0x3c09, 0xfca: 0x3c39, 0xfcb: 0x3c69, 0xfcc: 0x3c99, 0xfcd: 0x3cbd, 0xfce: 0x3cb1, 0xfcf: 0x3cdd, 0xfd0: 0x3cfd, 0xfd1: 0x3d15, 0xfd2: 0x3d2d, 0xfd3: 0x3d45, 0xfd4: 0x3d5d, 0xfd5: 0x3d5d, 0xfd6: 0x3d45, 0xfd7: 0x3d75, 0xfd8: 0x07bd, 0xfd9: 0x3d8d, 0xfda: 0x3da5, 0xfdb: 0x3dbd, 0xfdc: 0x3dd5, 0xfdd: 0x3ded, 0xfde: 0x3e05, 0xfdf: 0x3e1d, 0xfe0: 0x3e35, 0xfe1: 0x3e4d, 0xfe2: 0x3e65, 0xfe3: 0x3e7d, 0xfe4: 0x3e95, 0xfe5: 0x3e95, 0xfe6: 0x3ead, 0xfe7: 0x3ead, 0xfe8: 0x3ec5, 0xfe9: 0x3ec5, 0xfea: 0x3edd, 0xfeb: 0x3ef5, 0xfec: 0x3f0d, 0xfed: 0x3f25, 0xfee: 0x3f3d, 0xfef: 0x3f3d, 0xff0: 0x3f55, 0xff1: 0x3f55, 0xff2: 0x3f55, 0xff3: 0x3f6d, 0xff4: 0x3f85, 0xff5: 0x3f9d, 0xff6: 0x3fb5, 0xff7: 0x3f9d, 0xff8: 0x3fcd, 0xff9: 0x3fe5, 0xffa: 0x3f6d, 0xffb: 0x3ffd, 0xffc: 0x4015, 0xffd: 0x4015, 0xffe: 0x4015, 0xfff: 0x0040, // Block 0x40, offset 0x1000 0x1000: 0x3cc9, 0x1001: 0x3d31, 0x1002: 0x3d99, 0x1003: 0x3e01, 0x1004: 0x3e51, 0x1005: 0x3eb9, 0x1006: 0x3f09, 0x1007: 0x3f59, 0x1008: 0x3fd9, 0x1009: 0x4041, 0x100a: 0x4091, 0x100b: 0x40e1, 0x100c: 0x4131, 0x100d: 0x4199, 0x100e: 0x4201, 0x100f: 0x4251, 0x1010: 0x42a1, 0x1011: 0x42d9, 0x1012: 0x4329, 0x1013: 0x4391, 0x1014: 0x43f9, 0x1015: 0x4431, 0x1016: 0x44b1, 0x1017: 0x4549, 0x1018: 0x45c9, 0x1019: 0x4619, 0x101a: 0x4699, 0x101b: 0x4719, 0x101c: 0x4781, 0x101d: 0x47d1, 0x101e: 0x4821, 0x101f: 0x4871, 0x1020: 0x48d9, 0x1021: 0x4959, 0x1022: 0x49c1, 0x1023: 0x4a11, 0x1024: 0x4a61, 0x1025: 0x4ab1, 0x1026: 0x4ae9, 0x1027: 0x4b21, 0x1028: 0x4b59, 0x1029: 0x4b91, 0x102a: 0x4be1, 0x102b: 0x4c31, 0x102c: 0x4cb1, 0x102d: 0x4d01, 0x102e: 0x4d69, 0x102f: 0x4de9, 0x1030: 0x4e39, 0x1031: 0x4e71, 0x1032: 0x4ea9, 0x1033: 0x4f29, 0x1034: 0x4f91, 0x1035: 0x5011, 0x1036: 0x5061, 0x1037: 0x50e1, 0x1038: 0x5119, 0x1039: 0x5169, 0x103a: 0x51b9, 0x103b: 0x5209, 0x103c: 0x5259, 0x103d: 0x52a9, 0x103e: 0x5311, 0x103f: 0x5361, // Block 0x41, offset 0x1040 0x1040: 0x5399, 0x1041: 0x53e9, 0x1042: 0x5439, 0x1043: 0x5489, 0x1044: 0x54f1, 0x1045: 0x5541, 0x1046: 0x5591, 0x1047: 0x55e1, 0x1048: 0x5661, 0x1049: 0x56c9, 0x104a: 0x5701, 0x104b: 0x5781, 0x104c: 0x57b9, 0x104d: 0x5821, 0x104e: 0x5889, 0x104f: 0x58d9, 0x1050: 0x5929, 0x1051: 0x5979, 0x1052: 0x59e1, 0x1053: 0x5a19, 0x1054: 0x5a69, 0x1055: 0x5ad1, 0x1056: 0x5b09, 0x1057: 0x5b89, 0x1058: 0x5bd9, 0x1059: 0x5c01, 0x105a: 0x5c29, 0x105b: 0x5c51, 0x105c: 0x5c79, 0x105d: 0x5ca1, 0x105e: 0x5cc9, 0x105f: 0x5cf1, 0x1060: 0x5d19, 0x1061: 0x5d41, 0x1062: 0x5d69, 0x1063: 0x5d99, 0x1064: 0x5dc9, 0x1065: 0x5df9, 0x1066: 0x5e29, 0x1067: 0x5e59, 0x1068: 0x5e89, 0x1069: 0x5eb9, 0x106a: 0x5ee9, 0x106b: 0x5f19, 0x106c: 0x5f49, 0x106d: 0x5f79, 0x106e: 0x5fa9, 0x106f: 0x5fd9, 0x1070: 0x6009, 0x1071: 0x402d, 0x1072: 0x6039, 0x1073: 0x6051, 0x1074: 0x404d, 0x1075: 0x6069, 0x1076: 0x6081, 0x1077: 0x6099, 0x1078: 0x406d, 0x1079: 0x406d, 0x107a: 0x60b1, 0x107b: 0x60c9, 0x107c: 0x6101, 0x107d: 0x6139, 0x107e: 0x6171, 0x107f: 0x61a9, // Block 0x42, offset 0x1080 0x1080: 0x6211, 0x1081: 0x6229, 0x1082: 0x408d, 0x1083: 0x6241, 0x1084: 0x6259, 0x1085: 0x6271, 0x1086: 0x6289, 0x1087: 0x62a1, 0x1088: 0x40ad, 0x1089: 0x62b9, 0x108a: 0x62e1, 0x108b: 0x62f9, 0x108c: 0x40cd, 0x108d: 0x40cd, 0x108e: 0x6311, 0x108f: 0x6329, 0x1090: 0x6341, 0x1091: 0x40ed, 0x1092: 0x410d, 0x1093: 0x412d, 0x1094: 0x414d, 0x1095: 0x416d, 0x1096: 0x6359, 0x1097: 0x6371, 0x1098: 0x6389, 0x1099: 0x63a1, 0x109a: 0x63b9, 0x109b: 0x418d, 0x109c: 0x63d1, 0x109d: 0x63e9, 0x109e: 0x6401, 0x109f: 0x41ad, 0x10a0: 0x41cd, 0x10a1: 0x6419, 0x10a2: 0x41ed, 0x10a3: 0x420d, 0x10a4: 0x422d, 0x10a5: 0x6431, 0x10a6: 0x424d, 0x10a7: 0x6449, 0x10a8: 0x6479, 0x10a9: 0x6211, 0x10aa: 0x426d, 0x10ab: 0x428d, 0x10ac: 0x42ad, 0x10ad: 0x42cd, 0x10ae: 0x64b1, 0x10af: 0x64f1, 0x10b0: 0x6539, 0x10b1: 0x6551, 0x10b2: 0x42ed, 0x10b3: 0x6569, 0x10b4: 0x6581, 0x10b5: 0x6599, 0x10b6: 0x430d, 0x10b7: 0x65b1, 0x10b8: 0x65c9, 0x10b9: 0x65b1, 0x10ba: 0x65e1, 0x10bb: 0x65f9, 0x10bc: 0x432d, 0x10bd: 0x6611, 0x10be: 0x6629, 0x10bf: 0x6611, // Block 0x43, offset 0x10c0 0x10c0: 0x434d, 0x10c1: 0x436d, 0x10c2: 0x0040, 0x10c3: 0x6641, 0x10c4: 0x6659, 0x10c5: 0x6671, 0x10c6: 0x6689, 0x10c7: 0x0040, 0x10c8: 0x66c1, 0x10c9: 0x66d9, 0x10ca: 0x66f1, 0x10cb: 0x6709, 0x10cc: 0x6721, 0x10cd: 0x6739, 0x10ce: 0x6401, 0x10cf: 0x6751, 0x10d0: 0x6769, 0x10d1: 0x6781, 0x10d2: 0x438d, 0x10d3: 0x6799, 0x10d4: 0x6289, 0x10d5: 0x43ad, 0x10d6: 0x43cd, 0x10d7: 0x67b1, 0x10d8: 0x0040, 0x10d9: 0x43ed, 0x10da: 0x67c9, 0x10db: 0x67e1, 0x10dc: 0x67f9, 0x10dd: 0x6811, 0x10de: 0x6829, 0x10df: 0x6859, 0x10e0: 0x6889, 0x10e1: 0x68b1, 0x10e2: 0x68d9, 0x10e3: 0x6901, 0x10e4: 0x6929, 0x10e5: 0x6951, 0x10e6: 0x6979, 0x10e7: 0x69a1, 0x10e8: 0x69c9, 0x10e9: 0x69f1, 0x10ea: 0x6a21, 0x10eb: 0x6a51, 0x10ec: 0x6a81, 0x10ed: 0x6ab1, 0x10ee: 0x6ae1, 0x10ef: 0x6b11, 0x10f0: 0x6b41, 0x10f1: 0x6b71, 0x10f2: 0x6ba1, 0x10f3: 0x6bd1, 0x10f4: 0x6c01, 0x10f5: 0x6c31, 0x10f6: 0x6c61, 0x10f7: 0x6c91, 0x10f8: 0x6cc1, 0x10f9: 0x6cf1, 0x10fa: 0x6d21, 0x10fb: 0x6d51, 0x10fc: 0x6d81, 0x10fd: 0x6db1, 0x10fe: 0x6de1, 0x10ff: 0x440d, // Block 0x44, offset 0x1100 0x1100: 0xe00d, 0x1101: 0x0008, 0x1102: 0xe00d, 0x1103: 0x0008, 0x1104: 0xe00d, 0x1105: 0x0008, 0x1106: 0xe00d, 0x1107: 0x0008, 0x1108: 0xe00d, 0x1109: 0x0008, 0x110a: 0xe00d, 0x110b: 0x0008, 0x110c: 0xe00d, 0x110d: 0x0008, 0x110e: 0xe00d, 0x110f: 0x0008, 0x1110: 0xe00d, 0x1111: 0x0008, 0x1112: 0xe00d, 0x1113: 0x0008, 0x1114: 0xe00d, 0x1115: 0x0008, 0x1116: 0xe00d, 0x1117: 0x0008, 0x1118: 0xe00d, 0x1119: 0x0008, 0x111a: 0xe00d, 0x111b: 0x0008, 0x111c: 0xe00d, 0x111d: 0x0008, 0x111e: 0xe00d, 0x111f: 0x0008, 0x1120: 0xe00d, 0x1121: 0x0008, 0x1122: 0xe00d, 0x1123: 0x0008, 0x1124: 0xe00d, 0x1125: 0x0008, 0x1126: 0xe00d, 0x1127: 0x0008, 0x1128: 0xe00d, 0x1129: 0x0008, 0x112a: 0xe00d, 0x112b: 0x0008, 0x112c: 0xe00d, 0x112d: 0x0008, 0x112e: 0x0008, 0x112f: 0x3308, 0x1130: 0x3318, 0x1131: 0x3318, 0x1132: 0x3318, 0x1133: 0x0018, 0x1134: 0x3308, 0x1135: 0x3308, 0x1136: 0x3308, 0x1137: 0x3308, 0x1138: 0x3308, 0x1139: 0x3308, 0x113a: 0x3308, 0x113b: 0x3308, 0x113c: 0x3308, 0x113d: 0x3308, 0x113e: 0x0018, 0x113f: 0x0008, // Block 0x45, offset 0x1140 0x1140: 0xe00d, 0x1141: 0x0008, 0x1142: 0xe00d, 0x1143: 0x0008, 0x1144: 0xe00d, 0x1145: 0x0008, 0x1146: 0xe00d, 0x1147: 0x0008, 0x1148: 0xe00d, 0x1149: 0x0008, 0x114a: 0xe00d, 0x114b: 0x0008, 0x114c: 0xe00d, 0x114d: 0x0008, 0x114e: 0xe00d, 0x114f: 0x0008, 0x1150: 0xe00d, 0x1151: 0x0008, 0x1152: 0xe00d, 0x1153: 0x0008, 0x1154: 0xe00d, 0x1155: 0x0008, 0x1156: 0xe00d, 0x1157: 0x0008, 0x1158: 0xe00d, 0x1159: 0x0008, 0x115a: 0xe00d, 0x115b: 0x0008, 0x115c: 0x0ea1, 0x115d: 0x6e11, 0x115e: 0x3308, 0x115f: 0x3308, 0x1160: 0x0008, 0x1161: 0x0008, 0x1162: 0x0008, 0x1163: 0x0008, 0x1164: 0x0008, 0x1165: 0x0008, 0x1166: 0x0008, 0x1167: 0x0008, 0x1168: 0x0008, 0x1169: 0x0008, 0x116a: 0x0008, 0x116b: 0x0008, 0x116c: 0x0008, 0x116d: 0x0008, 0x116e: 0x0008, 0x116f: 0x0008, 0x1170: 0x0008, 0x1171: 0x0008, 0x1172: 0x0008, 0x1173: 0x0008, 0x1174: 0x0008, 0x1175: 0x0008, 0x1176: 0x0008, 0x1177: 0x0008, 0x1178: 0x0008, 0x1179: 0x0008, 0x117a: 0x0008, 0x117b: 0x0008, 0x117c: 0x0008, 0x117d: 0x0008, 0x117e: 0x0008, 0x117f: 0x0008, // Block 0x46, offset 0x1180 0x1180: 0x0018, 0x1181: 0x0018, 0x1182: 0x0018, 0x1183: 0x0018, 0x1184: 0x0018, 0x1185: 0x0018, 0x1186: 0x0018, 0x1187: 0x0018, 0x1188: 0x0018, 0x1189: 0x0018, 0x118a: 0x0018, 0x118b: 0x0018, 0x118c: 0x0018, 0x118d: 0x0018, 0x118e: 0x0018, 0x118f: 0x0018, 0x1190: 0x0018, 0x1191: 0x0018, 0x1192: 0x0018, 0x1193: 0x0018, 0x1194: 0x0018, 0x1195: 0x0018, 0x1196: 0x0018, 0x1197: 0x0008, 0x1198: 0x0008, 0x1199: 0x0008, 0x119a: 0x0008, 0x119b: 0x0008, 0x119c: 0x0008, 0x119d: 0x0008, 0x119e: 0x0008, 0x119f: 0x0008, 0x11a0: 0x0018, 0x11a1: 0x0018, 0x11a2: 0xe00d, 0x11a3: 0x0008, 0x11a4: 0xe00d, 0x11a5: 0x0008, 0x11a6: 0xe00d, 0x11a7: 0x0008, 0x11a8: 0xe00d, 0x11a9: 0x0008, 0x11aa: 0xe00d, 0x11ab: 0x0008, 0x11ac: 0xe00d, 0x11ad: 0x0008, 0x11ae: 0xe00d, 0x11af: 0x0008, 0x11b0: 0x0008, 0x11b1: 0x0008, 0x11b2: 0xe00d, 0x11b3: 0x0008, 0x11b4: 0xe00d, 0x11b5: 0x0008, 0x11b6: 0xe00d, 0x11b7: 0x0008, 0x11b8: 0xe00d, 0x11b9: 0x0008, 0x11ba: 0xe00d, 0x11bb: 0x0008, 0x11bc: 0xe00d, 0x11bd: 0x0008, 0x11be: 0xe00d, 0x11bf: 0x0008, // Block 0x47, offset 0x11c0 0x11c0: 0xe00d, 0x11c1: 0x0008, 0x11c2: 0xe00d, 0x11c3: 0x0008, 0x11c4: 0xe00d, 0x11c5: 0x0008, 0x11c6: 0xe00d, 0x11c7: 0x0008, 0x11c8: 0xe00d, 0x11c9: 0x0008, 0x11ca: 0xe00d, 0x11cb: 0x0008, 0x11cc: 0xe00d, 0x11cd: 0x0008, 0x11ce: 0xe00d, 0x11cf: 0x0008, 0x11d0: 0xe00d, 0x11d1: 0x0008, 0x11d2: 0xe00d, 0x11d3: 0x0008, 0x11d4: 0xe00d, 0x11d5: 0x0008, 0x11d6: 0xe00d, 0x11d7: 0x0008, 0x11d8: 0xe00d, 0x11d9: 0x0008, 0x11da: 0xe00d, 0x11db: 0x0008, 0x11dc: 0xe00d, 0x11dd: 0x0008, 0x11de: 0xe00d, 0x11df: 0x0008, 0x11e0: 0xe00d, 0x11e1: 0x0008, 0x11e2: 0xe00d, 0x11e3: 0x0008, 0x11e4: 0xe00d, 0x11e5: 0x0008, 0x11e6: 0xe00d, 0x11e7: 0x0008, 0x11e8: 0xe00d, 0x11e9: 0x0008, 0x11ea: 0xe00d, 0x11eb: 0x0008, 0x11ec: 0xe00d, 0x11ed: 0x0008, 0x11ee: 0xe00d, 0x11ef: 0x0008, 0x11f0: 0xe0fd, 0x11f1: 0x0008, 0x11f2: 0x0008, 0x11f3: 0x0008, 0x11f4: 0x0008, 0x11f5: 0x0008, 0x11f6: 0x0008, 0x11f7: 0x0008, 0x11f8: 0x0008, 0x11f9: 0xe01d, 0x11fa: 0x0008, 0x11fb: 0xe03d, 0x11fc: 0x0008, 0x11fd: 0x442d, 0x11fe: 0xe00d, 0x11ff: 0x0008, // Block 0x48, offset 0x1200 0x1200: 0xe00d, 0x1201: 0x0008, 0x1202: 0xe00d, 0x1203: 0x0008, 0x1204: 0xe00d, 0x1205: 0x0008, 0x1206: 0xe00d, 0x1207: 0x0008, 0x1208: 0x0008, 0x1209: 0x0018, 0x120a: 0x0018, 0x120b: 0xe03d, 0x120c: 0x0008, 0x120d: 0x11d9, 0x120e: 0x0008, 0x120f: 0x0008, 0x1210: 0xe00d, 0x1211: 0x0008, 0x1212: 0xe00d, 0x1213: 0x0008, 0x1214: 0x0008, 0x1215: 0x0008, 0x1216: 0xe00d, 0x1217: 0x0008, 0x1218: 0xe00d, 0x1219: 0x0008, 0x121a: 0xe00d, 0x121b: 0x0008, 0x121c: 0xe00d, 0x121d: 0x0008, 0x121e: 0xe00d, 0x121f: 0x0008, 0x1220: 0xe00d, 0x1221: 0x0008, 0x1222: 0xe00d, 0x1223: 0x0008, 0x1224: 0xe00d, 0x1225: 0x0008, 0x1226: 0xe00d, 0x1227: 0x0008, 0x1228: 0xe00d, 0x1229: 0x0008, 0x122a: 0x6e29, 0x122b: 0x1029, 0x122c: 0x11c1, 0x122d: 0x6e41, 0x122e: 0x1221, 0x122f: 0x0040, 0x1230: 0x6e59, 0x1231: 0x6e71, 0x1232: 0x1239, 0x1233: 0x444d, 0x1234: 0xe00d, 0x1235: 0x0008, 0x1236: 0xe00d, 0x1237: 0x0008, 0x1238: 0x0040, 0x1239: 0x0040, 0x123a: 0x0040, 0x123b: 0x0040, 0x123c: 0x0040, 0x123d: 0x0040, 0x123e: 0x0040, 0x123f: 0x0040, // Block 0x49, offset 0x1240 0x1240: 0x64d5, 0x1241: 0x64f5, 0x1242: 0x6515, 0x1243: 0x6535, 0x1244: 0x6555, 0x1245: 0x6575, 0x1246: 0x6595, 0x1247: 0x65b5, 0x1248: 0x65d5, 0x1249: 0x65f5, 0x124a: 0x6615, 0x124b: 0x6635, 0x124c: 0x6655, 0x124d: 0x6675, 0x124e: 0x0008, 0x124f: 0x0008, 0x1250: 0x6695, 0x1251: 0x0008, 0x1252: 0x66b5, 0x1253: 0x0008, 0x1254: 0x0008, 0x1255: 0x66d5, 0x1256: 0x66f5, 0x1257: 0x6715, 0x1258: 0x6735, 0x1259: 0x6755, 0x125a: 0x6775, 0x125b: 0x6795, 0x125c: 0x67b5, 0x125d: 0x67d5, 0x125e: 0x67f5, 0x125f: 0x0008, 0x1260: 0x6815, 0x1261: 0x0008, 0x1262: 0x6835, 0x1263: 0x0008, 0x1264: 0x0008, 0x1265: 0x6855, 0x1266: 0x6875, 0x1267: 0x0008, 0x1268: 0x0008, 0x1269: 0x0008, 0x126a: 0x6895, 0x126b: 0x68b5, 0x126c: 0x68d5, 0x126d: 0x68f5, 0x126e: 0x6915, 0x126f: 0x6935, 0x1270: 0x6955, 0x1271: 0x6975, 0x1272: 0x6995, 0x1273: 0x69b5, 0x1274: 0x69d5, 0x1275: 0x69f5, 0x1276: 0x6a15, 0x1277: 0x6a35, 0x1278: 0x6a55, 0x1279: 0x6a75, 0x127a: 0x6a95, 0x127b: 0x6ab5, 0x127c: 0x6ad5, 0x127d: 0x6af5, 0x127e: 0x6b15, 0x127f: 0x6b35, // Block 0x4a, offset 0x1280 0x1280: 0x7a95, 0x1281: 0x7ab5, 0x1282: 0x7ad5, 0x1283: 0x7af5, 0x1284: 0x7b15, 0x1285: 0x7b35, 0x1286: 0x7b55, 0x1287: 0x7b75, 0x1288: 0x7b95, 0x1289: 0x7bb5, 0x128a: 0x7bd5, 0x128b: 0x7bf5, 0x128c: 0x7c15, 0x128d: 0x7c35, 0x128e: 0x7c55, 0x128f: 0x6ec9, 0x1290: 0x6ef1, 0x1291: 0x6f19, 0x1292: 0x7c75, 0x1293: 0x7c95, 0x1294: 0x7cb5, 0x1295: 0x6f41, 0x1296: 0x6f69, 0x1297: 0x6f91, 0x1298: 0x7cd5, 0x1299: 0x7cf5, 0x129a: 0x0040, 0x129b: 0x0040, 0x129c: 0x0040, 0x129d: 0x0040, 0x129e: 0x0040, 0x129f: 0x0040, 0x12a0: 0x0040, 0x12a1: 0x0040, 0x12a2: 0x0040, 0x12a3: 0x0040, 0x12a4: 0x0040, 0x12a5: 0x0040, 0x12a6: 0x0040, 0x12a7: 0x0040, 0x12a8: 0x0040, 0x12a9: 0x0040, 0x12aa: 0x0040, 0x12ab: 0x0040, 0x12ac: 0x0040, 0x12ad: 0x0040, 0x12ae: 0x0040, 0x12af: 0x0040, 0x12b0: 0x0040, 0x12b1: 0x0040, 0x12b2: 0x0040, 0x12b3: 0x0040, 0x12b4: 0x0040, 0x12b5: 0x0040, 0x12b6: 0x0040, 0x12b7: 0x0040, 0x12b8: 0x0040, 0x12b9: 0x0040, 0x12ba: 0x0040, 0x12bb: 0x0040, 0x12bc: 0x0040, 0x12bd: 0x0040, 0x12be: 0x0040, 0x12bf: 0x0040, // Block 0x4b, offset 0x12c0 0x12c0: 0x6fb9, 0x12c1: 0x6fd1, 0x12c2: 0x6fe9, 0x12c3: 0x7d15, 0x12c4: 0x7d35, 0x12c5: 0x7001, 0x12c6: 0x7001, 0x12c7: 0x0040, 0x12c8: 0x0040, 0x12c9: 0x0040, 0x12ca: 0x0040, 0x12cb: 0x0040, 0x12cc: 0x0040, 0x12cd: 0x0040, 0x12ce: 0x0040, 0x12cf: 0x0040, 0x12d0: 0x0040, 0x12d1: 0x0040, 0x12d2: 0x0040, 0x12d3: 0x7019, 0x12d4: 0x7041, 0x12d5: 0x7069, 0x12d6: 0x7091, 0x12d7: 0x70b9, 0x12d8: 0x0040, 0x12d9: 0x0040, 0x12da: 0x0040, 0x12db: 0x0040, 0x12dc: 0x0040, 0x12dd: 0x70e1, 0x12de: 0x3308, 0x12df: 0x7109, 0x12e0: 0x7131, 0x12e1: 0x20a9, 0x12e2: 0x20f1, 0x12e3: 0x7149, 0x12e4: 0x7161, 0x12e5: 0x7179, 0x12e6: 0x7191, 0x12e7: 0x71a9, 0x12e8: 0x71c1, 0x12e9: 0x1fb2, 0x12ea: 0x71d9, 0x12eb: 0x7201, 0x12ec: 0x7229, 0x12ed: 0x7261, 0x12ee: 0x7299, 0x12ef: 0x72c1, 0x12f0: 0x72e9, 0x12f1: 0x7311, 0x12f2: 0x7339, 0x12f3: 0x7361, 0x12f4: 0x7389, 0x12f5: 0x73b1, 0x12f6: 0x73d9, 0x12f7: 0x0040, 0x12f8: 0x7401, 0x12f9: 0x7429, 0x12fa: 0x7451, 0x12fb: 0x7479, 0x12fc: 0x74a1, 0x12fd: 0x0040, 0x12fe: 0x74c9, 0x12ff: 0x0040, // Block 0x4c, offset 0x1300 0x1300: 0x74f1, 0x1301: 0x7519, 0x1302: 0x0040, 0x1303: 0x7541, 0x1304: 0x7569, 0x1305: 0x0040, 0x1306: 0x7591, 0x1307: 0x75b9, 0x1308: 0x75e1, 0x1309: 0x7609, 0x130a: 0x7631, 0x130b: 0x7659, 0x130c: 0x7681, 0x130d: 0x76a9, 0x130e: 0x76d1, 0x130f: 0x76f9, 0x1310: 0x7721, 0x1311: 0x7721, 0x1312: 0x7739, 0x1313: 0x7739, 0x1314: 0x7739, 0x1315: 0x7739, 0x1316: 0x7751, 0x1317: 0x7751, 0x1318: 0x7751, 0x1319: 0x7751, 0x131a: 0x7769, 0x131b: 0x7769, 0x131c: 0x7769, 0x131d: 0x7769, 0x131e: 0x7781, 0x131f: 0x7781, 0x1320: 0x7781, 0x1321: 0x7781, 0x1322: 0x7799, 0x1323: 0x7799, 0x1324: 0x7799, 0x1325: 0x7799, 0x1326: 0x77b1, 0x1327: 0x77b1, 0x1328: 0x77b1, 0x1329: 0x77b1, 0x132a: 0x77c9, 0x132b: 0x77c9, 0x132c: 0x77c9, 0x132d: 0x77c9, 0x132e: 0x77e1, 0x132f: 0x77e1, 0x1330: 0x77e1, 0x1331: 0x77e1, 0x1332: 0x77f9, 0x1333: 0x77f9, 0x1334: 0x77f9, 0x1335: 0x77f9, 0x1336: 0x7811, 0x1337: 0x7811, 0x1338: 0x7811, 0x1339: 0x7811, 0x133a: 0x7829, 0x133b: 0x7829, 0x133c: 0x7829, 0x133d: 0x7829, 0x133e: 0x7841, 0x133f: 0x7841, // Block 0x4d, offset 0x1340 0x1340: 0x7841, 0x1341: 0x7841, 0x1342: 0x7859, 0x1343: 0x7859, 0x1344: 0x7871, 0x1345: 0x7871, 0x1346: 0x7889, 0x1347: 0x7889, 0x1348: 0x78a1, 0x1349: 0x78a1, 0x134a: 0x78b9, 0x134b: 0x78b9, 0x134c: 0x78d1, 0x134d: 0x78d1, 0x134e: 0x78e9, 0x134f: 0x78e9, 0x1350: 0x78e9, 0x1351: 0x78e9, 0x1352: 0x7901, 0x1353: 0x7901, 0x1354: 0x7901, 0x1355: 0x7901, 0x1356: 0x7919, 0x1357: 0x7919, 0x1358: 0x7919, 0x1359: 0x7919, 0x135a: 0x7931, 0x135b: 0x7931, 0x135c: 0x7931, 0x135d: 0x7931, 0x135e: 0x7949, 0x135f: 0x7949, 0x1360: 0x7961, 0x1361: 0x7961, 0x1362: 0x7961, 0x1363: 0x7961, 0x1364: 0x7979, 0x1365: 0x7979, 0x1366: 0x7991, 0x1367: 0x7991, 0x1368: 0x7991, 0x1369: 0x7991, 0x136a: 0x79a9, 0x136b: 0x79a9, 0x136c: 0x79a9, 0x136d: 0x79a9, 0x136e: 0x79c1, 0x136f: 0x79c1, 0x1370: 0x79d9, 0x1371: 0x79d9, 0x1372: 0x0818, 0x1373: 0x0818, 0x1374: 0x0818, 0x1375: 0x0818, 0x1376: 0x0818, 0x1377: 0x0818, 0x1378: 0x0818, 0x1379: 0x0818, 0x137a: 0x0818, 0x137b: 0x0818, 0x137c: 0x0818, 0x137d: 0x0818, 0x137e: 0x0818, 0x137f: 0x0818, // Block 0x4e, offset 0x1380 0x1380: 0x0818, 0x1381: 0x0818, 0x1382: 0x0040, 0x1383: 0x0040, 0x1384: 0x0040, 0x1385: 0x0040, 0x1386: 0x0040, 0x1387: 0x0040, 0x1388: 0x0040, 0x1389: 0x0040, 0x138a: 0x0040, 0x138b: 0x0040, 0x138c: 0x0040, 0x138d: 0x0040, 0x138e: 0x0040, 0x138f: 0x0040, 0x1390: 0x0040, 0x1391: 0x0040, 0x1392: 0x0040, 0x1393: 0x79f1, 0x1394: 0x79f1, 0x1395: 0x79f1, 0x1396: 0x79f1, 0x1397: 0x7a09, 0x1398: 0x7a09, 0x1399: 0x7a21, 0x139a: 0x7a21, 0x139b: 0x7a39, 0x139c: 0x7a39, 0x139d: 0x0479, 0x139e: 0x7a51, 0x139f: 0x7a51, 0x13a0: 0x7a69, 0x13a1: 0x7a69, 0x13a2: 0x7a81, 0x13a3: 0x7a81, 0x13a4: 0x7a99, 0x13a5: 0x7a99, 0x13a6: 0x7a99, 0x13a7: 0x7a99, 0x13a8: 0x7ab1, 0x13a9: 0x7ab1, 0x13aa: 0x7ac9, 0x13ab: 0x7ac9, 0x13ac: 0x7af1, 0x13ad: 0x7af1, 0x13ae: 0x7b19, 0x13af: 0x7b19, 0x13b0: 0x7b41, 0x13b1: 0x7b41, 0x13b2: 0x7b69, 0x13b3: 0x7b69, 0x13b4: 0x7b91, 0x13b5: 0x7b91, 0x13b6: 0x7bb9, 0x13b7: 0x7bb9, 0x13b8: 0x7bb9, 0x13b9: 0x7be1, 0x13ba: 0x7be1, 0x13bb: 0x7be1, 0x13bc: 0x7c09, 0x13bd: 0x7c09, 0x13be: 0x7c09, 0x13bf: 0x7c09, // Block 0x4f, offset 0x13c0 0x13c0: 0x85f9, 0x13c1: 0x8621, 0x13c2: 0x8649, 0x13c3: 0x8671, 0x13c4: 0x8699, 0x13c5: 0x86c1, 0x13c6: 0x86e9, 0x13c7: 0x8711, 0x13c8: 0x8739, 0x13c9: 0x8761, 0x13ca: 0x8789, 0x13cb: 0x87b1, 0x13cc: 0x87d9, 0x13cd: 0x8801, 0x13ce: 0x8829, 0x13cf: 0x8851, 0x13d0: 0x8879, 0x13d1: 0x88a1, 0x13d2: 0x88c9, 0x13d3: 0x88f1, 0x13d4: 0x8919, 0x13d5: 0x8941, 0x13d6: 0x8969, 0x13d7: 0x8991, 0x13d8: 0x89b9, 0x13d9: 0x89e1, 0x13da: 0x8a09, 0x13db: 0x8a31, 0x13dc: 0x8a59, 0x13dd: 0x8a81, 0x13de: 0x8aaa, 0x13df: 0x8ada, 0x13e0: 0x8b0a, 0x13e1: 0x8b3a, 0x13e2: 0x8b6a, 0x13e3: 0x8b9a, 0x13e4: 0x8bc9, 0x13e5: 0x8bf1, 0x13e6: 0x7c71, 0x13e7: 0x8c19, 0x13e8: 0x7be1, 0x13e9: 0x7c99, 0x13ea: 0x8c41, 0x13eb: 0x8c69, 0x13ec: 0x7d39, 0x13ed: 0x8c91, 0x13ee: 0x7d61, 0x13ef: 0x7d89, 0x13f0: 0x8cb9, 0x13f1: 0x8ce1, 0x13f2: 0x7e29, 0x13f3: 0x8d09, 0x13f4: 0x7e51, 0x13f5: 0x7e79, 0x13f6: 0x8d31, 0x13f7: 0x8d59, 0x13f8: 0x7ec9, 0x13f9: 0x8d81, 0x13fa: 0x7ef1, 0x13fb: 0x7f19, 0x13fc: 0x83a1, 0x13fd: 0x83c9, 0x13fe: 0x8441, 0x13ff: 0x8469, // Block 0x50, offset 0x1400 0x1400: 0x8491, 0x1401: 0x8531, 0x1402: 0x8559, 0x1403: 0x8581, 0x1404: 0x85a9, 0x1405: 0x8649, 0x1406: 0x8671, 0x1407: 0x8699, 0x1408: 0x8da9, 0x1409: 0x8739, 0x140a: 0x8dd1, 0x140b: 0x8df9, 0x140c: 0x8829, 0x140d: 0x8e21, 0x140e: 0x8851, 0x140f: 0x8879, 0x1410: 0x8a81, 0x1411: 0x8e49, 0x1412: 0x8e71, 0x1413: 0x89b9, 0x1414: 0x8e99, 0x1415: 0x89e1, 0x1416: 0x8a09, 0x1417: 0x7c21, 0x1418: 0x7c49, 0x1419: 0x8ec1, 0x141a: 0x7c71, 0x141b: 0x8ee9, 0x141c: 0x7cc1, 0x141d: 0x7ce9, 0x141e: 0x7d11, 0x141f: 0x7d39, 0x1420: 0x8f11, 0x1421: 0x7db1, 0x1422: 0x7dd9, 0x1423: 0x7e01, 0x1424: 0x7e29, 0x1425: 0x8f39, 0x1426: 0x7ec9, 0x1427: 0x7f41, 0x1428: 0x7f69, 0x1429: 0x7f91, 0x142a: 0x7fb9, 0x142b: 0x7fe1, 0x142c: 0x8031, 0x142d: 0x8059, 0x142e: 0x8081, 0x142f: 0x80a9, 0x1430: 0x80d1, 0x1431: 0x80f9, 0x1432: 0x8f61, 0x1433: 0x8121, 0x1434: 0x8149, 0x1435: 0x8171, 0x1436: 0x8199, 0x1437: 0x81c1, 0x1438: 0x81e9, 0x1439: 0x8239, 0x143a: 0x8261, 0x143b: 0x8289, 0x143c: 0x82b1, 0x143d: 0x82d9, 0x143e: 0x8301, 0x143f: 0x8329, // Block 0x51, offset 0x1440 0x1440: 0x8351, 0x1441: 0x8379, 0x1442: 0x83f1, 0x1443: 0x8419, 0x1444: 0x84b9, 0x1445: 0x84e1, 0x1446: 0x8509, 0x1447: 0x8531, 0x1448: 0x8559, 0x1449: 0x85d1, 0x144a: 0x85f9, 0x144b: 0x8621, 0x144c: 0x8649, 0x144d: 0x8f89, 0x144e: 0x86c1, 0x144f: 0x86e9, 0x1450: 0x8711, 0x1451: 0x8739, 0x1452: 0x87b1, 0x1453: 0x87d9, 0x1454: 0x8801, 0x1455: 0x8829, 0x1456: 0x8fb1, 0x1457: 0x88a1, 0x1458: 0x88c9, 0x1459: 0x8fd9, 0x145a: 0x8941, 0x145b: 0x8969, 0x145c: 0x8991, 0x145d: 0x89b9, 0x145e: 0x9001, 0x145f: 0x7c71, 0x1460: 0x8ee9, 0x1461: 0x7d39, 0x1462: 0x8f11, 0x1463: 0x7e29, 0x1464: 0x8f39, 0x1465: 0x7ec9, 0x1466: 0x9029, 0x1467: 0x80d1, 0x1468: 0x9051, 0x1469: 0x9079, 0x146a: 0x90a1, 0x146b: 0x8531, 0x146c: 0x8559, 0x146d: 0x8649, 0x146e: 0x8829, 0x146f: 0x8fb1, 0x1470: 0x89b9, 0x1471: 0x9001, 0x1472: 0x90c9, 0x1473: 0x9101, 0x1474: 0x9139, 0x1475: 0x9171, 0x1476: 0x9199, 0x1477: 0x91c1, 0x1478: 0x91e9, 0x1479: 0x9211, 0x147a: 0x9239, 0x147b: 0x9261, 0x147c: 0x9289, 0x147d: 0x92b1, 0x147e: 0x92d9, 0x147f: 0x9301, // Block 0x52, offset 0x1480 0x1480: 0x9329, 0x1481: 0x9351, 0x1482: 0x9379, 0x1483: 0x93a1, 0x1484: 0x93c9, 0x1485: 0x93f1, 0x1486: 0x9419, 0x1487: 0x9441, 0x1488: 0x9469, 0x1489: 0x9491, 0x148a: 0x94b9, 0x148b: 0x94e1, 0x148c: 0x9079, 0x148d: 0x9509, 0x148e: 0x9531, 0x148f: 0x9559, 0x1490: 0x9581, 0x1491: 0x9171, 0x1492: 0x9199, 0x1493: 0x91c1, 0x1494: 0x91e9, 0x1495: 0x9211, 0x1496: 0x9239, 0x1497: 0x9261, 0x1498: 0x9289, 0x1499: 0x92b1, 0x149a: 0x92d9, 0x149b: 0x9301, 0x149c: 0x9329, 0x149d: 0x9351, 0x149e: 0x9379, 0x149f: 0x93a1, 0x14a0: 0x93c9, 0x14a1: 0x93f1, 0x14a2: 0x9419, 0x14a3: 0x9441, 0x14a4: 0x9469, 0x14a5: 0x9491, 0x14a6: 0x94b9, 0x14a7: 0x94e1, 0x14a8: 0x9079, 0x14a9: 0x9509, 0x14aa: 0x9531, 0x14ab: 0x9559, 0x14ac: 0x9581, 0x14ad: 0x9491, 0x14ae: 0x94b9, 0x14af: 0x94e1, 0x14b0: 0x9079, 0x14b1: 0x9051, 0x14b2: 0x90a1, 0x14b3: 0x8211, 0x14b4: 0x8059, 0x14b5: 0x8081, 0x14b6: 0x80a9, 0x14b7: 0x9491, 0x14b8: 0x94b9, 0x14b9: 0x94e1, 0x14ba: 0x8211, 0x14bb: 0x8239, 0x14bc: 0x95a9, 0x14bd: 0x95a9, 0x14be: 0x0018, 0x14bf: 0x0018, // Block 0x53, offset 0x14c0 0x14c0: 0x0040, 0x14c1: 0x0040, 0x14c2: 0x0040, 0x14c3: 0x0040, 0x14c4: 0x0040, 0x14c5: 0x0040, 0x14c6: 0x0040, 0x14c7: 0x0040, 0x14c8: 0x0040, 0x14c9: 0x0040, 0x14ca: 0x0040, 0x14cb: 0x0040, 0x14cc: 0x0040, 0x14cd: 0x0040, 0x14ce: 0x0040, 0x14cf: 0x0040, 0x14d0: 0x95d1, 0x14d1: 0x9609, 0x14d2: 0x9609, 0x14d3: 0x9641, 0x14d4: 0x9679, 0x14d5: 0x96b1, 0x14d6: 0x96e9, 0x14d7: 0x9721, 0x14d8: 0x9759, 0x14d9: 0x9759, 0x14da: 0x9791, 0x14db: 0x97c9, 0x14dc: 0x9801, 0x14dd: 0x9839, 0x14de: 0x9871, 0x14df: 0x98a9, 0x14e0: 0x98a9, 0x14e1: 0x98e1, 0x14e2: 0x9919, 0x14e3: 0x9919, 0x14e4: 0x9951, 0x14e5: 0x9951, 0x14e6: 0x9989, 0x14e7: 0x99c1, 0x14e8: 0x99c1, 0x14e9: 0x99f9, 0x14ea: 0x9a31, 0x14eb: 0x9a31, 0x14ec: 0x9a69, 0x14ed: 0x9a69, 0x14ee: 0x9aa1, 0x14ef: 0x9ad9, 0x14f0: 0x9ad9, 0x14f1: 0x9b11, 0x14f2: 0x9b11, 0x14f3: 0x9b49, 0x14f4: 0x9b81, 0x14f5: 0x9bb9, 0x14f6: 0x9bf1, 0x14f7: 0x9bf1, 0x14f8: 0x9c29, 0x14f9: 0x9c61, 0x14fa: 0x9c99, 0x14fb: 0x9cd1, 0x14fc: 0x9d09, 0x14fd: 0x9d09, 0x14fe: 0x9d41, 0x14ff: 0x9d79, // Block 0x54, offset 0x1500 0x1500: 0xa949, 0x1501: 0xa981, 0x1502: 0xa9b9, 0x1503: 0xa8a1, 0x1504: 0x9bb9, 0x1505: 0x9989, 0x1506: 0xa9f1, 0x1507: 0xaa29, 0x1508: 0x0040, 0x1509: 0x0040, 0x150a: 0x0040, 0x150b: 0x0040, 0x150c: 0x0040, 0x150d: 0x0040, 0x150e: 0x0040, 0x150f: 0x0040, 0x1510: 0x0040, 0x1511: 0x0040, 0x1512: 0x0040, 0x1513: 0x0040, 0x1514: 0x0040, 0x1515: 0x0040, 0x1516: 0x0040, 0x1517: 0x0040, 0x1518: 0x0040, 0x1519: 0x0040, 0x151a: 0x0040, 0x151b: 0x0040, 0x151c: 0x0040, 0x151d: 0x0040, 0x151e: 0x0040, 0x151f: 0x0040, 0x1520: 0x0040, 0x1521: 0x0040, 0x1522: 0x0040, 0x1523: 0x0040, 0x1524: 0x0040, 0x1525: 0x0040, 0x1526: 0x0040, 0x1527: 0x0040, 0x1528: 0x0040, 0x1529: 0x0040, 0x152a: 0x0040, 0x152b: 0x0040, 0x152c: 0x0040, 0x152d: 0x0040, 0x152e: 0x0040, 0x152f: 0x0040, 0x1530: 0xaa61, 0x1531: 0xaa99, 0x1532: 0xaad1, 0x1533: 0xab19, 0x1534: 0xab61, 0x1535: 0xaba9, 0x1536: 0xabf1, 0x1537: 0xac39, 0x1538: 0xac81, 0x1539: 0xacc9, 0x153a: 0xad02, 0x153b: 0xae12, 0x153c: 0xae91, 0x153d: 0x0018, 0x153e: 0x0040, 0x153f: 0x0040, // Block 0x55, offset 0x1540 0x1540: 0x33c0, 0x1541: 0x33c0, 0x1542: 0x33c0, 0x1543: 0x33c0, 0x1544: 0x33c0, 0x1545: 0x33c0, 0x1546: 0x33c0, 0x1547: 0x33c0, 0x1548: 0x33c0, 0x1549: 0x33c0, 0x154a: 0x33c0, 0x154b: 0x33c0, 0x154c: 0x33c0, 0x154d: 0x33c0, 0x154e: 0x33c0, 0x154f: 0x33c0, 0x1550: 0xaeda, 0x1551: 0x7d55, 0x1552: 0x0040, 0x1553: 0xaeea, 0x1554: 0x03c2, 0x1555: 0xaefa, 0x1556: 0xaf0a, 0x1557: 0x7d75, 0x1558: 0x7d95, 0x1559: 0x0040, 0x155a: 0x0040, 0x155b: 0x0040, 0x155c: 0x0040, 0x155d: 0x0040, 0x155e: 0x0040, 0x155f: 0x0040, 0x1560: 0x3308, 0x1561: 0x3308, 0x1562: 0x3308, 0x1563: 0x3308, 0x1564: 0x3308, 0x1565: 0x3308, 0x1566: 0x3308, 0x1567: 0x3308, 0x1568: 0x3308, 0x1569: 0x3308, 0x156a: 0x3308, 0x156b: 0x3308, 0x156c: 0x3308, 0x156d: 0x3308, 0x156e: 0x3308, 0x156f: 0x3308, 0x1570: 0x0040, 0x1571: 0x7db5, 0x1572: 0x7dd5, 0x1573: 0xaf1a, 0x1574: 0xaf1a, 0x1575: 0x1fd2, 0x1576: 0x1fe2, 0x1577: 0xaf2a, 0x1578: 0xaf3a, 0x1579: 0x7df5, 0x157a: 0x7e15, 0x157b: 0x7e35, 0x157c: 0x7df5, 0x157d: 0x7e55, 0x157e: 0x7e75, 0x157f: 0x7e55, // Block 0x56, offset 0x1580 0x1580: 0x7e95, 0x1581: 0x7eb5, 0x1582: 0x7ed5, 0x1583: 0x7eb5, 0x1584: 0x7ef5, 0x1585: 0x0018, 0x1586: 0x0018, 0x1587: 0xaf4a, 0x1588: 0xaf5a, 0x1589: 0x7f16, 0x158a: 0x7f36, 0x158b: 0x7f56, 0x158c: 0x7f76, 0x158d: 0xaf1a, 0x158e: 0xaf1a, 0x158f: 0xaf1a, 0x1590: 0xaeda, 0x1591: 0x7f95, 0x1592: 0x0040, 0x1593: 0x0040, 0x1594: 0x03c2, 0x1595: 0xaeea, 0x1596: 0xaf0a, 0x1597: 0xaefa, 0x1598: 0x7fb5, 0x1599: 0x1fd2, 0x159a: 0x1fe2, 0x159b: 0xaf2a, 0x159c: 0xaf3a, 0x159d: 0x7e95, 0x159e: 0x7ef5, 0x159f: 0xaf6a, 0x15a0: 0xaf7a, 0x15a1: 0xaf8a, 0x15a2: 0x1fb2, 0x15a3: 0xaf99, 0x15a4: 0xafaa, 0x15a5: 0xafba, 0x15a6: 0x1fc2, 0x15a7: 0x0040, 0x15a8: 0xafca, 0x15a9: 0xafda, 0x15aa: 0xafea, 0x15ab: 0xaffa, 0x15ac: 0x0040, 0x15ad: 0x0040, 0x15ae: 0x0040, 0x15af: 0x0040, 0x15b0: 0x7fd6, 0x15b1: 0xb009, 0x15b2: 0x7ff6, 0x15b3: 0x0808, 0x15b4: 0x8016, 0x15b5: 0x0040, 0x15b6: 0x8036, 0x15b7: 0xb031, 0x15b8: 0x8056, 0x15b9: 0xb059, 0x15ba: 0x8076, 0x15bb: 0xb081, 0x15bc: 0x8096, 0x15bd: 0xb0a9, 0x15be: 0x80b6, 0x15bf: 0xb0d1, // Block 0x57, offset 0x15c0 0x15c0: 0xb0f9, 0x15c1: 0xb111, 0x15c2: 0xb111, 0x15c3: 0xb129, 0x15c4: 0xb129, 0x15c5: 0xb141, 0x15c6: 0xb141, 0x15c7: 0xb159, 0x15c8: 0xb159, 0x15c9: 0xb171, 0x15ca: 0xb171, 0x15cb: 0xb171, 0x15cc: 0xb171, 0x15cd: 0xb189, 0x15ce: 0xb189, 0x15cf: 0xb1a1, 0x15d0: 0xb1a1, 0x15d1: 0xb1a1, 0x15d2: 0xb1a1, 0x15d3: 0xb1b9, 0x15d4: 0xb1b9, 0x15d5: 0xb1d1, 0x15d6: 0xb1d1, 0x15d7: 0xb1d1, 0x15d8: 0xb1d1, 0x15d9: 0xb1e9, 0x15da: 0xb1e9, 0x15db: 0xb1e9, 0x15dc: 0xb1e9, 0x15dd: 0xb201, 0x15de: 0xb201, 0x15df: 0xb201, 0x15e0: 0xb201, 0x15e1: 0xb219, 0x15e2: 0xb219, 0x15e3: 0xb219, 0x15e4: 0xb219, 0x15e5: 0xb231, 0x15e6: 0xb231, 0x15e7: 0xb231, 0x15e8: 0xb231, 0x15e9: 0xb249, 0x15ea: 0xb249, 0x15eb: 0xb261, 0x15ec: 0xb261, 0x15ed: 0xb279, 0x15ee: 0xb279, 0x15ef: 0xb291, 0x15f0: 0xb291, 0x15f1: 0xb2a9, 0x15f2: 0xb2a9, 0x15f3: 0xb2a9, 0x15f4: 0xb2a9, 0x15f5: 0xb2c1, 0x15f6: 0xb2c1, 0x15f7: 0xb2c1, 0x15f8: 0xb2c1, 0x15f9: 0xb2d9, 0x15fa: 0xb2d9, 0x15fb: 0xb2d9, 0x15fc: 0xb2d9, 0x15fd: 0xb2f1, 0x15fe: 0xb2f1, 0x15ff: 0xb2f1, // Block 0x58, offset 0x1600 0x1600: 0xb2f1, 0x1601: 0xb309, 0x1602: 0xb309, 0x1603: 0xb309, 0x1604: 0xb309, 0x1605: 0xb321, 0x1606: 0xb321, 0x1607: 0xb321, 0x1608: 0xb321, 0x1609: 0xb339, 0x160a: 0xb339, 0x160b: 0xb339, 0x160c: 0xb339, 0x160d: 0xb351, 0x160e: 0xb351, 0x160f: 0xb351, 0x1610: 0xb351, 0x1611: 0xb369, 0x1612: 0xb369, 0x1613: 0xb369, 0x1614: 0xb369, 0x1615: 0xb381, 0x1616: 0xb381, 0x1617: 0xb381, 0x1618: 0xb381, 0x1619: 0xb399, 0x161a: 0xb399, 0x161b: 0xb399, 0x161c: 0xb399, 0x161d: 0xb3b1, 0x161e: 0xb3b1, 0x161f: 0xb3b1, 0x1620: 0xb3b1, 0x1621: 0xb3c9, 0x1622: 0xb3c9, 0x1623: 0xb3c9, 0x1624: 0xb3c9, 0x1625: 0xb3e1, 0x1626: 0xb3e1, 0x1627: 0xb3e1, 0x1628: 0xb3e1, 0x1629: 0xb3f9, 0x162a: 0xb3f9, 0x162b: 0xb3f9, 0x162c: 0xb3f9, 0x162d: 0xb411, 0x162e: 0xb411, 0x162f: 0x7ab1, 0x1630: 0x7ab1, 0x1631: 0xb429, 0x1632: 0xb429, 0x1633: 0xb429, 0x1634: 0xb429, 0x1635: 0xb441, 0x1636: 0xb441, 0x1637: 0xb469, 0x1638: 0xb469, 0x1639: 0xb491, 0x163a: 0xb491, 0x163b: 0xb4b9, 0x163c: 0xb4b9, 0x163d: 0x0040, 0x163e: 0x0040, 0x163f: 0x03c0, // Block 0x59, offset 0x1640 0x1640: 0x0040, 0x1641: 0xaefa, 0x1642: 0xb4e2, 0x1643: 0xaf6a, 0x1644: 0xafda, 0x1645: 0xafea, 0x1646: 0xaf7a, 0x1647: 0xb4f2, 0x1648: 0x1fd2, 0x1649: 0x1fe2, 0x164a: 0xaf8a, 0x164b: 0x1fb2, 0x164c: 0xaeda, 0x164d: 0xaf99, 0x164e: 0x29d1, 0x164f: 0xb502, 0x1650: 0x1f41, 0x1651: 0x00c9, 0x1652: 0x0069, 0x1653: 0x0079, 0x1654: 0x1f51, 0x1655: 0x1f61, 0x1656: 0x1f71, 0x1657: 0x1f81, 0x1658: 0x1f91, 0x1659: 0x1fa1, 0x165a: 0xaeea, 0x165b: 0x03c2, 0x165c: 0xafaa, 0x165d: 0x1fc2, 0x165e: 0xafba, 0x165f: 0xaf0a, 0x1660: 0xaffa, 0x1661: 0x0039, 0x1662: 0x0ee9, 0x1663: 0x1159, 0x1664: 0x0ef9, 0x1665: 0x0f09, 0x1666: 0x1199, 0x1667: 0x0f31, 0x1668: 0x0249, 0x1669: 0x0f41, 0x166a: 0x0259, 0x166b: 0x0f51, 0x166c: 0x0359, 0x166d: 0x0f61, 0x166e: 0x0f71, 0x166f: 0x00d9, 0x1670: 0x0f99, 0x1671: 0x2039, 0x1672: 0x0269, 0x1673: 0x01d9, 0x1674: 0x0fa9, 0x1675: 0x0fb9, 0x1676: 0x1089, 0x1677: 0x0279, 0x1678: 0x0369, 0x1679: 0x0289, 0x167a: 0x13d1, 0x167b: 0xaf4a, 0x167c: 0xafca, 0x167d: 0xaf5a, 0x167e: 0xb512, 0x167f: 0xaf1a, // Block 0x5a, offset 0x1680 0x1680: 0x1caa, 0x1681: 0x0039, 0x1682: 0x0ee9, 0x1683: 0x1159, 0x1684: 0x0ef9, 0x1685: 0x0f09, 0x1686: 0x1199, 0x1687: 0x0f31, 0x1688: 0x0249, 0x1689: 0x0f41, 0x168a: 0x0259, 0x168b: 0x0f51, 0x168c: 0x0359, 0x168d: 0x0f61, 0x168e: 0x0f71, 0x168f: 0x00d9, 0x1690: 0x0f99, 0x1691: 0x2039, 0x1692: 0x0269, 0x1693: 0x01d9, 0x1694: 0x0fa9, 0x1695: 0x0fb9, 0x1696: 0x1089, 0x1697: 0x0279, 0x1698: 0x0369, 0x1699: 0x0289, 0x169a: 0x13d1, 0x169b: 0xaf2a, 0x169c: 0xb522, 0x169d: 0xaf3a, 0x169e: 0xb532, 0x169f: 0x80d5, 0x16a0: 0x80f5, 0x16a1: 0x29d1, 0x16a2: 0x8115, 0x16a3: 0x8115, 0x16a4: 0x8135, 0x16a5: 0x8155, 0x16a6: 0x8175, 0x16a7: 0x8195, 0x16a8: 0x81b5, 0x16a9: 0x81d5, 0x16aa: 0x81f5, 0x16ab: 0x8215, 0x16ac: 0x8235, 0x16ad: 0x8255, 0x16ae: 0x8275, 0x16af: 0x8295, 0x16b0: 0x82b5, 0x16b1: 0x82d5, 0x16b2: 0x82f5, 0x16b3: 0x8315, 0x16b4: 0x8335, 0x16b5: 0x8355, 0x16b6: 0x8375, 0x16b7: 0x8395, 0x16b8: 0x83b5, 0x16b9: 0x83d5, 0x16ba: 0x83f5, 0x16bb: 0x8415, 0x16bc: 0x81b5, 0x16bd: 0x8435, 0x16be: 0x8455, 0x16bf: 0x8215, // Block 0x5b, offset 0x16c0 0x16c0: 0x8475, 0x16c1: 0x8495, 0x16c2: 0x84b5, 0x16c3: 0x84d5, 0x16c4: 0x84f5, 0x16c5: 0x8515, 0x16c6: 0x8535, 0x16c7: 0x8555, 0x16c8: 0x84d5, 0x16c9: 0x8575, 0x16ca: 0x84d5, 0x16cb: 0x8595, 0x16cc: 0x8595, 0x16cd: 0x85b5, 0x16ce: 0x85b5, 0x16cf: 0x85d5, 0x16d0: 0x8515, 0x16d1: 0x85f5, 0x16d2: 0x8615, 0x16d3: 0x85f5, 0x16d4: 0x8635, 0x16d5: 0x8615, 0x16d6: 0x8655, 0x16d7: 0x8655, 0x16d8: 0x8675, 0x16d9: 0x8675, 0x16da: 0x8695, 0x16db: 0x8695, 0x16dc: 0x8615, 0x16dd: 0x8115, 0x16de: 0x86b5, 0x16df: 0x86d5, 0x16e0: 0x0040, 0x16e1: 0x86f5, 0x16e2: 0x8715, 0x16e3: 0x8735, 0x16e4: 0x8755, 0x16e5: 0x8735, 0x16e6: 0x8775, 0x16e7: 0x8795, 0x16e8: 0x87b5, 0x16e9: 0x87b5, 0x16ea: 0x87d5, 0x16eb: 0x87d5, 0x16ec: 0x87f5, 0x16ed: 0x87f5, 0x16ee: 0x87d5, 0x16ef: 0x87d5, 0x16f0: 0x8815, 0x16f1: 0x8835, 0x16f2: 0x8855, 0x16f3: 0x8875, 0x16f4: 0x8895, 0x16f5: 0x88b5, 0x16f6: 0x88b5, 0x16f7: 0x88b5, 0x16f8: 0x88d5, 0x16f9: 0x88d5, 0x16fa: 0x88d5, 0x16fb: 0x88d5, 0x16fc: 0x87b5, 0x16fd: 0x87b5, 0x16fe: 0x87b5, 0x16ff: 0x0040, // Block 0x5c, offset 0x1700 0x1700: 0x0040, 0x1701: 0x0040, 0x1702: 0x8715, 0x1703: 0x86f5, 0x1704: 0x88f5, 0x1705: 0x86f5, 0x1706: 0x8715, 0x1707: 0x86f5, 0x1708: 0x0040, 0x1709: 0x0040, 0x170a: 0x8915, 0x170b: 0x8715, 0x170c: 0x8935, 0x170d: 0x88f5, 0x170e: 0x8935, 0x170f: 0x8715, 0x1710: 0x0040, 0x1711: 0x0040, 0x1712: 0x8955, 0x1713: 0x8975, 0x1714: 0x8875, 0x1715: 0x8935, 0x1716: 0x88f5, 0x1717: 0x8935, 0x1718: 0x0040, 0x1719: 0x0040, 0x171a: 0x8995, 0x171b: 0x89b5, 0x171c: 0x8995, 0x171d: 0x0040, 0x171e: 0x0040, 0x171f: 0x0040, 0x1720: 0xb541, 0x1721: 0xb559, 0x1722: 0xb571, 0x1723: 0x89d6, 0x1724: 0xb589, 0x1725: 0xb5a1, 0x1726: 0x89f5, 0x1727: 0x0040, 0x1728: 0x8a15, 0x1729: 0x8a35, 0x172a: 0x8a55, 0x172b: 0x8a35, 0x172c: 0x8a75, 0x172d: 0x8a95, 0x172e: 0x8ab5, 0x172f: 0x0040, 0x1730: 0x0040, 0x1731: 0x0040, 0x1732: 0x0040, 0x1733: 0x0040, 0x1734: 0x0040, 0x1735: 0x0040, 0x1736: 0x0040, 0x1737: 0x0040, 0x1738: 0x0040, 0x1739: 0x0340, 0x173a: 0x0340, 0x173b: 0x0340, 0x173c: 0x0040, 0x173d: 0x0040, 0x173e: 0x0040, 0x173f: 0x0040, // Block 0x5d, offset 0x1740 0x1740: 0x0a08, 0x1741: 0x0a08, 0x1742: 0x0a08, 0x1743: 0x0a08, 0x1744: 0x0a08, 0x1745: 0x0c08, 0x1746: 0x0808, 0x1747: 0x0c08, 0x1748: 0x0818, 0x1749: 0x0c08, 0x174a: 0x0c08, 0x174b: 0x0808, 0x174c: 0x0808, 0x174d: 0x0908, 0x174e: 0x0c08, 0x174f: 0x0c08, 0x1750: 0x0c08, 0x1751: 0x0c08, 0x1752: 0x0c08, 0x1753: 0x0a08, 0x1754: 0x0a08, 0x1755: 0x0a08, 0x1756: 0x0a08, 0x1757: 0x0908, 0x1758: 0x0a08, 0x1759: 0x0a08, 0x175a: 0x0a08, 0x175b: 0x0a08, 0x175c: 0x0a08, 0x175d: 0x0c08, 0x175e: 0x0a08, 0x175f: 0x0a08, 0x1760: 0x0a08, 0x1761: 0x0c08, 0x1762: 0x0808, 0x1763: 0x0808, 0x1764: 0x0c08, 0x1765: 0x3308, 0x1766: 0x3308, 0x1767: 0x0040, 0x1768: 0x0040, 0x1769: 0x0040, 0x176a: 0x0040, 0x176b: 0x0a18, 0x176c: 0x0a18, 0x176d: 0x0a18, 0x176e: 0x0a18, 0x176f: 0x0c18, 0x1770: 0x0818, 0x1771: 0x0818, 0x1772: 0x0818, 0x1773: 0x0818, 0x1774: 0x0818, 0x1775: 0x0818, 0x1776: 0x0818, 0x1777: 0x0040, 0x1778: 0x0040, 0x1779: 0x0040, 0x177a: 0x0040, 0x177b: 0x0040, 0x177c: 0x0040, 0x177d: 0x0040, 0x177e: 0x0040, 0x177f: 0x0040, // Block 0x5e, offset 0x1780 0x1780: 0x0a08, 0x1781: 0x0c08, 0x1782: 0x0a08, 0x1783: 0x0c08, 0x1784: 0x0c08, 0x1785: 0x0c08, 0x1786: 0x0a08, 0x1787: 0x0a08, 0x1788: 0x0a08, 0x1789: 0x0c08, 0x178a: 0x0a08, 0x178b: 0x0a08, 0x178c: 0x0c08, 0x178d: 0x0a08, 0x178e: 0x0c08, 0x178f: 0x0c08, 0x1790: 0x0a08, 0x1791: 0x0c08, 0x1792: 0x0040, 0x1793: 0x0040, 0x1794: 0x0040, 0x1795: 0x0040, 0x1796: 0x0040, 0x1797: 0x0040, 0x1798: 0x0040, 0x1799: 0x0818, 0x179a: 0x0818, 0x179b: 0x0818, 0x179c: 0x0818, 0x179d: 0x0040, 0x179e: 0x0040, 0x179f: 0x0040, 0x17a0: 0x0040, 0x17a1: 0x0040, 0x17a2: 0x0040, 0x17a3: 0x0040, 0x17a4: 0x0040, 0x17a5: 0x0040, 0x17a6: 0x0040, 0x17a7: 0x0040, 0x17a8: 0x0040, 0x17a9: 0x0c18, 0x17aa: 0x0c18, 0x17ab: 0x0c18, 0x17ac: 0x0c18, 0x17ad: 0x0a18, 0x17ae: 0x0a18, 0x17af: 0x0818, 0x17b0: 0x0040, 0x17b1: 0x0040, 0x17b2: 0x0040, 0x17b3: 0x0040, 0x17b4: 0x0040, 0x17b5: 0x0040, 0x17b6: 0x0040, 0x17b7: 0x0040, 0x17b8: 0x0040, 0x17b9: 0x0040, 0x17ba: 0x0040, 0x17bb: 0x0040, 0x17bc: 0x0040, 0x17bd: 0x0040, 0x17be: 0x0040, 0x17bf: 0x0040, // Block 0x5f, offset 0x17c0 0x17c0: 0x3308, 0x17c1: 0x3308, 0x17c2: 0x3008, 0x17c3: 0x3008, 0x17c4: 0x0040, 0x17c5: 0x0008, 0x17c6: 0x0008, 0x17c7: 0x0008, 0x17c8: 0x0008, 0x17c9: 0x0008, 0x17ca: 0x0008, 0x17cb: 0x0008, 0x17cc: 0x0008, 0x17cd: 0x0040, 0x17ce: 0x0040, 0x17cf: 0x0008, 0x17d0: 0x0008, 0x17d1: 0x0040, 0x17d2: 0x0040, 0x17d3: 0x0008, 0x17d4: 0x0008, 0x17d5: 0x0008, 0x17d6: 0x0008, 0x17d7: 0x0008, 0x17d8: 0x0008, 0x17d9: 0x0008, 0x17da: 0x0008, 0x17db: 0x0008, 0x17dc: 0x0008, 0x17dd: 0x0008, 0x17de: 0x0008, 0x17df: 0x0008, 0x17e0: 0x0008, 0x17e1: 0x0008, 0x17e2: 0x0008, 0x17e3: 0x0008, 0x17e4: 0x0008, 0x17e5: 0x0008, 0x17e6: 0x0008, 0x17e7: 0x0008, 0x17e8: 0x0008, 0x17e9: 0x0040, 0x17ea: 0x0008, 0x17eb: 0x0008, 0x17ec: 0x0008, 0x17ed: 0x0008, 0x17ee: 0x0008, 0x17ef: 0x0008, 0x17f0: 0x0008, 0x17f1: 0x0040, 0x17f2: 0x0008, 0x17f3: 0x0008, 0x17f4: 0x0040, 0x17f5: 0x0008, 0x17f6: 0x0008, 0x17f7: 0x0008, 0x17f8: 0x0008, 0x17f9: 0x0008, 0x17fa: 0x0040, 0x17fb: 0x0040, 0x17fc: 0x3308, 0x17fd: 0x0008, 0x17fe: 0x3008, 0x17ff: 0x3008, // Block 0x60, offset 0x1800 0x1800: 0x3308, 0x1801: 0x3008, 0x1802: 0x3008, 0x1803: 0x3008, 0x1804: 0x3008, 0x1805: 0x0040, 0x1806: 0x0040, 0x1807: 0x3008, 0x1808: 0x3008, 0x1809: 0x0040, 0x180a: 0x0040, 0x180b: 0x3008, 0x180c: 0x3008, 0x180d: 0x3808, 0x180e: 0x0040, 0x180f: 0x0040, 0x1810: 0x0008, 0x1811: 0x0040, 0x1812: 0x0040, 0x1813: 0x0040, 0x1814: 0x0040, 0x1815: 0x0040, 0x1816: 0x0040, 0x1817: 0x3008, 0x1818: 0x0040, 0x1819: 0x0040, 0x181a: 0x0040, 0x181b: 0x0040, 0x181c: 0x0040, 0x181d: 0x0008, 0x181e: 0x0008, 0x181f: 0x0008, 0x1820: 0x0008, 0x1821: 0x0008, 0x1822: 0x3008, 0x1823: 0x3008, 0x1824: 0x0040, 0x1825: 0x0040, 0x1826: 0x3308, 0x1827: 0x3308, 0x1828: 0x3308, 0x1829: 0x3308, 0x182a: 0x3308, 0x182b: 0x3308, 0x182c: 0x3308, 0x182d: 0x0040, 0x182e: 0x0040, 0x182f: 0x0040, 0x1830: 0x3308, 0x1831: 0x3308, 0x1832: 0x3308, 0x1833: 0x3308, 0x1834: 0x3308, 0x1835: 0x0040, 0x1836: 0x0040, 0x1837: 0x0040, 0x1838: 0x0040, 0x1839: 0x0040, 0x183a: 0x0040, 0x183b: 0x0040, 0x183c: 0x0040, 0x183d: 0x0040, 0x183e: 0x0040, 0x183f: 0x0040, // Block 0x61, offset 0x1840 0x1840: 0x0039, 0x1841: 0x0ee9, 0x1842: 0x1159, 0x1843: 0x0ef9, 0x1844: 0x0f09, 0x1845: 0x1199, 0x1846: 0x0f31, 0x1847: 0x0249, 0x1848: 0x0f41, 0x1849: 0x0259, 0x184a: 0x0f51, 0x184b: 0x0359, 0x184c: 0x0f61, 0x184d: 0x0f71, 0x184e: 0x00d9, 0x184f: 0x0f99, 0x1850: 0x2039, 0x1851: 0x0269, 0x1852: 0x01d9, 0x1853: 0x0fa9, 0x1854: 0x0fb9, 0x1855: 0x1089, 0x1856: 0x0279, 0x1857: 0x0369, 0x1858: 0x0289, 0x1859: 0x13d1, 0x185a: 0x0039, 0x185b: 0x0ee9, 0x185c: 0x1159, 0x185d: 0x0ef9, 0x185e: 0x0f09, 0x185f: 0x1199, 0x1860: 0x0f31, 0x1861: 0x0249, 0x1862: 0x0f41, 0x1863: 0x0259, 0x1864: 0x0f51, 0x1865: 0x0359, 0x1866: 0x0f61, 0x1867: 0x0f71, 0x1868: 0x00d9, 0x1869: 0x0f99, 0x186a: 0x2039, 0x186b: 0x0269, 0x186c: 0x01d9, 0x186d: 0x0fa9, 0x186e: 0x0fb9, 0x186f: 0x1089, 0x1870: 0x0279, 0x1871: 0x0369, 0x1872: 0x0289, 0x1873: 0x13d1, 0x1874: 0x0039, 0x1875: 0x0ee9, 0x1876: 0x1159, 0x1877: 0x0ef9, 0x1878: 0x0f09, 0x1879: 0x1199, 0x187a: 0x0f31, 0x187b: 0x0249, 0x187c: 0x0f41, 0x187d: 0x0259, 0x187e: 0x0f51, 0x187f: 0x0359, // Block 0x62, offset 0x1880 0x1880: 0x0f61, 0x1881: 0x0f71, 0x1882: 0x00d9, 0x1883: 0x0f99, 0x1884: 0x2039, 0x1885: 0x0269, 0x1886: 0x01d9, 0x1887: 0x0fa9, 0x1888: 0x0fb9, 0x1889: 0x1089, 0x188a: 0x0279, 0x188b: 0x0369, 0x188c: 0x0289, 0x188d: 0x13d1, 0x188e: 0x0039, 0x188f: 0x0ee9, 0x1890: 0x1159, 0x1891: 0x0ef9, 0x1892: 0x0f09, 0x1893: 0x1199, 0x1894: 0x0f31, 0x1895: 0x0040, 0x1896: 0x0f41, 0x1897: 0x0259, 0x1898: 0x0f51, 0x1899: 0x0359, 0x189a: 0x0f61, 0x189b: 0x0f71, 0x189c: 0x00d9, 0x189d: 0x0f99, 0x189e: 0x2039, 0x189f: 0x0269, 0x18a0: 0x01d9, 0x18a1: 0x0fa9, 0x18a2: 0x0fb9, 0x18a3: 0x1089, 0x18a4: 0x0279, 0x18a5: 0x0369, 0x18a6: 0x0289, 0x18a7: 0x13d1, 0x18a8: 0x0039, 0x18a9: 0x0ee9, 0x18aa: 0x1159, 0x18ab: 0x0ef9, 0x18ac: 0x0f09, 0x18ad: 0x1199, 0x18ae: 0x0f31, 0x18af: 0x0249, 0x18b0: 0x0f41, 0x18b1: 0x0259, 0x18b2: 0x0f51, 0x18b3: 0x0359, 0x18b4: 0x0f61, 0x18b5: 0x0f71, 0x18b6: 0x00d9, 0x18b7: 0x0f99, 0x18b8: 0x2039, 0x18b9: 0x0269, 0x18ba: 0x01d9, 0x18bb: 0x0fa9, 0x18bc: 0x0fb9, 0x18bd: 0x1089, 0x18be: 0x0279, 0x18bf: 0x0369, // Block 0x63, offset 0x18c0 0x18c0: 0x0289, 0x18c1: 0x13d1, 0x18c2: 0x0039, 0x18c3: 0x0ee9, 0x18c4: 0x1159, 0x18c5: 0x0ef9, 0x18c6: 0x0f09, 0x18c7: 0x1199, 0x18c8: 0x0f31, 0x18c9: 0x0249, 0x18ca: 0x0f41, 0x18cb: 0x0259, 0x18cc: 0x0f51, 0x18cd: 0x0359, 0x18ce: 0x0f61, 0x18cf: 0x0f71, 0x18d0: 0x00d9, 0x18d1: 0x0f99, 0x18d2: 0x2039, 0x18d3: 0x0269, 0x18d4: 0x01d9, 0x18d5: 0x0fa9, 0x18d6: 0x0fb9, 0x18d7: 0x1089, 0x18d8: 0x0279, 0x18d9: 0x0369, 0x18da: 0x0289, 0x18db: 0x13d1, 0x18dc: 0x0039, 0x18dd: 0x0040, 0x18de: 0x1159, 0x18df: 0x0ef9, 0x18e0: 0x0040, 0x18e1: 0x0040, 0x18e2: 0x0f31, 0x18e3: 0x0040, 0x18e4: 0x0040, 0x18e5: 0x0259, 0x18e6: 0x0f51, 0x18e7: 0x0040, 0x18e8: 0x0040, 0x18e9: 0x0f71, 0x18ea: 0x00d9, 0x18eb: 0x0f99, 0x18ec: 0x2039, 0x18ed: 0x0040, 0x18ee: 0x01d9, 0x18ef: 0x0fa9, 0x18f0: 0x0fb9, 0x18f1: 0x1089, 0x18f2: 0x0279, 0x18f3: 0x0369, 0x18f4: 0x0289, 0x18f5: 0x13d1, 0x18f6: 0x0039, 0x18f7: 0x0ee9, 0x18f8: 0x1159, 0x18f9: 0x0ef9, 0x18fa: 0x0040, 0x18fb: 0x1199, 0x18fc: 0x0040, 0x18fd: 0x0249, 0x18fe: 0x0f41, 0x18ff: 0x0259, // Block 0x64, offset 0x1900 0x1900: 0x0f51, 0x1901: 0x0359, 0x1902: 0x0f61, 0x1903: 0x0f71, 0x1904: 0x0040, 0x1905: 0x0f99, 0x1906: 0x2039, 0x1907: 0x0269, 0x1908: 0x01d9, 0x1909: 0x0fa9, 0x190a: 0x0fb9, 0x190b: 0x1089, 0x190c: 0x0279, 0x190d: 0x0369, 0x190e: 0x0289, 0x190f: 0x13d1, 0x1910: 0x0039, 0x1911: 0x0ee9, 0x1912: 0x1159, 0x1913: 0x0ef9, 0x1914: 0x0f09, 0x1915: 0x1199, 0x1916: 0x0f31, 0x1917: 0x0249, 0x1918: 0x0f41, 0x1919: 0x0259, 0x191a: 0x0f51, 0x191b: 0x0359, 0x191c: 0x0f61, 0x191d: 0x0f71, 0x191e: 0x00d9, 0x191f: 0x0f99, 0x1920: 0x2039, 0x1921: 0x0269, 0x1922: 0x01d9, 0x1923: 0x0fa9, 0x1924: 0x0fb9, 0x1925: 0x1089, 0x1926: 0x0279, 0x1927: 0x0369, 0x1928: 0x0289, 0x1929: 0x13d1, 0x192a: 0x0039, 0x192b: 0x0ee9, 0x192c: 0x1159, 0x192d: 0x0ef9, 0x192e: 0x0f09, 0x192f: 0x1199, 0x1930: 0x0f31, 0x1931: 0x0249, 0x1932: 0x0f41, 0x1933: 0x0259, 0x1934: 0x0f51, 0x1935: 0x0359, 0x1936: 0x0f61, 0x1937: 0x0f71, 0x1938: 0x00d9, 0x1939: 0x0f99, 0x193a: 0x2039, 0x193b: 0x0269, 0x193c: 0x01d9, 0x193d: 0x0fa9, 0x193e: 0x0fb9, 0x193f: 0x1089, // Block 0x65, offset 0x1940 0x1940: 0x0279, 0x1941: 0x0369, 0x1942: 0x0289, 0x1943: 0x13d1, 0x1944: 0x0039, 0x1945: 0x0ee9, 0x1946: 0x0040, 0x1947: 0x0ef9, 0x1948: 0x0f09, 0x1949: 0x1199, 0x194a: 0x0f31, 0x194b: 0x0040, 0x194c: 0x0040, 0x194d: 0x0259, 0x194e: 0x0f51, 0x194f: 0x0359, 0x1950: 0x0f61, 0x1951: 0x0f71, 0x1952: 0x00d9, 0x1953: 0x0f99, 0x1954: 0x2039, 0x1955: 0x0040, 0x1956: 0x01d9, 0x1957: 0x0fa9, 0x1958: 0x0fb9, 0x1959: 0x1089, 0x195a: 0x0279, 0x195b: 0x0369, 0x195c: 0x0289, 0x195d: 0x0040, 0x195e: 0x0039, 0x195f: 0x0ee9, 0x1960: 0x1159, 0x1961: 0x0ef9, 0x1962: 0x0f09, 0x1963: 0x1199, 0x1964: 0x0f31, 0x1965: 0x0249, 0x1966: 0x0f41, 0x1967: 0x0259, 0x1968: 0x0f51, 0x1969: 0x0359, 0x196a: 0x0f61, 0x196b: 0x0f71, 0x196c: 0x00d9, 0x196d: 0x0f99, 0x196e: 0x2039, 0x196f: 0x0269, 0x1970: 0x01d9, 0x1971: 0x0fa9, 0x1972: 0x0fb9, 0x1973: 0x1089, 0x1974: 0x0279, 0x1975: 0x0369, 0x1976: 0x0289, 0x1977: 0x13d1, 0x1978: 0x0039, 0x1979: 0x0ee9, 0x197a: 0x0040, 0x197b: 0x0ef9, 0x197c: 0x0f09, 0x197d: 0x1199, 0x197e: 0x0f31, 0x197f: 0x0040, // Block 0x66, offset 0x1980 0x1980: 0x0f41, 0x1981: 0x0259, 0x1982: 0x0f51, 0x1983: 0x0359, 0x1984: 0x0f61, 0x1985: 0x0040, 0x1986: 0x00d9, 0x1987: 0x0040, 0x1988: 0x0040, 0x1989: 0x0040, 0x198a: 0x01d9, 0x198b: 0x0fa9, 0x198c: 0x0fb9, 0x198d: 0x1089, 0x198e: 0x0279, 0x198f: 0x0369, 0x1990: 0x0289, 0x1991: 0x0040, 0x1992: 0x0039, 0x1993: 0x0ee9, 0x1994: 0x1159, 0x1995: 0x0ef9, 0x1996: 0x0f09, 0x1997: 0x1199, 0x1998: 0x0f31, 0x1999: 0x0249, 0x199a: 0x0f41, 0x199b: 0x0259, 0x199c: 0x0f51, 0x199d: 0x0359, 0x199e: 0x0f61, 0x199f: 0x0f71, 0x19a0: 0x00d9, 0x19a1: 0x0f99, 0x19a2: 0x2039, 0x19a3: 0x0269, 0x19a4: 0x01d9, 0x19a5: 0x0fa9, 0x19a6: 0x0fb9, 0x19a7: 0x1089, 0x19a8: 0x0279, 0x19a9: 0x0369, 0x19aa: 0x0289, 0x19ab: 0x13d1, 0x19ac: 0x0039, 0x19ad: 0x0ee9, 0x19ae: 0x1159, 0x19af: 0x0ef9, 0x19b0: 0x0f09, 0x19b1: 0x1199, 0x19b2: 0x0f31, 0x19b3: 0x0249, 0x19b4: 0x0f41, 0x19b5: 0x0259, 0x19b6: 0x0f51, 0x19b7: 0x0359, 0x19b8: 0x0f61, 0x19b9: 0x0f71, 0x19ba: 0x00d9, 0x19bb: 0x0f99, 0x19bc: 0x2039, 0x19bd: 0x0269, 0x19be: 0x01d9, 0x19bf: 0x0fa9, // Block 0x67, offset 0x19c0 0x19c0: 0x0fb9, 0x19c1: 0x1089, 0x19c2: 0x0279, 0x19c3: 0x0369, 0x19c4: 0x0289, 0x19c5: 0x13d1, 0x19c6: 0x0039, 0x19c7: 0x0ee9, 0x19c8: 0x1159, 0x19c9: 0x0ef9, 0x19ca: 0x0f09, 0x19cb: 0x1199, 0x19cc: 0x0f31, 0x19cd: 0x0249, 0x19ce: 0x0f41, 0x19cf: 0x0259, 0x19d0: 0x0f51, 0x19d1: 0x0359, 0x19d2: 0x0f61, 0x19d3: 0x0f71, 0x19d4: 0x00d9, 0x19d5: 0x0f99, 0x19d6: 0x2039, 0x19d7: 0x0269, 0x19d8: 0x01d9, 0x19d9: 0x0fa9, 0x19da: 0x0fb9, 0x19db: 0x1089, 0x19dc: 0x0279, 0x19dd: 0x0369, 0x19de: 0x0289, 0x19df: 0x13d1, 0x19e0: 0x0039, 0x19e1: 0x0ee9, 0x19e2: 0x1159, 0x19e3: 0x0ef9, 0x19e4: 0x0f09, 0x19e5: 0x1199, 0x19e6: 0x0f31, 0x19e7: 0x0249, 0x19e8: 0x0f41, 0x19e9: 0x0259, 0x19ea: 0x0f51, 0x19eb: 0x0359, 0x19ec: 0x0f61, 0x19ed: 0x0f71, 0x19ee: 0x00d9, 0x19ef: 0x0f99, 0x19f0: 0x2039, 0x19f1: 0x0269, 0x19f2: 0x01d9, 0x19f3: 0x0fa9, 0x19f4: 0x0fb9, 0x19f5: 0x1089, 0x19f6: 0x0279, 0x19f7: 0x0369, 0x19f8: 0x0289, 0x19f9: 0x13d1, 0x19fa: 0x0039, 0x19fb: 0x0ee9, 0x19fc: 0x1159, 0x19fd: 0x0ef9, 0x19fe: 0x0f09, 0x19ff: 0x1199, // Block 0x68, offset 0x1a00 0x1a00: 0x0f31, 0x1a01: 0x0249, 0x1a02: 0x0f41, 0x1a03: 0x0259, 0x1a04: 0x0f51, 0x1a05: 0x0359, 0x1a06: 0x0f61, 0x1a07: 0x0f71, 0x1a08: 0x00d9, 0x1a09: 0x0f99, 0x1a0a: 0x2039, 0x1a0b: 0x0269, 0x1a0c: 0x01d9, 0x1a0d: 0x0fa9, 0x1a0e: 0x0fb9, 0x1a0f: 0x1089, 0x1a10: 0x0279, 0x1a11: 0x0369, 0x1a12: 0x0289, 0x1a13: 0x13d1, 0x1a14: 0x0039, 0x1a15: 0x0ee9, 0x1a16: 0x1159, 0x1a17: 0x0ef9, 0x1a18: 0x0f09, 0x1a19: 0x1199, 0x1a1a: 0x0f31, 0x1a1b: 0x0249, 0x1a1c: 0x0f41, 0x1a1d: 0x0259, 0x1a1e: 0x0f51, 0x1a1f: 0x0359, 0x1a20: 0x0f61, 0x1a21: 0x0f71, 0x1a22: 0x00d9, 0x1a23: 0x0f99, 0x1a24: 0x2039, 0x1a25: 0x0269, 0x1a26: 0x01d9, 0x1a27: 0x0fa9, 0x1a28: 0x0fb9, 0x1a29: 0x1089, 0x1a2a: 0x0279, 0x1a2b: 0x0369, 0x1a2c: 0x0289, 0x1a2d: 0x13d1, 0x1a2e: 0x0039, 0x1a2f: 0x0ee9, 0x1a30: 0x1159, 0x1a31: 0x0ef9, 0x1a32: 0x0f09, 0x1a33: 0x1199, 0x1a34: 0x0f31, 0x1a35: 0x0249, 0x1a36: 0x0f41, 0x1a37: 0x0259, 0x1a38: 0x0f51, 0x1a39: 0x0359, 0x1a3a: 0x0f61, 0x1a3b: 0x0f71, 0x1a3c: 0x00d9, 0x1a3d: 0x0f99, 0x1a3e: 0x2039, 0x1a3f: 0x0269, // Block 0x69, offset 0x1a40 0x1a40: 0x01d9, 0x1a41: 0x0fa9, 0x1a42: 0x0fb9, 0x1a43: 0x1089, 0x1a44: 0x0279, 0x1a45: 0x0369, 0x1a46: 0x0289, 0x1a47: 0x13d1, 0x1a48: 0x0039, 0x1a49: 0x0ee9, 0x1a4a: 0x1159, 0x1a4b: 0x0ef9, 0x1a4c: 0x0f09, 0x1a4d: 0x1199, 0x1a4e: 0x0f31, 0x1a4f: 0x0249, 0x1a50: 0x0f41, 0x1a51: 0x0259, 0x1a52: 0x0f51, 0x1a53: 0x0359, 0x1a54: 0x0f61, 0x1a55: 0x0f71, 0x1a56: 0x00d9, 0x1a57: 0x0f99, 0x1a58: 0x2039, 0x1a59: 0x0269, 0x1a5a: 0x01d9, 0x1a5b: 0x0fa9, 0x1a5c: 0x0fb9, 0x1a5d: 0x1089, 0x1a5e: 0x0279, 0x1a5f: 0x0369, 0x1a60: 0x0289, 0x1a61: 0x13d1, 0x1a62: 0x0039, 0x1a63: 0x0ee9, 0x1a64: 0x1159, 0x1a65: 0x0ef9, 0x1a66: 0x0f09, 0x1a67: 0x1199, 0x1a68: 0x0f31, 0x1a69: 0x0249, 0x1a6a: 0x0f41, 0x1a6b: 0x0259, 0x1a6c: 0x0f51, 0x1a6d: 0x0359, 0x1a6e: 0x0f61, 0x1a6f: 0x0f71, 0x1a70: 0x00d9, 0x1a71: 0x0f99, 0x1a72: 0x2039, 0x1a73: 0x0269, 0x1a74: 0x01d9, 0x1a75: 0x0fa9, 0x1a76: 0x0fb9, 0x1a77: 0x1089, 0x1a78: 0x0279, 0x1a79: 0x0369, 0x1a7a: 0x0289, 0x1a7b: 0x13d1, 0x1a7c: 0x0039, 0x1a7d: 0x0ee9, 0x1a7e: 0x1159, 0x1a7f: 0x0ef9, // Block 0x6a, offset 0x1a80 0x1a80: 0x0f09, 0x1a81: 0x1199, 0x1a82: 0x0f31, 0x1a83: 0x0249, 0x1a84: 0x0f41, 0x1a85: 0x0259, 0x1a86: 0x0f51, 0x1a87: 0x0359, 0x1a88: 0x0f61, 0x1a89: 0x0f71, 0x1a8a: 0x00d9, 0x1a8b: 0x0f99, 0x1a8c: 0x2039, 0x1a8d: 0x0269, 0x1a8e: 0x01d9, 0x1a8f: 0x0fa9, 0x1a90: 0x0fb9, 0x1a91: 0x1089, 0x1a92: 0x0279, 0x1a93: 0x0369, 0x1a94: 0x0289, 0x1a95: 0x13d1, 0x1a96: 0x0039, 0x1a97: 0x0ee9, 0x1a98: 0x1159, 0x1a99: 0x0ef9, 0x1a9a: 0x0f09, 0x1a9b: 0x1199, 0x1a9c: 0x0f31, 0x1a9d: 0x0249, 0x1a9e: 0x0f41, 0x1a9f: 0x0259, 0x1aa0: 0x0f51, 0x1aa1: 0x0359, 0x1aa2: 0x0f61, 0x1aa3: 0x0f71, 0x1aa4: 0x00d9, 0x1aa5: 0x0f99, 0x1aa6: 0x2039, 0x1aa7: 0x0269, 0x1aa8: 0x01d9, 0x1aa9: 0x0fa9, 0x1aaa: 0x0fb9, 0x1aab: 0x1089, 0x1aac: 0x0279, 0x1aad: 0x0369, 0x1aae: 0x0289, 0x1aaf: 0x13d1, 0x1ab0: 0x0039, 0x1ab1: 0x0ee9, 0x1ab2: 0x1159, 0x1ab3: 0x0ef9, 0x1ab4: 0x0f09, 0x1ab5: 0x1199, 0x1ab6: 0x0f31, 0x1ab7: 0x0249, 0x1ab8: 0x0f41, 0x1ab9: 0x0259, 0x1aba: 0x0f51, 0x1abb: 0x0359, 0x1abc: 0x0f61, 0x1abd: 0x0f71, 0x1abe: 0x00d9, 0x1abf: 0x0f99, // Block 0x6b, offset 0x1ac0 0x1ac0: 0x2039, 0x1ac1: 0x0269, 0x1ac2: 0x01d9, 0x1ac3: 0x0fa9, 0x1ac4: 0x0fb9, 0x1ac5: 0x1089, 0x1ac6: 0x0279, 0x1ac7: 0x0369, 0x1ac8: 0x0289, 0x1ac9: 0x13d1, 0x1aca: 0x0039, 0x1acb: 0x0ee9, 0x1acc: 0x1159, 0x1acd: 0x0ef9, 0x1ace: 0x0f09, 0x1acf: 0x1199, 0x1ad0: 0x0f31, 0x1ad1: 0x0249, 0x1ad2: 0x0f41, 0x1ad3: 0x0259, 0x1ad4: 0x0f51, 0x1ad5: 0x0359, 0x1ad6: 0x0f61, 0x1ad7: 0x0f71, 0x1ad8: 0x00d9, 0x1ad9: 0x0f99, 0x1ada: 0x2039, 0x1adb: 0x0269, 0x1adc: 0x01d9, 0x1add: 0x0fa9, 0x1ade: 0x0fb9, 0x1adf: 0x1089, 0x1ae0: 0x0279, 0x1ae1: 0x0369, 0x1ae2: 0x0289, 0x1ae3: 0x13d1, 0x1ae4: 0xba81, 0x1ae5: 0xba99, 0x1ae6: 0x0040, 0x1ae7: 0x0040, 0x1ae8: 0xbab1, 0x1ae9: 0x1099, 0x1aea: 0x10b1, 0x1aeb: 0x10c9, 0x1aec: 0xbac9, 0x1aed: 0xbae1, 0x1aee: 0xbaf9, 0x1aef: 0x1429, 0x1af0: 0x1a31, 0x1af1: 0xbb11, 0x1af2: 0xbb29, 0x1af3: 0xbb41, 0x1af4: 0xbb59, 0x1af5: 0xbb71, 0x1af6: 0xbb89, 0x1af7: 0x2109, 0x1af8: 0x1111, 0x1af9: 0x1429, 0x1afa: 0xbba1, 0x1afb: 0xbbb9, 0x1afc: 0xbbd1, 0x1afd: 0x10e1, 0x1afe: 0x10f9, 0x1aff: 0xbbe9, // Block 0x6c, offset 0x1b00 0x1b00: 0x2079, 0x1b01: 0xbc01, 0x1b02: 0xbab1, 0x1b03: 0x1099, 0x1b04: 0x10b1, 0x1b05: 0x10c9, 0x1b06: 0xbac9, 0x1b07: 0xbae1, 0x1b08: 0xbaf9, 0x1b09: 0x1429, 0x1b0a: 0x1a31, 0x1b0b: 0xbb11, 0x1b0c: 0xbb29, 0x1b0d: 0xbb41, 0x1b0e: 0xbb59, 0x1b0f: 0xbb71, 0x1b10: 0xbb89, 0x1b11: 0x2109, 0x1b12: 0x1111, 0x1b13: 0xbba1, 0x1b14: 0xbba1, 0x1b15: 0xbbb9, 0x1b16: 0xbbd1, 0x1b17: 0x10e1, 0x1b18: 0x10f9, 0x1b19: 0xbbe9, 0x1b1a: 0x2079, 0x1b1b: 0xbc21, 0x1b1c: 0xbac9, 0x1b1d: 0x1429, 0x1b1e: 0xbb11, 0x1b1f: 0x10e1, 0x1b20: 0x1111, 0x1b21: 0x2109, 0x1b22: 0xbab1, 0x1b23: 0x1099, 0x1b24: 0x10b1, 0x1b25: 0x10c9, 0x1b26: 0xbac9, 0x1b27: 0xbae1, 0x1b28: 0xbaf9, 0x1b29: 0x1429, 0x1b2a: 0x1a31, 0x1b2b: 0xbb11, 0x1b2c: 0xbb29, 0x1b2d: 0xbb41, 0x1b2e: 0xbb59, 0x1b2f: 0xbb71, 0x1b30: 0xbb89, 0x1b31: 0x2109, 0x1b32: 0x1111, 0x1b33: 0x1429, 0x1b34: 0xbba1, 0x1b35: 0xbbb9, 0x1b36: 0xbbd1, 0x1b37: 0x10e1, 0x1b38: 0x10f9, 0x1b39: 0xbbe9, 0x1b3a: 0x2079, 0x1b3b: 0xbc01, 0x1b3c: 0xbab1, 0x1b3d: 0x1099, 0x1b3e: 0x10b1, 0x1b3f: 0x10c9, // Block 0x6d, offset 0x1b40 0x1b40: 0xbac9, 0x1b41: 0xbae1, 0x1b42: 0xbaf9, 0x1b43: 0x1429, 0x1b44: 0x1a31, 0x1b45: 0xbb11, 0x1b46: 0xbb29, 0x1b47: 0xbb41, 0x1b48: 0xbb59, 0x1b49: 0xbb71, 0x1b4a: 0xbb89, 0x1b4b: 0x2109, 0x1b4c: 0x1111, 0x1b4d: 0xbba1, 0x1b4e: 0xbba1, 0x1b4f: 0xbbb9, 0x1b50: 0xbbd1, 0x1b51: 0x10e1, 0x1b52: 0x10f9, 0x1b53: 0xbbe9, 0x1b54: 0x2079, 0x1b55: 0xbc21, 0x1b56: 0xbac9, 0x1b57: 0x1429, 0x1b58: 0xbb11, 0x1b59: 0x10e1, 0x1b5a: 0x1111, 0x1b5b: 0x2109, 0x1b5c: 0xbab1, 0x1b5d: 0x1099, 0x1b5e: 0x10b1, 0x1b5f: 0x10c9, 0x1b60: 0xbac9, 0x1b61: 0xbae1, 0x1b62: 0xbaf9, 0x1b63: 0x1429, 0x1b64: 0x1a31, 0x1b65: 0xbb11, 0x1b66: 0xbb29, 0x1b67: 0xbb41, 0x1b68: 0xbb59, 0x1b69: 0xbb71, 0x1b6a: 0xbb89, 0x1b6b: 0x2109, 0x1b6c: 0x1111, 0x1b6d: 0x1429, 0x1b6e: 0xbba1, 0x1b6f: 0xbbb9, 0x1b70: 0xbbd1, 0x1b71: 0x10e1, 0x1b72: 0x10f9, 0x1b73: 0xbbe9, 0x1b74: 0x2079, 0x1b75: 0xbc01, 0x1b76: 0xbab1, 0x1b77: 0x1099, 0x1b78: 0x10b1, 0x1b79: 0x10c9, 0x1b7a: 0xbac9, 0x1b7b: 0xbae1, 0x1b7c: 0xbaf9, 0x1b7d: 0x1429, 0x1b7e: 0x1a31, 0x1b7f: 0xbb11, // Block 0x6e, offset 0x1b80 0x1b80: 0xbb29, 0x1b81: 0xbb41, 0x1b82: 0xbb59, 0x1b83: 0xbb71, 0x1b84: 0xbb89, 0x1b85: 0x2109, 0x1b86: 0x1111, 0x1b87: 0xbba1, 0x1b88: 0xbba1, 0x1b89: 0xbbb9, 0x1b8a: 0xbbd1, 0x1b8b: 0x10e1, 0x1b8c: 0x10f9, 0x1b8d: 0xbbe9, 0x1b8e: 0x2079, 0x1b8f: 0xbc21, 0x1b90: 0xbac9, 0x1b91: 0x1429, 0x1b92: 0xbb11, 0x1b93: 0x10e1, 0x1b94: 0x1111, 0x1b95: 0x2109, 0x1b96: 0xbab1, 0x1b97: 0x1099, 0x1b98: 0x10b1, 0x1b99: 0x10c9, 0x1b9a: 0xbac9, 0x1b9b: 0xbae1, 0x1b9c: 0xbaf9, 0x1b9d: 0x1429, 0x1b9e: 0x1a31, 0x1b9f: 0xbb11, 0x1ba0: 0xbb29, 0x1ba1: 0xbb41, 0x1ba2: 0xbb59, 0x1ba3: 0xbb71, 0x1ba4: 0xbb89, 0x1ba5: 0x2109, 0x1ba6: 0x1111, 0x1ba7: 0x1429, 0x1ba8: 0xbba1, 0x1ba9: 0xbbb9, 0x1baa: 0xbbd1, 0x1bab: 0x10e1, 0x1bac: 0x10f9, 0x1bad: 0xbbe9, 0x1bae: 0x2079, 0x1baf: 0xbc01, 0x1bb0: 0xbab1, 0x1bb1: 0x1099, 0x1bb2: 0x10b1, 0x1bb3: 0x10c9, 0x1bb4: 0xbac9, 0x1bb5: 0xbae1, 0x1bb6: 0xbaf9, 0x1bb7: 0x1429, 0x1bb8: 0x1a31, 0x1bb9: 0xbb11, 0x1bba: 0xbb29, 0x1bbb: 0xbb41, 0x1bbc: 0xbb59, 0x1bbd: 0xbb71, 0x1bbe: 0xbb89, 0x1bbf: 0x2109, // Block 0x6f, offset 0x1bc0 0x1bc0: 0x1111, 0x1bc1: 0xbba1, 0x1bc2: 0xbba1, 0x1bc3: 0xbbb9, 0x1bc4: 0xbbd1, 0x1bc5: 0x10e1, 0x1bc6: 0x10f9, 0x1bc7: 0xbbe9, 0x1bc8: 0x2079, 0x1bc9: 0xbc21, 0x1bca: 0xbac9, 0x1bcb: 0x1429, 0x1bcc: 0xbb11, 0x1bcd: 0x10e1, 0x1bce: 0x1111, 0x1bcf: 0x2109, 0x1bd0: 0xbab1, 0x1bd1: 0x1099, 0x1bd2: 0x10b1, 0x1bd3: 0x10c9, 0x1bd4: 0xbac9, 0x1bd5: 0xbae1, 0x1bd6: 0xbaf9, 0x1bd7: 0x1429, 0x1bd8: 0x1a31, 0x1bd9: 0xbb11, 0x1bda: 0xbb29, 0x1bdb: 0xbb41, 0x1bdc: 0xbb59, 0x1bdd: 0xbb71, 0x1bde: 0xbb89, 0x1bdf: 0x2109, 0x1be0: 0x1111, 0x1be1: 0x1429, 0x1be2: 0xbba1, 0x1be3: 0xbbb9, 0x1be4: 0xbbd1, 0x1be5: 0x10e1, 0x1be6: 0x10f9, 0x1be7: 0xbbe9, 0x1be8: 0x2079, 0x1be9: 0xbc01, 0x1bea: 0xbab1, 0x1beb: 0x1099, 0x1bec: 0x10b1, 0x1bed: 0x10c9, 0x1bee: 0xbac9, 0x1bef: 0xbae1, 0x1bf0: 0xbaf9, 0x1bf1: 0x1429, 0x1bf2: 0x1a31, 0x1bf3: 0xbb11, 0x1bf4: 0xbb29, 0x1bf5: 0xbb41, 0x1bf6: 0xbb59, 0x1bf7: 0xbb71, 0x1bf8: 0xbb89, 0x1bf9: 0x2109, 0x1bfa: 0x1111, 0x1bfb: 0xbba1, 0x1bfc: 0xbba1, 0x1bfd: 0xbbb9, 0x1bfe: 0xbbd1, 0x1bff: 0x10e1, // Block 0x70, offset 0x1c00 0x1c00: 0x10f9, 0x1c01: 0xbbe9, 0x1c02: 0x2079, 0x1c03: 0xbc21, 0x1c04: 0xbac9, 0x1c05: 0x1429, 0x1c06: 0xbb11, 0x1c07: 0x10e1, 0x1c08: 0x1111, 0x1c09: 0x2109, 0x1c0a: 0xbc41, 0x1c0b: 0xbc41, 0x1c0c: 0x0040, 0x1c0d: 0x0040, 0x1c0e: 0x1f41, 0x1c0f: 0x00c9, 0x1c10: 0x0069, 0x1c11: 0x0079, 0x1c12: 0x1f51, 0x1c13: 0x1f61, 0x1c14: 0x1f71, 0x1c15: 0x1f81, 0x1c16: 0x1f91, 0x1c17: 0x1fa1, 0x1c18: 0x1f41, 0x1c19: 0x00c9, 0x1c1a: 0x0069, 0x1c1b: 0x0079, 0x1c1c: 0x1f51, 0x1c1d: 0x1f61, 0x1c1e: 0x1f71, 0x1c1f: 0x1f81, 0x1c20: 0x1f91, 0x1c21: 0x1fa1, 0x1c22: 0x1f41, 0x1c23: 0x00c9, 0x1c24: 0x0069, 0x1c25: 0x0079, 0x1c26: 0x1f51, 0x1c27: 0x1f61, 0x1c28: 0x1f71, 0x1c29: 0x1f81, 0x1c2a: 0x1f91, 0x1c2b: 0x1fa1, 0x1c2c: 0x1f41, 0x1c2d: 0x00c9, 0x1c2e: 0x0069, 0x1c2f: 0x0079, 0x1c30: 0x1f51, 0x1c31: 0x1f61, 0x1c32: 0x1f71, 0x1c33: 0x1f81, 0x1c34: 0x1f91, 0x1c35: 0x1fa1, 0x1c36: 0x1f41, 0x1c37: 0x00c9, 0x1c38: 0x0069, 0x1c39: 0x0079, 0x1c3a: 0x1f51, 0x1c3b: 0x1f61, 0x1c3c: 0x1f71, 0x1c3d: 0x1f81, 0x1c3e: 0x1f91, 0x1c3f: 0x1fa1, // Block 0x71, offset 0x1c40 0x1c40: 0xe115, 0x1c41: 0xe115, 0x1c42: 0xe135, 0x1c43: 0xe135, 0x1c44: 0xe115, 0x1c45: 0xe115, 0x1c46: 0xe175, 0x1c47: 0xe175, 0x1c48: 0xe115, 0x1c49: 0xe115, 0x1c4a: 0xe135, 0x1c4b: 0xe135, 0x1c4c: 0xe115, 0x1c4d: 0xe115, 0x1c4e: 0xe1f5, 0x1c4f: 0xe1f5, 0x1c50: 0xe115, 0x1c51: 0xe115, 0x1c52: 0xe135, 0x1c53: 0xe135, 0x1c54: 0xe115, 0x1c55: 0xe115, 0x1c56: 0xe175, 0x1c57: 0xe175, 0x1c58: 0xe115, 0x1c59: 0xe115, 0x1c5a: 0xe135, 0x1c5b: 0xe135, 0x1c5c: 0xe115, 0x1c5d: 0xe115, 0x1c5e: 0x8b05, 0x1c5f: 0x8b05, 0x1c60: 0x04b5, 0x1c61: 0x04b5, 0x1c62: 0x0a08, 0x1c63: 0x0a08, 0x1c64: 0x0a08, 0x1c65: 0x0a08, 0x1c66: 0x0a08, 0x1c67: 0x0a08, 0x1c68: 0x0a08, 0x1c69: 0x0a08, 0x1c6a: 0x0a08, 0x1c6b: 0x0a08, 0x1c6c: 0x0a08, 0x1c6d: 0x0a08, 0x1c6e: 0x0a08, 0x1c6f: 0x0a08, 0x1c70: 0x0a08, 0x1c71: 0x0a08, 0x1c72: 0x0a08, 0x1c73: 0x0a08, 0x1c74: 0x0a08, 0x1c75: 0x0a08, 0x1c76: 0x0a08, 0x1c77: 0x0a08, 0x1c78: 0x0a08, 0x1c79: 0x0a08, 0x1c7a: 0x0a08, 0x1c7b: 0x0a08, 0x1c7c: 0x0a08, 0x1c7d: 0x0a08, 0x1c7e: 0x0a08, 0x1c7f: 0x0a08, // Block 0x72, offset 0x1c80 0x1c80: 0xb189, 0x1c81: 0xb1a1, 0x1c82: 0xb201, 0x1c83: 0xb249, 0x1c84: 0x0040, 0x1c85: 0xb411, 0x1c86: 0xb291, 0x1c87: 0xb219, 0x1c88: 0xb309, 0x1c89: 0xb429, 0x1c8a: 0xb399, 0x1c8b: 0xb3b1, 0x1c8c: 0xb3c9, 0x1c8d: 0xb3e1, 0x1c8e: 0xb2a9, 0x1c8f: 0xb339, 0x1c90: 0xb369, 0x1c91: 0xb2d9, 0x1c92: 0xb381, 0x1c93: 0xb279, 0x1c94: 0xb2c1, 0x1c95: 0xb1d1, 0x1c96: 0xb1e9, 0x1c97: 0xb231, 0x1c98: 0xb261, 0x1c99: 0xb2f1, 0x1c9a: 0xb321, 0x1c9b: 0xb351, 0x1c9c: 0xbc59, 0x1c9d: 0x7949, 0x1c9e: 0xbc71, 0x1c9f: 0xbc89, 0x1ca0: 0x0040, 0x1ca1: 0xb1a1, 0x1ca2: 0xb201, 0x1ca3: 0x0040, 0x1ca4: 0xb3f9, 0x1ca5: 0x0040, 0x1ca6: 0x0040, 0x1ca7: 0xb219, 0x1ca8: 0x0040, 0x1ca9: 0xb429, 0x1caa: 0xb399, 0x1cab: 0xb3b1, 0x1cac: 0xb3c9, 0x1cad: 0xb3e1, 0x1cae: 0xb2a9, 0x1caf: 0xb339, 0x1cb0: 0xb369, 0x1cb1: 0xb2d9, 0x1cb2: 0xb381, 0x1cb3: 0x0040, 0x1cb4: 0xb2c1, 0x1cb5: 0xb1d1, 0x1cb6: 0xb1e9, 0x1cb7: 0xb231, 0x1cb8: 0x0040, 0x1cb9: 0xb2f1, 0x1cba: 0x0040, 0x1cbb: 0xb351, 0x1cbc: 0x0040, 0x1cbd: 0x0040, 0x1cbe: 0x0040, 0x1cbf: 0x0040, // Block 0x73, offset 0x1cc0 0x1cc0: 0x0040, 0x1cc1: 0x0040, 0x1cc2: 0xb201, 0x1cc3: 0x0040, 0x1cc4: 0x0040, 0x1cc5: 0x0040, 0x1cc6: 0x0040, 0x1cc7: 0xb219, 0x1cc8: 0x0040, 0x1cc9: 0xb429, 0x1cca: 0x0040, 0x1ccb: 0xb3b1, 0x1ccc: 0x0040, 0x1ccd: 0xb3e1, 0x1cce: 0xb2a9, 0x1ccf: 0xb339, 0x1cd0: 0x0040, 0x1cd1: 0xb2d9, 0x1cd2: 0xb381, 0x1cd3: 0x0040, 0x1cd4: 0xb2c1, 0x1cd5: 0x0040, 0x1cd6: 0x0040, 0x1cd7: 0xb231, 0x1cd8: 0x0040, 0x1cd9: 0xb2f1, 0x1cda: 0x0040, 0x1cdb: 0xb351, 0x1cdc: 0x0040, 0x1cdd: 0x7949, 0x1cde: 0x0040, 0x1cdf: 0xbc89, 0x1ce0: 0x0040, 0x1ce1: 0xb1a1, 0x1ce2: 0xb201, 0x1ce3: 0x0040, 0x1ce4: 0xb3f9, 0x1ce5: 0x0040, 0x1ce6: 0x0040, 0x1ce7: 0xb219, 0x1ce8: 0xb309, 0x1ce9: 0xb429, 0x1cea: 0xb399, 0x1ceb: 0x0040, 0x1cec: 0xb3c9, 0x1ced: 0xb3e1, 0x1cee: 0xb2a9, 0x1cef: 0xb339, 0x1cf0: 0xb369, 0x1cf1: 0xb2d9, 0x1cf2: 0xb381, 0x1cf3: 0x0040, 0x1cf4: 0xb2c1, 0x1cf5: 0xb1d1, 0x1cf6: 0xb1e9, 0x1cf7: 0xb231, 0x1cf8: 0x0040, 0x1cf9: 0xb2f1, 0x1cfa: 0xb321, 0x1cfb: 0xb351, 0x1cfc: 0xbc59, 0x1cfd: 0x0040, 0x1cfe: 0xbc71, 0x1cff: 0x0040, // Block 0x74, offset 0x1d00 0x1d00: 0xb189, 0x1d01: 0xb1a1, 0x1d02: 0xb201, 0x1d03: 0xb249, 0x1d04: 0xb3f9, 0x1d05: 0xb411, 0x1d06: 0xb291, 0x1d07: 0xb219, 0x1d08: 0xb309, 0x1d09: 0xb429, 0x1d0a: 0x0040, 0x1d0b: 0xb3b1, 0x1d0c: 0xb3c9, 0x1d0d: 0xb3e1, 0x1d0e: 0xb2a9, 0x1d0f: 0xb339, 0x1d10: 0xb369, 0x1d11: 0xb2d9, 0x1d12: 0xb381, 0x1d13: 0xb279, 0x1d14: 0xb2c1, 0x1d15: 0xb1d1, 0x1d16: 0xb1e9, 0x1d17: 0xb231, 0x1d18: 0xb261, 0x1d19: 0xb2f1, 0x1d1a: 0xb321, 0x1d1b: 0xb351, 0x1d1c: 0x0040, 0x1d1d: 0x0040, 0x1d1e: 0x0040, 0x1d1f: 0x0040, 0x1d20: 0x0040, 0x1d21: 0xb1a1, 0x1d22: 0xb201, 0x1d23: 0xb249, 0x1d24: 0x0040, 0x1d25: 0xb411, 0x1d26: 0xb291, 0x1d27: 0xb219, 0x1d28: 0xb309, 0x1d29: 0xb429, 0x1d2a: 0x0040, 0x1d2b: 0xb3b1, 0x1d2c: 0xb3c9, 0x1d2d: 0xb3e1, 0x1d2e: 0xb2a9, 0x1d2f: 0xb339, 0x1d30: 0xb369, 0x1d31: 0xb2d9, 0x1d32: 0xb381, 0x1d33: 0xb279, 0x1d34: 0xb2c1, 0x1d35: 0xb1d1, 0x1d36: 0xb1e9, 0x1d37: 0xb231, 0x1d38: 0xb261, 0x1d39: 0xb2f1, 0x1d3a: 0xb321, 0x1d3b: 0xb351, 0x1d3c: 0x0040, 0x1d3d: 0x0040, 0x1d3e: 0x0040, 0x1d3f: 0x0040, // Block 0x75, offset 0x1d40 0x1d40: 0x0040, 0x1d41: 0xbca2, 0x1d42: 0xbcba, 0x1d43: 0xbcd2, 0x1d44: 0xbcea, 0x1d45: 0xbd02, 0x1d46: 0xbd1a, 0x1d47: 0xbd32, 0x1d48: 0xbd4a, 0x1d49: 0xbd62, 0x1d4a: 0xbd7a, 0x1d4b: 0x0018, 0x1d4c: 0x0018, 0x1d4d: 0x0040, 0x1d4e: 0x0040, 0x1d4f: 0x0040, 0x1d50: 0xbd92, 0x1d51: 0xbdb2, 0x1d52: 0xbdd2, 0x1d53: 0xbdf2, 0x1d54: 0xbe12, 0x1d55: 0xbe32, 0x1d56: 0xbe52, 0x1d57: 0xbe72, 0x1d58: 0xbe92, 0x1d59: 0xbeb2, 0x1d5a: 0xbed2, 0x1d5b: 0xbef2, 0x1d5c: 0xbf12, 0x1d5d: 0xbf32, 0x1d5e: 0xbf52, 0x1d5f: 0xbf72, 0x1d60: 0xbf92, 0x1d61: 0xbfb2, 0x1d62: 0xbfd2, 0x1d63: 0xbff2, 0x1d64: 0xc012, 0x1d65: 0xc032, 0x1d66: 0xc052, 0x1d67: 0xc072, 0x1d68: 0xc092, 0x1d69: 0xc0b2, 0x1d6a: 0xc0d1, 0x1d6b: 0x1159, 0x1d6c: 0x0269, 0x1d6d: 0x6671, 0x1d6e: 0xc111, 0x1d6f: 0x0040, 0x1d70: 0x0039, 0x1d71: 0x0ee9, 0x1d72: 0x1159, 0x1d73: 0x0ef9, 0x1d74: 0x0f09, 0x1d75: 0x1199, 0x1d76: 0x0f31, 0x1d77: 0x0249, 0x1d78: 0x0f41, 0x1d79: 0x0259, 0x1d7a: 0x0f51, 0x1d7b: 0x0359, 0x1d7c: 0x0f61, 0x1d7d: 0x0f71, 0x1d7e: 0x00d9, 0x1d7f: 0x0f99, // Block 0x76, offset 0x1d80 0x1d80: 0x2039, 0x1d81: 0x0269, 0x1d82: 0x01d9, 0x1d83: 0x0fa9, 0x1d84: 0x0fb9, 0x1d85: 0x1089, 0x1d86: 0x0279, 0x1d87: 0x0369, 0x1d88: 0x0289, 0x1d89: 0x13d1, 0x1d8a: 0xc129, 0x1d8b: 0x65b1, 0x1d8c: 0xc141, 0x1d8d: 0x1441, 0x1d8e: 0xc159, 0x1d8f: 0xc179, 0x1d90: 0x0018, 0x1d91: 0x0018, 0x1d92: 0x0018, 0x1d93: 0x0018, 0x1d94: 0x0018, 0x1d95: 0x0018, 0x1d96: 0x0018, 0x1d97: 0x0018, 0x1d98: 0x0018, 0x1d99: 0x0018, 0x1d9a: 0x0018, 0x1d9b: 0x0018, 0x1d9c: 0x0018, 0x1d9d: 0x0018, 0x1d9e: 0x0018, 0x1d9f: 0x0018, 0x1da0: 0x0018, 0x1da1: 0x0018, 0x1da2: 0x0018, 0x1da3: 0x0018, 0x1da4: 0x0018, 0x1da5: 0x0018, 0x1da6: 0x0018, 0x1da7: 0x0018, 0x1da8: 0x0018, 0x1da9: 0x0018, 0x1daa: 0xc191, 0x1dab: 0xc1a9, 0x1dac: 0x0040, 0x1dad: 0x0040, 0x1dae: 0x0040, 0x1daf: 0x0040, 0x1db0: 0x0018, 0x1db1: 0x0018, 0x1db2: 0x0018, 0x1db3: 0x0018, 0x1db4: 0x0018, 0x1db5: 0x0018, 0x1db6: 0x0018, 0x1db7: 0x0018, 0x1db8: 0x0018, 0x1db9: 0x0018, 0x1dba: 0x0018, 0x1dbb: 0x0018, 0x1dbc: 0x0018, 0x1dbd: 0x0018, 0x1dbe: 0x0018, 0x1dbf: 0x0018, // Block 0x77, offset 0x1dc0 0x1dc0: 0xc1d9, 0x1dc1: 0xc211, 0x1dc2: 0xc249, 0x1dc3: 0x0040, 0x1dc4: 0x0040, 0x1dc5: 0x0040, 0x1dc6: 0x0040, 0x1dc7: 0x0040, 0x1dc8: 0x0040, 0x1dc9: 0x0040, 0x1dca: 0x0040, 0x1dcb: 0x0040, 0x1dcc: 0x0040, 0x1dcd: 0x0040, 0x1dce: 0x0040, 0x1dcf: 0x0040, 0x1dd0: 0xc269, 0x1dd1: 0xc289, 0x1dd2: 0xc2a9, 0x1dd3: 0xc2c9, 0x1dd4: 0xc2e9, 0x1dd5: 0xc309, 0x1dd6: 0xc329, 0x1dd7: 0xc349, 0x1dd8: 0xc369, 0x1dd9: 0xc389, 0x1dda: 0xc3a9, 0x1ddb: 0xc3c9, 0x1ddc: 0xc3e9, 0x1ddd: 0xc409, 0x1dde: 0xc429, 0x1ddf: 0xc449, 0x1de0: 0xc469, 0x1de1: 0xc489, 0x1de2: 0xc4a9, 0x1de3: 0xc4c9, 0x1de4: 0xc4e9, 0x1de5: 0xc509, 0x1de6: 0xc529, 0x1de7: 0xc549, 0x1de8: 0xc569, 0x1de9: 0xc589, 0x1dea: 0xc5a9, 0x1deb: 0xc5c9, 0x1dec: 0xc5e9, 0x1ded: 0xc609, 0x1dee: 0xc629, 0x1def: 0xc649, 0x1df0: 0xc669, 0x1df1: 0xc689, 0x1df2: 0xc6a9, 0x1df3: 0xc6c9, 0x1df4: 0xc6e9, 0x1df5: 0xc709, 0x1df6: 0xc729, 0x1df7: 0xc749, 0x1df8: 0xc769, 0x1df9: 0xc789, 0x1dfa: 0xc7a9, 0x1dfb: 0xc7c9, 0x1dfc: 0x0040, 0x1dfd: 0x0040, 0x1dfe: 0x0040, 0x1dff: 0x0040, // Block 0x78, offset 0x1e00 0x1e00: 0xcaf9, 0x1e01: 0xcb19, 0x1e02: 0xcb39, 0x1e03: 0x8b1d, 0x1e04: 0xcb59, 0x1e05: 0xcb79, 0x1e06: 0xcb99, 0x1e07: 0xcbb9, 0x1e08: 0xcbd9, 0x1e09: 0xcbf9, 0x1e0a: 0xcc19, 0x1e0b: 0xcc39, 0x1e0c: 0xcc59, 0x1e0d: 0x8b3d, 0x1e0e: 0xcc79, 0x1e0f: 0xcc99, 0x1e10: 0xccb9, 0x1e11: 0xccd9, 0x1e12: 0x8b5d, 0x1e13: 0xccf9, 0x1e14: 0xcd19, 0x1e15: 0xc429, 0x1e16: 0x8b7d, 0x1e17: 0xcd39, 0x1e18: 0xcd59, 0x1e19: 0xcd79, 0x1e1a: 0xcd99, 0x1e1b: 0xcdb9, 0x1e1c: 0x8b9d, 0x1e1d: 0xcdd9, 0x1e1e: 0xcdf9, 0x1e1f: 0xce19, 0x1e20: 0xce39, 0x1e21: 0xce59, 0x1e22: 0xc789, 0x1e23: 0xce79, 0x1e24: 0xce99, 0x1e25: 0xceb9, 0x1e26: 0xced9, 0x1e27: 0xcef9, 0x1e28: 0xcf19, 0x1e29: 0xcf39, 0x1e2a: 0xcf59, 0x1e2b: 0xcf79, 0x1e2c: 0xcf99, 0x1e2d: 0xcfb9, 0x1e2e: 0xcfd9, 0x1e2f: 0xcff9, 0x1e30: 0xd019, 0x1e31: 0xd039, 0x1e32: 0xd039, 0x1e33: 0xd039, 0x1e34: 0x8bbd, 0x1e35: 0xd059, 0x1e36: 0xd079, 0x1e37: 0xd099, 0x1e38: 0x8bdd, 0x1e39: 0xd0b9, 0x1e3a: 0xd0d9, 0x1e3b: 0xd0f9, 0x1e3c: 0xd119, 0x1e3d: 0xd139, 0x1e3e: 0xd159, 0x1e3f: 0xd179, // Block 0x79, offset 0x1e40 0x1e40: 0xd199, 0x1e41: 0xd1b9, 0x1e42: 0xd1d9, 0x1e43: 0xd1f9, 0x1e44: 0xd219, 0x1e45: 0xd239, 0x1e46: 0xd239, 0x1e47: 0xd259, 0x1e48: 0xd279, 0x1e49: 0xd299, 0x1e4a: 0xd2b9, 0x1e4b: 0xd2d9, 0x1e4c: 0xd2f9, 0x1e4d: 0xd319, 0x1e4e: 0xd339, 0x1e4f: 0xd359, 0x1e50: 0xd379, 0x1e51: 0xd399, 0x1e52: 0xd3b9, 0x1e53: 0xd3d9, 0x1e54: 0xd3f9, 0x1e55: 0xd419, 0x1e56: 0xd439, 0x1e57: 0xd459, 0x1e58: 0xd479, 0x1e59: 0x8bfd, 0x1e5a: 0xd499, 0x1e5b: 0xd4b9, 0x1e5c: 0xd4d9, 0x1e5d: 0xc309, 0x1e5e: 0xd4f9, 0x1e5f: 0xd519, 0x1e60: 0x8c1d, 0x1e61: 0x8c3d, 0x1e62: 0xd539, 0x1e63: 0xd559, 0x1e64: 0xd579, 0x1e65: 0xd599, 0x1e66: 0xd5b9, 0x1e67: 0xd5d9, 0x1e68: 0x2040, 0x1e69: 0xd5f9, 0x1e6a: 0xd619, 0x1e6b: 0xd619, 0x1e6c: 0x8c5d, 0x1e6d: 0xd639, 0x1e6e: 0xd659, 0x1e6f: 0xd679, 0x1e70: 0xd699, 0x1e71: 0x8c7d, 0x1e72: 0xd6b9, 0x1e73: 0xd6d9, 0x1e74: 0x2040, 0x1e75: 0xd6f9, 0x1e76: 0xd719, 0x1e77: 0xd739, 0x1e78: 0xd759, 0x1e79: 0xd779, 0x1e7a: 0xd799, 0x1e7b: 0x8c9d, 0x1e7c: 0xd7b9, 0x1e7d: 0x8cbd, 0x1e7e: 0xd7d9, 0x1e7f: 0xd7f9, // Block 0x7a, offset 0x1e80 0x1e80: 0xd819, 0x1e81: 0xd839, 0x1e82: 0xd859, 0x1e83: 0xd879, 0x1e84: 0xd899, 0x1e85: 0xd8b9, 0x1e86: 0xd8d9, 0x1e87: 0xd8f9, 0x1e88: 0xd919, 0x1e89: 0x8cdd, 0x1e8a: 0xd939, 0x1e8b: 0xd959, 0x1e8c: 0xd979, 0x1e8d: 0xd999, 0x1e8e: 0xd9b9, 0x1e8f: 0x8cfd, 0x1e90: 0xd9d9, 0x1e91: 0x8d1d, 0x1e92: 0x8d3d, 0x1e93: 0xd9f9, 0x1e94: 0xda19, 0x1e95: 0xda19, 0x1e96: 0xda39, 0x1e97: 0x8d5d, 0x1e98: 0x8d7d, 0x1e99: 0xda59, 0x1e9a: 0xda79, 0x1e9b: 0xda99, 0x1e9c: 0xdab9, 0x1e9d: 0xdad9, 0x1e9e: 0xdaf9, 0x1e9f: 0xdb19, 0x1ea0: 0xdb39, 0x1ea1: 0xdb59, 0x1ea2: 0xdb79, 0x1ea3: 0xdb99, 0x1ea4: 0x8d9d, 0x1ea5: 0xdbb9, 0x1ea6: 0xdbd9, 0x1ea7: 0xdbf9, 0x1ea8: 0xdc19, 0x1ea9: 0xdbf9, 0x1eaa: 0xdc39, 0x1eab: 0xdc59, 0x1eac: 0xdc79, 0x1ead: 0xdc99, 0x1eae: 0xdcb9, 0x1eaf: 0xdcd9, 0x1eb0: 0xdcf9, 0x1eb1: 0xdd19, 0x1eb2: 0xdd39, 0x1eb3: 0xdd59, 0x1eb4: 0xdd79, 0x1eb5: 0xdd99, 0x1eb6: 0xddb9, 0x1eb7: 0xddd9, 0x1eb8: 0x8dbd, 0x1eb9: 0xddf9, 0x1eba: 0xde19, 0x1ebb: 0xde39, 0x1ebc: 0xde59, 0x1ebd: 0xde79, 0x1ebe: 0x8ddd, 0x1ebf: 0xde99, // Block 0x7b, offset 0x1ec0 0x1ec0: 0xe599, 0x1ec1: 0xe5b9, 0x1ec2: 0xe5d9, 0x1ec3: 0xe5f9, 0x1ec4: 0xe619, 0x1ec5: 0xe639, 0x1ec6: 0x8efd, 0x1ec7: 0xe659, 0x1ec8: 0xe679, 0x1ec9: 0xe699, 0x1eca: 0xe6b9, 0x1ecb: 0xe6d9, 0x1ecc: 0xe6f9, 0x1ecd: 0x8f1d, 0x1ece: 0xe719, 0x1ecf: 0xe739, 0x1ed0: 0x8f3d, 0x1ed1: 0x8f5d, 0x1ed2: 0xe759, 0x1ed3: 0xe779, 0x1ed4: 0xe799, 0x1ed5: 0xe7b9, 0x1ed6: 0xe7d9, 0x1ed7: 0xe7f9, 0x1ed8: 0xe819, 0x1ed9: 0xe839, 0x1eda: 0xe859, 0x1edb: 0x8f7d, 0x1edc: 0xe879, 0x1edd: 0x8f9d, 0x1ede: 0xe899, 0x1edf: 0x2040, 0x1ee0: 0xe8b9, 0x1ee1: 0xe8d9, 0x1ee2: 0xe8f9, 0x1ee3: 0x8fbd, 0x1ee4: 0xe919, 0x1ee5: 0xe939, 0x1ee6: 0x8fdd, 0x1ee7: 0x8ffd, 0x1ee8: 0xe959, 0x1ee9: 0xe979, 0x1eea: 0xe999, 0x1eeb: 0xe9b9, 0x1eec: 0xe9d9, 0x1eed: 0xe9d9, 0x1eee: 0xe9f9, 0x1eef: 0xea19, 0x1ef0: 0xea39, 0x1ef1: 0xea59, 0x1ef2: 0xea79, 0x1ef3: 0xea99, 0x1ef4: 0xeab9, 0x1ef5: 0x901d, 0x1ef6: 0xead9, 0x1ef7: 0x903d, 0x1ef8: 0xeaf9, 0x1ef9: 0x905d, 0x1efa: 0xeb19, 0x1efb: 0x907d, 0x1efc: 0x909d, 0x1efd: 0x90bd, 0x1efe: 0xeb39, 0x1eff: 0xeb59, // Block 0x7c, offset 0x1f00 0x1f00: 0xeb79, 0x1f01: 0x90dd, 0x1f02: 0x90fd, 0x1f03: 0x911d, 0x1f04: 0x913d, 0x1f05: 0xeb99, 0x1f06: 0xebb9, 0x1f07: 0xebb9, 0x1f08: 0xebd9, 0x1f09: 0xebf9, 0x1f0a: 0xec19, 0x1f0b: 0xec39, 0x1f0c: 0xec59, 0x1f0d: 0x915d, 0x1f0e: 0xec79, 0x1f0f: 0xec99, 0x1f10: 0xecb9, 0x1f11: 0xecd9, 0x1f12: 0x917d, 0x1f13: 0xecf9, 0x1f14: 0x919d, 0x1f15: 0x91bd, 0x1f16: 0xed19, 0x1f17: 0xed39, 0x1f18: 0xed59, 0x1f19: 0xed79, 0x1f1a: 0xed99, 0x1f1b: 0xedb9, 0x1f1c: 0x91dd, 0x1f1d: 0x91fd, 0x1f1e: 0x921d, 0x1f1f: 0x2040, 0x1f20: 0xedd9, 0x1f21: 0x923d, 0x1f22: 0xedf9, 0x1f23: 0xee19, 0x1f24: 0xee39, 0x1f25: 0x925d, 0x1f26: 0xee59, 0x1f27: 0xee79, 0x1f28: 0xee99, 0x1f29: 0xeeb9, 0x1f2a: 0xeed9, 0x1f2b: 0x927d, 0x1f2c: 0xeef9, 0x1f2d: 0xef19, 0x1f2e: 0xef39, 0x1f2f: 0xef59, 0x1f30: 0xef79, 0x1f31: 0xef99, 0x1f32: 0x929d, 0x1f33: 0x92bd, 0x1f34: 0xefb9, 0x1f35: 0x92dd, 0x1f36: 0xefd9, 0x1f37: 0x92fd, 0x1f38: 0xeff9, 0x1f39: 0xf019, 0x1f3a: 0xf039, 0x1f3b: 0x931d, 0x1f3c: 0x933d, 0x1f3d: 0xf059, 0x1f3e: 0x935d, 0x1f3f: 0xf079, // Block 0x7d, offset 0x1f40 0x1f40: 0xf6b9, 0x1f41: 0xf6d9, 0x1f42: 0xf6f9, 0x1f43: 0xf719, 0x1f44: 0xf739, 0x1f45: 0x951d, 0x1f46: 0xf759, 0x1f47: 0xf779, 0x1f48: 0xf799, 0x1f49: 0xf7b9, 0x1f4a: 0xf7d9, 0x1f4b: 0x953d, 0x1f4c: 0x955d, 0x1f4d: 0xf7f9, 0x1f4e: 0xf819, 0x1f4f: 0xf839, 0x1f50: 0xf859, 0x1f51: 0xf879, 0x1f52: 0xf899, 0x1f53: 0x957d, 0x1f54: 0xf8b9, 0x1f55: 0xf8d9, 0x1f56: 0xf8f9, 0x1f57: 0xf919, 0x1f58: 0x959d, 0x1f59: 0x95bd, 0x1f5a: 0xf939, 0x1f5b: 0xf959, 0x1f5c: 0xf979, 0x1f5d: 0x95dd, 0x1f5e: 0xf999, 0x1f5f: 0xf9b9, 0x1f60: 0x6815, 0x1f61: 0x95fd, 0x1f62: 0xf9d9, 0x1f63: 0xf9f9, 0x1f64: 0xfa19, 0x1f65: 0x961d, 0x1f66: 0xfa39, 0x1f67: 0xfa59, 0x1f68: 0xfa79, 0x1f69: 0xfa99, 0x1f6a: 0xfab9, 0x1f6b: 0xfad9, 0x1f6c: 0xfaf9, 0x1f6d: 0x963d, 0x1f6e: 0xfb19, 0x1f6f: 0xfb39, 0x1f70: 0xfb59, 0x1f71: 0x965d, 0x1f72: 0xfb79, 0x1f73: 0xfb99, 0x1f74: 0xfbb9, 0x1f75: 0xfbd9, 0x1f76: 0x7b35, 0x1f77: 0x967d, 0x1f78: 0xfbf9, 0x1f79: 0xfc19, 0x1f7a: 0xfc39, 0x1f7b: 0x969d, 0x1f7c: 0xfc59, 0x1f7d: 0x96bd, 0x1f7e: 0xfc79, 0x1f7f: 0xfc79, // Block 0x7e, offset 0x1f80 0x1f80: 0xfc99, 0x1f81: 0x96dd, 0x1f82: 0xfcb9, 0x1f83: 0xfcd9, 0x1f84: 0xfcf9, 0x1f85: 0xfd19, 0x1f86: 0xfd39, 0x1f87: 0xfd59, 0x1f88: 0xfd79, 0x1f89: 0x96fd, 0x1f8a: 0xfd99, 0x1f8b: 0xfdb9, 0x1f8c: 0xfdd9, 0x1f8d: 0xfdf9, 0x1f8e: 0xfe19, 0x1f8f: 0xfe39, 0x1f90: 0x971d, 0x1f91: 0xfe59, 0x1f92: 0x973d, 0x1f93: 0x975d, 0x1f94: 0x977d, 0x1f95: 0xfe79, 0x1f96: 0xfe99, 0x1f97: 0xfeb9, 0x1f98: 0xfed9, 0x1f99: 0xfef9, 0x1f9a: 0xff19, 0x1f9b: 0xff39, 0x1f9c: 0xff59, 0x1f9d: 0x979d, 0x1f9e: 0x0040, 0x1f9f: 0x0040, 0x1fa0: 0x0040, 0x1fa1: 0x0040, 0x1fa2: 0x0040, 0x1fa3: 0x0040, 0x1fa4: 0x0040, 0x1fa5: 0x0040, 0x1fa6: 0x0040, 0x1fa7: 0x0040, 0x1fa8: 0x0040, 0x1fa9: 0x0040, 0x1faa: 0x0040, 0x1fab: 0x0040, 0x1fac: 0x0040, 0x1fad: 0x0040, 0x1fae: 0x0040, 0x1faf: 0x0040, 0x1fb0: 0x0040, 0x1fb1: 0x0040, 0x1fb2: 0x0040, 0x1fb3: 0x0040, 0x1fb4: 0x0040, 0x1fb5: 0x0040, 0x1fb6: 0x0040, 0x1fb7: 0x0040, 0x1fb8: 0x0040, 0x1fb9: 0x0040, 0x1fba: 0x0040, 0x1fbb: 0x0040, 0x1fbc: 0x0040, 0x1fbd: 0x0040, 0x1fbe: 0x0040, 0x1fbf: 0x0040, } // idnaIndex: 36 blocks, 2304 entries, 4608 bytes // Block 0 is the zero block. var idnaIndex = [2304]uint16{ // Block 0x0, offset 0x0 // Block 0x1, offset 0x40 // Block 0x2, offset 0x80 // Block 0x3, offset 0xc0 0xc2: 0x01, 0xc3: 0x7d, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x04, 0xc7: 0x05, 0xc8: 0x06, 0xc9: 0x7e, 0xca: 0x7f, 0xcb: 0x07, 0xcc: 0x80, 0xcd: 0x08, 0xce: 0x09, 0xcf: 0x0a, 0xd0: 0x81, 0xd1: 0x0b, 0xd2: 0x0c, 0xd3: 0x0d, 0xd4: 0x0e, 0xd5: 0x82, 0xd6: 0x83, 0xd7: 0x84, 0xd8: 0x0f, 0xd9: 0x10, 0xda: 0x85, 0xdb: 0x11, 0xdc: 0x12, 0xdd: 0x86, 0xde: 0x87, 0xdf: 0x88, 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06, 0xe5: 0x07, 0xe6: 0x07, 0xe7: 0x07, 0xe8: 0x07, 0xe9: 0x08, 0xea: 0x09, 0xeb: 0x07, 0xec: 0x07, 0xed: 0x0a, 0xee: 0x0b, 0xef: 0x0c, 0xf0: 0x1d, 0xf1: 0x1e, 0xf2: 0x1e, 0xf3: 0x20, 0xf4: 0x21, // Block 0x4, offset 0x100 0x120: 0x89, 0x121: 0x13, 0x122: 0x8a, 0x123: 0x8b, 0x124: 0x8c, 0x125: 0x14, 0x126: 0x15, 0x127: 0x16, 0x128: 0x17, 0x129: 0x18, 0x12a: 0x19, 0x12b: 0x1a, 0x12c: 0x1b, 0x12d: 0x1c, 0x12e: 0x1d, 0x12f: 0x8d, 0x130: 0x8e, 0x131: 0x1e, 0x132: 0x1f, 0x133: 0x20, 0x134: 0x8f, 0x135: 0x21, 0x136: 0x90, 0x137: 0x91, 0x138: 0x92, 0x139: 0x93, 0x13a: 0x22, 0x13b: 0x94, 0x13c: 0x95, 0x13d: 0x23, 0x13e: 0x24, 0x13f: 0x96, // Block 0x5, offset 0x140 0x140: 0x97, 0x141: 0x98, 0x142: 0x99, 0x143: 0x9a, 0x144: 0x9b, 0x145: 0x9c, 0x146: 0x9d, 0x147: 0x9e, 0x148: 0x9f, 0x149: 0xa0, 0x14a: 0xa1, 0x14b: 0xa2, 0x14c: 0xa3, 0x14d: 0xa4, 0x14e: 0xa5, 0x14f: 0xa6, 0x150: 0xa7, 0x151: 0x9f, 0x152: 0x9f, 0x153: 0x9f, 0x154: 0x9f, 0x155: 0x9f, 0x156: 0x9f, 0x157: 0x9f, 0x158: 0x9f, 0x159: 0xa8, 0x15a: 0xa9, 0x15b: 0xaa, 0x15c: 0xab, 0x15d: 0xac, 0x15e: 0xad, 0x15f: 0xae, 0x160: 0xaf, 0x161: 0xb0, 0x162: 0xb1, 0x163: 0xb2, 0x164: 0xb3, 0x165: 0xb4, 0x166: 0xb5, 0x167: 0xb6, 0x168: 0xb7, 0x169: 0xb8, 0x16a: 0xb9, 0x16b: 0xba, 0x16c: 0xbb, 0x16d: 0xbc, 0x16e: 0xbd, 0x16f: 0xbe, 0x170: 0xbf, 0x171: 0xc0, 0x172: 0xc1, 0x173: 0xc2, 0x174: 0x25, 0x175: 0x26, 0x176: 0x27, 0x177: 0xc3, 0x178: 0x28, 0x179: 0x28, 0x17a: 0x29, 0x17b: 0x28, 0x17c: 0xc4, 0x17d: 0x2a, 0x17e: 0x2b, 0x17f: 0x2c, // Block 0x6, offset 0x180 0x180: 0x2d, 0x181: 0x2e, 0x182: 0x2f, 0x183: 0xc5, 0x184: 0x30, 0x185: 0x31, 0x186: 0xc6, 0x187: 0x9b, 0x188: 0xc7, 0x189: 0xc8, 0x18a: 0x9b, 0x18b: 0x9b, 0x18c: 0xc9, 0x18d: 0x9b, 0x18e: 0x9b, 0x18f: 0x9b, 0x190: 0xca, 0x191: 0x32, 0x192: 0x33, 0x193: 0x34, 0x194: 0x9b, 0x195: 0x9b, 0x196: 0x9b, 0x197: 0x9b, 0x198: 0x9b, 0x199: 0x9b, 0x19a: 0x9b, 0x19b: 0x9b, 0x19c: 0x9b, 0x19d: 0x9b, 0x19e: 0x9b, 0x19f: 0x9b, 0x1a0: 0x9b, 0x1a1: 0x9b, 0x1a2: 0x9b, 0x1a3: 0x9b, 0x1a4: 0x9b, 0x1a5: 0x9b, 0x1a6: 0x9b, 0x1a7: 0x9b, 0x1a8: 0xcb, 0x1a9: 0xcc, 0x1aa: 0x9b, 0x1ab: 0xcd, 0x1ac: 0x9b, 0x1ad: 0xce, 0x1ae: 0xcf, 0x1af: 0xd0, 0x1b0: 0xd1, 0x1b1: 0x35, 0x1b2: 0x28, 0x1b3: 0x36, 0x1b4: 0xd2, 0x1b5: 0xd3, 0x1b6: 0xd4, 0x1b7: 0xd5, 0x1b8: 0xd6, 0x1b9: 0xd7, 0x1ba: 0xd8, 0x1bb: 0xd9, 0x1bc: 0xda, 0x1bd: 0xdb, 0x1be: 0xdc, 0x1bf: 0x37, // Block 0x7, offset 0x1c0 0x1c0: 0x38, 0x1c1: 0xdd, 0x1c2: 0xde, 0x1c3: 0xdf, 0x1c4: 0xe0, 0x1c5: 0x39, 0x1c6: 0x3a, 0x1c7: 0xe1, 0x1c8: 0xe2, 0x1c9: 0x3b, 0x1ca: 0x3c, 0x1cb: 0x3d, 0x1cc: 0x3e, 0x1cd: 0x3f, 0x1ce: 0x40, 0x1cf: 0x41, 0x1d0: 0x9f, 0x1d1: 0x9f, 0x1d2: 0x9f, 0x1d3: 0x9f, 0x1d4: 0x9f, 0x1d5: 0x9f, 0x1d6: 0x9f, 0x1d7: 0x9f, 0x1d8: 0x9f, 0x1d9: 0x9f, 0x1da: 0x9f, 0x1db: 0x9f, 0x1dc: 0x9f, 0x1dd: 0x9f, 0x1de: 0x9f, 0x1df: 0x9f, 0x1e0: 0x9f, 0x1e1: 0x9f, 0x1e2: 0x9f, 0x1e3: 0x9f, 0x1e4: 0x9f, 0x1e5: 0x9f, 0x1e6: 0x9f, 0x1e7: 0x9f, 0x1e8: 0x9f, 0x1e9: 0x9f, 0x1ea: 0x9f, 0x1eb: 0x9f, 0x1ec: 0x9f, 0x1ed: 0x9f, 0x1ee: 0x9f, 0x1ef: 0x9f, 0x1f0: 0x9f, 0x1f1: 0x9f, 0x1f2: 0x9f, 0x1f3: 0x9f, 0x1f4: 0x9f, 0x1f5: 0x9f, 0x1f6: 0x9f, 0x1f7: 0x9f, 0x1f8: 0x9f, 0x1f9: 0x9f, 0x1fa: 0x9f, 0x1fb: 0x9f, 0x1fc: 0x9f, 0x1fd: 0x9f, 0x1fe: 0x9f, 0x1ff: 0x9f, // Block 0x8, offset 0x200 0x200: 0x9f, 0x201: 0x9f, 0x202: 0x9f, 0x203: 0x9f, 0x204: 0x9f, 0x205: 0x9f, 0x206: 0x9f, 0x207: 0x9f, 0x208: 0x9f, 0x209: 0x9f, 0x20a: 0x9f, 0x20b: 0x9f, 0x20c: 0x9f, 0x20d: 0x9f, 0x20e: 0x9f, 0x20f: 0x9f, 0x210: 0x9f, 0x211: 0x9f, 0x212: 0x9f, 0x213: 0x9f, 0x214: 0x9f, 0x215: 0x9f, 0x216: 0x9f, 0x217: 0x9f, 0x218: 0x9f, 0x219: 0x9f, 0x21a: 0x9f, 0x21b: 0x9f, 0x21c: 0x9f, 0x21d: 0x9f, 0x21e: 0x9f, 0x21f: 0x9f, 0x220: 0x9f, 0x221: 0x9f, 0x222: 0x9f, 0x223: 0x9f, 0x224: 0x9f, 0x225: 0x9f, 0x226: 0x9f, 0x227: 0x9f, 0x228: 0x9f, 0x229: 0x9f, 0x22a: 0x9f, 0x22b: 0x9f, 0x22c: 0x9f, 0x22d: 0x9f, 0x22e: 0x9f, 0x22f: 0x9f, 0x230: 0x9f, 0x231: 0x9f, 0x232: 0x9f, 0x233: 0x9f, 0x234: 0x9f, 0x235: 0x9f, 0x236: 0xb2, 0x237: 0x9b, 0x238: 0x9f, 0x239: 0x9f, 0x23a: 0x9f, 0x23b: 0x9f, 0x23c: 0x9f, 0x23d: 0x9f, 0x23e: 0x9f, 0x23f: 0x9f, // Block 0x9, offset 0x240 0x240: 0x9f, 0x241: 0x9f, 0x242: 0x9f, 0x243: 0x9f, 0x244: 0x9f, 0x245: 0x9f, 0x246: 0x9f, 0x247: 0x9f, 0x248: 0x9f, 0x249: 0x9f, 0x24a: 0x9f, 0x24b: 0x9f, 0x24c: 0x9f, 0x24d: 0x9f, 0x24e: 0x9f, 0x24f: 0x9f, 0x250: 0x9f, 0x251: 0x9f, 0x252: 0x9f, 0x253: 0x9f, 0x254: 0x9f, 0x255: 0x9f, 0x256: 0x9f, 0x257: 0x9f, 0x258: 0x9f, 0x259: 0x9f, 0x25a: 0x9f, 0x25b: 0x9f, 0x25c: 0x9f, 0x25d: 0x9f, 0x25e: 0x9f, 0x25f: 0x9f, 0x260: 0x9f, 0x261: 0x9f, 0x262: 0x9f, 0x263: 0x9f, 0x264: 0x9f, 0x265: 0x9f, 0x266: 0x9f, 0x267: 0x9f, 0x268: 0x9f, 0x269: 0x9f, 0x26a: 0x9f, 0x26b: 0x9f, 0x26c: 0x9f, 0x26d: 0x9f, 0x26e: 0x9f, 0x26f: 0x9f, 0x270: 0x9f, 0x271: 0x9f, 0x272: 0x9f, 0x273: 0x9f, 0x274: 0x9f, 0x275: 0x9f, 0x276: 0x9f, 0x277: 0x9f, 0x278: 0x9f, 0x279: 0x9f, 0x27a: 0x9f, 0x27b: 0x9f, 0x27c: 0x9f, 0x27d: 0x9f, 0x27e: 0x9f, 0x27f: 0x9f, // Block 0xa, offset 0x280 0x280: 0x9f, 0x281: 0x9f, 0x282: 0x9f, 0x283: 0x9f, 0x284: 0x9f, 0x285: 0x9f, 0x286: 0x9f, 0x287: 0x9f, 0x288: 0x9f, 0x289: 0x9f, 0x28a: 0x9f, 0x28b: 0x9f, 0x28c: 0x9f, 0x28d: 0x9f, 0x28e: 0x9f, 0x28f: 0x9f, 0x290: 0x9f, 0x291: 0x9f, 0x292: 0x9f, 0x293: 0x9f, 0x294: 0x9f, 0x295: 0x9f, 0x296: 0x9f, 0x297: 0x9f, 0x298: 0x9f, 0x299: 0x9f, 0x29a: 0x9f, 0x29b: 0x9f, 0x29c: 0x9f, 0x29d: 0x9f, 0x29e: 0x9f, 0x29f: 0x9f, 0x2a0: 0x9f, 0x2a1: 0x9f, 0x2a2: 0x9f, 0x2a3: 0x9f, 0x2a4: 0x9f, 0x2a5: 0x9f, 0x2a6: 0x9f, 0x2a7: 0x9f, 0x2a8: 0x9f, 0x2a9: 0x9f, 0x2aa: 0x9f, 0x2ab: 0x9f, 0x2ac: 0x9f, 0x2ad: 0x9f, 0x2ae: 0x9f, 0x2af: 0x9f, 0x2b0: 0x9f, 0x2b1: 0x9f, 0x2b2: 0x9f, 0x2b3: 0x9f, 0x2b4: 0x9f, 0x2b5: 0x9f, 0x2b6: 0x9f, 0x2b7: 0x9f, 0x2b8: 0x9f, 0x2b9: 0x9f, 0x2ba: 0x9f, 0x2bb: 0x9f, 0x2bc: 0x9f, 0x2bd: 0x9f, 0x2be: 0x9f, 0x2bf: 0xe3, // Block 0xb, offset 0x2c0 0x2c0: 0x9f, 0x2c1: 0x9f, 0x2c2: 0x9f, 0x2c3: 0x9f, 0x2c4: 0x9f, 0x2c5: 0x9f, 0x2c6: 0x9f, 0x2c7: 0x9f, 0x2c8: 0x9f, 0x2c9: 0x9f, 0x2ca: 0x9f, 0x2cb: 0x9f, 0x2cc: 0x9f, 0x2cd: 0x9f, 0x2ce: 0x9f, 0x2cf: 0x9f, 0x2d0: 0x9f, 0x2d1: 0x9f, 0x2d2: 0xe4, 0x2d3: 0xe5, 0x2d4: 0x9f, 0x2d5: 0x9f, 0x2d6: 0x9f, 0x2d7: 0x9f, 0x2d8: 0xe6, 0x2d9: 0x42, 0x2da: 0x43, 0x2db: 0xe7, 0x2dc: 0x44, 0x2dd: 0x45, 0x2de: 0x46, 0x2df: 0xe8, 0x2e0: 0xe9, 0x2e1: 0xea, 0x2e2: 0xeb, 0x2e3: 0xec, 0x2e4: 0xed, 0x2e5: 0xee, 0x2e6: 0xef, 0x2e7: 0xf0, 0x2e8: 0xf1, 0x2e9: 0xf2, 0x2ea: 0xf3, 0x2eb: 0xf4, 0x2ec: 0xf5, 0x2ed: 0xf6, 0x2ee: 0xf7, 0x2ef: 0xf8, 0x2f0: 0x9f, 0x2f1: 0x9f, 0x2f2: 0x9f, 0x2f3: 0x9f, 0x2f4: 0x9f, 0x2f5: 0x9f, 0x2f6: 0x9f, 0x2f7: 0x9f, 0x2f8: 0x9f, 0x2f9: 0x9f, 0x2fa: 0x9f, 0x2fb: 0x9f, 0x2fc: 0x9f, 0x2fd: 0x9f, 0x2fe: 0x9f, 0x2ff: 0x9f, // Block 0xc, offset 0x300 0x300: 0x9f, 0x301: 0x9f, 0x302: 0x9f, 0x303: 0x9f, 0x304: 0x9f, 0x305: 0x9f, 0x306: 0x9f, 0x307: 0x9f, 0x308: 0x9f, 0x309: 0x9f, 0x30a: 0x9f, 0x30b: 0x9f, 0x30c: 0x9f, 0x30d: 0x9f, 0x30e: 0x9f, 0x30f: 0x9f, 0x310: 0x9f, 0x311: 0x9f, 0x312: 0x9f, 0x313: 0x9f, 0x314: 0x9f, 0x315: 0x9f, 0x316: 0x9f, 0x317: 0x9f, 0x318: 0x9f, 0x319: 0x9f, 0x31a: 0x9f, 0x31b: 0x9f, 0x31c: 0x9f, 0x31d: 0x9f, 0x31e: 0xf9, 0x31f: 0xfa, // Block 0xd, offset 0x340 0x340: 0xba, 0x341: 0xba, 0x342: 0xba, 0x343: 0xba, 0x344: 0xba, 0x345: 0xba, 0x346: 0xba, 0x347: 0xba, 0x348: 0xba, 0x349: 0xba, 0x34a: 0xba, 0x34b: 0xba, 0x34c: 0xba, 0x34d: 0xba, 0x34e: 0xba, 0x34f: 0xba, 0x350: 0xba, 0x351: 0xba, 0x352: 0xba, 0x353: 0xba, 0x354: 0xba, 0x355: 0xba, 0x356: 0xba, 0x357: 0xba, 0x358: 0xba, 0x359: 0xba, 0x35a: 0xba, 0x35b: 0xba, 0x35c: 0xba, 0x35d: 0xba, 0x35e: 0xba, 0x35f: 0xba, 0x360: 0xba, 0x361: 0xba, 0x362: 0xba, 0x363: 0xba, 0x364: 0xba, 0x365: 0xba, 0x366: 0xba, 0x367: 0xba, 0x368: 0xba, 0x369: 0xba, 0x36a: 0xba, 0x36b: 0xba, 0x36c: 0xba, 0x36d: 0xba, 0x36e: 0xba, 0x36f: 0xba, 0x370: 0xba, 0x371: 0xba, 0x372: 0xba, 0x373: 0xba, 0x374: 0xba, 0x375: 0xba, 0x376: 0xba, 0x377: 0xba, 0x378: 0xba, 0x379: 0xba, 0x37a: 0xba, 0x37b: 0xba, 0x37c: 0xba, 0x37d: 0xba, 0x37e: 0xba, 0x37f: 0xba, // Block 0xe, offset 0x380 0x380: 0xba, 0x381: 0xba, 0x382: 0xba, 0x383: 0xba, 0x384: 0xba, 0x385: 0xba, 0x386: 0xba, 0x387: 0xba, 0x388: 0xba, 0x389: 0xba, 0x38a: 0xba, 0x38b: 0xba, 0x38c: 0xba, 0x38d: 0xba, 0x38e: 0xba, 0x38f: 0xba, 0x390: 0xba, 0x391: 0xba, 0x392: 0xba, 0x393: 0xba, 0x394: 0xba, 0x395: 0xba, 0x396: 0xba, 0x397: 0xba, 0x398: 0xba, 0x399: 0xba, 0x39a: 0xba, 0x39b: 0xba, 0x39c: 0xba, 0x39d: 0xba, 0x39e: 0xba, 0x39f: 0xba, 0x3a0: 0xba, 0x3a1: 0xba, 0x3a2: 0xba, 0x3a3: 0xba, 0x3a4: 0xfb, 0x3a5: 0xfc, 0x3a6: 0xfd, 0x3a7: 0xfe, 0x3a8: 0x47, 0x3a9: 0xff, 0x3aa: 0x100, 0x3ab: 0x48, 0x3ac: 0x49, 0x3ad: 0x4a, 0x3ae: 0x4b, 0x3af: 0x4c, 0x3b0: 0x101, 0x3b1: 0x4d, 0x3b2: 0x4e, 0x3b3: 0x4f, 0x3b4: 0x50, 0x3b5: 0x51, 0x3b6: 0x102, 0x3b7: 0x52, 0x3b8: 0x53, 0x3b9: 0x54, 0x3ba: 0x55, 0x3bb: 0x56, 0x3bc: 0x57, 0x3bd: 0x58, 0x3be: 0x59, 0x3bf: 0x5a, // Block 0xf, offset 0x3c0 0x3c0: 0x103, 0x3c1: 0x104, 0x3c2: 0x9f, 0x3c3: 0x105, 0x3c4: 0x106, 0x3c5: 0x9b, 0x3c6: 0x107, 0x3c7: 0x108, 0x3c8: 0xba, 0x3c9: 0xba, 0x3ca: 0x109, 0x3cb: 0x10a, 0x3cc: 0x10b, 0x3cd: 0x10c, 0x3ce: 0x10d, 0x3cf: 0x10e, 0x3d0: 0x10f, 0x3d1: 0x9f, 0x3d2: 0x110, 0x3d3: 0x111, 0x3d4: 0x112, 0x3d5: 0x113, 0x3d6: 0xba, 0x3d7: 0xba, 0x3d8: 0x9f, 0x3d9: 0x9f, 0x3da: 0x9f, 0x3db: 0x9f, 0x3dc: 0x114, 0x3dd: 0x115, 0x3de: 0xba, 0x3df: 0xba, 0x3e0: 0x116, 0x3e1: 0x117, 0x3e2: 0x118, 0x3e3: 0x119, 0x3e4: 0x11a, 0x3e5: 0xba, 0x3e6: 0x11b, 0x3e7: 0x11c, 0x3e8: 0x11d, 0x3e9: 0x11e, 0x3ea: 0x11f, 0x3eb: 0x5b, 0x3ec: 0x120, 0x3ed: 0x121, 0x3ee: 0x5c, 0x3ef: 0xba, 0x3f0: 0x122, 0x3f1: 0x123, 0x3f2: 0x124, 0x3f3: 0x125, 0x3f4: 0xba, 0x3f5: 0xba, 0x3f6: 0xba, 0x3f7: 0xba, 0x3f8: 0xba, 0x3f9: 0x126, 0x3fa: 0xba, 0x3fb: 0xba, 0x3fc: 0xba, 0x3fd: 0xba, 0x3fe: 0xba, 0x3ff: 0xba, // Block 0x10, offset 0x400 0x400: 0x127, 0x401: 0x128, 0x402: 0x129, 0x403: 0x12a, 0x404: 0x12b, 0x405: 0x12c, 0x406: 0x12d, 0x407: 0x12e, 0x408: 0x12f, 0x409: 0xba, 0x40a: 0x130, 0x40b: 0x131, 0x40c: 0x5d, 0x40d: 0x5e, 0x40e: 0xba, 0x40f: 0xba, 0x410: 0x132, 0x411: 0x133, 0x412: 0x134, 0x413: 0x135, 0x414: 0xba, 0x415: 0xba, 0x416: 0x136, 0x417: 0x137, 0x418: 0x138, 0x419: 0x139, 0x41a: 0x13a, 0x41b: 0x13b, 0x41c: 0x13c, 0x41d: 0xba, 0x41e: 0xba, 0x41f: 0xba, 0x420: 0xba, 0x421: 0xba, 0x422: 0x13d, 0x423: 0x13e, 0x424: 0xba, 0x425: 0xba, 0x426: 0xba, 0x427: 0xba, 0x428: 0x13f, 0x429: 0x140, 0x42a: 0x141, 0x42b: 0x142, 0x42c: 0xba, 0x42d: 0xba, 0x42e: 0xba, 0x42f: 0xba, 0x430: 0x143, 0x431: 0x144, 0x432: 0x145, 0x433: 0xba, 0x434: 0x146, 0x435: 0x147, 0x436: 0xba, 0x437: 0xba, 0x438: 0xba, 0x439: 0xba, 0x43a: 0xba, 0x43b: 0xba, 0x43c: 0xba, 0x43d: 0xba, 0x43e: 0xba, 0x43f: 0xba, // Block 0x11, offset 0x440 0x440: 0x9f, 0x441: 0x9f, 0x442: 0x9f, 0x443: 0x9f, 0x444: 0x9f, 0x445: 0x9f, 0x446: 0x9f, 0x447: 0x9f, 0x448: 0x9f, 0x449: 0x9f, 0x44a: 0x9f, 0x44b: 0x9f, 0x44c: 0x9f, 0x44d: 0x9f, 0x44e: 0x148, 0x44f: 0xba, 0x450: 0x9b, 0x451: 0x149, 0x452: 0x9f, 0x453: 0x9f, 0x454: 0x9f, 0x455: 0x14a, 0x456: 0xba, 0x457: 0xba, 0x458: 0xba, 0x459: 0xba, 0x45a: 0xba, 0x45b: 0xba, 0x45c: 0xba, 0x45d: 0xba, 0x45e: 0xba, 0x45f: 0xba, 0x460: 0xba, 0x461: 0xba, 0x462: 0xba, 0x463: 0xba, 0x464: 0xba, 0x465: 0xba, 0x466: 0xba, 0x467: 0xba, 0x468: 0xba, 0x469: 0xba, 0x46a: 0xba, 0x46b: 0xba, 0x46c: 0xba, 0x46d: 0xba, 0x46e: 0xba, 0x46f: 0xba, 0x470: 0xba, 0x471: 0xba, 0x472: 0xba, 0x473: 0xba, 0x474: 0xba, 0x475: 0xba, 0x476: 0xba, 0x477: 0xba, 0x478: 0xba, 0x479: 0xba, 0x47a: 0xba, 0x47b: 0xba, 0x47c: 0xba, 0x47d: 0xba, 0x47e: 0xba, 0x47f: 0xba, // Block 0x12, offset 0x480 0x480: 0x9f, 0x481: 0x9f, 0x482: 0x9f, 0x483: 0x9f, 0x484: 0x9f, 0x485: 0x9f, 0x486: 0x9f, 0x487: 0x9f, 0x488: 0x9f, 0x489: 0x9f, 0x48a: 0x9f, 0x48b: 0x9f, 0x48c: 0x9f, 0x48d: 0x9f, 0x48e: 0x9f, 0x48f: 0x9f, 0x490: 0x14b, 0x491: 0xba, 0x492: 0xba, 0x493: 0xba, 0x494: 0xba, 0x495: 0xba, 0x496: 0xba, 0x497: 0xba, 0x498: 0xba, 0x499: 0xba, 0x49a: 0xba, 0x49b: 0xba, 0x49c: 0xba, 0x49d: 0xba, 0x49e: 0xba, 0x49f: 0xba, 0x4a0: 0xba, 0x4a1: 0xba, 0x4a2: 0xba, 0x4a3: 0xba, 0x4a4: 0xba, 0x4a5: 0xba, 0x4a6: 0xba, 0x4a7: 0xba, 0x4a8: 0xba, 0x4a9: 0xba, 0x4aa: 0xba, 0x4ab: 0xba, 0x4ac: 0xba, 0x4ad: 0xba, 0x4ae: 0xba, 0x4af: 0xba, 0x4b0: 0xba, 0x4b1: 0xba, 0x4b2: 0xba, 0x4b3: 0xba, 0x4b4: 0xba, 0x4b5: 0xba, 0x4b6: 0xba, 0x4b7: 0xba, 0x4b8: 0xba, 0x4b9: 0xba, 0x4ba: 0xba, 0x4bb: 0xba, 0x4bc: 0xba, 0x4bd: 0xba, 0x4be: 0xba, 0x4bf: 0xba, // Block 0x13, offset 0x4c0 0x4c0: 0xba, 0x4c1: 0xba, 0x4c2: 0xba, 0x4c3: 0xba, 0x4c4: 0xba, 0x4c5: 0xba, 0x4c6: 0xba, 0x4c7: 0xba, 0x4c8: 0xba, 0x4c9: 0xba, 0x4ca: 0xba, 0x4cb: 0xba, 0x4cc: 0xba, 0x4cd: 0xba, 0x4ce: 0xba, 0x4cf: 0xba, 0x4d0: 0x9f, 0x4d1: 0x9f, 0x4d2: 0x9f, 0x4d3: 0x9f, 0x4d4: 0x9f, 0x4d5: 0x9f, 0x4d6: 0x9f, 0x4d7: 0x9f, 0x4d8: 0x9f, 0x4d9: 0x14c, 0x4da: 0xba, 0x4db: 0xba, 0x4dc: 0xba, 0x4dd: 0xba, 0x4de: 0xba, 0x4df: 0xba, 0x4e0: 0xba, 0x4e1: 0xba, 0x4e2: 0xba, 0x4e3: 0xba, 0x4e4: 0xba, 0x4e5: 0xba, 0x4e6: 0xba, 0x4e7: 0xba, 0x4e8: 0xba, 0x4e9: 0xba, 0x4ea: 0xba, 0x4eb: 0xba, 0x4ec: 0xba, 0x4ed: 0xba, 0x4ee: 0xba, 0x4ef: 0xba, 0x4f0: 0xba, 0x4f1: 0xba, 0x4f2: 0xba, 0x4f3: 0xba, 0x4f4: 0xba, 0x4f5: 0xba, 0x4f6: 0xba, 0x4f7: 0xba, 0x4f8: 0xba, 0x4f9: 0xba, 0x4fa: 0xba, 0x4fb: 0xba, 0x4fc: 0xba, 0x4fd: 0xba, 0x4fe: 0xba, 0x4ff: 0xba, // Block 0x14, offset 0x500 0x500: 0xba, 0x501: 0xba, 0x502: 0xba, 0x503: 0xba, 0x504: 0xba, 0x505: 0xba, 0x506: 0xba, 0x507: 0xba, 0x508: 0xba, 0x509: 0xba, 0x50a: 0xba, 0x50b: 0xba, 0x50c: 0xba, 0x50d: 0xba, 0x50e: 0xba, 0x50f: 0xba, 0x510: 0xba, 0x511: 0xba, 0x512: 0xba, 0x513: 0xba, 0x514: 0xba, 0x515: 0xba, 0x516: 0xba, 0x517: 0xba, 0x518: 0xba, 0x519: 0xba, 0x51a: 0xba, 0x51b: 0xba, 0x51c: 0xba, 0x51d: 0xba, 0x51e: 0xba, 0x51f: 0xba, 0x520: 0x9f, 0x521: 0x9f, 0x522: 0x9f, 0x523: 0x9f, 0x524: 0x9f, 0x525: 0x9f, 0x526: 0x9f, 0x527: 0x9f, 0x528: 0x142, 0x529: 0x14d, 0x52a: 0xba, 0x52b: 0x14e, 0x52c: 0x14f, 0x52d: 0x150, 0x52e: 0x151, 0x52f: 0xba, 0x530: 0xba, 0x531: 0xba, 0x532: 0xba, 0x533: 0xba, 0x534: 0xba, 0x535: 0xba, 0x536: 0xba, 0x537: 0xba, 0x538: 0xba, 0x539: 0xba, 0x53a: 0xba, 0x53b: 0xba, 0x53c: 0x9f, 0x53d: 0x152, 0x53e: 0x153, 0x53f: 0x154, // Block 0x15, offset 0x540 0x540: 0x9f, 0x541: 0x9f, 0x542: 0x9f, 0x543: 0x9f, 0x544: 0x9f, 0x545: 0x9f, 0x546: 0x9f, 0x547: 0x9f, 0x548: 0x9f, 0x549: 0x9f, 0x54a: 0x9f, 0x54b: 0x9f, 0x54c: 0x9f, 0x54d: 0x9f, 0x54e: 0x9f, 0x54f: 0x9f, 0x550: 0x9f, 0x551: 0x9f, 0x552: 0x9f, 0x553: 0x9f, 0x554: 0x9f, 0x555: 0x9f, 0x556: 0x9f, 0x557: 0x9f, 0x558: 0x9f, 0x559: 0x9f, 0x55a: 0x9f, 0x55b: 0x9f, 0x55c: 0x9f, 0x55d: 0x9f, 0x55e: 0x9f, 0x55f: 0x155, 0x560: 0x9f, 0x561: 0x9f, 0x562: 0x9f, 0x563: 0x9f, 0x564: 0x9f, 0x565: 0x9f, 0x566: 0x9f, 0x567: 0x9f, 0x568: 0x9f, 0x569: 0x9f, 0x56a: 0x9f, 0x56b: 0x156, 0x56c: 0xba, 0x56d: 0xba, 0x56e: 0xba, 0x56f: 0xba, 0x570: 0xba, 0x571: 0xba, 0x572: 0xba, 0x573: 0xba, 0x574: 0xba, 0x575: 0xba, 0x576: 0xba, 0x577: 0xba, 0x578: 0xba, 0x579: 0xba, 0x57a: 0xba, 0x57b: 0xba, 0x57c: 0xba, 0x57d: 0xba, 0x57e: 0xba, 0x57f: 0xba, // Block 0x16, offset 0x580 0x580: 0x9f, 0x581: 0x9f, 0x582: 0x9f, 0x583: 0x9f, 0x584: 0x157, 0x585: 0x158, 0x586: 0x9f, 0x587: 0x9f, 0x588: 0x9f, 0x589: 0x9f, 0x58a: 0x9f, 0x58b: 0x159, 0x58c: 0xba, 0x58d: 0xba, 0x58e: 0xba, 0x58f: 0xba, 0x590: 0xba, 0x591: 0xba, 0x592: 0xba, 0x593: 0xba, 0x594: 0xba, 0x595: 0xba, 0x596: 0xba, 0x597: 0xba, 0x598: 0xba, 0x599: 0xba, 0x59a: 0xba, 0x59b: 0xba, 0x59c: 0xba, 0x59d: 0xba, 0x59e: 0xba, 0x59f: 0xba, 0x5a0: 0xba, 0x5a1: 0xba, 0x5a2: 0xba, 0x5a3: 0xba, 0x5a4: 0xba, 0x5a5: 0xba, 0x5a6: 0xba, 0x5a7: 0xba, 0x5a8: 0xba, 0x5a9: 0xba, 0x5aa: 0xba, 0x5ab: 0xba, 0x5ac: 0xba, 0x5ad: 0xba, 0x5ae: 0xba, 0x5af: 0xba, 0x5b0: 0x9f, 0x5b1: 0x15a, 0x5b2: 0x15b, 0x5b3: 0xba, 0x5b4: 0xba, 0x5b5: 0xba, 0x5b6: 0xba, 0x5b7: 0xba, 0x5b8: 0xba, 0x5b9: 0xba, 0x5ba: 0xba, 0x5bb: 0xba, 0x5bc: 0xba, 0x5bd: 0xba, 0x5be: 0xba, 0x5bf: 0xba, // Block 0x17, offset 0x5c0 0x5c0: 0x9b, 0x5c1: 0x9b, 0x5c2: 0x9b, 0x5c3: 0x15c, 0x5c4: 0x15d, 0x5c5: 0x15e, 0x5c6: 0x15f, 0x5c7: 0x160, 0x5c8: 0x9b, 0x5c9: 0x161, 0x5ca: 0xba, 0x5cb: 0xba, 0x5cc: 0x9b, 0x5cd: 0x162, 0x5ce: 0xba, 0x5cf: 0xba, 0x5d0: 0x5f, 0x5d1: 0x60, 0x5d2: 0x61, 0x5d3: 0x62, 0x5d4: 0x63, 0x5d5: 0x64, 0x5d6: 0x65, 0x5d7: 0x66, 0x5d8: 0x67, 0x5d9: 0x68, 0x5da: 0x69, 0x5db: 0x6a, 0x5dc: 0x6b, 0x5dd: 0x6c, 0x5de: 0x6d, 0x5df: 0x6e, 0x5e0: 0x9b, 0x5e1: 0x9b, 0x5e2: 0x9b, 0x5e3: 0x9b, 0x5e4: 0x9b, 0x5e5: 0x9b, 0x5e6: 0x9b, 0x5e7: 0x9b, 0x5e8: 0x163, 0x5e9: 0x164, 0x5ea: 0x165, 0x5eb: 0xba, 0x5ec: 0xba, 0x5ed: 0xba, 0x5ee: 0xba, 0x5ef: 0xba, 0x5f0: 0xba, 0x5f1: 0xba, 0x5f2: 0xba, 0x5f3: 0xba, 0x5f4: 0xba, 0x5f5: 0xba, 0x5f6: 0xba, 0x5f7: 0xba, 0x5f8: 0xba, 0x5f9: 0xba, 0x5fa: 0xba, 0x5fb: 0xba, 0x5fc: 0xba, 0x5fd: 0xba, 0x5fe: 0xba, 0x5ff: 0xba, // Block 0x18, offset 0x600 0x600: 0x166, 0x601: 0xba, 0x602: 0xba, 0x603: 0xba, 0x604: 0xba, 0x605: 0xba, 0x606: 0xba, 0x607: 0xba, 0x608: 0xba, 0x609: 0xba, 0x60a: 0xba, 0x60b: 0xba, 0x60c: 0xba, 0x60d: 0xba, 0x60e: 0xba, 0x60f: 0xba, 0x610: 0xba, 0x611: 0xba, 0x612: 0xba, 0x613: 0xba, 0x614: 0xba, 0x615: 0xba, 0x616: 0xba, 0x617: 0xba, 0x618: 0xba, 0x619: 0xba, 0x61a: 0xba, 0x61b: 0xba, 0x61c: 0xba, 0x61d: 0xba, 0x61e: 0xba, 0x61f: 0xba, 0x620: 0x122, 0x621: 0x122, 0x622: 0x122, 0x623: 0x167, 0x624: 0x6f, 0x625: 0x168, 0x626: 0xba, 0x627: 0xba, 0x628: 0xba, 0x629: 0xba, 0x62a: 0xba, 0x62b: 0xba, 0x62c: 0xba, 0x62d: 0xba, 0x62e: 0xba, 0x62f: 0xba, 0x630: 0xba, 0x631: 0xba, 0x632: 0xba, 0x633: 0xba, 0x634: 0xba, 0x635: 0xba, 0x636: 0xba, 0x637: 0xba, 0x638: 0x70, 0x639: 0x71, 0x63a: 0x72, 0x63b: 0x169, 0x63c: 0xba, 0x63d: 0xba, 0x63e: 0xba, 0x63f: 0xba, // Block 0x19, offset 0x640 0x640: 0x16a, 0x641: 0x9b, 0x642: 0x16b, 0x643: 0x16c, 0x644: 0x73, 0x645: 0x74, 0x646: 0x16d, 0x647: 0x16e, 0x648: 0x75, 0x649: 0x16f, 0x64a: 0xba, 0x64b: 0xba, 0x64c: 0x9b, 0x64d: 0x9b, 0x64e: 0x9b, 0x64f: 0x9b, 0x650: 0x9b, 0x651: 0x9b, 0x652: 0x9b, 0x653: 0x9b, 0x654: 0x9b, 0x655: 0x9b, 0x656: 0x9b, 0x657: 0x9b, 0x658: 0x9b, 0x659: 0x9b, 0x65a: 0x9b, 0x65b: 0x170, 0x65c: 0x9b, 0x65d: 0x171, 0x65e: 0x9b, 0x65f: 0x172, 0x660: 0x173, 0x661: 0x174, 0x662: 0x175, 0x663: 0xba, 0x664: 0x176, 0x665: 0x177, 0x666: 0x178, 0x667: 0x179, 0x668: 0xba, 0x669: 0xba, 0x66a: 0xba, 0x66b: 0xba, 0x66c: 0xba, 0x66d: 0xba, 0x66e: 0xba, 0x66f: 0xba, 0x670: 0xba, 0x671: 0xba, 0x672: 0xba, 0x673: 0xba, 0x674: 0xba, 0x675: 0xba, 0x676: 0xba, 0x677: 0xba, 0x678: 0xba, 0x679: 0xba, 0x67a: 0xba, 0x67b: 0xba, 0x67c: 0xba, 0x67d: 0xba, 0x67e: 0xba, 0x67f: 0xba, // Block 0x1a, offset 0x680 0x680: 0x9f, 0x681: 0x9f, 0x682: 0x9f, 0x683: 0x9f, 0x684: 0x9f, 0x685: 0x9f, 0x686: 0x9f, 0x687: 0x9f, 0x688: 0x9f, 0x689: 0x9f, 0x68a: 0x9f, 0x68b: 0x9f, 0x68c: 0x9f, 0x68d: 0x9f, 0x68e: 0x9f, 0x68f: 0x9f, 0x690: 0x9f, 0x691: 0x9f, 0x692: 0x9f, 0x693: 0x9f, 0x694: 0x9f, 0x695: 0x9f, 0x696: 0x9f, 0x697: 0x9f, 0x698: 0x9f, 0x699: 0x9f, 0x69a: 0x9f, 0x69b: 0x17a, 0x69c: 0x9f, 0x69d: 0x9f, 0x69e: 0x9f, 0x69f: 0x9f, 0x6a0: 0x9f, 0x6a1: 0x9f, 0x6a2: 0x9f, 0x6a3: 0x9f, 0x6a4: 0x9f, 0x6a5: 0x9f, 0x6a6: 0x9f, 0x6a7: 0x9f, 0x6a8: 0x9f, 0x6a9: 0x9f, 0x6aa: 0x9f, 0x6ab: 0x9f, 0x6ac: 0x9f, 0x6ad: 0x9f, 0x6ae: 0x9f, 0x6af: 0x9f, 0x6b0: 0x9f, 0x6b1: 0x9f, 0x6b2: 0x9f, 0x6b3: 0x9f, 0x6b4: 0x9f, 0x6b5: 0x9f, 0x6b6: 0x9f, 0x6b7: 0x9f, 0x6b8: 0x9f, 0x6b9: 0x9f, 0x6ba: 0x9f, 0x6bb: 0x9f, 0x6bc: 0x9f, 0x6bd: 0x9f, 0x6be: 0x9f, 0x6bf: 0x9f, // Block 0x1b, offset 0x6c0 0x6c0: 0x9f, 0x6c1: 0x9f, 0x6c2: 0x9f, 0x6c3: 0x9f, 0x6c4: 0x9f, 0x6c5: 0x9f, 0x6c6: 0x9f, 0x6c7: 0x9f, 0x6c8: 0x9f, 0x6c9: 0x9f, 0x6ca: 0x9f, 0x6cb: 0x9f, 0x6cc: 0x9f, 0x6cd: 0x9f, 0x6ce: 0x9f, 0x6cf: 0x9f, 0x6d0: 0x9f, 0x6d1: 0x9f, 0x6d2: 0x9f, 0x6d3: 0x9f, 0x6d4: 0x9f, 0x6d5: 0x9f, 0x6d6: 0x9f, 0x6d7: 0x9f, 0x6d8: 0x9f, 0x6d9: 0x9f, 0x6da: 0x9f, 0x6db: 0x9f, 0x6dc: 0x17b, 0x6dd: 0x9f, 0x6de: 0x9f, 0x6df: 0x9f, 0x6e0: 0x17c, 0x6e1: 0x9f, 0x6e2: 0x9f, 0x6e3: 0x9f, 0x6e4: 0x9f, 0x6e5: 0x9f, 0x6e6: 0x9f, 0x6e7: 0x9f, 0x6e8: 0x9f, 0x6e9: 0x9f, 0x6ea: 0x9f, 0x6eb: 0x9f, 0x6ec: 0x9f, 0x6ed: 0x9f, 0x6ee: 0x9f, 0x6ef: 0x9f, 0x6f0: 0x9f, 0x6f1: 0x9f, 0x6f2: 0x9f, 0x6f3: 0x9f, 0x6f4: 0x9f, 0x6f5: 0x9f, 0x6f6: 0x9f, 0x6f7: 0x9f, 0x6f8: 0x9f, 0x6f9: 0x9f, 0x6fa: 0x9f, 0x6fb: 0x9f, 0x6fc: 0x9f, 0x6fd: 0x9f, 0x6fe: 0x9f, 0x6ff: 0x9f, // Block 0x1c, offset 0x700 0x700: 0x9f, 0x701: 0x9f, 0x702: 0x9f, 0x703: 0x9f, 0x704: 0x9f, 0x705: 0x9f, 0x706: 0x9f, 0x707: 0x9f, 0x708: 0x9f, 0x709: 0x9f, 0x70a: 0x9f, 0x70b: 0x9f, 0x70c: 0x9f, 0x70d: 0x9f, 0x70e: 0x9f, 0x70f: 0x9f, 0x710: 0x9f, 0x711: 0x9f, 0x712: 0x9f, 0x713: 0x9f, 0x714: 0x9f, 0x715: 0x9f, 0x716: 0x9f, 0x717: 0x9f, 0x718: 0x9f, 0x719: 0x9f, 0x71a: 0x9f, 0x71b: 0x9f, 0x71c: 0x9f, 0x71d: 0x9f, 0x71e: 0x9f, 0x71f: 0x9f, 0x720: 0x9f, 0x721: 0x9f, 0x722: 0x9f, 0x723: 0x9f, 0x724: 0x9f, 0x725: 0x9f, 0x726: 0x9f, 0x727: 0x9f, 0x728: 0x9f, 0x729: 0x9f, 0x72a: 0x9f, 0x72b: 0x9f, 0x72c: 0x9f, 0x72d: 0x9f, 0x72e: 0x9f, 0x72f: 0x9f, 0x730: 0x9f, 0x731: 0x9f, 0x732: 0x9f, 0x733: 0x9f, 0x734: 0x9f, 0x735: 0x9f, 0x736: 0x9f, 0x737: 0x9f, 0x738: 0x9f, 0x739: 0x9f, 0x73a: 0x17d, 0x73b: 0x9f, 0x73c: 0x9f, 0x73d: 0x9f, 0x73e: 0x9f, 0x73f: 0x9f, // Block 0x1d, offset 0x740 0x740: 0x9f, 0x741: 0x9f, 0x742: 0x9f, 0x743: 0x9f, 0x744: 0x9f, 0x745: 0x9f, 0x746: 0x9f, 0x747: 0x9f, 0x748: 0x9f, 0x749: 0x9f, 0x74a: 0x9f, 0x74b: 0x9f, 0x74c: 0x9f, 0x74d: 0x9f, 0x74e: 0x9f, 0x74f: 0x9f, 0x750: 0x9f, 0x751: 0x9f, 0x752: 0x9f, 0x753: 0x9f, 0x754: 0x9f, 0x755: 0x9f, 0x756: 0x9f, 0x757: 0x9f, 0x758: 0x9f, 0x759: 0x9f, 0x75a: 0x9f, 0x75b: 0x9f, 0x75c: 0x9f, 0x75d: 0x9f, 0x75e: 0x9f, 0x75f: 0x9f, 0x760: 0x9f, 0x761: 0x9f, 0x762: 0x9f, 0x763: 0x9f, 0x764: 0x9f, 0x765: 0x9f, 0x766: 0x9f, 0x767: 0x9f, 0x768: 0x9f, 0x769: 0x9f, 0x76a: 0x9f, 0x76b: 0x9f, 0x76c: 0x9f, 0x76d: 0x9f, 0x76e: 0x9f, 0x76f: 0x17e, 0x770: 0xba, 0x771: 0xba, 0x772: 0xba, 0x773: 0xba, 0x774: 0xba, 0x775: 0xba, 0x776: 0xba, 0x777: 0xba, 0x778: 0xba, 0x779: 0xba, 0x77a: 0xba, 0x77b: 0xba, 0x77c: 0xba, 0x77d: 0xba, 0x77e: 0xba, 0x77f: 0xba, // Block 0x1e, offset 0x780 0x780: 0xba, 0x781: 0xba, 0x782: 0xba, 0x783: 0xba, 0x784: 0xba, 0x785: 0xba, 0x786: 0xba, 0x787: 0xba, 0x788: 0xba, 0x789: 0xba, 0x78a: 0xba, 0x78b: 0xba, 0x78c: 0xba, 0x78d: 0xba, 0x78e: 0xba, 0x78f: 0xba, 0x790: 0xba, 0x791: 0xba, 0x792: 0xba, 0x793: 0xba, 0x794: 0xba, 0x795: 0xba, 0x796: 0xba, 0x797: 0xba, 0x798: 0xba, 0x799: 0xba, 0x79a: 0xba, 0x79b: 0xba, 0x79c: 0xba, 0x79d: 0xba, 0x79e: 0xba, 0x79f: 0xba, 0x7a0: 0x76, 0x7a1: 0x77, 0x7a2: 0x78, 0x7a3: 0x17f, 0x7a4: 0x79, 0x7a5: 0x7a, 0x7a6: 0x180, 0x7a7: 0x7b, 0x7a8: 0x7c, 0x7a9: 0xba, 0x7aa: 0xba, 0x7ab: 0xba, 0x7ac: 0xba, 0x7ad: 0xba, 0x7ae: 0xba, 0x7af: 0xba, 0x7b0: 0xba, 0x7b1: 0xba, 0x7b2: 0xba, 0x7b3: 0xba, 0x7b4: 0xba, 0x7b5: 0xba, 0x7b6: 0xba, 0x7b7: 0xba, 0x7b8: 0xba, 0x7b9: 0xba, 0x7ba: 0xba, 0x7bb: 0xba, 0x7bc: 0xba, 0x7bd: 0xba, 0x7be: 0xba, 0x7bf: 0xba, // Block 0x1f, offset 0x7c0 0x7d0: 0x0d, 0x7d1: 0x0e, 0x7d2: 0x0f, 0x7d3: 0x10, 0x7d4: 0x11, 0x7d5: 0x0b, 0x7d6: 0x12, 0x7d7: 0x07, 0x7d8: 0x13, 0x7d9: 0x0b, 0x7da: 0x0b, 0x7db: 0x14, 0x7dc: 0x0b, 0x7dd: 0x15, 0x7de: 0x16, 0x7df: 0x17, 0x7e0: 0x07, 0x7e1: 0x07, 0x7e2: 0x07, 0x7e3: 0x07, 0x7e4: 0x07, 0x7e5: 0x07, 0x7e6: 0x07, 0x7e7: 0x07, 0x7e8: 0x07, 0x7e9: 0x07, 0x7ea: 0x18, 0x7eb: 0x19, 0x7ec: 0x1a, 0x7ed: 0x07, 0x7ee: 0x1b, 0x7ef: 0x1c, 0x7f0: 0x0b, 0x7f1: 0x0b, 0x7f2: 0x0b, 0x7f3: 0x0b, 0x7f4: 0x0b, 0x7f5: 0x0b, 0x7f6: 0x0b, 0x7f7: 0x0b, 0x7f8: 0x0b, 0x7f9: 0x0b, 0x7fa: 0x0b, 0x7fb: 0x0b, 0x7fc: 0x0b, 0x7fd: 0x0b, 0x7fe: 0x0b, 0x7ff: 0x0b, // Block 0x20, offset 0x800 0x800: 0x0b, 0x801: 0x0b, 0x802: 0x0b, 0x803: 0x0b, 0x804: 0x0b, 0x805: 0x0b, 0x806: 0x0b, 0x807: 0x0b, 0x808: 0x0b, 0x809: 0x0b, 0x80a: 0x0b, 0x80b: 0x0b, 0x80c: 0x0b, 0x80d: 0x0b, 0x80e: 0x0b, 0x80f: 0x0b, 0x810: 0x0b, 0x811: 0x0b, 0x812: 0x0b, 0x813: 0x0b, 0x814: 0x0b, 0x815: 0x0b, 0x816: 0x0b, 0x817: 0x0b, 0x818: 0x0b, 0x819: 0x0b, 0x81a: 0x0b, 0x81b: 0x0b, 0x81c: 0x0b, 0x81d: 0x0b, 0x81e: 0x0b, 0x81f: 0x0b, 0x820: 0x0b, 0x821: 0x0b, 0x822: 0x0b, 0x823: 0x0b, 0x824: 0x0b, 0x825: 0x0b, 0x826: 0x0b, 0x827: 0x0b, 0x828: 0x0b, 0x829: 0x0b, 0x82a: 0x0b, 0x82b: 0x0b, 0x82c: 0x0b, 0x82d: 0x0b, 0x82e: 0x0b, 0x82f: 0x0b, 0x830: 0x0b, 0x831: 0x0b, 0x832: 0x0b, 0x833: 0x0b, 0x834: 0x0b, 0x835: 0x0b, 0x836: 0x0b, 0x837: 0x0b, 0x838: 0x0b, 0x839: 0x0b, 0x83a: 0x0b, 0x83b: 0x0b, 0x83c: 0x0b, 0x83d: 0x0b, 0x83e: 0x0b, 0x83f: 0x0b, // Block 0x21, offset 0x840 0x840: 0x181, 0x841: 0x182, 0x842: 0xba, 0x843: 0xba, 0x844: 0x183, 0x845: 0x183, 0x846: 0x183, 0x847: 0x184, 0x848: 0xba, 0x849: 0xba, 0x84a: 0xba, 0x84b: 0xba, 0x84c: 0xba, 0x84d: 0xba, 0x84e: 0xba, 0x84f: 0xba, 0x850: 0xba, 0x851: 0xba, 0x852: 0xba, 0x853: 0xba, 0x854: 0xba, 0x855: 0xba, 0x856: 0xba, 0x857: 0xba, 0x858: 0xba, 0x859: 0xba, 0x85a: 0xba, 0x85b: 0xba, 0x85c: 0xba, 0x85d: 0xba, 0x85e: 0xba, 0x85f: 0xba, 0x860: 0xba, 0x861: 0xba, 0x862: 0xba, 0x863: 0xba, 0x864: 0xba, 0x865: 0xba, 0x866: 0xba, 0x867: 0xba, 0x868: 0xba, 0x869: 0xba, 0x86a: 0xba, 0x86b: 0xba, 0x86c: 0xba, 0x86d: 0xba, 0x86e: 0xba, 0x86f: 0xba, 0x870: 0xba, 0x871: 0xba, 0x872: 0xba, 0x873: 0xba, 0x874: 0xba, 0x875: 0xba, 0x876: 0xba, 0x877: 0xba, 0x878: 0xba, 0x879: 0xba, 0x87a: 0xba, 0x87b: 0xba, 0x87c: 0xba, 0x87d: 0xba, 0x87e: 0xba, 0x87f: 0xba, // Block 0x22, offset 0x880 0x880: 0x0b, 0x881: 0x0b, 0x882: 0x0b, 0x883: 0x0b, 0x884: 0x0b, 0x885: 0x0b, 0x886: 0x0b, 0x887: 0x0b, 0x888: 0x0b, 0x889: 0x0b, 0x88a: 0x0b, 0x88b: 0x0b, 0x88c: 0x0b, 0x88d: 0x0b, 0x88e: 0x0b, 0x88f: 0x0b, 0x890: 0x0b, 0x891: 0x0b, 0x892: 0x0b, 0x893: 0x0b, 0x894: 0x0b, 0x895: 0x0b, 0x896: 0x0b, 0x897: 0x0b, 0x898: 0x0b, 0x899: 0x0b, 0x89a: 0x0b, 0x89b: 0x0b, 0x89c: 0x0b, 0x89d: 0x0b, 0x89e: 0x0b, 0x89f: 0x0b, 0x8a0: 0x1f, 0x8a1: 0x0b, 0x8a2: 0x0b, 0x8a3: 0x0b, 0x8a4: 0x0b, 0x8a5: 0x0b, 0x8a6: 0x0b, 0x8a7: 0x0b, 0x8a8: 0x0b, 0x8a9: 0x0b, 0x8aa: 0x0b, 0x8ab: 0x0b, 0x8ac: 0x0b, 0x8ad: 0x0b, 0x8ae: 0x0b, 0x8af: 0x0b, 0x8b0: 0x0b, 0x8b1: 0x0b, 0x8b2: 0x0b, 0x8b3: 0x0b, 0x8b4: 0x0b, 0x8b5: 0x0b, 0x8b6: 0x0b, 0x8b7: 0x0b, 0x8b8: 0x0b, 0x8b9: 0x0b, 0x8ba: 0x0b, 0x8bb: 0x0b, 0x8bc: 0x0b, 0x8bd: 0x0b, 0x8be: 0x0b, 0x8bf: 0x0b, // Block 0x23, offset 0x8c0 0x8c0: 0x0b, 0x8c1: 0x0b, 0x8c2: 0x0b, 0x8c3: 0x0b, 0x8c4: 0x0b, 0x8c5: 0x0b, 0x8c6: 0x0b, 0x8c7: 0x0b, 0x8c8: 0x0b, 0x8c9: 0x0b, 0x8ca: 0x0b, 0x8cb: 0x0b, 0x8cc: 0x0b, 0x8cd: 0x0b, 0x8ce: 0x0b, 0x8cf: 0x0b, } // idnaSparseOffset: 264 entries, 528 bytes var idnaSparseOffset = []uint16{0x0, 0x8, 0x19, 0x25, 0x27, 0x2c, 0x34, 0x3f, 0x4b, 0x4f, 0x5e, 0x63, 0x6b, 0x77, 0x85, 0x8a, 0x93, 0xa3, 0xb1, 0xbd, 0xc9, 0xda, 0xe4, 0xeb, 0xf8, 0x109, 0x110, 0x11b, 0x12a, 0x138, 0x142, 0x144, 0x149, 0x14c, 0x14f, 0x151, 0x15d, 0x168, 0x170, 0x176, 0x17c, 0x181, 0x186, 0x189, 0x18d, 0x193, 0x198, 0x1a4, 0x1ae, 0x1b4, 0x1c5, 0x1cf, 0x1d2, 0x1da, 0x1dd, 0x1ea, 0x1f2, 0x1f6, 0x1fd, 0x205, 0x215, 0x221, 0x223, 0x22d, 0x239, 0x245, 0x251, 0x259, 0x25e, 0x268, 0x279, 0x27d, 0x288, 0x28c, 0x295, 0x29d, 0x2a3, 0x2a8, 0x2ab, 0x2af, 0x2b5, 0x2b9, 0x2bd, 0x2c3, 0x2ca, 0x2d0, 0x2d8, 0x2df, 0x2ea, 0x2f4, 0x2f8, 0x2fb, 0x301, 0x305, 0x307, 0x30a, 0x30c, 0x30f, 0x319, 0x31c, 0x32b, 0x32f, 0x334, 0x337, 0x33b, 0x340, 0x345, 0x34b, 0x351, 0x360, 0x366, 0x36a, 0x379, 0x37e, 0x386, 0x390, 0x39b, 0x3a3, 0x3b4, 0x3bd, 0x3cd, 0x3da, 0x3e4, 0x3e9, 0x3f6, 0x3fa, 0x3ff, 0x401, 0x405, 0x407, 0x40b, 0x414, 0x41a, 0x41e, 0x42e, 0x438, 0x43d, 0x440, 0x446, 0x44d, 0x452, 0x456, 0x45c, 0x461, 0x46a, 0x46f, 0x475, 0x47c, 0x483, 0x48a, 0x48e, 0x493, 0x496, 0x49b, 0x4a7, 0x4ad, 0x4b2, 0x4b9, 0x4c1, 0x4c6, 0x4ca, 0x4da, 0x4e1, 0x4e5, 0x4e9, 0x4f0, 0x4f2, 0x4f5, 0x4f8, 0x4fc, 0x500, 0x506, 0x50f, 0x51b, 0x522, 0x52b, 0x533, 0x53a, 0x548, 0x555, 0x562, 0x56b, 0x56f, 0x57d, 0x585, 0x590, 0x599, 0x59f, 0x5a7, 0x5b0, 0x5ba, 0x5bd, 0x5c9, 0x5cc, 0x5d1, 0x5de, 0x5e7, 0x5f3, 0x5f6, 0x600, 0x609, 0x615, 0x622, 0x62a, 0x62d, 0x632, 0x635, 0x638, 0x63b, 0x642, 0x649, 0x64d, 0x658, 0x65b, 0x661, 0x666, 0x66a, 0x66d, 0x670, 0x673, 0x676, 0x679, 0x67e, 0x688, 0x68b, 0x68f, 0x69e, 0x6aa, 0x6ae, 0x6b3, 0x6b8, 0x6bc, 0x6c1, 0x6ca, 0x6d5, 0x6db, 0x6e3, 0x6e7, 0x6eb, 0x6f1, 0x6f7, 0x6fc, 0x6ff, 0x70f, 0x716, 0x719, 0x71c, 0x720, 0x726, 0x72b, 0x730, 0x735, 0x738, 0x73d, 0x740, 0x743, 0x747, 0x74b, 0x74e, 0x75e, 0x76f, 0x774, 0x776, 0x778} // idnaSparseValues: 1915 entries, 7660 bytes var idnaSparseValues = [1915]valueRange{ // Block 0x0, offset 0x0 {value: 0x0000, lo: 0x07}, {value: 0xe105, lo: 0x80, hi: 0x96}, {value: 0x0018, lo: 0x97, hi: 0x97}, {value: 0xe105, lo: 0x98, hi: 0x9e}, {value: 0x001f, lo: 0x9f, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xb7}, {value: 0x0008, lo: 0xb8, hi: 0xbf}, // Block 0x1, offset 0x8 {value: 0x0000, lo: 0x10}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0xe01d, lo: 0x81, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0x82}, {value: 0x0335, lo: 0x83, hi: 0x83}, {value: 0x034d, lo: 0x84, hi: 0x84}, {value: 0x0365, lo: 0x85, hi: 0x85}, {value: 0xe00d, lo: 0x86, hi: 0x86}, {value: 0x0008, lo: 0x87, hi: 0x87}, {value: 0xe00d, lo: 0x88, hi: 0x88}, {value: 0x0008, lo: 0x89, hi: 0x89}, {value: 0xe00d, lo: 0x8a, hi: 0x8a}, {value: 0x0008, lo: 0x8b, hi: 0x8b}, {value: 0xe00d, lo: 0x8c, hi: 0x8c}, {value: 0x0008, lo: 0x8d, hi: 0x8d}, {value: 0xe00d, lo: 0x8e, hi: 0x8e}, {value: 0x0008, lo: 0x8f, hi: 0xbf}, // Block 0x2, offset 0x19 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x0249, lo: 0xb0, hi: 0xb0}, {value: 0x037d, lo: 0xb1, hi: 0xb1}, {value: 0x0259, lo: 0xb2, hi: 0xb2}, {value: 0x0269, lo: 0xb3, hi: 0xb3}, {value: 0x034d, lo: 0xb4, hi: 0xb4}, {value: 0x0395, lo: 0xb5, hi: 0xb5}, {value: 0xe1bd, lo: 0xb6, hi: 0xb6}, {value: 0x0279, lo: 0xb7, hi: 0xb7}, {value: 0x0289, lo: 0xb8, hi: 0xb8}, {value: 0x0008, lo: 0xb9, hi: 0xbf}, // Block 0x3, offset 0x25 {value: 0x0000, lo: 0x01}, {value: 0x3308, lo: 0x80, hi: 0xbf}, // Block 0x4, offset 0x27 {value: 0x0000, lo: 0x04}, {value: 0x03f5, lo: 0x80, hi: 0x8f}, {value: 0xe105, lo: 0x90, hi: 0x9f}, {value: 0x049d, lo: 0xa0, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x5, offset 0x2c {value: 0x0000, lo: 0x07}, {value: 0xe185, lo: 0x80, hi: 0x8f}, {value: 0x0545, lo: 0x90, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x98}, {value: 0x0008, lo: 0x99, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xa0}, {value: 0x0008, lo: 0xa1, hi: 0xbf}, // Block 0x6, offset 0x34 {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0401, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x88}, {value: 0x0018, lo: 0x89, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x90}, {value: 0x3308, lo: 0x91, hi: 0xbd}, {value: 0x0818, lo: 0xbe, hi: 0xbe}, {value: 0x3308, lo: 0xbf, hi: 0xbf}, // Block 0x7, offset 0x3f {value: 0x0000, lo: 0x0b}, {value: 0x0818, lo: 0x80, hi: 0x80}, {value: 0x3308, lo: 0x81, hi: 0x82}, {value: 0x0818, lo: 0x83, hi: 0x83}, {value: 0x3308, lo: 0x84, hi: 0x85}, {value: 0x0818, lo: 0x86, hi: 0x86}, {value: 0x3308, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0808, lo: 0x90, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xaf}, {value: 0x0808, lo: 0xb0, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0x8, offset 0x4b {value: 0x0000, lo: 0x03}, {value: 0x0a08, lo: 0x80, hi: 0x87}, {value: 0x0c08, lo: 0x88, hi: 0x99}, {value: 0x0a08, lo: 0x9a, hi: 0xbf}, // Block 0x9, offset 0x4f {value: 0x0000, lo: 0x0e}, {value: 0x3308, lo: 0x80, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8c}, {value: 0x0c08, lo: 0x8d, hi: 0x8d}, {value: 0x0a08, lo: 0x8e, hi: 0x98}, {value: 0x0c08, lo: 0x99, hi: 0x9b}, {value: 0x0a08, lo: 0x9c, hi: 0xaa}, {value: 0x0c08, lo: 0xab, hi: 0xac}, {value: 0x0a08, lo: 0xad, hi: 0xb0}, {value: 0x0c08, lo: 0xb1, hi: 0xb1}, {value: 0x0a08, lo: 0xb2, hi: 0xb2}, {value: 0x0c08, lo: 0xb3, hi: 0xb4}, {value: 0x0a08, lo: 0xb5, hi: 0xb7}, {value: 0x0c08, lo: 0xb8, hi: 0xb9}, {value: 0x0a08, lo: 0xba, hi: 0xbf}, // Block 0xa, offset 0x5e {value: 0x0000, lo: 0x04}, {value: 0x0808, lo: 0x80, hi: 0xa5}, {value: 0x3308, lo: 0xa6, hi: 0xb0}, {value: 0x0808, lo: 0xb1, hi: 0xb1}, {value: 0x0040, lo: 0xb2, hi: 0xbf}, // Block 0xb, offset 0x63 {value: 0x0000, lo: 0x07}, {value: 0x0808, lo: 0x80, hi: 0x89}, {value: 0x0a08, lo: 0x8a, hi: 0xaa}, {value: 0x3308, lo: 0xab, hi: 0xb3}, {value: 0x0808, lo: 0xb4, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xb9}, {value: 0x0818, lo: 0xba, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbf}, // Block 0xc, offset 0x6b {value: 0x0000, lo: 0x0b}, {value: 0x0808, lo: 0x80, hi: 0x95}, {value: 0x3308, lo: 0x96, hi: 0x99}, {value: 0x0808, lo: 0x9a, hi: 0x9a}, {value: 0x3308, lo: 0x9b, hi: 0xa3}, {value: 0x0808, lo: 0xa4, hi: 0xa4}, {value: 0x3308, lo: 0xa5, hi: 0xa7}, {value: 0x0808, lo: 0xa8, hi: 0xa8}, {value: 0x3308, lo: 0xa9, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x0818, lo: 0xb0, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0xd, offset 0x77 {value: 0x0000, lo: 0x0d}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0a08, lo: 0xa0, hi: 0xa9}, {value: 0x0c08, lo: 0xaa, hi: 0xac}, {value: 0x0808, lo: 0xad, hi: 0xad}, {value: 0x0c08, lo: 0xae, hi: 0xae}, {value: 0x0a08, lo: 0xaf, hi: 0xb0}, {value: 0x0c08, lo: 0xb1, hi: 0xb2}, {value: 0x0a08, lo: 0xb3, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xb5}, {value: 0x0a08, lo: 0xb6, hi: 0xb8}, {value: 0x0c08, lo: 0xb9, hi: 0xb9}, {value: 0x0a08, lo: 0xba, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, // Block 0xe, offset 0x85 {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x93}, {value: 0x3308, lo: 0x94, hi: 0xa1}, {value: 0x0840, lo: 0xa2, hi: 0xa2}, {value: 0x3308, lo: 0xa3, hi: 0xbf}, // Block 0xf, offset 0x8a {value: 0x0000, lo: 0x08}, {value: 0x3308, lo: 0x80, hi: 0x82}, {value: 0x3008, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0xb9}, {value: 0x3308, lo: 0xba, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbf}, // Block 0x10, offset 0x93 {value: 0x0000, lo: 0x0f}, {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x3008, lo: 0x81, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x85}, {value: 0x3008, lo: 0x86, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x3008, lo: 0x8a, hi: 0x8c}, {value: 0x3b08, lo: 0x8d, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x96}, {value: 0x3008, lo: 0x97, hi: 0x97}, {value: 0x0040, lo: 0x98, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbf}, // Block 0x11, offset 0xa3 {value: 0x0000, lo: 0x0d}, {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x3008, lo: 0x81, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, {value: 0x0008, lo: 0x8e, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x91}, {value: 0x0008, lo: 0x92, hi: 0xa8}, {value: 0x0040, lo: 0xa9, hi: 0xa9}, {value: 0x0008, lo: 0xaa, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x3308, lo: 0xbe, hi: 0xbf}, // Block 0x12, offset 0xb1 {value: 0x0000, lo: 0x0b}, {value: 0x3308, lo: 0x80, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, {value: 0x0008, lo: 0x8e, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x91}, {value: 0x0008, lo: 0x92, hi: 0xba}, {value: 0x3b08, lo: 0xbb, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbf}, // Block 0x13, offset 0xbd {value: 0x0000, lo: 0x0b}, {value: 0x0040, lo: 0x80, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x99}, {value: 0x0008, lo: 0x9a, hi: 0xb1}, {value: 0x0040, lo: 0xb2, hi: 0xb2}, {value: 0x0008, lo: 0xb3, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, // Block 0x14, offset 0xc9 {value: 0x0000, lo: 0x10}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x89}, {value: 0x3b08, lo: 0x8a, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8e}, {value: 0x3008, lo: 0x8f, hi: 0x91}, {value: 0x3308, lo: 0x92, hi: 0x94}, {value: 0x0040, lo: 0x95, hi: 0x95}, {value: 0x3308, lo: 0x96, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x97}, {value: 0x3008, lo: 0x98, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xb1}, {value: 0x3008, lo: 0xb2, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0x15, offset 0xda {value: 0x0000, lo: 0x09}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0xb0}, {value: 0x3308, lo: 0xb1, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xb2}, {value: 0x08f1, lo: 0xb3, hi: 0xb3}, {value: 0x3308, lo: 0xb4, hi: 0xb9}, {value: 0x3b08, lo: 0xba, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbe}, {value: 0x0018, lo: 0xbf, hi: 0xbf}, // Block 0x16, offset 0xe4 {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x3308, lo: 0x87, hi: 0x8e}, {value: 0x0018, lo: 0x8f, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0xbf}, // Block 0x17, offset 0xeb {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x85}, {value: 0x0008, lo: 0x86, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, {value: 0x3308, lo: 0x88, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9b}, {value: 0x0961, lo: 0x9c, hi: 0x9c}, {value: 0x0999, lo: 0x9d, hi: 0x9d}, {value: 0x0008, lo: 0x9e, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, // Block 0x18, offset 0xf8 {value: 0x0000, lo: 0x10}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x8a}, {value: 0x0008, lo: 0x8b, hi: 0x8b}, {value: 0xe03d, lo: 0x8c, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x97}, {value: 0x3308, lo: 0x98, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa9}, {value: 0x0018, lo: 0xaa, hi: 0xb4}, {value: 0x3308, lo: 0xb5, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xb6}, {value: 0x3308, lo: 0xb7, hi: 0xb7}, {value: 0x0018, lo: 0xb8, hi: 0xb8}, {value: 0x3308, lo: 0xb9, hi: 0xb9}, {value: 0x0018, lo: 0xba, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbf}, // Block 0x19, offset 0x109 {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x85}, {value: 0x3308, lo: 0x86, hi: 0x86}, {value: 0x0018, lo: 0x87, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, {value: 0x0018, lo: 0x8e, hi: 0x9a}, {value: 0x0040, lo: 0x9b, hi: 0xbf}, // Block 0x1a, offset 0x110 {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0xaa}, {value: 0x3008, lo: 0xab, hi: 0xac}, {value: 0x3308, lo: 0xad, hi: 0xb0}, {value: 0x3008, lo: 0xb1, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb7}, {value: 0x3008, lo: 0xb8, hi: 0xb8}, {value: 0x3b08, lo: 0xb9, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbc}, {value: 0x3308, lo: 0xbd, hi: 0xbe}, {value: 0x0008, lo: 0xbf, hi: 0xbf}, // Block 0x1b, offset 0x11b {value: 0x0000, lo: 0x0e}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0018, lo: 0x8a, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x95}, {value: 0x3008, lo: 0x96, hi: 0x97}, {value: 0x3308, lo: 0x98, hi: 0x99}, {value: 0x0008, lo: 0x9a, hi: 0x9d}, {value: 0x3308, lo: 0x9e, hi: 0xa0}, {value: 0x0008, lo: 0xa1, hi: 0xa1}, {value: 0x3008, lo: 0xa2, hi: 0xa4}, {value: 0x0008, lo: 0xa5, hi: 0xa6}, {value: 0x3008, lo: 0xa7, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xb0}, {value: 0x3308, lo: 0xb1, hi: 0xb4}, {value: 0x0008, lo: 0xb5, hi: 0xbf}, // Block 0x1c, offset 0x12a {value: 0x0000, lo: 0x0d}, {value: 0x0008, lo: 0x80, hi: 0x81}, {value: 0x3308, lo: 0x82, hi: 0x82}, {value: 0x3008, lo: 0x83, hi: 0x84}, {value: 0x3308, lo: 0x85, hi: 0x86}, {value: 0x3008, lo: 0x87, hi: 0x8c}, {value: 0x3308, lo: 0x8d, hi: 0x8d}, {value: 0x0008, lo: 0x8e, hi: 0x8e}, {value: 0x3008, lo: 0x8f, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x3008, lo: 0x9a, hi: 0x9c}, {value: 0x3308, lo: 0x9d, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, // Block 0x1d, offset 0x138 {value: 0x0000, lo: 0x09}, {value: 0x0040, lo: 0x80, hi: 0x86}, {value: 0x055d, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8c}, {value: 0x055d, lo: 0x8d, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xba}, {value: 0x0018, lo: 0xbb, hi: 0xbb}, {value: 0xe105, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbf}, // Block 0x1e, offset 0x142 {value: 0x0000, lo: 0x01}, {value: 0x0018, lo: 0x80, hi: 0xbf}, // Block 0x1f, offset 0x144 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0xa0}, {value: 0x2018, lo: 0xa1, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xbf}, // Block 0x20, offset 0x149 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xa7}, {value: 0x2018, lo: 0xa8, hi: 0xbf}, // Block 0x21, offset 0x14c {value: 0x0000, lo: 0x02}, {value: 0x2018, lo: 0x80, hi: 0x82}, {value: 0x0018, lo: 0x83, hi: 0xbf}, // Block 0x22, offset 0x14f {value: 0x0000, lo: 0x01}, {value: 0x0008, lo: 0x80, hi: 0xbf}, // Block 0x23, offset 0x151 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0008, lo: 0x8a, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0x98}, {value: 0x0040, lo: 0x99, hi: 0x99}, {value: 0x0008, lo: 0x9a, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x24, offset 0x15d {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0008, lo: 0x8a, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb7}, {value: 0x0008, lo: 0xb8, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0x25, offset 0x168 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0040, lo: 0x81, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0xbf}, // Block 0x26, offset 0x170 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x91}, {value: 0x0008, lo: 0x92, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0xbf}, // Block 0x27, offset 0x176 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x9a}, {value: 0x0040, lo: 0x9b, hi: 0x9c}, {value: 0x3308, lo: 0x9d, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, // Block 0x28, offset 0x17c {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x29, offset 0x181 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb7}, {value: 0xe045, lo: 0xb8, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, // Block 0x2a, offset 0x186 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0xbf}, // Block 0x2b, offset 0x189 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xac}, {value: 0x0018, lo: 0xad, hi: 0xae}, {value: 0x0008, lo: 0xaf, hi: 0xbf}, // Block 0x2c, offset 0x18d {value: 0x0000, lo: 0x05}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9c}, {value: 0x0040, lo: 0x9d, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x2d, offset 0x193 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xaa}, {value: 0x0018, lo: 0xab, hi: 0xb0}, {value: 0x0008, lo: 0xb1, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbf}, // Block 0x2e, offset 0x198 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, {value: 0x0008, lo: 0x8e, hi: 0x91}, {value: 0x3308, lo: 0x92, hi: 0x93}, {value: 0x3b08, lo: 0x94, hi: 0x94}, {value: 0x0040, lo: 0x95, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb3}, {value: 0x3b08, lo: 0xb4, hi: 0xb4}, {value: 0x0018, lo: 0xb5, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0x2f, offset 0x1a4 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x91}, {value: 0x3308, lo: 0x92, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbf}, // Block 0x30, offset 0x1ae {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0xb3}, {value: 0x3340, lo: 0xb4, hi: 0xb5}, {value: 0x3008, lo: 0xb6, hi: 0xb6}, {value: 0x3308, lo: 0xb7, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbf}, // Block 0x31, offset 0x1b4 {value: 0x0000, lo: 0x10}, {value: 0x3008, lo: 0x80, hi: 0x85}, {value: 0x3308, lo: 0x86, hi: 0x86}, {value: 0x3008, lo: 0x87, hi: 0x88}, {value: 0x3308, lo: 0x89, hi: 0x91}, {value: 0x3b08, lo: 0x92, hi: 0x92}, {value: 0x3308, lo: 0x93, hi: 0x93}, {value: 0x0018, lo: 0x94, hi: 0x96}, {value: 0x0008, lo: 0x97, hi: 0x97}, {value: 0x0018, lo: 0x98, hi: 0x9b}, {value: 0x0008, lo: 0x9c, hi: 0x9c}, {value: 0x3308, lo: 0x9d, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa9}, {value: 0x0040, lo: 0xaa, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0x32, offset 0x1c5 {value: 0x0000, lo: 0x09}, {value: 0x0018, lo: 0x80, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x86}, {value: 0x0218, lo: 0x87, hi: 0x87}, {value: 0x0018, lo: 0x88, hi: 0x8a}, {value: 0x33c0, lo: 0x8b, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0208, lo: 0xa0, hi: 0xbf}, // Block 0x33, offset 0x1cf {value: 0x0000, lo: 0x02}, {value: 0x0208, lo: 0x80, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbf}, // Block 0x34, offset 0x1d2 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x84}, {value: 0x3308, lo: 0x85, hi: 0x86}, {value: 0x0208, lo: 0x87, hi: 0xa8}, {value: 0x3308, lo: 0xa9, hi: 0xa9}, {value: 0x0208, lo: 0xaa, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x35, offset 0x1da {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, // Block 0x36, offset 0x1dd {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x3308, lo: 0xa0, hi: 0xa2}, {value: 0x3008, lo: 0xa3, hi: 0xa6}, {value: 0x3308, lo: 0xa7, hi: 0xa8}, {value: 0x3008, lo: 0xa9, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x3008, lo: 0xb0, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb2}, {value: 0x3008, lo: 0xb3, hi: 0xb8}, {value: 0x3308, lo: 0xb9, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, // Block 0x37, offset 0x1ea {value: 0x0000, lo: 0x07}, {value: 0x0018, lo: 0x80, hi: 0x80}, {value: 0x0040, lo: 0x81, hi: 0x83}, {value: 0x0018, lo: 0x84, hi: 0x85}, {value: 0x0008, lo: 0x86, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0x38, offset 0x1f2 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x39, offset 0x1f6 {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0028, lo: 0x9a, hi: 0x9a}, {value: 0x0040, lo: 0x9b, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0xbf}, // Block 0x3a, offset 0x1fd {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x96}, {value: 0x3308, lo: 0x97, hi: 0x98}, {value: 0x3008, lo: 0x99, hi: 0x9a}, {value: 0x3308, lo: 0x9b, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x3b, offset 0x205 {value: 0x0000, lo: 0x0f}, {value: 0x0008, lo: 0x80, hi: 0x94}, {value: 0x3008, lo: 0x95, hi: 0x95}, {value: 0x3308, lo: 0x96, hi: 0x96}, {value: 0x3008, lo: 0x97, hi: 0x97}, {value: 0x3308, lo: 0x98, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x3b08, lo: 0xa0, hi: 0xa0}, {value: 0x3008, lo: 0xa1, hi: 0xa1}, {value: 0x3308, lo: 0xa2, hi: 0xa2}, {value: 0x3008, lo: 0xa3, hi: 0xa4}, {value: 0x3308, lo: 0xa5, hi: 0xac}, {value: 0x3008, lo: 0xad, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbe}, {value: 0x3308, lo: 0xbf, hi: 0xbf}, // Block 0x3c, offset 0x215 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa6}, {value: 0x0008, lo: 0xa7, hi: 0xa7}, {value: 0x0018, lo: 0xa8, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xbd}, {value: 0x3318, lo: 0xbe, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0x3d, offset 0x221 {value: 0x0000, lo: 0x01}, {value: 0x0040, lo: 0x80, hi: 0xbf}, // Block 0x3e, offset 0x223 {value: 0x0000, lo: 0x09}, {value: 0x3308, lo: 0x80, hi: 0x83}, {value: 0x3008, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0xb3}, {value: 0x3308, lo: 0xb4, hi: 0xb4}, {value: 0x3008, lo: 0xb5, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbc}, {value: 0x3008, lo: 0xbd, hi: 0xbf}, // Block 0x3f, offset 0x22d {value: 0x0000, lo: 0x0b}, {value: 0x3008, lo: 0x80, hi: 0x81}, {value: 0x3308, lo: 0x82, hi: 0x82}, {value: 0x3008, lo: 0x83, hi: 0x83}, {value: 0x3808, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0xaa}, {value: 0x3308, lo: 0xab, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, // Block 0x40, offset 0x239 {value: 0x0000, lo: 0x0b}, {value: 0x3308, lo: 0x80, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xa0}, {value: 0x3008, lo: 0xa1, hi: 0xa1}, {value: 0x3308, lo: 0xa2, hi: 0xa5}, {value: 0x3008, lo: 0xa6, hi: 0xa7}, {value: 0x3308, lo: 0xa8, hi: 0xa9}, {value: 0x3808, lo: 0xaa, hi: 0xaa}, {value: 0x3b08, lo: 0xab, hi: 0xab}, {value: 0x3308, lo: 0xac, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xbf}, // Block 0x41, offset 0x245 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0xa5}, {value: 0x3308, lo: 0xa6, hi: 0xa6}, {value: 0x3008, lo: 0xa7, hi: 0xa7}, {value: 0x3308, lo: 0xa8, hi: 0xa9}, {value: 0x3008, lo: 0xaa, hi: 0xac}, {value: 0x3308, lo: 0xad, hi: 0xad}, {value: 0x3008, lo: 0xae, hi: 0xae}, {value: 0x3308, lo: 0xaf, hi: 0xb1}, {value: 0x3808, lo: 0xb2, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbb}, {value: 0x0018, lo: 0xbc, hi: 0xbf}, // Block 0x42, offset 0x251 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xa3}, {value: 0x3008, lo: 0xa4, hi: 0xab}, {value: 0x3308, lo: 0xac, hi: 0xb3}, {value: 0x3008, lo: 0xb4, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xba}, {value: 0x0018, lo: 0xbb, hi: 0xbf}, // Block 0x43, offset 0x259 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0x8c}, {value: 0x0008, lo: 0x8d, hi: 0xbd}, {value: 0x0018, lo: 0xbe, hi: 0xbf}, // Block 0x44, offset 0x25e {value: 0x0000, lo: 0x09}, {value: 0x0e29, lo: 0x80, hi: 0x80}, {value: 0x0e41, lo: 0x81, hi: 0x81}, {value: 0x0e59, lo: 0x82, hi: 0x82}, {value: 0x0e71, lo: 0x83, hi: 0x83}, {value: 0x0e89, lo: 0x84, hi: 0x85}, {value: 0x0ea1, lo: 0x86, hi: 0x86}, {value: 0x0eb9, lo: 0x87, hi: 0x87}, {value: 0x057d, lo: 0x88, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0xbf}, // Block 0x45, offset 0x268 {value: 0x0000, lo: 0x10}, {value: 0x0018, lo: 0x80, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x3308, lo: 0x90, hi: 0x92}, {value: 0x0018, lo: 0x93, hi: 0x93}, {value: 0x3308, lo: 0x94, hi: 0xa0}, {value: 0x3008, lo: 0xa1, hi: 0xa1}, {value: 0x3308, lo: 0xa2, hi: 0xa8}, {value: 0x0008, lo: 0xa9, hi: 0xac}, {value: 0x3308, lo: 0xad, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xb1}, {value: 0x3008, lo: 0xb2, hi: 0xb3}, {value: 0x3308, lo: 0xb4, hi: 0xb4}, {value: 0x0008, lo: 0xb5, hi: 0xb6}, {value: 0x3008, lo: 0xb7, hi: 0xb7}, {value: 0x3308, lo: 0xb8, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0x46, offset 0x279 {value: 0x0000, lo: 0x03}, {value: 0x3308, lo: 0x80, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xba}, {value: 0x3308, lo: 0xbb, hi: 0xbf}, // Block 0x47, offset 0x27d {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x87}, {value: 0xe045, lo: 0x88, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x97}, {value: 0xe045, lo: 0x98, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa7}, {value: 0xe045, lo: 0xa8, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb7}, {value: 0xe045, lo: 0xb8, hi: 0xbf}, // Block 0x48, offset 0x288 {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0x8f}, {value: 0x3318, lo: 0x90, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xbf}, // Block 0x49, offset 0x28c {value: 0x0000, lo: 0x08}, {value: 0x0018, lo: 0x80, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x84}, {value: 0x0018, lo: 0x85, hi: 0x88}, {value: 0x24c1, lo: 0x89, hi: 0x89}, {value: 0x0018, lo: 0x8a, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbf}, // Block 0x4a, offset 0x295 {value: 0x0000, lo: 0x07}, {value: 0x0018, lo: 0x80, hi: 0xab}, {value: 0x24f1, lo: 0xac, hi: 0xac}, {value: 0x2529, lo: 0xad, hi: 0xad}, {value: 0x0018, lo: 0xae, hi: 0xae}, {value: 0x2579, lo: 0xaf, hi: 0xaf}, {value: 0x25b1, lo: 0xb0, hi: 0xb0}, {value: 0x0018, lo: 0xb1, hi: 0xbf}, // Block 0x4b, offset 0x29d {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x9f}, {value: 0x0080, lo: 0xa0, hi: 0xa0}, {value: 0x0018, lo: 0xa1, hi: 0xad}, {value: 0x0080, lo: 0xae, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, // Block 0x4c, offset 0x2a3 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0xa8}, {value: 0x09c5, lo: 0xa9, hi: 0xa9}, {value: 0x09e5, lo: 0xaa, hi: 0xaa}, {value: 0x0018, lo: 0xab, hi: 0xbf}, // Block 0x4d, offset 0x2a8 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xbf}, // Block 0x4e, offset 0x2ab {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0x8b}, {value: 0x28c1, lo: 0x8c, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0xbf}, // Block 0x4f, offset 0x2af {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0xb3}, {value: 0x0e66, lo: 0xb4, hi: 0xb4}, {value: 0x292a, lo: 0xb5, hi: 0xb5}, {value: 0x0e86, lo: 0xb6, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xbf}, // Block 0x50, offset 0x2b5 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0x9b}, {value: 0x2941, lo: 0x9c, hi: 0x9c}, {value: 0x0018, lo: 0x9d, hi: 0xbf}, // Block 0x51, offset 0x2b9 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xbf}, // Block 0x52, offset 0x2bd {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x97}, {value: 0x0018, lo: 0x98, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbc}, {value: 0x0018, lo: 0xbd, hi: 0xbf}, // Block 0x53, offset 0x2c3 {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0018, lo: 0x8a, hi: 0x92}, {value: 0x0040, lo: 0x93, hi: 0xab}, {value: 0x0018, lo: 0xac, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, // Block 0x54, offset 0x2ca {value: 0x0000, lo: 0x05}, {value: 0xe185, lo: 0x80, hi: 0x8f}, {value: 0x03f5, lo: 0x90, hi: 0x9f}, {value: 0x0ea5, lo: 0xa0, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x55, offset 0x2d0 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xa5}, {value: 0x0040, lo: 0xa6, hi: 0xa6}, {value: 0x0008, lo: 0xa7, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xac}, {value: 0x0008, lo: 0xad, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x56, offset 0x2d8 {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xae}, {value: 0xe075, lo: 0xaf, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0x57, offset 0x2df {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xa7}, {value: 0x0008, lo: 0xa8, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xb7}, {value: 0x0008, lo: 0xb8, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0x58, offset 0x2ea {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x8e}, {value: 0x0040, lo: 0x8f, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x3308, lo: 0xa0, hi: 0xbf}, // Block 0x59, offset 0x2f4 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xae}, {value: 0x0008, lo: 0xaf, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, // Block 0x5a, offset 0x2f8 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0xbf}, // Block 0x5b, offset 0x2fb {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9e}, {value: 0x0edd, lo: 0x9f, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xbf}, // Block 0x5c, offset 0x301 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xb2}, {value: 0x0efd, lo: 0xb3, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbf}, // Block 0x5d, offset 0x305 {value: 0x0020, lo: 0x01}, {value: 0x0f1d, lo: 0x80, hi: 0xbf}, // Block 0x5e, offset 0x307 {value: 0x0020, lo: 0x02}, {value: 0x171d, lo: 0x80, hi: 0x8f}, {value: 0x18fd, lo: 0x90, hi: 0xbf}, // Block 0x5f, offset 0x30a {value: 0x0020, lo: 0x01}, {value: 0x1efd, lo: 0x80, hi: 0xbf}, // Block 0x60, offset 0x30c {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0xbf}, // Block 0x61, offset 0x30f {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x98}, {value: 0x3308, lo: 0x99, hi: 0x9a}, {value: 0x29e2, lo: 0x9b, hi: 0x9b}, {value: 0x2a0a, lo: 0x9c, hi: 0x9c}, {value: 0x0008, lo: 0x9d, hi: 0x9e}, {value: 0x2a31, lo: 0x9f, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa0}, {value: 0x0008, lo: 0xa1, hi: 0xbf}, // Block 0x62, offset 0x319 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xbe}, {value: 0x2a69, lo: 0xbf, hi: 0xbf}, // Block 0x63, offset 0x31c {value: 0x0000, lo: 0x0e}, {value: 0x0040, lo: 0x80, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xb0}, {value: 0x2a1d, lo: 0xb1, hi: 0xb1}, {value: 0x2a3d, lo: 0xb2, hi: 0xb2}, {value: 0x2a5d, lo: 0xb3, hi: 0xb3}, {value: 0x2a7d, lo: 0xb4, hi: 0xb4}, {value: 0x2a5d, lo: 0xb5, hi: 0xb5}, {value: 0x2a9d, lo: 0xb6, hi: 0xb6}, {value: 0x2abd, lo: 0xb7, hi: 0xb7}, {value: 0x2add, lo: 0xb8, hi: 0xb9}, {value: 0x2afd, lo: 0xba, hi: 0xbb}, {value: 0x2b1d, lo: 0xbc, hi: 0xbd}, {value: 0x2afd, lo: 0xbe, hi: 0xbf}, // Block 0x64, offset 0x32b {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x65, offset 0x32f {value: 0x0030, lo: 0x04}, {value: 0x2aa2, lo: 0x80, hi: 0x9d}, {value: 0x305a, lo: 0x9e, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x30a2, lo: 0xa0, hi: 0xbf}, // Block 0x66, offset 0x334 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xbf}, // Block 0x67, offset 0x337 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbf}, // Block 0x68, offset 0x33b {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xbd}, {value: 0x0018, lo: 0xbe, hi: 0xbf}, // Block 0x69, offset 0x340 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xbf}, // Block 0x6a, offset 0x345 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0xa5}, {value: 0x0018, lo: 0xa6, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb1}, {value: 0x0018, lo: 0xb2, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbf}, // Block 0x6b, offset 0x34b {value: 0x0000, lo: 0x05}, {value: 0x0040, lo: 0x80, hi: 0xb6}, {value: 0x0008, lo: 0xb7, hi: 0xb7}, {value: 0x2009, lo: 0xb8, hi: 0xb8}, {value: 0x6e89, lo: 0xb9, hi: 0xb9}, {value: 0x0008, lo: 0xba, hi: 0xbf}, // Block 0x6c, offset 0x351 {value: 0x0000, lo: 0x0e}, {value: 0x0008, lo: 0x80, hi: 0x81}, {value: 0x3308, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0x85}, {value: 0x3b08, lo: 0x86, hi: 0x86}, {value: 0x0008, lo: 0x87, hi: 0x8a}, {value: 0x3308, lo: 0x8b, hi: 0x8b}, {value: 0x0008, lo: 0x8c, hi: 0xa2}, {value: 0x3008, lo: 0xa3, hi: 0xa4}, {value: 0x3308, lo: 0xa5, hi: 0xa6}, {value: 0x3008, lo: 0xa7, hi: 0xa7}, {value: 0x0018, lo: 0xa8, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0x6d, offset 0x360 {value: 0x0000, lo: 0x05}, {value: 0x0208, lo: 0x80, hi: 0xb1}, {value: 0x0108, lo: 0xb2, hi: 0xb2}, {value: 0x0008, lo: 0xb3, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbf}, // Block 0x6e, offset 0x366 {value: 0x0000, lo: 0x03}, {value: 0x3008, lo: 0x80, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0xb3}, {value: 0x3008, lo: 0xb4, hi: 0xbf}, // Block 0x6f, offset 0x36a {value: 0x0000, lo: 0x0e}, {value: 0x3008, lo: 0x80, hi: 0x83}, {value: 0x3b08, lo: 0x84, hi: 0x84}, {value: 0x3308, lo: 0x85, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x8d}, {value: 0x0018, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x3308, lo: 0xa0, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xb7}, {value: 0x0018, lo: 0xb8, hi: 0xba}, {value: 0x0008, lo: 0xbb, hi: 0xbb}, {value: 0x0018, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, // Block 0x70, offset 0x379 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xa5}, {value: 0x3308, lo: 0xa6, hi: 0xad}, {value: 0x0018, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x71, offset 0x37e {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x3308, lo: 0x87, hi: 0x91}, {value: 0x3008, lo: 0x92, hi: 0x92}, {value: 0x3808, lo: 0x93, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, // Block 0x72, offset 0x386 {value: 0x0000, lo: 0x09}, {value: 0x3308, lo: 0x80, hi: 0x82}, {value: 0x3008, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xb3}, {value: 0x3008, lo: 0xb4, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xb9}, {value: 0x3008, lo: 0xba, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbc}, {value: 0x3008, lo: 0xbd, hi: 0xbf}, // Block 0x73, offset 0x390 {value: 0x0000, lo: 0x0a}, {value: 0x3808, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8e}, {value: 0x0008, lo: 0x8f, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa4}, {value: 0x3308, lo: 0xa5, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0x74, offset 0x39b {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xa8}, {value: 0x3308, lo: 0xa9, hi: 0xae}, {value: 0x3008, lo: 0xaf, hi: 0xb0}, {value: 0x3308, lo: 0xb1, hi: 0xb2}, {value: 0x3008, lo: 0xb3, hi: 0xb4}, {value: 0x3308, lo: 0xb5, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0x75, offset 0x3a3 {value: 0x0000, lo: 0x10}, {value: 0x0008, lo: 0x80, hi: 0x82}, {value: 0x3308, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x8b}, {value: 0x3308, lo: 0x8c, hi: 0x8c}, {value: 0x3008, lo: 0x8d, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9b}, {value: 0x0018, lo: 0x9c, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xb9}, {value: 0x0008, lo: 0xba, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbc}, {value: 0x3008, lo: 0xbd, hi: 0xbd}, {value: 0x0008, lo: 0xbe, hi: 0xbf}, // Block 0x76, offset 0x3b4 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb0}, {value: 0x0008, lo: 0xb1, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb4}, {value: 0x0008, lo: 0xb5, hi: 0xb6}, {value: 0x3308, lo: 0xb7, hi: 0xb8}, {value: 0x0008, lo: 0xb9, hi: 0xbd}, {value: 0x3308, lo: 0xbe, hi: 0xbf}, // Block 0x77, offset 0x3bd {value: 0x0000, lo: 0x0f}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x3308, lo: 0x81, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x9a}, {value: 0x0008, lo: 0x9b, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xaa}, {value: 0x3008, lo: 0xab, hi: 0xab}, {value: 0x3308, lo: 0xac, hi: 0xad}, {value: 0x3008, lo: 0xae, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xb4}, {value: 0x3008, lo: 0xb5, hi: 0xb5}, {value: 0x3b08, lo: 0xb6, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0x78, offset 0x3cd {value: 0x0000, lo: 0x0c}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x88}, {value: 0x0008, lo: 0x89, hi: 0x8e}, {value: 0x0040, lo: 0x8f, hi: 0x90}, {value: 0x0008, lo: 0x91, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xa7}, {value: 0x0008, lo: 0xa8, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x79, offset 0x3da {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9b}, {value: 0x4465, lo: 0x9c, hi: 0x9c}, {value: 0x447d, lo: 0x9d, hi: 0x9d}, {value: 0x2971, lo: 0x9e, hi: 0x9e}, {value: 0xe06d, lo: 0x9f, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa5}, {value: 0x0040, lo: 0xa6, hi: 0xaf}, {value: 0x4495, lo: 0xb0, hi: 0xbf}, // Block 0x7a, offset 0x3e4 {value: 0x0000, lo: 0x04}, {value: 0x44b5, lo: 0x80, hi: 0x8f}, {value: 0x44d5, lo: 0x90, hi: 0x9f}, {value: 0x44f5, lo: 0xa0, hi: 0xaf}, {value: 0x44d5, lo: 0xb0, hi: 0xbf}, // Block 0x7b, offset 0x3e9 {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0xa2}, {value: 0x3008, lo: 0xa3, hi: 0xa4}, {value: 0x3308, lo: 0xa5, hi: 0xa5}, {value: 0x3008, lo: 0xa6, hi: 0xa7}, {value: 0x3308, lo: 0xa8, hi: 0xa8}, {value: 0x3008, lo: 0xa9, hi: 0xaa}, {value: 0x0018, lo: 0xab, hi: 0xab}, {value: 0x3008, lo: 0xac, hi: 0xac}, {value: 0x3b08, lo: 0xad, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0x7c, offset 0x3f6 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, // Block 0x7d, offset 0x3fa {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x8a}, {value: 0x0018, lo: 0x8b, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, // Block 0x7e, offset 0x3ff {value: 0x0020, lo: 0x01}, {value: 0x4515, lo: 0x80, hi: 0xbf}, // Block 0x7f, offset 0x401 {value: 0x0020, lo: 0x03}, {value: 0x4d15, lo: 0x80, hi: 0x94}, {value: 0x4ad5, lo: 0x95, hi: 0x95}, {value: 0x4fb5, lo: 0x96, hi: 0xbf}, // Block 0x80, offset 0x405 {value: 0x0020, lo: 0x01}, {value: 0x54f5, lo: 0x80, hi: 0xbf}, // Block 0x81, offset 0x407 {value: 0x0020, lo: 0x03}, {value: 0x5cf5, lo: 0x80, hi: 0x84}, {value: 0x5655, lo: 0x85, hi: 0x85}, {value: 0x5d95, lo: 0x86, hi: 0xbf}, // Block 0x82, offset 0x40b {value: 0x0020, lo: 0x08}, {value: 0x6b55, lo: 0x80, hi: 0x8f}, {value: 0x6d15, lo: 0x90, hi: 0x90}, {value: 0x6d55, lo: 0x91, hi: 0xab}, {value: 0x6ea1, lo: 0xac, hi: 0xac}, {value: 0x70b5, lo: 0xad, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x70d5, lo: 0xb0, hi: 0xbf}, // Block 0x83, offset 0x414 {value: 0x0020, lo: 0x05}, {value: 0x72d5, lo: 0x80, hi: 0xad}, {value: 0x6535, lo: 0xae, hi: 0xae}, {value: 0x7895, lo: 0xaf, hi: 0xb5}, {value: 0x6f55, lo: 0xb6, hi: 0xb6}, {value: 0x7975, lo: 0xb7, hi: 0xbf}, // Block 0x84, offset 0x41a {value: 0x0028, lo: 0x03}, {value: 0x7c21, lo: 0x80, hi: 0x82}, {value: 0x7be1, lo: 0x83, hi: 0x83}, {value: 0x7c99, lo: 0x84, hi: 0xbf}, // Block 0x85, offset 0x41e {value: 0x0038, lo: 0x0f}, {value: 0x9db1, lo: 0x80, hi: 0x83}, {value: 0x9e59, lo: 0x84, hi: 0x85}, {value: 0x9e91, lo: 0x86, hi: 0x87}, {value: 0x9ec9, lo: 0x88, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x91}, {value: 0xa089, lo: 0x92, hi: 0x97}, {value: 0xa1a1, lo: 0x98, hi: 0x9c}, {value: 0xa281, lo: 0x9d, hi: 0xb3}, {value: 0x9d41, lo: 0xb4, hi: 0xb4}, {value: 0x9db1, lo: 0xb5, hi: 0xb5}, {value: 0xa789, lo: 0xb6, hi: 0xbb}, {value: 0xa869, lo: 0xbc, hi: 0xbc}, {value: 0xa7f9, lo: 0xbd, hi: 0xbd}, {value: 0xa8d9, lo: 0xbe, hi: 0xbf}, // Block 0x86, offset 0x42e {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8c}, {value: 0x0008, lo: 0x8d, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xa7}, {value: 0x0008, lo: 0xa8, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbb}, {value: 0x0008, lo: 0xbc, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbe}, {value: 0x0008, lo: 0xbf, hi: 0xbf}, // Block 0x87, offset 0x438 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0xbf}, // Block 0x88, offset 0x43d {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbf}, // Block 0x89, offset 0x440 {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x86}, {value: 0x0018, lo: 0x87, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xbf}, // Block 0x8a, offset 0x446 {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x8e}, {value: 0x0040, lo: 0x8f, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa0}, {value: 0x0040, lo: 0xa1, hi: 0xbf}, // Block 0x8b, offset 0x44d {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbc}, {value: 0x3308, lo: 0xbd, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, // Block 0x8c, offset 0x452 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0x9c}, {value: 0x0040, lo: 0x9d, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x8d, offset 0x456 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x9f}, {value: 0x3308, lo: 0xa0, hi: 0xa0}, {value: 0x0018, lo: 0xa1, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, // Block 0x8e, offset 0x45c {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xac}, {value: 0x0008, lo: 0xad, hi: 0xbf}, // Block 0x8f, offset 0x461 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0x89}, {value: 0x0018, lo: 0x8a, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbf}, // Block 0x90, offset 0x46a {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x91, offset 0x46f {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0xbf}, // Block 0x92, offset 0x475 {value: 0x0000, lo: 0x06}, {value: 0xe145, lo: 0x80, hi: 0x87}, {value: 0xe1c5, lo: 0x88, hi: 0x8f}, {value: 0xe145, lo: 0x90, hi: 0x97}, {value: 0x8ad5, lo: 0x98, hi: 0x9f}, {value: 0x8aed, lo: 0xa0, hi: 0xa7}, {value: 0x0008, lo: 0xa8, hi: 0xbf}, // Block 0x93, offset 0x47c {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa9}, {value: 0x0040, lo: 0xaa, hi: 0xaf}, {value: 0x8aed, lo: 0xb0, hi: 0xb7}, {value: 0x8ad5, lo: 0xb8, hi: 0xbf}, // Block 0x94, offset 0x483 {value: 0x0000, lo: 0x06}, {value: 0xe145, lo: 0x80, hi: 0x87}, {value: 0xe1c5, lo: 0x88, hi: 0x8f}, {value: 0xe145, lo: 0x90, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, // Block 0x95, offset 0x48a {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x96, offset 0x48e {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xae}, {value: 0x0018, lo: 0xaf, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, // Block 0x97, offset 0x493 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0x98, offset 0x496 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xbf}, // Block 0x99, offset 0x49b {value: 0x0000, lo: 0x0b}, {value: 0x0808, lo: 0x80, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x87}, {value: 0x0808, lo: 0x88, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0808, lo: 0x8a, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb6}, {value: 0x0808, lo: 0xb7, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbb}, {value: 0x0808, lo: 0xbc, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbe}, {value: 0x0808, lo: 0xbf, hi: 0xbf}, // Block 0x9a, offset 0x4a7 {value: 0x0000, lo: 0x05}, {value: 0x0808, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x96}, {value: 0x0818, lo: 0x97, hi: 0x9f}, {value: 0x0808, lo: 0xa0, hi: 0xb6}, {value: 0x0818, lo: 0xb7, hi: 0xbf}, // Block 0x9b, offset 0x4ad {value: 0x0000, lo: 0x04}, {value: 0x0808, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0xa6}, {value: 0x0818, lo: 0xa7, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, // Block 0x9c, offset 0x4b2 {value: 0x0000, lo: 0x06}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0808, lo: 0xa0, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xb3}, {value: 0x0808, lo: 0xb4, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xba}, {value: 0x0818, lo: 0xbb, hi: 0xbf}, // Block 0x9d, offset 0x4b9 {value: 0x0000, lo: 0x07}, {value: 0x0808, lo: 0x80, hi: 0x95}, {value: 0x0818, lo: 0x96, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0x9f}, {value: 0x0808, lo: 0xa0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbe}, {value: 0x0818, lo: 0xbf, hi: 0xbf}, // Block 0x9e, offset 0x4c1 {value: 0x0000, lo: 0x04}, {value: 0x0808, lo: 0x80, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbb}, {value: 0x0818, lo: 0xbc, hi: 0xbd}, {value: 0x0808, lo: 0xbe, hi: 0xbf}, // Block 0x9f, offset 0x4c6 {value: 0x0000, lo: 0x03}, {value: 0x0818, lo: 0x80, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x91}, {value: 0x0818, lo: 0x92, hi: 0xbf}, // Block 0xa0, offset 0x4ca {value: 0x0000, lo: 0x0f}, {value: 0x0808, lo: 0x80, hi: 0x80}, {value: 0x3308, lo: 0x81, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x84}, {value: 0x3308, lo: 0x85, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x8b}, {value: 0x3308, lo: 0x8c, hi: 0x8f}, {value: 0x0808, lo: 0x90, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x94}, {value: 0x0808, lo: 0x95, hi: 0x97}, {value: 0x0040, lo: 0x98, hi: 0x98}, {value: 0x0808, lo: 0x99, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xb7}, {value: 0x3308, lo: 0xb8, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0xa1, offset 0x4da {value: 0x0000, lo: 0x06}, {value: 0x0818, lo: 0x80, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0818, lo: 0x90, hi: 0x98}, {value: 0x0040, lo: 0x99, hi: 0x9f}, {value: 0x0808, lo: 0xa0, hi: 0xbc}, {value: 0x0818, lo: 0xbd, hi: 0xbf}, // Block 0xa2, offset 0x4e1 {value: 0x0000, lo: 0x03}, {value: 0x0808, lo: 0x80, hi: 0x9c}, {value: 0x0818, lo: 0x9d, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, // Block 0xa3, offset 0x4e5 {value: 0x0000, lo: 0x03}, {value: 0x0808, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb8}, {value: 0x0018, lo: 0xb9, hi: 0xbf}, // Block 0xa4, offset 0x4e9 {value: 0x0000, lo: 0x06}, {value: 0x0808, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x97}, {value: 0x0818, lo: 0x98, hi: 0x9f}, {value: 0x0808, lo: 0xa0, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xb7}, {value: 0x0818, lo: 0xb8, hi: 0xbf}, // Block 0xa5, offset 0x4f0 {value: 0x0000, lo: 0x01}, {value: 0x0808, lo: 0x80, hi: 0xbf}, // Block 0xa6, offset 0x4f2 {value: 0x0000, lo: 0x02}, {value: 0x0808, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0xbf}, // Block 0xa7, offset 0x4f5 {value: 0x0000, lo: 0x02}, {value: 0x03dd, lo: 0x80, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xbf}, // Block 0xa8, offset 0x4f8 {value: 0x0000, lo: 0x03}, {value: 0x0808, lo: 0x80, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xb9}, {value: 0x0818, lo: 0xba, hi: 0xbf}, // Block 0xa9, offset 0x4fc {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0818, lo: 0xa0, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0xaa, offset 0x500 {value: 0x0000, lo: 0x05}, {value: 0x3008, lo: 0x80, hi: 0x80}, {value: 0x3308, lo: 0x81, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xb7}, {value: 0x3308, lo: 0xb8, hi: 0xbf}, // Block 0xab, offset 0x506 {value: 0x0000, lo: 0x08}, {value: 0x3308, lo: 0x80, hi: 0x85}, {value: 0x3b08, lo: 0x86, hi: 0x86}, {value: 0x0018, lo: 0x87, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x91}, {value: 0x0018, lo: 0x92, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0xac, offset 0x50f {value: 0x0000, lo: 0x0b}, {value: 0x3308, lo: 0x80, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xaf}, {value: 0x3008, lo: 0xb0, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xb6}, {value: 0x3008, lo: 0xb7, hi: 0xb8}, {value: 0x3b08, lo: 0xb9, hi: 0xb9}, {value: 0x3308, lo: 0xba, hi: 0xba}, {value: 0x0018, lo: 0xbb, hi: 0xbc}, {value: 0x0340, lo: 0xbd, hi: 0xbd}, {value: 0x0018, lo: 0xbe, hi: 0xbf}, // Block 0xad, offset 0x51b {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x81}, {value: 0x0040, lo: 0x82, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xa8}, {value: 0x0040, lo: 0xa9, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0xae, offset 0x522 {value: 0x0000, lo: 0x08}, {value: 0x3308, lo: 0x80, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xa6}, {value: 0x3308, lo: 0xa7, hi: 0xab}, {value: 0x3008, lo: 0xac, hi: 0xac}, {value: 0x3308, lo: 0xad, hi: 0xb2}, {value: 0x3b08, lo: 0xb3, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xb5}, {value: 0x0008, lo: 0xb6, hi: 0xbf}, // Block 0xaf, offset 0x52b {value: 0x0000, lo: 0x07}, {value: 0x0018, lo: 0x80, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xb5}, {value: 0x0008, lo: 0xb6, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0xb0, offset 0x533 {value: 0x0000, lo: 0x06}, {value: 0x3308, lo: 0x80, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xb2}, {value: 0x3008, lo: 0xb3, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xbe}, {value: 0x3008, lo: 0xbf, hi: 0xbf}, // Block 0xb1, offset 0x53a {value: 0x0000, lo: 0x0d}, {value: 0x3808, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0x84}, {value: 0x0018, lo: 0x85, hi: 0x89}, {value: 0x3308, lo: 0x8a, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9b}, {value: 0x0008, lo: 0x9c, hi: 0x9c}, {value: 0x0018, lo: 0x9d, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xa0}, {value: 0x0018, lo: 0xa1, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0xb2, offset 0x548 {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x91}, {value: 0x0040, lo: 0x92, hi: 0x92}, {value: 0x0008, lo: 0x93, hi: 0xab}, {value: 0x3008, lo: 0xac, hi: 0xae}, {value: 0x3308, lo: 0xaf, hi: 0xb1}, {value: 0x3008, lo: 0xb2, hi: 0xb3}, {value: 0x3308, lo: 0xb4, hi: 0xb4}, {value: 0x3808, lo: 0xb5, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xb7}, {value: 0x0018, lo: 0xb8, hi: 0xbd}, {value: 0x3308, lo: 0xbe, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0xb3, offset 0x555 {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0008, lo: 0x8a, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8e}, {value: 0x0008, lo: 0x8f, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9e}, {value: 0x0008, lo: 0x9f, hi: 0xa8}, {value: 0x0018, lo: 0xa9, hi: 0xa9}, {value: 0x0040, lo: 0xaa, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0xb4, offset 0x562 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0x9e}, {value: 0x3308, lo: 0x9f, hi: 0x9f}, {value: 0x3008, lo: 0xa0, hi: 0xa2}, {value: 0x3308, lo: 0xa3, hi: 0xa9}, {value: 0x3b08, lo: 0xaa, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0xb5, offset 0x56b {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xb4}, {value: 0x3008, lo: 0xb5, hi: 0xb7}, {value: 0x3308, lo: 0xb8, hi: 0xbf}, // Block 0xb6, offset 0x56f {value: 0x0000, lo: 0x0d}, {value: 0x3008, lo: 0x80, hi: 0x81}, {value: 0x3b08, lo: 0x82, hi: 0x82}, {value: 0x3308, lo: 0x83, hi: 0x84}, {value: 0x3008, lo: 0x85, hi: 0x85}, {value: 0x3308, lo: 0x86, hi: 0x86}, {value: 0x0008, lo: 0x87, hi: 0x8a}, {value: 0x0018, lo: 0x8b, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0x9c}, {value: 0x0018, lo: 0x9d, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0xbf}, // Block 0xb7, offset 0x57d {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x3008, lo: 0xb0, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xb8}, {value: 0x3008, lo: 0xb9, hi: 0xb9}, {value: 0x3308, lo: 0xba, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbe}, {value: 0x3308, lo: 0xbf, hi: 0xbf}, // Block 0xb8, offset 0x585 {value: 0x0000, lo: 0x0a}, {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x3008, lo: 0x81, hi: 0x81}, {value: 0x3b08, lo: 0x82, hi: 0x82}, {value: 0x3308, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x85}, {value: 0x0018, lo: 0x86, hi: 0x86}, {value: 0x0008, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0xbf}, // Block 0xb9, offset 0x590 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0xae}, {value: 0x3008, lo: 0xaf, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb7}, {value: 0x3008, lo: 0xb8, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0xba, offset 0x599 {value: 0x0000, lo: 0x05}, {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0x9b}, {value: 0x3308, lo: 0x9c, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0xbf}, // Block 0xbb, offset 0x59f {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x3008, lo: 0xb0, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbc}, {value: 0x3308, lo: 0xbd, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0xbc, offset 0x5a7 {value: 0x0000, lo: 0x08}, {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xbf}, // Block 0xbd, offset 0x5b0 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0xaa}, {value: 0x3308, lo: 0xab, hi: 0xab}, {value: 0x3008, lo: 0xac, hi: 0xac}, {value: 0x3308, lo: 0xad, hi: 0xad}, {value: 0x3008, lo: 0xae, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb5}, {value: 0x3808, lo: 0xb6, hi: 0xb6}, {value: 0x3308, lo: 0xb7, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbf}, // Block 0xbe, offset 0x5ba {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0xbf}, // Block 0xbf, offset 0x5bd {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9c}, {value: 0x3308, lo: 0x9d, hi: 0x9f}, {value: 0x3008, lo: 0xa0, hi: 0xa1}, {value: 0x3308, lo: 0xa2, hi: 0xa5}, {value: 0x3008, lo: 0xa6, hi: 0xa6}, {value: 0x3308, lo: 0xa7, hi: 0xaa}, {value: 0x3b08, lo: 0xab, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0018, lo: 0xba, hi: 0xbf}, // Block 0xc0, offset 0x5c9 {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x049d, lo: 0xa0, hi: 0xbf}, // Block 0xc1, offset 0x5cc {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xa9}, {value: 0x0018, lo: 0xaa, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xbe}, {value: 0x0008, lo: 0xbf, hi: 0xbf}, // Block 0xc2, offset 0x5d1 {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x3308, lo: 0x81, hi: 0x86}, {value: 0x3008, lo: 0x87, hi: 0x88}, {value: 0x3308, lo: 0x89, hi: 0x8a}, {value: 0x0008, lo: 0x8b, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xb3}, {value: 0x3b08, lo: 0xb4, hi: 0xb4}, {value: 0x3308, lo: 0xb5, hi: 0xb8}, {value: 0x3008, lo: 0xb9, hi: 0xb9}, {value: 0x0008, lo: 0xba, hi: 0xba}, {value: 0x3308, lo: 0xbb, hi: 0xbe}, {value: 0x0018, lo: 0xbf, hi: 0xbf}, // Block 0xc3, offset 0x5de {value: 0x0000, lo: 0x08}, {value: 0x0018, lo: 0x80, hi: 0x86}, {value: 0x3b08, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x90}, {value: 0x3308, lo: 0x91, hi: 0x96}, {value: 0x3008, lo: 0x97, hi: 0x98}, {value: 0x3308, lo: 0x99, hi: 0x9b}, {value: 0x0008, lo: 0x9c, hi: 0xbf}, // Block 0xc4, offset 0x5e7 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x85}, {value: 0x0008, lo: 0x86, hi: 0x89}, {value: 0x3308, lo: 0x8a, hi: 0x96}, {value: 0x3008, lo: 0x97, hi: 0x97}, {value: 0x3308, lo: 0x98, hi: 0x98}, {value: 0x3b08, lo: 0x99, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0x9c}, {value: 0x0040, lo: 0x9d, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0xa2}, {value: 0x0040, lo: 0xa3, hi: 0xbf}, // Block 0xc5, offset 0x5f3 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbf}, // Block 0xc6, offset 0x5f6 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0008, lo: 0x8a, hi: 0xae}, {value: 0x3008, lo: 0xaf, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xb7}, {value: 0x3308, lo: 0xb8, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0xc7, offset 0x600 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xbf}, // Block 0xc8, offset 0x609 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x91}, {value: 0x3308, lo: 0x92, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xa8}, {value: 0x3008, lo: 0xa9, hi: 0xa9}, {value: 0x3308, lo: 0xaa, hi: 0xb0}, {value: 0x3008, lo: 0xb1, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb3}, {value: 0x3008, lo: 0xb4, hi: 0xb4}, {value: 0x3308, lo: 0xb5, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0xc9, offset 0x615 {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0x8a}, {value: 0x0008, lo: 0x8b, hi: 0xb0}, {value: 0x3308, lo: 0xb1, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xb9}, {value: 0x3308, lo: 0xba, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbe}, {value: 0x3308, lo: 0xbf, hi: 0xbf}, // Block 0xca, offset 0x622 {value: 0x0000, lo: 0x07}, {value: 0x3308, lo: 0x80, hi: 0x83}, {value: 0x3b08, lo: 0x84, hi: 0x85}, {value: 0x0008, lo: 0x86, hi: 0x86}, {value: 0x3308, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0xbf}, // Block 0xcb, offset 0x62a {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0xbf}, // Block 0xcc, offset 0x62d {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0xcd, offset 0x632 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0xbf}, // Block 0xce, offset 0x635 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xbf}, // Block 0xcf, offset 0x638 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0xbf}, // Block 0xd0, offset 0x63b {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa9}, {value: 0x0040, lo: 0xaa, hi: 0xad}, {value: 0x0018, lo: 0xae, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, // Block 0xd1, offset 0x642 {value: 0x0000, lo: 0x06}, {value: 0x0040, lo: 0x80, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb4}, {value: 0x0018, lo: 0xb5, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, // Block 0xd2, offset 0x649 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xbf}, // Block 0xd3, offset 0x64d {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x83}, {value: 0x0018, lo: 0x84, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0xa1}, {value: 0x0040, lo: 0xa2, hi: 0xa2}, {value: 0x0008, lo: 0xa3, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbf}, // Block 0xd4, offset 0x658 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0xbf}, // Block 0xd5, offset 0x65b {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x90}, {value: 0x3008, lo: 0x91, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0xd6, offset 0x661 {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x8e}, {value: 0x3308, lo: 0x8f, hi: 0x92}, {value: 0x0008, lo: 0x93, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, // Block 0xd7, offset 0x666 {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa1}, {value: 0x0040, lo: 0xa2, hi: 0xbf}, // Block 0xd8, offset 0x66a {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xbf}, // Block 0xd9, offset 0x66d {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xbf}, // Block 0xda, offset 0x670 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0xbf}, // Block 0xdb, offset 0x673 {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0xdc, offset 0x676 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, // Block 0xdd, offset 0x679 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, // Block 0xde, offset 0x67e {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9b}, {value: 0x0018, lo: 0x9c, hi: 0x9c}, {value: 0x3308, lo: 0x9d, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0x9f}, {value: 0x03c0, lo: 0xa0, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xbf}, // Block 0xdf, offset 0x688 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, // Block 0xe0, offset 0x68b {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xa8}, {value: 0x0018, lo: 0xa9, hi: 0xbf}, // Block 0xe1, offset 0x68f {value: 0x0000, lo: 0x0e}, {value: 0x0018, lo: 0x80, hi: 0x9d}, {value: 0xb5b9, lo: 0x9e, hi: 0x9e}, {value: 0xb601, lo: 0x9f, hi: 0x9f}, {value: 0xb649, lo: 0xa0, hi: 0xa0}, {value: 0xb6b1, lo: 0xa1, hi: 0xa1}, {value: 0xb719, lo: 0xa2, hi: 0xa2}, {value: 0xb781, lo: 0xa3, hi: 0xa3}, {value: 0xb7e9, lo: 0xa4, hi: 0xa4}, {value: 0x3018, lo: 0xa5, hi: 0xa6}, {value: 0x3318, lo: 0xa7, hi: 0xa9}, {value: 0x0018, lo: 0xaa, hi: 0xac}, {value: 0x3018, lo: 0xad, hi: 0xb2}, {value: 0x0340, lo: 0xb3, hi: 0xba}, {value: 0x3318, lo: 0xbb, hi: 0xbf}, // Block 0xe2, offset 0x69e {value: 0x0000, lo: 0x0b}, {value: 0x3318, lo: 0x80, hi: 0x82}, {value: 0x0018, lo: 0x83, hi: 0x84}, {value: 0x3318, lo: 0x85, hi: 0x8b}, {value: 0x0018, lo: 0x8c, hi: 0xa9}, {value: 0x3318, lo: 0xaa, hi: 0xad}, {value: 0x0018, lo: 0xae, hi: 0xba}, {value: 0xb851, lo: 0xbb, hi: 0xbb}, {value: 0xb899, lo: 0xbc, hi: 0xbc}, {value: 0xb8e1, lo: 0xbd, hi: 0xbd}, {value: 0xb949, lo: 0xbe, hi: 0xbe}, {value: 0xb9b1, lo: 0xbf, hi: 0xbf}, // Block 0xe3, offset 0x6aa {value: 0x0000, lo: 0x03}, {value: 0xba19, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0xa8}, {value: 0x0040, lo: 0xa9, hi: 0xbf}, // Block 0xe4, offset 0x6ae {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x81}, {value: 0x3318, lo: 0x82, hi: 0x84}, {value: 0x0018, lo: 0x85, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0xbf}, // Block 0xe5, offset 0x6b3 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xb1}, {value: 0x0040, lo: 0xb2, hi: 0xbf}, // Block 0xe6, offset 0x6b8 {value: 0x0000, lo: 0x03}, {value: 0x3308, lo: 0x80, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xba}, {value: 0x3308, lo: 0xbb, hi: 0xbf}, // Block 0xe7, offset 0x6bc {value: 0x0000, lo: 0x04}, {value: 0x3308, lo: 0x80, hi: 0xac}, {value: 0x0018, lo: 0xad, hi: 0xb4}, {value: 0x3308, lo: 0xb5, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xbf}, // Block 0xe8, offset 0x6c1 {value: 0x0000, lo: 0x08}, {value: 0x0018, lo: 0x80, hi: 0x83}, {value: 0x3308, lo: 0x84, hi: 0x84}, {value: 0x0018, lo: 0x85, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x9a}, {value: 0x3308, lo: 0x9b, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xa0}, {value: 0x3308, lo: 0xa1, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, // Block 0xe9, offset 0x6ca {value: 0x0000, lo: 0x0a}, {value: 0x3308, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, {value: 0x3308, lo: 0x88, hi: 0x98}, {value: 0x0040, lo: 0x99, hi: 0x9a}, {value: 0x3308, lo: 0x9b, hi: 0xa1}, {value: 0x0040, lo: 0xa2, hi: 0xa2}, {value: 0x3308, lo: 0xa3, hi: 0xa4}, {value: 0x0040, lo: 0xa5, hi: 0xa5}, {value: 0x3308, lo: 0xa6, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xbf}, // Block 0xea, offset 0x6d5 {value: 0x0000, lo: 0x05}, {value: 0x0808, lo: 0x80, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x86}, {value: 0x0818, lo: 0x87, hi: 0x8f}, {value: 0x3308, lo: 0x90, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0xbf}, // Block 0xeb, offset 0x6db {value: 0x0000, lo: 0x07}, {value: 0x0a08, lo: 0x80, hi: 0x83}, {value: 0x3308, lo: 0x84, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8f}, {value: 0x0808, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9d}, {value: 0x0818, lo: 0x9e, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, // Block 0xec, offset 0x6e3 {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb1}, {value: 0x0040, lo: 0xb2, hi: 0xbf}, // Block 0xed, offset 0x6e7 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, // Block 0xee, offset 0x6eb {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xb0}, {value: 0x0018, lo: 0xb1, hi: 0xbf}, // Block 0xef, offset 0x6f1 {value: 0x0000, lo: 0x05}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x90}, {value: 0x0018, lo: 0x91, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, // Block 0xf0, offset 0x6f7 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x8f}, {value: 0xc1c1, lo: 0x90, hi: 0x90}, {value: 0x0018, lo: 0x91, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xbf}, // Block 0xf1, offset 0x6fc {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0xa5}, {value: 0x0018, lo: 0xa6, hi: 0xbf}, // Block 0xf2, offset 0x6ff {value: 0x0000, lo: 0x0f}, {value: 0xc7e9, lo: 0x80, hi: 0x80}, {value: 0xc839, lo: 0x81, hi: 0x81}, {value: 0xc889, lo: 0x82, hi: 0x82}, {value: 0xc8d9, lo: 0x83, hi: 0x83}, {value: 0xc929, lo: 0x84, hi: 0x84}, {value: 0xc979, lo: 0x85, hi: 0x85}, {value: 0xc9c9, lo: 0x86, hi: 0x86}, {value: 0xca19, lo: 0x87, hi: 0x87}, {value: 0xca69, lo: 0x88, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x8f}, {value: 0xcab9, lo: 0x90, hi: 0x90}, {value: 0xcad9, lo: 0x91, hi: 0x91}, {value: 0x0040, lo: 0x92, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa5}, {value: 0x0040, lo: 0xa6, hi: 0xbf}, // Block 0xf3, offset 0x70f {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x94}, {value: 0x0040, lo: 0x95, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbf}, // Block 0xf4, offset 0x716 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbf}, // Block 0xf5, offset 0x719 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0x94}, {value: 0x0040, lo: 0x95, hi: 0xbf}, // Block 0xf6, offset 0x71c {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbf}, // Block 0xf7, offset 0x720 {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xbf}, // Block 0xf8, offset 0x726 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xbf}, // Block 0xf9, offset 0x72b {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0xfa, offset 0x730 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xbf}, // Block 0xfb, offset 0x735 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0x97}, {value: 0x0040, lo: 0x98, hi: 0xbf}, // Block 0xfc, offset 0x738 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x80}, {value: 0x0040, lo: 0x81, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xbf}, // Block 0xfd, offset 0x73d {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0xbf}, // Block 0xfe, offset 0x740 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0xff, offset 0x743 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x100, offset 0x747 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xa1}, {value: 0x0040, lo: 0xa2, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x101, offset 0x74b {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xa0}, {value: 0x0040, lo: 0xa1, hi: 0xbf}, // Block 0x102, offset 0x74e {value: 0x0020, lo: 0x0f}, {value: 0xdeb9, lo: 0x80, hi: 0x89}, {value: 0x8dfd, lo: 0x8a, hi: 0x8a}, {value: 0xdff9, lo: 0x8b, hi: 0x9c}, {value: 0x8e1d, lo: 0x9d, hi: 0x9d}, {value: 0xe239, lo: 0x9e, hi: 0xa2}, {value: 0x8e3d, lo: 0xa3, hi: 0xa3}, {value: 0xe2d9, lo: 0xa4, hi: 0xab}, {value: 0x7ed5, lo: 0xac, hi: 0xac}, {value: 0xe3d9, lo: 0xad, hi: 0xaf}, {value: 0x8e5d, lo: 0xb0, hi: 0xb0}, {value: 0xe439, lo: 0xb1, hi: 0xb6}, {value: 0x8e7d, lo: 0xb7, hi: 0xb9}, {value: 0xe4f9, lo: 0xba, hi: 0xba}, {value: 0x8edd, lo: 0xbb, hi: 0xbb}, {value: 0xe519, lo: 0xbc, hi: 0xbf}, // Block 0x103, offset 0x75e {value: 0x0020, lo: 0x10}, {value: 0x937d, lo: 0x80, hi: 0x80}, {value: 0xf099, lo: 0x81, hi: 0x86}, {value: 0x939d, lo: 0x87, hi: 0x8a}, {value: 0xd9f9, lo: 0x8b, hi: 0x8b}, {value: 0xf159, lo: 0x8c, hi: 0x96}, {value: 0x941d, lo: 0x97, hi: 0x97}, {value: 0xf2b9, lo: 0x98, hi: 0xa3}, {value: 0x943d, lo: 0xa4, hi: 0xa6}, {value: 0xf439, lo: 0xa7, hi: 0xaa}, {value: 0x949d, lo: 0xab, hi: 0xab}, {value: 0xf4b9, lo: 0xac, hi: 0xac}, {value: 0x94bd, lo: 0xad, hi: 0xad}, {value: 0xf4d9, lo: 0xae, hi: 0xaf}, {value: 0x94dd, lo: 0xb0, hi: 0xb1}, {value: 0xf519, lo: 0xb2, hi: 0xbe}, {value: 0x2040, lo: 0xbf, hi: 0xbf}, // Block 0x104, offset 0x76f {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0340, lo: 0x81, hi: 0x81}, {value: 0x0040, lo: 0x82, hi: 0x9f}, {value: 0x0340, lo: 0xa0, hi: 0xbf}, // Block 0x105, offset 0x774 {value: 0x0000, lo: 0x01}, {value: 0x0340, lo: 0x80, hi: 0xbf}, // Block 0x106, offset 0x776 {value: 0x0000, lo: 0x01}, {value: 0x33c0, lo: 0x80, hi: 0xbf}, // Block 0x107, offset 0x778 {value: 0x0000, lo: 0x02}, {value: 0x33c0, lo: 0x80, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, } // Total table size 42114 bytes (41KiB); checksum: 355A58A4 ================================================ FILE: vendor/golang.org/x/net/idna/tables11.0.0.go ================================================ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // +build go1.13 package idna // UnicodeVersion is the Unicode version from which the tables in this package are derived. const UnicodeVersion = "11.0.0" var mappings string = "" + // Size: 8175 bytes "\x00\x01 \x03 ̈\x01a\x03 ̄\x012\x013\x03 ́\x03 ̧\x011\x01o\x051⁄4\x051⁄2" + "\x053⁄4\x03i̇\x03l·\x03ʼn\x01s\x03dž\x03ⱥ\x03ⱦ\x01h\x01j\x01r\x01w\x01y" + "\x03 ̆\x03 ̇\x03 ̊\x03 ̨\x03 ̃\x03 ̋\x01l\x01x\x04̈́\x03 ι\x01;\x05 ̈́" + "\x04եւ\x04اٴ\x04وٴ\x04ۇٴ\x04يٴ\x06क़\x06ख़\x06ग़\x06ज़\x06ड़\x06ढ़\x06फ़" + "\x06य़\x06ড়\x06ঢ়\x06য়\x06ਲ਼\x06ਸ਼\x06ਖ਼\x06ਗ਼\x06ਜ਼\x06ਫ਼\x06ଡ଼\x06ଢ଼" + "\x06ํา\x06ໍາ\x06ຫນ\x06ຫມ\x06གྷ\x06ཌྷ\x06དྷ\x06བྷ\x06ཛྷ\x06ཀྵ\x06ཱི\x06ཱུ" + "\x06ྲྀ\x09ྲཱྀ\x06ླྀ\x09ླཱྀ\x06ཱྀ\x06ྒྷ\x06ྜྷ\x06ྡྷ\x06ྦྷ\x06ྫྷ\x06ྐྵ\x02" + "в\x02д\x02о\x02с\x02т\x02ъ\x02ѣ\x02æ\x01b\x01d\x01e\x02ǝ\x01g\x01i\x01k" + "\x01m\x01n\x02ȣ\x01p\x01t\x01u\x02ɐ\x02ɑ\x02ə\x02ɛ\x02ɜ\x02ŋ\x02ɔ\x02ɯ" + "\x01v\x02β\x02γ\x02δ\x02φ\x02χ\x02ρ\x02н\x02ɒ\x01c\x02ɕ\x02ð\x01f\x02ɟ" + "\x02ɡ\x02ɥ\x02ɨ\x02ɩ\x02ɪ\x02ʝ\x02ɭ\x02ʟ\x02ɱ\x02ɰ\x02ɲ\x02ɳ\x02ɴ\x02ɵ" + "\x02ɸ\x02ʂ\x02ʃ\x02ƫ\x02ʉ\x02ʊ\x02ʋ\x02ʌ\x01z\x02ʐ\x02ʑ\x02ʒ\x02θ\x02ss" + "\x02ά\x02έ\x02ή\x02ί\x02ό\x02ύ\x02ώ\x05ἀι\x05ἁι\x05ἂι\x05ἃι\x05ἄι\x05ἅι" + "\x05ἆι\x05ἇι\x05ἠι\x05ἡι\x05ἢι\x05ἣι\x05ἤι\x05ἥι\x05ἦι\x05ἧι\x05ὠι\x05ὡι" + "\x05ὢι\x05ὣι\x05ὤι\x05ὥι\x05ὦι\x05ὧι\x05ὰι\x04αι\x04άι\x05ᾶι\x02ι\x05 ̈͂" + "\x05ὴι\x04ηι\x04ήι\x05ῆι\x05 ̓̀\x05 ̓́\x05 ̓͂\x02ΐ\x05 ̔̀\x05 ̔́\x05 ̔͂" + "\x02ΰ\x05 ̈̀\x01`\x05ὼι\x04ωι\x04ώι\x05ῶι\x06′′\x09′′′\x06‵‵\x09‵‵‵\x02!" + "!\x02??\x02?!\x02!?\x0c′′′′\x010\x014\x015\x016\x017\x018\x019\x01+\x01=" + "\x01(\x01)\x02rs\x02ħ\x02no\x01q\x02sm\x02tm\x02ω\x02å\x02א\x02ב\x02ג" + "\x02ד\x02π\x051⁄7\x051⁄9\x061⁄10\x051⁄3\x052⁄3\x051⁄5\x052⁄5\x053⁄5\x054" + "⁄5\x051⁄6\x055⁄6\x051⁄8\x053⁄8\x055⁄8\x057⁄8\x041⁄\x02ii\x02iv\x02vi" + "\x04viii\x02ix\x02xi\x050⁄3\x06∫∫\x09∫∫∫\x06∮∮\x09∮∮∮\x0210\x0211\x0212" + "\x0213\x0214\x0215\x0216\x0217\x0218\x0219\x0220\x04(10)\x04(11)\x04(12)" + "\x04(13)\x04(14)\x04(15)\x04(16)\x04(17)\x04(18)\x04(19)\x04(20)\x0c∫∫∫∫" + "\x02==\x05⫝̸\x02ɫ\x02ɽ\x02ȿ\x02ɀ\x01.\x04 ゙\x04 ゚\x06より\x06コト\x05(ᄀ)\x05" + "(ᄂ)\x05(ᄃ)\x05(ᄅ)\x05(ᄆ)\x05(ᄇ)\x05(ᄉ)\x05(ᄋ)\x05(ᄌ)\x05(ᄎ)\x05(ᄏ)\x05(ᄐ" + ")\x05(ᄑ)\x05(ᄒ)\x05(가)\x05(나)\x05(다)\x05(라)\x05(마)\x05(바)\x05(사)\x05(아)" + "\x05(자)\x05(차)\x05(카)\x05(타)\x05(파)\x05(하)\x05(주)\x08(오전)\x08(오후)\x05(一)" + "\x05(二)\x05(三)\x05(四)\x05(五)\x05(六)\x05(七)\x05(八)\x05(九)\x05(十)\x05(月)" + "\x05(火)\x05(水)\x05(木)\x05(金)\x05(土)\x05(日)\x05(株)\x05(有)\x05(社)\x05(名)" + "\x05(特)\x05(財)\x05(祝)\x05(労)\x05(代)\x05(呼)\x05(学)\x05(監)\x05(企)\x05(資)" + "\x05(協)\x05(祭)\x05(休)\x05(自)\x05(至)\x0221\x0222\x0223\x0224\x0225\x0226" + "\x0227\x0228\x0229\x0230\x0231\x0232\x0233\x0234\x0235\x06참고\x06주의\x0236" + "\x0237\x0238\x0239\x0240\x0241\x0242\x0243\x0244\x0245\x0246\x0247\x0248" + "\x0249\x0250\x041月\x042月\x043月\x044月\x045月\x046月\x047月\x048月\x049月\x0510" + "月\x0511月\x0512月\x02hg\x02ev\x0cアパート\x0cアルファ\x0cアンペア\x09アール\x0cイニング\x09" + "インチ\x09ウォン\x0fエスクード\x0cエーカー\x09オンス\x09オーム\x09カイリ\x0cカラット\x0cカロリー\x09ガロ" + "ン\x09ガンマ\x06ギガ\x09ギニー\x0cキュリー\x0cギルダー\x06キロ\x0fキログラム\x12キロメートル\x0fキロワッ" + "ト\x09グラム\x0fグラムトン\x0fクルゼイロ\x0cクローネ\x09ケース\x09コルナ\x09コーポ\x0cサイクル\x0fサンチ" + "ーム\x0cシリング\x09センチ\x09セント\x09ダース\x06デシ\x06ドル\x06トン\x06ナノ\x09ノット\x09ハイツ" + "\x0fパーセント\x09パーツ\x0cバーレル\x0fピアストル\x09ピクル\x06ピコ\x06ビル\x0fファラッド\x0cフィート" + "\x0fブッシェル\x09フラン\x0fヘクタール\x06ペソ\x09ペニヒ\x09ヘルツ\x09ペンス\x09ページ\x09ベータ\x0cポイ" + "ント\x09ボルト\x06ホン\x09ポンド\x09ホール\x09ホーン\x0cマイクロ\x09マイル\x09マッハ\x09マルク\x0fマ" + "ンション\x0cミクロン\x06ミリ\x0fミリバール\x06メガ\x0cメガトン\x0cメートル\x09ヤード\x09ヤール\x09ユアン" + "\x0cリットル\x06リラ\x09ルピー\x0cルーブル\x06レム\x0fレントゲン\x09ワット\x040点\x041点\x042点" + "\x043点\x044点\x045点\x046点\x047点\x048点\x049点\x0510点\x0511点\x0512点\x0513点" + "\x0514点\x0515点\x0516点\x0517点\x0518点\x0519点\x0520点\x0521点\x0522点\x0523点" + "\x0524点\x02da\x02au\x02ov\x02pc\x02dm\x02iu\x06平成\x06昭和\x06大正\x06明治\x0c株" + "式会社\x02pa\x02na\x02ma\x02ka\x02kb\x02mb\x02gb\x04kcal\x02pf\x02nf\x02m" + "g\x02kg\x02hz\x02ml\x02dl\x02kl\x02fm\x02nm\x02mm\x02cm\x02km\x02m2\x02m" + "3\x05m∕s\x06m∕s2\x07rad∕s\x08rad∕s2\x02ps\x02ns\x02ms\x02pv\x02nv\x02mv" + "\x02kv\x02pw\x02nw\x02mw\x02kw\x02bq\x02cc\x02cd\x06c∕kg\x02db\x02gy\x02" + "ha\x02hp\x02in\x02kk\x02kt\x02lm\x02ln\x02lx\x02ph\x02pr\x02sr\x02sv\x02" + "wb\x05v∕m\x05a∕m\x041日\x042日\x043日\x044日\x045日\x046日\x047日\x048日\x049日" + "\x0510日\x0511日\x0512日\x0513日\x0514日\x0515日\x0516日\x0517日\x0518日\x0519日" + "\x0520日\x0521日\x0522日\x0523日\x0524日\x0525日\x0526日\x0527日\x0528日\x0529日" + "\x0530日\x0531日\x02ь\x02ɦ\x02ɬ\x02ʞ\x02ʇ\x02œ\x04𤋮\x04𢡊\x04𢡄\x04𣏕\x04𥉉" + "\x04𥳐\x04𧻓\x02ff\x02fi\x02fl\x02st\x04մն\x04մե\x04մի\x04վն\x04մխ\x04יִ" + "\x04ײַ\x02ע\x02ה\x02כ\x02ל\x02ם\x02ר\x02ת\x04שׁ\x04שׂ\x06שּׁ\x06שּׂ\x04א" + "ַ\x04אָ\x04אּ\x04בּ\x04גּ\x04דּ\x04הּ\x04וּ\x04זּ\x04טּ\x04יּ\x04ךּ\x04" + "כּ\x04לּ\x04מּ\x04נּ\x04סּ\x04ףּ\x04פּ\x04צּ\x04קּ\x04רּ\x04שּ\x04תּ" + "\x04וֹ\x04בֿ\x04כֿ\x04פֿ\x04אל\x02ٱ\x02ٻ\x02پ\x02ڀ\x02ٺ\x02ٿ\x02ٹ\x02ڤ" + "\x02ڦ\x02ڄ\x02ڃ\x02چ\x02ڇ\x02ڍ\x02ڌ\x02ڎ\x02ڈ\x02ژ\x02ڑ\x02ک\x02گ\x02ڳ" + "\x02ڱ\x02ں\x02ڻ\x02ۀ\x02ہ\x02ھ\x02ے\x02ۓ\x02ڭ\x02ۇ\x02ۆ\x02ۈ\x02ۋ\x02ۅ" + "\x02ۉ\x02ې\x02ى\x04ئا\x04ئە\x04ئو\x04ئۇ\x04ئۆ\x04ئۈ\x04ئې\x04ئى\x02ی\x04" + "ئج\x04ئح\x04ئم\x04ئي\x04بج\x04بح\x04بخ\x04بم\x04بى\x04بي\x04تج\x04تح" + "\x04تخ\x04تم\x04تى\x04تي\x04ثج\x04ثم\x04ثى\x04ثي\x04جح\x04جم\x04حج\x04حم" + "\x04خج\x04خح\x04خم\x04سج\x04سح\x04سخ\x04سم\x04صح\x04صم\x04ضج\x04ضح\x04ضخ" + "\x04ضم\x04طح\x04طم\x04ظم\x04عج\x04عم\x04غج\x04غم\x04فج\x04فح\x04فخ\x04فم" + "\x04فى\x04في\x04قح\x04قم\x04قى\x04قي\x04كا\x04كج\x04كح\x04كخ\x04كل\x04كم" + "\x04كى\x04كي\x04لج\x04لح\x04لخ\x04لم\x04لى\x04لي\x04مج\x04مح\x04مخ\x04مم" + "\x04مى\x04مي\x04نج\x04نح\x04نخ\x04نم\x04نى\x04ني\x04هج\x04هم\x04هى\x04هي" + "\x04يج\x04يح\x04يخ\x04يم\x04يى\x04يي\x04ذٰ\x04رٰ\x04ىٰ\x05 ٌّ\x05 ٍّ\x05" + " َّ\x05 ُّ\x05 ِّ\x05 ّٰ\x04ئر\x04ئز\x04ئن\x04بر\x04بز\x04بن\x04تر\x04تز" + "\x04تن\x04ثر\x04ثز\x04ثن\x04ما\x04نر\x04نز\x04نن\x04ير\x04يز\x04ين\x04ئخ" + "\x04ئه\x04به\x04ته\x04صخ\x04له\x04نه\x04هٰ\x04يه\x04ثه\x04سه\x04شم\x04شه" + "\x06ـَّ\x06ـُّ\x06ـِّ\x04طى\x04طي\x04عى\x04عي\x04غى\x04غي\x04سى\x04سي" + "\x04شى\x04شي\x04حى\x04حي\x04جى\x04جي\x04خى\x04خي\x04صى\x04صي\x04ضى\x04ضي" + "\x04شج\x04شح\x04شخ\x04شر\x04سر\x04صر\x04ضر\x04اً\x06تجم\x06تحج\x06تحم" + "\x06تخم\x06تمج\x06تمح\x06تمخ\x06جمح\x06حمي\x06حمى\x06سحج\x06سجح\x06سجى" + "\x06سمح\x06سمج\x06سمم\x06صحح\x06صمم\x06شحم\x06شجي\x06شمخ\x06شمم\x06ضحى" + "\x06ضخم\x06طمح\x06طمم\x06طمي\x06عجم\x06عمم\x06عمى\x06غمم\x06غمي\x06غمى" + "\x06فخم\x06قمح\x06قمم\x06لحم\x06لحي\x06لحى\x06لجج\x06لخم\x06لمح\x06محج" + "\x06محم\x06محي\x06مجح\x06مجم\x06مخج\x06مخم\x06مجخ\x06همج\x06همم\x06نحم" + "\x06نحى\x06نجم\x06نجى\x06نمي\x06نمى\x06يمم\x06بخي\x06تجي\x06تجى\x06تخي" + "\x06تخى\x06تمي\x06تمى\x06جمي\x06جحى\x06جمى\x06سخى\x06صحي\x06شحي\x06ضحي" + "\x06لجي\x06لمي\x06يحي\x06يجي\x06يمي\x06ممي\x06قمي\x06نحي\x06عمي\x06كمي" + "\x06نجح\x06مخي\x06لجم\x06كمم\x06جحي\x06حجي\x06مجي\x06فمي\x06بحي\x06سخي" + "\x06نجي\x06صلے\x06قلے\x08الله\x08اكبر\x08محمد\x08صلعم\x08رسول\x08عليه" + "\x08وسلم\x06صلى!صلى الله عليه وسلم\x0fجل جلاله\x08ریال\x01,\x01:\x01!" + "\x01?\x01_\x01{\x01}\x01[\x01]\x01#\x01&\x01*\x01-\x01<\x01>\x01\\\x01$" + "\x01%\x01@\x04ـً\x04ـَ\x04ـُ\x04ـِ\x04ـّ\x04ـْ\x02ء\x02آ\x02أ\x02ؤ\x02إ" + "\x02ئ\x02ا\x02ب\x02ة\x02ت\x02ث\x02ج\x02ح\x02خ\x02د\x02ذ\x02ر\x02ز\x02س" + "\x02ش\x02ص\x02ض\x02ط\x02ظ\x02ع\x02غ\x02ف\x02ق\x02ك\x02ل\x02م\x02ن\x02ه" + "\x02و\x02ي\x04لآ\x04لأ\x04لإ\x04لا\x01\x22\x01'\x01/\x01^\x01|\x01~\x02¢" + "\x02£\x02¬\x02¦\x02¥\x08𝅗𝅥\x08𝅘𝅥\x0c𝅘𝅥𝅮\x0c𝅘𝅥𝅯\x0c𝅘𝅥𝅰\x0c𝅘𝅥𝅱\x0c𝅘𝅥𝅲\x08𝆹" + "𝅥\x08𝆺𝅥\x0c𝆹𝅥𝅮\x0c𝆺𝅥𝅮\x0c𝆹𝅥𝅯\x0c𝆺𝅥𝅯\x02ı\x02ȷ\x02α\x02ε\x02ζ\x02η\x02" + "κ\x02λ\x02μ\x02ν\x02ξ\x02ο\x02σ\x02τ\x02υ\x02ψ\x03∇\x03∂\x02ϝ\x02ٮ\x02ڡ" + "\x02ٯ\x020,\x021,\x022,\x023,\x024,\x025,\x026,\x027,\x028,\x029,\x03(a)" + "\x03(b)\x03(c)\x03(d)\x03(e)\x03(f)\x03(g)\x03(h)\x03(i)\x03(j)\x03(k)" + "\x03(l)\x03(m)\x03(n)\x03(o)\x03(p)\x03(q)\x03(r)\x03(s)\x03(t)\x03(u)" + "\x03(v)\x03(w)\x03(x)\x03(y)\x03(z)\x07〔s〕\x02wz\x02hv\x02sd\x03ppv\x02w" + "c\x02mc\x02md\x02dj\x06ほか\x06ココ\x03サ\x03手\x03字\x03双\x03デ\x03二\x03多\x03解" + "\x03天\x03交\x03映\x03無\x03料\x03前\x03後\x03再\x03新\x03初\x03終\x03生\x03販\x03声" + "\x03吹\x03演\x03投\x03捕\x03一\x03三\x03遊\x03左\x03中\x03右\x03指\x03走\x03打\x03禁" + "\x03空\x03合\x03満\x03有\x03月\x03申\x03割\x03営\x03配\x09〔本〕\x09〔三〕\x09〔二〕\x09〔安" + "〕\x09〔点〕\x09〔打〕\x09〔盗〕\x09〔勝〕\x09〔敗〕\x03得\x03可\x03丽\x03丸\x03乁\x03你\x03" + "侮\x03侻\x03倂\x03偺\x03備\x03僧\x03像\x03㒞\x03免\x03兔\x03兤\x03具\x03㒹\x03內\x03" + "冗\x03冤\x03仌\x03冬\x03况\x03凵\x03刃\x03㓟\x03刻\x03剆\x03剷\x03㔕\x03勇\x03勉\x03" + "勤\x03勺\x03包\x03匆\x03北\x03卉\x03卑\x03博\x03即\x03卽\x03卿\x03灰\x03及\x03叟\x03" + "叫\x03叱\x03吆\x03咞\x03吸\x03呈\x03周\x03咢\x03哶\x03唐\x03啓\x03啣\x03善\x03喙\x03" + "喫\x03喳\x03嗂\x03圖\x03嘆\x03圗\x03噑\x03噴\x03切\x03壮\x03城\x03埴\x03堍\x03型\x03" + "堲\x03報\x03墬\x03売\x03壷\x03夆\x03夢\x03奢\x03姬\x03娛\x03娧\x03姘\x03婦\x03㛮\x03" + "嬈\x03嬾\x03寃\x03寘\x03寧\x03寳\x03寿\x03将\x03尢\x03㞁\x03屠\x03屮\x03峀\x03岍\x03" + "嵃\x03嵮\x03嵫\x03嵼\x03巡\x03巢\x03㠯\x03巽\x03帨\x03帽\x03幩\x03㡢\x03㡼\x03庰\x03" + "庳\x03庶\x03廊\x03廾\x03舁\x03弢\x03㣇\x03形\x03彫\x03㣣\x03徚\x03忍\x03志\x03忹\x03" + "悁\x03㤺\x03㤜\x03悔\x03惇\x03慈\x03慌\x03慎\x03慺\x03憎\x03憲\x03憤\x03憯\x03懞\x03" + "懲\x03懶\x03成\x03戛\x03扝\x03抱\x03拔\x03捐\x03挽\x03拼\x03捨\x03掃\x03揤\x03搢\x03" + "揅\x03掩\x03㨮\x03摩\x03摾\x03撝\x03摷\x03㩬\x03敏\x03敬\x03旣\x03書\x03晉\x03㬙\x03" + "暑\x03㬈\x03㫤\x03冒\x03冕\x03最\x03暜\x03肭\x03䏙\x03朗\x03望\x03朡\x03杞\x03杓\x03" + "㭉\x03柺\x03枅\x03桒\x03梅\x03梎\x03栟\x03椔\x03㮝\x03楂\x03榣\x03槪\x03檨\x03櫛\x03" + "㰘\x03次\x03歔\x03㱎\x03歲\x03殟\x03殺\x03殻\x03汎\x03沿\x03泍\x03汧\x03洖\x03派\x03" + "海\x03流\x03浩\x03浸\x03涅\x03洴\x03港\x03湮\x03㴳\x03滋\x03滇\x03淹\x03潮\x03濆\x03" + "瀹\x03瀞\x03瀛\x03㶖\x03灊\x03災\x03灷\x03炭\x03煅\x03熜\x03爨\x03爵\x03牐\x03犀\x03" + "犕\x03獺\x03王\x03㺬\x03玥\x03㺸\x03瑇\x03瑜\x03瑱\x03璅\x03瓊\x03㼛\x03甤\x03甾\x03" + "異\x03瘐\x03㿼\x03䀈\x03直\x03眞\x03真\x03睊\x03䀹\x03瞋\x03䁆\x03䂖\x03硎\x03碌\x03" + "磌\x03䃣\x03祖\x03福\x03秫\x03䄯\x03穀\x03穊\x03穏\x03䈂\x03篆\x03築\x03䈧\x03糒\x03" + "䊠\x03糨\x03糣\x03紀\x03絣\x03䌁\x03緇\x03縂\x03繅\x03䌴\x03䍙\x03罺\x03羕\x03翺\x03" + "者\x03聠\x03聰\x03䏕\x03育\x03脃\x03䐋\x03脾\x03媵\x03舄\x03辞\x03䑫\x03芑\x03芋\x03" + "芝\x03劳\x03花\x03芳\x03芽\x03苦\x03若\x03茝\x03荣\x03莭\x03茣\x03莽\x03菧\x03著\x03" + "荓\x03菊\x03菌\x03菜\x03䔫\x03蓱\x03蓳\x03蔖\x03蕤\x03䕝\x03䕡\x03䕫\x03虐\x03虜\x03" + "虧\x03虩\x03蚩\x03蚈\x03蜎\x03蛢\x03蝹\x03蜨\x03蝫\x03螆\x03蟡\x03蠁\x03䗹\x03衠\x03" + "衣\x03裗\x03裞\x03䘵\x03裺\x03㒻\x03䚾\x03䛇\x03誠\x03諭\x03變\x03豕\x03貫\x03賁\x03" + "贛\x03起\x03跋\x03趼\x03跰\x03軔\x03輸\x03邔\x03郱\x03鄑\x03鄛\x03鈸\x03鋗\x03鋘\x03" + "鉼\x03鏹\x03鐕\x03開\x03䦕\x03閷\x03䧦\x03雃\x03嶲\x03霣\x03䩮\x03䩶\x03韠\x03䪲\x03" + "頋\x03頩\x03飢\x03䬳\x03餩\x03馧\x03駂\x03駾\x03䯎\x03鬒\x03鱀\x03鳽\x03䳎\x03䳭\x03" + "鵧\x03䳸\x03麻\x03䵖\x03黹\x03黾\x03鼅\x03鼏\x03鼖\x03鼻" var xorData string = "" + // Size: 4855 bytes "\x02\x0c\x09\x02\xb0\xec\x02\xad\xd8\x02\xad\xd9\x02\x06\x07\x02\x0f\x12" + "\x02\x0f\x1f\x02\x0f\x1d\x02\x01\x13\x02\x0f\x16\x02\x0f\x0b\x02\x0f3" + "\x02\x0f7\x02\x0f?\x02\x0f/\x02\x0f*\x02\x0c&\x02\x0c*\x02\x0c;\x02\x0c9" + "\x02\x0c%\x02\xab\xed\x02\xab\xe2\x02\xab\xe3\x02\xa9\xe0\x02\xa9\xe1" + "\x02\xa9\xe6\x02\xa3\xcb\x02\xa3\xc8\x02\xa3\xc9\x02\x01#\x02\x01\x08" + "\x02\x0e>\x02\x0e'\x02\x0f\x03\x02\x03\x0d\x02\x03\x09\x02\x03\x17\x02" + "\x03\x0e\x02\x02\x03\x02\x011\x02\x01\x00\x02\x01\x10\x02\x03<\x02\x07" + "\x0d\x02\x02\x0c\x02\x0c0\x02\x01\x03\x02\x01\x01\x02\x01 \x02\x01\x22" + "\x02\x01)\x02\x01\x0a\x02\x01\x0c\x02\x02\x06\x02\x02\x02\x02\x03\x10" + "\x03\x037 \x03\x0b+\x03\x02\x01\x04\x02\x01\x02\x02\x019\x02\x03\x1c\x02" + "\x02$\x03\x80p$\x02\x03:\x02\x03\x0a\x03\xc1r.\x03\xc1r,\x03\xc1r\x02" + "\x02\x02:\x02\x02>\x02\x02,\x02\x02\x10\x02\x02\x00\x03\xc1s<\x03\xc1s*" + "\x03\xc2L$\x03\xc2L;\x02\x09)\x02\x0a\x19\x03\x83\xab\xe3\x03\x83\xab" + "\xf2\x03 4\xe0\x03\x81\xab\xea\x03\x81\xab\xf3\x03 4\xef\x03\x96\xe1\xcd" + "\x03\x84\xe5\xc3\x02\x0d\x11\x03\x8b\xec\xcb\x03\x94\xec\xcf\x03\x9a\xec" + "\xc2\x03\x8b\xec\xdb\x03\x94\xec\xdf\x03\x9a\xec\xd2\x03\x01\x0c!\x03" + "\x01\x0c#\x03ʠ\x9d\x03ʣ\x9c\x03ʢ\x9f\x03ʥ\x9e\x03ʤ\x91\x03ʧ\x90\x03ʦ\x93" + "\x03ʩ\x92\x03ʨ\x95\x03\xca\xf3\xb5\x03\xca\xf0\xb4\x03\xca\xf1\xb7\x03" + "\xca\xf6\xb6\x03\xca\xf7\x89\x03\xca\xf4\x88\x03\xca\xf5\x8b\x03\xca\xfa" + "\x8a\x03\xca\xfb\x8d\x03\xca\xf8\x8c\x03\xca\xf9\x8f\x03\xca\xfe\x8e\x03" + "\xca\xff\x81\x03\xca\xfc\x80\x03\xca\xfd\x83\x03\xca\xe2\x82\x03\xca\xe3" + "\x85\x03\xca\xe0\x84\x03\xca\xe1\x87\x03\xca\xe6\x86\x03\xca\xe7\x99\x03" + "\xca\xe4\x98\x03\xca\xe5\x9b\x03\xca\xea\x9a\x03\xca\xeb\x9d\x03\xca\xe8" + "\x9c\x03ؓ\x89\x03ߔ\x8b\x02\x010\x03\x03\x04\x1e\x03\x04\x15\x12\x03\x0b" + "\x05,\x03\x06\x04\x00\x03\x06\x04)\x03\x06\x044\x03\x06\x04<\x03\x06\x05" + "\x1d\x03\x06\x06\x00\x03\x06\x06\x0a\x03\x06\x06'\x03\x06\x062\x03\x0786" + "\x03\x079/\x03\x079 \x03\x07:\x0e\x03\x07:\x1b\x03\x07:%\x03\x07;/\x03" + "\x07;%\x03\x074\x11\x03\x076\x09\x03\x077*\x03\x070\x01\x03\x070\x0f\x03" + "\x070.\x03\x071\x16\x03\x071\x04\x03\x0710\x03\x072\x18\x03\x072-\x03" + "\x073\x14\x03\x073>\x03\x07'\x09\x03\x07 \x00\x03\x07\x1f\x0b\x03\x07" + "\x18#\x03\x07\x18(\x03\x07\x186\x03\x07\x18\x03\x03\x07\x19\x16\x03\x07" + "\x116\x03\x07\x12'\x03\x07\x13\x10\x03\x07\x0c&\x03\x07\x0c\x08\x03\x07" + "\x0c\x13\x03\x07\x0d\x02\x03\x07\x0d\x1c\x03\x07\x0b5\x03\x07\x0b\x0a" + "\x03\x07\x0b\x01\x03\x07\x0b\x0f\x03\x07\x05\x00\x03\x07\x05\x09\x03\x07" + "\x05\x0b\x03\x07\x07\x01\x03\x07\x07\x08\x03\x07\x00<\x03\x07\x00+\x03" + "\x07\x01)\x03\x07\x01\x1b\x03\x07\x01\x08\x03\x07\x03?\x03\x0445\x03\x04" + "4\x08\x03\x0454\x03\x04)/\x03\x04)5\x03\x04+\x05\x03\x04+\x14\x03\x04+ " + "\x03\x04+<\x03\x04*&\x03\x04*\x22\x03\x04&8\x03\x04!\x01\x03\x04!\x22" + "\x03\x04\x11+\x03\x04\x10.\x03\x04\x104\x03\x04\x13=\x03\x04\x12\x04\x03" + "\x04\x12\x0a\x03\x04\x0d\x1d\x03\x04\x0d\x07\x03\x04\x0d \x03\x05<>\x03" + "\x055<\x03\x055!\x03\x055#\x03\x055&\x03\x054\x1d\x03\x054\x02\x03\x054" + "\x07\x03\x0571\x03\x053\x1a\x03\x053\x16\x03\x05.<\x03\x05.\x07\x03\x05)" + ":\x03\x05)<\x03\x05)\x0c\x03\x05)\x15\x03\x05+-\x03\x05+5\x03\x05$\x1e" + "\x03\x05$\x14\x03\x05'\x04\x03\x05'\x14\x03\x05&\x02\x03\x05\x226\x03" + "\x05\x22\x0c\x03\x05\x22\x1c\x03\x05\x19\x0a\x03\x05\x1b\x09\x03\x05\x1b" + "\x0c\x03\x05\x14\x07\x03\x05\x16?\x03\x05\x16\x0c\x03\x05\x0c\x05\x03" + "\x05\x0e\x0f\x03\x05\x01\x0e\x03\x05\x00(\x03\x05\x030\x03\x05\x03\x06" + "\x03\x0a==\x03\x0a=1\x03\x0a=,\x03\x0a=\x0c\x03\x0a??\x03\x0a<\x08\x03" + "\x0a9!\x03\x0a9)\x03\x0a97\x03\x0a99\x03\x0a6\x0a\x03\x0a6\x1c\x03\x0a6" + "\x17\x03\x0a7'\x03\x0a78\x03\x0a73\x03\x0a'\x01\x03\x0a'&\x03\x0a\x1f" + "\x0e\x03\x0a\x1f\x03\x03\x0a\x1f3\x03\x0a\x1b/\x03\x0a\x18\x19\x03\x0a" + "\x19\x01\x03\x0a\x16\x14\x03\x0a\x0e\x22\x03\x0a\x0f\x10\x03\x0a\x0f\x02" + "\x03\x0a\x0f \x03\x0a\x0c\x04\x03\x0a\x0b>\x03\x0a\x0b+\x03\x0a\x08/\x03" + "\x0a\x046\x03\x0a\x05\x14\x03\x0a\x00\x04\x03\x0a\x00\x10\x03\x0a\x00" + "\x14\x03\x0b<3\x03\x0b;*\x03\x0b9\x22\x03\x0b9)\x03\x0b97\x03\x0b+\x10" + "\x03\x0b((\x03\x0b&5\x03\x0b$\x1c\x03\x0b$\x12\x03\x0b%\x04\x03\x0b#<" + "\x03\x0b#0\x03\x0b#\x0d\x03\x0b#\x19\x03\x0b!:\x03\x0b!\x1f\x03\x0b!\x00" + "\x03\x0b\x1e5\x03\x0b\x1c\x1d\x03\x0b\x1d-\x03\x0b\x1d(\x03\x0b\x18.\x03" + "\x0b\x18 \x03\x0b\x18\x16\x03\x0b\x14\x13\x03\x0b\x15$\x03\x0b\x15\x22" + "\x03\x0b\x12\x1b\x03\x0b\x12\x10\x03\x0b\x132\x03\x0b\x13=\x03\x0b\x12" + "\x18\x03\x0b\x0c&\x03\x0b\x061\x03\x0b\x06:\x03\x0b\x05#\x03\x0b\x05<" + "\x03\x0b\x04\x0b\x03\x0b\x04\x04\x03\x0b\x04\x1b\x03\x0b\x042\x03\x0b" + "\x041\x03\x0b\x03\x03\x03\x0b\x03\x1d\x03\x0b\x03/\x03\x0b\x03+\x03\x0b" + "\x02\x1b\x03\x0b\x02\x00\x03\x0b\x01\x1e\x03\x0b\x01\x08\x03\x0b\x015" + "\x03\x06\x0d9\x03\x06\x0d=\x03\x06\x0d?\x03\x02\x001\x03\x02\x003\x03" + "\x02\x02\x19\x03\x02\x006\x03\x02\x02\x1b\x03\x02\x004\x03\x02\x00<\x03" + "\x02\x02\x0a\x03\x02\x02\x0e\x03\x02\x01\x1a\x03\x02\x01\x07\x03\x02\x01" + "\x05\x03\x02\x01\x0b\x03\x02\x01%\x03\x02\x01\x0c\x03\x02\x01\x04\x03" + "\x02\x01\x1c\x03\x02\x00.\x03\x02\x002\x03\x02\x00>\x03\x02\x00\x12\x03" + "\x02\x00\x16\x03\x02\x011\x03\x02\x013\x03\x02\x02 \x03\x02\x02%\x03\x02" + "\x02$\x03\x02\x028\x03\x02\x02;\x03\x02\x024\x03\x02\x012\x03\x02\x022" + "\x03\x02\x02/\x03\x02\x01,\x03\x02\x01\x13\x03\x02\x01\x16\x03\x02\x01" + "\x11\x03\x02\x01\x1e\x03\x02\x01\x15\x03\x02\x01\x17\x03\x02\x01\x0f\x03" + "\x02\x01\x08\x03\x02\x00?\x03\x02\x03\x07\x03\x02\x03\x0d\x03\x02\x03" + "\x13\x03\x02\x03\x1d\x03\x02\x03\x1f\x03\x02\x00\x03\x03\x02\x00\x0d\x03" + "\x02\x00\x01\x03\x02\x00\x1b\x03\x02\x00\x19\x03\x02\x00\x18\x03\x02\x00" + "\x13\x03\x02\x00/\x03\x07>\x12\x03\x07<\x1f\x03\x07>\x1d\x03\x06\x1d\x0e" + "\x03\x07>\x1c\x03\x07>:\x03\x07>\x13\x03\x04\x12+\x03\x07?\x03\x03\x07>" + "\x02\x03\x06\x224\x03\x06\x1a.\x03\x07<%\x03\x06\x1c\x0b\x03\x0609\x03" + "\x05\x1f\x01\x03\x04'\x08\x03\x93\xfd\xf5\x03\x02\x0d \x03\x02\x0d#\x03" + "\x02\x0d!\x03\x02\x0d&\x03\x02\x0d\x22\x03\x02\x0d/\x03\x02\x0d,\x03\x02" + "\x0d$\x03\x02\x0d'\x03\x02\x0d%\x03\x02\x0d;\x03\x02\x0d=\x03\x02\x0d?" + "\x03\x099.\x03\x08\x0b7\x03\x08\x02\x14\x03\x08\x14\x0d\x03\x08.:\x03" + "\x089'\x03\x0f\x0b\x18\x03\x0f\x1c1\x03\x0f\x17&\x03\x0f9\x1f\x03\x0f0" + "\x0c\x03\x0e\x0a9\x03\x0e\x056\x03\x0e\x1c#\x03\x0f\x13\x0e\x03\x072\x00" + "\x03\x070\x0d\x03\x072\x0b\x03\x06\x11\x18\x03\x070\x10\x03\x06\x0f(\x03" + "\x072\x05\x03\x06\x0f,\x03\x073\x15\x03\x06\x07\x08\x03\x05\x16\x02\x03" + "\x04\x0b \x03\x05:8\x03\x05\x16%\x03\x0a\x0d\x1f\x03\x06\x16\x10\x03\x05" + "\x1d5\x03\x05*;\x03\x05\x16\x1b\x03\x04.-\x03\x06\x1a\x19\x03\x04\x03," + "\x03\x0b87\x03\x04/\x0a\x03\x06\x00,\x03\x04-\x01\x03\x04\x1e-\x03\x06/(" + "\x03\x0a\x0b5\x03\x06\x0e7\x03\x06\x07.\x03\x0597\x03\x0a*%\x03\x0760" + "\x03\x06\x0c;\x03\x05'\x00\x03\x072.\x03\x072\x08\x03\x06=\x01\x03\x06" + "\x05\x1b\x03\x06\x06\x12\x03\x06$=\x03\x06'\x0d\x03\x04\x11\x0f\x03\x076" + ",\x03\x06\x07;\x03\x06.,\x03\x86\xf9\xea\x03\x8f\xff\xeb\x02\x092\x02" + "\x095\x02\x094\x02\x09;\x02\x09>\x02\x098\x02\x09*\x02\x09/\x02\x09,\x02" + "\x09%\x02\x09&\x02\x09#\x02\x09 \x02\x08!\x02\x08%\x02\x08$\x02\x08+\x02" + "\x08.\x02\x08*\x02\x08&\x02\x088\x02\x08>\x02\x084\x02\x086\x02\x080\x02" + "\x08\x10\x02\x08\x17\x02\x08\x12\x02\x08\x1d\x02\x08\x1f\x02\x08\x13\x02" + "\x08\x15\x02\x08\x14\x02\x08\x0c\x03\x8b\xfd\xd0\x03\x81\xec\xc6\x03\x87" + "\xe0\x8a\x03-2\xe3\x03\x80\xef\xe4\x03-2\xea\x03\x88\xe6\xeb\x03\x8e\xe6" + "\xe8\x03\x84\xe6\xe9\x03\x97\xe6\xee\x03-2\xf9\x03-2\xf6\x03\x8e\xe3\xad" + "\x03\x80\xe3\x92\x03\x88\xe3\x90\x03\x8e\xe3\x90\x03\x80\xe3\x97\x03\x88" + "\xe3\x95\x03\x88\xfe\xcb\x03\x8e\xfe\xca\x03\x84\xfe\xcd\x03\x91\xef\xc9" + "\x03-2\xc1\x03-2\xc0\x03-2\xcb\x03\x88@\x09\x03\x8e@\x08\x03\x8f\xe0\xf5" + "\x03\x8e\xe6\xf9\x03\x8e\xe0\xfa\x03\x93\xff\xf4\x03\x84\xee\xd3\x03\x0b" + "(\x04\x023 \x021;\x02\x01*\x03\x0b#\x10\x03\x0b 0\x03\x0b!\x10\x03\x0b!0" + "\x03\x07\x15\x08\x03\x09?5\x03\x07\x1f\x08\x03\x07\x17\x0b\x03\x09\x1f" + "\x15\x03\x0b\x1c7\x03\x0a+#\x03\x06\x1a\x1b\x03\x06\x1a\x14\x03\x0a\x01" + "\x18\x03\x06#\x1b\x03\x0a2\x0c\x03\x0a\x01\x04\x03\x09#;\x03\x08='\x03" + "\x08\x1a\x0a\x03\x07\x03\x0a\x111\x03\x09\x1b\x09\x03\x073.\x03\x07\x01\x00" + "\x03\x09/,\x03\x07#>\x03\x07\x048\x03\x0a\x1f\x22\x03\x098>\x03\x09\x11" + "\x00\x03\x08/\x17\x03\x06'\x22\x03\x0b\x1a+\x03\x0a\x22\x19\x03\x0a/1" + "\x03\x0974\x03\x09\x0f\x22\x03\x08,\x22\x03\x08?\x14\x03\x07$5\x03\x07<3" + "\x03\x07=*\x03\x07\x13\x18\x03\x068\x0a\x03\x06\x09\x16\x03\x06\x13\x00" + "\x03\x08\x067\x03\x08\x01\x03\x03\x08\x12\x1d\x03\x07+7\x03\x06(;\x03" + "\x06\x1c?\x03\x07\x0e\x17\x03\x0a\x06\x1d\x03\x0a\x19\x07\x03\x08\x14$" + "\x03\x07$;\x03\x08,$\x03\x08\x06\x0d\x03\x07\x16\x0a\x03\x06>>\x03\x0a" + "\x06\x12\x03\x0a\x14)\x03\x09\x0d\x1f\x03\x09\x12\x17\x03\x09\x19\x01" + "\x03\x08\x11 \x03\x08\x1d'\x03\x06<\x1a\x03\x0a.\x00\x03\x07'\x18\x03" + "\x0a\x22\x08\x03\x08\x0d\x0a\x03\x08\x13)\x03\x07*)\x03\x06<,\x03\x07" + "\x0b\x1a\x03\x09.\x14\x03\x09\x0d\x1e\x03\x07\x0e#\x03\x0b\x1d'\x03\x0a" + "\x0a8\x03\x09%2\x03\x08+&\x03\x080\x12\x03\x0a)4\x03\x08\x06\x1f\x03\x0b" + "\x1b\x1a\x03\x0a\x1b\x0f\x03\x0b\x1d*\x03\x09\x16$\x03\x090\x11\x03\x08" + "\x11\x08\x03\x0a*(\x03\x0a\x042\x03\x089,\x03\x074'\x03\x07\x0f\x05\x03" + "\x09\x0b\x0a\x03\x07\x1b\x01\x03\x09\x17:\x03\x09.\x0d\x03\x07.\x11\x03" + "\x09+\x15\x03\x080\x13\x03\x0b\x1f\x19\x03\x0a \x11\x03\x0a\x220\x03\x09" + "\x07;\x03\x08\x16\x1c\x03\x07,\x13\x03\x07\x0e/\x03\x06\x221\x03\x0a." + "\x0a\x03\x0a7\x02\x03\x0a\x032\x03\x0a\x1d.\x03\x091\x06\x03\x09\x19:" + "\x03\x08\x02/\x03\x060+\x03\x06\x0f-\x03\x06\x1c\x1f\x03\x06\x1d\x07\x03" + "\x0a,\x11\x03\x09=\x0d\x03\x09\x0b;\x03\x07\x1b/\x03\x0a\x1f:\x03\x09 " + "\x1f\x03\x09.\x10\x03\x094\x0b\x03\x09\x1a1\x03\x08#\x1a\x03\x084\x1d" + "\x03\x08\x01\x1f\x03\x08\x11\x22\x03\x07'8\x03\x07\x1a>\x03\x0757\x03" + "\x06&9\x03\x06+\x11\x03\x0a.\x0b\x03\x0a,>\x03\x0a4#\x03\x08%\x17\x03" + "\x07\x05\x22\x03\x07\x0c\x0b\x03\x0a\x1d+\x03\x0a\x19\x16\x03\x09+\x1f" + "\x03\x09\x08\x0b\x03\x08\x16\x18\x03\x08+\x12\x03\x0b\x1d\x0c\x03\x0a=" + "\x10\x03\x0a\x09\x0d\x03\x0a\x10\x11\x03\x09&0\x03\x08(\x1f\x03\x087\x07" + "\x03\x08\x185\x03\x07'6\x03\x06.\x05\x03\x06=\x04\x03\x06;;\x03\x06\x06," + "\x03\x0b\x18>\x03\x08\x00\x18\x03\x06 \x03\x03\x06<\x00\x03\x09%\x18\x03" + "\x0b\x1c<\x03\x0a%!\x03\x0a\x09\x12\x03\x0a\x16\x02\x03\x090'\x03\x09" + "\x0e=\x03\x08 \x0e\x03\x08>\x03\x03\x074>\x03\x06&?\x03\x06\x19\x09\x03" + "\x06?(\x03\x0a-\x0e\x03\x09:3\x03\x098:\x03\x09\x12\x0b\x03\x09\x1d\x17" + "\x03\x087\x05\x03\x082\x14\x03\x08\x06%\x03\x08\x13\x1f\x03\x06\x06\x0e" + "\x03\x0a\x22<\x03\x09/<\x03\x06>+\x03\x0a'?\x03\x0a\x13\x0c\x03\x09\x10<" + "\x03\x07\x1b=\x03\x0a\x19\x13\x03\x09\x22\x1d\x03\x09\x07\x0d\x03\x08)" + "\x1c\x03\x06=\x1a\x03\x0a/4\x03\x0a7\x11\x03\x0a\x16:\x03\x09?3\x03\x09:" + "/\x03\x09\x05\x0a\x03\x09\x14\x06\x03\x087\x22\x03\x080\x07\x03\x08\x1a" + "\x1f\x03\x07\x04(\x03\x07\x04\x09\x03\x06 %\x03\x06<\x08\x03\x0a+\x14" + "\x03\x09\x1d\x16\x03\x0a70\x03\x08 >\x03\x0857\x03\x070\x0a\x03\x06=\x12" + "\x03\x06\x16%\x03\x06\x1d,\x03\x099#\x03\x09\x10>\x03\x07 \x1e\x03\x08" + "\x0c<\x03\x08\x0b\x18\x03\x08\x15+\x03\x08,:\x03\x08%\x22\x03\x07\x0a$" + "\x03\x0b\x1c=\x03\x07+\x08\x03\x0a/\x05\x03\x0a \x07\x03\x0a\x12'\x03" + "\x09#\x11\x03\x08\x1b\x15\x03\x0a\x06\x01\x03\x09\x1c\x1b\x03\x0922\x03" + "\x07\x14<\x03\x07\x09\x04\x03\x061\x04\x03\x07\x0e\x01\x03\x0a\x13\x18" + "\x03\x0a-\x0c\x03\x0a?\x0d\x03\x0a\x09\x0a\x03\x091&\x03\x0a/\x0b\x03" + "\x08$<\x03\x083\x1d\x03\x08\x0c$\x03\x08\x0d\x07\x03\x08\x0d?\x03\x08" + "\x0e\x14\x03\x065\x0a\x03\x08\x1a#\x03\x08\x16#\x03\x0702\x03\x07\x03" + "\x1a\x03\x06(\x1d\x03\x06+\x1b\x03\x06\x0b\x05\x03\x06\x0b\x17\x03\x06" + "\x0c\x04\x03\x06\x1e\x19\x03\x06+0\x03\x062\x18\x03\x0b\x16\x1e\x03\x0a+" + "\x16\x03\x0a-?\x03\x0a#:\x03\x0a#\x10\x03\x0a%$\x03\x0a>+\x03\x0a01\x03" + "\x0a1\x10\x03\x0a\x099\x03\x0a\x0a\x12\x03\x0a\x19\x1f\x03\x0a\x19\x12" + "\x03\x09*)\x03\x09-\x16\x03\x09.1\x03\x09.2\x03\x09<\x0e\x03\x09> \x03" + "\x093\x12\x03\x09\x0b\x01\x03\x09\x1c2\x03\x09\x11\x1c\x03\x09\x15%\x03" + "\x08,&\x03\x08!\x22\x03\x089(\x03\x08\x0b\x1a\x03\x08\x0d2\x03\x08\x0c" + "\x04\x03\x08\x0c\x06\x03\x08\x0c\x1f\x03\x08\x0c\x0c\x03\x08\x0f\x1f\x03" + "\x08\x0f\x1d\x03\x08\x00\x14\x03\x08\x03\x14\x03\x08\x06\x16\x03\x08\x1e" + "#\x03\x08\x11\x11\x03\x08\x10\x18\x03\x08\x14(\x03\x07)\x1e\x03\x07.1" + "\x03\x07 $\x03\x07 '\x03\x078\x08\x03\x07\x0d0\x03\x07\x0f7\x03\x07\x05#" + "\x03\x07\x05\x1a\x03\x07\x1a7\x03\x07\x1d-\x03\x07\x17\x10\x03\x06)\x1f" + "\x03\x062\x0b\x03\x066\x16\x03\x06\x09\x11\x03\x09(\x1e\x03\x07!5\x03" + "\x0b\x11\x16\x03\x0a/\x04\x03\x0a,\x1a\x03\x0b\x173\x03\x0a,1\x03\x0a/5" + "\x03\x0a\x221\x03\x0a\x22\x0d\x03\x0a?%\x03\x0a<,\x03\x0a?#\x03\x0a>\x19" + "\x03\x0a\x08&\x03\x0a\x0b\x0e\x03\x0a\x0c:\x03\x0a\x0c+\x03\x0a\x03\x22" + "\x03\x0a\x06)\x03\x0a\x11\x10\x03\x0a\x11\x1a\x03\x0a\x17-\x03\x0a\x14(" + "\x03\x09)\x1e\x03\x09/\x09\x03\x09.\x00\x03\x09,\x07\x03\x09/*\x03\x09-9" + "\x03\x09\x228\x03\x09%\x09\x03\x09:\x12\x03\x09;\x1d\x03\x09?\x06\x03" + "\x093%\x03\x096\x05\x03\x096\x08\x03\x097\x02\x03\x09\x07,\x03\x09\x04," + "\x03\x09\x1f\x16\x03\x09\x11\x03\x03\x09\x11\x12\x03\x09\x168\x03\x08*" + "\x05\x03\x08/2\x03\x084:\x03\x08\x22+\x03\x08 0\x03\x08&\x0a\x03\x08;" + "\x10\x03\x08>$\x03\x08>\x18\x03\x0829\x03\x082:\x03\x081,\x03\x081<\x03" + "\x081\x1c\x03\x087#\x03\x087*\x03\x08\x09'\x03\x08\x00\x1d\x03\x08\x05-" + "\x03\x08\x1f4\x03\x08\x1d\x04\x03\x08\x16\x0f\x03\x07*7\x03\x07'!\x03" + "\x07%\x1b\x03\x077\x0c\x03\x07\x0c1\x03\x07\x0c.\x03\x07\x00\x06\x03\x07" + "\x01\x02\x03\x07\x010\x03\x07\x06=\x03\x07\x01\x03\x03\x07\x01\x13\x03" + "\x07\x06\x06\x03\x07\x05\x0a\x03\x07\x1f\x09\x03\x07\x17:\x03\x06*1\x03" + "\x06-\x1d\x03\x06\x223\x03\x062:\x03\x060$\x03\x066\x1e\x03\x064\x12\x03" + "\x0645\x03\x06\x0b\x00\x03\x06\x0b7\x03\x06\x07\x1f\x03\x06\x15\x12\x03" + "\x0c\x05\x0f\x03\x0b+\x0b\x03\x0b+-\x03\x06\x16\x1b\x03\x06\x15\x17\x03" + "\x89\xca\xea\x03\x89\xca\xe8\x03\x0c8\x10\x03\x0c8\x01\x03\x0c8\x0f\x03" + "\x0d8%\x03\x0d8!\x03\x0c8-\x03\x0c8/\x03\x0c8+\x03\x0c87\x03\x0c85\x03" + "\x0c9\x09\x03\x0c9\x0d\x03\x0c9\x0f\x03\x0c9\x0b\x03\xcfu\x0c\x03\xcfu" + "\x0f\x03\xcfu\x0e\x03\xcfu\x09\x03\x0c9\x10\x03\x0d9\x0c\x03\xcf`;\x03" + "\xcf`>\x03\xcf`9\x03\xcf`8\x03\xcf`7\x03\xcf`*\x03\xcf`-\x03\xcf`,\x03" + "\x0d\x1b\x1a\x03\x0d\x1b&\x03\x0c=.\x03\x0c=%\x03\x0c>\x1e\x03\x0c>\x14" + "\x03\x0c?\x06\x03\x0c?\x0b\x03\x0c?\x0c\x03\x0c?\x0d\x03\x0c?\x02\x03" + "\x0c>\x0f\x03\x0c>\x08\x03\x0c>\x09\x03\x0c>,\x03\x0c>\x0c\x03\x0c?\x13" + "\x03\x0c?\x16\x03\x0c?\x15\x03\x0c?\x1c\x03\x0c?\x1f\x03\x0c?\x1d\x03" + "\x0c?\x1a\x03\x0c?\x17\x03\x0c?\x08\x03\x0c?\x09\x03\x0c?\x0e\x03\x0c?" + "\x04\x03\x0c?\x05\x03\x0c" + "\x03\x0c=2\x03\x0c=6\x03\x0c<\x07\x03\x0c<\x05\x03\x0e:!\x03\x0e:#\x03" + "\x0e8\x09\x03\x0e:&\x03\x0e8\x0b\x03\x0e:$\x03\x0e:,\x03\x0e8\x1a\x03" + "\x0e8\x1e\x03\x0e:*\x03\x0e:7\x03\x0e:5\x03\x0e:;\x03\x0e:\x15\x03\x0e:<" + "\x03\x0e:4\x03\x0e:'\x03\x0e:-\x03\x0e:%\x03\x0e:?\x03\x0e:=\x03\x0e:)" + "\x03\x0e:/\x03\xcfs'\x03\x0d=\x0f\x03\x0d+*\x03\x0d99\x03\x0d9;\x03\x0d9" + "?\x03\x0d)\x0d\x03\x0d(%\x02\x01\x18\x02\x01(\x02\x01\x1e\x03\x0f$!\x03" + "\x0f87\x03\x0f4\x0e\x03\x0f5\x1d\x03\x06'\x03\x03\x0f\x08\x18\x03\x0f" + "\x0d\x1b\x03\x0e2=\x03\x0e;\x08\x03\x0e:\x0b\x03\x0e\x06$\x03\x0e\x0d)" + "\x03\x0e\x16\x1f\x03\x0e\x16\x1b\x03\x0d$\x0a\x03\x05,\x1d\x03\x0d. \x03" + "\x0d.#\x03\x0c(/\x03\x09%\x02\x03\x0d90\x03\x0d\x0e4\x03\x0d\x0d\x0f\x03" + "\x0c#\x00\x03\x0c,\x1e\x03\x0c2\x0e\x03\x0c\x01\x17\x03\x0c\x09:\x03\x0e" + "\x173\x03\x0c\x08\x03\x03\x0c\x11\x07\x03\x0c\x10\x18\x03\x0c\x1f\x1c" + "\x03\x0c\x19\x0e\x03\x0c\x1a\x1f\x03\x0f0>\x03\x0b->\x03\x0b<+\x03\x0b8" + "\x13\x03\x0b\x043\x03\x0b\x14\x03\x03\x0b\x16%\x03\x0d\x22&\x03\x0b\x1a" + "\x1a\x03\x0b\x1a\x04\x03\x0a%9\x03\x0a&2\x03\x0a&0\x03\x0a!\x1a\x03\x0a!" + "7\x03\x0a5\x10\x03\x0a=4\x03\x0a?\x0e\x03\x0a>\x10\x03\x0a\x00 \x03\x0a" + "\x0f:\x03\x0a\x0f9\x03\x0a\x0b\x0a\x03\x0a\x17%\x03\x0a\x1b-\x03\x09-" + "\x1a\x03\x09,4\x03\x09.,\x03\x09)\x09\x03\x096!\x03\x091\x1f\x03\x093" + "\x16\x03\x0c+\x1f\x03\x098 \x03\x098=\x03\x0c(\x1a\x03\x0c(\x16\x03\x09" + "\x0a+\x03\x09\x16\x12\x03\x09\x13\x0e\x03\x09\x153\x03\x08)!\x03\x09\x1a" + "\x01\x03\x09\x18\x01\x03\x08%#\x03\x08>\x22\x03\x08\x05%\x03\x08\x02*" + "\x03\x08\x15;\x03\x08\x1b7\x03\x0f\x07\x1d\x03\x0f\x04\x03\x03\x070\x0c" + "\x03\x07;\x0b\x03\x07\x08\x17\x03\x07\x12\x06\x03\x06/-\x03\x0671\x03" + "\x065+\x03\x06>7\x03\x06\x049\x03\x05+\x1e\x03\x05,\x17\x03\x05 \x1d\x03" + "\x05\x22\x05\x03\x050\x1d" // lookup returns the trie value for the first UTF-8 encoding in s and // the width in bytes of this encoding. The size will be 0 if s does not // hold enough bytes to complete the encoding. len(s) must be greater than 0. func (t *idnaTrie) lookup(s []byte) (v uint16, sz int) { c0 := s[0] switch { case c0 < 0x80: // is ASCII return idnaValues[c0], 1 case c0 < 0xC2: return 0, 1 // Illegal UTF-8: not a starter, not ASCII. case c0 < 0xE0: // 2-byte UTF-8 if len(s) < 2 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c1), 2 case c0 < 0xF0: // 3-byte UTF-8 if len(s) < 3 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } o := uint32(i)<<6 + uint32(c1) i = idnaIndex[o] c2 := s[2] if c2 < 0x80 || 0xC0 <= c2 { return 0, 2 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c2), 3 case c0 < 0xF8: // 4-byte UTF-8 if len(s) < 4 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } o := uint32(i)<<6 + uint32(c1) i = idnaIndex[o] c2 := s[2] if c2 < 0x80 || 0xC0 <= c2 { return 0, 2 // Illegal UTF-8: not a continuation byte. } o = uint32(i)<<6 + uint32(c2) i = idnaIndex[o] c3 := s[3] if c3 < 0x80 || 0xC0 <= c3 { return 0, 3 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c3), 4 } // Illegal rune return 0, 1 } // lookupUnsafe returns the trie value for the first UTF-8 encoding in s. // s must start with a full and valid UTF-8 encoded rune. func (t *idnaTrie) lookupUnsafe(s []byte) uint16 { c0 := s[0] if c0 < 0x80 { // is ASCII return idnaValues[c0] } i := idnaIndex[c0] if c0 < 0xE0 { // 2-byte UTF-8 return t.lookupValue(uint32(i), s[1]) } i = idnaIndex[uint32(i)<<6+uint32(s[1])] if c0 < 0xF0 { // 3-byte UTF-8 return t.lookupValue(uint32(i), s[2]) } i = idnaIndex[uint32(i)<<6+uint32(s[2])] if c0 < 0xF8 { // 4-byte UTF-8 return t.lookupValue(uint32(i), s[3]) } return 0 } // lookupString returns the trie value for the first UTF-8 encoding in s and // the width in bytes of this encoding. The size will be 0 if s does not // hold enough bytes to complete the encoding. len(s) must be greater than 0. func (t *idnaTrie) lookupString(s string) (v uint16, sz int) { c0 := s[0] switch { case c0 < 0x80: // is ASCII return idnaValues[c0], 1 case c0 < 0xC2: return 0, 1 // Illegal UTF-8: not a starter, not ASCII. case c0 < 0xE0: // 2-byte UTF-8 if len(s) < 2 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c1), 2 case c0 < 0xF0: // 3-byte UTF-8 if len(s) < 3 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } o := uint32(i)<<6 + uint32(c1) i = idnaIndex[o] c2 := s[2] if c2 < 0x80 || 0xC0 <= c2 { return 0, 2 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c2), 3 case c0 < 0xF8: // 4-byte UTF-8 if len(s) < 4 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } o := uint32(i)<<6 + uint32(c1) i = idnaIndex[o] c2 := s[2] if c2 < 0x80 || 0xC0 <= c2 { return 0, 2 // Illegal UTF-8: not a continuation byte. } o = uint32(i)<<6 + uint32(c2) i = idnaIndex[o] c3 := s[3] if c3 < 0x80 || 0xC0 <= c3 { return 0, 3 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c3), 4 } // Illegal rune return 0, 1 } // lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. // s must start with a full and valid UTF-8 encoded rune. func (t *idnaTrie) lookupStringUnsafe(s string) uint16 { c0 := s[0] if c0 < 0x80 { // is ASCII return idnaValues[c0] } i := idnaIndex[c0] if c0 < 0xE0 { // 2-byte UTF-8 return t.lookupValue(uint32(i), s[1]) } i = idnaIndex[uint32(i)<<6+uint32(s[1])] if c0 < 0xF0 { // 3-byte UTF-8 return t.lookupValue(uint32(i), s[2]) } i = idnaIndex[uint32(i)<<6+uint32(s[2])] if c0 < 0xF8 { // 4-byte UTF-8 return t.lookupValue(uint32(i), s[3]) } return 0 } // idnaTrie. Total size: 29404 bytes (28.71 KiB). Checksum: 848c45acb5f7991c. type idnaTrie struct{} func newIdnaTrie(i int) *idnaTrie { return &idnaTrie{} } // lookupValue determines the type of block n and looks up the value for b. func (t *idnaTrie) lookupValue(n uint32, b byte) uint16 { switch { case n < 125: return uint16(idnaValues[n<<6+uint32(b)]) default: n -= 125 return uint16(idnaSparse.lookup(n, b)) } } // idnaValues: 127 blocks, 8128 entries, 16256 bytes // The third block is the zero block. var idnaValues = [8128]uint16{ // Block 0x0, offset 0x0 0x00: 0x0080, 0x01: 0x0080, 0x02: 0x0080, 0x03: 0x0080, 0x04: 0x0080, 0x05: 0x0080, 0x06: 0x0080, 0x07: 0x0080, 0x08: 0x0080, 0x09: 0x0080, 0x0a: 0x0080, 0x0b: 0x0080, 0x0c: 0x0080, 0x0d: 0x0080, 0x0e: 0x0080, 0x0f: 0x0080, 0x10: 0x0080, 0x11: 0x0080, 0x12: 0x0080, 0x13: 0x0080, 0x14: 0x0080, 0x15: 0x0080, 0x16: 0x0080, 0x17: 0x0080, 0x18: 0x0080, 0x19: 0x0080, 0x1a: 0x0080, 0x1b: 0x0080, 0x1c: 0x0080, 0x1d: 0x0080, 0x1e: 0x0080, 0x1f: 0x0080, 0x20: 0x0080, 0x21: 0x0080, 0x22: 0x0080, 0x23: 0x0080, 0x24: 0x0080, 0x25: 0x0080, 0x26: 0x0080, 0x27: 0x0080, 0x28: 0x0080, 0x29: 0x0080, 0x2a: 0x0080, 0x2b: 0x0080, 0x2c: 0x0080, 0x2d: 0x0008, 0x2e: 0x0008, 0x2f: 0x0080, 0x30: 0x0008, 0x31: 0x0008, 0x32: 0x0008, 0x33: 0x0008, 0x34: 0x0008, 0x35: 0x0008, 0x36: 0x0008, 0x37: 0x0008, 0x38: 0x0008, 0x39: 0x0008, 0x3a: 0x0080, 0x3b: 0x0080, 0x3c: 0x0080, 0x3d: 0x0080, 0x3e: 0x0080, 0x3f: 0x0080, // Block 0x1, offset 0x40 0x40: 0x0080, 0x41: 0xe105, 0x42: 0xe105, 0x43: 0xe105, 0x44: 0xe105, 0x45: 0xe105, 0x46: 0xe105, 0x47: 0xe105, 0x48: 0xe105, 0x49: 0xe105, 0x4a: 0xe105, 0x4b: 0xe105, 0x4c: 0xe105, 0x4d: 0xe105, 0x4e: 0xe105, 0x4f: 0xe105, 0x50: 0xe105, 0x51: 0xe105, 0x52: 0xe105, 0x53: 0xe105, 0x54: 0xe105, 0x55: 0xe105, 0x56: 0xe105, 0x57: 0xe105, 0x58: 0xe105, 0x59: 0xe105, 0x5a: 0xe105, 0x5b: 0x0080, 0x5c: 0x0080, 0x5d: 0x0080, 0x5e: 0x0080, 0x5f: 0x0080, 0x60: 0x0080, 0x61: 0x0008, 0x62: 0x0008, 0x63: 0x0008, 0x64: 0x0008, 0x65: 0x0008, 0x66: 0x0008, 0x67: 0x0008, 0x68: 0x0008, 0x69: 0x0008, 0x6a: 0x0008, 0x6b: 0x0008, 0x6c: 0x0008, 0x6d: 0x0008, 0x6e: 0x0008, 0x6f: 0x0008, 0x70: 0x0008, 0x71: 0x0008, 0x72: 0x0008, 0x73: 0x0008, 0x74: 0x0008, 0x75: 0x0008, 0x76: 0x0008, 0x77: 0x0008, 0x78: 0x0008, 0x79: 0x0008, 0x7a: 0x0008, 0x7b: 0x0080, 0x7c: 0x0080, 0x7d: 0x0080, 0x7e: 0x0080, 0x7f: 0x0080, // Block 0x2, offset 0x80 // Block 0x3, offset 0xc0 0xc0: 0x0040, 0xc1: 0x0040, 0xc2: 0x0040, 0xc3: 0x0040, 0xc4: 0x0040, 0xc5: 0x0040, 0xc6: 0x0040, 0xc7: 0x0040, 0xc8: 0x0040, 0xc9: 0x0040, 0xca: 0x0040, 0xcb: 0x0040, 0xcc: 0x0040, 0xcd: 0x0040, 0xce: 0x0040, 0xcf: 0x0040, 0xd0: 0x0040, 0xd1: 0x0040, 0xd2: 0x0040, 0xd3: 0x0040, 0xd4: 0x0040, 0xd5: 0x0040, 0xd6: 0x0040, 0xd7: 0x0040, 0xd8: 0x0040, 0xd9: 0x0040, 0xda: 0x0040, 0xdb: 0x0040, 0xdc: 0x0040, 0xdd: 0x0040, 0xde: 0x0040, 0xdf: 0x0040, 0xe0: 0x000a, 0xe1: 0x0018, 0xe2: 0x0018, 0xe3: 0x0018, 0xe4: 0x0018, 0xe5: 0x0018, 0xe6: 0x0018, 0xe7: 0x0018, 0xe8: 0x001a, 0xe9: 0x0018, 0xea: 0x0039, 0xeb: 0x0018, 0xec: 0x0018, 0xed: 0x03c0, 0xee: 0x0018, 0xef: 0x004a, 0xf0: 0x0018, 0xf1: 0x0018, 0xf2: 0x0069, 0xf3: 0x0079, 0xf4: 0x008a, 0xf5: 0x0005, 0xf6: 0x0018, 0xf7: 0x0008, 0xf8: 0x00aa, 0xf9: 0x00c9, 0xfa: 0x00d9, 0xfb: 0x0018, 0xfc: 0x00e9, 0xfd: 0x0119, 0xfe: 0x0149, 0xff: 0x0018, // Block 0x4, offset 0x100 0x100: 0xe00d, 0x101: 0x0008, 0x102: 0xe00d, 0x103: 0x0008, 0x104: 0xe00d, 0x105: 0x0008, 0x106: 0xe00d, 0x107: 0x0008, 0x108: 0xe00d, 0x109: 0x0008, 0x10a: 0xe00d, 0x10b: 0x0008, 0x10c: 0xe00d, 0x10d: 0x0008, 0x10e: 0xe00d, 0x10f: 0x0008, 0x110: 0xe00d, 0x111: 0x0008, 0x112: 0xe00d, 0x113: 0x0008, 0x114: 0xe00d, 0x115: 0x0008, 0x116: 0xe00d, 0x117: 0x0008, 0x118: 0xe00d, 0x119: 0x0008, 0x11a: 0xe00d, 0x11b: 0x0008, 0x11c: 0xe00d, 0x11d: 0x0008, 0x11e: 0xe00d, 0x11f: 0x0008, 0x120: 0xe00d, 0x121: 0x0008, 0x122: 0xe00d, 0x123: 0x0008, 0x124: 0xe00d, 0x125: 0x0008, 0x126: 0xe00d, 0x127: 0x0008, 0x128: 0xe00d, 0x129: 0x0008, 0x12a: 0xe00d, 0x12b: 0x0008, 0x12c: 0xe00d, 0x12d: 0x0008, 0x12e: 0xe00d, 0x12f: 0x0008, 0x130: 0x0179, 0x131: 0x0008, 0x132: 0x0035, 0x133: 0x004d, 0x134: 0xe00d, 0x135: 0x0008, 0x136: 0xe00d, 0x137: 0x0008, 0x138: 0x0008, 0x139: 0xe01d, 0x13a: 0x0008, 0x13b: 0xe03d, 0x13c: 0x0008, 0x13d: 0xe01d, 0x13e: 0x0008, 0x13f: 0x0199, // Block 0x5, offset 0x140 0x140: 0x0199, 0x141: 0xe01d, 0x142: 0x0008, 0x143: 0xe03d, 0x144: 0x0008, 0x145: 0xe01d, 0x146: 0x0008, 0x147: 0xe07d, 0x148: 0x0008, 0x149: 0x01b9, 0x14a: 0xe00d, 0x14b: 0x0008, 0x14c: 0xe00d, 0x14d: 0x0008, 0x14e: 0xe00d, 0x14f: 0x0008, 0x150: 0xe00d, 0x151: 0x0008, 0x152: 0xe00d, 0x153: 0x0008, 0x154: 0xe00d, 0x155: 0x0008, 0x156: 0xe00d, 0x157: 0x0008, 0x158: 0xe00d, 0x159: 0x0008, 0x15a: 0xe00d, 0x15b: 0x0008, 0x15c: 0xe00d, 0x15d: 0x0008, 0x15e: 0xe00d, 0x15f: 0x0008, 0x160: 0xe00d, 0x161: 0x0008, 0x162: 0xe00d, 0x163: 0x0008, 0x164: 0xe00d, 0x165: 0x0008, 0x166: 0xe00d, 0x167: 0x0008, 0x168: 0xe00d, 0x169: 0x0008, 0x16a: 0xe00d, 0x16b: 0x0008, 0x16c: 0xe00d, 0x16d: 0x0008, 0x16e: 0xe00d, 0x16f: 0x0008, 0x170: 0xe00d, 0x171: 0x0008, 0x172: 0xe00d, 0x173: 0x0008, 0x174: 0xe00d, 0x175: 0x0008, 0x176: 0xe00d, 0x177: 0x0008, 0x178: 0x0065, 0x179: 0xe01d, 0x17a: 0x0008, 0x17b: 0xe03d, 0x17c: 0x0008, 0x17d: 0xe01d, 0x17e: 0x0008, 0x17f: 0x01d9, // Block 0x6, offset 0x180 0x180: 0x0008, 0x181: 0x007d, 0x182: 0xe00d, 0x183: 0x0008, 0x184: 0xe00d, 0x185: 0x0008, 0x186: 0x007d, 0x187: 0xe07d, 0x188: 0x0008, 0x189: 0x0095, 0x18a: 0x00ad, 0x18b: 0xe03d, 0x18c: 0x0008, 0x18d: 0x0008, 0x18e: 0x00c5, 0x18f: 0x00dd, 0x190: 0x00f5, 0x191: 0xe01d, 0x192: 0x0008, 0x193: 0x010d, 0x194: 0x0125, 0x195: 0x0008, 0x196: 0x013d, 0x197: 0x013d, 0x198: 0xe00d, 0x199: 0x0008, 0x19a: 0x0008, 0x19b: 0x0008, 0x19c: 0x010d, 0x19d: 0x0155, 0x19e: 0x0008, 0x19f: 0x016d, 0x1a0: 0xe00d, 0x1a1: 0x0008, 0x1a2: 0xe00d, 0x1a3: 0x0008, 0x1a4: 0xe00d, 0x1a5: 0x0008, 0x1a6: 0x0185, 0x1a7: 0xe07d, 0x1a8: 0x0008, 0x1a9: 0x019d, 0x1aa: 0x0008, 0x1ab: 0x0008, 0x1ac: 0xe00d, 0x1ad: 0x0008, 0x1ae: 0x0185, 0x1af: 0xe0fd, 0x1b0: 0x0008, 0x1b1: 0x01b5, 0x1b2: 0x01cd, 0x1b3: 0xe03d, 0x1b4: 0x0008, 0x1b5: 0xe01d, 0x1b6: 0x0008, 0x1b7: 0x01e5, 0x1b8: 0xe00d, 0x1b9: 0x0008, 0x1ba: 0x0008, 0x1bb: 0x0008, 0x1bc: 0xe00d, 0x1bd: 0x0008, 0x1be: 0x0008, 0x1bf: 0x0008, // Block 0x7, offset 0x1c0 0x1c0: 0x0008, 0x1c1: 0x0008, 0x1c2: 0x0008, 0x1c3: 0x0008, 0x1c4: 0x01e9, 0x1c5: 0x01e9, 0x1c6: 0x01e9, 0x1c7: 0x01fd, 0x1c8: 0x0215, 0x1c9: 0x022d, 0x1ca: 0x0245, 0x1cb: 0x025d, 0x1cc: 0x0275, 0x1cd: 0xe01d, 0x1ce: 0x0008, 0x1cf: 0xe0fd, 0x1d0: 0x0008, 0x1d1: 0xe01d, 0x1d2: 0x0008, 0x1d3: 0xe03d, 0x1d4: 0x0008, 0x1d5: 0xe01d, 0x1d6: 0x0008, 0x1d7: 0xe07d, 0x1d8: 0x0008, 0x1d9: 0xe01d, 0x1da: 0x0008, 0x1db: 0xe03d, 0x1dc: 0x0008, 0x1dd: 0x0008, 0x1de: 0xe00d, 0x1df: 0x0008, 0x1e0: 0xe00d, 0x1e1: 0x0008, 0x1e2: 0xe00d, 0x1e3: 0x0008, 0x1e4: 0xe00d, 0x1e5: 0x0008, 0x1e6: 0xe00d, 0x1e7: 0x0008, 0x1e8: 0xe00d, 0x1e9: 0x0008, 0x1ea: 0xe00d, 0x1eb: 0x0008, 0x1ec: 0xe00d, 0x1ed: 0x0008, 0x1ee: 0xe00d, 0x1ef: 0x0008, 0x1f0: 0x0008, 0x1f1: 0x028d, 0x1f2: 0x02a5, 0x1f3: 0x02bd, 0x1f4: 0xe00d, 0x1f5: 0x0008, 0x1f6: 0x02d5, 0x1f7: 0x02ed, 0x1f8: 0xe00d, 0x1f9: 0x0008, 0x1fa: 0xe00d, 0x1fb: 0x0008, 0x1fc: 0xe00d, 0x1fd: 0x0008, 0x1fe: 0xe00d, 0x1ff: 0x0008, // Block 0x8, offset 0x200 0x200: 0xe00d, 0x201: 0x0008, 0x202: 0xe00d, 0x203: 0x0008, 0x204: 0xe00d, 0x205: 0x0008, 0x206: 0xe00d, 0x207: 0x0008, 0x208: 0xe00d, 0x209: 0x0008, 0x20a: 0xe00d, 0x20b: 0x0008, 0x20c: 0xe00d, 0x20d: 0x0008, 0x20e: 0xe00d, 0x20f: 0x0008, 0x210: 0xe00d, 0x211: 0x0008, 0x212: 0xe00d, 0x213: 0x0008, 0x214: 0xe00d, 0x215: 0x0008, 0x216: 0xe00d, 0x217: 0x0008, 0x218: 0xe00d, 0x219: 0x0008, 0x21a: 0xe00d, 0x21b: 0x0008, 0x21c: 0xe00d, 0x21d: 0x0008, 0x21e: 0xe00d, 0x21f: 0x0008, 0x220: 0x0305, 0x221: 0x0008, 0x222: 0xe00d, 0x223: 0x0008, 0x224: 0xe00d, 0x225: 0x0008, 0x226: 0xe00d, 0x227: 0x0008, 0x228: 0xe00d, 0x229: 0x0008, 0x22a: 0xe00d, 0x22b: 0x0008, 0x22c: 0xe00d, 0x22d: 0x0008, 0x22e: 0xe00d, 0x22f: 0x0008, 0x230: 0xe00d, 0x231: 0x0008, 0x232: 0xe00d, 0x233: 0x0008, 0x234: 0x0008, 0x235: 0x0008, 0x236: 0x0008, 0x237: 0x0008, 0x238: 0x0008, 0x239: 0x0008, 0x23a: 0x0209, 0x23b: 0xe03d, 0x23c: 0x0008, 0x23d: 0x031d, 0x23e: 0x0229, 0x23f: 0x0008, // Block 0x9, offset 0x240 0x240: 0x0008, 0x241: 0x0008, 0x242: 0x0018, 0x243: 0x0018, 0x244: 0x0018, 0x245: 0x0018, 0x246: 0x0008, 0x247: 0x0008, 0x248: 0x0008, 0x249: 0x0008, 0x24a: 0x0008, 0x24b: 0x0008, 0x24c: 0x0008, 0x24d: 0x0008, 0x24e: 0x0008, 0x24f: 0x0008, 0x250: 0x0008, 0x251: 0x0008, 0x252: 0x0018, 0x253: 0x0018, 0x254: 0x0018, 0x255: 0x0018, 0x256: 0x0018, 0x257: 0x0018, 0x258: 0x029a, 0x259: 0x02ba, 0x25a: 0x02da, 0x25b: 0x02fa, 0x25c: 0x031a, 0x25d: 0x033a, 0x25e: 0x0018, 0x25f: 0x0018, 0x260: 0x03ad, 0x261: 0x0359, 0x262: 0x01d9, 0x263: 0x0369, 0x264: 0x03c5, 0x265: 0x0018, 0x266: 0x0018, 0x267: 0x0018, 0x268: 0x0018, 0x269: 0x0018, 0x26a: 0x0018, 0x26b: 0x0018, 0x26c: 0x0008, 0x26d: 0x0018, 0x26e: 0x0008, 0x26f: 0x0018, 0x270: 0x0018, 0x271: 0x0018, 0x272: 0x0018, 0x273: 0x0018, 0x274: 0x0018, 0x275: 0x0018, 0x276: 0x0018, 0x277: 0x0018, 0x278: 0x0018, 0x279: 0x0018, 0x27a: 0x0018, 0x27b: 0x0018, 0x27c: 0x0018, 0x27d: 0x0018, 0x27e: 0x0018, 0x27f: 0x0018, // Block 0xa, offset 0x280 0x280: 0x03dd, 0x281: 0x03dd, 0x282: 0x3308, 0x283: 0x03f5, 0x284: 0x0379, 0x285: 0x040d, 0x286: 0x3308, 0x287: 0x3308, 0x288: 0x3308, 0x289: 0x3308, 0x28a: 0x3308, 0x28b: 0x3308, 0x28c: 0x3308, 0x28d: 0x3308, 0x28e: 0x3308, 0x28f: 0x33c0, 0x290: 0x3308, 0x291: 0x3308, 0x292: 0x3308, 0x293: 0x3308, 0x294: 0x3308, 0x295: 0x3308, 0x296: 0x3308, 0x297: 0x3308, 0x298: 0x3308, 0x299: 0x3308, 0x29a: 0x3308, 0x29b: 0x3308, 0x29c: 0x3308, 0x29d: 0x3308, 0x29e: 0x3308, 0x29f: 0x3308, 0x2a0: 0x3308, 0x2a1: 0x3308, 0x2a2: 0x3308, 0x2a3: 0x3308, 0x2a4: 0x3308, 0x2a5: 0x3308, 0x2a6: 0x3308, 0x2a7: 0x3308, 0x2a8: 0x3308, 0x2a9: 0x3308, 0x2aa: 0x3308, 0x2ab: 0x3308, 0x2ac: 0x3308, 0x2ad: 0x3308, 0x2ae: 0x3308, 0x2af: 0x3308, 0x2b0: 0xe00d, 0x2b1: 0x0008, 0x2b2: 0xe00d, 0x2b3: 0x0008, 0x2b4: 0x0425, 0x2b5: 0x0008, 0x2b6: 0xe00d, 0x2b7: 0x0008, 0x2b8: 0x0040, 0x2b9: 0x0040, 0x2ba: 0x03a2, 0x2bb: 0x0008, 0x2bc: 0x0008, 0x2bd: 0x0008, 0x2be: 0x03c2, 0x2bf: 0x043d, // Block 0xb, offset 0x2c0 0x2c0: 0x0040, 0x2c1: 0x0040, 0x2c2: 0x0040, 0x2c3: 0x0040, 0x2c4: 0x008a, 0x2c5: 0x03d2, 0x2c6: 0xe155, 0x2c7: 0x0455, 0x2c8: 0xe12d, 0x2c9: 0xe13d, 0x2ca: 0xe12d, 0x2cb: 0x0040, 0x2cc: 0x03dd, 0x2cd: 0x0040, 0x2ce: 0x046d, 0x2cf: 0x0485, 0x2d0: 0x0008, 0x2d1: 0xe105, 0x2d2: 0xe105, 0x2d3: 0xe105, 0x2d4: 0xe105, 0x2d5: 0xe105, 0x2d6: 0xe105, 0x2d7: 0xe105, 0x2d8: 0xe105, 0x2d9: 0xe105, 0x2da: 0xe105, 0x2db: 0xe105, 0x2dc: 0xe105, 0x2dd: 0xe105, 0x2de: 0xe105, 0x2df: 0xe105, 0x2e0: 0x049d, 0x2e1: 0x049d, 0x2e2: 0x0040, 0x2e3: 0x049d, 0x2e4: 0x049d, 0x2e5: 0x049d, 0x2e6: 0x049d, 0x2e7: 0x049d, 0x2e8: 0x049d, 0x2e9: 0x049d, 0x2ea: 0x049d, 0x2eb: 0x049d, 0x2ec: 0x0008, 0x2ed: 0x0008, 0x2ee: 0x0008, 0x2ef: 0x0008, 0x2f0: 0x0008, 0x2f1: 0x0008, 0x2f2: 0x0008, 0x2f3: 0x0008, 0x2f4: 0x0008, 0x2f5: 0x0008, 0x2f6: 0x0008, 0x2f7: 0x0008, 0x2f8: 0x0008, 0x2f9: 0x0008, 0x2fa: 0x0008, 0x2fb: 0x0008, 0x2fc: 0x0008, 0x2fd: 0x0008, 0x2fe: 0x0008, 0x2ff: 0x0008, // Block 0xc, offset 0x300 0x300: 0x0008, 0x301: 0x0008, 0x302: 0xe00f, 0x303: 0x0008, 0x304: 0x0008, 0x305: 0x0008, 0x306: 0x0008, 0x307: 0x0008, 0x308: 0x0008, 0x309: 0x0008, 0x30a: 0x0008, 0x30b: 0x0008, 0x30c: 0x0008, 0x30d: 0x0008, 0x30e: 0x0008, 0x30f: 0xe0c5, 0x310: 0x04b5, 0x311: 0x04cd, 0x312: 0xe0bd, 0x313: 0xe0f5, 0x314: 0xe0fd, 0x315: 0xe09d, 0x316: 0xe0b5, 0x317: 0x0008, 0x318: 0xe00d, 0x319: 0x0008, 0x31a: 0xe00d, 0x31b: 0x0008, 0x31c: 0xe00d, 0x31d: 0x0008, 0x31e: 0xe00d, 0x31f: 0x0008, 0x320: 0xe00d, 0x321: 0x0008, 0x322: 0xe00d, 0x323: 0x0008, 0x324: 0xe00d, 0x325: 0x0008, 0x326: 0xe00d, 0x327: 0x0008, 0x328: 0xe00d, 0x329: 0x0008, 0x32a: 0xe00d, 0x32b: 0x0008, 0x32c: 0xe00d, 0x32d: 0x0008, 0x32e: 0xe00d, 0x32f: 0x0008, 0x330: 0x04e5, 0x331: 0xe185, 0x332: 0xe18d, 0x333: 0x0008, 0x334: 0x04fd, 0x335: 0x03dd, 0x336: 0x0018, 0x337: 0xe07d, 0x338: 0x0008, 0x339: 0xe1d5, 0x33a: 0xe00d, 0x33b: 0x0008, 0x33c: 0x0008, 0x33d: 0x0515, 0x33e: 0x052d, 0x33f: 0x052d, // Block 0xd, offset 0x340 0x340: 0x0008, 0x341: 0x0008, 0x342: 0x0008, 0x343: 0x0008, 0x344: 0x0008, 0x345: 0x0008, 0x346: 0x0008, 0x347: 0x0008, 0x348: 0x0008, 0x349: 0x0008, 0x34a: 0x0008, 0x34b: 0x0008, 0x34c: 0x0008, 0x34d: 0x0008, 0x34e: 0x0008, 0x34f: 0x0008, 0x350: 0x0008, 0x351: 0x0008, 0x352: 0x0008, 0x353: 0x0008, 0x354: 0x0008, 0x355: 0x0008, 0x356: 0x0008, 0x357: 0x0008, 0x358: 0x0008, 0x359: 0x0008, 0x35a: 0x0008, 0x35b: 0x0008, 0x35c: 0x0008, 0x35d: 0x0008, 0x35e: 0x0008, 0x35f: 0x0008, 0x360: 0xe00d, 0x361: 0x0008, 0x362: 0xe00d, 0x363: 0x0008, 0x364: 0xe00d, 0x365: 0x0008, 0x366: 0xe00d, 0x367: 0x0008, 0x368: 0xe00d, 0x369: 0x0008, 0x36a: 0xe00d, 0x36b: 0x0008, 0x36c: 0xe00d, 0x36d: 0x0008, 0x36e: 0xe00d, 0x36f: 0x0008, 0x370: 0xe00d, 0x371: 0x0008, 0x372: 0xe00d, 0x373: 0x0008, 0x374: 0xe00d, 0x375: 0x0008, 0x376: 0xe00d, 0x377: 0x0008, 0x378: 0xe00d, 0x379: 0x0008, 0x37a: 0xe00d, 0x37b: 0x0008, 0x37c: 0xe00d, 0x37d: 0x0008, 0x37e: 0xe00d, 0x37f: 0x0008, // Block 0xe, offset 0x380 0x380: 0xe00d, 0x381: 0x0008, 0x382: 0x0018, 0x383: 0x3308, 0x384: 0x3308, 0x385: 0x3308, 0x386: 0x3308, 0x387: 0x3308, 0x388: 0x3318, 0x389: 0x3318, 0x38a: 0xe00d, 0x38b: 0x0008, 0x38c: 0xe00d, 0x38d: 0x0008, 0x38e: 0xe00d, 0x38f: 0x0008, 0x390: 0xe00d, 0x391: 0x0008, 0x392: 0xe00d, 0x393: 0x0008, 0x394: 0xe00d, 0x395: 0x0008, 0x396: 0xe00d, 0x397: 0x0008, 0x398: 0xe00d, 0x399: 0x0008, 0x39a: 0xe00d, 0x39b: 0x0008, 0x39c: 0xe00d, 0x39d: 0x0008, 0x39e: 0xe00d, 0x39f: 0x0008, 0x3a0: 0xe00d, 0x3a1: 0x0008, 0x3a2: 0xe00d, 0x3a3: 0x0008, 0x3a4: 0xe00d, 0x3a5: 0x0008, 0x3a6: 0xe00d, 0x3a7: 0x0008, 0x3a8: 0xe00d, 0x3a9: 0x0008, 0x3aa: 0xe00d, 0x3ab: 0x0008, 0x3ac: 0xe00d, 0x3ad: 0x0008, 0x3ae: 0xe00d, 0x3af: 0x0008, 0x3b0: 0xe00d, 0x3b1: 0x0008, 0x3b2: 0xe00d, 0x3b3: 0x0008, 0x3b4: 0xe00d, 0x3b5: 0x0008, 0x3b6: 0xe00d, 0x3b7: 0x0008, 0x3b8: 0xe00d, 0x3b9: 0x0008, 0x3ba: 0xe00d, 0x3bb: 0x0008, 0x3bc: 0xe00d, 0x3bd: 0x0008, 0x3be: 0xe00d, 0x3bf: 0x0008, // Block 0xf, offset 0x3c0 0x3c0: 0x0040, 0x3c1: 0xe01d, 0x3c2: 0x0008, 0x3c3: 0xe03d, 0x3c4: 0x0008, 0x3c5: 0xe01d, 0x3c6: 0x0008, 0x3c7: 0xe07d, 0x3c8: 0x0008, 0x3c9: 0xe01d, 0x3ca: 0x0008, 0x3cb: 0xe03d, 0x3cc: 0x0008, 0x3cd: 0xe01d, 0x3ce: 0x0008, 0x3cf: 0x0008, 0x3d0: 0xe00d, 0x3d1: 0x0008, 0x3d2: 0xe00d, 0x3d3: 0x0008, 0x3d4: 0xe00d, 0x3d5: 0x0008, 0x3d6: 0xe00d, 0x3d7: 0x0008, 0x3d8: 0xe00d, 0x3d9: 0x0008, 0x3da: 0xe00d, 0x3db: 0x0008, 0x3dc: 0xe00d, 0x3dd: 0x0008, 0x3de: 0xe00d, 0x3df: 0x0008, 0x3e0: 0xe00d, 0x3e1: 0x0008, 0x3e2: 0xe00d, 0x3e3: 0x0008, 0x3e4: 0xe00d, 0x3e5: 0x0008, 0x3e6: 0xe00d, 0x3e7: 0x0008, 0x3e8: 0xe00d, 0x3e9: 0x0008, 0x3ea: 0xe00d, 0x3eb: 0x0008, 0x3ec: 0xe00d, 0x3ed: 0x0008, 0x3ee: 0xe00d, 0x3ef: 0x0008, 0x3f0: 0xe00d, 0x3f1: 0x0008, 0x3f2: 0xe00d, 0x3f3: 0x0008, 0x3f4: 0xe00d, 0x3f5: 0x0008, 0x3f6: 0xe00d, 0x3f7: 0x0008, 0x3f8: 0xe00d, 0x3f9: 0x0008, 0x3fa: 0xe00d, 0x3fb: 0x0008, 0x3fc: 0xe00d, 0x3fd: 0x0008, 0x3fe: 0xe00d, 0x3ff: 0x0008, // Block 0x10, offset 0x400 0x400: 0xe00d, 0x401: 0x0008, 0x402: 0xe00d, 0x403: 0x0008, 0x404: 0xe00d, 0x405: 0x0008, 0x406: 0xe00d, 0x407: 0x0008, 0x408: 0xe00d, 0x409: 0x0008, 0x40a: 0xe00d, 0x40b: 0x0008, 0x40c: 0xe00d, 0x40d: 0x0008, 0x40e: 0xe00d, 0x40f: 0x0008, 0x410: 0xe00d, 0x411: 0x0008, 0x412: 0xe00d, 0x413: 0x0008, 0x414: 0xe00d, 0x415: 0x0008, 0x416: 0xe00d, 0x417: 0x0008, 0x418: 0xe00d, 0x419: 0x0008, 0x41a: 0xe00d, 0x41b: 0x0008, 0x41c: 0xe00d, 0x41d: 0x0008, 0x41e: 0xe00d, 0x41f: 0x0008, 0x420: 0xe00d, 0x421: 0x0008, 0x422: 0xe00d, 0x423: 0x0008, 0x424: 0xe00d, 0x425: 0x0008, 0x426: 0xe00d, 0x427: 0x0008, 0x428: 0xe00d, 0x429: 0x0008, 0x42a: 0xe00d, 0x42b: 0x0008, 0x42c: 0xe00d, 0x42d: 0x0008, 0x42e: 0xe00d, 0x42f: 0x0008, 0x430: 0x0040, 0x431: 0x03f5, 0x432: 0x03f5, 0x433: 0x03f5, 0x434: 0x03f5, 0x435: 0x03f5, 0x436: 0x03f5, 0x437: 0x03f5, 0x438: 0x03f5, 0x439: 0x03f5, 0x43a: 0x03f5, 0x43b: 0x03f5, 0x43c: 0x03f5, 0x43d: 0x03f5, 0x43e: 0x03f5, 0x43f: 0x03f5, // Block 0x11, offset 0x440 0x440: 0x0840, 0x441: 0x0840, 0x442: 0x0840, 0x443: 0x0840, 0x444: 0x0840, 0x445: 0x0840, 0x446: 0x0018, 0x447: 0x0018, 0x448: 0x0818, 0x449: 0x0018, 0x44a: 0x0018, 0x44b: 0x0818, 0x44c: 0x0018, 0x44d: 0x0818, 0x44e: 0x0018, 0x44f: 0x0018, 0x450: 0x3308, 0x451: 0x3308, 0x452: 0x3308, 0x453: 0x3308, 0x454: 0x3308, 0x455: 0x3308, 0x456: 0x3308, 0x457: 0x3308, 0x458: 0x3308, 0x459: 0x3308, 0x45a: 0x3308, 0x45b: 0x0818, 0x45c: 0x0b40, 0x45d: 0x0040, 0x45e: 0x0818, 0x45f: 0x0818, 0x460: 0x0a08, 0x461: 0x0808, 0x462: 0x0c08, 0x463: 0x0c08, 0x464: 0x0c08, 0x465: 0x0c08, 0x466: 0x0a08, 0x467: 0x0c08, 0x468: 0x0a08, 0x469: 0x0c08, 0x46a: 0x0a08, 0x46b: 0x0a08, 0x46c: 0x0a08, 0x46d: 0x0a08, 0x46e: 0x0a08, 0x46f: 0x0c08, 0x470: 0x0c08, 0x471: 0x0c08, 0x472: 0x0c08, 0x473: 0x0a08, 0x474: 0x0a08, 0x475: 0x0a08, 0x476: 0x0a08, 0x477: 0x0a08, 0x478: 0x0a08, 0x479: 0x0a08, 0x47a: 0x0a08, 0x47b: 0x0a08, 0x47c: 0x0a08, 0x47d: 0x0a08, 0x47e: 0x0a08, 0x47f: 0x0a08, // Block 0x12, offset 0x480 0x480: 0x0818, 0x481: 0x0a08, 0x482: 0x0a08, 0x483: 0x0a08, 0x484: 0x0a08, 0x485: 0x0a08, 0x486: 0x0a08, 0x487: 0x0a08, 0x488: 0x0c08, 0x489: 0x0a08, 0x48a: 0x0a08, 0x48b: 0x3308, 0x48c: 0x3308, 0x48d: 0x3308, 0x48e: 0x3308, 0x48f: 0x3308, 0x490: 0x3308, 0x491: 0x3308, 0x492: 0x3308, 0x493: 0x3308, 0x494: 0x3308, 0x495: 0x3308, 0x496: 0x3308, 0x497: 0x3308, 0x498: 0x3308, 0x499: 0x3308, 0x49a: 0x3308, 0x49b: 0x3308, 0x49c: 0x3308, 0x49d: 0x3308, 0x49e: 0x3308, 0x49f: 0x3308, 0x4a0: 0x0808, 0x4a1: 0x0808, 0x4a2: 0x0808, 0x4a3: 0x0808, 0x4a4: 0x0808, 0x4a5: 0x0808, 0x4a6: 0x0808, 0x4a7: 0x0808, 0x4a8: 0x0808, 0x4a9: 0x0808, 0x4aa: 0x0018, 0x4ab: 0x0818, 0x4ac: 0x0818, 0x4ad: 0x0818, 0x4ae: 0x0a08, 0x4af: 0x0a08, 0x4b0: 0x3308, 0x4b1: 0x0c08, 0x4b2: 0x0c08, 0x4b3: 0x0c08, 0x4b4: 0x0808, 0x4b5: 0x0429, 0x4b6: 0x0451, 0x4b7: 0x0479, 0x4b8: 0x04a1, 0x4b9: 0x0a08, 0x4ba: 0x0a08, 0x4bb: 0x0a08, 0x4bc: 0x0a08, 0x4bd: 0x0a08, 0x4be: 0x0a08, 0x4bf: 0x0a08, // Block 0x13, offset 0x4c0 0x4c0: 0x0c08, 0x4c1: 0x0a08, 0x4c2: 0x0a08, 0x4c3: 0x0c08, 0x4c4: 0x0c08, 0x4c5: 0x0c08, 0x4c6: 0x0c08, 0x4c7: 0x0c08, 0x4c8: 0x0c08, 0x4c9: 0x0c08, 0x4ca: 0x0c08, 0x4cb: 0x0c08, 0x4cc: 0x0a08, 0x4cd: 0x0c08, 0x4ce: 0x0a08, 0x4cf: 0x0c08, 0x4d0: 0x0a08, 0x4d1: 0x0a08, 0x4d2: 0x0c08, 0x4d3: 0x0c08, 0x4d4: 0x0818, 0x4d5: 0x0c08, 0x4d6: 0x3308, 0x4d7: 0x3308, 0x4d8: 0x3308, 0x4d9: 0x3308, 0x4da: 0x3308, 0x4db: 0x3308, 0x4dc: 0x3308, 0x4dd: 0x0840, 0x4de: 0x0018, 0x4df: 0x3308, 0x4e0: 0x3308, 0x4e1: 0x3308, 0x4e2: 0x3308, 0x4e3: 0x3308, 0x4e4: 0x3308, 0x4e5: 0x0808, 0x4e6: 0x0808, 0x4e7: 0x3308, 0x4e8: 0x3308, 0x4e9: 0x0018, 0x4ea: 0x3308, 0x4eb: 0x3308, 0x4ec: 0x3308, 0x4ed: 0x3308, 0x4ee: 0x0c08, 0x4ef: 0x0c08, 0x4f0: 0x0008, 0x4f1: 0x0008, 0x4f2: 0x0008, 0x4f3: 0x0008, 0x4f4: 0x0008, 0x4f5: 0x0008, 0x4f6: 0x0008, 0x4f7: 0x0008, 0x4f8: 0x0008, 0x4f9: 0x0008, 0x4fa: 0x0a08, 0x4fb: 0x0a08, 0x4fc: 0x0a08, 0x4fd: 0x0808, 0x4fe: 0x0808, 0x4ff: 0x0a08, // Block 0x14, offset 0x500 0x500: 0x0818, 0x501: 0x0818, 0x502: 0x0818, 0x503: 0x0818, 0x504: 0x0818, 0x505: 0x0818, 0x506: 0x0818, 0x507: 0x0818, 0x508: 0x0818, 0x509: 0x0818, 0x50a: 0x0818, 0x50b: 0x0818, 0x50c: 0x0818, 0x50d: 0x0818, 0x50e: 0x0040, 0x50f: 0x0b40, 0x510: 0x0c08, 0x511: 0x3308, 0x512: 0x0a08, 0x513: 0x0a08, 0x514: 0x0a08, 0x515: 0x0c08, 0x516: 0x0c08, 0x517: 0x0c08, 0x518: 0x0c08, 0x519: 0x0c08, 0x51a: 0x0a08, 0x51b: 0x0a08, 0x51c: 0x0a08, 0x51d: 0x0a08, 0x51e: 0x0c08, 0x51f: 0x0a08, 0x520: 0x0a08, 0x521: 0x0a08, 0x522: 0x0a08, 0x523: 0x0a08, 0x524: 0x0a08, 0x525: 0x0a08, 0x526: 0x0a08, 0x527: 0x0a08, 0x528: 0x0c08, 0x529: 0x0a08, 0x52a: 0x0c08, 0x52b: 0x0a08, 0x52c: 0x0c08, 0x52d: 0x0a08, 0x52e: 0x0a08, 0x52f: 0x0c08, 0x530: 0x3308, 0x531: 0x3308, 0x532: 0x3308, 0x533: 0x3308, 0x534: 0x3308, 0x535: 0x3308, 0x536: 0x3308, 0x537: 0x3308, 0x538: 0x3308, 0x539: 0x3308, 0x53a: 0x3308, 0x53b: 0x3308, 0x53c: 0x3308, 0x53d: 0x3308, 0x53e: 0x3308, 0x53f: 0x3308, // Block 0x15, offset 0x540 0x540: 0x0c08, 0x541: 0x0a08, 0x542: 0x0a08, 0x543: 0x0a08, 0x544: 0x0a08, 0x545: 0x0a08, 0x546: 0x0c08, 0x547: 0x0c08, 0x548: 0x0a08, 0x549: 0x0c08, 0x54a: 0x0a08, 0x54b: 0x0a08, 0x54c: 0x0a08, 0x54d: 0x0a08, 0x54e: 0x0a08, 0x54f: 0x0a08, 0x550: 0x0a08, 0x551: 0x0a08, 0x552: 0x0a08, 0x553: 0x0a08, 0x554: 0x0c08, 0x555: 0x0a08, 0x556: 0x0808, 0x557: 0x0808, 0x558: 0x0808, 0x559: 0x3308, 0x55a: 0x3308, 0x55b: 0x3308, 0x55c: 0x0040, 0x55d: 0x0040, 0x55e: 0x0818, 0x55f: 0x0040, 0x560: 0x0a08, 0x561: 0x0808, 0x562: 0x0a08, 0x563: 0x0a08, 0x564: 0x0a08, 0x565: 0x0a08, 0x566: 0x0808, 0x567: 0x0c08, 0x568: 0x0a08, 0x569: 0x0c08, 0x56a: 0x0c08, 0x56b: 0x0040, 0x56c: 0x0040, 0x56d: 0x0040, 0x56e: 0x0040, 0x56f: 0x0040, 0x570: 0x0040, 0x571: 0x0040, 0x572: 0x0040, 0x573: 0x0040, 0x574: 0x0040, 0x575: 0x0040, 0x576: 0x0040, 0x577: 0x0040, 0x578: 0x0040, 0x579: 0x0040, 0x57a: 0x0040, 0x57b: 0x0040, 0x57c: 0x0040, 0x57d: 0x0040, 0x57e: 0x0040, 0x57f: 0x0040, // Block 0x16, offset 0x580 0x580: 0x3008, 0x581: 0x3308, 0x582: 0x3308, 0x583: 0x3308, 0x584: 0x3308, 0x585: 0x3308, 0x586: 0x3308, 0x587: 0x3308, 0x588: 0x3308, 0x589: 0x3008, 0x58a: 0x3008, 0x58b: 0x3008, 0x58c: 0x3008, 0x58d: 0x3b08, 0x58e: 0x3008, 0x58f: 0x3008, 0x590: 0x0008, 0x591: 0x3308, 0x592: 0x3308, 0x593: 0x3308, 0x594: 0x3308, 0x595: 0x3308, 0x596: 0x3308, 0x597: 0x3308, 0x598: 0x04c9, 0x599: 0x0501, 0x59a: 0x0539, 0x59b: 0x0571, 0x59c: 0x05a9, 0x59d: 0x05e1, 0x59e: 0x0619, 0x59f: 0x0651, 0x5a0: 0x0008, 0x5a1: 0x0008, 0x5a2: 0x3308, 0x5a3: 0x3308, 0x5a4: 0x0018, 0x5a5: 0x0018, 0x5a6: 0x0008, 0x5a7: 0x0008, 0x5a8: 0x0008, 0x5a9: 0x0008, 0x5aa: 0x0008, 0x5ab: 0x0008, 0x5ac: 0x0008, 0x5ad: 0x0008, 0x5ae: 0x0008, 0x5af: 0x0008, 0x5b0: 0x0018, 0x5b1: 0x0008, 0x5b2: 0x0008, 0x5b3: 0x0008, 0x5b4: 0x0008, 0x5b5: 0x0008, 0x5b6: 0x0008, 0x5b7: 0x0008, 0x5b8: 0x0008, 0x5b9: 0x0008, 0x5ba: 0x0008, 0x5bb: 0x0008, 0x5bc: 0x0008, 0x5bd: 0x0008, 0x5be: 0x0008, 0x5bf: 0x0008, // Block 0x17, offset 0x5c0 0x5c0: 0x0008, 0x5c1: 0x3308, 0x5c2: 0x3008, 0x5c3: 0x3008, 0x5c4: 0x0040, 0x5c5: 0x0008, 0x5c6: 0x0008, 0x5c7: 0x0008, 0x5c8: 0x0008, 0x5c9: 0x0008, 0x5ca: 0x0008, 0x5cb: 0x0008, 0x5cc: 0x0008, 0x5cd: 0x0040, 0x5ce: 0x0040, 0x5cf: 0x0008, 0x5d0: 0x0008, 0x5d1: 0x0040, 0x5d2: 0x0040, 0x5d3: 0x0008, 0x5d4: 0x0008, 0x5d5: 0x0008, 0x5d6: 0x0008, 0x5d7: 0x0008, 0x5d8: 0x0008, 0x5d9: 0x0008, 0x5da: 0x0008, 0x5db: 0x0008, 0x5dc: 0x0008, 0x5dd: 0x0008, 0x5de: 0x0008, 0x5df: 0x0008, 0x5e0: 0x0008, 0x5e1: 0x0008, 0x5e2: 0x0008, 0x5e3: 0x0008, 0x5e4: 0x0008, 0x5e5: 0x0008, 0x5e6: 0x0008, 0x5e7: 0x0008, 0x5e8: 0x0008, 0x5e9: 0x0040, 0x5ea: 0x0008, 0x5eb: 0x0008, 0x5ec: 0x0008, 0x5ed: 0x0008, 0x5ee: 0x0008, 0x5ef: 0x0008, 0x5f0: 0x0008, 0x5f1: 0x0040, 0x5f2: 0x0008, 0x5f3: 0x0040, 0x5f4: 0x0040, 0x5f5: 0x0040, 0x5f6: 0x0008, 0x5f7: 0x0008, 0x5f8: 0x0008, 0x5f9: 0x0008, 0x5fa: 0x0040, 0x5fb: 0x0040, 0x5fc: 0x3308, 0x5fd: 0x0008, 0x5fe: 0x3008, 0x5ff: 0x3008, // Block 0x18, offset 0x600 0x600: 0x3008, 0x601: 0x3308, 0x602: 0x3308, 0x603: 0x3308, 0x604: 0x3308, 0x605: 0x0040, 0x606: 0x0040, 0x607: 0x3008, 0x608: 0x3008, 0x609: 0x0040, 0x60a: 0x0040, 0x60b: 0x3008, 0x60c: 0x3008, 0x60d: 0x3b08, 0x60e: 0x0008, 0x60f: 0x0040, 0x610: 0x0040, 0x611: 0x0040, 0x612: 0x0040, 0x613: 0x0040, 0x614: 0x0040, 0x615: 0x0040, 0x616: 0x0040, 0x617: 0x3008, 0x618: 0x0040, 0x619: 0x0040, 0x61a: 0x0040, 0x61b: 0x0040, 0x61c: 0x0689, 0x61d: 0x06c1, 0x61e: 0x0040, 0x61f: 0x06f9, 0x620: 0x0008, 0x621: 0x0008, 0x622: 0x3308, 0x623: 0x3308, 0x624: 0x0040, 0x625: 0x0040, 0x626: 0x0008, 0x627: 0x0008, 0x628: 0x0008, 0x629: 0x0008, 0x62a: 0x0008, 0x62b: 0x0008, 0x62c: 0x0008, 0x62d: 0x0008, 0x62e: 0x0008, 0x62f: 0x0008, 0x630: 0x0008, 0x631: 0x0008, 0x632: 0x0018, 0x633: 0x0018, 0x634: 0x0018, 0x635: 0x0018, 0x636: 0x0018, 0x637: 0x0018, 0x638: 0x0018, 0x639: 0x0018, 0x63a: 0x0018, 0x63b: 0x0018, 0x63c: 0x0008, 0x63d: 0x0018, 0x63e: 0x3308, 0x63f: 0x0040, // Block 0x19, offset 0x640 0x640: 0x0040, 0x641: 0x3308, 0x642: 0x3308, 0x643: 0x3008, 0x644: 0x0040, 0x645: 0x0008, 0x646: 0x0008, 0x647: 0x0008, 0x648: 0x0008, 0x649: 0x0008, 0x64a: 0x0008, 0x64b: 0x0040, 0x64c: 0x0040, 0x64d: 0x0040, 0x64e: 0x0040, 0x64f: 0x0008, 0x650: 0x0008, 0x651: 0x0040, 0x652: 0x0040, 0x653: 0x0008, 0x654: 0x0008, 0x655: 0x0008, 0x656: 0x0008, 0x657: 0x0008, 0x658: 0x0008, 0x659: 0x0008, 0x65a: 0x0008, 0x65b: 0x0008, 0x65c: 0x0008, 0x65d: 0x0008, 0x65e: 0x0008, 0x65f: 0x0008, 0x660: 0x0008, 0x661: 0x0008, 0x662: 0x0008, 0x663: 0x0008, 0x664: 0x0008, 0x665: 0x0008, 0x666: 0x0008, 0x667: 0x0008, 0x668: 0x0008, 0x669: 0x0040, 0x66a: 0x0008, 0x66b: 0x0008, 0x66c: 0x0008, 0x66d: 0x0008, 0x66e: 0x0008, 0x66f: 0x0008, 0x670: 0x0008, 0x671: 0x0040, 0x672: 0x0008, 0x673: 0x0731, 0x674: 0x0040, 0x675: 0x0008, 0x676: 0x0769, 0x677: 0x0040, 0x678: 0x0008, 0x679: 0x0008, 0x67a: 0x0040, 0x67b: 0x0040, 0x67c: 0x3308, 0x67d: 0x0040, 0x67e: 0x3008, 0x67f: 0x3008, // Block 0x1a, offset 0x680 0x680: 0x3008, 0x681: 0x3308, 0x682: 0x3308, 0x683: 0x0040, 0x684: 0x0040, 0x685: 0x0040, 0x686: 0x0040, 0x687: 0x3308, 0x688: 0x3308, 0x689: 0x0040, 0x68a: 0x0040, 0x68b: 0x3308, 0x68c: 0x3308, 0x68d: 0x3b08, 0x68e: 0x0040, 0x68f: 0x0040, 0x690: 0x0040, 0x691: 0x3308, 0x692: 0x0040, 0x693: 0x0040, 0x694: 0x0040, 0x695: 0x0040, 0x696: 0x0040, 0x697: 0x0040, 0x698: 0x0040, 0x699: 0x07a1, 0x69a: 0x07d9, 0x69b: 0x0811, 0x69c: 0x0008, 0x69d: 0x0040, 0x69e: 0x0849, 0x69f: 0x0040, 0x6a0: 0x0040, 0x6a1: 0x0040, 0x6a2: 0x0040, 0x6a3: 0x0040, 0x6a4: 0x0040, 0x6a5: 0x0040, 0x6a6: 0x0008, 0x6a7: 0x0008, 0x6a8: 0x0008, 0x6a9: 0x0008, 0x6aa: 0x0008, 0x6ab: 0x0008, 0x6ac: 0x0008, 0x6ad: 0x0008, 0x6ae: 0x0008, 0x6af: 0x0008, 0x6b0: 0x3308, 0x6b1: 0x3308, 0x6b2: 0x0008, 0x6b3: 0x0008, 0x6b4: 0x0008, 0x6b5: 0x3308, 0x6b6: 0x0018, 0x6b7: 0x0040, 0x6b8: 0x0040, 0x6b9: 0x0040, 0x6ba: 0x0040, 0x6bb: 0x0040, 0x6bc: 0x0040, 0x6bd: 0x0040, 0x6be: 0x0040, 0x6bf: 0x0040, // Block 0x1b, offset 0x6c0 0x6c0: 0x0040, 0x6c1: 0x3308, 0x6c2: 0x3308, 0x6c3: 0x3008, 0x6c4: 0x0040, 0x6c5: 0x0008, 0x6c6: 0x0008, 0x6c7: 0x0008, 0x6c8: 0x0008, 0x6c9: 0x0008, 0x6ca: 0x0008, 0x6cb: 0x0008, 0x6cc: 0x0008, 0x6cd: 0x0008, 0x6ce: 0x0040, 0x6cf: 0x0008, 0x6d0: 0x0008, 0x6d1: 0x0008, 0x6d2: 0x0040, 0x6d3: 0x0008, 0x6d4: 0x0008, 0x6d5: 0x0008, 0x6d6: 0x0008, 0x6d7: 0x0008, 0x6d8: 0x0008, 0x6d9: 0x0008, 0x6da: 0x0008, 0x6db: 0x0008, 0x6dc: 0x0008, 0x6dd: 0x0008, 0x6de: 0x0008, 0x6df: 0x0008, 0x6e0: 0x0008, 0x6e1: 0x0008, 0x6e2: 0x0008, 0x6e3: 0x0008, 0x6e4: 0x0008, 0x6e5: 0x0008, 0x6e6: 0x0008, 0x6e7: 0x0008, 0x6e8: 0x0008, 0x6e9: 0x0040, 0x6ea: 0x0008, 0x6eb: 0x0008, 0x6ec: 0x0008, 0x6ed: 0x0008, 0x6ee: 0x0008, 0x6ef: 0x0008, 0x6f0: 0x0008, 0x6f1: 0x0040, 0x6f2: 0x0008, 0x6f3: 0x0008, 0x6f4: 0x0040, 0x6f5: 0x0008, 0x6f6: 0x0008, 0x6f7: 0x0008, 0x6f8: 0x0008, 0x6f9: 0x0008, 0x6fa: 0x0040, 0x6fb: 0x0040, 0x6fc: 0x3308, 0x6fd: 0x0008, 0x6fe: 0x3008, 0x6ff: 0x3008, // Block 0x1c, offset 0x700 0x700: 0x3008, 0x701: 0x3308, 0x702: 0x3308, 0x703: 0x3308, 0x704: 0x3308, 0x705: 0x3308, 0x706: 0x0040, 0x707: 0x3308, 0x708: 0x3308, 0x709: 0x3008, 0x70a: 0x0040, 0x70b: 0x3008, 0x70c: 0x3008, 0x70d: 0x3b08, 0x70e: 0x0040, 0x70f: 0x0040, 0x710: 0x0008, 0x711: 0x0040, 0x712: 0x0040, 0x713: 0x0040, 0x714: 0x0040, 0x715: 0x0040, 0x716: 0x0040, 0x717: 0x0040, 0x718: 0x0040, 0x719: 0x0040, 0x71a: 0x0040, 0x71b: 0x0040, 0x71c: 0x0040, 0x71d: 0x0040, 0x71e: 0x0040, 0x71f: 0x0040, 0x720: 0x0008, 0x721: 0x0008, 0x722: 0x3308, 0x723: 0x3308, 0x724: 0x0040, 0x725: 0x0040, 0x726: 0x0008, 0x727: 0x0008, 0x728: 0x0008, 0x729: 0x0008, 0x72a: 0x0008, 0x72b: 0x0008, 0x72c: 0x0008, 0x72d: 0x0008, 0x72e: 0x0008, 0x72f: 0x0008, 0x730: 0x0018, 0x731: 0x0018, 0x732: 0x0040, 0x733: 0x0040, 0x734: 0x0040, 0x735: 0x0040, 0x736: 0x0040, 0x737: 0x0040, 0x738: 0x0040, 0x739: 0x0008, 0x73a: 0x3308, 0x73b: 0x3308, 0x73c: 0x3308, 0x73d: 0x3308, 0x73e: 0x3308, 0x73f: 0x3308, // Block 0x1d, offset 0x740 0x740: 0x0040, 0x741: 0x3308, 0x742: 0x3008, 0x743: 0x3008, 0x744: 0x0040, 0x745: 0x0008, 0x746: 0x0008, 0x747: 0x0008, 0x748: 0x0008, 0x749: 0x0008, 0x74a: 0x0008, 0x74b: 0x0008, 0x74c: 0x0008, 0x74d: 0x0040, 0x74e: 0x0040, 0x74f: 0x0008, 0x750: 0x0008, 0x751: 0x0040, 0x752: 0x0040, 0x753: 0x0008, 0x754: 0x0008, 0x755: 0x0008, 0x756: 0x0008, 0x757: 0x0008, 0x758: 0x0008, 0x759: 0x0008, 0x75a: 0x0008, 0x75b: 0x0008, 0x75c: 0x0008, 0x75d: 0x0008, 0x75e: 0x0008, 0x75f: 0x0008, 0x760: 0x0008, 0x761: 0x0008, 0x762: 0x0008, 0x763: 0x0008, 0x764: 0x0008, 0x765: 0x0008, 0x766: 0x0008, 0x767: 0x0008, 0x768: 0x0008, 0x769: 0x0040, 0x76a: 0x0008, 0x76b: 0x0008, 0x76c: 0x0008, 0x76d: 0x0008, 0x76e: 0x0008, 0x76f: 0x0008, 0x770: 0x0008, 0x771: 0x0040, 0x772: 0x0008, 0x773: 0x0008, 0x774: 0x0040, 0x775: 0x0008, 0x776: 0x0008, 0x777: 0x0008, 0x778: 0x0008, 0x779: 0x0008, 0x77a: 0x0040, 0x77b: 0x0040, 0x77c: 0x3308, 0x77d: 0x0008, 0x77e: 0x3008, 0x77f: 0x3308, // Block 0x1e, offset 0x780 0x780: 0x3008, 0x781: 0x3308, 0x782: 0x3308, 0x783: 0x3308, 0x784: 0x3308, 0x785: 0x0040, 0x786: 0x0040, 0x787: 0x3008, 0x788: 0x3008, 0x789: 0x0040, 0x78a: 0x0040, 0x78b: 0x3008, 0x78c: 0x3008, 0x78d: 0x3b08, 0x78e: 0x0040, 0x78f: 0x0040, 0x790: 0x0040, 0x791: 0x0040, 0x792: 0x0040, 0x793: 0x0040, 0x794: 0x0040, 0x795: 0x0040, 0x796: 0x3308, 0x797: 0x3008, 0x798: 0x0040, 0x799: 0x0040, 0x79a: 0x0040, 0x79b: 0x0040, 0x79c: 0x0881, 0x79d: 0x08b9, 0x79e: 0x0040, 0x79f: 0x0008, 0x7a0: 0x0008, 0x7a1: 0x0008, 0x7a2: 0x3308, 0x7a3: 0x3308, 0x7a4: 0x0040, 0x7a5: 0x0040, 0x7a6: 0x0008, 0x7a7: 0x0008, 0x7a8: 0x0008, 0x7a9: 0x0008, 0x7aa: 0x0008, 0x7ab: 0x0008, 0x7ac: 0x0008, 0x7ad: 0x0008, 0x7ae: 0x0008, 0x7af: 0x0008, 0x7b0: 0x0018, 0x7b1: 0x0008, 0x7b2: 0x0018, 0x7b3: 0x0018, 0x7b4: 0x0018, 0x7b5: 0x0018, 0x7b6: 0x0018, 0x7b7: 0x0018, 0x7b8: 0x0040, 0x7b9: 0x0040, 0x7ba: 0x0040, 0x7bb: 0x0040, 0x7bc: 0x0040, 0x7bd: 0x0040, 0x7be: 0x0040, 0x7bf: 0x0040, // Block 0x1f, offset 0x7c0 0x7c0: 0x0040, 0x7c1: 0x0040, 0x7c2: 0x3308, 0x7c3: 0x0008, 0x7c4: 0x0040, 0x7c5: 0x0008, 0x7c6: 0x0008, 0x7c7: 0x0008, 0x7c8: 0x0008, 0x7c9: 0x0008, 0x7ca: 0x0008, 0x7cb: 0x0040, 0x7cc: 0x0040, 0x7cd: 0x0040, 0x7ce: 0x0008, 0x7cf: 0x0008, 0x7d0: 0x0008, 0x7d1: 0x0040, 0x7d2: 0x0008, 0x7d3: 0x0008, 0x7d4: 0x0008, 0x7d5: 0x0008, 0x7d6: 0x0040, 0x7d7: 0x0040, 0x7d8: 0x0040, 0x7d9: 0x0008, 0x7da: 0x0008, 0x7db: 0x0040, 0x7dc: 0x0008, 0x7dd: 0x0040, 0x7de: 0x0008, 0x7df: 0x0008, 0x7e0: 0x0040, 0x7e1: 0x0040, 0x7e2: 0x0040, 0x7e3: 0x0008, 0x7e4: 0x0008, 0x7e5: 0x0040, 0x7e6: 0x0040, 0x7e7: 0x0040, 0x7e8: 0x0008, 0x7e9: 0x0008, 0x7ea: 0x0008, 0x7eb: 0x0040, 0x7ec: 0x0040, 0x7ed: 0x0040, 0x7ee: 0x0008, 0x7ef: 0x0008, 0x7f0: 0x0008, 0x7f1: 0x0008, 0x7f2: 0x0008, 0x7f3: 0x0008, 0x7f4: 0x0008, 0x7f5: 0x0008, 0x7f6: 0x0008, 0x7f7: 0x0008, 0x7f8: 0x0008, 0x7f9: 0x0008, 0x7fa: 0x0040, 0x7fb: 0x0040, 0x7fc: 0x0040, 0x7fd: 0x0040, 0x7fe: 0x3008, 0x7ff: 0x3008, // Block 0x20, offset 0x800 0x800: 0x3308, 0x801: 0x3008, 0x802: 0x3008, 0x803: 0x3008, 0x804: 0x3008, 0x805: 0x0040, 0x806: 0x3308, 0x807: 0x3308, 0x808: 0x3308, 0x809: 0x0040, 0x80a: 0x3308, 0x80b: 0x3308, 0x80c: 0x3308, 0x80d: 0x3b08, 0x80e: 0x0040, 0x80f: 0x0040, 0x810: 0x0040, 0x811: 0x0040, 0x812: 0x0040, 0x813: 0x0040, 0x814: 0x0040, 0x815: 0x3308, 0x816: 0x3308, 0x817: 0x0040, 0x818: 0x0008, 0x819: 0x0008, 0x81a: 0x0008, 0x81b: 0x0040, 0x81c: 0x0040, 0x81d: 0x0040, 0x81e: 0x0040, 0x81f: 0x0040, 0x820: 0x0008, 0x821: 0x0008, 0x822: 0x3308, 0x823: 0x3308, 0x824: 0x0040, 0x825: 0x0040, 0x826: 0x0008, 0x827: 0x0008, 0x828: 0x0008, 0x829: 0x0008, 0x82a: 0x0008, 0x82b: 0x0008, 0x82c: 0x0008, 0x82d: 0x0008, 0x82e: 0x0008, 0x82f: 0x0008, 0x830: 0x0040, 0x831: 0x0040, 0x832: 0x0040, 0x833: 0x0040, 0x834: 0x0040, 0x835: 0x0040, 0x836: 0x0040, 0x837: 0x0040, 0x838: 0x0018, 0x839: 0x0018, 0x83a: 0x0018, 0x83b: 0x0018, 0x83c: 0x0018, 0x83d: 0x0018, 0x83e: 0x0018, 0x83f: 0x0018, // Block 0x21, offset 0x840 0x840: 0x0008, 0x841: 0x3308, 0x842: 0x3008, 0x843: 0x3008, 0x844: 0x0018, 0x845: 0x0008, 0x846: 0x0008, 0x847: 0x0008, 0x848: 0x0008, 0x849: 0x0008, 0x84a: 0x0008, 0x84b: 0x0008, 0x84c: 0x0008, 0x84d: 0x0040, 0x84e: 0x0008, 0x84f: 0x0008, 0x850: 0x0008, 0x851: 0x0040, 0x852: 0x0008, 0x853: 0x0008, 0x854: 0x0008, 0x855: 0x0008, 0x856: 0x0008, 0x857: 0x0008, 0x858: 0x0008, 0x859: 0x0008, 0x85a: 0x0008, 0x85b: 0x0008, 0x85c: 0x0008, 0x85d: 0x0008, 0x85e: 0x0008, 0x85f: 0x0008, 0x860: 0x0008, 0x861: 0x0008, 0x862: 0x0008, 0x863: 0x0008, 0x864: 0x0008, 0x865: 0x0008, 0x866: 0x0008, 0x867: 0x0008, 0x868: 0x0008, 0x869: 0x0040, 0x86a: 0x0008, 0x86b: 0x0008, 0x86c: 0x0008, 0x86d: 0x0008, 0x86e: 0x0008, 0x86f: 0x0008, 0x870: 0x0008, 0x871: 0x0008, 0x872: 0x0008, 0x873: 0x0008, 0x874: 0x0040, 0x875: 0x0008, 0x876: 0x0008, 0x877: 0x0008, 0x878: 0x0008, 0x879: 0x0008, 0x87a: 0x0040, 0x87b: 0x0040, 0x87c: 0x3308, 0x87d: 0x0008, 0x87e: 0x3008, 0x87f: 0x3308, // Block 0x22, offset 0x880 0x880: 0x3008, 0x881: 0x3008, 0x882: 0x3008, 0x883: 0x3008, 0x884: 0x3008, 0x885: 0x0040, 0x886: 0x3308, 0x887: 0x3008, 0x888: 0x3008, 0x889: 0x0040, 0x88a: 0x3008, 0x88b: 0x3008, 0x88c: 0x3308, 0x88d: 0x3b08, 0x88e: 0x0040, 0x88f: 0x0040, 0x890: 0x0040, 0x891: 0x0040, 0x892: 0x0040, 0x893: 0x0040, 0x894: 0x0040, 0x895: 0x3008, 0x896: 0x3008, 0x897: 0x0040, 0x898: 0x0040, 0x899: 0x0040, 0x89a: 0x0040, 0x89b: 0x0040, 0x89c: 0x0040, 0x89d: 0x0040, 0x89e: 0x0008, 0x89f: 0x0040, 0x8a0: 0x0008, 0x8a1: 0x0008, 0x8a2: 0x3308, 0x8a3: 0x3308, 0x8a4: 0x0040, 0x8a5: 0x0040, 0x8a6: 0x0008, 0x8a7: 0x0008, 0x8a8: 0x0008, 0x8a9: 0x0008, 0x8aa: 0x0008, 0x8ab: 0x0008, 0x8ac: 0x0008, 0x8ad: 0x0008, 0x8ae: 0x0008, 0x8af: 0x0008, 0x8b0: 0x0040, 0x8b1: 0x0008, 0x8b2: 0x0008, 0x8b3: 0x0040, 0x8b4: 0x0040, 0x8b5: 0x0040, 0x8b6: 0x0040, 0x8b7: 0x0040, 0x8b8: 0x0040, 0x8b9: 0x0040, 0x8ba: 0x0040, 0x8bb: 0x0040, 0x8bc: 0x0040, 0x8bd: 0x0040, 0x8be: 0x0040, 0x8bf: 0x0040, // Block 0x23, offset 0x8c0 0x8c0: 0x3008, 0x8c1: 0x3308, 0x8c2: 0x3308, 0x8c3: 0x3308, 0x8c4: 0x3308, 0x8c5: 0x0040, 0x8c6: 0x3008, 0x8c7: 0x3008, 0x8c8: 0x3008, 0x8c9: 0x0040, 0x8ca: 0x3008, 0x8cb: 0x3008, 0x8cc: 0x3008, 0x8cd: 0x3b08, 0x8ce: 0x0008, 0x8cf: 0x0018, 0x8d0: 0x0040, 0x8d1: 0x0040, 0x8d2: 0x0040, 0x8d3: 0x0040, 0x8d4: 0x0008, 0x8d5: 0x0008, 0x8d6: 0x0008, 0x8d7: 0x3008, 0x8d8: 0x0018, 0x8d9: 0x0018, 0x8da: 0x0018, 0x8db: 0x0018, 0x8dc: 0x0018, 0x8dd: 0x0018, 0x8de: 0x0018, 0x8df: 0x0008, 0x8e0: 0x0008, 0x8e1: 0x0008, 0x8e2: 0x3308, 0x8e3: 0x3308, 0x8e4: 0x0040, 0x8e5: 0x0040, 0x8e6: 0x0008, 0x8e7: 0x0008, 0x8e8: 0x0008, 0x8e9: 0x0008, 0x8ea: 0x0008, 0x8eb: 0x0008, 0x8ec: 0x0008, 0x8ed: 0x0008, 0x8ee: 0x0008, 0x8ef: 0x0008, 0x8f0: 0x0018, 0x8f1: 0x0018, 0x8f2: 0x0018, 0x8f3: 0x0018, 0x8f4: 0x0018, 0x8f5: 0x0018, 0x8f6: 0x0018, 0x8f7: 0x0018, 0x8f8: 0x0018, 0x8f9: 0x0018, 0x8fa: 0x0008, 0x8fb: 0x0008, 0x8fc: 0x0008, 0x8fd: 0x0008, 0x8fe: 0x0008, 0x8ff: 0x0008, // Block 0x24, offset 0x900 0x900: 0x0040, 0x901: 0x0008, 0x902: 0x0008, 0x903: 0x0040, 0x904: 0x0008, 0x905: 0x0040, 0x906: 0x0040, 0x907: 0x0008, 0x908: 0x0008, 0x909: 0x0040, 0x90a: 0x0008, 0x90b: 0x0040, 0x90c: 0x0040, 0x90d: 0x0008, 0x90e: 0x0040, 0x90f: 0x0040, 0x910: 0x0040, 0x911: 0x0040, 0x912: 0x0040, 0x913: 0x0040, 0x914: 0x0008, 0x915: 0x0008, 0x916: 0x0008, 0x917: 0x0008, 0x918: 0x0040, 0x919: 0x0008, 0x91a: 0x0008, 0x91b: 0x0008, 0x91c: 0x0008, 0x91d: 0x0008, 0x91e: 0x0008, 0x91f: 0x0008, 0x920: 0x0040, 0x921: 0x0008, 0x922: 0x0008, 0x923: 0x0008, 0x924: 0x0040, 0x925: 0x0008, 0x926: 0x0040, 0x927: 0x0008, 0x928: 0x0040, 0x929: 0x0040, 0x92a: 0x0008, 0x92b: 0x0008, 0x92c: 0x0040, 0x92d: 0x0008, 0x92e: 0x0008, 0x92f: 0x0008, 0x930: 0x0008, 0x931: 0x3308, 0x932: 0x0008, 0x933: 0x0929, 0x934: 0x3308, 0x935: 0x3308, 0x936: 0x3308, 0x937: 0x3308, 0x938: 0x3308, 0x939: 0x3308, 0x93a: 0x0040, 0x93b: 0x3308, 0x93c: 0x3308, 0x93d: 0x0008, 0x93e: 0x0040, 0x93f: 0x0040, // Block 0x25, offset 0x940 0x940: 0x0008, 0x941: 0x0008, 0x942: 0x0008, 0x943: 0x09d1, 0x944: 0x0008, 0x945: 0x0008, 0x946: 0x0008, 0x947: 0x0008, 0x948: 0x0040, 0x949: 0x0008, 0x94a: 0x0008, 0x94b: 0x0008, 0x94c: 0x0008, 0x94d: 0x0a09, 0x94e: 0x0008, 0x94f: 0x0008, 0x950: 0x0008, 0x951: 0x0008, 0x952: 0x0a41, 0x953: 0x0008, 0x954: 0x0008, 0x955: 0x0008, 0x956: 0x0008, 0x957: 0x0a79, 0x958: 0x0008, 0x959: 0x0008, 0x95a: 0x0008, 0x95b: 0x0008, 0x95c: 0x0ab1, 0x95d: 0x0008, 0x95e: 0x0008, 0x95f: 0x0008, 0x960: 0x0008, 0x961: 0x0008, 0x962: 0x0008, 0x963: 0x0008, 0x964: 0x0008, 0x965: 0x0008, 0x966: 0x0008, 0x967: 0x0008, 0x968: 0x0008, 0x969: 0x0ae9, 0x96a: 0x0008, 0x96b: 0x0008, 0x96c: 0x0008, 0x96d: 0x0040, 0x96e: 0x0040, 0x96f: 0x0040, 0x970: 0x0040, 0x971: 0x3308, 0x972: 0x3308, 0x973: 0x0b21, 0x974: 0x3308, 0x975: 0x0b59, 0x976: 0x0b91, 0x977: 0x0bc9, 0x978: 0x0c19, 0x979: 0x0c51, 0x97a: 0x3308, 0x97b: 0x3308, 0x97c: 0x3308, 0x97d: 0x3308, 0x97e: 0x3308, 0x97f: 0x3008, // Block 0x26, offset 0x980 0x980: 0x3308, 0x981: 0x0ca1, 0x982: 0x3308, 0x983: 0x3308, 0x984: 0x3b08, 0x985: 0x0018, 0x986: 0x3308, 0x987: 0x3308, 0x988: 0x0008, 0x989: 0x0008, 0x98a: 0x0008, 0x98b: 0x0008, 0x98c: 0x0008, 0x98d: 0x3308, 0x98e: 0x3308, 0x98f: 0x3308, 0x990: 0x3308, 0x991: 0x3308, 0x992: 0x3308, 0x993: 0x0cd9, 0x994: 0x3308, 0x995: 0x3308, 0x996: 0x3308, 0x997: 0x3308, 0x998: 0x0040, 0x999: 0x3308, 0x99a: 0x3308, 0x99b: 0x3308, 0x99c: 0x3308, 0x99d: 0x0d11, 0x99e: 0x3308, 0x99f: 0x3308, 0x9a0: 0x3308, 0x9a1: 0x3308, 0x9a2: 0x0d49, 0x9a3: 0x3308, 0x9a4: 0x3308, 0x9a5: 0x3308, 0x9a6: 0x3308, 0x9a7: 0x0d81, 0x9a8: 0x3308, 0x9a9: 0x3308, 0x9aa: 0x3308, 0x9ab: 0x3308, 0x9ac: 0x0db9, 0x9ad: 0x3308, 0x9ae: 0x3308, 0x9af: 0x3308, 0x9b0: 0x3308, 0x9b1: 0x3308, 0x9b2: 0x3308, 0x9b3: 0x3308, 0x9b4: 0x3308, 0x9b5: 0x3308, 0x9b6: 0x3308, 0x9b7: 0x3308, 0x9b8: 0x3308, 0x9b9: 0x0df1, 0x9ba: 0x3308, 0x9bb: 0x3308, 0x9bc: 0x3308, 0x9bd: 0x0040, 0x9be: 0x0018, 0x9bf: 0x0018, // Block 0x27, offset 0x9c0 0x9c0: 0x0008, 0x9c1: 0x0008, 0x9c2: 0x0008, 0x9c3: 0x0008, 0x9c4: 0x0008, 0x9c5: 0x0008, 0x9c6: 0x0008, 0x9c7: 0x0008, 0x9c8: 0x0008, 0x9c9: 0x0008, 0x9ca: 0x0008, 0x9cb: 0x0008, 0x9cc: 0x0008, 0x9cd: 0x0008, 0x9ce: 0x0008, 0x9cf: 0x0008, 0x9d0: 0x0008, 0x9d1: 0x0008, 0x9d2: 0x0008, 0x9d3: 0x0008, 0x9d4: 0x0008, 0x9d5: 0x0008, 0x9d6: 0x0008, 0x9d7: 0x0008, 0x9d8: 0x0008, 0x9d9: 0x0008, 0x9da: 0x0008, 0x9db: 0x0008, 0x9dc: 0x0008, 0x9dd: 0x0008, 0x9de: 0x0008, 0x9df: 0x0008, 0x9e0: 0x0008, 0x9e1: 0x0008, 0x9e2: 0x0008, 0x9e3: 0x0008, 0x9e4: 0x0008, 0x9e5: 0x0008, 0x9e6: 0x0008, 0x9e7: 0x0008, 0x9e8: 0x0008, 0x9e9: 0x0008, 0x9ea: 0x0008, 0x9eb: 0x0008, 0x9ec: 0x0039, 0x9ed: 0x0ed1, 0x9ee: 0x0ee9, 0x9ef: 0x0008, 0x9f0: 0x0ef9, 0x9f1: 0x0f09, 0x9f2: 0x0f19, 0x9f3: 0x0f31, 0x9f4: 0x0249, 0x9f5: 0x0f41, 0x9f6: 0x0259, 0x9f7: 0x0f51, 0x9f8: 0x0359, 0x9f9: 0x0f61, 0x9fa: 0x0f71, 0x9fb: 0x0008, 0x9fc: 0x00d9, 0x9fd: 0x0f81, 0x9fe: 0x0f99, 0x9ff: 0x0269, // Block 0x28, offset 0xa00 0xa00: 0x0fa9, 0xa01: 0x0fb9, 0xa02: 0x0279, 0xa03: 0x0039, 0xa04: 0x0fc9, 0xa05: 0x0fe1, 0xa06: 0x059d, 0xa07: 0x0ee9, 0xa08: 0x0ef9, 0xa09: 0x0f09, 0xa0a: 0x0ff9, 0xa0b: 0x1011, 0xa0c: 0x1029, 0xa0d: 0x0f31, 0xa0e: 0x0008, 0xa0f: 0x0f51, 0xa10: 0x0f61, 0xa11: 0x1041, 0xa12: 0x00d9, 0xa13: 0x1059, 0xa14: 0x05b5, 0xa15: 0x05b5, 0xa16: 0x0f99, 0xa17: 0x0fa9, 0xa18: 0x0fb9, 0xa19: 0x059d, 0xa1a: 0x1071, 0xa1b: 0x1089, 0xa1c: 0x05cd, 0xa1d: 0x1099, 0xa1e: 0x10b1, 0xa1f: 0x10c9, 0xa20: 0x10e1, 0xa21: 0x10f9, 0xa22: 0x0f41, 0xa23: 0x0269, 0xa24: 0x0fb9, 0xa25: 0x1089, 0xa26: 0x1099, 0xa27: 0x10b1, 0xa28: 0x1111, 0xa29: 0x10e1, 0xa2a: 0x10f9, 0xa2b: 0x0008, 0xa2c: 0x0008, 0xa2d: 0x0008, 0xa2e: 0x0008, 0xa2f: 0x0008, 0xa30: 0x0008, 0xa31: 0x0008, 0xa32: 0x0008, 0xa33: 0x0008, 0xa34: 0x0008, 0xa35: 0x0008, 0xa36: 0x0008, 0xa37: 0x0008, 0xa38: 0x1129, 0xa39: 0x0008, 0xa3a: 0x0008, 0xa3b: 0x0008, 0xa3c: 0x0008, 0xa3d: 0x0008, 0xa3e: 0x0008, 0xa3f: 0x0008, // Block 0x29, offset 0xa40 0xa40: 0x0008, 0xa41: 0x0008, 0xa42: 0x0008, 0xa43: 0x0008, 0xa44: 0x0008, 0xa45: 0x0008, 0xa46: 0x0008, 0xa47: 0x0008, 0xa48: 0x0008, 0xa49: 0x0008, 0xa4a: 0x0008, 0xa4b: 0x0008, 0xa4c: 0x0008, 0xa4d: 0x0008, 0xa4e: 0x0008, 0xa4f: 0x0008, 0xa50: 0x0008, 0xa51: 0x0008, 0xa52: 0x0008, 0xa53: 0x0008, 0xa54: 0x0008, 0xa55: 0x0008, 0xa56: 0x0008, 0xa57: 0x0008, 0xa58: 0x0008, 0xa59: 0x0008, 0xa5a: 0x0008, 0xa5b: 0x1141, 0xa5c: 0x1159, 0xa5d: 0x1169, 0xa5e: 0x1181, 0xa5f: 0x1029, 0xa60: 0x1199, 0xa61: 0x11a9, 0xa62: 0x11c1, 0xa63: 0x11d9, 0xa64: 0x11f1, 0xa65: 0x1209, 0xa66: 0x1221, 0xa67: 0x05e5, 0xa68: 0x1239, 0xa69: 0x1251, 0xa6a: 0xe17d, 0xa6b: 0x1269, 0xa6c: 0x1281, 0xa6d: 0x1299, 0xa6e: 0x12b1, 0xa6f: 0x12c9, 0xa70: 0x12e1, 0xa71: 0x12f9, 0xa72: 0x1311, 0xa73: 0x1329, 0xa74: 0x1341, 0xa75: 0x1359, 0xa76: 0x1371, 0xa77: 0x1389, 0xa78: 0x05fd, 0xa79: 0x13a1, 0xa7a: 0x13b9, 0xa7b: 0x13d1, 0xa7c: 0x13e1, 0xa7d: 0x13f9, 0xa7e: 0x1411, 0xa7f: 0x1429, // Block 0x2a, offset 0xa80 0xa80: 0xe00d, 0xa81: 0x0008, 0xa82: 0xe00d, 0xa83: 0x0008, 0xa84: 0xe00d, 0xa85: 0x0008, 0xa86: 0xe00d, 0xa87: 0x0008, 0xa88: 0xe00d, 0xa89: 0x0008, 0xa8a: 0xe00d, 0xa8b: 0x0008, 0xa8c: 0xe00d, 0xa8d: 0x0008, 0xa8e: 0xe00d, 0xa8f: 0x0008, 0xa90: 0xe00d, 0xa91: 0x0008, 0xa92: 0xe00d, 0xa93: 0x0008, 0xa94: 0xe00d, 0xa95: 0x0008, 0xa96: 0xe00d, 0xa97: 0x0008, 0xa98: 0xe00d, 0xa99: 0x0008, 0xa9a: 0xe00d, 0xa9b: 0x0008, 0xa9c: 0xe00d, 0xa9d: 0x0008, 0xa9e: 0xe00d, 0xa9f: 0x0008, 0xaa0: 0xe00d, 0xaa1: 0x0008, 0xaa2: 0xe00d, 0xaa3: 0x0008, 0xaa4: 0xe00d, 0xaa5: 0x0008, 0xaa6: 0xe00d, 0xaa7: 0x0008, 0xaa8: 0xe00d, 0xaa9: 0x0008, 0xaaa: 0xe00d, 0xaab: 0x0008, 0xaac: 0xe00d, 0xaad: 0x0008, 0xaae: 0xe00d, 0xaaf: 0x0008, 0xab0: 0xe00d, 0xab1: 0x0008, 0xab2: 0xe00d, 0xab3: 0x0008, 0xab4: 0xe00d, 0xab5: 0x0008, 0xab6: 0xe00d, 0xab7: 0x0008, 0xab8: 0xe00d, 0xab9: 0x0008, 0xaba: 0xe00d, 0xabb: 0x0008, 0xabc: 0xe00d, 0xabd: 0x0008, 0xabe: 0xe00d, 0xabf: 0x0008, // Block 0x2b, offset 0xac0 0xac0: 0xe00d, 0xac1: 0x0008, 0xac2: 0xe00d, 0xac3: 0x0008, 0xac4: 0xe00d, 0xac5: 0x0008, 0xac6: 0xe00d, 0xac7: 0x0008, 0xac8: 0xe00d, 0xac9: 0x0008, 0xaca: 0xe00d, 0xacb: 0x0008, 0xacc: 0xe00d, 0xacd: 0x0008, 0xace: 0xe00d, 0xacf: 0x0008, 0xad0: 0xe00d, 0xad1: 0x0008, 0xad2: 0xe00d, 0xad3: 0x0008, 0xad4: 0xe00d, 0xad5: 0x0008, 0xad6: 0x0008, 0xad7: 0x0008, 0xad8: 0x0008, 0xad9: 0x0008, 0xada: 0x0615, 0xadb: 0x0635, 0xadc: 0x0008, 0xadd: 0x0008, 0xade: 0x1441, 0xadf: 0x0008, 0xae0: 0xe00d, 0xae1: 0x0008, 0xae2: 0xe00d, 0xae3: 0x0008, 0xae4: 0xe00d, 0xae5: 0x0008, 0xae6: 0xe00d, 0xae7: 0x0008, 0xae8: 0xe00d, 0xae9: 0x0008, 0xaea: 0xe00d, 0xaeb: 0x0008, 0xaec: 0xe00d, 0xaed: 0x0008, 0xaee: 0xe00d, 0xaef: 0x0008, 0xaf0: 0xe00d, 0xaf1: 0x0008, 0xaf2: 0xe00d, 0xaf3: 0x0008, 0xaf4: 0xe00d, 0xaf5: 0x0008, 0xaf6: 0xe00d, 0xaf7: 0x0008, 0xaf8: 0xe00d, 0xaf9: 0x0008, 0xafa: 0xe00d, 0xafb: 0x0008, 0xafc: 0xe00d, 0xafd: 0x0008, 0xafe: 0xe00d, 0xaff: 0x0008, // Block 0x2c, offset 0xb00 0xb00: 0x0008, 0xb01: 0x0008, 0xb02: 0x0008, 0xb03: 0x0008, 0xb04: 0x0008, 0xb05: 0x0008, 0xb06: 0x0040, 0xb07: 0x0040, 0xb08: 0xe045, 0xb09: 0xe045, 0xb0a: 0xe045, 0xb0b: 0xe045, 0xb0c: 0xe045, 0xb0d: 0xe045, 0xb0e: 0x0040, 0xb0f: 0x0040, 0xb10: 0x0008, 0xb11: 0x0008, 0xb12: 0x0008, 0xb13: 0x0008, 0xb14: 0x0008, 0xb15: 0x0008, 0xb16: 0x0008, 0xb17: 0x0008, 0xb18: 0x0040, 0xb19: 0xe045, 0xb1a: 0x0040, 0xb1b: 0xe045, 0xb1c: 0x0040, 0xb1d: 0xe045, 0xb1e: 0x0040, 0xb1f: 0xe045, 0xb20: 0x0008, 0xb21: 0x0008, 0xb22: 0x0008, 0xb23: 0x0008, 0xb24: 0x0008, 0xb25: 0x0008, 0xb26: 0x0008, 0xb27: 0x0008, 0xb28: 0xe045, 0xb29: 0xe045, 0xb2a: 0xe045, 0xb2b: 0xe045, 0xb2c: 0xe045, 0xb2d: 0xe045, 0xb2e: 0xe045, 0xb2f: 0xe045, 0xb30: 0x0008, 0xb31: 0x1459, 0xb32: 0x0008, 0xb33: 0x1471, 0xb34: 0x0008, 0xb35: 0x1489, 0xb36: 0x0008, 0xb37: 0x14a1, 0xb38: 0x0008, 0xb39: 0x14b9, 0xb3a: 0x0008, 0xb3b: 0x14d1, 0xb3c: 0x0008, 0xb3d: 0x14e9, 0xb3e: 0x0040, 0xb3f: 0x0040, // Block 0x2d, offset 0xb40 0xb40: 0x1501, 0xb41: 0x1531, 0xb42: 0x1561, 0xb43: 0x1591, 0xb44: 0x15c1, 0xb45: 0x15f1, 0xb46: 0x1621, 0xb47: 0x1651, 0xb48: 0x1501, 0xb49: 0x1531, 0xb4a: 0x1561, 0xb4b: 0x1591, 0xb4c: 0x15c1, 0xb4d: 0x15f1, 0xb4e: 0x1621, 0xb4f: 0x1651, 0xb50: 0x1681, 0xb51: 0x16b1, 0xb52: 0x16e1, 0xb53: 0x1711, 0xb54: 0x1741, 0xb55: 0x1771, 0xb56: 0x17a1, 0xb57: 0x17d1, 0xb58: 0x1681, 0xb59: 0x16b1, 0xb5a: 0x16e1, 0xb5b: 0x1711, 0xb5c: 0x1741, 0xb5d: 0x1771, 0xb5e: 0x17a1, 0xb5f: 0x17d1, 0xb60: 0x1801, 0xb61: 0x1831, 0xb62: 0x1861, 0xb63: 0x1891, 0xb64: 0x18c1, 0xb65: 0x18f1, 0xb66: 0x1921, 0xb67: 0x1951, 0xb68: 0x1801, 0xb69: 0x1831, 0xb6a: 0x1861, 0xb6b: 0x1891, 0xb6c: 0x18c1, 0xb6d: 0x18f1, 0xb6e: 0x1921, 0xb6f: 0x1951, 0xb70: 0x0008, 0xb71: 0x0008, 0xb72: 0x1981, 0xb73: 0x19b1, 0xb74: 0x19d9, 0xb75: 0x0040, 0xb76: 0x0008, 0xb77: 0x1a01, 0xb78: 0xe045, 0xb79: 0xe045, 0xb7a: 0x064d, 0xb7b: 0x1459, 0xb7c: 0x19b1, 0xb7d: 0x0666, 0xb7e: 0x1a31, 0xb7f: 0x0686, // Block 0x2e, offset 0xb80 0xb80: 0x06a6, 0xb81: 0x1a4a, 0xb82: 0x1a79, 0xb83: 0x1aa9, 0xb84: 0x1ad1, 0xb85: 0x0040, 0xb86: 0x0008, 0xb87: 0x1af9, 0xb88: 0x06c5, 0xb89: 0x1471, 0xb8a: 0x06dd, 0xb8b: 0x1489, 0xb8c: 0x1aa9, 0xb8d: 0x1b2a, 0xb8e: 0x1b5a, 0xb8f: 0x1b8a, 0xb90: 0x0008, 0xb91: 0x0008, 0xb92: 0x0008, 0xb93: 0x1bb9, 0xb94: 0x0040, 0xb95: 0x0040, 0xb96: 0x0008, 0xb97: 0x0008, 0xb98: 0xe045, 0xb99: 0xe045, 0xb9a: 0x06f5, 0xb9b: 0x14a1, 0xb9c: 0x0040, 0xb9d: 0x1bd2, 0xb9e: 0x1c02, 0xb9f: 0x1c32, 0xba0: 0x0008, 0xba1: 0x0008, 0xba2: 0x0008, 0xba3: 0x1c61, 0xba4: 0x0008, 0xba5: 0x0008, 0xba6: 0x0008, 0xba7: 0x0008, 0xba8: 0xe045, 0xba9: 0xe045, 0xbaa: 0x070d, 0xbab: 0x14d1, 0xbac: 0xe04d, 0xbad: 0x1c7a, 0xbae: 0x03d2, 0xbaf: 0x1caa, 0xbb0: 0x0040, 0xbb1: 0x0040, 0xbb2: 0x1cb9, 0xbb3: 0x1ce9, 0xbb4: 0x1d11, 0xbb5: 0x0040, 0xbb6: 0x0008, 0xbb7: 0x1d39, 0xbb8: 0x0725, 0xbb9: 0x14b9, 0xbba: 0x0515, 0xbbb: 0x14e9, 0xbbc: 0x1ce9, 0xbbd: 0x073e, 0xbbe: 0x075e, 0xbbf: 0x0040, // Block 0x2f, offset 0xbc0 0xbc0: 0x000a, 0xbc1: 0x000a, 0xbc2: 0x000a, 0xbc3: 0x000a, 0xbc4: 0x000a, 0xbc5: 0x000a, 0xbc6: 0x000a, 0xbc7: 0x000a, 0xbc8: 0x000a, 0xbc9: 0x000a, 0xbca: 0x000a, 0xbcb: 0x03c0, 0xbcc: 0x0003, 0xbcd: 0x0003, 0xbce: 0x0340, 0xbcf: 0x0b40, 0xbd0: 0x0018, 0xbd1: 0xe00d, 0xbd2: 0x0018, 0xbd3: 0x0018, 0xbd4: 0x0018, 0xbd5: 0x0018, 0xbd6: 0x0018, 0xbd7: 0x077e, 0xbd8: 0x0018, 0xbd9: 0x0018, 0xbda: 0x0018, 0xbdb: 0x0018, 0xbdc: 0x0018, 0xbdd: 0x0018, 0xbde: 0x0018, 0xbdf: 0x0018, 0xbe0: 0x0018, 0xbe1: 0x0018, 0xbe2: 0x0018, 0xbe3: 0x0018, 0xbe4: 0x0040, 0xbe5: 0x0040, 0xbe6: 0x0040, 0xbe7: 0x0018, 0xbe8: 0x0040, 0xbe9: 0x0040, 0xbea: 0x0340, 0xbeb: 0x0340, 0xbec: 0x0340, 0xbed: 0x0340, 0xbee: 0x0340, 0xbef: 0x000a, 0xbf0: 0x0018, 0xbf1: 0x0018, 0xbf2: 0x0018, 0xbf3: 0x1d69, 0xbf4: 0x1da1, 0xbf5: 0x0018, 0xbf6: 0x1df1, 0xbf7: 0x1e29, 0xbf8: 0x0018, 0xbf9: 0x0018, 0xbfa: 0x0018, 0xbfb: 0x0018, 0xbfc: 0x1e7a, 0xbfd: 0x0018, 0xbfe: 0x079e, 0xbff: 0x0018, // Block 0x30, offset 0xc00 0xc00: 0x0018, 0xc01: 0x0018, 0xc02: 0x0018, 0xc03: 0x0018, 0xc04: 0x0018, 0xc05: 0x0018, 0xc06: 0x0018, 0xc07: 0x1e92, 0xc08: 0x1eaa, 0xc09: 0x1ec2, 0xc0a: 0x0018, 0xc0b: 0x0018, 0xc0c: 0x0018, 0xc0d: 0x0018, 0xc0e: 0x0018, 0xc0f: 0x0018, 0xc10: 0x0018, 0xc11: 0x0018, 0xc12: 0x0018, 0xc13: 0x0018, 0xc14: 0x0018, 0xc15: 0x0018, 0xc16: 0x0018, 0xc17: 0x1ed9, 0xc18: 0x0018, 0xc19: 0x0018, 0xc1a: 0x0018, 0xc1b: 0x0018, 0xc1c: 0x0018, 0xc1d: 0x0018, 0xc1e: 0x0018, 0xc1f: 0x000a, 0xc20: 0x03c0, 0xc21: 0x0340, 0xc22: 0x0340, 0xc23: 0x0340, 0xc24: 0x03c0, 0xc25: 0x0040, 0xc26: 0x0040, 0xc27: 0x0040, 0xc28: 0x0040, 0xc29: 0x0040, 0xc2a: 0x0340, 0xc2b: 0x0340, 0xc2c: 0x0340, 0xc2d: 0x0340, 0xc2e: 0x0340, 0xc2f: 0x0340, 0xc30: 0x1f41, 0xc31: 0x0f41, 0xc32: 0x0040, 0xc33: 0x0040, 0xc34: 0x1f51, 0xc35: 0x1f61, 0xc36: 0x1f71, 0xc37: 0x1f81, 0xc38: 0x1f91, 0xc39: 0x1fa1, 0xc3a: 0x1fb2, 0xc3b: 0x07bd, 0xc3c: 0x1fc2, 0xc3d: 0x1fd2, 0xc3e: 0x1fe2, 0xc3f: 0x0f71, // Block 0x31, offset 0xc40 0xc40: 0x1f41, 0xc41: 0x00c9, 0xc42: 0x0069, 0xc43: 0x0079, 0xc44: 0x1f51, 0xc45: 0x1f61, 0xc46: 0x1f71, 0xc47: 0x1f81, 0xc48: 0x1f91, 0xc49: 0x1fa1, 0xc4a: 0x1fb2, 0xc4b: 0x07d5, 0xc4c: 0x1fc2, 0xc4d: 0x1fd2, 0xc4e: 0x1fe2, 0xc4f: 0x0040, 0xc50: 0x0039, 0xc51: 0x0f09, 0xc52: 0x00d9, 0xc53: 0x0369, 0xc54: 0x0ff9, 0xc55: 0x0249, 0xc56: 0x0f51, 0xc57: 0x0359, 0xc58: 0x0f61, 0xc59: 0x0f71, 0xc5a: 0x0f99, 0xc5b: 0x01d9, 0xc5c: 0x0fa9, 0xc5d: 0x0040, 0xc5e: 0x0040, 0xc5f: 0x0040, 0xc60: 0x0018, 0xc61: 0x0018, 0xc62: 0x0018, 0xc63: 0x0018, 0xc64: 0x0018, 0xc65: 0x0018, 0xc66: 0x0018, 0xc67: 0x0018, 0xc68: 0x1ff1, 0xc69: 0x0018, 0xc6a: 0x0018, 0xc6b: 0x0018, 0xc6c: 0x0018, 0xc6d: 0x0018, 0xc6e: 0x0018, 0xc6f: 0x0018, 0xc70: 0x0018, 0xc71: 0x0018, 0xc72: 0x0018, 0xc73: 0x0018, 0xc74: 0x0018, 0xc75: 0x0018, 0xc76: 0x0018, 0xc77: 0x0018, 0xc78: 0x0018, 0xc79: 0x0018, 0xc7a: 0x0018, 0xc7b: 0x0018, 0xc7c: 0x0018, 0xc7d: 0x0018, 0xc7e: 0x0018, 0xc7f: 0x0018, // Block 0x32, offset 0xc80 0xc80: 0x07ee, 0xc81: 0x080e, 0xc82: 0x1159, 0xc83: 0x082d, 0xc84: 0x0018, 0xc85: 0x084e, 0xc86: 0x086e, 0xc87: 0x1011, 0xc88: 0x0018, 0xc89: 0x088d, 0xc8a: 0x0f31, 0xc8b: 0x0249, 0xc8c: 0x0249, 0xc8d: 0x0249, 0xc8e: 0x0249, 0xc8f: 0x2009, 0xc90: 0x0f41, 0xc91: 0x0f41, 0xc92: 0x0359, 0xc93: 0x0359, 0xc94: 0x0018, 0xc95: 0x0f71, 0xc96: 0x2021, 0xc97: 0x0018, 0xc98: 0x0018, 0xc99: 0x0f99, 0xc9a: 0x2039, 0xc9b: 0x0269, 0xc9c: 0x0269, 0xc9d: 0x0269, 0xc9e: 0x0018, 0xc9f: 0x0018, 0xca0: 0x2049, 0xca1: 0x08ad, 0xca2: 0x2061, 0xca3: 0x0018, 0xca4: 0x13d1, 0xca5: 0x0018, 0xca6: 0x2079, 0xca7: 0x0018, 0xca8: 0x13d1, 0xca9: 0x0018, 0xcaa: 0x0f51, 0xcab: 0x2091, 0xcac: 0x0ee9, 0xcad: 0x1159, 0xcae: 0x0018, 0xcaf: 0x0f09, 0xcb0: 0x0f09, 0xcb1: 0x1199, 0xcb2: 0x0040, 0xcb3: 0x0f61, 0xcb4: 0x00d9, 0xcb5: 0x20a9, 0xcb6: 0x20c1, 0xcb7: 0x20d9, 0xcb8: 0x20f1, 0xcb9: 0x0f41, 0xcba: 0x0018, 0xcbb: 0x08cd, 0xcbc: 0x2109, 0xcbd: 0x10b1, 0xcbe: 0x10b1, 0xcbf: 0x2109, // Block 0x33, offset 0xcc0 0xcc0: 0x08ed, 0xcc1: 0x0018, 0xcc2: 0x0018, 0xcc3: 0x0018, 0xcc4: 0x0018, 0xcc5: 0x0ef9, 0xcc6: 0x0ef9, 0xcc7: 0x0f09, 0xcc8: 0x0f41, 0xcc9: 0x0259, 0xcca: 0x0018, 0xccb: 0x0018, 0xccc: 0x0018, 0xccd: 0x0018, 0xcce: 0x0008, 0xccf: 0x0018, 0xcd0: 0x2121, 0xcd1: 0x2151, 0xcd2: 0x2181, 0xcd3: 0x21b9, 0xcd4: 0x21e9, 0xcd5: 0x2219, 0xcd6: 0x2249, 0xcd7: 0x2279, 0xcd8: 0x22a9, 0xcd9: 0x22d9, 0xcda: 0x2309, 0xcdb: 0x2339, 0xcdc: 0x2369, 0xcdd: 0x2399, 0xcde: 0x23c9, 0xcdf: 0x23f9, 0xce0: 0x0f41, 0xce1: 0x2421, 0xce2: 0x0905, 0xce3: 0x2439, 0xce4: 0x1089, 0xce5: 0x2451, 0xce6: 0x0925, 0xce7: 0x2469, 0xce8: 0x2491, 0xce9: 0x0369, 0xcea: 0x24a9, 0xceb: 0x0945, 0xcec: 0x0359, 0xced: 0x1159, 0xcee: 0x0ef9, 0xcef: 0x0f61, 0xcf0: 0x0f41, 0xcf1: 0x2421, 0xcf2: 0x0965, 0xcf3: 0x2439, 0xcf4: 0x1089, 0xcf5: 0x2451, 0xcf6: 0x0985, 0xcf7: 0x2469, 0xcf8: 0x2491, 0xcf9: 0x0369, 0xcfa: 0x24a9, 0xcfb: 0x09a5, 0xcfc: 0x0359, 0xcfd: 0x1159, 0xcfe: 0x0ef9, 0xcff: 0x0f61, // Block 0x34, offset 0xd00 0xd00: 0x0018, 0xd01: 0x0018, 0xd02: 0x0018, 0xd03: 0x0018, 0xd04: 0x0018, 0xd05: 0x0018, 0xd06: 0x0018, 0xd07: 0x0018, 0xd08: 0x0018, 0xd09: 0x0018, 0xd0a: 0x0018, 0xd0b: 0x0040, 0xd0c: 0x0040, 0xd0d: 0x0040, 0xd0e: 0x0040, 0xd0f: 0x0040, 0xd10: 0x0040, 0xd11: 0x0040, 0xd12: 0x0040, 0xd13: 0x0040, 0xd14: 0x0040, 0xd15: 0x0040, 0xd16: 0x0040, 0xd17: 0x0040, 0xd18: 0x0040, 0xd19: 0x0040, 0xd1a: 0x0040, 0xd1b: 0x0040, 0xd1c: 0x0040, 0xd1d: 0x0040, 0xd1e: 0x0040, 0xd1f: 0x0040, 0xd20: 0x00c9, 0xd21: 0x0069, 0xd22: 0x0079, 0xd23: 0x1f51, 0xd24: 0x1f61, 0xd25: 0x1f71, 0xd26: 0x1f81, 0xd27: 0x1f91, 0xd28: 0x1fa1, 0xd29: 0x2601, 0xd2a: 0x2619, 0xd2b: 0x2631, 0xd2c: 0x2649, 0xd2d: 0x2661, 0xd2e: 0x2679, 0xd2f: 0x2691, 0xd30: 0x26a9, 0xd31: 0x26c1, 0xd32: 0x26d9, 0xd33: 0x26f1, 0xd34: 0x0a06, 0xd35: 0x0a26, 0xd36: 0x0a46, 0xd37: 0x0a66, 0xd38: 0x0a86, 0xd39: 0x0aa6, 0xd3a: 0x0ac6, 0xd3b: 0x0ae6, 0xd3c: 0x0b06, 0xd3d: 0x270a, 0xd3e: 0x2732, 0xd3f: 0x275a, // Block 0x35, offset 0xd40 0xd40: 0x2782, 0xd41: 0x27aa, 0xd42: 0x27d2, 0xd43: 0x27fa, 0xd44: 0x2822, 0xd45: 0x284a, 0xd46: 0x2872, 0xd47: 0x289a, 0xd48: 0x0040, 0xd49: 0x0040, 0xd4a: 0x0040, 0xd4b: 0x0040, 0xd4c: 0x0040, 0xd4d: 0x0040, 0xd4e: 0x0040, 0xd4f: 0x0040, 0xd50: 0x0040, 0xd51: 0x0040, 0xd52: 0x0040, 0xd53: 0x0040, 0xd54: 0x0040, 0xd55: 0x0040, 0xd56: 0x0040, 0xd57: 0x0040, 0xd58: 0x0040, 0xd59: 0x0040, 0xd5a: 0x0040, 0xd5b: 0x0040, 0xd5c: 0x0b26, 0xd5d: 0x0b46, 0xd5e: 0x0b66, 0xd5f: 0x0b86, 0xd60: 0x0ba6, 0xd61: 0x0bc6, 0xd62: 0x0be6, 0xd63: 0x0c06, 0xd64: 0x0c26, 0xd65: 0x0c46, 0xd66: 0x0c66, 0xd67: 0x0c86, 0xd68: 0x0ca6, 0xd69: 0x0cc6, 0xd6a: 0x0ce6, 0xd6b: 0x0d06, 0xd6c: 0x0d26, 0xd6d: 0x0d46, 0xd6e: 0x0d66, 0xd6f: 0x0d86, 0xd70: 0x0da6, 0xd71: 0x0dc6, 0xd72: 0x0de6, 0xd73: 0x0e06, 0xd74: 0x0e26, 0xd75: 0x0e46, 0xd76: 0x0039, 0xd77: 0x0ee9, 0xd78: 0x1159, 0xd79: 0x0ef9, 0xd7a: 0x0f09, 0xd7b: 0x1199, 0xd7c: 0x0f31, 0xd7d: 0x0249, 0xd7e: 0x0f41, 0xd7f: 0x0259, // Block 0x36, offset 0xd80 0xd80: 0x0f51, 0xd81: 0x0359, 0xd82: 0x0f61, 0xd83: 0x0f71, 0xd84: 0x00d9, 0xd85: 0x0f99, 0xd86: 0x2039, 0xd87: 0x0269, 0xd88: 0x01d9, 0xd89: 0x0fa9, 0xd8a: 0x0fb9, 0xd8b: 0x1089, 0xd8c: 0x0279, 0xd8d: 0x0369, 0xd8e: 0x0289, 0xd8f: 0x13d1, 0xd90: 0x0039, 0xd91: 0x0ee9, 0xd92: 0x1159, 0xd93: 0x0ef9, 0xd94: 0x0f09, 0xd95: 0x1199, 0xd96: 0x0f31, 0xd97: 0x0249, 0xd98: 0x0f41, 0xd99: 0x0259, 0xd9a: 0x0f51, 0xd9b: 0x0359, 0xd9c: 0x0f61, 0xd9d: 0x0f71, 0xd9e: 0x00d9, 0xd9f: 0x0f99, 0xda0: 0x2039, 0xda1: 0x0269, 0xda2: 0x01d9, 0xda3: 0x0fa9, 0xda4: 0x0fb9, 0xda5: 0x1089, 0xda6: 0x0279, 0xda7: 0x0369, 0xda8: 0x0289, 0xda9: 0x13d1, 0xdaa: 0x1f41, 0xdab: 0x0018, 0xdac: 0x0018, 0xdad: 0x0018, 0xdae: 0x0018, 0xdaf: 0x0018, 0xdb0: 0x0018, 0xdb1: 0x0018, 0xdb2: 0x0018, 0xdb3: 0x0018, 0xdb4: 0x0018, 0xdb5: 0x0018, 0xdb6: 0x0018, 0xdb7: 0x0018, 0xdb8: 0x0018, 0xdb9: 0x0018, 0xdba: 0x0018, 0xdbb: 0x0018, 0xdbc: 0x0018, 0xdbd: 0x0018, 0xdbe: 0x0018, 0xdbf: 0x0018, // Block 0x37, offset 0xdc0 0xdc0: 0x0008, 0xdc1: 0x0008, 0xdc2: 0x0008, 0xdc3: 0x0008, 0xdc4: 0x0008, 0xdc5: 0x0008, 0xdc6: 0x0008, 0xdc7: 0x0008, 0xdc8: 0x0008, 0xdc9: 0x0008, 0xdca: 0x0008, 0xdcb: 0x0008, 0xdcc: 0x0008, 0xdcd: 0x0008, 0xdce: 0x0008, 0xdcf: 0x0008, 0xdd0: 0x0008, 0xdd1: 0x0008, 0xdd2: 0x0008, 0xdd3: 0x0008, 0xdd4: 0x0008, 0xdd5: 0x0008, 0xdd6: 0x0008, 0xdd7: 0x0008, 0xdd8: 0x0008, 0xdd9: 0x0008, 0xdda: 0x0008, 0xddb: 0x0008, 0xddc: 0x0008, 0xddd: 0x0008, 0xdde: 0x0008, 0xddf: 0x0040, 0xde0: 0xe00d, 0xde1: 0x0008, 0xde2: 0x2971, 0xde3: 0x0ebd, 0xde4: 0x2989, 0xde5: 0x0008, 0xde6: 0x0008, 0xde7: 0xe07d, 0xde8: 0x0008, 0xde9: 0xe01d, 0xdea: 0x0008, 0xdeb: 0xe03d, 0xdec: 0x0008, 0xded: 0x0fe1, 0xdee: 0x1281, 0xdef: 0x0fc9, 0xdf0: 0x1141, 0xdf1: 0x0008, 0xdf2: 0xe00d, 0xdf3: 0x0008, 0xdf4: 0x0008, 0xdf5: 0xe01d, 0xdf6: 0x0008, 0xdf7: 0x0008, 0xdf8: 0x0008, 0xdf9: 0x0008, 0xdfa: 0x0008, 0xdfb: 0x0008, 0xdfc: 0x0259, 0xdfd: 0x1089, 0xdfe: 0x29a1, 0xdff: 0x29b9, // Block 0x38, offset 0xe00 0xe00: 0xe00d, 0xe01: 0x0008, 0xe02: 0xe00d, 0xe03: 0x0008, 0xe04: 0xe00d, 0xe05: 0x0008, 0xe06: 0xe00d, 0xe07: 0x0008, 0xe08: 0xe00d, 0xe09: 0x0008, 0xe0a: 0xe00d, 0xe0b: 0x0008, 0xe0c: 0xe00d, 0xe0d: 0x0008, 0xe0e: 0xe00d, 0xe0f: 0x0008, 0xe10: 0xe00d, 0xe11: 0x0008, 0xe12: 0xe00d, 0xe13: 0x0008, 0xe14: 0xe00d, 0xe15: 0x0008, 0xe16: 0xe00d, 0xe17: 0x0008, 0xe18: 0xe00d, 0xe19: 0x0008, 0xe1a: 0xe00d, 0xe1b: 0x0008, 0xe1c: 0xe00d, 0xe1d: 0x0008, 0xe1e: 0xe00d, 0xe1f: 0x0008, 0xe20: 0xe00d, 0xe21: 0x0008, 0xe22: 0xe00d, 0xe23: 0x0008, 0xe24: 0x0008, 0xe25: 0x0018, 0xe26: 0x0018, 0xe27: 0x0018, 0xe28: 0x0018, 0xe29: 0x0018, 0xe2a: 0x0018, 0xe2b: 0xe03d, 0xe2c: 0x0008, 0xe2d: 0xe01d, 0xe2e: 0x0008, 0xe2f: 0x3308, 0xe30: 0x3308, 0xe31: 0x3308, 0xe32: 0xe00d, 0xe33: 0x0008, 0xe34: 0x0040, 0xe35: 0x0040, 0xe36: 0x0040, 0xe37: 0x0040, 0xe38: 0x0040, 0xe39: 0x0018, 0xe3a: 0x0018, 0xe3b: 0x0018, 0xe3c: 0x0018, 0xe3d: 0x0018, 0xe3e: 0x0018, 0xe3f: 0x0018, // Block 0x39, offset 0xe40 0xe40: 0x26fd, 0xe41: 0x271d, 0xe42: 0x273d, 0xe43: 0x275d, 0xe44: 0x277d, 0xe45: 0x279d, 0xe46: 0x27bd, 0xe47: 0x27dd, 0xe48: 0x27fd, 0xe49: 0x281d, 0xe4a: 0x283d, 0xe4b: 0x285d, 0xe4c: 0x287d, 0xe4d: 0x289d, 0xe4e: 0x28bd, 0xe4f: 0x28dd, 0xe50: 0x28fd, 0xe51: 0x291d, 0xe52: 0x293d, 0xe53: 0x295d, 0xe54: 0x297d, 0xe55: 0x299d, 0xe56: 0x0040, 0xe57: 0x0040, 0xe58: 0x0040, 0xe59: 0x0040, 0xe5a: 0x0040, 0xe5b: 0x0040, 0xe5c: 0x0040, 0xe5d: 0x0040, 0xe5e: 0x0040, 0xe5f: 0x0040, 0xe60: 0x0040, 0xe61: 0x0040, 0xe62: 0x0040, 0xe63: 0x0040, 0xe64: 0x0040, 0xe65: 0x0040, 0xe66: 0x0040, 0xe67: 0x0040, 0xe68: 0x0040, 0xe69: 0x0040, 0xe6a: 0x0040, 0xe6b: 0x0040, 0xe6c: 0x0040, 0xe6d: 0x0040, 0xe6e: 0x0040, 0xe6f: 0x0040, 0xe70: 0x0040, 0xe71: 0x0040, 0xe72: 0x0040, 0xe73: 0x0040, 0xe74: 0x0040, 0xe75: 0x0040, 0xe76: 0x0040, 0xe77: 0x0040, 0xe78: 0x0040, 0xe79: 0x0040, 0xe7a: 0x0040, 0xe7b: 0x0040, 0xe7c: 0x0040, 0xe7d: 0x0040, 0xe7e: 0x0040, 0xe7f: 0x0040, // Block 0x3a, offset 0xe80 0xe80: 0x000a, 0xe81: 0x0018, 0xe82: 0x29d1, 0xe83: 0x0018, 0xe84: 0x0018, 0xe85: 0x0008, 0xe86: 0x0008, 0xe87: 0x0008, 0xe88: 0x0018, 0xe89: 0x0018, 0xe8a: 0x0018, 0xe8b: 0x0018, 0xe8c: 0x0018, 0xe8d: 0x0018, 0xe8e: 0x0018, 0xe8f: 0x0018, 0xe90: 0x0018, 0xe91: 0x0018, 0xe92: 0x0018, 0xe93: 0x0018, 0xe94: 0x0018, 0xe95: 0x0018, 0xe96: 0x0018, 0xe97: 0x0018, 0xe98: 0x0018, 0xe99: 0x0018, 0xe9a: 0x0018, 0xe9b: 0x0018, 0xe9c: 0x0018, 0xe9d: 0x0018, 0xe9e: 0x0018, 0xe9f: 0x0018, 0xea0: 0x0018, 0xea1: 0x0018, 0xea2: 0x0018, 0xea3: 0x0018, 0xea4: 0x0018, 0xea5: 0x0018, 0xea6: 0x0018, 0xea7: 0x0018, 0xea8: 0x0018, 0xea9: 0x0018, 0xeaa: 0x3308, 0xeab: 0x3308, 0xeac: 0x3308, 0xead: 0x3308, 0xeae: 0x3018, 0xeaf: 0x3018, 0xeb0: 0x0018, 0xeb1: 0x0018, 0xeb2: 0x0018, 0xeb3: 0x0018, 0xeb4: 0x0018, 0xeb5: 0x0018, 0xeb6: 0xe125, 0xeb7: 0x0018, 0xeb8: 0x29bd, 0xeb9: 0x29dd, 0xeba: 0x29fd, 0xebb: 0x0018, 0xebc: 0x0008, 0xebd: 0x0018, 0xebe: 0x0018, 0xebf: 0x0018, // Block 0x3b, offset 0xec0 0xec0: 0x2b3d, 0xec1: 0x2b5d, 0xec2: 0x2b7d, 0xec3: 0x2b9d, 0xec4: 0x2bbd, 0xec5: 0x2bdd, 0xec6: 0x2bdd, 0xec7: 0x2bdd, 0xec8: 0x2bfd, 0xec9: 0x2bfd, 0xeca: 0x2bfd, 0xecb: 0x2bfd, 0xecc: 0x2c1d, 0xecd: 0x2c1d, 0xece: 0x2c1d, 0xecf: 0x2c3d, 0xed0: 0x2c5d, 0xed1: 0x2c5d, 0xed2: 0x2a7d, 0xed3: 0x2a7d, 0xed4: 0x2c5d, 0xed5: 0x2c5d, 0xed6: 0x2c7d, 0xed7: 0x2c7d, 0xed8: 0x2c5d, 0xed9: 0x2c5d, 0xeda: 0x2a7d, 0xedb: 0x2a7d, 0xedc: 0x2c5d, 0xedd: 0x2c5d, 0xede: 0x2c3d, 0xedf: 0x2c3d, 0xee0: 0x2c9d, 0xee1: 0x2c9d, 0xee2: 0x2cbd, 0xee3: 0x2cbd, 0xee4: 0x0040, 0xee5: 0x2cdd, 0xee6: 0x2cfd, 0xee7: 0x2d1d, 0xee8: 0x2d1d, 0xee9: 0x2d3d, 0xeea: 0x2d5d, 0xeeb: 0x2d7d, 0xeec: 0x2d9d, 0xeed: 0x2dbd, 0xeee: 0x2ddd, 0xeef: 0x2dfd, 0xef0: 0x2e1d, 0xef1: 0x2e3d, 0xef2: 0x2e3d, 0xef3: 0x2e5d, 0xef4: 0x2e7d, 0xef5: 0x2e7d, 0xef6: 0x2e9d, 0xef7: 0x2ebd, 0xef8: 0x2e5d, 0xef9: 0x2edd, 0xefa: 0x2efd, 0xefb: 0x2edd, 0xefc: 0x2e5d, 0xefd: 0x2f1d, 0xefe: 0x2f3d, 0xeff: 0x2f5d, // Block 0x3c, offset 0xf00 0xf00: 0x2f7d, 0xf01: 0x2f9d, 0xf02: 0x2cfd, 0xf03: 0x2cdd, 0xf04: 0x2fbd, 0xf05: 0x2fdd, 0xf06: 0x2ffd, 0xf07: 0x301d, 0xf08: 0x303d, 0xf09: 0x305d, 0xf0a: 0x307d, 0xf0b: 0x309d, 0xf0c: 0x30bd, 0xf0d: 0x30dd, 0xf0e: 0x30fd, 0xf0f: 0x0040, 0xf10: 0x0018, 0xf11: 0x0018, 0xf12: 0x311d, 0xf13: 0x313d, 0xf14: 0x315d, 0xf15: 0x317d, 0xf16: 0x319d, 0xf17: 0x31bd, 0xf18: 0x31dd, 0xf19: 0x31fd, 0xf1a: 0x321d, 0xf1b: 0x323d, 0xf1c: 0x315d, 0xf1d: 0x325d, 0xf1e: 0x327d, 0xf1f: 0x329d, 0xf20: 0x0008, 0xf21: 0x0008, 0xf22: 0x0008, 0xf23: 0x0008, 0xf24: 0x0008, 0xf25: 0x0008, 0xf26: 0x0008, 0xf27: 0x0008, 0xf28: 0x0008, 0xf29: 0x0008, 0xf2a: 0x0008, 0xf2b: 0x0008, 0xf2c: 0x0008, 0xf2d: 0x0008, 0xf2e: 0x0008, 0xf2f: 0x0008, 0xf30: 0x0008, 0xf31: 0x0008, 0xf32: 0x0008, 0xf33: 0x0008, 0xf34: 0x0008, 0xf35: 0x0008, 0xf36: 0x0008, 0xf37: 0x0008, 0xf38: 0x0008, 0xf39: 0x0008, 0xf3a: 0x0008, 0xf3b: 0x0040, 0xf3c: 0x0040, 0xf3d: 0x0040, 0xf3e: 0x0040, 0xf3f: 0x0040, // Block 0x3d, offset 0xf40 0xf40: 0x36a2, 0xf41: 0x36d2, 0xf42: 0x3702, 0xf43: 0x3732, 0xf44: 0x32bd, 0xf45: 0x32dd, 0xf46: 0x32fd, 0xf47: 0x331d, 0xf48: 0x0018, 0xf49: 0x0018, 0xf4a: 0x0018, 0xf4b: 0x0018, 0xf4c: 0x0018, 0xf4d: 0x0018, 0xf4e: 0x0018, 0xf4f: 0x0018, 0xf50: 0x333d, 0xf51: 0x3761, 0xf52: 0x3779, 0xf53: 0x3791, 0xf54: 0x37a9, 0xf55: 0x37c1, 0xf56: 0x37d9, 0xf57: 0x37f1, 0xf58: 0x3809, 0xf59: 0x3821, 0xf5a: 0x3839, 0xf5b: 0x3851, 0xf5c: 0x3869, 0xf5d: 0x3881, 0xf5e: 0x3899, 0xf5f: 0x38b1, 0xf60: 0x335d, 0xf61: 0x337d, 0xf62: 0x339d, 0xf63: 0x33bd, 0xf64: 0x33dd, 0xf65: 0x33dd, 0xf66: 0x33fd, 0xf67: 0x341d, 0xf68: 0x343d, 0xf69: 0x345d, 0xf6a: 0x347d, 0xf6b: 0x349d, 0xf6c: 0x34bd, 0xf6d: 0x34dd, 0xf6e: 0x34fd, 0xf6f: 0x351d, 0xf70: 0x353d, 0xf71: 0x355d, 0xf72: 0x357d, 0xf73: 0x359d, 0xf74: 0x35bd, 0xf75: 0x35dd, 0xf76: 0x35fd, 0xf77: 0x361d, 0xf78: 0x363d, 0xf79: 0x365d, 0xf7a: 0x367d, 0xf7b: 0x369d, 0xf7c: 0x38c9, 0xf7d: 0x3901, 0xf7e: 0x36bd, 0xf7f: 0x0018, // Block 0x3e, offset 0xf80 0xf80: 0x36dd, 0xf81: 0x36fd, 0xf82: 0x371d, 0xf83: 0x373d, 0xf84: 0x375d, 0xf85: 0x377d, 0xf86: 0x379d, 0xf87: 0x37bd, 0xf88: 0x37dd, 0xf89: 0x37fd, 0xf8a: 0x381d, 0xf8b: 0x383d, 0xf8c: 0x385d, 0xf8d: 0x387d, 0xf8e: 0x389d, 0xf8f: 0x38bd, 0xf90: 0x38dd, 0xf91: 0x38fd, 0xf92: 0x391d, 0xf93: 0x393d, 0xf94: 0x395d, 0xf95: 0x397d, 0xf96: 0x399d, 0xf97: 0x39bd, 0xf98: 0x39dd, 0xf99: 0x39fd, 0xf9a: 0x3a1d, 0xf9b: 0x3a3d, 0xf9c: 0x3a5d, 0xf9d: 0x3a7d, 0xf9e: 0x3a9d, 0xf9f: 0x3abd, 0xfa0: 0x3add, 0xfa1: 0x3afd, 0xfa2: 0x3b1d, 0xfa3: 0x3b3d, 0xfa4: 0x3b5d, 0xfa5: 0x3b7d, 0xfa6: 0x127d, 0xfa7: 0x3b9d, 0xfa8: 0x3bbd, 0xfa9: 0x3bdd, 0xfaa: 0x3bfd, 0xfab: 0x3c1d, 0xfac: 0x3c3d, 0xfad: 0x3c5d, 0xfae: 0x239d, 0xfaf: 0x3c7d, 0xfb0: 0x3c9d, 0xfb1: 0x3939, 0xfb2: 0x3951, 0xfb3: 0x3969, 0xfb4: 0x3981, 0xfb5: 0x3999, 0xfb6: 0x39b1, 0xfb7: 0x39c9, 0xfb8: 0x39e1, 0xfb9: 0x39f9, 0xfba: 0x3a11, 0xfbb: 0x3a29, 0xfbc: 0x3a41, 0xfbd: 0x3a59, 0xfbe: 0x3a71, 0xfbf: 0x3a89, // Block 0x3f, offset 0xfc0 0xfc0: 0x3aa1, 0xfc1: 0x3ac9, 0xfc2: 0x3af1, 0xfc3: 0x3b19, 0xfc4: 0x3b41, 0xfc5: 0x3b69, 0xfc6: 0x3b91, 0xfc7: 0x3bb9, 0xfc8: 0x3be1, 0xfc9: 0x3c09, 0xfca: 0x3c39, 0xfcb: 0x3c69, 0xfcc: 0x3c99, 0xfcd: 0x3cbd, 0xfce: 0x3cb1, 0xfcf: 0x3cdd, 0xfd0: 0x3cfd, 0xfd1: 0x3d15, 0xfd2: 0x3d2d, 0xfd3: 0x3d45, 0xfd4: 0x3d5d, 0xfd5: 0x3d5d, 0xfd6: 0x3d45, 0xfd7: 0x3d75, 0xfd8: 0x07bd, 0xfd9: 0x3d8d, 0xfda: 0x3da5, 0xfdb: 0x3dbd, 0xfdc: 0x3dd5, 0xfdd: 0x3ded, 0xfde: 0x3e05, 0xfdf: 0x3e1d, 0xfe0: 0x3e35, 0xfe1: 0x3e4d, 0xfe2: 0x3e65, 0xfe3: 0x3e7d, 0xfe4: 0x3e95, 0xfe5: 0x3e95, 0xfe6: 0x3ead, 0xfe7: 0x3ead, 0xfe8: 0x3ec5, 0xfe9: 0x3ec5, 0xfea: 0x3edd, 0xfeb: 0x3ef5, 0xfec: 0x3f0d, 0xfed: 0x3f25, 0xfee: 0x3f3d, 0xfef: 0x3f3d, 0xff0: 0x3f55, 0xff1: 0x3f55, 0xff2: 0x3f55, 0xff3: 0x3f6d, 0xff4: 0x3f85, 0xff5: 0x3f9d, 0xff6: 0x3fb5, 0xff7: 0x3f9d, 0xff8: 0x3fcd, 0xff9: 0x3fe5, 0xffa: 0x3f6d, 0xffb: 0x3ffd, 0xffc: 0x4015, 0xffd: 0x4015, 0xffe: 0x4015, 0xfff: 0x0040, // Block 0x40, offset 0x1000 0x1000: 0x3cc9, 0x1001: 0x3d31, 0x1002: 0x3d99, 0x1003: 0x3e01, 0x1004: 0x3e51, 0x1005: 0x3eb9, 0x1006: 0x3f09, 0x1007: 0x3f59, 0x1008: 0x3fd9, 0x1009: 0x4041, 0x100a: 0x4091, 0x100b: 0x40e1, 0x100c: 0x4131, 0x100d: 0x4199, 0x100e: 0x4201, 0x100f: 0x4251, 0x1010: 0x42a1, 0x1011: 0x42d9, 0x1012: 0x4329, 0x1013: 0x4391, 0x1014: 0x43f9, 0x1015: 0x4431, 0x1016: 0x44b1, 0x1017: 0x4549, 0x1018: 0x45c9, 0x1019: 0x4619, 0x101a: 0x4699, 0x101b: 0x4719, 0x101c: 0x4781, 0x101d: 0x47d1, 0x101e: 0x4821, 0x101f: 0x4871, 0x1020: 0x48d9, 0x1021: 0x4959, 0x1022: 0x49c1, 0x1023: 0x4a11, 0x1024: 0x4a61, 0x1025: 0x4ab1, 0x1026: 0x4ae9, 0x1027: 0x4b21, 0x1028: 0x4b59, 0x1029: 0x4b91, 0x102a: 0x4be1, 0x102b: 0x4c31, 0x102c: 0x4cb1, 0x102d: 0x4d01, 0x102e: 0x4d69, 0x102f: 0x4de9, 0x1030: 0x4e39, 0x1031: 0x4e71, 0x1032: 0x4ea9, 0x1033: 0x4f29, 0x1034: 0x4f91, 0x1035: 0x5011, 0x1036: 0x5061, 0x1037: 0x50e1, 0x1038: 0x5119, 0x1039: 0x5169, 0x103a: 0x51b9, 0x103b: 0x5209, 0x103c: 0x5259, 0x103d: 0x52a9, 0x103e: 0x5311, 0x103f: 0x5361, // Block 0x41, offset 0x1040 0x1040: 0x5399, 0x1041: 0x53e9, 0x1042: 0x5439, 0x1043: 0x5489, 0x1044: 0x54f1, 0x1045: 0x5541, 0x1046: 0x5591, 0x1047: 0x55e1, 0x1048: 0x5661, 0x1049: 0x56c9, 0x104a: 0x5701, 0x104b: 0x5781, 0x104c: 0x57b9, 0x104d: 0x5821, 0x104e: 0x5889, 0x104f: 0x58d9, 0x1050: 0x5929, 0x1051: 0x5979, 0x1052: 0x59e1, 0x1053: 0x5a19, 0x1054: 0x5a69, 0x1055: 0x5ad1, 0x1056: 0x5b09, 0x1057: 0x5b89, 0x1058: 0x5bd9, 0x1059: 0x5c01, 0x105a: 0x5c29, 0x105b: 0x5c51, 0x105c: 0x5c79, 0x105d: 0x5ca1, 0x105e: 0x5cc9, 0x105f: 0x5cf1, 0x1060: 0x5d19, 0x1061: 0x5d41, 0x1062: 0x5d69, 0x1063: 0x5d99, 0x1064: 0x5dc9, 0x1065: 0x5df9, 0x1066: 0x5e29, 0x1067: 0x5e59, 0x1068: 0x5e89, 0x1069: 0x5eb9, 0x106a: 0x5ee9, 0x106b: 0x5f19, 0x106c: 0x5f49, 0x106d: 0x5f79, 0x106e: 0x5fa9, 0x106f: 0x5fd9, 0x1070: 0x6009, 0x1071: 0x402d, 0x1072: 0x6039, 0x1073: 0x6051, 0x1074: 0x404d, 0x1075: 0x6069, 0x1076: 0x6081, 0x1077: 0x6099, 0x1078: 0x406d, 0x1079: 0x406d, 0x107a: 0x60b1, 0x107b: 0x60c9, 0x107c: 0x6101, 0x107d: 0x6139, 0x107e: 0x6171, 0x107f: 0x61a9, // Block 0x42, offset 0x1080 0x1080: 0x6211, 0x1081: 0x6229, 0x1082: 0x408d, 0x1083: 0x6241, 0x1084: 0x6259, 0x1085: 0x6271, 0x1086: 0x6289, 0x1087: 0x62a1, 0x1088: 0x40ad, 0x1089: 0x62b9, 0x108a: 0x62e1, 0x108b: 0x62f9, 0x108c: 0x40cd, 0x108d: 0x40cd, 0x108e: 0x6311, 0x108f: 0x6329, 0x1090: 0x6341, 0x1091: 0x40ed, 0x1092: 0x410d, 0x1093: 0x412d, 0x1094: 0x414d, 0x1095: 0x416d, 0x1096: 0x6359, 0x1097: 0x6371, 0x1098: 0x6389, 0x1099: 0x63a1, 0x109a: 0x63b9, 0x109b: 0x418d, 0x109c: 0x63d1, 0x109d: 0x63e9, 0x109e: 0x6401, 0x109f: 0x41ad, 0x10a0: 0x41cd, 0x10a1: 0x6419, 0x10a2: 0x41ed, 0x10a3: 0x420d, 0x10a4: 0x422d, 0x10a5: 0x6431, 0x10a6: 0x424d, 0x10a7: 0x6449, 0x10a8: 0x6479, 0x10a9: 0x6211, 0x10aa: 0x426d, 0x10ab: 0x428d, 0x10ac: 0x42ad, 0x10ad: 0x42cd, 0x10ae: 0x64b1, 0x10af: 0x64f1, 0x10b0: 0x6539, 0x10b1: 0x6551, 0x10b2: 0x42ed, 0x10b3: 0x6569, 0x10b4: 0x6581, 0x10b5: 0x6599, 0x10b6: 0x430d, 0x10b7: 0x65b1, 0x10b8: 0x65c9, 0x10b9: 0x65b1, 0x10ba: 0x65e1, 0x10bb: 0x65f9, 0x10bc: 0x432d, 0x10bd: 0x6611, 0x10be: 0x6629, 0x10bf: 0x6611, // Block 0x43, offset 0x10c0 0x10c0: 0x434d, 0x10c1: 0x436d, 0x10c2: 0x0040, 0x10c3: 0x6641, 0x10c4: 0x6659, 0x10c5: 0x6671, 0x10c6: 0x6689, 0x10c7: 0x0040, 0x10c8: 0x66c1, 0x10c9: 0x66d9, 0x10ca: 0x66f1, 0x10cb: 0x6709, 0x10cc: 0x6721, 0x10cd: 0x6739, 0x10ce: 0x6401, 0x10cf: 0x6751, 0x10d0: 0x6769, 0x10d1: 0x6781, 0x10d2: 0x438d, 0x10d3: 0x6799, 0x10d4: 0x6289, 0x10d5: 0x43ad, 0x10d6: 0x43cd, 0x10d7: 0x67b1, 0x10d8: 0x0040, 0x10d9: 0x43ed, 0x10da: 0x67c9, 0x10db: 0x67e1, 0x10dc: 0x67f9, 0x10dd: 0x6811, 0x10de: 0x6829, 0x10df: 0x6859, 0x10e0: 0x6889, 0x10e1: 0x68b1, 0x10e2: 0x68d9, 0x10e3: 0x6901, 0x10e4: 0x6929, 0x10e5: 0x6951, 0x10e6: 0x6979, 0x10e7: 0x69a1, 0x10e8: 0x69c9, 0x10e9: 0x69f1, 0x10ea: 0x6a21, 0x10eb: 0x6a51, 0x10ec: 0x6a81, 0x10ed: 0x6ab1, 0x10ee: 0x6ae1, 0x10ef: 0x6b11, 0x10f0: 0x6b41, 0x10f1: 0x6b71, 0x10f2: 0x6ba1, 0x10f3: 0x6bd1, 0x10f4: 0x6c01, 0x10f5: 0x6c31, 0x10f6: 0x6c61, 0x10f7: 0x6c91, 0x10f8: 0x6cc1, 0x10f9: 0x6cf1, 0x10fa: 0x6d21, 0x10fb: 0x6d51, 0x10fc: 0x6d81, 0x10fd: 0x6db1, 0x10fe: 0x6de1, 0x10ff: 0x440d, // Block 0x44, offset 0x1100 0x1100: 0xe00d, 0x1101: 0x0008, 0x1102: 0xe00d, 0x1103: 0x0008, 0x1104: 0xe00d, 0x1105: 0x0008, 0x1106: 0xe00d, 0x1107: 0x0008, 0x1108: 0xe00d, 0x1109: 0x0008, 0x110a: 0xe00d, 0x110b: 0x0008, 0x110c: 0xe00d, 0x110d: 0x0008, 0x110e: 0xe00d, 0x110f: 0x0008, 0x1110: 0xe00d, 0x1111: 0x0008, 0x1112: 0xe00d, 0x1113: 0x0008, 0x1114: 0xe00d, 0x1115: 0x0008, 0x1116: 0xe00d, 0x1117: 0x0008, 0x1118: 0xe00d, 0x1119: 0x0008, 0x111a: 0xe00d, 0x111b: 0x0008, 0x111c: 0xe00d, 0x111d: 0x0008, 0x111e: 0xe00d, 0x111f: 0x0008, 0x1120: 0xe00d, 0x1121: 0x0008, 0x1122: 0xe00d, 0x1123: 0x0008, 0x1124: 0xe00d, 0x1125: 0x0008, 0x1126: 0xe00d, 0x1127: 0x0008, 0x1128: 0xe00d, 0x1129: 0x0008, 0x112a: 0xe00d, 0x112b: 0x0008, 0x112c: 0xe00d, 0x112d: 0x0008, 0x112e: 0x0008, 0x112f: 0x3308, 0x1130: 0x3318, 0x1131: 0x3318, 0x1132: 0x3318, 0x1133: 0x0018, 0x1134: 0x3308, 0x1135: 0x3308, 0x1136: 0x3308, 0x1137: 0x3308, 0x1138: 0x3308, 0x1139: 0x3308, 0x113a: 0x3308, 0x113b: 0x3308, 0x113c: 0x3308, 0x113d: 0x3308, 0x113e: 0x0018, 0x113f: 0x0008, // Block 0x45, offset 0x1140 0x1140: 0xe00d, 0x1141: 0x0008, 0x1142: 0xe00d, 0x1143: 0x0008, 0x1144: 0xe00d, 0x1145: 0x0008, 0x1146: 0xe00d, 0x1147: 0x0008, 0x1148: 0xe00d, 0x1149: 0x0008, 0x114a: 0xe00d, 0x114b: 0x0008, 0x114c: 0xe00d, 0x114d: 0x0008, 0x114e: 0xe00d, 0x114f: 0x0008, 0x1150: 0xe00d, 0x1151: 0x0008, 0x1152: 0xe00d, 0x1153: 0x0008, 0x1154: 0xe00d, 0x1155: 0x0008, 0x1156: 0xe00d, 0x1157: 0x0008, 0x1158: 0xe00d, 0x1159: 0x0008, 0x115a: 0xe00d, 0x115b: 0x0008, 0x115c: 0x0ea1, 0x115d: 0x6e11, 0x115e: 0x3308, 0x115f: 0x3308, 0x1160: 0x0008, 0x1161: 0x0008, 0x1162: 0x0008, 0x1163: 0x0008, 0x1164: 0x0008, 0x1165: 0x0008, 0x1166: 0x0008, 0x1167: 0x0008, 0x1168: 0x0008, 0x1169: 0x0008, 0x116a: 0x0008, 0x116b: 0x0008, 0x116c: 0x0008, 0x116d: 0x0008, 0x116e: 0x0008, 0x116f: 0x0008, 0x1170: 0x0008, 0x1171: 0x0008, 0x1172: 0x0008, 0x1173: 0x0008, 0x1174: 0x0008, 0x1175: 0x0008, 0x1176: 0x0008, 0x1177: 0x0008, 0x1178: 0x0008, 0x1179: 0x0008, 0x117a: 0x0008, 0x117b: 0x0008, 0x117c: 0x0008, 0x117d: 0x0008, 0x117e: 0x0008, 0x117f: 0x0008, // Block 0x46, offset 0x1180 0x1180: 0x0018, 0x1181: 0x0018, 0x1182: 0x0018, 0x1183: 0x0018, 0x1184: 0x0018, 0x1185: 0x0018, 0x1186: 0x0018, 0x1187: 0x0018, 0x1188: 0x0018, 0x1189: 0x0018, 0x118a: 0x0018, 0x118b: 0x0018, 0x118c: 0x0018, 0x118d: 0x0018, 0x118e: 0x0018, 0x118f: 0x0018, 0x1190: 0x0018, 0x1191: 0x0018, 0x1192: 0x0018, 0x1193: 0x0018, 0x1194: 0x0018, 0x1195: 0x0018, 0x1196: 0x0018, 0x1197: 0x0008, 0x1198: 0x0008, 0x1199: 0x0008, 0x119a: 0x0008, 0x119b: 0x0008, 0x119c: 0x0008, 0x119d: 0x0008, 0x119e: 0x0008, 0x119f: 0x0008, 0x11a0: 0x0018, 0x11a1: 0x0018, 0x11a2: 0xe00d, 0x11a3: 0x0008, 0x11a4: 0xe00d, 0x11a5: 0x0008, 0x11a6: 0xe00d, 0x11a7: 0x0008, 0x11a8: 0xe00d, 0x11a9: 0x0008, 0x11aa: 0xe00d, 0x11ab: 0x0008, 0x11ac: 0xe00d, 0x11ad: 0x0008, 0x11ae: 0xe00d, 0x11af: 0x0008, 0x11b0: 0x0008, 0x11b1: 0x0008, 0x11b2: 0xe00d, 0x11b3: 0x0008, 0x11b4: 0xe00d, 0x11b5: 0x0008, 0x11b6: 0xe00d, 0x11b7: 0x0008, 0x11b8: 0xe00d, 0x11b9: 0x0008, 0x11ba: 0xe00d, 0x11bb: 0x0008, 0x11bc: 0xe00d, 0x11bd: 0x0008, 0x11be: 0xe00d, 0x11bf: 0x0008, // Block 0x47, offset 0x11c0 0x11c0: 0xe00d, 0x11c1: 0x0008, 0x11c2: 0xe00d, 0x11c3: 0x0008, 0x11c4: 0xe00d, 0x11c5: 0x0008, 0x11c6: 0xe00d, 0x11c7: 0x0008, 0x11c8: 0xe00d, 0x11c9: 0x0008, 0x11ca: 0xe00d, 0x11cb: 0x0008, 0x11cc: 0xe00d, 0x11cd: 0x0008, 0x11ce: 0xe00d, 0x11cf: 0x0008, 0x11d0: 0xe00d, 0x11d1: 0x0008, 0x11d2: 0xe00d, 0x11d3: 0x0008, 0x11d4: 0xe00d, 0x11d5: 0x0008, 0x11d6: 0xe00d, 0x11d7: 0x0008, 0x11d8: 0xe00d, 0x11d9: 0x0008, 0x11da: 0xe00d, 0x11db: 0x0008, 0x11dc: 0xe00d, 0x11dd: 0x0008, 0x11de: 0xe00d, 0x11df: 0x0008, 0x11e0: 0xe00d, 0x11e1: 0x0008, 0x11e2: 0xe00d, 0x11e3: 0x0008, 0x11e4: 0xe00d, 0x11e5: 0x0008, 0x11e6: 0xe00d, 0x11e7: 0x0008, 0x11e8: 0xe00d, 0x11e9: 0x0008, 0x11ea: 0xe00d, 0x11eb: 0x0008, 0x11ec: 0xe00d, 0x11ed: 0x0008, 0x11ee: 0xe00d, 0x11ef: 0x0008, 0x11f0: 0xe0fd, 0x11f1: 0x0008, 0x11f2: 0x0008, 0x11f3: 0x0008, 0x11f4: 0x0008, 0x11f5: 0x0008, 0x11f6: 0x0008, 0x11f7: 0x0008, 0x11f8: 0x0008, 0x11f9: 0xe01d, 0x11fa: 0x0008, 0x11fb: 0xe03d, 0x11fc: 0x0008, 0x11fd: 0x442d, 0x11fe: 0xe00d, 0x11ff: 0x0008, // Block 0x48, offset 0x1200 0x1200: 0xe00d, 0x1201: 0x0008, 0x1202: 0xe00d, 0x1203: 0x0008, 0x1204: 0xe00d, 0x1205: 0x0008, 0x1206: 0xe00d, 0x1207: 0x0008, 0x1208: 0x0008, 0x1209: 0x0018, 0x120a: 0x0018, 0x120b: 0xe03d, 0x120c: 0x0008, 0x120d: 0x11d9, 0x120e: 0x0008, 0x120f: 0x0008, 0x1210: 0xe00d, 0x1211: 0x0008, 0x1212: 0xe00d, 0x1213: 0x0008, 0x1214: 0x0008, 0x1215: 0x0008, 0x1216: 0xe00d, 0x1217: 0x0008, 0x1218: 0xe00d, 0x1219: 0x0008, 0x121a: 0xe00d, 0x121b: 0x0008, 0x121c: 0xe00d, 0x121d: 0x0008, 0x121e: 0xe00d, 0x121f: 0x0008, 0x1220: 0xe00d, 0x1221: 0x0008, 0x1222: 0xe00d, 0x1223: 0x0008, 0x1224: 0xe00d, 0x1225: 0x0008, 0x1226: 0xe00d, 0x1227: 0x0008, 0x1228: 0xe00d, 0x1229: 0x0008, 0x122a: 0x6e29, 0x122b: 0x1029, 0x122c: 0x11c1, 0x122d: 0x6e41, 0x122e: 0x1221, 0x122f: 0x0008, 0x1230: 0x6e59, 0x1231: 0x6e71, 0x1232: 0x1239, 0x1233: 0x444d, 0x1234: 0xe00d, 0x1235: 0x0008, 0x1236: 0xe00d, 0x1237: 0x0008, 0x1238: 0x0040, 0x1239: 0x0008, 0x123a: 0x0040, 0x123b: 0x0040, 0x123c: 0x0040, 0x123d: 0x0040, 0x123e: 0x0040, 0x123f: 0x0040, // Block 0x49, offset 0x1240 0x1240: 0x64d5, 0x1241: 0x64f5, 0x1242: 0x6515, 0x1243: 0x6535, 0x1244: 0x6555, 0x1245: 0x6575, 0x1246: 0x6595, 0x1247: 0x65b5, 0x1248: 0x65d5, 0x1249: 0x65f5, 0x124a: 0x6615, 0x124b: 0x6635, 0x124c: 0x6655, 0x124d: 0x6675, 0x124e: 0x0008, 0x124f: 0x0008, 0x1250: 0x6695, 0x1251: 0x0008, 0x1252: 0x66b5, 0x1253: 0x0008, 0x1254: 0x0008, 0x1255: 0x66d5, 0x1256: 0x66f5, 0x1257: 0x6715, 0x1258: 0x6735, 0x1259: 0x6755, 0x125a: 0x6775, 0x125b: 0x6795, 0x125c: 0x67b5, 0x125d: 0x67d5, 0x125e: 0x67f5, 0x125f: 0x0008, 0x1260: 0x6815, 0x1261: 0x0008, 0x1262: 0x6835, 0x1263: 0x0008, 0x1264: 0x0008, 0x1265: 0x6855, 0x1266: 0x6875, 0x1267: 0x0008, 0x1268: 0x0008, 0x1269: 0x0008, 0x126a: 0x6895, 0x126b: 0x68b5, 0x126c: 0x68d5, 0x126d: 0x68f5, 0x126e: 0x6915, 0x126f: 0x6935, 0x1270: 0x6955, 0x1271: 0x6975, 0x1272: 0x6995, 0x1273: 0x69b5, 0x1274: 0x69d5, 0x1275: 0x69f5, 0x1276: 0x6a15, 0x1277: 0x6a35, 0x1278: 0x6a55, 0x1279: 0x6a75, 0x127a: 0x6a95, 0x127b: 0x6ab5, 0x127c: 0x6ad5, 0x127d: 0x6af5, 0x127e: 0x6b15, 0x127f: 0x6b35, // Block 0x4a, offset 0x1280 0x1280: 0x7a95, 0x1281: 0x7ab5, 0x1282: 0x7ad5, 0x1283: 0x7af5, 0x1284: 0x7b15, 0x1285: 0x7b35, 0x1286: 0x7b55, 0x1287: 0x7b75, 0x1288: 0x7b95, 0x1289: 0x7bb5, 0x128a: 0x7bd5, 0x128b: 0x7bf5, 0x128c: 0x7c15, 0x128d: 0x7c35, 0x128e: 0x7c55, 0x128f: 0x6ec9, 0x1290: 0x6ef1, 0x1291: 0x6f19, 0x1292: 0x7c75, 0x1293: 0x7c95, 0x1294: 0x7cb5, 0x1295: 0x6f41, 0x1296: 0x6f69, 0x1297: 0x6f91, 0x1298: 0x7cd5, 0x1299: 0x7cf5, 0x129a: 0x0040, 0x129b: 0x0040, 0x129c: 0x0040, 0x129d: 0x0040, 0x129e: 0x0040, 0x129f: 0x0040, 0x12a0: 0x0040, 0x12a1: 0x0040, 0x12a2: 0x0040, 0x12a3: 0x0040, 0x12a4: 0x0040, 0x12a5: 0x0040, 0x12a6: 0x0040, 0x12a7: 0x0040, 0x12a8: 0x0040, 0x12a9: 0x0040, 0x12aa: 0x0040, 0x12ab: 0x0040, 0x12ac: 0x0040, 0x12ad: 0x0040, 0x12ae: 0x0040, 0x12af: 0x0040, 0x12b0: 0x0040, 0x12b1: 0x0040, 0x12b2: 0x0040, 0x12b3: 0x0040, 0x12b4: 0x0040, 0x12b5: 0x0040, 0x12b6: 0x0040, 0x12b7: 0x0040, 0x12b8: 0x0040, 0x12b9: 0x0040, 0x12ba: 0x0040, 0x12bb: 0x0040, 0x12bc: 0x0040, 0x12bd: 0x0040, 0x12be: 0x0040, 0x12bf: 0x0040, // Block 0x4b, offset 0x12c0 0x12c0: 0x6fb9, 0x12c1: 0x6fd1, 0x12c2: 0x6fe9, 0x12c3: 0x7d15, 0x12c4: 0x7d35, 0x12c5: 0x7001, 0x12c6: 0x7001, 0x12c7: 0x0040, 0x12c8: 0x0040, 0x12c9: 0x0040, 0x12ca: 0x0040, 0x12cb: 0x0040, 0x12cc: 0x0040, 0x12cd: 0x0040, 0x12ce: 0x0040, 0x12cf: 0x0040, 0x12d0: 0x0040, 0x12d1: 0x0040, 0x12d2: 0x0040, 0x12d3: 0x7019, 0x12d4: 0x7041, 0x12d5: 0x7069, 0x12d6: 0x7091, 0x12d7: 0x70b9, 0x12d8: 0x0040, 0x12d9: 0x0040, 0x12da: 0x0040, 0x12db: 0x0040, 0x12dc: 0x0040, 0x12dd: 0x70e1, 0x12de: 0x3308, 0x12df: 0x7109, 0x12e0: 0x7131, 0x12e1: 0x20a9, 0x12e2: 0x20f1, 0x12e3: 0x7149, 0x12e4: 0x7161, 0x12e5: 0x7179, 0x12e6: 0x7191, 0x12e7: 0x71a9, 0x12e8: 0x71c1, 0x12e9: 0x1fb2, 0x12ea: 0x71d9, 0x12eb: 0x7201, 0x12ec: 0x7229, 0x12ed: 0x7261, 0x12ee: 0x7299, 0x12ef: 0x72c1, 0x12f0: 0x72e9, 0x12f1: 0x7311, 0x12f2: 0x7339, 0x12f3: 0x7361, 0x12f4: 0x7389, 0x12f5: 0x73b1, 0x12f6: 0x73d9, 0x12f7: 0x0040, 0x12f8: 0x7401, 0x12f9: 0x7429, 0x12fa: 0x7451, 0x12fb: 0x7479, 0x12fc: 0x74a1, 0x12fd: 0x0040, 0x12fe: 0x74c9, 0x12ff: 0x0040, // Block 0x4c, offset 0x1300 0x1300: 0x74f1, 0x1301: 0x7519, 0x1302: 0x0040, 0x1303: 0x7541, 0x1304: 0x7569, 0x1305: 0x0040, 0x1306: 0x7591, 0x1307: 0x75b9, 0x1308: 0x75e1, 0x1309: 0x7609, 0x130a: 0x7631, 0x130b: 0x7659, 0x130c: 0x7681, 0x130d: 0x76a9, 0x130e: 0x76d1, 0x130f: 0x76f9, 0x1310: 0x7721, 0x1311: 0x7721, 0x1312: 0x7739, 0x1313: 0x7739, 0x1314: 0x7739, 0x1315: 0x7739, 0x1316: 0x7751, 0x1317: 0x7751, 0x1318: 0x7751, 0x1319: 0x7751, 0x131a: 0x7769, 0x131b: 0x7769, 0x131c: 0x7769, 0x131d: 0x7769, 0x131e: 0x7781, 0x131f: 0x7781, 0x1320: 0x7781, 0x1321: 0x7781, 0x1322: 0x7799, 0x1323: 0x7799, 0x1324: 0x7799, 0x1325: 0x7799, 0x1326: 0x77b1, 0x1327: 0x77b1, 0x1328: 0x77b1, 0x1329: 0x77b1, 0x132a: 0x77c9, 0x132b: 0x77c9, 0x132c: 0x77c9, 0x132d: 0x77c9, 0x132e: 0x77e1, 0x132f: 0x77e1, 0x1330: 0x77e1, 0x1331: 0x77e1, 0x1332: 0x77f9, 0x1333: 0x77f9, 0x1334: 0x77f9, 0x1335: 0x77f9, 0x1336: 0x7811, 0x1337: 0x7811, 0x1338: 0x7811, 0x1339: 0x7811, 0x133a: 0x7829, 0x133b: 0x7829, 0x133c: 0x7829, 0x133d: 0x7829, 0x133e: 0x7841, 0x133f: 0x7841, // Block 0x4d, offset 0x1340 0x1340: 0x7841, 0x1341: 0x7841, 0x1342: 0x7859, 0x1343: 0x7859, 0x1344: 0x7871, 0x1345: 0x7871, 0x1346: 0x7889, 0x1347: 0x7889, 0x1348: 0x78a1, 0x1349: 0x78a1, 0x134a: 0x78b9, 0x134b: 0x78b9, 0x134c: 0x78d1, 0x134d: 0x78d1, 0x134e: 0x78e9, 0x134f: 0x78e9, 0x1350: 0x78e9, 0x1351: 0x78e9, 0x1352: 0x7901, 0x1353: 0x7901, 0x1354: 0x7901, 0x1355: 0x7901, 0x1356: 0x7919, 0x1357: 0x7919, 0x1358: 0x7919, 0x1359: 0x7919, 0x135a: 0x7931, 0x135b: 0x7931, 0x135c: 0x7931, 0x135d: 0x7931, 0x135e: 0x7949, 0x135f: 0x7949, 0x1360: 0x7961, 0x1361: 0x7961, 0x1362: 0x7961, 0x1363: 0x7961, 0x1364: 0x7979, 0x1365: 0x7979, 0x1366: 0x7991, 0x1367: 0x7991, 0x1368: 0x7991, 0x1369: 0x7991, 0x136a: 0x79a9, 0x136b: 0x79a9, 0x136c: 0x79a9, 0x136d: 0x79a9, 0x136e: 0x79c1, 0x136f: 0x79c1, 0x1370: 0x79d9, 0x1371: 0x79d9, 0x1372: 0x0818, 0x1373: 0x0818, 0x1374: 0x0818, 0x1375: 0x0818, 0x1376: 0x0818, 0x1377: 0x0818, 0x1378: 0x0818, 0x1379: 0x0818, 0x137a: 0x0818, 0x137b: 0x0818, 0x137c: 0x0818, 0x137d: 0x0818, 0x137e: 0x0818, 0x137f: 0x0818, // Block 0x4e, offset 0x1380 0x1380: 0x0818, 0x1381: 0x0818, 0x1382: 0x0040, 0x1383: 0x0040, 0x1384: 0x0040, 0x1385: 0x0040, 0x1386: 0x0040, 0x1387: 0x0040, 0x1388: 0x0040, 0x1389: 0x0040, 0x138a: 0x0040, 0x138b: 0x0040, 0x138c: 0x0040, 0x138d: 0x0040, 0x138e: 0x0040, 0x138f: 0x0040, 0x1390: 0x0040, 0x1391: 0x0040, 0x1392: 0x0040, 0x1393: 0x79f1, 0x1394: 0x79f1, 0x1395: 0x79f1, 0x1396: 0x79f1, 0x1397: 0x7a09, 0x1398: 0x7a09, 0x1399: 0x7a21, 0x139a: 0x7a21, 0x139b: 0x7a39, 0x139c: 0x7a39, 0x139d: 0x0479, 0x139e: 0x7a51, 0x139f: 0x7a51, 0x13a0: 0x7a69, 0x13a1: 0x7a69, 0x13a2: 0x7a81, 0x13a3: 0x7a81, 0x13a4: 0x7a99, 0x13a5: 0x7a99, 0x13a6: 0x7a99, 0x13a7: 0x7a99, 0x13a8: 0x7ab1, 0x13a9: 0x7ab1, 0x13aa: 0x7ac9, 0x13ab: 0x7ac9, 0x13ac: 0x7af1, 0x13ad: 0x7af1, 0x13ae: 0x7b19, 0x13af: 0x7b19, 0x13b0: 0x7b41, 0x13b1: 0x7b41, 0x13b2: 0x7b69, 0x13b3: 0x7b69, 0x13b4: 0x7b91, 0x13b5: 0x7b91, 0x13b6: 0x7bb9, 0x13b7: 0x7bb9, 0x13b8: 0x7bb9, 0x13b9: 0x7be1, 0x13ba: 0x7be1, 0x13bb: 0x7be1, 0x13bc: 0x7c09, 0x13bd: 0x7c09, 0x13be: 0x7c09, 0x13bf: 0x7c09, // Block 0x4f, offset 0x13c0 0x13c0: 0x85f9, 0x13c1: 0x8621, 0x13c2: 0x8649, 0x13c3: 0x8671, 0x13c4: 0x8699, 0x13c5: 0x86c1, 0x13c6: 0x86e9, 0x13c7: 0x8711, 0x13c8: 0x8739, 0x13c9: 0x8761, 0x13ca: 0x8789, 0x13cb: 0x87b1, 0x13cc: 0x87d9, 0x13cd: 0x8801, 0x13ce: 0x8829, 0x13cf: 0x8851, 0x13d0: 0x8879, 0x13d1: 0x88a1, 0x13d2: 0x88c9, 0x13d3: 0x88f1, 0x13d4: 0x8919, 0x13d5: 0x8941, 0x13d6: 0x8969, 0x13d7: 0x8991, 0x13d8: 0x89b9, 0x13d9: 0x89e1, 0x13da: 0x8a09, 0x13db: 0x8a31, 0x13dc: 0x8a59, 0x13dd: 0x8a81, 0x13de: 0x8aaa, 0x13df: 0x8ada, 0x13e0: 0x8b0a, 0x13e1: 0x8b3a, 0x13e2: 0x8b6a, 0x13e3: 0x8b9a, 0x13e4: 0x8bc9, 0x13e5: 0x8bf1, 0x13e6: 0x7c71, 0x13e7: 0x8c19, 0x13e8: 0x7be1, 0x13e9: 0x7c99, 0x13ea: 0x8c41, 0x13eb: 0x8c69, 0x13ec: 0x7d39, 0x13ed: 0x8c91, 0x13ee: 0x7d61, 0x13ef: 0x7d89, 0x13f0: 0x8cb9, 0x13f1: 0x8ce1, 0x13f2: 0x7e29, 0x13f3: 0x8d09, 0x13f4: 0x7e51, 0x13f5: 0x7e79, 0x13f6: 0x8d31, 0x13f7: 0x8d59, 0x13f8: 0x7ec9, 0x13f9: 0x8d81, 0x13fa: 0x7ef1, 0x13fb: 0x7f19, 0x13fc: 0x83a1, 0x13fd: 0x83c9, 0x13fe: 0x8441, 0x13ff: 0x8469, // Block 0x50, offset 0x1400 0x1400: 0x8491, 0x1401: 0x8531, 0x1402: 0x8559, 0x1403: 0x8581, 0x1404: 0x85a9, 0x1405: 0x8649, 0x1406: 0x8671, 0x1407: 0x8699, 0x1408: 0x8da9, 0x1409: 0x8739, 0x140a: 0x8dd1, 0x140b: 0x8df9, 0x140c: 0x8829, 0x140d: 0x8e21, 0x140e: 0x8851, 0x140f: 0x8879, 0x1410: 0x8a81, 0x1411: 0x8e49, 0x1412: 0x8e71, 0x1413: 0x89b9, 0x1414: 0x8e99, 0x1415: 0x89e1, 0x1416: 0x8a09, 0x1417: 0x7c21, 0x1418: 0x7c49, 0x1419: 0x8ec1, 0x141a: 0x7c71, 0x141b: 0x8ee9, 0x141c: 0x7cc1, 0x141d: 0x7ce9, 0x141e: 0x7d11, 0x141f: 0x7d39, 0x1420: 0x8f11, 0x1421: 0x7db1, 0x1422: 0x7dd9, 0x1423: 0x7e01, 0x1424: 0x7e29, 0x1425: 0x8f39, 0x1426: 0x7ec9, 0x1427: 0x7f41, 0x1428: 0x7f69, 0x1429: 0x7f91, 0x142a: 0x7fb9, 0x142b: 0x7fe1, 0x142c: 0x8031, 0x142d: 0x8059, 0x142e: 0x8081, 0x142f: 0x80a9, 0x1430: 0x80d1, 0x1431: 0x80f9, 0x1432: 0x8f61, 0x1433: 0x8121, 0x1434: 0x8149, 0x1435: 0x8171, 0x1436: 0x8199, 0x1437: 0x81c1, 0x1438: 0x81e9, 0x1439: 0x8239, 0x143a: 0x8261, 0x143b: 0x8289, 0x143c: 0x82b1, 0x143d: 0x82d9, 0x143e: 0x8301, 0x143f: 0x8329, // Block 0x51, offset 0x1440 0x1440: 0x8351, 0x1441: 0x8379, 0x1442: 0x83f1, 0x1443: 0x8419, 0x1444: 0x84b9, 0x1445: 0x84e1, 0x1446: 0x8509, 0x1447: 0x8531, 0x1448: 0x8559, 0x1449: 0x85d1, 0x144a: 0x85f9, 0x144b: 0x8621, 0x144c: 0x8649, 0x144d: 0x8f89, 0x144e: 0x86c1, 0x144f: 0x86e9, 0x1450: 0x8711, 0x1451: 0x8739, 0x1452: 0x87b1, 0x1453: 0x87d9, 0x1454: 0x8801, 0x1455: 0x8829, 0x1456: 0x8fb1, 0x1457: 0x88a1, 0x1458: 0x88c9, 0x1459: 0x8fd9, 0x145a: 0x8941, 0x145b: 0x8969, 0x145c: 0x8991, 0x145d: 0x89b9, 0x145e: 0x9001, 0x145f: 0x7c71, 0x1460: 0x8ee9, 0x1461: 0x7d39, 0x1462: 0x8f11, 0x1463: 0x7e29, 0x1464: 0x8f39, 0x1465: 0x7ec9, 0x1466: 0x9029, 0x1467: 0x80d1, 0x1468: 0x9051, 0x1469: 0x9079, 0x146a: 0x90a1, 0x146b: 0x8531, 0x146c: 0x8559, 0x146d: 0x8649, 0x146e: 0x8829, 0x146f: 0x8fb1, 0x1470: 0x89b9, 0x1471: 0x9001, 0x1472: 0x90c9, 0x1473: 0x9101, 0x1474: 0x9139, 0x1475: 0x9171, 0x1476: 0x9199, 0x1477: 0x91c1, 0x1478: 0x91e9, 0x1479: 0x9211, 0x147a: 0x9239, 0x147b: 0x9261, 0x147c: 0x9289, 0x147d: 0x92b1, 0x147e: 0x92d9, 0x147f: 0x9301, // Block 0x52, offset 0x1480 0x1480: 0x9329, 0x1481: 0x9351, 0x1482: 0x9379, 0x1483: 0x93a1, 0x1484: 0x93c9, 0x1485: 0x93f1, 0x1486: 0x9419, 0x1487: 0x9441, 0x1488: 0x9469, 0x1489: 0x9491, 0x148a: 0x94b9, 0x148b: 0x94e1, 0x148c: 0x9079, 0x148d: 0x9509, 0x148e: 0x9531, 0x148f: 0x9559, 0x1490: 0x9581, 0x1491: 0x9171, 0x1492: 0x9199, 0x1493: 0x91c1, 0x1494: 0x91e9, 0x1495: 0x9211, 0x1496: 0x9239, 0x1497: 0x9261, 0x1498: 0x9289, 0x1499: 0x92b1, 0x149a: 0x92d9, 0x149b: 0x9301, 0x149c: 0x9329, 0x149d: 0x9351, 0x149e: 0x9379, 0x149f: 0x93a1, 0x14a0: 0x93c9, 0x14a1: 0x93f1, 0x14a2: 0x9419, 0x14a3: 0x9441, 0x14a4: 0x9469, 0x14a5: 0x9491, 0x14a6: 0x94b9, 0x14a7: 0x94e1, 0x14a8: 0x9079, 0x14a9: 0x9509, 0x14aa: 0x9531, 0x14ab: 0x9559, 0x14ac: 0x9581, 0x14ad: 0x9491, 0x14ae: 0x94b9, 0x14af: 0x94e1, 0x14b0: 0x9079, 0x14b1: 0x9051, 0x14b2: 0x90a1, 0x14b3: 0x8211, 0x14b4: 0x8059, 0x14b5: 0x8081, 0x14b6: 0x80a9, 0x14b7: 0x9491, 0x14b8: 0x94b9, 0x14b9: 0x94e1, 0x14ba: 0x8211, 0x14bb: 0x8239, 0x14bc: 0x95a9, 0x14bd: 0x95a9, 0x14be: 0x0018, 0x14bf: 0x0018, // Block 0x53, offset 0x14c0 0x14c0: 0x0040, 0x14c1: 0x0040, 0x14c2: 0x0040, 0x14c3: 0x0040, 0x14c4: 0x0040, 0x14c5: 0x0040, 0x14c6: 0x0040, 0x14c7: 0x0040, 0x14c8: 0x0040, 0x14c9: 0x0040, 0x14ca: 0x0040, 0x14cb: 0x0040, 0x14cc: 0x0040, 0x14cd: 0x0040, 0x14ce: 0x0040, 0x14cf: 0x0040, 0x14d0: 0x95d1, 0x14d1: 0x9609, 0x14d2: 0x9609, 0x14d3: 0x9641, 0x14d4: 0x9679, 0x14d5: 0x96b1, 0x14d6: 0x96e9, 0x14d7: 0x9721, 0x14d8: 0x9759, 0x14d9: 0x9759, 0x14da: 0x9791, 0x14db: 0x97c9, 0x14dc: 0x9801, 0x14dd: 0x9839, 0x14de: 0x9871, 0x14df: 0x98a9, 0x14e0: 0x98a9, 0x14e1: 0x98e1, 0x14e2: 0x9919, 0x14e3: 0x9919, 0x14e4: 0x9951, 0x14e5: 0x9951, 0x14e6: 0x9989, 0x14e7: 0x99c1, 0x14e8: 0x99c1, 0x14e9: 0x99f9, 0x14ea: 0x9a31, 0x14eb: 0x9a31, 0x14ec: 0x9a69, 0x14ed: 0x9a69, 0x14ee: 0x9aa1, 0x14ef: 0x9ad9, 0x14f0: 0x9ad9, 0x14f1: 0x9b11, 0x14f2: 0x9b11, 0x14f3: 0x9b49, 0x14f4: 0x9b81, 0x14f5: 0x9bb9, 0x14f6: 0x9bf1, 0x14f7: 0x9bf1, 0x14f8: 0x9c29, 0x14f9: 0x9c61, 0x14fa: 0x9c99, 0x14fb: 0x9cd1, 0x14fc: 0x9d09, 0x14fd: 0x9d09, 0x14fe: 0x9d41, 0x14ff: 0x9d79, // Block 0x54, offset 0x1500 0x1500: 0xa949, 0x1501: 0xa981, 0x1502: 0xa9b9, 0x1503: 0xa8a1, 0x1504: 0x9bb9, 0x1505: 0x9989, 0x1506: 0xa9f1, 0x1507: 0xaa29, 0x1508: 0x0040, 0x1509: 0x0040, 0x150a: 0x0040, 0x150b: 0x0040, 0x150c: 0x0040, 0x150d: 0x0040, 0x150e: 0x0040, 0x150f: 0x0040, 0x1510: 0x0040, 0x1511: 0x0040, 0x1512: 0x0040, 0x1513: 0x0040, 0x1514: 0x0040, 0x1515: 0x0040, 0x1516: 0x0040, 0x1517: 0x0040, 0x1518: 0x0040, 0x1519: 0x0040, 0x151a: 0x0040, 0x151b: 0x0040, 0x151c: 0x0040, 0x151d: 0x0040, 0x151e: 0x0040, 0x151f: 0x0040, 0x1520: 0x0040, 0x1521: 0x0040, 0x1522: 0x0040, 0x1523: 0x0040, 0x1524: 0x0040, 0x1525: 0x0040, 0x1526: 0x0040, 0x1527: 0x0040, 0x1528: 0x0040, 0x1529: 0x0040, 0x152a: 0x0040, 0x152b: 0x0040, 0x152c: 0x0040, 0x152d: 0x0040, 0x152e: 0x0040, 0x152f: 0x0040, 0x1530: 0xaa61, 0x1531: 0xaa99, 0x1532: 0xaad1, 0x1533: 0xab19, 0x1534: 0xab61, 0x1535: 0xaba9, 0x1536: 0xabf1, 0x1537: 0xac39, 0x1538: 0xac81, 0x1539: 0xacc9, 0x153a: 0xad02, 0x153b: 0xae12, 0x153c: 0xae91, 0x153d: 0x0018, 0x153e: 0x0040, 0x153f: 0x0040, // Block 0x55, offset 0x1540 0x1540: 0x33c0, 0x1541: 0x33c0, 0x1542: 0x33c0, 0x1543: 0x33c0, 0x1544: 0x33c0, 0x1545: 0x33c0, 0x1546: 0x33c0, 0x1547: 0x33c0, 0x1548: 0x33c0, 0x1549: 0x33c0, 0x154a: 0x33c0, 0x154b: 0x33c0, 0x154c: 0x33c0, 0x154d: 0x33c0, 0x154e: 0x33c0, 0x154f: 0x33c0, 0x1550: 0xaeda, 0x1551: 0x7d55, 0x1552: 0x0040, 0x1553: 0xaeea, 0x1554: 0x03c2, 0x1555: 0xaefa, 0x1556: 0xaf0a, 0x1557: 0x7d75, 0x1558: 0x7d95, 0x1559: 0x0040, 0x155a: 0x0040, 0x155b: 0x0040, 0x155c: 0x0040, 0x155d: 0x0040, 0x155e: 0x0040, 0x155f: 0x0040, 0x1560: 0x3308, 0x1561: 0x3308, 0x1562: 0x3308, 0x1563: 0x3308, 0x1564: 0x3308, 0x1565: 0x3308, 0x1566: 0x3308, 0x1567: 0x3308, 0x1568: 0x3308, 0x1569: 0x3308, 0x156a: 0x3308, 0x156b: 0x3308, 0x156c: 0x3308, 0x156d: 0x3308, 0x156e: 0x3308, 0x156f: 0x3308, 0x1570: 0x0040, 0x1571: 0x7db5, 0x1572: 0x7dd5, 0x1573: 0xaf1a, 0x1574: 0xaf1a, 0x1575: 0x1fd2, 0x1576: 0x1fe2, 0x1577: 0xaf2a, 0x1578: 0xaf3a, 0x1579: 0x7df5, 0x157a: 0x7e15, 0x157b: 0x7e35, 0x157c: 0x7df5, 0x157d: 0x7e55, 0x157e: 0x7e75, 0x157f: 0x7e55, // Block 0x56, offset 0x1580 0x1580: 0x7e95, 0x1581: 0x7eb5, 0x1582: 0x7ed5, 0x1583: 0x7eb5, 0x1584: 0x7ef5, 0x1585: 0x0018, 0x1586: 0x0018, 0x1587: 0xaf4a, 0x1588: 0xaf5a, 0x1589: 0x7f16, 0x158a: 0x7f36, 0x158b: 0x7f56, 0x158c: 0x7f76, 0x158d: 0xaf1a, 0x158e: 0xaf1a, 0x158f: 0xaf1a, 0x1590: 0xaeda, 0x1591: 0x7f95, 0x1592: 0x0040, 0x1593: 0x0040, 0x1594: 0x03c2, 0x1595: 0xaeea, 0x1596: 0xaf0a, 0x1597: 0xaefa, 0x1598: 0x7fb5, 0x1599: 0x1fd2, 0x159a: 0x1fe2, 0x159b: 0xaf2a, 0x159c: 0xaf3a, 0x159d: 0x7e95, 0x159e: 0x7ef5, 0x159f: 0xaf6a, 0x15a0: 0xaf7a, 0x15a1: 0xaf8a, 0x15a2: 0x1fb2, 0x15a3: 0xaf99, 0x15a4: 0xafaa, 0x15a5: 0xafba, 0x15a6: 0x1fc2, 0x15a7: 0x0040, 0x15a8: 0xafca, 0x15a9: 0xafda, 0x15aa: 0xafea, 0x15ab: 0xaffa, 0x15ac: 0x0040, 0x15ad: 0x0040, 0x15ae: 0x0040, 0x15af: 0x0040, 0x15b0: 0x7fd6, 0x15b1: 0xb009, 0x15b2: 0x7ff6, 0x15b3: 0x0808, 0x15b4: 0x8016, 0x15b5: 0x0040, 0x15b6: 0x8036, 0x15b7: 0xb031, 0x15b8: 0x8056, 0x15b9: 0xb059, 0x15ba: 0x8076, 0x15bb: 0xb081, 0x15bc: 0x8096, 0x15bd: 0xb0a9, 0x15be: 0x80b6, 0x15bf: 0xb0d1, // Block 0x57, offset 0x15c0 0x15c0: 0xb0f9, 0x15c1: 0xb111, 0x15c2: 0xb111, 0x15c3: 0xb129, 0x15c4: 0xb129, 0x15c5: 0xb141, 0x15c6: 0xb141, 0x15c7: 0xb159, 0x15c8: 0xb159, 0x15c9: 0xb171, 0x15ca: 0xb171, 0x15cb: 0xb171, 0x15cc: 0xb171, 0x15cd: 0xb189, 0x15ce: 0xb189, 0x15cf: 0xb1a1, 0x15d0: 0xb1a1, 0x15d1: 0xb1a1, 0x15d2: 0xb1a1, 0x15d3: 0xb1b9, 0x15d4: 0xb1b9, 0x15d5: 0xb1d1, 0x15d6: 0xb1d1, 0x15d7: 0xb1d1, 0x15d8: 0xb1d1, 0x15d9: 0xb1e9, 0x15da: 0xb1e9, 0x15db: 0xb1e9, 0x15dc: 0xb1e9, 0x15dd: 0xb201, 0x15de: 0xb201, 0x15df: 0xb201, 0x15e0: 0xb201, 0x15e1: 0xb219, 0x15e2: 0xb219, 0x15e3: 0xb219, 0x15e4: 0xb219, 0x15e5: 0xb231, 0x15e6: 0xb231, 0x15e7: 0xb231, 0x15e8: 0xb231, 0x15e9: 0xb249, 0x15ea: 0xb249, 0x15eb: 0xb261, 0x15ec: 0xb261, 0x15ed: 0xb279, 0x15ee: 0xb279, 0x15ef: 0xb291, 0x15f0: 0xb291, 0x15f1: 0xb2a9, 0x15f2: 0xb2a9, 0x15f3: 0xb2a9, 0x15f4: 0xb2a9, 0x15f5: 0xb2c1, 0x15f6: 0xb2c1, 0x15f7: 0xb2c1, 0x15f8: 0xb2c1, 0x15f9: 0xb2d9, 0x15fa: 0xb2d9, 0x15fb: 0xb2d9, 0x15fc: 0xb2d9, 0x15fd: 0xb2f1, 0x15fe: 0xb2f1, 0x15ff: 0xb2f1, // Block 0x58, offset 0x1600 0x1600: 0xb2f1, 0x1601: 0xb309, 0x1602: 0xb309, 0x1603: 0xb309, 0x1604: 0xb309, 0x1605: 0xb321, 0x1606: 0xb321, 0x1607: 0xb321, 0x1608: 0xb321, 0x1609: 0xb339, 0x160a: 0xb339, 0x160b: 0xb339, 0x160c: 0xb339, 0x160d: 0xb351, 0x160e: 0xb351, 0x160f: 0xb351, 0x1610: 0xb351, 0x1611: 0xb369, 0x1612: 0xb369, 0x1613: 0xb369, 0x1614: 0xb369, 0x1615: 0xb381, 0x1616: 0xb381, 0x1617: 0xb381, 0x1618: 0xb381, 0x1619: 0xb399, 0x161a: 0xb399, 0x161b: 0xb399, 0x161c: 0xb399, 0x161d: 0xb3b1, 0x161e: 0xb3b1, 0x161f: 0xb3b1, 0x1620: 0xb3b1, 0x1621: 0xb3c9, 0x1622: 0xb3c9, 0x1623: 0xb3c9, 0x1624: 0xb3c9, 0x1625: 0xb3e1, 0x1626: 0xb3e1, 0x1627: 0xb3e1, 0x1628: 0xb3e1, 0x1629: 0xb3f9, 0x162a: 0xb3f9, 0x162b: 0xb3f9, 0x162c: 0xb3f9, 0x162d: 0xb411, 0x162e: 0xb411, 0x162f: 0x7ab1, 0x1630: 0x7ab1, 0x1631: 0xb429, 0x1632: 0xb429, 0x1633: 0xb429, 0x1634: 0xb429, 0x1635: 0xb441, 0x1636: 0xb441, 0x1637: 0xb469, 0x1638: 0xb469, 0x1639: 0xb491, 0x163a: 0xb491, 0x163b: 0xb4b9, 0x163c: 0xb4b9, 0x163d: 0x0040, 0x163e: 0x0040, 0x163f: 0x03c0, // Block 0x59, offset 0x1640 0x1640: 0x0040, 0x1641: 0xaefa, 0x1642: 0xb4e2, 0x1643: 0xaf6a, 0x1644: 0xafda, 0x1645: 0xafea, 0x1646: 0xaf7a, 0x1647: 0xb4f2, 0x1648: 0x1fd2, 0x1649: 0x1fe2, 0x164a: 0xaf8a, 0x164b: 0x1fb2, 0x164c: 0xaeda, 0x164d: 0xaf99, 0x164e: 0x29d1, 0x164f: 0xb502, 0x1650: 0x1f41, 0x1651: 0x00c9, 0x1652: 0x0069, 0x1653: 0x0079, 0x1654: 0x1f51, 0x1655: 0x1f61, 0x1656: 0x1f71, 0x1657: 0x1f81, 0x1658: 0x1f91, 0x1659: 0x1fa1, 0x165a: 0xaeea, 0x165b: 0x03c2, 0x165c: 0xafaa, 0x165d: 0x1fc2, 0x165e: 0xafba, 0x165f: 0xaf0a, 0x1660: 0xaffa, 0x1661: 0x0039, 0x1662: 0x0ee9, 0x1663: 0x1159, 0x1664: 0x0ef9, 0x1665: 0x0f09, 0x1666: 0x1199, 0x1667: 0x0f31, 0x1668: 0x0249, 0x1669: 0x0f41, 0x166a: 0x0259, 0x166b: 0x0f51, 0x166c: 0x0359, 0x166d: 0x0f61, 0x166e: 0x0f71, 0x166f: 0x00d9, 0x1670: 0x0f99, 0x1671: 0x2039, 0x1672: 0x0269, 0x1673: 0x01d9, 0x1674: 0x0fa9, 0x1675: 0x0fb9, 0x1676: 0x1089, 0x1677: 0x0279, 0x1678: 0x0369, 0x1679: 0x0289, 0x167a: 0x13d1, 0x167b: 0xaf4a, 0x167c: 0xafca, 0x167d: 0xaf5a, 0x167e: 0xb512, 0x167f: 0xaf1a, // Block 0x5a, offset 0x1680 0x1680: 0x1caa, 0x1681: 0x0039, 0x1682: 0x0ee9, 0x1683: 0x1159, 0x1684: 0x0ef9, 0x1685: 0x0f09, 0x1686: 0x1199, 0x1687: 0x0f31, 0x1688: 0x0249, 0x1689: 0x0f41, 0x168a: 0x0259, 0x168b: 0x0f51, 0x168c: 0x0359, 0x168d: 0x0f61, 0x168e: 0x0f71, 0x168f: 0x00d9, 0x1690: 0x0f99, 0x1691: 0x2039, 0x1692: 0x0269, 0x1693: 0x01d9, 0x1694: 0x0fa9, 0x1695: 0x0fb9, 0x1696: 0x1089, 0x1697: 0x0279, 0x1698: 0x0369, 0x1699: 0x0289, 0x169a: 0x13d1, 0x169b: 0xaf2a, 0x169c: 0xb522, 0x169d: 0xaf3a, 0x169e: 0xb532, 0x169f: 0x80d5, 0x16a0: 0x80f5, 0x16a1: 0x29d1, 0x16a2: 0x8115, 0x16a3: 0x8115, 0x16a4: 0x8135, 0x16a5: 0x8155, 0x16a6: 0x8175, 0x16a7: 0x8195, 0x16a8: 0x81b5, 0x16a9: 0x81d5, 0x16aa: 0x81f5, 0x16ab: 0x8215, 0x16ac: 0x8235, 0x16ad: 0x8255, 0x16ae: 0x8275, 0x16af: 0x8295, 0x16b0: 0x82b5, 0x16b1: 0x82d5, 0x16b2: 0x82f5, 0x16b3: 0x8315, 0x16b4: 0x8335, 0x16b5: 0x8355, 0x16b6: 0x8375, 0x16b7: 0x8395, 0x16b8: 0x83b5, 0x16b9: 0x83d5, 0x16ba: 0x83f5, 0x16bb: 0x8415, 0x16bc: 0x81b5, 0x16bd: 0x8435, 0x16be: 0x8455, 0x16bf: 0x8215, // Block 0x5b, offset 0x16c0 0x16c0: 0x8475, 0x16c1: 0x8495, 0x16c2: 0x84b5, 0x16c3: 0x84d5, 0x16c4: 0x84f5, 0x16c5: 0x8515, 0x16c6: 0x8535, 0x16c7: 0x8555, 0x16c8: 0x84d5, 0x16c9: 0x8575, 0x16ca: 0x84d5, 0x16cb: 0x8595, 0x16cc: 0x8595, 0x16cd: 0x85b5, 0x16ce: 0x85b5, 0x16cf: 0x85d5, 0x16d0: 0x8515, 0x16d1: 0x85f5, 0x16d2: 0x8615, 0x16d3: 0x85f5, 0x16d4: 0x8635, 0x16d5: 0x8615, 0x16d6: 0x8655, 0x16d7: 0x8655, 0x16d8: 0x8675, 0x16d9: 0x8675, 0x16da: 0x8695, 0x16db: 0x8695, 0x16dc: 0x8615, 0x16dd: 0x8115, 0x16de: 0x86b5, 0x16df: 0x86d5, 0x16e0: 0x0040, 0x16e1: 0x86f5, 0x16e2: 0x8715, 0x16e3: 0x8735, 0x16e4: 0x8755, 0x16e5: 0x8735, 0x16e6: 0x8775, 0x16e7: 0x8795, 0x16e8: 0x87b5, 0x16e9: 0x87b5, 0x16ea: 0x87d5, 0x16eb: 0x87d5, 0x16ec: 0x87f5, 0x16ed: 0x87f5, 0x16ee: 0x87d5, 0x16ef: 0x87d5, 0x16f0: 0x8815, 0x16f1: 0x8835, 0x16f2: 0x8855, 0x16f3: 0x8875, 0x16f4: 0x8895, 0x16f5: 0x88b5, 0x16f6: 0x88b5, 0x16f7: 0x88b5, 0x16f8: 0x88d5, 0x16f9: 0x88d5, 0x16fa: 0x88d5, 0x16fb: 0x88d5, 0x16fc: 0x87b5, 0x16fd: 0x87b5, 0x16fe: 0x87b5, 0x16ff: 0x0040, // Block 0x5c, offset 0x1700 0x1700: 0x0040, 0x1701: 0x0040, 0x1702: 0x8715, 0x1703: 0x86f5, 0x1704: 0x88f5, 0x1705: 0x86f5, 0x1706: 0x8715, 0x1707: 0x86f5, 0x1708: 0x0040, 0x1709: 0x0040, 0x170a: 0x8915, 0x170b: 0x8715, 0x170c: 0x8935, 0x170d: 0x88f5, 0x170e: 0x8935, 0x170f: 0x8715, 0x1710: 0x0040, 0x1711: 0x0040, 0x1712: 0x8955, 0x1713: 0x8975, 0x1714: 0x8875, 0x1715: 0x8935, 0x1716: 0x88f5, 0x1717: 0x8935, 0x1718: 0x0040, 0x1719: 0x0040, 0x171a: 0x8995, 0x171b: 0x89b5, 0x171c: 0x8995, 0x171d: 0x0040, 0x171e: 0x0040, 0x171f: 0x0040, 0x1720: 0xb541, 0x1721: 0xb559, 0x1722: 0xb571, 0x1723: 0x89d6, 0x1724: 0xb589, 0x1725: 0xb5a1, 0x1726: 0x89f5, 0x1727: 0x0040, 0x1728: 0x8a15, 0x1729: 0x8a35, 0x172a: 0x8a55, 0x172b: 0x8a35, 0x172c: 0x8a75, 0x172d: 0x8a95, 0x172e: 0x8ab5, 0x172f: 0x0040, 0x1730: 0x0040, 0x1731: 0x0040, 0x1732: 0x0040, 0x1733: 0x0040, 0x1734: 0x0040, 0x1735: 0x0040, 0x1736: 0x0040, 0x1737: 0x0040, 0x1738: 0x0040, 0x1739: 0x0340, 0x173a: 0x0340, 0x173b: 0x0340, 0x173c: 0x0040, 0x173d: 0x0040, 0x173e: 0x0040, 0x173f: 0x0040, // Block 0x5d, offset 0x1740 0x1740: 0x0a08, 0x1741: 0x0a08, 0x1742: 0x0a08, 0x1743: 0x0a08, 0x1744: 0x0a08, 0x1745: 0x0c08, 0x1746: 0x0808, 0x1747: 0x0c08, 0x1748: 0x0818, 0x1749: 0x0c08, 0x174a: 0x0c08, 0x174b: 0x0808, 0x174c: 0x0808, 0x174d: 0x0908, 0x174e: 0x0c08, 0x174f: 0x0c08, 0x1750: 0x0c08, 0x1751: 0x0c08, 0x1752: 0x0c08, 0x1753: 0x0a08, 0x1754: 0x0a08, 0x1755: 0x0a08, 0x1756: 0x0a08, 0x1757: 0x0908, 0x1758: 0x0a08, 0x1759: 0x0a08, 0x175a: 0x0a08, 0x175b: 0x0a08, 0x175c: 0x0a08, 0x175d: 0x0c08, 0x175e: 0x0a08, 0x175f: 0x0a08, 0x1760: 0x0a08, 0x1761: 0x0c08, 0x1762: 0x0808, 0x1763: 0x0808, 0x1764: 0x0c08, 0x1765: 0x3308, 0x1766: 0x3308, 0x1767: 0x0040, 0x1768: 0x0040, 0x1769: 0x0040, 0x176a: 0x0040, 0x176b: 0x0a18, 0x176c: 0x0a18, 0x176d: 0x0a18, 0x176e: 0x0a18, 0x176f: 0x0c18, 0x1770: 0x0818, 0x1771: 0x0818, 0x1772: 0x0818, 0x1773: 0x0818, 0x1774: 0x0818, 0x1775: 0x0818, 0x1776: 0x0818, 0x1777: 0x0040, 0x1778: 0x0040, 0x1779: 0x0040, 0x177a: 0x0040, 0x177b: 0x0040, 0x177c: 0x0040, 0x177d: 0x0040, 0x177e: 0x0040, 0x177f: 0x0040, // Block 0x5e, offset 0x1780 0x1780: 0x0a08, 0x1781: 0x0c08, 0x1782: 0x0a08, 0x1783: 0x0c08, 0x1784: 0x0c08, 0x1785: 0x0c08, 0x1786: 0x0a08, 0x1787: 0x0a08, 0x1788: 0x0a08, 0x1789: 0x0c08, 0x178a: 0x0a08, 0x178b: 0x0a08, 0x178c: 0x0c08, 0x178d: 0x0a08, 0x178e: 0x0c08, 0x178f: 0x0c08, 0x1790: 0x0a08, 0x1791: 0x0c08, 0x1792: 0x0040, 0x1793: 0x0040, 0x1794: 0x0040, 0x1795: 0x0040, 0x1796: 0x0040, 0x1797: 0x0040, 0x1798: 0x0040, 0x1799: 0x0818, 0x179a: 0x0818, 0x179b: 0x0818, 0x179c: 0x0818, 0x179d: 0x0040, 0x179e: 0x0040, 0x179f: 0x0040, 0x17a0: 0x0040, 0x17a1: 0x0040, 0x17a2: 0x0040, 0x17a3: 0x0040, 0x17a4: 0x0040, 0x17a5: 0x0040, 0x17a6: 0x0040, 0x17a7: 0x0040, 0x17a8: 0x0040, 0x17a9: 0x0c18, 0x17aa: 0x0c18, 0x17ab: 0x0c18, 0x17ac: 0x0c18, 0x17ad: 0x0a18, 0x17ae: 0x0a18, 0x17af: 0x0818, 0x17b0: 0x0040, 0x17b1: 0x0040, 0x17b2: 0x0040, 0x17b3: 0x0040, 0x17b4: 0x0040, 0x17b5: 0x0040, 0x17b6: 0x0040, 0x17b7: 0x0040, 0x17b8: 0x0040, 0x17b9: 0x0040, 0x17ba: 0x0040, 0x17bb: 0x0040, 0x17bc: 0x0040, 0x17bd: 0x0040, 0x17be: 0x0040, 0x17bf: 0x0040, // Block 0x5f, offset 0x17c0 0x17c0: 0x3308, 0x17c1: 0x3308, 0x17c2: 0x3008, 0x17c3: 0x3008, 0x17c4: 0x0040, 0x17c5: 0x0008, 0x17c6: 0x0008, 0x17c7: 0x0008, 0x17c8: 0x0008, 0x17c9: 0x0008, 0x17ca: 0x0008, 0x17cb: 0x0008, 0x17cc: 0x0008, 0x17cd: 0x0040, 0x17ce: 0x0040, 0x17cf: 0x0008, 0x17d0: 0x0008, 0x17d1: 0x0040, 0x17d2: 0x0040, 0x17d3: 0x0008, 0x17d4: 0x0008, 0x17d5: 0x0008, 0x17d6: 0x0008, 0x17d7: 0x0008, 0x17d8: 0x0008, 0x17d9: 0x0008, 0x17da: 0x0008, 0x17db: 0x0008, 0x17dc: 0x0008, 0x17dd: 0x0008, 0x17de: 0x0008, 0x17df: 0x0008, 0x17e0: 0x0008, 0x17e1: 0x0008, 0x17e2: 0x0008, 0x17e3: 0x0008, 0x17e4: 0x0008, 0x17e5: 0x0008, 0x17e6: 0x0008, 0x17e7: 0x0008, 0x17e8: 0x0008, 0x17e9: 0x0040, 0x17ea: 0x0008, 0x17eb: 0x0008, 0x17ec: 0x0008, 0x17ed: 0x0008, 0x17ee: 0x0008, 0x17ef: 0x0008, 0x17f0: 0x0008, 0x17f1: 0x0040, 0x17f2: 0x0008, 0x17f3: 0x0008, 0x17f4: 0x0040, 0x17f5: 0x0008, 0x17f6: 0x0008, 0x17f7: 0x0008, 0x17f8: 0x0008, 0x17f9: 0x0008, 0x17fa: 0x0040, 0x17fb: 0x3308, 0x17fc: 0x3308, 0x17fd: 0x0008, 0x17fe: 0x3008, 0x17ff: 0x3008, // Block 0x60, offset 0x1800 0x1800: 0x3308, 0x1801: 0x3008, 0x1802: 0x3008, 0x1803: 0x3008, 0x1804: 0x3008, 0x1805: 0x0040, 0x1806: 0x0040, 0x1807: 0x3008, 0x1808: 0x3008, 0x1809: 0x0040, 0x180a: 0x0040, 0x180b: 0x3008, 0x180c: 0x3008, 0x180d: 0x3808, 0x180e: 0x0040, 0x180f: 0x0040, 0x1810: 0x0008, 0x1811: 0x0040, 0x1812: 0x0040, 0x1813: 0x0040, 0x1814: 0x0040, 0x1815: 0x0040, 0x1816: 0x0040, 0x1817: 0x3008, 0x1818: 0x0040, 0x1819: 0x0040, 0x181a: 0x0040, 0x181b: 0x0040, 0x181c: 0x0040, 0x181d: 0x0008, 0x181e: 0x0008, 0x181f: 0x0008, 0x1820: 0x0008, 0x1821: 0x0008, 0x1822: 0x3008, 0x1823: 0x3008, 0x1824: 0x0040, 0x1825: 0x0040, 0x1826: 0x3308, 0x1827: 0x3308, 0x1828: 0x3308, 0x1829: 0x3308, 0x182a: 0x3308, 0x182b: 0x3308, 0x182c: 0x3308, 0x182d: 0x0040, 0x182e: 0x0040, 0x182f: 0x0040, 0x1830: 0x3308, 0x1831: 0x3308, 0x1832: 0x3308, 0x1833: 0x3308, 0x1834: 0x3308, 0x1835: 0x0040, 0x1836: 0x0040, 0x1837: 0x0040, 0x1838: 0x0040, 0x1839: 0x0040, 0x183a: 0x0040, 0x183b: 0x0040, 0x183c: 0x0040, 0x183d: 0x0040, 0x183e: 0x0040, 0x183f: 0x0040, // Block 0x61, offset 0x1840 0x1840: 0x0039, 0x1841: 0x0ee9, 0x1842: 0x1159, 0x1843: 0x0ef9, 0x1844: 0x0f09, 0x1845: 0x1199, 0x1846: 0x0f31, 0x1847: 0x0249, 0x1848: 0x0f41, 0x1849: 0x0259, 0x184a: 0x0f51, 0x184b: 0x0359, 0x184c: 0x0f61, 0x184d: 0x0f71, 0x184e: 0x00d9, 0x184f: 0x0f99, 0x1850: 0x2039, 0x1851: 0x0269, 0x1852: 0x01d9, 0x1853: 0x0fa9, 0x1854: 0x0fb9, 0x1855: 0x1089, 0x1856: 0x0279, 0x1857: 0x0369, 0x1858: 0x0289, 0x1859: 0x13d1, 0x185a: 0x0039, 0x185b: 0x0ee9, 0x185c: 0x1159, 0x185d: 0x0ef9, 0x185e: 0x0f09, 0x185f: 0x1199, 0x1860: 0x0f31, 0x1861: 0x0249, 0x1862: 0x0f41, 0x1863: 0x0259, 0x1864: 0x0f51, 0x1865: 0x0359, 0x1866: 0x0f61, 0x1867: 0x0f71, 0x1868: 0x00d9, 0x1869: 0x0f99, 0x186a: 0x2039, 0x186b: 0x0269, 0x186c: 0x01d9, 0x186d: 0x0fa9, 0x186e: 0x0fb9, 0x186f: 0x1089, 0x1870: 0x0279, 0x1871: 0x0369, 0x1872: 0x0289, 0x1873: 0x13d1, 0x1874: 0x0039, 0x1875: 0x0ee9, 0x1876: 0x1159, 0x1877: 0x0ef9, 0x1878: 0x0f09, 0x1879: 0x1199, 0x187a: 0x0f31, 0x187b: 0x0249, 0x187c: 0x0f41, 0x187d: 0x0259, 0x187e: 0x0f51, 0x187f: 0x0359, // Block 0x62, offset 0x1880 0x1880: 0x0f61, 0x1881: 0x0f71, 0x1882: 0x00d9, 0x1883: 0x0f99, 0x1884: 0x2039, 0x1885: 0x0269, 0x1886: 0x01d9, 0x1887: 0x0fa9, 0x1888: 0x0fb9, 0x1889: 0x1089, 0x188a: 0x0279, 0x188b: 0x0369, 0x188c: 0x0289, 0x188d: 0x13d1, 0x188e: 0x0039, 0x188f: 0x0ee9, 0x1890: 0x1159, 0x1891: 0x0ef9, 0x1892: 0x0f09, 0x1893: 0x1199, 0x1894: 0x0f31, 0x1895: 0x0040, 0x1896: 0x0f41, 0x1897: 0x0259, 0x1898: 0x0f51, 0x1899: 0x0359, 0x189a: 0x0f61, 0x189b: 0x0f71, 0x189c: 0x00d9, 0x189d: 0x0f99, 0x189e: 0x2039, 0x189f: 0x0269, 0x18a0: 0x01d9, 0x18a1: 0x0fa9, 0x18a2: 0x0fb9, 0x18a3: 0x1089, 0x18a4: 0x0279, 0x18a5: 0x0369, 0x18a6: 0x0289, 0x18a7: 0x13d1, 0x18a8: 0x0039, 0x18a9: 0x0ee9, 0x18aa: 0x1159, 0x18ab: 0x0ef9, 0x18ac: 0x0f09, 0x18ad: 0x1199, 0x18ae: 0x0f31, 0x18af: 0x0249, 0x18b0: 0x0f41, 0x18b1: 0x0259, 0x18b2: 0x0f51, 0x18b3: 0x0359, 0x18b4: 0x0f61, 0x18b5: 0x0f71, 0x18b6: 0x00d9, 0x18b7: 0x0f99, 0x18b8: 0x2039, 0x18b9: 0x0269, 0x18ba: 0x01d9, 0x18bb: 0x0fa9, 0x18bc: 0x0fb9, 0x18bd: 0x1089, 0x18be: 0x0279, 0x18bf: 0x0369, // Block 0x63, offset 0x18c0 0x18c0: 0x0289, 0x18c1: 0x13d1, 0x18c2: 0x0039, 0x18c3: 0x0ee9, 0x18c4: 0x1159, 0x18c5: 0x0ef9, 0x18c6: 0x0f09, 0x18c7: 0x1199, 0x18c8: 0x0f31, 0x18c9: 0x0249, 0x18ca: 0x0f41, 0x18cb: 0x0259, 0x18cc: 0x0f51, 0x18cd: 0x0359, 0x18ce: 0x0f61, 0x18cf: 0x0f71, 0x18d0: 0x00d9, 0x18d1: 0x0f99, 0x18d2: 0x2039, 0x18d3: 0x0269, 0x18d4: 0x01d9, 0x18d5: 0x0fa9, 0x18d6: 0x0fb9, 0x18d7: 0x1089, 0x18d8: 0x0279, 0x18d9: 0x0369, 0x18da: 0x0289, 0x18db: 0x13d1, 0x18dc: 0x0039, 0x18dd: 0x0040, 0x18de: 0x1159, 0x18df: 0x0ef9, 0x18e0: 0x0040, 0x18e1: 0x0040, 0x18e2: 0x0f31, 0x18e3: 0x0040, 0x18e4: 0x0040, 0x18e5: 0x0259, 0x18e6: 0x0f51, 0x18e7: 0x0040, 0x18e8: 0x0040, 0x18e9: 0x0f71, 0x18ea: 0x00d9, 0x18eb: 0x0f99, 0x18ec: 0x2039, 0x18ed: 0x0040, 0x18ee: 0x01d9, 0x18ef: 0x0fa9, 0x18f0: 0x0fb9, 0x18f1: 0x1089, 0x18f2: 0x0279, 0x18f3: 0x0369, 0x18f4: 0x0289, 0x18f5: 0x13d1, 0x18f6: 0x0039, 0x18f7: 0x0ee9, 0x18f8: 0x1159, 0x18f9: 0x0ef9, 0x18fa: 0x0040, 0x18fb: 0x1199, 0x18fc: 0x0040, 0x18fd: 0x0249, 0x18fe: 0x0f41, 0x18ff: 0x0259, // Block 0x64, offset 0x1900 0x1900: 0x0f51, 0x1901: 0x0359, 0x1902: 0x0f61, 0x1903: 0x0f71, 0x1904: 0x0040, 0x1905: 0x0f99, 0x1906: 0x2039, 0x1907: 0x0269, 0x1908: 0x01d9, 0x1909: 0x0fa9, 0x190a: 0x0fb9, 0x190b: 0x1089, 0x190c: 0x0279, 0x190d: 0x0369, 0x190e: 0x0289, 0x190f: 0x13d1, 0x1910: 0x0039, 0x1911: 0x0ee9, 0x1912: 0x1159, 0x1913: 0x0ef9, 0x1914: 0x0f09, 0x1915: 0x1199, 0x1916: 0x0f31, 0x1917: 0x0249, 0x1918: 0x0f41, 0x1919: 0x0259, 0x191a: 0x0f51, 0x191b: 0x0359, 0x191c: 0x0f61, 0x191d: 0x0f71, 0x191e: 0x00d9, 0x191f: 0x0f99, 0x1920: 0x2039, 0x1921: 0x0269, 0x1922: 0x01d9, 0x1923: 0x0fa9, 0x1924: 0x0fb9, 0x1925: 0x1089, 0x1926: 0x0279, 0x1927: 0x0369, 0x1928: 0x0289, 0x1929: 0x13d1, 0x192a: 0x0039, 0x192b: 0x0ee9, 0x192c: 0x1159, 0x192d: 0x0ef9, 0x192e: 0x0f09, 0x192f: 0x1199, 0x1930: 0x0f31, 0x1931: 0x0249, 0x1932: 0x0f41, 0x1933: 0x0259, 0x1934: 0x0f51, 0x1935: 0x0359, 0x1936: 0x0f61, 0x1937: 0x0f71, 0x1938: 0x00d9, 0x1939: 0x0f99, 0x193a: 0x2039, 0x193b: 0x0269, 0x193c: 0x01d9, 0x193d: 0x0fa9, 0x193e: 0x0fb9, 0x193f: 0x1089, // Block 0x65, offset 0x1940 0x1940: 0x0279, 0x1941: 0x0369, 0x1942: 0x0289, 0x1943: 0x13d1, 0x1944: 0x0039, 0x1945: 0x0ee9, 0x1946: 0x0040, 0x1947: 0x0ef9, 0x1948: 0x0f09, 0x1949: 0x1199, 0x194a: 0x0f31, 0x194b: 0x0040, 0x194c: 0x0040, 0x194d: 0x0259, 0x194e: 0x0f51, 0x194f: 0x0359, 0x1950: 0x0f61, 0x1951: 0x0f71, 0x1952: 0x00d9, 0x1953: 0x0f99, 0x1954: 0x2039, 0x1955: 0x0040, 0x1956: 0x01d9, 0x1957: 0x0fa9, 0x1958: 0x0fb9, 0x1959: 0x1089, 0x195a: 0x0279, 0x195b: 0x0369, 0x195c: 0x0289, 0x195d: 0x0040, 0x195e: 0x0039, 0x195f: 0x0ee9, 0x1960: 0x1159, 0x1961: 0x0ef9, 0x1962: 0x0f09, 0x1963: 0x1199, 0x1964: 0x0f31, 0x1965: 0x0249, 0x1966: 0x0f41, 0x1967: 0x0259, 0x1968: 0x0f51, 0x1969: 0x0359, 0x196a: 0x0f61, 0x196b: 0x0f71, 0x196c: 0x00d9, 0x196d: 0x0f99, 0x196e: 0x2039, 0x196f: 0x0269, 0x1970: 0x01d9, 0x1971: 0x0fa9, 0x1972: 0x0fb9, 0x1973: 0x1089, 0x1974: 0x0279, 0x1975: 0x0369, 0x1976: 0x0289, 0x1977: 0x13d1, 0x1978: 0x0039, 0x1979: 0x0ee9, 0x197a: 0x0040, 0x197b: 0x0ef9, 0x197c: 0x0f09, 0x197d: 0x1199, 0x197e: 0x0f31, 0x197f: 0x0040, // Block 0x66, offset 0x1980 0x1980: 0x0f41, 0x1981: 0x0259, 0x1982: 0x0f51, 0x1983: 0x0359, 0x1984: 0x0f61, 0x1985: 0x0040, 0x1986: 0x00d9, 0x1987: 0x0040, 0x1988: 0x0040, 0x1989: 0x0040, 0x198a: 0x01d9, 0x198b: 0x0fa9, 0x198c: 0x0fb9, 0x198d: 0x1089, 0x198e: 0x0279, 0x198f: 0x0369, 0x1990: 0x0289, 0x1991: 0x0040, 0x1992: 0x0039, 0x1993: 0x0ee9, 0x1994: 0x1159, 0x1995: 0x0ef9, 0x1996: 0x0f09, 0x1997: 0x1199, 0x1998: 0x0f31, 0x1999: 0x0249, 0x199a: 0x0f41, 0x199b: 0x0259, 0x199c: 0x0f51, 0x199d: 0x0359, 0x199e: 0x0f61, 0x199f: 0x0f71, 0x19a0: 0x00d9, 0x19a1: 0x0f99, 0x19a2: 0x2039, 0x19a3: 0x0269, 0x19a4: 0x01d9, 0x19a5: 0x0fa9, 0x19a6: 0x0fb9, 0x19a7: 0x1089, 0x19a8: 0x0279, 0x19a9: 0x0369, 0x19aa: 0x0289, 0x19ab: 0x13d1, 0x19ac: 0x0039, 0x19ad: 0x0ee9, 0x19ae: 0x1159, 0x19af: 0x0ef9, 0x19b0: 0x0f09, 0x19b1: 0x1199, 0x19b2: 0x0f31, 0x19b3: 0x0249, 0x19b4: 0x0f41, 0x19b5: 0x0259, 0x19b6: 0x0f51, 0x19b7: 0x0359, 0x19b8: 0x0f61, 0x19b9: 0x0f71, 0x19ba: 0x00d9, 0x19bb: 0x0f99, 0x19bc: 0x2039, 0x19bd: 0x0269, 0x19be: 0x01d9, 0x19bf: 0x0fa9, // Block 0x67, offset 0x19c0 0x19c0: 0x0fb9, 0x19c1: 0x1089, 0x19c2: 0x0279, 0x19c3: 0x0369, 0x19c4: 0x0289, 0x19c5: 0x13d1, 0x19c6: 0x0039, 0x19c7: 0x0ee9, 0x19c8: 0x1159, 0x19c9: 0x0ef9, 0x19ca: 0x0f09, 0x19cb: 0x1199, 0x19cc: 0x0f31, 0x19cd: 0x0249, 0x19ce: 0x0f41, 0x19cf: 0x0259, 0x19d0: 0x0f51, 0x19d1: 0x0359, 0x19d2: 0x0f61, 0x19d3: 0x0f71, 0x19d4: 0x00d9, 0x19d5: 0x0f99, 0x19d6: 0x2039, 0x19d7: 0x0269, 0x19d8: 0x01d9, 0x19d9: 0x0fa9, 0x19da: 0x0fb9, 0x19db: 0x1089, 0x19dc: 0x0279, 0x19dd: 0x0369, 0x19de: 0x0289, 0x19df: 0x13d1, 0x19e0: 0x0039, 0x19e1: 0x0ee9, 0x19e2: 0x1159, 0x19e3: 0x0ef9, 0x19e4: 0x0f09, 0x19e5: 0x1199, 0x19e6: 0x0f31, 0x19e7: 0x0249, 0x19e8: 0x0f41, 0x19e9: 0x0259, 0x19ea: 0x0f51, 0x19eb: 0x0359, 0x19ec: 0x0f61, 0x19ed: 0x0f71, 0x19ee: 0x00d9, 0x19ef: 0x0f99, 0x19f0: 0x2039, 0x19f1: 0x0269, 0x19f2: 0x01d9, 0x19f3: 0x0fa9, 0x19f4: 0x0fb9, 0x19f5: 0x1089, 0x19f6: 0x0279, 0x19f7: 0x0369, 0x19f8: 0x0289, 0x19f9: 0x13d1, 0x19fa: 0x0039, 0x19fb: 0x0ee9, 0x19fc: 0x1159, 0x19fd: 0x0ef9, 0x19fe: 0x0f09, 0x19ff: 0x1199, // Block 0x68, offset 0x1a00 0x1a00: 0x0f31, 0x1a01: 0x0249, 0x1a02: 0x0f41, 0x1a03: 0x0259, 0x1a04: 0x0f51, 0x1a05: 0x0359, 0x1a06: 0x0f61, 0x1a07: 0x0f71, 0x1a08: 0x00d9, 0x1a09: 0x0f99, 0x1a0a: 0x2039, 0x1a0b: 0x0269, 0x1a0c: 0x01d9, 0x1a0d: 0x0fa9, 0x1a0e: 0x0fb9, 0x1a0f: 0x1089, 0x1a10: 0x0279, 0x1a11: 0x0369, 0x1a12: 0x0289, 0x1a13: 0x13d1, 0x1a14: 0x0039, 0x1a15: 0x0ee9, 0x1a16: 0x1159, 0x1a17: 0x0ef9, 0x1a18: 0x0f09, 0x1a19: 0x1199, 0x1a1a: 0x0f31, 0x1a1b: 0x0249, 0x1a1c: 0x0f41, 0x1a1d: 0x0259, 0x1a1e: 0x0f51, 0x1a1f: 0x0359, 0x1a20: 0x0f61, 0x1a21: 0x0f71, 0x1a22: 0x00d9, 0x1a23: 0x0f99, 0x1a24: 0x2039, 0x1a25: 0x0269, 0x1a26: 0x01d9, 0x1a27: 0x0fa9, 0x1a28: 0x0fb9, 0x1a29: 0x1089, 0x1a2a: 0x0279, 0x1a2b: 0x0369, 0x1a2c: 0x0289, 0x1a2d: 0x13d1, 0x1a2e: 0x0039, 0x1a2f: 0x0ee9, 0x1a30: 0x1159, 0x1a31: 0x0ef9, 0x1a32: 0x0f09, 0x1a33: 0x1199, 0x1a34: 0x0f31, 0x1a35: 0x0249, 0x1a36: 0x0f41, 0x1a37: 0x0259, 0x1a38: 0x0f51, 0x1a39: 0x0359, 0x1a3a: 0x0f61, 0x1a3b: 0x0f71, 0x1a3c: 0x00d9, 0x1a3d: 0x0f99, 0x1a3e: 0x2039, 0x1a3f: 0x0269, // Block 0x69, offset 0x1a40 0x1a40: 0x01d9, 0x1a41: 0x0fa9, 0x1a42: 0x0fb9, 0x1a43: 0x1089, 0x1a44: 0x0279, 0x1a45: 0x0369, 0x1a46: 0x0289, 0x1a47: 0x13d1, 0x1a48: 0x0039, 0x1a49: 0x0ee9, 0x1a4a: 0x1159, 0x1a4b: 0x0ef9, 0x1a4c: 0x0f09, 0x1a4d: 0x1199, 0x1a4e: 0x0f31, 0x1a4f: 0x0249, 0x1a50: 0x0f41, 0x1a51: 0x0259, 0x1a52: 0x0f51, 0x1a53: 0x0359, 0x1a54: 0x0f61, 0x1a55: 0x0f71, 0x1a56: 0x00d9, 0x1a57: 0x0f99, 0x1a58: 0x2039, 0x1a59: 0x0269, 0x1a5a: 0x01d9, 0x1a5b: 0x0fa9, 0x1a5c: 0x0fb9, 0x1a5d: 0x1089, 0x1a5e: 0x0279, 0x1a5f: 0x0369, 0x1a60: 0x0289, 0x1a61: 0x13d1, 0x1a62: 0x0039, 0x1a63: 0x0ee9, 0x1a64: 0x1159, 0x1a65: 0x0ef9, 0x1a66: 0x0f09, 0x1a67: 0x1199, 0x1a68: 0x0f31, 0x1a69: 0x0249, 0x1a6a: 0x0f41, 0x1a6b: 0x0259, 0x1a6c: 0x0f51, 0x1a6d: 0x0359, 0x1a6e: 0x0f61, 0x1a6f: 0x0f71, 0x1a70: 0x00d9, 0x1a71: 0x0f99, 0x1a72: 0x2039, 0x1a73: 0x0269, 0x1a74: 0x01d9, 0x1a75: 0x0fa9, 0x1a76: 0x0fb9, 0x1a77: 0x1089, 0x1a78: 0x0279, 0x1a79: 0x0369, 0x1a7a: 0x0289, 0x1a7b: 0x13d1, 0x1a7c: 0x0039, 0x1a7d: 0x0ee9, 0x1a7e: 0x1159, 0x1a7f: 0x0ef9, // Block 0x6a, offset 0x1a80 0x1a80: 0x0f09, 0x1a81: 0x1199, 0x1a82: 0x0f31, 0x1a83: 0x0249, 0x1a84: 0x0f41, 0x1a85: 0x0259, 0x1a86: 0x0f51, 0x1a87: 0x0359, 0x1a88: 0x0f61, 0x1a89: 0x0f71, 0x1a8a: 0x00d9, 0x1a8b: 0x0f99, 0x1a8c: 0x2039, 0x1a8d: 0x0269, 0x1a8e: 0x01d9, 0x1a8f: 0x0fa9, 0x1a90: 0x0fb9, 0x1a91: 0x1089, 0x1a92: 0x0279, 0x1a93: 0x0369, 0x1a94: 0x0289, 0x1a95: 0x13d1, 0x1a96: 0x0039, 0x1a97: 0x0ee9, 0x1a98: 0x1159, 0x1a99: 0x0ef9, 0x1a9a: 0x0f09, 0x1a9b: 0x1199, 0x1a9c: 0x0f31, 0x1a9d: 0x0249, 0x1a9e: 0x0f41, 0x1a9f: 0x0259, 0x1aa0: 0x0f51, 0x1aa1: 0x0359, 0x1aa2: 0x0f61, 0x1aa3: 0x0f71, 0x1aa4: 0x00d9, 0x1aa5: 0x0f99, 0x1aa6: 0x2039, 0x1aa7: 0x0269, 0x1aa8: 0x01d9, 0x1aa9: 0x0fa9, 0x1aaa: 0x0fb9, 0x1aab: 0x1089, 0x1aac: 0x0279, 0x1aad: 0x0369, 0x1aae: 0x0289, 0x1aaf: 0x13d1, 0x1ab0: 0x0039, 0x1ab1: 0x0ee9, 0x1ab2: 0x1159, 0x1ab3: 0x0ef9, 0x1ab4: 0x0f09, 0x1ab5: 0x1199, 0x1ab6: 0x0f31, 0x1ab7: 0x0249, 0x1ab8: 0x0f41, 0x1ab9: 0x0259, 0x1aba: 0x0f51, 0x1abb: 0x0359, 0x1abc: 0x0f61, 0x1abd: 0x0f71, 0x1abe: 0x00d9, 0x1abf: 0x0f99, // Block 0x6b, offset 0x1ac0 0x1ac0: 0x2039, 0x1ac1: 0x0269, 0x1ac2: 0x01d9, 0x1ac3: 0x0fa9, 0x1ac4: 0x0fb9, 0x1ac5: 0x1089, 0x1ac6: 0x0279, 0x1ac7: 0x0369, 0x1ac8: 0x0289, 0x1ac9: 0x13d1, 0x1aca: 0x0039, 0x1acb: 0x0ee9, 0x1acc: 0x1159, 0x1acd: 0x0ef9, 0x1ace: 0x0f09, 0x1acf: 0x1199, 0x1ad0: 0x0f31, 0x1ad1: 0x0249, 0x1ad2: 0x0f41, 0x1ad3: 0x0259, 0x1ad4: 0x0f51, 0x1ad5: 0x0359, 0x1ad6: 0x0f61, 0x1ad7: 0x0f71, 0x1ad8: 0x00d9, 0x1ad9: 0x0f99, 0x1ada: 0x2039, 0x1adb: 0x0269, 0x1adc: 0x01d9, 0x1add: 0x0fa9, 0x1ade: 0x0fb9, 0x1adf: 0x1089, 0x1ae0: 0x0279, 0x1ae1: 0x0369, 0x1ae2: 0x0289, 0x1ae3: 0x13d1, 0x1ae4: 0xba81, 0x1ae5: 0xba99, 0x1ae6: 0x0040, 0x1ae7: 0x0040, 0x1ae8: 0xbab1, 0x1ae9: 0x1099, 0x1aea: 0x10b1, 0x1aeb: 0x10c9, 0x1aec: 0xbac9, 0x1aed: 0xbae1, 0x1aee: 0xbaf9, 0x1aef: 0x1429, 0x1af0: 0x1a31, 0x1af1: 0xbb11, 0x1af2: 0xbb29, 0x1af3: 0xbb41, 0x1af4: 0xbb59, 0x1af5: 0xbb71, 0x1af6: 0xbb89, 0x1af7: 0x2109, 0x1af8: 0x1111, 0x1af9: 0x1429, 0x1afa: 0xbba1, 0x1afb: 0xbbb9, 0x1afc: 0xbbd1, 0x1afd: 0x10e1, 0x1afe: 0x10f9, 0x1aff: 0xbbe9, // Block 0x6c, offset 0x1b00 0x1b00: 0x2079, 0x1b01: 0xbc01, 0x1b02: 0xbab1, 0x1b03: 0x1099, 0x1b04: 0x10b1, 0x1b05: 0x10c9, 0x1b06: 0xbac9, 0x1b07: 0xbae1, 0x1b08: 0xbaf9, 0x1b09: 0x1429, 0x1b0a: 0x1a31, 0x1b0b: 0xbb11, 0x1b0c: 0xbb29, 0x1b0d: 0xbb41, 0x1b0e: 0xbb59, 0x1b0f: 0xbb71, 0x1b10: 0xbb89, 0x1b11: 0x2109, 0x1b12: 0x1111, 0x1b13: 0xbba1, 0x1b14: 0xbba1, 0x1b15: 0xbbb9, 0x1b16: 0xbbd1, 0x1b17: 0x10e1, 0x1b18: 0x10f9, 0x1b19: 0xbbe9, 0x1b1a: 0x2079, 0x1b1b: 0xbc21, 0x1b1c: 0xbac9, 0x1b1d: 0x1429, 0x1b1e: 0xbb11, 0x1b1f: 0x10e1, 0x1b20: 0x1111, 0x1b21: 0x2109, 0x1b22: 0xbab1, 0x1b23: 0x1099, 0x1b24: 0x10b1, 0x1b25: 0x10c9, 0x1b26: 0xbac9, 0x1b27: 0xbae1, 0x1b28: 0xbaf9, 0x1b29: 0x1429, 0x1b2a: 0x1a31, 0x1b2b: 0xbb11, 0x1b2c: 0xbb29, 0x1b2d: 0xbb41, 0x1b2e: 0xbb59, 0x1b2f: 0xbb71, 0x1b30: 0xbb89, 0x1b31: 0x2109, 0x1b32: 0x1111, 0x1b33: 0x1429, 0x1b34: 0xbba1, 0x1b35: 0xbbb9, 0x1b36: 0xbbd1, 0x1b37: 0x10e1, 0x1b38: 0x10f9, 0x1b39: 0xbbe9, 0x1b3a: 0x2079, 0x1b3b: 0xbc01, 0x1b3c: 0xbab1, 0x1b3d: 0x1099, 0x1b3e: 0x10b1, 0x1b3f: 0x10c9, // Block 0x6d, offset 0x1b40 0x1b40: 0xbac9, 0x1b41: 0xbae1, 0x1b42: 0xbaf9, 0x1b43: 0x1429, 0x1b44: 0x1a31, 0x1b45: 0xbb11, 0x1b46: 0xbb29, 0x1b47: 0xbb41, 0x1b48: 0xbb59, 0x1b49: 0xbb71, 0x1b4a: 0xbb89, 0x1b4b: 0x2109, 0x1b4c: 0x1111, 0x1b4d: 0xbba1, 0x1b4e: 0xbba1, 0x1b4f: 0xbbb9, 0x1b50: 0xbbd1, 0x1b51: 0x10e1, 0x1b52: 0x10f9, 0x1b53: 0xbbe9, 0x1b54: 0x2079, 0x1b55: 0xbc21, 0x1b56: 0xbac9, 0x1b57: 0x1429, 0x1b58: 0xbb11, 0x1b59: 0x10e1, 0x1b5a: 0x1111, 0x1b5b: 0x2109, 0x1b5c: 0xbab1, 0x1b5d: 0x1099, 0x1b5e: 0x10b1, 0x1b5f: 0x10c9, 0x1b60: 0xbac9, 0x1b61: 0xbae1, 0x1b62: 0xbaf9, 0x1b63: 0x1429, 0x1b64: 0x1a31, 0x1b65: 0xbb11, 0x1b66: 0xbb29, 0x1b67: 0xbb41, 0x1b68: 0xbb59, 0x1b69: 0xbb71, 0x1b6a: 0xbb89, 0x1b6b: 0x2109, 0x1b6c: 0x1111, 0x1b6d: 0x1429, 0x1b6e: 0xbba1, 0x1b6f: 0xbbb9, 0x1b70: 0xbbd1, 0x1b71: 0x10e1, 0x1b72: 0x10f9, 0x1b73: 0xbbe9, 0x1b74: 0x2079, 0x1b75: 0xbc01, 0x1b76: 0xbab1, 0x1b77: 0x1099, 0x1b78: 0x10b1, 0x1b79: 0x10c9, 0x1b7a: 0xbac9, 0x1b7b: 0xbae1, 0x1b7c: 0xbaf9, 0x1b7d: 0x1429, 0x1b7e: 0x1a31, 0x1b7f: 0xbb11, // Block 0x6e, offset 0x1b80 0x1b80: 0xbb29, 0x1b81: 0xbb41, 0x1b82: 0xbb59, 0x1b83: 0xbb71, 0x1b84: 0xbb89, 0x1b85: 0x2109, 0x1b86: 0x1111, 0x1b87: 0xbba1, 0x1b88: 0xbba1, 0x1b89: 0xbbb9, 0x1b8a: 0xbbd1, 0x1b8b: 0x10e1, 0x1b8c: 0x10f9, 0x1b8d: 0xbbe9, 0x1b8e: 0x2079, 0x1b8f: 0xbc21, 0x1b90: 0xbac9, 0x1b91: 0x1429, 0x1b92: 0xbb11, 0x1b93: 0x10e1, 0x1b94: 0x1111, 0x1b95: 0x2109, 0x1b96: 0xbab1, 0x1b97: 0x1099, 0x1b98: 0x10b1, 0x1b99: 0x10c9, 0x1b9a: 0xbac9, 0x1b9b: 0xbae1, 0x1b9c: 0xbaf9, 0x1b9d: 0x1429, 0x1b9e: 0x1a31, 0x1b9f: 0xbb11, 0x1ba0: 0xbb29, 0x1ba1: 0xbb41, 0x1ba2: 0xbb59, 0x1ba3: 0xbb71, 0x1ba4: 0xbb89, 0x1ba5: 0x2109, 0x1ba6: 0x1111, 0x1ba7: 0x1429, 0x1ba8: 0xbba1, 0x1ba9: 0xbbb9, 0x1baa: 0xbbd1, 0x1bab: 0x10e1, 0x1bac: 0x10f9, 0x1bad: 0xbbe9, 0x1bae: 0x2079, 0x1baf: 0xbc01, 0x1bb0: 0xbab1, 0x1bb1: 0x1099, 0x1bb2: 0x10b1, 0x1bb3: 0x10c9, 0x1bb4: 0xbac9, 0x1bb5: 0xbae1, 0x1bb6: 0xbaf9, 0x1bb7: 0x1429, 0x1bb8: 0x1a31, 0x1bb9: 0xbb11, 0x1bba: 0xbb29, 0x1bbb: 0xbb41, 0x1bbc: 0xbb59, 0x1bbd: 0xbb71, 0x1bbe: 0xbb89, 0x1bbf: 0x2109, // Block 0x6f, offset 0x1bc0 0x1bc0: 0x1111, 0x1bc1: 0xbba1, 0x1bc2: 0xbba1, 0x1bc3: 0xbbb9, 0x1bc4: 0xbbd1, 0x1bc5: 0x10e1, 0x1bc6: 0x10f9, 0x1bc7: 0xbbe9, 0x1bc8: 0x2079, 0x1bc9: 0xbc21, 0x1bca: 0xbac9, 0x1bcb: 0x1429, 0x1bcc: 0xbb11, 0x1bcd: 0x10e1, 0x1bce: 0x1111, 0x1bcf: 0x2109, 0x1bd0: 0xbab1, 0x1bd1: 0x1099, 0x1bd2: 0x10b1, 0x1bd3: 0x10c9, 0x1bd4: 0xbac9, 0x1bd5: 0xbae1, 0x1bd6: 0xbaf9, 0x1bd7: 0x1429, 0x1bd8: 0x1a31, 0x1bd9: 0xbb11, 0x1bda: 0xbb29, 0x1bdb: 0xbb41, 0x1bdc: 0xbb59, 0x1bdd: 0xbb71, 0x1bde: 0xbb89, 0x1bdf: 0x2109, 0x1be0: 0x1111, 0x1be1: 0x1429, 0x1be2: 0xbba1, 0x1be3: 0xbbb9, 0x1be4: 0xbbd1, 0x1be5: 0x10e1, 0x1be6: 0x10f9, 0x1be7: 0xbbe9, 0x1be8: 0x2079, 0x1be9: 0xbc01, 0x1bea: 0xbab1, 0x1beb: 0x1099, 0x1bec: 0x10b1, 0x1bed: 0x10c9, 0x1bee: 0xbac9, 0x1bef: 0xbae1, 0x1bf0: 0xbaf9, 0x1bf1: 0x1429, 0x1bf2: 0x1a31, 0x1bf3: 0xbb11, 0x1bf4: 0xbb29, 0x1bf5: 0xbb41, 0x1bf6: 0xbb59, 0x1bf7: 0xbb71, 0x1bf8: 0xbb89, 0x1bf9: 0x2109, 0x1bfa: 0x1111, 0x1bfb: 0xbba1, 0x1bfc: 0xbba1, 0x1bfd: 0xbbb9, 0x1bfe: 0xbbd1, 0x1bff: 0x10e1, // Block 0x70, offset 0x1c00 0x1c00: 0x10f9, 0x1c01: 0xbbe9, 0x1c02: 0x2079, 0x1c03: 0xbc21, 0x1c04: 0xbac9, 0x1c05: 0x1429, 0x1c06: 0xbb11, 0x1c07: 0x10e1, 0x1c08: 0x1111, 0x1c09: 0x2109, 0x1c0a: 0xbc41, 0x1c0b: 0xbc41, 0x1c0c: 0x0040, 0x1c0d: 0x0040, 0x1c0e: 0x1f41, 0x1c0f: 0x00c9, 0x1c10: 0x0069, 0x1c11: 0x0079, 0x1c12: 0x1f51, 0x1c13: 0x1f61, 0x1c14: 0x1f71, 0x1c15: 0x1f81, 0x1c16: 0x1f91, 0x1c17: 0x1fa1, 0x1c18: 0x1f41, 0x1c19: 0x00c9, 0x1c1a: 0x0069, 0x1c1b: 0x0079, 0x1c1c: 0x1f51, 0x1c1d: 0x1f61, 0x1c1e: 0x1f71, 0x1c1f: 0x1f81, 0x1c20: 0x1f91, 0x1c21: 0x1fa1, 0x1c22: 0x1f41, 0x1c23: 0x00c9, 0x1c24: 0x0069, 0x1c25: 0x0079, 0x1c26: 0x1f51, 0x1c27: 0x1f61, 0x1c28: 0x1f71, 0x1c29: 0x1f81, 0x1c2a: 0x1f91, 0x1c2b: 0x1fa1, 0x1c2c: 0x1f41, 0x1c2d: 0x00c9, 0x1c2e: 0x0069, 0x1c2f: 0x0079, 0x1c30: 0x1f51, 0x1c31: 0x1f61, 0x1c32: 0x1f71, 0x1c33: 0x1f81, 0x1c34: 0x1f91, 0x1c35: 0x1fa1, 0x1c36: 0x1f41, 0x1c37: 0x00c9, 0x1c38: 0x0069, 0x1c39: 0x0079, 0x1c3a: 0x1f51, 0x1c3b: 0x1f61, 0x1c3c: 0x1f71, 0x1c3d: 0x1f81, 0x1c3e: 0x1f91, 0x1c3f: 0x1fa1, // Block 0x71, offset 0x1c40 0x1c40: 0xe115, 0x1c41: 0xe115, 0x1c42: 0xe135, 0x1c43: 0xe135, 0x1c44: 0xe115, 0x1c45: 0xe115, 0x1c46: 0xe175, 0x1c47: 0xe175, 0x1c48: 0xe115, 0x1c49: 0xe115, 0x1c4a: 0xe135, 0x1c4b: 0xe135, 0x1c4c: 0xe115, 0x1c4d: 0xe115, 0x1c4e: 0xe1f5, 0x1c4f: 0xe1f5, 0x1c50: 0xe115, 0x1c51: 0xe115, 0x1c52: 0xe135, 0x1c53: 0xe135, 0x1c54: 0xe115, 0x1c55: 0xe115, 0x1c56: 0xe175, 0x1c57: 0xe175, 0x1c58: 0xe115, 0x1c59: 0xe115, 0x1c5a: 0xe135, 0x1c5b: 0xe135, 0x1c5c: 0xe115, 0x1c5d: 0xe115, 0x1c5e: 0x8b05, 0x1c5f: 0x8b05, 0x1c60: 0x04b5, 0x1c61: 0x04b5, 0x1c62: 0x0a08, 0x1c63: 0x0a08, 0x1c64: 0x0a08, 0x1c65: 0x0a08, 0x1c66: 0x0a08, 0x1c67: 0x0a08, 0x1c68: 0x0a08, 0x1c69: 0x0a08, 0x1c6a: 0x0a08, 0x1c6b: 0x0a08, 0x1c6c: 0x0a08, 0x1c6d: 0x0a08, 0x1c6e: 0x0a08, 0x1c6f: 0x0a08, 0x1c70: 0x0a08, 0x1c71: 0x0a08, 0x1c72: 0x0a08, 0x1c73: 0x0a08, 0x1c74: 0x0a08, 0x1c75: 0x0a08, 0x1c76: 0x0a08, 0x1c77: 0x0a08, 0x1c78: 0x0a08, 0x1c79: 0x0a08, 0x1c7a: 0x0a08, 0x1c7b: 0x0a08, 0x1c7c: 0x0a08, 0x1c7d: 0x0a08, 0x1c7e: 0x0a08, 0x1c7f: 0x0a08, // Block 0x72, offset 0x1c80 0x1c80: 0xb189, 0x1c81: 0xb1a1, 0x1c82: 0xb201, 0x1c83: 0xb249, 0x1c84: 0x0040, 0x1c85: 0xb411, 0x1c86: 0xb291, 0x1c87: 0xb219, 0x1c88: 0xb309, 0x1c89: 0xb429, 0x1c8a: 0xb399, 0x1c8b: 0xb3b1, 0x1c8c: 0xb3c9, 0x1c8d: 0xb3e1, 0x1c8e: 0xb2a9, 0x1c8f: 0xb339, 0x1c90: 0xb369, 0x1c91: 0xb2d9, 0x1c92: 0xb381, 0x1c93: 0xb279, 0x1c94: 0xb2c1, 0x1c95: 0xb1d1, 0x1c96: 0xb1e9, 0x1c97: 0xb231, 0x1c98: 0xb261, 0x1c99: 0xb2f1, 0x1c9a: 0xb321, 0x1c9b: 0xb351, 0x1c9c: 0xbc59, 0x1c9d: 0x7949, 0x1c9e: 0xbc71, 0x1c9f: 0xbc89, 0x1ca0: 0x0040, 0x1ca1: 0xb1a1, 0x1ca2: 0xb201, 0x1ca3: 0x0040, 0x1ca4: 0xb3f9, 0x1ca5: 0x0040, 0x1ca6: 0x0040, 0x1ca7: 0xb219, 0x1ca8: 0x0040, 0x1ca9: 0xb429, 0x1caa: 0xb399, 0x1cab: 0xb3b1, 0x1cac: 0xb3c9, 0x1cad: 0xb3e1, 0x1cae: 0xb2a9, 0x1caf: 0xb339, 0x1cb0: 0xb369, 0x1cb1: 0xb2d9, 0x1cb2: 0xb381, 0x1cb3: 0x0040, 0x1cb4: 0xb2c1, 0x1cb5: 0xb1d1, 0x1cb6: 0xb1e9, 0x1cb7: 0xb231, 0x1cb8: 0x0040, 0x1cb9: 0xb2f1, 0x1cba: 0x0040, 0x1cbb: 0xb351, 0x1cbc: 0x0040, 0x1cbd: 0x0040, 0x1cbe: 0x0040, 0x1cbf: 0x0040, // Block 0x73, offset 0x1cc0 0x1cc0: 0x0040, 0x1cc1: 0x0040, 0x1cc2: 0xb201, 0x1cc3: 0x0040, 0x1cc4: 0x0040, 0x1cc5: 0x0040, 0x1cc6: 0x0040, 0x1cc7: 0xb219, 0x1cc8: 0x0040, 0x1cc9: 0xb429, 0x1cca: 0x0040, 0x1ccb: 0xb3b1, 0x1ccc: 0x0040, 0x1ccd: 0xb3e1, 0x1cce: 0xb2a9, 0x1ccf: 0xb339, 0x1cd0: 0x0040, 0x1cd1: 0xb2d9, 0x1cd2: 0xb381, 0x1cd3: 0x0040, 0x1cd4: 0xb2c1, 0x1cd5: 0x0040, 0x1cd6: 0x0040, 0x1cd7: 0xb231, 0x1cd8: 0x0040, 0x1cd9: 0xb2f1, 0x1cda: 0x0040, 0x1cdb: 0xb351, 0x1cdc: 0x0040, 0x1cdd: 0x7949, 0x1cde: 0x0040, 0x1cdf: 0xbc89, 0x1ce0: 0x0040, 0x1ce1: 0xb1a1, 0x1ce2: 0xb201, 0x1ce3: 0x0040, 0x1ce4: 0xb3f9, 0x1ce5: 0x0040, 0x1ce6: 0x0040, 0x1ce7: 0xb219, 0x1ce8: 0xb309, 0x1ce9: 0xb429, 0x1cea: 0xb399, 0x1ceb: 0x0040, 0x1cec: 0xb3c9, 0x1ced: 0xb3e1, 0x1cee: 0xb2a9, 0x1cef: 0xb339, 0x1cf0: 0xb369, 0x1cf1: 0xb2d9, 0x1cf2: 0xb381, 0x1cf3: 0x0040, 0x1cf4: 0xb2c1, 0x1cf5: 0xb1d1, 0x1cf6: 0xb1e9, 0x1cf7: 0xb231, 0x1cf8: 0x0040, 0x1cf9: 0xb2f1, 0x1cfa: 0xb321, 0x1cfb: 0xb351, 0x1cfc: 0xbc59, 0x1cfd: 0x0040, 0x1cfe: 0xbc71, 0x1cff: 0x0040, // Block 0x74, offset 0x1d00 0x1d00: 0xb189, 0x1d01: 0xb1a1, 0x1d02: 0xb201, 0x1d03: 0xb249, 0x1d04: 0xb3f9, 0x1d05: 0xb411, 0x1d06: 0xb291, 0x1d07: 0xb219, 0x1d08: 0xb309, 0x1d09: 0xb429, 0x1d0a: 0x0040, 0x1d0b: 0xb3b1, 0x1d0c: 0xb3c9, 0x1d0d: 0xb3e1, 0x1d0e: 0xb2a9, 0x1d0f: 0xb339, 0x1d10: 0xb369, 0x1d11: 0xb2d9, 0x1d12: 0xb381, 0x1d13: 0xb279, 0x1d14: 0xb2c1, 0x1d15: 0xb1d1, 0x1d16: 0xb1e9, 0x1d17: 0xb231, 0x1d18: 0xb261, 0x1d19: 0xb2f1, 0x1d1a: 0xb321, 0x1d1b: 0xb351, 0x1d1c: 0x0040, 0x1d1d: 0x0040, 0x1d1e: 0x0040, 0x1d1f: 0x0040, 0x1d20: 0x0040, 0x1d21: 0xb1a1, 0x1d22: 0xb201, 0x1d23: 0xb249, 0x1d24: 0x0040, 0x1d25: 0xb411, 0x1d26: 0xb291, 0x1d27: 0xb219, 0x1d28: 0xb309, 0x1d29: 0xb429, 0x1d2a: 0x0040, 0x1d2b: 0xb3b1, 0x1d2c: 0xb3c9, 0x1d2d: 0xb3e1, 0x1d2e: 0xb2a9, 0x1d2f: 0xb339, 0x1d30: 0xb369, 0x1d31: 0xb2d9, 0x1d32: 0xb381, 0x1d33: 0xb279, 0x1d34: 0xb2c1, 0x1d35: 0xb1d1, 0x1d36: 0xb1e9, 0x1d37: 0xb231, 0x1d38: 0xb261, 0x1d39: 0xb2f1, 0x1d3a: 0xb321, 0x1d3b: 0xb351, 0x1d3c: 0x0040, 0x1d3d: 0x0040, 0x1d3e: 0x0040, 0x1d3f: 0x0040, // Block 0x75, offset 0x1d40 0x1d40: 0x0040, 0x1d41: 0xbca2, 0x1d42: 0xbcba, 0x1d43: 0xbcd2, 0x1d44: 0xbcea, 0x1d45: 0xbd02, 0x1d46: 0xbd1a, 0x1d47: 0xbd32, 0x1d48: 0xbd4a, 0x1d49: 0xbd62, 0x1d4a: 0xbd7a, 0x1d4b: 0x0018, 0x1d4c: 0x0018, 0x1d4d: 0x0040, 0x1d4e: 0x0040, 0x1d4f: 0x0040, 0x1d50: 0xbd92, 0x1d51: 0xbdb2, 0x1d52: 0xbdd2, 0x1d53: 0xbdf2, 0x1d54: 0xbe12, 0x1d55: 0xbe32, 0x1d56: 0xbe52, 0x1d57: 0xbe72, 0x1d58: 0xbe92, 0x1d59: 0xbeb2, 0x1d5a: 0xbed2, 0x1d5b: 0xbef2, 0x1d5c: 0xbf12, 0x1d5d: 0xbf32, 0x1d5e: 0xbf52, 0x1d5f: 0xbf72, 0x1d60: 0xbf92, 0x1d61: 0xbfb2, 0x1d62: 0xbfd2, 0x1d63: 0xbff2, 0x1d64: 0xc012, 0x1d65: 0xc032, 0x1d66: 0xc052, 0x1d67: 0xc072, 0x1d68: 0xc092, 0x1d69: 0xc0b2, 0x1d6a: 0xc0d1, 0x1d6b: 0x1159, 0x1d6c: 0x0269, 0x1d6d: 0x6671, 0x1d6e: 0xc111, 0x1d6f: 0x0018, 0x1d70: 0x0039, 0x1d71: 0x0ee9, 0x1d72: 0x1159, 0x1d73: 0x0ef9, 0x1d74: 0x0f09, 0x1d75: 0x1199, 0x1d76: 0x0f31, 0x1d77: 0x0249, 0x1d78: 0x0f41, 0x1d79: 0x0259, 0x1d7a: 0x0f51, 0x1d7b: 0x0359, 0x1d7c: 0x0f61, 0x1d7d: 0x0f71, 0x1d7e: 0x00d9, 0x1d7f: 0x0f99, // Block 0x76, offset 0x1d80 0x1d80: 0x2039, 0x1d81: 0x0269, 0x1d82: 0x01d9, 0x1d83: 0x0fa9, 0x1d84: 0x0fb9, 0x1d85: 0x1089, 0x1d86: 0x0279, 0x1d87: 0x0369, 0x1d88: 0x0289, 0x1d89: 0x13d1, 0x1d8a: 0xc129, 0x1d8b: 0x65b1, 0x1d8c: 0xc141, 0x1d8d: 0x1441, 0x1d8e: 0xc159, 0x1d8f: 0xc179, 0x1d90: 0x0018, 0x1d91: 0x0018, 0x1d92: 0x0018, 0x1d93: 0x0018, 0x1d94: 0x0018, 0x1d95: 0x0018, 0x1d96: 0x0018, 0x1d97: 0x0018, 0x1d98: 0x0018, 0x1d99: 0x0018, 0x1d9a: 0x0018, 0x1d9b: 0x0018, 0x1d9c: 0x0018, 0x1d9d: 0x0018, 0x1d9e: 0x0018, 0x1d9f: 0x0018, 0x1da0: 0x0018, 0x1da1: 0x0018, 0x1da2: 0x0018, 0x1da3: 0x0018, 0x1da4: 0x0018, 0x1da5: 0x0018, 0x1da6: 0x0018, 0x1da7: 0x0018, 0x1da8: 0x0018, 0x1da9: 0x0018, 0x1daa: 0xc191, 0x1dab: 0xc1a9, 0x1dac: 0x0040, 0x1dad: 0x0040, 0x1dae: 0x0040, 0x1daf: 0x0040, 0x1db0: 0x0018, 0x1db1: 0x0018, 0x1db2: 0x0018, 0x1db3: 0x0018, 0x1db4: 0x0018, 0x1db5: 0x0018, 0x1db6: 0x0018, 0x1db7: 0x0018, 0x1db8: 0x0018, 0x1db9: 0x0018, 0x1dba: 0x0018, 0x1dbb: 0x0018, 0x1dbc: 0x0018, 0x1dbd: 0x0018, 0x1dbe: 0x0018, 0x1dbf: 0x0018, // Block 0x77, offset 0x1dc0 0x1dc0: 0xc1d9, 0x1dc1: 0xc211, 0x1dc2: 0xc249, 0x1dc3: 0x0040, 0x1dc4: 0x0040, 0x1dc5: 0x0040, 0x1dc6: 0x0040, 0x1dc7: 0x0040, 0x1dc8: 0x0040, 0x1dc9: 0x0040, 0x1dca: 0x0040, 0x1dcb: 0x0040, 0x1dcc: 0x0040, 0x1dcd: 0x0040, 0x1dce: 0x0040, 0x1dcf: 0x0040, 0x1dd0: 0xc269, 0x1dd1: 0xc289, 0x1dd2: 0xc2a9, 0x1dd3: 0xc2c9, 0x1dd4: 0xc2e9, 0x1dd5: 0xc309, 0x1dd6: 0xc329, 0x1dd7: 0xc349, 0x1dd8: 0xc369, 0x1dd9: 0xc389, 0x1dda: 0xc3a9, 0x1ddb: 0xc3c9, 0x1ddc: 0xc3e9, 0x1ddd: 0xc409, 0x1dde: 0xc429, 0x1ddf: 0xc449, 0x1de0: 0xc469, 0x1de1: 0xc489, 0x1de2: 0xc4a9, 0x1de3: 0xc4c9, 0x1de4: 0xc4e9, 0x1de5: 0xc509, 0x1de6: 0xc529, 0x1de7: 0xc549, 0x1de8: 0xc569, 0x1de9: 0xc589, 0x1dea: 0xc5a9, 0x1deb: 0xc5c9, 0x1dec: 0xc5e9, 0x1ded: 0xc609, 0x1dee: 0xc629, 0x1def: 0xc649, 0x1df0: 0xc669, 0x1df1: 0xc689, 0x1df2: 0xc6a9, 0x1df3: 0xc6c9, 0x1df4: 0xc6e9, 0x1df5: 0xc709, 0x1df6: 0xc729, 0x1df7: 0xc749, 0x1df8: 0xc769, 0x1df9: 0xc789, 0x1dfa: 0xc7a9, 0x1dfb: 0xc7c9, 0x1dfc: 0x0040, 0x1dfd: 0x0040, 0x1dfe: 0x0040, 0x1dff: 0x0040, // Block 0x78, offset 0x1e00 0x1e00: 0xcaf9, 0x1e01: 0xcb19, 0x1e02: 0xcb39, 0x1e03: 0x8b1d, 0x1e04: 0xcb59, 0x1e05: 0xcb79, 0x1e06: 0xcb99, 0x1e07: 0xcbb9, 0x1e08: 0xcbd9, 0x1e09: 0xcbf9, 0x1e0a: 0xcc19, 0x1e0b: 0xcc39, 0x1e0c: 0xcc59, 0x1e0d: 0x8b3d, 0x1e0e: 0xcc79, 0x1e0f: 0xcc99, 0x1e10: 0xccb9, 0x1e11: 0xccd9, 0x1e12: 0x8b5d, 0x1e13: 0xccf9, 0x1e14: 0xcd19, 0x1e15: 0xc429, 0x1e16: 0x8b7d, 0x1e17: 0xcd39, 0x1e18: 0xcd59, 0x1e19: 0xcd79, 0x1e1a: 0xcd99, 0x1e1b: 0xcdb9, 0x1e1c: 0x8b9d, 0x1e1d: 0xcdd9, 0x1e1e: 0xcdf9, 0x1e1f: 0xce19, 0x1e20: 0xce39, 0x1e21: 0xce59, 0x1e22: 0xc789, 0x1e23: 0xce79, 0x1e24: 0xce99, 0x1e25: 0xceb9, 0x1e26: 0xced9, 0x1e27: 0xcef9, 0x1e28: 0xcf19, 0x1e29: 0xcf39, 0x1e2a: 0xcf59, 0x1e2b: 0xcf79, 0x1e2c: 0xcf99, 0x1e2d: 0xcfb9, 0x1e2e: 0xcfd9, 0x1e2f: 0xcff9, 0x1e30: 0xd019, 0x1e31: 0xd039, 0x1e32: 0xd039, 0x1e33: 0xd039, 0x1e34: 0x8bbd, 0x1e35: 0xd059, 0x1e36: 0xd079, 0x1e37: 0xd099, 0x1e38: 0x8bdd, 0x1e39: 0xd0b9, 0x1e3a: 0xd0d9, 0x1e3b: 0xd0f9, 0x1e3c: 0xd119, 0x1e3d: 0xd139, 0x1e3e: 0xd159, 0x1e3f: 0xd179, // Block 0x79, offset 0x1e40 0x1e40: 0xd199, 0x1e41: 0xd1b9, 0x1e42: 0xd1d9, 0x1e43: 0xd1f9, 0x1e44: 0xd219, 0x1e45: 0xd239, 0x1e46: 0xd239, 0x1e47: 0xd259, 0x1e48: 0xd279, 0x1e49: 0xd299, 0x1e4a: 0xd2b9, 0x1e4b: 0xd2d9, 0x1e4c: 0xd2f9, 0x1e4d: 0xd319, 0x1e4e: 0xd339, 0x1e4f: 0xd359, 0x1e50: 0xd379, 0x1e51: 0xd399, 0x1e52: 0xd3b9, 0x1e53: 0xd3d9, 0x1e54: 0xd3f9, 0x1e55: 0xd419, 0x1e56: 0xd439, 0x1e57: 0xd459, 0x1e58: 0xd479, 0x1e59: 0x8bfd, 0x1e5a: 0xd499, 0x1e5b: 0xd4b9, 0x1e5c: 0xd4d9, 0x1e5d: 0xc309, 0x1e5e: 0xd4f9, 0x1e5f: 0xd519, 0x1e60: 0x8c1d, 0x1e61: 0x8c3d, 0x1e62: 0xd539, 0x1e63: 0xd559, 0x1e64: 0xd579, 0x1e65: 0xd599, 0x1e66: 0xd5b9, 0x1e67: 0xd5d9, 0x1e68: 0x2040, 0x1e69: 0xd5f9, 0x1e6a: 0xd619, 0x1e6b: 0xd619, 0x1e6c: 0x8c5d, 0x1e6d: 0xd639, 0x1e6e: 0xd659, 0x1e6f: 0xd679, 0x1e70: 0xd699, 0x1e71: 0x8c7d, 0x1e72: 0xd6b9, 0x1e73: 0xd6d9, 0x1e74: 0x2040, 0x1e75: 0xd6f9, 0x1e76: 0xd719, 0x1e77: 0xd739, 0x1e78: 0xd759, 0x1e79: 0xd779, 0x1e7a: 0xd799, 0x1e7b: 0x8c9d, 0x1e7c: 0xd7b9, 0x1e7d: 0x8cbd, 0x1e7e: 0xd7d9, 0x1e7f: 0xd7f9, // Block 0x7a, offset 0x1e80 0x1e80: 0xd819, 0x1e81: 0xd839, 0x1e82: 0xd859, 0x1e83: 0xd879, 0x1e84: 0xd899, 0x1e85: 0xd8b9, 0x1e86: 0xd8d9, 0x1e87: 0xd8f9, 0x1e88: 0xd919, 0x1e89: 0x8cdd, 0x1e8a: 0xd939, 0x1e8b: 0xd959, 0x1e8c: 0xd979, 0x1e8d: 0xd999, 0x1e8e: 0xd9b9, 0x1e8f: 0x8cfd, 0x1e90: 0xd9d9, 0x1e91: 0x8d1d, 0x1e92: 0x8d3d, 0x1e93: 0xd9f9, 0x1e94: 0xda19, 0x1e95: 0xda19, 0x1e96: 0xda39, 0x1e97: 0x8d5d, 0x1e98: 0x8d7d, 0x1e99: 0xda59, 0x1e9a: 0xda79, 0x1e9b: 0xda99, 0x1e9c: 0xdab9, 0x1e9d: 0xdad9, 0x1e9e: 0xdaf9, 0x1e9f: 0xdb19, 0x1ea0: 0xdb39, 0x1ea1: 0xdb59, 0x1ea2: 0xdb79, 0x1ea3: 0xdb99, 0x1ea4: 0x8d9d, 0x1ea5: 0xdbb9, 0x1ea6: 0xdbd9, 0x1ea7: 0xdbf9, 0x1ea8: 0xdc19, 0x1ea9: 0xdbf9, 0x1eaa: 0xdc39, 0x1eab: 0xdc59, 0x1eac: 0xdc79, 0x1ead: 0xdc99, 0x1eae: 0xdcb9, 0x1eaf: 0xdcd9, 0x1eb0: 0xdcf9, 0x1eb1: 0xdd19, 0x1eb2: 0xdd39, 0x1eb3: 0xdd59, 0x1eb4: 0xdd79, 0x1eb5: 0xdd99, 0x1eb6: 0xddb9, 0x1eb7: 0xddd9, 0x1eb8: 0x8dbd, 0x1eb9: 0xddf9, 0x1eba: 0xde19, 0x1ebb: 0xde39, 0x1ebc: 0xde59, 0x1ebd: 0xde79, 0x1ebe: 0x8ddd, 0x1ebf: 0xde99, // Block 0x7b, offset 0x1ec0 0x1ec0: 0xe599, 0x1ec1: 0xe5b9, 0x1ec2: 0xe5d9, 0x1ec3: 0xe5f9, 0x1ec4: 0xe619, 0x1ec5: 0xe639, 0x1ec6: 0x8efd, 0x1ec7: 0xe659, 0x1ec8: 0xe679, 0x1ec9: 0xe699, 0x1eca: 0xe6b9, 0x1ecb: 0xe6d9, 0x1ecc: 0xe6f9, 0x1ecd: 0x8f1d, 0x1ece: 0xe719, 0x1ecf: 0xe739, 0x1ed0: 0x8f3d, 0x1ed1: 0x8f5d, 0x1ed2: 0xe759, 0x1ed3: 0xe779, 0x1ed4: 0xe799, 0x1ed5: 0xe7b9, 0x1ed6: 0xe7d9, 0x1ed7: 0xe7f9, 0x1ed8: 0xe819, 0x1ed9: 0xe839, 0x1eda: 0xe859, 0x1edb: 0x8f7d, 0x1edc: 0xe879, 0x1edd: 0x8f9d, 0x1ede: 0xe899, 0x1edf: 0x2040, 0x1ee0: 0xe8b9, 0x1ee1: 0xe8d9, 0x1ee2: 0xe8f9, 0x1ee3: 0x8fbd, 0x1ee4: 0xe919, 0x1ee5: 0xe939, 0x1ee6: 0x8fdd, 0x1ee7: 0x8ffd, 0x1ee8: 0xe959, 0x1ee9: 0xe979, 0x1eea: 0xe999, 0x1eeb: 0xe9b9, 0x1eec: 0xe9d9, 0x1eed: 0xe9d9, 0x1eee: 0xe9f9, 0x1eef: 0xea19, 0x1ef0: 0xea39, 0x1ef1: 0xea59, 0x1ef2: 0xea79, 0x1ef3: 0xea99, 0x1ef4: 0xeab9, 0x1ef5: 0x901d, 0x1ef6: 0xead9, 0x1ef7: 0x903d, 0x1ef8: 0xeaf9, 0x1ef9: 0x905d, 0x1efa: 0xeb19, 0x1efb: 0x907d, 0x1efc: 0x909d, 0x1efd: 0x90bd, 0x1efe: 0xeb39, 0x1eff: 0xeb59, // Block 0x7c, offset 0x1f00 0x1f00: 0xeb79, 0x1f01: 0x90dd, 0x1f02: 0x90fd, 0x1f03: 0x911d, 0x1f04: 0x913d, 0x1f05: 0xeb99, 0x1f06: 0xebb9, 0x1f07: 0xebb9, 0x1f08: 0xebd9, 0x1f09: 0xebf9, 0x1f0a: 0xec19, 0x1f0b: 0xec39, 0x1f0c: 0xec59, 0x1f0d: 0x915d, 0x1f0e: 0xec79, 0x1f0f: 0xec99, 0x1f10: 0xecb9, 0x1f11: 0xecd9, 0x1f12: 0x917d, 0x1f13: 0xecf9, 0x1f14: 0x919d, 0x1f15: 0x91bd, 0x1f16: 0xed19, 0x1f17: 0xed39, 0x1f18: 0xed59, 0x1f19: 0xed79, 0x1f1a: 0xed99, 0x1f1b: 0xedb9, 0x1f1c: 0x91dd, 0x1f1d: 0x91fd, 0x1f1e: 0x921d, 0x1f1f: 0x2040, 0x1f20: 0xedd9, 0x1f21: 0x923d, 0x1f22: 0xedf9, 0x1f23: 0xee19, 0x1f24: 0xee39, 0x1f25: 0x925d, 0x1f26: 0xee59, 0x1f27: 0xee79, 0x1f28: 0xee99, 0x1f29: 0xeeb9, 0x1f2a: 0xeed9, 0x1f2b: 0x927d, 0x1f2c: 0xeef9, 0x1f2d: 0xef19, 0x1f2e: 0xef39, 0x1f2f: 0xef59, 0x1f30: 0xef79, 0x1f31: 0xef99, 0x1f32: 0x929d, 0x1f33: 0x92bd, 0x1f34: 0xefb9, 0x1f35: 0x92dd, 0x1f36: 0xefd9, 0x1f37: 0x92fd, 0x1f38: 0xeff9, 0x1f39: 0xf019, 0x1f3a: 0xf039, 0x1f3b: 0x931d, 0x1f3c: 0x933d, 0x1f3d: 0xf059, 0x1f3e: 0x935d, 0x1f3f: 0xf079, // Block 0x7d, offset 0x1f40 0x1f40: 0xf6b9, 0x1f41: 0xf6d9, 0x1f42: 0xf6f9, 0x1f43: 0xf719, 0x1f44: 0xf739, 0x1f45: 0x951d, 0x1f46: 0xf759, 0x1f47: 0xf779, 0x1f48: 0xf799, 0x1f49: 0xf7b9, 0x1f4a: 0xf7d9, 0x1f4b: 0x953d, 0x1f4c: 0x955d, 0x1f4d: 0xf7f9, 0x1f4e: 0xf819, 0x1f4f: 0xf839, 0x1f50: 0xf859, 0x1f51: 0xf879, 0x1f52: 0xf899, 0x1f53: 0x957d, 0x1f54: 0xf8b9, 0x1f55: 0xf8d9, 0x1f56: 0xf8f9, 0x1f57: 0xf919, 0x1f58: 0x959d, 0x1f59: 0x95bd, 0x1f5a: 0xf939, 0x1f5b: 0xf959, 0x1f5c: 0xf979, 0x1f5d: 0x95dd, 0x1f5e: 0xf999, 0x1f5f: 0xf9b9, 0x1f60: 0x6815, 0x1f61: 0x95fd, 0x1f62: 0xf9d9, 0x1f63: 0xf9f9, 0x1f64: 0xfa19, 0x1f65: 0x961d, 0x1f66: 0xfa39, 0x1f67: 0xfa59, 0x1f68: 0xfa79, 0x1f69: 0xfa99, 0x1f6a: 0xfab9, 0x1f6b: 0xfad9, 0x1f6c: 0xfaf9, 0x1f6d: 0x963d, 0x1f6e: 0xfb19, 0x1f6f: 0xfb39, 0x1f70: 0xfb59, 0x1f71: 0x965d, 0x1f72: 0xfb79, 0x1f73: 0xfb99, 0x1f74: 0xfbb9, 0x1f75: 0xfbd9, 0x1f76: 0x7b35, 0x1f77: 0x967d, 0x1f78: 0xfbf9, 0x1f79: 0xfc19, 0x1f7a: 0xfc39, 0x1f7b: 0x969d, 0x1f7c: 0xfc59, 0x1f7d: 0x96bd, 0x1f7e: 0xfc79, 0x1f7f: 0xfc79, // Block 0x7e, offset 0x1f80 0x1f80: 0xfc99, 0x1f81: 0x96dd, 0x1f82: 0xfcb9, 0x1f83: 0xfcd9, 0x1f84: 0xfcf9, 0x1f85: 0xfd19, 0x1f86: 0xfd39, 0x1f87: 0xfd59, 0x1f88: 0xfd79, 0x1f89: 0x96fd, 0x1f8a: 0xfd99, 0x1f8b: 0xfdb9, 0x1f8c: 0xfdd9, 0x1f8d: 0xfdf9, 0x1f8e: 0xfe19, 0x1f8f: 0xfe39, 0x1f90: 0x971d, 0x1f91: 0xfe59, 0x1f92: 0x973d, 0x1f93: 0x975d, 0x1f94: 0x977d, 0x1f95: 0xfe79, 0x1f96: 0xfe99, 0x1f97: 0xfeb9, 0x1f98: 0xfed9, 0x1f99: 0xfef9, 0x1f9a: 0xff19, 0x1f9b: 0xff39, 0x1f9c: 0xff59, 0x1f9d: 0x979d, 0x1f9e: 0x0040, 0x1f9f: 0x0040, 0x1fa0: 0x0040, 0x1fa1: 0x0040, 0x1fa2: 0x0040, 0x1fa3: 0x0040, 0x1fa4: 0x0040, 0x1fa5: 0x0040, 0x1fa6: 0x0040, 0x1fa7: 0x0040, 0x1fa8: 0x0040, 0x1fa9: 0x0040, 0x1faa: 0x0040, 0x1fab: 0x0040, 0x1fac: 0x0040, 0x1fad: 0x0040, 0x1fae: 0x0040, 0x1faf: 0x0040, 0x1fb0: 0x0040, 0x1fb1: 0x0040, 0x1fb2: 0x0040, 0x1fb3: 0x0040, 0x1fb4: 0x0040, 0x1fb5: 0x0040, 0x1fb6: 0x0040, 0x1fb7: 0x0040, 0x1fb8: 0x0040, 0x1fb9: 0x0040, 0x1fba: 0x0040, 0x1fbb: 0x0040, 0x1fbc: 0x0040, 0x1fbd: 0x0040, 0x1fbe: 0x0040, 0x1fbf: 0x0040, } // idnaIndex: 36 blocks, 2304 entries, 4608 bytes // Block 0 is the zero block. var idnaIndex = [2304]uint16{ // Block 0x0, offset 0x0 // Block 0x1, offset 0x40 // Block 0x2, offset 0x80 // Block 0x3, offset 0xc0 0xc2: 0x01, 0xc3: 0x7d, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x04, 0xc7: 0x05, 0xc8: 0x06, 0xc9: 0x7e, 0xca: 0x7f, 0xcb: 0x07, 0xcc: 0x80, 0xcd: 0x08, 0xce: 0x09, 0xcf: 0x0a, 0xd0: 0x81, 0xd1: 0x0b, 0xd2: 0x0c, 0xd3: 0x0d, 0xd4: 0x0e, 0xd5: 0x82, 0xd6: 0x83, 0xd7: 0x84, 0xd8: 0x0f, 0xd9: 0x10, 0xda: 0x85, 0xdb: 0x11, 0xdc: 0x12, 0xdd: 0x86, 0xde: 0x87, 0xdf: 0x88, 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06, 0xe5: 0x07, 0xe6: 0x07, 0xe7: 0x07, 0xe8: 0x07, 0xe9: 0x08, 0xea: 0x09, 0xeb: 0x07, 0xec: 0x07, 0xed: 0x0a, 0xee: 0x0b, 0xef: 0x0c, 0xf0: 0x1d, 0xf1: 0x1e, 0xf2: 0x1e, 0xf3: 0x20, 0xf4: 0x21, // Block 0x4, offset 0x100 0x120: 0x89, 0x121: 0x13, 0x122: 0x8a, 0x123: 0x8b, 0x124: 0x8c, 0x125: 0x14, 0x126: 0x15, 0x127: 0x16, 0x128: 0x17, 0x129: 0x18, 0x12a: 0x19, 0x12b: 0x1a, 0x12c: 0x1b, 0x12d: 0x1c, 0x12e: 0x1d, 0x12f: 0x8d, 0x130: 0x8e, 0x131: 0x1e, 0x132: 0x1f, 0x133: 0x20, 0x134: 0x8f, 0x135: 0x21, 0x136: 0x90, 0x137: 0x91, 0x138: 0x92, 0x139: 0x93, 0x13a: 0x22, 0x13b: 0x94, 0x13c: 0x95, 0x13d: 0x23, 0x13e: 0x24, 0x13f: 0x96, // Block 0x5, offset 0x140 0x140: 0x97, 0x141: 0x98, 0x142: 0x99, 0x143: 0x9a, 0x144: 0x9b, 0x145: 0x9c, 0x146: 0x9d, 0x147: 0x9e, 0x148: 0x9f, 0x149: 0xa0, 0x14a: 0xa1, 0x14b: 0xa2, 0x14c: 0xa3, 0x14d: 0xa4, 0x14e: 0xa5, 0x14f: 0xa6, 0x150: 0xa7, 0x151: 0x9f, 0x152: 0x9f, 0x153: 0x9f, 0x154: 0x9f, 0x155: 0x9f, 0x156: 0x9f, 0x157: 0x9f, 0x158: 0x9f, 0x159: 0xa8, 0x15a: 0xa9, 0x15b: 0xaa, 0x15c: 0xab, 0x15d: 0xac, 0x15e: 0xad, 0x15f: 0xae, 0x160: 0xaf, 0x161: 0xb0, 0x162: 0xb1, 0x163: 0xb2, 0x164: 0xb3, 0x165: 0xb4, 0x166: 0xb5, 0x167: 0xb6, 0x168: 0xb7, 0x169: 0xb8, 0x16a: 0xb9, 0x16b: 0xba, 0x16c: 0xbb, 0x16d: 0xbc, 0x16e: 0xbd, 0x16f: 0xbe, 0x170: 0xbf, 0x171: 0xc0, 0x172: 0xc1, 0x173: 0xc2, 0x174: 0x25, 0x175: 0x26, 0x176: 0x27, 0x177: 0xc3, 0x178: 0x28, 0x179: 0x28, 0x17a: 0x29, 0x17b: 0x28, 0x17c: 0xc4, 0x17d: 0x2a, 0x17e: 0x2b, 0x17f: 0x2c, // Block 0x6, offset 0x180 0x180: 0x2d, 0x181: 0x2e, 0x182: 0x2f, 0x183: 0xc5, 0x184: 0x30, 0x185: 0x31, 0x186: 0xc6, 0x187: 0x9b, 0x188: 0xc7, 0x189: 0xc8, 0x18a: 0x9b, 0x18b: 0x9b, 0x18c: 0xc9, 0x18d: 0x9b, 0x18e: 0x9b, 0x18f: 0x9b, 0x190: 0xca, 0x191: 0x32, 0x192: 0x33, 0x193: 0x34, 0x194: 0x9b, 0x195: 0x9b, 0x196: 0x9b, 0x197: 0x9b, 0x198: 0x9b, 0x199: 0x9b, 0x19a: 0x9b, 0x19b: 0x9b, 0x19c: 0x9b, 0x19d: 0x9b, 0x19e: 0x9b, 0x19f: 0x9b, 0x1a0: 0x9b, 0x1a1: 0x9b, 0x1a2: 0x9b, 0x1a3: 0x9b, 0x1a4: 0x9b, 0x1a5: 0x9b, 0x1a6: 0x9b, 0x1a7: 0x9b, 0x1a8: 0xcb, 0x1a9: 0xcc, 0x1aa: 0x9b, 0x1ab: 0xcd, 0x1ac: 0x9b, 0x1ad: 0xce, 0x1ae: 0xcf, 0x1af: 0xd0, 0x1b0: 0xd1, 0x1b1: 0x35, 0x1b2: 0x28, 0x1b3: 0x36, 0x1b4: 0xd2, 0x1b5: 0xd3, 0x1b6: 0xd4, 0x1b7: 0xd5, 0x1b8: 0xd6, 0x1b9: 0xd7, 0x1ba: 0xd8, 0x1bb: 0xd9, 0x1bc: 0xda, 0x1bd: 0xdb, 0x1be: 0xdc, 0x1bf: 0x37, // Block 0x7, offset 0x1c0 0x1c0: 0x38, 0x1c1: 0xdd, 0x1c2: 0xde, 0x1c3: 0xdf, 0x1c4: 0xe0, 0x1c5: 0x39, 0x1c6: 0x3a, 0x1c7: 0xe1, 0x1c8: 0xe2, 0x1c9: 0x3b, 0x1ca: 0x3c, 0x1cb: 0x3d, 0x1cc: 0x3e, 0x1cd: 0x3f, 0x1ce: 0x40, 0x1cf: 0x41, 0x1d0: 0x9f, 0x1d1: 0x9f, 0x1d2: 0x9f, 0x1d3: 0x9f, 0x1d4: 0x9f, 0x1d5: 0x9f, 0x1d6: 0x9f, 0x1d7: 0x9f, 0x1d8: 0x9f, 0x1d9: 0x9f, 0x1da: 0x9f, 0x1db: 0x9f, 0x1dc: 0x9f, 0x1dd: 0x9f, 0x1de: 0x9f, 0x1df: 0x9f, 0x1e0: 0x9f, 0x1e1: 0x9f, 0x1e2: 0x9f, 0x1e3: 0x9f, 0x1e4: 0x9f, 0x1e5: 0x9f, 0x1e6: 0x9f, 0x1e7: 0x9f, 0x1e8: 0x9f, 0x1e9: 0x9f, 0x1ea: 0x9f, 0x1eb: 0x9f, 0x1ec: 0x9f, 0x1ed: 0x9f, 0x1ee: 0x9f, 0x1ef: 0x9f, 0x1f0: 0x9f, 0x1f1: 0x9f, 0x1f2: 0x9f, 0x1f3: 0x9f, 0x1f4: 0x9f, 0x1f5: 0x9f, 0x1f6: 0x9f, 0x1f7: 0x9f, 0x1f8: 0x9f, 0x1f9: 0x9f, 0x1fa: 0x9f, 0x1fb: 0x9f, 0x1fc: 0x9f, 0x1fd: 0x9f, 0x1fe: 0x9f, 0x1ff: 0x9f, // Block 0x8, offset 0x200 0x200: 0x9f, 0x201: 0x9f, 0x202: 0x9f, 0x203: 0x9f, 0x204: 0x9f, 0x205: 0x9f, 0x206: 0x9f, 0x207: 0x9f, 0x208: 0x9f, 0x209: 0x9f, 0x20a: 0x9f, 0x20b: 0x9f, 0x20c: 0x9f, 0x20d: 0x9f, 0x20e: 0x9f, 0x20f: 0x9f, 0x210: 0x9f, 0x211: 0x9f, 0x212: 0x9f, 0x213: 0x9f, 0x214: 0x9f, 0x215: 0x9f, 0x216: 0x9f, 0x217: 0x9f, 0x218: 0x9f, 0x219: 0x9f, 0x21a: 0x9f, 0x21b: 0x9f, 0x21c: 0x9f, 0x21d: 0x9f, 0x21e: 0x9f, 0x21f: 0x9f, 0x220: 0x9f, 0x221: 0x9f, 0x222: 0x9f, 0x223: 0x9f, 0x224: 0x9f, 0x225: 0x9f, 0x226: 0x9f, 0x227: 0x9f, 0x228: 0x9f, 0x229: 0x9f, 0x22a: 0x9f, 0x22b: 0x9f, 0x22c: 0x9f, 0x22d: 0x9f, 0x22e: 0x9f, 0x22f: 0x9f, 0x230: 0x9f, 0x231: 0x9f, 0x232: 0x9f, 0x233: 0x9f, 0x234: 0x9f, 0x235: 0x9f, 0x236: 0xb2, 0x237: 0x9b, 0x238: 0x9f, 0x239: 0x9f, 0x23a: 0x9f, 0x23b: 0x9f, 0x23c: 0x9f, 0x23d: 0x9f, 0x23e: 0x9f, 0x23f: 0x9f, // Block 0x9, offset 0x240 0x240: 0x9f, 0x241: 0x9f, 0x242: 0x9f, 0x243: 0x9f, 0x244: 0x9f, 0x245: 0x9f, 0x246: 0x9f, 0x247: 0x9f, 0x248: 0x9f, 0x249: 0x9f, 0x24a: 0x9f, 0x24b: 0x9f, 0x24c: 0x9f, 0x24d: 0x9f, 0x24e: 0x9f, 0x24f: 0x9f, 0x250: 0x9f, 0x251: 0x9f, 0x252: 0x9f, 0x253: 0x9f, 0x254: 0x9f, 0x255: 0x9f, 0x256: 0x9f, 0x257: 0x9f, 0x258: 0x9f, 0x259: 0x9f, 0x25a: 0x9f, 0x25b: 0x9f, 0x25c: 0x9f, 0x25d: 0x9f, 0x25e: 0x9f, 0x25f: 0x9f, 0x260: 0x9f, 0x261: 0x9f, 0x262: 0x9f, 0x263: 0x9f, 0x264: 0x9f, 0x265: 0x9f, 0x266: 0x9f, 0x267: 0x9f, 0x268: 0x9f, 0x269: 0x9f, 0x26a: 0x9f, 0x26b: 0x9f, 0x26c: 0x9f, 0x26d: 0x9f, 0x26e: 0x9f, 0x26f: 0x9f, 0x270: 0x9f, 0x271: 0x9f, 0x272: 0x9f, 0x273: 0x9f, 0x274: 0x9f, 0x275: 0x9f, 0x276: 0x9f, 0x277: 0x9f, 0x278: 0x9f, 0x279: 0x9f, 0x27a: 0x9f, 0x27b: 0x9f, 0x27c: 0x9f, 0x27d: 0x9f, 0x27e: 0x9f, 0x27f: 0x9f, // Block 0xa, offset 0x280 0x280: 0x9f, 0x281: 0x9f, 0x282: 0x9f, 0x283: 0x9f, 0x284: 0x9f, 0x285: 0x9f, 0x286: 0x9f, 0x287: 0x9f, 0x288: 0x9f, 0x289: 0x9f, 0x28a: 0x9f, 0x28b: 0x9f, 0x28c: 0x9f, 0x28d: 0x9f, 0x28e: 0x9f, 0x28f: 0x9f, 0x290: 0x9f, 0x291: 0x9f, 0x292: 0x9f, 0x293: 0x9f, 0x294: 0x9f, 0x295: 0x9f, 0x296: 0x9f, 0x297: 0x9f, 0x298: 0x9f, 0x299: 0x9f, 0x29a: 0x9f, 0x29b: 0x9f, 0x29c: 0x9f, 0x29d: 0x9f, 0x29e: 0x9f, 0x29f: 0x9f, 0x2a0: 0x9f, 0x2a1: 0x9f, 0x2a2: 0x9f, 0x2a3: 0x9f, 0x2a4: 0x9f, 0x2a5: 0x9f, 0x2a6: 0x9f, 0x2a7: 0x9f, 0x2a8: 0x9f, 0x2a9: 0x9f, 0x2aa: 0x9f, 0x2ab: 0x9f, 0x2ac: 0x9f, 0x2ad: 0x9f, 0x2ae: 0x9f, 0x2af: 0x9f, 0x2b0: 0x9f, 0x2b1: 0x9f, 0x2b2: 0x9f, 0x2b3: 0x9f, 0x2b4: 0x9f, 0x2b5: 0x9f, 0x2b6: 0x9f, 0x2b7: 0x9f, 0x2b8: 0x9f, 0x2b9: 0x9f, 0x2ba: 0x9f, 0x2bb: 0x9f, 0x2bc: 0x9f, 0x2bd: 0x9f, 0x2be: 0x9f, 0x2bf: 0xe3, // Block 0xb, offset 0x2c0 0x2c0: 0x9f, 0x2c1: 0x9f, 0x2c2: 0x9f, 0x2c3: 0x9f, 0x2c4: 0x9f, 0x2c5: 0x9f, 0x2c6: 0x9f, 0x2c7: 0x9f, 0x2c8: 0x9f, 0x2c9: 0x9f, 0x2ca: 0x9f, 0x2cb: 0x9f, 0x2cc: 0x9f, 0x2cd: 0x9f, 0x2ce: 0x9f, 0x2cf: 0x9f, 0x2d0: 0x9f, 0x2d1: 0x9f, 0x2d2: 0xe4, 0x2d3: 0xe5, 0x2d4: 0x9f, 0x2d5: 0x9f, 0x2d6: 0x9f, 0x2d7: 0x9f, 0x2d8: 0xe6, 0x2d9: 0x42, 0x2da: 0x43, 0x2db: 0xe7, 0x2dc: 0x44, 0x2dd: 0x45, 0x2de: 0x46, 0x2df: 0xe8, 0x2e0: 0xe9, 0x2e1: 0xea, 0x2e2: 0xeb, 0x2e3: 0xec, 0x2e4: 0xed, 0x2e5: 0xee, 0x2e6: 0xef, 0x2e7: 0xf0, 0x2e8: 0xf1, 0x2e9: 0xf2, 0x2ea: 0xf3, 0x2eb: 0xf4, 0x2ec: 0xf5, 0x2ed: 0xf6, 0x2ee: 0xf7, 0x2ef: 0xf8, 0x2f0: 0x9f, 0x2f1: 0x9f, 0x2f2: 0x9f, 0x2f3: 0x9f, 0x2f4: 0x9f, 0x2f5: 0x9f, 0x2f6: 0x9f, 0x2f7: 0x9f, 0x2f8: 0x9f, 0x2f9: 0x9f, 0x2fa: 0x9f, 0x2fb: 0x9f, 0x2fc: 0x9f, 0x2fd: 0x9f, 0x2fe: 0x9f, 0x2ff: 0x9f, // Block 0xc, offset 0x300 0x300: 0x9f, 0x301: 0x9f, 0x302: 0x9f, 0x303: 0x9f, 0x304: 0x9f, 0x305: 0x9f, 0x306: 0x9f, 0x307: 0x9f, 0x308: 0x9f, 0x309: 0x9f, 0x30a: 0x9f, 0x30b: 0x9f, 0x30c: 0x9f, 0x30d: 0x9f, 0x30e: 0x9f, 0x30f: 0x9f, 0x310: 0x9f, 0x311: 0x9f, 0x312: 0x9f, 0x313: 0x9f, 0x314: 0x9f, 0x315: 0x9f, 0x316: 0x9f, 0x317: 0x9f, 0x318: 0x9f, 0x319: 0x9f, 0x31a: 0x9f, 0x31b: 0x9f, 0x31c: 0x9f, 0x31d: 0x9f, 0x31e: 0xf9, 0x31f: 0xfa, // Block 0xd, offset 0x340 0x340: 0xba, 0x341: 0xba, 0x342: 0xba, 0x343: 0xba, 0x344: 0xba, 0x345: 0xba, 0x346: 0xba, 0x347: 0xba, 0x348: 0xba, 0x349: 0xba, 0x34a: 0xba, 0x34b: 0xba, 0x34c: 0xba, 0x34d: 0xba, 0x34e: 0xba, 0x34f: 0xba, 0x350: 0xba, 0x351: 0xba, 0x352: 0xba, 0x353: 0xba, 0x354: 0xba, 0x355: 0xba, 0x356: 0xba, 0x357: 0xba, 0x358: 0xba, 0x359: 0xba, 0x35a: 0xba, 0x35b: 0xba, 0x35c: 0xba, 0x35d: 0xba, 0x35e: 0xba, 0x35f: 0xba, 0x360: 0xba, 0x361: 0xba, 0x362: 0xba, 0x363: 0xba, 0x364: 0xba, 0x365: 0xba, 0x366: 0xba, 0x367: 0xba, 0x368: 0xba, 0x369: 0xba, 0x36a: 0xba, 0x36b: 0xba, 0x36c: 0xba, 0x36d: 0xba, 0x36e: 0xba, 0x36f: 0xba, 0x370: 0xba, 0x371: 0xba, 0x372: 0xba, 0x373: 0xba, 0x374: 0xba, 0x375: 0xba, 0x376: 0xba, 0x377: 0xba, 0x378: 0xba, 0x379: 0xba, 0x37a: 0xba, 0x37b: 0xba, 0x37c: 0xba, 0x37d: 0xba, 0x37e: 0xba, 0x37f: 0xba, // Block 0xe, offset 0x380 0x380: 0xba, 0x381: 0xba, 0x382: 0xba, 0x383: 0xba, 0x384: 0xba, 0x385: 0xba, 0x386: 0xba, 0x387: 0xba, 0x388: 0xba, 0x389: 0xba, 0x38a: 0xba, 0x38b: 0xba, 0x38c: 0xba, 0x38d: 0xba, 0x38e: 0xba, 0x38f: 0xba, 0x390: 0xba, 0x391: 0xba, 0x392: 0xba, 0x393: 0xba, 0x394: 0xba, 0x395: 0xba, 0x396: 0xba, 0x397: 0xba, 0x398: 0xba, 0x399: 0xba, 0x39a: 0xba, 0x39b: 0xba, 0x39c: 0xba, 0x39d: 0xba, 0x39e: 0xba, 0x39f: 0xba, 0x3a0: 0xba, 0x3a1: 0xba, 0x3a2: 0xba, 0x3a3: 0xba, 0x3a4: 0xfb, 0x3a5: 0xfc, 0x3a6: 0xfd, 0x3a7: 0xfe, 0x3a8: 0x47, 0x3a9: 0xff, 0x3aa: 0x100, 0x3ab: 0x48, 0x3ac: 0x49, 0x3ad: 0x4a, 0x3ae: 0x4b, 0x3af: 0x4c, 0x3b0: 0x101, 0x3b1: 0x4d, 0x3b2: 0x4e, 0x3b3: 0x4f, 0x3b4: 0x50, 0x3b5: 0x51, 0x3b6: 0x102, 0x3b7: 0x52, 0x3b8: 0x53, 0x3b9: 0x54, 0x3ba: 0x55, 0x3bb: 0x56, 0x3bc: 0x57, 0x3bd: 0x58, 0x3be: 0x59, 0x3bf: 0x5a, // Block 0xf, offset 0x3c0 0x3c0: 0x103, 0x3c1: 0x104, 0x3c2: 0x9f, 0x3c3: 0x105, 0x3c4: 0x106, 0x3c5: 0x9b, 0x3c6: 0x107, 0x3c7: 0x108, 0x3c8: 0xba, 0x3c9: 0xba, 0x3ca: 0x109, 0x3cb: 0x10a, 0x3cc: 0x10b, 0x3cd: 0x10c, 0x3ce: 0x10d, 0x3cf: 0x10e, 0x3d0: 0x10f, 0x3d1: 0x9f, 0x3d2: 0x110, 0x3d3: 0x111, 0x3d4: 0x112, 0x3d5: 0x113, 0x3d6: 0xba, 0x3d7: 0xba, 0x3d8: 0x9f, 0x3d9: 0x9f, 0x3da: 0x9f, 0x3db: 0x9f, 0x3dc: 0x114, 0x3dd: 0x115, 0x3de: 0xba, 0x3df: 0xba, 0x3e0: 0x116, 0x3e1: 0x117, 0x3e2: 0x118, 0x3e3: 0x119, 0x3e4: 0x11a, 0x3e5: 0xba, 0x3e6: 0x11b, 0x3e7: 0x11c, 0x3e8: 0x11d, 0x3e9: 0x11e, 0x3ea: 0x11f, 0x3eb: 0x5b, 0x3ec: 0x120, 0x3ed: 0x121, 0x3ee: 0x5c, 0x3ef: 0xba, 0x3f0: 0x122, 0x3f1: 0x123, 0x3f2: 0x124, 0x3f3: 0x125, 0x3f4: 0x126, 0x3f5: 0xba, 0x3f6: 0xba, 0x3f7: 0xba, 0x3f8: 0xba, 0x3f9: 0x127, 0x3fa: 0xba, 0x3fb: 0xba, 0x3fc: 0x128, 0x3fd: 0x129, 0x3fe: 0xba, 0x3ff: 0xba, // Block 0x10, offset 0x400 0x400: 0x12a, 0x401: 0x12b, 0x402: 0x12c, 0x403: 0x12d, 0x404: 0x12e, 0x405: 0x12f, 0x406: 0x130, 0x407: 0x131, 0x408: 0x132, 0x409: 0xba, 0x40a: 0x133, 0x40b: 0x134, 0x40c: 0x5d, 0x40d: 0x5e, 0x40e: 0xba, 0x40f: 0xba, 0x410: 0x135, 0x411: 0x136, 0x412: 0x137, 0x413: 0x138, 0x414: 0xba, 0x415: 0xba, 0x416: 0x139, 0x417: 0x13a, 0x418: 0x13b, 0x419: 0x13c, 0x41a: 0x13d, 0x41b: 0x13e, 0x41c: 0x13f, 0x41d: 0xba, 0x41e: 0xba, 0x41f: 0xba, 0x420: 0x140, 0x421: 0xba, 0x422: 0x141, 0x423: 0x142, 0x424: 0xba, 0x425: 0xba, 0x426: 0xba, 0x427: 0xba, 0x428: 0x143, 0x429: 0x144, 0x42a: 0x145, 0x42b: 0x146, 0x42c: 0xba, 0x42d: 0xba, 0x42e: 0xba, 0x42f: 0xba, 0x430: 0x147, 0x431: 0x148, 0x432: 0x149, 0x433: 0xba, 0x434: 0x14a, 0x435: 0x14b, 0x436: 0x14c, 0x437: 0xba, 0x438: 0xba, 0x439: 0xba, 0x43a: 0xba, 0x43b: 0x14d, 0x43c: 0xba, 0x43d: 0xba, 0x43e: 0xba, 0x43f: 0xba, // Block 0x11, offset 0x440 0x440: 0x9f, 0x441: 0x9f, 0x442: 0x9f, 0x443: 0x9f, 0x444: 0x9f, 0x445: 0x9f, 0x446: 0x9f, 0x447: 0x9f, 0x448: 0x9f, 0x449: 0x9f, 0x44a: 0x9f, 0x44b: 0x9f, 0x44c: 0x9f, 0x44d: 0x9f, 0x44e: 0x14e, 0x44f: 0xba, 0x450: 0x9b, 0x451: 0x14f, 0x452: 0x9f, 0x453: 0x9f, 0x454: 0x9f, 0x455: 0x150, 0x456: 0xba, 0x457: 0xba, 0x458: 0xba, 0x459: 0xba, 0x45a: 0xba, 0x45b: 0xba, 0x45c: 0xba, 0x45d: 0xba, 0x45e: 0xba, 0x45f: 0xba, 0x460: 0xba, 0x461: 0xba, 0x462: 0xba, 0x463: 0xba, 0x464: 0xba, 0x465: 0xba, 0x466: 0xba, 0x467: 0xba, 0x468: 0xba, 0x469: 0xba, 0x46a: 0xba, 0x46b: 0xba, 0x46c: 0xba, 0x46d: 0xba, 0x46e: 0xba, 0x46f: 0xba, 0x470: 0xba, 0x471: 0xba, 0x472: 0xba, 0x473: 0xba, 0x474: 0xba, 0x475: 0xba, 0x476: 0xba, 0x477: 0xba, 0x478: 0xba, 0x479: 0xba, 0x47a: 0xba, 0x47b: 0xba, 0x47c: 0xba, 0x47d: 0xba, 0x47e: 0xba, 0x47f: 0xba, // Block 0x12, offset 0x480 0x480: 0x9f, 0x481: 0x9f, 0x482: 0x9f, 0x483: 0x9f, 0x484: 0x9f, 0x485: 0x9f, 0x486: 0x9f, 0x487: 0x9f, 0x488: 0x9f, 0x489: 0x9f, 0x48a: 0x9f, 0x48b: 0x9f, 0x48c: 0x9f, 0x48d: 0x9f, 0x48e: 0x9f, 0x48f: 0x9f, 0x490: 0x151, 0x491: 0xba, 0x492: 0xba, 0x493: 0xba, 0x494: 0xba, 0x495: 0xba, 0x496: 0xba, 0x497: 0xba, 0x498: 0xba, 0x499: 0xba, 0x49a: 0xba, 0x49b: 0xba, 0x49c: 0xba, 0x49d: 0xba, 0x49e: 0xba, 0x49f: 0xba, 0x4a0: 0xba, 0x4a1: 0xba, 0x4a2: 0xba, 0x4a3: 0xba, 0x4a4: 0xba, 0x4a5: 0xba, 0x4a6: 0xba, 0x4a7: 0xba, 0x4a8: 0xba, 0x4a9: 0xba, 0x4aa: 0xba, 0x4ab: 0xba, 0x4ac: 0xba, 0x4ad: 0xba, 0x4ae: 0xba, 0x4af: 0xba, 0x4b0: 0xba, 0x4b1: 0xba, 0x4b2: 0xba, 0x4b3: 0xba, 0x4b4: 0xba, 0x4b5: 0xba, 0x4b6: 0xba, 0x4b7: 0xba, 0x4b8: 0xba, 0x4b9: 0xba, 0x4ba: 0xba, 0x4bb: 0xba, 0x4bc: 0xba, 0x4bd: 0xba, 0x4be: 0xba, 0x4bf: 0xba, // Block 0x13, offset 0x4c0 0x4c0: 0xba, 0x4c1: 0xba, 0x4c2: 0xba, 0x4c3: 0xba, 0x4c4: 0xba, 0x4c5: 0xba, 0x4c6: 0xba, 0x4c7: 0xba, 0x4c8: 0xba, 0x4c9: 0xba, 0x4ca: 0xba, 0x4cb: 0xba, 0x4cc: 0xba, 0x4cd: 0xba, 0x4ce: 0xba, 0x4cf: 0xba, 0x4d0: 0x9f, 0x4d1: 0x9f, 0x4d2: 0x9f, 0x4d3: 0x9f, 0x4d4: 0x9f, 0x4d5: 0x9f, 0x4d6: 0x9f, 0x4d7: 0x9f, 0x4d8: 0x9f, 0x4d9: 0x152, 0x4da: 0xba, 0x4db: 0xba, 0x4dc: 0xba, 0x4dd: 0xba, 0x4de: 0xba, 0x4df: 0xba, 0x4e0: 0xba, 0x4e1: 0xba, 0x4e2: 0xba, 0x4e3: 0xba, 0x4e4: 0xba, 0x4e5: 0xba, 0x4e6: 0xba, 0x4e7: 0xba, 0x4e8: 0xba, 0x4e9: 0xba, 0x4ea: 0xba, 0x4eb: 0xba, 0x4ec: 0xba, 0x4ed: 0xba, 0x4ee: 0xba, 0x4ef: 0xba, 0x4f0: 0xba, 0x4f1: 0xba, 0x4f2: 0xba, 0x4f3: 0xba, 0x4f4: 0xba, 0x4f5: 0xba, 0x4f6: 0xba, 0x4f7: 0xba, 0x4f8: 0xba, 0x4f9: 0xba, 0x4fa: 0xba, 0x4fb: 0xba, 0x4fc: 0xba, 0x4fd: 0xba, 0x4fe: 0xba, 0x4ff: 0xba, // Block 0x14, offset 0x500 0x500: 0xba, 0x501: 0xba, 0x502: 0xba, 0x503: 0xba, 0x504: 0xba, 0x505: 0xba, 0x506: 0xba, 0x507: 0xba, 0x508: 0xba, 0x509: 0xba, 0x50a: 0xba, 0x50b: 0xba, 0x50c: 0xba, 0x50d: 0xba, 0x50e: 0xba, 0x50f: 0xba, 0x510: 0xba, 0x511: 0xba, 0x512: 0xba, 0x513: 0xba, 0x514: 0xba, 0x515: 0xba, 0x516: 0xba, 0x517: 0xba, 0x518: 0xba, 0x519: 0xba, 0x51a: 0xba, 0x51b: 0xba, 0x51c: 0xba, 0x51d: 0xba, 0x51e: 0xba, 0x51f: 0xba, 0x520: 0x9f, 0x521: 0x9f, 0x522: 0x9f, 0x523: 0x9f, 0x524: 0x9f, 0x525: 0x9f, 0x526: 0x9f, 0x527: 0x9f, 0x528: 0x146, 0x529: 0x153, 0x52a: 0xba, 0x52b: 0x154, 0x52c: 0x155, 0x52d: 0x156, 0x52e: 0x157, 0x52f: 0xba, 0x530: 0xba, 0x531: 0xba, 0x532: 0xba, 0x533: 0xba, 0x534: 0xba, 0x535: 0xba, 0x536: 0xba, 0x537: 0xba, 0x538: 0xba, 0x539: 0x158, 0x53a: 0x159, 0x53b: 0xba, 0x53c: 0x9f, 0x53d: 0x15a, 0x53e: 0x15b, 0x53f: 0x15c, // Block 0x15, offset 0x540 0x540: 0x9f, 0x541: 0x9f, 0x542: 0x9f, 0x543: 0x9f, 0x544: 0x9f, 0x545: 0x9f, 0x546: 0x9f, 0x547: 0x9f, 0x548: 0x9f, 0x549: 0x9f, 0x54a: 0x9f, 0x54b: 0x9f, 0x54c: 0x9f, 0x54d: 0x9f, 0x54e: 0x9f, 0x54f: 0x9f, 0x550: 0x9f, 0x551: 0x9f, 0x552: 0x9f, 0x553: 0x9f, 0x554: 0x9f, 0x555: 0x9f, 0x556: 0x9f, 0x557: 0x9f, 0x558: 0x9f, 0x559: 0x9f, 0x55a: 0x9f, 0x55b: 0x9f, 0x55c: 0x9f, 0x55d: 0x9f, 0x55e: 0x9f, 0x55f: 0x15d, 0x560: 0x9f, 0x561: 0x9f, 0x562: 0x9f, 0x563: 0x9f, 0x564: 0x9f, 0x565: 0x9f, 0x566: 0x9f, 0x567: 0x9f, 0x568: 0x9f, 0x569: 0x9f, 0x56a: 0x9f, 0x56b: 0x15e, 0x56c: 0xba, 0x56d: 0xba, 0x56e: 0xba, 0x56f: 0xba, 0x570: 0xba, 0x571: 0xba, 0x572: 0xba, 0x573: 0xba, 0x574: 0xba, 0x575: 0xba, 0x576: 0xba, 0x577: 0xba, 0x578: 0xba, 0x579: 0xba, 0x57a: 0xba, 0x57b: 0xba, 0x57c: 0xba, 0x57d: 0xba, 0x57e: 0xba, 0x57f: 0xba, // Block 0x16, offset 0x580 0x580: 0x9f, 0x581: 0x9f, 0x582: 0x9f, 0x583: 0x9f, 0x584: 0x15f, 0x585: 0x160, 0x586: 0x9f, 0x587: 0x9f, 0x588: 0x9f, 0x589: 0x9f, 0x58a: 0x9f, 0x58b: 0x161, 0x58c: 0xba, 0x58d: 0xba, 0x58e: 0xba, 0x58f: 0xba, 0x590: 0xba, 0x591: 0xba, 0x592: 0xba, 0x593: 0xba, 0x594: 0xba, 0x595: 0xba, 0x596: 0xba, 0x597: 0xba, 0x598: 0xba, 0x599: 0xba, 0x59a: 0xba, 0x59b: 0xba, 0x59c: 0xba, 0x59d: 0xba, 0x59e: 0xba, 0x59f: 0xba, 0x5a0: 0xba, 0x5a1: 0xba, 0x5a2: 0xba, 0x5a3: 0xba, 0x5a4: 0xba, 0x5a5: 0xba, 0x5a6: 0xba, 0x5a7: 0xba, 0x5a8: 0xba, 0x5a9: 0xba, 0x5aa: 0xba, 0x5ab: 0xba, 0x5ac: 0xba, 0x5ad: 0xba, 0x5ae: 0xba, 0x5af: 0xba, 0x5b0: 0x9f, 0x5b1: 0x162, 0x5b2: 0x163, 0x5b3: 0xba, 0x5b4: 0xba, 0x5b5: 0xba, 0x5b6: 0xba, 0x5b7: 0xba, 0x5b8: 0xba, 0x5b9: 0xba, 0x5ba: 0xba, 0x5bb: 0xba, 0x5bc: 0xba, 0x5bd: 0xba, 0x5be: 0xba, 0x5bf: 0xba, // Block 0x17, offset 0x5c0 0x5c0: 0x9b, 0x5c1: 0x9b, 0x5c2: 0x9b, 0x5c3: 0x164, 0x5c4: 0x165, 0x5c5: 0x166, 0x5c6: 0x167, 0x5c7: 0x168, 0x5c8: 0x9b, 0x5c9: 0x169, 0x5ca: 0xba, 0x5cb: 0x16a, 0x5cc: 0x9b, 0x5cd: 0x16b, 0x5ce: 0xba, 0x5cf: 0xba, 0x5d0: 0x5f, 0x5d1: 0x60, 0x5d2: 0x61, 0x5d3: 0x62, 0x5d4: 0x63, 0x5d5: 0x64, 0x5d6: 0x65, 0x5d7: 0x66, 0x5d8: 0x67, 0x5d9: 0x68, 0x5da: 0x69, 0x5db: 0x6a, 0x5dc: 0x6b, 0x5dd: 0x6c, 0x5de: 0x6d, 0x5df: 0x6e, 0x5e0: 0x9b, 0x5e1: 0x9b, 0x5e2: 0x9b, 0x5e3: 0x9b, 0x5e4: 0x9b, 0x5e5: 0x9b, 0x5e6: 0x9b, 0x5e7: 0x9b, 0x5e8: 0x16c, 0x5e9: 0x16d, 0x5ea: 0x16e, 0x5eb: 0xba, 0x5ec: 0xba, 0x5ed: 0xba, 0x5ee: 0xba, 0x5ef: 0xba, 0x5f0: 0xba, 0x5f1: 0xba, 0x5f2: 0xba, 0x5f3: 0xba, 0x5f4: 0xba, 0x5f5: 0xba, 0x5f6: 0xba, 0x5f7: 0xba, 0x5f8: 0xba, 0x5f9: 0xba, 0x5fa: 0xba, 0x5fb: 0xba, 0x5fc: 0xba, 0x5fd: 0xba, 0x5fe: 0xba, 0x5ff: 0xba, // Block 0x18, offset 0x600 0x600: 0x16f, 0x601: 0xba, 0x602: 0xba, 0x603: 0xba, 0x604: 0xba, 0x605: 0xba, 0x606: 0xba, 0x607: 0xba, 0x608: 0xba, 0x609: 0xba, 0x60a: 0xba, 0x60b: 0xba, 0x60c: 0xba, 0x60d: 0xba, 0x60e: 0xba, 0x60f: 0xba, 0x610: 0xba, 0x611: 0xba, 0x612: 0xba, 0x613: 0xba, 0x614: 0xba, 0x615: 0xba, 0x616: 0xba, 0x617: 0xba, 0x618: 0xba, 0x619: 0xba, 0x61a: 0xba, 0x61b: 0xba, 0x61c: 0xba, 0x61d: 0xba, 0x61e: 0xba, 0x61f: 0xba, 0x620: 0x122, 0x621: 0x122, 0x622: 0x122, 0x623: 0x170, 0x624: 0x6f, 0x625: 0x171, 0x626: 0xba, 0x627: 0xba, 0x628: 0xba, 0x629: 0xba, 0x62a: 0xba, 0x62b: 0xba, 0x62c: 0xba, 0x62d: 0xba, 0x62e: 0xba, 0x62f: 0xba, 0x630: 0xba, 0x631: 0x172, 0x632: 0x173, 0x633: 0xba, 0x634: 0xba, 0x635: 0xba, 0x636: 0xba, 0x637: 0xba, 0x638: 0x70, 0x639: 0x71, 0x63a: 0x72, 0x63b: 0x174, 0x63c: 0xba, 0x63d: 0xba, 0x63e: 0xba, 0x63f: 0xba, // Block 0x19, offset 0x640 0x640: 0x175, 0x641: 0x9b, 0x642: 0x176, 0x643: 0x177, 0x644: 0x73, 0x645: 0x74, 0x646: 0x178, 0x647: 0x179, 0x648: 0x75, 0x649: 0x17a, 0x64a: 0xba, 0x64b: 0xba, 0x64c: 0x9b, 0x64d: 0x9b, 0x64e: 0x9b, 0x64f: 0x9b, 0x650: 0x9b, 0x651: 0x9b, 0x652: 0x9b, 0x653: 0x9b, 0x654: 0x9b, 0x655: 0x9b, 0x656: 0x9b, 0x657: 0x9b, 0x658: 0x9b, 0x659: 0x9b, 0x65a: 0x9b, 0x65b: 0x17b, 0x65c: 0x9b, 0x65d: 0x17c, 0x65e: 0x9b, 0x65f: 0x17d, 0x660: 0x17e, 0x661: 0x17f, 0x662: 0x180, 0x663: 0xba, 0x664: 0x181, 0x665: 0x182, 0x666: 0x183, 0x667: 0x184, 0x668: 0xba, 0x669: 0x185, 0x66a: 0xba, 0x66b: 0xba, 0x66c: 0xba, 0x66d: 0xba, 0x66e: 0xba, 0x66f: 0xba, 0x670: 0xba, 0x671: 0xba, 0x672: 0xba, 0x673: 0xba, 0x674: 0xba, 0x675: 0xba, 0x676: 0xba, 0x677: 0xba, 0x678: 0xba, 0x679: 0xba, 0x67a: 0xba, 0x67b: 0xba, 0x67c: 0xba, 0x67d: 0xba, 0x67e: 0xba, 0x67f: 0xba, // Block 0x1a, offset 0x680 0x680: 0x9f, 0x681: 0x9f, 0x682: 0x9f, 0x683: 0x9f, 0x684: 0x9f, 0x685: 0x9f, 0x686: 0x9f, 0x687: 0x9f, 0x688: 0x9f, 0x689: 0x9f, 0x68a: 0x9f, 0x68b: 0x9f, 0x68c: 0x9f, 0x68d: 0x9f, 0x68e: 0x9f, 0x68f: 0x9f, 0x690: 0x9f, 0x691: 0x9f, 0x692: 0x9f, 0x693: 0x9f, 0x694: 0x9f, 0x695: 0x9f, 0x696: 0x9f, 0x697: 0x9f, 0x698: 0x9f, 0x699: 0x9f, 0x69a: 0x9f, 0x69b: 0x186, 0x69c: 0x9f, 0x69d: 0x9f, 0x69e: 0x9f, 0x69f: 0x9f, 0x6a0: 0x9f, 0x6a1: 0x9f, 0x6a2: 0x9f, 0x6a3: 0x9f, 0x6a4: 0x9f, 0x6a5: 0x9f, 0x6a6: 0x9f, 0x6a7: 0x9f, 0x6a8: 0x9f, 0x6a9: 0x9f, 0x6aa: 0x9f, 0x6ab: 0x9f, 0x6ac: 0x9f, 0x6ad: 0x9f, 0x6ae: 0x9f, 0x6af: 0x9f, 0x6b0: 0x9f, 0x6b1: 0x9f, 0x6b2: 0x9f, 0x6b3: 0x9f, 0x6b4: 0x9f, 0x6b5: 0x9f, 0x6b6: 0x9f, 0x6b7: 0x9f, 0x6b8: 0x9f, 0x6b9: 0x9f, 0x6ba: 0x9f, 0x6bb: 0x9f, 0x6bc: 0x9f, 0x6bd: 0x9f, 0x6be: 0x9f, 0x6bf: 0x9f, // Block 0x1b, offset 0x6c0 0x6c0: 0x9f, 0x6c1: 0x9f, 0x6c2: 0x9f, 0x6c3: 0x9f, 0x6c4: 0x9f, 0x6c5: 0x9f, 0x6c6: 0x9f, 0x6c7: 0x9f, 0x6c8: 0x9f, 0x6c9: 0x9f, 0x6ca: 0x9f, 0x6cb: 0x9f, 0x6cc: 0x9f, 0x6cd: 0x9f, 0x6ce: 0x9f, 0x6cf: 0x9f, 0x6d0: 0x9f, 0x6d1: 0x9f, 0x6d2: 0x9f, 0x6d3: 0x9f, 0x6d4: 0x9f, 0x6d5: 0x9f, 0x6d6: 0x9f, 0x6d7: 0x9f, 0x6d8: 0x9f, 0x6d9: 0x9f, 0x6da: 0x9f, 0x6db: 0x9f, 0x6dc: 0x187, 0x6dd: 0x9f, 0x6de: 0x9f, 0x6df: 0x9f, 0x6e0: 0x188, 0x6e1: 0x9f, 0x6e2: 0x9f, 0x6e3: 0x9f, 0x6e4: 0x9f, 0x6e5: 0x9f, 0x6e6: 0x9f, 0x6e7: 0x9f, 0x6e8: 0x9f, 0x6e9: 0x9f, 0x6ea: 0x9f, 0x6eb: 0x9f, 0x6ec: 0x9f, 0x6ed: 0x9f, 0x6ee: 0x9f, 0x6ef: 0x9f, 0x6f0: 0x9f, 0x6f1: 0x9f, 0x6f2: 0x9f, 0x6f3: 0x9f, 0x6f4: 0x9f, 0x6f5: 0x9f, 0x6f6: 0x9f, 0x6f7: 0x9f, 0x6f8: 0x9f, 0x6f9: 0x9f, 0x6fa: 0x9f, 0x6fb: 0x9f, 0x6fc: 0x9f, 0x6fd: 0x9f, 0x6fe: 0x9f, 0x6ff: 0x9f, // Block 0x1c, offset 0x700 0x700: 0x9f, 0x701: 0x9f, 0x702: 0x9f, 0x703: 0x9f, 0x704: 0x9f, 0x705: 0x9f, 0x706: 0x9f, 0x707: 0x9f, 0x708: 0x9f, 0x709: 0x9f, 0x70a: 0x9f, 0x70b: 0x9f, 0x70c: 0x9f, 0x70d: 0x9f, 0x70e: 0x9f, 0x70f: 0x9f, 0x710: 0x9f, 0x711: 0x9f, 0x712: 0x9f, 0x713: 0x9f, 0x714: 0x9f, 0x715: 0x9f, 0x716: 0x9f, 0x717: 0x9f, 0x718: 0x9f, 0x719: 0x9f, 0x71a: 0x9f, 0x71b: 0x9f, 0x71c: 0x9f, 0x71d: 0x9f, 0x71e: 0x9f, 0x71f: 0x9f, 0x720: 0x9f, 0x721: 0x9f, 0x722: 0x9f, 0x723: 0x9f, 0x724: 0x9f, 0x725: 0x9f, 0x726: 0x9f, 0x727: 0x9f, 0x728: 0x9f, 0x729: 0x9f, 0x72a: 0x9f, 0x72b: 0x9f, 0x72c: 0x9f, 0x72d: 0x9f, 0x72e: 0x9f, 0x72f: 0x9f, 0x730: 0x9f, 0x731: 0x9f, 0x732: 0x9f, 0x733: 0x9f, 0x734: 0x9f, 0x735: 0x9f, 0x736: 0x9f, 0x737: 0x9f, 0x738: 0x9f, 0x739: 0x9f, 0x73a: 0x189, 0x73b: 0x9f, 0x73c: 0x9f, 0x73d: 0x9f, 0x73e: 0x9f, 0x73f: 0x9f, // Block 0x1d, offset 0x740 0x740: 0x9f, 0x741: 0x9f, 0x742: 0x9f, 0x743: 0x9f, 0x744: 0x9f, 0x745: 0x9f, 0x746: 0x9f, 0x747: 0x9f, 0x748: 0x9f, 0x749: 0x9f, 0x74a: 0x9f, 0x74b: 0x9f, 0x74c: 0x9f, 0x74d: 0x9f, 0x74e: 0x9f, 0x74f: 0x9f, 0x750: 0x9f, 0x751: 0x9f, 0x752: 0x9f, 0x753: 0x9f, 0x754: 0x9f, 0x755: 0x9f, 0x756: 0x9f, 0x757: 0x9f, 0x758: 0x9f, 0x759: 0x9f, 0x75a: 0x9f, 0x75b: 0x9f, 0x75c: 0x9f, 0x75d: 0x9f, 0x75e: 0x9f, 0x75f: 0x9f, 0x760: 0x9f, 0x761: 0x9f, 0x762: 0x9f, 0x763: 0x9f, 0x764: 0x9f, 0x765: 0x9f, 0x766: 0x9f, 0x767: 0x9f, 0x768: 0x9f, 0x769: 0x9f, 0x76a: 0x9f, 0x76b: 0x9f, 0x76c: 0x9f, 0x76d: 0x9f, 0x76e: 0x9f, 0x76f: 0x18a, 0x770: 0xba, 0x771: 0xba, 0x772: 0xba, 0x773: 0xba, 0x774: 0xba, 0x775: 0xba, 0x776: 0xba, 0x777: 0xba, 0x778: 0xba, 0x779: 0xba, 0x77a: 0xba, 0x77b: 0xba, 0x77c: 0xba, 0x77d: 0xba, 0x77e: 0xba, 0x77f: 0xba, // Block 0x1e, offset 0x780 0x780: 0xba, 0x781: 0xba, 0x782: 0xba, 0x783: 0xba, 0x784: 0xba, 0x785: 0xba, 0x786: 0xba, 0x787: 0xba, 0x788: 0xba, 0x789: 0xba, 0x78a: 0xba, 0x78b: 0xba, 0x78c: 0xba, 0x78d: 0xba, 0x78e: 0xba, 0x78f: 0xba, 0x790: 0xba, 0x791: 0xba, 0x792: 0xba, 0x793: 0xba, 0x794: 0xba, 0x795: 0xba, 0x796: 0xba, 0x797: 0xba, 0x798: 0xba, 0x799: 0xba, 0x79a: 0xba, 0x79b: 0xba, 0x79c: 0xba, 0x79d: 0xba, 0x79e: 0xba, 0x79f: 0xba, 0x7a0: 0x76, 0x7a1: 0x77, 0x7a2: 0x78, 0x7a3: 0x18b, 0x7a4: 0x79, 0x7a5: 0x7a, 0x7a6: 0x18c, 0x7a7: 0x7b, 0x7a8: 0x7c, 0x7a9: 0xba, 0x7aa: 0xba, 0x7ab: 0xba, 0x7ac: 0xba, 0x7ad: 0xba, 0x7ae: 0xba, 0x7af: 0xba, 0x7b0: 0xba, 0x7b1: 0xba, 0x7b2: 0xba, 0x7b3: 0xba, 0x7b4: 0xba, 0x7b5: 0xba, 0x7b6: 0xba, 0x7b7: 0xba, 0x7b8: 0xba, 0x7b9: 0xba, 0x7ba: 0xba, 0x7bb: 0xba, 0x7bc: 0xba, 0x7bd: 0xba, 0x7be: 0xba, 0x7bf: 0xba, // Block 0x1f, offset 0x7c0 0x7d0: 0x0d, 0x7d1: 0x0e, 0x7d2: 0x0f, 0x7d3: 0x10, 0x7d4: 0x11, 0x7d5: 0x0b, 0x7d6: 0x12, 0x7d7: 0x07, 0x7d8: 0x13, 0x7d9: 0x0b, 0x7da: 0x0b, 0x7db: 0x14, 0x7dc: 0x0b, 0x7dd: 0x15, 0x7de: 0x16, 0x7df: 0x17, 0x7e0: 0x07, 0x7e1: 0x07, 0x7e2: 0x07, 0x7e3: 0x07, 0x7e4: 0x07, 0x7e5: 0x07, 0x7e6: 0x07, 0x7e7: 0x07, 0x7e8: 0x07, 0x7e9: 0x07, 0x7ea: 0x18, 0x7eb: 0x19, 0x7ec: 0x1a, 0x7ed: 0x07, 0x7ee: 0x1b, 0x7ef: 0x1c, 0x7f0: 0x0b, 0x7f1: 0x0b, 0x7f2: 0x0b, 0x7f3: 0x0b, 0x7f4: 0x0b, 0x7f5: 0x0b, 0x7f6: 0x0b, 0x7f7: 0x0b, 0x7f8: 0x0b, 0x7f9: 0x0b, 0x7fa: 0x0b, 0x7fb: 0x0b, 0x7fc: 0x0b, 0x7fd: 0x0b, 0x7fe: 0x0b, 0x7ff: 0x0b, // Block 0x20, offset 0x800 0x800: 0x0b, 0x801: 0x0b, 0x802: 0x0b, 0x803: 0x0b, 0x804: 0x0b, 0x805: 0x0b, 0x806: 0x0b, 0x807: 0x0b, 0x808: 0x0b, 0x809: 0x0b, 0x80a: 0x0b, 0x80b: 0x0b, 0x80c: 0x0b, 0x80d: 0x0b, 0x80e: 0x0b, 0x80f: 0x0b, 0x810: 0x0b, 0x811: 0x0b, 0x812: 0x0b, 0x813: 0x0b, 0x814: 0x0b, 0x815: 0x0b, 0x816: 0x0b, 0x817: 0x0b, 0x818: 0x0b, 0x819: 0x0b, 0x81a: 0x0b, 0x81b: 0x0b, 0x81c: 0x0b, 0x81d: 0x0b, 0x81e: 0x0b, 0x81f: 0x0b, 0x820: 0x0b, 0x821: 0x0b, 0x822: 0x0b, 0x823: 0x0b, 0x824: 0x0b, 0x825: 0x0b, 0x826: 0x0b, 0x827: 0x0b, 0x828: 0x0b, 0x829: 0x0b, 0x82a: 0x0b, 0x82b: 0x0b, 0x82c: 0x0b, 0x82d: 0x0b, 0x82e: 0x0b, 0x82f: 0x0b, 0x830: 0x0b, 0x831: 0x0b, 0x832: 0x0b, 0x833: 0x0b, 0x834: 0x0b, 0x835: 0x0b, 0x836: 0x0b, 0x837: 0x0b, 0x838: 0x0b, 0x839: 0x0b, 0x83a: 0x0b, 0x83b: 0x0b, 0x83c: 0x0b, 0x83d: 0x0b, 0x83e: 0x0b, 0x83f: 0x0b, // Block 0x21, offset 0x840 0x840: 0x18d, 0x841: 0x18e, 0x842: 0xba, 0x843: 0xba, 0x844: 0x18f, 0x845: 0x18f, 0x846: 0x18f, 0x847: 0x190, 0x848: 0xba, 0x849: 0xba, 0x84a: 0xba, 0x84b: 0xba, 0x84c: 0xba, 0x84d: 0xba, 0x84e: 0xba, 0x84f: 0xba, 0x850: 0xba, 0x851: 0xba, 0x852: 0xba, 0x853: 0xba, 0x854: 0xba, 0x855: 0xba, 0x856: 0xba, 0x857: 0xba, 0x858: 0xba, 0x859: 0xba, 0x85a: 0xba, 0x85b: 0xba, 0x85c: 0xba, 0x85d: 0xba, 0x85e: 0xba, 0x85f: 0xba, 0x860: 0xba, 0x861: 0xba, 0x862: 0xba, 0x863: 0xba, 0x864: 0xba, 0x865: 0xba, 0x866: 0xba, 0x867: 0xba, 0x868: 0xba, 0x869: 0xba, 0x86a: 0xba, 0x86b: 0xba, 0x86c: 0xba, 0x86d: 0xba, 0x86e: 0xba, 0x86f: 0xba, 0x870: 0xba, 0x871: 0xba, 0x872: 0xba, 0x873: 0xba, 0x874: 0xba, 0x875: 0xba, 0x876: 0xba, 0x877: 0xba, 0x878: 0xba, 0x879: 0xba, 0x87a: 0xba, 0x87b: 0xba, 0x87c: 0xba, 0x87d: 0xba, 0x87e: 0xba, 0x87f: 0xba, // Block 0x22, offset 0x880 0x880: 0x0b, 0x881: 0x0b, 0x882: 0x0b, 0x883: 0x0b, 0x884: 0x0b, 0x885: 0x0b, 0x886: 0x0b, 0x887: 0x0b, 0x888: 0x0b, 0x889: 0x0b, 0x88a: 0x0b, 0x88b: 0x0b, 0x88c: 0x0b, 0x88d: 0x0b, 0x88e: 0x0b, 0x88f: 0x0b, 0x890: 0x0b, 0x891: 0x0b, 0x892: 0x0b, 0x893: 0x0b, 0x894: 0x0b, 0x895: 0x0b, 0x896: 0x0b, 0x897: 0x0b, 0x898: 0x0b, 0x899: 0x0b, 0x89a: 0x0b, 0x89b: 0x0b, 0x89c: 0x0b, 0x89d: 0x0b, 0x89e: 0x0b, 0x89f: 0x0b, 0x8a0: 0x1f, 0x8a1: 0x0b, 0x8a2: 0x0b, 0x8a3: 0x0b, 0x8a4: 0x0b, 0x8a5: 0x0b, 0x8a6: 0x0b, 0x8a7: 0x0b, 0x8a8: 0x0b, 0x8a9: 0x0b, 0x8aa: 0x0b, 0x8ab: 0x0b, 0x8ac: 0x0b, 0x8ad: 0x0b, 0x8ae: 0x0b, 0x8af: 0x0b, 0x8b0: 0x0b, 0x8b1: 0x0b, 0x8b2: 0x0b, 0x8b3: 0x0b, 0x8b4: 0x0b, 0x8b5: 0x0b, 0x8b6: 0x0b, 0x8b7: 0x0b, 0x8b8: 0x0b, 0x8b9: 0x0b, 0x8ba: 0x0b, 0x8bb: 0x0b, 0x8bc: 0x0b, 0x8bd: 0x0b, 0x8be: 0x0b, 0x8bf: 0x0b, // Block 0x23, offset 0x8c0 0x8c0: 0x0b, 0x8c1: 0x0b, 0x8c2: 0x0b, 0x8c3: 0x0b, 0x8c4: 0x0b, 0x8c5: 0x0b, 0x8c6: 0x0b, 0x8c7: 0x0b, 0x8c8: 0x0b, 0x8c9: 0x0b, 0x8ca: 0x0b, 0x8cb: 0x0b, 0x8cc: 0x0b, 0x8cd: 0x0b, 0x8ce: 0x0b, 0x8cf: 0x0b, } // idnaSparseOffset: 276 entries, 552 bytes var idnaSparseOffset = []uint16{0x0, 0x8, 0x19, 0x25, 0x27, 0x2c, 0x33, 0x3e, 0x4a, 0x4e, 0x5d, 0x62, 0x6c, 0x78, 0x86, 0x8b, 0x94, 0xa4, 0xb2, 0xbe, 0xca, 0xdb, 0xe5, 0xec, 0xf9, 0x10a, 0x111, 0x11c, 0x12b, 0x139, 0x143, 0x145, 0x14a, 0x14d, 0x150, 0x152, 0x15e, 0x169, 0x171, 0x177, 0x17d, 0x182, 0x187, 0x18a, 0x18e, 0x194, 0x199, 0x1a5, 0x1af, 0x1b5, 0x1c6, 0x1d0, 0x1d3, 0x1db, 0x1de, 0x1eb, 0x1f3, 0x1f7, 0x1fe, 0x206, 0x216, 0x222, 0x224, 0x22e, 0x23a, 0x246, 0x252, 0x25a, 0x25f, 0x269, 0x27a, 0x27e, 0x289, 0x28d, 0x296, 0x29e, 0x2a4, 0x2a9, 0x2ac, 0x2b0, 0x2b6, 0x2ba, 0x2be, 0x2c2, 0x2c7, 0x2cd, 0x2d5, 0x2dc, 0x2e7, 0x2f1, 0x2f5, 0x2f8, 0x2fe, 0x302, 0x304, 0x307, 0x309, 0x30c, 0x316, 0x319, 0x328, 0x32c, 0x331, 0x334, 0x338, 0x33d, 0x342, 0x348, 0x34e, 0x35d, 0x363, 0x367, 0x376, 0x37b, 0x383, 0x38d, 0x398, 0x3a0, 0x3b1, 0x3ba, 0x3ca, 0x3d7, 0x3e1, 0x3e6, 0x3f3, 0x3f7, 0x3fc, 0x3fe, 0x402, 0x404, 0x408, 0x411, 0x417, 0x41b, 0x42b, 0x435, 0x43a, 0x43d, 0x443, 0x44a, 0x44f, 0x453, 0x459, 0x45e, 0x467, 0x46c, 0x472, 0x479, 0x480, 0x487, 0x48b, 0x490, 0x493, 0x498, 0x4a4, 0x4aa, 0x4af, 0x4b6, 0x4be, 0x4c3, 0x4c7, 0x4d7, 0x4de, 0x4e2, 0x4e6, 0x4ed, 0x4ef, 0x4f2, 0x4f5, 0x4f9, 0x502, 0x506, 0x50e, 0x516, 0x51c, 0x525, 0x531, 0x538, 0x541, 0x54b, 0x552, 0x560, 0x56d, 0x57a, 0x583, 0x587, 0x596, 0x59e, 0x5a9, 0x5b2, 0x5b8, 0x5c0, 0x5c9, 0x5d3, 0x5d6, 0x5e2, 0x5eb, 0x5ee, 0x5f3, 0x5fe, 0x607, 0x613, 0x616, 0x620, 0x629, 0x635, 0x642, 0x64f, 0x65d, 0x664, 0x667, 0x66c, 0x66f, 0x672, 0x675, 0x67c, 0x683, 0x687, 0x692, 0x695, 0x698, 0x69b, 0x6a1, 0x6a6, 0x6aa, 0x6ad, 0x6b0, 0x6b3, 0x6b6, 0x6b9, 0x6be, 0x6c8, 0x6cb, 0x6cf, 0x6de, 0x6ea, 0x6ee, 0x6f3, 0x6f7, 0x6fc, 0x700, 0x705, 0x70e, 0x719, 0x71f, 0x727, 0x72a, 0x72d, 0x731, 0x735, 0x73b, 0x741, 0x746, 0x749, 0x759, 0x760, 0x763, 0x766, 0x76a, 0x770, 0x775, 0x77a, 0x782, 0x787, 0x78b, 0x78f, 0x792, 0x795, 0x799, 0x79d, 0x7a0, 0x7b0, 0x7c1, 0x7c6, 0x7c8, 0x7ca} // idnaSparseValues: 1997 entries, 7988 bytes var idnaSparseValues = [1997]valueRange{ // Block 0x0, offset 0x0 {value: 0x0000, lo: 0x07}, {value: 0xe105, lo: 0x80, hi: 0x96}, {value: 0x0018, lo: 0x97, hi: 0x97}, {value: 0xe105, lo: 0x98, hi: 0x9e}, {value: 0x001f, lo: 0x9f, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xb7}, {value: 0x0008, lo: 0xb8, hi: 0xbf}, // Block 0x1, offset 0x8 {value: 0x0000, lo: 0x10}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0xe01d, lo: 0x81, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0x82}, {value: 0x0335, lo: 0x83, hi: 0x83}, {value: 0x034d, lo: 0x84, hi: 0x84}, {value: 0x0365, lo: 0x85, hi: 0x85}, {value: 0xe00d, lo: 0x86, hi: 0x86}, {value: 0x0008, lo: 0x87, hi: 0x87}, {value: 0xe00d, lo: 0x88, hi: 0x88}, {value: 0x0008, lo: 0x89, hi: 0x89}, {value: 0xe00d, lo: 0x8a, hi: 0x8a}, {value: 0x0008, lo: 0x8b, hi: 0x8b}, {value: 0xe00d, lo: 0x8c, hi: 0x8c}, {value: 0x0008, lo: 0x8d, hi: 0x8d}, {value: 0xe00d, lo: 0x8e, hi: 0x8e}, {value: 0x0008, lo: 0x8f, hi: 0xbf}, // Block 0x2, offset 0x19 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x0249, lo: 0xb0, hi: 0xb0}, {value: 0x037d, lo: 0xb1, hi: 0xb1}, {value: 0x0259, lo: 0xb2, hi: 0xb2}, {value: 0x0269, lo: 0xb3, hi: 0xb3}, {value: 0x034d, lo: 0xb4, hi: 0xb4}, {value: 0x0395, lo: 0xb5, hi: 0xb5}, {value: 0xe1bd, lo: 0xb6, hi: 0xb6}, {value: 0x0279, lo: 0xb7, hi: 0xb7}, {value: 0x0289, lo: 0xb8, hi: 0xb8}, {value: 0x0008, lo: 0xb9, hi: 0xbf}, // Block 0x3, offset 0x25 {value: 0x0000, lo: 0x01}, {value: 0x3308, lo: 0x80, hi: 0xbf}, // Block 0x4, offset 0x27 {value: 0x0000, lo: 0x04}, {value: 0x03f5, lo: 0x80, hi: 0x8f}, {value: 0xe105, lo: 0x90, hi: 0x9f}, {value: 0x049d, lo: 0xa0, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x5, offset 0x2c {value: 0x0000, lo: 0x06}, {value: 0xe185, lo: 0x80, hi: 0x8f}, {value: 0x0545, lo: 0x90, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x98}, {value: 0x0008, lo: 0x99, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x6, offset 0x33 {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0401, lo: 0x87, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x88}, {value: 0x0018, lo: 0x89, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x90}, {value: 0x3308, lo: 0x91, hi: 0xbd}, {value: 0x0818, lo: 0xbe, hi: 0xbe}, {value: 0x3308, lo: 0xbf, hi: 0xbf}, // Block 0x7, offset 0x3e {value: 0x0000, lo: 0x0b}, {value: 0x0818, lo: 0x80, hi: 0x80}, {value: 0x3308, lo: 0x81, hi: 0x82}, {value: 0x0818, lo: 0x83, hi: 0x83}, {value: 0x3308, lo: 0x84, hi: 0x85}, {value: 0x0818, lo: 0x86, hi: 0x86}, {value: 0x3308, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0808, lo: 0x90, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xae}, {value: 0x0808, lo: 0xaf, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0x8, offset 0x4a {value: 0x0000, lo: 0x03}, {value: 0x0a08, lo: 0x80, hi: 0x87}, {value: 0x0c08, lo: 0x88, hi: 0x99}, {value: 0x0a08, lo: 0x9a, hi: 0xbf}, // Block 0x9, offset 0x4e {value: 0x0000, lo: 0x0e}, {value: 0x3308, lo: 0x80, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8c}, {value: 0x0c08, lo: 0x8d, hi: 0x8d}, {value: 0x0a08, lo: 0x8e, hi: 0x98}, {value: 0x0c08, lo: 0x99, hi: 0x9b}, {value: 0x0a08, lo: 0x9c, hi: 0xaa}, {value: 0x0c08, lo: 0xab, hi: 0xac}, {value: 0x0a08, lo: 0xad, hi: 0xb0}, {value: 0x0c08, lo: 0xb1, hi: 0xb1}, {value: 0x0a08, lo: 0xb2, hi: 0xb2}, {value: 0x0c08, lo: 0xb3, hi: 0xb4}, {value: 0x0a08, lo: 0xb5, hi: 0xb7}, {value: 0x0c08, lo: 0xb8, hi: 0xb9}, {value: 0x0a08, lo: 0xba, hi: 0xbf}, // Block 0xa, offset 0x5d {value: 0x0000, lo: 0x04}, {value: 0x0808, lo: 0x80, hi: 0xa5}, {value: 0x3308, lo: 0xa6, hi: 0xb0}, {value: 0x0808, lo: 0xb1, hi: 0xb1}, {value: 0x0040, lo: 0xb2, hi: 0xbf}, // Block 0xb, offset 0x62 {value: 0x0000, lo: 0x09}, {value: 0x0808, lo: 0x80, hi: 0x89}, {value: 0x0a08, lo: 0x8a, hi: 0xaa}, {value: 0x3308, lo: 0xab, hi: 0xb3}, {value: 0x0808, lo: 0xb4, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xb9}, {value: 0x0818, lo: 0xba, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbc}, {value: 0x3308, lo: 0xbd, hi: 0xbd}, {value: 0x0818, lo: 0xbe, hi: 0xbf}, // Block 0xc, offset 0x6c {value: 0x0000, lo: 0x0b}, {value: 0x0808, lo: 0x80, hi: 0x95}, {value: 0x3308, lo: 0x96, hi: 0x99}, {value: 0x0808, lo: 0x9a, hi: 0x9a}, {value: 0x3308, lo: 0x9b, hi: 0xa3}, {value: 0x0808, lo: 0xa4, hi: 0xa4}, {value: 0x3308, lo: 0xa5, hi: 0xa7}, {value: 0x0808, lo: 0xa8, hi: 0xa8}, {value: 0x3308, lo: 0xa9, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x0818, lo: 0xb0, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0xd, offset 0x78 {value: 0x0000, lo: 0x0d}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0a08, lo: 0xa0, hi: 0xa9}, {value: 0x0c08, lo: 0xaa, hi: 0xac}, {value: 0x0808, lo: 0xad, hi: 0xad}, {value: 0x0c08, lo: 0xae, hi: 0xae}, {value: 0x0a08, lo: 0xaf, hi: 0xb0}, {value: 0x0c08, lo: 0xb1, hi: 0xb2}, {value: 0x0a08, lo: 0xb3, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xb5}, {value: 0x0a08, lo: 0xb6, hi: 0xb8}, {value: 0x0c08, lo: 0xb9, hi: 0xb9}, {value: 0x0a08, lo: 0xba, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, // Block 0xe, offset 0x86 {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x92}, {value: 0x3308, lo: 0x93, hi: 0xa1}, {value: 0x0840, lo: 0xa2, hi: 0xa2}, {value: 0x3308, lo: 0xa3, hi: 0xbf}, // Block 0xf, offset 0x8b {value: 0x0000, lo: 0x08}, {value: 0x3308, lo: 0x80, hi: 0x82}, {value: 0x3008, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0xb9}, {value: 0x3308, lo: 0xba, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbf}, // Block 0x10, offset 0x94 {value: 0x0000, lo: 0x0f}, {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x3008, lo: 0x81, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x85}, {value: 0x3008, lo: 0x86, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x3008, lo: 0x8a, hi: 0x8c}, {value: 0x3b08, lo: 0x8d, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x96}, {value: 0x3008, lo: 0x97, hi: 0x97}, {value: 0x0040, lo: 0x98, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbf}, // Block 0x11, offset 0xa4 {value: 0x0000, lo: 0x0d}, {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x3008, lo: 0x81, hi: 0x83}, {value: 0x3308, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, {value: 0x0008, lo: 0x8e, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x91}, {value: 0x0008, lo: 0x92, hi: 0xa8}, {value: 0x0040, lo: 0xa9, hi: 0xa9}, {value: 0x0008, lo: 0xaa, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x3308, lo: 0xbe, hi: 0xbf}, // Block 0x12, offset 0xb2 {value: 0x0000, lo: 0x0b}, {value: 0x3308, lo: 0x80, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, {value: 0x0008, lo: 0x8e, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x91}, {value: 0x0008, lo: 0x92, hi: 0xba}, {value: 0x3b08, lo: 0xbb, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbf}, // Block 0x13, offset 0xbe {value: 0x0000, lo: 0x0b}, {value: 0x0040, lo: 0x80, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x99}, {value: 0x0008, lo: 0x9a, hi: 0xb1}, {value: 0x0040, lo: 0xb2, hi: 0xb2}, {value: 0x0008, lo: 0xb3, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, // Block 0x14, offset 0xca {value: 0x0000, lo: 0x10}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x89}, {value: 0x3b08, lo: 0x8a, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8e}, {value: 0x3008, lo: 0x8f, hi: 0x91}, {value: 0x3308, lo: 0x92, hi: 0x94}, {value: 0x0040, lo: 0x95, hi: 0x95}, {value: 0x3308, lo: 0x96, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x97}, {value: 0x3008, lo: 0x98, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xb1}, {value: 0x3008, lo: 0xb2, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0x15, offset 0xdb {value: 0x0000, lo: 0x09}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0xb0}, {value: 0x3308, lo: 0xb1, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xb2}, {value: 0x08f1, lo: 0xb3, hi: 0xb3}, {value: 0x3308, lo: 0xb4, hi: 0xb9}, {value: 0x3b08, lo: 0xba, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbe}, {value: 0x0018, lo: 0xbf, hi: 0xbf}, // Block 0x16, offset 0xe5 {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x3308, lo: 0x87, hi: 0x8e}, {value: 0x0018, lo: 0x8f, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0xbf}, // Block 0x17, offset 0xec {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x85}, {value: 0x0008, lo: 0x86, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, {value: 0x3308, lo: 0x88, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9b}, {value: 0x0961, lo: 0x9c, hi: 0x9c}, {value: 0x0999, lo: 0x9d, hi: 0x9d}, {value: 0x0008, lo: 0x9e, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, // Block 0x18, offset 0xf9 {value: 0x0000, lo: 0x10}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x8a}, {value: 0x0008, lo: 0x8b, hi: 0x8b}, {value: 0xe03d, lo: 0x8c, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x97}, {value: 0x3308, lo: 0x98, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa9}, {value: 0x0018, lo: 0xaa, hi: 0xb4}, {value: 0x3308, lo: 0xb5, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xb6}, {value: 0x3308, lo: 0xb7, hi: 0xb7}, {value: 0x0018, lo: 0xb8, hi: 0xb8}, {value: 0x3308, lo: 0xb9, hi: 0xb9}, {value: 0x0018, lo: 0xba, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbf}, // Block 0x19, offset 0x10a {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x85}, {value: 0x3308, lo: 0x86, hi: 0x86}, {value: 0x0018, lo: 0x87, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, {value: 0x0018, lo: 0x8e, hi: 0x9a}, {value: 0x0040, lo: 0x9b, hi: 0xbf}, // Block 0x1a, offset 0x111 {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0xaa}, {value: 0x3008, lo: 0xab, hi: 0xac}, {value: 0x3308, lo: 0xad, hi: 0xb0}, {value: 0x3008, lo: 0xb1, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb7}, {value: 0x3008, lo: 0xb8, hi: 0xb8}, {value: 0x3b08, lo: 0xb9, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbc}, {value: 0x3308, lo: 0xbd, hi: 0xbe}, {value: 0x0008, lo: 0xbf, hi: 0xbf}, // Block 0x1b, offset 0x11c {value: 0x0000, lo: 0x0e}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0018, lo: 0x8a, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x95}, {value: 0x3008, lo: 0x96, hi: 0x97}, {value: 0x3308, lo: 0x98, hi: 0x99}, {value: 0x0008, lo: 0x9a, hi: 0x9d}, {value: 0x3308, lo: 0x9e, hi: 0xa0}, {value: 0x0008, lo: 0xa1, hi: 0xa1}, {value: 0x3008, lo: 0xa2, hi: 0xa4}, {value: 0x0008, lo: 0xa5, hi: 0xa6}, {value: 0x3008, lo: 0xa7, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xb0}, {value: 0x3308, lo: 0xb1, hi: 0xb4}, {value: 0x0008, lo: 0xb5, hi: 0xbf}, // Block 0x1c, offset 0x12b {value: 0x0000, lo: 0x0d}, {value: 0x0008, lo: 0x80, hi: 0x81}, {value: 0x3308, lo: 0x82, hi: 0x82}, {value: 0x3008, lo: 0x83, hi: 0x84}, {value: 0x3308, lo: 0x85, hi: 0x86}, {value: 0x3008, lo: 0x87, hi: 0x8c}, {value: 0x3308, lo: 0x8d, hi: 0x8d}, {value: 0x0008, lo: 0x8e, hi: 0x8e}, {value: 0x3008, lo: 0x8f, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x3008, lo: 0x9a, hi: 0x9c}, {value: 0x3308, lo: 0x9d, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, // Block 0x1d, offset 0x139 {value: 0x0000, lo: 0x09}, {value: 0x0040, lo: 0x80, hi: 0x86}, {value: 0x055d, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8c}, {value: 0x055d, lo: 0x8d, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xba}, {value: 0x0018, lo: 0xbb, hi: 0xbb}, {value: 0xe105, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbf}, // Block 0x1e, offset 0x143 {value: 0x0000, lo: 0x01}, {value: 0x0018, lo: 0x80, hi: 0xbf}, // Block 0x1f, offset 0x145 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0xa0}, {value: 0x2018, lo: 0xa1, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xbf}, // Block 0x20, offset 0x14a {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xa7}, {value: 0x2018, lo: 0xa8, hi: 0xbf}, // Block 0x21, offset 0x14d {value: 0x0000, lo: 0x02}, {value: 0x2018, lo: 0x80, hi: 0x82}, {value: 0x0018, lo: 0x83, hi: 0xbf}, // Block 0x22, offset 0x150 {value: 0x0000, lo: 0x01}, {value: 0x0008, lo: 0x80, hi: 0xbf}, // Block 0x23, offset 0x152 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0008, lo: 0x8a, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0x98}, {value: 0x0040, lo: 0x99, hi: 0x99}, {value: 0x0008, lo: 0x9a, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x24, offset 0x15e {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0008, lo: 0x8a, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb7}, {value: 0x0008, lo: 0xb8, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0x25, offset 0x169 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0040, lo: 0x81, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0xbf}, // Block 0x26, offset 0x171 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x91}, {value: 0x0008, lo: 0x92, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0xbf}, // Block 0x27, offset 0x177 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x9a}, {value: 0x0040, lo: 0x9b, hi: 0x9c}, {value: 0x3308, lo: 0x9d, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, // Block 0x28, offset 0x17d {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x29, offset 0x182 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb7}, {value: 0xe045, lo: 0xb8, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, // Block 0x2a, offset 0x187 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0xbf}, // Block 0x2b, offset 0x18a {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xac}, {value: 0x0018, lo: 0xad, hi: 0xae}, {value: 0x0008, lo: 0xaf, hi: 0xbf}, // Block 0x2c, offset 0x18e {value: 0x0000, lo: 0x05}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9c}, {value: 0x0040, lo: 0x9d, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x2d, offset 0x194 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xaa}, {value: 0x0018, lo: 0xab, hi: 0xb0}, {value: 0x0008, lo: 0xb1, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbf}, // Block 0x2e, offset 0x199 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, {value: 0x0008, lo: 0x8e, hi: 0x91}, {value: 0x3308, lo: 0x92, hi: 0x93}, {value: 0x3b08, lo: 0x94, hi: 0x94}, {value: 0x0040, lo: 0x95, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb3}, {value: 0x3b08, lo: 0xb4, hi: 0xb4}, {value: 0x0018, lo: 0xb5, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0x2f, offset 0x1a5 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x91}, {value: 0x3308, lo: 0x92, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbf}, // Block 0x30, offset 0x1af {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0xb3}, {value: 0x3340, lo: 0xb4, hi: 0xb5}, {value: 0x3008, lo: 0xb6, hi: 0xb6}, {value: 0x3308, lo: 0xb7, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbf}, // Block 0x31, offset 0x1b5 {value: 0x0000, lo: 0x10}, {value: 0x3008, lo: 0x80, hi: 0x85}, {value: 0x3308, lo: 0x86, hi: 0x86}, {value: 0x3008, lo: 0x87, hi: 0x88}, {value: 0x3308, lo: 0x89, hi: 0x91}, {value: 0x3b08, lo: 0x92, hi: 0x92}, {value: 0x3308, lo: 0x93, hi: 0x93}, {value: 0x0018, lo: 0x94, hi: 0x96}, {value: 0x0008, lo: 0x97, hi: 0x97}, {value: 0x0018, lo: 0x98, hi: 0x9b}, {value: 0x0008, lo: 0x9c, hi: 0x9c}, {value: 0x3308, lo: 0x9d, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa9}, {value: 0x0040, lo: 0xaa, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0x32, offset 0x1c6 {value: 0x0000, lo: 0x09}, {value: 0x0018, lo: 0x80, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x86}, {value: 0x0218, lo: 0x87, hi: 0x87}, {value: 0x0018, lo: 0x88, hi: 0x8a}, {value: 0x33c0, lo: 0x8b, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0208, lo: 0xa0, hi: 0xbf}, // Block 0x33, offset 0x1d0 {value: 0x0000, lo: 0x02}, {value: 0x0208, lo: 0x80, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbf}, // Block 0x34, offset 0x1d3 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x84}, {value: 0x3308, lo: 0x85, hi: 0x86}, {value: 0x0208, lo: 0x87, hi: 0xa8}, {value: 0x3308, lo: 0xa9, hi: 0xa9}, {value: 0x0208, lo: 0xaa, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x35, offset 0x1db {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, // Block 0x36, offset 0x1de {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x3308, lo: 0xa0, hi: 0xa2}, {value: 0x3008, lo: 0xa3, hi: 0xa6}, {value: 0x3308, lo: 0xa7, hi: 0xa8}, {value: 0x3008, lo: 0xa9, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x3008, lo: 0xb0, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb2}, {value: 0x3008, lo: 0xb3, hi: 0xb8}, {value: 0x3308, lo: 0xb9, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, // Block 0x37, offset 0x1eb {value: 0x0000, lo: 0x07}, {value: 0x0018, lo: 0x80, hi: 0x80}, {value: 0x0040, lo: 0x81, hi: 0x83}, {value: 0x0018, lo: 0x84, hi: 0x85}, {value: 0x0008, lo: 0x86, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0x38, offset 0x1f3 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x39, offset 0x1f7 {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0028, lo: 0x9a, hi: 0x9a}, {value: 0x0040, lo: 0x9b, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0xbf}, // Block 0x3a, offset 0x1fe {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x96}, {value: 0x3308, lo: 0x97, hi: 0x98}, {value: 0x3008, lo: 0x99, hi: 0x9a}, {value: 0x3308, lo: 0x9b, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x3b, offset 0x206 {value: 0x0000, lo: 0x0f}, {value: 0x0008, lo: 0x80, hi: 0x94}, {value: 0x3008, lo: 0x95, hi: 0x95}, {value: 0x3308, lo: 0x96, hi: 0x96}, {value: 0x3008, lo: 0x97, hi: 0x97}, {value: 0x3308, lo: 0x98, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x3b08, lo: 0xa0, hi: 0xa0}, {value: 0x3008, lo: 0xa1, hi: 0xa1}, {value: 0x3308, lo: 0xa2, hi: 0xa2}, {value: 0x3008, lo: 0xa3, hi: 0xa4}, {value: 0x3308, lo: 0xa5, hi: 0xac}, {value: 0x3008, lo: 0xad, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbe}, {value: 0x3308, lo: 0xbf, hi: 0xbf}, // Block 0x3c, offset 0x216 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa6}, {value: 0x0008, lo: 0xa7, hi: 0xa7}, {value: 0x0018, lo: 0xa8, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xbd}, {value: 0x3318, lo: 0xbe, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0x3d, offset 0x222 {value: 0x0000, lo: 0x01}, {value: 0x0040, lo: 0x80, hi: 0xbf}, // Block 0x3e, offset 0x224 {value: 0x0000, lo: 0x09}, {value: 0x3308, lo: 0x80, hi: 0x83}, {value: 0x3008, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0xb3}, {value: 0x3308, lo: 0xb4, hi: 0xb4}, {value: 0x3008, lo: 0xb5, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbc}, {value: 0x3008, lo: 0xbd, hi: 0xbf}, // Block 0x3f, offset 0x22e {value: 0x0000, lo: 0x0b}, {value: 0x3008, lo: 0x80, hi: 0x81}, {value: 0x3308, lo: 0x82, hi: 0x82}, {value: 0x3008, lo: 0x83, hi: 0x83}, {value: 0x3808, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0xaa}, {value: 0x3308, lo: 0xab, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, // Block 0x40, offset 0x23a {value: 0x0000, lo: 0x0b}, {value: 0x3308, lo: 0x80, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xa0}, {value: 0x3008, lo: 0xa1, hi: 0xa1}, {value: 0x3308, lo: 0xa2, hi: 0xa5}, {value: 0x3008, lo: 0xa6, hi: 0xa7}, {value: 0x3308, lo: 0xa8, hi: 0xa9}, {value: 0x3808, lo: 0xaa, hi: 0xaa}, {value: 0x3b08, lo: 0xab, hi: 0xab}, {value: 0x3308, lo: 0xac, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xbf}, // Block 0x41, offset 0x246 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0xa5}, {value: 0x3308, lo: 0xa6, hi: 0xa6}, {value: 0x3008, lo: 0xa7, hi: 0xa7}, {value: 0x3308, lo: 0xa8, hi: 0xa9}, {value: 0x3008, lo: 0xaa, hi: 0xac}, {value: 0x3308, lo: 0xad, hi: 0xad}, {value: 0x3008, lo: 0xae, hi: 0xae}, {value: 0x3308, lo: 0xaf, hi: 0xb1}, {value: 0x3808, lo: 0xb2, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbb}, {value: 0x0018, lo: 0xbc, hi: 0xbf}, // Block 0x42, offset 0x252 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xa3}, {value: 0x3008, lo: 0xa4, hi: 0xab}, {value: 0x3308, lo: 0xac, hi: 0xb3}, {value: 0x3008, lo: 0xb4, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xba}, {value: 0x0018, lo: 0xbb, hi: 0xbf}, // Block 0x43, offset 0x25a {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0x8c}, {value: 0x0008, lo: 0x8d, hi: 0xbd}, {value: 0x0018, lo: 0xbe, hi: 0xbf}, // Block 0x44, offset 0x25f {value: 0x0000, lo: 0x09}, {value: 0x0e29, lo: 0x80, hi: 0x80}, {value: 0x0e41, lo: 0x81, hi: 0x81}, {value: 0x0e59, lo: 0x82, hi: 0x82}, {value: 0x0e71, lo: 0x83, hi: 0x83}, {value: 0x0e89, lo: 0x84, hi: 0x85}, {value: 0x0ea1, lo: 0x86, hi: 0x86}, {value: 0x0eb9, lo: 0x87, hi: 0x87}, {value: 0x057d, lo: 0x88, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0xbf}, // Block 0x45, offset 0x269 {value: 0x0000, lo: 0x10}, {value: 0x0018, lo: 0x80, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x3308, lo: 0x90, hi: 0x92}, {value: 0x0018, lo: 0x93, hi: 0x93}, {value: 0x3308, lo: 0x94, hi: 0xa0}, {value: 0x3008, lo: 0xa1, hi: 0xa1}, {value: 0x3308, lo: 0xa2, hi: 0xa8}, {value: 0x0008, lo: 0xa9, hi: 0xac}, {value: 0x3308, lo: 0xad, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xb1}, {value: 0x3008, lo: 0xb2, hi: 0xb3}, {value: 0x3308, lo: 0xb4, hi: 0xb4}, {value: 0x0008, lo: 0xb5, hi: 0xb6}, {value: 0x3008, lo: 0xb7, hi: 0xb7}, {value: 0x3308, lo: 0xb8, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0x46, offset 0x27a {value: 0x0000, lo: 0x03}, {value: 0x3308, lo: 0x80, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xba}, {value: 0x3308, lo: 0xbb, hi: 0xbf}, // Block 0x47, offset 0x27e {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x87}, {value: 0xe045, lo: 0x88, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x97}, {value: 0xe045, lo: 0x98, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa7}, {value: 0xe045, lo: 0xa8, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb7}, {value: 0xe045, lo: 0xb8, hi: 0xbf}, // Block 0x48, offset 0x289 {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0x8f}, {value: 0x3318, lo: 0x90, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xbf}, // Block 0x49, offset 0x28d {value: 0x0000, lo: 0x08}, {value: 0x0018, lo: 0x80, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x84}, {value: 0x0018, lo: 0x85, hi: 0x88}, {value: 0x24c1, lo: 0x89, hi: 0x89}, {value: 0x0018, lo: 0x8a, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbf}, // Block 0x4a, offset 0x296 {value: 0x0000, lo: 0x07}, {value: 0x0018, lo: 0x80, hi: 0xab}, {value: 0x24f1, lo: 0xac, hi: 0xac}, {value: 0x2529, lo: 0xad, hi: 0xad}, {value: 0x0018, lo: 0xae, hi: 0xae}, {value: 0x2579, lo: 0xaf, hi: 0xaf}, {value: 0x25b1, lo: 0xb0, hi: 0xb0}, {value: 0x0018, lo: 0xb1, hi: 0xbf}, // Block 0x4b, offset 0x29e {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x9f}, {value: 0x0080, lo: 0xa0, hi: 0xa0}, {value: 0x0018, lo: 0xa1, hi: 0xad}, {value: 0x0080, lo: 0xae, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, // Block 0x4c, offset 0x2a4 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0xa8}, {value: 0x09c5, lo: 0xa9, hi: 0xa9}, {value: 0x09e5, lo: 0xaa, hi: 0xaa}, {value: 0x0018, lo: 0xab, hi: 0xbf}, // Block 0x4d, offset 0x2a9 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xbf}, // Block 0x4e, offset 0x2ac {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0x8b}, {value: 0x28c1, lo: 0x8c, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0xbf}, // Block 0x4f, offset 0x2b0 {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0xb3}, {value: 0x0e66, lo: 0xb4, hi: 0xb4}, {value: 0x292a, lo: 0xb5, hi: 0xb5}, {value: 0x0e86, lo: 0xb6, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xbf}, // Block 0x50, offset 0x2b6 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0x9b}, {value: 0x2941, lo: 0x9c, hi: 0x9c}, {value: 0x0018, lo: 0x9d, hi: 0xbf}, // Block 0x51, offset 0x2ba {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xbf}, // Block 0x52, offset 0x2be {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x97}, {value: 0x0018, lo: 0x98, hi: 0xbf}, // Block 0x53, offset 0x2c2 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0018, lo: 0x8a, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0x54, offset 0x2c7 {value: 0x0000, lo: 0x05}, {value: 0xe185, lo: 0x80, hi: 0x8f}, {value: 0x03f5, lo: 0x90, hi: 0x9f}, {value: 0x0ea5, lo: 0xa0, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x55, offset 0x2cd {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xa5}, {value: 0x0040, lo: 0xa6, hi: 0xa6}, {value: 0x0008, lo: 0xa7, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xac}, {value: 0x0008, lo: 0xad, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x56, offset 0x2d5 {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xae}, {value: 0xe075, lo: 0xaf, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0x57, offset 0x2dc {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xa7}, {value: 0x0008, lo: 0xa8, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xb7}, {value: 0x0008, lo: 0xb8, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0x58, offset 0x2e7 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x8e}, {value: 0x0040, lo: 0x8f, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x3308, lo: 0xa0, hi: 0xbf}, // Block 0x59, offset 0x2f1 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xae}, {value: 0x0008, lo: 0xaf, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, // Block 0x5a, offset 0x2f5 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0x8e}, {value: 0x0040, lo: 0x8f, hi: 0xbf}, // Block 0x5b, offset 0x2f8 {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9e}, {value: 0x0edd, lo: 0x9f, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xbf}, // Block 0x5c, offset 0x2fe {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xb2}, {value: 0x0efd, lo: 0xb3, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbf}, // Block 0x5d, offset 0x302 {value: 0x0020, lo: 0x01}, {value: 0x0f1d, lo: 0x80, hi: 0xbf}, // Block 0x5e, offset 0x304 {value: 0x0020, lo: 0x02}, {value: 0x171d, lo: 0x80, hi: 0x8f}, {value: 0x18fd, lo: 0x90, hi: 0xbf}, // Block 0x5f, offset 0x307 {value: 0x0020, lo: 0x01}, {value: 0x1efd, lo: 0x80, hi: 0xbf}, // Block 0x60, offset 0x309 {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0xbf}, // Block 0x61, offset 0x30c {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x98}, {value: 0x3308, lo: 0x99, hi: 0x9a}, {value: 0x29e2, lo: 0x9b, hi: 0x9b}, {value: 0x2a0a, lo: 0x9c, hi: 0x9c}, {value: 0x0008, lo: 0x9d, hi: 0x9e}, {value: 0x2a31, lo: 0x9f, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa0}, {value: 0x0008, lo: 0xa1, hi: 0xbf}, // Block 0x62, offset 0x316 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xbe}, {value: 0x2a69, lo: 0xbf, hi: 0xbf}, // Block 0x63, offset 0x319 {value: 0x0000, lo: 0x0e}, {value: 0x0040, lo: 0x80, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xb0}, {value: 0x2a1d, lo: 0xb1, hi: 0xb1}, {value: 0x2a3d, lo: 0xb2, hi: 0xb2}, {value: 0x2a5d, lo: 0xb3, hi: 0xb3}, {value: 0x2a7d, lo: 0xb4, hi: 0xb4}, {value: 0x2a5d, lo: 0xb5, hi: 0xb5}, {value: 0x2a9d, lo: 0xb6, hi: 0xb6}, {value: 0x2abd, lo: 0xb7, hi: 0xb7}, {value: 0x2add, lo: 0xb8, hi: 0xb9}, {value: 0x2afd, lo: 0xba, hi: 0xbb}, {value: 0x2b1d, lo: 0xbc, hi: 0xbd}, {value: 0x2afd, lo: 0xbe, hi: 0xbf}, // Block 0x64, offset 0x328 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x65, offset 0x32c {value: 0x0030, lo: 0x04}, {value: 0x2aa2, lo: 0x80, hi: 0x9d}, {value: 0x305a, lo: 0x9e, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x30a2, lo: 0xa0, hi: 0xbf}, // Block 0x66, offset 0x331 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, // Block 0x67, offset 0x334 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbf}, // Block 0x68, offset 0x338 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xbd}, {value: 0x0018, lo: 0xbe, hi: 0xbf}, // Block 0x69, offset 0x33d {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xbf}, // Block 0x6a, offset 0x342 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0xa5}, {value: 0x0018, lo: 0xa6, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb1}, {value: 0x0018, lo: 0xb2, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbf}, // Block 0x6b, offset 0x348 {value: 0x0000, lo: 0x05}, {value: 0x0040, lo: 0x80, hi: 0xb6}, {value: 0x0008, lo: 0xb7, hi: 0xb7}, {value: 0x2009, lo: 0xb8, hi: 0xb8}, {value: 0x6e89, lo: 0xb9, hi: 0xb9}, {value: 0x0008, lo: 0xba, hi: 0xbf}, // Block 0x6c, offset 0x34e {value: 0x0000, lo: 0x0e}, {value: 0x0008, lo: 0x80, hi: 0x81}, {value: 0x3308, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0x85}, {value: 0x3b08, lo: 0x86, hi: 0x86}, {value: 0x0008, lo: 0x87, hi: 0x8a}, {value: 0x3308, lo: 0x8b, hi: 0x8b}, {value: 0x0008, lo: 0x8c, hi: 0xa2}, {value: 0x3008, lo: 0xa3, hi: 0xa4}, {value: 0x3308, lo: 0xa5, hi: 0xa6}, {value: 0x3008, lo: 0xa7, hi: 0xa7}, {value: 0x0018, lo: 0xa8, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0x6d, offset 0x35d {value: 0x0000, lo: 0x05}, {value: 0x0208, lo: 0x80, hi: 0xb1}, {value: 0x0108, lo: 0xb2, hi: 0xb2}, {value: 0x0008, lo: 0xb3, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbf}, // Block 0x6e, offset 0x363 {value: 0x0000, lo: 0x03}, {value: 0x3008, lo: 0x80, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0xb3}, {value: 0x3008, lo: 0xb4, hi: 0xbf}, // Block 0x6f, offset 0x367 {value: 0x0000, lo: 0x0e}, {value: 0x3008, lo: 0x80, hi: 0x83}, {value: 0x3b08, lo: 0x84, hi: 0x84}, {value: 0x3308, lo: 0x85, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x8d}, {value: 0x0018, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x3308, lo: 0xa0, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xb7}, {value: 0x0018, lo: 0xb8, hi: 0xba}, {value: 0x0008, lo: 0xbb, hi: 0xbb}, {value: 0x0018, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbe}, {value: 0x3308, lo: 0xbf, hi: 0xbf}, // Block 0x70, offset 0x376 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xa5}, {value: 0x3308, lo: 0xa6, hi: 0xad}, {value: 0x0018, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x71, offset 0x37b {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x3308, lo: 0x87, hi: 0x91}, {value: 0x3008, lo: 0x92, hi: 0x92}, {value: 0x3808, lo: 0x93, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, // Block 0x72, offset 0x383 {value: 0x0000, lo: 0x09}, {value: 0x3308, lo: 0x80, hi: 0x82}, {value: 0x3008, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xb3}, {value: 0x3008, lo: 0xb4, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xb9}, {value: 0x3008, lo: 0xba, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbc}, {value: 0x3008, lo: 0xbd, hi: 0xbf}, // Block 0x73, offset 0x38d {value: 0x0000, lo: 0x0a}, {value: 0x3808, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8e}, {value: 0x0008, lo: 0x8f, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa4}, {value: 0x3308, lo: 0xa5, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0x74, offset 0x398 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xa8}, {value: 0x3308, lo: 0xa9, hi: 0xae}, {value: 0x3008, lo: 0xaf, hi: 0xb0}, {value: 0x3308, lo: 0xb1, hi: 0xb2}, {value: 0x3008, lo: 0xb3, hi: 0xb4}, {value: 0x3308, lo: 0xb5, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0x75, offset 0x3a0 {value: 0x0000, lo: 0x10}, {value: 0x0008, lo: 0x80, hi: 0x82}, {value: 0x3308, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x8b}, {value: 0x3308, lo: 0x8c, hi: 0x8c}, {value: 0x3008, lo: 0x8d, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9b}, {value: 0x0018, lo: 0x9c, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xb9}, {value: 0x0008, lo: 0xba, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbc}, {value: 0x3008, lo: 0xbd, hi: 0xbd}, {value: 0x0008, lo: 0xbe, hi: 0xbf}, // Block 0x76, offset 0x3b1 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb0}, {value: 0x0008, lo: 0xb1, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb4}, {value: 0x0008, lo: 0xb5, hi: 0xb6}, {value: 0x3308, lo: 0xb7, hi: 0xb8}, {value: 0x0008, lo: 0xb9, hi: 0xbd}, {value: 0x3308, lo: 0xbe, hi: 0xbf}, // Block 0x77, offset 0x3ba {value: 0x0000, lo: 0x0f}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x3308, lo: 0x81, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x9a}, {value: 0x0008, lo: 0x9b, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xaa}, {value: 0x3008, lo: 0xab, hi: 0xab}, {value: 0x3308, lo: 0xac, hi: 0xad}, {value: 0x3008, lo: 0xae, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xb4}, {value: 0x3008, lo: 0xb5, hi: 0xb5}, {value: 0x3b08, lo: 0xb6, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0x78, offset 0x3ca {value: 0x0000, lo: 0x0c}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x88}, {value: 0x0008, lo: 0x89, hi: 0x8e}, {value: 0x0040, lo: 0x8f, hi: 0x90}, {value: 0x0008, lo: 0x91, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xa7}, {value: 0x0008, lo: 0xa8, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x79, offset 0x3d7 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9b}, {value: 0x4465, lo: 0x9c, hi: 0x9c}, {value: 0x447d, lo: 0x9d, hi: 0x9d}, {value: 0x2971, lo: 0x9e, hi: 0x9e}, {value: 0xe06d, lo: 0x9f, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa5}, {value: 0x0040, lo: 0xa6, hi: 0xaf}, {value: 0x4495, lo: 0xb0, hi: 0xbf}, // Block 0x7a, offset 0x3e1 {value: 0x0000, lo: 0x04}, {value: 0x44b5, lo: 0x80, hi: 0x8f}, {value: 0x44d5, lo: 0x90, hi: 0x9f}, {value: 0x44f5, lo: 0xa0, hi: 0xaf}, {value: 0x44d5, lo: 0xb0, hi: 0xbf}, // Block 0x7b, offset 0x3e6 {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0xa2}, {value: 0x3008, lo: 0xa3, hi: 0xa4}, {value: 0x3308, lo: 0xa5, hi: 0xa5}, {value: 0x3008, lo: 0xa6, hi: 0xa7}, {value: 0x3308, lo: 0xa8, hi: 0xa8}, {value: 0x3008, lo: 0xa9, hi: 0xaa}, {value: 0x0018, lo: 0xab, hi: 0xab}, {value: 0x3008, lo: 0xac, hi: 0xac}, {value: 0x3b08, lo: 0xad, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0x7c, offset 0x3f3 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, // Block 0x7d, offset 0x3f7 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x8a}, {value: 0x0018, lo: 0x8b, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, // Block 0x7e, offset 0x3fc {value: 0x0020, lo: 0x01}, {value: 0x4515, lo: 0x80, hi: 0xbf}, // Block 0x7f, offset 0x3fe {value: 0x0020, lo: 0x03}, {value: 0x4d15, lo: 0x80, hi: 0x94}, {value: 0x4ad5, lo: 0x95, hi: 0x95}, {value: 0x4fb5, lo: 0x96, hi: 0xbf}, // Block 0x80, offset 0x402 {value: 0x0020, lo: 0x01}, {value: 0x54f5, lo: 0x80, hi: 0xbf}, // Block 0x81, offset 0x404 {value: 0x0020, lo: 0x03}, {value: 0x5cf5, lo: 0x80, hi: 0x84}, {value: 0x5655, lo: 0x85, hi: 0x85}, {value: 0x5d95, lo: 0x86, hi: 0xbf}, // Block 0x82, offset 0x408 {value: 0x0020, lo: 0x08}, {value: 0x6b55, lo: 0x80, hi: 0x8f}, {value: 0x6d15, lo: 0x90, hi: 0x90}, {value: 0x6d55, lo: 0x91, hi: 0xab}, {value: 0x6ea1, lo: 0xac, hi: 0xac}, {value: 0x70b5, lo: 0xad, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x70d5, lo: 0xb0, hi: 0xbf}, // Block 0x83, offset 0x411 {value: 0x0020, lo: 0x05}, {value: 0x72d5, lo: 0x80, hi: 0xad}, {value: 0x6535, lo: 0xae, hi: 0xae}, {value: 0x7895, lo: 0xaf, hi: 0xb5}, {value: 0x6f55, lo: 0xb6, hi: 0xb6}, {value: 0x7975, lo: 0xb7, hi: 0xbf}, // Block 0x84, offset 0x417 {value: 0x0028, lo: 0x03}, {value: 0x7c21, lo: 0x80, hi: 0x82}, {value: 0x7be1, lo: 0x83, hi: 0x83}, {value: 0x7c99, lo: 0x84, hi: 0xbf}, // Block 0x85, offset 0x41b {value: 0x0038, lo: 0x0f}, {value: 0x9db1, lo: 0x80, hi: 0x83}, {value: 0x9e59, lo: 0x84, hi: 0x85}, {value: 0x9e91, lo: 0x86, hi: 0x87}, {value: 0x9ec9, lo: 0x88, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x91}, {value: 0xa089, lo: 0x92, hi: 0x97}, {value: 0xa1a1, lo: 0x98, hi: 0x9c}, {value: 0xa281, lo: 0x9d, hi: 0xb3}, {value: 0x9d41, lo: 0xb4, hi: 0xb4}, {value: 0x9db1, lo: 0xb5, hi: 0xb5}, {value: 0xa789, lo: 0xb6, hi: 0xbb}, {value: 0xa869, lo: 0xbc, hi: 0xbc}, {value: 0xa7f9, lo: 0xbd, hi: 0xbd}, {value: 0xa8d9, lo: 0xbe, hi: 0xbf}, // Block 0x86, offset 0x42b {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8c}, {value: 0x0008, lo: 0x8d, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xa7}, {value: 0x0008, lo: 0xa8, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbb}, {value: 0x0008, lo: 0xbc, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbe}, {value: 0x0008, lo: 0xbf, hi: 0xbf}, // Block 0x87, offset 0x435 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0xbf}, // Block 0x88, offset 0x43a {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbf}, // Block 0x89, offset 0x43d {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x86}, {value: 0x0018, lo: 0x87, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xbf}, // Block 0x8a, offset 0x443 {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x8e}, {value: 0x0040, lo: 0x8f, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa0}, {value: 0x0040, lo: 0xa1, hi: 0xbf}, // Block 0x8b, offset 0x44a {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbc}, {value: 0x3308, lo: 0xbd, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, // Block 0x8c, offset 0x44f {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0x9c}, {value: 0x0040, lo: 0x9d, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x8d, offset 0x453 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x9f}, {value: 0x3308, lo: 0xa0, hi: 0xa0}, {value: 0x0018, lo: 0xa1, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, // Block 0x8e, offset 0x459 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xac}, {value: 0x0008, lo: 0xad, hi: 0xbf}, // Block 0x8f, offset 0x45e {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0x89}, {value: 0x0018, lo: 0x8a, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbf}, // Block 0x90, offset 0x467 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x91, offset 0x46c {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0xbf}, // Block 0x92, offset 0x472 {value: 0x0000, lo: 0x06}, {value: 0xe145, lo: 0x80, hi: 0x87}, {value: 0xe1c5, lo: 0x88, hi: 0x8f}, {value: 0xe145, lo: 0x90, hi: 0x97}, {value: 0x8ad5, lo: 0x98, hi: 0x9f}, {value: 0x8aed, lo: 0xa0, hi: 0xa7}, {value: 0x0008, lo: 0xa8, hi: 0xbf}, // Block 0x93, offset 0x479 {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa9}, {value: 0x0040, lo: 0xaa, hi: 0xaf}, {value: 0x8aed, lo: 0xb0, hi: 0xb7}, {value: 0x8ad5, lo: 0xb8, hi: 0xbf}, // Block 0x94, offset 0x480 {value: 0x0000, lo: 0x06}, {value: 0xe145, lo: 0x80, hi: 0x87}, {value: 0xe1c5, lo: 0x88, hi: 0x8f}, {value: 0xe145, lo: 0x90, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, // Block 0x95, offset 0x487 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x96, offset 0x48b {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xae}, {value: 0x0018, lo: 0xaf, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, // Block 0x97, offset 0x490 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0x98, offset 0x493 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xbf}, // Block 0x99, offset 0x498 {value: 0x0000, lo: 0x0b}, {value: 0x0808, lo: 0x80, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x87}, {value: 0x0808, lo: 0x88, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0808, lo: 0x8a, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb6}, {value: 0x0808, lo: 0xb7, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbb}, {value: 0x0808, lo: 0xbc, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbe}, {value: 0x0808, lo: 0xbf, hi: 0xbf}, // Block 0x9a, offset 0x4a4 {value: 0x0000, lo: 0x05}, {value: 0x0808, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x96}, {value: 0x0818, lo: 0x97, hi: 0x9f}, {value: 0x0808, lo: 0xa0, hi: 0xb6}, {value: 0x0818, lo: 0xb7, hi: 0xbf}, // Block 0x9b, offset 0x4aa {value: 0x0000, lo: 0x04}, {value: 0x0808, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0xa6}, {value: 0x0818, lo: 0xa7, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, // Block 0x9c, offset 0x4af {value: 0x0000, lo: 0x06}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0808, lo: 0xa0, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xb3}, {value: 0x0808, lo: 0xb4, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xba}, {value: 0x0818, lo: 0xbb, hi: 0xbf}, // Block 0x9d, offset 0x4b6 {value: 0x0000, lo: 0x07}, {value: 0x0808, lo: 0x80, hi: 0x95}, {value: 0x0818, lo: 0x96, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0x9f}, {value: 0x0808, lo: 0xa0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbe}, {value: 0x0818, lo: 0xbf, hi: 0xbf}, // Block 0x9e, offset 0x4be {value: 0x0000, lo: 0x04}, {value: 0x0808, lo: 0x80, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbb}, {value: 0x0818, lo: 0xbc, hi: 0xbd}, {value: 0x0808, lo: 0xbe, hi: 0xbf}, // Block 0x9f, offset 0x4c3 {value: 0x0000, lo: 0x03}, {value: 0x0818, lo: 0x80, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x91}, {value: 0x0818, lo: 0x92, hi: 0xbf}, // Block 0xa0, offset 0x4c7 {value: 0x0000, lo: 0x0f}, {value: 0x0808, lo: 0x80, hi: 0x80}, {value: 0x3308, lo: 0x81, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x84}, {value: 0x3308, lo: 0x85, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x8b}, {value: 0x3308, lo: 0x8c, hi: 0x8f}, {value: 0x0808, lo: 0x90, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x94}, {value: 0x0808, lo: 0x95, hi: 0x97}, {value: 0x0040, lo: 0x98, hi: 0x98}, {value: 0x0808, lo: 0x99, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb7}, {value: 0x3308, lo: 0xb8, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0xa1, offset 0x4d7 {value: 0x0000, lo: 0x06}, {value: 0x0818, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x8f}, {value: 0x0818, lo: 0x90, hi: 0x98}, {value: 0x0040, lo: 0x99, hi: 0x9f}, {value: 0x0808, lo: 0xa0, hi: 0xbc}, {value: 0x0818, lo: 0xbd, hi: 0xbf}, // Block 0xa2, offset 0x4de {value: 0x0000, lo: 0x03}, {value: 0x0808, lo: 0x80, hi: 0x9c}, {value: 0x0818, lo: 0x9d, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, // Block 0xa3, offset 0x4e2 {value: 0x0000, lo: 0x03}, {value: 0x0808, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb8}, {value: 0x0018, lo: 0xb9, hi: 0xbf}, // Block 0xa4, offset 0x4e6 {value: 0x0000, lo: 0x06}, {value: 0x0808, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x97}, {value: 0x0818, lo: 0x98, hi: 0x9f}, {value: 0x0808, lo: 0xa0, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xb7}, {value: 0x0818, lo: 0xb8, hi: 0xbf}, // Block 0xa5, offset 0x4ed {value: 0x0000, lo: 0x01}, {value: 0x0808, lo: 0x80, hi: 0xbf}, // Block 0xa6, offset 0x4ef {value: 0x0000, lo: 0x02}, {value: 0x0808, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0xbf}, // Block 0xa7, offset 0x4f2 {value: 0x0000, lo: 0x02}, {value: 0x03dd, lo: 0x80, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xbf}, // Block 0xa8, offset 0x4f5 {value: 0x0000, lo: 0x03}, {value: 0x0808, lo: 0x80, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xb9}, {value: 0x0818, lo: 0xba, hi: 0xbf}, // Block 0xa9, offset 0x4f9 {value: 0x0000, lo: 0x08}, {value: 0x0908, lo: 0x80, hi: 0x80}, {value: 0x0a08, lo: 0x81, hi: 0xa1}, {value: 0x0c08, lo: 0xa2, hi: 0xa2}, {value: 0x0a08, lo: 0xa3, hi: 0xa3}, {value: 0x3308, lo: 0xa4, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xaf}, {value: 0x0808, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0xaa, offset 0x502 {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0818, lo: 0xa0, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0xab, offset 0x506 {value: 0x0000, lo: 0x07}, {value: 0x0808, lo: 0x80, hi: 0x9c}, {value: 0x0818, lo: 0x9d, hi: 0xa6}, {value: 0x0808, lo: 0xa7, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xaf}, {value: 0x0a08, lo: 0xb0, hi: 0xb2}, {value: 0x0c08, lo: 0xb3, hi: 0xb3}, {value: 0x0a08, lo: 0xb4, hi: 0xbf}, // Block 0xac, offset 0x50e {value: 0x0000, lo: 0x07}, {value: 0x0a08, lo: 0x80, hi: 0x84}, {value: 0x0808, lo: 0x85, hi: 0x85}, {value: 0x3308, lo: 0x86, hi: 0x90}, {value: 0x0a18, lo: 0x91, hi: 0x93}, {value: 0x0c18, lo: 0x94, hi: 0x94}, {value: 0x0818, lo: 0x95, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0xbf}, // Block 0xad, offset 0x516 {value: 0x0000, lo: 0x05}, {value: 0x3008, lo: 0x80, hi: 0x80}, {value: 0x3308, lo: 0x81, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xb7}, {value: 0x3308, lo: 0xb8, hi: 0xbf}, // Block 0xae, offset 0x51c {value: 0x0000, lo: 0x08}, {value: 0x3308, lo: 0x80, hi: 0x85}, {value: 0x3b08, lo: 0x86, hi: 0x86}, {value: 0x0018, lo: 0x87, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x91}, {value: 0x0018, lo: 0x92, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0xaf, offset 0x525 {value: 0x0000, lo: 0x0b}, {value: 0x3308, lo: 0x80, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xaf}, {value: 0x3008, lo: 0xb0, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xb6}, {value: 0x3008, lo: 0xb7, hi: 0xb8}, {value: 0x3b08, lo: 0xb9, hi: 0xb9}, {value: 0x3308, lo: 0xba, hi: 0xba}, {value: 0x0018, lo: 0xbb, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbd}, {value: 0x0018, lo: 0xbe, hi: 0xbf}, // Block 0xb0, offset 0x531 {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x81}, {value: 0x0040, lo: 0x82, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xa8}, {value: 0x0040, lo: 0xa9, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0xb1, offset 0x538 {value: 0x0000, lo: 0x08}, {value: 0x3308, lo: 0x80, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xa6}, {value: 0x3308, lo: 0xa7, hi: 0xab}, {value: 0x3008, lo: 0xac, hi: 0xac}, {value: 0x3308, lo: 0xad, hi: 0xb2}, {value: 0x3b08, lo: 0xb3, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xb5}, {value: 0x0008, lo: 0xb6, hi: 0xbf}, // Block 0xb2, offset 0x541 {value: 0x0000, lo: 0x09}, {value: 0x0018, lo: 0x80, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x84}, {value: 0x3008, lo: 0x85, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xb5}, {value: 0x0008, lo: 0xb6, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0xb3, offset 0x54b {value: 0x0000, lo: 0x06}, {value: 0x3308, lo: 0x80, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xb2}, {value: 0x3008, lo: 0xb3, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xbe}, {value: 0x3008, lo: 0xbf, hi: 0xbf}, // Block 0xb4, offset 0x552 {value: 0x0000, lo: 0x0d}, {value: 0x3808, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0x84}, {value: 0x0018, lo: 0x85, hi: 0x88}, {value: 0x3308, lo: 0x89, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9b}, {value: 0x0008, lo: 0x9c, hi: 0x9c}, {value: 0x0018, lo: 0x9d, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xa0}, {value: 0x0018, lo: 0xa1, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0xb5, offset 0x560 {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x91}, {value: 0x0040, lo: 0x92, hi: 0x92}, {value: 0x0008, lo: 0x93, hi: 0xab}, {value: 0x3008, lo: 0xac, hi: 0xae}, {value: 0x3308, lo: 0xaf, hi: 0xb1}, {value: 0x3008, lo: 0xb2, hi: 0xb3}, {value: 0x3308, lo: 0xb4, hi: 0xb4}, {value: 0x3808, lo: 0xb5, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xb7}, {value: 0x0018, lo: 0xb8, hi: 0xbd}, {value: 0x3308, lo: 0xbe, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0xb6, offset 0x56d {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0008, lo: 0x8a, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8e}, {value: 0x0008, lo: 0x8f, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9e}, {value: 0x0008, lo: 0x9f, hi: 0xa8}, {value: 0x0018, lo: 0xa9, hi: 0xa9}, {value: 0x0040, lo: 0xaa, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0xb7, offset 0x57a {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0x9e}, {value: 0x3308, lo: 0x9f, hi: 0x9f}, {value: 0x3008, lo: 0xa0, hi: 0xa2}, {value: 0x3308, lo: 0xa3, hi: 0xa9}, {value: 0x3b08, lo: 0xaa, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0xb8, offset 0x583 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xb4}, {value: 0x3008, lo: 0xb5, hi: 0xb7}, {value: 0x3308, lo: 0xb8, hi: 0xbf}, // Block 0xb9, offset 0x587 {value: 0x0000, lo: 0x0e}, {value: 0x3008, lo: 0x80, hi: 0x81}, {value: 0x3b08, lo: 0x82, hi: 0x82}, {value: 0x3308, lo: 0x83, hi: 0x84}, {value: 0x3008, lo: 0x85, hi: 0x85}, {value: 0x3308, lo: 0x86, hi: 0x86}, {value: 0x0008, lo: 0x87, hi: 0x8a}, {value: 0x0018, lo: 0x8b, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0x9c}, {value: 0x0018, lo: 0x9d, hi: 0x9d}, {value: 0x3308, lo: 0x9e, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0xbf}, // Block 0xba, offset 0x596 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x3008, lo: 0xb0, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xb8}, {value: 0x3008, lo: 0xb9, hi: 0xb9}, {value: 0x3308, lo: 0xba, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbe}, {value: 0x3308, lo: 0xbf, hi: 0xbf}, // Block 0xbb, offset 0x59e {value: 0x0000, lo: 0x0a}, {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x3008, lo: 0x81, hi: 0x81}, {value: 0x3b08, lo: 0x82, hi: 0x82}, {value: 0x3308, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x85}, {value: 0x0018, lo: 0x86, hi: 0x86}, {value: 0x0008, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0xbf}, // Block 0xbc, offset 0x5a9 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0xae}, {value: 0x3008, lo: 0xaf, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb7}, {value: 0x3008, lo: 0xb8, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0xbd, offset 0x5b2 {value: 0x0000, lo: 0x05}, {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0x9b}, {value: 0x3308, lo: 0x9c, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0xbf}, // Block 0xbe, offset 0x5b8 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x3008, lo: 0xb0, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbc}, {value: 0x3308, lo: 0xbd, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0xbf, offset 0x5c0 {value: 0x0000, lo: 0x08}, {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xbf}, // Block 0xc0, offset 0x5c9 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0xaa}, {value: 0x3308, lo: 0xab, hi: 0xab}, {value: 0x3008, lo: 0xac, hi: 0xac}, {value: 0x3308, lo: 0xad, hi: 0xad}, {value: 0x3008, lo: 0xae, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb5}, {value: 0x3808, lo: 0xb6, hi: 0xb6}, {value: 0x3308, lo: 0xb7, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbf}, // Block 0xc1, offset 0x5d3 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0xbf}, // Block 0xc2, offset 0x5d6 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x9a}, {value: 0x0040, lo: 0x9b, hi: 0x9c}, {value: 0x3308, lo: 0x9d, hi: 0x9f}, {value: 0x3008, lo: 0xa0, hi: 0xa1}, {value: 0x3308, lo: 0xa2, hi: 0xa5}, {value: 0x3008, lo: 0xa6, hi: 0xa6}, {value: 0x3308, lo: 0xa7, hi: 0xaa}, {value: 0x3b08, lo: 0xab, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0018, lo: 0xba, hi: 0xbf}, // Block 0xc3, offset 0x5e2 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0xab}, {value: 0x3008, lo: 0xac, hi: 0xae}, {value: 0x3308, lo: 0xaf, hi: 0xb7}, {value: 0x3008, lo: 0xb8, hi: 0xb8}, {value: 0x3b08, lo: 0xb9, hi: 0xb9}, {value: 0x3308, lo: 0xba, hi: 0xba}, {value: 0x0018, lo: 0xbb, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, // Block 0xc4, offset 0x5eb {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x049d, lo: 0xa0, hi: 0xbf}, // Block 0xc5, offset 0x5ee {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xa9}, {value: 0x0018, lo: 0xaa, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xbe}, {value: 0x0008, lo: 0xbf, hi: 0xbf}, // Block 0xc6, offset 0x5f3 {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x3308, lo: 0x81, hi: 0x8a}, {value: 0x0008, lo: 0x8b, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xb3}, {value: 0x3b08, lo: 0xb4, hi: 0xb4}, {value: 0x3308, lo: 0xb5, hi: 0xb8}, {value: 0x3008, lo: 0xb9, hi: 0xb9}, {value: 0x0008, lo: 0xba, hi: 0xba}, {value: 0x3308, lo: 0xbb, hi: 0xbe}, {value: 0x0018, lo: 0xbf, hi: 0xbf}, // Block 0xc7, offset 0x5fe {value: 0x0000, lo: 0x08}, {value: 0x0018, lo: 0x80, hi: 0x86}, {value: 0x3b08, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x90}, {value: 0x3308, lo: 0x91, hi: 0x96}, {value: 0x3008, lo: 0x97, hi: 0x98}, {value: 0x3308, lo: 0x99, hi: 0x9b}, {value: 0x0008, lo: 0x9c, hi: 0xbf}, // Block 0xc8, offset 0x607 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x85}, {value: 0x0008, lo: 0x86, hi: 0x89}, {value: 0x3308, lo: 0x8a, hi: 0x96}, {value: 0x3008, lo: 0x97, hi: 0x97}, {value: 0x3308, lo: 0x98, hi: 0x98}, {value: 0x3b08, lo: 0x99, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0x9c}, {value: 0x0008, lo: 0x9d, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0xa2}, {value: 0x0040, lo: 0xa3, hi: 0xbf}, // Block 0xc9, offset 0x613 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbf}, // Block 0xca, offset 0x616 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0008, lo: 0x8a, hi: 0xae}, {value: 0x3008, lo: 0xaf, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xb7}, {value: 0x3308, lo: 0xb8, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0xcb, offset 0x620 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xbf}, // Block 0xcc, offset 0x629 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x91}, {value: 0x3308, lo: 0x92, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xa8}, {value: 0x3008, lo: 0xa9, hi: 0xa9}, {value: 0x3308, lo: 0xaa, hi: 0xb0}, {value: 0x3008, lo: 0xb1, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb3}, {value: 0x3008, lo: 0xb4, hi: 0xb4}, {value: 0x3308, lo: 0xb5, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0xcd, offset 0x635 {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0x8a}, {value: 0x0008, lo: 0x8b, hi: 0xb0}, {value: 0x3308, lo: 0xb1, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xb9}, {value: 0x3308, lo: 0xba, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbe}, {value: 0x3308, lo: 0xbf, hi: 0xbf}, // Block 0xce, offset 0x642 {value: 0x0000, lo: 0x0c}, {value: 0x3308, lo: 0x80, hi: 0x83}, {value: 0x3b08, lo: 0x84, hi: 0x85}, {value: 0x0008, lo: 0x86, hi: 0x86}, {value: 0x3308, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa5}, {value: 0x0040, lo: 0xa6, hi: 0xa6}, {value: 0x0008, lo: 0xa7, hi: 0xa8}, {value: 0x0040, lo: 0xa9, hi: 0xa9}, {value: 0x0008, lo: 0xaa, hi: 0xbf}, // Block 0xcf, offset 0x64f {value: 0x0000, lo: 0x0d}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x3008, lo: 0x8a, hi: 0x8e}, {value: 0x0040, lo: 0x8f, hi: 0x8f}, {value: 0x3308, lo: 0x90, hi: 0x91}, {value: 0x0040, lo: 0x92, hi: 0x92}, {value: 0x3008, lo: 0x93, hi: 0x94}, {value: 0x3308, lo: 0x95, hi: 0x95}, {value: 0x3008, lo: 0x96, hi: 0x96}, {value: 0x3b08, lo: 0x97, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0x98}, {value: 0x0040, lo: 0x99, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa9}, {value: 0x0040, lo: 0xaa, hi: 0xbf}, // Block 0xd0, offset 0x65d {value: 0x0000, lo: 0x06}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xb4}, {value: 0x3008, lo: 0xb5, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbf}, // Block 0xd1, offset 0x664 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0xbf}, // Block 0xd2, offset 0x667 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0xd3, offset 0x66c {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0xbf}, // Block 0xd4, offset 0x66f {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xbf}, // Block 0xd5, offset 0x672 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0xbf}, // Block 0xd6, offset 0x675 {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa9}, {value: 0x0040, lo: 0xaa, hi: 0xad}, {value: 0x0018, lo: 0xae, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, // Block 0xd7, offset 0x67c {value: 0x0000, lo: 0x06}, {value: 0x0040, lo: 0x80, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb4}, {value: 0x0018, lo: 0xb5, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, // Block 0xd8, offset 0x683 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xbf}, // Block 0xd9, offset 0x687 {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x83}, {value: 0x0018, lo: 0x84, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0xa1}, {value: 0x0040, lo: 0xa2, hi: 0xa2}, {value: 0x0008, lo: 0xa3, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbf}, // Block 0xda, offset 0x692 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0xbf}, // Block 0xdb, offset 0x695 {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0xdc, offset 0x698 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0x9a}, {value: 0x0040, lo: 0x9b, hi: 0xbf}, // Block 0xdd, offset 0x69b {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x90}, {value: 0x3008, lo: 0x91, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0xde, offset 0x6a1 {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x8e}, {value: 0x3308, lo: 0x8f, hi: 0x92}, {value: 0x0008, lo: 0x93, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, // Block 0xdf, offset 0x6a6 {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa1}, {value: 0x0040, lo: 0xa2, hi: 0xbf}, // Block 0xe0, offset 0x6aa {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb1}, {value: 0x0040, lo: 0xb2, hi: 0xbf}, // Block 0xe1, offset 0x6ad {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xbf}, // Block 0xe2, offset 0x6b0 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0xbf}, // Block 0xe3, offset 0x6b3 {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0xe4, offset 0x6b6 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, // Block 0xe5, offset 0x6b9 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, // Block 0xe6, offset 0x6be {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9b}, {value: 0x0018, lo: 0x9c, hi: 0x9c}, {value: 0x3308, lo: 0x9d, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0x9f}, {value: 0x03c0, lo: 0xa0, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xbf}, // Block 0xe7, offset 0x6c8 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, // Block 0xe8, offset 0x6cb {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xa8}, {value: 0x0018, lo: 0xa9, hi: 0xbf}, // Block 0xe9, offset 0x6cf {value: 0x0000, lo: 0x0e}, {value: 0x0018, lo: 0x80, hi: 0x9d}, {value: 0xb5b9, lo: 0x9e, hi: 0x9e}, {value: 0xb601, lo: 0x9f, hi: 0x9f}, {value: 0xb649, lo: 0xa0, hi: 0xa0}, {value: 0xb6b1, lo: 0xa1, hi: 0xa1}, {value: 0xb719, lo: 0xa2, hi: 0xa2}, {value: 0xb781, lo: 0xa3, hi: 0xa3}, {value: 0xb7e9, lo: 0xa4, hi: 0xa4}, {value: 0x3018, lo: 0xa5, hi: 0xa6}, {value: 0x3318, lo: 0xa7, hi: 0xa9}, {value: 0x0018, lo: 0xaa, hi: 0xac}, {value: 0x3018, lo: 0xad, hi: 0xb2}, {value: 0x0340, lo: 0xb3, hi: 0xba}, {value: 0x3318, lo: 0xbb, hi: 0xbf}, // Block 0xea, offset 0x6de {value: 0x0000, lo: 0x0b}, {value: 0x3318, lo: 0x80, hi: 0x82}, {value: 0x0018, lo: 0x83, hi: 0x84}, {value: 0x3318, lo: 0x85, hi: 0x8b}, {value: 0x0018, lo: 0x8c, hi: 0xa9}, {value: 0x3318, lo: 0xaa, hi: 0xad}, {value: 0x0018, lo: 0xae, hi: 0xba}, {value: 0xb851, lo: 0xbb, hi: 0xbb}, {value: 0xb899, lo: 0xbc, hi: 0xbc}, {value: 0xb8e1, lo: 0xbd, hi: 0xbd}, {value: 0xb949, lo: 0xbe, hi: 0xbe}, {value: 0xb9b1, lo: 0xbf, hi: 0xbf}, // Block 0xeb, offset 0x6ea {value: 0x0000, lo: 0x03}, {value: 0xba19, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0xa8}, {value: 0x0040, lo: 0xa9, hi: 0xbf}, // Block 0xec, offset 0x6ee {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x81}, {value: 0x3318, lo: 0x82, hi: 0x84}, {value: 0x0018, lo: 0x85, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0xbf}, // Block 0xed, offset 0x6f3 {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbf}, // Block 0xee, offset 0x6f7 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbf}, // Block 0xef, offset 0x6fc {value: 0x0000, lo: 0x03}, {value: 0x3308, lo: 0x80, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xba}, {value: 0x3308, lo: 0xbb, hi: 0xbf}, // Block 0xf0, offset 0x700 {value: 0x0000, lo: 0x04}, {value: 0x3308, lo: 0x80, hi: 0xac}, {value: 0x0018, lo: 0xad, hi: 0xb4}, {value: 0x3308, lo: 0xb5, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xbf}, // Block 0xf1, offset 0x705 {value: 0x0000, lo: 0x08}, {value: 0x0018, lo: 0x80, hi: 0x83}, {value: 0x3308, lo: 0x84, hi: 0x84}, {value: 0x0018, lo: 0x85, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x9a}, {value: 0x3308, lo: 0x9b, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xa0}, {value: 0x3308, lo: 0xa1, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, // Block 0xf2, offset 0x70e {value: 0x0000, lo: 0x0a}, {value: 0x3308, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, {value: 0x3308, lo: 0x88, hi: 0x98}, {value: 0x0040, lo: 0x99, hi: 0x9a}, {value: 0x3308, lo: 0x9b, hi: 0xa1}, {value: 0x0040, lo: 0xa2, hi: 0xa2}, {value: 0x3308, lo: 0xa3, hi: 0xa4}, {value: 0x0040, lo: 0xa5, hi: 0xa5}, {value: 0x3308, lo: 0xa6, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xbf}, // Block 0xf3, offset 0x719 {value: 0x0000, lo: 0x05}, {value: 0x0808, lo: 0x80, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x86}, {value: 0x0818, lo: 0x87, hi: 0x8f}, {value: 0x3308, lo: 0x90, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0xbf}, // Block 0xf4, offset 0x71f {value: 0x0000, lo: 0x07}, {value: 0x0a08, lo: 0x80, hi: 0x83}, {value: 0x3308, lo: 0x84, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8f}, {value: 0x0808, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9d}, {value: 0x0818, lo: 0x9e, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, // Block 0xf5, offset 0x727 {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0xb0}, {value: 0x0818, lo: 0xb1, hi: 0xbf}, // Block 0xf6, offset 0x72a {value: 0x0000, lo: 0x02}, {value: 0x0818, lo: 0x80, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0xf7, offset 0x72d {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb1}, {value: 0x0040, lo: 0xb2, hi: 0xbf}, // Block 0xf8, offset 0x731 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, // Block 0xf9, offset 0x735 {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xb0}, {value: 0x0018, lo: 0xb1, hi: 0xbf}, // Block 0xfa, offset 0x73b {value: 0x0000, lo: 0x05}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x90}, {value: 0x0018, lo: 0x91, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, // Block 0xfb, offset 0x741 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x8f}, {value: 0xc1c1, lo: 0x90, hi: 0x90}, {value: 0x0018, lo: 0x91, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xbf}, // Block 0xfc, offset 0x746 {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0xa5}, {value: 0x0018, lo: 0xa6, hi: 0xbf}, // Block 0xfd, offset 0x749 {value: 0x0000, lo: 0x0f}, {value: 0xc7e9, lo: 0x80, hi: 0x80}, {value: 0xc839, lo: 0x81, hi: 0x81}, {value: 0xc889, lo: 0x82, hi: 0x82}, {value: 0xc8d9, lo: 0x83, hi: 0x83}, {value: 0xc929, lo: 0x84, hi: 0x84}, {value: 0xc979, lo: 0x85, hi: 0x85}, {value: 0xc9c9, lo: 0x86, hi: 0x86}, {value: 0xca19, lo: 0x87, hi: 0x87}, {value: 0xca69, lo: 0x88, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x8f}, {value: 0xcab9, lo: 0x90, hi: 0x90}, {value: 0xcad9, lo: 0x91, hi: 0x91}, {value: 0x0040, lo: 0x92, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa5}, {value: 0x0040, lo: 0xa6, hi: 0xbf}, // Block 0xfe, offset 0x759 {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x94}, {value: 0x0040, lo: 0x95, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0xff, offset 0x760 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbf}, // Block 0x100, offset 0x763 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0x98}, {value: 0x0040, lo: 0x99, hi: 0xbf}, // Block 0x101, offset 0x766 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbf}, // Block 0x102, offset 0x76a {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xbf}, // Block 0x103, offset 0x770 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xbf}, // Block 0x104, offset 0x775 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0x105, offset 0x77a {value: 0x0000, lo: 0x07}, {value: 0x0018, lo: 0x80, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xb2}, {value: 0x0018, lo: 0xb3, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xb9}, {value: 0x0018, lo: 0xba, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbb}, {value: 0x0018, lo: 0xbc, hi: 0xbf}, // Block 0x106, offset 0x782 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0xa2}, {value: 0x0040, lo: 0xa3, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0x107, offset 0x787 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbf}, // Block 0x108, offset 0x78b {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xbf}, // Block 0x109, offset 0x78f {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0xbf}, // Block 0x10a, offset 0x792 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0x10b, offset 0x795 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x10c, offset 0x799 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xa1}, {value: 0x0040, lo: 0xa2, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x10d, offset 0x79d {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xa0}, {value: 0x0040, lo: 0xa1, hi: 0xbf}, // Block 0x10e, offset 0x7a0 {value: 0x0020, lo: 0x0f}, {value: 0xdeb9, lo: 0x80, hi: 0x89}, {value: 0x8dfd, lo: 0x8a, hi: 0x8a}, {value: 0xdff9, lo: 0x8b, hi: 0x9c}, {value: 0x8e1d, lo: 0x9d, hi: 0x9d}, {value: 0xe239, lo: 0x9e, hi: 0xa2}, {value: 0x8e3d, lo: 0xa3, hi: 0xa3}, {value: 0xe2d9, lo: 0xa4, hi: 0xab}, {value: 0x7ed5, lo: 0xac, hi: 0xac}, {value: 0xe3d9, lo: 0xad, hi: 0xaf}, {value: 0x8e5d, lo: 0xb0, hi: 0xb0}, {value: 0xe439, lo: 0xb1, hi: 0xb6}, {value: 0x8e7d, lo: 0xb7, hi: 0xb9}, {value: 0xe4f9, lo: 0xba, hi: 0xba}, {value: 0x8edd, lo: 0xbb, hi: 0xbb}, {value: 0xe519, lo: 0xbc, hi: 0xbf}, // Block 0x10f, offset 0x7b0 {value: 0x0020, lo: 0x10}, {value: 0x937d, lo: 0x80, hi: 0x80}, {value: 0xf099, lo: 0x81, hi: 0x86}, {value: 0x939d, lo: 0x87, hi: 0x8a}, {value: 0xd9f9, lo: 0x8b, hi: 0x8b}, {value: 0xf159, lo: 0x8c, hi: 0x96}, {value: 0x941d, lo: 0x97, hi: 0x97}, {value: 0xf2b9, lo: 0x98, hi: 0xa3}, {value: 0x943d, lo: 0xa4, hi: 0xa6}, {value: 0xf439, lo: 0xa7, hi: 0xaa}, {value: 0x949d, lo: 0xab, hi: 0xab}, {value: 0xf4b9, lo: 0xac, hi: 0xac}, {value: 0x94bd, lo: 0xad, hi: 0xad}, {value: 0xf4d9, lo: 0xae, hi: 0xaf}, {value: 0x94dd, lo: 0xb0, hi: 0xb1}, {value: 0xf519, lo: 0xb2, hi: 0xbe}, {value: 0x2040, lo: 0xbf, hi: 0xbf}, // Block 0x110, offset 0x7c1 {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0340, lo: 0x81, hi: 0x81}, {value: 0x0040, lo: 0x82, hi: 0x9f}, {value: 0x0340, lo: 0xa0, hi: 0xbf}, // Block 0x111, offset 0x7c6 {value: 0x0000, lo: 0x01}, {value: 0x0340, lo: 0x80, hi: 0xbf}, // Block 0x112, offset 0x7c8 {value: 0x0000, lo: 0x01}, {value: 0x33c0, lo: 0x80, hi: 0xbf}, // Block 0x113, offset 0x7ca {value: 0x0000, lo: 0x02}, {value: 0x33c0, lo: 0x80, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, } // Total table size 42466 bytes (41KiB); checksum: 355A58A4 ================================================ FILE: vendor/golang.org/x/net/idna/tables9.0.0.go ================================================ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // +build !go1.10 package idna // UnicodeVersion is the Unicode version from which the tables in this package are derived. const UnicodeVersion = "9.0.0" var mappings string = "" + // Size: 8175 bytes "\x00\x01 \x03 ̈\x01a\x03 ̄\x012\x013\x03 ́\x03 ̧\x011\x01o\x051⁄4\x051⁄2" + "\x053⁄4\x03i̇\x03l·\x03ʼn\x01s\x03dž\x03ⱥ\x03ⱦ\x01h\x01j\x01r\x01w\x01y" + "\x03 ̆\x03 ̇\x03 ̊\x03 ̨\x03 ̃\x03 ̋\x01l\x01x\x04̈́\x03 ι\x01;\x05 ̈́" + "\x04եւ\x04اٴ\x04وٴ\x04ۇٴ\x04يٴ\x06क़\x06ख़\x06ग़\x06ज़\x06ड़\x06ढ़\x06फ़" + "\x06य़\x06ড়\x06ঢ়\x06য়\x06ਲ਼\x06ਸ਼\x06ਖ਼\x06ਗ਼\x06ਜ਼\x06ਫ਼\x06ଡ଼\x06ଢ଼" + "\x06ํา\x06ໍາ\x06ຫນ\x06ຫມ\x06གྷ\x06ཌྷ\x06དྷ\x06བྷ\x06ཛྷ\x06ཀྵ\x06ཱི\x06ཱུ" + "\x06ྲྀ\x09ྲཱྀ\x06ླྀ\x09ླཱྀ\x06ཱྀ\x06ྒྷ\x06ྜྷ\x06ྡྷ\x06ྦྷ\x06ྫྷ\x06ྐྵ\x02" + "в\x02д\x02о\x02с\x02т\x02ъ\x02ѣ\x02æ\x01b\x01d\x01e\x02ǝ\x01g\x01i\x01k" + "\x01m\x01n\x02ȣ\x01p\x01t\x01u\x02ɐ\x02ɑ\x02ə\x02ɛ\x02ɜ\x02ŋ\x02ɔ\x02ɯ" + "\x01v\x02β\x02γ\x02δ\x02φ\x02χ\x02ρ\x02н\x02ɒ\x01c\x02ɕ\x02ð\x01f\x02ɟ" + "\x02ɡ\x02ɥ\x02ɨ\x02ɩ\x02ɪ\x02ʝ\x02ɭ\x02ʟ\x02ɱ\x02ɰ\x02ɲ\x02ɳ\x02ɴ\x02ɵ" + "\x02ɸ\x02ʂ\x02ʃ\x02ƫ\x02ʉ\x02ʊ\x02ʋ\x02ʌ\x01z\x02ʐ\x02ʑ\x02ʒ\x02θ\x02ss" + "\x02ά\x02έ\x02ή\x02ί\x02ό\x02ύ\x02ώ\x05ἀι\x05ἁι\x05ἂι\x05ἃι\x05ἄι\x05ἅι" + "\x05ἆι\x05ἇι\x05ἠι\x05ἡι\x05ἢι\x05ἣι\x05ἤι\x05ἥι\x05ἦι\x05ἧι\x05ὠι\x05ὡι" + "\x05ὢι\x05ὣι\x05ὤι\x05ὥι\x05ὦι\x05ὧι\x05ὰι\x04αι\x04άι\x05ᾶι\x02ι\x05 ̈͂" + "\x05ὴι\x04ηι\x04ήι\x05ῆι\x05 ̓̀\x05 ̓́\x05 ̓͂\x02ΐ\x05 ̔̀\x05 ̔́\x05 ̔͂" + "\x02ΰ\x05 ̈̀\x01`\x05ὼι\x04ωι\x04ώι\x05ῶι\x06′′\x09′′′\x06‵‵\x09‵‵‵\x02!" + "!\x02??\x02?!\x02!?\x0c′′′′\x010\x014\x015\x016\x017\x018\x019\x01+\x01=" + "\x01(\x01)\x02rs\x02ħ\x02no\x01q\x02sm\x02tm\x02ω\x02å\x02א\x02ב\x02ג" + "\x02ד\x02π\x051⁄7\x051⁄9\x061⁄10\x051⁄3\x052⁄3\x051⁄5\x052⁄5\x053⁄5\x054" + "⁄5\x051⁄6\x055⁄6\x051⁄8\x053⁄8\x055⁄8\x057⁄8\x041⁄\x02ii\x02iv\x02vi" + "\x04viii\x02ix\x02xi\x050⁄3\x06∫∫\x09∫∫∫\x06∮∮\x09∮∮∮\x0210\x0211\x0212" + "\x0213\x0214\x0215\x0216\x0217\x0218\x0219\x0220\x04(10)\x04(11)\x04(12)" + "\x04(13)\x04(14)\x04(15)\x04(16)\x04(17)\x04(18)\x04(19)\x04(20)\x0c∫∫∫∫" + "\x02==\x05⫝̸\x02ɫ\x02ɽ\x02ȿ\x02ɀ\x01.\x04 ゙\x04 ゚\x06より\x06コト\x05(ᄀ)\x05" + "(ᄂ)\x05(ᄃ)\x05(ᄅ)\x05(ᄆ)\x05(ᄇ)\x05(ᄉ)\x05(ᄋ)\x05(ᄌ)\x05(ᄎ)\x05(ᄏ)\x05(ᄐ" + ")\x05(ᄑ)\x05(ᄒ)\x05(가)\x05(나)\x05(다)\x05(라)\x05(마)\x05(바)\x05(사)\x05(아)" + "\x05(자)\x05(차)\x05(카)\x05(타)\x05(파)\x05(하)\x05(주)\x08(오전)\x08(오후)\x05(一)" + "\x05(二)\x05(三)\x05(四)\x05(五)\x05(六)\x05(七)\x05(八)\x05(九)\x05(十)\x05(月)" + "\x05(火)\x05(水)\x05(木)\x05(金)\x05(土)\x05(日)\x05(株)\x05(有)\x05(社)\x05(名)" + "\x05(特)\x05(財)\x05(祝)\x05(労)\x05(代)\x05(呼)\x05(学)\x05(監)\x05(企)\x05(資)" + "\x05(協)\x05(祭)\x05(休)\x05(自)\x05(至)\x0221\x0222\x0223\x0224\x0225\x0226" + "\x0227\x0228\x0229\x0230\x0231\x0232\x0233\x0234\x0235\x06참고\x06주의\x0236" + "\x0237\x0238\x0239\x0240\x0241\x0242\x0243\x0244\x0245\x0246\x0247\x0248" + "\x0249\x0250\x041月\x042月\x043月\x044月\x045月\x046月\x047月\x048月\x049月\x0510" + "月\x0511月\x0512月\x02hg\x02ev\x0cアパート\x0cアルファ\x0cアンペア\x09アール\x0cイニング\x09" + "インチ\x09ウォン\x0fエスクード\x0cエーカー\x09オンス\x09オーム\x09カイリ\x0cカラット\x0cカロリー\x09ガロ" + "ン\x09ガンマ\x06ギガ\x09ギニー\x0cキュリー\x0cギルダー\x06キロ\x0fキログラム\x12キロメートル\x0fキロワッ" + "ト\x09グラム\x0fグラムトン\x0fクルゼイロ\x0cクローネ\x09ケース\x09コルナ\x09コーポ\x0cサイクル\x0fサンチ" + "ーム\x0cシリング\x09センチ\x09セント\x09ダース\x06デシ\x06ドル\x06トン\x06ナノ\x09ノット\x09ハイツ" + "\x0fパーセント\x09パーツ\x0cバーレル\x0fピアストル\x09ピクル\x06ピコ\x06ビル\x0fファラッド\x0cフィート" + "\x0fブッシェル\x09フラン\x0fヘクタール\x06ペソ\x09ペニヒ\x09ヘルツ\x09ペンス\x09ページ\x09ベータ\x0cポイ" + "ント\x09ボルト\x06ホン\x09ポンド\x09ホール\x09ホーン\x0cマイクロ\x09マイル\x09マッハ\x09マルク\x0fマ" + "ンション\x0cミクロン\x06ミリ\x0fミリバール\x06メガ\x0cメガトン\x0cメートル\x09ヤード\x09ヤール\x09ユアン" + "\x0cリットル\x06リラ\x09ルピー\x0cルーブル\x06レム\x0fレントゲン\x09ワット\x040点\x041点\x042点" + "\x043点\x044点\x045点\x046点\x047点\x048点\x049点\x0510点\x0511点\x0512点\x0513点" + "\x0514点\x0515点\x0516点\x0517点\x0518点\x0519点\x0520点\x0521点\x0522点\x0523点" + "\x0524点\x02da\x02au\x02ov\x02pc\x02dm\x02iu\x06平成\x06昭和\x06大正\x06明治\x0c株" + "式会社\x02pa\x02na\x02ma\x02ka\x02kb\x02mb\x02gb\x04kcal\x02pf\x02nf\x02m" + "g\x02kg\x02hz\x02ml\x02dl\x02kl\x02fm\x02nm\x02mm\x02cm\x02km\x02m2\x02m" + "3\x05m∕s\x06m∕s2\x07rad∕s\x08rad∕s2\x02ps\x02ns\x02ms\x02pv\x02nv\x02mv" + "\x02kv\x02pw\x02nw\x02mw\x02kw\x02bq\x02cc\x02cd\x06c∕kg\x02db\x02gy\x02" + "ha\x02hp\x02in\x02kk\x02kt\x02lm\x02ln\x02lx\x02ph\x02pr\x02sr\x02sv\x02" + "wb\x05v∕m\x05a∕m\x041日\x042日\x043日\x044日\x045日\x046日\x047日\x048日\x049日" + "\x0510日\x0511日\x0512日\x0513日\x0514日\x0515日\x0516日\x0517日\x0518日\x0519日" + "\x0520日\x0521日\x0522日\x0523日\x0524日\x0525日\x0526日\x0527日\x0528日\x0529日" + "\x0530日\x0531日\x02ь\x02ɦ\x02ɬ\x02ʞ\x02ʇ\x02œ\x04𤋮\x04𢡊\x04𢡄\x04𣏕\x04𥉉" + "\x04𥳐\x04𧻓\x02ff\x02fi\x02fl\x02st\x04մն\x04մե\x04մի\x04վն\x04մխ\x04יִ" + "\x04ײַ\x02ע\x02ה\x02כ\x02ל\x02ם\x02ר\x02ת\x04שׁ\x04שׂ\x06שּׁ\x06שּׂ\x04א" + "ַ\x04אָ\x04אּ\x04בּ\x04גּ\x04דּ\x04הּ\x04וּ\x04זּ\x04טּ\x04יּ\x04ךּ\x04" + "כּ\x04לּ\x04מּ\x04נּ\x04סּ\x04ףּ\x04פּ\x04צּ\x04קּ\x04רּ\x04שּ\x04תּ" + "\x04וֹ\x04בֿ\x04כֿ\x04פֿ\x04אל\x02ٱ\x02ٻ\x02پ\x02ڀ\x02ٺ\x02ٿ\x02ٹ\x02ڤ" + "\x02ڦ\x02ڄ\x02ڃ\x02چ\x02ڇ\x02ڍ\x02ڌ\x02ڎ\x02ڈ\x02ژ\x02ڑ\x02ک\x02گ\x02ڳ" + "\x02ڱ\x02ں\x02ڻ\x02ۀ\x02ہ\x02ھ\x02ے\x02ۓ\x02ڭ\x02ۇ\x02ۆ\x02ۈ\x02ۋ\x02ۅ" + "\x02ۉ\x02ې\x02ى\x04ئا\x04ئە\x04ئو\x04ئۇ\x04ئۆ\x04ئۈ\x04ئې\x04ئى\x02ی\x04" + "ئج\x04ئح\x04ئم\x04ئي\x04بج\x04بح\x04بخ\x04بم\x04بى\x04بي\x04تج\x04تح" + "\x04تخ\x04تم\x04تى\x04تي\x04ثج\x04ثم\x04ثى\x04ثي\x04جح\x04جم\x04حج\x04حم" + "\x04خج\x04خح\x04خم\x04سج\x04سح\x04سخ\x04سم\x04صح\x04صم\x04ضج\x04ضح\x04ضخ" + "\x04ضم\x04طح\x04طم\x04ظم\x04عج\x04عم\x04غج\x04غم\x04فج\x04فح\x04فخ\x04فم" + "\x04فى\x04في\x04قح\x04قم\x04قى\x04قي\x04كا\x04كج\x04كح\x04كخ\x04كل\x04كم" + "\x04كى\x04كي\x04لج\x04لح\x04لخ\x04لم\x04لى\x04لي\x04مج\x04مح\x04مخ\x04مم" + "\x04مى\x04مي\x04نج\x04نح\x04نخ\x04نم\x04نى\x04ني\x04هج\x04هم\x04هى\x04هي" + "\x04يج\x04يح\x04يخ\x04يم\x04يى\x04يي\x04ذٰ\x04رٰ\x04ىٰ\x05 ٌّ\x05 ٍّ\x05" + " َّ\x05 ُّ\x05 ِّ\x05 ّٰ\x04ئر\x04ئز\x04ئن\x04بر\x04بز\x04بن\x04تر\x04تز" + "\x04تن\x04ثر\x04ثز\x04ثن\x04ما\x04نر\x04نز\x04نن\x04ير\x04يز\x04ين\x04ئخ" + "\x04ئه\x04به\x04ته\x04صخ\x04له\x04نه\x04هٰ\x04يه\x04ثه\x04سه\x04شم\x04شه" + "\x06ـَّ\x06ـُّ\x06ـِّ\x04طى\x04طي\x04عى\x04عي\x04غى\x04غي\x04سى\x04سي" + "\x04شى\x04شي\x04حى\x04حي\x04جى\x04جي\x04خى\x04خي\x04صى\x04صي\x04ضى\x04ضي" + "\x04شج\x04شح\x04شخ\x04شر\x04سر\x04صر\x04ضر\x04اً\x06تجم\x06تحج\x06تحم" + "\x06تخم\x06تمج\x06تمح\x06تمخ\x06جمح\x06حمي\x06حمى\x06سحج\x06سجح\x06سجى" + "\x06سمح\x06سمج\x06سمم\x06صحح\x06صمم\x06شحم\x06شجي\x06شمخ\x06شمم\x06ضحى" + "\x06ضخم\x06طمح\x06طمم\x06طمي\x06عجم\x06عمم\x06عمى\x06غمم\x06غمي\x06غمى" + "\x06فخم\x06قمح\x06قمم\x06لحم\x06لحي\x06لحى\x06لجج\x06لخم\x06لمح\x06محج" + "\x06محم\x06محي\x06مجح\x06مجم\x06مخج\x06مخم\x06مجخ\x06همج\x06همم\x06نحم" + "\x06نحى\x06نجم\x06نجى\x06نمي\x06نمى\x06يمم\x06بخي\x06تجي\x06تجى\x06تخي" + "\x06تخى\x06تمي\x06تمى\x06جمي\x06جحى\x06جمى\x06سخى\x06صحي\x06شحي\x06ضحي" + "\x06لجي\x06لمي\x06يحي\x06يجي\x06يمي\x06ممي\x06قمي\x06نحي\x06عمي\x06كمي" + "\x06نجح\x06مخي\x06لجم\x06كمم\x06جحي\x06حجي\x06مجي\x06فمي\x06بحي\x06سخي" + "\x06نجي\x06صلے\x06قلے\x08الله\x08اكبر\x08محمد\x08صلعم\x08رسول\x08عليه" + "\x08وسلم\x06صلى!صلى الله عليه وسلم\x0fجل جلاله\x08ریال\x01,\x01:\x01!" + "\x01?\x01_\x01{\x01}\x01[\x01]\x01#\x01&\x01*\x01-\x01<\x01>\x01\\\x01$" + "\x01%\x01@\x04ـً\x04ـَ\x04ـُ\x04ـِ\x04ـّ\x04ـْ\x02ء\x02آ\x02أ\x02ؤ\x02إ" + "\x02ئ\x02ا\x02ب\x02ة\x02ت\x02ث\x02ج\x02ح\x02خ\x02د\x02ذ\x02ر\x02ز\x02س" + "\x02ش\x02ص\x02ض\x02ط\x02ظ\x02ع\x02غ\x02ف\x02ق\x02ك\x02ل\x02م\x02ن\x02ه" + "\x02و\x02ي\x04لآ\x04لأ\x04لإ\x04لا\x01\x22\x01'\x01/\x01^\x01|\x01~\x02¢" + "\x02£\x02¬\x02¦\x02¥\x08𝅗𝅥\x08𝅘𝅥\x0c𝅘𝅥𝅮\x0c𝅘𝅥𝅯\x0c𝅘𝅥𝅰\x0c𝅘𝅥𝅱\x0c𝅘𝅥𝅲\x08𝆹" + "𝅥\x08𝆺𝅥\x0c𝆹𝅥𝅮\x0c𝆺𝅥𝅮\x0c𝆹𝅥𝅯\x0c𝆺𝅥𝅯\x02ı\x02ȷ\x02α\x02ε\x02ζ\x02η\x02" + "κ\x02λ\x02μ\x02ν\x02ξ\x02ο\x02σ\x02τ\x02υ\x02ψ\x03∇\x03∂\x02ϝ\x02ٮ\x02ڡ" + "\x02ٯ\x020,\x021,\x022,\x023,\x024,\x025,\x026,\x027,\x028,\x029,\x03(a)" + "\x03(b)\x03(c)\x03(d)\x03(e)\x03(f)\x03(g)\x03(h)\x03(i)\x03(j)\x03(k)" + "\x03(l)\x03(m)\x03(n)\x03(o)\x03(p)\x03(q)\x03(r)\x03(s)\x03(t)\x03(u)" + "\x03(v)\x03(w)\x03(x)\x03(y)\x03(z)\x07〔s〕\x02wz\x02hv\x02sd\x03ppv\x02w" + "c\x02mc\x02md\x02dj\x06ほか\x06ココ\x03サ\x03手\x03字\x03双\x03デ\x03二\x03多\x03解" + "\x03天\x03交\x03映\x03無\x03料\x03前\x03後\x03再\x03新\x03初\x03終\x03生\x03販\x03声" + "\x03吹\x03演\x03投\x03捕\x03一\x03三\x03遊\x03左\x03中\x03右\x03指\x03走\x03打\x03禁" + "\x03空\x03合\x03満\x03有\x03月\x03申\x03割\x03営\x03配\x09〔本〕\x09〔三〕\x09〔二〕\x09〔安" + "〕\x09〔点〕\x09〔打〕\x09〔盗〕\x09〔勝〕\x09〔敗〕\x03得\x03可\x03丽\x03丸\x03乁\x03你\x03" + "侮\x03侻\x03倂\x03偺\x03備\x03僧\x03像\x03㒞\x03免\x03兔\x03兤\x03具\x03㒹\x03內\x03" + "冗\x03冤\x03仌\x03冬\x03况\x03凵\x03刃\x03㓟\x03刻\x03剆\x03剷\x03㔕\x03勇\x03勉\x03" + "勤\x03勺\x03包\x03匆\x03北\x03卉\x03卑\x03博\x03即\x03卽\x03卿\x03灰\x03及\x03叟\x03" + "叫\x03叱\x03吆\x03咞\x03吸\x03呈\x03周\x03咢\x03哶\x03唐\x03啓\x03啣\x03善\x03喙\x03" + "喫\x03喳\x03嗂\x03圖\x03嘆\x03圗\x03噑\x03噴\x03切\x03壮\x03城\x03埴\x03堍\x03型\x03" + "堲\x03報\x03墬\x03売\x03壷\x03夆\x03夢\x03奢\x03姬\x03娛\x03娧\x03姘\x03婦\x03㛮\x03" + "嬈\x03嬾\x03寃\x03寘\x03寧\x03寳\x03寿\x03将\x03尢\x03㞁\x03屠\x03屮\x03峀\x03岍\x03" + "嵃\x03嵮\x03嵫\x03嵼\x03巡\x03巢\x03㠯\x03巽\x03帨\x03帽\x03幩\x03㡢\x03㡼\x03庰\x03" + "庳\x03庶\x03廊\x03廾\x03舁\x03弢\x03㣇\x03形\x03彫\x03㣣\x03徚\x03忍\x03志\x03忹\x03" + "悁\x03㤺\x03㤜\x03悔\x03惇\x03慈\x03慌\x03慎\x03慺\x03憎\x03憲\x03憤\x03憯\x03懞\x03" + "懲\x03懶\x03成\x03戛\x03扝\x03抱\x03拔\x03捐\x03挽\x03拼\x03捨\x03掃\x03揤\x03搢\x03" + "揅\x03掩\x03㨮\x03摩\x03摾\x03撝\x03摷\x03㩬\x03敏\x03敬\x03旣\x03書\x03晉\x03㬙\x03" + "暑\x03㬈\x03㫤\x03冒\x03冕\x03最\x03暜\x03肭\x03䏙\x03朗\x03望\x03朡\x03杞\x03杓\x03" + "㭉\x03柺\x03枅\x03桒\x03梅\x03梎\x03栟\x03椔\x03㮝\x03楂\x03榣\x03槪\x03檨\x03櫛\x03" + "㰘\x03次\x03歔\x03㱎\x03歲\x03殟\x03殺\x03殻\x03汎\x03沿\x03泍\x03汧\x03洖\x03派\x03" + "海\x03流\x03浩\x03浸\x03涅\x03洴\x03港\x03湮\x03㴳\x03滋\x03滇\x03淹\x03潮\x03濆\x03" + "瀹\x03瀞\x03瀛\x03㶖\x03灊\x03災\x03灷\x03炭\x03煅\x03熜\x03爨\x03爵\x03牐\x03犀\x03" + "犕\x03獺\x03王\x03㺬\x03玥\x03㺸\x03瑇\x03瑜\x03瑱\x03璅\x03瓊\x03㼛\x03甤\x03甾\x03" + "異\x03瘐\x03㿼\x03䀈\x03直\x03眞\x03真\x03睊\x03䀹\x03瞋\x03䁆\x03䂖\x03硎\x03碌\x03" + "磌\x03䃣\x03祖\x03福\x03秫\x03䄯\x03穀\x03穊\x03穏\x03䈂\x03篆\x03築\x03䈧\x03糒\x03" + "䊠\x03糨\x03糣\x03紀\x03絣\x03䌁\x03緇\x03縂\x03繅\x03䌴\x03䍙\x03罺\x03羕\x03翺\x03" + "者\x03聠\x03聰\x03䏕\x03育\x03脃\x03䐋\x03脾\x03媵\x03舄\x03辞\x03䑫\x03芑\x03芋\x03" + "芝\x03劳\x03花\x03芳\x03芽\x03苦\x03若\x03茝\x03荣\x03莭\x03茣\x03莽\x03菧\x03著\x03" + "荓\x03菊\x03菌\x03菜\x03䔫\x03蓱\x03蓳\x03蔖\x03蕤\x03䕝\x03䕡\x03䕫\x03虐\x03虜\x03" + "虧\x03虩\x03蚩\x03蚈\x03蜎\x03蛢\x03蝹\x03蜨\x03蝫\x03螆\x03蟡\x03蠁\x03䗹\x03衠\x03" + "衣\x03裗\x03裞\x03䘵\x03裺\x03㒻\x03䚾\x03䛇\x03誠\x03諭\x03變\x03豕\x03貫\x03賁\x03" + "贛\x03起\x03跋\x03趼\x03跰\x03軔\x03輸\x03邔\x03郱\x03鄑\x03鄛\x03鈸\x03鋗\x03鋘\x03" + "鉼\x03鏹\x03鐕\x03開\x03䦕\x03閷\x03䧦\x03雃\x03嶲\x03霣\x03䩮\x03䩶\x03韠\x03䪲\x03" + "頋\x03頩\x03飢\x03䬳\x03餩\x03馧\x03駂\x03駾\x03䯎\x03鬒\x03鱀\x03鳽\x03䳎\x03䳭\x03" + "鵧\x03䳸\x03麻\x03䵖\x03黹\x03黾\x03鼅\x03鼏\x03鼖\x03鼻" var xorData string = "" + // Size: 4855 bytes "\x02\x0c\x09\x02\xb0\xec\x02\xad\xd8\x02\xad\xd9\x02\x06\x07\x02\x0f\x12" + "\x02\x0f\x1f\x02\x0f\x1d\x02\x01\x13\x02\x0f\x16\x02\x0f\x0b\x02\x0f3" + "\x02\x0f7\x02\x0f?\x02\x0f/\x02\x0f*\x02\x0c&\x02\x0c*\x02\x0c;\x02\x0c9" + "\x02\x0c%\x02\xab\xed\x02\xab\xe2\x02\xab\xe3\x02\xa9\xe0\x02\xa9\xe1" + "\x02\xa9\xe6\x02\xa3\xcb\x02\xa3\xc8\x02\xa3\xc9\x02\x01#\x02\x01\x08" + "\x02\x0e>\x02\x0e'\x02\x0f\x03\x02\x03\x0d\x02\x03\x09\x02\x03\x17\x02" + "\x03\x0e\x02\x02\x03\x02\x011\x02\x01\x00\x02\x01\x10\x02\x03<\x02\x07" + "\x0d\x02\x02\x0c\x02\x0c0\x02\x01\x03\x02\x01\x01\x02\x01 \x02\x01\x22" + "\x02\x01)\x02\x01\x0a\x02\x01\x0c\x02\x02\x06\x02\x02\x02\x02\x03\x10" + "\x03\x037 \x03\x0b+\x03\x02\x01\x04\x02\x01\x02\x02\x019\x02\x03\x1c\x02" + "\x02$\x03\x80p$\x02\x03:\x02\x03\x0a\x03\xc1r.\x03\xc1r,\x03\xc1r\x02" + "\x02\x02:\x02\x02>\x02\x02,\x02\x02\x10\x02\x02\x00\x03\xc1s<\x03\xc1s*" + "\x03\xc2L$\x03\xc2L;\x02\x09)\x02\x0a\x19\x03\x83\xab\xe3\x03\x83\xab" + "\xf2\x03 4\xe0\x03\x81\xab\xea\x03\x81\xab\xf3\x03 4\xef\x03\x96\xe1\xcd" + "\x03\x84\xe5\xc3\x02\x0d\x11\x03\x8b\xec\xcb\x03\x94\xec\xcf\x03\x9a\xec" + "\xc2\x03\x8b\xec\xdb\x03\x94\xec\xdf\x03\x9a\xec\xd2\x03\x01\x0c!\x03" + "\x01\x0c#\x03ʠ\x9d\x03ʣ\x9c\x03ʢ\x9f\x03ʥ\x9e\x03ʤ\x91\x03ʧ\x90\x03ʦ\x93" + "\x03ʩ\x92\x03ʨ\x95\x03\xca\xf3\xb5\x03\xca\xf0\xb4\x03\xca\xf1\xb7\x03" + "\xca\xf6\xb6\x03\xca\xf7\x89\x03\xca\xf4\x88\x03\xca\xf5\x8b\x03\xca\xfa" + "\x8a\x03\xca\xfb\x8d\x03\xca\xf8\x8c\x03\xca\xf9\x8f\x03\xca\xfe\x8e\x03" + "\xca\xff\x81\x03\xca\xfc\x80\x03\xca\xfd\x83\x03\xca\xe2\x82\x03\xca\xe3" + "\x85\x03\xca\xe0\x84\x03\xca\xe1\x87\x03\xca\xe6\x86\x03\xca\xe7\x99\x03" + "\xca\xe4\x98\x03\xca\xe5\x9b\x03\xca\xea\x9a\x03\xca\xeb\x9d\x03\xca\xe8" + "\x9c\x03ؓ\x89\x03ߔ\x8b\x02\x010\x03\x03\x04\x1e\x03\x04\x15\x12\x03\x0b" + "\x05,\x03\x06\x04\x00\x03\x06\x04)\x03\x06\x044\x03\x06\x04<\x03\x06\x05" + "\x1d\x03\x06\x06\x00\x03\x06\x06\x0a\x03\x06\x06'\x03\x06\x062\x03\x0786" + "\x03\x079/\x03\x079 \x03\x07:\x0e\x03\x07:\x1b\x03\x07:%\x03\x07;/\x03" + "\x07;%\x03\x074\x11\x03\x076\x09\x03\x077*\x03\x070\x01\x03\x070\x0f\x03" + "\x070.\x03\x071\x16\x03\x071\x04\x03\x0710\x03\x072\x18\x03\x072-\x03" + "\x073\x14\x03\x073>\x03\x07'\x09\x03\x07 \x00\x03\x07\x1f\x0b\x03\x07" + "\x18#\x03\x07\x18(\x03\x07\x186\x03\x07\x18\x03\x03\x07\x19\x16\x03\x07" + "\x116\x03\x07\x12'\x03\x07\x13\x10\x03\x07\x0c&\x03\x07\x0c\x08\x03\x07" + "\x0c\x13\x03\x07\x0d\x02\x03\x07\x0d\x1c\x03\x07\x0b5\x03\x07\x0b\x0a" + "\x03\x07\x0b\x01\x03\x07\x0b\x0f\x03\x07\x05\x00\x03\x07\x05\x09\x03\x07" + "\x05\x0b\x03\x07\x07\x01\x03\x07\x07\x08\x03\x07\x00<\x03\x07\x00+\x03" + "\x07\x01)\x03\x07\x01\x1b\x03\x07\x01\x08\x03\x07\x03?\x03\x0445\x03\x04" + "4\x08\x03\x0454\x03\x04)/\x03\x04)5\x03\x04+\x05\x03\x04+\x14\x03\x04+ " + "\x03\x04+<\x03\x04*&\x03\x04*\x22\x03\x04&8\x03\x04!\x01\x03\x04!\x22" + "\x03\x04\x11+\x03\x04\x10.\x03\x04\x104\x03\x04\x13=\x03\x04\x12\x04\x03" + "\x04\x12\x0a\x03\x04\x0d\x1d\x03\x04\x0d\x07\x03\x04\x0d \x03\x05<>\x03" + "\x055<\x03\x055!\x03\x055#\x03\x055&\x03\x054\x1d\x03\x054\x02\x03\x054" + "\x07\x03\x0571\x03\x053\x1a\x03\x053\x16\x03\x05.<\x03\x05.\x07\x03\x05)" + ":\x03\x05)<\x03\x05)\x0c\x03\x05)\x15\x03\x05+-\x03\x05+5\x03\x05$\x1e" + "\x03\x05$\x14\x03\x05'\x04\x03\x05'\x14\x03\x05&\x02\x03\x05\x226\x03" + "\x05\x22\x0c\x03\x05\x22\x1c\x03\x05\x19\x0a\x03\x05\x1b\x09\x03\x05\x1b" + "\x0c\x03\x05\x14\x07\x03\x05\x16?\x03\x05\x16\x0c\x03\x05\x0c\x05\x03" + "\x05\x0e\x0f\x03\x05\x01\x0e\x03\x05\x00(\x03\x05\x030\x03\x05\x03\x06" + "\x03\x0a==\x03\x0a=1\x03\x0a=,\x03\x0a=\x0c\x03\x0a??\x03\x0a<\x08\x03" + "\x0a9!\x03\x0a9)\x03\x0a97\x03\x0a99\x03\x0a6\x0a\x03\x0a6\x1c\x03\x0a6" + "\x17\x03\x0a7'\x03\x0a78\x03\x0a73\x03\x0a'\x01\x03\x0a'&\x03\x0a\x1f" + "\x0e\x03\x0a\x1f\x03\x03\x0a\x1f3\x03\x0a\x1b/\x03\x0a\x18\x19\x03\x0a" + "\x19\x01\x03\x0a\x16\x14\x03\x0a\x0e\x22\x03\x0a\x0f\x10\x03\x0a\x0f\x02" + "\x03\x0a\x0f \x03\x0a\x0c\x04\x03\x0a\x0b>\x03\x0a\x0b+\x03\x0a\x08/\x03" + "\x0a\x046\x03\x0a\x05\x14\x03\x0a\x00\x04\x03\x0a\x00\x10\x03\x0a\x00" + "\x14\x03\x0b<3\x03\x0b;*\x03\x0b9\x22\x03\x0b9)\x03\x0b97\x03\x0b+\x10" + "\x03\x0b((\x03\x0b&5\x03\x0b$\x1c\x03\x0b$\x12\x03\x0b%\x04\x03\x0b#<" + "\x03\x0b#0\x03\x0b#\x0d\x03\x0b#\x19\x03\x0b!:\x03\x0b!\x1f\x03\x0b!\x00" + "\x03\x0b\x1e5\x03\x0b\x1c\x1d\x03\x0b\x1d-\x03\x0b\x1d(\x03\x0b\x18.\x03" + "\x0b\x18 \x03\x0b\x18\x16\x03\x0b\x14\x13\x03\x0b\x15$\x03\x0b\x15\x22" + "\x03\x0b\x12\x1b\x03\x0b\x12\x10\x03\x0b\x132\x03\x0b\x13=\x03\x0b\x12" + "\x18\x03\x0b\x0c&\x03\x0b\x061\x03\x0b\x06:\x03\x0b\x05#\x03\x0b\x05<" + "\x03\x0b\x04\x0b\x03\x0b\x04\x04\x03\x0b\x04\x1b\x03\x0b\x042\x03\x0b" + "\x041\x03\x0b\x03\x03\x03\x0b\x03\x1d\x03\x0b\x03/\x03\x0b\x03+\x03\x0b" + "\x02\x1b\x03\x0b\x02\x00\x03\x0b\x01\x1e\x03\x0b\x01\x08\x03\x0b\x015" + "\x03\x06\x0d9\x03\x06\x0d=\x03\x06\x0d?\x03\x02\x001\x03\x02\x003\x03" + "\x02\x02\x19\x03\x02\x006\x03\x02\x02\x1b\x03\x02\x004\x03\x02\x00<\x03" + "\x02\x02\x0a\x03\x02\x02\x0e\x03\x02\x01\x1a\x03\x02\x01\x07\x03\x02\x01" + "\x05\x03\x02\x01\x0b\x03\x02\x01%\x03\x02\x01\x0c\x03\x02\x01\x04\x03" + "\x02\x01\x1c\x03\x02\x00.\x03\x02\x002\x03\x02\x00>\x03\x02\x00\x12\x03" + "\x02\x00\x16\x03\x02\x011\x03\x02\x013\x03\x02\x02 \x03\x02\x02%\x03\x02" + "\x02$\x03\x02\x028\x03\x02\x02;\x03\x02\x024\x03\x02\x012\x03\x02\x022" + "\x03\x02\x02/\x03\x02\x01,\x03\x02\x01\x13\x03\x02\x01\x16\x03\x02\x01" + "\x11\x03\x02\x01\x1e\x03\x02\x01\x15\x03\x02\x01\x17\x03\x02\x01\x0f\x03" + "\x02\x01\x08\x03\x02\x00?\x03\x02\x03\x07\x03\x02\x03\x0d\x03\x02\x03" + "\x13\x03\x02\x03\x1d\x03\x02\x03\x1f\x03\x02\x00\x03\x03\x02\x00\x0d\x03" + "\x02\x00\x01\x03\x02\x00\x1b\x03\x02\x00\x19\x03\x02\x00\x18\x03\x02\x00" + "\x13\x03\x02\x00/\x03\x07>\x12\x03\x07<\x1f\x03\x07>\x1d\x03\x06\x1d\x0e" + "\x03\x07>\x1c\x03\x07>:\x03\x07>\x13\x03\x04\x12+\x03\x07?\x03\x03\x07>" + "\x02\x03\x06\x224\x03\x06\x1a.\x03\x07<%\x03\x06\x1c\x0b\x03\x0609\x03" + "\x05\x1f\x01\x03\x04'\x08\x03\x93\xfd\xf5\x03\x02\x0d \x03\x02\x0d#\x03" + "\x02\x0d!\x03\x02\x0d&\x03\x02\x0d\x22\x03\x02\x0d/\x03\x02\x0d,\x03\x02" + "\x0d$\x03\x02\x0d'\x03\x02\x0d%\x03\x02\x0d;\x03\x02\x0d=\x03\x02\x0d?" + "\x03\x099.\x03\x08\x0b7\x03\x08\x02\x14\x03\x08\x14\x0d\x03\x08.:\x03" + "\x089'\x03\x0f\x0b\x18\x03\x0f\x1c1\x03\x0f\x17&\x03\x0f9\x1f\x03\x0f0" + "\x0c\x03\x0e\x0a9\x03\x0e\x056\x03\x0e\x1c#\x03\x0f\x13\x0e\x03\x072\x00" + "\x03\x070\x0d\x03\x072\x0b\x03\x06\x11\x18\x03\x070\x10\x03\x06\x0f(\x03" + "\x072\x05\x03\x06\x0f,\x03\x073\x15\x03\x06\x07\x08\x03\x05\x16\x02\x03" + "\x04\x0b \x03\x05:8\x03\x05\x16%\x03\x0a\x0d\x1f\x03\x06\x16\x10\x03\x05" + "\x1d5\x03\x05*;\x03\x05\x16\x1b\x03\x04.-\x03\x06\x1a\x19\x03\x04\x03," + "\x03\x0b87\x03\x04/\x0a\x03\x06\x00,\x03\x04-\x01\x03\x04\x1e-\x03\x06/(" + "\x03\x0a\x0b5\x03\x06\x0e7\x03\x06\x07.\x03\x0597\x03\x0a*%\x03\x0760" + "\x03\x06\x0c;\x03\x05'\x00\x03\x072.\x03\x072\x08\x03\x06=\x01\x03\x06" + "\x05\x1b\x03\x06\x06\x12\x03\x06$=\x03\x06'\x0d\x03\x04\x11\x0f\x03\x076" + ",\x03\x06\x07;\x03\x06.,\x03\x86\xf9\xea\x03\x8f\xff\xeb\x02\x092\x02" + "\x095\x02\x094\x02\x09;\x02\x09>\x02\x098\x02\x09*\x02\x09/\x02\x09,\x02" + "\x09%\x02\x09&\x02\x09#\x02\x09 \x02\x08!\x02\x08%\x02\x08$\x02\x08+\x02" + "\x08.\x02\x08*\x02\x08&\x02\x088\x02\x08>\x02\x084\x02\x086\x02\x080\x02" + "\x08\x10\x02\x08\x17\x02\x08\x12\x02\x08\x1d\x02\x08\x1f\x02\x08\x13\x02" + "\x08\x15\x02\x08\x14\x02\x08\x0c\x03\x8b\xfd\xd0\x03\x81\xec\xc6\x03\x87" + "\xe0\x8a\x03-2\xe3\x03\x80\xef\xe4\x03-2\xea\x03\x88\xe6\xeb\x03\x8e\xe6" + "\xe8\x03\x84\xe6\xe9\x03\x97\xe6\xee\x03-2\xf9\x03-2\xf6\x03\x8e\xe3\xad" + "\x03\x80\xe3\x92\x03\x88\xe3\x90\x03\x8e\xe3\x90\x03\x80\xe3\x97\x03\x88" + "\xe3\x95\x03\x88\xfe\xcb\x03\x8e\xfe\xca\x03\x84\xfe\xcd\x03\x91\xef\xc9" + "\x03-2\xc1\x03-2\xc0\x03-2\xcb\x03\x88@\x09\x03\x8e@\x08\x03\x8f\xe0\xf5" + "\x03\x8e\xe6\xf9\x03\x8e\xe0\xfa\x03\x93\xff\xf4\x03\x84\xee\xd3\x03\x0b" + "(\x04\x023 \x021;\x02\x01*\x03\x0b#\x10\x03\x0b 0\x03\x0b!\x10\x03\x0b!0" + "\x03\x07\x15\x08\x03\x09?5\x03\x07\x1f\x08\x03\x07\x17\x0b\x03\x09\x1f" + "\x15\x03\x0b\x1c7\x03\x0a+#\x03\x06\x1a\x1b\x03\x06\x1a\x14\x03\x0a\x01" + "\x18\x03\x06#\x1b\x03\x0a2\x0c\x03\x0a\x01\x04\x03\x09#;\x03\x08='\x03" + "\x08\x1a\x0a\x03\x07\x03\x0a\x111\x03\x09\x1b\x09\x03\x073.\x03\x07\x01\x00" + "\x03\x09/,\x03\x07#>\x03\x07\x048\x03\x0a\x1f\x22\x03\x098>\x03\x09\x11" + "\x00\x03\x08/\x17\x03\x06'\x22\x03\x0b\x1a+\x03\x0a\x22\x19\x03\x0a/1" + "\x03\x0974\x03\x09\x0f\x22\x03\x08,\x22\x03\x08?\x14\x03\x07$5\x03\x07<3" + "\x03\x07=*\x03\x07\x13\x18\x03\x068\x0a\x03\x06\x09\x16\x03\x06\x13\x00" + "\x03\x08\x067\x03\x08\x01\x03\x03\x08\x12\x1d\x03\x07+7\x03\x06(;\x03" + "\x06\x1c?\x03\x07\x0e\x17\x03\x0a\x06\x1d\x03\x0a\x19\x07\x03\x08\x14$" + "\x03\x07$;\x03\x08,$\x03\x08\x06\x0d\x03\x07\x16\x0a\x03\x06>>\x03\x0a" + "\x06\x12\x03\x0a\x14)\x03\x09\x0d\x1f\x03\x09\x12\x17\x03\x09\x19\x01" + "\x03\x08\x11 \x03\x08\x1d'\x03\x06<\x1a\x03\x0a.\x00\x03\x07'\x18\x03" + "\x0a\x22\x08\x03\x08\x0d\x0a\x03\x08\x13)\x03\x07*)\x03\x06<,\x03\x07" + "\x0b\x1a\x03\x09.\x14\x03\x09\x0d\x1e\x03\x07\x0e#\x03\x0b\x1d'\x03\x0a" + "\x0a8\x03\x09%2\x03\x08+&\x03\x080\x12\x03\x0a)4\x03\x08\x06\x1f\x03\x0b" + "\x1b\x1a\x03\x0a\x1b\x0f\x03\x0b\x1d*\x03\x09\x16$\x03\x090\x11\x03\x08" + "\x11\x08\x03\x0a*(\x03\x0a\x042\x03\x089,\x03\x074'\x03\x07\x0f\x05\x03" + "\x09\x0b\x0a\x03\x07\x1b\x01\x03\x09\x17:\x03\x09.\x0d\x03\x07.\x11\x03" + "\x09+\x15\x03\x080\x13\x03\x0b\x1f\x19\x03\x0a \x11\x03\x0a\x220\x03\x09" + "\x07;\x03\x08\x16\x1c\x03\x07,\x13\x03\x07\x0e/\x03\x06\x221\x03\x0a." + "\x0a\x03\x0a7\x02\x03\x0a\x032\x03\x0a\x1d.\x03\x091\x06\x03\x09\x19:" + "\x03\x08\x02/\x03\x060+\x03\x06\x0f-\x03\x06\x1c\x1f\x03\x06\x1d\x07\x03" + "\x0a,\x11\x03\x09=\x0d\x03\x09\x0b;\x03\x07\x1b/\x03\x0a\x1f:\x03\x09 " + "\x1f\x03\x09.\x10\x03\x094\x0b\x03\x09\x1a1\x03\x08#\x1a\x03\x084\x1d" + "\x03\x08\x01\x1f\x03\x08\x11\x22\x03\x07'8\x03\x07\x1a>\x03\x0757\x03" + "\x06&9\x03\x06+\x11\x03\x0a.\x0b\x03\x0a,>\x03\x0a4#\x03\x08%\x17\x03" + "\x07\x05\x22\x03\x07\x0c\x0b\x03\x0a\x1d+\x03\x0a\x19\x16\x03\x09+\x1f" + "\x03\x09\x08\x0b\x03\x08\x16\x18\x03\x08+\x12\x03\x0b\x1d\x0c\x03\x0a=" + "\x10\x03\x0a\x09\x0d\x03\x0a\x10\x11\x03\x09&0\x03\x08(\x1f\x03\x087\x07" + "\x03\x08\x185\x03\x07'6\x03\x06.\x05\x03\x06=\x04\x03\x06;;\x03\x06\x06," + "\x03\x0b\x18>\x03\x08\x00\x18\x03\x06 \x03\x03\x06<\x00\x03\x09%\x18\x03" + "\x0b\x1c<\x03\x0a%!\x03\x0a\x09\x12\x03\x0a\x16\x02\x03\x090'\x03\x09" + "\x0e=\x03\x08 \x0e\x03\x08>\x03\x03\x074>\x03\x06&?\x03\x06\x19\x09\x03" + "\x06?(\x03\x0a-\x0e\x03\x09:3\x03\x098:\x03\x09\x12\x0b\x03\x09\x1d\x17" + "\x03\x087\x05\x03\x082\x14\x03\x08\x06%\x03\x08\x13\x1f\x03\x06\x06\x0e" + "\x03\x0a\x22<\x03\x09/<\x03\x06>+\x03\x0a'?\x03\x0a\x13\x0c\x03\x09\x10<" + "\x03\x07\x1b=\x03\x0a\x19\x13\x03\x09\x22\x1d\x03\x09\x07\x0d\x03\x08)" + "\x1c\x03\x06=\x1a\x03\x0a/4\x03\x0a7\x11\x03\x0a\x16:\x03\x09?3\x03\x09:" + "/\x03\x09\x05\x0a\x03\x09\x14\x06\x03\x087\x22\x03\x080\x07\x03\x08\x1a" + "\x1f\x03\x07\x04(\x03\x07\x04\x09\x03\x06 %\x03\x06<\x08\x03\x0a+\x14" + "\x03\x09\x1d\x16\x03\x0a70\x03\x08 >\x03\x0857\x03\x070\x0a\x03\x06=\x12" + "\x03\x06\x16%\x03\x06\x1d,\x03\x099#\x03\x09\x10>\x03\x07 \x1e\x03\x08" + "\x0c<\x03\x08\x0b\x18\x03\x08\x15+\x03\x08,:\x03\x08%\x22\x03\x07\x0a$" + "\x03\x0b\x1c=\x03\x07+\x08\x03\x0a/\x05\x03\x0a \x07\x03\x0a\x12'\x03" + "\x09#\x11\x03\x08\x1b\x15\x03\x0a\x06\x01\x03\x09\x1c\x1b\x03\x0922\x03" + "\x07\x14<\x03\x07\x09\x04\x03\x061\x04\x03\x07\x0e\x01\x03\x0a\x13\x18" + "\x03\x0a-\x0c\x03\x0a?\x0d\x03\x0a\x09\x0a\x03\x091&\x03\x0a/\x0b\x03" + "\x08$<\x03\x083\x1d\x03\x08\x0c$\x03\x08\x0d\x07\x03\x08\x0d?\x03\x08" + "\x0e\x14\x03\x065\x0a\x03\x08\x1a#\x03\x08\x16#\x03\x0702\x03\x07\x03" + "\x1a\x03\x06(\x1d\x03\x06+\x1b\x03\x06\x0b\x05\x03\x06\x0b\x17\x03\x06" + "\x0c\x04\x03\x06\x1e\x19\x03\x06+0\x03\x062\x18\x03\x0b\x16\x1e\x03\x0a+" + "\x16\x03\x0a-?\x03\x0a#:\x03\x0a#\x10\x03\x0a%$\x03\x0a>+\x03\x0a01\x03" + "\x0a1\x10\x03\x0a\x099\x03\x0a\x0a\x12\x03\x0a\x19\x1f\x03\x0a\x19\x12" + "\x03\x09*)\x03\x09-\x16\x03\x09.1\x03\x09.2\x03\x09<\x0e\x03\x09> \x03" + "\x093\x12\x03\x09\x0b\x01\x03\x09\x1c2\x03\x09\x11\x1c\x03\x09\x15%\x03" + "\x08,&\x03\x08!\x22\x03\x089(\x03\x08\x0b\x1a\x03\x08\x0d2\x03\x08\x0c" + "\x04\x03\x08\x0c\x06\x03\x08\x0c\x1f\x03\x08\x0c\x0c\x03\x08\x0f\x1f\x03" + "\x08\x0f\x1d\x03\x08\x00\x14\x03\x08\x03\x14\x03\x08\x06\x16\x03\x08\x1e" + "#\x03\x08\x11\x11\x03\x08\x10\x18\x03\x08\x14(\x03\x07)\x1e\x03\x07.1" + "\x03\x07 $\x03\x07 '\x03\x078\x08\x03\x07\x0d0\x03\x07\x0f7\x03\x07\x05#" + "\x03\x07\x05\x1a\x03\x07\x1a7\x03\x07\x1d-\x03\x07\x17\x10\x03\x06)\x1f" + "\x03\x062\x0b\x03\x066\x16\x03\x06\x09\x11\x03\x09(\x1e\x03\x07!5\x03" + "\x0b\x11\x16\x03\x0a/\x04\x03\x0a,\x1a\x03\x0b\x173\x03\x0a,1\x03\x0a/5" + "\x03\x0a\x221\x03\x0a\x22\x0d\x03\x0a?%\x03\x0a<,\x03\x0a?#\x03\x0a>\x19" + "\x03\x0a\x08&\x03\x0a\x0b\x0e\x03\x0a\x0c:\x03\x0a\x0c+\x03\x0a\x03\x22" + "\x03\x0a\x06)\x03\x0a\x11\x10\x03\x0a\x11\x1a\x03\x0a\x17-\x03\x0a\x14(" + "\x03\x09)\x1e\x03\x09/\x09\x03\x09.\x00\x03\x09,\x07\x03\x09/*\x03\x09-9" + "\x03\x09\x228\x03\x09%\x09\x03\x09:\x12\x03\x09;\x1d\x03\x09?\x06\x03" + "\x093%\x03\x096\x05\x03\x096\x08\x03\x097\x02\x03\x09\x07,\x03\x09\x04," + "\x03\x09\x1f\x16\x03\x09\x11\x03\x03\x09\x11\x12\x03\x09\x168\x03\x08*" + "\x05\x03\x08/2\x03\x084:\x03\x08\x22+\x03\x08 0\x03\x08&\x0a\x03\x08;" + "\x10\x03\x08>$\x03\x08>\x18\x03\x0829\x03\x082:\x03\x081,\x03\x081<\x03" + "\x081\x1c\x03\x087#\x03\x087*\x03\x08\x09'\x03\x08\x00\x1d\x03\x08\x05-" + "\x03\x08\x1f4\x03\x08\x1d\x04\x03\x08\x16\x0f\x03\x07*7\x03\x07'!\x03" + "\x07%\x1b\x03\x077\x0c\x03\x07\x0c1\x03\x07\x0c.\x03\x07\x00\x06\x03\x07" + "\x01\x02\x03\x07\x010\x03\x07\x06=\x03\x07\x01\x03\x03\x07\x01\x13\x03" + "\x07\x06\x06\x03\x07\x05\x0a\x03\x07\x1f\x09\x03\x07\x17:\x03\x06*1\x03" + "\x06-\x1d\x03\x06\x223\x03\x062:\x03\x060$\x03\x066\x1e\x03\x064\x12\x03" + "\x0645\x03\x06\x0b\x00\x03\x06\x0b7\x03\x06\x07\x1f\x03\x06\x15\x12\x03" + "\x0c\x05\x0f\x03\x0b+\x0b\x03\x0b+-\x03\x06\x16\x1b\x03\x06\x15\x17\x03" + "\x89\xca\xea\x03\x89\xca\xe8\x03\x0c8\x10\x03\x0c8\x01\x03\x0c8\x0f\x03" + "\x0d8%\x03\x0d8!\x03\x0c8-\x03\x0c8/\x03\x0c8+\x03\x0c87\x03\x0c85\x03" + "\x0c9\x09\x03\x0c9\x0d\x03\x0c9\x0f\x03\x0c9\x0b\x03\xcfu\x0c\x03\xcfu" + "\x0f\x03\xcfu\x0e\x03\xcfu\x09\x03\x0c9\x10\x03\x0d9\x0c\x03\xcf`;\x03" + "\xcf`>\x03\xcf`9\x03\xcf`8\x03\xcf`7\x03\xcf`*\x03\xcf`-\x03\xcf`,\x03" + "\x0d\x1b\x1a\x03\x0d\x1b&\x03\x0c=.\x03\x0c=%\x03\x0c>\x1e\x03\x0c>\x14" + "\x03\x0c?\x06\x03\x0c?\x0b\x03\x0c?\x0c\x03\x0c?\x0d\x03\x0c?\x02\x03" + "\x0c>\x0f\x03\x0c>\x08\x03\x0c>\x09\x03\x0c>,\x03\x0c>\x0c\x03\x0c?\x13" + "\x03\x0c?\x16\x03\x0c?\x15\x03\x0c?\x1c\x03\x0c?\x1f\x03\x0c?\x1d\x03" + "\x0c?\x1a\x03\x0c?\x17\x03\x0c?\x08\x03\x0c?\x09\x03\x0c?\x0e\x03\x0c?" + "\x04\x03\x0c?\x05\x03\x0c" + "\x03\x0c=2\x03\x0c=6\x03\x0c<\x07\x03\x0c<\x05\x03\x0e:!\x03\x0e:#\x03" + "\x0e8\x09\x03\x0e:&\x03\x0e8\x0b\x03\x0e:$\x03\x0e:,\x03\x0e8\x1a\x03" + "\x0e8\x1e\x03\x0e:*\x03\x0e:7\x03\x0e:5\x03\x0e:;\x03\x0e:\x15\x03\x0e:<" + "\x03\x0e:4\x03\x0e:'\x03\x0e:-\x03\x0e:%\x03\x0e:?\x03\x0e:=\x03\x0e:)" + "\x03\x0e:/\x03\xcfs'\x03\x0d=\x0f\x03\x0d+*\x03\x0d99\x03\x0d9;\x03\x0d9" + "?\x03\x0d)\x0d\x03\x0d(%\x02\x01\x18\x02\x01(\x02\x01\x1e\x03\x0f$!\x03" + "\x0f87\x03\x0f4\x0e\x03\x0f5\x1d\x03\x06'\x03\x03\x0f\x08\x18\x03\x0f" + "\x0d\x1b\x03\x0e2=\x03\x0e;\x08\x03\x0e:\x0b\x03\x0e\x06$\x03\x0e\x0d)" + "\x03\x0e\x16\x1f\x03\x0e\x16\x1b\x03\x0d$\x0a\x03\x05,\x1d\x03\x0d. \x03" + "\x0d.#\x03\x0c(/\x03\x09%\x02\x03\x0d90\x03\x0d\x0e4\x03\x0d\x0d\x0f\x03" + "\x0c#\x00\x03\x0c,\x1e\x03\x0c2\x0e\x03\x0c\x01\x17\x03\x0c\x09:\x03\x0e" + "\x173\x03\x0c\x08\x03\x03\x0c\x11\x07\x03\x0c\x10\x18\x03\x0c\x1f\x1c" + "\x03\x0c\x19\x0e\x03\x0c\x1a\x1f\x03\x0f0>\x03\x0b->\x03\x0b<+\x03\x0b8" + "\x13\x03\x0b\x043\x03\x0b\x14\x03\x03\x0b\x16%\x03\x0d\x22&\x03\x0b\x1a" + "\x1a\x03\x0b\x1a\x04\x03\x0a%9\x03\x0a&2\x03\x0a&0\x03\x0a!\x1a\x03\x0a!" + "7\x03\x0a5\x10\x03\x0a=4\x03\x0a?\x0e\x03\x0a>\x10\x03\x0a\x00 \x03\x0a" + "\x0f:\x03\x0a\x0f9\x03\x0a\x0b\x0a\x03\x0a\x17%\x03\x0a\x1b-\x03\x09-" + "\x1a\x03\x09,4\x03\x09.,\x03\x09)\x09\x03\x096!\x03\x091\x1f\x03\x093" + "\x16\x03\x0c+\x1f\x03\x098 \x03\x098=\x03\x0c(\x1a\x03\x0c(\x16\x03\x09" + "\x0a+\x03\x09\x16\x12\x03\x09\x13\x0e\x03\x09\x153\x03\x08)!\x03\x09\x1a" + "\x01\x03\x09\x18\x01\x03\x08%#\x03\x08>\x22\x03\x08\x05%\x03\x08\x02*" + "\x03\x08\x15;\x03\x08\x1b7\x03\x0f\x07\x1d\x03\x0f\x04\x03\x03\x070\x0c" + "\x03\x07;\x0b\x03\x07\x08\x17\x03\x07\x12\x06\x03\x06/-\x03\x0671\x03" + "\x065+\x03\x06>7\x03\x06\x049\x03\x05+\x1e\x03\x05,\x17\x03\x05 \x1d\x03" + "\x05\x22\x05\x03\x050\x1d" // lookup returns the trie value for the first UTF-8 encoding in s and // the width in bytes of this encoding. The size will be 0 if s does not // hold enough bytes to complete the encoding. len(s) must be greater than 0. func (t *idnaTrie) lookup(s []byte) (v uint16, sz int) { c0 := s[0] switch { case c0 < 0x80: // is ASCII return idnaValues[c0], 1 case c0 < 0xC2: return 0, 1 // Illegal UTF-8: not a starter, not ASCII. case c0 < 0xE0: // 2-byte UTF-8 if len(s) < 2 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c1), 2 case c0 < 0xF0: // 3-byte UTF-8 if len(s) < 3 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } o := uint32(i)<<6 + uint32(c1) i = idnaIndex[o] c2 := s[2] if c2 < 0x80 || 0xC0 <= c2 { return 0, 2 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c2), 3 case c0 < 0xF8: // 4-byte UTF-8 if len(s) < 4 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } o := uint32(i)<<6 + uint32(c1) i = idnaIndex[o] c2 := s[2] if c2 < 0x80 || 0xC0 <= c2 { return 0, 2 // Illegal UTF-8: not a continuation byte. } o = uint32(i)<<6 + uint32(c2) i = idnaIndex[o] c3 := s[3] if c3 < 0x80 || 0xC0 <= c3 { return 0, 3 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c3), 4 } // Illegal rune return 0, 1 } // lookupUnsafe returns the trie value for the first UTF-8 encoding in s. // s must start with a full and valid UTF-8 encoded rune. func (t *idnaTrie) lookupUnsafe(s []byte) uint16 { c0 := s[0] if c0 < 0x80 { // is ASCII return idnaValues[c0] } i := idnaIndex[c0] if c0 < 0xE0 { // 2-byte UTF-8 return t.lookupValue(uint32(i), s[1]) } i = idnaIndex[uint32(i)<<6+uint32(s[1])] if c0 < 0xF0 { // 3-byte UTF-8 return t.lookupValue(uint32(i), s[2]) } i = idnaIndex[uint32(i)<<6+uint32(s[2])] if c0 < 0xF8 { // 4-byte UTF-8 return t.lookupValue(uint32(i), s[3]) } return 0 } // lookupString returns the trie value for the first UTF-8 encoding in s and // the width in bytes of this encoding. The size will be 0 if s does not // hold enough bytes to complete the encoding. len(s) must be greater than 0. func (t *idnaTrie) lookupString(s string) (v uint16, sz int) { c0 := s[0] switch { case c0 < 0x80: // is ASCII return idnaValues[c0], 1 case c0 < 0xC2: return 0, 1 // Illegal UTF-8: not a starter, not ASCII. case c0 < 0xE0: // 2-byte UTF-8 if len(s) < 2 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c1), 2 case c0 < 0xF0: // 3-byte UTF-8 if len(s) < 3 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } o := uint32(i)<<6 + uint32(c1) i = idnaIndex[o] c2 := s[2] if c2 < 0x80 || 0xC0 <= c2 { return 0, 2 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c2), 3 case c0 < 0xF8: // 4-byte UTF-8 if len(s) < 4 { return 0, 0 } i := idnaIndex[c0] c1 := s[1] if c1 < 0x80 || 0xC0 <= c1 { return 0, 1 // Illegal UTF-8: not a continuation byte. } o := uint32(i)<<6 + uint32(c1) i = idnaIndex[o] c2 := s[2] if c2 < 0x80 || 0xC0 <= c2 { return 0, 2 // Illegal UTF-8: not a continuation byte. } o = uint32(i)<<6 + uint32(c2) i = idnaIndex[o] c3 := s[3] if c3 < 0x80 || 0xC0 <= c3 { return 0, 3 // Illegal UTF-8: not a continuation byte. } return t.lookupValue(uint32(i), c3), 4 } // Illegal rune return 0, 1 } // lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. // s must start with a full and valid UTF-8 encoded rune. func (t *idnaTrie) lookupStringUnsafe(s string) uint16 { c0 := s[0] if c0 < 0x80 { // is ASCII return idnaValues[c0] } i := idnaIndex[c0] if c0 < 0xE0 { // 2-byte UTF-8 return t.lookupValue(uint32(i), s[1]) } i = idnaIndex[uint32(i)<<6+uint32(s[1])] if c0 < 0xF0 { // 3-byte UTF-8 return t.lookupValue(uint32(i), s[2]) } i = idnaIndex[uint32(i)<<6+uint32(s[2])] if c0 < 0xF8 { // 4-byte UTF-8 return t.lookupValue(uint32(i), s[3]) } return 0 } // idnaTrie. Total size: 28600 bytes (27.93 KiB). Checksum: 95575047b5d8fff. type idnaTrie struct{} func newIdnaTrie(i int) *idnaTrie { return &idnaTrie{} } // lookupValue determines the type of block n and looks up the value for b. func (t *idnaTrie) lookupValue(n uint32, b byte) uint16 { switch { case n < 124: return uint16(idnaValues[n<<6+uint32(b)]) default: n -= 124 return uint16(idnaSparse.lookup(n, b)) } } // idnaValues: 126 blocks, 8064 entries, 16128 bytes // The third block is the zero block. var idnaValues = [8064]uint16{ // Block 0x0, offset 0x0 0x00: 0x0080, 0x01: 0x0080, 0x02: 0x0080, 0x03: 0x0080, 0x04: 0x0080, 0x05: 0x0080, 0x06: 0x0080, 0x07: 0x0080, 0x08: 0x0080, 0x09: 0x0080, 0x0a: 0x0080, 0x0b: 0x0080, 0x0c: 0x0080, 0x0d: 0x0080, 0x0e: 0x0080, 0x0f: 0x0080, 0x10: 0x0080, 0x11: 0x0080, 0x12: 0x0080, 0x13: 0x0080, 0x14: 0x0080, 0x15: 0x0080, 0x16: 0x0080, 0x17: 0x0080, 0x18: 0x0080, 0x19: 0x0080, 0x1a: 0x0080, 0x1b: 0x0080, 0x1c: 0x0080, 0x1d: 0x0080, 0x1e: 0x0080, 0x1f: 0x0080, 0x20: 0x0080, 0x21: 0x0080, 0x22: 0x0080, 0x23: 0x0080, 0x24: 0x0080, 0x25: 0x0080, 0x26: 0x0080, 0x27: 0x0080, 0x28: 0x0080, 0x29: 0x0080, 0x2a: 0x0080, 0x2b: 0x0080, 0x2c: 0x0080, 0x2d: 0x0008, 0x2e: 0x0008, 0x2f: 0x0080, 0x30: 0x0008, 0x31: 0x0008, 0x32: 0x0008, 0x33: 0x0008, 0x34: 0x0008, 0x35: 0x0008, 0x36: 0x0008, 0x37: 0x0008, 0x38: 0x0008, 0x39: 0x0008, 0x3a: 0x0080, 0x3b: 0x0080, 0x3c: 0x0080, 0x3d: 0x0080, 0x3e: 0x0080, 0x3f: 0x0080, // Block 0x1, offset 0x40 0x40: 0x0080, 0x41: 0xe105, 0x42: 0xe105, 0x43: 0xe105, 0x44: 0xe105, 0x45: 0xe105, 0x46: 0xe105, 0x47: 0xe105, 0x48: 0xe105, 0x49: 0xe105, 0x4a: 0xe105, 0x4b: 0xe105, 0x4c: 0xe105, 0x4d: 0xe105, 0x4e: 0xe105, 0x4f: 0xe105, 0x50: 0xe105, 0x51: 0xe105, 0x52: 0xe105, 0x53: 0xe105, 0x54: 0xe105, 0x55: 0xe105, 0x56: 0xe105, 0x57: 0xe105, 0x58: 0xe105, 0x59: 0xe105, 0x5a: 0xe105, 0x5b: 0x0080, 0x5c: 0x0080, 0x5d: 0x0080, 0x5e: 0x0080, 0x5f: 0x0080, 0x60: 0x0080, 0x61: 0x0008, 0x62: 0x0008, 0x63: 0x0008, 0x64: 0x0008, 0x65: 0x0008, 0x66: 0x0008, 0x67: 0x0008, 0x68: 0x0008, 0x69: 0x0008, 0x6a: 0x0008, 0x6b: 0x0008, 0x6c: 0x0008, 0x6d: 0x0008, 0x6e: 0x0008, 0x6f: 0x0008, 0x70: 0x0008, 0x71: 0x0008, 0x72: 0x0008, 0x73: 0x0008, 0x74: 0x0008, 0x75: 0x0008, 0x76: 0x0008, 0x77: 0x0008, 0x78: 0x0008, 0x79: 0x0008, 0x7a: 0x0008, 0x7b: 0x0080, 0x7c: 0x0080, 0x7d: 0x0080, 0x7e: 0x0080, 0x7f: 0x0080, // Block 0x2, offset 0x80 // Block 0x3, offset 0xc0 0xc0: 0x0040, 0xc1: 0x0040, 0xc2: 0x0040, 0xc3: 0x0040, 0xc4: 0x0040, 0xc5: 0x0040, 0xc6: 0x0040, 0xc7: 0x0040, 0xc8: 0x0040, 0xc9: 0x0040, 0xca: 0x0040, 0xcb: 0x0040, 0xcc: 0x0040, 0xcd: 0x0040, 0xce: 0x0040, 0xcf: 0x0040, 0xd0: 0x0040, 0xd1: 0x0040, 0xd2: 0x0040, 0xd3: 0x0040, 0xd4: 0x0040, 0xd5: 0x0040, 0xd6: 0x0040, 0xd7: 0x0040, 0xd8: 0x0040, 0xd9: 0x0040, 0xda: 0x0040, 0xdb: 0x0040, 0xdc: 0x0040, 0xdd: 0x0040, 0xde: 0x0040, 0xdf: 0x0040, 0xe0: 0x000a, 0xe1: 0x0018, 0xe2: 0x0018, 0xe3: 0x0018, 0xe4: 0x0018, 0xe5: 0x0018, 0xe6: 0x0018, 0xe7: 0x0018, 0xe8: 0x001a, 0xe9: 0x0018, 0xea: 0x0039, 0xeb: 0x0018, 0xec: 0x0018, 0xed: 0x03c0, 0xee: 0x0018, 0xef: 0x004a, 0xf0: 0x0018, 0xf1: 0x0018, 0xf2: 0x0069, 0xf3: 0x0079, 0xf4: 0x008a, 0xf5: 0x0005, 0xf6: 0x0018, 0xf7: 0x0008, 0xf8: 0x00aa, 0xf9: 0x00c9, 0xfa: 0x00d9, 0xfb: 0x0018, 0xfc: 0x00e9, 0xfd: 0x0119, 0xfe: 0x0149, 0xff: 0x0018, // Block 0x4, offset 0x100 0x100: 0xe00d, 0x101: 0x0008, 0x102: 0xe00d, 0x103: 0x0008, 0x104: 0xe00d, 0x105: 0x0008, 0x106: 0xe00d, 0x107: 0x0008, 0x108: 0xe00d, 0x109: 0x0008, 0x10a: 0xe00d, 0x10b: 0x0008, 0x10c: 0xe00d, 0x10d: 0x0008, 0x10e: 0xe00d, 0x10f: 0x0008, 0x110: 0xe00d, 0x111: 0x0008, 0x112: 0xe00d, 0x113: 0x0008, 0x114: 0xe00d, 0x115: 0x0008, 0x116: 0xe00d, 0x117: 0x0008, 0x118: 0xe00d, 0x119: 0x0008, 0x11a: 0xe00d, 0x11b: 0x0008, 0x11c: 0xe00d, 0x11d: 0x0008, 0x11e: 0xe00d, 0x11f: 0x0008, 0x120: 0xe00d, 0x121: 0x0008, 0x122: 0xe00d, 0x123: 0x0008, 0x124: 0xe00d, 0x125: 0x0008, 0x126: 0xe00d, 0x127: 0x0008, 0x128: 0xe00d, 0x129: 0x0008, 0x12a: 0xe00d, 0x12b: 0x0008, 0x12c: 0xe00d, 0x12d: 0x0008, 0x12e: 0xe00d, 0x12f: 0x0008, 0x130: 0x0179, 0x131: 0x0008, 0x132: 0x0035, 0x133: 0x004d, 0x134: 0xe00d, 0x135: 0x0008, 0x136: 0xe00d, 0x137: 0x0008, 0x138: 0x0008, 0x139: 0xe01d, 0x13a: 0x0008, 0x13b: 0xe03d, 0x13c: 0x0008, 0x13d: 0xe01d, 0x13e: 0x0008, 0x13f: 0x0199, // Block 0x5, offset 0x140 0x140: 0x0199, 0x141: 0xe01d, 0x142: 0x0008, 0x143: 0xe03d, 0x144: 0x0008, 0x145: 0xe01d, 0x146: 0x0008, 0x147: 0xe07d, 0x148: 0x0008, 0x149: 0x01b9, 0x14a: 0xe00d, 0x14b: 0x0008, 0x14c: 0xe00d, 0x14d: 0x0008, 0x14e: 0xe00d, 0x14f: 0x0008, 0x150: 0xe00d, 0x151: 0x0008, 0x152: 0xe00d, 0x153: 0x0008, 0x154: 0xe00d, 0x155: 0x0008, 0x156: 0xe00d, 0x157: 0x0008, 0x158: 0xe00d, 0x159: 0x0008, 0x15a: 0xe00d, 0x15b: 0x0008, 0x15c: 0xe00d, 0x15d: 0x0008, 0x15e: 0xe00d, 0x15f: 0x0008, 0x160: 0xe00d, 0x161: 0x0008, 0x162: 0xe00d, 0x163: 0x0008, 0x164: 0xe00d, 0x165: 0x0008, 0x166: 0xe00d, 0x167: 0x0008, 0x168: 0xe00d, 0x169: 0x0008, 0x16a: 0xe00d, 0x16b: 0x0008, 0x16c: 0xe00d, 0x16d: 0x0008, 0x16e: 0xe00d, 0x16f: 0x0008, 0x170: 0xe00d, 0x171: 0x0008, 0x172: 0xe00d, 0x173: 0x0008, 0x174: 0xe00d, 0x175: 0x0008, 0x176: 0xe00d, 0x177: 0x0008, 0x178: 0x0065, 0x179: 0xe01d, 0x17a: 0x0008, 0x17b: 0xe03d, 0x17c: 0x0008, 0x17d: 0xe01d, 0x17e: 0x0008, 0x17f: 0x01d9, // Block 0x6, offset 0x180 0x180: 0x0008, 0x181: 0x007d, 0x182: 0xe00d, 0x183: 0x0008, 0x184: 0xe00d, 0x185: 0x0008, 0x186: 0x007d, 0x187: 0xe07d, 0x188: 0x0008, 0x189: 0x0095, 0x18a: 0x00ad, 0x18b: 0xe03d, 0x18c: 0x0008, 0x18d: 0x0008, 0x18e: 0x00c5, 0x18f: 0x00dd, 0x190: 0x00f5, 0x191: 0xe01d, 0x192: 0x0008, 0x193: 0x010d, 0x194: 0x0125, 0x195: 0x0008, 0x196: 0x013d, 0x197: 0x013d, 0x198: 0xe00d, 0x199: 0x0008, 0x19a: 0x0008, 0x19b: 0x0008, 0x19c: 0x010d, 0x19d: 0x0155, 0x19e: 0x0008, 0x19f: 0x016d, 0x1a0: 0xe00d, 0x1a1: 0x0008, 0x1a2: 0xe00d, 0x1a3: 0x0008, 0x1a4: 0xe00d, 0x1a5: 0x0008, 0x1a6: 0x0185, 0x1a7: 0xe07d, 0x1a8: 0x0008, 0x1a9: 0x019d, 0x1aa: 0x0008, 0x1ab: 0x0008, 0x1ac: 0xe00d, 0x1ad: 0x0008, 0x1ae: 0x0185, 0x1af: 0xe0fd, 0x1b0: 0x0008, 0x1b1: 0x01b5, 0x1b2: 0x01cd, 0x1b3: 0xe03d, 0x1b4: 0x0008, 0x1b5: 0xe01d, 0x1b6: 0x0008, 0x1b7: 0x01e5, 0x1b8: 0xe00d, 0x1b9: 0x0008, 0x1ba: 0x0008, 0x1bb: 0x0008, 0x1bc: 0xe00d, 0x1bd: 0x0008, 0x1be: 0x0008, 0x1bf: 0x0008, // Block 0x7, offset 0x1c0 0x1c0: 0x0008, 0x1c1: 0x0008, 0x1c2: 0x0008, 0x1c3: 0x0008, 0x1c4: 0x01e9, 0x1c5: 0x01e9, 0x1c6: 0x01e9, 0x1c7: 0x01fd, 0x1c8: 0x0215, 0x1c9: 0x022d, 0x1ca: 0x0245, 0x1cb: 0x025d, 0x1cc: 0x0275, 0x1cd: 0xe01d, 0x1ce: 0x0008, 0x1cf: 0xe0fd, 0x1d0: 0x0008, 0x1d1: 0xe01d, 0x1d2: 0x0008, 0x1d3: 0xe03d, 0x1d4: 0x0008, 0x1d5: 0xe01d, 0x1d6: 0x0008, 0x1d7: 0xe07d, 0x1d8: 0x0008, 0x1d9: 0xe01d, 0x1da: 0x0008, 0x1db: 0xe03d, 0x1dc: 0x0008, 0x1dd: 0x0008, 0x1de: 0xe00d, 0x1df: 0x0008, 0x1e0: 0xe00d, 0x1e1: 0x0008, 0x1e2: 0xe00d, 0x1e3: 0x0008, 0x1e4: 0xe00d, 0x1e5: 0x0008, 0x1e6: 0xe00d, 0x1e7: 0x0008, 0x1e8: 0xe00d, 0x1e9: 0x0008, 0x1ea: 0xe00d, 0x1eb: 0x0008, 0x1ec: 0xe00d, 0x1ed: 0x0008, 0x1ee: 0xe00d, 0x1ef: 0x0008, 0x1f0: 0x0008, 0x1f1: 0x028d, 0x1f2: 0x02a5, 0x1f3: 0x02bd, 0x1f4: 0xe00d, 0x1f5: 0x0008, 0x1f6: 0x02d5, 0x1f7: 0x02ed, 0x1f8: 0xe00d, 0x1f9: 0x0008, 0x1fa: 0xe00d, 0x1fb: 0x0008, 0x1fc: 0xe00d, 0x1fd: 0x0008, 0x1fe: 0xe00d, 0x1ff: 0x0008, // Block 0x8, offset 0x200 0x200: 0xe00d, 0x201: 0x0008, 0x202: 0xe00d, 0x203: 0x0008, 0x204: 0xe00d, 0x205: 0x0008, 0x206: 0xe00d, 0x207: 0x0008, 0x208: 0xe00d, 0x209: 0x0008, 0x20a: 0xe00d, 0x20b: 0x0008, 0x20c: 0xe00d, 0x20d: 0x0008, 0x20e: 0xe00d, 0x20f: 0x0008, 0x210: 0xe00d, 0x211: 0x0008, 0x212: 0xe00d, 0x213: 0x0008, 0x214: 0xe00d, 0x215: 0x0008, 0x216: 0xe00d, 0x217: 0x0008, 0x218: 0xe00d, 0x219: 0x0008, 0x21a: 0xe00d, 0x21b: 0x0008, 0x21c: 0xe00d, 0x21d: 0x0008, 0x21e: 0xe00d, 0x21f: 0x0008, 0x220: 0x0305, 0x221: 0x0008, 0x222: 0xe00d, 0x223: 0x0008, 0x224: 0xe00d, 0x225: 0x0008, 0x226: 0xe00d, 0x227: 0x0008, 0x228: 0xe00d, 0x229: 0x0008, 0x22a: 0xe00d, 0x22b: 0x0008, 0x22c: 0xe00d, 0x22d: 0x0008, 0x22e: 0xe00d, 0x22f: 0x0008, 0x230: 0xe00d, 0x231: 0x0008, 0x232: 0xe00d, 0x233: 0x0008, 0x234: 0x0008, 0x235: 0x0008, 0x236: 0x0008, 0x237: 0x0008, 0x238: 0x0008, 0x239: 0x0008, 0x23a: 0x0209, 0x23b: 0xe03d, 0x23c: 0x0008, 0x23d: 0x031d, 0x23e: 0x0229, 0x23f: 0x0008, // Block 0x9, offset 0x240 0x240: 0x0008, 0x241: 0x0008, 0x242: 0x0018, 0x243: 0x0018, 0x244: 0x0018, 0x245: 0x0018, 0x246: 0x0008, 0x247: 0x0008, 0x248: 0x0008, 0x249: 0x0008, 0x24a: 0x0008, 0x24b: 0x0008, 0x24c: 0x0008, 0x24d: 0x0008, 0x24e: 0x0008, 0x24f: 0x0008, 0x250: 0x0008, 0x251: 0x0008, 0x252: 0x0018, 0x253: 0x0018, 0x254: 0x0018, 0x255: 0x0018, 0x256: 0x0018, 0x257: 0x0018, 0x258: 0x029a, 0x259: 0x02ba, 0x25a: 0x02da, 0x25b: 0x02fa, 0x25c: 0x031a, 0x25d: 0x033a, 0x25e: 0x0018, 0x25f: 0x0018, 0x260: 0x03ad, 0x261: 0x0359, 0x262: 0x01d9, 0x263: 0x0369, 0x264: 0x03c5, 0x265: 0x0018, 0x266: 0x0018, 0x267: 0x0018, 0x268: 0x0018, 0x269: 0x0018, 0x26a: 0x0018, 0x26b: 0x0018, 0x26c: 0x0008, 0x26d: 0x0018, 0x26e: 0x0008, 0x26f: 0x0018, 0x270: 0x0018, 0x271: 0x0018, 0x272: 0x0018, 0x273: 0x0018, 0x274: 0x0018, 0x275: 0x0018, 0x276: 0x0018, 0x277: 0x0018, 0x278: 0x0018, 0x279: 0x0018, 0x27a: 0x0018, 0x27b: 0x0018, 0x27c: 0x0018, 0x27d: 0x0018, 0x27e: 0x0018, 0x27f: 0x0018, // Block 0xa, offset 0x280 0x280: 0x03dd, 0x281: 0x03dd, 0x282: 0x3308, 0x283: 0x03f5, 0x284: 0x0379, 0x285: 0x040d, 0x286: 0x3308, 0x287: 0x3308, 0x288: 0x3308, 0x289: 0x3308, 0x28a: 0x3308, 0x28b: 0x3308, 0x28c: 0x3308, 0x28d: 0x3308, 0x28e: 0x3308, 0x28f: 0x33c0, 0x290: 0x3308, 0x291: 0x3308, 0x292: 0x3308, 0x293: 0x3308, 0x294: 0x3308, 0x295: 0x3308, 0x296: 0x3308, 0x297: 0x3308, 0x298: 0x3308, 0x299: 0x3308, 0x29a: 0x3308, 0x29b: 0x3308, 0x29c: 0x3308, 0x29d: 0x3308, 0x29e: 0x3308, 0x29f: 0x3308, 0x2a0: 0x3308, 0x2a1: 0x3308, 0x2a2: 0x3308, 0x2a3: 0x3308, 0x2a4: 0x3308, 0x2a5: 0x3308, 0x2a6: 0x3308, 0x2a7: 0x3308, 0x2a8: 0x3308, 0x2a9: 0x3308, 0x2aa: 0x3308, 0x2ab: 0x3308, 0x2ac: 0x3308, 0x2ad: 0x3308, 0x2ae: 0x3308, 0x2af: 0x3308, 0x2b0: 0xe00d, 0x2b1: 0x0008, 0x2b2: 0xe00d, 0x2b3: 0x0008, 0x2b4: 0x0425, 0x2b5: 0x0008, 0x2b6: 0xe00d, 0x2b7: 0x0008, 0x2b8: 0x0040, 0x2b9: 0x0040, 0x2ba: 0x03a2, 0x2bb: 0x0008, 0x2bc: 0x0008, 0x2bd: 0x0008, 0x2be: 0x03c2, 0x2bf: 0x043d, // Block 0xb, offset 0x2c0 0x2c0: 0x0040, 0x2c1: 0x0040, 0x2c2: 0x0040, 0x2c3: 0x0040, 0x2c4: 0x008a, 0x2c5: 0x03d2, 0x2c6: 0xe155, 0x2c7: 0x0455, 0x2c8: 0xe12d, 0x2c9: 0xe13d, 0x2ca: 0xe12d, 0x2cb: 0x0040, 0x2cc: 0x03dd, 0x2cd: 0x0040, 0x2ce: 0x046d, 0x2cf: 0x0485, 0x2d0: 0x0008, 0x2d1: 0xe105, 0x2d2: 0xe105, 0x2d3: 0xe105, 0x2d4: 0xe105, 0x2d5: 0xe105, 0x2d6: 0xe105, 0x2d7: 0xe105, 0x2d8: 0xe105, 0x2d9: 0xe105, 0x2da: 0xe105, 0x2db: 0xe105, 0x2dc: 0xe105, 0x2dd: 0xe105, 0x2de: 0xe105, 0x2df: 0xe105, 0x2e0: 0x049d, 0x2e1: 0x049d, 0x2e2: 0x0040, 0x2e3: 0x049d, 0x2e4: 0x049d, 0x2e5: 0x049d, 0x2e6: 0x049d, 0x2e7: 0x049d, 0x2e8: 0x049d, 0x2e9: 0x049d, 0x2ea: 0x049d, 0x2eb: 0x049d, 0x2ec: 0x0008, 0x2ed: 0x0008, 0x2ee: 0x0008, 0x2ef: 0x0008, 0x2f0: 0x0008, 0x2f1: 0x0008, 0x2f2: 0x0008, 0x2f3: 0x0008, 0x2f4: 0x0008, 0x2f5: 0x0008, 0x2f6: 0x0008, 0x2f7: 0x0008, 0x2f8: 0x0008, 0x2f9: 0x0008, 0x2fa: 0x0008, 0x2fb: 0x0008, 0x2fc: 0x0008, 0x2fd: 0x0008, 0x2fe: 0x0008, 0x2ff: 0x0008, // Block 0xc, offset 0x300 0x300: 0x0008, 0x301: 0x0008, 0x302: 0xe00f, 0x303: 0x0008, 0x304: 0x0008, 0x305: 0x0008, 0x306: 0x0008, 0x307: 0x0008, 0x308: 0x0008, 0x309: 0x0008, 0x30a: 0x0008, 0x30b: 0x0008, 0x30c: 0x0008, 0x30d: 0x0008, 0x30e: 0x0008, 0x30f: 0xe0c5, 0x310: 0x04b5, 0x311: 0x04cd, 0x312: 0xe0bd, 0x313: 0xe0f5, 0x314: 0xe0fd, 0x315: 0xe09d, 0x316: 0xe0b5, 0x317: 0x0008, 0x318: 0xe00d, 0x319: 0x0008, 0x31a: 0xe00d, 0x31b: 0x0008, 0x31c: 0xe00d, 0x31d: 0x0008, 0x31e: 0xe00d, 0x31f: 0x0008, 0x320: 0xe00d, 0x321: 0x0008, 0x322: 0xe00d, 0x323: 0x0008, 0x324: 0xe00d, 0x325: 0x0008, 0x326: 0xe00d, 0x327: 0x0008, 0x328: 0xe00d, 0x329: 0x0008, 0x32a: 0xe00d, 0x32b: 0x0008, 0x32c: 0xe00d, 0x32d: 0x0008, 0x32e: 0xe00d, 0x32f: 0x0008, 0x330: 0x04e5, 0x331: 0xe185, 0x332: 0xe18d, 0x333: 0x0008, 0x334: 0x04fd, 0x335: 0x03dd, 0x336: 0x0018, 0x337: 0xe07d, 0x338: 0x0008, 0x339: 0xe1d5, 0x33a: 0xe00d, 0x33b: 0x0008, 0x33c: 0x0008, 0x33d: 0x0515, 0x33e: 0x052d, 0x33f: 0x052d, // Block 0xd, offset 0x340 0x340: 0x0008, 0x341: 0x0008, 0x342: 0x0008, 0x343: 0x0008, 0x344: 0x0008, 0x345: 0x0008, 0x346: 0x0008, 0x347: 0x0008, 0x348: 0x0008, 0x349: 0x0008, 0x34a: 0x0008, 0x34b: 0x0008, 0x34c: 0x0008, 0x34d: 0x0008, 0x34e: 0x0008, 0x34f: 0x0008, 0x350: 0x0008, 0x351: 0x0008, 0x352: 0x0008, 0x353: 0x0008, 0x354: 0x0008, 0x355: 0x0008, 0x356: 0x0008, 0x357: 0x0008, 0x358: 0x0008, 0x359: 0x0008, 0x35a: 0x0008, 0x35b: 0x0008, 0x35c: 0x0008, 0x35d: 0x0008, 0x35e: 0x0008, 0x35f: 0x0008, 0x360: 0xe00d, 0x361: 0x0008, 0x362: 0xe00d, 0x363: 0x0008, 0x364: 0xe00d, 0x365: 0x0008, 0x366: 0xe00d, 0x367: 0x0008, 0x368: 0xe00d, 0x369: 0x0008, 0x36a: 0xe00d, 0x36b: 0x0008, 0x36c: 0xe00d, 0x36d: 0x0008, 0x36e: 0xe00d, 0x36f: 0x0008, 0x370: 0xe00d, 0x371: 0x0008, 0x372: 0xe00d, 0x373: 0x0008, 0x374: 0xe00d, 0x375: 0x0008, 0x376: 0xe00d, 0x377: 0x0008, 0x378: 0xe00d, 0x379: 0x0008, 0x37a: 0xe00d, 0x37b: 0x0008, 0x37c: 0xe00d, 0x37d: 0x0008, 0x37e: 0xe00d, 0x37f: 0x0008, // Block 0xe, offset 0x380 0x380: 0xe00d, 0x381: 0x0008, 0x382: 0x0018, 0x383: 0x3308, 0x384: 0x3308, 0x385: 0x3308, 0x386: 0x3308, 0x387: 0x3308, 0x388: 0x3318, 0x389: 0x3318, 0x38a: 0xe00d, 0x38b: 0x0008, 0x38c: 0xe00d, 0x38d: 0x0008, 0x38e: 0xe00d, 0x38f: 0x0008, 0x390: 0xe00d, 0x391: 0x0008, 0x392: 0xe00d, 0x393: 0x0008, 0x394: 0xe00d, 0x395: 0x0008, 0x396: 0xe00d, 0x397: 0x0008, 0x398: 0xe00d, 0x399: 0x0008, 0x39a: 0xe00d, 0x39b: 0x0008, 0x39c: 0xe00d, 0x39d: 0x0008, 0x39e: 0xe00d, 0x39f: 0x0008, 0x3a0: 0xe00d, 0x3a1: 0x0008, 0x3a2: 0xe00d, 0x3a3: 0x0008, 0x3a4: 0xe00d, 0x3a5: 0x0008, 0x3a6: 0xe00d, 0x3a7: 0x0008, 0x3a8: 0xe00d, 0x3a9: 0x0008, 0x3aa: 0xe00d, 0x3ab: 0x0008, 0x3ac: 0xe00d, 0x3ad: 0x0008, 0x3ae: 0xe00d, 0x3af: 0x0008, 0x3b0: 0xe00d, 0x3b1: 0x0008, 0x3b2: 0xe00d, 0x3b3: 0x0008, 0x3b4: 0xe00d, 0x3b5: 0x0008, 0x3b6: 0xe00d, 0x3b7: 0x0008, 0x3b8: 0xe00d, 0x3b9: 0x0008, 0x3ba: 0xe00d, 0x3bb: 0x0008, 0x3bc: 0xe00d, 0x3bd: 0x0008, 0x3be: 0xe00d, 0x3bf: 0x0008, // Block 0xf, offset 0x3c0 0x3c0: 0x0040, 0x3c1: 0xe01d, 0x3c2: 0x0008, 0x3c3: 0xe03d, 0x3c4: 0x0008, 0x3c5: 0xe01d, 0x3c6: 0x0008, 0x3c7: 0xe07d, 0x3c8: 0x0008, 0x3c9: 0xe01d, 0x3ca: 0x0008, 0x3cb: 0xe03d, 0x3cc: 0x0008, 0x3cd: 0xe01d, 0x3ce: 0x0008, 0x3cf: 0x0008, 0x3d0: 0xe00d, 0x3d1: 0x0008, 0x3d2: 0xe00d, 0x3d3: 0x0008, 0x3d4: 0xe00d, 0x3d5: 0x0008, 0x3d6: 0xe00d, 0x3d7: 0x0008, 0x3d8: 0xe00d, 0x3d9: 0x0008, 0x3da: 0xe00d, 0x3db: 0x0008, 0x3dc: 0xe00d, 0x3dd: 0x0008, 0x3de: 0xe00d, 0x3df: 0x0008, 0x3e0: 0xe00d, 0x3e1: 0x0008, 0x3e2: 0xe00d, 0x3e3: 0x0008, 0x3e4: 0xe00d, 0x3e5: 0x0008, 0x3e6: 0xe00d, 0x3e7: 0x0008, 0x3e8: 0xe00d, 0x3e9: 0x0008, 0x3ea: 0xe00d, 0x3eb: 0x0008, 0x3ec: 0xe00d, 0x3ed: 0x0008, 0x3ee: 0xe00d, 0x3ef: 0x0008, 0x3f0: 0xe00d, 0x3f1: 0x0008, 0x3f2: 0xe00d, 0x3f3: 0x0008, 0x3f4: 0xe00d, 0x3f5: 0x0008, 0x3f6: 0xe00d, 0x3f7: 0x0008, 0x3f8: 0xe00d, 0x3f9: 0x0008, 0x3fa: 0xe00d, 0x3fb: 0x0008, 0x3fc: 0xe00d, 0x3fd: 0x0008, 0x3fe: 0xe00d, 0x3ff: 0x0008, // Block 0x10, offset 0x400 0x400: 0xe00d, 0x401: 0x0008, 0x402: 0xe00d, 0x403: 0x0008, 0x404: 0xe00d, 0x405: 0x0008, 0x406: 0xe00d, 0x407: 0x0008, 0x408: 0xe00d, 0x409: 0x0008, 0x40a: 0xe00d, 0x40b: 0x0008, 0x40c: 0xe00d, 0x40d: 0x0008, 0x40e: 0xe00d, 0x40f: 0x0008, 0x410: 0xe00d, 0x411: 0x0008, 0x412: 0xe00d, 0x413: 0x0008, 0x414: 0xe00d, 0x415: 0x0008, 0x416: 0xe00d, 0x417: 0x0008, 0x418: 0xe00d, 0x419: 0x0008, 0x41a: 0xe00d, 0x41b: 0x0008, 0x41c: 0xe00d, 0x41d: 0x0008, 0x41e: 0xe00d, 0x41f: 0x0008, 0x420: 0xe00d, 0x421: 0x0008, 0x422: 0xe00d, 0x423: 0x0008, 0x424: 0xe00d, 0x425: 0x0008, 0x426: 0xe00d, 0x427: 0x0008, 0x428: 0xe00d, 0x429: 0x0008, 0x42a: 0xe00d, 0x42b: 0x0008, 0x42c: 0xe00d, 0x42d: 0x0008, 0x42e: 0xe00d, 0x42f: 0x0008, 0x430: 0x0040, 0x431: 0x03f5, 0x432: 0x03f5, 0x433: 0x03f5, 0x434: 0x03f5, 0x435: 0x03f5, 0x436: 0x03f5, 0x437: 0x03f5, 0x438: 0x03f5, 0x439: 0x03f5, 0x43a: 0x03f5, 0x43b: 0x03f5, 0x43c: 0x03f5, 0x43d: 0x03f5, 0x43e: 0x03f5, 0x43f: 0x03f5, // Block 0x11, offset 0x440 0x440: 0x0840, 0x441: 0x0840, 0x442: 0x0840, 0x443: 0x0840, 0x444: 0x0840, 0x445: 0x0840, 0x446: 0x0018, 0x447: 0x0018, 0x448: 0x0818, 0x449: 0x0018, 0x44a: 0x0018, 0x44b: 0x0818, 0x44c: 0x0018, 0x44d: 0x0818, 0x44e: 0x0018, 0x44f: 0x0018, 0x450: 0x3308, 0x451: 0x3308, 0x452: 0x3308, 0x453: 0x3308, 0x454: 0x3308, 0x455: 0x3308, 0x456: 0x3308, 0x457: 0x3308, 0x458: 0x3308, 0x459: 0x3308, 0x45a: 0x3308, 0x45b: 0x0818, 0x45c: 0x0b40, 0x45d: 0x0040, 0x45e: 0x0818, 0x45f: 0x0818, 0x460: 0x0a08, 0x461: 0x0808, 0x462: 0x0c08, 0x463: 0x0c08, 0x464: 0x0c08, 0x465: 0x0c08, 0x466: 0x0a08, 0x467: 0x0c08, 0x468: 0x0a08, 0x469: 0x0c08, 0x46a: 0x0a08, 0x46b: 0x0a08, 0x46c: 0x0a08, 0x46d: 0x0a08, 0x46e: 0x0a08, 0x46f: 0x0c08, 0x470: 0x0c08, 0x471: 0x0c08, 0x472: 0x0c08, 0x473: 0x0a08, 0x474: 0x0a08, 0x475: 0x0a08, 0x476: 0x0a08, 0x477: 0x0a08, 0x478: 0x0a08, 0x479: 0x0a08, 0x47a: 0x0a08, 0x47b: 0x0a08, 0x47c: 0x0a08, 0x47d: 0x0a08, 0x47e: 0x0a08, 0x47f: 0x0a08, // Block 0x12, offset 0x480 0x480: 0x0818, 0x481: 0x0a08, 0x482: 0x0a08, 0x483: 0x0a08, 0x484: 0x0a08, 0x485: 0x0a08, 0x486: 0x0a08, 0x487: 0x0a08, 0x488: 0x0c08, 0x489: 0x0a08, 0x48a: 0x0a08, 0x48b: 0x3308, 0x48c: 0x3308, 0x48d: 0x3308, 0x48e: 0x3308, 0x48f: 0x3308, 0x490: 0x3308, 0x491: 0x3308, 0x492: 0x3308, 0x493: 0x3308, 0x494: 0x3308, 0x495: 0x3308, 0x496: 0x3308, 0x497: 0x3308, 0x498: 0x3308, 0x499: 0x3308, 0x49a: 0x3308, 0x49b: 0x3308, 0x49c: 0x3308, 0x49d: 0x3308, 0x49e: 0x3308, 0x49f: 0x3308, 0x4a0: 0x0808, 0x4a1: 0x0808, 0x4a2: 0x0808, 0x4a3: 0x0808, 0x4a4: 0x0808, 0x4a5: 0x0808, 0x4a6: 0x0808, 0x4a7: 0x0808, 0x4a8: 0x0808, 0x4a9: 0x0808, 0x4aa: 0x0018, 0x4ab: 0x0818, 0x4ac: 0x0818, 0x4ad: 0x0818, 0x4ae: 0x0a08, 0x4af: 0x0a08, 0x4b0: 0x3308, 0x4b1: 0x0c08, 0x4b2: 0x0c08, 0x4b3: 0x0c08, 0x4b4: 0x0808, 0x4b5: 0x0429, 0x4b6: 0x0451, 0x4b7: 0x0479, 0x4b8: 0x04a1, 0x4b9: 0x0a08, 0x4ba: 0x0a08, 0x4bb: 0x0a08, 0x4bc: 0x0a08, 0x4bd: 0x0a08, 0x4be: 0x0a08, 0x4bf: 0x0a08, // Block 0x13, offset 0x4c0 0x4c0: 0x0c08, 0x4c1: 0x0a08, 0x4c2: 0x0a08, 0x4c3: 0x0c08, 0x4c4: 0x0c08, 0x4c5: 0x0c08, 0x4c6: 0x0c08, 0x4c7: 0x0c08, 0x4c8: 0x0c08, 0x4c9: 0x0c08, 0x4ca: 0x0c08, 0x4cb: 0x0c08, 0x4cc: 0x0a08, 0x4cd: 0x0c08, 0x4ce: 0x0a08, 0x4cf: 0x0c08, 0x4d0: 0x0a08, 0x4d1: 0x0a08, 0x4d2: 0x0c08, 0x4d3: 0x0c08, 0x4d4: 0x0818, 0x4d5: 0x0c08, 0x4d6: 0x3308, 0x4d7: 0x3308, 0x4d8: 0x3308, 0x4d9: 0x3308, 0x4da: 0x3308, 0x4db: 0x3308, 0x4dc: 0x3308, 0x4dd: 0x0840, 0x4de: 0x0018, 0x4df: 0x3308, 0x4e0: 0x3308, 0x4e1: 0x3308, 0x4e2: 0x3308, 0x4e3: 0x3308, 0x4e4: 0x3308, 0x4e5: 0x0808, 0x4e6: 0x0808, 0x4e7: 0x3308, 0x4e8: 0x3308, 0x4e9: 0x0018, 0x4ea: 0x3308, 0x4eb: 0x3308, 0x4ec: 0x3308, 0x4ed: 0x3308, 0x4ee: 0x0c08, 0x4ef: 0x0c08, 0x4f0: 0x0008, 0x4f1: 0x0008, 0x4f2: 0x0008, 0x4f3: 0x0008, 0x4f4: 0x0008, 0x4f5: 0x0008, 0x4f6: 0x0008, 0x4f7: 0x0008, 0x4f8: 0x0008, 0x4f9: 0x0008, 0x4fa: 0x0a08, 0x4fb: 0x0a08, 0x4fc: 0x0a08, 0x4fd: 0x0808, 0x4fe: 0x0808, 0x4ff: 0x0a08, // Block 0x14, offset 0x500 0x500: 0x0818, 0x501: 0x0818, 0x502: 0x0818, 0x503: 0x0818, 0x504: 0x0818, 0x505: 0x0818, 0x506: 0x0818, 0x507: 0x0818, 0x508: 0x0818, 0x509: 0x0818, 0x50a: 0x0818, 0x50b: 0x0818, 0x50c: 0x0818, 0x50d: 0x0818, 0x50e: 0x0040, 0x50f: 0x0b40, 0x510: 0x0c08, 0x511: 0x3308, 0x512: 0x0a08, 0x513: 0x0a08, 0x514: 0x0a08, 0x515: 0x0c08, 0x516: 0x0c08, 0x517: 0x0c08, 0x518: 0x0c08, 0x519: 0x0c08, 0x51a: 0x0a08, 0x51b: 0x0a08, 0x51c: 0x0a08, 0x51d: 0x0a08, 0x51e: 0x0c08, 0x51f: 0x0a08, 0x520: 0x0a08, 0x521: 0x0a08, 0x522: 0x0a08, 0x523: 0x0a08, 0x524: 0x0a08, 0x525: 0x0a08, 0x526: 0x0a08, 0x527: 0x0a08, 0x528: 0x0c08, 0x529: 0x0a08, 0x52a: 0x0c08, 0x52b: 0x0a08, 0x52c: 0x0c08, 0x52d: 0x0a08, 0x52e: 0x0a08, 0x52f: 0x0c08, 0x530: 0x3308, 0x531: 0x3308, 0x532: 0x3308, 0x533: 0x3308, 0x534: 0x3308, 0x535: 0x3308, 0x536: 0x3308, 0x537: 0x3308, 0x538: 0x3308, 0x539: 0x3308, 0x53a: 0x3308, 0x53b: 0x3308, 0x53c: 0x3308, 0x53d: 0x3308, 0x53e: 0x3308, 0x53f: 0x3308, // Block 0x15, offset 0x540 0x540: 0x3008, 0x541: 0x3308, 0x542: 0x3308, 0x543: 0x3308, 0x544: 0x3308, 0x545: 0x3308, 0x546: 0x3308, 0x547: 0x3308, 0x548: 0x3308, 0x549: 0x3008, 0x54a: 0x3008, 0x54b: 0x3008, 0x54c: 0x3008, 0x54d: 0x3b08, 0x54e: 0x3008, 0x54f: 0x3008, 0x550: 0x0008, 0x551: 0x3308, 0x552: 0x3308, 0x553: 0x3308, 0x554: 0x3308, 0x555: 0x3308, 0x556: 0x3308, 0x557: 0x3308, 0x558: 0x04c9, 0x559: 0x0501, 0x55a: 0x0539, 0x55b: 0x0571, 0x55c: 0x05a9, 0x55d: 0x05e1, 0x55e: 0x0619, 0x55f: 0x0651, 0x560: 0x0008, 0x561: 0x0008, 0x562: 0x3308, 0x563: 0x3308, 0x564: 0x0018, 0x565: 0x0018, 0x566: 0x0008, 0x567: 0x0008, 0x568: 0x0008, 0x569: 0x0008, 0x56a: 0x0008, 0x56b: 0x0008, 0x56c: 0x0008, 0x56d: 0x0008, 0x56e: 0x0008, 0x56f: 0x0008, 0x570: 0x0018, 0x571: 0x0008, 0x572: 0x0008, 0x573: 0x0008, 0x574: 0x0008, 0x575: 0x0008, 0x576: 0x0008, 0x577: 0x0008, 0x578: 0x0008, 0x579: 0x0008, 0x57a: 0x0008, 0x57b: 0x0008, 0x57c: 0x0008, 0x57d: 0x0008, 0x57e: 0x0008, 0x57f: 0x0008, // Block 0x16, offset 0x580 0x580: 0x0008, 0x581: 0x3308, 0x582: 0x3008, 0x583: 0x3008, 0x584: 0x0040, 0x585: 0x0008, 0x586: 0x0008, 0x587: 0x0008, 0x588: 0x0008, 0x589: 0x0008, 0x58a: 0x0008, 0x58b: 0x0008, 0x58c: 0x0008, 0x58d: 0x0040, 0x58e: 0x0040, 0x58f: 0x0008, 0x590: 0x0008, 0x591: 0x0040, 0x592: 0x0040, 0x593: 0x0008, 0x594: 0x0008, 0x595: 0x0008, 0x596: 0x0008, 0x597: 0x0008, 0x598: 0x0008, 0x599: 0x0008, 0x59a: 0x0008, 0x59b: 0x0008, 0x59c: 0x0008, 0x59d: 0x0008, 0x59e: 0x0008, 0x59f: 0x0008, 0x5a0: 0x0008, 0x5a1: 0x0008, 0x5a2: 0x0008, 0x5a3: 0x0008, 0x5a4: 0x0008, 0x5a5: 0x0008, 0x5a6: 0x0008, 0x5a7: 0x0008, 0x5a8: 0x0008, 0x5a9: 0x0040, 0x5aa: 0x0008, 0x5ab: 0x0008, 0x5ac: 0x0008, 0x5ad: 0x0008, 0x5ae: 0x0008, 0x5af: 0x0008, 0x5b0: 0x0008, 0x5b1: 0x0040, 0x5b2: 0x0008, 0x5b3: 0x0040, 0x5b4: 0x0040, 0x5b5: 0x0040, 0x5b6: 0x0008, 0x5b7: 0x0008, 0x5b8: 0x0008, 0x5b9: 0x0008, 0x5ba: 0x0040, 0x5bb: 0x0040, 0x5bc: 0x3308, 0x5bd: 0x0008, 0x5be: 0x3008, 0x5bf: 0x3008, // Block 0x17, offset 0x5c0 0x5c0: 0x3008, 0x5c1: 0x3308, 0x5c2: 0x3308, 0x5c3: 0x3308, 0x5c4: 0x3308, 0x5c5: 0x0040, 0x5c6: 0x0040, 0x5c7: 0x3008, 0x5c8: 0x3008, 0x5c9: 0x0040, 0x5ca: 0x0040, 0x5cb: 0x3008, 0x5cc: 0x3008, 0x5cd: 0x3b08, 0x5ce: 0x0008, 0x5cf: 0x0040, 0x5d0: 0x0040, 0x5d1: 0x0040, 0x5d2: 0x0040, 0x5d3: 0x0040, 0x5d4: 0x0040, 0x5d5: 0x0040, 0x5d6: 0x0040, 0x5d7: 0x3008, 0x5d8: 0x0040, 0x5d9: 0x0040, 0x5da: 0x0040, 0x5db: 0x0040, 0x5dc: 0x0689, 0x5dd: 0x06c1, 0x5de: 0x0040, 0x5df: 0x06f9, 0x5e0: 0x0008, 0x5e1: 0x0008, 0x5e2: 0x3308, 0x5e3: 0x3308, 0x5e4: 0x0040, 0x5e5: 0x0040, 0x5e6: 0x0008, 0x5e7: 0x0008, 0x5e8: 0x0008, 0x5e9: 0x0008, 0x5ea: 0x0008, 0x5eb: 0x0008, 0x5ec: 0x0008, 0x5ed: 0x0008, 0x5ee: 0x0008, 0x5ef: 0x0008, 0x5f0: 0x0008, 0x5f1: 0x0008, 0x5f2: 0x0018, 0x5f3: 0x0018, 0x5f4: 0x0018, 0x5f5: 0x0018, 0x5f6: 0x0018, 0x5f7: 0x0018, 0x5f8: 0x0018, 0x5f9: 0x0018, 0x5fa: 0x0018, 0x5fb: 0x0018, 0x5fc: 0x0040, 0x5fd: 0x0040, 0x5fe: 0x0040, 0x5ff: 0x0040, // Block 0x18, offset 0x600 0x600: 0x0040, 0x601: 0x3308, 0x602: 0x3308, 0x603: 0x3008, 0x604: 0x0040, 0x605: 0x0008, 0x606: 0x0008, 0x607: 0x0008, 0x608: 0x0008, 0x609: 0x0008, 0x60a: 0x0008, 0x60b: 0x0040, 0x60c: 0x0040, 0x60d: 0x0040, 0x60e: 0x0040, 0x60f: 0x0008, 0x610: 0x0008, 0x611: 0x0040, 0x612: 0x0040, 0x613: 0x0008, 0x614: 0x0008, 0x615: 0x0008, 0x616: 0x0008, 0x617: 0x0008, 0x618: 0x0008, 0x619: 0x0008, 0x61a: 0x0008, 0x61b: 0x0008, 0x61c: 0x0008, 0x61d: 0x0008, 0x61e: 0x0008, 0x61f: 0x0008, 0x620: 0x0008, 0x621: 0x0008, 0x622: 0x0008, 0x623: 0x0008, 0x624: 0x0008, 0x625: 0x0008, 0x626: 0x0008, 0x627: 0x0008, 0x628: 0x0008, 0x629: 0x0040, 0x62a: 0x0008, 0x62b: 0x0008, 0x62c: 0x0008, 0x62d: 0x0008, 0x62e: 0x0008, 0x62f: 0x0008, 0x630: 0x0008, 0x631: 0x0040, 0x632: 0x0008, 0x633: 0x0731, 0x634: 0x0040, 0x635: 0x0008, 0x636: 0x0769, 0x637: 0x0040, 0x638: 0x0008, 0x639: 0x0008, 0x63a: 0x0040, 0x63b: 0x0040, 0x63c: 0x3308, 0x63d: 0x0040, 0x63e: 0x3008, 0x63f: 0x3008, // Block 0x19, offset 0x640 0x640: 0x3008, 0x641: 0x3308, 0x642: 0x3308, 0x643: 0x0040, 0x644: 0x0040, 0x645: 0x0040, 0x646: 0x0040, 0x647: 0x3308, 0x648: 0x3308, 0x649: 0x0040, 0x64a: 0x0040, 0x64b: 0x3308, 0x64c: 0x3308, 0x64d: 0x3b08, 0x64e: 0x0040, 0x64f: 0x0040, 0x650: 0x0040, 0x651: 0x3308, 0x652: 0x0040, 0x653: 0x0040, 0x654: 0x0040, 0x655: 0x0040, 0x656: 0x0040, 0x657: 0x0040, 0x658: 0x0040, 0x659: 0x07a1, 0x65a: 0x07d9, 0x65b: 0x0811, 0x65c: 0x0008, 0x65d: 0x0040, 0x65e: 0x0849, 0x65f: 0x0040, 0x660: 0x0040, 0x661: 0x0040, 0x662: 0x0040, 0x663: 0x0040, 0x664: 0x0040, 0x665: 0x0040, 0x666: 0x0008, 0x667: 0x0008, 0x668: 0x0008, 0x669: 0x0008, 0x66a: 0x0008, 0x66b: 0x0008, 0x66c: 0x0008, 0x66d: 0x0008, 0x66e: 0x0008, 0x66f: 0x0008, 0x670: 0x3308, 0x671: 0x3308, 0x672: 0x0008, 0x673: 0x0008, 0x674: 0x0008, 0x675: 0x3308, 0x676: 0x0040, 0x677: 0x0040, 0x678: 0x0040, 0x679: 0x0040, 0x67a: 0x0040, 0x67b: 0x0040, 0x67c: 0x0040, 0x67d: 0x0040, 0x67e: 0x0040, 0x67f: 0x0040, // Block 0x1a, offset 0x680 0x680: 0x0040, 0x681: 0x3308, 0x682: 0x3308, 0x683: 0x3008, 0x684: 0x0040, 0x685: 0x0008, 0x686: 0x0008, 0x687: 0x0008, 0x688: 0x0008, 0x689: 0x0008, 0x68a: 0x0008, 0x68b: 0x0008, 0x68c: 0x0008, 0x68d: 0x0008, 0x68e: 0x0040, 0x68f: 0x0008, 0x690: 0x0008, 0x691: 0x0008, 0x692: 0x0040, 0x693: 0x0008, 0x694: 0x0008, 0x695: 0x0008, 0x696: 0x0008, 0x697: 0x0008, 0x698: 0x0008, 0x699: 0x0008, 0x69a: 0x0008, 0x69b: 0x0008, 0x69c: 0x0008, 0x69d: 0x0008, 0x69e: 0x0008, 0x69f: 0x0008, 0x6a0: 0x0008, 0x6a1: 0x0008, 0x6a2: 0x0008, 0x6a3: 0x0008, 0x6a4: 0x0008, 0x6a5: 0x0008, 0x6a6: 0x0008, 0x6a7: 0x0008, 0x6a8: 0x0008, 0x6a9: 0x0040, 0x6aa: 0x0008, 0x6ab: 0x0008, 0x6ac: 0x0008, 0x6ad: 0x0008, 0x6ae: 0x0008, 0x6af: 0x0008, 0x6b0: 0x0008, 0x6b1: 0x0040, 0x6b2: 0x0008, 0x6b3: 0x0008, 0x6b4: 0x0040, 0x6b5: 0x0008, 0x6b6: 0x0008, 0x6b7: 0x0008, 0x6b8: 0x0008, 0x6b9: 0x0008, 0x6ba: 0x0040, 0x6bb: 0x0040, 0x6bc: 0x3308, 0x6bd: 0x0008, 0x6be: 0x3008, 0x6bf: 0x3008, // Block 0x1b, offset 0x6c0 0x6c0: 0x3008, 0x6c1: 0x3308, 0x6c2: 0x3308, 0x6c3: 0x3308, 0x6c4: 0x3308, 0x6c5: 0x3308, 0x6c6: 0x0040, 0x6c7: 0x3308, 0x6c8: 0x3308, 0x6c9: 0x3008, 0x6ca: 0x0040, 0x6cb: 0x3008, 0x6cc: 0x3008, 0x6cd: 0x3b08, 0x6ce: 0x0040, 0x6cf: 0x0040, 0x6d0: 0x0008, 0x6d1: 0x0040, 0x6d2: 0x0040, 0x6d3: 0x0040, 0x6d4: 0x0040, 0x6d5: 0x0040, 0x6d6: 0x0040, 0x6d7: 0x0040, 0x6d8: 0x0040, 0x6d9: 0x0040, 0x6da: 0x0040, 0x6db: 0x0040, 0x6dc: 0x0040, 0x6dd: 0x0040, 0x6de: 0x0040, 0x6df: 0x0040, 0x6e0: 0x0008, 0x6e1: 0x0008, 0x6e2: 0x3308, 0x6e3: 0x3308, 0x6e4: 0x0040, 0x6e5: 0x0040, 0x6e6: 0x0008, 0x6e7: 0x0008, 0x6e8: 0x0008, 0x6e9: 0x0008, 0x6ea: 0x0008, 0x6eb: 0x0008, 0x6ec: 0x0008, 0x6ed: 0x0008, 0x6ee: 0x0008, 0x6ef: 0x0008, 0x6f0: 0x0018, 0x6f1: 0x0018, 0x6f2: 0x0040, 0x6f3: 0x0040, 0x6f4: 0x0040, 0x6f5: 0x0040, 0x6f6: 0x0040, 0x6f7: 0x0040, 0x6f8: 0x0040, 0x6f9: 0x0008, 0x6fa: 0x0040, 0x6fb: 0x0040, 0x6fc: 0x0040, 0x6fd: 0x0040, 0x6fe: 0x0040, 0x6ff: 0x0040, // Block 0x1c, offset 0x700 0x700: 0x0040, 0x701: 0x3308, 0x702: 0x3008, 0x703: 0x3008, 0x704: 0x0040, 0x705: 0x0008, 0x706: 0x0008, 0x707: 0x0008, 0x708: 0x0008, 0x709: 0x0008, 0x70a: 0x0008, 0x70b: 0x0008, 0x70c: 0x0008, 0x70d: 0x0040, 0x70e: 0x0040, 0x70f: 0x0008, 0x710: 0x0008, 0x711: 0x0040, 0x712: 0x0040, 0x713: 0x0008, 0x714: 0x0008, 0x715: 0x0008, 0x716: 0x0008, 0x717: 0x0008, 0x718: 0x0008, 0x719: 0x0008, 0x71a: 0x0008, 0x71b: 0x0008, 0x71c: 0x0008, 0x71d: 0x0008, 0x71e: 0x0008, 0x71f: 0x0008, 0x720: 0x0008, 0x721: 0x0008, 0x722: 0x0008, 0x723: 0x0008, 0x724: 0x0008, 0x725: 0x0008, 0x726: 0x0008, 0x727: 0x0008, 0x728: 0x0008, 0x729: 0x0040, 0x72a: 0x0008, 0x72b: 0x0008, 0x72c: 0x0008, 0x72d: 0x0008, 0x72e: 0x0008, 0x72f: 0x0008, 0x730: 0x0008, 0x731: 0x0040, 0x732: 0x0008, 0x733: 0x0008, 0x734: 0x0040, 0x735: 0x0008, 0x736: 0x0008, 0x737: 0x0008, 0x738: 0x0008, 0x739: 0x0008, 0x73a: 0x0040, 0x73b: 0x0040, 0x73c: 0x3308, 0x73d: 0x0008, 0x73e: 0x3008, 0x73f: 0x3308, // Block 0x1d, offset 0x740 0x740: 0x3008, 0x741: 0x3308, 0x742: 0x3308, 0x743: 0x3308, 0x744: 0x3308, 0x745: 0x0040, 0x746: 0x0040, 0x747: 0x3008, 0x748: 0x3008, 0x749: 0x0040, 0x74a: 0x0040, 0x74b: 0x3008, 0x74c: 0x3008, 0x74d: 0x3b08, 0x74e: 0x0040, 0x74f: 0x0040, 0x750: 0x0040, 0x751: 0x0040, 0x752: 0x0040, 0x753: 0x0040, 0x754: 0x0040, 0x755: 0x0040, 0x756: 0x3308, 0x757: 0x3008, 0x758: 0x0040, 0x759: 0x0040, 0x75a: 0x0040, 0x75b: 0x0040, 0x75c: 0x0881, 0x75d: 0x08b9, 0x75e: 0x0040, 0x75f: 0x0008, 0x760: 0x0008, 0x761: 0x0008, 0x762: 0x3308, 0x763: 0x3308, 0x764: 0x0040, 0x765: 0x0040, 0x766: 0x0008, 0x767: 0x0008, 0x768: 0x0008, 0x769: 0x0008, 0x76a: 0x0008, 0x76b: 0x0008, 0x76c: 0x0008, 0x76d: 0x0008, 0x76e: 0x0008, 0x76f: 0x0008, 0x770: 0x0018, 0x771: 0x0008, 0x772: 0x0018, 0x773: 0x0018, 0x774: 0x0018, 0x775: 0x0018, 0x776: 0x0018, 0x777: 0x0018, 0x778: 0x0040, 0x779: 0x0040, 0x77a: 0x0040, 0x77b: 0x0040, 0x77c: 0x0040, 0x77d: 0x0040, 0x77e: 0x0040, 0x77f: 0x0040, // Block 0x1e, offset 0x780 0x780: 0x0040, 0x781: 0x0040, 0x782: 0x3308, 0x783: 0x0008, 0x784: 0x0040, 0x785: 0x0008, 0x786: 0x0008, 0x787: 0x0008, 0x788: 0x0008, 0x789: 0x0008, 0x78a: 0x0008, 0x78b: 0x0040, 0x78c: 0x0040, 0x78d: 0x0040, 0x78e: 0x0008, 0x78f: 0x0008, 0x790: 0x0008, 0x791: 0x0040, 0x792: 0x0008, 0x793: 0x0008, 0x794: 0x0008, 0x795: 0x0008, 0x796: 0x0040, 0x797: 0x0040, 0x798: 0x0040, 0x799: 0x0008, 0x79a: 0x0008, 0x79b: 0x0040, 0x79c: 0x0008, 0x79d: 0x0040, 0x79e: 0x0008, 0x79f: 0x0008, 0x7a0: 0x0040, 0x7a1: 0x0040, 0x7a2: 0x0040, 0x7a3: 0x0008, 0x7a4: 0x0008, 0x7a5: 0x0040, 0x7a6: 0x0040, 0x7a7: 0x0040, 0x7a8: 0x0008, 0x7a9: 0x0008, 0x7aa: 0x0008, 0x7ab: 0x0040, 0x7ac: 0x0040, 0x7ad: 0x0040, 0x7ae: 0x0008, 0x7af: 0x0008, 0x7b0: 0x0008, 0x7b1: 0x0008, 0x7b2: 0x0008, 0x7b3: 0x0008, 0x7b4: 0x0008, 0x7b5: 0x0008, 0x7b6: 0x0008, 0x7b7: 0x0008, 0x7b8: 0x0008, 0x7b9: 0x0008, 0x7ba: 0x0040, 0x7bb: 0x0040, 0x7bc: 0x0040, 0x7bd: 0x0040, 0x7be: 0x3008, 0x7bf: 0x3008, // Block 0x1f, offset 0x7c0 0x7c0: 0x3308, 0x7c1: 0x3008, 0x7c2: 0x3008, 0x7c3: 0x3008, 0x7c4: 0x3008, 0x7c5: 0x0040, 0x7c6: 0x3308, 0x7c7: 0x3308, 0x7c8: 0x3308, 0x7c9: 0x0040, 0x7ca: 0x3308, 0x7cb: 0x3308, 0x7cc: 0x3308, 0x7cd: 0x3b08, 0x7ce: 0x0040, 0x7cf: 0x0040, 0x7d0: 0x0040, 0x7d1: 0x0040, 0x7d2: 0x0040, 0x7d3: 0x0040, 0x7d4: 0x0040, 0x7d5: 0x3308, 0x7d6: 0x3308, 0x7d7: 0x0040, 0x7d8: 0x0008, 0x7d9: 0x0008, 0x7da: 0x0008, 0x7db: 0x0040, 0x7dc: 0x0040, 0x7dd: 0x0040, 0x7de: 0x0040, 0x7df: 0x0040, 0x7e0: 0x0008, 0x7e1: 0x0008, 0x7e2: 0x3308, 0x7e3: 0x3308, 0x7e4: 0x0040, 0x7e5: 0x0040, 0x7e6: 0x0008, 0x7e7: 0x0008, 0x7e8: 0x0008, 0x7e9: 0x0008, 0x7ea: 0x0008, 0x7eb: 0x0008, 0x7ec: 0x0008, 0x7ed: 0x0008, 0x7ee: 0x0008, 0x7ef: 0x0008, 0x7f0: 0x0040, 0x7f1: 0x0040, 0x7f2: 0x0040, 0x7f3: 0x0040, 0x7f4: 0x0040, 0x7f5: 0x0040, 0x7f6: 0x0040, 0x7f7: 0x0040, 0x7f8: 0x0018, 0x7f9: 0x0018, 0x7fa: 0x0018, 0x7fb: 0x0018, 0x7fc: 0x0018, 0x7fd: 0x0018, 0x7fe: 0x0018, 0x7ff: 0x0018, // Block 0x20, offset 0x800 0x800: 0x0008, 0x801: 0x3308, 0x802: 0x3008, 0x803: 0x3008, 0x804: 0x0040, 0x805: 0x0008, 0x806: 0x0008, 0x807: 0x0008, 0x808: 0x0008, 0x809: 0x0008, 0x80a: 0x0008, 0x80b: 0x0008, 0x80c: 0x0008, 0x80d: 0x0040, 0x80e: 0x0008, 0x80f: 0x0008, 0x810: 0x0008, 0x811: 0x0040, 0x812: 0x0008, 0x813: 0x0008, 0x814: 0x0008, 0x815: 0x0008, 0x816: 0x0008, 0x817: 0x0008, 0x818: 0x0008, 0x819: 0x0008, 0x81a: 0x0008, 0x81b: 0x0008, 0x81c: 0x0008, 0x81d: 0x0008, 0x81e: 0x0008, 0x81f: 0x0008, 0x820: 0x0008, 0x821: 0x0008, 0x822: 0x0008, 0x823: 0x0008, 0x824: 0x0008, 0x825: 0x0008, 0x826: 0x0008, 0x827: 0x0008, 0x828: 0x0008, 0x829: 0x0040, 0x82a: 0x0008, 0x82b: 0x0008, 0x82c: 0x0008, 0x82d: 0x0008, 0x82e: 0x0008, 0x82f: 0x0008, 0x830: 0x0008, 0x831: 0x0008, 0x832: 0x0008, 0x833: 0x0008, 0x834: 0x0040, 0x835: 0x0008, 0x836: 0x0008, 0x837: 0x0008, 0x838: 0x0008, 0x839: 0x0008, 0x83a: 0x0040, 0x83b: 0x0040, 0x83c: 0x3308, 0x83d: 0x0008, 0x83e: 0x3008, 0x83f: 0x3308, // Block 0x21, offset 0x840 0x840: 0x3008, 0x841: 0x3008, 0x842: 0x3008, 0x843: 0x3008, 0x844: 0x3008, 0x845: 0x0040, 0x846: 0x3308, 0x847: 0x3008, 0x848: 0x3008, 0x849: 0x0040, 0x84a: 0x3008, 0x84b: 0x3008, 0x84c: 0x3308, 0x84d: 0x3b08, 0x84e: 0x0040, 0x84f: 0x0040, 0x850: 0x0040, 0x851: 0x0040, 0x852: 0x0040, 0x853: 0x0040, 0x854: 0x0040, 0x855: 0x3008, 0x856: 0x3008, 0x857: 0x0040, 0x858: 0x0040, 0x859: 0x0040, 0x85a: 0x0040, 0x85b: 0x0040, 0x85c: 0x0040, 0x85d: 0x0040, 0x85e: 0x0008, 0x85f: 0x0040, 0x860: 0x0008, 0x861: 0x0008, 0x862: 0x3308, 0x863: 0x3308, 0x864: 0x0040, 0x865: 0x0040, 0x866: 0x0008, 0x867: 0x0008, 0x868: 0x0008, 0x869: 0x0008, 0x86a: 0x0008, 0x86b: 0x0008, 0x86c: 0x0008, 0x86d: 0x0008, 0x86e: 0x0008, 0x86f: 0x0008, 0x870: 0x0040, 0x871: 0x0008, 0x872: 0x0008, 0x873: 0x0040, 0x874: 0x0040, 0x875: 0x0040, 0x876: 0x0040, 0x877: 0x0040, 0x878: 0x0040, 0x879: 0x0040, 0x87a: 0x0040, 0x87b: 0x0040, 0x87c: 0x0040, 0x87d: 0x0040, 0x87e: 0x0040, 0x87f: 0x0040, // Block 0x22, offset 0x880 0x880: 0x3008, 0x881: 0x3308, 0x882: 0x3308, 0x883: 0x3308, 0x884: 0x3308, 0x885: 0x0040, 0x886: 0x3008, 0x887: 0x3008, 0x888: 0x3008, 0x889: 0x0040, 0x88a: 0x3008, 0x88b: 0x3008, 0x88c: 0x3008, 0x88d: 0x3b08, 0x88e: 0x0008, 0x88f: 0x0018, 0x890: 0x0040, 0x891: 0x0040, 0x892: 0x0040, 0x893: 0x0040, 0x894: 0x0008, 0x895: 0x0008, 0x896: 0x0008, 0x897: 0x3008, 0x898: 0x0018, 0x899: 0x0018, 0x89a: 0x0018, 0x89b: 0x0018, 0x89c: 0x0018, 0x89d: 0x0018, 0x89e: 0x0018, 0x89f: 0x0008, 0x8a0: 0x0008, 0x8a1: 0x0008, 0x8a2: 0x3308, 0x8a3: 0x3308, 0x8a4: 0x0040, 0x8a5: 0x0040, 0x8a6: 0x0008, 0x8a7: 0x0008, 0x8a8: 0x0008, 0x8a9: 0x0008, 0x8aa: 0x0008, 0x8ab: 0x0008, 0x8ac: 0x0008, 0x8ad: 0x0008, 0x8ae: 0x0008, 0x8af: 0x0008, 0x8b0: 0x0018, 0x8b1: 0x0018, 0x8b2: 0x0018, 0x8b3: 0x0018, 0x8b4: 0x0018, 0x8b5: 0x0018, 0x8b6: 0x0018, 0x8b7: 0x0018, 0x8b8: 0x0018, 0x8b9: 0x0018, 0x8ba: 0x0008, 0x8bb: 0x0008, 0x8bc: 0x0008, 0x8bd: 0x0008, 0x8be: 0x0008, 0x8bf: 0x0008, // Block 0x23, offset 0x8c0 0x8c0: 0x0040, 0x8c1: 0x0008, 0x8c2: 0x0008, 0x8c3: 0x0040, 0x8c4: 0x0008, 0x8c5: 0x0040, 0x8c6: 0x0040, 0x8c7: 0x0008, 0x8c8: 0x0008, 0x8c9: 0x0040, 0x8ca: 0x0008, 0x8cb: 0x0040, 0x8cc: 0x0040, 0x8cd: 0x0008, 0x8ce: 0x0040, 0x8cf: 0x0040, 0x8d0: 0x0040, 0x8d1: 0x0040, 0x8d2: 0x0040, 0x8d3: 0x0040, 0x8d4: 0x0008, 0x8d5: 0x0008, 0x8d6: 0x0008, 0x8d7: 0x0008, 0x8d8: 0x0040, 0x8d9: 0x0008, 0x8da: 0x0008, 0x8db: 0x0008, 0x8dc: 0x0008, 0x8dd: 0x0008, 0x8de: 0x0008, 0x8df: 0x0008, 0x8e0: 0x0040, 0x8e1: 0x0008, 0x8e2: 0x0008, 0x8e3: 0x0008, 0x8e4: 0x0040, 0x8e5: 0x0008, 0x8e6: 0x0040, 0x8e7: 0x0008, 0x8e8: 0x0040, 0x8e9: 0x0040, 0x8ea: 0x0008, 0x8eb: 0x0008, 0x8ec: 0x0040, 0x8ed: 0x0008, 0x8ee: 0x0008, 0x8ef: 0x0008, 0x8f0: 0x0008, 0x8f1: 0x3308, 0x8f2: 0x0008, 0x8f3: 0x0929, 0x8f4: 0x3308, 0x8f5: 0x3308, 0x8f6: 0x3308, 0x8f7: 0x3308, 0x8f8: 0x3308, 0x8f9: 0x3308, 0x8fa: 0x0040, 0x8fb: 0x3308, 0x8fc: 0x3308, 0x8fd: 0x0008, 0x8fe: 0x0040, 0x8ff: 0x0040, // Block 0x24, offset 0x900 0x900: 0x0008, 0x901: 0x0008, 0x902: 0x0008, 0x903: 0x09d1, 0x904: 0x0008, 0x905: 0x0008, 0x906: 0x0008, 0x907: 0x0008, 0x908: 0x0040, 0x909: 0x0008, 0x90a: 0x0008, 0x90b: 0x0008, 0x90c: 0x0008, 0x90d: 0x0a09, 0x90e: 0x0008, 0x90f: 0x0008, 0x910: 0x0008, 0x911: 0x0008, 0x912: 0x0a41, 0x913: 0x0008, 0x914: 0x0008, 0x915: 0x0008, 0x916: 0x0008, 0x917: 0x0a79, 0x918: 0x0008, 0x919: 0x0008, 0x91a: 0x0008, 0x91b: 0x0008, 0x91c: 0x0ab1, 0x91d: 0x0008, 0x91e: 0x0008, 0x91f: 0x0008, 0x920: 0x0008, 0x921: 0x0008, 0x922: 0x0008, 0x923: 0x0008, 0x924: 0x0008, 0x925: 0x0008, 0x926: 0x0008, 0x927: 0x0008, 0x928: 0x0008, 0x929: 0x0ae9, 0x92a: 0x0008, 0x92b: 0x0008, 0x92c: 0x0008, 0x92d: 0x0040, 0x92e: 0x0040, 0x92f: 0x0040, 0x930: 0x0040, 0x931: 0x3308, 0x932: 0x3308, 0x933: 0x0b21, 0x934: 0x3308, 0x935: 0x0b59, 0x936: 0x0b91, 0x937: 0x0bc9, 0x938: 0x0c19, 0x939: 0x0c51, 0x93a: 0x3308, 0x93b: 0x3308, 0x93c: 0x3308, 0x93d: 0x3308, 0x93e: 0x3308, 0x93f: 0x3008, // Block 0x25, offset 0x940 0x940: 0x3308, 0x941: 0x0ca1, 0x942: 0x3308, 0x943: 0x3308, 0x944: 0x3b08, 0x945: 0x0018, 0x946: 0x3308, 0x947: 0x3308, 0x948: 0x0008, 0x949: 0x0008, 0x94a: 0x0008, 0x94b: 0x0008, 0x94c: 0x0008, 0x94d: 0x3308, 0x94e: 0x3308, 0x94f: 0x3308, 0x950: 0x3308, 0x951: 0x3308, 0x952: 0x3308, 0x953: 0x0cd9, 0x954: 0x3308, 0x955: 0x3308, 0x956: 0x3308, 0x957: 0x3308, 0x958: 0x0040, 0x959: 0x3308, 0x95a: 0x3308, 0x95b: 0x3308, 0x95c: 0x3308, 0x95d: 0x0d11, 0x95e: 0x3308, 0x95f: 0x3308, 0x960: 0x3308, 0x961: 0x3308, 0x962: 0x0d49, 0x963: 0x3308, 0x964: 0x3308, 0x965: 0x3308, 0x966: 0x3308, 0x967: 0x0d81, 0x968: 0x3308, 0x969: 0x3308, 0x96a: 0x3308, 0x96b: 0x3308, 0x96c: 0x0db9, 0x96d: 0x3308, 0x96e: 0x3308, 0x96f: 0x3308, 0x970: 0x3308, 0x971: 0x3308, 0x972: 0x3308, 0x973: 0x3308, 0x974: 0x3308, 0x975: 0x3308, 0x976: 0x3308, 0x977: 0x3308, 0x978: 0x3308, 0x979: 0x0df1, 0x97a: 0x3308, 0x97b: 0x3308, 0x97c: 0x3308, 0x97d: 0x0040, 0x97e: 0x0018, 0x97f: 0x0018, // Block 0x26, offset 0x980 0x980: 0x0008, 0x981: 0x0008, 0x982: 0x0008, 0x983: 0x0008, 0x984: 0x0008, 0x985: 0x0008, 0x986: 0x0008, 0x987: 0x0008, 0x988: 0x0008, 0x989: 0x0008, 0x98a: 0x0008, 0x98b: 0x0008, 0x98c: 0x0008, 0x98d: 0x0008, 0x98e: 0x0008, 0x98f: 0x0008, 0x990: 0x0008, 0x991: 0x0008, 0x992: 0x0008, 0x993: 0x0008, 0x994: 0x0008, 0x995: 0x0008, 0x996: 0x0008, 0x997: 0x0008, 0x998: 0x0008, 0x999: 0x0008, 0x99a: 0x0008, 0x99b: 0x0008, 0x99c: 0x0008, 0x99d: 0x0008, 0x99e: 0x0008, 0x99f: 0x0008, 0x9a0: 0x0008, 0x9a1: 0x0008, 0x9a2: 0x0008, 0x9a3: 0x0008, 0x9a4: 0x0008, 0x9a5: 0x0008, 0x9a6: 0x0008, 0x9a7: 0x0008, 0x9a8: 0x0008, 0x9a9: 0x0008, 0x9aa: 0x0008, 0x9ab: 0x0008, 0x9ac: 0x0039, 0x9ad: 0x0ed1, 0x9ae: 0x0ee9, 0x9af: 0x0008, 0x9b0: 0x0ef9, 0x9b1: 0x0f09, 0x9b2: 0x0f19, 0x9b3: 0x0f31, 0x9b4: 0x0249, 0x9b5: 0x0f41, 0x9b6: 0x0259, 0x9b7: 0x0f51, 0x9b8: 0x0359, 0x9b9: 0x0f61, 0x9ba: 0x0f71, 0x9bb: 0x0008, 0x9bc: 0x00d9, 0x9bd: 0x0f81, 0x9be: 0x0f99, 0x9bf: 0x0269, // Block 0x27, offset 0x9c0 0x9c0: 0x0fa9, 0x9c1: 0x0fb9, 0x9c2: 0x0279, 0x9c3: 0x0039, 0x9c4: 0x0fc9, 0x9c5: 0x0fe1, 0x9c6: 0x059d, 0x9c7: 0x0ee9, 0x9c8: 0x0ef9, 0x9c9: 0x0f09, 0x9ca: 0x0ff9, 0x9cb: 0x1011, 0x9cc: 0x1029, 0x9cd: 0x0f31, 0x9ce: 0x0008, 0x9cf: 0x0f51, 0x9d0: 0x0f61, 0x9d1: 0x1041, 0x9d2: 0x00d9, 0x9d3: 0x1059, 0x9d4: 0x05b5, 0x9d5: 0x05b5, 0x9d6: 0x0f99, 0x9d7: 0x0fa9, 0x9d8: 0x0fb9, 0x9d9: 0x059d, 0x9da: 0x1071, 0x9db: 0x1089, 0x9dc: 0x05cd, 0x9dd: 0x1099, 0x9de: 0x10b1, 0x9df: 0x10c9, 0x9e0: 0x10e1, 0x9e1: 0x10f9, 0x9e2: 0x0f41, 0x9e3: 0x0269, 0x9e4: 0x0fb9, 0x9e5: 0x1089, 0x9e6: 0x1099, 0x9e7: 0x10b1, 0x9e8: 0x1111, 0x9e9: 0x10e1, 0x9ea: 0x10f9, 0x9eb: 0x0008, 0x9ec: 0x0008, 0x9ed: 0x0008, 0x9ee: 0x0008, 0x9ef: 0x0008, 0x9f0: 0x0008, 0x9f1: 0x0008, 0x9f2: 0x0008, 0x9f3: 0x0008, 0x9f4: 0x0008, 0x9f5: 0x0008, 0x9f6: 0x0008, 0x9f7: 0x0008, 0x9f8: 0x1129, 0x9f9: 0x0008, 0x9fa: 0x0008, 0x9fb: 0x0008, 0x9fc: 0x0008, 0x9fd: 0x0008, 0x9fe: 0x0008, 0x9ff: 0x0008, // Block 0x28, offset 0xa00 0xa00: 0x0008, 0xa01: 0x0008, 0xa02: 0x0008, 0xa03: 0x0008, 0xa04: 0x0008, 0xa05: 0x0008, 0xa06: 0x0008, 0xa07: 0x0008, 0xa08: 0x0008, 0xa09: 0x0008, 0xa0a: 0x0008, 0xa0b: 0x0008, 0xa0c: 0x0008, 0xa0d: 0x0008, 0xa0e: 0x0008, 0xa0f: 0x0008, 0xa10: 0x0008, 0xa11: 0x0008, 0xa12: 0x0008, 0xa13: 0x0008, 0xa14: 0x0008, 0xa15: 0x0008, 0xa16: 0x0008, 0xa17: 0x0008, 0xa18: 0x0008, 0xa19: 0x0008, 0xa1a: 0x0008, 0xa1b: 0x1141, 0xa1c: 0x1159, 0xa1d: 0x1169, 0xa1e: 0x1181, 0xa1f: 0x1029, 0xa20: 0x1199, 0xa21: 0x11a9, 0xa22: 0x11c1, 0xa23: 0x11d9, 0xa24: 0x11f1, 0xa25: 0x1209, 0xa26: 0x1221, 0xa27: 0x05e5, 0xa28: 0x1239, 0xa29: 0x1251, 0xa2a: 0xe17d, 0xa2b: 0x1269, 0xa2c: 0x1281, 0xa2d: 0x1299, 0xa2e: 0x12b1, 0xa2f: 0x12c9, 0xa30: 0x12e1, 0xa31: 0x12f9, 0xa32: 0x1311, 0xa33: 0x1329, 0xa34: 0x1341, 0xa35: 0x1359, 0xa36: 0x1371, 0xa37: 0x1389, 0xa38: 0x05fd, 0xa39: 0x13a1, 0xa3a: 0x13b9, 0xa3b: 0x13d1, 0xa3c: 0x13e1, 0xa3d: 0x13f9, 0xa3e: 0x1411, 0xa3f: 0x1429, // Block 0x29, offset 0xa40 0xa40: 0xe00d, 0xa41: 0x0008, 0xa42: 0xe00d, 0xa43: 0x0008, 0xa44: 0xe00d, 0xa45: 0x0008, 0xa46: 0xe00d, 0xa47: 0x0008, 0xa48: 0xe00d, 0xa49: 0x0008, 0xa4a: 0xe00d, 0xa4b: 0x0008, 0xa4c: 0xe00d, 0xa4d: 0x0008, 0xa4e: 0xe00d, 0xa4f: 0x0008, 0xa50: 0xe00d, 0xa51: 0x0008, 0xa52: 0xe00d, 0xa53: 0x0008, 0xa54: 0xe00d, 0xa55: 0x0008, 0xa56: 0xe00d, 0xa57: 0x0008, 0xa58: 0xe00d, 0xa59: 0x0008, 0xa5a: 0xe00d, 0xa5b: 0x0008, 0xa5c: 0xe00d, 0xa5d: 0x0008, 0xa5e: 0xe00d, 0xa5f: 0x0008, 0xa60: 0xe00d, 0xa61: 0x0008, 0xa62: 0xe00d, 0xa63: 0x0008, 0xa64: 0xe00d, 0xa65: 0x0008, 0xa66: 0xe00d, 0xa67: 0x0008, 0xa68: 0xe00d, 0xa69: 0x0008, 0xa6a: 0xe00d, 0xa6b: 0x0008, 0xa6c: 0xe00d, 0xa6d: 0x0008, 0xa6e: 0xe00d, 0xa6f: 0x0008, 0xa70: 0xe00d, 0xa71: 0x0008, 0xa72: 0xe00d, 0xa73: 0x0008, 0xa74: 0xe00d, 0xa75: 0x0008, 0xa76: 0xe00d, 0xa77: 0x0008, 0xa78: 0xe00d, 0xa79: 0x0008, 0xa7a: 0xe00d, 0xa7b: 0x0008, 0xa7c: 0xe00d, 0xa7d: 0x0008, 0xa7e: 0xe00d, 0xa7f: 0x0008, // Block 0x2a, offset 0xa80 0xa80: 0xe00d, 0xa81: 0x0008, 0xa82: 0xe00d, 0xa83: 0x0008, 0xa84: 0xe00d, 0xa85: 0x0008, 0xa86: 0xe00d, 0xa87: 0x0008, 0xa88: 0xe00d, 0xa89: 0x0008, 0xa8a: 0xe00d, 0xa8b: 0x0008, 0xa8c: 0xe00d, 0xa8d: 0x0008, 0xa8e: 0xe00d, 0xa8f: 0x0008, 0xa90: 0xe00d, 0xa91: 0x0008, 0xa92: 0xe00d, 0xa93: 0x0008, 0xa94: 0xe00d, 0xa95: 0x0008, 0xa96: 0x0008, 0xa97: 0x0008, 0xa98: 0x0008, 0xa99: 0x0008, 0xa9a: 0x0615, 0xa9b: 0x0635, 0xa9c: 0x0008, 0xa9d: 0x0008, 0xa9e: 0x1441, 0xa9f: 0x0008, 0xaa0: 0xe00d, 0xaa1: 0x0008, 0xaa2: 0xe00d, 0xaa3: 0x0008, 0xaa4: 0xe00d, 0xaa5: 0x0008, 0xaa6: 0xe00d, 0xaa7: 0x0008, 0xaa8: 0xe00d, 0xaa9: 0x0008, 0xaaa: 0xe00d, 0xaab: 0x0008, 0xaac: 0xe00d, 0xaad: 0x0008, 0xaae: 0xe00d, 0xaaf: 0x0008, 0xab0: 0xe00d, 0xab1: 0x0008, 0xab2: 0xe00d, 0xab3: 0x0008, 0xab4: 0xe00d, 0xab5: 0x0008, 0xab6: 0xe00d, 0xab7: 0x0008, 0xab8: 0xe00d, 0xab9: 0x0008, 0xaba: 0xe00d, 0xabb: 0x0008, 0xabc: 0xe00d, 0xabd: 0x0008, 0xabe: 0xe00d, 0xabf: 0x0008, // Block 0x2b, offset 0xac0 0xac0: 0x0008, 0xac1: 0x0008, 0xac2: 0x0008, 0xac3: 0x0008, 0xac4: 0x0008, 0xac5: 0x0008, 0xac6: 0x0040, 0xac7: 0x0040, 0xac8: 0xe045, 0xac9: 0xe045, 0xaca: 0xe045, 0xacb: 0xe045, 0xacc: 0xe045, 0xacd: 0xe045, 0xace: 0x0040, 0xacf: 0x0040, 0xad0: 0x0008, 0xad1: 0x0008, 0xad2: 0x0008, 0xad3: 0x0008, 0xad4: 0x0008, 0xad5: 0x0008, 0xad6: 0x0008, 0xad7: 0x0008, 0xad8: 0x0040, 0xad9: 0xe045, 0xada: 0x0040, 0xadb: 0xe045, 0xadc: 0x0040, 0xadd: 0xe045, 0xade: 0x0040, 0xadf: 0xe045, 0xae0: 0x0008, 0xae1: 0x0008, 0xae2: 0x0008, 0xae3: 0x0008, 0xae4: 0x0008, 0xae5: 0x0008, 0xae6: 0x0008, 0xae7: 0x0008, 0xae8: 0xe045, 0xae9: 0xe045, 0xaea: 0xe045, 0xaeb: 0xe045, 0xaec: 0xe045, 0xaed: 0xe045, 0xaee: 0xe045, 0xaef: 0xe045, 0xaf0: 0x0008, 0xaf1: 0x1459, 0xaf2: 0x0008, 0xaf3: 0x1471, 0xaf4: 0x0008, 0xaf5: 0x1489, 0xaf6: 0x0008, 0xaf7: 0x14a1, 0xaf8: 0x0008, 0xaf9: 0x14b9, 0xafa: 0x0008, 0xafb: 0x14d1, 0xafc: 0x0008, 0xafd: 0x14e9, 0xafe: 0x0040, 0xaff: 0x0040, // Block 0x2c, offset 0xb00 0xb00: 0x1501, 0xb01: 0x1531, 0xb02: 0x1561, 0xb03: 0x1591, 0xb04: 0x15c1, 0xb05: 0x15f1, 0xb06: 0x1621, 0xb07: 0x1651, 0xb08: 0x1501, 0xb09: 0x1531, 0xb0a: 0x1561, 0xb0b: 0x1591, 0xb0c: 0x15c1, 0xb0d: 0x15f1, 0xb0e: 0x1621, 0xb0f: 0x1651, 0xb10: 0x1681, 0xb11: 0x16b1, 0xb12: 0x16e1, 0xb13: 0x1711, 0xb14: 0x1741, 0xb15: 0x1771, 0xb16: 0x17a1, 0xb17: 0x17d1, 0xb18: 0x1681, 0xb19: 0x16b1, 0xb1a: 0x16e1, 0xb1b: 0x1711, 0xb1c: 0x1741, 0xb1d: 0x1771, 0xb1e: 0x17a1, 0xb1f: 0x17d1, 0xb20: 0x1801, 0xb21: 0x1831, 0xb22: 0x1861, 0xb23: 0x1891, 0xb24: 0x18c1, 0xb25: 0x18f1, 0xb26: 0x1921, 0xb27: 0x1951, 0xb28: 0x1801, 0xb29: 0x1831, 0xb2a: 0x1861, 0xb2b: 0x1891, 0xb2c: 0x18c1, 0xb2d: 0x18f1, 0xb2e: 0x1921, 0xb2f: 0x1951, 0xb30: 0x0008, 0xb31: 0x0008, 0xb32: 0x1981, 0xb33: 0x19b1, 0xb34: 0x19d9, 0xb35: 0x0040, 0xb36: 0x0008, 0xb37: 0x1a01, 0xb38: 0xe045, 0xb39: 0xe045, 0xb3a: 0x064d, 0xb3b: 0x1459, 0xb3c: 0x19b1, 0xb3d: 0x0666, 0xb3e: 0x1a31, 0xb3f: 0x0686, // Block 0x2d, offset 0xb40 0xb40: 0x06a6, 0xb41: 0x1a4a, 0xb42: 0x1a79, 0xb43: 0x1aa9, 0xb44: 0x1ad1, 0xb45: 0x0040, 0xb46: 0x0008, 0xb47: 0x1af9, 0xb48: 0x06c5, 0xb49: 0x1471, 0xb4a: 0x06dd, 0xb4b: 0x1489, 0xb4c: 0x1aa9, 0xb4d: 0x1b2a, 0xb4e: 0x1b5a, 0xb4f: 0x1b8a, 0xb50: 0x0008, 0xb51: 0x0008, 0xb52: 0x0008, 0xb53: 0x1bb9, 0xb54: 0x0040, 0xb55: 0x0040, 0xb56: 0x0008, 0xb57: 0x0008, 0xb58: 0xe045, 0xb59: 0xe045, 0xb5a: 0x06f5, 0xb5b: 0x14a1, 0xb5c: 0x0040, 0xb5d: 0x1bd2, 0xb5e: 0x1c02, 0xb5f: 0x1c32, 0xb60: 0x0008, 0xb61: 0x0008, 0xb62: 0x0008, 0xb63: 0x1c61, 0xb64: 0x0008, 0xb65: 0x0008, 0xb66: 0x0008, 0xb67: 0x0008, 0xb68: 0xe045, 0xb69: 0xe045, 0xb6a: 0x070d, 0xb6b: 0x14d1, 0xb6c: 0xe04d, 0xb6d: 0x1c7a, 0xb6e: 0x03d2, 0xb6f: 0x1caa, 0xb70: 0x0040, 0xb71: 0x0040, 0xb72: 0x1cb9, 0xb73: 0x1ce9, 0xb74: 0x1d11, 0xb75: 0x0040, 0xb76: 0x0008, 0xb77: 0x1d39, 0xb78: 0x0725, 0xb79: 0x14b9, 0xb7a: 0x0515, 0xb7b: 0x14e9, 0xb7c: 0x1ce9, 0xb7d: 0x073e, 0xb7e: 0x075e, 0xb7f: 0x0040, // Block 0x2e, offset 0xb80 0xb80: 0x000a, 0xb81: 0x000a, 0xb82: 0x000a, 0xb83: 0x000a, 0xb84: 0x000a, 0xb85: 0x000a, 0xb86: 0x000a, 0xb87: 0x000a, 0xb88: 0x000a, 0xb89: 0x000a, 0xb8a: 0x000a, 0xb8b: 0x03c0, 0xb8c: 0x0003, 0xb8d: 0x0003, 0xb8e: 0x0340, 0xb8f: 0x0b40, 0xb90: 0x0018, 0xb91: 0xe00d, 0xb92: 0x0018, 0xb93: 0x0018, 0xb94: 0x0018, 0xb95: 0x0018, 0xb96: 0x0018, 0xb97: 0x077e, 0xb98: 0x0018, 0xb99: 0x0018, 0xb9a: 0x0018, 0xb9b: 0x0018, 0xb9c: 0x0018, 0xb9d: 0x0018, 0xb9e: 0x0018, 0xb9f: 0x0018, 0xba0: 0x0018, 0xba1: 0x0018, 0xba2: 0x0018, 0xba3: 0x0018, 0xba4: 0x0040, 0xba5: 0x0040, 0xba6: 0x0040, 0xba7: 0x0018, 0xba8: 0x0040, 0xba9: 0x0040, 0xbaa: 0x0340, 0xbab: 0x0340, 0xbac: 0x0340, 0xbad: 0x0340, 0xbae: 0x0340, 0xbaf: 0x000a, 0xbb0: 0x0018, 0xbb1: 0x0018, 0xbb2: 0x0018, 0xbb3: 0x1d69, 0xbb4: 0x1da1, 0xbb5: 0x0018, 0xbb6: 0x1df1, 0xbb7: 0x1e29, 0xbb8: 0x0018, 0xbb9: 0x0018, 0xbba: 0x0018, 0xbbb: 0x0018, 0xbbc: 0x1e7a, 0xbbd: 0x0018, 0xbbe: 0x079e, 0xbbf: 0x0018, // Block 0x2f, offset 0xbc0 0xbc0: 0x0018, 0xbc1: 0x0018, 0xbc2: 0x0018, 0xbc3: 0x0018, 0xbc4: 0x0018, 0xbc5: 0x0018, 0xbc6: 0x0018, 0xbc7: 0x1e92, 0xbc8: 0x1eaa, 0xbc9: 0x1ec2, 0xbca: 0x0018, 0xbcb: 0x0018, 0xbcc: 0x0018, 0xbcd: 0x0018, 0xbce: 0x0018, 0xbcf: 0x0018, 0xbd0: 0x0018, 0xbd1: 0x0018, 0xbd2: 0x0018, 0xbd3: 0x0018, 0xbd4: 0x0018, 0xbd5: 0x0018, 0xbd6: 0x0018, 0xbd7: 0x1ed9, 0xbd8: 0x0018, 0xbd9: 0x0018, 0xbda: 0x0018, 0xbdb: 0x0018, 0xbdc: 0x0018, 0xbdd: 0x0018, 0xbde: 0x0018, 0xbdf: 0x000a, 0xbe0: 0x03c0, 0xbe1: 0x0340, 0xbe2: 0x0340, 0xbe3: 0x0340, 0xbe4: 0x03c0, 0xbe5: 0x0040, 0xbe6: 0x0040, 0xbe7: 0x0040, 0xbe8: 0x0040, 0xbe9: 0x0040, 0xbea: 0x0340, 0xbeb: 0x0340, 0xbec: 0x0340, 0xbed: 0x0340, 0xbee: 0x0340, 0xbef: 0x0340, 0xbf0: 0x1f41, 0xbf1: 0x0f41, 0xbf2: 0x0040, 0xbf3: 0x0040, 0xbf4: 0x1f51, 0xbf5: 0x1f61, 0xbf6: 0x1f71, 0xbf7: 0x1f81, 0xbf8: 0x1f91, 0xbf9: 0x1fa1, 0xbfa: 0x1fb2, 0xbfb: 0x07bd, 0xbfc: 0x1fc2, 0xbfd: 0x1fd2, 0xbfe: 0x1fe2, 0xbff: 0x0f71, // Block 0x30, offset 0xc00 0xc00: 0x1f41, 0xc01: 0x00c9, 0xc02: 0x0069, 0xc03: 0x0079, 0xc04: 0x1f51, 0xc05: 0x1f61, 0xc06: 0x1f71, 0xc07: 0x1f81, 0xc08: 0x1f91, 0xc09: 0x1fa1, 0xc0a: 0x1fb2, 0xc0b: 0x07d5, 0xc0c: 0x1fc2, 0xc0d: 0x1fd2, 0xc0e: 0x1fe2, 0xc0f: 0x0040, 0xc10: 0x0039, 0xc11: 0x0f09, 0xc12: 0x00d9, 0xc13: 0x0369, 0xc14: 0x0ff9, 0xc15: 0x0249, 0xc16: 0x0f51, 0xc17: 0x0359, 0xc18: 0x0f61, 0xc19: 0x0f71, 0xc1a: 0x0f99, 0xc1b: 0x01d9, 0xc1c: 0x0fa9, 0xc1d: 0x0040, 0xc1e: 0x0040, 0xc1f: 0x0040, 0xc20: 0x0018, 0xc21: 0x0018, 0xc22: 0x0018, 0xc23: 0x0018, 0xc24: 0x0018, 0xc25: 0x0018, 0xc26: 0x0018, 0xc27: 0x0018, 0xc28: 0x1ff1, 0xc29: 0x0018, 0xc2a: 0x0018, 0xc2b: 0x0018, 0xc2c: 0x0018, 0xc2d: 0x0018, 0xc2e: 0x0018, 0xc2f: 0x0018, 0xc30: 0x0018, 0xc31: 0x0018, 0xc32: 0x0018, 0xc33: 0x0018, 0xc34: 0x0018, 0xc35: 0x0018, 0xc36: 0x0018, 0xc37: 0x0018, 0xc38: 0x0018, 0xc39: 0x0018, 0xc3a: 0x0018, 0xc3b: 0x0018, 0xc3c: 0x0018, 0xc3d: 0x0018, 0xc3e: 0x0018, 0xc3f: 0x0040, // Block 0x31, offset 0xc40 0xc40: 0x07ee, 0xc41: 0x080e, 0xc42: 0x1159, 0xc43: 0x082d, 0xc44: 0x0018, 0xc45: 0x084e, 0xc46: 0x086e, 0xc47: 0x1011, 0xc48: 0x0018, 0xc49: 0x088d, 0xc4a: 0x0f31, 0xc4b: 0x0249, 0xc4c: 0x0249, 0xc4d: 0x0249, 0xc4e: 0x0249, 0xc4f: 0x2009, 0xc50: 0x0f41, 0xc51: 0x0f41, 0xc52: 0x0359, 0xc53: 0x0359, 0xc54: 0x0018, 0xc55: 0x0f71, 0xc56: 0x2021, 0xc57: 0x0018, 0xc58: 0x0018, 0xc59: 0x0f99, 0xc5a: 0x2039, 0xc5b: 0x0269, 0xc5c: 0x0269, 0xc5d: 0x0269, 0xc5e: 0x0018, 0xc5f: 0x0018, 0xc60: 0x2049, 0xc61: 0x08ad, 0xc62: 0x2061, 0xc63: 0x0018, 0xc64: 0x13d1, 0xc65: 0x0018, 0xc66: 0x2079, 0xc67: 0x0018, 0xc68: 0x13d1, 0xc69: 0x0018, 0xc6a: 0x0f51, 0xc6b: 0x2091, 0xc6c: 0x0ee9, 0xc6d: 0x1159, 0xc6e: 0x0018, 0xc6f: 0x0f09, 0xc70: 0x0f09, 0xc71: 0x1199, 0xc72: 0x0040, 0xc73: 0x0f61, 0xc74: 0x00d9, 0xc75: 0x20a9, 0xc76: 0x20c1, 0xc77: 0x20d9, 0xc78: 0x20f1, 0xc79: 0x0f41, 0xc7a: 0x0018, 0xc7b: 0x08cd, 0xc7c: 0x2109, 0xc7d: 0x10b1, 0xc7e: 0x10b1, 0xc7f: 0x2109, // Block 0x32, offset 0xc80 0xc80: 0x08ed, 0xc81: 0x0018, 0xc82: 0x0018, 0xc83: 0x0018, 0xc84: 0x0018, 0xc85: 0x0ef9, 0xc86: 0x0ef9, 0xc87: 0x0f09, 0xc88: 0x0f41, 0xc89: 0x0259, 0xc8a: 0x0018, 0xc8b: 0x0018, 0xc8c: 0x0018, 0xc8d: 0x0018, 0xc8e: 0x0008, 0xc8f: 0x0018, 0xc90: 0x2121, 0xc91: 0x2151, 0xc92: 0x2181, 0xc93: 0x21b9, 0xc94: 0x21e9, 0xc95: 0x2219, 0xc96: 0x2249, 0xc97: 0x2279, 0xc98: 0x22a9, 0xc99: 0x22d9, 0xc9a: 0x2309, 0xc9b: 0x2339, 0xc9c: 0x2369, 0xc9d: 0x2399, 0xc9e: 0x23c9, 0xc9f: 0x23f9, 0xca0: 0x0f41, 0xca1: 0x2421, 0xca2: 0x0905, 0xca3: 0x2439, 0xca4: 0x1089, 0xca5: 0x2451, 0xca6: 0x0925, 0xca7: 0x2469, 0xca8: 0x2491, 0xca9: 0x0369, 0xcaa: 0x24a9, 0xcab: 0x0945, 0xcac: 0x0359, 0xcad: 0x1159, 0xcae: 0x0ef9, 0xcaf: 0x0f61, 0xcb0: 0x0f41, 0xcb1: 0x2421, 0xcb2: 0x0965, 0xcb3: 0x2439, 0xcb4: 0x1089, 0xcb5: 0x2451, 0xcb6: 0x0985, 0xcb7: 0x2469, 0xcb8: 0x2491, 0xcb9: 0x0369, 0xcba: 0x24a9, 0xcbb: 0x09a5, 0xcbc: 0x0359, 0xcbd: 0x1159, 0xcbe: 0x0ef9, 0xcbf: 0x0f61, // Block 0x33, offset 0xcc0 0xcc0: 0x0018, 0xcc1: 0x0018, 0xcc2: 0x0018, 0xcc3: 0x0018, 0xcc4: 0x0018, 0xcc5: 0x0018, 0xcc6: 0x0018, 0xcc7: 0x0018, 0xcc8: 0x0018, 0xcc9: 0x0018, 0xcca: 0x0018, 0xccb: 0x0040, 0xccc: 0x0040, 0xccd: 0x0040, 0xcce: 0x0040, 0xccf: 0x0040, 0xcd0: 0x0040, 0xcd1: 0x0040, 0xcd2: 0x0040, 0xcd3: 0x0040, 0xcd4: 0x0040, 0xcd5: 0x0040, 0xcd6: 0x0040, 0xcd7: 0x0040, 0xcd8: 0x0040, 0xcd9: 0x0040, 0xcda: 0x0040, 0xcdb: 0x0040, 0xcdc: 0x0040, 0xcdd: 0x0040, 0xcde: 0x0040, 0xcdf: 0x0040, 0xce0: 0x00c9, 0xce1: 0x0069, 0xce2: 0x0079, 0xce3: 0x1f51, 0xce4: 0x1f61, 0xce5: 0x1f71, 0xce6: 0x1f81, 0xce7: 0x1f91, 0xce8: 0x1fa1, 0xce9: 0x2601, 0xcea: 0x2619, 0xceb: 0x2631, 0xcec: 0x2649, 0xced: 0x2661, 0xcee: 0x2679, 0xcef: 0x2691, 0xcf0: 0x26a9, 0xcf1: 0x26c1, 0xcf2: 0x26d9, 0xcf3: 0x26f1, 0xcf4: 0x0a06, 0xcf5: 0x0a26, 0xcf6: 0x0a46, 0xcf7: 0x0a66, 0xcf8: 0x0a86, 0xcf9: 0x0aa6, 0xcfa: 0x0ac6, 0xcfb: 0x0ae6, 0xcfc: 0x0b06, 0xcfd: 0x270a, 0xcfe: 0x2732, 0xcff: 0x275a, // Block 0x34, offset 0xd00 0xd00: 0x2782, 0xd01: 0x27aa, 0xd02: 0x27d2, 0xd03: 0x27fa, 0xd04: 0x2822, 0xd05: 0x284a, 0xd06: 0x2872, 0xd07: 0x289a, 0xd08: 0x0040, 0xd09: 0x0040, 0xd0a: 0x0040, 0xd0b: 0x0040, 0xd0c: 0x0040, 0xd0d: 0x0040, 0xd0e: 0x0040, 0xd0f: 0x0040, 0xd10: 0x0040, 0xd11: 0x0040, 0xd12: 0x0040, 0xd13: 0x0040, 0xd14: 0x0040, 0xd15: 0x0040, 0xd16: 0x0040, 0xd17: 0x0040, 0xd18: 0x0040, 0xd19: 0x0040, 0xd1a: 0x0040, 0xd1b: 0x0040, 0xd1c: 0x0b26, 0xd1d: 0x0b46, 0xd1e: 0x0b66, 0xd1f: 0x0b86, 0xd20: 0x0ba6, 0xd21: 0x0bc6, 0xd22: 0x0be6, 0xd23: 0x0c06, 0xd24: 0x0c26, 0xd25: 0x0c46, 0xd26: 0x0c66, 0xd27: 0x0c86, 0xd28: 0x0ca6, 0xd29: 0x0cc6, 0xd2a: 0x0ce6, 0xd2b: 0x0d06, 0xd2c: 0x0d26, 0xd2d: 0x0d46, 0xd2e: 0x0d66, 0xd2f: 0x0d86, 0xd30: 0x0da6, 0xd31: 0x0dc6, 0xd32: 0x0de6, 0xd33: 0x0e06, 0xd34: 0x0e26, 0xd35: 0x0e46, 0xd36: 0x0039, 0xd37: 0x0ee9, 0xd38: 0x1159, 0xd39: 0x0ef9, 0xd3a: 0x0f09, 0xd3b: 0x1199, 0xd3c: 0x0f31, 0xd3d: 0x0249, 0xd3e: 0x0f41, 0xd3f: 0x0259, // Block 0x35, offset 0xd40 0xd40: 0x0f51, 0xd41: 0x0359, 0xd42: 0x0f61, 0xd43: 0x0f71, 0xd44: 0x00d9, 0xd45: 0x0f99, 0xd46: 0x2039, 0xd47: 0x0269, 0xd48: 0x01d9, 0xd49: 0x0fa9, 0xd4a: 0x0fb9, 0xd4b: 0x1089, 0xd4c: 0x0279, 0xd4d: 0x0369, 0xd4e: 0x0289, 0xd4f: 0x13d1, 0xd50: 0x0039, 0xd51: 0x0ee9, 0xd52: 0x1159, 0xd53: 0x0ef9, 0xd54: 0x0f09, 0xd55: 0x1199, 0xd56: 0x0f31, 0xd57: 0x0249, 0xd58: 0x0f41, 0xd59: 0x0259, 0xd5a: 0x0f51, 0xd5b: 0x0359, 0xd5c: 0x0f61, 0xd5d: 0x0f71, 0xd5e: 0x00d9, 0xd5f: 0x0f99, 0xd60: 0x2039, 0xd61: 0x0269, 0xd62: 0x01d9, 0xd63: 0x0fa9, 0xd64: 0x0fb9, 0xd65: 0x1089, 0xd66: 0x0279, 0xd67: 0x0369, 0xd68: 0x0289, 0xd69: 0x13d1, 0xd6a: 0x1f41, 0xd6b: 0x0018, 0xd6c: 0x0018, 0xd6d: 0x0018, 0xd6e: 0x0018, 0xd6f: 0x0018, 0xd70: 0x0018, 0xd71: 0x0018, 0xd72: 0x0018, 0xd73: 0x0018, 0xd74: 0x0018, 0xd75: 0x0018, 0xd76: 0x0018, 0xd77: 0x0018, 0xd78: 0x0018, 0xd79: 0x0018, 0xd7a: 0x0018, 0xd7b: 0x0018, 0xd7c: 0x0018, 0xd7d: 0x0018, 0xd7e: 0x0018, 0xd7f: 0x0018, // Block 0x36, offset 0xd80 0xd80: 0x0008, 0xd81: 0x0008, 0xd82: 0x0008, 0xd83: 0x0008, 0xd84: 0x0008, 0xd85: 0x0008, 0xd86: 0x0008, 0xd87: 0x0008, 0xd88: 0x0008, 0xd89: 0x0008, 0xd8a: 0x0008, 0xd8b: 0x0008, 0xd8c: 0x0008, 0xd8d: 0x0008, 0xd8e: 0x0008, 0xd8f: 0x0008, 0xd90: 0x0008, 0xd91: 0x0008, 0xd92: 0x0008, 0xd93: 0x0008, 0xd94: 0x0008, 0xd95: 0x0008, 0xd96: 0x0008, 0xd97: 0x0008, 0xd98: 0x0008, 0xd99: 0x0008, 0xd9a: 0x0008, 0xd9b: 0x0008, 0xd9c: 0x0008, 0xd9d: 0x0008, 0xd9e: 0x0008, 0xd9f: 0x0040, 0xda0: 0xe00d, 0xda1: 0x0008, 0xda2: 0x2971, 0xda3: 0x0ebd, 0xda4: 0x2989, 0xda5: 0x0008, 0xda6: 0x0008, 0xda7: 0xe07d, 0xda8: 0x0008, 0xda9: 0xe01d, 0xdaa: 0x0008, 0xdab: 0xe03d, 0xdac: 0x0008, 0xdad: 0x0fe1, 0xdae: 0x1281, 0xdaf: 0x0fc9, 0xdb0: 0x1141, 0xdb1: 0x0008, 0xdb2: 0xe00d, 0xdb3: 0x0008, 0xdb4: 0x0008, 0xdb5: 0xe01d, 0xdb6: 0x0008, 0xdb7: 0x0008, 0xdb8: 0x0008, 0xdb9: 0x0008, 0xdba: 0x0008, 0xdbb: 0x0008, 0xdbc: 0x0259, 0xdbd: 0x1089, 0xdbe: 0x29a1, 0xdbf: 0x29b9, // Block 0x37, offset 0xdc0 0xdc0: 0xe00d, 0xdc1: 0x0008, 0xdc2: 0xe00d, 0xdc3: 0x0008, 0xdc4: 0xe00d, 0xdc5: 0x0008, 0xdc6: 0xe00d, 0xdc7: 0x0008, 0xdc8: 0xe00d, 0xdc9: 0x0008, 0xdca: 0xe00d, 0xdcb: 0x0008, 0xdcc: 0xe00d, 0xdcd: 0x0008, 0xdce: 0xe00d, 0xdcf: 0x0008, 0xdd0: 0xe00d, 0xdd1: 0x0008, 0xdd2: 0xe00d, 0xdd3: 0x0008, 0xdd4: 0xe00d, 0xdd5: 0x0008, 0xdd6: 0xe00d, 0xdd7: 0x0008, 0xdd8: 0xe00d, 0xdd9: 0x0008, 0xdda: 0xe00d, 0xddb: 0x0008, 0xddc: 0xe00d, 0xddd: 0x0008, 0xdde: 0xe00d, 0xddf: 0x0008, 0xde0: 0xe00d, 0xde1: 0x0008, 0xde2: 0xe00d, 0xde3: 0x0008, 0xde4: 0x0008, 0xde5: 0x0018, 0xde6: 0x0018, 0xde7: 0x0018, 0xde8: 0x0018, 0xde9: 0x0018, 0xdea: 0x0018, 0xdeb: 0xe03d, 0xdec: 0x0008, 0xded: 0xe01d, 0xdee: 0x0008, 0xdef: 0x3308, 0xdf0: 0x3308, 0xdf1: 0x3308, 0xdf2: 0xe00d, 0xdf3: 0x0008, 0xdf4: 0x0040, 0xdf5: 0x0040, 0xdf6: 0x0040, 0xdf7: 0x0040, 0xdf8: 0x0040, 0xdf9: 0x0018, 0xdfa: 0x0018, 0xdfb: 0x0018, 0xdfc: 0x0018, 0xdfd: 0x0018, 0xdfe: 0x0018, 0xdff: 0x0018, // Block 0x38, offset 0xe00 0xe00: 0x26fd, 0xe01: 0x271d, 0xe02: 0x273d, 0xe03: 0x275d, 0xe04: 0x277d, 0xe05: 0x279d, 0xe06: 0x27bd, 0xe07: 0x27dd, 0xe08: 0x27fd, 0xe09: 0x281d, 0xe0a: 0x283d, 0xe0b: 0x285d, 0xe0c: 0x287d, 0xe0d: 0x289d, 0xe0e: 0x28bd, 0xe0f: 0x28dd, 0xe10: 0x28fd, 0xe11: 0x291d, 0xe12: 0x293d, 0xe13: 0x295d, 0xe14: 0x297d, 0xe15: 0x299d, 0xe16: 0x0040, 0xe17: 0x0040, 0xe18: 0x0040, 0xe19: 0x0040, 0xe1a: 0x0040, 0xe1b: 0x0040, 0xe1c: 0x0040, 0xe1d: 0x0040, 0xe1e: 0x0040, 0xe1f: 0x0040, 0xe20: 0x0040, 0xe21: 0x0040, 0xe22: 0x0040, 0xe23: 0x0040, 0xe24: 0x0040, 0xe25: 0x0040, 0xe26: 0x0040, 0xe27: 0x0040, 0xe28: 0x0040, 0xe29: 0x0040, 0xe2a: 0x0040, 0xe2b: 0x0040, 0xe2c: 0x0040, 0xe2d: 0x0040, 0xe2e: 0x0040, 0xe2f: 0x0040, 0xe30: 0x0040, 0xe31: 0x0040, 0xe32: 0x0040, 0xe33: 0x0040, 0xe34: 0x0040, 0xe35: 0x0040, 0xe36: 0x0040, 0xe37: 0x0040, 0xe38: 0x0040, 0xe39: 0x0040, 0xe3a: 0x0040, 0xe3b: 0x0040, 0xe3c: 0x0040, 0xe3d: 0x0040, 0xe3e: 0x0040, 0xe3f: 0x0040, // Block 0x39, offset 0xe40 0xe40: 0x000a, 0xe41: 0x0018, 0xe42: 0x29d1, 0xe43: 0x0018, 0xe44: 0x0018, 0xe45: 0x0008, 0xe46: 0x0008, 0xe47: 0x0008, 0xe48: 0x0018, 0xe49: 0x0018, 0xe4a: 0x0018, 0xe4b: 0x0018, 0xe4c: 0x0018, 0xe4d: 0x0018, 0xe4e: 0x0018, 0xe4f: 0x0018, 0xe50: 0x0018, 0xe51: 0x0018, 0xe52: 0x0018, 0xe53: 0x0018, 0xe54: 0x0018, 0xe55: 0x0018, 0xe56: 0x0018, 0xe57: 0x0018, 0xe58: 0x0018, 0xe59: 0x0018, 0xe5a: 0x0018, 0xe5b: 0x0018, 0xe5c: 0x0018, 0xe5d: 0x0018, 0xe5e: 0x0018, 0xe5f: 0x0018, 0xe60: 0x0018, 0xe61: 0x0018, 0xe62: 0x0018, 0xe63: 0x0018, 0xe64: 0x0018, 0xe65: 0x0018, 0xe66: 0x0018, 0xe67: 0x0018, 0xe68: 0x0018, 0xe69: 0x0018, 0xe6a: 0x3308, 0xe6b: 0x3308, 0xe6c: 0x3308, 0xe6d: 0x3308, 0xe6e: 0x3018, 0xe6f: 0x3018, 0xe70: 0x0018, 0xe71: 0x0018, 0xe72: 0x0018, 0xe73: 0x0018, 0xe74: 0x0018, 0xe75: 0x0018, 0xe76: 0xe125, 0xe77: 0x0018, 0xe78: 0x29bd, 0xe79: 0x29dd, 0xe7a: 0x29fd, 0xe7b: 0x0018, 0xe7c: 0x0008, 0xe7d: 0x0018, 0xe7e: 0x0018, 0xe7f: 0x0018, // Block 0x3a, offset 0xe80 0xe80: 0x2b3d, 0xe81: 0x2b5d, 0xe82: 0x2b7d, 0xe83: 0x2b9d, 0xe84: 0x2bbd, 0xe85: 0x2bdd, 0xe86: 0x2bdd, 0xe87: 0x2bdd, 0xe88: 0x2bfd, 0xe89: 0x2bfd, 0xe8a: 0x2bfd, 0xe8b: 0x2bfd, 0xe8c: 0x2c1d, 0xe8d: 0x2c1d, 0xe8e: 0x2c1d, 0xe8f: 0x2c3d, 0xe90: 0x2c5d, 0xe91: 0x2c5d, 0xe92: 0x2a7d, 0xe93: 0x2a7d, 0xe94: 0x2c5d, 0xe95: 0x2c5d, 0xe96: 0x2c7d, 0xe97: 0x2c7d, 0xe98: 0x2c5d, 0xe99: 0x2c5d, 0xe9a: 0x2a7d, 0xe9b: 0x2a7d, 0xe9c: 0x2c5d, 0xe9d: 0x2c5d, 0xe9e: 0x2c3d, 0xe9f: 0x2c3d, 0xea0: 0x2c9d, 0xea1: 0x2c9d, 0xea2: 0x2cbd, 0xea3: 0x2cbd, 0xea4: 0x0040, 0xea5: 0x2cdd, 0xea6: 0x2cfd, 0xea7: 0x2d1d, 0xea8: 0x2d1d, 0xea9: 0x2d3d, 0xeaa: 0x2d5d, 0xeab: 0x2d7d, 0xeac: 0x2d9d, 0xead: 0x2dbd, 0xeae: 0x2ddd, 0xeaf: 0x2dfd, 0xeb0: 0x2e1d, 0xeb1: 0x2e3d, 0xeb2: 0x2e3d, 0xeb3: 0x2e5d, 0xeb4: 0x2e7d, 0xeb5: 0x2e7d, 0xeb6: 0x2e9d, 0xeb7: 0x2ebd, 0xeb8: 0x2e5d, 0xeb9: 0x2edd, 0xeba: 0x2efd, 0xebb: 0x2edd, 0xebc: 0x2e5d, 0xebd: 0x2f1d, 0xebe: 0x2f3d, 0xebf: 0x2f5d, // Block 0x3b, offset 0xec0 0xec0: 0x2f7d, 0xec1: 0x2f9d, 0xec2: 0x2cfd, 0xec3: 0x2cdd, 0xec4: 0x2fbd, 0xec5: 0x2fdd, 0xec6: 0x2ffd, 0xec7: 0x301d, 0xec8: 0x303d, 0xec9: 0x305d, 0xeca: 0x307d, 0xecb: 0x309d, 0xecc: 0x30bd, 0xecd: 0x30dd, 0xece: 0x30fd, 0xecf: 0x0040, 0xed0: 0x0018, 0xed1: 0x0018, 0xed2: 0x311d, 0xed3: 0x313d, 0xed4: 0x315d, 0xed5: 0x317d, 0xed6: 0x319d, 0xed7: 0x31bd, 0xed8: 0x31dd, 0xed9: 0x31fd, 0xeda: 0x321d, 0xedb: 0x323d, 0xedc: 0x315d, 0xedd: 0x325d, 0xede: 0x327d, 0xedf: 0x329d, 0xee0: 0x0008, 0xee1: 0x0008, 0xee2: 0x0008, 0xee3: 0x0008, 0xee4: 0x0008, 0xee5: 0x0008, 0xee6: 0x0008, 0xee7: 0x0008, 0xee8: 0x0008, 0xee9: 0x0008, 0xeea: 0x0008, 0xeeb: 0x0008, 0xeec: 0x0008, 0xeed: 0x0008, 0xeee: 0x0008, 0xeef: 0x0008, 0xef0: 0x0008, 0xef1: 0x0008, 0xef2: 0x0008, 0xef3: 0x0008, 0xef4: 0x0008, 0xef5: 0x0008, 0xef6: 0x0008, 0xef7: 0x0008, 0xef8: 0x0008, 0xef9: 0x0008, 0xefa: 0x0008, 0xefb: 0x0040, 0xefc: 0x0040, 0xefd: 0x0040, 0xefe: 0x0040, 0xeff: 0x0040, // Block 0x3c, offset 0xf00 0xf00: 0x36a2, 0xf01: 0x36d2, 0xf02: 0x3702, 0xf03: 0x3732, 0xf04: 0x32bd, 0xf05: 0x32dd, 0xf06: 0x32fd, 0xf07: 0x331d, 0xf08: 0x0018, 0xf09: 0x0018, 0xf0a: 0x0018, 0xf0b: 0x0018, 0xf0c: 0x0018, 0xf0d: 0x0018, 0xf0e: 0x0018, 0xf0f: 0x0018, 0xf10: 0x333d, 0xf11: 0x3761, 0xf12: 0x3779, 0xf13: 0x3791, 0xf14: 0x37a9, 0xf15: 0x37c1, 0xf16: 0x37d9, 0xf17: 0x37f1, 0xf18: 0x3809, 0xf19: 0x3821, 0xf1a: 0x3839, 0xf1b: 0x3851, 0xf1c: 0x3869, 0xf1d: 0x3881, 0xf1e: 0x3899, 0xf1f: 0x38b1, 0xf20: 0x335d, 0xf21: 0x337d, 0xf22: 0x339d, 0xf23: 0x33bd, 0xf24: 0x33dd, 0xf25: 0x33dd, 0xf26: 0x33fd, 0xf27: 0x341d, 0xf28: 0x343d, 0xf29: 0x345d, 0xf2a: 0x347d, 0xf2b: 0x349d, 0xf2c: 0x34bd, 0xf2d: 0x34dd, 0xf2e: 0x34fd, 0xf2f: 0x351d, 0xf30: 0x353d, 0xf31: 0x355d, 0xf32: 0x357d, 0xf33: 0x359d, 0xf34: 0x35bd, 0xf35: 0x35dd, 0xf36: 0x35fd, 0xf37: 0x361d, 0xf38: 0x363d, 0xf39: 0x365d, 0xf3a: 0x367d, 0xf3b: 0x369d, 0xf3c: 0x38c9, 0xf3d: 0x3901, 0xf3e: 0x36bd, 0xf3f: 0x0018, // Block 0x3d, offset 0xf40 0xf40: 0x36dd, 0xf41: 0x36fd, 0xf42: 0x371d, 0xf43: 0x373d, 0xf44: 0x375d, 0xf45: 0x377d, 0xf46: 0x379d, 0xf47: 0x37bd, 0xf48: 0x37dd, 0xf49: 0x37fd, 0xf4a: 0x381d, 0xf4b: 0x383d, 0xf4c: 0x385d, 0xf4d: 0x387d, 0xf4e: 0x389d, 0xf4f: 0x38bd, 0xf50: 0x38dd, 0xf51: 0x38fd, 0xf52: 0x391d, 0xf53: 0x393d, 0xf54: 0x395d, 0xf55: 0x397d, 0xf56: 0x399d, 0xf57: 0x39bd, 0xf58: 0x39dd, 0xf59: 0x39fd, 0xf5a: 0x3a1d, 0xf5b: 0x3a3d, 0xf5c: 0x3a5d, 0xf5d: 0x3a7d, 0xf5e: 0x3a9d, 0xf5f: 0x3abd, 0xf60: 0x3add, 0xf61: 0x3afd, 0xf62: 0x3b1d, 0xf63: 0x3b3d, 0xf64: 0x3b5d, 0xf65: 0x3b7d, 0xf66: 0x127d, 0xf67: 0x3b9d, 0xf68: 0x3bbd, 0xf69: 0x3bdd, 0xf6a: 0x3bfd, 0xf6b: 0x3c1d, 0xf6c: 0x3c3d, 0xf6d: 0x3c5d, 0xf6e: 0x239d, 0xf6f: 0x3c7d, 0xf70: 0x3c9d, 0xf71: 0x3939, 0xf72: 0x3951, 0xf73: 0x3969, 0xf74: 0x3981, 0xf75: 0x3999, 0xf76: 0x39b1, 0xf77: 0x39c9, 0xf78: 0x39e1, 0xf79: 0x39f9, 0xf7a: 0x3a11, 0xf7b: 0x3a29, 0xf7c: 0x3a41, 0xf7d: 0x3a59, 0xf7e: 0x3a71, 0xf7f: 0x3a89, // Block 0x3e, offset 0xf80 0xf80: 0x3aa1, 0xf81: 0x3ac9, 0xf82: 0x3af1, 0xf83: 0x3b19, 0xf84: 0x3b41, 0xf85: 0x3b69, 0xf86: 0x3b91, 0xf87: 0x3bb9, 0xf88: 0x3be1, 0xf89: 0x3c09, 0xf8a: 0x3c39, 0xf8b: 0x3c69, 0xf8c: 0x3c99, 0xf8d: 0x3cbd, 0xf8e: 0x3cb1, 0xf8f: 0x3cdd, 0xf90: 0x3cfd, 0xf91: 0x3d15, 0xf92: 0x3d2d, 0xf93: 0x3d45, 0xf94: 0x3d5d, 0xf95: 0x3d5d, 0xf96: 0x3d45, 0xf97: 0x3d75, 0xf98: 0x07bd, 0xf99: 0x3d8d, 0xf9a: 0x3da5, 0xf9b: 0x3dbd, 0xf9c: 0x3dd5, 0xf9d: 0x3ded, 0xf9e: 0x3e05, 0xf9f: 0x3e1d, 0xfa0: 0x3e35, 0xfa1: 0x3e4d, 0xfa2: 0x3e65, 0xfa3: 0x3e7d, 0xfa4: 0x3e95, 0xfa5: 0x3e95, 0xfa6: 0x3ead, 0xfa7: 0x3ead, 0xfa8: 0x3ec5, 0xfa9: 0x3ec5, 0xfaa: 0x3edd, 0xfab: 0x3ef5, 0xfac: 0x3f0d, 0xfad: 0x3f25, 0xfae: 0x3f3d, 0xfaf: 0x3f3d, 0xfb0: 0x3f55, 0xfb1: 0x3f55, 0xfb2: 0x3f55, 0xfb3: 0x3f6d, 0xfb4: 0x3f85, 0xfb5: 0x3f9d, 0xfb6: 0x3fb5, 0xfb7: 0x3f9d, 0xfb8: 0x3fcd, 0xfb9: 0x3fe5, 0xfba: 0x3f6d, 0xfbb: 0x3ffd, 0xfbc: 0x4015, 0xfbd: 0x4015, 0xfbe: 0x4015, 0xfbf: 0x0040, // Block 0x3f, offset 0xfc0 0xfc0: 0x3cc9, 0xfc1: 0x3d31, 0xfc2: 0x3d99, 0xfc3: 0x3e01, 0xfc4: 0x3e51, 0xfc5: 0x3eb9, 0xfc6: 0x3f09, 0xfc7: 0x3f59, 0xfc8: 0x3fd9, 0xfc9: 0x4041, 0xfca: 0x4091, 0xfcb: 0x40e1, 0xfcc: 0x4131, 0xfcd: 0x4199, 0xfce: 0x4201, 0xfcf: 0x4251, 0xfd0: 0x42a1, 0xfd1: 0x42d9, 0xfd2: 0x4329, 0xfd3: 0x4391, 0xfd4: 0x43f9, 0xfd5: 0x4431, 0xfd6: 0x44b1, 0xfd7: 0x4549, 0xfd8: 0x45c9, 0xfd9: 0x4619, 0xfda: 0x4699, 0xfdb: 0x4719, 0xfdc: 0x4781, 0xfdd: 0x47d1, 0xfde: 0x4821, 0xfdf: 0x4871, 0xfe0: 0x48d9, 0xfe1: 0x4959, 0xfe2: 0x49c1, 0xfe3: 0x4a11, 0xfe4: 0x4a61, 0xfe5: 0x4ab1, 0xfe6: 0x4ae9, 0xfe7: 0x4b21, 0xfe8: 0x4b59, 0xfe9: 0x4b91, 0xfea: 0x4be1, 0xfeb: 0x4c31, 0xfec: 0x4cb1, 0xfed: 0x4d01, 0xfee: 0x4d69, 0xfef: 0x4de9, 0xff0: 0x4e39, 0xff1: 0x4e71, 0xff2: 0x4ea9, 0xff3: 0x4f29, 0xff4: 0x4f91, 0xff5: 0x5011, 0xff6: 0x5061, 0xff7: 0x50e1, 0xff8: 0x5119, 0xff9: 0x5169, 0xffa: 0x51b9, 0xffb: 0x5209, 0xffc: 0x5259, 0xffd: 0x52a9, 0xffe: 0x5311, 0xfff: 0x5361, // Block 0x40, offset 0x1000 0x1000: 0x5399, 0x1001: 0x53e9, 0x1002: 0x5439, 0x1003: 0x5489, 0x1004: 0x54f1, 0x1005: 0x5541, 0x1006: 0x5591, 0x1007: 0x55e1, 0x1008: 0x5661, 0x1009: 0x56c9, 0x100a: 0x5701, 0x100b: 0x5781, 0x100c: 0x57b9, 0x100d: 0x5821, 0x100e: 0x5889, 0x100f: 0x58d9, 0x1010: 0x5929, 0x1011: 0x5979, 0x1012: 0x59e1, 0x1013: 0x5a19, 0x1014: 0x5a69, 0x1015: 0x5ad1, 0x1016: 0x5b09, 0x1017: 0x5b89, 0x1018: 0x5bd9, 0x1019: 0x5c01, 0x101a: 0x5c29, 0x101b: 0x5c51, 0x101c: 0x5c79, 0x101d: 0x5ca1, 0x101e: 0x5cc9, 0x101f: 0x5cf1, 0x1020: 0x5d19, 0x1021: 0x5d41, 0x1022: 0x5d69, 0x1023: 0x5d99, 0x1024: 0x5dc9, 0x1025: 0x5df9, 0x1026: 0x5e29, 0x1027: 0x5e59, 0x1028: 0x5e89, 0x1029: 0x5eb9, 0x102a: 0x5ee9, 0x102b: 0x5f19, 0x102c: 0x5f49, 0x102d: 0x5f79, 0x102e: 0x5fa9, 0x102f: 0x5fd9, 0x1030: 0x6009, 0x1031: 0x402d, 0x1032: 0x6039, 0x1033: 0x6051, 0x1034: 0x404d, 0x1035: 0x6069, 0x1036: 0x6081, 0x1037: 0x6099, 0x1038: 0x406d, 0x1039: 0x406d, 0x103a: 0x60b1, 0x103b: 0x60c9, 0x103c: 0x6101, 0x103d: 0x6139, 0x103e: 0x6171, 0x103f: 0x61a9, // Block 0x41, offset 0x1040 0x1040: 0x6211, 0x1041: 0x6229, 0x1042: 0x408d, 0x1043: 0x6241, 0x1044: 0x6259, 0x1045: 0x6271, 0x1046: 0x6289, 0x1047: 0x62a1, 0x1048: 0x40ad, 0x1049: 0x62b9, 0x104a: 0x62e1, 0x104b: 0x62f9, 0x104c: 0x40cd, 0x104d: 0x40cd, 0x104e: 0x6311, 0x104f: 0x6329, 0x1050: 0x6341, 0x1051: 0x40ed, 0x1052: 0x410d, 0x1053: 0x412d, 0x1054: 0x414d, 0x1055: 0x416d, 0x1056: 0x6359, 0x1057: 0x6371, 0x1058: 0x6389, 0x1059: 0x63a1, 0x105a: 0x63b9, 0x105b: 0x418d, 0x105c: 0x63d1, 0x105d: 0x63e9, 0x105e: 0x6401, 0x105f: 0x41ad, 0x1060: 0x41cd, 0x1061: 0x6419, 0x1062: 0x41ed, 0x1063: 0x420d, 0x1064: 0x422d, 0x1065: 0x6431, 0x1066: 0x424d, 0x1067: 0x6449, 0x1068: 0x6479, 0x1069: 0x6211, 0x106a: 0x426d, 0x106b: 0x428d, 0x106c: 0x42ad, 0x106d: 0x42cd, 0x106e: 0x64b1, 0x106f: 0x64f1, 0x1070: 0x6539, 0x1071: 0x6551, 0x1072: 0x42ed, 0x1073: 0x6569, 0x1074: 0x6581, 0x1075: 0x6599, 0x1076: 0x430d, 0x1077: 0x65b1, 0x1078: 0x65c9, 0x1079: 0x65b1, 0x107a: 0x65e1, 0x107b: 0x65f9, 0x107c: 0x432d, 0x107d: 0x6611, 0x107e: 0x6629, 0x107f: 0x6611, // Block 0x42, offset 0x1080 0x1080: 0x434d, 0x1081: 0x436d, 0x1082: 0x0040, 0x1083: 0x6641, 0x1084: 0x6659, 0x1085: 0x6671, 0x1086: 0x6689, 0x1087: 0x0040, 0x1088: 0x66c1, 0x1089: 0x66d9, 0x108a: 0x66f1, 0x108b: 0x6709, 0x108c: 0x6721, 0x108d: 0x6739, 0x108e: 0x6401, 0x108f: 0x6751, 0x1090: 0x6769, 0x1091: 0x6781, 0x1092: 0x438d, 0x1093: 0x6799, 0x1094: 0x6289, 0x1095: 0x43ad, 0x1096: 0x43cd, 0x1097: 0x67b1, 0x1098: 0x0040, 0x1099: 0x43ed, 0x109a: 0x67c9, 0x109b: 0x67e1, 0x109c: 0x67f9, 0x109d: 0x6811, 0x109e: 0x6829, 0x109f: 0x6859, 0x10a0: 0x6889, 0x10a1: 0x68b1, 0x10a2: 0x68d9, 0x10a3: 0x6901, 0x10a4: 0x6929, 0x10a5: 0x6951, 0x10a6: 0x6979, 0x10a7: 0x69a1, 0x10a8: 0x69c9, 0x10a9: 0x69f1, 0x10aa: 0x6a21, 0x10ab: 0x6a51, 0x10ac: 0x6a81, 0x10ad: 0x6ab1, 0x10ae: 0x6ae1, 0x10af: 0x6b11, 0x10b0: 0x6b41, 0x10b1: 0x6b71, 0x10b2: 0x6ba1, 0x10b3: 0x6bd1, 0x10b4: 0x6c01, 0x10b5: 0x6c31, 0x10b6: 0x6c61, 0x10b7: 0x6c91, 0x10b8: 0x6cc1, 0x10b9: 0x6cf1, 0x10ba: 0x6d21, 0x10bb: 0x6d51, 0x10bc: 0x6d81, 0x10bd: 0x6db1, 0x10be: 0x6de1, 0x10bf: 0x440d, // Block 0x43, offset 0x10c0 0x10c0: 0xe00d, 0x10c1: 0x0008, 0x10c2: 0xe00d, 0x10c3: 0x0008, 0x10c4: 0xe00d, 0x10c5: 0x0008, 0x10c6: 0xe00d, 0x10c7: 0x0008, 0x10c8: 0xe00d, 0x10c9: 0x0008, 0x10ca: 0xe00d, 0x10cb: 0x0008, 0x10cc: 0xe00d, 0x10cd: 0x0008, 0x10ce: 0xe00d, 0x10cf: 0x0008, 0x10d0: 0xe00d, 0x10d1: 0x0008, 0x10d2: 0xe00d, 0x10d3: 0x0008, 0x10d4: 0xe00d, 0x10d5: 0x0008, 0x10d6: 0xe00d, 0x10d7: 0x0008, 0x10d8: 0xe00d, 0x10d9: 0x0008, 0x10da: 0xe00d, 0x10db: 0x0008, 0x10dc: 0xe00d, 0x10dd: 0x0008, 0x10de: 0xe00d, 0x10df: 0x0008, 0x10e0: 0xe00d, 0x10e1: 0x0008, 0x10e2: 0xe00d, 0x10e3: 0x0008, 0x10e4: 0xe00d, 0x10e5: 0x0008, 0x10e6: 0xe00d, 0x10e7: 0x0008, 0x10e8: 0xe00d, 0x10e9: 0x0008, 0x10ea: 0xe00d, 0x10eb: 0x0008, 0x10ec: 0xe00d, 0x10ed: 0x0008, 0x10ee: 0x0008, 0x10ef: 0x3308, 0x10f0: 0x3318, 0x10f1: 0x3318, 0x10f2: 0x3318, 0x10f3: 0x0018, 0x10f4: 0x3308, 0x10f5: 0x3308, 0x10f6: 0x3308, 0x10f7: 0x3308, 0x10f8: 0x3308, 0x10f9: 0x3308, 0x10fa: 0x3308, 0x10fb: 0x3308, 0x10fc: 0x3308, 0x10fd: 0x3308, 0x10fe: 0x0018, 0x10ff: 0x0008, // Block 0x44, offset 0x1100 0x1100: 0xe00d, 0x1101: 0x0008, 0x1102: 0xe00d, 0x1103: 0x0008, 0x1104: 0xe00d, 0x1105: 0x0008, 0x1106: 0xe00d, 0x1107: 0x0008, 0x1108: 0xe00d, 0x1109: 0x0008, 0x110a: 0xe00d, 0x110b: 0x0008, 0x110c: 0xe00d, 0x110d: 0x0008, 0x110e: 0xe00d, 0x110f: 0x0008, 0x1110: 0xe00d, 0x1111: 0x0008, 0x1112: 0xe00d, 0x1113: 0x0008, 0x1114: 0xe00d, 0x1115: 0x0008, 0x1116: 0xe00d, 0x1117: 0x0008, 0x1118: 0xe00d, 0x1119: 0x0008, 0x111a: 0xe00d, 0x111b: 0x0008, 0x111c: 0x0ea1, 0x111d: 0x6e11, 0x111e: 0x3308, 0x111f: 0x3308, 0x1120: 0x0008, 0x1121: 0x0008, 0x1122: 0x0008, 0x1123: 0x0008, 0x1124: 0x0008, 0x1125: 0x0008, 0x1126: 0x0008, 0x1127: 0x0008, 0x1128: 0x0008, 0x1129: 0x0008, 0x112a: 0x0008, 0x112b: 0x0008, 0x112c: 0x0008, 0x112d: 0x0008, 0x112e: 0x0008, 0x112f: 0x0008, 0x1130: 0x0008, 0x1131: 0x0008, 0x1132: 0x0008, 0x1133: 0x0008, 0x1134: 0x0008, 0x1135: 0x0008, 0x1136: 0x0008, 0x1137: 0x0008, 0x1138: 0x0008, 0x1139: 0x0008, 0x113a: 0x0008, 0x113b: 0x0008, 0x113c: 0x0008, 0x113d: 0x0008, 0x113e: 0x0008, 0x113f: 0x0008, // Block 0x45, offset 0x1140 0x1140: 0x0018, 0x1141: 0x0018, 0x1142: 0x0018, 0x1143: 0x0018, 0x1144: 0x0018, 0x1145: 0x0018, 0x1146: 0x0018, 0x1147: 0x0018, 0x1148: 0x0018, 0x1149: 0x0018, 0x114a: 0x0018, 0x114b: 0x0018, 0x114c: 0x0018, 0x114d: 0x0018, 0x114e: 0x0018, 0x114f: 0x0018, 0x1150: 0x0018, 0x1151: 0x0018, 0x1152: 0x0018, 0x1153: 0x0018, 0x1154: 0x0018, 0x1155: 0x0018, 0x1156: 0x0018, 0x1157: 0x0008, 0x1158: 0x0008, 0x1159: 0x0008, 0x115a: 0x0008, 0x115b: 0x0008, 0x115c: 0x0008, 0x115d: 0x0008, 0x115e: 0x0008, 0x115f: 0x0008, 0x1160: 0x0018, 0x1161: 0x0018, 0x1162: 0xe00d, 0x1163: 0x0008, 0x1164: 0xe00d, 0x1165: 0x0008, 0x1166: 0xe00d, 0x1167: 0x0008, 0x1168: 0xe00d, 0x1169: 0x0008, 0x116a: 0xe00d, 0x116b: 0x0008, 0x116c: 0xe00d, 0x116d: 0x0008, 0x116e: 0xe00d, 0x116f: 0x0008, 0x1170: 0x0008, 0x1171: 0x0008, 0x1172: 0xe00d, 0x1173: 0x0008, 0x1174: 0xe00d, 0x1175: 0x0008, 0x1176: 0xe00d, 0x1177: 0x0008, 0x1178: 0xe00d, 0x1179: 0x0008, 0x117a: 0xe00d, 0x117b: 0x0008, 0x117c: 0xe00d, 0x117d: 0x0008, 0x117e: 0xe00d, 0x117f: 0x0008, // Block 0x46, offset 0x1180 0x1180: 0xe00d, 0x1181: 0x0008, 0x1182: 0xe00d, 0x1183: 0x0008, 0x1184: 0xe00d, 0x1185: 0x0008, 0x1186: 0xe00d, 0x1187: 0x0008, 0x1188: 0xe00d, 0x1189: 0x0008, 0x118a: 0xe00d, 0x118b: 0x0008, 0x118c: 0xe00d, 0x118d: 0x0008, 0x118e: 0xe00d, 0x118f: 0x0008, 0x1190: 0xe00d, 0x1191: 0x0008, 0x1192: 0xe00d, 0x1193: 0x0008, 0x1194: 0xe00d, 0x1195: 0x0008, 0x1196: 0xe00d, 0x1197: 0x0008, 0x1198: 0xe00d, 0x1199: 0x0008, 0x119a: 0xe00d, 0x119b: 0x0008, 0x119c: 0xe00d, 0x119d: 0x0008, 0x119e: 0xe00d, 0x119f: 0x0008, 0x11a0: 0xe00d, 0x11a1: 0x0008, 0x11a2: 0xe00d, 0x11a3: 0x0008, 0x11a4: 0xe00d, 0x11a5: 0x0008, 0x11a6: 0xe00d, 0x11a7: 0x0008, 0x11a8: 0xe00d, 0x11a9: 0x0008, 0x11aa: 0xe00d, 0x11ab: 0x0008, 0x11ac: 0xe00d, 0x11ad: 0x0008, 0x11ae: 0xe00d, 0x11af: 0x0008, 0x11b0: 0xe0fd, 0x11b1: 0x0008, 0x11b2: 0x0008, 0x11b3: 0x0008, 0x11b4: 0x0008, 0x11b5: 0x0008, 0x11b6: 0x0008, 0x11b7: 0x0008, 0x11b8: 0x0008, 0x11b9: 0xe01d, 0x11ba: 0x0008, 0x11bb: 0xe03d, 0x11bc: 0x0008, 0x11bd: 0x442d, 0x11be: 0xe00d, 0x11bf: 0x0008, // Block 0x47, offset 0x11c0 0x11c0: 0xe00d, 0x11c1: 0x0008, 0x11c2: 0xe00d, 0x11c3: 0x0008, 0x11c4: 0xe00d, 0x11c5: 0x0008, 0x11c6: 0xe00d, 0x11c7: 0x0008, 0x11c8: 0x0008, 0x11c9: 0x0018, 0x11ca: 0x0018, 0x11cb: 0xe03d, 0x11cc: 0x0008, 0x11cd: 0x11d9, 0x11ce: 0x0008, 0x11cf: 0x0008, 0x11d0: 0xe00d, 0x11d1: 0x0008, 0x11d2: 0xe00d, 0x11d3: 0x0008, 0x11d4: 0x0008, 0x11d5: 0x0008, 0x11d6: 0xe00d, 0x11d7: 0x0008, 0x11d8: 0xe00d, 0x11d9: 0x0008, 0x11da: 0xe00d, 0x11db: 0x0008, 0x11dc: 0xe00d, 0x11dd: 0x0008, 0x11de: 0xe00d, 0x11df: 0x0008, 0x11e0: 0xe00d, 0x11e1: 0x0008, 0x11e2: 0xe00d, 0x11e3: 0x0008, 0x11e4: 0xe00d, 0x11e5: 0x0008, 0x11e6: 0xe00d, 0x11e7: 0x0008, 0x11e8: 0xe00d, 0x11e9: 0x0008, 0x11ea: 0x6e29, 0x11eb: 0x1029, 0x11ec: 0x11c1, 0x11ed: 0x6e41, 0x11ee: 0x1221, 0x11ef: 0x0040, 0x11f0: 0x6e59, 0x11f1: 0x6e71, 0x11f2: 0x1239, 0x11f3: 0x444d, 0x11f4: 0xe00d, 0x11f5: 0x0008, 0x11f6: 0xe00d, 0x11f7: 0x0008, 0x11f8: 0x0040, 0x11f9: 0x0040, 0x11fa: 0x0040, 0x11fb: 0x0040, 0x11fc: 0x0040, 0x11fd: 0x0040, 0x11fe: 0x0040, 0x11ff: 0x0040, // Block 0x48, offset 0x1200 0x1200: 0x64d5, 0x1201: 0x64f5, 0x1202: 0x6515, 0x1203: 0x6535, 0x1204: 0x6555, 0x1205: 0x6575, 0x1206: 0x6595, 0x1207: 0x65b5, 0x1208: 0x65d5, 0x1209: 0x65f5, 0x120a: 0x6615, 0x120b: 0x6635, 0x120c: 0x6655, 0x120d: 0x6675, 0x120e: 0x0008, 0x120f: 0x0008, 0x1210: 0x6695, 0x1211: 0x0008, 0x1212: 0x66b5, 0x1213: 0x0008, 0x1214: 0x0008, 0x1215: 0x66d5, 0x1216: 0x66f5, 0x1217: 0x6715, 0x1218: 0x6735, 0x1219: 0x6755, 0x121a: 0x6775, 0x121b: 0x6795, 0x121c: 0x67b5, 0x121d: 0x67d5, 0x121e: 0x67f5, 0x121f: 0x0008, 0x1220: 0x6815, 0x1221: 0x0008, 0x1222: 0x6835, 0x1223: 0x0008, 0x1224: 0x0008, 0x1225: 0x6855, 0x1226: 0x6875, 0x1227: 0x0008, 0x1228: 0x0008, 0x1229: 0x0008, 0x122a: 0x6895, 0x122b: 0x68b5, 0x122c: 0x68d5, 0x122d: 0x68f5, 0x122e: 0x6915, 0x122f: 0x6935, 0x1230: 0x6955, 0x1231: 0x6975, 0x1232: 0x6995, 0x1233: 0x69b5, 0x1234: 0x69d5, 0x1235: 0x69f5, 0x1236: 0x6a15, 0x1237: 0x6a35, 0x1238: 0x6a55, 0x1239: 0x6a75, 0x123a: 0x6a95, 0x123b: 0x6ab5, 0x123c: 0x6ad5, 0x123d: 0x6af5, 0x123e: 0x6b15, 0x123f: 0x6b35, // Block 0x49, offset 0x1240 0x1240: 0x7a95, 0x1241: 0x7ab5, 0x1242: 0x7ad5, 0x1243: 0x7af5, 0x1244: 0x7b15, 0x1245: 0x7b35, 0x1246: 0x7b55, 0x1247: 0x7b75, 0x1248: 0x7b95, 0x1249: 0x7bb5, 0x124a: 0x7bd5, 0x124b: 0x7bf5, 0x124c: 0x7c15, 0x124d: 0x7c35, 0x124e: 0x7c55, 0x124f: 0x6ec9, 0x1250: 0x6ef1, 0x1251: 0x6f19, 0x1252: 0x7c75, 0x1253: 0x7c95, 0x1254: 0x7cb5, 0x1255: 0x6f41, 0x1256: 0x6f69, 0x1257: 0x6f91, 0x1258: 0x7cd5, 0x1259: 0x7cf5, 0x125a: 0x0040, 0x125b: 0x0040, 0x125c: 0x0040, 0x125d: 0x0040, 0x125e: 0x0040, 0x125f: 0x0040, 0x1260: 0x0040, 0x1261: 0x0040, 0x1262: 0x0040, 0x1263: 0x0040, 0x1264: 0x0040, 0x1265: 0x0040, 0x1266: 0x0040, 0x1267: 0x0040, 0x1268: 0x0040, 0x1269: 0x0040, 0x126a: 0x0040, 0x126b: 0x0040, 0x126c: 0x0040, 0x126d: 0x0040, 0x126e: 0x0040, 0x126f: 0x0040, 0x1270: 0x0040, 0x1271: 0x0040, 0x1272: 0x0040, 0x1273: 0x0040, 0x1274: 0x0040, 0x1275: 0x0040, 0x1276: 0x0040, 0x1277: 0x0040, 0x1278: 0x0040, 0x1279: 0x0040, 0x127a: 0x0040, 0x127b: 0x0040, 0x127c: 0x0040, 0x127d: 0x0040, 0x127e: 0x0040, 0x127f: 0x0040, // Block 0x4a, offset 0x1280 0x1280: 0x6fb9, 0x1281: 0x6fd1, 0x1282: 0x6fe9, 0x1283: 0x7d15, 0x1284: 0x7d35, 0x1285: 0x7001, 0x1286: 0x7001, 0x1287: 0x0040, 0x1288: 0x0040, 0x1289: 0x0040, 0x128a: 0x0040, 0x128b: 0x0040, 0x128c: 0x0040, 0x128d: 0x0040, 0x128e: 0x0040, 0x128f: 0x0040, 0x1290: 0x0040, 0x1291: 0x0040, 0x1292: 0x0040, 0x1293: 0x7019, 0x1294: 0x7041, 0x1295: 0x7069, 0x1296: 0x7091, 0x1297: 0x70b9, 0x1298: 0x0040, 0x1299: 0x0040, 0x129a: 0x0040, 0x129b: 0x0040, 0x129c: 0x0040, 0x129d: 0x70e1, 0x129e: 0x3308, 0x129f: 0x7109, 0x12a0: 0x7131, 0x12a1: 0x20a9, 0x12a2: 0x20f1, 0x12a3: 0x7149, 0x12a4: 0x7161, 0x12a5: 0x7179, 0x12a6: 0x7191, 0x12a7: 0x71a9, 0x12a8: 0x71c1, 0x12a9: 0x1fb2, 0x12aa: 0x71d9, 0x12ab: 0x7201, 0x12ac: 0x7229, 0x12ad: 0x7261, 0x12ae: 0x7299, 0x12af: 0x72c1, 0x12b0: 0x72e9, 0x12b1: 0x7311, 0x12b2: 0x7339, 0x12b3: 0x7361, 0x12b4: 0x7389, 0x12b5: 0x73b1, 0x12b6: 0x73d9, 0x12b7: 0x0040, 0x12b8: 0x7401, 0x12b9: 0x7429, 0x12ba: 0x7451, 0x12bb: 0x7479, 0x12bc: 0x74a1, 0x12bd: 0x0040, 0x12be: 0x74c9, 0x12bf: 0x0040, // Block 0x4b, offset 0x12c0 0x12c0: 0x74f1, 0x12c1: 0x7519, 0x12c2: 0x0040, 0x12c3: 0x7541, 0x12c4: 0x7569, 0x12c5: 0x0040, 0x12c6: 0x7591, 0x12c7: 0x75b9, 0x12c8: 0x75e1, 0x12c9: 0x7609, 0x12ca: 0x7631, 0x12cb: 0x7659, 0x12cc: 0x7681, 0x12cd: 0x76a9, 0x12ce: 0x76d1, 0x12cf: 0x76f9, 0x12d0: 0x7721, 0x12d1: 0x7721, 0x12d2: 0x7739, 0x12d3: 0x7739, 0x12d4: 0x7739, 0x12d5: 0x7739, 0x12d6: 0x7751, 0x12d7: 0x7751, 0x12d8: 0x7751, 0x12d9: 0x7751, 0x12da: 0x7769, 0x12db: 0x7769, 0x12dc: 0x7769, 0x12dd: 0x7769, 0x12de: 0x7781, 0x12df: 0x7781, 0x12e0: 0x7781, 0x12e1: 0x7781, 0x12e2: 0x7799, 0x12e3: 0x7799, 0x12e4: 0x7799, 0x12e5: 0x7799, 0x12e6: 0x77b1, 0x12e7: 0x77b1, 0x12e8: 0x77b1, 0x12e9: 0x77b1, 0x12ea: 0x77c9, 0x12eb: 0x77c9, 0x12ec: 0x77c9, 0x12ed: 0x77c9, 0x12ee: 0x77e1, 0x12ef: 0x77e1, 0x12f0: 0x77e1, 0x12f1: 0x77e1, 0x12f2: 0x77f9, 0x12f3: 0x77f9, 0x12f4: 0x77f9, 0x12f5: 0x77f9, 0x12f6: 0x7811, 0x12f7: 0x7811, 0x12f8: 0x7811, 0x12f9: 0x7811, 0x12fa: 0x7829, 0x12fb: 0x7829, 0x12fc: 0x7829, 0x12fd: 0x7829, 0x12fe: 0x7841, 0x12ff: 0x7841, // Block 0x4c, offset 0x1300 0x1300: 0x7841, 0x1301: 0x7841, 0x1302: 0x7859, 0x1303: 0x7859, 0x1304: 0x7871, 0x1305: 0x7871, 0x1306: 0x7889, 0x1307: 0x7889, 0x1308: 0x78a1, 0x1309: 0x78a1, 0x130a: 0x78b9, 0x130b: 0x78b9, 0x130c: 0x78d1, 0x130d: 0x78d1, 0x130e: 0x78e9, 0x130f: 0x78e9, 0x1310: 0x78e9, 0x1311: 0x78e9, 0x1312: 0x7901, 0x1313: 0x7901, 0x1314: 0x7901, 0x1315: 0x7901, 0x1316: 0x7919, 0x1317: 0x7919, 0x1318: 0x7919, 0x1319: 0x7919, 0x131a: 0x7931, 0x131b: 0x7931, 0x131c: 0x7931, 0x131d: 0x7931, 0x131e: 0x7949, 0x131f: 0x7949, 0x1320: 0x7961, 0x1321: 0x7961, 0x1322: 0x7961, 0x1323: 0x7961, 0x1324: 0x7979, 0x1325: 0x7979, 0x1326: 0x7991, 0x1327: 0x7991, 0x1328: 0x7991, 0x1329: 0x7991, 0x132a: 0x79a9, 0x132b: 0x79a9, 0x132c: 0x79a9, 0x132d: 0x79a9, 0x132e: 0x79c1, 0x132f: 0x79c1, 0x1330: 0x79d9, 0x1331: 0x79d9, 0x1332: 0x0818, 0x1333: 0x0818, 0x1334: 0x0818, 0x1335: 0x0818, 0x1336: 0x0818, 0x1337: 0x0818, 0x1338: 0x0818, 0x1339: 0x0818, 0x133a: 0x0818, 0x133b: 0x0818, 0x133c: 0x0818, 0x133d: 0x0818, 0x133e: 0x0818, 0x133f: 0x0818, // Block 0x4d, offset 0x1340 0x1340: 0x0818, 0x1341: 0x0818, 0x1342: 0x0040, 0x1343: 0x0040, 0x1344: 0x0040, 0x1345: 0x0040, 0x1346: 0x0040, 0x1347: 0x0040, 0x1348: 0x0040, 0x1349: 0x0040, 0x134a: 0x0040, 0x134b: 0x0040, 0x134c: 0x0040, 0x134d: 0x0040, 0x134e: 0x0040, 0x134f: 0x0040, 0x1350: 0x0040, 0x1351: 0x0040, 0x1352: 0x0040, 0x1353: 0x79f1, 0x1354: 0x79f1, 0x1355: 0x79f1, 0x1356: 0x79f1, 0x1357: 0x7a09, 0x1358: 0x7a09, 0x1359: 0x7a21, 0x135a: 0x7a21, 0x135b: 0x7a39, 0x135c: 0x7a39, 0x135d: 0x0479, 0x135e: 0x7a51, 0x135f: 0x7a51, 0x1360: 0x7a69, 0x1361: 0x7a69, 0x1362: 0x7a81, 0x1363: 0x7a81, 0x1364: 0x7a99, 0x1365: 0x7a99, 0x1366: 0x7a99, 0x1367: 0x7a99, 0x1368: 0x7ab1, 0x1369: 0x7ab1, 0x136a: 0x7ac9, 0x136b: 0x7ac9, 0x136c: 0x7af1, 0x136d: 0x7af1, 0x136e: 0x7b19, 0x136f: 0x7b19, 0x1370: 0x7b41, 0x1371: 0x7b41, 0x1372: 0x7b69, 0x1373: 0x7b69, 0x1374: 0x7b91, 0x1375: 0x7b91, 0x1376: 0x7bb9, 0x1377: 0x7bb9, 0x1378: 0x7bb9, 0x1379: 0x7be1, 0x137a: 0x7be1, 0x137b: 0x7be1, 0x137c: 0x7c09, 0x137d: 0x7c09, 0x137e: 0x7c09, 0x137f: 0x7c09, // Block 0x4e, offset 0x1380 0x1380: 0x85f9, 0x1381: 0x8621, 0x1382: 0x8649, 0x1383: 0x8671, 0x1384: 0x8699, 0x1385: 0x86c1, 0x1386: 0x86e9, 0x1387: 0x8711, 0x1388: 0x8739, 0x1389: 0x8761, 0x138a: 0x8789, 0x138b: 0x87b1, 0x138c: 0x87d9, 0x138d: 0x8801, 0x138e: 0x8829, 0x138f: 0x8851, 0x1390: 0x8879, 0x1391: 0x88a1, 0x1392: 0x88c9, 0x1393: 0x88f1, 0x1394: 0x8919, 0x1395: 0x8941, 0x1396: 0x8969, 0x1397: 0x8991, 0x1398: 0x89b9, 0x1399: 0x89e1, 0x139a: 0x8a09, 0x139b: 0x8a31, 0x139c: 0x8a59, 0x139d: 0x8a81, 0x139e: 0x8aaa, 0x139f: 0x8ada, 0x13a0: 0x8b0a, 0x13a1: 0x8b3a, 0x13a2: 0x8b6a, 0x13a3: 0x8b9a, 0x13a4: 0x8bc9, 0x13a5: 0x8bf1, 0x13a6: 0x7c71, 0x13a7: 0x8c19, 0x13a8: 0x7be1, 0x13a9: 0x7c99, 0x13aa: 0x8c41, 0x13ab: 0x8c69, 0x13ac: 0x7d39, 0x13ad: 0x8c91, 0x13ae: 0x7d61, 0x13af: 0x7d89, 0x13b0: 0x8cb9, 0x13b1: 0x8ce1, 0x13b2: 0x7e29, 0x13b3: 0x8d09, 0x13b4: 0x7e51, 0x13b5: 0x7e79, 0x13b6: 0x8d31, 0x13b7: 0x8d59, 0x13b8: 0x7ec9, 0x13b9: 0x8d81, 0x13ba: 0x7ef1, 0x13bb: 0x7f19, 0x13bc: 0x83a1, 0x13bd: 0x83c9, 0x13be: 0x8441, 0x13bf: 0x8469, // Block 0x4f, offset 0x13c0 0x13c0: 0x8491, 0x13c1: 0x8531, 0x13c2: 0x8559, 0x13c3: 0x8581, 0x13c4: 0x85a9, 0x13c5: 0x8649, 0x13c6: 0x8671, 0x13c7: 0x8699, 0x13c8: 0x8da9, 0x13c9: 0x8739, 0x13ca: 0x8dd1, 0x13cb: 0x8df9, 0x13cc: 0x8829, 0x13cd: 0x8e21, 0x13ce: 0x8851, 0x13cf: 0x8879, 0x13d0: 0x8a81, 0x13d1: 0x8e49, 0x13d2: 0x8e71, 0x13d3: 0x89b9, 0x13d4: 0x8e99, 0x13d5: 0x89e1, 0x13d6: 0x8a09, 0x13d7: 0x7c21, 0x13d8: 0x7c49, 0x13d9: 0x8ec1, 0x13da: 0x7c71, 0x13db: 0x8ee9, 0x13dc: 0x7cc1, 0x13dd: 0x7ce9, 0x13de: 0x7d11, 0x13df: 0x7d39, 0x13e0: 0x8f11, 0x13e1: 0x7db1, 0x13e2: 0x7dd9, 0x13e3: 0x7e01, 0x13e4: 0x7e29, 0x13e5: 0x8f39, 0x13e6: 0x7ec9, 0x13e7: 0x7f41, 0x13e8: 0x7f69, 0x13e9: 0x7f91, 0x13ea: 0x7fb9, 0x13eb: 0x7fe1, 0x13ec: 0x8031, 0x13ed: 0x8059, 0x13ee: 0x8081, 0x13ef: 0x80a9, 0x13f0: 0x80d1, 0x13f1: 0x80f9, 0x13f2: 0x8f61, 0x13f3: 0x8121, 0x13f4: 0x8149, 0x13f5: 0x8171, 0x13f6: 0x8199, 0x13f7: 0x81c1, 0x13f8: 0x81e9, 0x13f9: 0x8239, 0x13fa: 0x8261, 0x13fb: 0x8289, 0x13fc: 0x82b1, 0x13fd: 0x82d9, 0x13fe: 0x8301, 0x13ff: 0x8329, // Block 0x50, offset 0x1400 0x1400: 0x8351, 0x1401: 0x8379, 0x1402: 0x83f1, 0x1403: 0x8419, 0x1404: 0x84b9, 0x1405: 0x84e1, 0x1406: 0x8509, 0x1407: 0x8531, 0x1408: 0x8559, 0x1409: 0x85d1, 0x140a: 0x85f9, 0x140b: 0x8621, 0x140c: 0x8649, 0x140d: 0x8f89, 0x140e: 0x86c1, 0x140f: 0x86e9, 0x1410: 0x8711, 0x1411: 0x8739, 0x1412: 0x87b1, 0x1413: 0x87d9, 0x1414: 0x8801, 0x1415: 0x8829, 0x1416: 0x8fb1, 0x1417: 0x88a1, 0x1418: 0x88c9, 0x1419: 0x8fd9, 0x141a: 0x8941, 0x141b: 0x8969, 0x141c: 0x8991, 0x141d: 0x89b9, 0x141e: 0x9001, 0x141f: 0x7c71, 0x1420: 0x8ee9, 0x1421: 0x7d39, 0x1422: 0x8f11, 0x1423: 0x7e29, 0x1424: 0x8f39, 0x1425: 0x7ec9, 0x1426: 0x9029, 0x1427: 0x80d1, 0x1428: 0x9051, 0x1429: 0x9079, 0x142a: 0x90a1, 0x142b: 0x8531, 0x142c: 0x8559, 0x142d: 0x8649, 0x142e: 0x8829, 0x142f: 0x8fb1, 0x1430: 0x89b9, 0x1431: 0x9001, 0x1432: 0x90c9, 0x1433: 0x9101, 0x1434: 0x9139, 0x1435: 0x9171, 0x1436: 0x9199, 0x1437: 0x91c1, 0x1438: 0x91e9, 0x1439: 0x9211, 0x143a: 0x9239, 0x143b: 0x9261, 0x143c: 0x9289, 0x143d: 0x92b1, 0x143e: 0x92d9, 0x143f: 0x9301, // Block 0x51, offset 0x1440 0x1440: 0x9329, 0x1441: 0x9351, 0x1442: 0x9379, 0x1443: 0x93a1, 0x1444: 0x93c9, 0x1445: 0x93f1, 0x1446: 0x9419, 0x1447: 0x9441, 0x1448: 0x9469, 0x1449: 0x9491, 0x144a: 0x94b9, 0x144b: 0x94e1, 0x144c: 0x9079, 0x144d: 0x9509, 0x144e: 0x9531, 0x144f: 0x9559, 0x1450: 0x9581, 0x1451: 0x9171, 0x1452: 0x9199, 0x1453: 0x91c1, 0x1454: 0x91e9, 0x1455: 0x9211, 0x1456: 0x9239, 0x1457: 0x9261, 0x1458: 0x9289, 0x1459: 0x92b1, 0x145a: 0x92d9, 0x145b: 0x9301, 0x145c: 0x9329, 0x145d: 0x9351, 0x145e: 0x9379, 0x145f: 0x93a1, 0x1460: 0x93c9, 0x1461: 0x93f1, 0x1462: 0x9419, 0x1463: 0x9441, 0x1464: 0x9469, 0x1465: 0x9491, 0x1466: 0x94b9, 0x1467: 0x94e1, 0x1468: 0x9079, 0x1469: 0x9509, 0x146a: 0x9531, 0x146b: 0x9559, 0x146c: 0x9581, 0x146d: 0x9491, 0x146e: 0x94b9, 0x146f: 0x94e1, 0x1470: 0x9079, 0x1471: 0x9051, 0x1472: 0x90a1, 0x1473: 0x8211, 0x1474: 0x8059, 0x1475: 0x8081, 0x1476: 0x80a9, 0x1477: 0x9491, 0x1478: 0x94b9, 0x1479: 0x94e1, 0x147a: 0x8211, 0x147b: 0x8239, 0x147c: 0x95a9, 0x147d: 0x95a9, 0x147e: 0x0018, 0x147f: 0x0018, // Block 0x52, offset 0x1480 0x1480: 0x0040, 0x1481: 0x0040, 0x1482: 0x0040, 0x1483: 0x0040, 0x1484: 0x0040, 0x1485: 0x0040, 0x1486: 0x0040, 0x1487: 0x0040, 0x1488: 0x0040, 0x1489: 0x0040, 0x148a: 0x0040, 0x148b: 0x0040, 0x148c: 0x0040, 0x148d: 0x0040, 0x148e: 0x0040, 0x148f: 0x0040, 0x1490: 0x95d1, 0x1491: 0x9609, 0x1492: 0x9609, 0x1493: 0x9641, 0x1494: 0x9679, 0x1495: 0x96b1, 0x1496: 0x96e9, 0x1497: 0x9721, 0x1498: 0x9759, 0x1499: 0x9759, 0x149a: 0x9791, 0x149b: 0x97c9, 0x149c: 0x9801, 0x149d: 0x9839, 0x149e: 0x9871, 0x149f: 0x98a9, 0x14a0: 0x98a9, 0x14a1: 0x98e1, 0x14a2: 0x9919, 0x14a3: 0x9919, 0x14a4: 0x9951, 0x14a5: 0x9951, 0x14a6: 0x9989, 0x14a7: 0x99c1, 0x14a8: 0x99c1, 0x14a9: 0x99f9, 0x14aa: 0x9a31, 0x14ab: 0x9a31, 0x14ac: 0x9a69, 0x14ad: 0x9a69, 0x14ae: 0x9aa1, 0x14af: 0x9ad9, 0x14b0: 0x9ad9, 0x14b1: 0x9b11, 0x14b2: 0x9b11, 0x14b3: 0x9b49, 0x14b4: 0x9b81, 0x14b5: 0x9bb9, 0x14b6: 0x9bf1, 0x14b7: 0x9bf1, 0x14b8: 0x9c29, 0x14b9: 0x9c61, 0x14ba: 0x9c99, 0x14bb: 0x9cd1, 0x14bc: 0x9d09, 0x14bd: 0x9d09, 0x14be: 0x9d41, 0x14bf: 0x9d79, // Block 0x53, offset 0x14c0 0x14c0: 0xa949, 0x14c1: 0xa981, 0x14c2: 0xa9b9, 0x14c3: 0xa8a1, 0x14c4: 0x9bb9, 0x14c5: 0x9989, 0x14c6: 0xa9f1, 0x14c7: 0xaa29, 0x14c8: 0x0040, 0x14c9: 0x0040, 0x14ca: 0x0040, 0x14cb: 0x0040, 0x14cc: 0x0040, 0x14cd: 0x0040, 0x14ce: 0x0040, 0x14cf: 0x0040, 0x14d0: 0x0040, 0x14d1: 0x0040, 0x14d2: 0x0040, 0x14d3: 0x0040, 0x14d4: 0x0040, 0x14d5: 0x0040, 0x14d6: 0x0040, 0x14d7: 0x0040, 0x14d8: 0x0040, 0x14d9: 0x0040, 0x14da: 0x0040, 0x14db: 0x0040, 0x14dc: 0x0040, 0x14dd: 0x0040, 0x14de: 0x0040, 0x14df: 0x0040, 0x14e0: 0x0040, 0x14e1: 0x0040, 0x14e2: 0x0040, 0x14e3: 0x0040, 0x14e4: 0x0040, 0x14e5: 0x0040, 0x14e6: 0x0040, 0x14e7: 0x0040, 0x14e8: 0x0040, 0x14e9: 0x0040, 0x14ea: 0x0040, 0x14eb: 0x0040, 0x14ec: 0x0040, 0x14ed: 0x0040, 0x14ee: 0x0040, 0x14ef: 0x0040, 0x14f0: 0xaa61, 0x14f1: 0xaa99, 0x14f2: 0xaad1, 0x14f3: 0xab19, 0x14f4: 0xab61, 0x14f5: 0xaba9, 0x14f6: 0xabf1, 0x14f7: 0xac39, 0x14f8: 0xac81, 0x14f9: 0xacc9, 0x14fa: 0xad02, 0x14fb: 0xae12, 0x14fc: 0xae91, 0x14fd: 0x0018, 0x14fe: 0x0040, 0x14ff: 0x0040, // Block 0x54, offset 0x1500 0x1500: 0x33c0, 0x1501: 0x33c0, 0x1502: 0x33c0, 0x1503: 0x33c0, 0x1504: 0x33c0, 0x1505: 0x33c0, 0x1506: 0x33c0, 0x1507: 0x33c0, 0x1508: 0x33c0, 0x1509: 0x33c0, 0x150a: 0x33c0, 0x150b: 0x33c0, 0x150c: 0x33c0, 0x150d: 0x33c0, 0x150e: 0x33c0, 0x150f: 0x33c0, 0x1510: 0xaeda, 0x1511: 0x7d55, 0x1512: 0x0040, 0x1513: 0xaeea, 0x1514: 0x03c2, 0x1515: 0xaefa, 0x1516: 0xaf0a, 0x1517: 0x7d75, 0x1518: 0x7d95, 0x1519: 0x0040, 0x151a: 0x0040, 0x151b: 0x0040, 0x151c: 0x0040, 0x151d: 0x0040, 0x151e: 0x0040, 0x151f: 0x0040, 0x1520: 0x3308, 0x1521: 0x3308, 0x1522: 0x3308, 0x1523: 0x3308, 0x1524: 0x3308, 0x1525: 0x3308, 0x1526: 0x3308, 0x1527: 0x3308, 0x1528: 0x3308, 0x1529: 0x3308, 0x152a: 0x3308, 0x152b: 0x3308, 0x152c: 0x3308, 0x152d: 0x3308, 0x152e: 0x3308, 0x152f: 0x3308, 0x1530: 0x0040, 0x1531: 0x7db5, 0x1532: 0x7dd5, 0x1533: 0xaf1a, 0x1534: 0xaf1a, 0x1535: 0x1fd2, 0x1536: 0x1fe2, 0x1537: 0xaf2a, 0x1538: 0xaf3a, 0x1539: 0x7df5, 0x153a: 0x7e15, 0x153b: 0x7e35, 0x153c: 0x7df5, 0x153d: 0x7e55, 0x153e: 0x7e75, 0x153f: 0x7e55, // Block 0x55, offset 0x1540 0x1540: 0x7e95, 0x1541: 0x7eb5, 0x1542: 0x7ed5, 0x1543: 0x7eb5, 0x1544: 0x7ef5, 0x1545: 0x0018, 0x1546: 0x0018, 0x1547: 0xaf4a, 0x1548: 0xaf5a, 0x1549: 0x7f16, 0x154a: 0x7f36, 0x154b: 0x7f56, 0x154c: 0x7f76, 0x154d: 0xaf1a, 0x154e: 0xaf1a, 0x154f: 0xaf1a, 0x1550: 0xaeda, 0x1551: 0x7f95, 0x1552: 0x0040, 0x1553: 0x0040, 0x1554: 0x03c2, 0x1555: 0xaeea, 0x1556: 0xaf0a, 0x1557: 0xaefa, 0x1558: 0x7fb5, 0x1559: 0x1fd2, 0x155a: 0x1fe2, 0x155b: 0xaf2a, 0x155c: 0xaf3a, 0x155d: 0x7e95, 0x155e: 0x7ef5, 0x155f: 0xaf6a, 0x1560: 0xaf7a, 0x1561: 0xaf8a, 0x1562: 0x1fb2, 0x1563: 0xaf99, 0x1564: 0xafaa, 0x1565: 0xafba, 0x1566: 0x1fc2, 0x1567: 0x0040, 0x1568: 0xafca, 0x1569: 0xafda, 0x156a: 0xafea, 0x156b: 0xaffa, 0x156c: 0x0040, 0x156d: 0x0040, 0x156e: 0x0040, 0x156f: 0x0040, 0x1570: 0x7fd6, 0x1571: 0xb009, 0x1572: 0x7ff6, 0x1573: 0x0808, 0x1574: 0x8016, 0x1575: 0x0040, 0x1576: 0x8036, 0x1577: 0xb031, 0x1578: 0x8056, 0x1579: 0xb059, 0x157a: 0x8076, 0x157b: 0xb081, 0x157c: 0x8096, 0x157d: 0xb0a9, 0x157e: 0x80b6, 0x157f: 0xb0d1, // Block 0x56, offset 0x1580 0x1580: 0xb0f9, 0x1581: 0xb111, 0x1582: 0xb111, 0x1583: 0xb129, 0x1584: 0xb129, 0x1585: 0xb141, 0x1586: 0xb141, 0x1587: 0xb159, 0x1588: 0xb159, 0x1589: 0xb171, 0x158a: 0xb171, 0x158b: 0xb171, 0x158c: 0xb171, 0x158d: 0xb189, 0x158e: 0xb189, 0x158f: 0xb1a1, 0x1590: 0xb1a1, 0x1591: 0xb1a1, 0x1592: 0xb1a1, 0x1593: 0xb1b9, 0x1594: 0xb1b9, 0x1595: 0xb1d1, 0x1596: 0xb1d1, 0x1597: 0xb1d1, 0x1598: 0xb1d1, 0x1599: 0xb1e9, 0x159a: 0xb1e9, 0x159b: 0xb1e9, 0x159c: 0xb1e9, 0x159d: 0xb201, 0x159e: 0xb201, 0x159f: 0xb201, 0x15a0: 0xb201, 0x15a1: 0xb219, 0x15a2: 0xb219, 0x15a3: 0xb219, 0x15a4: 0xb219, 0x15a5: 0xb231, 0x15a6: 0xb231, 0x15a7: 0xb231, 0x15a8: 0xb231, 0x15a9: 0xb249, 0x15aa: 0xb249, 0x15ab: 0xb261, 0x15ac: 0xb261, 0x15ad: 0xb279, 0x15ae: 0xb279, 0x15af: 0xb291, 0x15b0: 0xb291, 0x15b1: 0xb2a9, 0x15b2: 0xb2a9, 0x15b3: 0xb2a9, 0x15b4: 0xb2a9, 0x15b5: 0xb2c1, 0x15b6: 0xb2c1, 0x15b7: 0xb2c1, 0x15b8: 0xb2c1, 0x15b9: 0xb2d9, 0x15ba: 0xb2d9, 0x15bb: 0xb2d9, 0x15bc: 0xb2d9, 0x15bd: 0xb2f1, 0x15be: 0xb2f1, 0x15bf: 0xb2f1, // Block 0x57, offset 0x15c0 0x15c0: 0xb2f1, 0x15c1: 0xb309, 0x15c2: 0xb309, 0x15c3: 0xb309, 0x15c4: 0xb309, 0x15c5: 0xb321, 0x15c6: 0xb321, 0x15c7: 0xb321, 0x15c8: 0xb321, 0x15c9: 0xb339, 0x15ca: 0xb339, 0x15cb: 0xb339, 0x15cc: 0xb339, 0x15cd: 0xb351, 0x15ce: 0xb351, 0x15cf: 0xb351, 0x15d0: 0xb351, 0x15d1: 0xb369, 0x15d2: 0xb369, 0x15d3: 0xb369, 0x15d4: 0xb369, 0x15d5: 0xb381, 0x15d6: 0xb381, 0x15d7: 0xb381, 0x15d8: 0xb381, 0x15d9: 0xb399, 0x15da: 0xb399, 0x15db: 0xb399, 0x15dc: 0xb399, 0x15dd: 0xb3b1, 0x15de: 0xb3b1, 0x15df: 0xb3b1, 0x15e0: 0xb3b1, 0x15e1: 0xb3c9, 0x15e2: 0xb3c9, 0x15e3: 0xb3c9, 0x15e4: 0xb3c9, 0x15e5: 0xb3e1, 0x15e6: 0xb3e1, 0x15e7: 0xb3e1, 0x15e8: 0xb3e1, 0x15e9: 0xb3f9, 0x15ea: 0xb3f9, 0x15eb: 0xb3f9, 0x15ec: 0xb3f9, 0x15ed: 0xb411, 0x15ee: 0xb411, 0x15ef: 0x7ab1, 0x15f0: 0x7ab1, 0x15f1: 0xb429, 0x15f2: 0xb429, 0x15f3: 0xb429, 0x15f4: 0xb429, 0x15f5: 0xb441, 0x15f6: 0xb441, 0x15f7: 0xb469, 0x15f8: 0xb469, 0x15f9: 0xb491, 0x15fa: 0xb491, 0x15fb: 0xb4b9, 0x15fc: 0xb4b9, 0x15fd: 0x0040, 0x15fe: 0x0040, 0x15ff: 0x03c0, // Block 0x58, offset 0x1600 0x1600: 0x0040, 0x1601: 0xaefa, 0x1602: 0xb4e2, 0x1603: 0xaf6a, 0x1604: 0xafda, 0x1605: 0xafea, 0x1606: 0xaf7a, 0x1607: 0xb4f2, 0x1608: 0x1fd2, 0x1609: 0x1fe2, 0x160a: 0xaf8a, 0x160b: 0x1fb2, 0x160c: 0xaeda, 0x160d: 0xaf99, 0x160e: 0x29d1, 0x160f: 0xb502, 0x1610: 0x1f41, 0x1611: 0x00c9, 0x1612: 0x0069, 0x1613: 0x0079, 0x1614: 0x1f51, 0x1615: 0x1f61, 0x1616: 0x1f71, 0x1617: 0x1f81, 0x1618: 0x1f91, 0x1619: 0x1fa1, 0x161a: 0xaeea, 0x161b: 0x03c2, 0x161c: 0xafaa, 0x161d: 0x1fc2, 0x161e: 0xafba, 0x161f: 0xaf0a, 0x1620: 0xaffa, 0x1621: 0x0039, 0x1622: 0x0ee9, 0x1623: 0x1159, 0x1624: 0x0ef9, 0x1625: 0x0f09, 0x1626: 0x1199, 0x1627: 0x0f31, 0x1628: 0x0249, 0x1629: 0x0f41, 0x162a: 0x0259, 0x162b: 0x0f51, 0x162c: 0x0359, 0x162d: 0x0f61, 0x162e: 0x0f71, 0x162f: 0x00d9, 0x1630: 0x0f99, 0x1631: 0x2039, 0x1632: 0x0269, 0x1633: 0x01d9, 0x1634: 0x0fa9, 0x1635: 0x0fb9, 0x1636: 0x1089, 0x1637: 0x0279, 0x1638: 0x0369, 0x1639: 0x0289, 0x163a: 0x13d1, 0x163b: 0xaf4a, 0x163c: 0xafca, 0x163d: 0xaf5a, 0x163e: 0xb512, 0x163f: 0xaf1a, // Block 0x59, offset 0x1640 0x1640: 0x1caa, 0x1641: 0x0039, 0x1642: 0x0ee9, 0x1643: 0x1159, 0x1644: 0x0ef9, 0x1645: 0x0f09, 0x1646: 0x1199, 0x1647: 0x0f31, 0x1648: 0x0249, 0x1649: 0x0f41, 0x164a: 0x0259, 0x164b: 0x0f51, 0x164c: 0x0359, 0x164d: 0x0f61, 0x164e: 0x0f71, 0x164f: 0x00d9, 0x1650: 0x0f99, 0x1651: 0x2039, 0x1652: 0x0269, 0x1653: 0x01d9, 0x1654: 0x0fa9, 0x1655: 0x0fb9, 0x1656: 0x1089, 0x1657: 0x0279, 0x1658: 0x0369, 0x1659: 0x0289, 0x165a: 0x13d1, 0x165b: 0xaf2a, 0x165c: 0xb522, 0x165d: 0xaf3a, 0x165e: 0xb532, 0x165f: 0x80d5, 0x1660: 0x80f5, 0x1661: 0x29d1, 0x1662: 0x8115, 0x1663: 0x8115, 0x1664: 0x8135, 0x1665: 0x8155, 0x1666: 0x8175, 0x1667: 0x8195, 0x1668: 0x81b5, 0x1669: 0x81d5, 0x166a: 0x81f5, 0x166b: 0x8215, 0x166c: 0x8235, 0x166d: 0x8255, 0x166e: 0x8275, 0x166f: 0x8295, 0x1670: 0x82b5, 0x1671: 0x82d5, 0x1672: 0x82f5, 0x1673: 0x8315, 0x1674: 0x8335, 0x1675: 0x8355, 0x1676: 0x8375, 0x1677: 0x8395, 0x1678: 0x83b5, 0x1679: 0x83d5, 0x167a: 0x83f5, 0x167b: 0x8415, 0x167c: 0x81b5, 0x167d: 0x8435, 0x167e: 0x8455, 0x167f: 0x8215, // Block 0x5a, offset 0x1680 0x1680: 0x8475, 0x1681: 0x8495, 0x1682: 0x84b5, 0x1683: 0x84d5, 0x1684: 0x84f5, 0x1685: 0x8515, 0x1686: 0x8535, 0x1687: 0x8555, 0x1688: 0x84d5, 0x1689: 0x8575, 0x168a: 0x84d5, 0x168b: 0x8595, 0x168c: 0x8595, 0x168d: 0x85b5, 0x168e: 0x85b5, 0x168f: 0x85d5, 0x1690: 0x8515, 0x1691: 0x85f5, 0x1692: 0x8615, 0x1693: 0x85f5, 0x1694: 0x8635, 0x1695: 0x8615, 0x1696: 0x8655, 0x1697: 0x8655, 0x1698: 0x8675, 0x1699: 0x8675, 0x169a: 0x8695, 0x169b: 0x8695, 0x169c: 0x8615, 0x169d: 0x8115, 0x169e: 0x86b5, 0x169f: 0x86d5, 0x16a0: 0x0040, 0x16a1: 0x86f5, 0x16a2: 0x8715, 0x16a3: 0x8735, 0x16a4: 0x8755, 0x16a5: 0x8735, 0x16a6: 0x8775, 0x16a7: 0x8795, 0x16a8: 0x87b5, 0x16a9: 0x87b5, 0x16aa: 0x87d5, 0x16ab: 0x87d5, 0x16ac: 0x87f5, 0x16ad: 0x87f5, 0x16ae: 0x87d5, 0x16af: 0x87d5, 0x16b0: 0x8815, 0x16b1: 0x8835, 0x16b2: 0x8855, 0x16b3: 0x8875, 0x16b4: 0x8895, 0x16b5: 0x88b5, 0x16b6: 0x88b5, 0x16b7: 0x88b5, 0x16b8: 0x88d5, 0x16b9: 0x88d5, 0x16ba: 0x88d5, 0x16bb: 0x88d5, 0x16bc: 0x87b5, 0x16bd: 0x87b5, 0x16be: 0x87b5, 0x16bf: 0x0040, // Block 0x5b, offset 0x16c0 0x16c0: 0x0040, 0x16c1: 0x0040, 0x16c2: 0x8715, 0x16c3: 0x86f5, 0x16c4: 0x88f5, 0x16c5: 0x86f5, 0x16c6: 0x8715, 0x16c7: 0x86f5, 0x16c8: 0x0040, 0x16c9: 0x0040, 0x16ca: 0x8915, 0x16cb: 0x8715, 0x16cc: 0x8935, 0x16cd: 0x88f5, 0x16ce: 0x8935, 0x16cf: 0x8715, 0x16d0: 0x0040, 0x16d1: 0x0040, 0x16d2: 0x8955, 0x16d3: 0x8975, 0x16d4: 0x8875, 0x16d5: 0x8935, 0x16d6: 0x88f5, 0x16d7: 0x8935, 0x16d8: 0x0040, 0x16d9: 0x0040, 0x16da: 0x8995, 0x16db: 0x89b5, 0x16dc: 0x8995, 0x16dd: 0x0040, 0x16de: 0x0040, 0x16df: 0x0040, 0x16e0: 0xb541, 0x16e1: 0xb559, 0x16e2: 0xb571, 0x16e3: 0x89d6, 0x16e4: 0xb589, 0x16e5: 0xb5a1, 0x16e6: 0x89f5, 0x16e7: 0x0040, 0x16e8: 0x8a15, 0x16e9: 0x8a35, 0x16ea: 0x8a55, 0x16eb: 0x8a35, 0x16ec: 0x8a75, 0x16ed: 0x8a95, 0x16ee: 0x8ab5, 0x16ef: 0x0040, 0x16f0: 0x0040, 0x16f1: 0x0040, 0x16f2: 0x0040, 0x16f3: 0x0040, 0x16f4: 0x0040, 0x16f5: 0x0040, 0x16f6: 0x0040, 0x16f7: 0x0040, 0x16f8: 0x0040, 0x16f9: 0x0340, 0x16fa: 0x0340, 0x16fb: 0x0340, 0x16fc: 0x0040, 0x16fd: 0x0040, 0x16fe: 0x0040, 0x16ff: 0x0040, // Block 0x5c, offset 0x1700 0x1700: 0x0a08, 0x1701: 0x0a08, 0x1702: 0x0a08, 0x1703: 0x0a08, 0x1704: 0x0a08, 0x1705: 0x0c08, 0x1706: 0x0808, 0x1707: 0x0c08, 0x1708: 0x0818, 0x1709: 0x0c08, 0x170a: 0x0c08, 0x170b: 0x0808, 0x170c: 0x0808, 0x170d: 0x0908, 0x170e: 0x0c08, 0x170f: 0x0c08, 0x1710: 0x0c08, 0x1711: 0x0c08, 0x1712: 0x0c08, 0x1713: 0x0a08, 0x1714: 0x0a08, 0x1715: 0x0a08, 0x1716: 0x0a08, 0x1717: 0x0908, 0x1718: 0x0a08, 0x1719: 0x0a08, 0x171a: 0x0a08, 0x171b: 0x0a08, 0x171c: 0x0a08, 0x171d: 0x0c08, 0x171e: 0x0a08, 0x171f: 0x0a08, 0x1720: 0x0a08, 0x1721: 0x0c08, 0x1722: 0x0808, 0x1723: 0x0808, 0x1724: 0x0c08, 0x1725: 0x3308, 0x1726: 0x3308, 0x1727: 0x0040, 0x1728: 0x0040, 0x1729: 0x0040, 0x172a: 0x0040, 0x172b: 0x0a18, 0x172c: 0x0a18, 0x172d: 0x0a18, 0x172e: 0x0a18, 0x172f: 0x0c18, 0x1730: 0x0818, 0x1731: 0x0818, 0x1732: 0x0818, 0x1733: 0x0818, 0x1734: 0x0818, 0x1735: 0x0818, 0x1736: 0x0818, 0x1737: 0x0040, 0x1738: 0x0040, 0x1739: 0x0040, 0x173a: 0x0040, 0x173b: 0x0040, 0x173c: 0x0040, 0x173d: 0x0040, 0x173e: 0x0040, 0x173f: 0x0040, // Block 0x5d, offset 0x1740 0x1740: 0x0a08, 0x1741: 0x0c08, 0x1742: 0x0a08, 0x1743: 0x0c08, 0x1744: 0x0c08, 0x1745: 0x0c08, 0x1746: 0x0a08, 0x1747: 0x0a08, 0x1748: 0x0a08, 0x1749: 0x0c08, 0x174a: 0x0a08, 0x174b: 0x0a08, 0x174c: 0x0c08, 0x174d: 0x0a08, 0x174e: 0x0c08, 0x174f: 0x0c08, 0x1750: 0x0a08, 0x1751: 0x0c08, 0x1752: 0x0040, 0x1753: 0x0040, 0x1754: 0x0040, 0x1755: 0x0040, 0x1756: 0x0040, 0x1757: 0x0040, 0x1758: 0x0040, 0x1759: 0x0818, 0x175a: 0x0818, 0x175b: 0x0818, 0x175c: 0x0818, 0x175d: 0x0040, 0x175e: 0x0040, 0x175f: 0x0040, 0x1760: 0x0040, 0x1761: 0x0040, 0x1762: 0x0040, 0x1763: 0x0040, 0x1764: 0x0040, 0x1765: 0x0040, 0x1766: 0x0040, 0x1767: 0x0040, 0x1768: 0x0040, 0x1769: 0x0c18, 0x176a: 0x0c18, 0x176b: 0x0c18, 0x176c: 0x0c18, 0x176d: 0x0a18, 0x176e: 0x0a18, 0x176f: 0x0818, 0x1770: 0x0040, 0x1771: 0x0040, 0x1772: 0x0040, 0x1773: 0x0040, 0x1774: 0x0040, 0x1775: 0x0040, 0x1776: 0x0040, 0x1777: 0x0040, 0x1778: 0x0040, 0x1779: 0x0040, 0x177a: 0x0040, 0x177b: 0x0040, 0x177c: 0x0040, 0x177d: 0x0040, 0x177e: 0x0040, 0x177f: 0x0040, // Block 0x5e, offset 0x1780 0x1780: 0x3308, 0x1781: 0x3308, 0x1782: 0x3008, 0x1783: 0x3008, 0x1784: 0x0040, 0x1785: 0x0008, 0x1786: 0x0008, 0x1787: 0x0008, 0x1788: 0x0008, 0x1789: 0x0008, 0x178a: 0x0008, 0x178b: 0x0008, 0x178c: 0x0008, 0x178d: 0x0040, 0x178e: 0x0040, 0x178f: 0x0008, 0x1790: 0x0008, 0x1791: 0x0040, 0x1792: 0x0040, 0x1793: 0x0008, 0x1794: 0x0008, 0x1795: 0x0008, 0x1796: 0x0008, 0x1797: 0x0008, 0x1798: 0x0008, 0x1799: 0x0008, 0x179a: 0x0008, 0x179b: 0x0008, 0x179c: 0x0008, 0x179d: 0x0008, 0x179e: 0x0008, 0x179f: 0x0008, 0x17a0: 0x0008, 0x17a1: 0x0008, 0x17a2: 0x0008, 0x17a3: 0x0008, 0x17a4: 0x0008, 0x17a5: 0x0008, 0x17a6: 0x0008, 0x17a7: 0x0008, 0x17a8: 0x0008, 0x17a9: 0x0040, 0x17aa: 0x0008, 0x17ab: 0x0008, 0x17ac: 0x0008, 0x17ad: 0x0008, 0x17ae: 0x0008, 0x17af: 0x0008, 0x17b0: 0x0008, 0x17b1: 0x0040, 0x17b2: 0x0008, 0x17b3: 0x0008, 0x17b4: 0x0040, 0x17b5: 0x0008, 0x17b6: 0x0008, 0x17b7: 0x0008, 0x17b8: 0x0008, 0x17b9: 0x0008, 0x17ba: 0x0040, 0x17bb: 0x0040, 0x17bc: 0x3308, 0x17bd: 0x0008, 0x17be: 0x3008, 0x17bf: 0x3008, // Block 0x5f, offset 0x17c0 0x17c0: 0x3308, 0x17c1: 0x3008, 0x17c2: 0x3008, 0x17c3: 0x3008, 0x17c4: 0x3008, 0x17c5: 0x0040, 0x17c6: 0x0040, 0x17c7: 0x3008, 0x17c8: 0x3008, 0x17c9: 0x0040, 0x17ca: 0x0040, 0x17cb: 0x3008, 0x17cc: 0x3008, 0x17cd: 0x3808, 0x17ce: 0x0040, 0x17cf: 0x0040, 0x17d0: 0x0008, 0x17d1: 0x0040, 0x17d2: 0x0040, 0x17d3: 0x0040, 0x17d4: 0x0040, 0x17d5: 0x0040, 0x17d6: 0x0040, 0x17d7: 0x3008, 0x17d8: 0x0040, 0x17d9: 0x0040, 0x17da: 0x0040, 0x17db: 0x0040, 0x17dc: 0x0040, 0x17dd: 0x0008, 0x17de: 0x0008, 0x17df: 0x0008, 0x17e0: 0x0008, 0x17e1: 0x0008, 0x17e2: 0x3008, 0x17e3: 0x3008, 0x17e4: 0x0040, 0x17e5: 0x0040, 0x17e6: 0x3308, 0x17e7: 0x3308, 0x17e8: 0x3308, 0x17e9: 0x3308, 0x17ea: 0x3308, 0x17eb: 0x3308, 0x17ec: 0x3308, 0x17ed: 0x0040, 0x17ee: 0x0040, 0x17ef: 0x0040, 0x17f0: 0x3308, 0x17f1: 0x3308, 0x17f2: 0x3308, 0x17f3: 0x3308, 0x17f4: 0x3308, 0x17f5: 0x0040, 0x17f6: 0x0040, 0x17f7: 0x0040, 0x17f8: 0x0040, 0x17f9: 0x0040, 0x17fa: 0x0040, 0x17fb: 0x0040, 0x17fc: 0x0040, 0x17fd: 0x0040, 0x17fe: 0x0040, 0x17ff: 0x0040, // Block 0x60, offset 0x1800 0x1800: 0x0039, 0x1801: 0x0ee9, 0x1802: 0x1159, 0x1803: 0x0ef9, 0x1804: 0x0f09, 0x1805: 0x1199, 0x1806: 0x0f31, 0x1807: 0x0249, 0x1808: 0x0f41, 0x1809: 0x0259, 0x180a: 0x0f51, 0x180b: 0x0359, 0x180c: 0x0f61, 0x180d: 0x0f71, 0x180e: 0x00d9, 0x180f: 0x0f99, 0x1810: 0x2039, 0x1811: 0x0269, 0x1812: 0x01d9, 0x1813: 0x0fa9, 0x1814: 0x0fb9, 0x1815: 0x1089, 0x1816: 0x0279, 0x1817: 0x0369, 0x1818: 0x0289, 0x1819: 0x13d1, 0x181a: 0x0039, 0x181b: 0x0ee9, 0x181c: 0x1159, 0x181d: 0x0ef9, 0x181e: 0x0f09, 0x181f: 0x1199, 0x1820: 0x0f31, 0x1821: 0x0249, 0x1822: 0x0f41, 0x1823: 0x0259, 0x1824: 0x0f51, 0x1825: 0x0359, 0x1826: 0x0f61, 0x1827: 0x0f71, 0x1828: 0x00d9, 0x1829: 0x0f99, 0x182a: 0x2039, 0x182b: 0x0269, 0x182c: 0x01d9, 0x182d: 0x0fa9, 0x182e: 0x0fb9, 0x182f: 0x1089, 0x1830: 0x0279, 0x1831: 0x0369, 0x1832: 0x0289, 0x1833: 0x13d1, 0x1834: 0x0039, 0x1835: 0x0ee9, 0x1836: 0x1159, 0x1837: 0x0ef9, 0x1838: 0x0f09, 0x1839: 0x1199, 0x183a: 0x0f31, 0x183b: 0x0249, 0x183c: 0x0f41, 0x183d: 0x0259, 0x183e: 0x0f51, 0x183f: 0x0359, // Block 0x61, offset 0x1840 0x1840: 0x0f61, 0x1841: 0x0f71, 0x1842: 0x00d9, 0x1843: 0x0f99, 0x1844: 0x2039, 0x1845: 0x0269, 0x1846: 0x01d9, 0x1847: 0x0fa9, 0x1848: 0x0fb9, 0x1849: 0x1089, 0x184a: 0x0279, 0x184b: 0x0369, 0x184c: 0x0289, 0x184d: 0x13d1, 0x184e: 0x0039, 0x184f: 0x0ee9, 0x1850: 0x1159, 0x1851: 0x0ef9, 0x1852: 0x0f09, 0x1853: 0x1199, 0x1854: 0x0f31, 0x1855: 0x0040, 0x1856: 0x0f41, 0x1857: 0x0259, 0x1858: 0x0f51, 0x1859: 0x0359, 0x185a: 0x0f61, 0x185b: 0x0f71, 0x185c: 0x00d9, 0x185d: 0x0f99, 0x185e: 0x2039, 0x185f: 0x0269, 0x1860: 0x01d9, 0x1861: 0x0fa9, 0x1862: 0x0fb9, 0x1863: 0x1089, 0x1864: 0x0279, 0x1865: 0x0369, 0x1866: 0x0289, 0x1867: 0x13d1, 0x1868: 0x0039, 0x1869: 0x0ee9, 0x186a: 0x1159, 0x186b: 0x0ef9, 0x186c: 0x0f09, 0x186d: 0x1199, 0x186e: 0x0f31, 0x186f: 0x0249, 0x1870: 0x0f41, 0x1871: 0x0259, 0x1872: 0x0f51, 0x1873: 0x0359, 0x1874: 0x0f61, 0x1875: 0x0f71, 0x1876: 0x00d9, 0x1877: 0x0f99, 0x1878: 0x2039, 0x1879: 0x0269, 0x187a: 0x01d9, 0x187b: 0x0fa9, 0x187c: 0x0fb9, 0x187d: 0x1089, 0x187e: 0x0279, 0x187f: 0x0369, // Block 0x62, offset 0x1880 0x1880: 0x0289, 0x1881: 0x13d1, 0x1882: 0x0039, 0x1883: 0x0ee9, 0x1884: 0x1159, 0x1885: 0x0ef9, 0x1886: 0x0f09, 0x1887: 0x1199, 0x1888: 0x0f31, 0x1889: 0x0249, 0x188a: 0x0f41, 0x188b: 0x0259, 0x188c: 0x0f51, 0x188d: 0x0359, 0x188e: 0x0f61, 0x188f: 0x0f71, 0x1890: 0x00d9, 0x1891: 0x0f99, 0x1892: 0x2039, 0x1893: 0x0269, 0x1894: 0x01d9, 0x1895: 0x0fa9, 0x1896: 0x0fb9, 0x1897: 0x1089, 0x1898: 0x0279, 0x1899: 0x0369, 0x189a: 0x0289, 0x189b: 0x13d1, 0x189c: 0x0039, 0x189d: 0x0040, 0x189e: 0x1159, 0x189f: 0x0ef9, 0x18a0: 0x0040, 0x18a1: 0x0040, 0x18a2: 0x0f31, 0x18a3: 0x0040, 0x18a4: 0x0040, 0x18a5: 0x0259, 0x18a6: 0x0f51, 0x18a7: 0x0040, 0x18a8: 0x0040, 0x18a9: 0x0f71, 0x18aa: 0x00d9, 0x18ab: 0x0f99, 0x18ac: 0x2039, 0x18ad: 0x0040, 0x18ae: 0x01d9, 0x18af: 0x0fa9, 0x18b0: 0x0fb9, 0x18b1: 0x1089, 0x18b2: 0x0279, 0x18b3: 0x0369, 0x18b4: 0x0289, 0x18b5: 0x13d1, 0x18b6: 0x0039, 0x18b7: 0x0ee9, 0x18b8: 0x1159, 0x18b9: 0x0ef9, 0x18ba: 0x0040, 0x18bb: 0x1199, 0x18bc: 0x0040, 0x18bd: 0x0249, 0x18be: 0x0f41, 0x18bf: 0x0259, // Block 0x63, offset 0x18c0 0x18c0: 0x0f51, 0x18c1: 0x0359, 0x18c2: 0x0f61, 0x18c3: 0x0f71, 0x18c4: 0x0040, 0x18c5: 0x0f99, 0x18c6: 0x2039, 0x18c7: 0x0269, 0x18c8: 0x01d9, 0x18c9: 0x0fa9, 0x18ca: 0x0fb9, 0x18cb: 0x1089, 0x18cc: 0x0279, 0x18cd: 0x0369, 0x18ce: 0x0289, 0x18cf: 0x13d1, 0x18d0: 0x0039, 0x18d1: 0x0ee9, 0x18d2: 0x1159, 0x18d3: 0x0ef9, 0x18d4: 0x0f09, 0x18d5: 0x1199, 0x18d6: 0x0f31, 0x18d7: 0x0249, 0x18d8: 0x0f41, 0x18d9: 0x0259, 0x18da: 0x0f51, 0x18db: 0x0359, 0x18dc: 0x0f61, 0x18dd: 0x0f71, 0x18de: 0x00d9, 0x18df: 0x0f99, 0x18e0: 0x2039, 0x18e1: 0x0269, 0x18e2: 0x01d9, 0x18e3: 0x0fa9, 0x18e4: 0x0fb9, 0x18e5: 0x1089, 0x18e6: 0x0279, 0x18e7: 0x0369, 0x18e8: 0x0289, 0x18e9: 0x13d1, 0x18ea: 0x0039, 0x18eb: 0x0ee9, 0x18ec: 0x1159, 0x18ed: 0x0ef9, 0x18ee: 0x0f09, 0x18ef: 0x1199, 0x18f0: 0x0f31, 0x18f1: 0x0249, 0x18f2: 0x0f41, 0x18f3: 0x0259, 0x18f4: 0x0f51, 0x18f5: 0x0359, 0x18f6: 0x0f61, 0x18f7: 0x0f71, 0x18f8: 0x00d9, 0x18f9: 0x0f99, 0x18fa: 0x2039, 0x18fb: 0x0269, 0x18fc: 0x01d9, 0x18fd: 0x0fa9, 0x18fe: 0x0fb9, 0x18ff: 0x1089, // Block 0x64, offset 0x1900 0x1900: 0x0279, 0x1901: 0x0369, 0x1902: 0x0289, 0x1903: 0x13d1, 0x1904: 0x0039, 0x1905: 0x0ee9, 0x1906: 0x0040, 0x1907: 0x0ef9, 0x1908: 0x0f09, 0x1909: 0x1199, 0x190a: 0x0f31, 0x190b: 0x0040, 0x190c: 0x0040, 0x190d: 0x0259, 0x190e: 0x0f51, 0x190f: 0x0359, 0x1910: 0x0f61, 0x1911: 0x0f71, 0x1912: 0x00d9, 0x1913: 0x0f99, 0x1914: 0x2039, 0x1915: 0x0040, 0x1916: 0x01d9, 0x1917: 0x0fa9, 0x1918: 0x0fb9, 0x1919: 0x1089, 0x191a: 0x0279, 0x191b: 0x0369, 0x191c: 0x0289, 0x191d: 0x0040, 0x191e: 0x0039, 0x191f: 0x0ee9, 0x1920: 0x1159, 0x1921: 0x0ef9, 0x1922: 0x0f09, 0x1923: 0x1199, 0x1924: 0x0f31, 0x1925: 0x0249, 0x1926: 0x0f41, 0x1927: 0x0259, 0x1928: 0x0f51, 0x1929: 0x0359, 0x192a: 0x0f61, 0x192b: 0x0f71, 0x192c: 0x00d9, 0x192d: 0x0f99, 0x192e: 0x2039, 0x192f: 0x0269, 0x1930: 0x01d9, 0x1931: 0x0fa9, 0x1932: 0x0fb9, 0x1933: 0x1089, 0x1934: 0x0279, 0x1935: 0x0369, 0x1936: 0x0289, 0x1937: 0x13d1, 0x1938: 0x0039, 0x1939: 0x0ee9, 0x193a: 0x0040, 0x193b: 0x0ef9, 0x193c: 0x0f09, 0x193d: 0x1199, 0x193e: 0x0f31, 0x193f: 0x0040, // Block 0x65, offset 0x1940 0x1940: 0x0f41, 0x1941: 0x0259, 0x1942: 0x0f51, 0x1943: 0x0359, 0x1944: 0x0f61, 0x1945: 0x0040, 0x1946: 0x00d9, 0x1947: 0x0040, 0x1948: 0x0040, 0x1949: 0x0040, 0x194a: 0x01d9, 0x194b: 0x0fa9, 0x194c: 0x0fb9, 0x194d: 0x1089, 0x194e: 0x0279, 0x194f: 0x0369, 0x1950: 0x0289, 0x1951: 0x0040, 0x1952: 0x0039, 0x1953: 0x0ee9, 0x1954: 0x1159, 0x1955: 0x0ef9, 0x1956: 0x0f09, 0x1957: 0x1199, 0x1958: 0x0f31, 0x1959: 0x0249, 0x195a: 0x0f41, 0x195b: 0x0259, 0x195c: 0x0f51, 0x195d: 0x0359, 0x195e: 0x0f61, 0x195f: 0x0f71, 0x1960: 0x00d9, 0x1961: 0x0f99, 0x1962: 0x2039, 0x1963: 0x0269, 0x1964: 0x01d9, 0x1965: 0x0fa9, 0x1966: 0x0fb9, 0x1967: 0x1089, 0x1968: 0x0279, 0x1969: 0x0369, 0x196a: 0x0289, 0x196b: 0x13d1, 0x196c: 0x0039, 0x196d: 0x0ee9, 0x196e: 0x1159, 0x196f: 0x0ef9, 0x1970: 0x0f09, 0x1971: 0x1199, 0x1972: 0x0f31, 0x1973: 0x0249, 0x1974: 0x0f41, 0x1975: 0x0259, 0x1976: 0x0f51, 0x1977: 0x0359, 0x1978: 0x0f61, 0x1979: 0x0f71, 0x197a: 0x00d9, 0x197b: 0x0f99, 0x197c: 0x2039, 0x197d: 0x0269, 0x197e: 0x01d9, 0x197f: 0x0fa9, // Block 0x66, offset 0x1980 0x1980: 0x0fb9, 0x1981: 0x1089, 0x1982: 0x0279, 0x1983: 0x0369, 0x1984: 0x0289, 0x1985: 0x13d1, 0x1986: 0x0039, 0x1987: 0x0ee9, 0x1988: 0x1159, 0x1989: 0x0ef9, 0x198a: 0x0f09, 0x198b: 0x1199, 0x198c: 0x0f31, 0x198d: 0x0249, 0x198e: 0x0f41, 0x198f: 0x0259, 0x1990: 0x0f51, 0x1991: 0x0359, 0x1992: 0x0f61, 0x1993: 0x0f71, 0x1994: 0x00d9, 0x1995: 0x0f99, 0x1996: 0x2039, 0x1997: 0x0269, 0x1998: 0x01d9, 0x1999: 0x0fa9, 0x199a: 0x0fb9, 0x199b: 0x1089, 0x199c: 0x0279, 0x199d: 0x0369, 0x199e: 0x0289, 0x199f: 0x13d1, 0x19a0: 0x0039, 0x19a1: 0x0ee9, 0x19a2: 0x1159, 0x19a3: 0x0ef9, 0x19a4: 0x0f09, 0x19a5: 0x1199, 0x19a6: 0x0f31, 0x19a7: 0x0249, 0x19a8: 0x0f41, 0x19a9: 0x0259, 0x19aa: 0x0f51, 0x19ab: 0x0359, 0x19ac: 0x0f61, 0x19ad: 0x0f71, 0x19ae: 0x00d9, 0x19af: 0x0f99, 0x19b0: 0x2039, 0x19b1: 0x0269, 0x19b2: 0x01d9, 0x19b3: 0x0fa9, 0x19b4: 0x0fb9, 0x19b5: 0x1089, 0x19b6: 0x0279, 0x19b7: 0x0369, 0x19b8: 0x0289, 0x19b9: 0x13d1, 0x19ba: 0x0039, 0x19bb: 0x0ee9, 0x19bc: 0x1159, 0x19bd: 0x0ef9, 0x19be: 0x0f09, 0x19bf: 0x1199, // Block 0x67, offset 0x19c0 0x19c0: 0x0f31, 0x19c1: 0x0249, 0x19c2: 0x0f41, 0x19c3: 0x0259, 0x19c4: 0x0f51, 0x19c5: 0x0359, 0x19c6: 0x0f61, 0x19c7: 0x0f71, 0x19c8: 0x00d9, 0x19c9: 0x0f99, 0x19ca: 0x2039, 0x19cb: 0x0269, 0x19cc: 0x01d9, 0x19cd: 0x0fa9, 0x19ce: 0x0fb9, 0x19cf: 0x1089, 0x19d0: 0x0279, 0x19d1: 0x0369, 0x19d2: 0x0289, 0x19d3: 0x13d1, 0x19d4: 0x0039, 0x19d5: 0x0ee9, 0x19d6: 0x1159, 0x19d7: 0x0ef9, 0x19d8: 0x0f09, 0x19d9: 0x1199, 0x19da: 0x0f31, 0x19db: 0x0249, 0x19dc: 0x0f41, 0x19dd: 0x0259, 0x19de: 0x0f51, 0x19df: 0x0359, 0x19e0: 0x0f61, 0x19e1: 0x0f71, 0x19e2: 0x00d9, 0x19e3: 0x0f99, 0x19e4: 0x2039, 0x19e5: 0x0269, 0x19e6: 0x01d9, 0x19e7: 0x0fa9, 0x19e8: 0x0fb9, 0x19e9: 0x1089, 0x19ea: 0x0279, 0x19eb: 0x0369, 0x19ec: 0x0289, 0x19ed: 0x13d1, 0x19ee: 0x0039, 0x19ef: 0x0ee9, 0x19f0: 0x1159, 0x19f1: 0x0ef9, 0x19f2: 0x0f09, 0x19f3: 0x1199, 0x19f4: 0x0f31, 0x19f5: 0x0249, 0x19f6: 0x0f41, 0x19f7: 0x0259, 0x19f8: 0x0f51, 0x19f9: 0x0359, 0x19fa: 0x0f61, 0x19fb: 0x0f71, 0x19fc: 0x00d9, 0x19fd: 0x0f99, 0x19fe: 0x2039, 0x19ff: 0x0269, // Block 0x68, offset 0x1a00 0x1a00: 0x01d9, 0x1a01: 0x0fa9, 0x1a02: 0x0fb9, 0x1a03: 0x1089, 0x1a04: 0x0279, 0x1a05: 0x0369, 0x1a06: 0x0289, 0x1a07: 0x13d1, 0x1a08: 0x0039, 0x1a09: 0x0ee9, 0x1a0a: 0x1159, 0x1a0b: 0x0ef9, 0x1a0c: 0x0f09, 0x1a0d: 0x1199, 0x1a0e: 0x0f31, 0x1a0f: 0x0249, 0x1a10: 0x0f41, 0x1a11: 0x0259, 0x1a12: 0x0f51, 0x1a13: 0x0359, 0x1a14: 0x0f61, 0x1a15: 0x0f71, 0x1a16: 0x00d9, 0x1a17: 0x0f99, 0x1a18: 0x2039, 0x1a19: 0x0269, 0x1a1a: 0x01d9, 0x1a1b: 0x0fa9, 0x1a1c: 0x0fb9, 0x1a1d: 0x1089, 0x1a1e: 0x0279, 0x1a1f: 0x0369, 0x1a20: 0x0289, 0x1a21: 0x13d1, 0x1a22: 0x0039, 0x1a23: 0x0ee9, 0x1a24: 0x1159, 0x1a25: 0x0ef9, 0x1a26: 0x0f09, 0x1a27: 0x1199, 0x1a28: 0x0f31, 0x1a29: 0x0249, 0x1a2a: 0x0f41, 0x1a2b: 0x0259, 0x1a2c: 0x0f51, 0x1a2d: 0x0359, 0x1a2e: 0x0f61, 0x1a2f: 0x0f71, 0x1a30: 0x00d9, 0x1a31: 0x0f99, 0x1a32: 0x2039, 0x1a33: 0x0269, 0x1a34: 0x01d9, 0x1a35: 0x0fa9, 0x1a36: 0x0fb9, 0x1a37: 0x1089, 0x1a38: 0x0279, 0x1a39: 0x0369, 0x1a3a: 0x0289, 0x1a3b: 0x13d1, 0x1a3c: 0x0039, 0x1a3d: 0x0ee9, 0x1a3e: 0x1159, 0x1a3f: 0x0ef9, // Block 0x69, offset 0x1a40 0x1a40: 0x0f09, 0x1a41: 0x1199, 0x1a42: 0x0f31, 0x1a43: 0x0249, 0x1a44: 0x0f41, 0x1a45: 0x0259, 0x1a46: 0x0f51, 0x1a47: 0x0359, 0x1a48: 0x0f61, 0x1a49: 0x0f71, 0x1a4a: 0x00d9, 0x1a4b: 0x0f99, 0x1a4c: 0x2039, 0x1a4d: 0x0269, 0x1a4e: 0x01d9, 0x1a4f: 0x0fa9, 0x1a50: 0x0fb9, 0x1a51: 0x1089, 0x1a52: 0x0279, 0x1a53: 0x0369, 0x1a54: 0x0289, 0x1a55: 0x13d1, 0x1a56: 0x0039, 0x1a57: 0x0ee9, 0x1a58: 0x1159, 0x1a59: 0x0ef9, 0x1a5a: 0x0f09, 0x1a5b: 0x1199, 0x1a5c: 0x0f31, 0x1a5d: 0x0249, 0x1a5e: 0x0f41, 0x1a5f: 0x0259, 0x1a60: 0x0f51, 0x1a61: 0x0359, 0x1a62: 0x0f61, 0x1a63: 0x0f71, 0x1a64: 0x00d9, 0x1a65: 0x0f99, 0x1a66: 0x2039, 0x1a67: 0x0269, 0x1a68: 0x01d9, 0x1a69: 0x0fa9, 0x1a6a: 0x0fb9, 0x1a6b: 0x1089, 0x1a6c: 0x0279, 0x1a6d: 0x0369, 0x1a6e: 0x0289, 0x1a6f: 0x13d1, 0x1a70: 0x0039, 0x1a71: 0x0ee9, 0x1a72: 0x1159, 0x1a73: 0x0ef9, 0x1a74: 0x0f09, 0x1a75: 0x1199, 0x1a76: 0x0f31, 0x1a77: 0x0249, 0x1a78: 0x0f41, 0x1a79: 0x0259, 0x1a7a: 0x0f51, 0x1a7b: 0x0359, 0x1a7c: 0x0f61, 0x1a7d: 0x0f71, 0x1a7e: 0x00d9, 0x1a7f: 0x0f99, // Block 0x6a, offset 0x1a80 0x1a80: 0x2039, 0x1a81: 0x0269, 0x1a82: 0x01d9, 0x1a83: 0x0fa9, 0x1a84: 0x0fb9, 0x1a85: 0x1089, 0x1a86: 0x0279, 0x1a87: 0x0369, 0x1a88: 0x0289, 0x1a89: 0x13d1, 0x1a8a: 0x0039, 0x1a8b: 0x0ee9, 0x1a8c: 0x1159, 0x1a8d: 0x0ef9, 0x1a8e: 0x0f09, 0x1a8f: 0x1199, 0x1a90: 0x0f31, 0x1a91: 0x0249, 0x1a92: 0x0f41, 0x1a93: 0x0259, 0x1a94: 0x0f51, 0x1a95: 0x0359, 0x1a96: 0x0f61, 0x1a97: 0x0f71, 0x1a98: 0x00d9, 0x1a99: 0x0f99, 0x1a9a: 0x2039, 0x1a9b: 0x0269, 0x1a9c: 0x01d9, 0x1a9d: 0x0fa9, 0x1a9e: 0x0fb9, 0x1a9f: 0x1089, 0x1aa0: 0x0279, 0x1aa1: 0x0369, 0x1aa2: 0x0289, 0x1aa3: 0x13d1, 0x1aa4: 0xba81, 0x1aa5: 0xba99, 0x1aa6: 0x0040, 0x1aa7: 0x0040, 0x1aa8: 0xbab1, 0x1aa9: 0x1099, 0x1aaa: 0x10b1, 0x1aab: 0x10c9, 0x1aac: 0xbac9, 0x1aad: 0xbae1, 0x1aae: 0xbaf9, 0x1aaf: 0x1429, 0x1ab0: 0x1a31, 0x1ab1: 0xbb11, 0x1ab2: 0xbb29, 0x1ab3: 0xbb41, 0x1ab4: 0xbb59, 0x1ab5: 0xbb71, 0x1ab6: 0xbb89, 0x1ab7: 0x2109, 0x1ab8: 0x1111, 0x1ab9: 0x1429, 0x1aba: 0xbba1, 0x1abb: 0xbbb9, 0x1abc: 0xbbd1, 0x1abd: 0x10e1, 0x1abe: 0x10f9, 0x1abf: 0xbbe9, // Block 0x6b, offset 0x1ac0 0x1ac0: 0x2079, 0x1ac1: 0xbc01, 0x1ac2: 0xbab1, 0x1ac3: 0x1099, 0x1ac4: 0x10b1, 0x1ac5: 0x10c9, 0x1ac6: 0xbac9, 0x1ac7: 0xbae1, 0x1ac8: 0xbaf9, 0x1ac9: 0x1429, 0x1aca: 0x1a31, 0x1acb: 0xbb11, 0x1acc: 0xbb29, 0x1acd: 0xbb41, 0x1ace: 0xbb59, 0x1acf: 0xbb71, 0x1ad0: 0xbb89, 0x1ad1: 0x2109, 0x1ad2: 0x1111, 0x1ad3: 0xbba1, 0x1ad4: 0xbba1, 0x1ad5: 0xbbb9, 0x1ad6: 0xbbd1, 0x1ad7: 0x10e1, 0x1ad8: 0x10f9, 0x1ad9: 0xbbe9, 0x1ada: 0x2079, 0x1adb: 0xbc21, 0x1adc: 0xbac9, 0x1add: 0x1429, 0x1ade: 0xbb11, 0x1adf: 0x10e1, 0x1ae0: 0x1111, 0x1ae1: 0x2109, 0x1ae2: 0xbab1, 0x1ae3: 0x1099, 0x1ae4: 0x10b1, 0x1ae5: 0x10c9, 0x1ae6: 0xbac9, 0x1ae7: 0xbae1, 0x1ae8: 0xbaf9, 0x1ae9: 0x1429, 0x1aea: 0x1a31, 0x1aeb: 0xbb11, 0x1aec: 0xbb29, 0x1aed: 0xbb41, 0x1aee: 0xbb59, 0x1aef: 0xbb71, 0x1af0: 0xbb89, 0x1af1: 0x2109, 0x1af2: 0x1111, 0x1af3: 0x1429, 0x1af4: 0xbba1, 0x1af5: 0xbbb9, 0x1af6: 0xbbd1, 0x1af7: 0x10e1, 0x1af8: 0x10f9, 0x1af9: 0xbbe9, 0x1afa: 0x2079, 0x1afb: 0xbc01, 0x1afc: 0xbab1, 0x1afd: 0x1099, 0x1afe: 0x10b1, 0x1aff: 0x10c9, // Block 0x6c, offset 0x1b00 0x1b00: 0xbac9, 0x1b01: 0xbae1, 0x1b02: 0xbaf9, 0x1b03: 0x1429, 0x1b04: 0x1a31, 0x1b05: 0xbb11, 0x1b06: 0xbb29, 0x1b07: 0xbb41, 0x1b08: 0xbb59, 0x1b09: 0xbb71, 0x1b0a: 0xbb89, 0x1b0b: 0x2109, 0x1b0c: 0x1111, 0x1b0d: 0xbba1, 0x1b0e: 0xbba1, 0x1b0f: 0xbbb9, 0x1b10: 0xbbd1, 0x1b11: 0x10e1, 0x1b12: 0x10f9, 0x1b13: 0xbbe9, 0x1b14: 0x2079, 0x1b15: 0xbc21, 0x1b16: 0xbac9, 0x1b17: 0x1429, 0x1b18: 0xbb11, 0x1b19: 0x10e1, 0x1b1a: 0x1111, 0x1b1b: 0x2109, 0x1b1c: 0xbab1, 0x1b1d: 0x1099, 0x1b1e: 0x10b1, 0x1b1f: 0x10c9, 0x1b20: 0xbac9, 0x1b21: 0xbae1, 0x1b22: 0xbaf9, 0x1b23: 0x1429, 0x1b24: 0x1a31, 0x1b25: 0xbb11, 0x1b26: 0xbb29, 0x1b27: 0xbb41, 0x1b28: 0xbb59, 0x1b29: 0xbb71, 0x1b2a: 0xbb89, 0x1b2b: 0x2109, 0x1b2c: 0x1111, 0x1b2d: 0x1429, 0x1b2e: 0xbba1, 0x1b2f: 0xbbb9, 0x1b30: 0xbbd1, 0x1b31: 0x10e1, 0x1b32: 0x10f9, 0x1b33: 0xbbe9, 0x1b34: 0x2079, 0x1b35: 0xbc01, 0x1b36: 0xbab1, 0x1b37: 0x1099, 0x1b38: 0x10b1, 0x1b39: 0x10c9, 0x1b3a: 0xbac9, 0x1b3b: 0xbae1, 0x1b3c: 0xbaf9, 0x1b3d: 0x1429, 0x1b3e: 0x1a31, 0x1b3f: 0xbb11, // Block 0x6d, offset 0x1b40 0x1b40: 0xbb29, 0x1b41: 0xbb41, 0x1b42: 0xbb59, 0x1b43: 0xbb71, 0x1b44: 0xbb89, 0x1b45: 0x2109, 0x1b46: 0x1111, 0x1b47: 0xbba1, 0x1b48: 0xbba1, 0x1b49: 0xbbb9, 0x1b4a: 0xbbd1, 0x1b4b: 0x10e1, 0x1b4c: 0x10f9, 0x1b4d: 0xbbe9, 0x1b4e: 0x2079, 0x1b4f: 0xbc21, 0x1b50: 0xbac9, 0x1b51: 0x1429, 0x1b52: 0xbb11, 0x1b53: 0x10e1, 0x1b54: 0x1111, 0x1b55: 0x2109, 0x1b56: 0xbab1, 0x1b57: 0x1099, 0x1b58: 0x10b1, 0x1b59: 0x10c9, 0x1b5a: 0xbac9, 0x1b5b: 0xbae1, 0x1b5c: 0xbaf9, 0x1b5d: 0x1429, 0x1b5e: 0x1a31, 0x1b5f: 0xbb11, 0x1b60: 0xbb29, 0x1b61: 0xbb41, 0x1b62: 0xbb59, 0x1b63: 0xbb71, 0x1b64: 0xbb89, 0x1b65: 0x2109, 0x1b66: 0x1111, 0x1b67: 0x1429, 0x1b68: 0xbba1, 0x1b69: 0xbbb9, 0x1b6a: 0xbbd1, 0x1b6b: 0x10e1, 0x1b6c: 0x10f9, 0x1b6d: 0xbbe9, 0x1b6e: 0x2079, 0x1b6f: 0xbc01, 0x1b70: 0xbab1, 0x1b71: 0x1099, 0x1b72: 0x10b1, 0x1b73: 0x10c9, 0x1b74: 0xbac9, 0x1b75: 0xbae1, 0x1b76: 0xbaf9, 0x1b77: 0x1429, 0x1b78: 0x1a31, 0x1b79: 0xbb11, 0x1b7a: 0xbb29, 0x1b7b: 0xbb41, 0x1b7c: 0xbb59, 0x1b7d: 0xbb71, 0x1b7e: 0xbb89, 0x1b7f: 0x2109, // Block 0x6e, offset 0x1b80 0x1b80: 0x1111, 0x1b81: 0xbba1, 0x1b82: 0xbba1, 0x1b83: 0xbbb9, 0x1b84: 0xbbd1, 0x1b85: 0x10e1, 0x1b86: 0x10f9, 0x1b87: 0xbbe9, 0x1b88: 0x2079, 0x1b89: 0xbc21, 0x1b8a: 0xbac9, 0x1b8b: 0x1429, 0x1b8c: 0xbb11, 0x1b8d: 0x10e1, 0x1b8e: 0x1111, 0x1b8f: 0x2109, 0x1b90: 0xbab1, 0x1b91: 0x1099, 0x1b92: 0x10b1, 0x1b93: 0x10c9, 0x1b94: 0xbac9, 0x1b95: 0xbae1, 0x1b96: 0xbaf9, 0x1b97: 0x1429, 0x1b98: 0x1a31, 0x1b99: 0xbb11, 0x1b9a: 0xbb29, 0x1b9b: 0xbb41, 0x1b9c: 0xbb59, 0x1b9d: 0xbb71, 0x1b9e: 0xbb89, 0x1b9f: 0x2109, 0x1ba0: 0x1111, 0x1ba1: 0x1429, 0x1ba2: 0xbba1, 0x1ba3: 0xbbb9, 0x1ba4: 0xbbd1, 0x1ba5: 0x10e1, 0x1ba6: 0x10f9, 0x1ba7: 0xbbe9, 0x1ba8: 0x2079, 0x1ba9: 0xbc01, 0x1baa: 0xbab1, 0x1bab: 0x1099, 0x1bac: 0x10b1, 0x1bad: 0x10c9, 0x1bae: 0xbac9, 0x1baf: 0xbae1, 0x1bb0: 0xbaf9, 0x1bb1: 0x1429, 0x1bb2: 0x1a31, 0x1bb3: 0xbb11, 0x1bb4: 0xbb29, 0x1bb5: 0xbb41, 0x1bb6: 0xbb59, 0x1bb7: 0xbb71, 0x1bb8: 0xbb89, 0x1bb9: 0x2109, 0x1bba: 0x1111, 0x1bbb: 0xbba1, 0x1bbc: 0xbba1, 0x1bbd: 0xbbb9, 0x1bbe: 0xbbd1, 0x1bbf: 0x10e1, // Block 0x6f, offset 0x1bc0 0x1bc0: 0x10f9, 0x1bc1: 0xbbe9, 0x1bc2: 0x2079, 0x1bc3: 0xbc21, 0x1bc4: 0xbac9, 0x1bc5: 0x1429, 0x1bc6: 0xbb11, 0x1bc7: 0x10e1, 0x1bc8: 0x1111, 0x1bc9: 0x2109, 0x1bca: 0xbc41, 0x1bcb: 0xbc41, 0x1bcc: 0x0040, 0x1bcd: 0x0040, 0x1bce: 0x1f41, 0x1bcf: 0x00c9, 0x1bd0: 0x0069, 0x1bd1: 0x0079, 0x1bd2: 0x1f51, 0x1bd3: 0x1f61, 0x1bd4: 0x1f71, 0x1bd5: 0x1f81, 0x1bd6: 0x1f91, 0x1bd7: 0x1fa1, 0x1bd8: 0x1f41, 0x1bd9: 0x00c9, 0x1bda: 0x0069, 0x1bdb: 0x0079, 0x1bdc: 0x1f51, 0x1bdd: 0x1f61, 0x1bde: 0x1f71, 0x1bdf: 0x1f81, 0x1be0: 0x1f91, 0x1be1: 0x1fa1, 0x1be2: 0x1f41, 0x1be3: 0x00c9, 0x1be4: 0x0069, 0x1be5: 0x0079, 0x1be6: 0x1f51, 0x1be7: 0x1f61, 0x1be8: 0x1f71, 0x1be9: 0x1f81, 0x1bea: 0x1f91, 0x1beb: 0x1fa1, 0x1bec: 0x1f41, 0x1bed: 0x00c9, 0x1bee: 0x0069, 0x1bef: 0x0079, 0x1bf0: 0x1f51, 0x1bf1: 0x1f61, 0x1bf2: 0x1f71, 0x1bf3: 0x1f81, 0x1bf4: 0x1f91, 0x1bf5: 0x1fa1, 0x1bf6: 0x1f41, 0x1bf7: 0x00c9, 0x1bf8: 0x0069, 0x1bf9: 0x0079, 0x1bfa: 0x1f51, 0x1bfb: 0x1f61, 0x1bfc: 0x1f71, 0x1bfd: 0x1f81, 0x1bfe: 0x1f91, 0x1bff: 0x1fa1, // Block 0x70, offset 0x1c00 0x1c00: 0xe115, 0x1c01: 0xe115, 0x1c02: 0xe135, 0x1c03: 0xe135, 0x1c04: 0xe115, 0x1c05: 0xe115, 0x1c06: 0xe175, 0x1c07: 0xe175, 0x1c08: 0xe115, 0x1c09: 0xe115, 0x1c0a: 0xe135, 0x1c0b: 0xe135, 0x1c0c: 0xe115, 0x1c0d: 0xe115, 0x1c0e: 0xe1f5, 0x1c0f: 0xe1f5, 0x1c10: 0xe115, 0x1c11: 0xe115, 0x1c12: 0xe135, 0x1c13: 0xe135, 0x1c14: 0xe115, 0x1c15: 0xe115, 0x1c16: 0xe175, 0x1c17: 0xe175, 0x1c18: 0xe115, 0x1c19: 0xe115, 0x1c1a: 0xe135, 0x1c1b: 0xe135, 0x1c1c: 0xe115, 0x1c1d: 0xe115, 0x1c1e: 0x8b05, 0x1c1f: 0x8b05, 0x1c20: 0x04b5, 0x1c21: 0x04b5, 0x1c22: 0x0a08, 0x1c23: 0x0a08, 0x1c24: 0x0a08, 0x1c25: 0x0a08, 0x1c26: 0x0a08, 0x1c27: 0x0a08, 0x1c28: 0x0a08, 0x1c29: 0x0a08, 0x1c2a: 0x0a08, 0x1c2b: 0x0a08, 0x1c2c: 0x0a08, 0x1c2d: 0x0a08, 0x1c2e: 0x0a08, 0x1c2f: 0x0a08, 0x1c30: 0x0a08, 0x1c31: 0x0a08, 0x1c32: 0x0a08, 0x1c33: 0x0a08, 0x1c34: 0x0a08, 0x1c35: 0x0a08, 0x1c36: 0x0a08, 0x1c37: 0x0a08, 0x1c38: 0x0a08, 0x1c39: 0x0a08, 0x1c3a: 0x0a08, 0x1c3b: 0x0a08, 0x1c3c: 0x0a08, 0x1c3d: 0x0a08, 0x1c3e: 0x0a08, 0x1c3f: 0x0a08, // Block 0x71, offset 0x1c40 0x1c40: 0xb189, 0x1c41: 0xb1a1, 0x1c42: 0xb201, 0x1c43: 0xb249, 0x1c44: 0x0040, 0x1c45: 0xb411, 0x1c46: 0xb291, 0x1c47: 0xb219, 0x1c48: 0xb309, 0x1c49: 0xb429, 0x1c4a: 0xb399, 0x1c4b: 0xb3b1, 0x1c4c: 0xb3c9, 0x1c4d: 0xb3e1, 0x1c4e: 0xb2a9, 0x1c4f: 0xb339, 0x1c50: 0xb369, 0x1c51: 0xb2d9, 0x1c52: 0xb381, 0x1c53: 0xb279, 0x1c54: 0xb2c1, 0x1c55: 0xb1d1, 0x1c56: 0xb1e9, 0x1c57: 0xb231, 0x1c58: 0xb261, 0x1c59: 0xb2f1, 0x1c5a: 0xb321, 0x1c5b: 0xb351, 0x1c5c: 0xbc59, 0x1c5d: 0x7949, 0x1c5e: 0xbc71, 0x1c5f: 0xbc89, 0x1c60: 0x0040, 0x1c61: 0xb1a1, 0x1c62: 0xb201, 0x1c63: 0x0040, 0x1c64: 0xb3f9, 0x1c65: 0x0040, 0x1c66: 0x0040, 0x1c67: 0xb219, 0x1c68: 0x0040, 0x1c69: 0xb429, 0x1c6a: 0xb399, 0x1c6b: 0xb3b1, 0x1c6c: 0xb3c9, 0x1c6d: 0xb3e1, 0x1c6e: 0xb2a9, 0x1c6f: 0xb339, 0x1c70: 0xb369, 0x1c71: 0xb2d9, 0x1c72: 0xb381, 0x1c73: 0x0040, 0x1c74: 0xb2c1, 0x1c75: 0xb1d1, 0x1c76: 0xb1e9, 0x1c77: 0xb231, 0x1c78: 0x0040, 0x1c79: 0xb2f1, 0x1c7a: 0x0040, 0x1c7b: 0xb351, 0x1c7c: 0x0040, 0x1c7d: 0x0040, 0x1c7e: 0x0040, 0x1c7f: 0x0040, // Block 0x72, offset 0x1c80 0x1c80: 0x0040, 0x1c81: 0x0040, 0x1c82: 0xb201, 0x1c83: 0x0040, 0x1c84: 0x0040, 0x1c85: 0x0040, 0x1c86: 0x0040, 0x1c87: 0xb219, 0x1c88: 0x0040, 0x1c89: 0xb429, 0x1c8a: 0x0040, 0x1c8b: 0xb3b1, 0x1c8c: 0x0040, 0x1c8d: 0xb3e1, 0x1c8e: 0xb2a9, 0x1c8f: 0xb339, 0x1c90: 0x0040, 0x1c91: 0xb2d9, 0x1c92: 0xb381, 0x1c93: 0x0040, 0x1c94: 0xb2c1, 0x1c95: 0x0040, 0x1c96: 0x0040, 0x1c97: 0xb231, 0x1c98: 0x0040, 0x1c99: 0xb2f1, 0x1c9a: 0x0040, 0x1c9b: 0xb351, 0x1c9c: 0x0040, 0x1c9d: 0x7949, 0x1c9e: 0x0040, 0x1c9f: 0xbc89, 0x1ca0: 0x0040, 0x1ca1: 0xb1a1, 0x1ca2: 0xb201, 0x1ca3: 0x0040, 0x1ca4: 0xb3f9, 0x1ca5: 0x0040, 0x1ca6: 0x0040, 0x1ca7: 0xb219, 0x1ca8: 0xb309, 0x1ca9: 0xb429, 0x1caa: 0xb399, 0x1cab: 0x0040, 0x1cac: 0xb3c9, 0x1cad: 0xb3e1, 0x1cae: 0xb2a9, 0x1caf: 0xb339, 0x1cb0: 0xb369, 0x1cb1: 0xb2d9, 0x1cb2: 0xb381, 0x1cb3: 0x0040, 0x1cb4: 0xb2c1, 0x1cb5: 0xb1d1, 0x1cb6: 0xb1e9, 0x1cb7: 0xb231, 0x1cb8: 0x0040, 0x1cb9: 0xb2f1, 0x1cba: 0xb321, 0x1cbb: 0xb351, 0x1cbc: 0xbc59, 0x1cbd: 0x0040, 0x1cbe: 0xbc71, 0x1cbf: 0x0040, // Block 0x73, offset 0x1cc0 0x1cc0: 0xb189, 0x1cc1: 0xb1a1, 0x1cc2: 0xb201, 0x1cc3: 0xb249, 0x1cc4: 0xb3f9, 0x1cc5: 0xb411, 0x1cc6: 0xb291, 0x1cc7: 0xb219, 0x1cc8: 0xb309, 0x1cc9: 0xb429, 0x1cca: 0x0040, 0x1ccb: 0xb3b1, 0x1ccc: 0xb3c9, 0x1ccd: 0xb3e1, 0x1cce: 0xb2a9, 0x1ccf: 0xb339, 0x1cd0: 0xb369, 0x1cd1: 0xb2d9, 0x1cd2: 0xb381, 0x1cd3: 0xb279, 0x1cd4: 0xb2c1, 0x1cd5: 0xb1d1, 0x1cd6: 0xb1e9, 0x1cd7: 0xb231, 0x1cd8: 0xb261, 0x1cd9: 0xb2f1, 0x1cda: 0xb321, 0x1cdb: 0xb351, 0x1cdc: 0x0040, 0x1cdd: 0x0040, 0x1cde: 0x0040, 0x1cdf: 0x0040, 0x1ce0: 0x0040, 0x1ce1: 0xb1a1, 0x1ce2: 0xb201, 0x1ce3: 0xb249, 0x1ce4: 0x0040, 0x1ce5: 0xb411, 0x1ce6: 0xb291, 0x1ce7: 0xb219, 0x1ce8: 0xb309, 0x1ce9: 0xb429, 0x1cea: 0x0040, 0x1ceb: 0xb3b1, 0x1cec: 0xb3c9, 0x1ced: 0xb3e1, 0x1cee: 0xb2a9, 0x1cef: 0xb339, 0x1cf0: 0xb369, 0x1cf1: 0xb2d9, 0x1cf2: 0xb381, 0x1cf3: 0xb279, 0x1cf4: 0xb2c1, 0x1cf5: 0xb1d1, 0x1cf6: 0xb1e9, 0x1cf7: 0xb231, 0x1cf8: 0xb261, 0x1cf9: 0xb2f1, 0x1cfa: 0xb321, 0x1cfb: 0xb351, 0x1cfc: 0x0040, 0x1cfd: 0x0040, 0x1cfe: 0x0040, 0x1cff: 0x0040, // Block 0x74, offset 0x1d00 0x1d00: 0x0040, 0x1d01: 0xbca2, 0x1d02: 0xbcba, 0x1d03: 0xbcd2, 0x1d04: 0xbcea, 0x1d05: 0xbd02, 0x1d06: 0xbd1a, 0x1d07: 0xbd32, 0x1d08: 0xbd4a, 0x1d09: 0xbd62, 0x1d0a: 0xbd7a, 0x1d0b: 0x0018, 0x1d0c: 0x0018, 0x1d0d: 0x0040, 0x1d0e: 0x0040, 0x1d0f: 0x0040, 0x1d10: 0xbd92, 0x1d11: 0xbdb2, 0x1d12: 0xbdd2, 0x1d13: 0xbdf2, 0x1d14: 0xbe12, 0x1d15: 0xbe32, 0x1d16: 0xbe52, 0x1d17: 0xbe72, 0x1d18: 0xbe92, 0x1d19: 0xbeb2, 0x1d1a: 0xbed2, 0x1d1b: 0xbef2, 0x1d1c: 0xbf12, 0x1d1d: 0xbf32, 0x1d1e: 0xbf52, 0x1d1f: 0xbf72, 0x1d20: 0xbf92, 0x1d21: 0xbfb2, 0x1d22: 0xbfd2, 0x1d23: 0xbff2, 0x1d24: 0xc012, 0x1d25: 0xc032, 0x1d26: 0xc052, 0x1d27: 0xc072, 0x1d28: 0xc092, 0x1d29: 0xc0b2, 0x1d2a: 0xc0d1, 0x1d2b: 0x1159, 0x1d2c: 0x0269, 0x1d2d: 0x6671, 0x1d2e: 0xc111, 0x1d2f: 0x0040, 0x1d30: 0x0039, 0x1d31: 0x0ee9, 0x1d32: 0x1159, 0x1d33: 0x0ef9, 0x1d34: 0x0f09, 0x1d35: 0x1199, 0x1d36: 0x0f31, 0x1d37: 0x0249, 0x1d38: 0x0f41, 0x1d39: 0x0259, 0x1d3a: 0x0f51, 0x1d3b: 0x0359, 0x1d3c: 0x0f61, 0x1d3d: 0x0f71, 0x1d3e: 0x00d9, 0x1d3f: 0x0f99, // Block 0x75, offset 0x1d40 0x1d40: 0x2039, 0x1d41: 0x0269, 0x1d42: 0x01d9, 0x1d43: 0x0fa9, 0x1d44: 0x0fb9, 0x1d45: 0x1089, 0x1d46: 0x0279, 0x1d47: 0x0369, 0x1d48: 0x0289, 0x1d49: 0x13d1, 0x1d4a: 0xc129, 0x1d4b: 0x65b1, 0x1d4c: 0xc141, 0x1d4d: 0x1441, 0x1d4e: 0xc159, 0x1d4f: 0xc179, 0x1d50: 0x0018, 0x1d51: 0x0018, 0x1d52: 0x0018, 0x1d53: 0x0018, 0x1d54: 0x0018, 0x1d55: 0x0018, 0x1d56: 0x0018, 0x1d57: 0x0018, 0x1d58: 0x0018, 0x1d59: 0x0018, 0x1d5a: 0x0018, 0x1d5b: 0x0018, 0x1d5c: 0x0018, 0x1d5d: 0x0018, 0x1d5e: 0x0018, 0x1d5f: 0x0018, 0x1d60: 0x0018, 0x1d61: 0x0018, 0x1d62: 0x0018, 0x1d63: 0x0018, 0x1d64: 0x0018, 0x1d65: 0x0018, 0x1d66: 0x0018, 0x1d67: 0x0018, 0x1d68: 0x0018, 0x1d69: 0x0018, 0x1d6a: 0xc191, 0x1d6b: 0xc1a9, 0x1d6c: 0x0040, 0x1d6d: 0x0040, 0x1d6e: 0x0040, 0x1d6f: 0x0040, 0x1d70: 0x0018, 0x1d71: 0x0018, 0x1d72: 0x0018, 0x1d73: 0x0018, 0x1d74: 0x0018, 0x1d75: 0x0018, 0x1d76: 0x0018, 0x1d77: 0x0018, 0x1d78: 0x0018, 0x1d79: 0x0018, 0x1d7a: 0x0018, 0x1d7b: 0x0018, 0x1d7c: 0x0018, 0x1d7d: 0x0018, 0x1d7e: 0x0018, 0x1d7f: 0x0018, // Block 0x76, offset 0x1d80 0x1d80: 0xc1d9, 0x1d81: 0xc211, 0x1d82: 0xc249, 0x1d83: 0x0040, 0x1d84: 0x0040, 0x1d85: 0x0040, 0x1d86: 0x0040, 0x1d87: 0x0040, 0x1d88: 0x0040, 0x1d89: 0x0040, 0x1d8a: 0x0040, 0x1d8b: 0x0040, 0x1d8c: 0x0040, 0x1d8d: 0x0040, 0x1d8e: 0x0040, 0x1d8f: 0x0040, 0x1d90: 0xc269, 0x1d91: 0xc289, 0x1d92: 0xc2a9, 0x1d93: 0xc2c9, 0x1d94: 0xc2e9, 0x1d95: 0xc309, 0x1d96: 0xc329, 0x1d97: 0xc349, 0x1d98: 0xc369, 0x1d99: 0xc389, 0x1d9a: 0xc3a9, 0x1d9b: 0xc3c9, 0x1d9c: 0xc3e9, 0x1d9d: 0xc409, 0x1d9e: 0xc429, 0x1d9f: 0xc449, 0x1da0: 0xc469, 0x1da1: 0xc489, 0x1da2: 0xc4a9, 0x1da3: 0xc4c9, 0x1da4: 0xc4e9, 0x1da5: 0xc509, 0x1da6: 0xc529, 0x1da7: 0xc549, 0x1da8: 0xc569, 0x1da9: 0xc589, 0x1daa: 0xc5a9, 0x1dab: 0xc5c9, 0x1dac: 0xc5e9, 0x1dad: 0xc609, 0x1dae: 0xc629, 0x1daf: 0xc649, 0x1db0: 0xc669, 0x1db1: 0xc689, 0x1db2: 0xc6a9, 0x1db3: 0xc6c9, 0x1db4: 0xc6e9, 0x1db5: 0xc709, 0x1db6: 0xc729, 0x1db7: 0xc749, 0x1db8: 0xc769, 0x1db9: 0xc789, 0x1dba: 0xc7a9, 0x1dbb: 0xc7c9, 0x1dbc: 0x0040, 0x1dbd: 0x0040, 0x1dbe: 0x0040, 0x1dbf: 0x0040, // Block 0x77, offset 0x1dc0 0x1dc0: 0xcaf9, 0x1dc1: 0xcb19, 0x1dc2: 0xcb39, 0x1dc3: 0x8b1d, 0x1dc4: 0xcb59, 0x1dc5: 0xcb79, 0x1dc6: 0xcb99, 0x1dc7: 0xcbb9, 0x1dc8: 0xcbd9, 0x1dc9: 0xcbf9, 0x1dca: 0xcc19, 0x1dcb: 0xcc39, 0x1dcc: 0xcc59, 0x1dcd: 0x8b3d, 0x1dce: 0xcc79, 0x1dcf: 0xcc99, 0x1dd0: 0xccb9, 0x1dd1: 0xccd9, 0x1dd2: 0x8b5d, 0x1dd3: 0xccf9, 0x1dd4: 0xcd19, 0x1dd5: 0xc429, 0x1dd6: 0x8b7d, 0x1dd7: 0xcd39, 0x1dd8: 0xcd59, 0x1dd9: 0xcd79, 0x1dda: 0xcd99, 0x1ddb: 0xcdb9, 0x1ddc: 0x8b9d, 0x1ddd: 0xcdd9, 0x1dde: 0xcdf9, 0x1ddf: 0xce19, 0x1de0: 0xce39, 0x1de1: 0xce59, 0x1de2: 0xc789, 0x1de3: 0xce79, 0x1de4: 0xce99, 0x1de5: 0xceb9, 0x1de6: 0xced9, 0x1de7: 0xcef9, 0x1de8: 0xcf19, 0x1de9: 0xcf39, 0x1dea: 0xcf59, 0x1deb: 0xcf79, 0x1dec: 0xcf99, 0x1ded: 0xcfb9, 0x1dee: 0xcfd9, 0x1def: 0xcff9, 0x1df0: 0xd019, 0x1df1: 0xd039, 0x1df2: 0xd039, 0x1df3: 0xd039, 0x1df4: 0x8bbd, 0x1df5: 0xd059, 0x1df6: 0xd079, 0x1df7: 0xd099, 0x1df8: 0x8bdd, 0x1df9: 0xd0b9, 0x1dfa: 0xd0d9, 0x1dfb: 0xd0f9, 0x1dfc: 0xd119, 0x1dfd: 0xd139, 0x1dfe: 0xd159, 0x1dff: 0xd179, // Block 0x78, offset 0x1e00 0x1e00: 0xd199, 0x1e01: 0xd1b9, 0x1e02: 0xd1d9, 0x1e03: 0xd1f9, 0x1e04: 0xd219, 0x1e05: 0xd239, 0x1e06: 0xd239, 0x1e07: 0xd259, 0x1e08: 0xd279, 0x1e09: 0xd299, 0x1e0a: 0xd2b9, 0x1e0b: 0xd2d9, 0x1e0c: 0xd2f9, 0x1e0d: 0xd319, 0x1e0e: 0xd339, 0x1e0f: 0xd359, 0x1e10: 0xd379, 0x1e11: 0xd399, 0x1e12: 0xd3b9, 0x1e13: 0xd3d9, 0x1e14: 0xd3f9, 0x1e15: 0xd419, 0x1e16: 0xd439, 0x1e17: 0xd459, 0x1e18: 0xd479, 0x1e19: 0x8bfd, 0x1e1a: 0xd499, 0x1e1b: 0xd4b9, 0x1e1c: 0xd4d9, 0x1e1d: 0xc309, 0x1e1e: 0xd4f9, 0x1e1f: 0xd519, 0x1e20: 0x8c1d, 0x1e21: 0x8c3d, 0x1e22: 0xd539, 0x1e23: 0xd559, 0x1e24: 0xd579, 0x1e25: 0xd599, 0x1e26: 0xd5b9, 0x1e27: 0xd5d9, 0x1e28: 0x2040, 0x1e29: 0xd5f9, 0x1e2a: 0xd619, 0x1e2b: 0xd619, 0x1e2c: 0x8c5d, 0x1e2d: 0xd639, 0x1e2e: 0xd659, 0x1e2f: 0xd679, 0x1e30: 0xd699, 0x1e31: 0x8c7d, 0x1e32: 0xd6b9, 0x1e33: 0xd6d9, 0x1e34: 0x2040, 0x1e35: 0xd6f9, 0x1e36: 0xd719, 0x1e37: 0xd739, 0x1e38: 0xd759, 0x1e39: 0xd779, 0x1e3a: 0xd799, 0x1e3b: 0x8c9d, 0x1e3c: 0xd7b9, 0x1e3d: 0x8cbd, 0x1e3e: 0xd7d9, 0x1e3f: 0xd7f9, // Block 0x79, offset 0x1e40 0x1e40: 0xd819, 0x1e41: 0xd839, 0x1e42: 0xd859, 0x1e43: 0xd879, 0x1e44: 0xd899, 0x1e45: 0xd8b9, 0x1e46: 0xd8d9, 0x1e47: 0xd8f9, 0x1e48: 0xd919, 0x1e49: 0x8cdd, 0x1e4a: 0xd939, 0x1e4b: 0xd959, 0x1e4c: 0xd979, 0x1e4d: 0xd999, 0x1e4e: 0xd9b9, 0x1e4f: 0x8cfd, 0x1e50: 0xd9d9, 0x1e51: 0x8d1d, 0x1e52: 0x8d3d, 0x1e53: 0xd9f9, 0x1e54: 0xda19, 0x1e55: 0xda19, 0x1e56: 0xda39, 0x1e57: 0x8d5d, 0x1e58: 0x8d7d, 0x1e59: 0xda59, 0x1e5a: 0xda79, 0x1e5b: 0xda99, 0x1e5c: 0xdab9, 0x1e5d: 0xdad9, 0x1e5e: 0xdaf9, 0x1e5f: 0xdb19, 0x1e60: 0xdb39, 0x1e61: 0xdb59, 0x1e62: 0xdb79, 0x1e63: 0xdb99, 0x1e64: 0x8d9d, 0x1e65: 0xdbb9, 0x1e66: 0xdbd9, 0x1e67: 0xdbf9, 0x1e68: 0xdc19, 0x1e69: 0xdbf9, 0x1e6a: 0xdc39, 0x1e6b: 0xdc59, 0x1e6c: 0xdc79, 0x1e6d: 0xdc99, 0x1e6e: 0xdcb9, 0x1e6f: 0xdcd9, 0x1e70: 0xdcf9, 0x1e71: 0xdd19, 0x1e72: 0xdd39, 0x1e73: 0xdd59, 0x1e74: 0xdd79, 0x1e75: 0xdd99, 0x1e76: 0xddb9, 0x1e77: 0xddd9, 0x1e78: 0x8dbd, 0x1e79: 0xddf9, 0x1e7a: 0xde19, 0x1e7b: 0xde39, 0x1e7c: 0xde59, 0x1e7d: 0xde79, 0x1e7e: 0x8ddd, 0x1e7f: 0xde99, // Block 0x7a, offset 0x1e80 0x1e80: 0xe599, 0x1e81: 0xe5b9, 0x1e82: 0xe5d9, 0x1e83: 0xe5f9, 0x1e84: 0xe619, 0x1e85: 0xe639, 0x1e86: 0x8efd, 0x1e87: 0xe659, 0x1e88: 0xe679, 0x1e89: 0xe699, 0x1e8a: 0xe6b9, 0x1e8b: 0xe6d9, 0x1e8c: 0xe6f9, 0x1e8d: 0x8f1d, 0x1e8e: 0xe719, 0x1e8f: 0xe739, 0x1e90: 0x8f3d, 0x1e91: 0x8f5d, 0x1e92: 0xe759, 0x1e93: 0xe779, 0x1e94: 0xe799, 0x1e95: 0xe7b9, 0x1e96: 0xe7d9, 0x1e97: 0xe7f9, 0x1e98: 0xe819, 0x1e99: 0xe839, 0x1e9a: 0xe859, 0x1e9b: 0x8f7d, 0x1e9c: 0xe879, 0x1e9d: 0x8f9d, 0x1e9e: 0xe899, 0x1e9f: 0x2040, 0x1ea0: 0xe8b9, 0x1ea1: 0xe8d9, 0x1ea2: 0xe8f9, 0x1ea3: 0x8fbd, 0x1ea4: 0xe919, 0x1ea5: 0xe939, 0x1ea6: 0x8fdd, 0x1ea7: 0x8ffd, 0x1ea8: 0xe959, 0x1ea9: 0xe979, 0x1eaa: 0xe999, 0x1eab: 0xe9b9, 0x1eac: 0xe9d9, 0x1ead: 0xe9d9, 0x1eae: 0xe9f9, 0x1eaf: 0xea19, 0x1eb0: 0xea39, 0x1eb1: 0xea59, 0x1eb2: 0xea79, 0x1eb3: 0xea99, 0x1eb4: 0xeab9, 0x1eb5: 0x901d, 0x1eb6: 0xead9, 0x1eb7: 0x903d, 0x1eb8: 0xeaf9, 0x1eb9: 0x905d, 0x1eba: 0xeb19, 0x1ebb: 0x907d, 0x1ebc: 0x909d, 0x1ebd: 0x90bd, 0x1ebe: 0xeb39, 0x1ebf: 0xeb59, // Block 0x7b, offset 0x1ec0 0x1ec0: 0xeb79, 0x1ec1: 0x90dd, 0x1ec2: 0x90fd, 0x1ec3: 0x911d, 0x1ec4: 0x913d, 0x1ec5: 0xeb99, 0x1ec6: 0xebb9, 0x1ec7: 0xebb9, 0x1ec8: 0xebd9, 0x1ec9: 0xebf9, 0x1eca: 0xec19, 0x1ecb: 0xec39, 0x1ecc: 0xec59, 0x1ecd: 0x915d, 0x1ece: 0xec79, 0x1ecf: 0xec99, 0x1ed0: 0xecb9, 0x1ed1: 0xecd9, 0x1ed2: 0x917d, 0x1ed3: 0xecf9, 0x1ed4: 0x919d, 0x1ed5: 0x91bd, 0x1ed6: 0xed19, 0x1ed7: 0xed39, 0x1ed8: 0xed59, 0x1ed9: 0xed79, 0x1eda: 0xed99, 0x1edb: 0xedb9, 0x1edc: 0x91dd, 0x1edd: 0x91fd, 0x1ede: 0x921d, 0x1edf: 0x2040, 0x1ee0: 0xedd9, 0x1ee1: 0x923d, 0x1ee2: 0xedf9, 0x1ee3: 0xee19, 0x1ee4: 0xee39, 0x1ee5: 0x925d, 0x1ee6: 0xee59, 0x1ee7: 0xee79, 0x1ee8: 0xee99, 0x1ee9: 0xeeb9, 0x1eea: 0xeed9, 0x1eeb: 0x927d, 0x1eec: 0xeef9, 0x1eed: 0xef19, 0x1eee: 0xef39, 0x1eef: 0xef59, 0x1ef0: 0xef79, 0x1ef1: 0xef99, 0x1ef2: 0x929d, 0x1ef3: 0x92bd, 0x1ef4: 0xefb9, 0x1ef5: 0x92dd, 0x1ef6: 0xefd9, 0x1ef7: 0x92fd, 0x1ef8: 0xeff9, 0x1ef9: 0xf019, 0x1efa: 0xf039, 0x1efb: 0x931d, 0x1efc: 0x933d, 0x1efd: 0xf059, 0x1efe: 0x935d, 0x1eff: 0xf079, // Block 0x7c, offset 0x1f00 0x1f00: 0xf6b9, 0x1f01: 0xf6d9, 0x1f02: 0xf6f9, 0x1f03: 0xf719, 0x1f04: 0xf739, 0x1f05: 0x951d, 0x1f06: 0xf759, 0x1f07: 0xf779, 0x1f08: 0xf799, 0x1f09: 0xf7b9, 0x1f0a: 0xf7d9, 0x1f0b: 0x953d, 0x1f0c: 0x955d, 0x1f0d: 0xf7f9, 0x1f0e: 0xf819, 0x1f0f: 0xf839, 0x1f10: 0xf859, 0x1f11: 0xf879, 0x1f12: 0xf899, 0x1f13: 0x957d, 0x1f14: 0xf8b9, 0x1f15: 0xf8d9, 0x1f16: 0xf8f9, 0x1f17: 0xf919, 0x1f18: 0x959d, 0x1f19: 0x95bd, 0x1f1a: 0xf939, 0x1f1b: 0xf959, 0x1f1c: 0xf979, 0x1f1d: 0x95dd, 0x1f1e: 0xf999, 0x1f1f: 0xf9b9, 0x1f20: 0x6815, 0x1f21: 0x95fd, 0x1f22: 0xf9d9, 0x1f23: 0xf9f9, 0x1f24: 0xfa19, 0x1f25: 0x961d, 0x1f26: 0xfa39, 0x1f27: 0xfa59, 0x1f28: 0xfa79, 0x1f29: 0xfa99, 0x1f2a: 0xfab9, 0x1f2b: 0xfad9, 0x1f2c: 0xfaf9, 0x1f2d: 0x963d, 0x1f2e: 0xfb19, 0x1f2f: 0xfb39, 0x1f30: 0xfb59, 0x1f31: 0x965d, 0x1f32: 0xfb79, 0x1f33: 0xfb99, 0x1f34: 0xfbb9, 0x1f35: 0xfbd9, 0x1f36: 0x7b35, 0x1f37: 0x967d, 0x1f38: 0xfbf9, 0x1f39: 0xfc19, 0x1f3a: 0xfc39, 0x1f3b: 0x969d, 0x1f3c: 0xfc59, 0x1f3d: 0x96bd, 0x1f3e: 0xfc79, 0x1f3f: 0xfc79, // Block 0x7d, offset 0x1f40 0x1f40: 0xfc99, 0x1f41: 0x96dd, 0x1f42: 0xfcb9, 0x1f43: 0xfcd9, 0x1f44: 0xfcf9, 0x1f45: 0xfd19, 0x1f46: 0xfd39, 0x1f47: 0xfd59, 0x1f48: 0xfd79, 0x1f49: 0x96fd, 0x1f4a: 0xfd99, 0x1f4b: 0xfdb9, 0x1f4c: 0xfdd9, 0x1f4d: 0xfdf9, 0x1f4e: 0xfe19, 0x1f4f: 0xfe39, 0x1f50: 0x971d, 0x1f51: 0xfe59, 0x1f52: 0x973d, 0x1f53: 0x975d, 0x1f54: 0x977d, 0x1f55: 0xfe79, 0x1f56: 0xfe99, 0x1f57: 0xfeb9, 0x1f58: 0xfed9, 0x1f59: 0xfef9, 0x1f5a: 0xff19, 0x1f5b: 0xff39, 0x1f5c: 0xff59, 0x1f5d: 0x979d, 0x1f5e: 0x0040, 0x1f5f: 0x0040, 0x1f60: 0x0040, 0x1f61: 0x0040, 0x1f62: 0x0040, 0x1f63: 0x0040, 0x1f64: 0x0040, 0x1f65: 0x0040, 0x1f66: 0x0040, 0x1f67: 0x0040, 0x1f68: 0x0040, 0x1f69: 0x0040, 0x1f6a: 0x0040, 0x1f6b: 0x0040, 0x1f6c: 0x0040, 0x1f6d: 0x0040, 0x1f6e: 0x0040, 0x1f6f: 0x0040, 0x1f70: 0x0040, 0x1f71: 0x0040, 0x1f72: 0x0040, 0x1f73: 0x0040, 0x1f74: 0x0040, 0x1f75: 0x0040, 0x1f76: 0x0040, 0x1f77: 0x0040, 0x1f78: 0x0040, 0x1f79: 0x0040, 0x1f7a: 0x0040, 0x1f7b: 0x0040, 0x1f7c: 0x0040, 0x1f7d: 0x0040, 0x1f7e: 0x0040, 0x1f7f: 0x0040, } // idnaIndex: 35 blocks, 2240 entries, 4480 bytes // Block 0 is the zero block. var idnaIndex = [2240]uint16{ // Block 0x0, offset 0x0 // Block 0x1, offset 0x40 // Block 0x2, offset 0x80 // Block 0x3, offset 0xc0 0xc2: 0x01, 0xc3: 0x7c, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x04, 0xc7: 0x05, 0xc8: 0x06, 0xc9: 0x7d, 0xca: 0x7e, 0xcb: 0x07, 0xcc: 0x7f, 0xcd: 0x08, 0xce: 0x09, 0xcf: 0x0a, 0xd0: 0x80, 0xd1: 0x0b, 0xd2: 0x0c, 0xd3: 0x0d, 0xd4: 0x0e, 0xd5: 0x81, 0xd6: 0x82, 0xd7: 0x83, 0xd8: 0x0f, 0xd9: 0x10, 0xda: 0x84, 0xdb: 0x11, 0xdc: 0x12, 0xdd: 0x85, 0xde: 0x86, 0xdf: 0x87, 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06, 0xe5: 0x07, 0xe6: 0x07, 0xe7: 0x07, 0xe8: 0x07, 0xe9: 0x08, 0xea: 0x09, 0xeb: 0x07, 0xec: 0x07, 0xed: 0x0a, 0xee: 0x0b, 0xef: 0x0c, 0xf0: 0x1c, 0xf1: 0x1d, 0xf2: 0x1d, 0xf3: 0x1f, 0xf4: 0x20, // Block 0x4, offset 0x100 0x120: 0x88, 0x121: 0x89, 0x122: 0x8a, 0x123: 0x8b, 0x124: 0x8c, 0x125: 0x13, 0x126: 0x14, 0x127: 0x15, 0x128: 0x16, 0x129: 0x17, 0x12a: 0x18, 0x12b: 0x19, 0x12c: 0x1a, 0x12d: 0x1b, 0x12e: 0x1c, 0x12f: 0x8d, 0x130: 0x8e, 0x131: 0x1d, 0x132: 0x1e, 0x133: 0x1f, 0x134: 0x8f, 0x135: 0x20, 0x136: 0x90, 0x137: 0x91, 0x138: 0x92, 0x139: 0x93, 0x13a: 0x21, 0x13b: 0x94, 0x13c: 0x95, 0x13d: 0x22, 0x13e: 0x23, 0x13f: 0x96, // Block 0x5, offset 0x140 0x140: 0x97, 0x141: 0x98, 0x142: 0x99, 0x143: 0x9a, 0x144: 0x9b, 0x145: 0x9c, 0x146: 0x9d, 0x147: 0x9e, 0x148: 0x9f, 0x149: 0xa0, 0x14a: 0xa1, 0x14b: 0xa2, 0x14c: 0xa3, 0x14d: 0xa4, 0x14e: 0xa5, 0x14f: 0xa6, 0x150: 0xa7, 0x151: 0x9f, 0x152: 0x9f, 0x153: 0x9f, 0x154: 0x9f, 0x155: 0x9f, 0x156: 0x9f, 0x157: 0x9f, 0x158: 0x9f, 0x159: 0xa8, 0x15a: 0xa9, 0x15b: 0xaa, 0x15c: 0xab, 0x15d: 0xac, 0x15e: 0xad, 0x15f: 0xae, 0x160: 0xaf, 0x161: 0xb0, 0x162: 0xb1, 0x163: 0xb2, 0x164: 0xb3, 0x165: 0xb4, 0x166: 0xb5, 0x167: 0xb6, 0x168: 0xb7, 0x169: 0xb8, 0x16a: 0xb9, 0x16b: 0xba, 0x16c: 0xbb, 0x16d: 0xbc, 0x16e: 0xbd, 0x16f: 0xbe, 0x170: 0xbf, 0x171: 0xc0, 0x172: 0xc1, 0x173: 0xc2, 0x174: 0x24, 0x175: 0x25, 0x176: 0x26, 0x177: 0xc3, 0x178: 0x27, 0x179: 0x27, 0x17a: 0x28, 0x17b: 0x27, 0x17c: 0xc4, 0x17d: 0x29, 0x17e: 0x2a, 0x17f: 0x2b, // Block 0x6, offset 0x180 0x180: 0x2c, 0x181: 0x2d, 0x182: 0x2e, 0x183: 0xc5, 0x184: 0x2f, 0x185: 0x30, 0x186: 0xc6, 0x187: 0x9b, 0x188: 0xc7, 0x189: 0xc8, 0x18a: 0x9b, 0x18b: 0x9b, 0x18c: 0xc9, 0x18d: 0x9b, 0x18e: 0x9b, 0x18f: 0xca, 0x190: 0xcb, 0x191: 0x31, 0x192: 0x32, 0x193: 0x33, 0x194: 0x9b, 0x195: 0x9b, 0x196: 0x9b, 0x197: 0x9b, 0x198: 0x9b, 0x199: 0x9b, 0x19a: 0x9b, 0x19b: 0x9b, 0x19c: 0x9b, 0x19d: 0x9b, 0x19e: 0x9b, 0x19f: 0x9b, 0x1a0: 0x9b, 0x1a1: 0x9b, 0x1a2: 0x9b, 0x1a3: 0x9b, 0x1a4: 0x9b, 0x1a5: 0x9b, 0x1a6: 0x9b, 0x1a7: 0x9b, 0x1a8: 0xcc, 0x1a9: 0xcd, 0x1aa: 0x9b, 0x1ab: 0xce, 0x1ac: 0x9b, 0x1ad: 0xcf, 0x1ae: 0xd0, 0x1af: 0xd1, 0x1b0: 0xd2, 0x1b1: 0x34, 0x1b2: 0x27, 0x1b3: 0x35, 0x1b4: 0xd3, 0x1b5: 0xd4, 0x1b6: 0xd5, 0x1b7: 0xd6, 0x1b8: 0xd7, 0x1b9: 0xd8, 0x1ba: 0xd9, 0x1bb: 0xda, 0x1bc: 0xdb, 0x1bd: 0xdc, 0x1be: 0xdd, 0x1bf: 0x36, // Block 0x7, offset 0x1c0 0x1c0: 0x37, 0x1c1: 0xde, 0x1c2: 0xdf, 0x1c3: 0xe0, 0x1c4: 0xe1, 0x1c5: 0x38, 0x1c6: 0x39, 0x1c7: 0xe2, 0x1c8: 0xe3, 0x1c9: 0x3a, 0x1ca: 0x3b, 0x1cb: 0x3c, 0x1cc: 0x3d, 0x1cd: 0x3e, 0x1ce: 0x3f, 0x1cf: 0x40, 0x1d0: 0x9f, 0x1d1: 0x9f, 0x1d2: 0x9f, 0x1d3: 0x9f, 0x1d4: 0x9f, 0x1d5: 0x9f, 0x1d6: 0x9f, 0x1d7: 0x9f, 0x1d8: 0x9f, 0x1d9: 0x9f, 0x1da: 0x9f, 0x1db: 0x9f, 0x1dc: 0x9f, 0x1dd: 0x9f, 0x1de: 0x9f, 0x1df: 0x9f, 0x1e0: 0x9f, 0x1e1: 0x9f, 0x1e2: 0x9f, 0x1e3: 0x9f, 0x1e4: 0x9f, 0x1e5: 0x9f, 0x1e6: 0x9f, 0x1e7: 0x9f, 0x1e8: 0x9f, 0x1e9: 0x9f, 0x1ea: 0x9f, 0x1eb: 0x9f, 0x1ec: 0x9f, 0x1ed: 0x9f, 0x1ee: 0x9f, 0x1ef: 0x9f, 0x1f0: 0x9f, 0x1f1: 0x9f, 0x1f2: 0x9f, 0x1f3: 0x9f, 0x1f4: 0x9f, 0x1f5: 0x9f, 0x1f6: 0x9f, 0x1f7: 0x9f, 0x1f8: 0x9f, 0x1f9: 0x9f, 0x1fa: 0x9f, 0x1fb: 0x9f, 0x1fc: 0x9f, 0x1fd: 0x9f, 0x1fe: 0x9f, 0x1ff: 0x9f, // Block 0x8, offset 0x200 0x200: 0x9f, 0x201: 0x9f, 0x202: 0x9f, 0x203: 0x9f, 0x204: 0x9f, 0x205: 0x9f, 0x206: 0x9f, 0x207: 0x9f, 0x208: 0x9f, 0x209: 0x9f, 0x20a: 0x9f, 0x20b: 0x9f, 0x20c: 0x9f, 0x20d: 0x9f, 0x20e: 0x9f, 0x20f: 0x9f, 0x210: 0x9f, 0x211: 0x9f, 0x212: 0x9f, 0x213: 0x9f, 0x214: 0x9f, 0x215: 0x9f, 0x216: 0x9f, 0x217: 0x9f, 0x218: 0x9f, 0x219: 0x9f, 0x21a: 0x9f, 0x21b: 0x9f, 0x21c: 0x9f, 0x21d: 0x9f, 0x21e: 0x9f, 0x21f: 0x9f, 0x220: 0x9f, 0x221: 0x9f, 0x222: 0x9f, 0x223: 0x9f, 0x224: 0x9f, 0x225: 0x9f, 0x226: 0x9f, 0x227: 0x9f, 0x228: 0x9f, 0x229: 0x9f, 0x22a: 0x9f, 0x22b: 0x9f, 0x22c: 0x9f, 0x22d: 0x9f, 0x22e: 0x9f, 0x22f: 0x9f, 0x230: 0x9f, 0x231: 0x9f, 0x232: 0x9f, 0x233: 0x9f, 0x234: 0x9f, 0x235: 0x9f, 0x236: 0xb2, 0x237: 0x9b, 0x238: 0x9f, 0x239: 0x9f, 0x23a: 0x9f, 0x23b: 0x9f, 0x23c: 0x9f, 0x23d: 0x9f, 0x23e: 0x9f, 0x23f: 0x9f, // Block 0x9, offset 0x240 0x240: 0x9f, 0x241: 0x9f, 0x242: 0x9f, 0x243: 0x9f, 0x244: 0x9f, 0x245: 0x9f, 0x246: 0x9f, 0x247: 0x9f, 0x248: 0x9f, 0x249: 0x9f, 0x24a: 0x9f, 0x24b: 0x9f, 0x24c: 0x9f, 0x24d: 0x9f, 0x24e: 0x9f, 0x24f: 0x9f, 0x250: 0x9f, 0x251: 0x9f, 0x252: 0x9f, 0x253: 0x9f, 0x254: 0x9f, 0x255: 0x9f, 0x256: 0x9f, 0x257: 0x9f, 0x258: 0x9f, 0x259: 0x9f, 0x25a: 0x9f, 0x25b: 0x9f, 0x25c: 0x9f, 0x25d: 0x9f, 0x25e: 0x9f, 0x25f: 0x9f, 0x260: 0x9f, 0x261: 0x9f, 0x262: 0x9f, 0x263: 0x9f, 0x264: 0x9f, 0x265: 0x9f, 0x266: 0x9f, 0x267: 0x9f, 0x268: 0x9f, 0x269: 0x9f, 0x26a: 0x9f, 0x26b: 0x9f, 0x26c: 0x9f, 0x26d: 0x9f, 0x26e: 0x9f, 0x26f: 0x9f, 0x270: 0x9f, 0x271: 0x9f, 0x272: 0x9f, 0x273: 0x9f, 0x274: 0x9f, 0x275: 0x9f, 0x276: 0x9f, 0x277: 0x9f, 0x278: 0x9f, 0x279: 0x9f, 0x27a: 0x9f, 0x27b: 0x9f, 0x27c: 0x9f, 0x27d: 0x9f, 0x27e: 0x9f, 0x27f: 0x9f, // Block 0xa, offset 0x280 0x280: 0x9f, 0x281: 0x9f, 0x282: 0x9f, 0x283: 0x9f, 0x284: 0x9f, 0x285: 0x9f, 0x286: 0x9f, 0x287: 0x9f, 0x288: 0x9f, 0x289: 0x9f, 0x28a: 0x9f, 0x28b: 0x9f, 0x28c: 0x9f, 0x28d: 0x9f, 0x28e: 0x9f, 0x28f: 0x9f, 0x290: 0x9f, 0x291: 0x9f, 0x292: 0x9f, 0x293: 0x9f, 0x294: 0x9f, 0x295: 0x9f, 0x296: 0x9f, 0x297: 0x9f, 0x298: 0x9f, 0x299: 0x9f, 0x29a: 0x9f, 0x29b: 0x9f, 0x29c: 0x9f, 0x29d: 0x9f, 0x29e: 0x9f, 0x29f: 0x9f, 0x2a0: 0x9f, 0x2a1: 0x9f, 0x2a2: 0x9f, 0x2a3: 0x9f, 0x2a4: 0x9f, 0x2a5: 0x9f, 0x2a6: 0x9f, 0x2a7: 0x9f, 0x2a8: 0x9f, 0x2a9: 0x9f, 0x2aa: 0x9f, 0x2ab: 0x9f, 0x2ac: 0x9f, 0x2ad: 0x9f, 0x2ae: 0x9f, 0x2af: 0x9f, 0x2b0: 0x9f, 0x2b1: 0x9f, 0x2b2: 0x9f, 0x2b3: 0x9f, 0x2b4: 0x9f, 0x2b5: 0x9f, 0x2b6: 0x9f, 0x2b7: 0x9f, 0x2b8: 0x9f, 0x2b9: 0x9f, 0x2ba: 0x9f, 0x2bb: 0x9f, 0x2bc: 0x9f, 0x2bd: 0x9f, 0x2be: 0x9f, 0x2bf: 0xe4, // Block 0xb, offset 0x2c0 0x2c0: 0x9f, 0x2c1: 0x9f, 0x2c2: 0x9f, 0x2c3: 0x9f, 0x2c4: 0x9f, 0x2c5: 0x9f, 0x2c6: 0x9f, 0x2c7: 0x9f, 0x2c8: 0x9f, 0x2c9: 0x9f, 0x2ca: 0x9f, 0x2cb: 0x9f, 0x2cc: 0x9f, 0x2cd: 0x9f, 0x2ce: 0x9f, 0x2cf: 0x9f, 0x2d0: 0x9f, 0x2d1: 0x9f, 0x2d2: 0xe5, 0x2d3: 0xe6, 0x2d4: 0x9f, 0x2d5: 0x9f, 0x2d6: 0x9f, 0x2d7: 0x9f, 0x2d8: 0xe7, 0x2d9: 0x41, 0x2da: 0x42, 0x2db: 0xe8, 0x2dc: 0x43, 0x2dd: 0x44, 0x2de: 0x45, 0x2df: 0xe9, 0x2e0: 0xea, 0x2e1: 0xeb, 0x2e2: 0xec, 0x2e3: 0xed, 0x2e4: 0xee, 0x2e5: 0xef, 0x2e6: 0xf0, 0x2e7: 0xf1, 0x2e8: 0xf2, 0x2e9: 0xf3, 0x2ea: 0xf4, 0x2eb: 0xf5, 0x2ec: 0xf6, 0x2ed: 0xf7, 0x2ee: 0xf8, 0x2ef: 0xf9, 0x2f0: 0x9f, 0x2f1: 0x9f, 0x2f2: 0x9f, 0x2f3: 0x9f, 0x2f4: 0x9f, 0x2f5: 0x9f, 0x2f6: 0x9f, 0x2f7: 0x9f, 0x2f8: 0x9f, 0x2f9: 0x9f, 0x2fa: 0x9f, 0x2fb: 0x9f, 0x2fc: 0x9f, 0x2fd: 0x9f, 0x2fe: 0x9f, 0x2ff: 0x9f, // Block 0xc, offset 0x300 0x300: 0x9f, 0x301: 0x9f, 0x302: 0x9f, 0x303: 0x9f, 0x304: 0x9f, 0x305: 0x9f, 0x306: 0x9f, 0x307: 0x9f, 0x308: 0x9f, 0x309: 0x9f, 0x30a: 0x9f, 0x30b: 0x9f, 0x30c: 0x9f, 0x30d: 0x9f, 0x30e: 0x9f, 0x30f: 0x9f, 0x310: 0x9f, 0x311: 0x9f, 0x312: 0x9f, 0x313: 0x9f, 0x314: 0x9f, 0x315: 0x9f, 0x316: 0x9f, 0x317: 0x9f, 0x318: 0x9f, 0x319: 0x9f, 0x31a: 0x9f, 0x31b: 0x9f, 0x31c: 0x9f, 0x31d: 0x9f, 0x31e: 0xfa, 0x31f: 0xfb, // Block 0xd, offset 0x340 0x340: 0xba, 0x341: 0xba, 0x342: 0xba, 0x343: 0xba, 0x344: 0xba, 0x345: 0xba, 0x346: 0xba, 0x347: 0xba, 0x348: 0xba, 0x349: 0xba, 0x34a: 0xba, 0x34b: 0xba, 0x34c: 0xba, 0x34d: 0xba, 0x34e: 0xba, 0x34f: 0xba, 0x350: 0xba, 0x351: 0xba, 0x352: 0xba, 0x353: 0xba, 0x354: 0xba, 0x355: 0xba, 0x356: 0xba, 0x357: 0xba, 0x358: 0xba, 0x359: 0xba, 0x35a: 0xba, 0x35b: 0xba, 0x35c: 0xba, 0x35d: 0xba, 0x35e: 0xba, 0x35f: 0xba, 0x360: 0xba, 0x361: 0xba, 0x362: 0xba, 0x363: 0xba, 0x364: 0xba, 0x365: 0xba, 0x366: 0xba, 0x367: 0xba, 0x368: 0xba, 0x369: 0xba, 0x36a: 0xba, 0x36b: 0xba, 0x36c: 0xba, 0x36d: 0xba, 0x36e: 0xba, 0x36f: 0xba, 0x370: 0xba, 0x371: 0xba, 0x372: 0xba, 0x373: 0xba, 0x374: 0xba, 0x375: 0xba, 0x376: 0xba, 0x377: 0xba, 0x378: 0xba, 0x379: 0xba, 0x37a: 0xba, 0x37b: 0xba, 0x37c: 0xba, 0x37d: 0xba, 0x37e: 0xba, 0x37f: 0xba, // Block 0xe, offset 0x380 0x380: 0xba, 0x381: 0xba, 0x382: 0xba, 0x383: 0xba, 0x384: 0xba, 0x385: 0xba, 0x386: 0xba, 0x387: 0xba, 0x388: 0xba, 0x389: 0xba, 0x38a: 0xba, 0x38b: 0xba, 0x38c: 0xba, 0x38d: 0xba, 0x38e: 0xba, 0x38f: 0xba, 0x390: 0xba, 0x391: 0xba, 0x392: 0xba, 0x393: 0xba, 0x394: 0xba, 0x395: 0xba, 0x396: 0xba, 0x397: 0xba, 0x398: 0xba, 0x399: 0xba, 0x39a: 0xba, 0x39b: 0xba, 0x39c: 0xba, 0x39d: 0xba, 0x39e: 0xba, 0x39f: 0xba, 0x3a0: 0xba, 0x3a1: 0xba, 0x3a2: 0xba, 0x3a3: 0xba, 0x3a4: 0xfc, 0x3a5: 0xfd, 0x3a6: 0xfe, 0x3a7: 0xff, 0x3a8: 0x46, 0x3a9: 0x100, 0x3aa: 0x101, 0x3ab: 0x47, 0x3ac: 0x48, 0x3ad: 0x49, 0x3ae: 0x4a, 0x3af: 0x4b, 0x3b0: 0x102, 0x3b1: 0x4c, 0x3b2: 0x4d, 0x3b3: 0x4e, 0x3b4: 0x4f, 0x3b5: 0x50, 0x3b6: 0x103, 0x3b7: 0x51, 0x3b8: 0x52, 0x3b9: 0x53, 0x3ba: 0x54, 0x3bb: 0x55, 0x3bc: 0x56, 0x3bd: 0x57, 0x3be: 0x58, 0x3bf: 0x59, // Block 0xf, offset 0x3c0 0x3c0: 0x104, 0x3c1: 0x105, 0x3c2: 0x9f, 0x3c3: 0x106, 0x3c4: 0x107, 0x3c5: 0x9b, 0x3c6: 0x108, 0x3c7: 0x109, 0x3c8: 0xba, 0x3c9: 0xba, 0x3ca: 0x10a, 0x3cb: 0x10b, 0x3cc: 0x10c, 0x3cd: 0x10d, 0x3ce: 0x10e, 0x3cf: 0x10f, 0x3d0: 0x110, 0x3d1: 0x9f, 0x3d2: 0x111, 0x3d3: 0x112, 0x3d4: 0x113, 0x3d5: 0x114, 0x3d6: 0xba, 0x3d7: 0xba, 0x3d8: 0x9f, 0x3d9: 0x9f, 0x3da: 0x9f, 0x3db: 0x9f, 0x3dc: 0x115, 0x3dd: 0x116, 0x3de: 0xba, 0x3df: 0xba, 0x3e0: 0x117, 0x3e1: 0x118, 0x3e2: 0x119, 0x3e3: 0x11a, 0x3e4: 0x11b, 0x3e5: 0xba, 0x3e6: 0x11c, 0x3e7: 0x11d, 0x3e8: 0x11e, 0x3e9: 0x11f, 0x3ea: 0x120, 0x3eb: 0x5a, 0x3ec: 0x121, 0x3ed: 0x122, 0x3ee: 0x5b, 0x3ef: 0xba, 0x3f0: 0x123, 0x3f1: 0x124, 0x3f2: 0x125, 0x3f3: 0x126, 0x3f4: 0xba, 0x3f5: 0xba, 0x3f6: 0xba, 0x3f7: 0xba, 0x3f8: 0xba, 0x3f9: 0x127, 0x3fa: 0xba, 0x3fb: 0xba, 0x3fc: 0xba, 0x3fd: 0xba, 0x3fe: 0xba, 0x3ff: 0xba, // Block 0x10, offset 0x400 0x400: 0x128, 0x401: 0x129, 0x402: 0x12a, 0x403: 0x12b, 0x404: 0x12c, 0x405: 0x12d, 0x406: 0x12e, 0x407: 0x12f, 0x408: 0x130, 0x409: 0xba, 0x40a: 0x131, 0x40b: 0x132, 0x40c: 0x5c, 0x40d: 0x5d, 0x40e: 0xba, 0x40f: 0xba, 0x410: 0x133, 0x411: 0x134, 0x412: 0x135, 0x413: 0x136, 0x414: 0xba, 0x415: 0xba, 0x416: 0x137, 0x417: 0x138, 0x418: 0x139, 0x419: 0x13a, 0x41a: 0x13b, 0x41b: 0x13c, 0x41c: 0x13d, 0x41d: 0xba, 0x41e: 0xba, 0x41f: 0xba, 0x420: 0xba, 0x421: 0xba, 0x422: 0x13e, 0x423: 0x13f, 0x424: 0xba, 0x425: 0xba, 0x426: 0xba, 0x427: 0xba, 0x428: 0xba, 0x429: 0xba, 0x42a: 0xba, 0x42b: 0x140, 0x42c: 0xba, 0x42d: 0xba, 0x42e: 0xba, 0x42f: 0xba, 0x430: 0x141, 0x431: 0x142, 0x432: 0x143, 0x433: 0xba, 0x434: 0xba, 0x435: 0xba, 0x436: 0xba, 0x437: 0xba, 0x438: 0xba, 0x439: 0xba, 0x43a: 0xba, 0x43b: 0xba, 0x43c: 0xba, 0x43d: 0xba, 0x43e: 0xba, 0x43f: 0xba, // Block 0x11, offset 0x440 0x440: 0x9f, 0x441: 0x9f, 0x442: 0x9f, 0x443: 0x9f, 0x444: 0x9f, 0x445: 0x9f, 0x446: 0x9f, 0x447: 0x9f, 0x448: 0x9f, 0x449: 0x9f, 0x44a: 0x9f, 0x44b: 0x9f, 0x44c: 0x9f, 0x44d: 0x9f, 0x44e: 0x144, 0x44f: 0xba, 0x450: 0x9b, 0x451: 0x145, 0x452: 0x9f, 0x453: 0x9f, 0x454: 0x9f, 0x455: 0x146, 0x456: 0xba, 0x457: 0xba, 0x458: 0xba, 0x459: 0xba, 0x45a: 0xba, 0x45b: 0xba, 0x45c: 0xba, 0x45d: 0xba, 0x45e: 0xba, 0x45f: 0xba, 0x460: 0xba, 0x461: 0xba, 0x462: 0xba, 0x463: 0xba, 0x464: 0xba, 0x465: 0xba, 0x466: 0xba, 0x467: 0xba, 0x468: 0xba, 0x469: 0xba, 0x46a: 0xba, 0x46b: 0xba, 0x46c: 0xba, 0x46d: 0xba, 0x46e: 0xba, 0x46f: 0xba, 0x470: 0xba, 0x471: 0xba, 0x472: 0xba, 0x473: 0xba, 0x474: 0xba, 0x475: 0xba, 0x476: 0xba, 0x477: 0xba, 0x478: 0xba, 0x479: 0xba, 0x47a: 0xba, 0x47b: 0xba, 0x47c: 0xba, 0x47d: 0xba, 0x47e: 0xba, 0x47f: 0xba, // Block 0x12, offset 0x480 0x480: 0x9f, 0x481: 0x9f, 0x482: 0x9f, 0x483: 0x9f, 0x484: 0x9f, 0x485: 0x9f, 0x486: 0x9f, 0x487: 0x9f, 0x488: 0x9f, 0x489: 0x9f, 0x48a: 0x9f, 0x48b: 0x9f, 0x48c: 0x9f, 0x48d: 0x9f, 0x48e: 0x9f, 0x48f: 0x9f, 0x490: 0x147, 0x491: 0xba, 0x492: 0xba, 0x493: 0xba, 0x494: 0xba, 0x495: 0xba, 0x496: 0xba, 0x497: 0xba, 0x498: 0xba, 0x499: 0xba, 0x49a: 0xba, 0x49b: 0xba, 0x49c: 0xba, 0x49d: 0xba, 0x49e: 0xba, 0x49f: 0xba, 0x4a0: 0xba, 0x4a1: 0xba, 0x4a2: 0xba, 0x4a3: 0xba, 0x4a4: 0xba, 0x4a5: 0xba, 0x4a6: 0xba, 0x4a7: 0xba, 0x4a8: 0xba, 0x4a9: 0xba, 0x4aa: 0xba, 0x4ab: 0xba, 0x4ac: 0xba, 0x4ad: 0xba, 0x4ae: 0xba, 0x4af: 0xba, 0x4b0: 0xba, 0x4b1: 0xba, 0x4b2: 0xba, 0x4b3: 0xba, 0x4b4: 0xba, 0x4b5: 0xba, 0x4b6: 0xba, 0x4b7: 0xba, 0x4b8: 0xba, 0x4b9: 0xba, 0x4ba: 0xba, 0x4bb: 0xba, 0x4bc: 0xba, 0x4bd: 0xba, 0x4be: 0xba, 0x4bf: 0xba, // Block 0x13, offset 0x4c0 0x4c0: 0xba, 0x4c1: 0xba, 0x4c2: 0xba, 0x4c3: 0xba, 0x4c4: 0xba, 0x4c5: 0xba, 0x4c6: 0xba, 0x4c7: 0xba, 0x4c8: 0xba, 0x4c9: 0xba, 0x4ca: 0xba, 0x4cb: 0xba, 0x4cc: 0xba, 0x4cd: 0xba, 0x4ce: 0xba, 0x4cf: 0xba, 0x4d0: 0x9f, 0x4d1: 0x9f, 0x4d2: 0x9f, 0x4d3: 0x9f, 0x4d4: 0x9f, 0x4d5: 0x9f, 0x4d6: 0x9f, 0x4d7: 0x9f, 0x4d8: 0x9f, 0x4d9: 0x148, 0x4da: 0xba, 0x4db: 0xba, 0x4dc: 0xba, 0x4dd: 0xba, 0x4de: 0xba, 0x4df: 0xba, 0x4e0: 0xba, 0x4e1: 0xba, 0x4e2: 0xba, 0x4e3: 0xba, 0x4e4: 0xba, 0x4e5: 0xba, 0x4e6: 0xba, 0x4e7: 0xba, 0x4e8: 0xba, 0x4e9: 0xba, 0x4ea: 0xba, 0x4eb: 0xba, 0x4ec: 0xba, 0x4ed: 0xba, 0x4ee: 0xba, 0x4ef: 0xba, 0x4f0: 0xba, 0x4f1: 0xba, 0x4f2: 0xba, 0x4f3: 0xba, 0x4f4: 0xba, 0x4f5: 0xba, 0x4f6: 0xba, 0x4f7: 0xba, 0x4f8: 0xba, 0x4f9: 0xba, 0x4fa: 0xba, 0x4fb: 0xba, 0x4fc: 0xba, 0x4fd: 0xba, 0x4fe: 0xba, 0x4ff: 0xba, // Block 0x14, offset 0x500 0x500: 0xba, 0x501: 0xba, 0x502: 0xba, 0x503: 0xba, 0x504: 0xba, 0x505: 0xba, 0x506: 0xba, 0x507: 0xba, 0x508: 0xba, 0x509: 0xba, 0x50a: 0xba, 0x50b: 0xba, 0x50c: 0xba, 0x50d: 0xba, 0x50e: 0xba, 0x50f: 0xba, 0x510: 0xba, 0x511: 0xba, 0x512: 0xba, 0x513: 0xba, 0x514: 0xba, 0x515: 0xba, 0x516: 0xba, 0x517: 0xba, 0x518: 0xba, 0x519: 0xba, 0x51a: 0xba, 0x51b: 0xba, 0x51c: 0xba, 0x51d: 0xba, 0x51e: 0xba, 0x51f: 0xba, 0x520: 0x9f, 0x521: 0x9f, 0x522: 0x9f, 0x523: 0x9f, 0x524: 0x9f, 0x525: 0x9f, 0x526: 0x9f, 0x527: 0x9f, 0x528: 0x140, 0x529: 0x149, 0x52a: 0xba, 0x52b: 0x14a, 0x52c: 0x14b, 0x52d: 0x14c, 0x52e: 0x14d, 0x52f: 0xba, 0x530: 0xba, 0x531: 0xba, 0x532: 0xba, 0x533: 0xba, 0x534: 0xba, 0x535: 0xba, 0x536: 0xba, 0x537: 0xba, 0x538: 0xba, 0x539: 0xba, 0x53a: 0xba, 0x53b: 0xba, 0x53c: 0x9f, 0x53d: 0x14e, 0x53e: 0x14f, 0x53f: 0x150, // Block 0x15, offset 0x540 0x540: 0x9f, 0x541: 0x9f, 0x542: 0x9f, 0x543: 0x9f, 0x544: 0x9f, 0x545: 0x9f, 0x546: 0x9f, 0x547: 0x9f, 0x548: 0x9f, 0x549: 0x9f, 0x54a: 0x9f, 0x54b: 0x9f, 0x54c: 0x9f, 0x54d: 0x9f, 0x54e: 0x9f, 0x54f: 0x9f, 0x550: 0x9f, 0x551: 0x9f, 0x552: 0x9f, 0x553: 0x9f, 0x554: 0x9f, 0x555: 0x9f, 0x556: 0x9f, 0x557: 0x9f, 0x558: 0x9f, 0x559: 0x9f, 0x55a: 0x9f, 0x55b: 0x9f, 0x55c: 0x9f, 0x55d: 0x9f, 0x55e: 0x9f, 0x55f: 0x151, 0x560: 0x9f, 0x561: 0x9f, 0x562: 0x9f, 0x563: 0x9f, 0x564: 0x9f, 0x565: 0x9f, 0x566: 0x9f, 0x567: 0x9f, 0x568: 0x9f, 0x569: 0x9f, 0x56a: 0x9f, 0x56b: 0x152, 0x56c: 0xba, 0x56d: 0xba, 0x56e: 0xba, 0x56f: 0xba, 0x570: 0xba, 0x571: 0xba, 0x572: 0xba, 0x573: 0xba, 0x574: 0xba, 0x575: 0xba, 0x576: 0xba, 0x577: 0xba, 0x578: 0xba, 0x579: 0xba, 0x57a: 0xba, 0x57b: 0xba, 0x57c: 0xba, 0x57d: 0xba, 0x57e: 0xba, 0x57f: 0xba, // Block 0x16, offset 0x580 0x580: 0x153, 0x581: 0xba, 0x582: 0xba, 0x583: 0xba, 0x584: 0xba, 0x585: 0xba, 0x586: 0xba, 0x587: 0xba, 0x588: 0xba, 0x589: 0xba, 0x58a: 0xba, 0x58b: 0xba, 0x58c: 0xba, 0x58d: 0xba, 0x58e: 0xba, 0x58f: 0xba, 0x590: 0xba, 0x591: 0xba, 0x592: 0xba, 0x593: 0xba, 0x594: 0xba, 0x595: 0xba, 0x596: 0xba, 0x597: 0xba, 0x598: 0xba, 0x599: 0xba, 0x59a: 0xba, 0x59b: 0xba, 0x59c: 0xba, 0x59d: 0xba, 0x59e: 0xba, 0x59f: 0xba, 0x5a0: 0xba, 0x5a1: 0xba, 0x5a2: 0xba, 0x5a3: 0xba, 0x5a4: 0xba, 0x5a5: 0xba, 0x5a6: 0xba, 0x5a7: 0xba, 0x5a8: 0xba, 0x5a9: 0xba, 0x5aa: 0xba, 0x5ab: 0xba, 0x5ac: 0xba, 0x5ad: 0xba, 0x5ae: 0xba, 0x5af: 0xba, 0x5b0: 0x9f, 0x5b1: 0x154, 0x5b2: 0x155, 0x5b3: 0xba, 0x5b4: 0xba, 0x5b5: 0xba, 0x5b6: 0xba, 0x5b7: 0xba, 0x5b8: 0xba, 0x5b9: 0xba, 0x5ba: 0xba, 0x5bb: 0xba, 0x5bc: 0xba, 0x5bd: 0xba, 0x5be: 0xba, 0x5bf: 0xba, // Block 0x17, offset 0x5c0 0x5c0: 0x9b, 0x5c1: 0x9b, 0x5c2: 0x9b, 0x5c3: 0x156, 0x5c4: 0x157, 0x5c5: 0x158, 0x5c6: 0x159, 0x5c7: 0x15a, 0x5c8: 0x9b, 0x5c9: 0x15b, 0x5ca: 0xba, 0x5cb: 0xba, 0x5cc: 0x9b, 0x5cd: 0x15c, 0x5ce: 0xba, 0x5cf: 0xba, 0x5d0: 0x5e, 0x5d1: 0x5f, 0x5d2: 0x60, 0x5d3: 0x61, 0x5d4: 0x62, 0x5d5: 0x63, 0x5d6: 0x64, 0x5d7: 0x65, 0x5d8: 0x66, 0x5d9: 0x67, 0x5da: 0x68, 0x5db: 0x69, 0x5dc: 0x6a, 0x5dd: 0x6b, 0x5de: 0x6c, 0x5df: 0x6d, 0x5e0: 0x9b, 0x5e1: 0x9b, 0x5e2: 0x9b, 0x5e3: 0x9b, 0x5e4: 0x9b, 0x5e5: 0x9b, 0x5e6: 0x9b, 0x5e7: 0x9b, 0x5e8: 0x15d, 0x5e9: 0x15e, 0x5ea: 0x15f, 0x5eb: 0xba, 0x5ec: 0xba, 0x5ed: 0xba, 0x5ee: 0xba, 0x5ef: 0xba, 0x5f0: 0xba, 0x5f1: 0xba, 0x5f2: 0xba, 0x5f3: 0xba, 0x5f4: 0xba, 0x5f5: 0xba, 0x5f6: 0xba, 0x5f7: 0xba, 0x5f8: 0xba, 0x5f9: 0xba, 0x5fa: 0xba, 0x5fb: 0xba, 0x5fc: 0xba, 0x5fd: 0xba, 0x5fe: 0xba, 0x5ff: 0xba, // Block 0x18, offset 0x600 0x600: 0x160, 0x601: 0xba, 0x602: 0xba, 0x603: 0xba, 0x604: 0xba, 0x605: 0xba, 0x606: 0xba, 0x607: 0xba, 0x608: 0xba, 0x609: 0xba, 0x60a: 0xba, 0x60b: 0xba, 0x60c: 0xba, 0x60d: 0xba, 0x60e: 0xba, 0x60f: 0xba, 0x610: 0xba, 0x611: 0xba, 0x612: 0xba, 0x613: 0xba, 0x614: 0xba, 0x615: 0xba, 0x616: 0xba, 0x617: 0xba, 0x618: 0xba, 0x619: 0xba, 0x61a: 0xba, 0x61b: 0xba, 0x61c: 0xba, 0x61d: 0xba, 0x61e: 0xba, 0x61f: 0xba, 0x620: 0x123, 0x621: 0x123, 0x622: 0x123, 0x623: 0x161, 0x624: 0x6e, 0x625: 0x162, 0x626: 0xba, 0x627: 0xba, 0x628: 0xba, 0x629: 0xba, 0x62a: 0xba, 0x62b: 0xba, 0x62c: 0xba, 0x62d: 0xba, 0x62e: 0xba, 0x62f: 0xba, 0x630: 0xba, 0x631: 0xba, 0x632: 0xba, 0x633: 0xba, 0x634: 0xba, 0x635: 0xba, 0x636: 0xba, 0x637: 0xba, 0x638: 0x6f, 0x639: 0x70, 0x63a: 0x71, 0x63b: 0x163, 0x63c: 0xba, 0x63d: 0xba, 0x63e: 0xba, 0x63f: 0xba, // Block 0x19, offset 0x640 0x640: 0x164, 0x641: 0x9b, 0x642: 0x165, 0x643: 0x166, 0x644: 0x72, 0x645: 0x73, 0x646: 0x167, 0x647: 0x168, 0x648: 0x74, 0x649: 0x169, 0x64a: 0xba, 0x64b: 0xba, 0x64c: 0x9b, 0x64d: 0x9b, 0x64e: 0x9b, 0x64f: 0x9b, 0x650: 0x9b, 0x651: 0x9b, 0x652: 0x9b, 0x653: 0x9b, 0x654: 0x9b, 0x655: 0x9b, 0x656: 0x9b, 0x657: 0x9b, 0x658: 0x9b, 0x659: 0x9b, 0x65a: 0x9b, 0x65b: 0x16a, 0x65c: 0x9b, 0x65d: 0x16b, 0x65e: 0x9b, 0x65f: 0x16c, 0x660: 0x16d, 0x661: 0x16e, 0x662: 0x16f, 0x663: 0xba, 0x664: 0x170, 0x665: 0x171, 0x666: 0x172, 0x667: 0x173, 0x668: 0xba, 0x669: 0xba, 0x66a: 0xba, 0x66b: 0xba, 0x66c: 0xba, 0x66d: 0xba, 0x66e: 0xba, 0x66f: 0xba, 0x670: 0xba, 0x671: 0xba, 0x672: 0xba, 0x673: 0xba, 0x674: 0xba, 0x675: 0xba, 0x676: 0xba, 0x677: 0xba, 0x678: 0xba, 0x679: 0xba, 0x67a: 0xba, 0x67b: 0xba, 0x67c: 0xba, 0x67d: 0xba, 0x67e: 0xba, 0x67f: 0xba, // Block 0x1a, offset 0x680 0x680: 0x9f, 0x681: 0x9f, 0x682: 0x9f, 0x683: 0x9f, 0x684: 0x9f, 0x685: 0x9f, 0x686: 0x9f, 0x687: 0x9f, 0x688: 0x9f, 0x689: 0x9f, 0x68a: 0x9f, 0x68b: 0x9f, 0x68c: 0x9f, 0x68d: 0x9f, 0x68e: 0x9f, 0x68f: 0x9f, 0x690: 0x9f, 0x691: 0x9f, 0x692: 0x9f, 0x693: 0x9f, 0x694: 0x9f, 0x695: 0x9f, 0x696: 0x9f, 0x697: 0x9f, 0x698: 0x9f, 0x699: 0x9f, 0x69a: 0x9f, 0x69b: 0x174, 0x69c: 0x9f, 0x69d: 0x9f, 0x69e: 0x9f, 0x69f: 0x9f, 0x6a0: 0x9f, 0x6a1: 0x9f, 0x6a2: 0x9f, 0x6a3: 0x9f, 0x6a4: 0x9f, 0x6a5: 0x9f, 0x6a6: 0x9f, 0x6a7: 0x9f, 0x6a8: 0x9f, 0x6a9: 0x9f, 0x6aa: 0x9f, 0x6ab: 0x9f, 0x6ac: 0x9f, 0x6ad: 0x9f, 0x6ae: 0x9f, 0x6af: 0x9f, 0x6b0: 0x9f, 0x6b1: 0x9f, 0x6b2: 0x9f, 0x6b3: 0x9f, 0x6b4: 0x9f, 0x6b5: 0x9f, 0x6b6: 0x9f, 0x6b7: 0x9f, 0x6b8: 0x9f, 0x6b9: 0x9f, 0x6ba: 0x9f, 0x6bb: 0x9f, 0x6bc: 0x9f, 0x6bd: 0x9f, 0x6be: 0x9f, 0x6bf: 0x9f, // Block 0x1b, offset 0x6c0 0x6c0: 0x9f, 0x6c1: 0x9f, 0x6c2: 0x9f, 0x6c3: 0x9f, 0x6c4: 0x9f, 0x6c5: 0x9f, 0x6c6: 0x9f, 0x6c7: 0x9f, 0x6c8: 0x9f, 0x6c9: 0x9f, 0x6ca: 0x9f, 0x6cb: 0x9f, 0x6cc: 0x9f, 0x6cd: 0x9f, 0x6ce: 0x9f, 0x6cf: 0x9f, 0x6d0: 0x9f, 0x6d1: 0x9f, 0x6d2: 0x9f, 0x6d3: 0x9f, 0x6d4: 0x9f, 0x6d5: 0x9f, 0x6d6: 0x9f, 0x6d7: 0x9f, 0x6d8: 0x9f, 0x6d9: 0x9f, 0x6da: 0x9f, 0x6db: 0x9f, 0x6dc: 0x175, 0x6dd: 0x9f, 0x6de: 0x9f, 0x6df: 0x9f, 0x6e0: 0x176, 0x6e1: 0x9f, 0x6e2: 0x9f, 0x6e3: 0x9f, 0x6e4: 0x9f, 0x6e5: 0x9f, 0x6e6: 0x9f, 0x6e7: 0x9f, 0x6e8: 0x9f, 0x6e9: 0x9f, 0x6ea: 0x9f, 0x6eb: 0x9f, 0x6ec: 0x9f, 0x6ed: 0x9f, 0x6ee: 0x9f, 0x6ef: 0x9f, 0x6f0: 0x9f, 0x6f1: 0x9f, 0x6f2: 0x9f, 0x6f3: 0x9f, 0x6f4: 0x9f, 0x6f5: 0x9f, 0x6f6: 0x9f, 0x6f7: 0x9f, 0x6f8: 0x9f, 0x6f9: 0x9f, 0x6fa: 0x9f, 0x6fb: 0x9f, 0x6fc: 0x9f, 0x6fd: 0x9f, 0x6fe: 0x9f, 0x6ff: 0x9f, // Block 0x1c, offset 0x700 0x700: 0x9f, 0x701: 0x9f, 0x702: 0x9f, 0x703: 0x9f, 0x704: 0x9f, 0x705: 0x9f, 0x706: 0x9f, 0x707: 0x9f, 0x708: 0x9f, 0x709: 0x9f, 0x70a: 0x9f, 0x70b: 0x9f, 0x70c: 0x9f, 0x70d: 0x9f, 0x70e: 0x9f, 0x70f: 0x9f, 0x710: 0x9f, 0x711: 0x9f, 0x712: 0x9f, 0x713: 0x9f, 0x714: 0x9f, 0x715: 0x9f, 0x716: 0x9f, 0x717: 0x9f, 0x718: 0x9f, 0x719: 0x9f, 0x71a: 0x9f, 0x71b: 0x9f, 0x71c: 0x9f, 0x71d: 0x9f, 0x71e: 0x9f, 0x71f: 0x9f, 0x720: 0x9f, 0x721: 0x9f, 0x722: 0x9f, 0x723: 0x9f, 0x724: 0x9f, 0x725: 0x9f, 0x726: 0x9f, 0x727: 0x9f, 0x728: 0x9f, 0x729: 0x9f, 0x72a: 0x9f, 0x72b: 0x9f, 0x72c: 0x9f, 0x72d: 0x9f, 0x72e: 0x9f, 0x72f: 0x9f, 0x730: 0x9f, 0x731: 0x9f, 0x732: 0x9f, 0x733: 0x9f, 0x734: 0x9f, 0x735: 0x9f, 0x736: 0x9f, 0x737: 0x9f, 0x738: 0x9f, 0x739: 0x9f, 0x73a: 0x177, 0x73b: 0xba, 0x73c: 0xba, 0x73d: 0xba, 0x73e: 0xba, 0x73f: 0xba, // Block 0x1d, offset 0x740 0x740: 0xba, 0x741: 0xba, 0x742: 0xba, 0x743: 0xba, 0x744: 0xba, 0x745: 0xba, 0x746: 0xba, 0x747: 0xba, 0x748: 0xba, 0x749: 0xba, 0x74a: 0xba, 0x74b: 0xba, 0x74c: 0xba, 0x74d: 0xba, 0x74e: 0xba, 0x74f: 0xba, 0x750: 0xba, 0x751: 0xba, 0x752: 0xba, 0x753: 0xba, 0x754: 0xba, 0x755: 0xba, 0x756: 0xba, 0x757: 0xba, 0x758: 0xba, 0x759: 0xba, 0x75a: 0xba, 0x75b: 0xba, 0x75c: 0xba, 0x75d: 0xba, 0x75e: 0xba, 0x75f: 0xba, 0x760: 0x75, 0x761: 0x76, 0x762: 0x77, 0x763: 0x178, 0x764: 0x78, 0x765: 0x79, 0x766: 0x179, 0x767: 0x7a, 0x768: 0x7b, 0x769: 0xba, 0x76a: 0xba, 0x76b: 0xba, 0x76c: 0xba, 0x76d: 0xba, 0x76e: 0xba, 0x76f: 0xba, 0x770: 0xba, 0x771: 0xba, 0x772: 0xba, 0x773: 0xba, 0x774: 0xba, 0x775: 0xba, 0x776: 0xba, 0x777: 0xba, 0x778: 0xba, 0x779: 0xba, 0x77a: 0xba, 0x77b: 0xba, 0x77c: 0xba, 0x77d: 0xba, 0x77e: 0xba, 0x77f: 0xba, // Block 0x1e, offset 0x780 0x790: 0x0d, 0x791: 0x0e, 0x792: 0x0f, 0x793: 0x10, 0x794: 0x11, 0x795: 0x0b, 0x796: 0x12, 0x797: 0x07, 0x798: 0x13, 0x799: 0x0b, 0x79a: 0x0b, 0x79b: 0x14, 0x79c: 0x0b, 0x79d: 0x15, 0x79e: 0x16, 0x79f: 0x17, 0x7a0: 0x07, 0x7a1: 0x07, 0x7a2: 0x07, 0x7a3: 0x07, 0x7a4: 0x07, 0x7a5: 0x07, 0x7a6: 0x07, 0x7a7: 0x07, 0x7a8: 0x07, 0x7a9: 0x07, 0x7aa: 0x18, 0x7ab: 0x19, 0x7ac: 0x1a, 0x7ad: 0x0b, 0x7ae: 0x0b, 0x7af: 0x1b, 0x7b0: 0x0b, 0x7b1: 0x0b, 0x7b2: 0x0b, 0x7b3: 0x0b, 0x7b4: 0x0b, 0x7b5: 0x0b, 0x7b6: 0x0b, 0x7b7: 0x0b, 0x7b8: 0x0b, 0x7b9: 0x0b, 0x7ba: 0x0b, 0x7bb: 0x0b, 0x7bc: 0x0b, 0x7bd: 0x0b, 0x7be: 0x0b, 0x7bf: 0x0b, // Block 0x1f, offset 0x7c0 0x7c0: 0x0b, 0x7c1: 0x0b, 0x7c2: 0x0b, 0x7c3: 0x0b, 0x7c4: 0x0b, 0x7c5: 0x0b, 0x7c6: 0x0b, 0x7c7: 0x0b, 0x7c8: 0x0b, 0x7c9: 0x0b, 0x7ca: 0x0b, 0x7cb: 0x0b, 0x7cc: 0x0b, 0x7cd: 0x0b, 0x7ce: 0x0b, 0x7cf: 0x0b, 0x7d0: 0x0b, 0x7d1: 0x0b, 0x7d2: 0x0b, 0x7d3: 0x0b, 0x7d4: 0x0b, 0x7d5: 0x0b, 0x7d6: 0x0b, 0x7d7: 0x0b, 0x7d8: 0x0b, 0x7d9: 0x0b, 0x7da: 0x0b, 0x7db: 0x0b, 0x7dc: 0x0b, 0x7dd: 0x0b, 0x7de: 0x0b, 0x7df: 0x0b, 0x7e0: 0x0b, 0x7e1: 0x0b, 0x7e2: 0x0b, 0x7e3: 0x0b, 0x7e4: 0x0b, 0x7e5: 0x0b, 0x7e6: 0x0b, 0x7e7: 0x0b, 0x7e8: 0x0b, 0x7e9: 0x0b, 0x7ea: 0x0b, 0x7eb: 0x0b, 0x7ec: 0x0b, 0x7ed: 0x0b, 0x7ee: 0x0b, 0x7ef: 0x0b, 0x7f0: 0x0b, 0x7f1: 0x0b, 0x7f2: 0x0b, 0x7f3: 0x0b, 0x7f4: 0x0b, 0x7f5: 0x0b, 0x7f6: 0x0b, 0x7f7: 0x0b, 0x7f8: 0x0b, 0x7f9: 0x0b, 0x7fa: 0x0b, 0x7fb: 0x0b, 0x7fc: 0x0b, 0x7fd: 0x0b, 0x7fe: 0x0b, 0x7ff: 0x0b, // Block 0x20, offset 0x800 0x800: 0x17a, 0x801: 0x17b, 0x802: 0xba, 0x803: 0xba, 0x804: 0x17c, 0x805: 0x17c, 0x806: 0x17c, 0x807: 0x17d, 0x808: 0xba, 0x809: 0xba, 0x80a: 0xba, 0x80b: 0xba, 0x80c: 0xba, 0x80d: 0xba, 0x80e: 0xba, 0x80f: 0xba, 0x810: 0xba, 0x811: 0xba, 0x812: 0xba, 0x813: 0xba, 0x814: 0xba, 0x815: 0xba, 0x816: 0xba, 0x817: 0xba, 0x818: 0xba, 0x819: 0xba, 0x81a: 0xba, 0x81b: 0xba, 0x81c: 0xba, 0x81d: 0xba, 0x81e: 0xba, 0x81f: 0xba, 0x820: 0xba, 0x821: 0xba, 0x822: 0xba, 0x823: 0xba, 0x824: 0xba, 0x825: 0xba, 0x826: 0xba, 0x827: 0xba, 0x828: 0xba, 0x829: 0xba, 0x82a: 0xba, 0x82b: 0xba, 0x82c: 0xba, 0x82d: 0xba, 0x82e: 0xba, 0x82f: 0xba, 0x830: 0xba, 0x831: 0xba, 0x832: 0xba, 0x833: 0xba, 0x834: 0xba, 0x835: 0xba, 0x836: 0xba, 0x837: 0xba, 0x838: 0xba, 0x839: 0xba, 0x83a: 0xba, 0x83b: 0xba, 0x83c: 0xba, 0x83d: 0xba, 0x83e: 0xba, 0x83f: 0xba, // Block 0x21, offset 0x840 0x840: 0x0b, 0x841: 0x0b, 0x842: 0x0b, 0x843: 0x0b, 0x844: 0x0b, 0x845: 0x0b, 0x846: 0x0b, 0x847: 0x0b, 0x848: 0x0b, 0x849: 0x0b, 0x84a: 0x0b, 0x84b: 0x0b, 0x84c: 0x0b, 0x84d: 0x0b, 0x84e: 0x0b, 0x84f: 0x0b, 0x850: 0x0b, 0x851: 0x0b, 0x852: 0x0b, 0x853: 0x0b, 0x854: 0x0b, 0x855: 0x0b, 0x856: 0x0b, 0x857: 0x0b, 0x858: 0x0b, 0x859: 0x0b, 0x85a: 0x0b, 0x85b: 0x0b, 0x85c: 0x0b, 0x85d: 0x0b, 0x85e: 0x0b, 0x85f: 0x0b, 0x860: 0x1e, 0x861: 0x0b, 0x862: 0x0b, 0x863: 0x0b, 0x864: 0x0b, 0x865: 0x0b, 0x866: 0x0b, 0x867: 0x0b, 0x868: 0x0b, 0x869: 0x0b, 0x86a: 0x0b, 0x86b: 0x0b, 0x86c: 0x0b, 0x86d: 0x0b, 0x86e: 0x0b, 0x86f: 0x0b, 0x870: 0x0b, 0x871: 0x0b, 0x872: 0x0b, 0x873: 0x0b, 0x874: 0x0b, 0x875: 0x0b, 0x876: 0x0b, 0x877: 0x0b, 0x878: 0x0b, 0x879: 0x0b, 0x87a: 0x0b, 0x87b: 0x0b, 0x87c: 0x0b, 0x87d: 0x0b, 0x87e: 0x0b, 0x87f: 0x0b, // Block 0x22, offset 0x880 0x880: 0x0b, 0x881: 0x0b, 0x882: 0x0b, 0x883: 0x0b, 0x884: 0x0b, 0x885: 0x0b, 0x886: 0x0b, 0x887: 0x0b, 0x888: 0x0b, 0x889: 0x0b, 0x88a: 0x0b, 0x88b: 0x0b, 0x88c: 0x0b, 0x88d: 0x0b, 0x88e: 0x0b, 0x88f: 0x0b, } // idnaSparseOffset: 258 entries, 516 bytes var idnaSparseOffset = []uint16{0x0, 0x8, 0x19, 0x25, 0x27, 0x2c, 0x34, 0x3f, 0x4b, 0x4f, 0x5e, 0x63, 0x6b, 0x77, 0x85, 0x93, 0x98, 0xa1, 0xb1, 0xbf, 0xcc, 0xd8, 0xe9, 0xf3, 0xfa, 0x107, 0x118, 0x11f, 0x12a, 0x139, 0x147, 0x151, 0x153, 0x158, 0x15b, 0x15e, 0x160, 0x16c, 0x177, 0x17f, 0x185, 0x18b, 0x190, 0x195, 0x198, 0x19c, 0x1a2, 0x1a7, 0x1b3, 0x1bd, 0x1c3, 0x1d4, 0x1de, 0x1e1, 0x1e9, 0x1ec, 0x1f9, 0x201, 0x205, 0x20c, 0x214, 0x224, 0x230, 0x232, 0x23c, 0x248, 0x254, 0x260, 0x268, 0x26d, 0x277, 0x288, 0x28c, 0x297, 0x29b, 0x2a4, 0x2ac, 0x2b2, 0x2b7, 0x2ba, 0x2bd, 0x2c1, 0x2c7, 0x2cb, 0x2cf, 0x2d5, 0x2dc, 0x2e2, 0x2ea, 0x2f1, 0x2fc, 0x306, 0x30a, 0x30d, 0x313, 0x317, 0x319, 0x31c, 0x31e, 0x321, 0x32b, 0x32e, 0x33d, 0x341, 0x346, 0x349, 0x34d, 0x352, 0x357, 0x35d, 0x363, 0x372, 0x378, 0x37c, 0x38b, 0x390, 0x398, 0x3a2, 0x3ad, 0x3b5, 0x3c6, 0x3cf, 0x3df, 0x3ec, 0x3f6, 0x3fb, 0x408, 0x40c, 0x411, 0x413, 0x417, 0x419, 0x41d, 0x426, 0x42c, 0x430, 0x440, 0x44a, 0x44f, 0x452, 0x458, 0x45f, 0x464, 0x468, 0x46e, 0x473, 0x47c, 0x481, 0x487, 0x48e, 0x495, 0x49c, 0x4a0, 0x4a5, 0x4a8, 0x4ad, 0x4b9, 0x4bf, 0x4c4, 0x4cb, 0x4d3, 0x4d8, 0x4dc, 0x4ec, 0x4f3, 0x4f7, 0x4fb, 0x502, 0x504, 0x507, 0x50a, 0x50e, 0x512, 0x518, 0x521, 0x52d, 0x534, 0x53d, 0x545, 0x54c, 0x55a, 0x567, 0x574, 0x57d, 0x581, 0x58f, 0x597, 0x5a2, 0x5ab, 0x5b1, 0x5b9, 0x5c2, 0x5cc, 0x5cf, 0x5db, 0x5de, 0x5e3, 0x5e6, 0x5f0, 0x5f9, 0x605, 0x608, 0x60d, 0x610, 0x613, 0x616, 0x61d, 0x624, 0x628, 0x633, 0x636, 0x63c, 0x641, 0x645, 0x648, 0x64b, 0x64e, 0x653, 0x65d, 0x660, 0x664, 0x673, 0x67f, 0x683, 0x688, 0x68d, 0x691, 0x696, 0x69f, 0x6aa, 0x6b0, 0x6b8, 0x6bc, 0x6c0, 0x6c6, 0x6cc, 0x6d1, 0x6d4, 0x6e2, 0x6e9, 0x6ec, 0x6ef, 0x6f3, 0x6f9, 0x6fe, 0x708, 0x70d, 0x710, 0x713, 0x716, 0x719, 0x71d, 0x720, 0x730, 0x741, 0x746, 0x748, 0x74a} // idnaSparseValues: 1869 entries, 7476 bytes var idnaSparseValues = [1869]valueRange{ // Block 0x0, offset 0x0 {value: 0x0000, lo: 0x07}, {value: 0xe105, lo: 0x80, hi: 0x96}, {value: 0x0018, lo: 0x97, hi: 0x97}, {value: 0xe105, lo: 0x98, hi: 0x9e}, {value: 0x001f, lo: 0x9f, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xb7}, {value: 0x0008, lo: 0xb8, hi: 0xbf}, // Block 0x1, offset 0x8 {value: 0x0000, lo: 0x10}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0xe01d, lo: 0x81, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0x82}, {value: 0x0335, lo: 0x83, hi: 0x83}, {value: 0x034d, lo: 0x84, hi: 0x84}, {value: 0x0365, lo: 0x85, hi: 0x85}, {value: 0xe00d, lo: 0x86, hi: 0x86}, {value: 0x0008, lo: 0x87, hi: 0x87}, {value: 0xe00d, lo: 0x88, hi: 0x88}, {value: 0x0008, lo: 0x89, hi: 0x89}, {value: 0xe00d, lo: 0x8a, hi: 0x8a}, {value: 0x0008, lo: 0x8b, hi: 0x8b}, {value: 0xe00d, lo: 0x8c, hi: 0x8c}, {value: 0x0008, lo: 0x8d, hi: 0x8d}, {value: 0xe00d, lo: 0x8e, hi: 0x8e}, {value: 0x0008, lo: 0x8f, hi: 0xbf}, // Block 0x2, offset 0x19 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x0249, lo: 0xb0, hi: 0xb0}, {value: 0x037d, lo: 0xb1, hi: 0xb1}, {value: 0x0259, lo: 0xb2, hi: 0xb2}, {value: 0x0269, lo: 0xb3, hi: 0xb3}, {value: 0x034d, lo: 0xb4, hi: 0xb4}, {value: 0x0395, lo: 0xb5, hi: 0xb5}, {value: 0xe1bd, lo: 0xb6, hi: 0xb6}, {value: 0x0279, lo: 0xb7, hi: 0xb7}, {value: 0x0289, lo: 0xb8, hi: 0xb8}, {value: 0x0008, lo: 0xb9, hi: 0xbf}, // Block 0x3, offset 0x25 {value: 0x0000, lo: 0x01}, {value: 0x3308, lo: 0x80, hi: 0xbf}, // Block 0x4, offset 0x27 {value: 0x0000, lo: 0x04}, {value: 0x03f5, lo: 0x80, hi: 0x8f}, {value: 0xe105, lo: 0x90, hi: 0x9f}, {value: 0x049d, lo: 0xa0, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x5, offset 0x2c {value: 0x0000, lo: 0x07}, {value: 0xe185, lo: 0x80, hi: 0x8f}, {value: 0x0545, lo: 0x90, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x98}, {value: 0x0008, lo: 0x99, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xa0}, {value: 0x0008, lo: 0xa1, hi: 0xbf}, // Block 0x6, offset 0x34 {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0401, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x88}, {value: 0x0018, lo: 0x89, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x90}, {value: 0x3308, lo: 0x91, hi: 0xbd}, {value: 0x0818, lo: 0xbe, hi: 0xbe}, {value: 0x3308, lo: 0xbf, hi: 0xbf}, // Block 0x7, offset 0x3f {value: 0x0000, lo: 0x0b}, {value: 0x0818, lo: 0x80, hi: 0x80}, {value: 0x3308, lo: 0x81, hi: 0x82}, {value: 0x0818, lo: 0x83, hi: 0x83}, {value: 0x3308, lo: 0x84, hi: 0x85}, {value: 0x0818, lo: 0x86, hi: 0x86}, {value: 0x3308, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0808, lo: 0x90, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xaf}, {value: 0x0808, lo: 0xb0, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0x8, offset 0x4b {value: 0x0000, lo: 0x03}, {value: 0x0a08, lo: 0x80, hi: 0x87}, {value: 0x0c08, lo: 0x88, hi: 0x99}, {value: 0x0a08, lo: 0x9a, hi: 0xbf}, // Block 0x9, offset 0x4f {value: 0x0000, lo: 0x0e}, {value: 0x3308, lo: 0x80, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8c}, {value: 0x0c08, lo: 0x8d, hi: 0x8d}, {value: 0x0a08, lo: 0x8e, hi: 0x98}, {value: 0x0c08, lo: 0x99, hi: 0x9b}, {value: 0x0a08, lo: 0x9c, hi: 0xaa}, {value: 0x0c08, lo: 0xab, hi: 0xac}, {value: 0x0a08, lo: 0xad, hi: 0xb0}, {value: 0x0c08, lo: 0xb1, hi: 0xb1}, {value: 0x0a08, lo: 0xb2, hi: 0xb2}, {value: 0x0c08, lo: 0xb3, hi: 0xb4}, {value: 0x0a08, lo: 0xb5, hi: 0xb7}, {value: 0x0c08, lo: 0xb8, hi: 0xb9}, {value: 0x0a08, lo: 0xba, hi: 0xbf}, // Block 0xa, offset 0x5e {value: 0x0000, lo: 0x04}, {value: 0x0808, lo: 0x80, hi: 0xa5}, {value: 0x3308, lo: 0xa6, hi: 0xb0}, {value: 0x0808, lo: 0xb1, hi: 0xb1}, {value: 0x0040, lo: 0xb2, hi: 0xbf}, // Block 0xb, offset 0x63 {value: 0x0000, lo: 0x07}, {value: 0x0808, lo: 0x80, hi: 0x89}, {value: 0x0a08, lo: 0x8a, hi: 0xaa}, {value: 0x3308, lo: 0xab, hi: 0xb3}, {value: 0x0808, lo: 0xb4, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xb9}, {value: 0x0818, lo: 0xba, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbf}, // Block 0xc, offset 0x6b {value: 0x0000, lo: 0x0b}, {value: 0x0808, lo: 0x80, hi: 0x95}, {value: 0x3308, lo: 0x96, hi: 0x99}, {value: 0x0808, lo: 0x9a, hi: 0x9a}, {value: 0x3308, lo: 0x9b, hi: 0xa3}, {value: 0x0808, lo: 0xa4, hi: 0xa4}, {value: 0x3308, lo: 0xa5, hi: 0xa7}, {value: 0x0808, lo: 0xa8, hi: 0xa8}, {value: 0x3308, lo: 0xa9, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x0818, lo: 0xb0, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0xd, offset 0x77 {value: 0x0000, lo: 0x0d}, {value: 0x0c08, lo: 0x80, hi: 0x80}, {value: 0x0a08, lo: 0x81, hi: 0x85}, {value: 0x0c08, lo: 0x86, hi: 0x87}, {value: 0x0a08, lo: 0x88, hi: 0x88}, {value: 0x0c08, lo: 0x89, hi: 0x89}, {value: 0x0a08, lo: 0x8a, hi: 0x93}, {value: 0x0c08, lo: 0x94, hi: 0x94}, {value: 0x0a08, lo: 0x95, hi: 0x95}, {value: 0x0808, lo: 0x96, hi: 0x98}, {value: 0x3308, lo: 0x99, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0x9d}, {value: 0x0818, lo: 0x9e, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0xbf}, // Block 0xe, offset 0x85 {value: 0x0000, lo: 0x0d}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0a08, lo: 0xa0, hi: 0xa9}, {value: 0x0c08, lo: 0xaa, hi: 0xac}, {value: 0x0808, lo: 0xad, hi: 0xad}, {value: 0x0c08, lo: 0xae, hi: 0xae}, {value: 0x0a08, lo: 0xaf, hi: 0xb0}, {value: 0x0c08, lo: 0xb1, hi: 0xb2}, {value: 0x0a08, lo: 0xb3, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xb5}, {value: 0x0a08, lo: 0xb6, hi: 0xb8}, {value: 0x0c08, lo: 0xb9, hi: 0xb9}, {value: 0x0a08, lo: 0xba, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, // Block 0xf, offset 0x93 {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x93}, {value: 0x3308, lo: 0x94, hi: 0xa1}, {value: 0x0840, lo: 0xa2, hi: 0xa2}, {value: 0x3308, lo: 0xa3, hi: 0xbf}, // Block 0x10, offset 0x98 {value: 0x0000, lo: 0x08}, {value: 0x3308, lo: 0x80, hi: 0x82}, {value: 0x3008, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0xb9}, {value: 0x3308, lo: 0xba, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbf}, // Block 0x11, offset 0xa1 {value: 0x0000, lo: 0x0f}, {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x3008, lo: 0x81, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x85}, {value: 0x3008, lo: 0x86, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x3008, lo: 0x8a, hi: 0x8c}, {value: 0x3b08, lo: 0x8d, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x96}, {value: 0x3008, lo: 0x97, hi: 0x97}, {value: 0x0040, lo: 0x98, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbf}, // Block 0x12, offset 0xb1 {value: 0x0000, lo: 0x0d}, {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x3008, lo: 0x81, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, {value: 0x0008, lo: 0x8e, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x91}, {value: 0x0008, lo: 0x92, hi: 0xa8}, {value: 0x0040, lo: 0xa9, hi: 0xa9}, {value: 0x0008, lo: 0xaa, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x3308, lo: 0xbe, hi: 0xbf}, // Block 0x13, offset 0xbf {value: 0x0000, lo: 0x0c}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x3308, lo: 0x81, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, {value: 0x0008, lo: 0x8e, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x91}, {value: 0x0008, lo: 0x92, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbf}, // Block 0x14, offset 0xcc {value: 0x0000, lo: 0x0b}, {value: 0x0040, lo: 0x80, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x99}, {value: 0x0008, lo: 0x9a, hi: 0xb1}, {value: 0x0040, lo: 0xb2, hi: 0xb2}, {value: 0x0008, lo: 0xb3, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, // Block 0x15, offset 0xd8 {value: 0x0000, lo: 0x10}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x89}, {value: 0x3b08, lo: 0x8a, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8e}, {value: 0x3008, lo: 0x8f, hi: 0x91}, {value: 0x3308, lo: 0x92, hi: 0x94}, {value: 0x0040, lo: 0x95, hi: 0x95}, {value: 0x3308, lo: 0x96, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x97}, {value: 0x3008, lo: 0x98, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xb1}, {value: 0x3008, lo: 0xb2, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0x16, offset 0xe9 {value: 0x0000, lo: 0x09}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0xb0}, {value: 0x3308, lo: 0xb1, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xb2}, {value: 0x08f1, lo: 0xb3, hi: 0xb3}, {value: 0x3308, lo: 0xb4, hi: 0xb9}, {value: 0x3b08, lo: 0xba, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbe}, {value: 0x0018, lo: 0xbf, hi: 0xbf}, // Block 0x17, offset 0xf3 {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x3308, lo: 0x87, hi: 0x8e}, {value: 0x0018, lo: 0x8f, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0xbf}, // Block 0x18, offset 0xfa {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x85}, {value: 0x0008, lo: 0x86, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, {value: 0x3308, lo: 0x88, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9b}, {value: 0x0961, lo: 0x9c, hi: 0x9c}, {value: 0x0999, lo: 0x9d, hi: 0x9d}, {value: 0x0008, lo: 0x9e, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, // Block 0x19, offset 0x107 {value: 0x0000, lo: 0x10}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x8a}, {value: 0x0008, lo: 0x8b, hi: 0x8b}, {value: 0xe03d, lo: 0x8c, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x97}, {value: 0x3308, lo: 0x98, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa9}, {value: 0x0018, lo: 0xaa, hi: 0xb4}, {value: 0x3308, lo: 0xb5, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xb6}, {value: 0x3308, lo: 0xb7, hi: 0xb7}, {value: 0x0018, lo: 0xb8, hi: 0xb8}, {value: 0x3308, lo: 0xb9, hi: 0xb9}, {value: 0x0018, lo: 0xba, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbf}, // Block 0x1a, offset 0x118 {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x85}, {value: 0x3308, lo: 0x86, hi: 0x86}, {value: 0x0018, lo: 0x87, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, {value: 0x0018, lo: 0x8e, hi: 0x9a}, {value: 0x0040, lo: 0x9b, hi: 0xbf}, // Block 0x1b, offset 0x11f {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0xaa}, {value: 0x3008, lo: 0xab, hi: 0xac}, {value: 0x3308, lo: 0xad, hi: 0xb0}, {value: 0x3008, lo: 0xb1, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb7}, {value: 0x3008, lo: 0xb8, hi: 0xb8}, {value: 0x3b08, lo: 0xb9, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbc}, {value: 0x3308, lo: 0xbd, hi: 0xbe}, {value: 0x0008, lo: 0xbf, hi: 0xbf}, // Block 0x1c, offset 0x12a {value: 0x0000, lo: 0x0e}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0018, lo: 0x8a, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x95}, {value: 0x3008, lo: 0x96, hi: 0x97}, {value: 0x3308, lo: 0x98, hi: 0x99}, {value: 0x0008, lo: 0x9a, hi: 0x9d}, {value: 0x3308, lo: 0x9e, hi: 0xa0}, {value: 0x0008, lo: 0xa1, hi: 0xa1}, {value: 0x3008, lo: 0xa2, hi: 0xa4}, {value: 0x0008, lo: 0xa5, hi: 0xa6}, {value: 0x3008, lo: 0xa7, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xb0}, {value: 0x3308, lo: 0xb1, hi: 0xb4}, {value: 0x0008, lo: 0xb5, hi: 0xbf}, // Block 0x1d, offset 0x139 {value: 0x0000, lo: 0x0d}, {value: 0x0008, lo: 0x80, hi: 0x81}, {value: 0x3308, lo: 0x82, hi: 0x82}, {value: 0x3008, lo: 0x83, hi: 0x84}, {value: 0x3308, lo: 0x85, hi: 0x86}, {value: 0x3008, lo: 0x87, hi: 0x8c}, {value: 0x3308, lo: 0x8d, hi: 0x8d}, {value: 0x0008, lo: 0x8e, hi: 0x8e}, {value: 0x3008, lo: 0x8f, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x3008, lo: 0x9a, hi: 0x9c}, {value: 0x3308, lo: 0x9d, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, // Block 0x1e, offset 0x147 {value: 0x0000, lo: 0x09}, {value: 0x0040, lo: 0x80, hi: 0x86}, {value: 0x055d, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8c}, {value: 0x055d, lo: 0x8d, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xba}, {value: 0x0018, lo: 0xbb, hi: 0xbb}, {value: 0xe105, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbf}, // Block 0x1f, offset 0x151 {value: 0x0000, lo: 0x01}, {value: 0x0018, lo: 0x80, hi: 0xbf}, // Block 0x20, offset 0x153 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0xa0}, {value: 0x2018, lo: 0xa1, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xbf}, // Block 0x21, offset 0x158 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xa7}, {value: 0x2018, lo: 0xa8, hi: 0xbf}, // Block 0x22, offset 0x15b {value: 0x0000, lo: 0x02}, {value: 0x2018, lo: 0x80, hi: 0x82}, {value: 0x0018, lo: 0x83, hi: 0xbf}, // Block 0x23, offset 0x15e {value: 0x0000, lo: 0x01}, {value: 0x0008, lo: 0x80, hi: 0xbf}, // Block 0x24, offset 0x160 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0008, lo: 0x8a, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0x98}, {value: 0x0040, lo: 0x99, hi: 0x99}, {value: 0x0008, lo: 0x9a, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x25, offset 0x16c {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0008, lo: 0x8a, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb7}, {value: 0x0008, lo: 0xb8, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0x26, offset 0x177 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0040, lo: 0x81, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0xbf}, // Block 0x27, offset 0x17f {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x91}, {value: 0x0008, lo: 0x92, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0xbf}, // Block 0x28, offset 0x185 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x9a}, {value: 0x0040, lo: 0x9b, hi: 0x9c}, {value: 0x3308, lo: 0x9d, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, // Block 0x29, offset 0x18b {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x2a, offset 0x190 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb7}, {value: 0xe045, lo: 0xb8, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, // Block 0x2b, offset 0x195 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0xbf}, // Block 0x2c, offset 0x198 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xac}, {value: 0x0018, lo: 0xad, hi: 0xae}, {value: 0x0008, lo: 0xaf, hi: 0xbf}, // Block 0x2d, offset 0x19c {value: 0x0000, lo: 0x05}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9c}, {value: 0x0040, lo: 0x9d, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x2e, offset 0x1a2 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xaa}, {value: 0x0018, lo: 0xab, hi: 0xb0}, {value: 0x0008, lo: 0xb1, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbf}, // Block 0x2f, offset 0x1a7 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, {value: 0x0008, lo: 0x8e, hi: 0x91}, {value: 0x3308, lo: 0x92, hi: 0x93}, {value: 0x3b08, lo: 0x94, hi: 0x94}, {value: 0x0040, lo: 0x95, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb3}, {value: 0x3b08, lo: 0xb4, hi: 0xb4}, {value: 0x0018, lo: 0xb5, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0x30, offset 0x1b3 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x91}, {value: 0x3308, lo: 0x92, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbf}, // Block 0x31, offset 0x1bd {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0xb3}, {value: 0x3340, lo: 0xb4, hi: 0xb5}, {value: 0x3008, lo: 0xb6, hi: 0xb6}, {value: 0x3308, lo: 0xb7, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbf}, // Block 0x32, offset 0x1c3 {value: 0x0000, lo: 0x10}, {value: 0x3008, lo: 0x80, hi: 0x85}, {value: 0x3308, lo: 0x86, hi: 0x86}, {value: 0x3008, lo: 0x87, hi: 0x88}, {value: 0x3308, lo: 0x89, hi: 0x91}, {value: 0x3b08, lo: 0x92, hi: 0x92}, {value: 0x3308, lo: 0x93, hi: 0x93}, {value: 0x0018, lo: 0x94, hi: 0x96}, {value: 0x0008, lo: 0x97, hi: 0x97}, {value: 0x0018, lo: 0x98, hi: 0x9b}, {value: 0x0008, lo: 0x9c, hi: 0x9c}, {value: 0x3308, lo: 0x9d, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa9}, {value: 0x0040, lo: 0xaa, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0x33, offset 0x1d4 {value: 0x0000, lo: 0x09}, {value: 0x0018, lo: 0x80, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x86}, {value: 0x0218, lo: 0x87, hi: 0x87}, {value: 0x0018, lo: 0x88, hi: 0x8a}, {value: 0x33c0, lo: 0x8b, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0208, lo: 0xa0, hi: 0xbf}, // Block 0x34, offset 0x1de {value: 0x0000, lo: 0x02}, {value: 0x0208, lo: 0x80, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbf}, // Block 0x35, offset 0x1e1 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x84}, {value: 0x3308, lo: 0x85, hi: 0x86}, {value: 0x0208, lo: 0x87, hi: 0xa8}, {value: 0x3308, lo: 0xa9, hi: 0xa9}, {value: 0x0208, lo: 0xaa, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x36, offset 0x1e9 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, // Block 0x37, offset 0x1ec {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x3308, lo: 0xa0, hi: 0xa2}, {value: 0x3008, lo: 0xa3, hi: 0xa6}, {value: 0x3308, lo: 0xa7, hi: 0xa8}, {value: 0x3008, lo: 0xa9, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x3008, lo: 0xb0, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb2}, {value: 0x3008, lo: 0xb3, hi: 0xb8}, {value: 0x3308, lo: 0xb9, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, // Block 0x38, offset 0x1f9 {value: 0x0000, lo: 0x07}, {value: 0x0018, lo: 0x80, hi: 0x80}, {value: 0x0040, lo: 0x81, hi: 0x83}, {value: 0x0018, lo: 0x84, hi: 0x85}, {value: 0x0008, lo: 0x86, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0x39, offset 0x201 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x3a, offset 0x205 {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0028, lo: 0x9a, hi: 0x9a}, {value: 0x0040, lo: 0x9b, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0xbf}, // Block 0x3b, offset 0x20c {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x96}, {value: 0x3308, lo: 0x97, hi: 0x98}, {value: 0x3008, lo: 0x99, hi: 0x9a}, {value: 0x3308, lo: 0x9b, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x3c, offset 0x214 {value: 0x0000, lo: 0x0f}, {value: 0x0008, lo: 0x80, hi: 0x94}, {value: 0x3008, lo: 0x95, hi: 0x95}, {value: 0x3308, lo: 0x96, hi: 0x96}, {value: 0x3008, lo: 0x97, hi: 0x97}, {value: 0x3308, lo: 0x98, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x3b08, lo: 0xa0, hi: 0xa0}, {value: 0x3008, lo: 0xa1, hi: 0xa1}, {value: 0x3308, lo: 0xa2, hi: 0xa2}, {value: 0x3008, lo: 0xa3, hi: 0xa4}, {value: 0x3308, lo: 0xa5, hi: 0xac}, {value: 0x3008, lo: 0xad, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbe}, {value: 0x3308, lo: 0xbf, hi: 0xbf}, // Block 0x3d, offset 0x224 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa6}, {value: 0x0008, lo: 0xa7, hi: 0xa7}, {value: 0x0018, lo: 0xa8, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xbd}, {value: 0x3318, lo: 0xbe, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0x3e, offset 0x230 {value: 0x0000, lo: 0x01}, {value: 0x0040, lo: 0x80, hi: 0xbf}, // Block 0x3f, offset 0x232 {value: 0x0000, lo: 0x09}, {value: 0x3308, lo: 0x80, hi: 0x83}, {value: 0x3008, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0xb3}, {value: 0x3308, lo: 0xb4, hi: 0xb4}, {value: 0x3008, lo: 0xb5, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbc}, {value: 0x3008, lo: 0xbd, hi: 0xbf}, // Block 0x40, offset 0x23c {value: 0x0000, lo: 0x0b}, {value: 0x3008, lo: 0x80, hi: 0x81}, {value: 0x3308, lo: 0x82, hi: 0x82}, {value: 0x3008, lo: 0x83, hi: 0x83}, {value: 0x3808, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0xaa}, {value: 0x3308, lo: 0xab, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, // Block 0x41, offset 0x248 {value: 0x0000, lo: 0x0b}, {value: 0x3308, lo: 0x80, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xa0}, {value: 0x3008, lo: 0xa1, hi: 0xa1}, {value: 0x3308, lo: 0xa2, hi: 0xa5}, {value: 0x3008, lo: 0xa6, hi: 0xa7}, {value: 0x3308, lo: 0xa8, hi: 0xa9}, {value: 0x3808, lo: 0xaa, hi: 0xaa}, {value: 0x3b08, lo: 0xab, hi: 0xab}, {value: 0x3308, lo: 0xac, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xbf}, // Block 0x42, offset 0x254 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0xa5}, {value: 0x3308, lo: 0xa6, hi: 0xa6}, {value: 0x3008, lo: 0xa7, hi: 0xa7}, {value: 0x3308, lo: 0xa8, hi: 0xa9}, {value: 0x3008, lo: 0xaa, hi: 0xac}, {value: 0x3308, lo: 0xad, hi: 0xad}, {value: 0x3008, lo: 0xae, hi: 0xae}, {value: 0x3308, lo: 0xaf, hi: 0xb1}, {value: 0x3808, lo: 0xb2, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbb}, {value: 0x0018, lo: 0xbc, hi: 0xbf}, // Block 0x43, offset 0x260 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xa3}, {value: 0x3008, lo: 0xa4, hi: 0xab}, {value: 0x3308, lo: 0xac, hi: 0xb3}, {value: 0x3008, lo: 0xb4, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xba}, {value: 0x0018, lo: 0xbb, hi: 0xbf}, // Block 0x44, offset 0x268 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0x8c}, {value: 0x0008, lo: 0x8d, hi: 0xbd}, {value: 0x0018, lo: 0xbe, hi: 0xbf}, // Block 0x45, offset 0x26d {value: 0x0000, lo: 0x09}, {value: 0x0e29, lo: 0x80, hi: 0x80}, {value: 0x0e41, lo: 0x81, hi: 0x81}, {value: 0x0e59, lo: 0x82, hi: 0x82}, {value: 0x0e71, lo: 0x83, hi: 0x83}, {value: 0x0e89, lo: 0x84, hi: 0x85}, {value: 0x0ea1, lo: 0x86, hi: 0x86}, {value: 0x0eb9, lo: 0x87, hi: 0x87}, {value: 0x057d, lo: 0x88, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0xbf}, // Block 0x46, offset 0x277 {value: 0x0000, lo: 0x10}, {value: 0x0018, lo: 0x80, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x3308, lo: 0x90, hi: 0x92}, {value: 0x0018, lo: 0x93, hi: 0x93}, {value: 0x3308, lo: 0x94, hi: 0xa0}, {value: 0x3008, lo: 0xa1, hi: 0xa1}, {value: 0x3308, lo: 0xa2, hi: 0xa8}, {value: 0x0008, lo: 0xa9, hi: 0xac}, {value: 0x3308, lo: 0xad, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xb1}, {value: 0x3008, lo: 0xb2, hi: 0xb3}, {value: 0x3308, lo: 0xb4, hi: 0xb4}, {value: 0x0008, lo: 0xb5, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xb7}, {value: 0x3308, lo: 0xb8, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0x47, offset 0x288 {value: 0x0000, lo: 0x03}, {value: 0x3308, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xba}, {value: 0x3308, lo: 0xbb, hi: 0xbf}, // Block 0x48, offset 0x28c {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x87}, {value: 0xe045, lo: 0x88, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x97}, {value: 0xe045, lo: 0x98, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa7}, {value: 0xe045, lo: 0xa8, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb7}, {value: 0xe045, lo: 0xb8, hi: 0xbf}, // Block 0x49, offset 0x297 {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0x8f}, {value: 0x3318, lo: 0x90, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xbf}, // Block 0x4a, offset 0x29b {value: 0x0000, lo: 0x08}, {value: 0x0018, lo: 0x80, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x84}, {value: 0x0018, lo: 0x85, hi: 0x88}, {value: 0x24c1, lo: 0x89, hi: 0x89}, {value: 0x0018, lo: 0x8a, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbf}, // Block 0x4b, offset 0x2a4 {value: 0x0000, lo: 0x07}, {value: 0x0018, lo: 0x80, hi: 0xab}, {value: 0x24f1, lo: 0xac, hi: 0xac}, {value: 0x2529, lo: 0xad, hi: 0xad}, {value: 0x0018, lo: 0xae, hi: 0xae}, {value: 0x2579, lo: 0xaf, hi: 0xaf}, {value: 0x25b1, lo: 0xb0, hi: 0xb0}, {value: 0x0018, lo: 0xb1, hi: 0xbf}, // Block 0x4c, offset 0x2ac {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x9f}, {value: 0x0080, lo: 0xa0, hi: 0xa0}, {value: 0x0018, lo: 0xa1, hi: 0xad}, {value: 0x0080, lo: 0xae, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, // Block 0x4d, offset 0x2b2 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0xa8}, {value: 0x09c5, lo: 0xa9, hi: 0xa9}, {value: 0x09e5, lo: 0xaa, hi: 0xaa}, {value: 0x0018, lo: 0xab, hi: 0xbf}, // Block 0x4e, offset 0x2b7 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0x4f, offset 0x2ba {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xbf}, // Block 0x50, offset 0x2bd {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0x8b}, {value: 0x28c1, lo: 0x8c, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0xbf}, // Block 0x51, offset 0x2c1 {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0xb3}, {value: 0x0e66, lo: 0xb4, hi: 0xb4}, {value: 0x292a, lo: 0xb5, hi: 0xb5}, {value: 0x0e86, lo: 0xb6, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xbf}, // Block 0x52, offset 0x2c7 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0x9b}, {value: 0x2941, lo: 0x9c, hi: 0x9c}, {value: 0x0018, lo: 0x9d, hi: 0xbf}, // Block 0x53, offset 0x2cb {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xbf}, // Block 0x54, offset 0x2cf {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x97}, {value: 0x0018, lo: 0x98, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbc}, {value: 0x0018, lo: 0xbd, hi: 0xbf}, // Block 0x55, offset 0x2d5 {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0018, lo: 0x8a, hi: 0x91}, {value: 0x0040, lo: 0x92, hi: 0xab}, {value: 0x0018, lo: 0xac, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, // Block 0x56, offset 0x2dc {value: 0x0000, lo: 0x05}, {value: 0xe185, lo: 0x80, hi: 0x8f}, {value: 0x03f5, lo: 0x90, hi: 0x9f}, {value: 0x0ea5, lo: 0xa0, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x57, offset 0x2e2 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xa5}, {value: 0x0040, lo: 0xa6, hi: 0xa6}, {value: 0x0008, lo: 0xa7, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xac}, {value: 0x0008, lo: 0xad, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x58, offset 0x2ea {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xae}, {value: 0xe075, lo: 0xaf, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0x59, offset 0x2f1 {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xa7}, {value: 0x0008, lo: 0xa8, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xb7}, {value: 0x0008, lo: 0xb8, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0x5a, offset 0x2fc {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x8e}, {value: 0x0040, lo: 0x8f, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x3308, lo: 0xa0, hi: 0xbf}, // Block 0x5b, offset 0x306 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xae}, {value: 0x0008, lo: 0xaf, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, // Block 0x5c, offset 0x30a {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0xbf}, // Block 0x5d, offset 0x30d {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9e}, {value: 0x0edd, lo: 0x9f, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xbf}, // Block 0x5e, offset 0x313 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xb2}, {value: 0x0efd, lo: 0xb3, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbf}, // Block 0x5f, offset 0x317 {value: 0x0020, lo: 0x01}, {value: 0x0f1d, lo: 0x80, hi: 0xbf}, // Block 0x60, offset 0x319 {value: 0x0020, lo: 0x02}, {value: 0x171d, lo: 0x80, hi: 0x8f}, {value: 0x18fd, lo: 0x90, hi: 0xbf}, // Block 0x61, offset 0x31c {value: 0x0020, lo: 0x01}, {value: 0x1efd, lo: 0x80, hi: 0xbf}, // Block 0x62, offset 0x31e {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0xbf}, // Block 0x63, offset 0x321 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x98}, {value: 0x3308, lo: 0x99, hi: 0x9a}, {value: 0x29e2, lo: 0x9b, hi: 0x9b}, {value: 0x2a0a, lo: 0x9c, hi: 0x9c}, {value: 0x0008, lo: 0x9d, hi: 0x9e}, {value: 0x2a31, lo: 0x9f, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa0}, {value: 0x0008, lo: 0xa1, hi: 0xbf}, // Block 0x64, offset 0x32b {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xbe}, {value: 0x2a69, lo: 0xbf, hi: 0xbf}, // Block 0x65, offset 0x32e {value: 0x0000, lo: 0x0e}, {value: 0x0040, lo: 0x80, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xb0}, {value: 0x2a1d, lo: 0xb1, hi: 0xb1}, {value: 0x2a3d, lo: 0xb2, hi: 0xb2}, {value: 0x2a5d, lo: 0xb3, hi: 0xb3}, {value: 0x2a7d, lo: 0xb4, hi: 0xb4}, {value: 0x2a5d, lo: 0xb5, hi: 0xb5}, {value: 0x2a9d, lo: 0xb6, hi: 0xb6}, {value: 0x2abd, lo: 0xb7, hi: 0xb7}, {value: 0x2add, lo: 0xb8, hi: 0xb9}, {value: 0x2afd, lo: 0xba, hi: 0xbb}, {value: 0x2b1d, lo: 0xbc, hi: 0xbd}, {value: 0x2afd, lo: 0xbe, hi: 0xbf}, // Block 0x66, offset 0x33d {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x67, offset 0x341 {value: 0x0030, lo: 0x04}, {value: 0x2aa2, lo: 0x80, hi: 0x9d}, {value: 0x305a, lo: 0x9e, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x30a2, lo: 0xa0, hi: 0xbf}, // Block 0x68, offset 0x346 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0xbf}, // Block 0x69, offset 0x349 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbf}, // Block 0x6a, offset 0x34d {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xbd}, {value: 0x0018, lo: 0xbe, hi: 0xbf}, // Block 0x6b, offset 0x352 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xbf}, // Block 0x6c, offset 0x357 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0xa5}, {value: 0x0018, lo: 0xa6, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb1}, {value: 0x0018, lo: 0xb2, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbf}, // Block 0x6d, offset 0x35d {value: 0x0000, lo: 0x05}, {value: 0x0040, lo: 0x80, hi: 0xb6}, {value: 0x0008, lo: 0xb7, hi: 0xb7}, {value: 0x2009, lo: 0xb8, hi: 0xb8}, {value: 0x6e89, lo: 0xb9, hi: 0xb9}, {value: 0x0008, lo: 0xba, hi: 0xbf}, // Block 0x6e, offset 0x363 {value: 0x0000, lo: 0x0e}, {value: 0x0008, lo: 0x80, hi: 0x81}, {value: 0x3308, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0x85}, {value: 0x3b08, lo: 0x86, hi: 0x86}, {value: 0x0008, lo: 0x87, hi: 0x8a}, {value: 0x3308, lo: 0x8b, hi: 0x8b}, {value: 0x0008, lo: 0x8c, hi: 0xa2}, {value: 0x3008, lo: 0xa3, hi: 0xa4}, {value: 0x3308, lo: 0xa5, hi: 0xa6}, {value: 0x3008, lo: 0xa7, hi: 0xa7}, {value: 0x0018, lo: 0xa8, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0x6f, offset 0x372 {value: 0x0000, lo: 0x05}, {value: 0x0208, lo: 0x80, hi: 0xb1}, {value: 0x0108, lo: 0xb2, hi: 0xb2}, {value: 0x0008, lo: 0xb3, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbf}, // Block 0x70, offset 0x378 {value: 0x0000, lo: 0x03}, {value: 0x3008, lo: 0x80, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0xb3}, {value: 0x3008, lo: 0xb4, hi: 0xbf}, // Block 0x71, offset 0x37c {value: 0x0000, lo: 0x0e}, {value: 0x3008, lo: 0x80, hi: 0x83}, {value: 0x3b08, lo: 0x84, hi: 0x84}, {value: 0x3308, lo: 0x85, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x8d}, {value: 0x0018, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x3308, lo: 0xa0, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xb7}, {value: 0x0018, lo: 0xb8, hi: 0xba}, {value: 0x0008, lo: 0xbb, hi: 0xbb}, {value: 0x0018, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, // Block 0x72, offset 0x38b {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xa5}, {value: 0x3308, lo: 0xa6, hi: 0xad}, {value: 0x0018, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x73, offset 0x390 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x3308, lo: 0x87, hi: 0x91}, {value: 0x3008, lo: 0x92, hi: 0x92}, {value: 0x3808, lo: 0x93, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, // Block 0x74, offset 0x398 {value: 0x0000, lo: 0x09}, {value: 0x3308, lo: 0x80, hi: 0x82}, {value: 0x3008, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xb3}, {value: 0x3008, lo: 0xb4, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xb9}, {value: 0x3008, lo: 0xba, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbc}, {value: 0x3008, lo: 0xbd, hi: 0xbf}, // Block 0x75, offset 0x3a2 {value: 0x0000, lo: 0x0a}, {value: 0x3808, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8e}, {value: 0x0008, lo: 0x8f, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa4}, {value: 0x3308, lo: 0xa5, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0x76, offset 0x3ad {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xa8}, {value: 0x3308, lo: 0xa9, hi: 0xae}, {value: 0x3008, lo: 0xaf, hi: 0xb0}, {value: 0x3308, lo: 0xb1, hi: 0xb2}, {value: 0x3008, lo: 0xb3, hi: 0xb4}, {value: 0x3308, lo: 0xb5, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0x77, offset 0x3b5 {value: 0x0000, lo: 0x10}, {value: 0x0008, lo: 0x80, hi: 0x82}, {value: 0x3308, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x8b}, {value: 0x3308, lo: 0x8c, hi: 0x8c}, {value: 0x3008, lo: 0x8d, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9b}, {value: 0x0018, lo: 0x9c, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xb9}, {value: 0x0008, lo: 0xba, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbc}, {value: 0x3008, lo: 0xbd, hi: 0xbd}, {value: 0x0008, lo: 0xbe, hi: 0xbf}, // Block 0x78, offset 0x3c6 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb0}, {value: 0x0008, lo: 0xb1, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb4}, {value: 0x0008, lo: 0xb5, hi: 0xb6}, {value: 0x3308, lo: 0xb7, hi: 0xb8}, {value: 0x0008, lo: 0xb9, hi: 0xbd}, {value: 0x3308, lo: 0xbe, hi: 0xbf}, // Block 0x79, offset 0x3cf {value: 0x0000, lo: 0x0f}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x3308, lo: 0x81, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x9a}, {value: 0x0008, lo: 0x9b, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xaa}, {value: 0x3008, lo: 0xab, hi: 0xab}, {value: 0x3308, lo: 0xac, hi: 0xad}, {value: 0x3008, lo: 0xae, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xb4}, {value: 0x3008, lo: 0xb5, hi: 0xb5}, {value: 0x3b08, lo: 0xb6, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0x7a, offset 0x3df {value: 0x0000, lo: 0x0c}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x88}, {value: 0x0008, lo: 0x89, hi: 0x8e}, {value: 0x0040, lo: 0x8f, hi: 0x90}, {value: 0x0008, lo: 0x91, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xa7}, {value: 0x0008, lo: 0xa8, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x7b, offset 0x3ec {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9b}, {value: 0x4465, lo: 0x9c, hi: 0x9c}, {value: 0x447d, lo: 0x9d, hi: 0x9d}, {value: 0x2971, lo: 0x9e, hi: 0x9e}, {value: 0xe06d, lo: 0x9f, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa5}, {value: 0x0040, lo: 0xa6, hi: 0xaf}, {value: 0x4495, lo: 0xb0, hi: 0xbf}, // Block 0x7c, offset 0x3f6 {value: 0x0000, lo: 0x04}, {value: 0x44b5, lo: 0x80, hi: 0x8f}, {value: 0x44d5, lo: 0x90, hi: 0x9f}, {value: 0x44f5, lo: 0xa0, hi: 0xaf}, {value: 0x44d5, lo: 0xb0, hi: 0xbf}, // Block 0x7d, offset 0x3fb {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0xa2}, {value: 0x3008, lo: 0xa3, hi: 0xa4}, {value: 0x3308, lo: 0xa5, hi: 0xa5}, {value: 0x3008, lo: 0xa6, hi: 0xa7}, {value: 0x3308, lo: 0xa8, hi: 0xa8}, {value: 0x3008, lo: 0xa9, hi: 0xaa}, {value: 0x0018, lo: 0xab, hi: 0xab}, {value: 0x3008, lo: 0xac, hi: 0xac}, {value: 0x3b08, lo: 0xad, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0x7e, offset 0x408 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, // Block 0x7f, offset 0x40c {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x8a}, {value: 0x0018, lo: 0x8b, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, // Block 0x80, offset 0x411 {value: 0x0020, lo: 0x01}, {value: 0x4515, lo: 0x80, hi: 0xbf}, // Block 0x81, offset 0x413 {value: 0x0020, lo: 0x03}, {value: 0x4d15, lo: 0x80, hi: 0x94}, {value: 0x4ad5, lo: 0x95, hi: 0x95}, {value: 0x4fb5, lo: 0x96, hi: 0xbf}, // Block 0x82, offset 0x417 {value: 0x0020, lo: 0x01}, {value: 0x54f5, lo: 0x80, hi: 0xbf}, // Block 0x83, offset 0x419 {value: 0x0020, lo: 0x03}, {value: 0x5cf5, lo: 0x80, hi: 0x84}, {value: 0x5655, lo: 0x85, hi: 0x85}, {value: 0x5d95, lo: 0x86, hi: 0xbf}, // Block 0x84, offset 0x41d {value: 0x0020, lo: 0x08}, {value: 0x6b55, lo: 0x80, hi: 0x8f}, {value: 0x6d15, lo: 0x90, hi: 0x90}, {value: 0x6d55, lo: 0x91, hi: 0xab}, {value: 0x6ea1, lo: 0xac, hi: 0xac}, {value: 0x70b5, lo: 0xad, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x70d5, lo: 0xb0, hi: 0xbf}, // Block 0x85, offset 0x426 {value: 0x0020, lo: 0x05}, {value: 0x72d5, lo: 0x80, hi: 0xad}, {value: 0x6535, lo: 0xae, hi: 0xae}, {value: 0x7895, lo: 0xaf, hi: 0xb5}, {value: 0x6f55, lo: 0xb6, hi: 0xb6}, {value: 0x7975, lo: 0xb7, hi: 0xbf}, // Block 0x86, offset 0x42c {value: 0x0028, lo: 0x03}, {value: 0x7c21, lo: 0x80, hi: 0x82}, {value: 0x7be1, lo: 0x83, hi: 0x83}, {value: 0x7c99, lo: 0x84, hi: 0xbf}, // Block 0x87, offset 0x430 {value: 0x0038, lo: 0x0f}, {value: 0x9db1, lo: 0x80, hi: 0x83}, {value: 0x9e59, lo: 0x84, hi: 0x85}, {value: 0x9e91, lo: 0x86, hi: 0x87}, {value: 0x9ec9, lo: 0x88, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x91}, {value: 0xa089, lo: 0x92, hi: 0x97}, {value: 0xa1a1, lo: 0x98, hi: 0x9c}, {value: 0xa281, lo: 0x9d, hi: 0xb3}, {value: 0x9d41, lo: 0xb4, hi: 0xb4}, {value: 0x9db1, lo: 0xb5, hi: 0xb5}, {value: 0xa789, lo: 0xb6, hi: 0xbb}, {value: 0xa869, lo: 0xbc, hi: 0xbc}, {value: 0xa7f9, lo: 0xbd, hi: 0xbd}, {value: 0xa8d9, lo: 0xbe, hi: 0xbf}, // Block 0x88, offset 0x440 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8c}, {value: 0x0008, lo: 0x8d, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xa7}, {value: 0x0008, lo: 0xa8, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbb}, {value: 0x0008, lo: 0xbc, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbe}, {value: 0x0008, lo: 0xbf, hi: 0xbf}, // Block 0x89, offset 0x44a {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0xbf}, // Block 0x8a, offset 0x44f {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbf}, // Block 0x8b, offset 0x452 {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x86}, {value: 0x0018, lo: 0x87, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xbf}, // Block 0x8c, offset 0x458 {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x8e}, {value: 0x0040, lo: 0x8f, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa0}, {value: 0x0040, lo: 0xa1, hi: 0xbf}, // Block 0x8d, offset 0x45f {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbc}, {value: 0x3308, lo: 0xbd, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, // Block 0x8e, offset 0x464 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0x9c}, {value: 0x0040, lo: 0x9d, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x8f, offset 0x468 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x9f}, {value: 0x3308, lo: 0xa0, hi: 0xa0}, {value: 0x0018, lo: 0xa1, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, // Block 0x90, offset 0x46e {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x91, offset 0x473 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0x89}, {value: 0x0018, lo: 0x8a, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbf}, // Block 0x92, offset 0x47c {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0x93, offset 0x481 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0xbf}, // Block 0x94, offset 0x487 {value: 0x0000, lo: 0x06}, {value: 0xe145, lo: 0x80, hi: 0x87}, {value: 0xe1c5, lo: 0x88, hi: 0x8f}, {value: 0xe145, lo: 0x90, hi: 0x97}, {value: 0x8ad5, lo: 0x98, hi: 0x9f}, {value: 0x8aed, lo: 0xa0, hi: 0xa7}, {value: 0x0008, lo: 0xa8, hi: 0xbf}, // Block 0x95, offset 0x48e {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa9}, {value: 0x0040, lo: 0xaa, hi: 0xaf}, {value: 0x8aed, lo: 0xb0, hi: 0xb7}, {value: 0x8ad5, lo: 0xb8, hi: 0xbf}, // Block 0x96, offset 0x495 {value: 0x0000, lo: 0x06}, {value: 0xe145, lo: 0x80, hi: 0x87}, {value: 0xe1c5, lo: 0x88, hi: 0x8f}, {value: 0xe145, lo: 0x90, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, // Block 0x97, offset 0x49c {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0x98, offset 0x4a0 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xae}, {value: 0x0018, lo: 0xaf, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, // Block 0x99, offset 0x4a5 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0x9a, offset 0x4a8 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xbf}, // Block 0x9b, offset 0x4ad {value: 0x0000, lo: 0x0b}, {value: 0x0808, lo: 0x80, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x87}, {value: 0x0808, lo: 0x88, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0808, lo: 0x8a, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb6}, {value: 0x0808, lo: 0xb7, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbb}, {value: 0x0808, lo: 0xbc, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbe}, {value: 0x0808, lo: 0xbf, hi: 0xbf}, // Block 0x9c, offset 0x4b9 {value: 0x0000, lo: 0x05}, {value: 0x0808, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x96}, {value: 0x0818, lo: 0x97, hi: 0x9f}, {value: 0x0808, lo: 0xa0, hi: 0xb6}, {value: 0x0818, lo: 0xb7, hi: 0xbf}, // Block 0x9d, offset 0x4bf {value: 0x0000, lo: 0x04}, {value: 0x0808, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0xa6}, {value: 0x0818, lo: 0xa7, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, // Block 0x9e, offset 0x4c4 {value: 0x0000, lo: 0x06}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0808, lo: 0xa0, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xb3}, {value: 0x0808, lo: 0xb4, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xba}, {value: 0x0818, lo: 0xbb, hi: 0xbf}, // Block 0x9f, offset 0x4cb {value: 0x0000, lo: 0x07}, {value: 0x0808, lo: 0x80, hi: 0x95}, {value: 0x0818, lo: 0x96, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0x9f}, {value: 0x0808, lo: 0xa0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbe}, {value: 0x0818, lo: 0xbf, hi: 0xbf}, // Block 0xa0, offset 0x4d3 {value: 0x0000, lo: 0x04}, {value: 0x0808, lo: 0x80, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbb}, {value: 0x0818, lo: 0xbc, hi: 0xbd}, {value: 0x0808, lo: 0xbe, hi: 0xbf}, // Block 0xa1, offset 0x4d8 {value: 0x0000, lo: 0x03}, {value: 0x0818, lo: 0x80, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x91}, {value: 0x0818, lo: 0x92, hi: 0xbf}, // Block 0xa2, offset 0x4dc {value: 0x0000, lo: 0x0f}, {value: 0x0808, lo: 0x80, hi: 0x80}, {value: 0x3308, lo: 0x81, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x84}, {value: 0x3308, lo: 0x85, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x8b}, {value: 0x3308, lo: 0x8c, hi: 0x8f}, {value: 0x0808, lo: 0x90, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x94}, {value: 0x0808, lo: 0x95, hi: 0x97}, {value: 0x0040, lo: 0x98, hi: 0x98}, {value: 0x0808, lo: 0x99, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xb7}, {value: 0x3308, lo: 0xb8, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0xa3, offset 0x4ec {value: 0x0000, lo: 0x06}, {value: 0x0818, lo: 0x80, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0818, lo: 0x90, hi: 0x98}, {value: 0x0040, lo: 0x99, hi: 0x9f}, {value: 0x0808, lo: 0xa0, hi: 0xbc}, {value: 0x0818, lo: 0xbd, hi: 0xbf}, // Block 0xa4, offset 0x4f3 {value: 0x0000, lo: 0x03}, {value: 0x0808, lo: 0x80, hi: 0x9c}, {value: 0x0818, lo: 0x9d, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, // Block 0xa5, offset 0x4f7 {value: 0x0000, lo: 0x03}, {value: 0x0808, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb8}, {value: 0x0018, lo: 0xb9, hi: 0xbf}, // Block 0xa6, offset 0x4fb {value: 0x0000, lo: 0x06}, {value: 0x0808, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x97}, {value: 0x0818, lo: 0x98, hi: 0x9f}, {value: 0x0808, lo: 0xa0, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xb7}, {value: 0x0818, lo: 0xb8, hi: 0xbf}, // Block 0xa7, offset 0x502 {value: 0x0000, lo: 0x01}, {value: 0x0808, lo: 0x80, hi: 0xbf}, // Block 0xa8, offset 0x504 {value: 0x0000, lo: 0x02}, {value: 0x0808, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0xbf}, // Block 0xa9, offset 0x507 {value: 0x0000, lo: 0x02}, {value: 0x03dd, lo: 0x80, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xbf}, // Block 0xaa, offset 0x50a {value: 0x0000, lo: 0x03}, {value: 0x0808, lo: 0x80, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xb9}, {value: 0x0818, lo: 0xba, hi: 0xbf}, // Block 0xab, offset 0x50e {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0818, lo: 0xa0, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0xac, offset 0x512 {value: 0x0000, lo: 0x05}, {value: 0x3008, lo: 0x80, hi: 0x80}, {value: 0x3308, lo: 0x81, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xb7}, {value: 0x3308, lo: 0xb8, hi: 0xbf}, // Block 0xad, offset 0x518 {value: 0x0000, lo: 0x08}, {value: 0x3308, lo: 0x80, hi: 0x85}, {value: 0x3b08, lo: 0x86, hi: 0x86}, {value: 0x0018, lo: 0x87, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x91}, {value: 0x0018, lo: 0x92, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0xae, offset 0x521 {value: 0x0000, lo: 0x0b}, {value: 0x3308, lo: 0x80, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xaf}, {value: 0x3008, lo: 0xb0, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xb6}, {value: 0x3008, lo: 0xb7, hi: 0xb8}, {value: 0x3b08, lo: 0xb9, hi: 0xb9}, {value: 0x3308, lo: 0xba, hi: 0xba}, {value: 0x0018, lo: 0xbb, hi: 0xbc}, {value: 0x0340, lo: 0xbd, hi: 0xbd}, {value: 0x0018, lo: 0xbe, hi: 0xbf}, // Block 0xaf, offset 0x52d {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x81}, {value: 0x0040, lo: 0x82, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xa8}, {value: 0x0040, lo: 0xa9, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0xb0, offset 0x534 {value: 0x0000, lo: 0x08}, {value: 0x3308, lo: 0x80, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xa6}, {value: 0x3308, lo: 0xa7, hi: 0xab}, {value: 0x3008, lo: 0xac, hi: 0xac}, {value: 0x3308, lo: 0xad, hi: 0xb2}, {value: 0x3b08, lo: 0xb3, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xb5}, {value: 0x0008, lo: 0xb6, hi: 0xbf}, // Block 0xb1, offset 0x53d {value: 0x0000, lo: 0x07}, {value: 0x0018, lo: 0x80, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xb5}, {value: 0x0008, lo: 0xb6, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0xb2, offset 0x545 {value: 0x0000, lo: 0x06}, {value: 0x3308, lo: 0x80, hi: 0x81}, {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xb2}, {value: 0x3008, lo: 0xb3, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xbe}, {value: 0x3008, lo: 0xbf, hi: 0xbf}, // Block 0xb3, offset 0x54c {value: 0x0000, lo: 0x0d}, {value: 0x3808, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0x84}, {value: 0x0018, lo: 0x85, hi: 0x89}, {value: 0x3308, lo: 0x8a, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9b}, {value: 0x0008, lo: 0x9c, hi: 0x9c}, {value: 0x0018, lo: 0x9d, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xa0}, {value: 0x0018, lo: 0xa1, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0xb4, offset 0x55a {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x91}, {value: 0x0040, lo: 0x92, hi: 0x92}, {value: 0x0008, lo: 0x93, hi: 0xab}, {value: 0x3008, lo: 0xac, hi: 0xae}, {value: 0x3308, lo: 0xaf, hi: 0xb1}, {value: 0x3008, lo: 0xb2, hi: 0xb3}, {value: 0x3308, lo: 0xb4, hi: 0xb4}, {value: 0x3808, lo: 0xb5, hi: 0xb5}, {value: 0x3308, lo: 0xb6, hi: 0xb7}, {value: 0x0018, lo: 0xb8, hi: 0xbd}, {value: 0x3308, lo: 0xbe, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0xb5, offset 0x567 {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0008, lo: 0x8a, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8e}, {value: 0x0008, lo: 0x8f, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9e}, {value: 0x0008, lo: 0x9f, hi: 0xa8}, {value: 0x0018, lo: 0xa9, hi: 0xa9}, {value: 0x0040, lo: 0xaa, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, // Block 0xb6, offset 0x574 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0x9e}, {value: 0x3308, lo: 0x9f, hi: 0x9f}, {value: 0x3008, lo: 0xa0, hi: 0xa2}, {value: 0x3308, lo: 0xa3, hi: 0xa9}, {value: 0x3b08, lo: 0xaa, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, // Block 0xb7, offset 0x57d {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xb4}, {value: 0x3008, lo: 0xb5, hi: 0xb7}, {value: 0x3308, lo: 0xb8, hi: 0xbf}, // Block 0xb8, offset 0x581 {value: 0x0000, lo: 0x0d}, {value: 0x3008, lo: 0x80, hi: 0x81}, {value: 0x3b08, lo: 0x82, hi: 0x82}, {value: 0x3308, lo: 0x83, hi: 0x84}, {value: 0x3008, lo: 0x85, hi: 0x85}, {value: 0x3308, lo: 0x86, hi: 0x86}, {value: 0x0008, lo: 0x87, hi: 0x8a}, {value: 0x0018, lo: 0x8b, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0x9c}, {value: 0x0018, lo: 0x9d, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0xbf}, // Block 0xb9, offset 0x58f {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x3008, lo: 0xb0, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xb8}, {value: 0x3008, lo: 0xb9, hi: 0xb9}, {value: 0x3308, lo: 0xba, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbe}, {value: 0x3308, lo: 0xbf, hi: 0xbf}, // Block 0xba, offset 0x597 {value: 0x0000, lo: 0x0a}, {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x3008, lo: 0x81, hi: 0x81}, {value: 0x3b08, lo: 0x82, hi: 0x82}, {value: 0x3308, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x85}, {value: 0x0018, lo: 0x86, hi: 0x86}, {value: 0x0008, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0xbf}, // Block 0xbb, offset 0x5a2 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0xae}, {value: 0x3008, lo: 0xaf, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb7}, {value: 0x3008, lo: 0xb8, hi: 0xbb}, {value: 0x3308, lo: 0xbc, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0xbc, offset 0x5ab {value: 0x0000, lo: 0x05}, {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0x9b}, {value: 0x3308, lo: 0x9c, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0xbf}, // Block 0xbd, offset 0x5b1 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x3008, lo: 0xb0, hi: 0xb2}, {value: 0x3308, lo: 0xb3, hi: 0xba}, {value: 0x3008, lo: 0xbb, hi: 0xbc}, {value: 0x3308, lo: 0xbd, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0xbe, offset 0x5b9 {value: 0x0000, lo: 0x08}, {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xbf}, // Block 0xbf, offset 0x5c2 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0xaa}, {value: 0x3308, lo: 0xab, hi: 0xab}, {value: 0x3008, lo: 0xac, hi: 0xac}, {value: 0x3308, lo: 0xad, hi: 0xad}, {value: 0x3008, lo: 0xae, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb5}, {value: 0x3808, lo: 0xb6, hi: 0xb6}, {value: 0x3308, lo: 0xb7, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbf}, // Block 0xc0, offset 0x5cc {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0xbf}, // Block 0xc1, offset 0x5cf {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9c}, {value: 0x3308, lo: 0x9d, hi: 0x9f}, {value: 0x3008, lo: 0xa0, hi: 0xa1}, {value: 0x3308, lo: 0xa2, hi: 0xa5}, {value: 0x3008, lo: 0xa6, hi: 0xa6}, {value: 0x3308, lo: 0xa7, hi: 0xaa}, {value: 0x3b08, lo: 0xab, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0018, lo: 0xba, hi: 0xbf}, // Block 0xc2, offset 0x5db {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x049d, lo: 0xa0, hi: 0xbf}, // Block 0xc3, offset 0x5de {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xa9}, {value: 0x0018, lo: 0xaa, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xbe}, {value: 0x0008, lo: 0xbf, hi: 0xbf}, // Block 0xc4, offset 0x5e3 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbf}, // Block 0xc5, offset 0x5e6 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0008, lo: 0x8a, hi: 0xae}, {value: 0x3008, lo: 0xaf, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xb7}, {value: 0x3308, lo: 0xb8, hi: 0xbd}, {value: 0x3008, lo: 0xbe, hi: 0xbe}, {value: 0x3b08, lo: 0xbf, hi: 0xbf}, // Block 0xc6, offset 0x5f0 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xbf}, // Block 0xc7, offset 0x5f9 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x91}, {value: 0x3308, lo: 0x92, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xa8}, {value: 0x3008, lo: 0xa9, hi: 0xa9}, {value: 0x3308, lo: 0xaa, hi: 0xb0}, {value: 0x3008, lo: 0xb1, hi: 0xb1}, {value: 0x3308, lo: 0xb2, hi: 0xb3}, {value: 0x3008, lo: 0xb4, hi: 0xb4}, {value: 0x3308, lo: 0xb5, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0xc8, offset 0x605 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0xbf}, // Block 0xc9, offset 0x608 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0xca, offset 0x60d {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0xbf}, // Block 0xcb, offset 0x610 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xbf}, // Block 0xcc, offset 0x613 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0xbf}, // Block 0xcd, offset 0x616 {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa9}, {value: 0x0040, lo: 0xaa, hi: 0xad}, {value: 0x0018, lo: 0xae, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, // Block 0xce, offset 0x61d {value: 0x0000, lo: 0x06}, {value: 0x0040, lo: 0x80, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb4}, {value: 0x0018, lo: 0xb5, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, // Block 0xcf, offset 0x624 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xaf}, {value: 0x3308, lo: 0xb0, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xbf}, // Block 0xd0, offset 0x628 {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x83}, {value: 0x0018, lo: 0x84, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0xa1}, {value: 0x0040, lo: 0xa2, hi: 0xa2}, {value: 0x0008, lo: 0xa3, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbf}, // Block 0xd1, offset 0x633 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0xbf}, // Block 0xd2, offset 0x636 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x90}, {value: 0x3008, lo: 0x91, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0xd3, offset 0x63c {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x8e}, {value: 0x3308, lo: 0x8f, hi: 0x92}, {value: 0x0008, lo: 0x93, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, // Block 0xd4, offset 0x641 {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa0}, {value: 0x0040, lo: 0xa1, hi: 0xbf}, // Block 0xd5, offset 0x645 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xbf}, // Block 0xd6, offset 0x648 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xbf}, // Block 0xd7, offset 0x64b {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x81}, {value: 0x0040, lo: 0x82, hi: 0xbf}, // Block 0xd8, offset 0x64e {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, // Block 0xd9, offset 0x653 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9b}, {value: 0x0018, lo: 0x9c, hi: 0x9c}, {value: 0x3308, lo: 0x9d, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0x9f}, {value: 0x03c0, lo: 0xa0, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xbf}, // Block 0xda, offset 0x65d {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, // Block 0xdb, offset 0x660 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xa8}, {value: 0x0018, lo: 0xa9, hi: 0xbf}, // Block 0xdc, offset 0x664 {value: 0x0000, lo: 0x0e}, {value: 0x0018, lo: 0x80, hi: 0x9d}, {value: 0xb5b9, lo: 0x9e, hi: 0x9e}, {value: 0xb601, lo: 0x9f, hi: 0x9f}, {value: 0xb649, lo: 0xa0, hi: 0xa0}, {value: 0xb6b1, lo: 0xa1, hi: 0xa1}, {value: 0xb719, lo: 0xa2, hi: 0xa2}, {value: 0xb781, lo: 0xa3, hi: 0xa3}, {value: 0xb7e9, lo: 0xa4, hi: 0xa4}, {value: 0x3018, lo: 0xa5, hi: 0xa6}, {value: 0x3318, lo: 0xa7, hi: 0xa9}, {value: 0x0018, lo: 0xaa, hi: 0xac}, {value: 0x3018, lo: 0xad, hi: 0xb2}, {value: 0x0340, lo: 0xb3, hi: 0xba}, {value: 0x3318, lo: 0xbb, hi: 0xbf}, // Block 0xdd, offset 0x673 {value: 0x0000, lo: 0x0b}, {value: 0x3318, lo: 0x80, hi: 0x82}, {value: 0x0018, lo: 0x83, hi: 0x84}, {value: 0x3318, lo: 0x85, hi: 0x8b}, {value: 0x0018, lo: 0x8c, hi: 0xa9}, {value: 0x3318, lo: 0xaa, hi: 0xad}, {value: 0x0018, lo: 0xae, hi: 0xba}, {value: 0xb851, lo: 0xbb, hi: 0xbb}, {value: 0xb899, lo: 0xbc, hi: 0xbc}, {value: 0xb8e1, lo: 0xbd, hi: 0xbd}, {value: 0xb949, lo: 0xbe, hi: 0xbe}, {value: 0xb9b1, lo: 0xbf, hi: 0xbf}, // Block 0xde, offset 0x67f {value: 0x0000, lo: 0x03}, {value: 0xba19, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0xa8}, {value: 0x0040, lo: 0xa9, hi: 0xbf}, // Block 0xdf, offset 0x683 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x81}, {value: 0x3318, lo: 0x82, hi: 0x84}, {value: 0x0018, lo: 0x85, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0xbf}, // Block 0xe0, offset 0x688 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xb1}, {value: 0x0040, lo: 0xb2, hi: 0xbf}, // Block 0xe1, offset 0x68d {value: 0x0000, lo: 0x03}, {value: 0x3308, lo: 0x80, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xba}, {value: 0x3308, lo: 0xbb, hi: 0xbf}, // Block 0xe2, offset 0x691 {value: 0x0000, lo: 0x04}, {value: 0x3308, lo: 0x80, hi: 0xac}, {value: 0x0018, lo: 0xad, hi: 0xb4}, {value: 0x3308, lo: 0xb5, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xbf}, // Block 0xe3, offset 0x696 {value: 0x0000, lo: 0x08}, {value: 0x0018, lo: 0x80, hi: 0x83}, {value: 0x3308, lo: 0x84, hi: 0x84}, {value: 0x0018, lo: 0x85, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x9a}, {value: 0x3308, lo: 0x9b, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xa0}, {value: 0x3308, lo: 0xa1, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, // Block 0xe4, offset 0x69f {value: 0x0000, lo: 0x0a}, {value: 0x3308, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, {value: 0x3308, lo: 0x88, hi: 0x98}, {value: 0x0040, lo: 0x99, hi: 0x9a}, {value: 0x3308, lo: 0x9b, hi: 0xa1}, {value: 0x0040, lo: 0xa2, hi: 0xa2}, {value: 0x3308, lo: 0xa3, hi: 0xa4}, {value: 0x0040, lo: 0xa5, hi: 0xa5}, {value: 0x3308, lo: 0xa6, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xbf}, // Block 0xe5, offset 0x6aa {value: 0x0000, lo: 0x05}, {value: 0x0808, lo: 0x80, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x86}, {value: 0x0818, lo: 0x87, hi: 0x8f}, {value: 0x3308, lo: 0x90, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0xbf}, // Block 0xe6, offset 0x6b0 {value: 0x0000, lo: 0x07}, {value: 0x0a08, lo: 0x80, hi: 0x83}, {value: 0x3308, lo: 0x84, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8f}, {value: 0x0808, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9d}, {value: 0x0818, lo: 0x9e, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, // Block 0xe7, offset 0x6b8 {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb1}, {value: 0x0040, lo: 0xb2, hi: 0xbf}, // Block 0xe8, offset 0x6bc {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, // Block 0xe9, offset 0x6c0 {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xb0}, {value: 0x0018, lo: 0xb1, hi: 0xbf}, // Block 0xea, offset 0x6c6 {value: 0x0000, lo: 0x05}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x90}, {value: 0x0018, lo: 0x91, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, // Block 0xeb, offset 0x6cc {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x8f}, {value: 0xc1c1, lo: 0x90, hi: 0x90}, {value: 0x0018, lo: 0x91, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xbf}, // Block 0xec, offset 0x6d1 {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0xa5}, {value: 0x0018, lo: 0xa6, hi: 0xbf}, // Block 0xed, offset 0x6d4 {value: 0x0000, lo: 0x0d}, {value: 0xc7e9, lo: 0x80, hi: 0x80}, {value: 0xc839, lo: 0x81, hi: 0x81}, {value: 0xc889, lo: 0x82, hi: 0x82}, {value: 0xc8d9, lo: 0x83, hi: 0x83}, {value: 0xc929, lo: 0x84, hi: 0x84}, {value: 0xc979, lo: 0x85, hi: 0x85}, {value: 0xc9c9, lo: 0x86, hi: 0x86}, {value: 0xca19, lo: 0x87, hi: 0x87}, {value: 0xca69, lo: 0x88, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x8f}, {value: 0xcab9, lo: 0x90, hi: 0x90}, {value: 0xcad9, lo: 0x91, hi: 0x91}, {value: 0x0040, lo: 0x92, hi: 0xbf}, // Block 0xee, offset 0x6e2 {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x92}, {value: 0x0040, lo: 0x93, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, // Block 0xef, offset 0x6e9 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbf}, // Block 0xf0, offset 0x6ec {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0x94}, {value: 0x0040, lo: 0x95, hi: 0xbf}, // Block 0xf1, offset 0x6ef {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbf}, // Block 0xf2, offset 0x6f3 {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xbf}, // Block 0xf3, offset 0x6f9 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xbf}, // Block 0xf4, offset 0x6fe {value: 0x0000, lo: 0x09}, {value: 0x0040, lo: 0x80, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xb2}, {value: 0x0018, lo: 0xb3, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, // Block 0xf5, offset 0x708 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0xbf}, // Block 0xf6, offset 0x70d {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0x91}, {value: 0x0040, lo: 0x92, hi: 0xbf}, // Block 0xf7, offset 0x710 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0x80}, {value: 0x0040, lo: 0x81, hi: 0xbf}, // Block 0xf8, offset 0x713 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0xbf}, // Block 0xf9, offset 0x716 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0xfa, offset 0x719 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, // Block 0xfb, offset 0x71d {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xa1}, {value: 0x0040, lo: 0xa2, hi: 0xbf}, // Block 0xfc, offset 0x720 {value: 0x0020, lo: 0x0f}, {value: 0xdeb9, lo: 0x80, hi: 0x89}, {value: 0x8dfd, lo: 0x8a, hi: 0x8a}, {value: 0xdff9, lo: 0x8b, hi: 0x9c}, {value: 0x8e1d, lo: 0x9d, hi: 0x9d}, {value: 0xe239, lo: 0x9e, hi: 0xa2}, {value: 0x8e3d, lo: 0xa3, hi: 0xa3}, {value: 0xe2d9, lo: 0xa4, hi: 0xab}, {value: 0x7ed5, lo: 0xac, hi: 0xac}, {value: 0xe3d9, lo: 0xad, hi: 0xaf}, {value: 0x8e5d, lo: 0xb0, hi: 0xb0}, {value: 0xe439, lo: 0xb1, hi: 0xb6}, {value: 0x8e7d, lo: 0xb7, hi: 0xb9}, {value: 0xe4f9, lo: 0xba, hi: 0xba}, {value: 0x8edd, lo: 0xbb, hi: 0xbb}, {value: 0xe519, lo: 0xbc, hi: 0xbf}, // Block 0xfd, offset 0x730 {value: 0x0020, lo: 0x10}, {value: 0x937d, lo: 0x80, hi: 0x80}, {value: 0xf099, lo: 0x81, hi: 0x86}, {value: 0x939d, lo: 0x87, hi: 0x8a}, {value: 0xd9f9, lo: 0x8b, hi: 0x8b}, {value: 0xf159, lo: 0x8c, hi: 0x96}, {value: 0x941d, lo: 0x97, hi: 0x97}, {value: 0xf2b9, lo: 0x98, hi: 0xa3}, {value: 0x943d, lo: 0xa4, hi: 0xa6}, {value: 0xf439, lo: 0xa7, hi: 0xaa}, {value: 0x949d, lo: 0xab, hi: 0xab}, {value: 0xf4b9, lo: 0xac, hi: 0xac}, {value: 0x94bd, lo: 0xad, hi: 0xad}, {value: 0xf4d9, lo: 0xae, hi: 0xaf}, {value: 0x94dd, lo: 0xb0, hi: 0xb1}, {value: 0xf519, lo: 0xb2, hi: 0xbe}, {value: 0x2040, lo: 0xbf, hi: 0xbf}, // Block 0xfe, offset 0x741 {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0340, lo: 0x81, hi: 0x81}, {value: 0x0040, lo: 0x82, hi: 0x9f}, {value: 0x0340, lo: 0xa0, hi: 0xbf}, // Block 0xff, offset 0x746 {value: 0x0000, lo: 0x01}, {value: 0x0340, lo: 0x80, hi: 0xbf}, // Block 0x100, offset 0x748 {value: 0x0000, lo: 0x01}, {value: 0x33c0, lo: 0x80, hi: 0xbf}, // Block 0x101, offset 0x74a {value: 0x0000, lo: 0x02}, {value: 0x33c0, lo: 0x80, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, } // Total table size 41662 bytes (40KiB); checksum: 355A58A4 ================================================ FILE: vendor/golang.org/x/net/idna/trie.go ================================================ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // 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 idna // appendMapping appends the mapping for the respective rune. isMapped must be // true. A mapping is a categorization of a rune as defined in UTS #46. func (c info) appendMapping(b []byte, s string) []byte { index := int(c >> indexShift) if c&xorBit == 0 { s := mappings[index:] return append(b, s[1:s[0]+1]...) } b = append(b, s...) if c&inlineXOR == inlineXOR { // TODO: support and handle two-byte inline masks b[len(b)-1] ^= byte(index) } else { for p := len(b) - int(xorData[index]); p < len(b); p++ { index++ b[p] ^= xorData[index] } } return b } // Sparse block handling code. type valueRange struct { value uint16 // header: value:stride lo, hi byte // header: lo:n } type sparseBlocks struct { values []valueRange offset []uint16 } var idnaSparse = sparseBlocks{ values: idnaSparseValues[:], offset: idnaSparseOffset[:], } // Don't use newIdnaTrie to avoid unconditional linking in of the table. var trie = &idnaTrie{} // lookup determines the type of block n and looks up the value for b. // For n < t.cutoff, the block is a simple lookup table. Otherwise, the block // is a list of ranges with an accompanying value. Given a matching range r, // the value for b is by r.value + (b - r.lo) * stride. func (t *sparseBlocks) lookup(n uint32, b byte) uint16 { offset := t.offset[n] header := t.values[offset] lo := offset + 1 hi := lo + uint16(header.lo) for lo < hi { m := lo + (hi-lo)/2 r := t.values[m] if r.lo <= b && b <= r.hi { return r.value + uint16(b-r.lo)*header.value } if b < r.lo { hi = m } else { lo = m + 1 } } return 0 } ================================================ FILE: vendor/golang.org/x/net/idna/trieval.go ================================================ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. package idna // This file contains definitions for interpreting the trie value of the idna // trie generated by "go run gen*.go". It is shared by both the generator // program and the resultant package. Sharing is achieved by the generator // copying gen_trieval.go to trieval.go and changing what's above this comment. // info holds information from the IDNA mapping table for a single rune. It is // the value returned by a trie lookup. In most cases, all information fits in // a 16-bit value. For mappings, this value may contain an index into a slice // with the mapped string. Such mappings can consist of the actual mapped value // or an XOR pattern to be applied to the bytes of the UTF8 encoding of the // input rune. This technique is used by the cases packages and reduces the // table size significantly. // // The per-rune values have the following format: // // if mapped { // if inlinedXOR { // 15..13 inline XOR marker // 12..11 unused // 10..3 inline XOR mask // } else { // 15..3 index into xor or mapping table // } // } else { // 15..14 unused // 13 mayNeedNorm // 12..11 attributes // 10..8 joining type // 7..3 category type // } // 2 use xor pattern // 1..0 mapped category // // See the definitions below for a more detailed description of the various // bits. type info uint16 const ( catSmallMask = 0x3 catBigMask = 0xF8 indexShift = 3 xorBit = 0x4 // interpret the index as an xor pattern inlineXOR = 0xE000 // These bits are set if the XOR pattern is inlined. joinShift = 8 joinMask = 0x07 // Attributes attributesMask = 0x1800 viramaModifier = 0x1800 modifier = 0x1000 rtl = 0x0800 mayNeedNorm = 0x2000 ) // A category corresponds to a category defined in the IDNA mapping table. type category uint16 const ( unknown category = 0 // not currently defined in unicode. mapped category = 1 disallowedSTD3Mapped category = 2 deviation category = 3 ) const ( valid category = 0x08 validNV8 category = 0x18 validXV8 category = 0x28 disallowed category = 0x40 disallowedSTD3Valid category = 0x80 ignored category = 0xC0 ) // join types and additional rune information const ( joiningL = (iota + 1) joiningD joiningT joiningR //the following types are derived during processing joinZWJ joinZWNJ joinVirama numJoinTypes ) func (c info) isMapped() bool { return c&0x3 != 0 } func (c info) category() category { small := c & catSmallMask if small != 0 { return category(small) } return category(c & catBigMask) } func (c info) joinType() info { if c.isMapped() { return 0 } return (c >> joinShift) & joinMask } func (c info) isModifier() bool { return c&(modifier|catSmallMask) == modifier } func (c info) isViramaModifier() bool { return c&(attributesMask|catSmallMask) == viramaModifier } ================================================ FILE: vendor/golang.org/x/net/webdav/file.go ================================================ // 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 webdav import ( "context" "encoding/xml" "io" "net/http" "os" "path" "path/filepath" "strings" "sync" "time" ) // slashClean is equivalent to but slightly more efficient than // path.Clean("/" + name). func slashClean(name string) string { if name == "" || name[0] != '/' { name = "/" + name } return path.Clean(name) } // A FileSystem implements access to a collection of named files. The elements // in a file path are separated by slash ('/', U+002F) characters, regardless // of host operating system convention. // // Each method has the same semantics as the os package's function of the same // name. // // Note that the os.Rename documentation says that "OS-specific restrictions // might apply". In particular, whether or not renaming a file or directory // overwriting another existing file or directory is an error is OS-dependent. type FileSystem interface { Mkdir(ctx context.Context, name string, perm os.FileMode) error OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (File, error) RemoveAll(ctx context.Context, name string) error Rename(ctx context.Context, oldName, newName string) error Stat(ctx context.Context, name string) (os.FileInfo, error) } // A File is returned by a FileSystem's OpenFile method and can be served by a // Handler. // // A File may optionally implement the DeadPropsHolder interface, if it can // load and save dead properties. type File interface { http.File io.Writer } // A Dir implements FileSystem using the native file system restricted to a // specific directory tree. // // While the FileSystem.OpenFile method takes '/'-separated paths, a Dir's // string value is a filename on the native file system, not a URL, so it is // separated by filepath.Separator, which isn't necessarily '/'. // // An empty Dir is treated as ".". type Dir string func (d Dir) resolve(name string) string { // This implementation is based on Dir.Open's code in the standard net/http package. if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 || strings.Contains(name, "\x00") { return "" } dir := string(d) if dir == "" { dir = "." } return filepath.Join(dir, filepath.FromSlash(slashClean(name))) } func (d Dir) Mkdir(ctx context.Context, name string, perm os.FileMode) error { if name = d.resolve(name); name == "" { return os.ErrNotExist } return os.Mkdir(name, perm) } func (d Dir) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (File, error) { if name = d.resolve(name); name == "" { return nil, os.ErrNotExist } f, err := os.OpenFile(name, flag, perm) if err != nil { return nil, err } return f, nil } func (d Dir) RemoveAll(ctx context.Context, name string) error { if name = d.resolve(name); name == "" { return os.ErrNotExist } if name == filepath.Clean(string(d)) { // Prohibit removing the virtual root directory. return os.ErrInvalid } return os.RemoveAll(name) } func (d Dir) Rename(ctx context.Context, oldName, newName string) error { if oldName = d.resolve(oldName); oldName == "" { return os.ErrNotExist } if newName = d.resolve(newName); newName == "" { return os.ErrNotExist } if root := filepath.Clean(string(d)); root == oldName || root == newName { // Prohibit renaming from or to the virtual root directory. return os.ErrInvalid } return os.Rename(oldName, newName) } func (d Dir) Stat(ctx context.Context, name string) (os.FileInfo, error) { if name = d.resolve(name); name == "" { return nil, os.ErrNotExist } return os.Stat(name) } // NewMemFS returns a new in-memory FileSystem implementation. func NewMemFS() FileSystem { return &memFS{ root: memFSNode{ children: make(map[string]*memFSNode), mode: 0660 | os.ModeDir, modTime: time.Now(), }, } } // A memFS implements FileSystem, storing all metadata and actual file data // in-memory. No limits on filesystem size are used, so it is not recommended // this be used where the clients are untrusted. // // Concurrent access is permitted. The tree structure is protected by a mutex, // and each node's contents and metadata are protected by a per-node mutex. // // TODO: Enforce file permissions. type memFS struct { mu sync.Mutex root memFSNode } // TODO: clean up and rationalize the walk/find code. // walk walks the directory tree for the fullname, calling f at each step. If f // returns an error, the walk will be aborted and return that same error. // // dir is the directory at that step, frag is the name fragment, and final is // whether it is the final step. For example, walking "/foo/bar/x" will result // in 3 calls to f: // - "/", "foo", false // - "/foo/", "bar", false // - "/foo/bar/", "x", true // The frag argument will be empty only if dir is the root node and the walk // ends at that root node. func (fs *memFS) walk(op, fullname string, f func(dir *memFSNode, frag string, final bool) error) error { original := fullname fullname = slashClean(fullname) // Strip any leading "/"s to make fullname a relative path, as the walk // starts at fs.root. if fullname[0] == '/' { fullname = fullname[1:] } dir := &fs.root for { frag, remaining := fullname, "" i := strings.IndexRune(fullname, '/') final := i < 0 if !final { frag, remaining = fullname[:i], fullname[i+1:] } if frag == "" && dir != &fs.root { panic("webdav: empty path fragment for a clean path") } if err := f(dir, frag, final); err != nil { return &os.PathError{ Op: op, Path: original, Err: err, } } if final { break } child := dir.children[frag] if child == nil { return &os.PathError{ Op: op, Path: original, Err: os.ErrNotExist, } } if !child.mode.IsDir() { return &os.PathError{ Op: op, Path: original, Err: os.ErrInvalid, } } dir, fullname = child, remaining } return nil } // find returns the parent of the named node and the relative name fragment // from the parent to the child. For example, if finding "/foo/bar/baz" then // parent will be the node for "/foo/bar" and frag will be "baz". // // If the fullname names the root node, then parent, frag and err will be zero. // // find returns an error if the parent does not already exist or the parent // isn't a directory, but it will not return an error per se if the child does // not already exist. The error returned is either nil or an *os.PathError // whose Op is op. func (fs *memFS) find(op, fullname string) (parent *memFSNode, frag string, err error) { err = fs.walk(op, fullname, func(parent0 *memFSNode, frag0 string, final bool) error { if !final { return nil } if frag0 != "" { parent, frag = parent0, frag0 } return nil }) return parent, frag, err } func (fs *memFS) Mkdir(ctx context.Context, name string, perm os.FileMode) error { fs.mu.Lock() defer fs.mu.Unlock() dir, frag, err := fs.find("mkdir", name) if err != nil { return err } if dir == nil { // We can't create the root. return os.ErrInvalid } if _, ok := dir.children[frag]; ok { return os.ErrExist } dir.children[frag] = &memFSNode{ children: make(map[string]*memFSNode), mode: perm.Perm() | os.ModeDir, modTime: time.Now(), } return nil } func (fs *memFS) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (File, error) { fs.mu.Lock() defer fs.mu.Unlock() dir, frag, err := fs.find("open", name) if err != nil { return nil, err } var n *memFSNode if dir == nil { // We're opening the root. if flag&(os.O_WRONLY|os.O_RDWR) != 0 { return nil, os.ErrPermission } n, frag = &fs.root, "/" } else { n = dir.children[frag] if flag&(os.O_SYNC|os.O_APPEND) != 0 { // memFile doesn't support these flags yet. return nil, os.ErrInvalid } if flag&os.O_CREATE != 0 { if flag&os.O_EXCL != 0 && n != nil { return nil, os.ErrExist } if n == nil { n = &memFSNode{ mode: perm.Perm(), } dir.children[frag] = n } } if n == nil { return nil, os.ErrNotExist } if flag&(os.O_WRONLY|os.O_RDWR) != 0 && flag&os.O_TRUNC != 0 { n.mu.Lock() n.data = nil n.mu.Unlock() } } children := make([]os.FileInfo, 0, len(n.children)) for cName, c := range n.children { children = append(children, c.stat(cName)) } return &memFile{ n: n, nameSnapshot: frag, childrenSnapshot: children, }, nil } func (fs *memFS) RemoveAll(ctx context.Context, name string) error { fs.mu.Lock() defer fs.mu.Unlock() dir, frag, err := fs.find("remove", name) if err != nil { return err } if dir == nil { // We can't remove the root. return os.ErrInvalid } delete(dir.children, frag) return nil } func (fs *memFS) Rename(ctx context.Context, oldName, newName string) error { fs.mu.Lock() defer fs.mu.Unlock() oldName = slashClean(oldName) newName = slashClean(newName) if oldName == newName { return nil } if strings.HasPrefix(newName, oldName+"/") { // We can't rename oldName to be a sub-directory of itself. return os.ErrInvalid } oDir, oFrag, err := fs.find("rename", oldName) if err != nil { return err } if oDir == nil { // We can't rename from the root. return os.ErrInvalid } nDir, nFrag, err := fs.find("rename", newName) if err != nil { return err } if nDir == nil { // We can't rename to the root. return os.ErrInvalid } oNode, ok := oDir.children[oFrag] if !ok { return os.ErrNotExist } if oNode.children != nil { if nNode, ok := nDir.children[nFrag]; ok { if nNode.children == nil { return errNotADirectory } if len(nNode.children) != 0 { return errDirectoryNotEmpty } } } delete(oDir.children, oFrag) nDir.children[nFrag] = oNode return nil } func (fs *memFS) Stat(ctx context.Context, name string) (os.FileInfo, error) { fs.mu.Lock() defer fs.mu.Unlock() dir, frag, err := fs.find("stat", name) if err != nil { return nil, err } if dir == nil { // We're stat'ting the root. return fs.root.stat("/"), nil } if n, ok := dir.children[frag]; ok { return n.stat(path.Base(name)), nil } return nil, os.ErrNotExist } // A memFSNode represents a single entry in the in-memory filesystem and also // implements os.FileInfo. type memFSNode struct { // children is protected by memFS.mu. children map[string]*memFSNode mu sync.Mutex data []byte mode os.FileMode modTime time.Time deadProps map[xml.Name]Property } func (n *memFSNode) stat(name string) *memFileInfo { n.mu.Lock() defer n.mu.Unlock() return &memFileInfo{ name: name, size: int64(len(n.data)), mode: n.mode, modTime: n.modTime, } } func (n *memFSNode) DeadProps() (map[xml.Name]Property, error) { n.mu.Lock() defer n.mu.Unlock() if len(n.deadProps) == 0 { return nil, nil } ret := make(map[xml.Name]Property, len(n.deadProps)) for k, v := range n.deadProps { ret[k] = v } return ret, nil } func (n *memFSNode) Patch(patches []Proppatch) ([]Propstat, error) { n.mu.Lock() defer n.mu.Unlock() pstat := Propstat{Status: http.StatusOK} for _, patch := range patches { for _, p := range patch.Props { pstat.Props = append(pstat.Props, Property{XMLName: p.XMLName}) if patch.Remove { delete(n.deadProps, p.XMLName) continue } if n.deadProps == nil { n.deadProps = map[xml.Name]Property{} } n.deadProps[p.XMLName] = p } } return []Propstat{pstat}, nil } type memFileInfo struct { name string size int64 mode os.FileMode modTime time.Time } func (f *memFileInfo) Name() string { return f.name } func (f *memFileInfo) Size() int64 { return f.size } func (f *memFileInfo) Mode() os.FileMode { return f.mode } func (f *memFileInfo) ModTime() time.Time { return f.modTime } func (f *memFileInfo) IsDir() bool { return f.mode.IsDir() } func (f *memFileInfo) Sys() interface{} { return nil } // A memFile is a File implementation for a memFSNode. It is a per-file (not // per-node) read/write position, and a snapshot of the memFS' tree structure // (a node's name and children) for that node. type memFile struct { n *memFSNode nameSnapshot string childrenSnapshot []os.FileInfo // pos is protected by n.mu. pos int } // A *memFile implements the optional DeadPropsHolder interface. var _ DeadPropsHolder = (*memFile)(nil) func (f *memFile) DeadProps() (map[xml.Name]Property, error) { return f.n.DeadProps() } func (f *memFile) Patch(patches []Proppatch) ([]Propstat, error) { return f.n.Patch(patches) } func (f *memFile) Close() error { return nil } func (f *memFile) Read(p []byte) (int, error) { f.n.mu.Lock() defer f.n.mu.Unlock() if f.n.mode.IsDir() { return 0, os.ErrInvalid } if f.pos >= len(f.n.data) { return 0, io.EOF } n := copy(p, f.n.data[f.pos:]) f.pos += n return n, nil } func (f *memFile) Readdir(count int) ([]os.FileInfo, error) { f.n.mu.Lock() defer f.n.mu.Unlock() if !f.n.mode.IsDir() { return nil, os.ErrInvalid } old := f.pos if old >= len(f.childrenSnapshot) { // The os.File Readdir docs say that at the end of a directory, // the error is io.EOF if count > 0 and nil if count <= 0. if count > 0 { return nil, io.EOF } return nil, nil } if count > 0 { f.pos += count if f.pos > len(f.childrenSnapshot) { f.pos = len(f.childrenSnapshot) } } else { f.pos = len(f.childrenSnapshot) old = 0 } return f.childrenSnapshot[old:f.pos], nil } func (f *memFile) Seek(offset int64, whence int) (int64, error) { f.n.mu.Lock() defer f.n.mu.Unlock() npos := f.pos // TODO: How to handle offsets greater than the size of system int? switch whence { case os.SEEK_SET: npos = int(offset) case os.SEEK_CUR: npos += int(offset) case os.SEEK_END: npos = len(f.n.data) + int(offset) default: npos = -1 } if npos < 0 { return 0, os.ErrInvalid } f.pos = npos return int64(f.pos), nil } func (f *memFile) Stat() (os.FileInfo, error) { return f.n.stat(f.nameSnapshot), nil } func (f *memFile) Write(p []byte) (int, error) { lenp := len(p) f.n.mu.Lock() defer f.n.mu.Unlock() if f.n.mode.IsDir() { return 0, os.ErrInvalid } if f.pos < len(f.n.data) { n := copy(f.n.data[f.pos:], p) f.pos += n p = p[n:] } else if f.pos > len(f.n.data) { // Write permits the creation of holes, if we've seek'ed past the // existing end of file. if f.pos <= cap(f.n.data) { oldLen := len(f.n.data) f.n.data = f.n.data[:f.pos] hole := f.n.data[oldLen:] for i := range hole { hole[i] = 0 } } else { d := make([]byte, f.pos, f.pos+len(p)) copy(d, f.n.data) f.n.data = d } } if len(p) > 0 { // We should only get here if f.pos == len(f.n.data). f.n.data = append(f.n.data, p...) f.pos = len(f.n.data) } f.n.modTime = time.Now() return lenp, nil } // moveFiles moves files and/or directories from src to dst. // // See section 9.9.4 for when various HTTP status codes apply. func moveFiles(ctx context.Context, fs FileSystem, src, dst string, overwrite bool) (status int, err error) { created := false if _, err := fs.Stat(ctx, dst); err != nil { if !os.IsNotExist(err) { return http.StatusForbidden, err } created = true } else if overwrite { // Section 9.9.3 says that "If a resource exists at the destination // and the Overwrite header is "T", then prior to performing the move, // the server must perform a DELETE with "Depth: infinity" on the // destination resource. if err := fs.RemoveAll(ctx, dst); err != nil { return http.StatusForbidden, err } } else { return http.StatusPreconditionFailed, os.ErrExist } if err := fs.Rename(ctx, src, dst); err != nil { return http.StatusForbidden, err } if created { return http.StatusCreated, nil } return http.StatusNoContent, nil } func copyProps(dst, src File) error { d, ok := dst.(DeadPropsHolder) if !ok { return nil } s, ok := src.(DeadPropsHolder) if !ok { return nil } m, err := s.DeadProps() if err != nil { return err } props := make([]Property, 0, len(m)) for _, prop := range m { props = append(props, prop) } _, err = d.Patch([]Proppatch{{Props: props}}) return err } // copyFiles copies files and/or directories from src to dst. // // See section 9.8.5 for when various HTTP status codes apply. func copyFiles(ctx context.Context, fs FileSystem, src, dst string, overwrite bool, depth int, recursion int) (status int, err error) { if recursion == 1000 { return http.StatusInternalServerError, errRecursionTooDeep } recursion++ // TODO: section 9.8.3 says that "Note that an infinite-depth COPY of /A/ // into /A/B/ could lead to infinite recursion if not handled correctly." srcFile, err := fs.OpenFile(ctx, src, os.O_RDONLY, 0) if err != nil { if os.IsNotExist(err) { return http.StatusNotFound, err } return http.StatusInternalServerError, err } defer srcFile.Close() srcStat, err := srcFile.Stat() if err != nil { if os.IsNotExist(err) { return http.StatusNotFound, err } return http.StatusInternalServerError, err } srcPerm := srcStat.Mode() & os.ModePerm created := false if _, err := fs.Stat(ctx, dst); err != nil { if os.IsNotExist(err) { created = true } else { return http.StatusForbidden, err } } else { if !overwrite { return http.StatusPreconditionFailed, os.ErrExist } if err := fs.RemoveAll(ctx, dst); err != nil && !os.IsNotExist(err) { return http.StatusForbidden, err } } if srcStat.IsDir() { if err := fs.Mkdir(ctx, dst, srcPerm); err != nil { return http.StatusForbidden, err } if depth == infiniteDepth { children, err := srcFile.Readdir(-1) if err != nil { return http.StatusForbidden, err } for _, c := range children { name := c.Name() s := path.Join(src, name) d := path.Join(dst, name) cStatus, cErr := copyFiles(ctx, fs, s, d, overwrite, depth, recursion) if cErr != nil { // TODO: MultiStatus. return cStatus, cErr } } } } else { dstFile, err := fs.OpenFile(ctx, dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, srcPerm) if err != nil { if os.IsNotExist(err) { return http.StatusConflict, err } return http.StatusForbidden, err } _, copyErr := io.Copy(dstFile, srcFile) propsErr := copyProps(dstFile, srcFile) closeErr := dstFile.Close() if copyErr != nil { return http.StatusInternalServerError, copyErr } if propsErr != nil { return http.StatusInternalServerError, propsErr } if closeErr != nil { return http.StatusInternalServerError, closeErr } } if created { return http.StatusCreated, nil } return http.StatusNoContent, nil } // walkFS traverses filesystem fs starting at name up to depth levels. // // Allowed values for depth are 0, 1 or infiniteDepth. For each visited node, // walkFS calls walkFn. If a visited file system node is a directory and // walkFn returns filepath.SkipDir, walkFS will skip traversal of this node. func walkFS(ctx context.Context, fs FileSystem, depth int, name string, info os.FileInfo, walkFn filepath.WalkFunc) error { // This implementation is based on Walk's code in the standard path/filepath package. err := walkFn(name, info, nil) if err != nil { if info.IsDir() && err == filepath.SkipDir { return nil } return err } if !info.IsDir() || depth == 0 { return nil } if depth == 1 { depth = 0 } // Read directory names. f, err := fs.OpenFile(ctx, name, os.O_RDONLY, 0) if err != nil { return walkFn(name, info, err) } fileInfos, err := f.Readdir(0) f.Close() if err != nil { return walkFn(name, info, err) } for _, fileInfo := range fileInfos { filename := path.Join(name, fileInfo.Name()) fileInfo, err := fs.Stat(ctx, filename) if err != nil { if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir { return err } } else { err = walkFS(ctx, fs, depth, filename, fileInfo, walkFn) if err != nil { if !fileInfo.IsDir() || err != filepath.SkipDir { return err } } } } return nil } ================================================ FILE: vendor/golang.org/x/net/webdav/if.go ================================================ // 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 webdav // The If header is covered by Section 10.4. // http://www.webdav.org/specs/rfc4918.html#HEADER_If import ( "strings" ) // ifHeader is a disjunction (OR) of ifLists. type ifHeader struct { lists []ifList } // ifList is a conjunction (AND) of Conditions, and an optional resource tag. type ifList struct { resourceTag string conditions []Condition } // parseIfHeader parses the "If: foo bar" HTTP header. The httpHeader string // should omit the "If:" prefix and have any "\r\n"s collapsed to a " ", as is // returned by req.Header.Get("If") for a http.Request req. func parseIfHeader(httpHeader string) (h ifHeader, ok bool) { s := strings.TrimSpace(httpHeader) switch tokenType, _, _ := lex(s); tokenType { case '(': return parseNoTagLists(s) case angleTokenType: return parseTaggedLists(s) default: return ifHeader{}, false } } func parseNoTagLists(s string) (h ifHeader, ok bool) { for { l, remaining, ok := parseList(s) if !ok { return ifHeader{}, false } h.lists = append(h.lists, l) if remaining == "" { return h, true } s = remaining } } func parseTaggedLists(s string) (h ifHeader, ok bool) { resourceTag, n := "", 0 for first := true; ; first = false { tokenType, tokenStr, remaining := lex(s) switch tokenType { case angleTokenType: if !first && n == 0 { return ifHeader{}, false } resourceTag, n = tokenStr, 0 s = remaining case '(': n++ l, remaining, ok := parseList(s) if !ok { return ifHeader{}, false } l.resourceTag = resourceTag h.lists = append(h.lists, l) if remaining == "" { return h, true } s = remaining default: return ifHeader{}, false } } } func parseList(s string) (l ifList, remaining string, ok bool) { tokenType, _, s := lex(s) if tokenType != '(' { return ifList{}, "", false } for { tokenType, _, remaining = lex(s) if tokenType == ')' { if len(l.conditions) == 0 { return ifList{}, "", false } return l, remaining, true } c, remaining, ok := parseCondition(s) if !ok { return ifList{}, "", false } l.conditions = append(l.conditions, c) s = remaining } } func parseCondition(s string) (c Condition, remaining string, ok bool) { tokenType, tokenStr, s := lex(s) if tokenType == notTokenType { c.Not = true tokenType, tokenStr, s = lex(s) } switch tokenType { case strTokenType, angleTokenType: c.Token = tokenStr case squareTokenType: c.ETag = tokenStr default: return Condition{}, "", false } return c, s, true } // Single-rune tokens like '(' or ')' have a token type equal to their rune. // All other tokens have a negative token type. const ( errTokenType = rune(-1) eofTokenType = rune(-2) strTokenType = rune(-3) notTokenType = rune(-4) angleTokenType = rune(-5) squareTokenType = rune(-6) ) func lex(s string) (tokenType rune, tokenStr string, remaining string) { // The net/textproto Reader that parses the HTTP header will collapse // Linear White Space that spans multiple "\r\n" lines to a single " ", // so we don't need to look for '\r' or '\n'. for len(s) > 0 && (s[0] == '\t' || s[0] == ' ') { s = s[1:] } if len(s) == 0 { return eofTokenType, "", "" } i := 0 loop: for ; i < len(s); i++ { switch s[i] { case '\t', ' ', '(', ')', '<', '>', '[', ']': break loop } } if i != 0 { tokenStr, remaining = s[:i], s[i:] if tokenStr == "Not" { return notTokenType, "", remaining } return strTokenType, tokenStr, remaining } j := 0 switch s[0] { case '<': j, tokenType = strings.IndexByte(s, '>'), angleTokenType case '[': j, tokenType = strings.IndexByte(s, ']'), squareTokenType default: return rune(s[0]), "", s[1:] } if j < 0 { return errTokenType, "", "" } return tokenType, s[1:j], s[j+1:] } ================================================ FILE: vendor/golang.org/x/net/webdav/internal/xml/README ================================================ This is a fork of the encoding/xml package at ca1d6c4, the last commit before https://go.googlesource.com/go/+/c0d6d33 "encoding/xml: restore Go 1.4 name space behavior" made late in the lead-up to the Go 1.5 release. The list of encoding/xml changes is at https://go.googlesource.com/go/+log/master/src/encoding/xml This fork is temporary, and I (nigeltao) expect to revert it after Go 1.6 is released. See http://golang.org/issue/11841 ================================================ FILE: vendor/golang.org/x/net/webdav/internal/xml/marshal.go ================================================ // 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 xml import ( "bufio" "bytes" "encoding" "fmt" "io" "reflect" "strconv" "strings" ) const ( // A generic XML header suitable for use with the output of Marshal. // This is not automatically added to any output of this package, // it is provided as a convenience. Header = `` + "\n" ) // Marshal returns the XML encoding of v. // // Marshal handles an array or slice by marshalling each of the elements. // Marshal handles a pointer by marshalling the value it points at or, if the // pointer is nil, by writing nothing. Marshal handles an interface value by // marshalling the value it contains or, if the interface value is nil, by // writing nothing. Marshal handles all other data by writing one or more XML // elements containing the data. // // The name for the XML elements is taken from, in order of preference: // - the tag on the XMLName field, if the data is a struct // - the value of the XMLName field of type xml.Name // - the tag of the struct field used to obtain the data // - the name of the struct field used to obtain the data // - the name of the marshalled type // // The XML element for a struct contains marshalled elements for each of the // exported fields of the struct, with these exceptions: // - the XMLName field, described above, is omitted. // - a field with tag "-" is omitted. // - a field with tag "name,attr" becomes an attribute with // the given name in the XML element. // - a field with tag ",attr" becomes an attribute with the // field name in the XML element. // - a field with tag ",chardata" is written as character data, // not as an XML element. // - a field with tag ",innerxml" is written verbatim, not subject // to the usual marshalling procedure. // - a field with tag ",comment" is written as an XML comment, not // subject to the usual marshalling procedure. It must not contain // the "--" string within it. // - a field with a tag including the "omitempty" option is omitted // if the field value is empty. The empty values are false, 0, any // nil pointer or interface value, and any array, slice, map, or // string of length zero. // - an anonymous struct field is handled as if the fields of its // value were part of the outer struct. // // If a field uses a tag "a>b>c", then the element c will be nested inside // parent elements a and b. Fields that appear next to each other that name // the same parent will be enclosed in one XML element. // // See MarshalIndent for an example. // // Marshal will return an error if asked to marshal a channel, function, or map. func Marshal(v interface{}) ([]byte, error) { var b bytes.Buffer if err := NewEncoder(&b).Encode(v); err != nil { return nil, err } return b.Bytes(), nil } // Marshaler is the interface implemented by objects that can marshal // themselves into valid XML elements. // // MarshalXML encodes the receiver as zero or more XML elements. // By convention, arrays or slices are typically encoded as a sequence // of elements, one per entry. // Using start as the element tag is not required, but doing so // will enable Unmarshal to match the XML elements to the correct // struct field. // One common implementation strategy is to construct a separate // value with a layout corresponding to the desired XML and then // to encode it using e.EncodeElement. // Another common strategy is to use repeated calls to e.EncodeToken // to generate the XML output one token at a time. // The sequence of encoded tokens must make up zero or more valid // XML elements. type Marshaler interface { MarshalXML(e *Encoder, start StartElement) error } // MarshalerAttr is the interface implemented by objects that can marshal // themselves into valid XML attributes. // // MarshalXMLAttr returns an XML attribute with the encoded value of the receiver. // Using name as the attribute name is not required, but doing so // will enable Unmarshal to match the attribute to the correct // struct field. // If MarshalXMLAttr returns the zero attribute Attr{}, no attribute // will be generated in the output. // MarshalXMLAttr is used only for struct fields with the // "attr" option in the field tag. type MarshalerAttr interface { MarshalXMLAttr(name Name) (Attr, error) } // MarshalIndent works like Marshal, but each XML element begins on a new // indented line that starts with prefix and is followed by one or more // copies of indent according to the nesting depth. func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { var b bytes.Buffer enc := NewEncoder(&b) enc.Indent(prefix, indent) if err := enc.Encode(v); err != nil { return nil, err } return b.Bytes(), nil } // An Encoder writes XML data to an output stream. type Encoder struct { p printer } // NewEncoder returns a new encoder that writes to w. func NewEncoder(w io.Writer) *Encoder { e := &Encoder{printer{Writer: bufio.NewWriter(w)}} e.p.encoder = e return e } // Indent sets the encoder to generate XML in which each element // begins on a new indented line that starts with prefix and is followed by // one or more copies of indent according to the nesting depth. func (enc *Encoder) Indent(prefix, indent string) { enc.p.prefix = prefix enc.p.indent = indent } // Encode writes the XML encoding of v to the stream. // // See the documentation for Marshal for details about the conversion // of Go values to XML. // // Encode calls Flush before returning. func (enc *Encoder) Encode(v interface{}) error { err := enc.p.marshalValue(reflect.ValueOf(v), nil, nil) if err != nil { return err } return enc.p.Flush() } // EncodeElement writes the XML encoding of v to the stream, // using start as the outermost tag in the encoding. // // See the documentation for Marshal for details about the conversion // of Go values to XML. // // EncodeElement calls Flush before returning. func (enc *Encoder) EncodeElement(v interface{}, start StartElement) error { err := enc.p.marshalValue(reflect.ValueOf(v), nil, &start) if err != nil { return err } return enc.p.Flush() } var ( begComment = []byte("") endProcInst = []byte("?>") endDirective = []byte(">") ) // EncodeToken writes the given XML token to the stream. // It returns an error if StartElement and EndElement tokens are not // properly matched. // // EncodeToken does not call Flush, because usually it is part of a // larger operation such as Encode or EncodeElement (or a custom // Marshaler's MarshalXML invoked during those), and those will call // Flush when finished. Callers that create an Encoder and then invoke // EncodeToken directly, without using Encode or EncodeElement, need to // call Flush when finished to ensure that the XML is written to the // underlying writer. // // EncodeToken allows writing a ProcInst with Target set to "xml" only // as the first token in the stream. // // When encoding a StartElement holding an XML namespace prefix // declaration for a prefix that is not already declared, contained // elements (including the StartElement itself) will use the declared // prefix when encoding names with matching namespace URIs. func (enc *Encoder) EncodeToken(t Token) error { p := &enc.p switch t := t.(type) { case StartElement: if err := p.writeStart(&t); err != nil { return err } case EndElement: if err := p.writeEnd(t.Name); err != nil { return err } case CharData: escapeText(p, t, false) case Comment: if bytes.Contains(t, endComment) { return fmt.Errorf("xml: EncodeToken of Comment containing --> marker") } p.WriteString("") return p.cachedWriteError() case ProcInst: // First token to be encoded which is also a ProcInst with target of xml // is the xml declaration. The only ProcInst where target of xml is allowed. if t.Target == "xml" && p.Buffered() != 0 { return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded") } if !isNameString(t.Target) { return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target") } if bytes.Contains(t.Inst, endProcInst) { return fmt.Errorf("xml: EncodeToken of ProcInst containing ?> marker") } p.WriteString(" 0 { p.WriteByte(' ') p.Write(t.Inst) } p.WriteString("?>") case Directive: if !isValidDirective(t) { return fmt.Errorf("xml: EncodeToken of Directive containing wrong < or > markers") } p.WriteString("") default: return fmt.Errorf("xml: EncodeToken of invalid token type") } return p.cachedWriteError() } // isValidDirective reports whether dir is a valid directive text, // meaning angle brackets are matched, ignoring comments and strings. func isValidDirective(dir Directive) bool { var ( depth int inquote uint8 incomment bool ) for i, c := range dir { switch { case incomment: if c == '>' { if n := 1 + i - len(endComment); n >= 0 && bytes.Equal(dir[n:i+1], endComment) { incomment = false } } // Just ignore anything in comment case inquote != 0: if c == inquote { inquote = 0 } // Just ignore anything within quotes case c == '\'' || c == '"': inquote = c case c == '<': if i+len(begComment) < len(dir) && bytes.Equal(dir[i:i+len(begComment)], begComment) { incomment = true } else { depth++ } case c == '>': if depth == 0 { return false } depth-- } } return depth == 0 && inquote == 0 && !incomment } // Flush flushes any buffered XML to the underlying writer. // See the EncodeToken documentation for details about when it is necessary. func (enc *Encoder) Flush() error { return enc.p.Flush() } type printer struct { *bufio.Writer encoder *Encoder seq int indent string prefix string depth int indentedIn bool putNewline bool defaultNS string attrNS map[string]string // map prefix -> name space attrPrefix map[string]string // map name space -> prefix prefixes []printerPrefix tags []Name } // printerPrefix holds a namespace undo record. // When an element is popped, the prefix record // is set back to the recorded URL. The empty // prefix records the URL for the default name space. // // The start of an element is recorded with an element // that has mark=true. type printerPrefix struct { prefix string url string mark bool } func (p *printer) prefixForNS(url string, isAttr bool) string { // The "http://www.w3.org/XML/1998/namespace" name space is predefined as "xml" // and must be referred to that way. // (The "http://www.w3.org/2000/xmlns/" name space is also predefined as "xmlns", // but users should not be trying to use that one directly - that's our job.) if url == xmlURL { return "xml" } if !isAttr && url == p.defaultNS { // We can use the default name space. return "" } return p.attrPrefix[url] } // defineNS pushes any namespace definition found in the given attribute. // If ignoreNonEmptyDefault is true, an xmlns="nonempty" // attribute will be ignored. func (p *printer) defineNS(attr Attr, ignoreNonEmptyDefault bool) error { var prefix string if attr.Name.Local == "xmlns" { if attr.Name.Space != "" && attr.Name.Space != "xml" && attr.Name.Space != xmlURL { return fmt.Errorf("xml: cannot redefine xmlns attribute prefix") } } else if attr.Name.Space == "xmlns" && attr.Name.Local != "" { prefix = attr.Name.Local if attr.Value == "" { // Technically, an empty XML namespace is allowed for an attribute. // From http://www.w3.org/TR/xml-names11/#scoping-defaulting: // // The attribute value in a namespace declaration for a prefix may be // empty. This has the effect, within the scope of the declaration, of removing // any association of the prefix with a namespace name. // // However our namespace prefixes here are used only as hints. There's // no need to respect the removal of a namespace prefix, so we ignore it. return nil } } else { // Ignore: it's not a namespace definition return nil } if prefix == "" { if attr.Value == p.defaultNS { // No need for redefinition. return nil } if attr.Value != "" && ignoreNonEmptyDefault { // We have an xmlns="..." value but // it can't define a name space in this context, // probably because the element has an empty // name space. In this case, we just ignore // the name space declaration. return nil } } else if _, ok := p.attrPrefix[attr.Value]; ok { // There's already a prefix for the given name space, // so use that. This prevents us from // having two prefixes for the same name space // so attrNS and attrPrefix can remain bijective. return nil } p.pushPrefix(prefix, attr.Value) return nil } // createNSPrefix creates a name space prefix attribute // to use for the given name space, defining a new prefix // if necessary. // If isAttr is true, the prefix is to be created for an attribute // prefix, which means that the default name space cannot // be used. func (p *printer) createNSPrefix(url string, isAttr bool) { if _, ok := p.attrPrefix[url]; ok { // We already have a prefix for the given URL. return } switch { case !isAttr && url == p.defaultNS: // We can use the default name space. return case url == "": // The only way we can encode names in the empty // name space is by using the default name space, // so we must use that. if p.defaultNS != "" { // The default namespace is non-empty, so we // need to set it to empty. p.pushPrefix("", "") } return case url == xmlURL: return } // TODO If the URL is an existing prefix, we could // use it as is. That would enable the // marshaling of elements that had been unmarshaled // and with a name space prefix that was not found. // although technically it would be incorrect. // Pick a name. We try to use the final element of the path // but fall back to _. prefix := strings.TrimRight(url, "/") if i := strings.LastIndex(prefix, "/"); i >= 0 { prefix = prefix[i+1:] } if prefix == "" || !isName([]byte(prefix)) || strings.Contains(prefix, ":") { prefix = "_" } if strings.HasPrefix(prefix, "xml") { // xmlanything is reserved. prefix = "_" + prefix } if p.attrNS[prefix] != "" { // Name is taken. Find a better one. for p.seq++; ; p.seq++ { if id := prefix + "_" + strconv.Itoa(p.seq); p.attrNS[id] == "" { prefix = id break } } } p.pushPrefix(prefix, url) } // writeNamespaces writes xmlns attributes for all the // namespace prefixes that have been defined in // the current element. func (p *printer) writeNamespaces() { for i := len(p.prefixes) - 1; i >= 0; i-- { prefix := p.prefixes[i] if prefix.mark { return } p.WriteString(" ") if prefix.prefix == "" { // Default name space. p.WriteString(`xmlns="`) } else { p.WriteString("xmlns:") p.WriteString(prefix.prefix) p.WriteString(`="`) } EscapeText(p, []byte(p.nsForPrefix(prefix.prefix))) p.WriteString(`"`) } } // pushPrefix pushes a new prefix on the prefix stack // without checking to see if it is already defined. func (p *printer) pushPrefix(prefix, url string) { p.prefixes = append(p.prefixes, printerPrefix{ prefix: prefix, url: p.nsForPrefix(prefix), }) p.setAttrPrefix(prefix, url) } // nsForPrefix returns the name space for the given // prefix. Note that this is not valid for the // empty attribute prefix, which always has an empty // name space. func (p *printer) nsForPrefix(prefix string) string { if prefix == "" { return p.defaultNS } return p.attrNS[prefix] } // markPrefix marks the start of an element on the prefix // stack. func (p *printer) markPrefix() { p.prefixes = append(p.prefixes, printerPrefix{ mark: true, }) } // popPrefix pops all defined prefixes for the current // element. func (p *printer) popPrefix() { for len(p.prefixes) > 0 { prefix := p.prefixes[len(p.prefixes)-1] p.prefixes = p.prefixes[:len(p.prefixes)-1] if prefix.mark { break } p.setAttrPrefix(prefix.prefix, prefix.url) } } // setAttrPrefix sets an attribute name space prefix. // If url is empty, the attribute is removed. // If prefix is empty, the default name space is set. func (p *printer) setAttrPrefix(prefix, url string) { if prefix == "" { p.defaultNS = url return } if url == "" { delete(p.attrPrefix, p.attrNS[prefix]) delete(p.attrNS, prefix) return } if p.attrPrefix == nil { // Need to define a new name space. p.attrPrefix = make(map[string]string) p.attrNS = make(map[string]string) } // Remove any old prefix value. This is OK because we maintain a // strict one-to-one mapping between prefix and URL (see // defineNS) delete(p.attrPrefix, p.attrNS[prefix]) p.attrPrefix[url] = prefix p.attrNS[prefix] = url } var ( marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() marshalerAttrType = reflect.TypeOf((*MarshalerAttr)(nil)).Elem() textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() ) // marshalValue writes one or more XML elements representing val. // If val was obtained from a struct field, finfo must have its details. func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplate *StartElement) error { if startTemplate != nil && startTemplate.Name.Local == "" { return fmt.Errorf("xml: EncodeElement of StartElement with missing name") } if !val.IsValid() { return nil } if finfo != nil && finfo.flags&fOmitEmpty != 0 && isEmptyValue(val) { return nil } // Drill into interfaces and pointers. // This can turn into an infinite loop given a cyclic chain, // but it matches the Go 1 behavior. for val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr { if val.IsNil() { return nil } val = val.Elem() } kind := val.Kind() typ := val.Type() // Check for marshaler. if val.CanInterface() && typ.Implements(marshalerType) { return p.marshalInterface(val.Interface().(Marshaler), p.defaultStart(typ, finfo, startTemplate)) } if val.CanAddr() { pv := val.Addr() if pv.CanInterface() && pv.Type().Implements(marshalerType) { return p.marshalInterface(pv.Interface().(Marshaler), p.defaultStart(pv.Type(), finfo, startTemplate)) } } // Check for text marshaler. if val.CanInterface() && typ.Implements(textMarshalerType) { return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), p.defaultStart(typ, finfo, startTemplate)) } if val.CanAddr() { pv := val.Addr() if pv.CanInterface() && pv.Type().Implements(textMarshalerType) { return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), p.defaultStart(pv.Type(), finfo, startTemplate)) } } // Slices and arrays iterate over the elements. They do not have an enclosing tag. if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() != reflect.Uint8 { for i, n := 0, val.Len(); i < n; i++ { if err := p.marshalValue(val.Index(i), finfo, startTemplate); err != nil { return err } } return nil } tinfo, err := getTypeInfo(typ) if err != nil { return err } // Create start element. // Precedence for the XML element name is: // 0. startTemplate // 1. XMLName field in underlying struct; // 2. field name/tag in the struct field; and // 3. type name var start StartElement // explicitNS records whether the element's name space has been // explicitly set (for example an XMLName field). explicitNS := false if startTemplate != nil { start.Name = startTemplate.Name explicitNS = true start.Attr = append(start.Attr, startTemplate.Attr...) } else if tinfo.xmlname != nil { xmlname := tinfo.xmlname if xmlname.name != "" { start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name } else if v, ok := xmlname.value(val).Interface().(Name); ok && v.Local != "" { start.Name = v } explicitNS = true } if start.Name.Local == "" && finfo != nil { start.Name.Local = finfo.name if finfo.xmlns != "" { start.Name.Space = finfo.xmlns explicitNS = true } } if start.Name.Local == "" { name := typ.Name() if name == "" { return &UnsupportedTypeError{typ} } start.Name.Local = name } // defaultNS records the default name space as set by a xmlns="..." // attribute. We don't set p.defaultNS because we want to let // the attribute writing code (in p.defineNS) be solely responsible // for maintaining that. defaultNS := p.defaultNS // Attributes for i := range tinfo.fields { finfo := &tinfo.fields[i] if finfo.flags&fAttr == 0 { continue } attr, err := p.fieldAttr(finfo, val) if err != nil { return err } if attr.Name.Local == "" { continue } start.Attr = append(start.Attr, attr) if attr.Name.Space == "" && attr.Name.Local == "xmlns" { defaultNS = attr.Value } } if !explicitNS { // Historic behavior: elements use the default name space // they are contained in by default. start.Name.Space = defaultNS } // Historic behaviour: an element that's in a namespace sets // the default namespace for all elements contained within it. start.setDefaultNamespace() if err := p.writeStart(&start); err != nil { return err } if val.Kind() == reflect.Struct { err = p.marshalStruct(tinfo, val) } else { s, b, err1 := p.marshalSimple(typ, val) if err1 != nil { err = err1 } else if b != nil { EscapeText(p, b) } else { p.EscapeString(s) } } if err != nil { return err } if err := p.writeEnd(start.Name); err != nil { return err } return p.cachedWriteError() } // fieldAttr returns the attribute of the given field. // If the returned attribute has an empty Name.Local, // it should not be used. // The given value holds the value containing the field. func (p *printer) fieldAttr(finfo *fieldInfo, val reflect.Value) (Attr, error) { fv := finfo.value(val) name := Name{Space: finfo.xmlns, Local: finfo.name} if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) { return Attr{}, nil } if fv.Kind() == reflect.Interface && fv.IsNil() { return Attr{}, nil } if fv.CanInterface() && fv.Type().Implements(marshalerAttrType) { attr, err := fv.Interface().(MarshalerAttr).MarshalXMLAttr(name) return attr, err } if fv.CanAddr() { pv := fv.Addr() if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) { attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name) return attr, err } } if fv.CanInterface() && fv.Type().Implements(textMarshalerType) { text, err := fv.Interface().(encoding.TextMarshaler).MarshalText() if err != nil { return Attr{}, err } return Attr{name, string(text)}, nil } if fv.CanAddr() { pv := fv.Addr() if pv.CanInterface() && pv.Type().Implements(textMarshalerType) { text, err := pv.Interface().(encoding.TextMarshaler).MarshalText() if err != nil { return Attr{}, err } return Attr{name, string(text)}, nil } } // Dereference or skip nil pointer, interface values. switch fv.Kind() { case reflect.Ptr, reflect.Interface: if fv.IsNil() { return Attr{}, nil } fv = fv.Elem() } s, b, err := p.marshalSimple(fv.Type(), fv) if err != nil { return Attr{}, err } if b != nil { s = string(b) } return Attr{name, s}, nil } // defaultStart returns the default start element to use, // given the reflect type, field info, and start template. func (p *printer) defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement { var start StartElement // Precedence for the XML element name is as above, // except that we do not look inside structs for the first field. if startTemplate != nil { start.Name = startTemplate.Name start.Attr = append(start.Attr, startTemplate.Attr...) } else if finfo != nil && finfo.name != "" { start.Name.Local = finfo.name start.Name.Space = finfo.xmlns } else if typ.Name() != "" { start.Name.Local = typ.Name() } else { // Must be a pointer to a named type, // since it has the Marshaler methods. start.Name.Local = typ.Elem().Name() } // Historic behaviour: elements use the name space of // the element they are contained in by default. if start.Name.Space == "" { start.Name.Space = p.defaultNS } start.setDefaultNamespace() return start } // marshalInterface marshals a Marshaler interface value. func (p *printer) marshalInterface(val Marshaler, start StartElement) error { // Push a marker onto the tag stack so that MarshalXML // cannot close the XML tags that it did not open. p.tags = append(p.tags, Name{}) n := len(p.tags) err := val.MarshalXML(p.encoder, start) if err != nil { return err } // Make sure MarshalXML closed all its tags. p.tags[n-1] is the mark. if len(p.tags) > n { return fmt.Errorf("xml: %s.MarshalXML wrote invalid XML: <%s> not closed", receiverType(val), p.tags[len(p.tags)-1].Local) } p.tags = p.tags[:n-1] return nil } // marshalTextInterface marshals a TextMarshaler interface value. func (p *printer) marshalTextInterface(val encoding.TextMarshaler, start StartElement) error { if err := p.writeStart(&start); err != nil { return err } text, err := val.MarshalText() if err != nil { return err } EscapeText(p, text) return p.writeEnd(start.Name) } // writeStart writes the given start element. func (p *printer) writeStart(start *StartElement) error { if start.Name.Local == "" { return fmt.Errorf("xml: start tag with no name") } p.tags = append(p.tags, start.Name) p.markPrefix() // Define any name spaces explicitly declared in the attributes. // We do this as a separate pass so that explicitly declared prefixes // will take precedence over implicitly declared prefixes // regardless of the order of the attributes. ignoreNonEmptyDefault := start.Name.Space == "" for _, attr := range start.Attr { if err := p.defineNS(attr, ignoreNonEmptyDefault); err != nil { return err } } // Define any new name spaces implied by the attributes. for _, attr := range start.Attr { name := attr.Name // From http://www.w3.org/TR/xml-names11/#defaulting // "Default namespace declarations do not apply directly // to attribute names; the interpretation of unprefixed // attributes is determined by the element on which they // appear." // This means we don't need to create a new namespace // when an attribute name space is empty. if name.Space != "" && !name.isNamespace() { p.createNSPrefix(name.Space, true) } } p.createNSPrefix(start.Name.Space, false) p.writeIndent(1) p.WriteByte('<') p.writeName(start.Name, false) p.writeNamespaces() for _, attr := range start.Attr { name := attr.Name if name.Local == "" || name.isNamespace() { // Namespaces have already been written by writeNamespaces above. continue } p.WriteByte(' ') p.writeName(name, true) p.WriteString(`="`) p.EscapeString(attr.Value) p.WriteByte('"') } p.WriteByte('>') return nil } // writeName writes the given name. It assumes // that p.createNSPrefix(name) has already been called. func (p *printer) writeName(name Name, isAttr bool) { if prefix := p.prefixForNS(name.Space, isAttr); prefix != "" { p.WriteString(prefix) p.WriteByte(':') } p.WriteString(name.Local) } func (p *printer) writeEnd(name Name) error { if name.Local == "" { return fmt.Errorf("xml: end tag with no name") } if len(p.tags) == 0 || p.tags[len(p.tags)-1].Local == "" { return fmt.Errorf("xml: end tag without start tag", name.Local) } if top := p.tags[len(p.tags)-1]; top != name { if top.Local != name.Local { return fmt.Errorf("xml: end tag does not match start tag <%s>", name.Local, top.Local) } return fmt.Errorf("xml: end tag in namespace %s does not match start tag <%s> in namespace %s", name.Local, name.Space, top.Local, top.Space) } p.tags = p.tags[:len(p.tags)-1] p.writeIndent(-1) p.WriteByte('<') p.WriteByte('/') p.writeName(name, false) p.WriteByte('>') p.popPrefix() return nil } func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, []byte, error) { switch val.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return strconv.FormatInt(val.Int(), 10), nil, nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return strconv.FormatUint(val.Uint(), 10), nil, nil case reflect.Float32, reflect.Float64: return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil, nil case reflect.String: return val.String(), nil, nil case reflect.Bool: return strconv.FormatBool(val.Bool()), nil, nil case reflect.Array: if typ.Elem().Kind() != reflect.Uint8 { break } // [...]byte var bytes []byte if val.CanAddr() { bytes = val.Slice(0, val.Len()).Bytes() } else { bytes = make([]byte, val.Len()) reflect.Copy(reflect.ValueOf(bytes), val) } return "", bytes, nil case reflect.Slice: if typ.Elem().Kind() != reflect.Uint8 { break } // []byte return "", val.Bytes(), nil } return "", nil, &UnsupportedTypeError{typ} } var ddBytes = []byte("--") func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { s := parentStack{p: p} for i := range tinfo.fields { finfo := &tinfo.fields[i] if finfo.flags&fAttr != 0 { continue } vf := finfo.value(val) // Dereference or skip nil pointer, interface values. switch vf.Kind() { case reflect.Ptr, reflect.Interface: if !vf.IsNil() { vf = vf.Elem() } } switch finfo.flags & fMode { case fCharData: if err := s.setParents(&noField, reflect.Value{}); err != nil { return err } if vf.CanInterface() && vf.Type().Implements(textMarshalerType) { data, err := vf.Interface().(encoding.TextMarshaler).MarshalText() if err != nil { return err } Escape(p, data) continue } if vf.CanAddr() { pv := vf.Addr() if pv.CanInterface() && pv.Type().Implements(textMarshalerType) { data, err := pv.Interface().(encoding.TextMarshaler).MarshalText() if err != nil { return err } Escape(p, data) continue } } var scratch [64]byte switch vf.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: Escape(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: Escape(p, strconv.AppendUint(scratch[:0], vf.Uint(), 10)) case reflect.Float32, reflect.Float64: Escape(p, strconv.AppendFloat(scratch[:0], vf.Float(), 'g', -1, vf.Type().Bits())) case reflect.Bool: Escape(p, strconv.AppendBool(scratch[:0], vf.Bool())) case reflect.String: if err := EscapeText(p, []byte(vf.String())); err != nil { return err } case reflect.Slice: if elem, ok := vf.Interface().([]byte); ok { if err := EscapeText(p, elem); err != nil { return err } } } continue case fComment: if err := s.setParents(&noField, reflect.Value{}); err != nil { return err } k := vf.Kind() if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) { return fmt.Errorf("xml: bad type for comment field of %s", val.Type()) } if vf.Len() == 0 { continue } p.writeIndent(0) p.WriteString("" is invalid grammar. Make it "- -->" p.WriteByte(' ') } p.WriteString("-->") continue case fInnerXml: iface := vf.Interface() switch raw := iface.(type) { case []byte: p.Write(raw) continue case string: p.WriteString(raw) continue } case fElement, fElement | fAny: if err := s.setParents(finfo, vf); err != nil { return err } } if err := p.marshalValue(vf, finfo, nil); err != nil { return err } } if err := s.setParents(&noField, reflect.Value{}); err != nil { return err } return p.cachedWriteError() } var noField fieldInfo // return the bufio Writer's cached write error func (p *printer) cachedWriteError() error { _, err := p.Write(nil) return err } func (p *printer) writeIndent(depthDelta int) { if len(p.prefix) == 0 && len(p.indent) == 0 { return } if depthDelta < 0 { p.depth-- if p.indentedIn { p.indentedIn = false return } p.indentedIn = false } if p.putNewline { p.WriteByte('\n') } else { p.putNewline = true } if len(p.prefix) > 0 { p.WriteString(p.prefix) } if len(p.indent) > 0 { for i := 0; i < p.depth; i++ { p.WriteString(p.indent) } } if depthDelta > 0 { p.depth++ p.indentedIn = true } } type parentStack struct { p *printer xmlns string parents []string } // setParents sets the stack of current parents to those found in finfo. // It only writes the start elements if vf holds a non-nil value. // If finfo is &noField, it pops all elements. func (s *parentStack) setParents(finfo *fieldInfo, vf reflect.Value) error { xmlns := s.p.defaultNS if finfo.xmlns != "" { xmlns = finfo.xmlns } commonParents := 0 if xmlns == s.xmlns { for ; commonParents < len(finfo.parents) && commonParents < len(s.parents); commonParents++ { if finfo.parents[commonParents] != s.parents[commonParents] { break } } } // Pop off any parents that aren't in common with the previous field. for i := len(s.parents) - 1; i >= commonParents; i-- { if err := s.p.writeEnd(Name{ Space: s.xmlns, Local: s.parents[i], }); err != nil { return err } } s.parents = finfo.parents s.xmlns = xmlns if commonParents >= len(s.parents) { // No new elements to push. return nil } if (vf.Kind() == reflect.Ptr || vf.Kind() == reflect.Interface) && vf.IsNil() { // The element is nil, so no need for the start elements. s.parents = s.parents[:commonParents] return nil } // Push any new parents required. for _, name := range s.parents[commonParents:] { start := &StartElement{ Name: Name{ Space: s.xmlns, Local: name, }, } // Set the default name space for parent elements // to match what we do with other elements. if s.xmlns != s.p.defaultNS { start.setDefaultNamespace() } if err := s.p.writeStart(start); err != nil { return err } } return nil } // A MarshalXMLError is returned when Marshal encounters a type // that cannot be converted into XML. type UnsupportedTypeError struct { Type reflect.Type } func (e *UnsupportedTypeError) Error() string { return "xml: unsupported type: " + e.Type.String() } func isEmptyValue(v reflect.Value) bool { switch v.Kind() { case reflect.Array, reflect.Map, reflect.Slice, reflect.String: return v.Len() == 0 case reflect.Bool: return !v.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflect.Interface, reflect.Ptr: return v.IsNil() } return false } ================================================ FILE: vendor/golang.org/x/net/webdav/internal/xml/read.go ================================================ // 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 xml import ( "bytes" "encoding" "errors" "fmt" "reflect" "strconv" "strings" ) // BUG(rsc): Mapping between XML elements and data structures is inherently flawed: // an XML element is an order-dependent collection of anonymous // values, while a data structure is an order-independent collection // of named values. // See package json for a textual representation more suitable // to data structures. // Unmarshal parses the XML-encoded data and stores the result in // the value pointed to by v, which must be an arbitrary struct, // slice, or string. Well-formed data that does not fit into v is // discarded. // // Because Unmarshal uses the reflect package, it can only assign // to exported (upper case) fields. Unmarshal uses a case-sensitive // comparison to match XML element names to tag values and struct // field names. // // Unmarshal maps an XML element to a struct using the following rules. // In the rules, the tag of a field refers to the value associated with the // key 'xml' in the struct field's tag (see the example above). // // * If the struct has a field of type []byte or string with tag // ",innerxml", Unmarshal accumulates the raw XML nested inside the // element in that field. The rest of the rules still apply. // // * If the struct has a field named XMLName of type xml.Name, // Unmarshal records the element name in that field. // // * If the XMLName field has an associated tag of the form // "name" or "namespace-URL name", the XML element must have // the given name (and, optionally, name space) or else Unmarshal // returns an error. // // * If the XML element has an attribute whose name matches a // struct field name with an associated tag containing ",attr" or // the explicit name in a struct field tag of the form "name,attr", // Unmarshal records the attribute value in that field. // // * If the XML element contains character data, that data is // accumulated in the first struct field that has tag ",chardata". // The struct field may have type []byte or string. // If there is no such field, the character data is discarded. // // * If the XML element contains comments, they are accumulated in // the first struct field that has tag ",comment". The struct // field may have type []byte or string. If there is no such // field, the comments are discarded. // // * If the XML element contains a sub-element whose name matches // the prefix of a tag formatted as "a" or "a>b>c", unmarshal // will descend into the XML structure looking for elements with the // given names, and will map the innermost elements to that struct // field. A tag starting with ">" is equivalent to one starting // with the field name followed by ">". // // * If the XML element contains a sub-element whose name matches // a struct field's XMLName tag and the struct field has no // explicit name tag as per the previous rule, unmarshal maps // the sub-element to that struct field. // // * If the XML element contains a sub-element whose name matches a // field without any mode flags (",attr", ",chardata", etc), Unmarshal // maps the sub-element to that struct field. // // * If the XML element contains a sub-element that hasn't matched any // of the above rules and the struct has a field with tag ",any", // unmarshal maps the sub-element to that struct field. // // * An anonymous struct field is handled as if the fields of its // value were part of the outer struct. // // * A struct field with tag "-" is never unmarshalled into. // // Unmarshal maps an XML element to a string or []byte by saving the // concatenation of that element's character data in the string or // []byte. The saved []byte is never nil. // // Unmarshal maps an attribute value to a string or []byte by saving // the value in the string or slice. // // Unmarshal maps an XML element to a slice by extending the length of // the slice and mapping the element to the newly created value. // // Unmarshal maps an XML element or attribute value to a bool by // setting it to the boolean value represented by the string. // // Unmarshal maps an XML element or attribute value to an integer or // floating-point field by setting the field to the result of // interpreting the string value in decimal. There is no check for // overflow. // // Unmarshal maps an XML element to an xml.Name by recording the // element name. // // Unmarshal maps an XML element to a pointer by setting the pointer // to a freshly allocated value and then mapping the element to that value. // func Unmarshal(data []byte, v interface{}) error { return NewDecoder(bytes.NewReader(data)).Decode(v) } // Decode works like xml.Unmarshal, except it reads the decoder // stream to find the start element. func (d *Decoder) Decode(v interface{}) error { return d.DecodeElement(v, nil) } // DecodeElement works like xml.Unmarshal except that it takes // a pointer to the start XML element to decode into v. // It is useful when a client reads some raw XML tokens itself // but also wants to defer to Unmarshal for some elements. func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error { val := reflect.ValueOf(v) if val.Kind() != reflect.Ptr { return errors.New("non-pointer passed to Unmarshal") } return d.unmarshal(val.Elem(), start) } // An UnmarshalError represents an error in the unmarshalling process. type UnmarshalError string func (e UnmarshalError) Error() string { return string(e) } // Unmarshaler is the interface implemented by objects that can unmarshal // an XML element description of themselves. // // UnmarshalXML decodes a single XML element // beginning with the given start element. // If it returns an error, the outer call to Unmarshal stops and // returns that error. // UnmarshalXML must consume exactly one XML element. // One common implementation strategy is to unmarshal into // a separate value with a layout matching the expected XML // using d.DecodeElement, and then to copy the data from // that value into the receiver. // Another common strategy is to use d.Token to process the // XML object one token at a time. // UnmarshalXML may not use d.RawToken. type Unmarshaler interface { UnmarshalXML(d *Decoder, start StartElement) error } // UnmarshalerAttr is the interface implemented by objects that can unmarshal // an XML attribute description of themselves. // // UnmarshalXMLAttr decodes a single XML attribute. // If it returns an error, the outer call to Unmarshal stops and // returns that error. // UnmarshalXMLAttr is used only for struct fields with the // "attr" option in the field tag. type UnmarshalerAttr interface { UnmarshalXMLAttr(attr Attr) error } // receiverType returns the receiver type to use in an expression like "%s.MethodName". func receiverType(val interface{}) string { t := reflect.TypeOf(val) if t.Name() != "" { return t.String() } return "(" + t.String() + ")" } // unmarshalInterface unmarshals a single XML element into val. // start is the opening tag of the element. func (p *Decoder) unmarshalInterface(val Unmarshaler, start *StartElement) error { // Record that decoder must stop at end tag corresponding to start. p.pushEOF() p.unmarshalDepth++ err := val.UnmarshalXML(p, *start) p.unmarshalDepth-- if err != nil { p.popEOF() return err } if !p.popEOF() { return fmt.Errorf("xml: %s.UnmarshalXML did not consume entire <%s> element", receiverType(val), start.Name.Local) } return nil } // unmarshalTextInterface unmarshals a single XML element into val. // The chardata contained in the element (but not its children) // is passed to the text unmarshaler. func (p *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler, start *StartElement) error { var buf []byte depth := 1 for depth > 0 { t, err := p.Token() if err != nil { return err } switch t := t.(type) { case CharData: if depth == 1 { buf = append(buf, t...) } case StartElement: depth++ case EndElement: depth-- } } return val.UnmarshalText(buf) } // unmarshalAttr unmarshals a single XML attribute into val. func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error { if val.Kind() == reflect.Ptr { if val.IsNil() { val.Set(reflect.New(val.Type().Elem())) } val = val.Elem() } if val.CanInterface() && val.Type().Implements(unmarshalerAttrType) { // This is an unmarshaler with a non-pointer receiver, // so it's likely to be incorrect, but we do what we're told. return val.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr) } if val.CanAddr() { pv := val.Addr() if pv.CanInterface() && pv.Type().Implements(unmarshalerAttrType) { return pv.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr) } } // Not an UnmarshalerAttr; try encoding.TextUnmarshaler. if val.CanInterface() && val.Type().Implements(textUnmarshalerType) { // This is an unmarshaler with a non-pointer receiver, // so it's likely to be incorrect, but we do what we're told. return val.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(attr.Value)) } if val.CanAddr() { pv := val.Addr() if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) { return pv.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(attr.Value)) } } copyValue(val, []byte(attr.Value)) return nil } var ( unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() unmarshalerAttrType = reflect.TypeOf((*UnmarshalerAttr)(nil)).Elem() textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() ) // Unmarshal a single XML element into val. func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { // Find start element if we need it. if start == nil { for { tok, err := p.Token() if err != nil { return err } if t, ok := tok.(StartElement); ok { start = &t break } } } // Load value from interface, but only if the result will be // usefully addressable. if val.Kind() == reflect.Interface && !val.IsNil() { e := val.Elem() if e.Kind() == reflect.Ptr && !e.IsNil() { val = e } } if val.Kind() == reflect.Ptr { if val.IsNil() { val.Set(reflect.New(val.Type().Elem())) } val = val.Elem() } if val.CanInterface() && val.Type().Implements(unmarshalerType) { // This is an unmarshaler with a non-pointer receiver, // so it's likely to be incorrect, but we do what we're told. return p.unmarshalInterface(val.Interface().(Unmarshaler), start) } if val.CanAddr() { pv := val.Addr() if pv.CanInterface() && pv.Type().Implements(unmarshalerType) { return p.unmarshalInterface(pv.Interface().(Unmarshaler), start) } } if val.CanInterface() && val.Type().Implements(textUnmarshalerType) { return p.unmarshalTextInterface(val.Interface().(encoding.TextUnmarshaler), start) } if val.CanAddr() { pv := val.Addr() if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) { return p.unmarshalTextInterface(pv.Interface().(encoding.TextUnmarshaler), start) } } var ( data []byte saveData reflect.Value comment []byte saveComment reflect.Value saveXML reflect.Value saveXMLIndex int saveXMLData []byte saveAny reflect.Value sv reflect.Value tinfo *typeInfo err error ) switch v := val; v.Kind() { default: return errors.New("unknown type " + v.Type().String()) case reflect.Interface: // TODO: For now, simply ignore the field. In the near // future we may choose to unmarshal the start // element on it, if not nil. return p.Skip() case reflect.Slice: typ := v.Type() if typ.Elem().Kind() == reflect.Uint8 { // []byte saveData = v break } // Slice of element values. // Grow slice. n := v.Len() if n >= v.Cap() { ncap := 2 * n if ncap < 4 { ncap = 4 } new := reflect.MakeSlice(typ, n, ncap) reflect.Copy(new, v) v.Set(new) } v.SetLen(n + 1) // Recur to read element into slice. if err := p.unmarshal(v.Index(n), start); err != nil { v.SetLen(n) return err } return nil case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.String: saveData = v case reflect.Struct: typ := v.Type() if typ == nameType { v.Set(reflect.ValueOf(start.Name)) break } sv = v tinfo, err = getTypeInfo(typ) if err != nil { return err } // Validate and assign element name. if tinfo.xmlname != nil { finfo := tinfo.xmlname if finfo.name != "" && finfo.name != start.Name.Local { return UnmarshalError("expected element type <" + finfo.name + "> but have <" + start.Name.Local + ">") } if finfo.xmlns != "" && finfo.xmlns != start.Name.Space { e := "expected element <" + finfo.name + "> in name space " + finfo.xmlns + " but have " if start.Name.Space == "" { e += "no name space" } else { e += start.Name.Space } return UnmarshalError(e) } fv := finfo.value(sv) if _, ok := fv.Interface().(Name); ok { fv.Set(reflect.ValueOf(start.Name)) } } // Assign attributes. // Also, determine whether we need to save character data or comments. for i := range tinfo.fields { finfo := &tinfo.fields[i] switch finfo.flags & fMode { case fAttr: strv := finfo.value(sv) // Look for attribute. for _, a := range start.Attr { if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) { if err := p.unmarshalAttr(strv, a); err != nil { return err } break } } case fCharData: if !saveData.IsValid() { saveData = finfo.value(sv) } case fComment: if !saveComment.IsValid() { saveComment = finfo.value(sv) } case fAny, fAny | fElement: if !saveAny.IsValid() { saveAny = finfo.value(sv) } case fInnerXml: if !saveXML.IsValid() { saveXML = finfo.value(sv) if p.saved == nil { saveXMLIndex = 0 p.saved = new(bytes.Buffer) } else { saveXMLIndex = p.savedOffset() } } } } } // Find end element. // Process sub-elements along the way. Loop: for { var savedOffset int if saveXML.IsValid() { savedOffset = p.savedOffset() } tok, err := p.Token() if err != nil { return err } switch t := tok.(type) { case StartElement: consumed := false if sv.IsValid() { consumed, err = p.unmarshalPath(tinfo, sv, nil, &t) if err != nil { return err } if !consumed && saveAny.IsValid() { consumed = true if err := p.unmarshal(saveAny, &t); err != nil { return err } } } if !consumed { if err := p.Skip(); err != nil { return err } } case EndElement: if saveXML.IsValid() { saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset] if saveXMLIndex == 0 { p.saved = nil } } break Loop case CharData: if saveData.IsValid() { data = append(data, t...) } case Comment: if saveComment.IsValid() { comment = append(comment, t...) } } } if saveData.IsValid() && saveData.CanInterface() && saveData.Type().Implements(textUnmarshalerType) { if err := saveData.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil { return err } saveData = reflect.Value{} } if saveData.IsValid() && saveData.CanAddr() { pv := saveData.Addr() if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) { if err := pv.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil { return err } saveData = reflect.Value{} } } if err := copyValue(saveData, data); err != nil { return err } switch t := saveComment; t.Kind() { case reflect.String: t.SetString(string(comment)) case reflect.Slice: t.Set(reflect.ValueOf(comment)) } switch t := saveXML; t.Kind() { case reflect.String: t.SetString(string(saveXMLData)) case reflect.Slice: t.Set(reflect.ValueOf(saveXMLData)) } return nil } func copyValue(dst reflect.Value, src []byte) (err error) { dst0 := dst if dst.Kind() == reflect.Ptr { if dst.IsNil() { dst.Set(reflect.New(dst.Type().Elem())) } dst = dst.Elem() } // Save accumulated data. switch dst.Kind() { case reflect.Invalid: // Probably a comment. default: return errors.New("cannot unmarshal into " + dst0.Type().String()) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: itmp, err := strconv.ParseInt(string(src), 10, dst.Type().Bits()) if err != nil { return err } dst.SetInt(itmp) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: utmp, err := strconv.ParseUint(string(src), 10, dst.Type().Bits()) if err != nil { return err } dst.SetUint(utmp) case reflect.Float32, reflect.Float64: ftmp, err := strconv.ParseFloat(string(src), dst.Type().Bits()) if err != nil { return err } dst.SetFloat(ftmp) case reflect.Bool: value, err := strconv.ParseBool(strings.TrimSpace(string(src))) if err != nil { return err } dst.SetBool(value) case reflect.String: dst.SetString(string(src)) case reflect.Slice: if len(src) == 0 { // non-nil to flag presence src = []byte{} } dst.SetBytes(src) } return nil } // unmarshalPath walks down an XML structure looking for wanted // paths, and calls unmarshal on them. // The consumed result tells whether XML elements have been consumed // from the Decoder until start's matching end element, or if it's // still untouched because start is uninteresting for sv's fields. func (p *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement) (consumed bool, err error) { recurse := false Loop: for i := range tinfo.fields { finfo := &tinfo.fields[i] if finfo.flags&fElement == 0 || len(finfo.parents) < len(parents) || finfo.xmlns != "" && finfo.xmlns != start.Name.Space { continue } for j := range parents { if parents[j] != finfo.parents[j] { continue Loop } } if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local { // It's a perfect match, unmarshal the field. return true, p.unmarshal(finfo.value(sv), start) } if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local { // It's a prefix for the field. Break and recurse // since it's not ok for one field path to be itself // the prefix for another field path. recurse = true // We can reuse the same slice as long as we // don't try to append to it. parents = finfo.parents[:len(parents)+1] break } } if !recurse { // We have no business with this element. return false, nil } // The element is not a perfect match for any field, but one // or more fields have the path to this element as a parent // prefix. Recurse and attempt to match these. for { var tok Token tok, err = p.Token() if err != nil { return true, err } switch t := tok.(type) { case StartElement: consumed2, err := p.unmarshalPath(tinfo, sv, parents, &t) if err != nil { return true, err } if !consumed2 { if err := p.Skip(); err != nil { return true, err } } case EndElement: return true, nil } } } // Skip reads tokens until it has consumed the end element // matching the most recent start element already consumed. // It recurs if it encounters a start element, so it can be used to // skip nested structures. // It returns nil if it finds an end element matching the start // element; otherwise it returns an error describing the problem. func (d *Decoder) Skip() error { for { tok, err := d.Token() if err != nil { return err } switch tok.(type) { case StartElement: if err := d.Skip(); err != nil { return err } case EndElement: return nil } } } ================================================ FILE: vendor/golang.org/x/net/webdav/internal/xml/typeinfo.go ================================================ // 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 xml import ( "fmt" "reflect" "strings" "sync" ) // typeInfo holds details for the xml representation of a type. type typeInfo struct { xmlname *fieldInfo fields []fieldInfo } // fieldInfo holds details for the xml representation of a single field. type fieldInfo struct { idx []int name string xmlns string flags fieldFlags parents []string } type fieldFlags int const ( fElement fieldFlags = 1 << iota fAttr fCharData fInnerXml fComment fAny fOmitEmpty fMode = fElement | fAttr | fCharData | fInnerXml | fComment | fAny ) var tinfoMap = make(map[reflect.Type]*typeInfo) var tinfoLock sync.RWMutex var nameType = reflect.TypeOf(Name{}) // getTypeInfo returns the typeInfo structure with details necessary // for marshalling and unmarshalling typ. func getTypeInfo(typ reflect.Type) (*typeInfo, error) { tinfoLock.RLock() tinfo, ok := tinfoMap[typ] tinfoLock.RUnlock() if ok { return tinfo, nil } tinfo = &typeInfo{} if typ.Kind() == reflect.Struct && typ != nameType { n := typ.NumField() for i := 0; i < n; i++ { f := typ.Field(i) if f.PkgPath != "" || f.Tag.Get("xml") == "-" { continue // Private field } // For embedded structs, embed its fields. if f.Anonymous { t := f.Type if t.Kind() == reflect.Ptr { t = t.Elem() } if t.Kind() == reflect.Struct { inner, err := getTypeInfo(t) if err != nil { return nil, err } if tinfo.xmlname == nil { tinfo.xmlname = inner.xmlname } for _, finfo := range inner.fields { finfo.idx = append([]int{i}, finfo.idx...) if err := addFieldInfo(typ, tinfo, &finfo); err != nil { return nil, err } } continue } } finfo, err := structFieldInfo(typ, &f) if err != nil { return nil, err } if f.Name == "XMLName" { tinfo.xmlname = finfo continue } // Add the field if it doesn't conflict with other fields. if err := addFieldInfo(typ, tinfo, finfo); err != nil { return nil, err } } } tinfoLock.Lock() tinfoMap[typ] = tinfo tinfoLock.Unlock() return tinfo, nil } // structFieldInfo builds and returns a fieldInfo for f. func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, error) { finfo := &fieldInfo{idx: f.Index} // Split the tag from the xml namespace if necessary. tag := f.Tag.Get("xml") if i := strings.Index(tag, " "); i >= 0 { finfo.xmlns, tag = tag[:i], tag[i+1:] } // Parse flags. tokens := strings.Split(tag, ",") if len(tokens) == 1 { finfo.flags = fElement } else { tag = tokens[0] for _, flag := range tokens[1:] { switch flag { case "attr": finfo.flags |= fAttr case "chardata": finfo.flags |= fCharData case "innerxml": finfo.flags |= fInnerXml case "comment": finfo.flags |= fComment case "any": finfo.flags |= fAny case "omitempty": finfo.flags |= fOmitEmpty } } // Validate the flags used. valid := true switch mode := finfo.flags & fMode; mode { case 0: finfo.flags |= fElement case fAttr, fCharData, fInnerXml, fComment, fAny: if f.Name == "XMLName" || tag != "" && mode != fAttr { valid = false } default: // This will also catch multiple modes in a single field. valid = false } if finfo.flags&fMode == fAny { finfo.flags |= fElement } if finfo.flags&fOmitEmpty != 0 && finfo.flags&(fElement|fAttr) == 0 { valid = false } if !valid { return nil, fmt.Errorf("xml: invalid tag in field %s of type %s: %q", f.Name, typ, f.Tag.Get("xml")) } } // Use of xmlns without a name is not allowed. if finfo.xmlns != "" && tag == "" { return nil, fmt.Errorf("xml: namespace without name in field %s of type %s: %q", f.Name, typ, f.Tag.Get("xml")) } if f.Name == "XMLName" { // The XMLName field records the XML element name. Don't // process it as usual because its name should default to // empty rather than to the field name. finfo.name = tag return finfo, nil } if tag == "" { // If the name part of the tag is completely empty, get // default from XMLName of underlying struct if feasible, // or field name otherwise. if xmlname := lookupXMLName(f.Type); xmlname != nil { finfo.xmlns, finfo.name = xmlname.xmlns, xmlname.name } else { finfo.name = f.Name } return finfo, nil } if finfo.xmlns == "" && finfo.flags&fAttr == 0 { // If it's an element no namespace specified, get the default // from the XMLName of enclosing struct if possible. if xmlname := lookupXMLName(typ); xmlname != nil { finfo.xmlns = xmlname.xmlns } } // Prepare field name and parents. parents := strings.Split(tag, ">") if parents[0] == "" { parents[0] = f.Name } if parents[len(parents)-1] == "" { return nil, fmt.Errorf("xml: trailing '>' in field %s of type %s", f.Name, typ) } finfo.name = parents[len(parents)-1] if len(parents) > 1 { if (finfo.flags & fElement) == 0 { return nil, fmt.Errorf("xml: %s chain not valid with %s flag", tag, strings.Join(tokens[1:], ",")) } finfo.parents = parents[:len(parents)-1] } // If the field type has an XMLName field, the names must match // so that the behavior of both marshalling and unmarshalling // is straightforward and unambiguous. if finfo.flags&fElement != 0 { ftyp := f.Type xmlname := lookupXMLName(ftyp) if xmlname != nil && xmlname.name != finfo.name { return nil, fmt.Errorf("xml: name %q in tag of %s.%s conflicts with name %q in %s.XMLName", finfo.name, typ, f.Name, xmlname.name, ftyp) } } return finfo, nil } // lookupXMLName returns the fieldInfo for typ's XMLName field // in case it exists and has a valid xml field tag, otherwise // it returns nil. func lookupXMLName(typ reflect.Type) (xmlname *fieldInfo) { for typ.Kind() == reflect.Ptr { typ = typ.Elem() } if typ.Kind() != reflect.Struct { return nil } for i, n := 0, typ.NumField(); i < n; i++ { f := typ.Field(i) if f.Name != "XMLName" { continue } finfo, err := structFieldInfo(typ, &f) if finfo.name != "" && err == nil { return finfo } // Also consider errors as a non-existent field tag // and let getTypeInfo itself report the error. break } return nil } func min(a, b int) int { if a <= b { return a } return b } // addFieldInfo adds finfo to tinfo.fields if there are no // conflicts, or if conflicts arise from previous fields that were // obtained from deeper embedded structures than finfo. In the latter // case, the conflicting entries are dropped. // A conflict occurs when the path (parent + name) to a field is // itself a prefix of another path, or when two paths match exactly. // It is okay for field paths to share a common, shorter prefix. func addFieldInfo(typ reflect.Type, tinfo *typeInfo, newf *fieldInfo) error { var conflicts []int Loop: // First, figure all conflicts. Most working code will have none. for i := range tinfo.fields { oldf := &tinfo.fields[i] if oldf.flags&fMode != newf.flags&fMode { continue } if oldf.xmlns != "" && newf.xmlns != "" && oldf.xmlns != newf.xmlns { continue } minl := min(len(newf.parents), len(oldf.parents)) for p := 0; p < minl; p++ { if oldf.parents[p] != newf.parents[p] { continue Loop } } if len(oldf.parents) > len(newf.parents) { if oldf.parents[len(newf.parents)] == newf.name { conflicts = append(conflicts, i) } } else if len(oldf.parents) < len(newf.parents) { if newf.parents[len(oldf.parents)] == oldf.name { conflicts = append(conflicts, i) } } else { if newf.name == oldf.name { conflicts = append(conflicts, i) } } } // Without conflicts, add the new field and return. if conflicts == nil { tinfo.fields = append(tinfo.fields, *newf) return nil } // If any conflict is shallower, ignore the new field. // This matches the Go field resolution on embedding. for _, i := range conflicts { if len(tinfo.fields[i].idx) < len(newf.idx) { return nil } } // Otherwise, if any of them is at the same depth level, it's an error. for _, i := range conflicts { oldf := &tinfo.fields[i] if len(oldf.idx) == len(newf.idx) { f1 := typ.FieldByIndex(oldf.idx) f2 := typ.FieldByIndex(newf.idx) return &TagPathError{typ, f1.Name, f1.Tag.Get("xml"), f2.Name, f2.Tag.Get("xml")} } } // Otherwise, the new field is shallower, and thus takes precedence, // so drop the conflicting fields from tinfo and append the new one. for c := len(conflicts) - 1; c >= 0; c-- { i := conflicts[c] copy(tinfo.fields[i:], tinfo.fields[i+1:]) tinfo.fields = tinfo.fields[:len(tinfo.fields)-1] } tinfo.fields = append(tinfo.fields, *newf) return nil } // A TagPathError represents an error in the unmarshalling process // caused by the use of field tags with conflicting paths. type TagPathError struct { Struct reflect.Type Field1, Tag1 string Field2, Tag2 string } func (e *TagPathError) Error() string { return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", e.Struct, e.Field1, e.Tag1, e.Field2, e.Tag2) } // value returns v's field value corresponding to finfo. // It's equivalent to v.FieldByIndex(finfo.idx), but initializes // and dereferences pointers as necessary. func (finfo *fieldInfo) value(v reflect.Value) reflect.Value { for i, x := range finfo.idx { if i > 0 { t := v.Type() if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct { if v.IsNil() { v.Set(reflect.New(v.Type().Elem())) } v = v.Elem() } } v = v.Field(x) } return v } ================================================ FILE: vendor/golang.org/x/net/webdav/internal/xml/xml.go ================================================ // 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 xml implements a simple XML 1.0 parser that // understands XML name spaces. package xml // References: // Annotated XML spec: http://www.xml.com/axml/testaxml.htm // XML name spaces: http://www.w3.org/TR/REC-xml-names/ // TODO(rsc): // Test error handling. import ( "bufio" "bytes" "errors" "fmt" "io" "strconv" "strings" "unicode" "unicode/utf8" ) // A SyntaxError represents a syntax error in the XML input stream. type SyntaxError struct { Msg string Line int } func (e *SyntaxError) Error() string { return "XML syntax error on line " + strconv.Itoa(e.Line) + ": " + e.Msg } // A Name represents an XML name (Local) annotated with a name space // identifier (Space). In tokens returned by Decoder.Token, the Space // identifier is given as a canonical URL, not the short prefix used in // the document being parsed. // // As a special case, XML namespace declarations will use the literal // string "xmlns" for the Space field instead of the fully resolved URL. // See Encoder.EncodeToken for more information on namespace encoding // behaviour. type Name struct { Space, Local string } // isNamespace reports whether the name is a namespace-defining name. func (name Name) isNamespace() bool { return name.Local == "xmlns" || name.Space == "xmlns" } // An Attr represents an attribute in an XML element (Name=Value). type Attr struct { Name Name Value string } // A Token is an interface holding one of the token types: // StartElement, EndElement, CharData, Comment, ProcInst, or Directive. type Token interface{} // A StartElement represents an XML start element. type StartElement struct { Name Name Attr []Attr } func (e StartElement) Copy() StartElement { attrs := make([]Attr, len(e.Attr)) copy(attrs, e.Attr) e.Attr = attrs return e } // End returns the corresponding XML end element. func (e StartElement) End() EndElement { return EndElement{e.Name} } // setDefaultNamespace sets the namespace of the element // as the default for all elements contained within it. func (e *StartElement) setDefaultNamespace() { if e.Name.Space == "" { // If there's no namespace on the element, don't // set the default. Strictly speaking this might be wrong, as // we can't tell if the element had no namespace set // or was just using the default namespace. return } // Don't add a default name space if there's already one set. for _, attr := range e.Attr { if attr.Name.Space == "" && attr.Name.Local == "xmlns" { return } } e.Attr = append(e.Attr, Attr{ Name: Name{ Local: "xmlns", }, Value: e.Name.Space, }) } // An EndElement represents an XML end element. type EndElement struct { Name Name } // A CharData represents XML character data (raw text), // in which XML escape sequences have been replaced by // the characters they represent. type CharData []byte func makeCopy(b []byte) []byte { b1 := make([]byte, len(b)) copy(b1, b) return b1 } func (c CharData) Copy() CharData { return CharData(makeCopy(c)) } // A Comment represents an XML comment of the form . // The bytes do not include the comment markers. type Comment []byte func (c Comment) Copy() Comment { return Comment(makeCopy(c)) } // A ProcInst represents an XML processing instruction of the form type ProcInst struct { Target string Inst []byte } func (p ProcInst) Copy() ProcInst { p.Inst = makeCopy(p.Inst) return p } // A Directive represents an XML directive of the form . // The bytes do not include the markers. type Directive []byte func (d Directive) Copy() Directive { return Directive(makeCopy(d)) } // CopyToken returns a copy of a Token. func CopyToken(t Token) Token { switch v := t.(type) { case CharData: return v.Copy() case Comment: return v.Copy() case Directive: return v.Copy() case ProcInst: return v.Copy() case StartElement: return v.Copy() } return t } // A Decoder represents an XML parser reading a particular input stream. // The parser assumes that its input is encoded in UTF-8. type Decoder struct { // Strict defaults to true, enforcing the requirements // of the XML specification. // If set to false, the parser allows input containing common // mistakes: // * If an element is missing an end tag, the parser invents // end tags as necessary to keep the return values from Token // properly balanced. // * In attribute values and character data, unknown or malformed // character entities (sequences beginning with &) are left alone. // // Setting: // // d.Strict = false; // d.AutoClose = HTMLAutoClose; // d.Entity = HTMLEntity // // creates a parser that can handle typical HTML. // // Strict mode does not enforce the requirements of the XML name spaces TR. // In particular it does not reject name space tags using undefined prefixes. // Such tags are recorded with the unknown prefix as the name space URL. Strict bool // When Strict == false, AutoClose indicates a set of elements to // consider closed immediately after they are opened, regardless // of whether an end element is present. AutoClose []string // Entity can be used to map non-standard entity names to string replacements. // The parser behaves as if these standard mappings are present in the map, // regardless of the actual map content: // // "lt": "<", // "gt": ">", // "amp": "&", // "apos": "'", // "quot": `"`, Entity map[string]string // CharsetReader, if non-nil, defines a function to generate // charset-conversion readers, converting from the provided // non-UTF-8 charset into UTF-8. If CharsetReader is nil or // returns an error, parsing stops with an error. One of the // the CharsetReader's result values must be non-nil. CharsetReader func(charset string, input io.Reader) (io.Reader, error) // DefaultSpace sets the default name space used for unadorned tags, // as if the entire XML stream were wrapped in an element containing // the attribute xmlns="DefaultSpace". DefaultSpace string r io.ByteReader buf bytes.Buffer saved *bytes.Buffer stk *stack free *stack needClose bool toClose Name nextToken Token nextByte int ns map[string]string err error line int offset int64 unmarshalDepth int } // NewDecoder creates a new XML parser reading from r. // If r does not implement io.ByteReader, NewDecoder will // do its own buffering. func NewDecoder(r io.Reader) *Decoder { d := &Decoder{ ns: make(map[string]string), nextByte: -1, line: 1, Strict: true, } d.switchToReader(r) return d } // Token returns the next XML token in the input stream. // At the end of the input stream, Token returns nil, io.EOF. // // Slices of bytes in the returned token data refer to the // parser's internal buffer and remain valid only until the next // call to Token. To acquire a copy of the bytes, call CopyToken // or the token's Copy method. // // Token expands self-closing elements such as
// into separate start and end elements returned by successive calls. // // Token guarantees that the StartElement and EndElement // tokens it returns are properly nested and matched: // if Token encounters an unexpected end element, // it will return an error. // // Token implements XML name spaces as described by // http://www.w3.org/TR/REC-xml-names/. Each of the // Name structures contained in the Token has the Space // set to the URL identifying its name space when known. // If Token encounters an unrecognized name space prefix, // it uses the prefix as the Space rather than report an error. func (d *Decoder) Token() (t Token, err error) { if d.stk != nil && d.stk.kind == stkEOF { err = io.EOF return } if d.nextToken != nil { t = d.nextToken d.nextToken = nil } else if t, err = d.rawToken(); err != nil { return } if !d.Strict { if t1, ok := d.autoClose(t); ok { d.nextToken = t t = t1 } } switch t1 := t.(type) { case StartElement: // In XML name spaces, the translations listed in the // attributes apply to the element name and // to the other attribute names, so process // the translations first. for _, a := range t1.Attr { if a.Name.Space == "xmlns" { v, ok := d.ns[a.Name.Local] d.pushNs(a.Name.Local, v, ok) d.ns[a.Name.Local] = a.Value } if a.Name.Space == "" && a.Name.Local == "xmlns" { // Default space for untagged names v, ok := d.ns[""] d.pushNs("", v, ok) d.ns[""] = a.Value } } d.translate(&t1.Name, true) for i := range t1.Attr { d.translate(&t1.Attr[i].Name, false) } d.pushElement(t1.Name) t = t1 case EndElement: d.translate(&t1.Name, true) if !d.popElement(&t1) { return nil, d.err } t = t1 } return } const xmlURL = "http://www.w3.org/XML/1998/namespace" // Apply name space translation to name n. // The default name space (for Space=="") // applies only to element names, not to attribute names. func (d *Decoder) translate(n *Name, isElementName bool) { switch { case n.Space == "xmlns": return case n.Space == "" && !isElementName: return case n.Space == "xml": n.Space = xmlURL case n.Space == "" && n.Local == "xmlns": return } if v, ok := d.ns[n.Space]; ok { n.Space = v } else if n.Space == "" { n.Space = d.DefaultSpace } } func (d *Decoder) switchToReader(r io.Reader) { // Get efficient byte at a time reader. // Assume that if reader has its own // ReadByte, it's efficient enough. // Otherwise, use bufio. if rb, ok := r.(io.ByteReader); ok { d.r = rb } else { d.r = bufio.NewReader(r) } } // Parsing state - stack holds old name space translations // and the current set of open elements. The translations to pop when // ending a given tag are *below* it on the stack, which is // more work but forced on us by XML. type stack struct { next *stack kind int name Name ok bool } const ( stkStart = iota stkNs stkEOF ) func (d *Decoder) push(kind int) *stack { s := d.free if s != nil { d.free = s.next } else { s = new(stack) } s.next = d.stk s.kind = kind d.stk = s return s } func (d *Decoder) pop() *stack { s := d.stk if s != nil { d.stk = s.next s.next = d.free d.free = s } return s } // Record that after the current element is finished // (that element is already pushed on the stack) // Token should return EOF until popEOF is called. func (d *Decoder) pushEOF() { // Walk down stack to find Start. // It might not be the top, because there might be stkNs // entries above it. start := d.stk for start.kind != stkStart { start = start.next } // The stkNs entries below a start are associated with that // element too; skip over them. for start.next != nil && start.next.kind == stkNs { start = start.next } s := d.free if s != nil { d.free = s.next } else { s = new(stack) } s.kind = stkEOF s.next = start.next start.next = s } // Undo a pushEOF. // The element must have been finished, so the EOF should be at the top of the stack. func (d *Decoder) popEOF() bool { if d.stk == nil || d.stk.kind != stkEOF { return false } d.pop() return true } // Record that we are starting an element with the given name. func (d *Decoder) pushElement(name Name) { s := d.push(stkStart) s.name = name } // Record that we are changing the value of ns[local]. // The old value is url, ok. func (d *Decoder) pushNs(local string, url string, ok bool) { s := d.push(stkNs) s.name.Local = local s.name.Space = url s.ok = ok } // Creates a SyntaxError with the current line number. func (d *Decoder) syntaxError(msg string) error { return &SyntaxError{Msg: msg, Line: d.line} } // Record that we are ending an element with the given name. // The name must match the record at the top of the stack, // which must be a pushElement record. // After popping the element, apply any undo records from // the stack to restore the name translations that existed // before we saw this element. func (d *Decoder) popElement(t *EndElement) bool { s := d.pop() name := t.Name switch { case s == nil || s.kind != stkStart: d.err = d.syntaxError("unexpected end element ") return false case s.name.Local != name.Local: if !d.Strict { d.needClose = true d.toClose = t.Name t.Name = s.name return true } d.err = d.syntaxError("element <" + s.name.Local + "> closed by ") return false case s.name.Space != name.Space: d.err = d.syntaxError("element <" + s.name.Local + "> in space " + s.name.Space + "closed by in space " + name.Space) return false } // Pop stack until a Start or EOF is on the top, undoing the // translations that were associated with the element we just closed. for d.stk != nil && d.stk.kind != stkStart && d.stk.kind != stkEOF { s := d.pop() if s.ok { d.ns[s.name.Local] = s.name.Space } else { delete(d.ns, s.name.Local) } } return true } // If the top element on the stack is autoclosing and // t is not the end tag, invent the end tag. func (d *Decoder) autoClose(t Token) (Token, bool) { if d.stk == nil || d.stk.kind != stkStart { return nil, false } name := strings.ToLower(d.stk.name.Local) for _, s := range d.AutoClose { if strings.ToLower(s) == name { // This one should be auto closed if t doesn't close it. et, ok := t.(EndElement) if !ok || et.Name.Local != name { return EndElement{d.stk.name}, true } break } } return nil, false } var errRawToken = errors.New("xml: cannot use RawToken from UnmarshalXML method") // RawToken is like Token but does not verify that // start and end elements match and does not translate // name space prefixes to their corresponding URLs. func (d *Decoder) RawToken() (Token, error) { if d.unmarshalDepth > 0 { return nil, errRawToken } return d.rawToken() } func (d *Decoder) rawToken() (Token, error) { if d.err != nil { return nil, d.err } if d.needClose { // The last element we read was self-closing and // we returned just the StartElement half. // Return the EndElement half now. d.needClose = false return EndElement{d.toClose}, nil } b, ok := d.getc() if !ok { return nil, d.err } if b != '<' { // Text section. d.ungetc(b) data := d.text(-1, false) if data == nil { return nil, d.err } return CharData(data), nil } if b, ok = d.mustgetc(); !ok { return nil, d.err } switch b { case '/': // ' { d.err = d.syntaxError("invalid characters between ") return nil, d.err } return EndElement{name}, nil case '?': // ' { break } b0 = b } data := d.buf.Bytes() data = data[0 : len(data)-2] // chop ?> if target == "xml" { content := string(data) ver := procInst("version", content) if ver != "" && ver != "1.0" { d.err = fmt.Errorf("xml: unsupported version %q; only version 1.0 is supported", ver) return nil, d.err } enc := procInst("encoding", content) if enc != "" && enc != "utf-8" && enc != "UTF-8" { if d.CharsetReader == nil { d.err = fmt.Errorf("xml: encoding %q declared but Decoder.CharsetReader is nil", enc) return nil, d.err } newr, err := d.CharsetReader(enc, d.r.(io.Reader)) if err != nil { d.err = fmt.Errorf("xml: opening charset %q: %v", enc, err) return nil, d.err } if newr == nil { panic("CharsetReader returned a nil Reader for charset " + enc) } d.switchToReader(newr) } } return ProcInst{target, data}, nil case '!': // ' { break } b0, b1 = b1, b } data := d.buf.Bytes() data = data[0 : len(data)-3] // chop --> return Comment(data), nil case '[': // . data := d.text(-1, true) if data == nil { return nil, d.err } return CharData(data), nil } // Probably a directive: , , etc. // We don't care, but accumulate for caller. Quoted angle // brackets do not count for nesting. d.buf.Reset() d.buf.WriteByte(b) inquote := uint8(0) depth := 0 for { if b, ok = d.mustgetc(); !ok { return nil, d.err } if inquote == 0 && b == '>' && depth == 0 { break } HandleB: d.buf.WriteByte(b) switch { case b == inquote: inquote = 0 case inquote != 0: // in quotes, no special action case b == '\'' || b == '"': inquote = b case b == '>' && inquote == 0: depth-- case b == '<' && inquote == 0: // Look for // // the ast.BinaryExpr(+) node is considered to enclose interval B // even though its [Pos()..End()) is actually only interval A. // This behaviour makes user interfaces more tolerant of imperfect // input. // // This function treats tokens as nodes, though they are not included // in the result. e.g. PathEnclosingInterval("+") returns the // enclosing ast.BinaryExpr("x + y"). // // If start==end, the 1-char interval following start is used instead. // // The 'exact' result is true if the interval contains only path[0] // and perhaps some adjacent whitespace. It is false if the interval // overlaps multiple children of path[0], or if it contains only // interior whitespace of path[0]. // In this example: // // z := x + y // add them // <--C--> <---E--> // ^ // D // // intervals C, D and E are inexact. C is contained by the // z-assignment statement, because it spans three of its children (:=, // x, +). So too is the 1-char interval D, because it contains only // interior whitespace of the assignment. E is considered interior // whitespace of the BlockStmt containing the assignment. // // Precondition: [start, end) both lie within the same file as root. // TODO(adonovan): return (nil, false) in this case and remove precond. // Requires FileSet; see loader.tokenFileContainsPos. // // Postcondition: path is never nil; it always contains at least 'root'. // func PathEnclosingInterval(root *ast.File, start, end token.Pos) (path []ast.Node, exact bool) { // fmt.Printf("EnclosingInterval %d %d\n", start, end) // debugging // Precondition: node.[Pos..End) and adjoining whitespace contain [start, end). var visit func(node ast.Node) bool visit = func(node ast.Node) bool { path = append(path, node) nodePos := node.Pos() nodeEnd := node.End() // fmt.Printf("visit(%T, %d, %d)\n", node, nodePos, nodeEnd) // debugging // Intersect [start, end) with interval of node. if start < nodePos { start = nodePos } if end > nodeEnd { end = nodeEnd } // Find sole child that contains [start, end). children := childrenOf(node) l := len(children) for i, child := range children { // [childPos, childEnd) is unaugmented interval of child. childPos := child.Pos() childEnd := child.End() // [augPos, augEnd) is whitespace-augmented interval of child. augPos := childPos augEnd := childEnd if i > 0 { augPos = children[i-1].End() // start of preceding whitespace } if i < l-1 { nextChildPos := children[i+1].Pos() // Does [start, end) lie between child and next child? if start >= augEnd && end <= nextChildPos { return false // inexact match } augEnd = nextChildPos // end of following whitespace } // fmt.Printf("\tchild %d: [%d..%d)\tcontains interval [%d..%d)?\n", // i, augPos, augEnd, start, end) // debugging // Does augmented child strictly contain [start, end)? if augPos <= start && end <= augEnd { _, isToken := child.(tokenNode) return isToken || visit(child) } // Does [start, end) overlap multiple children? // i.e. left-augmented child contains start // but LR-augmented child does not contain end. if start < childEnd && end > augEnd { break } } // No single child contained [start, end), // so node is the result. Is it exact? // (It's tempting to put this condition before the // child loop, but it gives the wrong result in the // case where a node (e.g. ExprStmt) and its sole // child have equal intervals.) if start == nodePos && end == nodeEnd { return true // exact match } return false // inexact: overlaps multiple children } if start > end { start, end = end, start } if start < root.End() && end > root.Pos() { if start == end { end = start + 1 // empty interval => interval of size 1 } exact = visit(root) // Reverse the path: for i, l := 0, len(path); i < l/2; i++ { path[i], path[l-1-i] = path[l-1-i], path[i] } } else { // Selection lies within whitespace preceding the // first (or following the last) declaration in the file. // The result nonetheless always includes the ast.File. path = append(path, root) } return } // tokenNode is a dummy implementation of ast.Node for a single token. // They are used transiently by PathEnclosingInterval but never escape // this package. // type tokenNode struct { pos token.Pos end token.Pos } func (n tokenNode) Pos() token.Pos { return n.pos } func (n tokenNode) End() token.Pos { return n.end } func tok(pos token.Pos, len int) ast.Node { return tokenNode{pos, pos + token.Pos(len)} } // childrenOf returns the direct non-nil children of ast.Node n. // It may include fake ast.Node implementations for bare tokens. // it is not safe to call (e.g.) ast.Walk on such nodes. // func childrenOf(n ast.Node) []ast.Node { var children []ast.Node // First add nodes for all true subtrees. ast.Inspect(n, func(node ast.Node) bool { if node == n { // push n return true // recur } if node != nil { // push child children = append(children, node) } return false // no recursion }) // Then add fake Nodes for bare tokens. switch n := n.(type) { case *ast.ArrayType: children = append(children, tok(n.Lbrack, len("[")), tok(n.Elt.End(), len("]"))) case *ast.AssignStmt: children = append(children, tok(n.TokPos, len(n.Tok.String()))) case *ast.BasicLit: children = append(children, tok(n.ValuePos, len(n.Value))) case *ast.BinaryExpr: children = append(children, tok(n.OpPos, len(n.Op.String()))) case *ast.BlockStmt: children = append(children, tok(n.Lbrace, len("{")), tok(n.Rbrace, len("}"))) case *ast.BranchStmt: children = append(children, tok(n.TokPos, len(n.Tok.String()))) case *ast.CallExpr: children = append(children, tok(n.Lparen, len("(")), tok(n.Rparen, len(")"))) if n.Ellipsis != 0 { children = append(children, tok(n.Ellipsis, len("..."))) } case *ast.CaseClause: if n.List == nil { children = append(children, tok(n.Case, len("default"))) } else { children = append(children, tok(n.Case, len("case"))) } children = append(children, tok(n.Colon, len(":"))) case *ast.ChanType: switch n.Dir { case ast.RECV: children = append(children, tok(n.Begin, len("<-chan"))) case ast.SEND: children = append(children, tok(n.Begin, len("chan<-"))) case ast.RECV | ast.SEND: children = append(children, tok(n.Begin, len("chan"))) } case *ast.CommClause: if n.Comm == nil { children = append(children, tok(n.Case, len("default"))) } else { children = append(children, tok(n.Case, len("case"))) } children = append(children, tok(n.Colon, len(":"))) case *ast.Comment: // nop case *ast.CommentGroup: // nop case *ast.CompositeLit: children = append(children, tok(n.Lbrace, len("{")), tok(n.Rbrace, len("{"))) case *ast.DeclStmt: // nop case *ast.DeferStmt: children = append(children, tok(n.Defer, len("defer"))) case *ast.Ellipsis: children = append(children, tok(n.Ellipsis, len("..."))) case *ast.EmptyStmt: // nop case *ast.ExprStmt: // nop case *ast.Field: // TODO(adonovan): Field.{Doc,Comment,Tag}? case *ast.FieldList: children = append(children, tok(n.Opening, len("(")), tok(n.Closing, len(")"))) case *ast.File: // TODO test: Doc children = append(children, tok(n.Package, len("package"))) case *ast.ForStmt: children = append(children, tok(n.For, len("for"))) case *ast.FuncDecl: // TODO(adonovan): FuncDecl.Comment? // Uniquely, FuncDecl breaks the invariant that // preorder traversal yields tokens in lexical order: // in fact, FuncDecl.Recv precedes FuncDecl.Type.Func. // // As a workaround, we inline the case for FuncType // here and order things correctly. // children = nil // discard ast.Walk(FuncDecl) info subtrees children = append(children, tok(n.Type.Func, len("func"))) if n.Recv != nil { children = append(children, n.Recv) } children = append(children, n.Name) if n.Type.Params != nil { children = append(children, n.Type.Params) } if n.Type.Results != nil { children = append(children, n.Type.Results) } if n.Body != nil { children = append(children, n.Body) } case *ast.FuncLit: // nop case *ast.FuncType: if n.Func != 0 { children = append(children, tok(n.Func, len("func"))) } case *ast.GenDecl: children = append(children, tok(n.TokPos, len(n.Tok.String()))) if n.Lparen != 0 { children = append(children, tok(n.Lparen, len("(")), tok(n.Rparen, len(")"))) } case *ast.GoStmt: children = append(children, tok(n.Go, len("go"))) case *ast.Ident: children = append(children, tok(n.NamePos, len(n.Name))) case *ast.IfStmt: children = append(children, tok(n.If, len("if"))) case *ast.ImportSpec: // TODO(adonovan): ImportSpec.{Doc,EndPos}? case *ast.IncDecStmt: children = append(children, tok(n.TokPos, len(n.Tok.String()))) case *ast.IndexExpr: children = append(children, tok(n.Lbrack, len("{")), tok(n.Rbrack, len("}"))) case *ast.InterfaceType: children = append(children, tok(n.Interface, len("interface"))) case *ast.KeyValueExpr: children = append(children, tok(n.Colon, len(":"))) case *ast.LabeledStmt: children = append(children, tok(n.Colon, len(":"))) case *ast.MapType: children = append(children, tok(n.Map, len("map"))) case *ast.ParenExpr: children = append(children, tok(n.Lparen, len("(")), tok(n.Rparen, len(")"))) case *ast.RangeStmt: children = append(children, tok(n.For, len("for")), tok(n.TokPos, len(n.Tok.String()))) case *ast.ReturnStmt: children = append(children, tok(n.Return, len("return"))) case *ast.SelectStmt: children = append(children, tok(n.Select, len("select"))) case *ast.SelectorExpr: // nop case *ast.SendStmt: children = append(children, tok(n.Arrow, len("<-"))) case *ast.SliceExpr: children = append(children, tok(n.Lbrack, len("[")), tok(n.Rbrack, len("]"))) case *ast.StarExpr: children = append(children, tok(n.Star, len("*"))) case *ast.StructType: children = append(children, tok(n.Struct, len("struct"))) case *ast.SwitchStmt: children = append(children, tok(n.Switch, len("switch"))) case *ast.TypeAssertExpr: children = append(children, tok(n.Lparen-1, len(".")), tok(n.Lparen, len("(")), tok(n.Rparen, len(")"))) case *ast.TypeSpec: // TODO(adonovan): TypeSpec.{Doc,Comment}? case *ast.TypeSwitchStmt: children = append(children, tok(n.Switch, len("switch"))) case *ast.UnaryExpr: children = append(children, tok(n.OpPos, len(n.Op.String()))) case *ast.ValueSpec: // TODO(adonovan): ValueSpec.{Doc,Comment}? case *ast.BadDecl, *ast.BadExpr, *ast.BadStmt: // nop } // TODO(adonovan): opt: merge the logic of ast.Inspect() into // the switch above so we can make interleaved callbacks for // both Nodes and Tokens in the right order and avoid the need // to sort. sort.Sort(byPos(children)) return children } type byPos []ast.Node func (sl byPos) Len() int { return len(sl) } func (sl byPos) Less(i, j int) bool { return sl[i].Pos() < sl[j].Pos() } func (sl byPos) Swap(i, j int) { sl[i], sl[j] = sl[j], sl[i] } // NodeDescription returns a description of the concrete type of n suitable // for a user interface. // // TODO(adonovan): in some cases (e.g. Field, FieldList, Ident, // StarExpr) we could be much more specific given the path to the AST // root. Perhaps we should do that. // func NodeDescription(n ast.Node) string { switch n := n.(type) { case *ast.ArrayType: return "array type" case *ast.AssignStmt: return "assignment" case *ast.BadDecl: return "bad declaration" case *ast.BadExpr: return "bad expression" case *ast.BadStmt: return "bad statement" case *ast.BasicLit: return "basic literal" case *ast.BinaryExpr: return fmt.Sprintf("binary %s operation", n.Op) case *ast.BlockStmt: return "block" case *ast.BranchStmt: switch n.Tok { case token.BREAK: return "break statement" case token.CONTINUE: return "continue statement" case token.GOTO: return "goto statement" case token.FALLTHROUGH: return "fall-through statement" } case *ast.CallExpr: if len(n.Args) == 1 && !n.Ellipsis.IsValid() { return "function call (or conversion)" } return "function call" case *ast.CaseClause: return "case clause" case *ast.ChanType: return "channel type" case *ast.CommClause: return "communication clause" case *ast.Comment: return "comment" case *ast.CommentGroup: return "comment group" case *ast.CompositeLit: return "composite literal" case *ast.DeclStmt: return NodeDescription(n.Decl) + " statement" case *ast.DeferStmt: return "defer statement" case *ast.Ellipsis: return "ellipsis" case *ast.EmptyStmt: return "empty statement" case *ast.ExprStmt: return "expression statement" case *ast.Field: // Can be any of these: // struct {x, y int} -- struct field(s) // struct {T} -- anon struct field // interface {I} -- interface embedding // interface {f()} -- interface method // func (A) func(B) C -- receiver, param(s), result(s) return "field/method/parameter" case *ast.FieldList: return "field/method/parameter list" case *ast.File: return "source file" case *ast.ForStmt: return "for loop" case *ast.FuncDecl: return "function declaration" case *ast.FuncLit: return "function literal" case *ast.FuncType: return "function type" case *ast.GenDecl: switch n.Tok { case token.IMPORT: return "import declaration" case token.CONST: return "constant declaration" case token.TYPE: return "type declaration" case token.VAR: return "variable declaration" } case *ast.GoStmt: return "go statement" case *ast.Ident: return "identifier" case *ast.IfStmt: return "if statement" case *ast.ImportSpec: return "import specification" case *ast.IncDecStmt: if n.Tok == token.INC { return "increment statement" } return "decrement statement" case *ast.IndexExpr: return "index expression" case *ast.InterfaceType: return "interface type" case *ast.KeyValueExpr: return "key/value association" case *ast.LabeledStmt: return "statement label" case *ast.MapType: return "map type" case *ast.Package: return "package" case *ast.ParenExpr: return "parenthesized " + NodeDescription(n.X) case *ast.RangeStmt: return "range loop" case *ast.ReturnStmt: return "return statement" case *ast.SelectStmt: return "select statement" case *ast.SelectorExpr: return "selector" case *ast.SendStmt: return "channel send" case *ast.SliceExpr: return "slice expression" case *ast.StarExpr: return "*-operation" // load/store expr or pointer type case *ast.StructType: return "struct type" case *ast.SwitchStmt: return "switch statement" case *ast.TypeAssertExpr: return "type assertion" case *ast.TypeSpec: return "type specification" case *ast.TypeSwitchStmt: return "type switch" case *ast.UnaryExpr: return fmt.Sprintf("unary %s operation", n.Op) case *ast.ValueSpec: return "value specification" } panic(fmt.Sprintf("unexpected node type: %T", n)) } ================================================ FILE: vendor/golang.org/x/tools/go/ast/astutil/imports.go ================================================ // 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 astutil contains common utilities for working with the Go AST. package astutil // import "golang.org/x/tools/go/ast/astutil" import ( "fmt" "go/ast" "go/token" "strconv" "strings" ) // AddImport adds the import path to the file f, if absent. func AddImport(fset *token.FileSet, f *ast.File, path string) (added bool) { return AddNamedImport(fset, f, "", path) } // AddNamedImport adds the import with the given name and path to the file f, if absent. // If name is not empty, it is used to rename the import. // // For example, calling // AddNamedImport(fset, f, "pathpkg", "path") // adds // import pathpkg "path" func AddNamedImport(fset *token.FileSet, f *ast.File, name, path string) (added bool) { if imports(f, name, path) { return false } newImport := &ast.ImportSpec{ Path: &ast.BasicLit{ Kind: token.STRING, Value: strconv.Quote(path), }, } if name != "" { newImport.Name = &ast.Ident{Name: name} } // Find an import decl to add to. // The goal is to find an existing import // whose import path has the longest shared // prefix with path. var ( bestMatch = -1 // length of longest shared prefix lastImport = -1 // index in f.Decls of the file's final import decl impDecl *ast.GenDecl // import decl containing the best match impIndex = -1 // spec index in impDecl containing the best match isThirdPartyPath = isThirdParty(path) ) for i, decl := range f.Decls { gen, ok := decl.(*ast.GenDecl) if ok && gen.Tok == token.IMPORT { lastImport = i // Do not add to import "C", to avoid disrupting the // association with its doc comment, breaking cgo. if declImports(gen, "C") { continue } // Match an empty import decl if that's all that is available. if len(gen.Specs) == 0 && bestMatch == -1 { impDecl = gen } // Compute longest shared prefix with imports in this group and find best // matched import spec. // 1. Always prefer import spec with longest shared prefix. // 2. While match length is 0, // - for stdlib package: prefer first import spec. // - for third party package: prefer first third party import spec. // We cannot use last import spec as best match for third party package // because grouped imports are usually placed last by goimports -local // flag. // See issue #19190. seenAnyThirdParty := false for j, spec := range gen.Specs { impspec := spec.(*ast.ImportSpec) p := importPath(impspec) n := matchLen(p, path) if n > bestMatch || (bestMatch == 0 && !seenAnyThirdParty && isThirdPartyPath) { bestMatch = n impDecl = gen impIndex = j } seenAnyThirdParty = seenAnyThirdParty || isThirdParty(p) } } } // If no import decl found, add one after the last import. if impDecl == nil { impDecl = &ast.GenDecl{ Tok: token.IMPORT, } if lastImport >= 0 { impDecl.TokPos = f.Decls[lastImport].End() } else { // There are no existing imports. // Our new import, preceded by a blank line, goes after the package declaration // and after the comment, if any, that starts on the same line as the // package declaration. impDecl.TokPos = f.Package file := fset.File(f.Package) pkgLine := file.Line(f.Package) for _, c := range f.Comments { if file.Line(c.Pos()) > pkgLine { break } // +2 for a blank line impDecl.TokPos = c.End() + 2 } } f.Decls = append(f.Decls, nil) copy(f.Decls[lastImport+2:], f.Decls[lastImport+1:]) f.Decls[lastImport+1] = impDecl } // Insert new import at insertAt. insertAt := 0 if impIndex >= 0 { // insert after the found import insertAt = impIndex + 1 } impDecl.Specs = append(impDecl.Specs, nil) copy(impDecl.Specs[insertAt+1:], impDecl.Specs[insertAt:]) impDecl.Specs[insertAt] = newImport pos := impDecl.Pos() if insertAt > 0 { // If there is a comment after an existing import, preserve the comment // position by adding the new import after the comment. if spec, ok := impDecl.Specs[insertAt-1].(*ast.ImportSpec); ok && spec.Comment != nil { pos = spec.Comment.End() } else { // Assign same position as the previous import, // so that the sorter sees it as being in the same block. pos = impDecl.Specs[insertAt-1].Pos() } } if newImport.Name != nil { newImport.Name.NamePos = pos } newImport.Path.ValuePos = pos newImport.EndPos = pos // Clean up parens. impDecl contains at least one spec. if len(impDecl.Specs) == 1 { // Remove unneeded parens. impDecl.Lparen = token.NoPos } else if !impDecl.Lparen.IsValid() { // impDecl needs parens added. impDecl.Lparen = impDecl.Specs[0].Pos() } f.Imports = append(f.Imports, newImport) if len(f.Decls) <= 1 { return true } // Merge all the import declarations into the first one. var first *ast.GenDecl for i := 0; i < len(f.Decls); i++ { decl := f.Decls[i] gen, ok := decl.(*ast.GenDecl) if !ok || gen.Tok != token.IMPORT || declImports(gen, "C") { continue } if first == nil { first = gen continue // Don't touch the first one. } // We now know there is more than one package in this import // declaration. Ensure that it ends up parenthesized. first.Lparen = first.Pos() // Move the imports of the other import declaration to the first one. for _, spec := range gen.Specs { spec.(*ast.ImportSpec).Path.ValuePos = first.Pos() first.Specs = append(first.Specs, spec) } f.Decls = append(f.Decls[:i], f.Decls[i+1:]...) i-- } return true } func isThirdParty(importPath string) bool { // Third party package import path usually contains "." (".com", ".org", ...) // This logic is taken from golang.org/x/tools/imports package. return strings.Contains(importPath, ".") } // DeleteImport deletes the import path from the file f, if present. // If there are duplicate import declarations, all matching ones are deleted. func DeleteImport(fset *token.FileSet, f *ast.File, path string) (deleted bool) { return DeleteNamedImport(fset, f, "", path) } // DeleteNamedImport deletes the import with the given name and path from the file f, if present. // If there are duplicate import declarations, all matching ones are deleted. func DeleteNamedImport(fset *token.FileSet, f *ast.File, name, path string) (deleted bool) { var delspecs []*ast.ImportSpec var delcomments []*ast.CommentGroup // Find the import nodes that import path, if any. for i := 0; i < len(f.Decls); i++ { decl := f.Decls[i] gen, ok := decl.(*ast.GenDecl) if !ok || gen.Tok != token.IMPORT { continue } for j := 0; j < len(gen.Specs); j++ { spec := gen.Specs[j] impspec := spec.(*ast.ImportSpec) if importName(impspec) != name || importPath(impspec) != path { continue } // We found an import spec that imports path. // Delete it. delspecs = append(delspecs, impspec) deleted = true copy(gen.Specs[j:], gen.Specs[j+1:]) gen.Specs = gen.Specs[:len(gen.Specs)-1] // If this was the last import spec in this decl, // delete the decl, too. if len(gen.Specs) == 0 { copy(f.Decls[i:], f.Decls[i+1:]) f.Decls = f.Decls[:len(f.Decls)-1] i-- break } else if len(gen.Specs) == 1 { if impspec.Doc != nil { delcomments = append(delcomments, impspec.Doc) } if impspec.Comment != nil { delcomments = append(delcomments, impspec.Comment) } for _, cg := range f.Comments { // Found comment on the same line as the import spec. if cg.End() < impspec.Pos() && fset.Position(cg.End()).Line == fset.Position(impspec.Pos()).Line { delcomments = append(delcomments, cg) break } } spec := gen.Specs[0].(*ast.ImportSpec) // Move the documentation right after the import decl. if spec.Doc != nil { for fset.Position(gen.TokPos).Line+1 < fset.Position(spec.Doc.Pos()).Line { fset.File(gen.TokPos).MergeLine(fset.Position(gen.TokPos).Line) } } for _, cg := range f.Comments { if cg.End() < spec.Pos() && fset.Position(cg.End()).Line == fset.Position(spec.Pos()).Line { for fset.Position(gen.TokPos).Line+1 < fset.Position(spec.Pos()).Line { fset.File(gen.TokPos).MergeLine(fset.Position(gen.TokPos).Line) } break } } } if j > 0 { lastImpspec := gen.Specs[j-1].(*ast.ImportSpec) lastLine := fset.Position(lastImpspec.Path.ValuePos).Line line := fset.Position(impspec.Path.ValuePos).Line // We deleted an entry but now there may be // a blank line-sized hole where the import was. if line-lastLine > 1 { // There was a blank line immediately preceding the deleted import, // so there's no need to close the hole. // Do nothing. } else if line != fset.File(gen.Rparen).LineCount() { // There was no blank line. Close the hole. fset.File(gen.Rparen).MergeLine(line) } } j-- } } // Delete imports from f.Imports. for i := 0; i < len(f.Imports); i++ { imp := f.Imports[i] for j, del := range delspecs { if imp == del { copy(f.Imports[i:], f.Imports[i+1:]) f.Imports = f.Imports[:len(f.Imports)-1] copy(delspecs[j:], delspecs[j+1:]) delspecs = delspecs[:len(delspecs)-1] i-- break } } } // Delete comments from f.Comments. for i := 0; i < len(f.Comments); i++ { cg := f.Comments[i] for j, del := range delcomments { if cg == del { copy(f.Comments[i:], f.Comments[i+1:]) f.Comments = f.Comments[:len(f.Comments)-1] copy(delcomments[j:], delcomments[j+1:]) delcomments = delcomments[:len(delcomments)-1] i-- break } } } if len(delspecs) > 0 { panic(fmt.Sprintf("deleted specs from Decls but not Imports: %v", delspecs)) } return } // RewriteImport rewrites any import of path oldPath to path newPath. func RewriteImport(fset *token.FileSet, f *ast.File, oldPath, newPath string) (rewrote bool) { for _, imp := range f.Imports { if importPath(imp) == oldPath { rewrote = true // record old End, because the default is to compute // it using the length of imp.Path.Value. imp.EndPos = imp.End() imp.Path.Value = strconv.Quote(newPath) } } return } // UsesImport reports whether a given import is used. func UsesImport(f *ast.File, path string) (used bool) { spec := importSpec(f, path) if spec == nil { return } name := spec.Name.String() switch name { case "": // If the package name is not explicitly specified, // make an educated guess. This is not guaranteed to be correct. lastSlash := strings.LastIndex(path, "/") if lastSlash == -1 { name = path } else { name = path[lastSlash+1:] } case "_", ".": // Not sure if this import is used - err on the side of caution. return true } ast.Walk(visitFn(func(n ast.Node) { sel, ok := n.(*ast.SelectorExpr) if ok && isTopName(sel.X, name) { used = true } }), f) return } type visitFn func(node ast.Node) func (fn visitFn) Visit(node ast.Node) ast.Visitor { fn(node) return fn } // imports reports whether f has an import with the specified name and path. func imports(f *ast.File, name, path string) bool { for _, s := range f.Imports { if importName(s) == name && importPath(s) == path { return true } } return false } // importSpec returns the import spec if f imports path, // or nil otherwise. func importSpec(f *ast.File, path string) *ast.ImportSpec { for _, s := range f.Imports { if importPath(s) == path { return s } } return nil } // importName returns the name of s, // or "" if the import is not named. func importName(s *ast.ImportSpec) string { if s.Name == nil { return "" } return s.Name.Name } // importPath returns the unquoted import path of s, // or "" if the path is not properly quoted. func importPath(s *ast.ImportSpec) string { t, err := strconv.Unquote(s.Path.Value) if err != nil { return "" } return t } // declImports reports whether gen contains an import of path. func declImports(gen *ast.GenDecl, path string) bool { if gen.Tok != token.IMPORT { return false } for _, spec := range gen.Specs { impspec := spec.(*ast.ImportSpec) if importPath(impspec) == path { return true } } return false } // matchLen returns the length of the longest path segment prefix shared by x and y. func matchLen(x, y string) int { n := 0 for i := 0; i < len(x) && i < len(y) && x[i] == y[i]; i++ { if x[i] == '/' { n++ } } return n } // isTopName returns true if n is a top-level unresolved identifier with the given name. func isTopName(n ast.Expr, name string) bool { id, ok := n.(*ast.Ident) return ok && id.Name == name && id.Obj == nil } // Imports returns the file imports grouped by paragraph. func Imports(fset *token.FileSet, f *ast.File) [][]*ast.ImportSpec { var groups [][]*ast.ImportSpec for _, decl := range f.Decls { genDecl, ok := decl.(*ast.GenDecl) if !ok || genDecl.Tok != token.IMPORT { break } group := []*ast.ImportSpec{} var lastLine int for _, spec := range genDecl.Specs { importSpec := spec.(*ast.ImportSpec) pos := importSpec.Path.ValuePos line := fset.Position(pos).Line if lastLine > 0 && pos > 0 && line-lastLine > 1 { groups = append(groups, group) group = []*ast.ImportSpec{} } group = append(group, importSpec) lastLine = line } groups = append(groups, group) } return groups } ================================================ FILE: vendor/golang.org/x/tools/go/ast/astutil/rewrite.go ================================================ // 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 astutil import ( "fmt" "go/ast" "reflect" "sort" ) // An ApplyFunc is invoked by Apply for each node n, even if n is nil, // before and/or after the node's children, using a Cursor describing // the current node and providing operations on it. // // The return value of ApplyFunc controls the syntax tree traversal. // See Apply for details. type ApplyFunc func(*Cursor) bool // Apply traverses a syntax tree recursively, starting with root, // and calling pre and post for each node as described below. // Apply returns the syntax tree, possibly modified. // // If pre is not nil, it is called for each node before the node's // children are traversed (pre-order). If pre returns false, no // children are traversed, and post is not called for that node. // // If post is not nil, and a prior call of pre didn't return false, // post is called for each node after its children are traversed // (post-order). If post returns false, traversal is terminated and // Apply returns immediately. // // Only fields that refer to AST nodes are considered children; // i.e., token.Pos, Scopes, Objects, and fields of basic types // (strings, etc.) are ignored. // // Children are traversed in the order in which they appear in the // respective node's struct definition. A package's files are // traversed in the filenames' alphabetical order. // func Apply(root ast.Node, pre, post ApplyFunc) (result ast.Node) { parent := &struct{ ast.Node }{root} defer func() { if r := recover(); r != nil && r != abort { panic(r) } result = parent.Node }() a := &application{pre: pre, post: post} a.apply(parent, "Node", nil, root) return } var abort = new(int) // singleton, to signal termination of Apply // A Cursor describes a node encountered during Apply. // Information about the node and its parent is available // from the Node, Parent, Name, and Index methods. // // If p is a variable of type and value of the current parent node // c.Parent(), and f is the field identifier with name c.Name(), // the following invariants hold: // // p.f == c.Node() if c.Index() < 0 // p.f[c.Index()] == c.Node() if c.Index() >= 0 // // The methods Replace, Delete, InsertBefore, and InsertAfter // can be used to change the AST without disrupting Apply. type Cursor struct { parent ast.Node name string iter *iterator // valid if non-nil node ast.Node } // Node returns the current Node. func (c *Cursor) Node() ast.Node { return c.node } // Parent returns the parent of the current Node. func (c *Cursor) Parent() ast.Node { return c.parent } // Name returns the name of the parent Node field that contains the current Node. // If the parent is a *ast.Package and the current Node is a *ast.File, Name returns // the filename for the current Node. func (c *Cursor) Name() string { return c.name } // Index reports the index >= 0 of the current Node in the slice of Nodes that // contains it, or a value < 0 if the current Node is not part of a slice. // The index of the current node changes if InsertBefore is called while // processing the current node. func (c *Cursor) Index() int { if c.iter != nil { return c.iter.index } return -1 } // field returns the current node's parent field value. func (c *Cursor) field() reflect.Value { return reflect.Indirect(reflect.ValueOf(c.parent)).FieldByName(c.name) } // Replace replaces the current Node with n. // The replacement node is not walked by Apply. func (c *Cursor) Replace(n ast.Node) { if _, ok := c.node.(*ast.File); ok { file, ok := n.(*ast.File) if !ok { panic("attempt to replace *ast.File with non-*ast.File") } c.parent.(*ast.Package).Files[c.name] = file return } v := c.field() if i := c.Index(); i >= 0 { v = v.Index(i) } v.Set(reflect.ValueOf(n)) } // Delete deletes the current Node from its containing slice. // If the current Node is not part of a slice, Delete panics. // As a special case, if the current node is a package file, // Delete removes it from the package's Files map. func (c *Cursor) Delete() { if _, ok := c.node.(*ast.File); ok { delete(c.parent.(*ast.Package).Files, c.name) return } i := c.Index() if i < 0 { panic("Delete node not contained in slice") } v := c.field() l := v.Len() reflect.Copy(v.Slice(i, l), v.Slice(i+1, l)) v.Index(l - 1).Set(reflect.Zero(v.Type().Elem())) v.SetLen(l - 1) c.iter.step-- } // InsertAfter inserts n after the current Node in its containing slice. // If the current Node is not part of a slice, InsertAfter panics. // Apply does not walk n. func (c *Cursor) InsertAfter(n ast.Node) { i := c.Index() if i < 0 { panic("InsertAfter node not contained in slice") } v := c.field() v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) l := v.Len() reflect.Copy(v.Slice(i+2, l), v.Slice(i+1, l)) v.Index(i + 1).Set(reflect.ValueOf(n)) c.iter.step++ } // InsertBefore inserts n before the current Node in its containing slice. // If the current Node is not part of a slice, InsertBefore panics. // Apply will not walk n. func (c *Cursor) InsertBefore(n ast.Node) { i := c.Index() if i < 0 { panic("InsertBefore node not contained in slice") } v := c.field() v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) l := v.Len() reflect.Copy(v.Slice(i+1, l), v.Slice(i, l)) v.Index(i).Set(reflect.ValueOf(n)) c.iter.index++ } // application carries all the shared data so we can pass it around cheaply. type application struct { pre, post ApplyFunc cursor Cursor iter iterator } func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast.Node) { // convert typed nil into untyped nil if v := reflect.ValueOf(n); v.Kind() == reflect.Ptr && v.IsNil() { n = nil } // avoid heap-allocating a new cursor for each apply call; reuse a.cursor instead saved := a.cursor a.cursor.parent = parent a.cursor.name = name a.cursor.iter = iter a.cursor.node = n if a.pre != nil && !a.pre(&a.cursor) { a.cursor = saved return } // walk children // (the order of the cases matches the order of the corresponding node types in go/ast) switch n := n.(type) { case nil: // nothing to do // Comments and fields case *ast.Comment: // nothing to do case *ast.CommentGroup: if n != nil { a.applyList(n, "List") } case *ast.Field: a.apply(n, "Doc", nil, n.Doc) a.applyList(n, "Names") a.apply(n, "Type", nil, n.Type) a.apply(n, "Tag", nil, n.Tag) a.apply(n, "Comment", nil, n.Comment) case *ast.FieldList: a.applyList(n, "List") // Expressions case *ast.BadExpr, *ast.Ident, *ast.BasicLit: // nothing to do case *ast.Ellipsis: a.apply(n, "Elt", nil, n.Elt) case *ast.FuncLit: a.apply(n, "Type", nil, n.Type) a.apply(n, "Body", nil, n.Body) case *ast.CompositeLit: a.apply(n, "Type", nil, n.Type) a.applyList(n, "Elts") case *ast.ParenExpr: a.apply(n, "X", nil, n.X) case *ast.SelectorExpr: a.apply(n, "X", nil, n.X) a.apply(n, "Sel", nil, n.Sel) case *ast.IndexExpr: a.apply(n, "X", nil, n.X) a.apply(n, "Index", nil, n.Index) case *ast.SliceExpr: a.apply(n, "X", nil, n.X) a.apply(n, "Low", nil, n.Low) a.apply(n, "High", nil, n.High) a.apply(n, "Max", nil, n.Max) case *ast.TypeAssertExpr: a.apply(n, "X", nil, n.X) a.apply(n, "Type", nil, n.Type) case *ast.CallExpr: a.apply(n, "Fun", nil, n.Fun) a.applyList(n, "Args") case *ast.StarExpr: a.apply(n, "X", nil, n.X) case *ast.UnaryExpr: a.apply(n, "X", nil, n.X) case *ast.BinaryExpr: a.apply(n, "X", nil, n.X) a.apply(n, "Y", nil, n.Y) case *ast.KeyValueExpr: a.apply(n, "Key", nil, n.Key) a.apply(n, "Value", nil, n.Value) // Types case *ast.ArrayType: a.apply(n, "Len", nil, n.Len) a.apply(n, "Elt", nil, n.Elt) case *ast.StructType: a.apply(n, "Fields", nil, n.Fields) case *ast.FuncType: a.apply(n, "Params", nil, n.Params) a.apply(n, "Results", nil, n.Results) case *ast.InterfaceType: a.apply(n, "Methods", nil, n.Methods) case *ast.MapType: a.apply(n, "Key", nil, n.Key) a.apply(n, "Value", nil, n.Value) case *ast.ChanType: a.apply(n, "Value", nil, n.Value) // Statements case *ast.BadStmt: // nothing to do case *ast.DeclStmt: a.apply(n, "Decl", nil, n.Decl) case *ast.EmptyStmt: // nothing to do case *ast.LabeledStmt: a.apply(n, "Label", nil, n.Label) a.apply(n, "Stmt", nil, n.Stmt) case *ast.ExprStmt: a.apply(n, "X", nil, n.X) case *ast.SendStmt: a.apply(n, "Chan", nil, n.Chan) a.apply(n, "Value", nil, n.Value) case *ast.IncDecStmt: a.apply(n, "X", nil, n.X) case *ast.AssignStmt: a.applyList(n, "Lhs") a.applyList(n, "Rhs") case *ast.GoStmt: a.apply(n, "Call", nil, n.Call) case *ast.DeferStmt: a.apply(n, "Call", nil, n.Call) case *ast.ReturnStmt: a.applyList(n, "Results") case *ast.BranchStmt: a.apply(n, "Label", nil, n.Label) case *ast.BlockStmt: a.applyList(n, "List") case *ast.IfStmt: a.apply(n, "Init", nil, n.Init) a.apply(n, "Cond", nil, n.Cond) a.apply(n, "Body", nil, n.Body) a.apply(n, "Else", nil, n.Else) case *ast.CaseClause: a.applyList(n, "List") a.applyList(n, "Body") case *ast.SwitchStmt: a.apply(n, "Init", nil, n.Init) a.apply(n, "Tag", nil, n.Tag) a.apply(n, "Body", nil, n.Body) case *ast.TypeSwitchStmt: a.apply(n, "Init", nil, n.Init) a.apply(n, "Assign", nil, n.Assign) a.apply(n, "Body", nil, n.Body) case *ast.CommClause: a.apply(n, "Comm", nil, n.Comm) a.applyList(n, "Body") case *ast.SelectStmt: a.apply(n, "Body", nil, n.Body) case *ast.ForStmt: a.apply(n, "Init", nil, n.Init) a.apply(n, "Cond", nil, n.Cond) a.apply(n, "Post", nil, n.Post) a.apply(n, "Body", nil, n.Body) case *ast.RangeStmt: a.apply(n, "Key", nil, n.Key) a.apply(n, "Value", nil, n.Value) a.apply(n, "X", nil, n.X) a.apply(n, "Body", nil, n.Body) // Declarations case *ast.ImportSpec: a.apply(n, "Doc", nil, n.Doc) a.apply(n, "Name", nil, n.Name) a.apply(n, "Path", nil, n.Path) a.apply(n, "Comment", nil, n.Comment) case *ast.ValueSpec: a.apply(n, "Doc", nil, n.Doc) a.applyList(n, "Names") a.apply(n, "Type", nil, n.Type) a.applyList(n, "Values") a.apply(n, "Comment", nil, n.Comment) case *ast.TypeSpec: a.apply(n, "Doc", nil, n.Doc) a.apply(n, "Name", nil, n.Name) a.apply(n, "Type", nil, n.Type) a.apply(n, "Comment", nil, n.Comment) case *ast.BadDecl: // nothing to do case *ast.GenDecl: a.apply(n, "Doc", nil, n.Doc) a.applyList(n, "Specs") case *ast.FuncDecl: a.apply(n, "Doc", nil, n.Doc) a.apply(n, "Recv", nil, n.Recv) a.apply(n, "Name", nil, n.Name) a.apply(n, "Type", nil, n.Type) a.apply(n, "Body", nil, n.Body) // Files and packages case *ast.File: a.apply(n, "Doc", nil, n.Doc) a.apply(n, "Name", nil, n.Name) a.applyList(n, "Decls") // Don't walk n.Comments; they have either been walked already if // they are Doc comments, or they can be easily walked explicitly. case *ast.Package: // collect and sort names for reproducible behavior var names []string for name := range n.Files { names = append(names, name) } sort.Strings(names) for _, name := range names { a.apply(n, name, nil, n.Files[name]) } default: panic(fmt.Sprintf("Apply: unexpected node type %T", n)) } if a.post != nil && !a.post(&a.cursor) { panic(abort) } a.cursor = saved } // An iterator controls iteration over a slice of nodes. type iterator struct { index, step int } func (a *application) applyList(parent ast.Node, name string) { // avoid heap-allocating a new iterator for each applyList call; reuse a.iter instead saved := a.iter a.iter.index = 0 for { // must reload parent.name each time, since cursor modifications might change it v := reflect.Indirect(reflect.ValueOf(parent)).FieldByName(name) if a.iter.index >= v.Len() { break } // element x may be nil in a bad AST - be cautious var x ast.Node if e := v.Index(a.iter.index); e.IsValid() { x = e.Interface().(ast.Node) } a.iter.step = 1 a.apply(parent, name, &a.iter, x) a.iter.index += a.iter.step } a.iter = saved } ================================================ FILE: vendor/golang.org/x/tools/go/ast/astutil/util.go ================================================ package astutil import "go/ast" // Unparen returns e with any enclosing parentheses stripped. func Unparen(e ast.Expr) ast.Expr { for { p, ok := e.(*ast.ParenExpr) if !ok { return e } e = p.X } } ================================================ FILE: vendor/golang.org/x/tools/go/buildutil/allpackages.go ================================================ // 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 buildutil provides utilities related to the go/build // package in the standard library. // // All I/O is done via the build.Context file system interface, which must // be concurrency-safe. package buildutil // import "golang.org/x/tools/go/buildutil" import ( "go/build" "os" "path/filepath" "sort" "strings" "sync" ) // AllPackages returns the package path of each Go package in any source // directory of the specified build context (e.g. $GOROOT or an element // of $GOPATH). Errors are ignored. The results are sorted. // All package paths are canonical, and thus may contain "/vendor/". // // The result may include import paths for directories that contain no // *.go files, such as "archive" (in $GOROOT/src). // // All I/O is done via the build.Context file system interface, // which must be concurrency-safe. // func AllPackages(ctxt *build.Context) []string { var list []string ForEachPackage(ctxt, func(pkg string, _ error) { list = append(list, pkg) }) sort.Strings(list) return list } // ForEachPackage calls the found function with the package path of // each Go package it finds in any source directory of the specified // build context (e.g. $GOROOT or an element of $GOPATH). // All package paths are canonical, and thus may contain "/vendor/". // // If the package directory exists but could not be read, the second // argument to the found function provides the error. // // All I/O is done via the build.Context file system interface, // which must be concurrency-safe. // func ForEachPackage(ctxt *build.Context, found func(importPath string, err error)) { ch := make(chan item) var wg sync.WaitGroup for _, root := range ctxt.SrcDirs() { root := root wg.Add(1) go func() { allPackages(ctxt, root, ch) wg.Done() }() } go func() { wg.Wait() close(ch) }() // All calls to found occur in the caller's goroutine. for i := range ch { found(i.importPath, i.err) } } type item struct { importPath string err error // (optional) } // We use a process-wide counting semaphore to limit // the number of parallel calls to ReadDir. var ioLimit = make(chan bool, 20) func allPackages(ctxt *build.Context, root string, ch chan<- item) { root = filepath.Clean(root) + string(os.PathSeparator) var wg sync.WaitGroup var walkDir func(dir string) walkDir = func(dir string) { // Avoid .foo, _foo, and testdata directory trees. base := filepath.Base(dir) if base == "" || base[0] == '.' || base[0] == '_' || base == "testdata" { return } pkg := filepath.ToSlash(strings.TrimPrefix(dir, root)) // Prune search if we encounter any of these import paths. switch pkg { case "builtin": return } ioLimit <- true files, err := ReadDir(ctxt, dir) <-ioLimit if pkg != "" || err != nil { ch <- item{pkg, err} } for _, fi := range files { fi := fi if fi.IsDir() { wg.Add(1) go func() { walkDir(filepath.Join(dir, fi.Name())) wg.Done() }() } } } walkDir(root) wg.Wait() } // ExpandPatterns returns the set of packages matched by patterns, // which may have the following forms: // // golang.org/x/tools/cmd/guru # a single package // golang.org/x/tools/... # all packages beneath dir // ... # the entire workspace. // // Order is significant: a pattern preceded by '-' removes matching // packages from the set. For example, these patterns match all encoding // packages except encoding/xml: // // encoding/... -encoding/xml // // A trailing slash in a pattern is ignored. (Path components of Go // package names are separated by slash, not the platform's path separator.) // func ExpandPatterns(ctxt *build.Context, patterns []string) map[string]bool { // TODO(adonovan): support other features of 'go list': // - "std"/"cmd"/"all" meta-packages // - "..." not at the end of a pattern // - relative patterns using "./" or "../" prefix pkgs := make(map[string]bool) doPkg := func(pkg string, neg bool) { if neg { delete(pkgs, pkg) } else { pkgs[pkg] = true } } // Scan entire workspace if wildcards are present. // TODO(adonovan): opt: scan only the necessary subtrees of the workspace. var all []string for _, arg := range patterns { if strings.HasSuffix(arg, "...") { all = AllPackages(ctxt) break } } for _, arg := range patterns { if arg == "" { continue } neg := arg[0] == '-' if neg { arg = arg[1:] } if arg == "..." { // ... matches all packages for _, pkg := range all { doPkg(pkg, neg) } } else if dir := strings.TrimSuffix(arg, "/..."); dir != arg { // dir/... matches all packages beneath dir for _, pkg := range all { if strings.HasPrefix(pkg, dir) && (len(pkg) == len(dir) || pkg[len(dir)] == '/') { doPkg(pkg, neg) } } } else { // single package doPkg(strings.TrimSuffix(arg, "/"), neg) } } return pkgs } ================================================ FILE: vendor/golang.org/x/tools/go/buildutil/fakecontext.go ================================================ package buildutil import ( "fmt" "go/build" "io" "io/ioutil" "os" "path" "path/filepath" "sort" "strings" "time" ) // FakeContext returns a build.Context for the fake file tree specified // by pkgs, which maps package import paths to a mapping from file base // names to contents. // // The fake Context has a GOROOT of "/go" and no GOPATH, and overrides // the necessary file access methods to read from memory instead of the // real file system. // // Unlike a real file tree, the fake one has only two levels---packages // and files---so ReadDir("/go/src/") returns all packages under // /go/src/ including, for instance, "math" and "math/big". // ReadDir("/go/src/math/big") would return all the files in the // "math/big" package. // func FakeContext(pkgs map[string]map[string]string) *build.Context { clean := func(filename string) string { f := path.Clean(filepath.ToSlash(filename)) // Removing "/go/src" while respecting segment // boundaries has this unfortunate corner case: if f == "/go/src" { return "" } return strings.TrimPrefix(f, "/go/src/") } ctxt := build.Default // copy ctxt.GOROOT = "/go" ctxt.GOPATH = "" ctxt.Compiler = "gc" ctxt.IsDir = func(dir string) bool { dir = clean(dir) if dir == "" { return true // needed by (*build.Context).SrcDirs } return pkgs[dir] != nil } ctxt.ReadDir = func(dir string) ([]os.FileInfo, error) { dir = clean(dir) var fis []os.FileInfo if dir == "" { // enumerate packages for importPath := range pkgs { fis = append(fis, fakeDirInfo(importPath)) } } else { // enumerate files of package for basename := range pkgs[dir] { fis = append(fis, fakeFileInfo(basename)) } } sort.Sort(byName(fis)) return fis, nil } ctxt.OpenFile = func(filename string) (io.ReadCloser, error) { filename = clean(filename) dir, base := path.Split(filename) content, ok := pkgs[path.Clean(dir)][base] if !ok { return nil, fmt.Errorf("file not found: %s", filename) } return ioutil.NopCloser(strings.NewReader(content)), nil } ctxt.IsAbsPath = func(path string) bool { path = filepath.ToSlash(path) // Don't rely on the default (filepath.Path) since on // Windows, it reports virtual paths as non-absolute. return strings.HasPrefix(path, "/") } return &ctxt } type byName []os.FileInfo func (s byName) Len() int { return len(s) } func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() } type fakeFileInfo string func (fi fakeFileInfo) Name() string { return string(fi) } func (fakeFileInfo) Sys() interface{} { return nil } func (fakeFileInfo) ModTime() time.Time { return time.Time{} } func (fakeFileInfo) IsDir() bool { return false } func (fakeFileInfo) Size() int64 { return 0 } func (fakeFileInfo) Mode() os.FileMode { return 0644 } type fakeDirInfo string func (fd fakeDirInfo) Name() string { return string(fd) } func (fakeDirInfo) Sys() interface{} { return nil } func (fakeDirInfo) ModTime() time.Time { return time.Time{} } func (fakeDirInfo) IsDir() bool { return true } func (fakeDirInfo) Size() int64 { return 0 } func (fakeDirInfo) Mode() os.FileMode { return 0755 } ================================================ FILE: vendor/golang.org/x/tools/go/buildutil/overlay.go ================================================ // 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 buildutil import ( "bufio" "bytes" "fmt" "go/build" "io" "io/ioutil" "path/filepath" "strconv" "strings" ) // OverlayContext overlays a build.Context with additional files from // a map. Files in the map take precedence over other files. // // In addition to plain string comparison, two file names are // considered equal if their base names match and their directory // components point at the same directory on the file system. That is, // symbolic links are followed for directories, but not files. // // A common use case for OverlayContext is to allow editors to pass in // a set of unsaved, modified files. // // Currently, only the Context.OpenFile function will respect the // overlay. This may change in the future. func OverlayContext(orig *build.Context, overlay map[string][]byte) *build.Context { // TODO(dominikh): Implement IsDir, HasSubdir and ReadDir rc := func(data []byte) (io.ReadCloser, error) { return ioutil.NopCloser(bytes.NewBuffer(data)), nil } copy := *orig // make a copy ctxt := © ctxt.OpenFile = func(path string) (io.ReadCloser, error) { // Fast path: names match exactly. if content, ok := overlay[path]; ok { return rc(content) } // Slow path: check for same file under a different // alias, perhaps due to a symbolic link. for filename, content := range overlay { if sameFile(path, filename) { return rc(content) } } return OpenFile(orig, path) } return ctxt } // ParseOverlayArchive parses an archive containing Go files and their // contents. The result is intended to be used with OverlayContext. // // // Archive format // // The archive consists of a series of files. Each file consists of a // name, a decimal file size and the file contents, separated by // newlinews. No newline follows after the file contents. func ParseOverlayArchive(archive io.Reader) (map[string][]byte, error) { overlay := make(map[string][]byte) r := bufio.NewReader(archive) for { // Read file name. filename, err := r.ReadString('\n') if err != nil { if err == io.EOF { break // OK } return nil, fmt.Errorf("reading archive file name: %v", err) } filename = filepath.Clean(strings.TrimSpace(filename)) // Read file size. sz, err := r.ReadString('\n') if err != nil { return nil, fmt.Errorf("reading size of archive file %s: %v", filename, err) } sz = strings.TrimSpace(sz) size, err := strconv.ParseUint(sz, 10, 32) if err != nil { return nil, fmt.Errorf("parsing size of archive file %s: %v", filename, err) } // Read file content. content := make([]byte, size) if _, err := io.ReadFull(r, content); err != nil { return nil, fmt.Errorf("reading archive file %s: %v", filename, err) } overlay[filename] = content } return overlay, nil } ================================================ FILE: vendor/golang.org/x/tools/go/buildutil/tags.go ================================================ package buildutil // This logic was copied from stringsFlag from $GOROOT/src/cmd/go/build.go. import "fmt" const TagsFlagDoc = "a list of `build tags` to consider satisfied during the build. " + "For more information about build tags, see the description of " + "build constraints in the documentation for the go/build package" // TagsFlag is an implementation of the flag.Value and flag.Getter interfaces that parses // a flag value in the same manner as go build's -tags flag and // populates a []string slice. // // See $GOROOT/src/go/build/doc.go for description of build tags. // See $GOROOT/src/cmd/go/doc.go for description of 'go build -tags' flag. // // Example: // flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc) type TagsFlag []string func (v *TagsFlag) Set(s string) error { var err error *v, err = splitQuotedFields(s) if *v == nil { *v = []string{} } return err } func (v *TagsFlag) Get() interface{} { return *v } func splitQuotedFields(s string) ([]string, error) { // Split fields allowing '' or "" around elements. // Quotes further inside the string do not count. var f []string for len(s) > 0 { for len(s) > 0 && isSpaceByte(s[0]) { s = s[1:] } if len(s) == 0 { break } // Accepted quoted string. No unescaping inside. if s[0] == '"' || s[0] == '\'' { quote := s[0] s = s[1:] i := 0 for i < len(s) && s[i] != quote { i++ } if i >= len(s) { return nil, fmt.Errorf("unterminated %c string", quote) } f = append(f, s[:i]) s = s[i+1:] continue } i := 0 for i < len(s) && !isSpaceByte(s[i]) { i++ } f = append(f, s[:i]) s = s[i:] } return f, nil } func (v *TagsFlag) String() string { return "" } func isSpaceByte(c byte) bool { return c == ' ' || c == '\t' || c == '\n' || c == '\r' } ================================================ FILE: vendor/golang.org/x/tools/go/buildutil/util.go ================================================ // 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 buildutil import ( "fmt" "go/ast" "go/build" "go/parser" "go/token" "io" "io/ioutil" "os" "path" "path/filepath" "strings" ) // ParseFile behaves like parser.ParseFile, // but uses the build context's file system interface, if any. // // If file is not absolute (as defined by IsAbsPath), the (dir, file) // components are joined using JoinPath; dir must be absolute. // // The displayPath function, if provided, is used to transform the // filename that will be attached to the ASTs. // // TODO(adonovan): call this from go/loader.parseFiles when the tree thaws. // func ParseFile(fset *token.FileSet, ctxt *build.Context, displayPath func(string) string, dir string, file string, mode parser.Mode) (*ast.File, error) { if !IsAbsPath(ctxt, file) { file = JoinPath(ctxt, dir, file) } rd, err := OpenFile(ctxt, file) if err != nil { return nil, err } defer rd.Close() // ignore error if displayPath != nil { file = displayPath(file) } return parser.ParseFile(fset, file, rd, mode) } // ContainingPackage returns the package containing filename. // // If filename is not absolute, it is interpreted relative to working directory dir. // All I/O is via the build context's file system interface, if any. // // The '...Files []string' fields of the resulting build.Package are not // populated (build.FindOnly mode). // func ContainingPackage(ctxt *build.Context, dir, filename string) (*build.Package, error) { if !IsAbsPath(ctxt, filename) { filename = JoinPath(ctxt, dir, filename) } // We must not assume the file tree uses // "/" always, // `\` always, // or os.PathSeparator (which varies by platform), // but to make any progress, we are forced to assume that // paths will not use `\` unless the PathSeparator // is also `\`, thus we can rely on filepath.ToSlash for some sanity. dirSlash := path.Dir(filepath.ToSlash(filename)) + "/" // We assume that no source root (GOPATH[i] or GOROOT) contains any other. for _, srcdir := range ctxt.SrcDirs() { srcdirSlash := filepath.ToSlash(srcdir) + "/" if importPath, ok := HasSubdir(ctxt, srcdirSlash, dirSlash); ok { return ctxt.Import(importPath, dir, build.FindOnly) } } return nil, fmt.Errorf("can't find package containing %s", filename) } // -- Effective methods of file system interface ------------------------- // (go/build.Context defines these as methods, but does not export them.) // hasSubdir calls ctxt.HasSubdir (if not nil) or else uses // the local file system to answer the question. func HasSubdir(ctxt *build.Context, root, dir string) (rel string, ok bool) { if f := ctxt.HasSubdir; f != nil { return f(root, dir) } // Try using paths we received. if rel, ok = hasSubdir(root, dir); ok { return } // Try expanding symlinks and comparing // expanded against unexpanded and // expanded against expanded. rootSym, _ := filepath.EvalSymlinks(root) dirSym, _ := filepath.EvalSymlinks(dir) if rel, ok = hasSubdir(rootSym, dir); ok { return } if rel, ok = hasSubdir(root, dirSym); ok { return } return hasSubdir(rootSym, dirSym) } func hasSubdir(root, dir string) (rel string, ok bool) { const sep = string(filepath.Separator) root = filepath.Clean(root) if !strings.HasSuffix(root, sep) { root += sep } dir = filepath.Clean(dir) if !strings.HasPrefix(dir, root) { return "", false } return filepath.ToSlash(dir[len(root):]), true } // FileExists returns true if the specified file exists, // using the build context's file system interface. func FileExists(ctxt *build.Context, path string) bool { if ctxt.OpenFile != nil { r, err := ctxt.OpenFile(path) if err != nil { return false } r.Close() // ignore error return true } _, err := os.Stat(path) return err == nil } // OpenFile behaves like os.Open, // but uses the build context's file system interface, if any. func OpenFile(ctxt *build.Context, path string) (io.ReadCloser, error) { if ctxt.OpenFile != nil { return ctxt.OpenFile(path) } return os.Open(path) } // IsAbsPath behaves like filepath.IsAbs, // but uses the build context's file system interface, if any. func IsAbsPath(ctxt *build.Context, path string) bool { if ctxt.IsAbsPath != nil { return ctxt.IsAbsPath(path) } return filepath.IsAbs(path) } // JoinPath behaves like filepath.Join, // but uses the build context's file system interface, if any. func JoinPath(ctxt *build.Context, path ...string) string { if ctxt.JoinPath != nil { return ctxt.JoinPath(path...) } return filepath.Join(path...) } // IsDir behaves like os.Stat plus IsDir, // but uses the build context's file system interface, if any. func IsDir(ctxt *build.Context, path string) bool { if ctxt.IsDir != nil { return ctxt.IsDir(path) } fi, err := os.Stat(path) return err == nil && fi.IsDir() } // ReadDir behaves like ioutil.ReadDir, // but uses the build context's file system interface, if any. func ReadDir(ctxt *build.Context, path string) ([]os.FileInfo, error) { if ctxt.ReadDir != nil { return ctxt.ReadDir(path) } return ioutil.ReadDir(path) } // SplitPathList behaves like filepath.SplitList, // but uses the build context's file system interface, if any. func SplitPathList(ctxt *build.Context, s string) []string { if ctxt.SplitPathList != nil { return ctxt.SplitPathList(s) } return filepath.SplitList(s) } // sameFile returns true if x and y have the same basename and denote // the same file. // func sameFile(x, y string) bool { if path.Clean(x) == path.Clean(y) { return true } if filepath.Base(x) == filepath.Base(y) { // (optimisation) if xi, err := os.Stat(x); err == nil { if yi, err := os.Stat(y); err == nil { return os.SameFile(xi, yi) } } } return false } ================================================ FILE: vendor/golang.org/x/tools/go/internal/cgo/cgo.go ================================================ // 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 cgo // This file handles cgo preprocessing of files containing `import "C"`. // // DESIGN // // The approach taken is to run the cgo processor on the package's // CgoFiles and parse the output, faking the filenames of the // resulting ASTs so that the synthetic file containing the C types is // called "C" (e.g. "~/go/src/net/C") and the preprocessed files // have their original names (e.g. "~/go/src/net/cgo_unix.go"), // not the names of the actual temporary files. // // The advantage of this approach is its fidelity to 'go build'. The // downside is that the token.Position.Offset for each AST node is // incorrect, being an offset within the temporary file. Line numbers // should still be correct because of the //line comments. // // The logic of this file is mostly plundered from the 'go build' // tool, which also invokes the cgo preprocessor. // // // REJECTED ALTERNATIVE // // An alternative approach that we explored is to extend go/types' // Importer mechanism to provide the identity of the importing package // so that each time `import "C"` appears it resolves to a different // synthetic package containing just the objects needed in that case. // The loader would invoke cgo but parse only the cgo_types.go file // defining the package-level objects, discarding the other files // resulting from preprocessing. // // The benefit of this approach would have been that source-level // syntax information would correspond exactly to the original cgo // file, with no preprocessing involved, making source tools like // godoc, guru, and eg happy. However, the approach was rejected // due to the additional complexity it would impose on go/types. (It // made for a beautiful demo, though.) // // cgo files, despite their *.go extension, are not legal Go source // files per the specification since they may refer to unexported // members of package "C" such as C.int. Also, a function such as // C.getpwent has in effect two types, one matching its C type and one // which additionally returns (errno C.int). The cgo preprocessor // uses name mangling to distinguish these two functions in the // processed code, but go/types would need to duplicate this logic in // its handling of function calls, analogous to the treatment of map // lookups in which y=m[k] and y,ok=m[k] are both legal. import ( "fmt" "go/ast" "go/build" "go/parser" "go/token" "io/ioutil" "log" "os" "os/exec" "path/filepath" "regexp" "strings" ) // ProcessFiles invokes the cgo preprocessor on bp.CgoFiles, parses // the output and returns the resulting ASTs. // func ProcessFiles(bp *build.Package, fset *token.FileSet, DisplayPath func(path string) string, mode parser.Mode) ([]*ast.File, error) { tmpdir, err := ioutil.TempDir("", strings.Replace(bp.ImportPath, "/", "_", -1)+"_C") if err != nil { return nil, err } defer os.RemoveAll(tmpdir) pkgdir := bp.Dir if DisplayPath != nil { pkgdir = DisplayPath(pkgdir) } cgoFiles, cgoDisplayFiles, err := Run(bp, pkgdir, tmpdir, false) if err != nil { return nil, err } var files []*ast.File for i := range cgoFiles { rd, err := os.Open(cgoFiles[i]) if err != nil { return nil, err } display := filepath.Join(bp.Dir, cgoDisplayFiles[i]) f, err := parser.ParseFile(fset, display, rd, mode) rd.Close() if err != nil { return nil, err } files = append(files, f) } return files, nil } var cgoRe = regexp.MustCompile(`[/\\:]`) // Run invokes the cgo preprocessor on bp.CgoFiles and returns two // lists of files: the resulting processed files (in temporary // directory tmpdir) and the corresponding names of the unprocessed files. // // Run is adapted from (*builder).cgo in // $GOROOT/src/cmd/go/build.go, but these features are unsupported: // Objective C, CGOPKGPATH, CGO_FLAGS. // // If useabs is set to true, absolute paths of the bp.CgoFiles will be passed in // to the cgo preprocessor. This in turn will set the // line comments // referring to those files to use absolute paths. This is needed for // go/packages using the legacy go list support so it is able to find // the original files. func Run(bp *build.Package, pkgdir, tmpdir string, useabs bool) (files, displayFiles []string, err error) { cgoCPPFLAGS, _, _, _ := cflags(bp, true) _, cgoexeCFLAGS, _, _ := cflags(bp, false) if len(bp.CgoPkgConfig) > 0 { pcCFLAGS, err := pkgConfigFlags(bp) if err != nil { return nil, nil, err } cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...) } // Allows including _cgo_export.h from .[ch] files in the package. cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", tmpdir) // _cgo_gotypes.go (displayed "C") contains the type definitions. files = append(files, filepath.Join(tmpdir, "_cgo_gotypes.go")) displayFiles = append(displayFiles, "C") for _, fn := range bp.CgoFiles { // "foo.cgo1.go" (displayed "foo.go") is the processed Go source. f := cgoRe.ReplaceAllString(fn[:len(fn)-len("go")], "_") files = append(files, filepath.Join(tmpdir, f+"cgo1.go")) displayFiles = append(displayFiles, fn) } var cgoflags []string if bp.Goroot && bp.ImportPath == "runtime/cgo" { cgoflags = append(cgoflags, "-import_runtime_cgo=false") } if bp.Goroot && bp.ImportPath == "runtime/race" || bp.ImportPath == "runtime/cgo" { cgoflags = append(cgoflags, "-import_syscall=false") } var cgoFiles []string = bp.CgoFiles if useabs { cgoFiles = make([]string, len(bp.CgoFiles)) for i := range cgoFiles { cgoFiles[i] = filepath.Join(pkgdir, bp.CgoFiles[i]) } } args := stringList( "go", "tool", "cgo", "-objdir", tmpdir, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, cgoFiles, ) if false { log.Printf("Running cgo for package %q: %s (dir=%s)", bp.ImportPath, args, pkgdir) } cmd := exec.Command(args[0], args[1:]...) cmd.Dir = pkgdir cmd.Stdout = os.Stderr cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { return nil, nil, fmt.Errorf("cgo failed: %s: %s", args, err) } return files, displayFiles, nil } // -- unmodified from 'go build' --------------------------------------- // Return the flags to use when invoking the C or C++ compilers, or cgo. func cflags(p *build.Package, def bool) (cppflags, cflags, cxxflags, ldflags []string) { var defaults string if def { defaults = "-g -O2" } cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS) cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS) cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS) ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS) return } // envList returns the value of the given environment variable broken // into fields, using the default value when the variable is empty. func envList(key, def string) []string { v := os.Getenv(key) if v == "" { v = def } return strings.Fields(v) } // stringList's arguments should be a sequence of string or []string values. // stringList flattens them into a single []string. func stringList(args ...interface{}) []string { var x []string for _, arg := range args { switch arg := arg.(type) { case []string: x = append(x, arg...) case string: x = append(x, arg) default: panic("stringList: invalid argument") } } return x } ================================================ FILE: vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go ================================================ // 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 cgo import ( "errors" "fmt" "go/build" "os/exec" "strings" ) // pkgConfig runs pkg-config with the specified arguments and returns the flags it prints. func pkgConfig(mode string, pkgs []string) (flags []string, err error) { cmd := exec.Command("pkg-config", append([]string{mode}, pkgs...)...) out, err := cmd.CombinedOutput() if err != nil { s := fmt.Sprintf("%s failed: %v", strings.Join(cmd.Args, " "), err) if len(out) > 0 { s = fmt.Sprintf("%s: %s", s, out) } return nil, errors.New(s) } if len(out) > 0 { flags = strings.Fields(string(out)) } return } // pkgConfigFlags calls pkg-config if needed and returns the cflags // needed to build the package. func pkgConfigFlags(p *build.Package) (cflags []string, err error) { if len(p.CgoPkgConfig) == 0 { return nil, nil } return pkgConfig("--cflags", p.CgoPkgConfig) } ================================================ FILE: vendor/golang.org/x/tools/go/loader/doc.go ================================================ // Copyright 2015 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 loader loads a complete Go program from source code, parsing // and type-checking the initial packages plus their transitive closure // of dependencies. The ASTs and the derived facts are retained for // later use. // // THIS INTERFACE IS EXPERIMENTAL AND IS LIKELY TO CHANGE. // // The package defines two primary types: Config, which specifies a // set of initial packages to load and various other options; and // Program, which is the result of successfully loading the packages // specified by a configuration. // // The configuration can be set directly, but *Config provides various // convenience methods to simplify the common cases, each of which can // be called any number of times. Finally, these are followed by a // call to Load() to actually load and type-check the program. // // var conf loader.Config // // // Use the command-line arguments to specify // // a set of initial packages to load from source. // // See FromArgsUsage for help. // rest, err := conf.FromArgs(os.Args[1:], wantTests) // // // Parse the specified files and create an ad hoc package with path "foo". // // All files must have the same 'package' declaration. // conf.CreateFromFilenames("foo", "foo.go", "bar.go") // // // Create an ad hoc package with path "foo" from // // the specified already-parsed files. // // All ASTs must have the same 'package' declaration. // conf.CreateFromFiles("foo", parsedFiles) // // // Add "runtime" to the set of packages to be loaded. // conf.Import("runtime") // // // Adds "fmt" and "fmt_test" to the set of packages // // to be loaded. "fmt" will include *_test.go files. // conf.ImportWithTests("fmt") // // // Finally, load all the packages specified by the configuration. // prog, err := conf.Load() // // See examples_test.go for examples of API usage. // // // CONCEPTS AND TERMINOLOGY // // The WORKSPACE is the set of packages accessible to the loader. The // workspace is defined by Config.Build, a *build.Context. The // default context treats subdirectories of $GOROOT and $GOPATH as // packages, but this behavior may be overridden. // // An AD HOC package is one specified as a set of source files on the // command line. In the simplest case, it may consist of a single file // such as $GOROOT/src/net/http/triv.go. // // EXTERNAL TEST packages are those comprised of a set of *_test.go // files all with the same 'package foo_test' declaration, all in the // same directory. (go/build.Package calls these files XTestFiles.) // // An IMPORTABLE package is one that can be referred to by some import // spec. Every importable package is uniquely identified by its // PACKAGE PATH or just PATH, a string such as "fmt", "encoding/json", // or "cmd/vendor/golang.org/x/arch/x86/x86asm". A package path // typically denotes a subdirectory of the workspace. // // An import declaration uses an IMPORT PATH to refer to a package. // Most import declarations use the package path as the import path. // // Due to VENDORING (https://golang.org/s/go15vendor), the // interpretation of an import path may depend on the directory in which // it appears. To resolve an import path to a package path, go/build // must search the enclosing directories for a subdirectory named // "vendor". // // ad hoc packages and external test packages are NON-IMPORTABLE. The // path of an ad hoc package is inferred from the package // declarations of its files and is therefore not a unique package key. // For example, Config.CreatePkgs may specify two initial ad hoc // packages, both with path "main". // // An AUGMENTED package is an importable package P plus all the // *_test.go files with same 'package foo' declaration as P. // (go/build.Package calls these files TestFiles.) // // The INITIAL packages are those specified in the configuration. A // DEPENDENCY is a package loaded to satisfy an import in an initial // package or another dependency. // package loader // IMPLEMENTATION NOTES // // 'go test', in-package test files, and import cycles // --------------------------------------------------- // // An external test package may depend upon members of the augmented // package that are not in the unaugmented package, such as functions // that expose internals. (See bufio/export_test.go for an example.) // So, the loader must ensure that for each external test package // it loads, it also augments the corresponding non-test package. // // The import graph over n unaugmented packages must be acyclic; the // import graph over n-1 unaugmented packages plus one augmented // package must also be acyclic. ('go test' relies on this.) But the // import graph over n augmented packages may contain cycles. // // First, all the (unaugmented) non-test packages and their // dependencies are imported in the usual way; the loader reports an // error if it detects an import cycle. // // Then, each package P for which testing is desired is augmented by // the list P' of its in-package test files, by calling // (*types.Checker).Files. This arrangement ensures that P' may // reference definitions within P, but P may not reference definitions // within P'. Furthermore, P' may import any other package, including // ones that depend upon P, without an import cycle error. // // Consider two packages A and B, both of which have lists of // in-package test files we'll call A' and B', and which have the // following import graph edges: // B imports A // B' imports A // A' imports B // This last edge would be expected to create an error were it not // for the special type-checking discipline above. // Cycles of size greater than two are possible. For example: // compress/bzip2/bzip2_test.go (package bzip2) imports "io/ioutil" // io/ioutil/tempfile_test.go (package ioutil) imports "regexp" // regexp/exec_test.go (package regexp) imports "compress/bzip2" // // // Concurrency // ----------- // // Let us define the import dependency graph as follows. Each node is a // list of files passed to (Checker).Files at once. Many of these lists // are the production code of an importable Go package, so those nodes // are labelled by the package's path. The remaining nodes are // ad hoc packages and lists of in-package *_test.go files that augment // an importable package; those nodes have no label. // // The edges of the graph represent import statements appearing within a // file. An edge connects a node (a list of files) to the node it // imports, which is importable and thus always labelled. // // Loading is controlled by this dependency graph. // // To reduce I/O latency, we start loading a package's dependencies // asynchronously as soon as we've parsed its files and enumerated its // imports (scanImports). This performs a preorder traversal of the // import dependency graph. // // To exploit hardware parallelism, we type-check unrelated packages in // parallel, where "unrelated" means not ordered by the partial order of // the import dependency graph. // // We use a concurrency-safe non-blocking cache (importer.imported) to // record the results of type-checking, whether success or failure. An // entry is created in this cache by startLoad the first time the // package is imported. The first goroutine to request an entry becomes // responsible for completing the task and broadcasting completion to // subsequent requestors, which block until then. // // Type checking occurs in (parallel) postorder: we cannot type-check a // set of files until we have loaded and type-checked all of their // immediate dependencies (and thus all of their transitive // dependencies). If the input were guaranteed free of import cycles, // this would be trivial: we could simply wait for completion of the // dependencies and then invoke the typechecker. // // But as we saw in the 'go test' section above, some cycles in the // import graph over packages are actually legal, so long as the // cycle-forming edge originates in the in-package test files that // augment the package. This explains why the nodes of the import // dependency graph are not packages, but lists of files: the unlabelled // nodes avoid the cycles. Consider packages A and B where B imports A // and A's in-package tests AT import B. The naively constructed import // graph over packages would contain a cycle (A+AT) --> B --> (A+AT) but // the graph over lists of files is AT --> B --> A, where AT is an // unlabelled node. // // Awaiting completion of the dependencies in a cyclic graph would // deadlock, so we must materialize the import dependency graph (as // importer.graph) and check whether each import edge forms a cycle. If // x imports y, and the graph already contains a path from y to x, then // there is an import cycle, in which case the processing of x must not // wait for the completion of processing of y. // // When the type-checker makes a callback (doImport) to the loader for a // given import edge, there are two possible cases. In the normal case, // the dependency has already been completely type-checked; doImport // does a cache lookup and returns it. In the cyclic case, the entry in // the cache is still necessarily incomplete, indicating a cycle. We // perform the cycle check again to obtain the error message, and return // the error. // // The result of using concurrency is about a 2.5x speedup for stdlib_test. // TODO(adonovan): overhaul the package documentation. ================================================ FILE: vendor/golang.org/x/tools/go/loader/loader.go ================================================ // 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 loader // See doc.go for package documentation and implementation notes. import ( "errors" "fmt" "go/ast" "go/build" "go/parser" "go/token" "go/types" "os" "path/filepath" "sort" "strings" "sync" "time" "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/internal/cgo" ) var ignoreVendor build.ImportMode const trace = false // show timing info for type-checking // Config specifies the configuration for loading a whole program from // Go source code. // The zero value for Config is a ready-to-use default configuration. type Config struct { // Fset is the file set for the parser to use when loading the // program. If nil, it may be lazily initialized by any // method of Config. Fset *token.FileSet // ParserMode specifies the mode to be used by the parser when // loading source packages. ParserMode parser.Mode // TypeChecker contains options relating to the type checker. // // The supplied IgnoreFuncBodies is not used; the effective // value comes from the TypeCheckFuncBodies func below. // The supplied Import function is not used either. TypeChecker types.Config // TypeCheckFuncBodies is a predicate over package paths. // A package for which the predicate is false will // have its package-level declarations type checked, but not // its function bodies; this can be used to quickly load // dependencies from source. If nil, all func bodies are type // checked. TypeCheckFuncBodies func(path string) bool // If Build is non-nil, it is used to locate source packages. // Otherwise &build.Default is used. // // By default, cgo is invoked to preprocess Go files that // import the fake package "C". This behaviour can be // disabled by setting CGO_ENABLED=0 in the environment prior // to startup, or by setting Build.CgoEnabled=false. Build *build.Context // The current directory, used for resolving relative package // references such as "./go/loader". If empty, os.Getwd will be // used instead. Cwd string // If DisplayPath is non-nil, it is used to transform each // file name obtained from Build.Import(). This can be used // to prevent a virtualized build.Config's file names from // leaking into the user interface. DisplayPath func(path string) string // If AllowErrors is true, Load will return a Program even // if some of the its packages contained I/O, parser or type // errors; such errors are accessible via PackageInfo.Errors. If // false, Load will fail if any package had an error. AllowErrors bool // CreatePkgs specifies a list of non-importable initial // packages to create. The resulting packages will appear in // the corresponding elements of the Program.Created slice. CreatePkgs []PkgSpec // ImportPkgs specifies a set of initial packages to load. // The map keys are package paths. // // The map value indicates whether to load tests. If true, Load // will add and type-check two lists of files to the package: // non-test files followed by in-package *_test.go files. In // addition, it will append the external test package (if any) // to Program.Created. ImportPkgs map[string]bool // FindPackage is called during Load to create the build.Package // for a given import path from a given directory. // If FindPackage is nil, (*build.Context).Import is used. // A client may use this hook to adapt to a proprietary build // system that does not follow the "go build" layout // conventions, for example. // // It must be safe to call concurrently from multiple goroutines. FindPackage func(ctxt *build.Context, importPath, fromDir string, mode build.ImportMode) (*build.Package, error) // AfterTypeCheck is called immediately after a list of files // has been type-checked and appended to info.Files. // // This optional hook function is the earliest opportunity for // the client to observe the output of the type checker, // which may be useful to reduce analysis latency when loading // a large program. // // The function is permitted to modify info.Info, for instance // to clear data structures that are no longer needed, which can // dramatically reduce peak memory consumption. // // The function may be called twice for the same PackageInfo: // once for the files of the package and again for the // in-package test files. // // It must be safe to call concurrently from multiple goroutines. AfterTypeCheck func(info *PackageInfo, files []*ast.File) } // A PkgSpec specifies a non-importable package to be created by Load. // Files are processed first, but typically only one of Files and // Filenames is provided. The path needn't be globally unique. // // For vendoring purposes, the package's directory is the one that // contains the first file. type PkgSpec struct { Path string // package path ("" => use package declaration) Files []*ast.File // ASTs of already-parsed files Filenames []string // names of files to be parsed } // A Program is a Go program loaded from source as specified by a Config. type Program struct { Fset *token.FileSet // the file set for this program // Created[i] contains the initial package whose ASTs or // filenames were supplied by Config.CreatePkgs[i], followed by // the external test package, if any, of each package in // Config.ImportPkgs ordered by ImportPath. // // NOTE: these files must not import "C". Cgo preprocessing is // only performed on imported packages, not ad hoc packages. // // TODO(adonovan): we need to copy and adapt the logic of // goFilesPackage (from $GOROOT/src/cmd/go/build.go) and make // Config.Import and Config.Create methods return the same kind // of entity, essentially a build.Package. // Perhaps we can even reuse that type directly. Created []*PackageInfo // Imported contains the initially imported packages, // as specified by Config.ImportPkgs. Imported map[string]*PackageInfo // AllPackages contains the PackageInfo of every package // encountered by Load: all initial packages and all // dependencies, including incomplete ones. AllPackages map[*types.Package]*PackageInfo // importMap is the canonical mapping of package paths to // packages. It contains all Imported initial packages, but not // Created ones, and all imported dependencies. importMap map[string]*types.Package } // PackageInfo holds the ASTs and facts derived by the type-checker // for a single package. // // Not mutated once exposed via the API. // type PackageInfo struct { Pkg *types.Package Importable bool // true if 'import "Pkg.Path()"' would resolve to this TransitivelyErrorFree bool // true if Pkg and all its dependencies are free of errors Files []*ast.File // syntax trees for the package's files Errors []error // non-nil if the package had errors types.Info // type-checker deductions. dir string // package directory checker *types.Checker // transient type-checker state errorFunc func(error) } func (info *PackageInfo) String() string { return info.Pkg.Path() } func (info *PackageInfo) appendError(err error) { if info.errorFunc != nil { info.errorFunc(err) } else { fmt.Fprintln(os.Stderr, err) } info.Errors = append(info.Errors, err) } func (conf *Config) fset() *token.FileSet { if conf.Fset == nil { conf.Fset = token.NewFileSet() } return conf.Fset } // ParseFile is a convenience function (intended for testing) that invokes // the parser using the Config's FileSet, which is initialized if nil. // // src specifies the parser input as a string, []byte, or io.Reader, and // filename is its apparent name. If src is nil, the contents of // filename are read from the file system. // func (conf *Config) ParseFile(filename string, src interface{}) (*ast.File, error) { // TODO(adonovan): use conf.build() etc like parseFiles does. return parser.ParseFile(conf.fset(), filename, src, conf.ParserMode) } // FromArgsUsage is a partial usage message that applications calling // FromArgs may wish to include in their -help output. const FromArgsUsage = ` is a list of arguments denoting a set of initial packages. It may take one of two forms: 1. A list of *.go source files. All of the specified files are loaded, parsed and type-checked as a single package. All the files must belong to the same directory. 2. A list of import paths, each denoting a package. The package's directory is found relative to the $GOROOT and $GOPATH using similar logic to 'go build', and the *.go files in that directory are loaded, parsed and type-checked as a single package. In addition, all *_test.go files in the directory are then loaded and parsed. Those files whose package declaration equals that of the non-*_test.go files are included in the primary package. Test files whose package declaration ends with "_test" are type-checked as another package, the 'external' test package, so that a single import path may denote two packages. (Whether this behaviour is enabled is tool-specific, and may depend on additional flags.) A '--' argument terminates the list of packages. ` // FromArgs interprets args as a set of initial packages to load from // source and updates the configuration. It returns the list of // unconsumed arguments. // // It is intended for use in command-line interfaces that require a // set of initial packages to be specified; see FromArgsUsage message // for details. // // Only superficial errors are reported at this stage; errors dependent // on I/O are detected during Load. // func (conf *Config) FromArgs(args []string, xtest bool) ([]string, error) { var rest []string for i, arg := range args { if arg == "--" { rest = args[i+1:] args = args[:i] break // consume "--" and return the remaining args } } if len(args) > 0 && strings.HasSuffix(args[0], ".go") { // Assume args is a list of a *.go files // denoting a single ad hoc package. for _, arg := range args { if !strings.HasSuffix(arg, ".go") { return nil, fmt.Errorf("named files must be .go files: %s", arg) } } conf.CreateFromFilenames("", args...) } else { // Assume args are directories each denoting a // package and (perhaps) an external test, iff xtest. for _, arg := range args { if xtest { conf.ImportWithTests(arg) } else { conf.Import(arg) } } } return rest, nil } // CreateFromFilenames is a convenience function that adds // a conf.CreatePkgs entry to create a package of the specified *.go // files. // func (conf *Config) CreateFromFilenames(path string, filenames ...string) { conf.CreatePkgs = append(conf.CreatePkgs, PkgSpec{Path: path, Filenames: filenames}) } // CreateFromFiles is a convenience function that adds a conf.CreatePkgs // entry to create package of the specified path and parsed files. // func (conf *Config) CreateFromFiles(path string, files ...*ast.File) { conf.CreatePkgs = append(conf.CreatePkgs, PkgSpec{Path: path, Files: files}) } // ImportWithTests is a convenience function that adds path to // ImportPkgs, the set of initial source packages located relative to // $GOPATH. The package will be augmented by any *_test.go files in // its directory that contain a "package x" (not "package x_test") // declaration. // // In addition, if any *_test.go files contain a "package x_test" // declaration, an additional package comprising just those files will // be added to CreatePkgs. // func (conf *Config) ImportWithTests(path string) { conf.addImport(path, true) } // Import is a convenience function that adds path to ImportPkgs, the // set of initial packages that will be imported from source. // func (conf *Config) Import(path string) { conf.addImport(path, false) } func (conf *Config) addImport(path string, tests bool) { if path == "C" { return // ignore; not a real package } if conf.ImportPkgs == nil { conf.ImportPkgs = make(map[string]bool) } conf.ImportPkgs[path] = conf.ImportPkgs[path] || tests } // PathEnclosingInterval returns the PackageInfo and ast.Node that // contain source interval [start, end), and all the node's ancestors // up to the AST root. It searches all ast.Files of all packages in prog. // exact is defined as for astutil.PathEnclosingInterval. // // The zero value is returned if not found. // func (prog *Program) PathEnclosingInterval(start, end token.Pos) (pkg *PackageInfo, path []ast.Node, exact bool) { for _, info := range prog.AllPackages { for _, f := range info.Files { if f.Pos() == token.NoPos { // This can happen if the parser saw // too many errors and bailed out. // (Use parser.AllErrors to prevent that.) continue } if !tokenFileContainsPos(prog.Fset.File(f.Pos()), start) { continue } if path, exact := astutil.PathEnclosingInterval(f, start, end); path != nil { return info, path, exact } } } return nil, nil, false } // InitialPackages returns a new slice containing the set of initial // packages (Created + Imported) in unspecified order. // func (prog *Program) InitialPackages() []*PackageInfo { infos := make([]*PackageInfo, 0, len(prog.Created)+len(prog.Imported)) infos = append(infos, prog.Created...) for _, info := range prog.Imported { infos = append(infos, info) } return infos } // Package returns the ASTs and results of type checking for the // specified package. func (prog *Program) Package(path string) *PackageInfo { if info, ok := prog.AllPackages[prog.importMap[path]]; ok { return info } for _, info := range prog.Created { if path == info.Pkg.Path() { return info } } return nil } // ---------- Implementation ---------- // importer holds the working state of the algorithm. type importer struct { conf *Config // the client configuration start time.Time // for logging progMu sync.Mutex // guards prog prog *Program // the resulting program // findpkg is a memoization of FindPackage. findpkgMu sync.Mutex // guards findpkg findpkg map[findpkgKey]*findpkgValue importedMu sync.Mutex // guards imported imported map[string]*importInfo // all imported packages (incl. failures) by import path // import dependency graph: graph[x][y] => x imports y // // Since non-importable packages cannot be cyclic, we ignore // their imports, thus we only need the subgraph over importable // packages. Nodes are identified by their import paths. graphMu sync.Mutex graph map[string]map[string]bool } type findpkgKey struct { importPath string fromDir string mode build.ImportMode } type findpkgValue struct { ready chan struct{} // closed to broadcast readiness bp *build.Package err error } // importInfo tracks the success or failure of a single import. // // Upon completion, exactly one of info and err is non-nil: // info on successful creation of a package, err otherwise. // A successful package may still contain type errors. // type importInfo struct { path string // import path info *PackageInfo // results of typechecking (including errors) complete chan struct{} // closed to broadcast that info is set. } // awaitCompletion blocks until ii is complete, // i.e. the info field is safe to inspect. func (ii *importInfo) awaitCompletion() { <-ii.complete // wait for close } // Complete marks ii as complete. // Its info and err fields will not be subsequently updated. func (ii *importInfo) Complete(info *PackageInfo) { if info == nil { panic("info == nil") } ii.info = info close(ii.complete) } type importError struct { path string // import path err error // reason for failure to create a package } // Load creates the initial packages specified by conf.{Create,Import}Pkgs, // loading their dependencies packages as needed. // // On success, Load returns a Program containing a PackageInfo for // each package. On failure, it returns an error. // // If AllowErrors is true, Load will return a Program even if some // packages contained I/O, parser or type errors, or if dependencies // were missing. (Such errors are accessible via PackageInfo.Errors. If // false, Load will fail if any package had an error. // // It is an error if no packages were loaded. // func (conf *Config) Load() (*Program, error) { // Create a simple default error handler for parse/type errors. if conf.TypeChecker.Error == nil { conf.TypeChecker.Error = func(e error) { fmt.Fprintln(os.Stderr, e) } } // Set default working directory for relative package references. if conf.Cwd == "" { var err error conf.Cwd, err = os.Getwd() if err != nil { return nil, err } } // Install default FindPackage hook using go/build logic. if conf.FindPackage == nil { conf.FindPackage = (*build.Context).Import } prog := &Program{ Fset: conf.fset(), Imported: make(map[string]*PackageInfo), importMap: make(map[string]*types.Package), AllPackages: make(map[*types.Package]*PackageInfo), } imp := importer{ conf: conf, prog: prog, findpkg: make(map[findpkgKey]*findpkgValue), imported: make(map[string]*importInfo), start: time.Now(), graph: make(map[string]map[string]bool), } // -- loading proper (concurrent phase) -------------------------------- var errpkgs []string // packages that contained errors // Load the initially imported packages and their dependencies, // in parallel. // No vendor check on packages imported from the command line. infos, importErrors := imp.importAll("", conf.Cwd, conf.ImportPkgs, ignoreVendor) for _, ie := range importErrors { conf.TypeChecker.Error(ie.err) // failed to create package errpkgs = append(errpkgs, ie.path) } for _, info := range infos { prog.Imported[info.Pkg.Path()] = info } // Augment the designated initial packages by their tests. // Dependencies are loaded in parallel. var xtestPkgs []*build.Package for importPath, augment := range conf.ImportPkgs { if !augment { continue } // No vendor check on packages imported from command line. bp, err := imp.findPackage(importPath, conf.Cwd, ignoreVendor) if err != nil { // Package not found, or can't even parse package declaration. // Already reported by previous loop; ignore it. continue } // Needs external test package? if len(bp.XTestGoFiles) > 0 { xtestPkgs = append(xtestPkgs, bp) } // Consult the cache using the canonical package path. path := bp.ImportPath imp.importedMu.Lock() // (unnecessary, we're sequential here) ii, ok := imp.imported[path] // Paranoid checks added due to issue #11012. if !ok { // Unreachable. // The previous loop called importAll and thus // startLoad for each path in ImportPkgs, which // populates imp.imported[path] with a non-zero value. panic(fmt.Sprintf("imported[%q] not found", path)) } if ii == nil { // Unreachable. // The ii values in this loop are the same as in // the previous loop, which enforced the invariant // that at least one of ii.err and ii.info is non-nil. panic(fmt.Sprintf("imported[%q] == nil", path)) } if ii.info == nil { // Unreachable. // awaitCompletion has the postcondition // ii.info != nil. panic(fmt.Sprintf("imported[%q].info = nil", path)) } info := ii.info imp.importedMu.Unlock() // Parse the in-package test files. files, errs := imp.conf.parsePackageFiles(bp, 't') for _, err := range errs { info.appendError(err) } // The test files augmenting package P cannot be imported, // but may import packages that import P, // so we must disable the cycle check. imp.addFiles(info, files, false) } createPkg := func(path, dir string, files []*ast.File, errs []error) { info := imp.newPackageInfo(path, dir) for _, err := range errs { info.appendError(err) } // Ad hoc packages are non-importable, // so no cycle check is needed. // addFiles loads dependencies in parallel. imp.addFiles(info, files, false) prog.Created = append(prog.Created, info) } // Create packages specified by conf.CreatePkgs. for _, cp := range conf.CreatePkgs { files, errs := parseFiles(conf.fset(), conf.build(), nil, conf.Cwd, cp.Filenames, conf.ParserMode) files = append(files, cp.Files...) path := cp.Path if path == "" { if len(files) > 0 { path = files[0].Name.Name } else { path = "(unnamed)" } } dir := conf.Cwd if len(files) > 0 && files[0].Pos().IsValid() { dir = filepath.Dir(conf.fset().File(files[0].Pos()).Name()) } createPkg(path, dir, files, errs) } // Create external test packages. sort.Sort(byImportPath(xtestPkgs)) for _, bp := range xtestPkgs { files, errs := imp.conf.parsePackageFiles(bp, 'x') createPkg(bp.ImportPath+"_test", bp.Dir, files, errs) } // -- finishing up (sequential) ---------------------------------------- if len(prog.Imported)+len(prog.Created) == 0 { return nil, errors.New("no initial packages were loaded") } // Create infos for indirectly imported packages. // e.g. incomplete packages without syntax, loaded from export data. for _, obj := range prog.importMap { info := prog.AllPackages[obj] if info == nil { prog.AllPackages[obj] = &PackageInfo{Pkg: obj, Importable: true} } else { // finished info.checker = nil info.errorFunc = nil } } if !conf.AllowErrors { // Report errors in indirectly imported packages. for _, info := range prog.AllPackages { if len(info.Errors) > 0 { errpkgs = append(errpkgs, info.Pkg.Path()) } } if errpkgs != nil { var more string if len(errpkgs) > 3 { more = fmt.Sprintf(" and %d more", len(errpkgs)-3) errpkgs = errpkgs[:3] } return nil, fmt.Errorf("couldn't load packages due to errors: %s%s", strings.Join(errpkgs, ", "), more) } } markErrorFreePackages(prog.AllPackages) return prog, nil } type byImportPath []*build.Package func (b byImportPath) Len() int { return len(b) } func (b byImportPath) Less(i, j int) bool { return b[i].ImportPath < b[j].ImportPath } func (b byImportPath) Swap(i, j int) { b[i], b[j] = b[j], b[i] } // markErrorFreePackages sets the TransitivelyErrorFree flag on all // applicable packages. func markErrorFreePackages(allPackages map[*types.Package]*PackageInfo) { // Build the transpose of the import graph. importedBy := make(map[*types.Package]map[*types.Package]bool) for P := range allPackages { for _, Q := range P.Imports() { clients, ok := importedBy[Q] if !ok { clients = make(map[*types.Package]bool) importedBy[Q] = clients } clients[P] = true } } // Find all packages reachable from some error package. reachable := make(map[*types.Package]bool) var visit func(*types.Package) visit = func(p *types.Package) { if !reachable[p] { reachable[p] = true for q := range importedBy[p] { visit(q) } } } for _, info := range allPackages { if len(info.Errors) > 0 { visit(info.Pkg) } } // Mark the others as "transitively error-free". for _, info := range allPackages { if !reachable[info.Pkg] { info.TransitivelyErrorFree = true } } } // build returns the effective build context. func (conf *Config) build() *build.Context { if conf.Build != nil { return conf.Build } return &build.Default } // parsePackageFiles enumerates the files belonging to package path, // then loads, parses and returns them, plus a list of I/O or parse // errors that were encountered. // // 'which' indicates which files to include: // 'g': include non-test *.go source files (GoFiles + processed CgoFiles) // 't': include in-package *_test.go source files (TestGoFiles) // 'x': include external *_test.go source files. (XTestGoFiles) // func (conf *Config) parsePackageFiles(bp *build.Package, which rune) ([]*ast.File, []error) { if bp.ImportPath == "unsafe" { return nil, nil } var filenames []string switch which { case 'g': filenames = bp.GoFiles case 't': filenames = bp.TestGoFiles case 'x': filenames = bp.XTestGoFiles default: panic(which) } files, errs := parseFiles(conf.fset(), conf.build(), conf.DisplayPath, bp.Dir, filenames, conf.ParserMode) // Preprocess CgoFiles and parse the outputs (sequentially). if which == 'g' && bp.CgoFiles != nil { cgofiles, err := cgo.ProcessFiles(bp, conf.fset(), conf.DisplayPath, conf.ParserMode) if err != nil { errs = append(errs, err) } else { files = append(files, cgofiles...) } } return files, errs } // doImport imports the package denoted by path. // It implements the types.Importer signature. // // It returns an error if a package could not be created // (e.g. go/build or parse error), but type errors are reported via // the types.Config.Error callback (the first of which is also saved // in the package's PackageInfo). // // Idempotent. // func (imp *importer) doImport(from *PackageInfo, to string) (*types.Package, error) { if to == "C" { // This should be unreachable, but ad hoc packages are // not currently subject to cgo preprocessing. // See https://golang.org/issue/11627. return nil, fmt.Errorf(`the loader doesn't cgo-process ad hoc packages like %q; see Go issue 11627`, from.Pkg.Path()) } bp, err := imp.findPackage(to, from.dir, 0) if err != nil { return nil, err } // The standard unsafe package is handled specially, // and has no PackageInfo. if bp.ImportPath == "unsafe" { return types.Unsafe, nil } // Look for the package in the cache using its canonical path. path := bp.ImportPath imp.importedMu.Lock() ii := imp.imported[path] imp.importedMu.Unlock() if ii == nil { panic("internal error: unexpected import: " + path) } if ii.info != nil { return ii.info.Pkg, nil } // Import of incomplete package: this indicates a cycle. fromPath := from.Pkg.Path() if cycle := imp.findPath(path, fromPath); cycle != nil { cycle = append([]string{fromPath}, cycle...) return nil, fmt.Errorf("import cycle: %s", strings.Join(cycle, " -> ")) } panic("internal error: import of incomplete (yet acyclic) package: " + fromPath) } // findPackage locates the package denoted by the importPath in the // specified directory. func (imp *importer) findPackage(importPath, fromDir string, mode build.ImportMode) (*build.Package, error) { // We use a non-blocking duplicate-suppressing cache (gopl.io §9.7) // to avoid holding the lock around FindPackage. key := findpkgKey{importPath, fromDir, mode} imp.findpkgMu.Lock() v, ok := imp.findpkg[key] if ok { // cache hit imp.findpkgMu.Unlock() <-v.ready // wait for entry to become ready } else { // Cache miss: this goroutine becomes responsible for // populating the map entry and broadcasting its readiness. v = &findpkgValue{ready: make(chan struct{})} imp.findpkg[key] = v imp.findpkgMu.Unlock() ioLimit <- true v.bp, v.err = imp.conf.FindPackage(imp.conf.build(), importPath, fromDir, mode) <-ioLimit if _, ok := v.err.(*build.NoGoError); ok { v.err = nil // empty directory is not an error } close(v.ready) // broadcast ready condition } return v.bp, v.err } // importAll loads, parses, and type-checks the specified packages in // parallel and returns their completed importInfos in unspecified order. // // fromPath is the package path of the importing package, if it is // importable, "" otherwise. It is used for cycle detection. // // fromDir is the directory containing the import declaration that // caused these imports. // func (imp *importer) importAll(fromPath, fromDir string, imports map[string]bool, mode build.ImportMode) (infos []*PackageInfo, errors []importError) { // TODO(adonovan): opt: do the loop in parallel once // findPackage is non-blocking. var pending []*importInfo for importPath := range imports { bp, err := imp.findPackage(importPath, fromDir, mode) if err != nil { errors = append(errors, importError{ path: importPath, err: err, }) continue } pending = append(pending, imp.startLoad(bp)) } if fromPath != "" { // We're loading a set of imports. // // We must record graph edges from the importing package // to its dependencies, and check for cycles. imp.graphMu.Lock() deps, ok := imp.graph[fromPath] if !ok { deps = make(map[string]bool) imp.graph[fromPath] = deps } for _, ii := range pending { deps[ii.path] = true } imp.graphMu.Unlock() } for _, ii := range pending { if fromPath != "" { if cycle := imp.findPath(ii.path, fromPath); cycle != nil { // Cycle-forming import: we must not await its // completion since it would deadlock. // // We don't record the error in ii since // the error is really associated with the // cycle-forming edge, not the package itself. // (Also it would complicate the // invariants of importPath completion.) if trace { fmt.Fprintf(os.Stderr, "import cycle: %q\n", cycle) } continue } } ii.awaitCompletion() infos = append(infos, ii.info) } return infos, errors } // findPath returns an arbitrary path from 'from' to 'to' in the import // graph, or nil if there was none. func (imp *importer) findPath(from, to string) []string { imp.graphMu.Lock() defer imp.graphMu.Unlock() seen := make(map[string]bool) var search func(stack []string, importPath string) []string search = func(stack []string, importPath string) []string { if !seen[importPath] { seen[importPath] = true stack = append(stack, importPath) if importPath == to { return stack } for x := range imp.graph[importPath] { if p := search(stack, x); p != nil { return p } } } return nil } return search(make([]string, 0, 20), from) } // startLoad initiates the loading, parsing and type-checking of the // specified package and its dependencies, if it has not already begun. // // It returns an importInfo, not necessarily in a completed state. The // caller must call awaitCompletion() before accessing its info field. // // startLoad is concurrency-safe and idempotent. // func (imp *importer) startLoad(bp *build.Package) *importInfo { path := bp.ImportPath imp.importedMu.Lock() ii, ok := imp.imported[path] if !ok { ii = &importInfo{path: path, complete: make(chan struct{})} imp.imported[path] = ii go func() { info := imp.load(bp) ii.Complete(info) }() } imp.importedMu.Unlock() return ii } // load implements package loading by parsing Go source files // located by go/build. func (imp *importer) load(bp *build.Package) *PackageInfo { info := imp.newPackageInfo(bp.ImportPath, bp.Dir) info.Importable = true files, errs := imp.conf.parsePackageFiles(bp, 'g') for _, err := range errs { info.appendError(err) } imp.addFiles(info, files, true) imp.progMu.Lock() imp.prog.importMap[bp.ImportPath] = info.Pkg imp.progMu.Unlock() return info } // addFiles adds and type-checks the specified files to info, loading // their dependencies if needed. The order of files determines the // package initialization order. It may be called multiple times on the // same package. Errors are appended to the info.Errors field. // // cycleCheck determines whether the imports within files create // dependency edges that should be checked for potential cycles. // func (imp *importer) addFiles(info *PackageInfo, files []*ast.File, cycleCheck bool) { // Ensure the dependencies are loaded, in parallel. var fromPath string if cycleCheck { fromPath = info.Pkg.Path() } // TODO(adonovan): opt: make the caller do scanImports. // Callers with a build.Package can skip it. imp.importAll(fromPath, info.dir, scanImports(files), 0) if trace { fmt.Fprintf(os.Stderr, "%s: start %q (%d)\n", time.Since(imp.start), info.Pkg.Path(), len(files)) } // Don't call checker.Files on Unsafe, even with zero files, // because it would mutate the package, which is a global. if info.Pkg == types.Unsafe { if len(files) > 0 { panic(`"unsafe" package contains unexpected files`) } } else { // Ignore the returned (first) error since we // already collect them all in the PackageInfo. info.checker.Files(files) info.Files = append(info.Files, files...) } if imp.conf.AfterTypeCheck != nil { imp.conf.AfterTypeCheck(info, files) } if trace { fmt.Fprintf(os.Stderr, "%s: stop %q\n", time.Since(imp.start), info.Pkg.Path()) } } func (imp *importer) newPackageInfo(path, dir string) *PackageInfo { var pkg *types.Package if path == "unsafe" { pkg = types.Unsafe } else { pkg = types.NewPackage(path, "") } info := &PackageInfo{ Pkg: pkg, Info: types.Info{ Types: make(map[ast.Expr]types.TypeAndValue), Defs: make(map[*ast.Ident]types.Object), Uses: make(map[*ast.Ident]types.Object), Implicits: make(map[ast.Node]types.Object), Scopes: make(map[ast.Node]*types.Scope), Selections: make(map[*ast.SelectorExpr]*types.Selection), }, errorFunc: imp.conf.TypeChecker.Error, dir: dir, } // Copy the types.Config so we can vary it across PackageInfos. tc := imp.conf.TypeChecker tc.IgnoreFuncBodies = false if f := imp.conf.TypeCheckFuncBodies; f != nil { tc.IgnoreFuncBodies = !f(path) } tc.Importer = closure{imp, info} tc.Error = info.appendError // appendError wraps the user's Error function info.checker = types.NewChecker(&tc, imp.conf.fset(), pkg, &info.Info) imp.progMu.Lock() imp.prog.AllPackages[pkg] = info imp.progMu.Unlock() return info } type closure struct { imp *importer info *PackageInfo } func (c closure) Import(to string) (*types.Package, error) { return c.imp.doImport(c.info, to) } ================================================ FILE: vendor/golang.org/x/tools/go/loader/util.go ================================================ // 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 loader import ( "go/ast" "go/build" "go/parser" "go/token" "io" "os" "strconv" "sync" "golang.org/x/tools/go/buildutil" ) // We use a counting semaphore to limit // the number of parallel I/O calls per process. var ioLimit = make(chan bool, 10) // parseFiles parses the Go source files within directory dir and // returns the ASTs of the ones that could be at least partially parsed, // along with a list of I/O and parse errors encountered. // // I/O is done via ctxt, which may specify a virtual file system. // displayPath is used to transform the filenames attached to the ASTs. // func parseFiles(fset *token.FileSet, ctxt *build.Context, displayPath func(string) string, dir string, files []string, mode parser.Mode) ([]*ast.File, []error) { if displayPath == nil { displayPath = func(path string) string { return path } } var wg sync.WaitGroup n := len(files) parsed := make([]*ast.File, n) errors := make([]error, n) for i, file := range files { if !buildutil.IsAbsPath(ctxt, file) { file = buildutil.JoinPath(ctxt, dir, file) } wg.Add(1) go func(i int, file string) { ioLimit <- true // wait defer func() { wg.Done() <-ioLimit // signal }() var rd io.ReadCloser var err error if ctxt.OpenFile != nil { rd, err = ctxt.OpenFile(file) } else { rd, err = os.Open(file) } if err != nil { errors[i] = err // open failed return } // ParseFile may return both an AST and an error. parsed[i], errors[i] = parser.ParseFile(fset, displayPath(file), rd, mode) rd.Close() }(i, file) } wg.Wait() // Eliminate nils, preserving order. var o int for _, f := range parsed { if f != nil { parsed[o] = f o++ } } parsed = parsed[:o] o = 0 for _, err := range errors { if err != nil { errors[o] = err o++ } } errors = errors[:o] return parsed, errors } // scanImports returns the set of all import paths from all // import specs in the specified files. func scanImports(files []*ast.File) map[string]bool { imports := make(map[string]bool) for _, f := range files { for _, decl := range f.Decls { if decl, ok := decl.(*ast.GenDecl); ok && decl.Tok == token.IMPORT { for _, spec := range decl.Specs { spec := spec.(*ast.ImportSpec) // NB: do not assume the program is well-formed! path, err := strconv.Unquote(spec.Path.Value) if err != nil { continue // quietly ignore the error } if path == "C" { continue // skip pseudopackage } imports[path] = true } } } } return imports } // ---------- Internal helpers ---------- // TODO(adonovan): make this a method: func (*token.File) Contains(token.Pos) func tokenFileContainsPos(f *token.File, pos token.Pos) bool { p := int(pos) base := f.Base() return base <= p && p < base+f.Size() } ================================================ FILE: vendor/google.golang.org/appengine/LICENSE ================================================ 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. ================================================ FILE: vendor/google.golang.org/appengine/cloudsql/cloudsql.go ================================================ // Copyright 2013 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. /* Package cloudsql exposes access to Google Cloud SQL databases. This package does not work in App Engine "flexible environment". This package is intended for MySQL drivers to make App Engine-specific connections. Applications should use this package through database/sql: Select a pure Go MySQL driver that supports this package, and use sql.Open with protocol "cloudsql" and an address of the Cloud SQL instance. A Go MySQL driver that has been tested to work well with Cloud SQL is the go-sql-driver: import "database/sql" import _ "github.com/go-sql-driver/mysql" db, err := sql.Open("mysql", "user@cloudsql(project-id:instance-name)/dbname") Another driver that works well with Cloud SQL is the mymysql driver: import "database/sql" import _ "github.com/ziutek/mymysql/godrv" db, err := sql.Open("mymysql", "cloudsql:instance-name*dbname/user/password") Using either of these drivers, you can perform a standard SQL query. This example assumes there is a table named 'users' with columns 'first_name' and 'last_name': rows, err := db.Query("SELECT first_name, last_name FROM users") if err != nil { log.Errorf(ctx, "db.Query: %v", err) } defer rows.Close() for rows.Next() { var firstName string var lastName string if err := rows.Scan(&firstName, &lastName); err != nil { log.Errorf(ctx, "rows.Scan: %v", err) continue } log.Infof(ctx, "First: %v - Last: %v", firstName, lastName) } if err := rows.Err(); err != nil { log.Errorf(ctx, "Row error: %v", err) } */ package cloudsql import ( "net" ) // Dial connects to the named Cloud SQL instance. func Dial(instance string) (net.Conn, error) { return connect(instance) } ================================================ FILE: vendor/google.golang.org/appengine/cloudsql/cloudsql_classic.go ================================================ // Copyright 2013 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // +build appengine package cloudsql import ( "net" "appengine/cloudsql" ) func connect(instance string) (net.Conn, error) { return cloudsql.Dial(instance) } ================================================ FILE: vendor/google.golang.org/appengine/cloudsql/cloudsql_vm.go ================================================ // Copyright 2013 Google Inc. All rights reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. // +build !appengine package cloudsql import ( "errors" "net" ) func connect(instance string) (net.Conn, error) { return nil, errors.New(`cloudsql: not supported in App Engine "flexible environment"`) } ================================================ FILE: vendor/gopkg.in/go-playground/validator.v8/.gitignore ================================================ # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof *.test *.out *.txt cover.html README.html ================================================ FILE: vendor/gopkg.in/go-playground/validator.v8/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 Dean Karn 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. ================================================ FILE: vendor/gopkg.in/go-playground/validator.v8/README.md ================================================ Package validator ================ [![Join the chat at https://gitter.im/bluesuncorp/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ![Project status](https://img.shields.io/badge/version-8.18.2-green.svg) [![Build Status](https://semaphoreci.com/api/v1/projects/ec20115f-ef1b-4c7d-9393-cc76aba74eb4/530054/badge.svg)](https://semaphoreci.com/joeybloggs/validator) [![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=v8&service=github)](https://coveralls.io/github/go-playground/validator?branch=v8) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) [![GoDoc](https://godoc.org/gopkg.in/go-playground/validator.v8?status.svg)](https://godoc.org/gopkg.in/go-playground/validator.v8) ![License](https://img.shields.io/dub/l/vibe-d.svg) Package validator implements value validations for structs and individual fields based on tags. It has the following **unique** features: - Cross Field and Cross Struct validations by using validation tags or custom validators. - Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated. - Handles type interface by determining it's underlying type prior to validation. - Handles custom field types such as sql driver Valuer see [Valuer](https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29) - Alias validation tags, which allows for mapping of several validations to a single tag for easier defining of validations on structs - Extraction of custom defined Field Name e.g. can specify to extract the JSON name while validating and have it available in the resulting FieldError Installation ------------ Use go get. go get gopkg.in/go-playground/validator.v8 or to update go get -u gopkg.in/go-playground/validator.v8 Then import the validator package into your own code. import "gopkg.in/go-playground/validator.v8" Error Return Value ------- Validation functions return type error They return type error to avoid the issue discussed in the following, where err is always != nil: * http://stackoverflow.com/a/29138676/3158232 * https://github.com/go-playground/validator/issues/134 validator only returns nil or ValidationErrors as type error; so in you code all you need to do is check if the error returned is not nil, and if it's not type cast it to type ValidationErrors like so: ```go err := validate.Struct(mystruct) validationErrors := err.(validator.ValidationErrors) ``` Usage and documentation ------ Please see http://godoc.org/gopkg.in/go-playground/validator.v8 for detailed usage docs. ##### Examples: Struct & Field validation ```go package main import ( "fmt" "gopkg.in/go-playground/validator.v8" ) // User contains user information type User struct { FirstName string `validate:"required"` LastName string `validate:"required"` Age uint8 `validate:"gte=0,lte=130"` Email string `validate:"required,email"` FavouriteColor string `validate:"hexcolor|rgb|rgba"` Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage... } // Address houses a users address information type Address struct { Street string `validate:"required"` City string `validate:"required"` Planet string `validate:"required"` Phone string `validate:"required"` } var validate *validator.Validate func main() { config := &validator.Config{TagName: "validate"} validate = validator.New(config) validateStruct() validateField() } func validateStruct() { address := &Address{ Street: "Eavesdown Docks", Planet: "Persphone", Phone: "none", } user := &User{ FirstName: "Badger", LastName: "Smith", Age: 135, Email: "Badger.Smith@gmail.com", FavouriteColor: "#000", Addresses: []*Address{address}, } // returns nil or ValidationErrors ( map[string]*FieldError ) errs := validate.Struct(user) if errs != nil { fmt.Println(errs) // output: Key: "User.Age" Error:Field validation for "Age" failed on the "lte" tag // Key: "User.Addresses[0].City" Error:Field validation for "City" failed on the "required" tag err := errs.(validator.ValidationErrors)["User.Addresses[0].City"] fmt.Println(err.Field) // output: City fmt.Println(err.Tag) // output: required fmt.Println(err.Kind) // output: string fmt.Println(err.Type) // output: string fmt.Println(err.Param) // output: fmt.Println(err.Value) // output: // from here you can create your own error messages in whatever language you wish return } // save user to database } func validateField() { myEmail := "joeybloggs.gmail.com" errs := validate.Field(myEmail, "required,email") if errs != nil { fmt.Println(errs) // output: Key: "" Error:Field validation for "" failed on the "email" tag return } // email ok, move on } ``` Custom Field Type ```go package main import ( "database/sql" "database/sql/driver" "fmt" "reflect" "gopkg.in/go-playground/validator.v8" ) // DbBackedUser User struct type DbBackedUser struct { Name sql.NullString `validate:"required"` Age sql.NullInt64 `validate:"required"` } func main() { config := &validator.Config{TagName: "validate"} validate := validator.New(config) // register all sql.Null* types to use the ValidateValuer CustomTypeFunc validate.RegisterCustomTypeFunc(ValidateValuer, sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{}) x := DbBackedUser{Name: sql.NullString{String: "", Valid: true}, Age: sql.NullInt64{Int64: 0, Valid: false}} errs := validate.Struct(x) if len(errs.(validator.ValidationErrors)) > 0 { fmt.Printf("Errs:\n%+v\n", errs) } } // ValidateValuer implements validator.CustomTypeFunc func ValidateValuer(field reflect.Value) interface{} { if valuer, ok := field.Interface().(driver.Valuer); ok { val, err := valuer.Value() if err == nil { return val } // handle the error how you want } return nil } ``` Struct Level Validation ```go package main import ( "fmt" "reflect" "gopkg.in/go-playground/validator.v8" ) // User contains user information type User struct { FirstName string `json:"fname"` LastName string `json:"lname"` Age uint8 `validate:"gte=0,lte=130"` Email string `validate:"required,email"` FavouriteColor string `validate:"hexcolor|rgb|rgba"` Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage... } // Address houses a users address information type Address struct { Street string `validate:"required"` City string `validate:"required"` Planet string `validate:"required"` Phone string `validate:"required"` } var validate *validator.Validate func main() { config := &validator.Config{TagName: "validate"} validate = validator.New(config) validate.RegisterStructValidation(UserStructLevelValidation, User{}) validateStruct() } // UserStructLevelValidation contains custom struct level validations that don't always // make sense at the field validation level. For Example this function validates that either // FirstName or LastName exist; could have done that with a custom field validation but then // would have had to add it to both fields duplicating the logic + overhead, this way it's // only validated once. // // NOTE: you may ask why wouldn't I just do this outside of validator, because doing this way // hooks right into validator and you can combine with validation tags and still have a // common error output format. func UserStructLevelValidation(v *validator.Validate, structLevel *validator.StructLevel) { user := structLevel.CurrentStruct.Interface().(User) if len(user.FirstName) == 0 && len(user.LastName) == 0 { structLevel.ReportError(reflect.ValueOf(user.FirstName), "FirstName", "fname", "fnameorlname") structLevel.ReportError(reflect.ValueOf(user.LastName), "LastName", "lname", "fnameorlname") } // plus can to more, even with different tag than "fnameorlname" } func validateStruct() { address := &Address{ Street: "Eavesdown Docks", Planet: "Persphone", Phone: "none", City: "Unknown", } user := &User{ FirstName: "", LastName: "", Age: 45, Email: "Badger.Smith@gmail.com", FavouriteColor: "#000", Addresses: []*Address{address}, } // returns nil or ValidationErrors ( map[string]*FieldError ) errs := validate.Struct(user) if errs != nil { fmt.Println(errs) // output: Key: 'User.LastName' Error:Field validation for 'LastName' failed on the 'fnameorlname' tag // Key: 'User.FirstName' Error:Field validation for 'FirstName' failed on the 'fnameorlname' tag err := errs.(validator.ValidationErrors)["User.FirstName"] fmt.Println(err.Field) // output: FirstName fmt.Println(err.Tag) // output: fnameorlname fmt.Println(err.Kind) // output: string fmt.Println(err.Type) // output: string fmt.Println(err.Param) // output: fmt.Println(err.Value) // output: // from here you can create your own error messages in whatever language you wish return } // save user to database } ``` Benchmarks ------ ###### Run on MacBook Pro (Retina, 15-inch, Late 2013) 2.6 GHz Intel Core i7 16 GB 1600 MHz DDR3 using Go version go1.5.3 darwin/amd64 ```go PASS BenchmarkFieldSuccess-8 20000000 118 ns/op 0 B/op 0 allocs/op BenchmarkFieldFailure-8 2000000 758 ns/op 432 B/op 4 allocs/op BenchmarkFieldDiveSuccess-8 500000 2471 ns/op 464 B/op 28 allocs/op BenchmarkFieldDiveFailure-8 500000 3172 ns/op 896 B/op 32 allocs/op BenchmarkFieldCustomTypeSuccess-8 5000000 300 ns/op 32 B/op 2 allocs/op BenchmarkFieldCustomTypeFailure-8 2000000 775 ns/op 432 B/op 4 allocs/op BenchmarkFieldOrTagSuccess-8 1000000 1122 ns/op 4 B/op 1 allocs/op BenchmarkFieldOrTagFailure-8 1000000 1167 ns/op 448 B/op 6 allocs/op BenchmarkStructLevelValidationSuccess-8 3000000 548 ns/op 160 B/op 5 allocs/op BenchmarkStructLevelValidationFailure-8 3000000 558 ns/op 160 B/op 5 allocs/op BenchmarkStructSimpleCustomTypeSuccess-8 2000000 623 ns/op 36 B/op 3 allocs/op BenchmarkStructSimpleCustomTypeFailure-8 1000000 1381 ns/op 640 B/op 9 allocs/op BenchmarkStructPartialSuccess-8 1000000 1036 ns/op 272 B/op 9 allocs/op BenchmarkStructPartialFailure-8 1000000 1734 ns/op 730 B/op 14 allocs/op BenchmarkStructExceptSuccess-8 2000000 888 ns/op 250 B/op 7 allocs/op BenchmarkStructExceptFailure-8 1000000 1036 ns/op 272 B/op 9 allocs/op BenchmarkStructSimpleCrossFieldSuccess-8 2000000 773 ns/op 80 B/op 4 allocs/op BenchmarkStructSimpleCrossFieldFailure-8 1000000 1487 ns/op 536 B/op 9 allocs/op BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 1000000 1261 ns/op 112 B/op 7 allocs/op BenchmarkStructSimpleCrossStructCrossFieldFailure-8 1000000 2055 ns/op 576 B/op 12 allocs/op BenchmarkStructSimpleSuccess-8 3000000 519 ns/op 4 B/op 1 allocs/op BenchmarkStructSimpleFailure-8 1000000 1429 ns/op 640 B/op 9 allocs/op BenchmarkStructSimpleSuccessParallel-8 10000000 146 ns/op 4 B/op 1 allocs/op BenchmarkStructSimpleFailureParallel-8 2000000 551 ns/op 640 B/op 9 allocs/op BenchmarkStructComplexSuccess-8 500000 3269 ns/op 244 B/op 15 allocs/op BenchmarkStructComplexFailure-8 200000 8436 ns/op 3609 B/op 60 allocs/op BenchmarkStructComplexSuccessParallel-8 1000000 1024 ns/op 244 B/op 15 allocs/op BenchmarkStructComplexFailureParallel-8 500000 3536 ns/op 3609 B/op 60 allocs/op ``` Complimentary Software ---------------------- Here is a list of software that compliments using this library either pre or post validation. * [form](https://github.com/go-playground/form) - Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support. * [Conform](https://github.com/leebenson/conform) - Trims, sanitizes & scrubs data based on struct tags. How to Contribute ------ There will always be a development branch for each version i.e. `v1-development`. In order to contribute, please make your pull requests against those branches. If the changes being proposed or requested are breaking changes, please create an issue, for discussion or create a pull request against the highest development branch for example this package has a v1 and v1-development branch however, there will also be a v2-development branch even though v2 doesn't exist yet. I strongly encourage everyone whom creates a custom validation function to contribute them and help make this package even better. License ------ Distributed under MIT License, please see license file in code for more details. ================================================ FILE: vendor/gopkg.in/go-playground/validator.v8/baked_in.go ================================================ package validator import ( "fmt" "net" "net/url" "reflect" "strings" "time" "unicode/utf8" ) // BakedInAliasValidators is a default mapping of a single validationstag that // defines a common or complex set of validation(s) to simplify // adding validation to structs. i.e. set key "_ageok" and the tags // are "gt=0,lte=130" or key "_preferredname" and tags "omitempty,gt=0,lte=60" var bakedInAliasValidators = map[string]string{ "iscolor": "hexcolor|rgb|rgba|hsl|hsla", } // BakedInValidators is the default map of ValidationFunc // you can add, remove or even replace items to suite your needs, // or even disregard and use your own map if so desired. var bakedInValidators = map[string]Func{ "required": HasValue, "len": HasLengthOf, "min": HasMinOf, "max": HasMaxOf, "eq": IsEq, "ne": IsNe, "lt": IsLt, "lte": IsLte, "gt": IsGt, "gte": IsGte, "eqfield": IsEqField, "eqcsfield": IsEqCrossStructField, "necsfield": IsNeCrossStructField, "gtcsfield": IsGtCrossStructField, "gtecsfield": IsGteCrossStructField, "ltcsfield": IsLtCrossStructField, "ltecsfield": IsLteCrossStructField, "nefield": IsNeField, "gtefield": IsGteField, "gtfield": IsGtField, "ltefield": IsLteField, "ltfield": IsLtField, "alpha": IsAlpha, "alphanum": IsAlphanum, "numeric": IsNumeric, "number": IsNumber, "hexadecimal": IsHexadecimal, "hexcolor": IsHEXColor, "rgb": IsRGB, "rgba": IsRGBA, "hsl": IsHSL, "hsla": IsHSLA, "email": IsEmail, "url": IsURL, "uri": IsURI, "base64": IsBase64, "contains": Contains, "containsany": ContainsAny, "containsrune": ContainsRune, "excludes": Excludes, "excludesall": ExcludesAll, "excludesrune": ExcludesRune, "isbn": IsISBN, "isbn10": IsISBN10, "isbn13": IsISBN13, "uuid": IsUUID, "uuid3": IsUUID3, "uuid4": IsUUID4, "uuid5": IsUUID5, "ascii": IsASCII, "printascii": IsPrintableASCII, "multibyte": HasMultiByteCharacter, "datauri": IsDataURI, "latitude": IsLatitude, "longitude": IsLongitude, "ssn": IsSSN, "ipv4": IsIPv4, "ipv6": IsIPv6, "ip": IsIP, "cidrv4": IsCIDRv4, "cidrv6": IsCIDRv6, "cidr": IsCIDR, "tcp4_addr": IsTCP4AddrResolvable, "tcp6_addr": IsTCP6AddrResolvable, "tcp_addr": IsTCPAddrResolvable, "udp4_addr": IsUDP4AddrResolvable, "udp6_addr": IsUDP6AddrResolvable, "udp_addr": IsUDPAddrResolvable, "ip4_addr": IsIP4AddrResolvable, "ip6_addr": IsIP6AddrResolvable, "ip_addr": IsIPAddrResolvable, "unix_addr": IsUnixAddrResolvable, "mac": IsMAC, } // IsMAC is the validation function for validating if the field's value is a valid MAC address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsMAC(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { _, err := net.ParseMAC(field.String()) return err == nil } // IsCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsCIDRv4(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { ip, _, err := net.ParseCIDR(field.String()) return err == nil && ip.To4() != nil } // IsCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsCIDRv6(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { ip, _, err := net.ParseCIDR(field.String()) return err == nil && ip.To4() == nil } // IsCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsCIDR(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { _, _, err := net.ParseCIDR(field.String()) return err == nil } // IsIPv4 is the validation function for validating if a value is a valid v4 IP address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsIPv4(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { ip := net.ParseIP(field.String()) return ip != nil && ip.To4() != nil } // IsIPv6 is the validation function for validating if the field's value is a valid v6 IP address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsIPv6(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { ip := net.ParseIP(field.String()) return ip != nil && ip.To4() == nil } // IsIP is the validation function for validating if the field's value is a valid v4 or v6 IP address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsIP(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { ip := net.ParseIP(field.String()) return ip != nil } // IsSSN is the validation function for validating if the field's value is a valid SSN. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsSSN(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if field.Len() != 11 { return false } return sSNRegex.MatchString(field.String()) } // IsLongitude is the validation function for validating if the field's value is a valid longitude coordinate. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsLongitude(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return longitudeRegex.MatchString(field.String()) } // IsLatitude is the validation function for validating if the field's value is a valid latitude coordinate. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsLatitude(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return latitudeRegex.MatchString(field.String()) } // IsDataURI is the validation function for validating if the field's value is a valid data URI. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsDataURI(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { uri := strings.SplitN(field.String(), ",", 2) if len(uri) != 2 { return false } if !dataURIRegex.MatchString(uri[0]) { return false } fld := reflect.ValueOf(uri[1]) return IsBase64(v, topStruct, currentStructOrField, fld, fld.Type(), fld.Kind(), param) } // HasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func HasMultiByteCharacter(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if field.Len() == 0 { return true } return multibyteRegex.MatchString(field.String()) } // IsPrintableASCII is the validation function for validating if the field's value is a valid printable ASCII character. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsPrintableASCII(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return printableASCIIRegex.MatchString(field.String()) } // IsASCII is the validation function for validating if the field's value is a valid ASCII character. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsASCII(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return aSCIIRegex.MatchString(field.String()) } // IsUUID5 is the validation function for validating if the field's value is a valid v5 UUID. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsUUID5(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return uUID5Regex.MatchString(field.String()) } // IsUUID4 is the validation function for validating if the field's value is a valid v4 UUID. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsUUID4(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return uUID4Regex.MatchString(field.String()) } // IsUUID3 is the validation function for validating if the field's value is a valid v3 UUID. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsUUID3(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return uUID3Regex.MatchString(field.String()) } // IsUUID is the validation function for validating if the field's value is a valid UUID of any version. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsUUID(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return uUIDRegex.MatchString(field.String()) } // IsISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsISBN(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return IsISBN10(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) || IsISBN13(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) } // IsISBN13 is the validation function for validating if the field's value is a valid v13 ISBN. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsISBN13(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { s := strings.Replace(strings.Replace(field.String(), "-", "", 4), " ", "", 4) if !iSBN13Regex.MatchString(s) { return false } var checksum int32 var i int32 factor := []int32{1, 3} for i = 0; i < 12; i++ { checksum += factor[i%2] * int32(s[i]-'0') } return (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0 } // IsISBN10 is the validation function for validating if the field's value is a valid v10 ISBN. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsISBN10(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { s := strings.Replace(strings.Replace(field.String(), "-", "", 3), " ", "", 3) if !iSBN10Regex.MatchString(s) { return false } var checksum int32 var i int32 for i = 0; i < 9; i++ { checksum += (i + 1) * int32(s[i]-'0') } if s[9] == 'X' { checksum += 10 * 10 } else { checksum += 10 * int32(s[9]-'0') } return checksum%11 == 0 } // ExcludesRune is the validation function for validating that the field's value does not contain the rune specified within the param. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func ExcludesRune(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return !ContainsRune(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) } // ExcludesAll is the validation function for validating that the field's value does not contain any of the characters specified within the param. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func ExcludesAll(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return !ContainsAny(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) } // Excludes is the validation function for validating that the field's value does not contain the text specified within the param. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func Excludes(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return !Contains(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) } // ContainsRune is the validation function for validating that the field's value contains the rune specified within the param. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func ContainsRune(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { r, _ := utf8.DecodeRuneInString(param) return strings.ContainsRune(field.String(), r) } // ContainsAny is the validation function for validating that the field's value contains any of the characters specified within the param. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func ContainsAny(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return strings.ContainsAny(field.String(), param) } // Contains is the validation function for validating that the field's value contains the text specified within the param. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func Contains(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return strings.Contains(field.String(), param) } // IsNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsNeField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param) if !ok || currentKind != fieldKind { return true } switch fieldKind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() != currentField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() != currentField.Uint() case reflect.Float32, reflect.Float64: return field.Float() != currentField.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) != int64(currentField.Len()) case reflect.Struct: // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return true } if fieldType == timeType { t := currentField.Interface().(time.Time) fieldTime := field.Interface().(time.Time) return !fieldTime.Equal(t) } } // default reflect.String: return field.String() != currentField.String() } // IsNe is the validation function for validating that the field's value does not equal the provided param value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsNe(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return !IsEq(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) } // IsLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsLteCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { topField, topKind, ok := v.GetStructFieldOK(topStruct, param) if !ok || topKind != fieldKind { return false } switch fieldKind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() <= topField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() <= topField.Uint() case reflect.Float32, reflect.Float64: return field.Float() <= topField.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) <= int64(topField.Len()) case reflect.Struct: // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return false } if fieldType == timeType { fieldTime := field.Interface().(time.Time) topTime := topField.Interface().(time.Time) return fieldTime.Before(topTime) || fieldTime.Equal(topTime) } } // default reflect.String: return field.String() <= topField.String() } // IsLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsLtCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { topField, topKind, ok := v.GetStructFieldOK(topStruct, param) if !ok || topKind != fieldKind { return false } switch fieldKind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() < topField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() < topField.Uint() case reflect.Float32, reflect.Float64: return field.Float() < topField.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) < int64(topField.Len()) case reflect.Struct: // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return false } if fieldType == timeType { fieldTime := field.Interface().(time.Time) topTime := topField.Interface().(time.Time) return fieldTime.Before(topTime) } } // default reflect.String: return field.String() < topField.String() } // IsGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsGteCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { topField, topKind, ok := v.GetStructFieldOK(topStruct, param) if !ok || topKind != fieldKind { return false } switch fieldKind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() >= topField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() >= topField.Uint() case reflect.Float32, reflect.Float64: return field.Float() >= topField.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) >= int64(topField.Len()) case reflect.Struct: // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return false } if fieldType == timeType { fieldTime := field.Interface().(time.Time) topTime := topField.Interface().(time.Time) return fieldTime.After(topTime) || fieldTime.Equal(topTime) } } // default reflect.String: return field.String() >= topField.String() } // IsGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsGtCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { topField, topKind, ok := v.GetStructFieldOK(topStruct, param) if !ok || topKind != fieldKind { return false } switch fieldKind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() > topField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() > topField.Uint() case reflect.Float32, reflect.Float64: return field.Float() > topField.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) > int64(topField.Len()) case reflect.Struct: // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return false } if fieldType == timeType { fieldTime := field.Interface().(time.Time) topTime := topField.Interface().(time.Time) return fieldTime.After(topTime) } } // default reflect.String: return field.String() > topField.String() } // IsNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsNeCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { topField, currentKind, ok := v.GetStructFieldOK(topStruct, param) if !ok || currentKind != fieldKind { return true } switch fieldKind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return topField.Int() != field.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return topField.Uint() != field.Uint() case reflect.Float32, reflect.Float64: return topField.Float() != field.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(topField.Len()) != int64(field.Len()) case reflect.Struct: // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return true } if fieldType == timeType { t := field.Interface().(time.Time) fieldTime := topField.Interface().(time.Time) return !fieldTime.Equal(t) } } // default reflect.String: return topField.String() != field.String() } // IsEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsEqCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { topField, topKind, ok := v.GetStructFieldOK(topStruct, param) if !ok || topKind != fieldKind { return false } switch fieldKind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return topField.Int() == field.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return topField.Uint() == field.Uint() case reflect.Float32, reflect.Float64: return topField.Float() == field.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(topField.Len()) == int64(field.Len()) case reflect.Struct: // Not Same underlying type i.e. struct and time if fieldType != topField.Type() { return false } if fieldType == timeType { t := field.Interface().(time.Time) fieldTime := topField.Interface().(time.Time) return fieldTime.Equal(t) } } // default reflect.String: return topField.String() == field.String() } // IsEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsEqField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param) if !ok || currentKind != fieldKind { return false } switch fieldKind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() == currentField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() == currentField.Uint() case reflect.Float32, reflect.Float64: return field.Float() == currentField.Float() case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) == int64(currentField.Len()) case reflect.Struct: // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return false } if fieldType == timeType { t := currentField.Interface().(time.Time) fieldTime := field.Interface().(time.Time) return fieldTime.Equal(t) } } // default reflect.String: return field.String() == currentField.String() } // IsEq is the validation function for validating if the current field's value is equal to the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsEq(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { case reflect.String: return field.String() == param case reflect.Slice, reflect.Map, reflect.Array: p := asInt(param) return int64(field.Len()) == p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p := asInt(param) return field.Int() == p case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: p := asUint(param) return field.Uint() == p case reflect.Float32, reflect.Float64: p := asFloat(param) return field.Float() == p } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // IsBase64 is the validation function for validating if the current field's value is a valid base 64. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsBase64(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return base64Regex.MatchString(field.String()) } // IsURI is the validation function for validating if the current field's value is a valid URI. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsURI(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { case reflect.String: s := field.String() // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195 // emulate browser and strip the '#' suffix prior to validation. see issue-#237 if i := strings.Index(s, "#"); i > -1 { s = s[:i] } if s == blank { return false } _, err := url.ParseRequestURI(s) return err == nil } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // IsURL is the validation function for validating if the current field's value is a valid URL. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsURL(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { case reflect.String: var i int s := field.String() // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195 // emulate browser and strip the '#' suffix prior to validation. see issue-#237 if i = strings.Index(s, "#"); i > -1 { s = s[:i] } if s == blank { return false } url, err := url.ParseRequestURI(s) if err != nil || url.Scheme == blank { return false } return err == nil } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // IsEmail is the validation function for validating if the current field's value is a valid email address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsEmail(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return emailRegex.MatchString(field.String()) } // IsHSLA is the validation function for validating if the current field's value is a valid HSLA color. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsHSLA(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return hslaRegex.MatchString(field.String()) } // IsHSL is the validation function for validating if the current field's value is a valid HSL color. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsHSL(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return hslRegex.MatchString(field.String()) } // IsRGBA is the validation function for validating if the current field's value is a valid RGBA color. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsRGBA(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return rgbaRegex.MatchString(field.String()) } // IsRGB is the validation function for validating if the current field's value is a valid RGB color. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsRGB(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return rgbRegex.MatchString(field.String()) } // IsHEXColor is the validation function for validating if the current field's value is a valid HEX color. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsHEXColor(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return hexcolorRegex.MatchString(field.String()) } // IsHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsHexadecimal(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return hexadecimalRegex.MatchString(field.String()) } // IsNumber is the validation function for validating if the current field's value is a valid number. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsNumber(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return numberRegex.MatchString(field.String()) } // IsNumeric is the validation function for validating if the current field's value is a valid numeric value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsNumeric(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return numericRegex.MatchString(field.String()) } // IsAlphanum is the validation function for validating if the current field's value is a valid alphanumeric value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsAlphanum(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return alphaNumericRegex.MatchString(field.String()) } // IsAlpha is the validation function for validating if the current field's value is a valid alpha value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsAlpha(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return alphaRegex.MatchString(field.String()) } // HasValue is the validation function for validating if the current field's value is not the default static value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func HasValue(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: return !field.IsNil() default: return field.IsValid() && field.Interface() != reflect.Zero(fieldType).Interface() } } // IsGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsGteField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param) if !ok || currentKind != fieldKind { return false } switch fieldKind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() >= currentField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() >= currentField.Uint() case reflect.Float32, reflect.Float64: return field.Float() >= currentField.Float() case reflect.Struct: // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return false } if fieldType == timeType { t := currentField.Interface().(time.Time) fieldTime := field.Interface().(time.Time) return fieldTime.After(t) || fieldTime.Equal(t) } } // default reflect.String return len(field.String()) >= len(currentField.String()) } // IsGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsGtField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param) if !ok || currentKind != fieldKind { return false } switch fieldKind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() > currentField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() > currentField.Uint() case reflect.Float32, reflect.Float64: return field.Float() > currentField.Float() case reflect.Struct: // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return false } if fieldType == timeType { t := currentField.Interface().(time.Time) fieldTime := field.Interface().(time.Time) return fieldTime.After(t) } } // default reflect.String return len(field.String()) > len(currentField.String()) } // IsGte is the validation function for validating if the current field's value is greater than or equal to the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsGte(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { case reflect.String: p := asInt(param) return int64(utf8.RuneCountInString(field.String())) >= p case reflect.Slice, reflect.Map, reflect.Array: p := asInt(param) return int64(field.Len()) >= p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p := asInt(param) return field.Int() >= p case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: p := asUint(param) return field.Uint() >= p case reflect.Float32, reflect.Float64: p := asFloat(param) return field.Float() >= p case reflect.Struct: if fieldType == timeType || fieldType == timePtrType { now := time.Now().UTC() t := field.Interface().(time.Time) return t.After(now) || t.Equal(now) } } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // IsGt is the validation function for validating if the current field's value is greater than the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsGt(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { case reflect.String: p := asInt(param) return int64(utf8.RuneCountInString(field.String())) > p case reflect.Slice, reflect.Map, reflect.Array: p := asInt(param) return int64(field.Len()) > p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p := asInt(param) return field.Int() > p case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: p := asUint(param) return field.Uint() > p case reflect.Float32, reflect.Float64: p := asFloat(param) return field.Float() > p case reflect.Struct: if fieldType == timeType || fieldType == timePtrType { return field.Interface().(time.Time).After(time.Now().UTC()) } } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // HasLengthOf is the validation function for validating if the current field's value is equal to the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func HasLengthOf(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { case reflect.String: p := asInt(param) return int64(utf8.RuneCountInString(field.String())) == p case reflect.Slice, reflect.Map, reflect.Array: p := asInt(param) return int64(field.Len()) == p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p := asInt(param) return field.Int() == p case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: p := asUint(param) return field.Uint() == p case reflect.Float32, reflect.Float64: p := asFloat(param) return field.Float() == p } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // HasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func HasMinOf(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return IsGte(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) } // IsLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsLteField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param) if !ok || currentKind != fieldKind { return false } switch fieldKind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() <= currentField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() <= currentField.Uint() case reflect.Float32, reflect.Float64: return field.Float() <= currentField.Float() case reflect.Struct: // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return false } if fieldType == timeType { t := currentField.Interface().(time.Time) fieldTime := field.Interface().(time.Time) return fieldTime.Before(t) || fieldTime.Equal(t) } } // default reflect.String return len(field.String()) <= len(currentField.String()) } // IsLtField is the validation function for validating if the current field's value is less than the field specified by the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsLtField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param) if !ok || currentKind != fieldKind { return false } switch fieldKind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return field.Int() < currentField.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return field.Uint() < currentField.Uint() case reflect.Float32, reflect.Float64: return field.Float() < currentField.Float() case reflect.Struct: // Not Same underlying type i.e. struct and time if fieldType != currentField.Type() { return false } if fieldType == timeType { t := currentField.Interface().(time.Time) fieldTime := field.Interface().(time.Time) return fieldTime.Before(t) } } // default reflect.String return len(field.String()) < len(currentField.String()) } // IsLte is the validation function for validating if the current field's value is less than or equal to the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsLte(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { case reflect.String: p := asInt(param) return int64(utf8.RuneCountInString(field.String())) <= p case reflect.Slice, reflect.Map, reflect.Array: p := asInt(param) return int64(field.Len()) <= p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p := asInt(param) return field.Int() <= p case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: p := asUint(param) return field.Uint() <= p case reflect.Float32, reflect.Float64: p := asFloat(param) return field.Float() <= p case reflect.Struct: if fieldType == timeType || fieldType == timePtrType { now := time.Now().UTC() t := field.Interface().(time.Time) return t.Before(now) || t.Equal(now) } } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // IsLt is the validation function for validating if the current field's value is less than the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsLt(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { switch fieldKind { case reflect.String: p := asInt(param) return int64(utf8.RuneCountInString(field.String())) < p case reflect.Slice, reflect.Map, reflect.Array: p := asInt(param) return int64(field.Len()) < p case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p := asInt(param) return field.Int() < p case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: p := asUint(param) return field.Uint() < p case reflect.Float32, reflect.Float64: p := asFloat(param) return field.Float() < p case reflect.Struct: if fieldType == timeType || fieldType == timePtrType { return field.Interface().(time.Time).Before(time.Now().UTC()) } } panic(fmt.Sprintf("Bad field type %T", field.Interface())) } // HasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func HasMaxOf(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return IsLte(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) } // IsTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsTCP4AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { return false } _, err := net.ResolveTCPAddr("tcp4", field.String()) return err == nil } // IsTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsTCP6AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { return false } _, err := net.ResolveTCPAddr("tcp6", field.String()) return err == nil } // IsTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsTCPAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) && !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { return false } _, err := net.ResolveTCPAddr("tcp", field.String()) return err == nil } // IsUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsUDP4AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { return false } _, err := net.ResolveUDPAddr("udp4", field.String()) return err == nil } // IsUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsUDP6AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { return false } _, err := net.ResolveUDPAddr("udp6", field.String()) return err == nil } // IsUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsUDPAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) && !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { return false } _, err := net.ResolveUDPAddr("udp", field.String()) return err == nil } // IsIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsIP4AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if !IsIPv4(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { return false } _, err := net.ResolveIPAddr("ip4", field.String()) return err == nil } // IsIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsIP6AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if !IsIPv6(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { return false } _, err := net.ResolveIPAddr("ip6", field.String()) return err == nil } // IsIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsIPAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if !IsIP(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { return false } _, err := net.ResolveIPAddr("ip", field.String()) return err == nil } // IsUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly. func IsUnixAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { _, err := net.ResolveUnixAddr("unix", field.String()) return err == nil } func isIP4Addr(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { val := field.String() if idx := strings.LastIndex(val, ":"); idx != -1 { val = val[0:idx] } if !IsIPv4(v, topStruct, currentStructOrField, reflect.ValueOf(val), fieldType, fieldKind, param) { return false } return true } func isIP6Addr(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { val := field.String() if idx := strings.LastIndex(val, ":"); idx != -1 { if idx != 0 && val[idx-1:idx] == "]" { val = val[1 : idx-1] } } if !IsIPv6(v, topStruct, currentStructOrField, reflect.ValueOf(val), fieldType, fieldKind, param) { return false } return true } ================================================ FILE: vendor/gopkg.in/go-playground/validator.v8/cache.go ================================================ package validator import ( "fmt" "reflect" "strings" "sync" "sync/atomic" ) type tagType uint8 const ( typeDefault tagType = iota typeOmitEmpty typeNoStructLevel typeStructOnly typeDive typeOr typeExists ) type structCache struct { lock sync.Mutex m atomic.Value // map[reflect.Type]*cStruct } func (sc *structCache) Get(key reflect.Type) (c *cStruct, found bool) { c, found = sc.m.Load().(map[reflect.Type]*cStruct)[key] return } func (sc *structCache) Set(key reflect.Type, value *cStruct) { m := sc.m.Load().(map[reflect.Type]*cStruct) nm := make(map[reflect.Type]*cStruct, len(m)+1) for k, v := range m { nm[k] = v } nm[key] = value sc.m.Store(nm) } type tagCache struct { lock sync.Mutex m atomic.Value // map[string]*cTag } func (tc *tagCache) Get(key string) (c *cTag, found bool) { c, found = tc.m.Load().(map[string]*cTag)[key] return } func (tc *tagCache) Set(key string, value *cTag) { m := tc.m.Load().(map[string]*cTag) nm := make(map[string]*cTag, len(m)+1) for k, v := range m { nm[k] = v } nm[key] = value tc.m.Store(nm) } type cStruct struct { Name string fields map[int]*cField fn StructLevelFunc } type cField struct { Idx int Name string AltName string cTags *cTag } type cTag struct { tag string aliasTag string actualAliasTag string param string hasAlias bool typeof tagType hasTag bool fn Func next *cTag } func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStruct { v.structCache.lock.Lock() defer v.structCache.lock.Unlock() // leave as defer! because if inner panics, it will never get unlocked otherwise! typ := current.Type() // could have been multiple trying to access, but once first is done this ensures struct // isn't parsed again. cs, ok := v.structCache.Get(typ) if ok { return cs } cs = &cStruct{Name: sName, fields: make(map[int]*cField), fn: v.structLevelFuncs[typ]} numFields := current.NumField() var ctag *cTag var fld reflect.StructField var tag string var customName string for i := 0; i < numFields; i++ { fld = typ.Field(i) if !fld.Anonymous && fld.PkgPath != blank { continue } tag = fld.Tag.Get(v.tagName) if tag == skipValidationTag { continue } customName = fld.Name if v.fieldNameTag != blank { name := strings.SplitN(fld.Tag.Get(v.fieldNameTag), ",", 2)[0] // dash check is for json "-" (aka skipValidationTag) means don't output in json if name != "" && name != skipValidationTag { customName = name } } // NOTE: cannot use shared tag cache, because tags may be equal, but things like alias may be different // and so only struct level caching can be used instead of combined with Field tag caching if len(tag) > 0 { ctag, _ = v.parseFieldTagsRecursive(tag, fld.Name, blank, false) } else { // even if field doesn't have validations need cTag for traversing to potential inner/nested // elements of the field. ctag = new(cTag) } cs.fields[i] = &cField{Idx: i, Name: fld.Name, AltName: customName, cTags: ctag} } v.structCache.Set(typ, cs) return cs } func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias string, hasAlias bool) (firstCtag *cTag, current *cTag) { var t string var ok bool noAlias := len(alias) == 0 tags := strings.Split(tag, tagSeparator) for i := 0; i < len(tags); i++ { t = tags[i] if noAlias { alias = t } if v.hasAliasValidators { // check map for alias and process new tags, otherwise process as usual if tagsVal, found := v.aliasValidators[t]; found { if i == 0 { firstCtag, current = v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) } else { next, curr := v.parseFieldTagsRecursive(tagsVal, fieldName, t, true) current.next, current = next, curr } continue } } if i == 0 { current = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true} firstCtag = current } else { current.next = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true} current = current.next } switch t { case diveTag: current.typeof = typeDive continue case omitempty: current.typeof = typeOmitEmpty continue case structOnlyTag: current.typeof = typeStructOnly continue case noStructLevelTag: current.typeof = typeNoStructLevel continue case existsTag: current.typeof = typeExists continue default: // if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C" orVals := strings.Split(t, orSeparator) for j := 0; j < len(orVals); j++ { vals := strings.SplitN(orVals[j], tagKeySeparator, 2) if noAlias { alias = vals[0] current.aliasTag = alias } else { current.actualAliasTag = t } if j > 0 { current.next = &cTag{aliasTag: alias, actualAliasTag: current.actualAliasTag, hasAlias: hasAlias, hasTag: true} current = current.next } current.tag = vals[0] if len(current.tag) == 0 { panic(strings.TrimSpace(fmt.Sprintf(invalidValidation, fieldName))) } if current.fn, ok = v.validationFuncs[current.tag]; !ok { panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, fieldName))) } if len(orVals) > 1 { current.typeof = typeOr } if len(vals) > 1 { current.param = strings.Replace(strings.Replace(vals[1], utf8HexComma, ",", -1), utf8Pipe, "|", -1) } } } } return } ================================================ FILE: vendor/gopkg.in/go-playground/validator.v8/doc.go ================================================ /* Package validator implements value validations for structs and individual fields based on tags. It can also handle Cross-Field and Cross-Struct validation for nested structs and has the ability to dive into arrays and maps of any type. Why not a better error message? Because this library intends for you to handle your own error messages. Why should I handle my own errors? Many reasons. We built an internationalized application and needed to know the field, and what validation failed so we could provide a localized error. if fieldErr.Field == "Name" { switch fieldErr.ErrorTag case "required": return "Translated string based on field + error" default: return "Translated string based on field" } Validation Functions Return Type error Doing things this way is actually the way the standard library does, see the file.Open method here: https://golang.org/pkg/os/#Open. The authors return type "error" to avoid the issue discussed in the following, where err is always != nil: http://stackoverflow.com/a/29138676/3158232 https://github.com/go-playground/validator/issues/134 Validator only returns nil or ValidationErrors as type error; so, in your code all you need to do is check if the error returned is not nil, and if it's not type cast it to type ValidationErrors like so err.(validator.ValidationErrors). Custom Functions Custom functions can be added. Example: // Structure func customFunc(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { if whatever { return false } return true } validate.RegisterValidation("custom tag name", customFunc) // NOTES: using the same tag name as an existing function // will overwrite the existing one Cross-Field Validation Cross-Field Validation can be done via the following tags: - eqfield - nefield - gtfield - gtefield - ltfield - ltefield - eqcsfield - necsfield - gtcsfield - ftecsfield - ltcsfield - ltecsfield If, however, some custom cross-field validation is required, it can be done using a custom validation. Why not just have cross-fields validation tags (i.e. only eqcsfield and not eqfield)? The reason is efficiency. If you want to check a field within the same struct "eqfield" only has to find the field on the same struct (1 level). But, if we used "eqcsfield" it could be multiple levels down. Example: type Inner struct { StartDate time.Time } type Outer struct { InnerStructField *Inner CreatedAt time.Time `validate:"ltecsfield=InnerStructField.StartDate"` } now := time.Now() inner := &Inner{ StartDate: now, } outer := &Outer{ InnerStructField: inner, CreatedAt: now, } errs := validate.Struct(outer) // NOTE: when calling validate.Struct(val) topStruct will be the top level struct passed // into the function // when calling validate.FieldWithValue(val, field, tag) val will be // whatever you pass, struct, field... // when calling validate.Field(field, tag) val will be nil Multiple Validators Multiple validators on a field will process in the order defined. Example: type Test struct { Field `validate:"max=10,min=1"` } // max will be checked then min Bad Validator definitions are not handled by the library. Example: type Test struct { Field `validate:"min=10,max=0"` } // this definition of min max will never succeed Using Validator Tags Baked In Cross-Field validation only compares fields on the same struct. If Cross-Field + Cross-Struct validation is needed you should implement your own custom validator. Comma (",") is the default separator of validation tags. If you wish to have a comma included within the parameter (i.e. excludesall=,) you will need to use the UTF-8 hex representation 0x2C, which is replaced in the code as a comma, so the above will become excludesall=0x2C. type Test struct { Field `validate:"excludesall=,"` // BAD! Do not include a comma. Field `validate:"excludesall=0x2C"` // GOOD! Use the UTF-8 hex representation. } Pipe ("|") is the default separator of validation tags. If you wish to have a pipe included within the parameter i.e. excludesall=| you will need to use the UTF-8 hex representation 0x7C, which is replaced in the code as a pipe, so the above will become excludesall=0x7C type Test struct { Field `validate:"excludesall=|"` // BAD! Do not include a a pipe! Field `validate:"excludesall=0x7C"` // GOOD! Use the UTF-8 hex representation. } Baked In Validators and Tags Here is a list of the current built in validators: Skip Field Tells the validation to skip this struct field; this is particularly handy in ignoring embedded structs from being validated. (Usage: -) Usage: - Or Operator This is the 'or' operator allowing multiple validators to be used and accepted. (Usage: rbg|rgba) <-- this would allow either rgb or rgba colors to be accepted. This can also be combined with 'and' for example ( Usage: omitempty,rgb|rgba) Usage: | StructOnly When a field that is a nested struct is encountered, and contains this flag any validation on the nested struct will be run, but none of the nested struct fields will be validated. This is usefull if inside of you program you know the struct will be valid, but need to verify it has been assigned. NOTE: only "required" and "omitempty" can be used on a struct itself. Usage: structonly NoStructLevel Same as structonly tag except that any struct level validations will not run. Usage: nostructlevel Exists Is a special tag without a validation function attached. It is used when a field is a Pointer, Interface or Invalid and you wish to validate that it exists. Example: want to ensure a bool exists if you define the bool as a pointer and use exists it will ensure there is a value; couldn't use required as it would fail when the bool was false. exists will fail is the value is a Pointer, Interface or Invalid and is nil. Usage: exists Omit Empty Allows conditional validation, for example if a field is not set with a value (Determined by the "required" validator) then other validation such as min or max won't run, but if a value is set validation will run. Usage: omitempty Dive This tells the validator to dive into a slice, array or map and validate that level of the slice, array or map with the validation tags that follow. Multidimensional nesting is also supported, each level you wish to dive will require another dive tag. Usage: dive Example #1 [][]string with validation tag "gt=0,dive,len=1,dive,required" // gt=0 will be applied to [] // len=1 will be applied to []string // required will be applied to string Example #2 [][]string with validation tag "gt=0,dive,dive,required" // gt=0 will be applied to [] // []string will be spared validation // required will be applied to string Required This validates that the value is not the data types default zero value. For numbers ensures value is not zero. For strings ensures value is not "". For slices, maps, pointers, interfaces, channels and functions ensures the value is not nil. Usage: required Length For numbers, max will ensure that the value is equal to the parameter given. For strings, it checks that the string length is exactly that number of characters. For slices, arrays, and maps, validates the number of items. Usage: len=10 Maximum For numbers, max will ensure that the value is less than or equal to the parameter given. For strings, it checks that the string length is at most that number of characters. For slices, arrays, and maps, validates the number of items. Usage: max=10 Mininum For numbers, min will ensure that the value is greater or equal to the parameter given. For strings, it checks that the string length is at least that number of characters. For slices, arrays, and maps, validates the number of items. Usage: min=10 Equals For strings & numbers, eq will ensure that the value is equal to the parameter given. For slices, arrays, and maps, validates the number of items. Usage: eq=10 Not Equal For strings & numbers, ne will ensure that the value is not equal to the parameter given. For slices, arrays, and maps, validates the number of items. Usage: ne=10 Greater Than For numbers, this will ensure that the value is greater than the parameter given. For strings, it checks that the string length is greater than that number of characters. For slices, arrays and maps it validates the number of items. Example #1 Usage: gt=10 Example #2 (time.Time) For time.Time ensures the time value is greater than time.Now.UTC(). Usage: gt Greater Than or Equal Same as 'min' above. Kept both to make terminology with 'len' easier. Example #1 Usage: gte=10 Example #2 (time.Time) For time.Time ensures the time value is greater than or equal to time.Now.UTC(). Usage: gte Less Than For numbers, this will ensure that the value is less than the parameter given. For strings, it checks that the string length is less than that number of characters. For slices, arrays, and maps it validates the number of items. Example #1 Usage: lt=10 Example #2 (time.Time) For time.Time ensures the time value is less than time.Now.UTC(). Usage: lt Less Than or Equal Same as 'max' above. Kept both to make terminology with 'len' easier. Example #1 Usage: lte=10 Example #2 (time.Time) For time.Time ensures the time value is less than or equal to time.Now.UTC(). Usage: lte Field Equals Another Field This will validate the field value against another fields value either within a struct or passed in field. Example #1: // Validation on Password field using: Usage: eqfield=ConfirmPassword Example #2: // Validating by field: validate.FieldWithValue(password, confirmpassword, "eqfield") Field Equals Another Field (relative) This does the same as eqfield except that it validates the field provided relative to the top level struct. Usage: eqcsfield=InnerStructField.Field) Field Does Not Equal Another Field This will validate the field value against another fields value either within a struct or passed in field. Examples: // Confirm two colors are not the same: // // Validation on Color field: Usage: nefield=Color2 // Validating by field: validate.FieldWithValue(color1, color2, "nefield") Field Does Not Equal Another Field (relative) This does the same as nefield except that it validates the field provided relative to the top level struct. Usage: necsfield=InnerStructField.Field Field Greater Than Another Field Only valid for Numbers and time.Time types, this will validate the field value against another fields value either within a struct or passed in field. usage examples are for validation of a Start and End date: Example #1: // Validation on End field using: validate.Struct Usage(gtfield=Start) Example #2: // Validating by field: validate.FieldWithValue(start, end, "gtfield") Field Greater Than Another Relative Field This does the same as gtfield except that it validates the field provided relative to the top level struct. Usage: gtcsfield=InnerStructField.Field Field Greater Than or Equal To Another Field Only valid for Numbers and time.Time types, this will validate the field value against another fields value either within a struct or passed in field. usage examples are for validation of a Start and End date: Example #1: // Validation on End field using: validate.Struct Usage(gtefield=Start) Example #2: // Validating by field: validate.FieldWithValue(start, end, "gtefield") Field Greater Than or Equal To Another Relative Field This does the same as gtefield except that it validates the field provided relative to the top level struct. Usage: gtecsfield=InnerStructField.Field Less Than Another Field Only valid for Numbers and time.Time types, this will validate the field value against another fields value either within a struct or passed in field. usage examples are for validation of a Start and End date: Example #1: // Validation on End field using: validate.Struct Usage(ltfield=Start) Example #2: // Validating by field: validate.FieldWithValue(start, end, "ltfield") Less Than Another Relative Field This does the same as ltfield except that it validates the field provided relative to the top level struct. Usage: ltcsfield=InnerStructField.Field Less Than or Equal To Another Field Only valid for Numbers and time.Time types, this will validate the field value against another fields value either within a struct or passed in field. usage examples are for validation of a Start and End date: Example #1: // Validation on End field using: validate.Struct Usage(ltefield=Start) Example #2: // Validating by field: validate.FieldWithValue(start, end, "ltefield") Less Than or Equal To Another Relative Field This does the same as ltefield except that it validates the field provided relative to the top level struct. Usage: ltecsfield=InnerStructField.Field Alpha Only This validates that a string value contains alpha characters only Usage: alpha Alphanumeric This validates that a string value contains alphanumeric characters only Usage: alphanum Numeric This validates that a string value contains a basic numeric value. basic excludes exponents etc... Usage: numeric Hexadecimal String This validates that a string value contains a valid hexadecimal. Usage: hexadecimal Hexcolor String This validates that a string value contains a valid hex color including hashtag (#) Usage: hexcolor RGB String This validates that a string value contains a valid rgb color Usage: rgb RGBA String This validates that a string value contains a valid rgba color Usage: rgba HSL String This validates that a string value contains a valid hsl color Usage: hsl HSLA String This validates that a string value contains a valid hsla color Usage: hsla E-mail String This validates that a string value contains a valid email This may not conform to all possibilities of any rfc standard, but neither does any email provider accept all posibilities. Usage: email URL String This validates that a string value contains a valid url This will accept any url the golang request uri accepts but must contain a schema for example http:// or rtmp:// Usage: url URI String This validates that a string value contains a valid uri This will accept any uri the golang request uri accepts Usage: uri Base64 String This validates that a string value contains a valid base64 value. Although an empty string is valid base64 this will report an empty string as an error, if you wish to accept an empty string as valid you can use this with the omitempty tag. Usage: base64 Contains This validates that a string value contains the substring value. Usage: contains=@ Contains Any This validates that a string value contains any Unicode code points in the substring value. Usage: containsany=!@#? Contains Rune This validates that a string value contains the supplied rune value. Usage: containsrune=@ Excludes This validates that a string value does not contain the substring value. Usage: excludes=@ Excludes All This validates that a string value does not contain any Unicode code points in the substring value. Usage: excludesall=!@#? Excludes Rune This validates that a string value does not contain the supplied rune value. Usage: excludesrune=@ International Standard Book Number This validates that a string value contains a valid isbn10 or isbn13 value. Usage: isbn International Standard Book Number 10 This validates that a string value contains a valid isbn10 value. Usage: isbn10 International Standard Book Number 13 This validates that a string value contains a valid isbn13 value. Usage: isbn13 Universally Unique Identifier UUID This validates that a string value contains a valid UUID. Usage: uuid Universally Unique Identifier UUID v3 This validates that a string value contains a valid version 3 UUID. Usage: uuid3 Universally Unique Identifier UUID v4 This validates that a string value contains a valid version 4 UUID. Usage: uuid4 Universally Unique Identifier UUID v5 This validates that a string value contains a valid version 5 UUID. Usage: uuid5 ASCII This validates that a string value contains only ASCII characters. NOTE: if the string is blank, this validates as true. Usage: ascii Printable ASCII This validates that a string value contains only printable ASCII characters. NOTE: if the string is blank, this validates as true. Usage: asciiprint Multi-Byte Characters This validates that a string value contains one or more multibyte characters. NOTE: if the string is blank, this validates as true. Usage: multibyte Data URL This validates that a string value contains a valid DataURI. NOTE: this will also validate that the data portion is valid base64 Usage: datauri Latitude This validates that a string value contains a valid latitude. Usage: latitude Longitude This validates that a string value contains a valid longitude. Usage: longitude Social Security Number SSN This validates that a string value contains a valid U.S. Social Security Number. Usage: ssn Internet Protocol Address IP This validates that a string value contains a valid IP Adress. Usage: ip Internet Protocol Address IPv4 This validates that a string value contains a valid v4 IP Adress. Usage: ipv4 Internet Protocol Address IPv6 This validates that a string value contains a valid v6 IP Adress. Usage: ipv6 Classless Inter-Domain Routing CIDR This validates that a string value contains a valid CIDR Adress. Usage: cidr Classless Inter-Domain Routing CIDRv4 This validates that a string value contains a valid v4 CIDR Adress. Usage: cidrv4 Classless Inter-Domain Routing CIDRv6 This validates that a string value contains a valid v6 CIDR Adress. Usage: cidrv6 Transmission Control Protocol Address TCP This validates that a string value contains a valid resolvable TCP Adress. Usage: tcp_addr Transmission Control Protocol Address TCPv4 This validates that a string value contains a valid resolvable v4 TCP Adress. Usage: tcp4_addr Transmission Control Protocol Address TCPv6 This validates that a string value contains a valid resolvable v6 TCP Adress. Usage: tcp6_addr User Datagram Protocol Address UDP This validates that a string value contains a valid resolvable UDP Adress. Usage: udp_addr User Datagram Protocol Address UDPv4 This validates that a string value contains a valid resolvable v4 UDP Adress. Usage: udp4_addr User Datagram Protocol Address UDPv6 This validates that a string value contains a valid resolvable v6 UDP Adress. Usage: udp6_addr Internet Protocol Address IP This validates that a string value contains a valid resolvable IP Adress. Usage: ip_addr Internet Protocol Address IPv4 This validates that a string value contains a valid resolvable v4 IP Adress. Usage: ip4_addr Internet Protocol Address IPv6 This validates that a string value contains a valid resolvable v6 IP Adress. Usage: ip6_addr Unix domain socket end point Address This validates that a string value contains a valid Unix Adress. Usage: unix_addr Media Access Control Address MAC This validates that a string value contains a valid MAC Adress. Usage: mac Note: See Go's ParseMAC for accepted formats and types: http://golang.org/src/net/mac.go?s=866:918#L29 Alias Validators and Tags NOTE: When returning an error, the tag returned in "FieldError" will be the alias tag unless the dive tag is part of the alias. Everything after the dive tag is not reported as the alias tag. Also, the "ActualTag" in the before case will be the actual tag within the alias that failed. Here is a list of the current built in alias tags: "iscolor" alias is "hexcolor|rgb|rgba|hsl|hsla" (Usage: iscolor) Validator notes: regex a regex validator won't be added because commas and = signs can be part of a regex which conflict with the validation definitions. Although workarounds can be made, they take away from using pure regex's. Furthermore it's quick and dirty but the regex's become harder to maintain and are not reusable, so it's as much a programming philosiphy as anything. In place of this new validator functions should be created; a regex can be used within the validator function and even be precompiled for better efficiency within regexes.go. And the best reason, you can submit a pull request and we can keep on adding to the validation library of this package! Panics This package panics when bad input is provided, this is by design, bad code like that should not make it to production. type Test struct { TestField string `validate:"nonexistantfunction=1"` } t := &Test{ TestField: "Test" } validate.Struct(t) // this will panic */ package validator ================================================ FILE: vendor/gopkg.in/go-playground/validator.v8/regexes.go ================================================ package validator import "regexp" const ( alphaRegexString = "^[a-zA-Z]+$" alphaNumericRegexString = "^[a-zA-Z0-9]+$" numericRegexString = "^[-+]?[0-9]+(?:\\.[0-9]+)?$" numberRegexString = "^[0-9]+$" hexadecimalRegexString = "^[0-9a-fA-F]+$" hexcolorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$" rgbRegexString = "^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])|(?: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*\\)$" rgbaRegexString = "^rgba\\(\\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])|(?: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*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$" hslRegexString = "^hsl\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*\\)$" hslaRegexString = "^hsla\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$" emailRegexString = "^(?:(?:(?:(?:[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}])))\\.?$" base64RegexString = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$" iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$" iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$" uUID3RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$" uUID4RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" uUID5RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" uUIDRegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$" aSCIIRegexString = "^[\x00-\x7F]*$" printableASCIIRegexString = "^[\x20-\x7E]*$" multibyteRegexString = "[^\x00-\x7F]" dataURIRegexString = "^data:.+\\/(.+);base64$" latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$" longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$" sSNRegexString = `^\d{3}[- ]?\d{2}[- ]?\d{4}$` ) var ( alphaRegex = regexp.MustCompile(alphaRegexString) alphaNumericRegex = regexp.MustCompile(alphaNumericRegexString) numericRegex = regexp.MustCompile(numericRegexString) numberRegex = regexp.MustCompile(numberRegexString) hexadecimalRegex = regexp.MustCompile(hexadecimalRegexString) hexcolorRegex = regexp.MustCompile(hexcolorRegexString) rgbRegex = regexp.MustCompile(rgbRegexString) rgbaRegex = regexp.MustCompile(rgbaRegexString) hslRegex = regexp.MustCompile(hslRegexString) hslaRegex = regexp.MustCompile(hslaRegexString) emailRegex = regexp.MustCompile(emailRegexString) base64Regex = regexp.MustCompile(base64RegexString) iSBN10Regex = regexp.MustCompile(iSBN10RegexString) iSBN13Regex = regexp.MustCompile(iSBN13RegexString) uUID3Regex = regexp.MustCompile(uUID3RegexString) uUID4Regex = regexp.MustCompile(uUID4RegexString) uUID5Regex = regexp.MustCompile(uUID5RegexString) uUIDRegex = regexp.MustCompile(uUIDRegexString) aSCIIRegex = regexp.MustCompile(aSCIIRegexString) printableASCIIRegex = regexp.MustCompile(printableASCIIRegexString) multibyteRegex = regexp.MustCompile(multibyteRegexString) dataURIRegex = regexp.MustCompile(dataURIRegexString) latitudeRegex = regexp.MustCompile(latitudeRegexString) longitudeRegex = regexp.MustCompile(longitudeRegexString) sSNRegex = regexp.MustCompile(sSNRegexString) ) ================================================ FILE: vendor/gopkg.in/go-playground/validator.v8/util.go ================================================ package validator import ( "reflect" "strconv" "strings" ) const ( blank = "" namespaceSeparator = "." leftBracket = "[" rightBracket = "]" restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}" restrictedAliasErr = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" restrictedTagErr = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation" ) var ( restrictedTags = map[string]struct{}{ diveTag: {}, existsTag: {}, structOnlyTag: {}, omitempty: {}, skipValidationTag: {}, utf8HexComma: {}, utf8Pipe: {}, noStructLevelTag: {}, } ) // ExtractType gets the actual underlying type of field value. // It will dive into pointers, customTypes and return you the // underlying value and it's kind. // it is exposed for use within you Custom Functions func (v *Validate) ExtractType(current reflect.Value) (reflect.Value, reflect.Kind) { val, k, _ := v.extractTypeInternal(current, false) return val, k } // only exists to not break backward compatibility, needed to return the third param for a bug fix internally func (v *Validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) { switch current.Kind() { case reflect.Ptr: nullable = true if current.IsNil() { return current, reflect.Ptr, nullable } return v.extractTypeInternal(current.Elem(), nullable) case reflect.Interface: nullable = true if current.IsNil() { return current, reflect.Interface, nullable } return v.extractTypeInternal(current.Elem(), nullable) case reflect.Invalid: return current, reflect.Invalid, nullable default: if v.hasCustomFuncs { if fn, ok := v.customTypeFuncs[current.Type()]; ok { return v.extractTypeInternal(reflect.ValueOf(fn(current)), nullable) } } return current, current.Kind(), nullable } } // GetStructFieldOK traverses a struct to retrieve a specific field denoted by the provided namespace and // returns the field, field kind and whether is was successful in retrieving the field at all. // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field // could not be retrieved because it didn't exist. func (v *Validate) GetStructFieldOK(current reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) { current, kind := v.ExtractType(current) if kind == reflect.Invalid { return current, kind, false } if namespace == blank { return current, kind, true } switch kind { case reflect.Ptr, reflect.Interface: return current, kind, false case reflect.Struct: typ := current.Type() fld := namespace ns := namespace if typ != timeType && typ != timePtrType { idx := strings.Index(namespace, namespaceSeparator) if idx != -1 { fld = namespace[:idx] ns = namespace[idx+1:] } else { ns = blank } bracketIdx := strings.Index(fld, leftBracket) if bracketIdx != -1 { fld = fld[:bracketIdx] ns = namespace[bracketIdx:] } current = current.FieldByName(fld) return v.GetStructFieldOK(current, ns) } case reflect.Array, reflect.Slice: idx := strings.Index(namespace, leftBracket) idx2 := strings.Index(namespace, rightBracket) arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2]) if arrIdx >= current.Len() { return current, kind, false } startIdx := idx2 + 1 if startIdx < len(namespace) { if namespace[startIdx:startIdx+1] == namespaceSeparator { startIdx++ } } return v.GetStructFieldOK(current.Index(arrIdx), namespace[startIdx:]) case reflect.Map: idx := strings.Index(namespace, leftBracket) + 1 idx2 := strings.Index(namespace, rightBracket) endIdx := idx2 if endIdx+1 < len(namespace) { if namespace[endIdx+1:endIdx+2] == namespaceSeparator { endIdx++ } } key := namespace[idx:idx2] switch current.Type().Key().Kind() { case reflect.Int: i, _ := strconv.Atoi(key) return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:]) case reflect.Int8: i, _ := strconv.ParseInt(key, 10, 8) return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(int8(i))), namespace[endIdx+1:]) case reflect.Int16: i, _ := strconv.ParseInt(key, 10, 16) return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(int16(i))), namespace[endIdx+1:]) case reflect.Int32: i, _ := strconv.ParseInt(key, 10, 32) return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(int32(i))), namespace[endIdx+1:]) case reflect.Int64: i, _ := strconv.ParseInt(key, 10, 64) return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:]) case reflect.Uint: i, _ := strconv.ParseUint(key, 10, 0) return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint(i))), namespace[endIdx+1:]) case reflect.Uint8: i, _ := strconv.ParseUint(key, 10, 8) return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint8(i))), namespace[endIdx+1:]) case reflect.Uint16: i, _ := strconv.ParseUint(key, 10, 16) return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint16(i))), namespace[endIdx+1:]) case reflect.Uint32: i, _ := strconv.ParseUint(key, 10, 32) return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint32(i))), namespace[endIdx+1:]) case reflect.Uint64: i, _ := strconv.ParseUint(key, 10, 64) return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:]) case reflect.Float32: f, _ := strconv.ParseFloat(key, 32) return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(float32(f))), namespace[endIdx+1:]) case reflect.Float64: f, _ := strconv.ParseFloat(key, 64) return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(f)), namespace[endIdx+1:]) case reflect.Bool: b, _ := strconv.ParseBool(key) return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(b)), namespace[endIdx+1:]) // reflect.Type = string default: return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(key)), namespace[endIdx+1:]) } } // if got here there was more namespace, cannot go any deeper panic("Invalid field namespace") } // asInt returns the parameter as a int64 // or panics if it can't convert func asInt(param string) int64 { i, err := strconv.ParseInt(param, 0, 64) panicIf(err) return i } // asUint returns the parameter as a uint64 // or panics if it can't convert func asUint(param string) uint64 { i, err := strconv.ParseUint(param, 0, 64) panicIf(err) return i } // asFloat returns the parameter as a float64 // or panics if it can't convert func asFloat(param string) float64 { i, err := strconv.ParseFloat(param, 64) panicIf(err) return i } func panicIf(err error) { if err != nil { panic(err.Error()) } } ================================================ FILE: vendor/gopkg.in/go-playground/validator.v8/validator.go ================================================ /** * Package validator * * MISC: * - anonymous structs - they don't have names so expect the Struct name within StructErrors to be blank * */ package validator import ( "bytes" "errors" "fmt" "reflect" "strings" "sync" "time" ) const ( utf8HexComma = "0x2C" utf8Pipe = "0x7C" tagSeparator = "," orSeparator = "|" tagKeySeparator = "=" structOnlyTag = "structonly" noStructLevelTag = "nostructlevel" omitempty = "omitempty" skipValidationTag = "-" diveTag = "dive" existsTag = "exists" fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag" arrayIndexFieldName = "%s" + leftBracket + "%d" + rightBracket mapIndexFieldName = "%s" + leftBracket + "%v" + rightBracket invalidValidation = "Invalid validation tag on field %s" undefinedValidation = "Undefined validation function on field %s" validatorNotInitialized = "Validator instance not initialized" fieldNameRequired = "Field Name Required" tagRequired = "Tag Required" ) var ( timeType = reflect.TypeOf(time.Time{}) timePtrType = reflect.TypeOf(&time.Time{}) defaultCField = new(cField) ) // StructLevel contains all of the information and helper methods // for reporting errors during struct level validation type StructLevel struct { TopStruct reflect.Value CurrentStruct reflect.Value errPrefix string nsPrefix string errs ValidationErrors v *Validate } // ReportValidationErrors accepts the key relative to the top level struct and validatin errors. // Example: had a triple nested struct User, ContactInfo, Country and ran errs := validate.Struct(country) // from within a User struct level validation would call this method like so: // ReportValidationErrors("ContactInfo.", errs) // NOTE: relativeKey can contain both the Field Relative and Custom name relative paths // i.e. ReportValidationErrors("ContactInfo.|cInfo", errs) where cInfo represents say the JSON name of // the relative path; this will be split into 2 variables in the next valiator version. func (sl *StructLevel) ReportValidationErrors(relativeKey string, errs ValidationErrors) { for _, e := range errs { idx := strings.Index(relativeKey, "|") var rel string var cRel string if idx != -1 { rel = relativeKey[:idx] cRel = relativeKey[idx+1:] } else { rel = relativeKey } key := sl.errPrefix + rel + e.Field e.FieldNamespace = key e.NameNamespace = sl.nsPrefix + cRel + e.Name sl.errs[key] = e } } // ReportError reports an error just by passing the field and tag information // NOTE: tag can be an existing validation tag or just something you make up // and precess on the flip side it's up to you. func (sl *StructLevel) ReportError(field reflect.Value, fieldName string, customName string, tag string) { field, kind := sl.v.ExtractType(field) if fieldName == blank { panic(fieldNameRequired) } if customName == blank { customName = fieldName } if tag == blank { panic(tagRequired) } ns := sl.errPrefix + fieldName switch kind { case reflect.Invalid: sl.errs[ns] = &FieldError{ FieldNamespace: ns, NameNamespace: sl.nsPrefix + customName, Name: customName, Field: fieldName, Tag: tag, ActualTag: tag, Param: blank, Kind: kind, } default: sl.errs[ns] = &FieldError{ FieldNamespace: ns, NameNamespace: sl.nsPrefix + customName, Name: customName, Field: fieldName, Tag: tag, ActualTag: tag, Param: blank, Value: field.Interface(), Kind: kind, Type: field.Type(), } } } // Validate contains the validator settings passed in using the Config struct type Validate struct { tagName string fieldNameTag string validationFuncs map[string]Func structLevelFuncs map[reflect.Type]StructLevelFunc customTypeFuncs map[reflect.Type]CustomTypeFunc aliasValidators map[string]string hasCustomFuncs bool hasAliasValidators bool hasStructLevelFuncs bool tagCache *tagCache structCache *structCache errsPool *sync.Pool } func (v *Validate) initCheck() { if v == nil { panic(validatorNotInitialized) } } // Config contains the options that a Validator instance will use. // It is passed to the New() function type Config struct { TagName string FieldNameTag string } // CustomTypeFunc allows for overriding or adding custom field type handler functions // field = field value of the type to return a value to be validated // example Valuer from sql drive see https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29 type CustomTypeFunc func(field reflect.Value) interface{} // Func accepts all values needed for file and cross field validation // v = validator instance, needed but some built in functions for it's custom types // topStruct = top level struct when validating by struct otherwise nil // currentStruct = current level struct when validating by struct otherwise optional comparison value // field = field value for validation // param = parameter used in validation i.e. gt=0 param would be 0 type Func func(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldtype reflect.Type, fieldKind reflect.Kind, param string) bool // StructLevelFunc accepts all values needed for struct level validation type StructLevelFunc func(v *Validate, structLevel *StructLevel) // ValidationErrors is a type of map[string]*FieldError // it exists to allow for multiple errors to be passed from this library // and yet still subscribe to the error interface type ValidationErrors map[string]*FieldError // Error is intended for use in development + debugging and not intended to be a production error message. // It allows ValidationErrors to subscribe to the Error interface. // All information to create an error message specific to your application is contained within // the FieldError found within the ValidationErrors map func (ve ValidationErrors) Error() string { buff := bytes.NewBufferString(blank) for key, err := range ve { buff.WriteString(fmt.Sprintf(fieldErrMsg, key, err.Field, err.Tag)) buff.WriteString("\n") } return strings.TrimSpace(buff.String()) } // FieldError contains a single field's validation error along // with other properties that may be needed for error message creation type FieldError struct { FieldNamespace string NameNamespace string Field string Name string Tag string ActualTag string Kind reflect.Kind Type reflect.Type Param string Value interface{} } // New creates a new Validate instance for use. func New(config *Config) *Validate { tc := new(tagCache) tc.m.Store(make(map[string]*cTag)) sc := new(structCache) sc.m.Store(make(map[reflect.Type]*cStruct)) v := &Validate{ tagName: config.TagName, fieldNameTag: config.FieldNameTag, tagCache: tc, structCache: sc, errsPool: &sync.Pool{New: func() interface{} { return ValidationErrors{} }}} if len(v.aliasValidators) == 0 { // must copy alias validators for separate validations to be used in each validator instance v.aliasValidators = map[string]string{} for k, val := range bakedInAliasValidators { v.RegisterAliasValidation(k, val) } } if len(v.validationFuncs) == 0 { // must copy validators for separate validations to be used in each instance v.validationFuncs = map[string]Func{} for k, val := range bakedInValidators { v.RegisterValidation(k, val) } } return v } // RegisterStructValidation registers a StructLevelFunc against a number of types // NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...interface{}) { v.initCheck() if v.structLevelFuncs == nil { v.structLevelFuncs = map[reflect.Type]StructLevelFunc{} } for _, t := range types { v.structLevelFuncs[reflect.TypeOf(t)] = fn } v.hasStructLevelFuncs = true } // RegisterValidation adds a validation Func to a Validate's map of validators denoted by the key // NOTE: if the key already exists, the previous validation function will be replaced. // NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation func (v *Validate) RegisterValidation(key string, fn Func) error { v.initCheck() if key == blank { return errors.New("Function Key cannot be empty") } if fn == nil { return errors.New("Function cannot be empty") } _, ok := restrictedTags[key] if ok || strings.ContainsAny(key, restrictedTagChars) { panic(fmt.Sprintf(restrictedTagErr, key)) } v.validationFuncs[key] = fn return nil } // RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types // NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) { v.initCheck() if v.customTypeFuncs == nil { v.customTypeFuncs = map[reflect.Type]CustomTypeFunc{} } for _, t := range types { v.customTypeFuncs[reflect.TypeOf(t)] = fn } v.hasCustomFuncs = true } // RegisterAliasValidation registers a mapping of a single validationstag that // defines a common or complex set of validation(s) to simplify adding validation // to structs. NOTE: when returning an error the tag returned in FieldError will be // the alias tag unless the dive tag is part of the alias; everything after the // dive tag is not reported as the alias tag. Also the ActualTag in the before case // will be the actual tag within the alias that failed. // NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation func (v *Validate) RegisterAliasValidation(alias, tags string) { v.initCheck() _, ok := restrictedTags[alias] if ok || strings.ContainsAny(alias, restrictedTagChars) { panic(fmt.Sprintf(restrictedAliasErr, alias)) } v.aliasValidators[alias] = tags v.hasAliasValidators = true } // Field validates a single field using tag style validation and returns nil or ValidationErrors as type error. // You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors. // NOTE: it returns ValidationErrors instead of a single FieldError because this can also // validate Array, Slice and maps fields which may contain more than one error func (v *Validate) Field(field interface{}, tag string) error { v.initCheck() if len(tag) == 0 || tag == skipValidationTag { return nil } errs := v.errsPool.Get().(ValidationErrors) fieldVal := reflect.ValueOf(field) ctag, ok := v.tagCache.Get(tag) if !ok { v.tagCache.lock.Lock() defer v.tagCache.lock.Unlock() // could have been multiple trying to access, but once first is done this ensures tag // isn't parsed again. ctag, ok = v.tagCache.Get(tag) if !ok { ctag, _ = v.parseFieldTagsRecursive(tag, blank, blank, false) v.tagCache.Set(tag, ctag) } } v.traverseField(fieldVal, fieldVal, fieldVal, blank, blank, errs, false, false, nil, nil, defaultCField, ctag) if len(errs) == 0 { v.errsPool.Put(errs) return nil } return errs } // FieldWithValue validates a single field, against another fields value using tag style validation and returns nil or ValidationErrors. // You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors. // NOTE: it returns ValidationErrors instead of a single FieldError because this can also // validate Array, Slice and maps fields which may contain more than one error func (v *Validate) FieldWithValue(val interface{}, field interface{}, tag string) error { v.initCheck() if len(tag) == 0 || tag == skipValidationTag { return nil } errs := v.errsPool.Get().(ValidationErrors) topVal := reflect.ValueOf(val) ctag, ok := v.tagCache.Get(tag) if !ok { v.tagCache.lock.Lock() defer v.tagCache.lock.Unlock() // could have been multiple trying to access, but once first is done this ensures tag // isn't parsed again. ctag, ok = v.tagCache.Get(tag) if !ok { ctag, _ = v.parseFieldTagsRecursive(tag, blank, blank, false) v.tagCache.Set(tag, ctag) } } v.traverseField(topVal, topVal, reflect.ValueOf(field), blank, blank, errs, false, false, nil, nil, defaultCField, ctag) if len(errs) == 0 { v.errsPool.Put(errs) return nil } return errs } // StructPartial validates the fields passed in only, ignoring all others. // Fields may be provided in a namespaced fashion relative to the struct provided // i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name and returns nil or ValidationErrors as error // You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors. func (v *Validate) StructPartial(current interface{}, fields ...string) error { v.initCheck() sv, _ := v.ExtractType(reflect.ValueOf(current)) name := sv.Type().Name() m := map[string]struct{}{} if fields != nil { for _, k := range fields { flds := strings.Split(k, namespaceSeparator) if len(flds) > 0 { key := name + namespaceSeparator for _, s := range flds { idx := strings.Index(s, leftBracket) if idx != -1 { for idx != -1 { key += s[:idx] m[key] = struct{}{} idx2 := strings.Index(s, rightBracket) idx2++ key += s[idx:idx2] m[key] = struct{}{} s = s[idx2:] idx = strings.Index(s, leftBracket) } } else { key += s m[key] = struct{}{} } key += namespaceSeparator } } } } errs := v.errsPool.Get().(ValidationErrors) v.ensureValidStruct(sv, sv, sv, blank, blank, errs, true, len(m) != 0, false, m, false) if len(errs) == 0 { v.errsPool.Put(errs) return nil } return errs } // StructExcept validates all fields except the ones passed in. // Fields may be provided in a namespaced fashion relative to the struct provided // i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name and returns nil or ValidationErrors as error // You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors. func (v *Validate) StructExcept(current interface{}, fields ...string) error { v.initCheck() sv, _ := v.ExtractType(reflect.ValueOf(current)) name := sv.Type().Name() m := map[string]struct{}{} for _, key := range fields { m[name+namespaceSeparator+key] = struct{}{} } errs := v.errsPool.Get().(ValidationErrors) v.ensureValidStruct(sv, sv, sv, blank, blank, errs, true, len(m) != 0, true, m, false) if len(errs) == 0 { v.errsPool.Put(errs) return nil } return errs } // Struct validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified. // it returns nil or ValidationErrors as error. // You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors. func (v *Validate) Struct(current interface{}) error { v.initCheck() errs := v.errsPool.Get().(ValidationErrors) sv := reflect.ValueOf(current) v.ensureValidStruct(sv, sv, sv, blank, blank, errs, true, false, false, nil, false) if len(errs) == 0 { v.errsPool.Put(errs) return nil } return errs } func (v *Validate) ensureValidStruct(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, useStructName bool, partial bool, exclude bool, includeExclude map[string]struct{}, isStructOnly bool) { if current.Kind() == reflect.Ptr && !current.IsNil() { current = current.Elem() } if current.Kind() != reflect.Struct && current.Kind() != reflect.Interface { panic("value passed for validation is not a struct") } v.tranverseStruct(topStruct, currentStruct, current, errPrefix, nsPrefix, errs, useStructName, partial, exclude, includeExclude, nil, nil) } // tranverseStruct traverses a structs fields and then passes them to be validated by traverseField func (v *Validate) tranverseStruct(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, useStructName bool, partial bool, exclude bool, includeExclude map[string]struct{}, cs *cStruct, ct *cTag) { var ok bool first := len(nsPrefix) == 0 typ := current.Type() cs, ok = v.structCache.Get(typ) if !ok { cs = v.extractStructCache(current, typ.Name()) } if useStructName { errPrefix += cs.Name + namespaceSeparator if len(v.fieldNameTag) != 0 { nsPrefix += cs.Name + namespaceSeparator } } // structonly tag present don't tranverseFields // but must still check and run below struct level validation // if present if first || ct == nil || ct.typeof != typeStructOnly { for _, f := range cs.fields { if partial { _, ok = includeExclude[errPrefix+f.Name] if (ok && exclude) || (!ok && !exclude) { continue } } v.traverseField(topStruct, currentStruct, current.Field(f.Idx), errPrefix, nsPrefix, errs, partial, exclude, includeExclude, cs, f, f.cTags) } } // check if any struct level validations, after all field validations already checked. if cs.fn != nil { cs.fn(v, &StructLevel{v: v, TopStruct: topStruct, CurrentStruct: current, errPrefix: errPrefix, nsPrefix: nsPrefix, errs: errs}) } } // traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, partial bool, exclude bool, includeExclude map[string]struct{}, cs *cStruct, cf *cField, ct *cTag) { current, kind, nullable := v.extractTypeInternal(current, false) var typ reflect.Type switch kind { case reflect.Ptr, reflect.Interface, reflect.Invalid: if ct == nil { return } if ct.typeof == typeOmitEmpty { return } if ct.hasTag { ns := errPrefix + cf.Name if kind == reflect.Invalid { errs[ns] = &FieldError{ FieldNamespace: ns, NameNamespace: nsPrefix + cf.AltName, Name: cf.AltName, Field: cf.Name, Tag: ct.aliasTag, ActualTag: ct.tag, Param: ct.param, Kind: kind, } return } errs[ns] = &FieldError{ FieldNamespace: ns, NameNamespace: nsPrefix + cf.AltName, Name: cf.AltName, Field: cf.Name, Tag: ct.aliasTag, ActualTag: ct.tag, Param: ct.param, Value: current.Interface(), Kind: kind, Type: current.Type(), } return } case reflect.Struct: typ = current.Type() if typ != timeType { if ct != nil { ct = ct.next } if ct != nil && ct.typeof == typeNoStructLevel { return } v.tranverseStruct(topStruct, current, current, errPrefix+cf.Name+namespaceSeparator, nsPrefix+cf.AltName+namespaceSeparator, errs, false, partial, exclude, includeExclude, cs, ct) return } } if !ct.hasTag { return } typ = current.Type() OUTER: for { if ct == nil { return } switch ct.typeof { case typeExists: ct = ct.next continue case typeOmitEmpty: if !nullable && !HasValue(v, topStruct, currentStruct, current, typ, kind, blank) { return } ct = ct.next continue case typeDive: ct = ct.next // traverse slice or map here // or panic ;) switch kind { case reflect.Slice, reflect.Array: for i := 0; i < current.Len(); i++ { v.traverseField(topStruct, currentStruct, current.Index(i), errPrefix, nsPrefix, errs, partial, exclude, includeExclude, cs, &cField{Name: fmt.Sprintf(arrayIndexFieldName, cf.Name, i), AltName: fmt.Sprintf(arrayIndexFieldName, cf.AltName, i)}, ct) } case reflect.Map: for _, key := range current.MapKeys() { v.traverseField(topStruct, currentStruct, current.MapIndex(key), errPrefix, nsPrefix, errs, partial, exclude, includeExclude, cs, &cField{Name: fmt.Sprintf(mapIndexFieldName, cf.Name, key.Interface()), AltName: fmt.Sprintf(mapIndexFieldName, cf.AltName, key.Interface())}, ct) } default: // throw error, if not a slice or map then should not have gotten here // bad dive tag panic("dive error! can't dive on a non slice or map") } return case typeOr: errTag := blank for { if ct.fn(v, topStruct, currentStruct, current, typ, kind, ct.param) { // drain rest of the 'or' values, then continue or leave for { ct = ct.next if ct == nil { return } if ct.typeof != typeOr { continue OUTER } } } errTag += orSeparator + ct.tag if ct.next == nil { // if we get here, no valid 'or' value and no more tags ns := errPrefix + cf.Name if ct.hasAlias { errs[ns] = &FieldError{ FieldNamespace: ns, NameNamespace: nsPrefix + cf.AltName, Name: cf.AltName, Field: cf.Name, Tag: ct.aliasTag, ActualTag: ct.actualAliasTag, Value: current.Interface(), Type: typ, Kind: kind, } } else { errs[errPrefix+cf.Name] = &FieldError{ FieldNamespace: ns, NameNamespace: nsPrefix + cf.AltName, Name: cf.AltName, Field: cf.Name, Tag: errTag[1:], ActualTag: errTag[1:], Value: current.Interface(), Type: typ, Kind: kind, } } return } ct = ct.next } default: if !ct.fn(v, topStruct, currentStruct, current, typ, kind, ct.param) { ns := errPrefix + cf.Name errs[ns] = &FieldError{ FieldNamespace: ns, NameNamespace: nsPrefix + cf.AltName, Name: cf.AltName, Field: cf.Name, Tag: ct.aliasTag, ActualTag: ct.tag, Value: current.Interface(), Param: ct.param, Type: typ, Kind: kind, } return } ct = ct.next } } } ================================================ FILE: vendor/gopkg.in/yaml.v2/.travis.yml ================================================ language: go go: - 1.4 - 1.5 - 1.6 - 1.7 - 1.8 - 1.9 - tip go_import_path: gopkg.in/yaml.v2 ================================================ FILE: vendor/gopkg.in/yaml.v2/LICENSE ================================================ 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. ================================================ FILE: vendor/gopkg.in/yaml.v2/LICENSE.libyaml ================================================ The following files were ported to Go from C files of libyaml, and thus are still covered by their original copyright and license: apic.go emitterc.go parserc.go readerc.go scannerc.go writerc.go yamlh.go yamlprivateh.go Copyright (c) 2006 Kirill Simonov 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. ================================================ FILE: vendor/gopkg.in/yaml.v2/NOTICE ================================================ Copyright 2011-2016 Canonical Ltd. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/gopkg.in/yaml.v2/README.md ================================================ # YAML support for the Go language Introduction ------------ The yaml package enables Go programs to comfortably encode and decode YAML values. It was developed within [Canonical](https://www.canonical.com) as part of the [juju](https://juju.ubuntu.com) project, and is based on a pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) C library to parse and generate YAML data quickly and reliably. Compatibility ------------- The yaml package supports most of YAML 1.1 and 1.2, including support for anchors, tags, map merging, etc. Multi-document unmarshalling is not yet implemented, and base-60 floats from YAML 1.1 are purposefully not supported since they're a poor design and are gone in YAML 1.2. Installation and usage ---------------------- The import path for the package is *gopkg.in/yaml.v2*. To install it, run: go get gopkg.in/yaml.v2 API documentation ----------------- If opened in a browser, the import path itself leads to the API documentation: * [https://gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) API stability ------------- The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in). License ------- The yaml package is licensed under the Apache License 2.0. Please see the LICENSE file for details. Example ------- ```Go package main import ( "fmt" "log" "gopkg.in/yaml.v2" ) var data = ` a: Easy! b: c: 2 d: [3, 4] ` // Note: struct fields must be public in order for unmarshal to // correctly populate the data. type T struct { A string B struct { RenamedC int `yaml:"c"` D []int `yaml:",flow"` } } func main() { t := T{} err := yaml.Unmarshal([]byte(data), &t) if err != nil { log.Fatalf("error: %v", err) } fmt.Printf("--- t:\n%v\n\n", t) d, err := yaml.Marshal(&t) if err != nil { log.Fatalf("error: %v", err) } fmt.Printf("--- t dump:\n%s\n\n", string(d)) m := make(map[interface{}]interface{}) err = yaml.Unmarshal([]byte(data), &m) if err != nil { log.Fatalf("error: %v", err) } fmt.Printf("--- m:\n%v\n\n", m) d, err = yaml.Marshal(&m) if err != nil { log.Fatalf("error: %v", err) } fmt.Printf("--- m dump:\n%s\n\n", string(d)) } ``` This example will generate the following output: ``` --- t: {Easy! {2 [3 4]}} --- t dump: a: Easy! b: c: 2 d: [3, 4] --- m: map[a:Easy! b:map[c:2 d:[3 4]]] --- m dump: a: Easy! b: c: 2 d: - 3 - 4 ``` ================================================ FILE: vendor/gopkg.in/yaml.v2/apic.go ================================================ package yaml import ( "io" ) func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) { //fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens)) // Check if we can move the queue at the beginning of the buffer. if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) { if parser.tokens_head != len(parser.tokens) { copy(parser.tokens, parser.tokens[parser.tokens_head:]) } parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head] parser.tokens_head = 0 } parser.tokens = append(parser.tokens, *token) if pos < 0 { return } copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:]) parser.tokens[parser.tokens_head+pos] = *token } // Create a new parser object. func yaml_parser_initialize(parser *yaml_parser_t) bool { *parser = yaml_parser_t{ raw_buffer: make([]byte, 0, input_raw_buffer_size), buffer: make([]byte, 0, input_buffer_size), } return true } // Destroy a parser object. func yaml_parser_delete(parser *yaml_parser_t) { *parser = yaml_parser_t{} } // String read handler. func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { if parser.input_pos == len(parser.input) { return 0, io.EOF } n = copy(buffer, parser.input[parser.input_pos:]) parser.input_pos += n return n, nil } // Reader read handler. func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { return parser.input_reader.Read(buffer) } // Set a string input. func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) { if parser.read_handler != nil { panic("must set the input source only once") } parser.read_handler = yaml_string_read_handler parser.input = input parser.input_pos = 0 } // Set a file input. func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) { if parser.read_handler != nil { panic("must set the input source only once") } parser.read_handler = yaml_reader_read_handler parser.input_reader = r } // Set the source encoding. func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) { if parser.encoding != yaml_ANY_ENCODING { panic("must set the encoding only once") } parser.encoding = encoding } // Create a new emitter object. func yaml_emitter_initialize(emitter *yaml_emitter_t) { *emitter = yaml_emitter_t{ buffer: make([]byte, output_buffer_size), raw_buffer: make([]byte, 0, output_raw_buffer_size), states: make([]yaml_emitter_state_t, 0, initial_stack_size), events: make([]yaml_event_t, 0, initial_queue_size), } } // Destroy an emitter object. func yaml_emitter_delete(emitter *yaml_emitter_t) { *emitter = yaml_emitter_t{} } // String write handler. func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error { *emitter.output_buffer = append(*emitter.output_buffer, buffer...) return nil } // yaml_writer_write_handler uses emitter.output_writer to write the // emitted text. func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error { _, err := emitter.output_writer.Write(buffer) return err } // Set a string output. func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) { if emitter.write_handler != nil { panic("must set the output target only once") } emitter.write_handler = yaml_string_write_handler emitter.output_buffer = output_buffer } // Set a file output. func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) { if emitter.write_handler != nil { panic("must set the output target only once") } emitter.write_handler = yaml_writer_write_handler emitter.output_writer = w } // Set the output encoding. func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) { if emitter.encoding != yaml_ANY_ENCODING { panic("must set the output encoding only once") } emitter.encoding = encoding } // Set the canonical output style. func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) { emitter.canonical = canonical } //// Set the indentation increment. func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) { if indent < 2 || indent > 9 { indent = 2 } emitter.best_indent = indent } // Set the preferred line width. func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) { if width < 0 { width = -1 } emitter.best_width = width } // Set if unescaped non-ASCII characters are allowed. func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) { emitter.unicode = unicode } // Set the preferred line break character. func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) { emitter.line_break = line_break } ///* // * Destroy a token object. // */ // //YAML_DECLARE(void) //yaml_token_delete(yaml_token_t *token) //{ // assert(token); // Non-NULL token object expected. // // switch (token.type) // { // case YAML_TAG_DIRECTIVE_TOKEN: // yaml_free(token.data.tag_directive.handle); // yaml_free(token.data.tag_directive.prefix); // break; // // case YAML_ALIAS_TOKEN: // yaml_free(token.data.alias.value); // break; // // case YAML_ANCHOR_TOKEN: // yaml_free(token.data.anchor.value); // break; // // case YAML_TAG_TOKEN: // yaml_free(token.data.tag.handle); // yaml_free(token.data.tag.suffix); // break; // // case YAML_SCALAR_TOKEN: // yaml_free(token.data.scalar.value); // break; // // default: // break; // } // // memset(token, 0, sizeof(yaml_token_t)); //} // ///* // * Check if a string is a valid UTF-8 sequence. // * // * Check 'reader.c' for more details on UTF-8 encoding. // */ // //static int //yaml_check_utf8(yaml_char_t *start, size_t length) //{ // yaml_char_t *end = start+length; // yaml_char_t *pointer = start; // // while (pointer < end) { // unsigned char octet; // unsigned int width; // unsigned int value; // size_t k; // // octet = pointer[0]; // width = (octet & 0x80) == 0x00 ? 1 : // (octet & 0xE0) == 0xC0 ? 2 : // (octet & 0xF0) == 0xE0 ? 3 : // (octet & 0xF8) == 0xF0 ? 4 : 0; // value = (octet & 0x80) == 0x00 ? octet & 0x7F : // (octet & 0xE0) == 0xC0 ? octet & 0x1F : // (octet & 0xF0) == 0xE0 ? octet & 0x0F : // (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; // if (!width) return 0; // if (pointer+width > end) return 0; // for (k = 1; k < width; k ++) { // octet = pointer[k]; // if ((octet & 0xC0) != 0x80) return 0; // value = (value << 6) + (octet & 0x3F); // } // if (!((width == 1) || // (width == 2 && value >= 0x80) || // (width == 3 && value >= 0x800) || // (width == 4 && value >= 0x10000))) return 0; // // pointer += width; // } // // return 1; //} // // Create STREAM-START. func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) { *event = yaml_event_t{ typ: yaml_STREAM_START_EVENT, encoding: encoding, } } // Create STREAM-END. func yaml_stream_end_event_initialize(event *yaml_event_t) { *event = yaml_event_t{ typ: yaml_STREAM_END_EVENT, } } // Create DOCUMENT-START. func yaml_document_start_event_initialize( event *yaml_event_t, version_directive *yaml_version_directive_t, tag_directives []yaml_tag_directive_t, implicit bool, ) { *event = yaml_event_t{ typ: yaml_DOCUMENT_START_EVENT, version_directive: version_directive, tag_directives: tag_directives, implicit: implicit, } } // Create DOCUMENT-END. func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) { *event = yaml_event_t{ typ: yaml_DOCUMENT_END_EVENT, implicit: implicit, } } ///* // * Create ALIAS. // */ // //YAML_DECLARE(int) //yaml_alias_event_initialize(event *yaml_event_t, anchor *yaml_char_t) //{ // mark yaml_mark_t = { 0, 0, 0 } // anchor_copy *yaml_char_t = NULL // // assert(event) // Non-NULL event object is expected. // assert(anchor) // Non-NULL anchor is expected. // // if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0 // // anchor_copy = yaml_strdup(anchor) // if (!anchor_copy) // return 0 // // ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark) // // return 1 //} // Create SCALAR. func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool { *event = yaml_event_t{ typ: yaml_SCALAR_EVENT, anchor: anchor, tag: tag, value: value, implicit: plain_implicit, quoted_implicit: quoted_implicit, style: yaml_style_t(style), } return true } // Create SEQUENCE-START. func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool { *event = yaml_event_t{ typ: yaml_SEQUENCE_START_EVENT, anchor: anchor, tag: tag, implicit: implicit, style: yaml_style_t(style), } return true } // Create SEQUENCE-END. func yaml_sequence_end_event_initialize(event *yaml_event_t) bool { *event = yaml_event_t{ typ: yaml_SEQUENCE_END_EVENT, } return true } // Create MAPPING-START. func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) { *event = yaml_event_t{ typ: yaml_MAPPING_START_EVENT, anchor: anchor, tag: tag, implicit: implicit, style: yaml_style_t(style), } } // Create MAPPING-END. func yaml_mapping_end_event_initialize(event *yaml_event_t) { *event = yaml_event_t{ typ: yaml_MAPPING_END_EVENT, } } // Destroy an event object. func yaml_event_delete(event *yaml_event_t) { *event = yaml_event_t{} } ///* // * Create a document object. // */ // //YAML_DECLARE(int) //yaml_document_initialize(document *yaml_document_t, // version_directive *yaml_version_directive_t, // tag_directives_start *yaml_tag_directive_t, // tag_directives_end *yaml_tag_directive_t, // start_implicit int, end_implicit int) //{ // struct { // error yaml_error_type_t // } context // struct { // start *yaml_node_t // end *yaml_node_t // top *yaml_node_t // } nodes = { NULL, NULL, NULL } // version_directive_copy *yaml_version_directive_t = NULL // struct { // start *yaml_tag_directive_t // end *yaml_tag_directive_t // top *yaml_tag_directive_t // } tag_directives_copy = { NULL, NULL, NULL } // value yaml_tag_directive_t = { NULL, NULL } // mark yaml_mark_t = { 0, 0, 0 } // // assert(document) // Non-NULL document object is expected. // assert((tag_directives_start && tag_directives_end) || // (tag_directives_start == tag_directives_end)) // // Valid tag directives are expected. // // if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error // // if (version_directive) { // version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)) // if (!version_directive_copy) goto error // version_directive_copy.major = version_directive.major // version_directive_copy.minor = version_directive.minor // } // // if (tag_directives_start != tag_directives_end) { // tag_directive *yaml_tag_directive_t // if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE)) // goto error // for (tag_directive = tag_directives_start // tag_directive != tag_directives_end; tag_directive ++) { // assert(tag_directive.handle) // assert(tag_directive.prefix) // if (!yaml_check_utf8(tag_directive.handle, // strlen((char *)tag_directive.handle))) // goto error // if (!yaml_check_utf8(tag_directive.prefix, // strlen((char *)tag_directive.prefix))) // goto error // value.handle = yaml_strdup(tag_directive.handle) // value.prefix = yaml_strdup(tag_directive.prefix) // if (!value.handle || !value.prefix) goto error // if (!PUSH(&context, tag_directives_copy, value)) // goto error // value.handle = NULL // value.prefix = NULL // } // } // // DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy, // tag_directives_copy.start, tag_directives_copy.top, // start_implicit, end_implicit, mark, mark) // // return 1 // //error: // STACK_DEL(&context, nodes) // yaml_free(version_directive_copy) // while (!STACK_EMPTY(&context, tag_directives_copy)) { // value yaml_tag_directive_t = POP(&context, tag_directives_copy) // yaml_free(value.handle) // yaml_free(value.prefix) // } // STACK_DEL(&context, tag_directives_copy) // yaml_free(value.handle) // yaml_free(value.prefix) // // return 0 //} // ///* // * Destroy a document object. // */ // //YAML_DECLARE(void) //yaml_document_delete(document *yaml_document_t) //{ // struct { // error yaml_error_type_t // } context // tag_directive *yaml_tag_directive_t // // context.error = YAML_NO_ERROR // Eliminate a compiler warning. // // assert(document) // Non-NULL document object is expected. // // while (!STACK_EMPTY(&context, document.nodes)) { // node yaml_node_t = POP(&context, document.nodes) // yaml_free(node.tag) // switch (node.type) { // case YAML_SCALAR_NODE: // yaml_free(node.data.scalar.value) // break // case YAML_SEQUENCE_NODE: // STACK_DEL(&context, node.data.sequence.items) // break // case YAML_MAPPING_NODE: // STACK_DEL(&context, node.data.mapping.pairs) // break // default: // assert(0) // Should not happen. // } // } // STACK_DEL(&context, document.nodes) // // yaml_free(document.version_directive) // for (tag_directive = document.tag_directives.start // tag_directive != document.tag_directives.end // tag_directive++) { // yaml_free(tag_directive.handle) // yaml_free(tag_directive.prefix) // } // yaml_free(document.tag_directives.start) // // memset(document, 0, sizeof(yaml_document_t)) //} // ///** // * Get a document node. // */ // //YAML_DECLARE(yaml_node_t *) //yaml_document_get_node(document *yaml_document_t, index int) //{ // assert(document) // Non-NULL document object is expected. // // if (index > 0 && document.nodes.start + index <= document.nodes.top) { // return document.nodes.start + index - 1 // } // return NULL //} // ///** // * Get the root object. // */ // //YAML_DECLARE(yaml_node_t *) //yaml_document_get_root_node(document *yaml_document_t) //{ // assert(document) // Non-NULL document object is expected. // // if (document.nodes.top != document.nodes.start) { // return document.nodes.start // } // return NULL //} // ///* // * Add a scalar node to a document. // */ // //YAML_DECLARE(int) //yaml_document_add_scalar(document *yaml_document_t, // tag *yaml_char_t, value *yaml_char_t, length int, // style yaml_scalar_style_t) //{ // struct { // error yaml_error_type_t // } context // mark yaml_mark_t = { 0, 0, 0 } // tag_copy *yaml_char_t = NULL // value_copy *yaml_char_t = NULL // node yaml_node_t // // assert(document) // Non-NULL document object is expected. // assert(value) // Non-NULL value is expected. // // if (!tag) { // tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG // } // // if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error // tag_copy = yaml_strdup(tag) // if (!tag_copy) goto error // // if (length < 0) { // length = strlen((char *)value) // } // // if (!yaml_check_utf8(value, length)) goto error // value_copy = yaml_malloc(length+1) // if (!value_copy) goto error // memcpy(value_copy, value, length) // value_copy[length] = '\0' // // SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark) // if (!PUSH(&context, document.nodes, node)) goto error // // return document.nodes.top - document.nodes.start // //error: // yaml_free(tag_copy) // yaml_free(value_copy) // // return 0 //} // ///* // * Add a sequence node to a document. // */ // //YAML_DECLARE(int) //yaml_document_add_sequence(document *yaml_document_t, // tag *yaml_char_t, style yaml_sequence_style_t) //{ // struct { // error yaml_error_type_t // } context // mark yaml_mark_t = { 0, 0, 0 } // tag_copy *yaml_char_t = NULL // struct { // start *yaml_node_item_t // end *yaml_node_item_t // top *yaml_node_item_t // } items = { NULL, NULL, NULL } // node yaml_node_t // // assert(document) // Non-NULL document object is expected. // // if (!tag) { // tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG // } // // if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error // tag_copy = yaml_strdup(tag) // if (!tag_copy) goto error // // if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error // // SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end, // style, mark, mark) // if (!PUSH(&context, document.nodes, node)) goto error // // return document.nodes.top - document.nodes.start // //error: // STACK_DEL(&context, items) // yaml_free(tag_copy) // // return 0 //} // ///* // * Add a mapping node to a document. // */ // //YAML_DECLARE(int) //yaml_document_add_mapping(document *yaml_document_t, // tag *yaml_char_t, style yaml_mapping_style_t) //{ // struct { // error yaml_error_type_t // } context // mark yaml_mark_t = { 0, 0, 0 } // tag_copy *yaml_char_t = NULL // struct { // start *yaml_node_pair_t // end *yaml_node_pair_t // top *yaml_node_pair_t // } pairs = { NULL, NULL, NULL } // node yaml_node_t // // assert(document) // Non-NULL document object is expected. // // if (!tag) { // tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG // } // // if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error // tag_copy = yaml_strdup(tag) // if (!tag_copy) goto error // // if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error // // MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end, // style, mark, mark) // if (!PUSH(&context, document.nodes, node)) goto error // // return document.nodes.top - document.nodes.start // //error: // STACK_DEL(&context, pairs) // yaml_free(tag_copy) // // return 0 //} // ///* // * Append an item to a sequence node. // */ // //YAML_DECLARE(int) //yaml_document_append_sequence_item(document *yaml_document_t, // sequence int, item int) //{ // struct { // error yaml_error_type_t // } context // // assert(document) // Non-NULL document is required. // assert(sequence > 0 // && document.nodes.start + sequence <= document.nodes.top) // // Valid sequence id is required. // assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE) // // A sequence node is required. // assert(item > 0 && document.nodes.start + item <= document.nodes.top) // // Valid item id is required. // // if (!PUSH(&context, // document.nodes.start[sequence-1].data.sequence.items, item)) // return 0 // // return 1 //} // ///* // * Append a pair of a key and a value to a mapping node. // */ // //YAML_DECLARE(int) //yaml_document_append_mapping_pair(document *yaml_document_t, // mapping int, key int, value int) //{ // struct { // error yaml_error_type_t // } context // // pair yaml_node_pair_t // // assert(document) // Non-NULL document is required. // assert(mapping > 0 // && document.nodes.start + mapping <= document.nodes.top) // // Valid mapping id is required. // assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE) // // A mapping node is required. // assert(key > 0 && document.nodes.start + key <= document.nodes.top) // // Valid key id is required. // assert(value > 0 && document.nodes.start + value <= document.nodes.top) // // Valid value id is required. // // pair.key = key // pair.value = value // // if (!PUSH(&context, // document.nodes.start[mapping-1].data.mapping.pairs, pair)) // return 0 // // return 1 //} // // ================================================ FILE: vendor/gopkg.in/yaml.v2/decode.go ================================================ package yaml import ( "encoding" "encoding/base64" "fmt" "io" "math" "reflect" "strconv" "time" ) const ( documentNode = 1 << iota mappingNode sequenceNode scalarNode aliasNode ) type node struct { kind int line, column int tag string // For an alias node, alias holds the resolved alias. alias *node value string implicit bool children []*node anchors map[string]*node } // ---------------------------------------------------------------------------- // Parser, produces a node tree out of a libyaml event stream. type parser struct { parser yaml_parser_t event yaml_event_t doc *node doneInit bool } func newParser(b []byte) *parser { p := parser{} if !yaml_parser_initialize(&p.parser) { panic("failed to initialize YAML emitter") } if len(b) == 0 { b = []byte{'\n'} } yaml_parser_set_input_string(&p.parser, b) return &p } func newParserFromReader(r io.Reader) *parser { p := parser{} if !yaml_parser_initialize(&p.parser) { panic("failed to initialize YAML emitter") } yaml_parser_set_input_reader(&p.parser, r) return &p } func (p *parser) init() { if p.doneInit { return } p.expect(yaml_STREAM_START_EVENT) p.doneInit = true } func (p *parser) destroy() { if p.event.typ != yaml_NO_EVENT { yaml_event_delete(&p.event) } yaml_parser_delete(&p.parser) } // expect consumes an event from the event stream and // checks that it's of the expected type. func (p *parser) expect(e yaml_event_type_t) { if p.event.typ == yaml_NO_EVENT { if !yaml_parser_parse(&p.parser, &p.event) { p.fail() } } if p.event.typ == yaml_STREAM_END_EVENT { failf("attempted to go past the end of stream; corrupted value?") } if p.event.typ != e { p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ) p.fail() } yaml_event_delete(&p.event) p.event.typ = yaml_NO_EVENT } // peek peeks at the next event in the event stream, // puts the results into p.event and returns the event type. func (p *parser) peek() yaml_event_type_t { if p.event.typ != yaml_NO_EVENT { return p.event.typ } if !yaml_parser_parse(&p.parser, &p.event) { p.fail() } return p.event.typ } func (p *parser) fail() { var where string var line int if p.parser.problem_mark.line != 0 { line = p.parser.problem_mark.line // Scanner errors don't iterate line before returning error if p.parser.error == yaml_SCANNER_ERROR { line++ } } else if p.parser.context_mark.line != 0 { line = p.parser.context_mark.line } if line != 0 { where = "line " + strconv.Itoa(line) + ": " } var msg string if len(p.parser.problem) > 0 { msg = p.parser.problem } else { msg = "unknown problem parsing YAML content" } failf("%s%s", where, msg) } func (p *parser) anchor(n *node, anchor []byte) { if anchor != nil { p.doc.anchors[string(anchor)] = n } } func (p *parser) parse() *node { p.init() switch p.peek() { case yaml_SCALAR_EVENT: return p.scalar() case yaml_ALIAS_EVENT: return p.alias() case yaml_MAPPING_START_EVENT: return p.mapping() case yaml_SEQUENCE_START_EVENT: return p.sequence() case yaml_DOCUMENT_START_EVENT: return p.document() case yaml_STREAM_END_EVENT: // Happens when attempting to decode an empty buffer. return nil default: panic("attempted to parse unknown event: " + p.event.typ.String()) } } func (p *parser) node(kind int) *node { return &node{ kind: kind, line: p.event.start_mark.line, column: p.event.start_mark.column, } } func (p *parser) document() *node { n := p.node(documentNode) n.anchors = make(map[string]*node) p.doc = n p.expect(yaml_DOCUMENT_START_EVENT) n.children = append(n.children, p.parse()) p.expect(yaml_DOCUMENT_END_EVENT) return n } func (p *parser) alias() *node { n := p.node(aliasNode) n.value = string(p.event.anchor) n.alias = p.doc.anchors[n.value] if n.alias == nil { failf("unknown anchor '%s' referenced", n.value) } p.expect(yaml_ALIAS_EVENT) return n } func (p *parser) scalar() *node { n := p.node(scalarNode) n.value = string(p.event.value) n.tag = string(p.event.tag) n.implicit = p.event.implicit p.anchor(n, p.event.anchor) p.expect(yaml_SCALAR_EVENT) return n } func (p *parser) sequence() *node { n := p.node(sequenceNode) p.anchor(n, p.event.anchor) p.expect(yaml_SEQUENCE_START_EVENT) for p.peek() != yaml_SEQUENCE_END_EVENT { n.children = append(n.children, p.parse()) } p.expect(yaml_SEQUENCE_END_EVENT) return n } func (p *parser) mapping() *node { n := p.node(mappingNode) p.anchor(n, p.event.anchor) p.expect(yaml_MAPPING_START_EVENT) for p.peek() != yaml_MAPPING_END_EVENT { n.children = append(n.children, p.parse(), p.parse()) } p.expect(yaml_MAPPING_END_EVENT) return n } // ---------------------------------------------------------------------------- // Decoder, unmarshals a node into a provided value. type decoder struct { doc *node aliases map[*node]bool mapType reflect.Type terrors []string strict bool } var ( mapItemType = reflect.TypeOf(MapItem{}) durationType = reflect.TypeOf(time.Duration(0)) defaultMapType = reflect.TypeOf(map[interface{}]interface{}{}) ifaceType = defaultMapType.Elem() timeType = reflect.TypeOf(time.Time{}) ptrTimeType = reflect.TypeOf(&time.Time{}) ) func newDecoder(strict bool) *decoder { d := &decoder{mapType: defaultMapType, strict: strict} d.aliases = make(map[*node]bool) return d } func (d *decoder) terror(n *node, tag string, out reflect.Value) { if n.tag != "" { tag = n.tag } value := n.value if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG { if len(value) > 10 { value = " `" + value[:7] + "...`" } else { value = " `" + value + "`" } } d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type())) } func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) { terrlen := len(d.terrors) err := u.UnmarshalYAML(func(v interface{}) (err error) { defer handleErr(&err) d.unmarshal(n, reflect.ValueOf(v)) if len(d.terrors) > terrlen { issues := d.terrors[terrlen:] d.terrors = d.terrors[:terrlen] return &TypeError{issues} } return nil }) if e, ok := err.(*TypeError); ok { d.terrors = append(d.terrors, e.Errors...) return false } if err != nil { fail(err) } return true } // d.prepare initializes and dereferences pointers and calls UnmarshalYAML // if a value is found to implement it. // It returns the initialized and dereferenced out value, whether // unmarshalling was already done by UnmarshalYAML, and if so whether // its types unmarshalled appropriately. // // If n holds a null value, prepare returns before doing anything. func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) { if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) { return out, false, false } again := true for again { again = false if out.Kind() == reflect.Ptr { if out.IsNil() { out.Set(reflect.New(out.Type().Elem())) } out = out.Elem() again = true } if out.CanAddr() { if u, ok := out.Addr().Interface().(Unmarshaler); ok { good = d.callUnmarshaler(n, u) return out, true, good } } } return out, false, false } func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) { switch n.kind { case documentNode: return d.document(n, out) case aliasNode: return d.alias(n, out) } out, unmarshaled, good := d.prepare(n, out) if unmarshaled { return good } switch n.kind { case scalarNode: good = d.scalar(n, out) case mappingNode: good = d.mapping(n, out) case sequenceNode: good = d.sequence(n, out) default: panic("internal error: unknown node kind: " + strconv.Itoa(n.kind)) } return good } func (d *decoder) document(n *node, out reflect.Value) (good bool) { if len(n.children) == 1 { d.doc = n d.unmarshal(n.children[0], out) return true } return false } func (d *decoder) alias(n *node, out reflect.Value) (good bool) { if d.aliases[n] { // TODO this could actually be allowed in some circumstances. failf("anchor '%s' value contains itself", n.value) } d.aliases[n] = true good = d.unmarshal(n.alias, out) delete(d.aliases, n) return good } var zeroValue reflect.Value func resetMap(out reflect.Value) { for _, k := range out.MapKeys() { out.SetMapIndex(k, zeroValue) } } func (d *decoder) scalar(n *node, out reflect.Value) bool { var tag string var resolved interface{} if n.tag == "" && !n.implicit { tag = yaml_STR_TAG resolved = n.value } else { tag, resolved = resolve(n.tag, n.value) if tag == yaml_BINARY_TAG { data, err := base64.StdEncoding.DecodeString(resolved.(string)) if err != nil { failf("!!binary value contains invalid base64 data") } resolved = string(data) } } if resolved == nil { if out.Kind() == reflect.Map && !out.CanAddr() { resetMap(out) } else { out.Set(reflect.Zero(out.Type())) } return true } if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { // We've resolved to exactly the type we want, so use that. out.Set(resolvedv) return true } // Perhaps we can use the value as a TextUnmarshaler to // set its value. if out.CanAddr() { u, ok := out.Addr().Interface().(encoding.TextUnmarshaler) if ok { var text []byte if tag == yaml_BINARY_TAG { text = []byte(resolved.(string)) } else { // We let any value be unmarshaled into TextUnmarshaler. // That might be more lax than we'd like, but the // TextUnmarshaler itself should bowl out any dubious values. text = []byte(n.value) } err := u.UnmarshalText(text) if err != nil { fail(err) } return true } } switch out.Kind() { case reflect.String: if tag == yaml_BINARY_TAG { out.SetString(resolved.(string)) return true } if resolved != nil { out.SetString(n.value) return true } case reflect.Interface: if resolved == nil { out.Set(reflect.Zero(out.Type())) } else if tag == yaml_TIMESTAMP_TAG { // It looks like a timestamp but for backward compatibility // reasons we set it as a string, so that code that unmarshals // timestamp-like values into interface{} will continue to // see a string and not a time.Time. // TODO(v3) Drop this. out.Set(reflect.ValueOf(n.value)) } else { out.Set(reflect.ValueOf(resolved)) } return true case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: switch resolved := resolved.(type) { case int: if !out.OverflowInt(int64(resolved)) { out.SetInt(int64(resolved)) return true } case int64: if !out.OverflowInt(resolved) { out.SetInt(resolved) return true } case uint64: if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { out.SetInt(int64(resolved)) return true } case float64: if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { out.SetInt(int64(resolved)) return true } case string: if out.Type() == durationType { d, err := time.ParseDuration(resolved) if err == nil { out.SetInt(int64(d)) return true } } } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: switch resolved := resolved.(type) { case int: if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { out.SetUint(uint64(resolved)) return true } case int64: if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { out.SetUint(uint64(resolved)) return true } case uint64: if !out.OverflowUint(uint64(resolved)) { out.SetUint(uint64(resolved)) return true } case float64: if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) { out.SetUint(uint64(resolved)) return true } } case reflect.Bool: switch resolved := resolved.(type) { case bool: out.SetBool(resolved) return true } case reflect.Float32, reflect.Float64: switch resolved := resolved.(type) { case int: out.SetFloat(float64(resolved)) return true case int64: out.SetFloat(float64(resolved)) return true case uint64: out.SetFloat(float64(resolved)) return true case float64: out.SetFloat(resolved) return true } case reflect.Struct: if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { out.Set(resolvedv) return true } case reflect.Ptr: if out.Type().Elem() == reflect.TypeOf(resolved) { // TODO DOes this make sense? When is out a Ptr except when decoding a nil value? elem := reflect.New(out.Type().Elem()) elem.Elem().Set(reflect.ValueOf(resolved)) out.Set(elem) return true } } d.terror(n, tag, out) return false } func settableValueOf(i interface{}) reflect.Value { v := reflect.ValueOf(i) sv := reflect.New(v.Type()).Elem() sv.Set(v) return sv } func (d *decoder) sequence(n *node, out reflect.Value) (good bool) { l := len(n.children) var iface reflect.Value switch out.Kind() { case reflect.Slice: out.Set(reflect.MakeSlice(out.Type(), l, l)) case reflect.Array: if l != out.Len() { failf("invalid array: want %d elements but got %d", out.Len(), l) } case reflect.Interface: // No type hints. Will have to use a generic sequence. iface = out out = settableValueOf(make([]interface{}, l)) default: d.terror(n, yaml_SEQ_TAG, out) return false } et := out.Type().Elem() j := 0 for i := 0; i < l; i++ { e := reflect.New(et).Elem() if ok := d.unmarshal(n.children[i], e); ok { out.Index(j).Set(e) j++ } } if out.Kind() != reflect.Array { out.Set(out.Slice(0, j)) } if iface.IsValid() { iface.Set(out) } return true } func (d *decoder) mapping(n *node, out reflect.Value) (good bool) { switch out.Kind() { case reflect.Struct: return d.mappingStruct(n, out) case reflect.Slice: return d.mappingSlice(n, out) case reflect.Map: // okay case reflect.Interface: if d.mapType.Kind() == reflect.Map { iface := out out = reflect.MakeMap(d.mapType) iface.Set(out) } else { slicev := reflect.New(d.mapType).Elem() if !d.mappingSlice(n, slicev) { return false } out.Set(slicev) return true } default: d.terror(n, yaml_MAP_TAG, out) return false } outt := out.Type() kt := outt.Key() et := outt.Elem() mapType := d.mapType if outt.Key() == ifaceType && outt.Elem() == ifaceType { d.mapType = outt } if out.IsNil() { out.Set(reflect.MakeMap(outt)) } l := len(n.children) for i := 0; i < l; i += 2 { if isMerge(n.children[i]) { d.merge(n.children[i+1], out) continue } k := reflect.New(kt).Elem() if d.unmarshal(n.children[i], k) { kkind := k.Kind() if kkind == reflect.Interface { kkind = k.Elem().Kind() } if kkind == reflect.Map || kkind == reflect.Slice { failf("invalid map key: %#v", k.Interface()) } e := reflect.New(et).Elem() if d.unmarshal(n.children[i+1], e) { d.setMapIndex(n.children[i+1], out, k, e) } } } d.mapType = mapType return true } func (d *decoder) setMapIndex(n *node, out, k, v reflect.Value) { if d.strict && out.MapIndex(k) != zeroValue { d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.line+1, k.Interface())) return } out.SetMapIndex(k, v) } func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) { outt := out.Type() if outt.Elem() != mapItemType { d.terror(n, yaml_MAP_TAG, out) return false } mapType := d.mapType d.mapType = outt var slice []MapItem var l = len(n.children) for i := 0; i < l; i += 2 { if isMerge(n.children[i]) { d.merge(n.children[i+1], out) continue } item := MapItem{} k := reflect.ValueOf(&item.Key).Elem() if d.unmarshal(n.children[i], k) { v := reflect.ValueOf(&item.Value).Elem() if d.unmarshal(n.children[i+1], v) { slice = append(slice, item) } } } out.Set(reflect.ValueOf(slice)) d.mapType = mapType return true } func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) { sinfo, err := getStructInfo(out.Type()) if err != nil { panic(err) } name := settableValueOf("") l := len(n.children) var inlineMap reflect.Value var elemType reflect.Type if sinfo.InlineMap != -1 { inlineMap = out.Field(sinfo.InlineMap) inlineMap.Set(reflect.New(inlineMap.Type()).Elem()) elemType = inlineMap.Type().Elem() } var doneFields []bool if d.strict { doneFields = make([]bool, len(sinfo.FieldsList)) } for i := 0; i < l; i += 2 { ni := n.children[i] if isMerge(ni) { d.merge(n.children[i+1], out) continue } if !d.unmarshal(ni, name) { continue } if info, ok := sinfo.FieldsMap[name.String()]; ok { if d.strict { if doneFields[info.Id] { d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.line+1, name.String(), out.Type())) continue } doneFields[info.Id] = true } var field reflect.Value if info.Inline == nil { field = out.Field(info.Num) } else { field = out.FieldByIndex(info.Inline) } d.unmarshal(n.children[i+1], field) } else if sinfo.InlineMap != -1 { if inlineMap.IsNil() { inlineMap.Set(reflect.MakeMap(inlineMap.Type())) } value := reflect.New(elemType).Elem() d.unmarshal(n.children[i+1], value) d.setMapIndex(n.children[i+1], inlineMap, name, value) } else if d.strict { d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.line+1, name.String(), out.Type())) } } return true } func failWantMap() { failf("map merge requires map or sequence of maps as the value") } func (d *decoder) merge(n *node, out reflect.Value) { switch n.kind { case mappingNode: d.unmarshal(n, out) case aliasNode: an, ok := d.doc.anchors[n.value] if ok && an.kind != mappingNode { failWantMap() } d.unmarshal(n, out) case sequenceNode: // Step backwards as earlier nodes take precedence. for i := len(n.children) - 1; i >= 0; i-- { ni := n.children[i] if ni.kind == aliasNode { an, ok := d.doc.anchors[ni.value] if ok && an.kind != mappingNode { failWantMap() } } else if ni.kind != mappingNode { failWantMap() } d.unmarshal(ni, out) } default: failWantMap() } } func isMerge(n *node) bool { return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG) } ================================================ FILE: vendor/gopkg.in/yaml.v2/emitterc.go ================================================ package yaml import ( "bytes" "fmt" ) // Flush the buffer if needed. func flush(emitter *yaml_emitter_t) bool { if emitter.buffer_pos+5 >= len(emitter.buffer) { return yaml_emitter_flush(emitter) } return true } // Put a character to the output buffer. func put(emitter *yaml_emitter_t, value byte) bool { if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { return false } emitter.buffer[emitter.buffer_pos] = value emitter.buffer_pos++ emitter.column++ return true } // Put a line break to the output buffer. func put_break(emitter *yaml_emitter_t) bool { if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { return false } switch emitter.line_break { case yaml_CR_BREAK: emitter.buffer[emitter.buffer_pos] = '\r' emitter.buffer_pos += 1 case yaml_LN_BREAK: emitter.buffer[emitter.buffer_pos] = '\n' emitter.buffer_pos += 1 case yaml_CRLN_BREAK: emitter.buffer[emitter.buffer_pos+0] = '\r' emitter.buffer[emitter.buffer_pos+1] = '\n' emitter.buffer_pos += 2 default: panic("unknown line break setting") } emitter.column = 0 emitter.line++ return true } // Copy a character from a string into buffer. func write(emitter *yaml_emitter_t, s []byte, i *int) bool { if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { return false } p := emitter.buffer_pos w := width(s[*i]) switch w { case 4: emitter.buffer[p+3] = s[*i+3] fallthrough case 3: emitter.buffer[p+2] = s[*i+2] fallthrough case 2: emitter.buffer[p+1] = s[*i+1] fallthrough case 1: emitter.buffer[p+0] = s[*i+0] default: panic("unknown character width") } emitter.column++ emitter.buffer_pos += w *i += w return true } // Write a whole string into buffer. func write_all(emitter *yaml_emitter_t, s []byte) bool { for i := 0; i < len(s); { if !write(emitter, s, &i) { return false } } return true } // Copy a line break character from a string into buffer. func write_break(emitter *yaml_emitter_t, s []byte, i *int) bool { if s[*i] == '\n' { if !put_break(emitter) { return false } *i++ } else { if !write(emitter, s, i) { return false } emitter.column = 0 emitter.line++ } return true } // Set an emitter error and return false. func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool { emitter.error = yaml_EMITTER_ERROR emitter.problem = problem return false } // Emit an event. func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool { emitter.events = append(emitter.events, *event) for !yaml_emitter_need_more_events(emitter) { event := &emitter.events[emitter.events_head] if !yaml_emitter_analyze_event(emitter, event) { return false } if !yaml_emitter_state_machine(emitter, event) { return false } yaml_event_delete(event) emitter.events_head++ } return true } // Check if we need to accumulate more events before emitting. // // We accumulate extra // - 1 event for DOCUMENT-START // - 2 events for SEQUENCE-START // - 3 events for MAPPING-START // func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool { if emitter.events_head == len(emitter.events) { return true } var accumulate int switch emitter.events[emitter.events_head].typ { case yaml_DOCUMENT_START_EVENT: accumulate = 1 break case yaml_SEQUENCE_START_EVENT: accumulate = 2 break case yaml_MAPPING_START_EVENT: accumulate = 3 break default: return false } if len(emitter.events)-emitter.events_head > accumulate { return false } var level int for i := emitter.events_head; i < len(emitter.events); i++ { switch emitter.events[i].typ { case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT: level++ case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT: level-- } if level == 0 { return false } } return true } // Append a directive to the directives stack. func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_directive_t, allow_duplicates bool) bool { for i := 0; i < len(emitter.tag_directives); i++ { if bytes.Equal(value.handle, emitter.tag_directives[i].handle) { if allow_duplicates { return true } return yaml_emitter_set_emitter_error(emitter, "duplicate %TAG directive") } } // [Go] Do we actually need to copy this given garbage collection // and the lack of deallocating destructors? tag_copy := yaml_tag_directive_t{ handle: make([]byte, len(value.handle)), prefix: make([]byte, len(value.prefix)), } copy(tag_copy.handle, value.handle) copy(tag_copy.prefix, value.prefix) emitter.tag_directives = append(emitter.tag_directives, tag_copy) return true } // Increase the indentation level. func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool { emitter.indents = append(emitter.indents, emitter.indent) if emitter.indent < 0 { if flow { emitter.indent = emitter.best_indent } else { emitter.indent = 0 } } else if !indentless { emitter.indent += emitter.best_indent } return true } // State dispatcher. func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool { switch emitter.state { default: case yaml_EMIT_STREAM_START_STATE: return yaml_emitter_emit_stream_start(emitter, event) case yaml_EMIT_FIRST_DOCUMENT_START_STATE: return yaml_emitter_emit_document_start(emitter, event, true) case yaml_EMIT_DOCUMENT_START_STATE: return yaml_emitter_emit_document_start(emitter, event, false) case yaml_EMIT_DOCUMENT_CONTENT_STATE: return yaml_emitter_emit_document_content(emitter, event) case yaml_EMIT_DOCUMENT_END_STATE: return yaml_emitter_emit_document_end(emitter, event) case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE: return yaml_emitter_emit_flow_sequence_item(emitter, event, true) case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE: return yaml_emitter_emit_flow_sequence_item(emitter, event, false) case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE: return yaml_emitter_emit_flow_mapping_key(emitter, event, true) case yaml_EMIT_FLOW_MAPPING_KEY_STATE: return yaml_emitter_emit_flow_mapping_key(emitter, event, false) case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE: return yaml_emitter_emit_flow_mapping_value(emitter, event, true) case yaml_EMIT_FLOW_MAPPING_VALUE_STATE: return yaml_emitter_emit_flow_mapping_value(emitter, event, false) case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE: return yaml_emitter_emit_block_sequence_item(emitter, event, true) case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE: return yaml_emitter_emit_block_sequence_item(emitter, event, false) case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE: return yaml_emitter_emit_block_mapping_key(emitter, event, true) case yaml_EMIT_BLOCK_MAPPING_KEY_STATE: return yaml_emitter_emit_block_mapping_key(emitter, event, false) case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE: return yaml_emitter_emit_block_mapping_value(emitter, event, true) case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE: return yaml_emitter_emit_block_mapping_value(emitter, event, false) case yaml_EMIT_END_STATE: return yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END") } panic("invalid emitter state") } // Expect STREAM-START. func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { if event.typ != yaml_STREAM_START_EVENT { return yaml_emitter_set_emitter_error(emitter, "expected STREAM-START") } if emitter.encoding == yaml_ANY_ENCODING { emitter.encoding = event.encoding if emitter.encoding == yaml_ANY_ENCODING { emitter.encoding = yaml_UTF8_ENCODING } } if emitter.best_indent < 2 || emitter.best_indent > 9 { emitter.best_indent = 2 } if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 { emitter.best_width = 80 } if emitter.best_width < 0 { emitter.best_width = 1<<31 - 1 } if emitter.line_break == yaml_ANY_BREAK { emitter.line_break = yaml_LN_BREAK } emitter.indent = -1 emitter.line = 0 emitter.column = 0 emitter.whitespace = true emitter.indention = true if emitter.encoding != yaml_UTF8_ENCODING { if !yaml_emitter_write_bom(emitter) { return false } } emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE return true } // Expect DOCUMENT-START or STREAM-END. func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { if event.typ == yaml_DOCUMENT_START_EVENT { if event.version_directive != nil { if !yaml_emitter_analyze_version_directive(emitter, event.version_directive) { return false } } for i := 0; i < len(event.tag_directives); i++ { tag_directive := &event.tag_directives[i] if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) { return false } if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) { return false } } for i := 0; i < len(default_tag_directives); i++ { tag_directive := &default_tag_directives[i] if !yaml_emitter_append_tag_directive(emitter, tag_directive, true) { return false } } implicit := event.implicit if !first || emitter.canonical { implicit = false } if emitter.open_ended && (event.version_directive != nil || len(event.tag_directives) > 0) { if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { return false } if !yaml_emitter_write_indent(emitter) { return false } } if event.version_directive != nil { implicit = false if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) { return false } if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) { return false } if !yaml_emitter_write_indent(emitter) { return false } } if len(event.tag_directives) > 0 { implicit = false for i := 0; i < len(event.tag_directives); i++ { tag_directive := &event.tag_directives[i] if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) { return false } if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) { return false } if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) { return false } if !yaml_emitter_write_indent(emitter) { return false } } } if yaml_emitter_check_empty_document(emitter) { implicit = false } if !implicit { if !yaml_emitter_write_indent(emitter) { return false } if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) { return false } if emitter.canonical { if !yaml_emitter_write_indent(emitter) { return false } } } emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE return true } if event.typ == yaml_STREAM_END_EVENT { if emitter.open_ended { if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { return false } if !yaml_emitter_write_indent(emitter) { return false } } if !yaml_emitter_flush(emitter) { return false } emitter.state = yaml_EMIT_END_STATE return true } return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-START or STREAM-END") } // Expect the root node. func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool { emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE) return yaml_emitter_emit_node(emitter, event, true, false, false, false) } // Expect DOCUMENT-END. func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool { if event.typ != yaml_DOCUMENT_END_EVENT { return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-END") } if !yaml_emitter_write_indent(emitter) { return false } if !event.implicit { // [Go] Allocate the slice elsewhere. if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { return false } if !yaml_emitter_write_indent(emitter) { return false } } if !yaml_emitter_flush(emitter) { return false } emitter.state = yaml_EMIT_DOCUMENT_START_STATE emitter.tag_directives = emitter.tag_directives[:0] return true } // Expect a flow item node. func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { if first { if !yaml_emitter_write_indicator(emitter, []byte{'['}, true, true, false) { return false } if !yaml_emitter_increase_indent(emitter, true, false) { return false } emitter.flow_level++ } if event.typ == yaml_SEQUENCE_END_EVENT { emitter.flow_level-- emitter.indent = emitter.indents[len(emitter.indents)-1] emitter.indents = emitter.indents[:len(emitter.indents)-1] if emitter.canonical && !first { if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { return false } if !yaml_emitter_write_indent(emitter) { return false } } if !yaml_emitter_write_indicator(emitter, []byte{']'}, false, false, false) { return false } emitter.state = emitter.states[len(emitter.states)-1] emitter.states = emitter.states[:len(emitter.states)-1] return true } if !first { if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { return false } } if emitter.canonical || emitter.column > emitter.best_width { if !yaml_emitter_write_indent(emitter) { return false } } emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE) return yaml_emitter_emit_node(emitter, event, false, true, false, false) } // Expect a flow key node. func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { if first { if !yaml_emitter_write_indicator(emitter, []byte{'{'}, true, true, false) { return false } if !yaml_emitter_increase_indent(emitter, true, false) { return false } emitter.flow_level++ } if event.typ == yaml_MAPPING_END_EVENT { emitter.flow_level-- emitter.indent = emitter.indents[len(emitter.indents)-1] emitter.indents = emitter.indents[:len(emitter.indents)-1] if emitter.canonical && !first { if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { return false } if !yaml_emitter_write_indent(emitter) { return false } } if !yaml_emitter_write_indicator(emitter, []byte{'}'}, false, false, false) { return false } emitter.state = emitter.states[len(emitter.states)-1] emitter.states = emitter.states[:len(emitter.states)-1] return true } if !first { if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { return false } } if emitter.canonical || emitter.column > emitter.best_width { if !yaml_emitter_write_indent(emitter) { return false } } if !emitter.canonical && yaml_emitter_check_simple_key(emitter) { emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE) return yaml_emitter_emit_node(emitter, event, false, false, true, true) } if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, false) { return false } emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE) return yaml_emitter_emit_node(emitter, event, false, false, true, false) } // Expect a flow value node. func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { if simple { if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { return false } } else { if emitter.canonical || emitter.column > emitter.best_width { if !yaml_emitter_write_indent(emitter) { return false } } if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, false) { return false } } emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE) return yaml_emitter_emit_node(emitter, event, false, false, true, false) } // Expect a block item node. func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { if first { if !yaml_emitter_increase_indent(emitter, false, emitter.mapping_context && !emitter.indention) { return false } } if event.typ == yaml_SEQUENCE_END_EVENT { emitter.indent = emitter.indents[len(emitter.indents)-1] emitter.indents = emitter.indents[:len(emitter.indents)-1] emitter.state = emitter.states[len(emitter.states)-1] emitter.states = emitter.states[:len(emitter.states)-1] return true } if !yaml_emitter_write_indent(emitter) { return false } if !yaml_emitter_write_indicator(emitter, []byte{'-'}, true, false, true) { return false } emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE) return yaml_emitter_emit_node(emitter, event, false, true, false, false) } // Expect a block key node. func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { if first { if !yaml_emitter_increase_indent(emitter, false, false) { return false } } if event.typ == yaml_MAPPING_END_EVENT { emitter.indent = emitter.indents[len(emitter.indents)-1] emitter.indents = emitter.indents[:len(emitter.indents)-1] emitter.state = emitter.states[len(emitter.states)-1] emitter.states = emitter.states[:len(emitter.states)-1] return true } if !yaml_emitter_write_indent(emitter) { return false } if yaml_emitter_check_simple_key(emitter) { emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE) return yaml_emitter_emit_node(emitter, event, false, false, true, true) } if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, true) { return false } emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE) return yaml_emitter_emit_node(emitter, event, false, false, true, false) } // Expect a block value node. func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { if simple { if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { return false } } else { if !yaml_emitter_write_indent(emitter) { return false } if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, true) { return false } } emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE) return yaml_emitter_emit_node(emitter, event, false, false, true, false) } // Expect a node. func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t, root bool, sequence bool, mapping bool, simple_key bool) bool { emitter.root_context = root emitter.sequence_context = sequence emitter.mapping_context = mapping emitter.simple_key_context = simple_key switch event.typ { case yaml_ALIAS_EVENT: return yaml_emitter_emit_alias(emitter, event) case yaml_SCALAR_EVENT: return yaml_emitter_emit_scalar(emitter, event) case yaml_SEQUENCE_START_EVENT: return yaml_emitter_emit_sequence_start(emitter, event) case yaml_MAPPING_START_EVENT: return yaml_emitter_emit_mapping_start(emitter, event) default: return yaml_emitter_set_emitter_error(emitter, fmt.Sprintf("expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got %v", event.typ)) } } // Expect ALIAS. func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool { if !yaml_emitter_process_anchor(emitter) { return false } emitter.state = emitter.states[len(emitter.states)-1] emitter.states = emitter.states[:len(emitter.states)-1] return true } // Expect SCALAR. func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool { if !yaml_emitter_select_scalar_style(emitter, event) { return false } if !yaml_emitter_process_anchor(emitter) { return false } if !yaml_emitter_process_tag(emitter) { return false } if !yaml_emitter_increase_indent(emitter, true, false) { return false } if !yaml_emitter_process_scalar(emitter) { return false } emitter.indent = emitter.indents[len(emitter.indents)-1] emitter.indents = emitter.indents[:len(emitter.indents)-1] emitter.state = emitter.states[len(emitter.states)-1] emitter.states = emitter.states[:len(emitter.states)-1] return true } // Expect SEQUENCE-START. func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { if !yaml_emitter_process_anchor(emitter) { return false } if !yaml_emitter_process_tag(emitter) { return false } if emitter.flow_level > 0 || emitter.canonical || event.sequence_style() == yaml_FLOW_SEQUENCE_STYLE || yaml_emitter_check_empty_sequence(emitter) { emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE } else { emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE } return true } // Expect MAPPING-START. func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { if !yaml_emitter_process_anchor(emitter) { return false } if !yaml_emitter_process_tag(emitter) { return false } if emitter.flow_level > 0 || emitter.canonical || event.mapping_style() == yaml_FLOW_MAPPING_STYLE || yaml_emitter_check_empty_mapping(emitter) { emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE } else { emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE } return true } // Check if the document content is an empty scalar. func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool { return false // [Go] Huh? } // Check if the next events represent an empty sequence. func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool { if len(emitter.events)-emitter.events_head < 2 { return false } return emitter.events[emitter.events_head].typ == yaml_SEQUENCE_START_EVENT && emitter.events[emitter.events_head+1].typ == yaml_SEQUENCE_END_EVENT } // Check if the next events represent an empty mapping. func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool { if len(emitter.events)-emitter.events_head < 2 { return false } return emitter.events[emitter.events_head].typ == yaml_MAPPING_START_EVENT && emitter.events[emitter.events_head+1].typ == yaml_MAPPING_END_EVENT } // Check if the next node can be expressed as a simple key. func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool { length := 0 switch emitter.events[emitter.events_head].typ { case yaml_ALIAS_EVENT: length += len(emitter.anchor_data.anchor) case yaml_SCALAR_EVENT: if emitter.scalar_data.multiline { return false } length += len(emitter.anchor_data.anchor) + len(emitter.tag_data.handle) + len(emitter.tag_data.suffix) + len(emitter.scalar_data.value) case yaml_SEQUENCE_START_EVENT: if !yaml_emitter_check_empty_sequence(emitter) { return false } length += len(emitter.anchor_data.anchor) + len(emitter.tag_data.handle) + len(emitter.tag_data.suffix) case yaml_MAPPING_START_EVENT: if !yaml_emitter_check_empty_mapping(emitter) { return false } length += len(emitter.anchor_data.anchor) + len(emitter.tag_data.handle) + len(emitter.tag_data.suffix) default: return false } return length <= 128 } // Determine an acceptable scalar style. func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool { no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 if no_tag && !event.implicit && !event.quoted_implicit { return yaml_emitter_set_emitter_error(emitter, "neither tag nor implicit flags are specified") } style := event.scalar_style() if style == yaml_ANY_SCALAR_STYLE { style = yaml_PLAIN_SCALAR_STYLE } if emitter.canonical { style = yaml_DOUBLE_QUOTED_SCALAR_STYLE } if emitter.simple_key_context && emitter.scalar_data.multiline { style = yaml_DOUBLE_QUOTED_SCALAR_STYLE } if style == yaml_PLAIN_SCALAR_STYLE { if emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed || emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed { style = yaml_SINGLE_QUOTED_SCALAR_STYLE } if len(emitter.scalar_data.value) == 0 && (emitter.flow_level > 0 || emitter.simple_key_context) { style = yaml_SINGLE_QUOTED_SCALAR_STYLE } if no_tag && !event.implicit { style = yaml_SINGLE_QUOTED_SCALAR_STYLE } } if style == yaml_SINGLE_QUOTED_SCALAR_STYLE { if !emitter.scalar_data.single_quoted_allowed { style = yaml_DOUBLE_QUOTED_SCALAR_STYLE } } if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE { if !emitter.scalar_data.block_allowed || emitter.flow_level > 0 || emitter.simple_key_context { style = yaml_DOUBLE_QUOTED_SCALAR_STYLE } } if no_tag && !event.quoted_implicit && style != yaml_PLAIN_SCALAR_STYLE { emitter.tag_data.handle = []byte{'!'} } emitter.scalar_data.style = style return true } // Write an anchor. func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool { if emitter.anchor_data.anchor == nil { return true } c := []byte{'&'} if emitter.anchor_data.alias { c[0] = '*' } if !yaml_emitter_write_indicator(emitter, c, true, false, false) { return false } return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor) } // Write a tag. func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool { if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 { return true } if len(emitter.tag_data.handle) > 0 { if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) { return false } if len(emitter.tag_data.suffix) > 0 { if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { return false } } } else { // [Go] Allocate these slices elsewhere. if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) { return false } if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { return false } if !yaml_emitter_write_indicator(emitter, []byte{'>'}, false, false, false) { return false } } return true } // Write a scalar. func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool { switch emitter.scalar_data.style { case yaml_PLAIN_SCALAR_STYLE: return yaml_emitter_write_plain_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) case yaml_SINGLE_QUOTED_SCALAR_STYLE: return yaml_emitter_write_single_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) case yaml_DOUBLE_QUOTED_SCALAR_STYLE: return yaml_emitter_write_double_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) case yaml_LITERAL_SCALAR_STYLE: return yaml_emitter_write_literal_scalar(emitter, emitter.scalar_data.value) case yaml_FOLDED_SCALAR_STYLE: return yaml_emitter_write_folded_scalar(emitter, emitter.scalar_data.value) } panic("unknown scalar style") } // Check if a %YAML directive is valid. func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t, version_directive *yaml_version_directive_t) bool { if version_directive.major != 1 || version_directive.minor != 1 { return yaml_emitter_set_emitter_error(emitter, "incompatible %YAML directive") } return true } // Check if a %TAG directive is valid. func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t, tag_directive *yaml_tag_directive_t) bool { handle := tag_directive.handle prefix := tag_directive.prefix if len(handle) == 0 { return yaml_emitter_set_emitter_error(emitter, "tag handle must not be empty") } if handle[0] != '!' { return yaml_emitter_set_emitter_error(emitter, "tag handle must start with '!'") } if handle[len(handle)-1] != '!' { return yaml_emitter_set_emitter_error(emitter, "tag handle must end with '!'") } for i := 1; i < len(handle)-1; i += width(handle[i]) { if !is_alpha(handle, i) { return yaml_emitter_set_emitter_error(emitter, "tag handle must contain alphanumerical characters only") } } if len(prefix) == 0 { return yaml_emitter_set_emitter_error(emitter, "tag prefix must not be empty") } return true } // Check if an anchor is valid. func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t, anchor []byte, alias bool) bool { if len(anchor) == 0 { problem := "anchor value must not be empty" if alias { problem = "alias value must not be empty" } return yaml_emitter_set_emitter_error(emitter, problem) } for i := 0; i < len(anchor); i += width(anchor[i]) { if !is_alpha(anchor, i) { problem := "anchor value must contain alphanumerical characters only" if alias { problem = "alias value must contain alphanumerical characters only" } return yaml_emitter_set_emitter_error(emitter, problem) } } emitter.anchor_data.anchor = anchor emitter.anchor_data.alias = alias return true } // Check if a tag is valid. func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool { if len(tag) == 0 { return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty") } for i := 0; i < len(emitter.tag_directives); i++ { tag_directive := &emitter.tag_directives[i] if bytes.HasPrefix(tag, tag_directive.prefix) { emitter.tag_data.handle = tag_directive.handle emitter.tag_data.suffix = tag[len(tag_directive.prefix):] return true } } emitter.tag_data.suffix = tag return true } // Check if a scalar is valid. func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool { var ( block_indicators = false flow_indicators = false line_breaks = false special_characters = false leading_space = false leading_break = false trailing_space = false trailing_break = false break_space = false space_break = false preceded_by_whitespace = false followed_by_whitespace = false previous_space = false previous_break = false ) emitter.scalar_data.value = value if len(value) == 0 { emitter.scalar_data.multiline = false emitter.scalar_data.flow_plain_allowed = false emitter.scalar_data.block_plain_allowed = true emitter.scalar_data.single_quoted_allowed = true emitter.scalar_data.block_allowed = false return true } if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') || (value[0] == '.' && value[1] == '.' && value[2] == '.')) { block_indicators = true flow_indicators = true } preceded_by_whitespace = true for i, w := 0, 0; i < len(value); i += w { w = width(value[i]) followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w) if i == 0 { switch value[i] { case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`': flow_indicators = true block_indicators = true case '?', ':': flow_indicators = true if followed_by_whitespace { block_indicators = true } case '-': if followed_by_whitespace { flow_indicators = true block_indicators = true } } } else { switch value[i] { case ',', '?', '[', ']', '{', '}': flow_indicators = true case ':': flow_indicators = true if followed_by_whitespace { block_indicators = true } case '#': if preceded_by_whitespace { flow_indicators = true block_indicators = true } } } if !is_printable(value, i) || !is_ascii(value, i) && !emitter.unicode { special_characters = true } if is_space(value, i) { if i == 0 { leading_space = true } if i+width(value[i]) == len(value) { trailing_space = true } if previous_break { break_space = true } previous_space = true previous_break = false } else if is_break(value, i) { line_breaks = true if i == 0 { leading_break = true } if i+width(value[i]) == len(value) { trailing_break = true } if previous_space { space_break = true } previous_space = false previous_break = true } else { previous_space = false previous_break = false } // [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition. preceded_by_whitespace = is_blankz(value, i) } emitter.scalar_data.multiline = line_breaks emitter.scalar_data.flow_plain_allowed = true emitter.scalar_data.block_plain_allowed = true emitter.scalar_data.single_quoted_allowed = true emitter.scalar_data.block_allowed = true if leading_space || leading_break || trailing_space || trailing_break { emitter.scalar_data.flow_plain_allowed = false emitter.scalar_data.block_plain_allowed = false } if trailing_space { emitter.scalar_data.block_allowed = false } if break_space { emitter.scalar_data.flow_plain_allowed = false emitter.scalar_data.block_plain_allowed = false emitter.scalar_data.single_quoted_allowed = false } if space_break || special_characters { emitter.scalar_data.flow_plain_allowed = false emitter.scalar_data.block_plain_allowed = false emitter.scalar_data.single_quoted_allowed = false emitter.scalar_data.block_allowed = false } if line_breaks { emitter.scalar_data.flow_plain_allowed = false emitter.scalar_data.block_plain_allowed = false } if flow_indicators { emitter.scalar_data.flow_plain_allowed = false } if block_indicators { emitter.scalar_data.block_plain_allowed = false } return true } // Check if the event data is valid. func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool { emitter.anchor_data.anchor = nil emitter.tag_data.handle = nil emitter.tag_data.suffix = nil emitter.scalar_data.value = nil switch event.typ { case yaml_ALIAS_EVENT: if !yaml_emitter_analyze_anchor(emitter, event.anchor, true) { return false } case yaml_SCALAR_EVENT: if len(event.anchor) > 0 { if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { return false } } if len(event.tag) > 0 && (emitter.canonical || (!event.implicit && !event.quoted_implicit)) { if !yaml_emitter_analyze_tag(emitter, event.tag) { return false } } if !yaml_emitter_analyze_scalar(emitter, event.value) { return false } case yaml_SEQUENCE_START_EVENT: if len(event.anchor) > 0 { if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { return false } } if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { if !yaml_emitter_analyze_tag(emitter, event.tag) { return false } } case yaml_MAPPING_START_EVENT: if len(event.anchor) > 0 { if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { return false } } if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { if !yaml_emitter_analyze_tag(emitter, event.tag) { return false } } } return true } // Write the BOM character. func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool { if !flush(emitter) { return false } pos := emitter.buffer_pos emitter.buffer[pos+0] = '\xEF' emitter.buffer[pos+1] = '\xBB' emitter.buffer[pos+2] = '\xBF' emitter.buffer_pos += 3 return true } func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool { indent := emitter.indent if indent < 0 { indent = 0 } if !emitter.indention || emitter.column > indent || (emitter.column == indent && !emitter.whitespace) { if !put_break(emitter) { return false } } for emitter.column < indent { if !put(emitter, ' ') { return false } } emitter.whitespace = true emitter.indention = true return true } func yaml_emitter_write_indicator(emitter *yaml_emitter_t, indicator []byte, need_whitespace, is_whitespace, is_indention bool) bool { if need_whitespace && !emitter.whitespace { if !put(emitter, ' ') { return false } } if !write_all(emitter, indicator) { return false } emitter.whitespace = is_whitespace emitter.indention = (emitter.indention && is_indention) emitter.open_ended = false return true } func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool { if !write_all(emitter, value) { return false } emitter.whitespace = false emitter.indention = false return true } func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool { if !emitter.whitespace { if !put(emitter, ' ') { return false } } if !write_all(emitter, value) { return false } emitter.whitespace = false emitter.indention = false return true } func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_whitespace bool) bool { if need_whitespace && !emitter.whitespace { if !put(emitter, ' ') { return false } } for i := 0; i < len(value); { var must_write bool switch value[i] { case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')', '[', ']': must_write = true default: must_write = is_alpha(value, i) } if must_write { if !write(emitter, value, &i) { return false } } else { w := width(value[i]) for k := 0; k < w; k++ { octet := value[i] i++ if !put(emitter, '%') { return false } c := octet >> 4 if c < 10 { c += '0' } else { c += 'A' - 10 } if !put(emitter, c) { return false } c = octet & 0x0f if c < 10 { c += '0' } else { c += 'A' - 10 } if !put(emitter, c) { return false } } } } emitter.whitespace = false emitter.indention = false return true } func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { if !emitter.whitespace { if !put(emitter, ' ') { return false } } spaces := false breaks := false for i := 0; i < len(value); { if is_space(value, i) { if allow_breaks && !spaces && emitter.column > emitter.best_width && !is_space(value, i+1) { if !yaml_emitter_write_indent(emitter) { return false } i += width(value[i]) } else { if !write(emitter, value, &i) { return false } } spaces = true } else if is_break(value, i) { if !breaks && value[i] == '\n' { if !put_break(emitter) { return false } } if !write_break(emitter, value, &i) { return false } emitter.indention = true breaks = true } else { if breaks { if !yaml_emitter_write_indent(emitter) { return false } } if !write(emitter, value, &i) { return false } emitter.indention = false spaces = false breaks = false } } emitter.whitespace = false emitter.indention = false if emitter.root_context { emitter.open_ended = true } return true } func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { if !yaml_emitter_write_indicator(emitter, []byte{'\''}, true, false, false) { return false } spaces := false breaks := false for i := 0; i < len(value); { if is_space(value, i) { if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 && !is_space(value, i+1) { if !yaml_emitter_write_indent(emitter) { return false } i += width(value[i]) } else { if !write(emitter, value, &i) { return false } } spaces = true } else if is_break(value, i) { if !breaks && value[i] == '\n' { if !put_break(emitter) { return false } } if !write_break(emitter, value, &i) { return false } emitter.indention = true breaks = true } else { if breaks { if !yaml_emitter_write_indent(emitter) { return false } } if value[i] == '\'' { if !put(emitter, '\'') { return false } } if !write(emitter, value, &i) { return false } emitter.indention = false spaces = false breaks = false } } if !yaml_emitter_write_indicator(emitter, []byte{'\''}, false, false, false) { return false } emitter.whitespace = false emitter.indention = false return true } func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { spaces := false if !yaml_emitter_write_indicator(emitter, []byte{'"'}, true, false, false) { return false } for i := 0; i < len(value); { if !is_printable(value, i) || (!emitter.unicode && !is_ascii(value, i)) || is_bom(value, i) || is_break(value, i) || value[i] == '"' || value[i] == '\\' { octet := value[i] var w int var v rune switch { case octet&0x80 == 0x00: w, v = 1, rune(octet&0x7F) case octet&0xE0 == 0xC0: w, v = 2, rune(octet&0x1F) case octet&0xF0 == 0xE0: w, v = 3, rune(octet&0x0F) case octet&0xF8 == 0xF0: w, v = 4, rune(octet&0x07) } for k := 1; k < w; k++ { octet = value[i+k] v = (v << 6) + (rune(octet) & 0x3F) } i += w if !put(emitter, '\\') { return false } var ok bool switch v { case 0x00: ok = put(emitter, '0') case 0x07: ok = put(emitter, 'a') case 0x08: ok = put(emitter, 'b') case 0x09: ok = put(emitter, 't') case 0x0A: ok = put(emitter, 'n') case 0x0b: ok = put(emitter, 'v') case 0x0c: ok = put(emitter, 'f') case 0x0d: ok = put(emitter, 'r') case 0x1b: ok = put(emitter, 'e') case 0x22: ok = put(emitter, '"') case 0x5c: ok = put(emitter, '\\') case 0x85: ok = put(emitter, 'N') case 0xA0: ok = put(emitter, '_') case 0x2028: ok = put(emitter, 'L') case 0x2029: ok = put(emitter, 'P') default: if v <= 0xFF { ok = put(emitter, 'x') w = 2 } else if v <= 0xFFFF { ok = put(emitter, 'u') w = 4 } else { ok = put(emitter, 'U') w = 8 } for k := (w - 1) * 4; ok && k >= 0; k -= 4 { digit := byte((v >> uint(k)) & 0x0F) if digit < 10 { ok = put(emitter, digit+'0') } else { ok = put(emitter, digit+'A'-10) } } } if !ok { return false } spaces = false } else if is_space(value, i) { if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 { if !yaml_emitter_write_indent(emitter) { return false } if is_space(value, i+1) { if !put(emitter, '\\') { return false } } i += width(value[i]) } else if !write(emitter, value, &i) { return false } spaces = true } else { if !write(emitter, value, &i) { return false } spaces = false } } if !yaml_emitter_write_indicator(emitter, []byte{'"'}, false, false, false) { return false } emitter.whitespace = false emitter.indention = false return true } func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool { if is_space(value, 0) || is_break(value, 0) { indent_hint := []byte{'0' + byte(emitter.best_indent)} if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) { return false } } emitter.open_ended = false var chomp_hint [1]byte if len(value) == 0 { chomp_hint[0] = '-' } else { i := len(value) - 1 for value[i]&0xC0 == 0x80 { i-- } if !is_break(value, i) { chomp_hint[0] = '-' } else if i == 0 { chomp_hint[0] = '+' emitter.open_ended = true } else { i-- for value[i]&0xC0 == 0x80 { i-- } if is_break(value, i) { chomp_hint[0] = '+' emitter.open_ended = true } } } if chomp_hint[0] != 0 { if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) { return false } } return true } func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool { if !yaml_emitter_write_indicator(emitter, []byte{'|'}, true, false, false) { return false } if !yaml_emitter_write_block_scalar_hints(emitter, value) { return false } if !put_break(emitter) { return false } emitter.indention = true emitter.whitespace = true breaks := true for i := 0; i < len(value); { if is_break(value, i) { if !write_break(emitter, value, &i) { return false } emitter.indention = true breaks = true } else { if breaks { if !yaml_emitter_write_indent(emitter) { return false } } if !write(emitter, value, &i) { return false } emitter.indention = false breaks = false } } return true } func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool { if !yaml_emitter_write_indicator(emitter, []byte{'>'}, true, false, false) { return false } if !yaml_emitter_write_block_scalar_hints(emitter, value) { return false } if !put_break(emitter) { return false } emitter.indention = true emitter.whitespace = true breaks := true leading_spaces := true for i := 0; i < len(value); { if is_break(value, i) { if !breaks && !leading_spaces && value[i] == '\n' { k := 0 for is_break(value, k) { k += width(value[k]) } if !is_blankz(value, k) { if !put_break(emitter) { return false } } } if !write_break(emitter, value, &i) { return false } emitter.indention = true breaks = true } else { if breaks { if !yaml_emitter_write_indent(emitter) { return false } leading_spaces = is_blank(value, i) } if !breaks && is_space(value, i) && !is_space(value, i+1) && emitter.column > emitter.best_width { if !yaml_emitter_write_indent(emitter) { return false } i += width(value[i]) } else { if !write(emitter, value, &i) { return false } } emitter.indention = false breaks = false } } return true } ================================================ FILE: vendor/gopkg.in/yaml.v2/encode.go ================================================ package yaml import ( "encoding" "fmt" "io" "reflect" "regexp" "sort" "strconv" "strings" "time" "unicode/utf8" ) // jsonNumber is the interface of the encoding/json.Number datatype. // Repeating the interface here avoids a dependency on encoding/json, and also // supports other libraries like jsoniter, which use a similar datatype with // the same interface. Detecting this interface is useful when dealing with // structures containing json.Number, which is a string under the hood. The // encoder should prefer the use of Int64(), Float64() and string(), in that // order, when encoding this type. type jsonNumber interface { Float64() (float64, error) Int64() (int64, error) String() string } type encoder struct { emitter yaml_emitter_t event yaml_event_t out []byte flow bool // doneInit holds whether the initial stream_start_event has been // emitted. doneInit bool } func newEncoder() *encoder { e := &encoder{} yaml_emitter_initialize(&e.emitter) yaml_emitter_set_output_string(&e.emitter, &e.out) yaml_emitter_set_unicode(&e.emitter, true) return e } func newEncoderWithWriter(w io.Writer) *encoder { e := &encoder{} yaml_emitter_initialize(&e.emitter) yaml_emitter_set_output_writer(&e.emitter, w) yaml_emitter_set_unicode(&e.emitter, true) return e } func (e *encoder) init() { if e.doneInit { return } yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING) e.emit() e.doneInit = true } func (e *encoder) finish() { e.emitter.open_ended = false yaml_stream_end_event_initialize(&e.event) e.emit() } func (e *encoder) destroy() { yaml_emitter_delete(&e.emitter) } func (e *encoder) emit() { // This will internally delete the e.event value. e.must(yaml_emitter_emit(&e.emitter, &e.event)) } func (e *encoder) must(ok bool) { if !ok { msg := e.emitter.problem if msg == "" { msg = "unknown problem generating YAML content" } failf("%s", msg) } } func (e *encoder) marshalDoc(tag string, in reflect.Value) { e.init() yaml_document_start_event_initialize(&e.event, nil, nil, true) e.emit() e.marshal(tag, in) yaml_document_end_event_initialize(&e.event, true) e.emit() } func (e *encoder) marshal(tag string, in reflect.Value) { if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() { e.nilv() return } iface := in.Interface() switch m := iface.(type) { case jsonNumber: integer, err := m.Int64() if err == nil { // In this case the json.Number is a valid int64 in = reflect.ValueOf(integer) break } float, err := m.Float64() if err == nil { // In this case the json.Number is a valid float64 in = reflect.ValueOf(float) break } // fallback case - no number could be obtained in = reflect.ValueOf(m.String()) case time.Time, *time.Time: // Although time.Time implements TextMarshaler, // we don't want to treat it as a string for YAML // purposes because YAML has special support for // timestamps. case Marshaler: v, err := m.MarshalYAML() if err != nil { fail(err) } if v == nil { e.nilv() return } in = reflect.ValueOf(v) case encoding.TextMarshaler: text, err := m.MarshalText() if err != nil { fail(err) } in = reflect.ValueOf(string(text)) case nil: e.nilv() return } switch in.Kind() { case reflect.Interface: e.marshal(tag, in.Elem()) case reflect.Map: e.mapv(tag, in) case reflect.Ptr: if in.Type() == ptrTimeType { e.timev(tag, in.Elem()) } else { e.marshal(tag, in.Elem()) } case reflect.Struct: if in.Type() == timeType { e.timev(tag, in) } else { e.structv(tag, in) } case reflect.Slice, reflect.Array: if in.Type().Elem() == mapItemType { e.itemsv(tag, in) } else { e.slicev(tag, in) } case reflect.String: e.stringv(tag, in) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if in.Type() == durationType { e.stringv(tag, reflect.ValueOf(iface.(time.Duration).String())) } else { e.intv(tag, in) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: e.uintv(tag, in) case reflect.Float32, reflect.Float64: e.floatv(tag, in) case reflect.Bool: e.boolv(tag, in) default: panic("cannot marshal type: " + in.Type().String()) } } func (e *encoder) mapv(tag string, in reflect.Value) { e.mappingv(tag, func() { keys := keyList(in.MapKeys()) sort.Sort(keys) for _, k := range keys { e.marshal("", k) e.marshal("", in.MapIndex(k)) } }) } func (e *encoder) itemsv(tag string, in reflect.Value) { e.mappingv(tag, func() { slice := in.Convert(reflect.TypeOf([]MapItem{})).Interface().([]MapItem) for _, item := range slice { e.marshal("", reflect.ValueOf(item.Key)) e.marshal("", reflect.ValueOf(item.Value)) } }) } func (e *encoder) structv(tag string, in reflect.Value) { sinfo, err := getStructInfo(in.Type()) if err != nil { panic(err) } e.mappingv(tag, func() { for _, info := range sinfo.FieldsList { var value reflect.Value if info.Inline == nil { value = in.Field(info.Num) } else { value = in.FieldByIndex(info.Inline) } if info.OmitEmpty && isZero(value) { continue } e.marshal("", reflect.ValueOf(info.Key)) e.flow = info.Flow e.marshal("", value) } if sinfo.InlineMap >= 0 { m := in.Field(sinfo.InlineMap) if m.Len() > 0 { e.flow = false keys := keyList(m.MapKeys()) sort.Sort(keys) for _, k := range keys { if _, found := sinfo.FieldsMap[k.String()]; found { panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", k.String())) } e.marshal("", k) e.flow = false e.marshal("", m.MapIndex(k)) } } } }) } func (e *encoder) mappingv(tag string, f func()) { implicit := tag == "" style := yaml_BLOCK_MAPPING_STYLE if e.flow { e.flow = false style = yaml_FLOW_MAPPING_STYLE } yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style) e.emit() f() yaml_mapping_end_event_initialize(&e.event) e.emit() } func (e *encoder) slicev(tag string, in reflect.Value) { implicit := tag == "" style := yaml_BLOCK_SEQUENCE_STYLE if e.flow { e.flow = false style = yaml_FLOW_SEQUENCE_STYLE } e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)) e.emit() n := in.Len() for i := 0; i < n; i++ { e.marshal("", in.Index(i)) } e.must(yaml_sequence_end_event_initialize(&e.event)) e.emit() } // isBase60 returns whether s is in base 60 notation as defined in YAML 1.1. // // The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported // in YAML 1.2 and by this package, but these should be marshalled quoted for // the time being for compatibility with other parsers. func isBase60Float(s string) (result bool) { // Fast path. if s == "" { return false } c := s[0] if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 { return false } // Do the full match. return base60float.MatchString(s) } // From http://yaml.org/type/float.html, except the regular expression there // is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix. var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`) func (e *encoder) stringv(tag string, in reflect.Value) { var style yaml_scalar_style_t s := in.String() canUsePlain := true switch { case !utf8.ValidString(s): if tag == yaml_BINARY_TAG { failf("explicitly tagged !!binary data must be base64-encoded") } if tag != "" { failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag)) } // It can't be encoded directly as YAML so use a binary tag // and encode it as base64. tag = yaml_BINARY_TAG s = encodeBase64(s) case tag == "": // Check to see if it would resolve to a specific // tag when encoded unquoted. If it doesn't, // there's no need to quote it. rtag, _ := resolve("", s) canUsePlain = rtag == yaml_STR_TAG && !isBase60Float(s) } // Note: it's possible for user code to emit invalid YAML // if they explicitly specify a tag and a string containing // text that's incompatible with that tag. switch { case strings.Contains(s, "\n"): style = yaml_LITERAL_SCALAR_STYLE case canUsePlain: style = yaml_PLAIN_SCALAR_STYLE default: style = yaml_DOUBLE_QUOTED_SCALAR_STYLE } e.emitScalar(s, "", tag, style) } func (e *encoder) boolv(tag string, in reflect.Value) { var s string if in.Bool() { s = "true" } else { s = "false" } e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) } func (e *encoder) intv(tag string, in reflect.Value) { s := strconv.FormatInt(in.Int(), 10) e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) } func (e *encoder) uintv(tag string, in reflect.Value) { s := strconv.FormatUint(in.Uint(), 10) e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) } func (e *encoder) timev(tag string, in reflect.Value) { t := in.Interface().(time.Time) s := t.Format(time.RFC3339Nano) e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) } func (e *encoder) floatv(tag string, in reflect.Value) { // Issue #352: When formatting, use the precision of the underlying value precision := 64 if in.Kind() == reflect.Float32 { precision = 32 } s := strconv.FormatFloat(in.Float(), 'g', -1, precision) switch s { case "+Inf": s = ".inf" case "-Inf": s = "-.inf" case "NaN": s = ".nan" } e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) } func (e *encoder) nilv() { e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE) } func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) { implicit := tag == "" e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style)) e.emit() } ================================================ FILE: vendor/gopkg.in/yaml.v2/go.mod ================================================ module "gopkg.in/yaml.v2" require ( "gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405 ) ================================================ FILE: vendor/gopkg.in/yaml.v2/parserc.go ================================================ package yaml import ( "bytes" ) // The parser implements the following grammar: // // stream ::= STREAM-START implicit_document? explicit_document* STREAM-END // implicit_document ::= block_node DOCUMENT-END* // explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* // block_node_or_indentless_sequence ::= // ALIAS // | properties (block_content | indentless_block_sequence)? // | block_content // | indentless_block_sequence // block_node ::= ALIAS // | properties block_content? // | block_content // flow_node ::= ALIAS // | properties flow_content? // | flow_content // properties ::= TAG ANCHOR? | ANCHOR TAG? // block_content ::= block_collection | flow_collection | SCALAR // flow_content ::= flow_collection | SCALAR // block_collection ::= block_sequence | block_mapping // flow_collection ::= flow_sequence | flow_mapping // block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END // indentless_sequence ::= (BLOCK-ENTRY block_node?)+ // block_mapping ::= BLOCK-MAPPING_START // ((KEY block_node_or_indentless_sequence?)? // (VALUE block_node_or_indentless_sequence?)?)* // BLOCK-END // flow_sequence ::= FLOW-SEQUENCE-START // (flow_sequence_entry FLOW-ENTRY)* // flow_sequence_entry? // FLOW-SEQUENCE-END // flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? // flow_mapping ::= FLOW-MAPPING-START // (flow_mapping_entry FLOW-ENTRY)* // flow_mapping_entry? // FLOW-MAPPING-END // flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? // Peek the next token in the token queue. func peek_token(parser *yaml_parser_t) *yaml_token_t { if parser.token_available || yaml_parser_fetch_more_tokens(parser) { return &parser.tokens[parser.tokens_head] } return nil } // Remove the next token from the queue (must be called after peek_token). func skip_token(parser *yaml_parser_t) { parser.token_available = false parser.tokens_parsed++ parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN parser.tokens_head++ } // Get the next event. func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool { // Erase the event object. *event = yaml_event_t{} // No events after the end of the stream or error. if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE { return true } // Generate the next event. return yaml_parser_state_machine(parser, event) } // Set parser error. func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool { parser.error = yaml_PARSER_ERROR parser.problem = problem parser.problem_mark = problem_mark return false } func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool { parser.error = yaml_PARSER_ERROR parser.context = context parser.context_mark = context_mark parser.problem = problem parser.problem_mark = problem_mark return false } // State dispatcher. func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool { //trace("yaml_parser_state_machine", "state:", parser.state.String()) switch parser.state { case yaml_PARSE_STREAM_START_STATE: return yaml_parser_parse_stream_start(parser, event) case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: return yaml_parser_parse_document_start(parser, event, true) case yaml_PARSE_DOCUMENT_START_STATE: return yaml_parser_parse_document_start(parser, event, false) case yaml_PARSE_DOCUMENT_CONTENT_STATE: return yaml_parser_parse_document_content(parser, event) case yaml_PARSE_DOCUMENT_END_STATE: return yaml_parser_parse_document_end(parser, event) case yaml_PARSE_BLOCK_NODE_STATE: return yaml_parser_parse_node(parser, event, true, false) case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: return yaml_parser_parse_node(parser, event, true, true) case yaml_PARSE_FLOW_NODE_STATE: return yaml_parser_parse_node(parser, event, false, false) case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: return yaml_parser_parse_block_sequence_entry(parser, event, true) case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: return yaml_parser_parse_block_sequence_entry(parser, event, false) case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: return yaml_parser_parse_indentless_sequence_entry(parser, event) case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: return yaml_parser_parse_block_mapping_key(parser, event, true) case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: return yaml_parser_parse_block_mapping_key(parser, event, false) case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: return yaml_parser_parse_block_mapping_value(parser, event) case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: return yaml_parser_parse_flow_sequence_entry(parser, event, true) case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: return yaml_parser_parse_flow_sequence_entry(parser, event, false) case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event) case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event) case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event) case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: return yaml_parser_parse_flow_mapping_key(parser, event, true) case yaml_PARSE_FLOW_MAPPING_KEY_STATE: return yaml_parser_parse_flow_mapping_key(parser, event, false) case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: return yaml_parser_parse_flow_mapping_value(parser, event, false) case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: return yaml_parser_parse_flow_mapping_value(parser, event, true) default: panic("invalid parser state") } } // Parse the production: // stream ::= STREAM-START implicit_document? explicit_document* STREAM-END // ************ func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { return false } if token.typ != yaml_STREAM_START_TOKEN { return yaml_parser_set_parser_error(parser, "did not find expected ", token.start_mark) } parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE *event = yaml_event_t{ typ: yaml_STREAM_START_EVENT, start_mark: token.start_mark, end_mark: token.end_mark, encoding: token.encoding, } skip_token(parser) return true } // Parse the productions: // implicit_document ::= block_node DOCUMENT-END* // * // explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* // ************************* func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool { token := peek_token(parser) if token == nil { return false } // Parse extra document end indicators. if !implicit { for token.typ == yaml_DOCUMENT_END_TOKEN { skip_token(parser) token = peek_token(parser) if token == nil { return false } } } if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN && token.typ != yaml_TAG_DIRECTIVE_TOKEN && token.typ != yaml_DOCUMENT_START_TOKEN && token.typ != yaml_STREAM_END_TOKEN { // Parse an implicit document. if !yaml_parser_process_directives(parser, nil, nil) { return false } parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) parser.state = yaml_PARSE_BLOCK_NODE_STATE *event = yaml_event_t{ typ: yaml_DOCUMENT_START_EVENT, start_mark: token.start_mark, end_mark: token.end_mark, } } else if token.typ != yaml_STREAM_END_TOKEN { // Parse an explicit document. var version_directive *yaml_version_directive_t var tag_directives []yaml_tag_directive_t start_mark := token.start_mark if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) { return false } token = peek_token(parser) if token == nil { return false } if token.typ != yaml_DOCUMENT_START_TOKEN { yaml_parser_set_parser_error(parser, "did not find expected ", token.start_mark) return false } parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE end_mark := token.end_mark *event = yaml_event_t{ typ: yaml_DOCUMENT_START_EVENT, start_mark: start_mark, end_mark: end_mark, version_directive: version_directive, tag_directives: tag_directives, implicit: false, } skip_token(parser) } else { // Parse the stream end. parser.state = yaml_PARSE_END_STATE *event = yaml_event_t{ typ: yaml_STREAM_END_EVENT, start_mark: token.start_mark, end_mark: token.end_mark, } skip_token(parser) } return true } // Parse the productions: // explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* // *********** // func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { return false } if token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN || token.typ == yaml_DOCUMENT_START_TOKEN || token.typ == yaml_DOCUMENT_END_TOKEN || token.typ == yaml_STREAM_END_TOKEN { parser.state = parser.states[len(parser.states)-1] parser.states = parser.states[:len(parser.states)-1] return yaml_parser_process_empty_scalar(parser, event, token.start_mark) } return yaml_parser_parse_node(parser, event, true, false) } // Parse the productions: // implicit_document ::= block_node DOCUMENT-END* // ************* // explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* // func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { return false } start_mark := token.start_mark end_mark := token.start_mark implicit := true if token.typ == yaml_DOCUMENT_END_TOKEN { end_mark = token.end_mark skip_token(parser) implicit = false } parser.tag_directives = parser.tag_directives[:0] parser.state = yaml_PARSE_DOCUMENT_START_STATE *event = yaml_event_t{ typ: yaml_DOCUMENT_END_EVENT, start_mark: start_mark, end_mark: end_mark, implicit: implicit, } return true } // Parse the productions: // block_node_or_indentless_sequence ::= // ALIAS // ***** // | properties (block_content | indentless_block_sequence)? // ********** * // | block_content | indentless_block_sequence // * // block_node ::= ALIAS // ***** // | properties block_content? // ********** * // | block_content // * // flow_node ::= ALIAS // ***** // | properties flow_content? // ********** * // | flow_content // * // properties ::= TAG ANCHOR? | ANCHOR TAG? // ************************* // block_content ::= block_collection | flow_collection | SCALAR // ****** // flow_content ::= flow_collection | SCALAR // ****** func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool { //defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)() token := peek_token(parser) if token == nil { return false } if token.typ == yaml_ALIAS_TOKEN { parser.state = parser.states[len(parser.states)-1] parser.states = parser.states[:len(parser.states)-1] *event = yaml_event_t{ typ: yaml_ALIAS_EVENT, start_mark: token.start_mark, end_mark: token.end_mark, anchor: token.value, } skip_token(parser) return true } start_mark := token.start_mark end_mark := token.start_mark var tag_token bool var tag_handle, tag_suffix, anchor []byte var tag_mark yaml_mark_t if token.typ == yaml_ANCHOR_TOKEN { anchor = token.value start_mark = token.start_mark end_mark = token.end_mark skip_token(parser) token = peek_token(parser) if token == nil { return false } if token.typ == yaml_TAG_TOKEN { tag_token = true tag_handle = token.value tag_suffix = token.suffix tag_mark = token.start_mark end_mark = token.end_mark skip_token(parser) token = peek_token(parser) if token == nil { return false } } } else if token.typ == yaml_TAG_TOKEN { tag_token = true tag_handle = token.value tag_suffix = token.suffix start_mark = token.start_mark tag_mark = token.start_mark end_mark = token.end_mark skip_token(parser) token = peek_token(parser) if token == nil { return false } if token.typ == yaml_ANCHOR_TOKEN { anchor = token.value end_mark = token.end_mark skip_token(parser) token = peek_token(parser) if token == nil { return false } } } var tag []byte if tag_token { if len(tag_handle) == 0 { tag = tag_suffix tag_suffix = nil } else { for i := range parser.tag_directives { if bytes.Equal(parser.tag_directives[i].handle, tag_handle) { tag = append([]byte(nil), parser.tag_directives[i].prefix...) tag = append(tag, tag_suffix...) break } } if len(tag) == 0 { yaml_parser_set_parser_error_context(parser, "while parsing a node", start_mark, "found undefined tag handle", tag_mark) return false } } } implicit := len(tag) == 0 if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN { end_mark = token.end_mark parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE *event = yaml_event_t{ typ: yaml_SEQUENCE_START_EVENT, start_mark: start_mark, end_mark: end_mark, anchor: anchor, tag: tag, implicit: implicit, style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), } return true } if token.typ == yaml_SCALAR_TOKEN { var plain_implicit, quoted_implicit bool end_mark = token.end_mark if (len(tag) == 0 && token.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') { plain_implicit = true } else if len(tag) == 0 { quoted_implicit = true } parser.state = parser.states[len(parser.states)-1] parser.states = parser.states[:len(parser.states)-1] *event = yaml_event_t{ typ: yaml_SCALAR_EVENT, start_mark: start_mark, end_mark: end_mark, anchor: anchor, tag: tag, value: token.value, implicit: plain_implicit, quoted_implicit: quoted_implicit, style: yaml_style_t(token.style), } skip_token(parser) return true } if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN { // [Go] Some of the events below can be merged as they differ only on style. end_mark = token.end_mark parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE *event = yaml_event_t{ typ: yaml_SEQUENCE_START_EVENT, start_mark: start_mark, end_mark: end_mark, anchor: anchor, tag: tag, implicit: implicit, style: yaml_style_t(yaml_FLOW_SEQUENCE_STYLE), } return true } if token.typ == yaml_FLOW_MAPPING_START_TOKEN { end_mark = token.end_mark parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE *event = yaml_event_t{ typ: yaml_MAPPING_START_EVENT, start_mark: start_mark, end_mark: end_mark, anchor: anchor, tag: tag, implicit: implicit, style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), } return true } if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN { end_mark = token.end_mark parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE *event = yaml_event_t{ typ: yaml_SEQUENCE_START_EVENT, start_mark: start_mark, end_mark: end_mark, anchor: anchor, tag: tag, implicit: implicit, style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), } return true } if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN { end_mark = token.end_mark parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE *event = yaml_event_t{ typ: yaml_MAPPING_START_EVENT, start_mark: start_mark, end_mark: end_mark, anchor: anchor, tag: tag, implicit: implicit, style: yaml_style_t(yaml_BLOCK_MAPPING_STYLE), } return true } if len(anchor) > 0 || len(tag) > 0 { parser.state = parser.states[len(parser.states)-1] parser.states = parser.states[:len(parser.states)-1] *event = yaml_event_t{ typ: yaml_SCALAR_EVENT, start_mark: start_mark, end_mark: end_mark, anchor: anchor, tag: tag, implicit: implicit, quoted_implicit: false, style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), } return true } context := "while parsing a flow node" if block { context = "while parsing a block node" } yaml_parser_set_parser_error_context(parser, context, start_mark, "did not find expected node content", token.start_mark) return false } // Parse the productions: // block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END // ******************** *********** * ********* // func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { if first { token := peek_token(parser) parser.marks = append(parser.marks, token.start_mark) skip_token(parser) } token := peek_token(parser) if token == nil { return false } if token.typ == yaml_BLOCK_ENTRY_TOKEN { mark := token.end_mark skip_token(parser) token = peek_token(parser) if token == nil { return false } if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN { parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE) return yaml_parser_parse_node(parser, event, true, false) } else { parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE return yaml_parser_process_empty_scalar(parser, event, mark) } } if token.typ == yaml_BLOCK_END_TOKEN { parser.state = parser.states[len(parser.states)-1] parser.states = parser.states[:len(parser.states)-1] parser.marks = parser.marks[:len(parser.marks)-1] *event = yaml_event_t{ typ: yaml_SEQUENCE_END_EVENT, start_mark: token.start_mark, end_mark: token.end_mark, } skip_token(parser) return true } context_mark := parser.marks[len(parser.marks)-1] parser.marks = parser.marks[:len(parser.marks)-1] return yaml_parser_set_parser_error_context(parser, "while parsing a block collection", context_mark, "did not find expected '-' indicator", token.start_mark) } // Parse the productions: // indentless_sequence ::= (BLOCK-ENTRY block_node?)+ // *********** * func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { return false } if token.typ == yaml_BLOCK_ENTRY_TOKEN { mark := token.end_mark skip_token(parser) token = peek_token(parser) if token == nil { return false } if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_KEY_TOKEN && token.typ != yaml_VALUE_TOKEN && token.typ != yaml_BLOCK_END_TOKEN { parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE) return yaml_parser_parse_node(parser, event, true, false) } parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE return yaml_parser_process_empty_scalar(parser, event, mark) } parser.state = parser.states[len(parser.states)-1] parser.states = parser.states[:len(parser.states)-1] *event = yaml_event_t{ typ: yaml_SEQUENCE_END_EVENT, start_mark: token.start_mark, end_mark: token.start_mark, // [Go] Shouldn't this be token.end_mark? } return true } // Parse the productions: // block_mapping ::= BLOCK-MAPPING_START // ******************* // ((KEY block_node_or_indentless_sequence?)? // *** * // (VALUE block_node_or_indentless_sequence?)?)* // // BLOCK-END // ********* // func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { if first { token := peek_token(parser) parser.marks = append(parser.marks, token.start_mark) skip_token(parser) } token := peek_token(parser) if token == nil { return false } if token.typ == yaml_KEY_TOKEN { mark := token.end_mark skip_token(parser) token = peek_token(parser) if token == nil { return false } if token.typ != yaml_KEY_TOKEN && token.typ != yaml_VALUE_TOKEN && token.typ != yaml_BLOCK_END_TOKEN { parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE) return yaml_parser_parse_node(parser, event, true, true) } else { parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE return yaml_parser_process_empty_scalar(parser, event, mark) } } else if token.typ == yaml_BLOCK_END_TOKEN { parser.state = parser.states[len(parser.states)-1] parser.states = parser.states[:len(parser.states)-1] parser.marks = parser.marks[:len(parser.marks)-1] *event = yaml_event_t{ typ: yaml_MAPPING_END_EVENT, start_mark: token.start_mark, end_mark: token.end_mark, } skip_token(parser) return true } context_mark := parser.marks[len(parser.marks)-1] parser.marks = parser.marks[:len(parser.marks)-1] return yaml_parser_set_parser_error_context(parser, "while parsing a block mapping", context_mark, "did not find expected key", token.start_mark) } // Parse the productions: // block_mapping ::= BLOCK-MAPPING_START // // ((KEY block_node_or_indentless_sequence?)? // // (VALUE block_node_or_indentless_sequence?)?)* // ***** * // BLOCK-END // // func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { return false } if token.typ == yaml_VALUE_TOKEN { mark := token.end_mark skip_token(parser) token = peek_token(parser) if token == nil { return false } if token.typ != yaml_KEY_TOKEN && token.typ != yaml_VALUE_TOKEN && token.typ != yaml_BLOCK_END_TOKEN { parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE) return yaml_parser_parse_node(parser, event, true, true) } parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE return yaml_parser_process_empty_scalar(parser, event, mark) } parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE return yaml_parser_process_empty_scalar(parser, event, token.start_mark) } // Parse the productions: // flow_sequence ::= FLOW-SEQUENCE-START // ******************* // (flow_sequence_entry FLOW-ENTRY)* // * ********** // flow_sequence_entry? // * // FLOW-SEQUENCE-END // ***************** // flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? // * // func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { if first { token := peek_token(parser) parser.marks = append(parser.marks, token.start_mark) skip_token(parser) } token := peek_token(parser) if token == nil { return false } if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { if !first { if token.typ == yaml_FLOW_ENTRY_TOKEN { skip_token(parser) token = peek_token(parser) if token == nil { return false } } else { context_mark := parser.marks[len(parser.marks)-1] parser.marks = parser.marks[:len(parser.marks)-1] return yaml_parser_set_parser_error_context(parser, "while parsing a flow sequence", context_mark, "did not find expected ',' or ']'", token.start_mark) } } if token.typ == yaml_KEY_TOKEN { parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE *event = yaml_event_t{ typ: yaml_MAPPING_START_EVENT, start_mark: token.start_mark, end_mark: token.end_mark, implicit: true, style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), } skip_token(parser) return true } else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE) return yaml_parser_parse_node(parser, event, false, false) } } parser.state = parser.states[len(parser.states)-1] parser.states = parser.states[:len(parser.states)-1] parser.marks = parser.marks[:len(parser.marks)-1] *event = yaml_event_t{ typ: yaml_SEQUENCE_END_EVENT, start_mark: token.start_mark, end_mark: token.end_mark, } skip_token(parser) return true } // // Parse the productions: // flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? // *** * // func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { return false } if token.typ != yaml_VALUE_TOKEN && token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE) return yaml_parser_parse_node(parser, event, false, false) } mark := token.end_mark skip_token(parser) parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE return yaml_parser_process_empty_scalar(parser, event, mark) } // Parse the productions: // flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? // ***** * // func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { return false } if token.typ == yaml_VALUE_TOKEN { skip_token(parser) token := peek_token(parser) if token == nil { return false } if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE) return yaml_parser_parse_node(parser, event, false, false) } } parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE return yaml_parser_process_empty_scalar(parser, event, token.start_mark) } // Parse the productions: // flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? // * // func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { return false } parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE *event = yaml_event_t{ typ: yaml_MAPPING_END_EVENT, start_mark: token.start_mark, end_mark: token.start_mark, // [Go] Shouldn't this be end_mark? } return true } // Parse the productions: // flow_mapping ::= FLOW-MAPPING-START // ****************** // (flow_mapping_entry FLOW-ENTRY)* // * ********** // flow_mapping_entry? // ****************** // FLOW-MAPPING-END // **************** // flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? // * *** * // func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { if first { token := peek_token(parser) parser.marks = append(parser.marks, token.start_mark) skip_token(parser) } token := peek_token(parser) if token == nil { return false } if token.typ != yaml_FLOW_MAPPING_END_TOKEN { if !first { if token.typ == yaml_FLOW_ENTRY_TOKEN { skip_token(parser) token = peek_token(parser) if token == nil { return false } } else { context_mark := parser.marks[len(parser.marks)-1] parser.marks = parser.marks[:len(parser.marks)-1] return yaml_parser_set_parser_error_context(parser, "while parsing a flow mapping", context_mark, "did not find expected ',' or '}'", token.start_mark) } } if token.typ == yaml_KEY_TOKEN { skip_token(parser) token = peek_token(parser) if token == nil { return false } if token.typ != yaml_VALUE_TOKEN && token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN { parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE) return yaml_parser_parse_node(parser, event, false, false) } else { parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE return yaml_parser_process_empty_scalar(parser, event, token.start_mark) } } else if token.typ != yaml_FLOW_MAPPING_END_TOKEN { parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE) return yaml_parser_parse_node(parser, event, false, false) } } parser.state = parser.states[len(parser.states)-1] parser.states = parser.states[:len(parser.states)-1] parser.marks = parser.marks[:len(parser.marks)-1] *event = yaml_event_t{ typ: yaml_MAPPING_END_EVENT, start_mark: token.start_mark, end_mark: token.end_mark, } skip_token(parser) return true } // Parse the productions: // flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? // * ***** * // func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool { token := peek_token(parser) if token == nil { return false } if empty { parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE return yaml_parser_process_empty_scalar(parser, event, token.start_mark) } if token.typ == yaml_VALUE_TOKEN { skip_token(parser) token = peek_token(parser) if token == nil { return false } if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN { parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE) return yaml_parser_parse_node(parser, event, false, false) } } parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE return yaml_parser_process_empty_scalar(parser, event, token.start_mark) } // Generate an empty scalar event. func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool { *event = yaml_event_t{ typ: yaml_SCALAR_EVENT, start_mark: mark, end_mark: mark, value: nil, // Empty implicit: true, style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), } return true } var default_tag_directives = []yaml_tag_directive_t{ {[]byte("!"), []byte("!")}, {[]byte("!!"), []byte("tag:yaml.org,2002:")}, } // Parse directives. func yaml_parser_process_directives(parser *yaml_parser_t, version_directive_ref **yaml_version_directive_t, tag_directives_ref *[]yaml_tag_directive_t) bool { var version_directive *yaml_version_directive_t var tag_directives []yaml_tag_directive_t token := peek_token(parser) if token == nil { return false } for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN { if token.typ == yaml_VERSION_DIRECTIVE_TOKEN { if version_directive != nil { yaml_parser_set_parser_error(parser, "found duplicate %YAML directive", token.start_mark) return false } if token.major != 1 || token.minor != 1 { yaml_parser_set_parser_error(parser, "found incompatible YAML document", token.start_mark) return false } version_directive = &yaml_version_directive_t{ major: token.major, minor: token.minor, } } else if token.typ == yaml_TAG_DIRECTIVE_TOKEN { value := yaml_tag_directive_t{ handle: token.value, prefix: token.prefix, } if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) { return false } tag_directives = append(tag_directives, value) } skip_token(parser) token = peek_token(parser) if token == nil { return false } } for i := range default_tag_directives { if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) { return false } } if version_directive_ref != nil { *version_directive_ref = version_directive } if tag_directives_ref != nil { *tag_directives_ref = tag_directives } return true } // Append a tag directive to the directives stack. func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool { for i := range parser.tag_directives { if bytes.Equal(value.handle, parser.tag_directives[i].handle) { if allow_duplicates { return true } return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark) } } // [Go] I suspect the copy is unnecessary. This was likely done // because there was no way to track ownership of the data. value_copy := yaml_tag_directive_t{ handle: make([]byte, len(value.handle)), prefix: make([]byte, len(value.prefix)), } copy(value_copy.handle, value.handle) copy(value_copy.prefix, value.prefix) parser.tag_directives = append(parser.tag_directives, value_copy) return true } ================================================ FILE: vendor/gopkg.in/yaml.v2/readerc.go ================================================ package yaml import ( "io" ) // Set the reader error and return 0. func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool { parser.error = yaml_READER_ERROR parser.problem = problem parser.problem_offset = offset parser.problem_value = value return false } // Byte order marks. const ( bom_UTF8 = "\xef\xbb\xbf" bom_UTF16LE = "\xff\xfe" bom_UTF16BE = "\xfe\xff" ) // Determine the input stream encoding by checking the BOM symbol. If no BOM is // found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. func yaml_parser_determine_encoding(parser *yaml_parser_t) bool { // Ensure that we had enough bytes in the raw buffer. for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 { if !yaml_parser_update_raw_buffer(parser) { return false } } // Determine the encoding. buf := parser.raw_buffer pos := parser.raw_buffer_pos avail := len(buf) - pos if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] { parser.encoding = yaml_UTF16LE_ENCODING parser.raw_buffer_pos += 2 parser.offset += 2 } else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] { parser.encoding = yaml_UTF16BE_ENCODING parser.raw_buffer_pos += 2 parser.offset += 2 } else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] { parser.encoding = yaml_UTF8_ENCODING parser.raw_buffer_pos += 3 parser.offset += 3 } else { parser.encoding = yaml_UTF8_ENCODING } return true } // Update the raw buffer. func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool { size_read := 0 // Return if the raw buffer is full. if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) { return true } // Return on EOF. if parser.eof { return true } // Move the remaining bytes in the raw buffer to the beginning. if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) { copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:]) } parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos] parser.raw_buffer_pos = 0 // Call the read handler to fill the buffer. size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)]) parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read] if err == io.EOF { parser.eof = true } else if err != nil { return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1) } return true } // Ensure that the buffer contains at least `length` characters. // Return true on success, false on failure. // // The length is supposed to be significantly less that the buffer size. func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool { if parser.read_handler == nil { panic("read handler must be set") } // [Go] This function was changed to guarantee the requested length size at EOF. // The fact we need to do this is pretty awful, but the description above implies // for that to be the case, and there are tests // If the EOF flag is set and the raw buffer is empty, do nothing. if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) { // [Go] ACTUALLY! Read the documentation of this function above. // This is just broken. To return true, we need to have the // given length in the buffer. Not doing that means every single // check that calls this function to make sure the buffer has a // given length is Go) panicking; or C) accessing invalid memory. //return true } // Return if the buffer contains enough characters. if parser.unread >= length { return true } // Determine the input encoding if it is not known yet. if parser.encoding == yaml_ANY_ENCODING { if !yaml_parser_determine_encoding(parser) { return false } } // Move the unread characters to the beginning of the buffer. buffer_len := len(parser.buffer) if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len { copy(parser.buffer, parser.buffer[parser.buffer_pos:]) buffer_len -= parser.buffer_pos parser.buffer_pos = 0 } else if parser.buffer_pos == buffer_len { buffer_len = 0 parser.buffer_pos = 0 } // Open the whole buffer for writing, and cut it before returning. parser.buffer = parser.buffer[:cap(parser.buffer)] // Fill the buffer until it has enough characters. first := true for parser.unread < length { // Fill the raw buffer if necessary. if !first || parser.raw_buffer_pos == len(parser.raw_buffer) { if !yaml_parser_update_raw_buffer(parser) { parser.buffer = parser.buffer[:buffer_len] return false } } first = false // Decode the raw buffer. inner: for parser.raw_buffer_pos != len(parser.raw_buffer) { var value rune var width int raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos // Decode the next character. switch parser.encoding { case yaml_UTF8_ENCODING: // Decode a UTF-8 character. Check RFC 3629 // (http://www.ietf.org/rfc/rfc3629.txt) for more details. // // The following table (taken from the RFC) is used for // decoding. // // Char. number range | UTF-8 octet sequence // (hexadecimal) | (binary) // --------------------+------------------------------------ // 0000 0000-0000 007F | 0xxxxxxx // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // // Additionally, the characters in the range 0xD800-0xDFFF // are prohibited as they are reserved for use with UTF-16 // surrogate pairs. // Determine the length of the UTF-8 sequence. octet := parser.raw_buffer[parser.raw_buffer_pos] switch { case octet&0x80 == 0x00: width = 1 case octet&0xE0 == 0xC0: width = 2 case octet&0xF0 == 0xE0: width = 3 case octet&0xF8 == 0xF0: width = 4 default: // The leading octet is invalid. return yaml_parser_set_reader_error(parser, "invalid leading UTF-8 octet", parser.offset, int(octet)) } // Check if the raw buffer contains an incomplete character. if width > raw_unread { if parser.eof { return yaml_parser_set_reader_error(parser, "incomplete UTF-8 octet sequence", parser.offset, -1) } break inner } // Decode the leading octet. switch { case octet&0x80 == 0x00: value = rune(octet & 0x7F) case octet&0xE0 == 0xC0: value = rune(octet & 0x1F) case octet&0xF0 == 0xE0: value = rune(octet & 0x0F) case octet&0xF8 == 0xF0: value = rune(octet & 0x07) default: value = 0 } // Check and decode the trailing octets. for k := 1; k < width; k++ { octet = parser.raw_buffer[parser.raw_buffer_pos+k] // Check if the octet is valid. if (octet & 0xC0) != 0x80 { return yaml_parser_set_reader_error(parser, "invalid trailing UTF-8 octet", parser.offset+k, int(octet)) } // Decode the octet. value = (value << 6) + rune(octet&0x3F) } // Check the length of the sequence against the value. switch { case width == 1: case width == 2 && value >= 0x80: case width == 3 && value >= 0x800: case width == 4 && value >= 0x10000: default: return yaml_parser_set_reader_error(parser, "invalid length of a UTF-8 sequence", parser.offset, -1) } // Check the range of the value. if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF { return yaml_parser_set_reader_error(parser, "invalid Unicode character", parser.offset, int(value)) } case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING: var low, high int if parser.encoding == yaml_UTF16LE_ENCODING { low, high = 0, 1 } else { low, high = 1, 0 } // The UTF-16 encoding is not as simple as one might // naively think. Check RFC 2781 // (http://www.ietf.org/rfc/rfc2781.txt). // // Normally, two subsequent bytes describe a Unicode // character. However a special technique (called a // surrogate pair) is used for specifying character // values larger than 0xFFFF. // // A surrogate pair consists of two pseudo-characters: // high surrogate area (0xD800-0xDBFF) // low surrogate area (0xDC00-0xDFFF) // // The following formulas are used for decoding // and encoding characters using surrogate pairs: // // U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF) // U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF) // W1 = 110110yyyyyyyyyy // W2 = 110111xxxxxxxxxx // // where U is the character value, W1 is the high surrogate // area, W2 is the low surrogate area. // Check for incomplete UTF-16 character. if raw_unread < 2 { if parser.eof { return yaml_parser_set_reader_error(parser, "incomplete UTF-16 character", parser.offset, -1) } break inner } // Get the character. value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) + (rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8) // Check for unexpected low surrogate area. if value&0xFC00 == 0xDC00 { return yaml_parser_set_reader_error(parser, "unexpected low surrogate area", parser.offset, int(value)) } // Check for a high surrogate area. if value&0xFC00 == 0xD800 { width = 4 // Check for incomplete surrogate pair. if raw_unread < 4 { if parser.eof { return yaml_parser_set_reader_error(parser, "incomplete UTF-16 surrogate pair", parser.offset, -1) } break inner } // Get the next character. value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) + (rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8) // Check for a low surrogate area. if value2&0xFC00 != 0xDC00 { return yaml_parser_set_reader_error(parser, "expected low surrogate area", parser.offset+2, int(value2)) } // Generate the value of the surrogate pair. value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF) } else { width = 2 } default: panic("impossible") } // Check if the character is in the allowed range: // #x9 | #xA | #xD | [#x20-#x7E] (8 bit) // | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit) // | [#x10000-#x10FFFF] (32 bit) switch { case value == 0x09: case value == 0x0A: case value == 0x0D: case value >= 0x20 && value <= 0x7E: case value == 0x85: case value >= 0xA0 && value <= 0xD7FF: case value >= 0xE000 && value <= 0xFFFD: case value >= 0x10000 && value <= 0x10FFFF: default: return yaml_parser_set_reader_error(parser, "control characters are not allowed", parser.offset, int(value)) } // Move the raw pointers. parser.raw_buffer_pos += width parser.offset += width // Finally put the character into the buffer. if value <= 0x7F { // 0000 0000-0000 007F . 0xxxxxxx parser.buffer[buffer_len+0] = byte(value) buffer_len += 1 } else if value <= 0x7FF { // 0000 0080-0000 07FF . 110xxxxx 10xxxxxx parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6)) parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F)) buffer_len += 2 } else if value <= 0xFFFF { // 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12)) parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F)) parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F)) buffer_len += 3 } else { // 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18)) parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F)) parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F)) parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F)) buffer_len += 4 } parser.unread++ } // On EOF, put NUL into the buffer and return. if parser.eof { parser.buffer[buffer_len] = 0 buffer_len++ parser.unread++ break } } // [Go] Read the documentation of this function above. To return true, // we need to have the given length in the buffer. Not doing that means // every single check that calls this function to make sure the buffer // has a given length is Go) panicking; or C) accessing invalid memory. // This happens here due to the EOF above breaking early. for buffer_len < length { parser.buffer[buffer_len] = 0 buffer_len++ } parser.buffer = parser.buffer[:buffer_len] return true } ================================================ FILE: vendor/gopkg.in/yaml.v2/resolve.go ================================================ package yaml import ( "encoding/base64" "math" "regexp" "strconv" "strings" "time" ) type resolveMapItem struct { value interface{} tag string } var resolveTable = make([]byte, 256) var resolveMap = make(map[string]resolveMapItem) func init() { t := resolveTable t[int('+')] = 'S' // Sign t[int('-')] = 'S' for _, c := range "0123456789" { t[int(c)] = 'D' // Digit } for _, c := range "yYnNtTfFoO~" { t[int(c)] = 'M' // In map } t[int('.')] = '.' // Float (potentially in map) var resolveMapList = []struct { v interface{} tag string l []string }{ {true, yaml_BOOL_TAG, []string{"y", "Y", "yes", "Yes", "YES"}}, {true, yaml_BOOL_TAG, []string{"true", "True", "TRUE"}}, {true, yaml_BOOL_TAG, []string{"on", "On", "ON"}}, {false, yaml_BOOL_TAG, []string{"n", "N", "no", "No", "NO"}}, {false, yaml_BOOL_TAG, []string{"false", "False", "FALSE"}}, {false, yaml_BOOL_TAG, []string{"off", "Off", "OFF"}}, {nil, yaml_NULL_TAG, []string{"", "~", "null", "Null", "NULL"}}, {math.NaN(), yaml_FLOAT_TAG, []string{".nan", ".NaN", ".NAN"}}, {math.Inf(+1), yaml_FLOAT_TAG, []string{".inf", ".Inf", ".INF"}}, {math.Inf(+1), yaml_FLOAT_TAG, []string{"+.inf", "+.Inf", "+.INF"}}, {math.Inf(-1), yaml_FLOAT_TAG, []string{"-.inf", "-.Inf", "-.INF"}}, {"<<", yaml_MERGE_TAG, []string{"<<"}}, } m := resolveMap for _, item := range resolveMapList { for _, s := range item.l { m[s] = resolveMapItem{item.v, item.tag} } } } const longTagPrefix = "tag:yaml.org,2002:" func shortTag(tag string) string { // TODO This can easily be made faster and produce less garbage. if strings.HasPrefix(tag, longTagPrefix) { return "!!" + tag[len(longTagPrefix):] } return tag } func longTag(tag string) string { if strings.HasPrefix(tag, "!!") { return longTagPrefix + tag[2:] } return tag } func resolvableTag(tag string) bool { switch tag { case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG, yaml_TIMESTAMP_TAG: return true } return false } var yamlStyleFloat = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+][0-9]+)?$`) func resolve(tag string, in string) (rtag string, out interface{}) { if !resolvableTag(tag) { return tag, in } defer func() { switch tag { case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG: return case yaml_FLOAT_TAG: if rtag == yaml_INT_TAG { switch v := out.(type) { case int64: rtag = yaml_FLOAT_TAG out = float64(v) return case int: rtag = yaml_FLOAT_TAG out = float64(v) return } } } failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag)) }() // Any data is accepted as a !!str or !!binary. // Otherwise, the prefix is enough of a hint about what it might be. hint := byte('N') if in != "" { hint = resolveTable[in[0]] } if hint != 0 && tag != yaml_STR_TAG && tag != yaml_BINARY_TAG { // Handle things we can lookup in a map. if item, ok := resolveMap[in]; ok { return item.tag, item.value } // Base 60 floats are a bad idea, were dropped in YAML 1.2, and // are purposefully unsupported here. They're still quoted on // the way out for compatibility with other parser, though. switch hint { case 'M': // We've already checked the map above. case '.': // Not in the map, so maybe a normal float. floatv, err := strconv.ParseFloat(in, 64) if err == nil { return yaml_FLOAT_TAG, floatv } case 'D', 'S': // Int, float, or timestamp. // Only try values as a timestamp if the value is unquoted or there's an explicit // !!timestamp tag. if tag == "" || tag == yaml_TIMESTAMP_TAG { t, ok := parseTimestamp(in) if ok { return yaml_TIMESTAMP_TAG, t } } plain := strings.Replace(in, "_", "", -1) intv, err := strconv.ParseInt(plain, 0, 64) if err == nil { if intv == int64(int(intv)) { return yaml_INT_TAG, int(intv) } else { return yaml_INT_TAG, intv } } uintv, err := strconv.ParseUint(plain, 0, 64) if err == nil { return yaml_INT_TAG, uintv } if yamlStyleFloat.MatchString(plain) { floatv, err := strconv.ParseFloat(plain, 64) if err == nil { return yaml_FLOAT_TAG, floatv } } if strings.HasPrefix(plain, "0b") { intv, err := strconv.ParseInt(plain[2:], 2, 64) if err == nil { if intv == int64(int(intv)) { return yaml_INT_TAG, int(intv) } else { return yaml_INT_TAG, intv } } uintv, err := strconv.ParseUint(plain[2:], 2, 64) if err == nil { return yaml_INT_TAG, uintv } } else if strings.HasPrefix(plain, "-0b") { intv, err := strconv.ParseInt("-" + plain[3:], 2, 64) if err == nil { if true || intv == int64(int(intv)) { return yaml_INT_TAG, int(intv) } else { return yaml_INT_TAG, intv } } } default: panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")") } } return yaml_STR_TAG, in } // encodeBase64 encodes s as base64 that is broken up into multiple lines // as appropriate for the resulting length. func encodeBase64(s string) string { const lineLen = 70 encLen := base64.StdEncoding.EncodedLen(len(s)) lines := encLen/lineLen + 1 buf := make([]byte, encLen*2+lines) in := buf[0:encLen] out := buf[encLen:] base64.StdEncoding.Encode(in, []byte(s)) k := 0 for i := 0; i < len(in); i += lineLen { j := i + lineLen if j > len(in) { j = len(in) } k += copy(out[k:], in[i:j]) if lines > 1 { out[k] = '\n' k++ } } return string(out[:k]) } // This is a subset of the formats allowed by the regular expression // defined at http://yaml.org/type/timestamp.html. var allowedTimestampFormats = []string{ "2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields. "2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t". "2006-1-2 15:4:5.999999999", // space separated with no time zone "2006-1-2", // date only // Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5" // from the set of examples. } // parseTimestamp parses s as a timestamp string and // returns the timestamp and reports whether it succeeded. // Timestamp formats are defined at http://yaml.org/type/timestamp.html func parseTimestamp(s string) (time.Time, bool) { // TODO write code to check all the formats supported by // http://yaml.org/type/timestamp.html instead of using time.Parse. // Quick check: all date formats start with YYYY-. i := 0 for ; i < len(s); i++ { if c := s[i]; c < '0' || c > '9' { break } } if i != 4 || i == len(s) || s[i] != '-' { return time.Time{}, false } for _, format := range allowedTimestampFormats { if t, err := time.Parse(format, s); err == nil { return t, true } } return time.Time{}, false } ================================================ FILE: vendor/gopkg.in/yaml.v2/scannerc.go ================================================ package yaml import ( "bytes" "fmt" ) // Introduction // ************ // // The following notes assume that you are familiar with the YAML specification // (http://yaml.org/spec/1.2/spec.html). We mostly follow it, although in // some cases we are less restrictive that it requires. // // The process of transforming a YAML stream into a sequence of events is // divided on two steps: Scanning and Parsing. // // The Scanner transforms the input stream into a sequence of tokens, while the // parser transform the sequence of tokens produced by the Scanner into a // sequence of parsing events. // // The Scanner is rather clever and complicated. The Parser, on the contrary, // is a straightforward implementation of a recursive-descendant parser (or, // LL(1) parser, as it is usually called). // // Actually there are two issues of Scanning that might be called "clever", the // rest is quite straightforward. The issues are "block collection start" and // "simple keys". Both issues are explained below in details. // // Here the Scanning step is explained and implemented. We start with the list // of all the tokens produced by the Scanner together with short descriptions. // // Now, tokens: // // STREAM-START(encoding) # The stream start. // STREAM-END # The stream end. // VERSION-DIRECTIVE(major,minor) # The '%YAML' directive. // TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive. // DOCUMENT-START # '---' // DOCUMENT-END # '...' // BLOCK-SEQUENCE-START # Indentation increase denoting a block // BLOCK-MAPPING-START # sequence or a block mapping. // BLOCK-END # Indentation decrease. // FLOW-SEQUENCE-START # '[' // FLOW-SEQUENCE-END # ']' // BLOCK-SEQUENCE-START # '{' // BLOCK-SEQUENCE-END # '}' // BLOCK-ENTRY # '-' // FLOW-ENTRY # ',' // KEY # '?' or nothing (simple keys). // VALUE # ':' // ALIAS(anchor) # '*anchor' // ANCHOR(anchor) # '&anchor' // TAG(handle,suffix) # '!handle!suffix' // SCALAR(value,style) # A scalar. // // The following two tokens are "virtual" tokens denoting the beginning and the // end of the stream: // // STREAM-START(encoding) // STREAM-END // // We pass the information about the input stream encoding with the // STREAM-START token. // // The next two tokens are responsible for tags: // // VERSION-DIRECTIVE(major,minor) // TAG-DIRECTIVE(handle,prefix) // // Example: // // %YAML 1.1 // %TAG ! !foo // %TAG !yaml! tag:yaml.org,2002: // --- // // The correspoding sequence of tokens: // // STREAM-START(utf-8) // VERSION-DIRECTIVE(1,1) // TAG-DIRECTIVE("!","!foo") // TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:") // DOCUMENT-START // STREAM-END // // Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole // line. // // The document start and end indicators are represented by: // // DOCUMENT-START // DOCUMENT-END // // Note that if a YAML stream contains an implicit document (without '---' // and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be // produced. // // In the following examples, we present whole documents together with the // produced tokens. // // 1. An implicit document: // // 'a scalar' // // Tokens: // // STREAM-START(utf-8) // SCALAR("a scalar",single-quoted) // STREAM-END // // 2. An explicit document: // // --- // 'a scalar' // ... // // Tokens: // // STREAM-START(utf-8) // DOCUMENT-START // SCALAR("a scalar",single-quoted) // DOCUMENT-END // STREAM-END // // 3. Several documents in a stream: // // 'a scalar' // --- // 'another scalar' // --- // 'yet another scalar' // // Tokens: // // STREAM-START(utf-8) // SCALAR("a scalar",single-quoted) // DOCUMENT-START // SCALAR("another scalar",single-quoted) // DOCUMENT-START // SCALAR("yet another scalar",single-quoted) // STREAM-END // // We have already introduced the SCALAR token above. The following tokens are // used to describe aliases, anchors, tag, and scalars: // // ALIAS(anchor) // ANCHOR(anchor) // TAG(handle,suffix) // SCALAR(value,style) // // The following series of examples illustrate the usage of these tokens: // // 1. A recursive sequence: // // &A [ *A ] // // Tokens: // // STREAM-START(utf-8) // ANCHOR("A") // FLOW-SEQUENCE-START // ALIAS("A") // FLOW-SEQUENCE-END // STREAM-END // // 2. A tagged scalar: // // !!float "3.14" # A good approximation. // // Tokens: // // STREAM-START(utf-8) // TAG("!!","float") // SCALAR("3.14",double-quoted) // STREAM-END // // 3. Various scalar styles: // // --- # Implicit empty plain scalars do not produce tokens. // --- a plain scalar // --- 'a single-quoted scalar' // --- "a double-quoted scalar" // --- |- // a literal scalar // --- >- // a folded // scalar // // Tokens: // // STREAM-START(utf-8) // DOCUMENT-START // DOCUMENT-START // SCALAR("a plain scalar",plain) // DOCUMENT-START // SCALAR("a single-quoted scalar",single-quoted) // DOCUMENT-START // SCALAR("a double-quoted scalar",double-quoted) // DOCUMENT-START // SCALAR("a literal scalar",literal) // DOCUMENT-START // SCALAR("a folded scalar",folded) // STREAM-END // // Now it's time to review collection-related tokens. We will start with // flow collections: // // FLOW-SEQUENCE-START // FLOW-SEQUENCE-END // FLOW-MAPPING-START // FLOW-MAPPING-END // FLOW-ENTRY // KEY // VALUE // // The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and // FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}' // correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the // indicators '?' and ':', which are used for denoting mapping keys and values, // are represented by the KEY and VALUE tokens. // // The following examples show flow collections: // // 1. A flow sequence: // // [item 1, item 2, item 3] // // Tokens: // // STREAM-START(utf-8) // FLOW-SEQUENCE-START // SCALAR("item 1",plain) // FLOW-ENTRY // SCALAR("item 2",plain) // FLOW-ENTRY // SCALAR("item 3",plain) // FLOW-SEQUENCE-END // STREAM-END // // 2. A flow mapping: // // { // a simple key: a value, # Note that the KEY token is produced. // ? a complex key: another value, // } // // Tokens: // // STREAM-START(utf-8) // FLOW-MAPPING-START // KEY // SCALAR("a simple key",plain) // VALUE // SCALAR("a value",plain) // FLOW-ENTRY // KEY // SCALAR("a complex key",plain) // VALUE // SCALAR("another value",plain) // FLOW-ENTRY // FLOW-MAPPING-END // STREAM-END // // A simple key is a key which is not denoted by the '?' indicator. Note that // the Scanner still produce the KEY token whenever it encounters a simple key. // // For scanning block collections, the following tokens are used (note that we // repeat KEY and VALUE here): // // BLOCK-SEQUENCE-START // BLOCK-MAPPING-START // BLOCK-END // BLOCK-ENTRY // KEY // VALUE // // The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation // increase that precedes a block collection (cf. the INDENT token in Python). // The token BLOCK-END denote indentation decrease that ends a block collection // (cf. the DEDENT token in Python). However YAML has some syntax pecularities // that makes detections of these tokens more complex. // // The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators // '-', '?', and ':' correspondingly. // // The following examples show how the tokens BLOCK-SEQUENCE-START, // BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner: // // 1. Block sequences: // // - item 1 // - item 2 // - // - item 3.1 // - item 3.2 // - // key 1: value 1 // key 2: value 2 // // Tokens: // // STREAM-START(utf-8) // BLOCK-SEQUENCE-START // BLOCK-ENTRY // SCALAR("item 1",plain) // BLOCK-ENTRY // SCALAR("item 2",plain) // BLOCK-ENTRY // BLOCK-SEQUENCE-START // BLOCK-ENTRY // SCALAR("item 3.1",plain) // BLOCK-ENTRY // SCALAR("item 3.2",plain) // BLOCK-END // BLOCK-ENTRY // BLOCK-MAPPING-START // KEY // SCALAR("key 1",plain) // VALUE // SCALAR("value 1",plain) // KEY // SCALAR("key 2",plain) // VALUE // SCALAR("value 2",plain) // BLOCK-END // BLOCK-END // STREAM-END // // 2. Block mappings: // // a simple key: a value # The KEY token is produced here. // ? a complex key // : another value // a mapping: // key 1: value 1 // key 2: value 2 // a sequence: // - item 1 // - item 2 // // Tokens: // // STREAM-START(utf-8) // BLOCK-MAPPING-START // KEY // SCALAR("a simple key",plain) // VALUE // SCALAR("a value",plain) // KEY // SCALAR("a complex key",plain) // VALUE // SCALAR("another value",plain) // KEY // SCALAR("a mapping",plain) // BLOCK-MAPPING-START // KEY // SCALAR("key 1",plain) // VALUE // SCALAR("value 1",plain) // KEY // SCALAR("key 2",plain) // VALUE // SCALAR("value 2",plain) // BLOCK-END // KEY // SCALAR("a sequence",plain) // VALUE // BLOCK-SEQUENCE-START // BLOCK-ENTRY // SCALAR("item 1",plain) // BLOCK-ENTRY // SCALAR("item 2",plain) // BLOCK-END // BLOCK-END // STREAM-END // // YAML does not always require to start a new block collection from a new // line. If the current line contains only '-', '?', and ':' indicators, a new // block collection may start at the current line. The following examples // illustrate this case: // // 1. Collections in a sequence: // // - - item 1 // - item 2 // - key 1: value 1 // key 2: value 2 // - ? complex key // : complex value // // Tokens: // // STREAM-START(utf-8) // BLOCK-SEQUENCE-START // BLOCK-ENTRY // BLOCK-SEQUENCE-START // BLOCK-ENTRY // SCALAR("item 1",plain) // BLOCK-ENTRY // SCALAR("item 2",plain) // BLOCK-END // BLOCK-ENTRY // BLOCK-MAPPING-START // KEY // SCALAR("key 1",plain) // VALUE // SCALAR("value 1",plain) // KEY // SCALAR("key 2",plain) // VALUE // SCALAR("value 2",plain) // BLOCK-END // BLOCK-ENTRY // BLOCK-MAPPING-START // KEY // SCALAR("complex key") // VALUE // SCALAR("complex value") // BLOCK-END // BLOCK-END // STREAM-END // // 2. Collections in a mapping: // // ? a sequence // : - item 1 // - item 2 // ? a mapping // : key 1: value 1 // key 2: value 2 // // Tokens: // // STREAM-START(utf-8) // BLOCK-MAPPING-START // KEY // SCALAR("a sequence",plain) // VALUE // BLOCK-SEQUENCE-START // BLOCK-ENTRY // SCALAR("item 1",plain) // BLOCK-ENTRY // SCALAR("item 2",plain) // BLOCK-END // KEY // SCALAR("a mapping",plain) // VALUE // BLOCK-MAPPING-START // KEY // SCALAR("key 1",plain) // VALUE // SCALAR("value 1",plain) // KEY // SCALAR("key 2",plain) // VALUE // SCALAR("value 2",plain) // BLOCK-END // BLOCK-END // STREAM-END // // YAML also permits non-indented sequences if they are included into a block // mapping. In this case, the token BLOCK-SEQUENCE-START is not produced: // // key: // - item 1 # BLOCK-SEQUENCE-START is NOT produced here. // - item 2 // // Tokens: // // STREAM-START(utf-8) // BLOCK-MAPPING-START // KEY // SCALAR("key",plain) // VALUE // BLOCK-ENTRY // SCALAR("item 1",plain) // BLOCK-ENTRY // SCALAR("item 2",plain) // BLOCK-END // // Ensure that the buffer contains the required number of characters. // Return true on success, false on failure (reader error or memory error). func cache(parser *yaml_parser_t, length int) bool { // [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B) return parser.unread >= length || yaml_parser_update_buffer(parser, length) } // Advance the buffer pointer. func skip(parser *yaml_parser_t) { parser.mark.index++ parser.mark.column++ parser.unread-- parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) } func skip_line(parser *yaml_parser_t) { if is_crlf(parser.buffer, parser.buffer_pos) { parser.mark.index += 2 parser.mark.column = 0 parser.mark.line++ parser.unread -= 2 parser.buffer_pos += 2 } else if is_break(parser.buffer, parser.buffer_pos) { parser.mark.index++ parser.mark.column = 0 parser.mark.line++ parser.unread-- parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) } } // Copy a character to a string buffer and advance pointers. func read(parser *yaml_parser_t, s []byte) []byte { w := width(parser.buffer[parser.buffer_pos]) if w == 0 { panic("invalid character sequence") } if len(s) == 0 { s = make([]byte, 0, 32) } if w == 1 && len(s)+w <= cap(s) { s = s[:len(s)+1] s[len(s)-1] = parser.buffer[parser.buffer_pos] parser.buffer_pos++ } else { s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...) parser.buffer_pos += w } parser.mark.index++ parser.mark.column++ parser.unread-- return s } // Copy a line break character to a string buffer and advance pointers. func read_line(parser *yaml_parser_t, s []byte) []byte { buf := parser.buffer pos := parser.buffer_pos switch { case buf[pos] == '\r' && buf[pos+1] == '\n': // CR LF . LF s = append(s, '\n') parser.buffer_pos += 2 parser.mark.index++ parser.unread-- case buf[pos] == '\r' || buf[pos] == '\n': // CR|LF . LF s = append(s, '\n') parser.buffer_pos += 1 case buf[pos] == '\xC2' && buf[pos+1] == '\x85': // NEL . LF s = append(s, '\n') parser.buffer_pos += 2 case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'): // LS|PS . LS|PS s = append(s, buf[parser.buffer_pos:pos+3]...) parser.buffer_pos += 3 default: return s } parser.mark.index++ parser.mark.column = 0 parser.mark.line++ parser.unread-- return s } // Get the next token. func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool { // Erase the token object. *token = yaml_token_t{} // [Go] Is this necessary? // No tokens after STREAM-END or error. if parser.stream_end_produced || parser.error != yaml_NO_ERROR { return true } // Ensure that the tokens queue contains enough tokens. if !parser.token_available { if !yaml_parser_fetch_more_tokens(parser) { return false } } // Fetch the next token from the queue. *token = parser.tokens[parser.tokens_head] parser.tokens_head++ parser.tokens_parsed++ parser.token_available = false if token.typ == yaml_STREAM_END_TOKEN { parser.stream_end_produced = true } return true } // Set the scanner error and return false. func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool { parser.error = yaml_SCANNER_ERROR parser.context = context parser.context_mark = context_mark parser.problem = problem parser.problem_mark = parser.mark return false } func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool { context := "while parsing a tag" if directive { context = "while parsing a %TAG directive" } return yaml_parser_set_scanner_error(parser, context, context_mark, problem) } func trace(args ...interface{}) func() { pargs := append([]interface{}{"+++"}, args...) fmt.Println(pargs...) pargs = append([]interface{}{"---"}, args...) return func() { fmt.Println(pargs...) } } // Ensure that the tokens queue contains at least one token which can be // returned to the Parser. func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool { // While we need more tokens to fetch, do it. for { // Check if we really need to fetch more tokens. need_more_tokens := false if parser.tokens_head == len(parser.tokens) { // Queue is empty. need_more_tokens = true } else { // Check if any potential simple key may occupy the head position. if !yaml_parser_stale_simple_keys(parser) { return false } for i := range parser.simple_keys { simple_key := &parser.simple_keys[i] if simple_key.possible && simple_key.token_number == parser.tokens_parsed { need_more_tokens = true break } } } // We are finished. if !need_more_tokens { break } // Fetch the next token. if !yaml_parser_fetch_next_token(parser) { return false } } parser.token_available = true return true } // The dispatcher for token fetchers. func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool { // Ensure that the buffer is initialized. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } // Check if we just started scanning. Fetch STREAM-START then. if !parser.stream_start_produced { return yaml_parser_fetch_stream_start(parser) } // Eat whitespaces and comments until we reach the next token. if !yaml_parser_scan_to_next_token(parser) { return false } // Remove obsolete potential simple keys. if !yaml_parser_stale_simple_keys(parser) { return false } // Check the indentation level against the current column. if !yaml_parser_unroll_indent(parser, parser.mark.column) { return false } // Ensure that the buffer contains at least 4 characters. 4 is the length // of the longest indicators ('--- ' and '... '). if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { return false } // Is it the end of the stream? if is_z(parser.buffer, parser.buffer_pos) { return yaml_parser_fetch_stream_end(parser) } // Is it a directive? if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' { return yaml_parser_fetch_directive(parser) } buf := parser.buffer pos := parser.buffer_pos // Is it the document start indicator? if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) { return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN) } // Is it the document end indicator? if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) { return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN) } // Is it the flow sequence start indicator? if buf[pos] == '[' { return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN) } // Is it the flow mapping start indicator? if parser.buffer[parser.buffer_pos] == '{' { return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN) } // Is it the flow sequence end indicator? if parser.buffer[parser.buffer_pos] == ']' { return yaml_parser_fetch_flow_collection_end(parser, yaml_FLOW_SEQUENCE_END_TOKEN) } // Is it the flow mapping end indicator? if parser.buffer[parser.buffer_pos] == '}' { return yaml_parser_fetch_flow_collection_end(parser, yaml_FLOW_MAPPING_END_TOKEN) } // Is it the flow entry indicator? if parser.buffer[parser.buffer_pos] == ',' { return yaml_parser_fetch_flow_entry(parser) } // Is it the block entry indicator? if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) { return yaml_parser_fetch_block_entry(parser) } // Is it the key indicator? if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { return yaml_parser_fetch_key(parser) } // Is it the value indicator? if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { return yaml_parser_fetch_value(parser) } // Is it an alias? if parser.buffer[parser.buffer_pos] == '*' { return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN) } // Is it an anchor? if parser.buffer[parser.buffer_pos] == '&' { return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN) } // Is it a tag? if parser.buffer[parser.buffer_pos] == '!' { return yaml_parser_fetch_tag(parser) } // Is it a literal scalar? if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 { return yaml_parser_fetch_block_scalar(parser, true) } // Is it a folded scalar? if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 { return yaml_parser_fetch_block_scalar(parser, false) } // Is it a single-quoted scalar? if parser.buffer[parser.buffer_pos] == '\'' { return yaml_parser_fetch_flow_scalar(parser, true) } // Is it a double-quoted scalar? if parser.buffer[parser.buffer_pos] == '"' { return yaml_parser_fetch_flow_scalar(parser, false) } // Is it a plain scalar? // // A plain scalar may start with any non-blank characters except // // '-', '?', ':', ',', '[', ']', '{', '}', // '#', '&', '*', '!', '|', '>', '\'', '\"', // '%', '@', '`'. // // In the block context (and, for the '-' indicator, in the flow context // too), it may also start with the characters // // '-', '?', ':' // // if it is followed by a non-space character. // // The last rule is more restrictive than the specification requires. // [Go] Make this logic more reasonable. //switch parser.buffer[parser.buffer_pos] { //case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`': //} if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' || parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' || parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' || parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' || parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') || (parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) || (parser.flow_level == 0 && (parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') && !is_blankz(parser.buffer, parser.buffer_pos+1)) { return yaml_parser_fetch_plain_scalar(parser) } // If we don't determine the token type so far, it is an error. return yaml_parser_set_scanner_error(parser, "while scanning for the next token", parser.mark, "found character that cannot start any token") } // Check the list of potential simple keys and remove the positions that // cannot contain simple keys anymore. func yaml_parser_stale_simple_keys(parser *yaml_parser_t) bool { // Check for a potential simple key for each flow level. for i := range parser.simple_keys { simple_key := &parser.simple_keys[i] // The specification requires that a simple key // // - is limited to a single line, // - is shorter than 1024 characters. if simple_key.possible && (simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index) { // Check if the potential simple key to be removed is required. if simple_key.required { return yaml_parser_set_scanner_error(parser, "while scanning a simple key", simple_key.mark, "could not find expected ':'") } simple_key.possible = false } } return true } // Check if a simple key may start at the current position and add it if // needed. func yaml_parser_save_simple_key(parser *yaml_parser_t) bool { // A simple key is required at the current position if the scanner is in // the block context and the current column coincides with the indentation // level. required := parser.flow_level == 0 && parser.indent == parser.mark.column // // If the current position may start a simple key, save it. // if parser.simple_key_allowed { simple_key := yaml_simple_key_t{ possible: true, required: required, token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), } simple_key.mark = parser.mark if !yaml_parser_remove_simple_key(parser) { return false } parser.simple_keys[len(parser.simple_keys)-1] = simple_key } return true } // Remove a potential simple key at the current flow level. func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool { i := len(parser.simple_keys) - 1 if parser.simple_keys[i].possible { // If the key is required, it is an error. if parser.simple_keys[i].required { return yaml_parser_set_scanner_error(parser, "while scanning a simple key", parser.simple_keys[i].mark, "could not find expected ':'") } } // Remove the key from the stack. parser.simple_keys[i].possible = false return true } // Increase the flow level and resize the simple key list if needed. func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool { // Reset the simple key on the next level. parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{}) // Increase the flow level. parser.flow_level++ return true } // Decrease the flow level. func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool { if parser.flow_level > 0 { parser.flow_level-- parser.simple_keys = parser.simple_keys[:len(parser.simple_keys)-1] } return true } // Push the current indentation level to the stack and set the new level // the current column is greater than the indentation level. In this case, // append or insert the specified token into the token queue. func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool { // In the flow context, do nothing. if parser.flow_level > 0 { return true } if parser.indent < column { // Push the current indentation level to the stack and set the new // indentation level. parser.indents = append(parser.indents, parser.indent) parser.indent = column // Create a token and insert it into the queue. token := yaml_token_t{ typ: typ, start_mark: mark, end_mark: mark, } if number > -1 { number -= parser.tokens_parsed } yaml_insert_token(parser, number, &token) } return true } // Pop indentation levels from the indents stack until the current level // becomes less or equal to the column. For each indentation level, append // the BLOCK-END token. func yaml_parser_unroll_indent(parser *yaml_parser_t, column int) bool { // In the flow context, do nothing. if parser.flow_level > 0 { return true } // Loop through the indentation levels in the stack. for parser.indent > column { // Create a token and append it to the queue. token := yaml_token_t{ typ: yaml_BLOCK_END_TOKEN, start_mark: parser.mark, end_mark: parser.mark, } yaml_insert_token(parser, -1, &token) // Pop the indentation level. parser.indent = parser.indents[len(parser.indents)-1] parser.indents = parser.indents[:len(parser.indents)-1] } return true } // Initialize the scanner and produce the STREAM-START token. func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool { // Set the initial indentation. parser.indent = -1 // Initialize the simple key stack. parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{}) // A simple key is allowed at the beginning of the stream. parser.simple_key_allowed = true // We have started. parser.stream_start_produced = true // Create the STREAM-START token and append it to the queue. token := yaml_token_t{ typ: yaml_STREAM_START_TOKEN, start_mark: parser.mark, end_mark: parser.mark, encoding: parser.encoding, } yaml_insert_token(parser, -1, &token) return true } // Produce the STREAM-END token and shut down the scanner. func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool { // Force new line. if parser.mark.column != 0 { parser.mark.column = 0 parser.mark.line++ } // Reset the indentation level. if !yaml_parser_unroll_indent(parser, -1) { return false } // Reset simple keys. if !yaml_parser_remove_simple_key(parser) { return false } parser.simple_key_allowed = false // Create the STREAM-END token and append it to the queue. token := yaml_token_t{ typ: yaml_STREAM_END_TOKEN, start_mark: parser.mark, end_mark: parser.mark, } yaml_insert_token(parser, -1, &token) return true } // Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token. func yaml_parser_fetch_directive(parser *yaml_parser_t) bool { // Reset the indentation level. if !yaml_parser_unroll_indent(parser, -1) { return false } // Reset simple keys. if !yaml_parser_remove_simple_key(parser) { return false } parser.simple_key_allowed = false // Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. token := yaml_token_t{} if !yaml_parser_scan_directive(parser, &token) { return false } // Append the token to the queue. yaml_insert_token(parser, -1, &token) return true } // Produce the DOCUMENT-START or DOCUMENT-END token. func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool { // Reset the indentation level. if !yaml_parser_unroll_indent(parser, -1) { return false } // Reset simple keys. if !yaml_parser_remove_simple_key(parser) { return false } parser.simple_key_allowed = false // Consume the token. start_mark := parser.mark skip(parser) skip(parser) skip(parser) end_mark := parser.mark // Create the DOCUMENT-START or DOCUMENT-END token. token := yaml_token_t{ typ: typ, start_mark: start_mark, end_mark: end_mark, } // Append the token to the queue. yaml_insert_token(parser, -1, &token) return true } // Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token. func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool { // The indicators '[' and '{' may start a simple key. if !yaml_parser_save_simple_key(parser) { return false } // Increase the flow level. if !yaml_parser_increase_flow_level(parser) { return false } // A simple key may follow the indicators '[' and '{'. parser.simple_key_allowed = true // Consume the token. start_mark := parser.mark skip(parser) end_mark := parser.mark // Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. token := yaml_token_t{ typ: typ, start_mark: start_mark, end_mark: end_mark, } // Append the token to the queue. yaml_insert_token(parser, -1, &token) return true } // Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token. func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool { // Reset any potential simple key on the current flow level. if !yaml_parser_remove_simple_key(parser) { return false } // Decrease the flow level. if !yaml_parser_decrease_flow_level(parser) { return false } // No simple keys after the indicators ']' and '}'. parser.simple_key_allowed = false // Consume the token. start_mark := parser.mark skip(parser) end_mark := parser.mark // Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. token := yaml_token_t{ typ: typ, start_mark: start_mark, end_mark: end_mark, } // Append the token to the queue. yaml_insert_token(parser, -1, &token) return true } // Produce the FLOW-ENTRY token. func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool { // Reset any potential simple keys on the current flow level. if !yaml_parser_remove_simple_key(parser) { return false } // Simple keys are allowed after ','. parser.simple_key_allowed = true // Consume the token. start_mark := parser.mark skip(parser) end_mark := parser.mark // Create the FLOW-ENTRY token and append it to the queue. token := yaml_token_t{ typ: yaml_FLOW_ENTRY_TOKEN, start_mark: start_mark, end_mark: end_mark, } yaml_insert_token(parser, -1, &token) return true } // Produce the BLOCK-ENTRY token. func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool { // Check if the scanner is in the block context. if parser.flow_level == 0 { // Check if we are allowed to start a new entry. if !parser.simple_key_allowed { return yaml_parser_set_scanner_error(parser, "", parser.mark, "block sequence entries are not allowed in this context") } // Add the BLOCK-SEQUENCE-START token if needed. if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) { return false } } else { // It is an error for the '-' indicator to occur in the flow context, // but we let the Parser detect and report about it because the Parser // is able to point to the context. } // Reset any potential simple keys on the current flow level. if !yaml_parser_remove_simple_key(parser) { return false } // Simple keys are allowed after '-'. parser.simple_key_allowed = true // Consume the token. start_mark := parser.mark skip(parser) end_mark := parser.mark // Create the BLOCK-ENTRY token and append it to the queue. token := yaml_token_t{ typ: yaml_BLOCK_ENTRY_TOKEN, start_mark: start_mark, end_mark: end_mark, } yaml_insert_token(parser, -1, &token) return true } // Produce the KEY token. func yaml_parser_fetch_key(parser *yaml_parser_t) bool { // In the block context, additional checks are required. if parser.flow_level == 0 { // Check if we are allowed to start a new key (not nessesary simple). if !parser.simple_key_allowed { return yaml_parser_set_scanner_error(parser, "", parser.mark, "mapping keys are not allowed in this context") } // Add the BLOCK-MAPPING-START token if needed. if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { return false } } // Reset any potential simple keys on the current flow level. if !yaml_parser_remove_simple_key(parser) { return false } // Simple keys are allowed after '?' in the block context. parser.simple_key_allowed = parser.flow_level == 0 // Consume the token. start_mark := parser.mark skip(parser) end_mark := parser.mark // Create the KEY token and append it to the queue. token := yaml_token_t{ typ: yaml_KEY_TOKEN, start_mark: start_mark, end_mark: end_mark, } yaml_insert_token(parser, -1, &token) return true } // Produce the VALUE token. func yaml_parser_fetch_value(parser *yaml_parser_t) bool { simple_key := &parser.simple_keys[len(parser.simple_keys)-1] // Have we found a simple key? if simple_key.possible { // Create the KEY token and insert it into the queue. token := yaml_token_t{ typ: yaml_KEY_TOKEN, start_mark: simple_key.mark, end_mark: simple_key.mark, } yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token) // In the block context, we may need to add the BLOCK-MAPPING-START token. if !yaml_parser_roll_indent(parser, simple_key.mark.column, simple_key.token_number, yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) { return false } // Remove the simple key. simple_key.possible = false // A simple key cannot follow another simple key. parser.simple_key_allowed = false } else { // The ':' indicator follows a complex key. // In the block context, extra checks are required. if parser.flow_level == 0 { // Check if we are allowed to start a complex value. if !parser.simple_key_allowed { return yaml_parser_set_scanner_error(parser, "", parser.mark, "mapping values are not allowed in this context") } // Add the BLOCK-MAPPING-START token if needed. if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { return false } } // Simple keys after ':' are allowed in the block context. parser.simple_key_allowed = parser.flow_level == 0 } // Consume the token. start_mark := parser.mark skip(parser) end_mark := parser.mark // Create the VALUE token and append it to the queue. token := yaml_token_t{ typ: yaml_VALUE_TOKEN, start_mark: start_mark, end_mark: end_mark, } yaml_insert_token(parser, -1, &token) return true } // Produce the ALIAS or ANCHOR token. func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool { // An anchor or an alias could be a simple key. if !yaml_parser_save_simple_key(parser) { return false } // A simple key cannot follow an anchor or an alias. parser.simple_key_allowed = false // Create the ALIAS or ANCHOR token and append it to the queue. var token yaml_token_t if !yaml_parser_scan_anchor(parser, &token, typ) { return false } yaml_insert_token(parser, -1, &token) return true } // Produce the TAG token. func yaml_parser_fetch_tag(parser *yaml_parser_t) bool { // A tag could be a simple key. if !yaml_parser_save_simple_key(parser) { return false } // A simple key cannot follow a tag. parser.simple_key_allowed = false // Create the TAG token and append it to the queue. var token yaml_token_t if !yaml_parser_scan_tag(parser, &token) { return false } yaml_insert_token(parser, -1, &token) return true } // Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens. func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool { // Remove any potential simple keys. if !yaml_parser_remove_simple_key(parser) { return false } // A simple key may follow a block scalar. parser.simple_key_allowed = true // Create the SCALAR token and append it to the queue. var token yaml_token_t if !yaml_parser_scan_block_scalar(parser, &token, literal) { return false } yaml_insert_token(parser, -1, &token) return true } // Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens. func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool { // A plain scalar could be a simple key. if !yaml_parser_save_simple_key(parser) { return false } // A simple key cannot follow a flow scalar. parser.simple_key_allowed = false // Create the SCALAR token and append it to the queue. var token yaml_token_t if !yaml_parser_scan_flow_scalar(parser, &token, single) { return false } yaml_insert_token(parser, -1, &token) return true } // Produce the SCALAR(...,plain) token. func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool { // A plain scalar could be a simple key. if !yaml_parser_save_simple_key(parser) { return false } // A simple key cannot follow a flow scalar. parser.simple_key_allowed = false // Create the SCALAR token and append it to the queue. var token yaml_token_t if !yaml_parser_scan_plain_scalar(parser, &token) { return false } yaml_insert_token(parser, -1, &token) return true } // Eat whitespaces and comments until the next token is found. func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool { // Until the next token is not found. for { // Allow the BOM mark to start a line. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) { skip(parser) } // Eat whitespaces. // Tabs are allowed: // - in the flow context // - in the block context, but not at the beginning of the line or // after '-', '?', or ':' (complex value). if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') { skip(parser) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } // Eat a comment until a line break. if parser.buffer[parser.buffer_pos] == '#' { for !is_breakz(parser.buffer, parser.buffer_pos) { skip(parser) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } } // If it is a line break, eat it. if is_break(parser.buffer, parser.buffer_pos) { if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { return false } skip_line(parser) // In the block context, a new line may start a simple key. if parser.flow_level == 0 { parser.simple_key_allowed = true } } else { break // We have found a token. } } return true } // Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. // // Scope: // %YAML 1.1 # a comment \n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // %TAG !yaml! tag:yaml.org,2002: \n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool { // Eat '%'. start_mark := parser.mark skip(parser) // Scan the directive name. var name []byte if !yaml_parser_scan_directive_name(parser, start_mark, &name) { return false } // Is it a YAML directive? if bytes.Equal(name, []byte("YAML")) { // Scan the VERSION directive value. var major, minor int8 if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) { return false } end_mark := parser.mark // Create a VERSION-DIRECTIVE token. *token = yaml_token_t{ typ: yaml_VERSION_DIRECTIVE_TOKEN, start_mark: start_mark, end_mark: end_mark, major: major, minor: minor, } // Is it a TAG directive? } else if bytes.Equal(name, []byte("TAG")) { // Scan the TAG directive value. var handle, prefix []byte if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) { return false } end_mark := parser.mark // Create a TAG-DIRECTIVE token. *token = yaml_token_t{ typ: yaml_TAG_DIRECTIVE_TOKEN, start_mark: start_mark, end_mark: end_mark, value: handle, prefix: prefix, } // Unknown directive. } else { yaml_parser_set_scanner_error(parser, "while scanning a directive", start_mark, "found unknown directive name") return false } // Eat the rest of the line including any comments. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } for is_blank(parser.buffer, parser.buffer_pos) { skip(parser) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } if parser.buffer[parser.buffer_pos] == '#' { for !is_breakz(parser.buffer, parser.buffer_pos) { skip(parser) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } } // Check if we are at the end of the line. if !is_breakz(parser.buffer, parser.buffer_pos) { yaml_parser_set_scanner_error(parser, "while scanning a directive", start_mark, "did not find expected comment or line break") return false } // Eat a line break. if is_break(parser.buffer, parser.buffer_pos) { if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { return false } skip_line(parser) } return true } // Scan the directive name. // // Scope: // %YAML 1.1 # a comment \n // ^^^^ // %TAG !yaml! tag:yaml.org,2002: \n // ^^^ // func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool { // Consume the directive name. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } var s []byte for is_alpha(parser.buffer, parser.buffer_pos) { s = read(parser, s) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } // Check if the name is empty. if len(s) == 0 { yaml_parser_set_scanner_error(parser, "while scanning a directive", start_mark, "could not find expected directive name") return false } // Check for an blank character after the name. if !is_blankz(parser.buffer, parser.buffer_pos) { yaml_parser_set_scanner_error(parser, "while scanning a directive", start_mark, "found unexpected non-alphabetical character") return false } *name = s return true } // Scan the value of VERSION-DIRECTIVE. // // Scope: // %YAML 1.1 # a comment \n // ^^^^^^ func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool { // Eat whitespaces. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } for is_blank(parser.buffer, parser.buffer_pos) { skip(parser) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } // Consume the major version number. if !yaml_parser_scan_version_directive_number(parser, start_mark, major) { return false } // Eat '.'. if parser.buffer[parser.buffer_pos] != '.' { return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", start_mark, "did not find expected digit or '.' character") } skip(parser) // Consume the minor version number. if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) { return false } return true } const max_number_length = 2 // Scan the version number of VERSION-DIRECTIVE. // // Scope: // %YAML 1.1 # a comment \n // ^ // %YAML 1.1 # a comment \n // ^ func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool { // Repeat while the next character is digit. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } var value, length int8 for is_digit(parser.buffer, parser.buffer_pos) { // Check if the number is too long. length++ if length > max_number_length { return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", start_mark, "found extremely long version number") } value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos)) skip(parser) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } // Check if the number was present. if length == 0 { return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", start_mark, "did not find expected version number") } *number = value return true } // Scan the value of a TAG-DIRECTIVE token. // // Scope: // %TAG !yaml! tag:yaml.org,2002: \n // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool { var handle_value, prefix_value []byte // Eat whitespaces. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } for is_blank(parser.buffer, parser.buffer_pos) { skip(parser) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } // Scan a handle. if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) { return false } // Expect a whitespace. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } if !is_blank(parser.buffer, parser.buffer_pos) { yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", start_mark, "did not find expected whitespace") return false } // Eat whitespaces. for is_blank(parser.buffer, parser.buffer_pos) { skip(parser) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } // Scan a prefix. if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) { return false } // Expect a whitespace or line break. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } if !is_blankz(parser.buffer, parser.buffer_pos) { yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", start_mark, "did not find expected whitespace or line break") return false } *handle = handle_value *prefix = prefix_value return true } func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool { var s []byte // Eat the indicator character. start_mark := parser.mark skip(parser) // Consume the value. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } for is_alpha(parser.buffer, parser.buffer_pos) { s = read(parser, s) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } end_mark := parser.mark /* * Check if length of the anchor is greater than 0 and it is followed by * a whitespace character or one of the indicators: * * '?', ':', ',', ']', '}', '%', '@', '`'. */ if len(s) == 0 || !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') { context := "while scanning an alias" if typ == yaml_ANCHOR_TOKEN { context = "while scanning an anchor" } yaml_parser_set_scanner_error(parser, context, start_mark, "did not find expected alphabetic or numeric character") return false } // Create a token. *token = yaml_token_t{ typ: typ, start_mark: start_mark, end_mark: end_mark, value: s, } return true } /* * Scan a TAG token. */ func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool { var handle, suffix []byte start_mark := parser.mark // Check if the tag is in the canonical form. if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { return false } if parser.buffer[parser.buffer_pos+1] == '<' { // Keep the handle as '' // Eat '!<' skip(parser) skip(parser) // Consume the tag value. if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { return false } // Check for '>' and eat it. if parser.buffer[parser.buffer_pos] != '>' { yaml_parser_set_scanner_error(parser, "while scanning a tag", start_mark, "did not find the expected '>'") return false } skip(parser) } else { // The tag has either the '!suffix' or the '!handle!suffix' form. // First, try to scan a handle. if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) { return false } // Check if it is, indeed, handle. if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' { // Scan the suffix now. if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { return false } } else { // It wasn't a handle after all. Scan the rest of the tag. if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) { return false } // Set the handle to '!'. handle = []byte{'!'} // A special case: the '!' tag. Set the handle to '' and the // suffix to '!'. if len(suffix) == 0 { handle, suffix = suffix, handle } } } // Check the character which ends the tag. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } if !is_blankz(parser.buffer, parser.buffer_pos) { yaml_parser_set_scanner_error(parser, "while scanning a tag", start_mark, "did not find expected whitespace or line break") return false } end_mark := parser.mark // Create a token. *token = yaml_token_t{ typ: yaml_TAG_TOKEN, start_mark: start_mark, end_mark: end_mark, value: handle, suffix: suffix, } return true } // Scan a tag handle. func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool { // Check the initial '!' character. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } if parser.buffer[parser.buffer_pos] != '!' { yaml_parser_set_scanner_tag_error(parser, directive, start_mark, "did not find expected '!'") return false } var s []byte // Copy the '!' character. s = read(parser, s) // Copy all subsequent alphabetical and numerical characters. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } for is_alpha(parser.buffer, parser.buffer_pos) { s = read(parser, s) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } // Check if the trailing character is '!' and copy it. if parser.buffer[parser.buffer_pos] == '!' { s = read(parser, s) } else { // It's either the '!' tag or not really a tag handle. If it's a %TAG // directive, it's an error. If it's a tag token, it must be a part of URI. if directive && string(s) != "!" { yaml_parser_set_scanner_tag_error(parser, directive, start_mark, "did not find expected '!'") return false } } *handle = s return true } // Scan a tag. func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool { //size_t length = head ? strlen((char *)head) : 0 var s []byte hasTag := len(head) > 0 // Copy the head if needed. // // Note that we don't copy the leading '!' character. if len(head) > 1 { s = append(s, head[1:]...) } // Scan the tag. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } // The set of characters that may appear in URI is as follows: // // '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', // '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']', // '%'. // [Go] Convert this into more reasonable logic. for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' || parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' || parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' || parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' || parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' || parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' || parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' || parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '%' { // Check if it is a URI-escape sequence. if parser.buffer[parser.buffer_pos] == '%' { if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) { return false } } else { s = read(parser, s) } if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } hasTag = true } if !hasTag { yaml_parser_set_scanner_tag_error(parser, directive, start_mark, "did not find expected tag URI") return false } *uri = s return true } // Decode an URI-escape sequence corresponding to a single UTF-8 character. func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool { // Decode the required number of characters. w := 1024 for w > 0 { // Check for a URI-escaped octet. if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { return false } if !(parser.buffer[parser.buffer_pos] == '%' && is_hex(parser.buffer, parser.buffer_pos+1) && is_hex(parser.buffer, parser.buffer_pos+2)) { return yaml_parser_set_scanner_tag_error(parser, directive, start_mark, "did not find URI escaped octet") } // Get the octet. octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2)) // If it is the leading octet, determine the length of the UTF-8 sequence. if w == 1024 { w = width(octet) if w == 0 { return yaml_parser_set_scanner_tag_error(parser, directive, start_mark, "found an incorrect leading UTF-8 octet") } } else { // Check if the trailing octet is correct. if octet&0xC0 != 0x80 { return yaml_parser_set_scanner_tag_error(parser, directive, start_mark, "found an incorrect trailing UTF-8 octet") } } // Copy the octet and move the pointers. *s = append(*s, octet) skip(parser) skip(parser) skip(parser) w-- } return true } // Scan a block scalar. func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool { // Eat the indicator '|' or '>'. start_mark := parser.mark skip(parser) // Scan the additional block scalar indicators. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } // Check for a chomping indicator. var chomping, increment int if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { // Set the chomping method and eat the indicator. if parser.buffer[parser.buffer_pos] == '+' { chomping = +1 } else { chomping = -1 } skip(parser) // Check for an indentation indicator. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } if is_digit(parser.buffer, parser.buffer_pos) { // Check that the indentation is greater than 0. if parser.buffer[parser.buffer_pos] == '0' { yaml_parser_set_scanner_error(parser, "while scanning a block scalar", start_mark, "found an indentation indicator equal to 0") return false } // Get the indentation level and eat the indicator. increment = as_digit(parser.buffer, parser.buffer_pos) skip(parser) } } else if is_digit(parser.buffer, parser.buffer_pos) { // Do the same as above, but in the opposite order. if parser.buffer[parser.buffer_pos] == '0' { yaml_parser_set_scanner_error(parser, "while scanning a block scalar", start_mark, "found an indentation indicator equal to 0") return false } increment = as_digit(parser.buffer, parser.buffer_pos) skip(parser) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { if parser.buffer[parser.buffer_pos] == '+' { chomping = +1 } else { chomping = -1 } skip(parser) } } // Eat whitespaces and comments to the end of the line. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } for is_blank(parser.buffer, parser.buffer_pos) { skip(parser) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } if parser.buffer[parser.buffer_pos] == '#' { for !is_breakz(parser.buffer, parser.buffer_pos) { skip(parser) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } } // Check if we are at the end of the line. if !is_breakz(parser.buffer, parser.buffer_pos) { yaml_parser_set_scanner_error(parser, "while scanning a block scalar", start_mark, "did not find expected comment or line break") return false } // Eat a line break. if is_break(parser.buffer, parser.buffer_pos) { if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { return false } skip_line(parser) } end_mark := parser.mark // Set the indentation level if it was specified. var indent int if increment > 0 { if parser.indent >= 0 { indent = parser.indent + increment } else { indent = increment } } // Scan the leading line breaks and determine the indentation level if needed. var s, leading_break, trailing_breaks []byte if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { return false } // Scan the block scalar content. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } var leading_blank, trailing_blank bool for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) { // We are at the beginning of a non-empty line. // Is it a trailing whitespace? trailing_blank = is_blank(parser.buffer, parser.buffer_pos) // Check if we need to fold the leading line break. if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' { // Do we need to join the lines by space? if len(trailing_breaks) == 0 { s = append(s, ' ') } } else { s = append(s, leading_break...) } leading_break = leading_break[:0] // Append the remaining line breaks. s = append(s, trailing_breaks...) trailing_breaks = trailing_breaks[:0] // Is it a leading whitespace? leading_blank = is_blank(parser.buffer, parser.buffer_pos) // Consume the current line. for !is_breakz(parser.buffer, parser.buffer_pos) { s = read(parser, s) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } // Consume the line break. if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { return false } leading_break = read_line(parser, leading_break) // Eat the following indentation spaces and line breaks. if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { return false } } // Chomp the tail. if chomping != -1 { s = append(s, leading_break...) } if chomping == 1 { s = append(s, trailing_breaks...) } // Create a token. *token = yaml_token_t{ typ: yaml_SCALAR_TOKEN, start_mark: start_mark, end_mark: end_mark, value: s, style: yaml_LITERAL_SCALAR_STYLE, } if !literal { token.style = yaml_FOLDED_SCALAR_STYLE } return true } // Scan indentation spaces and line breaks for a block scalar. Determine the // indentation level if needed. func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool { *end_mark = parser.mark // Eat the indentation spaces and line breaks. max_indent := 0 for { // Eat the indentation spaces. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) { skip(parser) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } if parser.mark.column > max_indent { max_indent = parser.mark.column } // Check for a tab character messing the indentation. if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) { return yaml_parser_set_scanner_error(parser, "while scanning a block scalar", start_mark, "found a tab character where an indentation space is expected") } // Have we found a non-empty line? if !is_break(parser.buffer, parser.buffer_pos) { break } // Consume the line break. if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { return false } // [Go] Should really be returning breaks instead. *breaks = read_line(parser, *breaks) *end_mark = parser.mark } // Determine the indentation level if needed. if *indent == 0 { *indent = max_indent if *indent < parser.indent+1 { *indent = parser.indent + 1 } if *indent < 1 { *indent = 1 } } return true } // Scan a quoted scalar. func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool { // Eat the left quote. start_mark := parser.mark skip(parser) // Consume the content of the quoted scalar. var s, leading_break, trailing_breaks, whitespaces []byte for { // Check that there are no document indicators at the beginning of the line. if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { return false } if parser.mark.column == 0 && ((parser.buffer[parser.buffer_pos+0] == '-' && parser.buffer[parser.buffer_pos+1] == '-' && parser.buffer[parser.buffer_pos+2] == '-') || (parser.buffer[parser.buffer_pos+0] == '.' && parser.buffer[parser.buffer_pos+1] == '.' && parser.buffer[parser.buffer_pos+2] == '.')) && is_blankz(parser.buffer, parser.buffer_pos+3) { yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", start_mark, "found unexpected document indicator") return false } // Check for EOF. if is_z(parser.buffer, parser.buffer_pos) { yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", start_mark, "found unexpected end of stream") return false } // Consume non-blank characters. leading_blanks := false for !is_blankz(parser.buffer, parser.buffer_pos) { if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' { // Is is an escaped single quote. s = append(s, '\'') skip(parser) skip(parser) } else if single && parser.buffer[parser.buffer_pos] == '\'' { // It is a right single quote. break } else if !single && parser.buffer[parser.buffer_pos] == '"' { // It is a right double quote. break } else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) { // It is an escaped line break. if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { return false } skip(parser) skip_line(parser) leading_blanks = true break } else if !single && parser.buffer[parser.buffer_pos] == '\\' { // It is an escape sequence. code_length := 0 // Check the escape character. switch parser.buffer[parser.buffer_pos+1] { case '0': s = append(s, 0) case 'a': s = append(s, '\x07') case 'b': s = append(s, '\x08') case 't', '\t': s = append(s, '\x09') case 'n': s = append(s, '\x0A') case 'v': s = append(s, '\x0B') case 'f': s = append(s, '\x0C') case 'r': s = append(s, '\x0D') case 'e': s = append(s, '\x1B') case ' ': s = append(s, '\x20') case '"': s = append(s, '"') case '\'': s = append(s, '\'') case '\\': s = append(s, '\\') case 'N': // NEL (#x85) s = append(s, '\xC2') s = append(s, '\x85') case '_': // #xA0 s = append(s, '\xC2') s = append(s, '\xA0') case 'L': // LS (#x2028) s = append(s, '\xE2') s = append(s, '\x80') s = append(s, '\xA8') case 'P': // PS (#x2029) s = append(s, '\xE2') s = append(s, '\x80') s = append(s, '\xA9') case 'x': code_length = 2 case 'u': code_length = 4 case 'U': code_length = 8 default: yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", start_mark, "found unknown escape character") return false } skip(parser) skip(parser) // Consume an arbitrary escape code. if code_length > 0 { var value int // Scan the character value. if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) { return false } for k := 0; k < code_length; k++ { if !is_hex(parser.buffer, parser.buffer_pos+k) { yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", start_mark, "did not find expected hexdecimal number") return false } value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k) } // Check the value and write the character. if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF { yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", start_mark, "found invalid Unicode character escape code") return false } if value <= 0x7F { s = append(s, byte(value)) } else if value <= 0x7FF { s = append(s, byte(0xC0+(value>>6))) s = append(s, byte(0x80+(value&0x3F))) } else if value <= 0xFFFF { s = append(s, byte(0xE0+(value>>12))) s = append(s, byte(0x80+((value>>6)&0x3F))) s = append(s, byte(0x80+(value&0x3F))) } else { s = append(s, byte(0xF0+(value>>18))) s = append(s, byte(0x80+((value>>12)&0x3F))) s = append(s, byte(0x80+((value>>6)&0x3F))) s = append(s, byte(0x80+(value&0x3F))) } // Advance the pointer. for k := 0; k < code_length; k++ { skip(parser) } } } else { // It is a non-escaped non-blank character. s = read(parser, s) } if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { return false } } if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } // Check if we are at the end of the scalar. if single { if parser.buffer[parser.buffer_pos] == '\'' { break } } else { if parser.buffer[parser.buffer_pos] == '"' { break } } // Consume blank characters. for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { if is_blank(parser.buffer, parser.buffer_pos) { // Consume a space or a tab character. if !leading_blanks { whitespaces = read(parser, whitespaces) } else { skip(parser) } } else { if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { return false } // Check if it is a first line break. if !leading_blanks { whitespaces = whitespaces[:0] leading_break = read_line(parser, leading_break) leading_blanks = true } else { trailing_breaks = read_line(parser, trailing_breaks) } } if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } // Join the whitespaces or fold line breaks. if leading_blanks { // Do we need to fold line breaks? if len(leading_break) > 0 && leading_break[0] == '\n' { if len(trailing_breaks) == 0 { s = append(s, ' ') } else { s = append(s, trailing_breaks...) } } else { s = append(s, leading_break...) s = append(s, trailing_breaks...) } trailing_breaks = trailing_breaks[:0] leading_break = leading_break[:0] } else { s = append(s, whitespaces...) whitespaces = whitespaces[:0] } } // Eat the right quote. skip(parser) end_mark := parser.mark // Create a token. *token = yaml_token_t{ typ: yaml_SCALAR_TOKEN, start_mark: start_mark, end_mark: end_mark, value: s, style: yaml_SINGLE_QUOTED_SCALAR_STYLE, } if !single { token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE } return true } // Scan a plain scalar. func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool { var s, leading_break, trailing_breaks, whitespaces []byte var leading_blanks bool var indent = parser.indent + 1 start_mark := parser.mark end_mark := parser.mark // Consume the content of the plain scalar. for { // Check for a document indicator. if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { return false } if parser.mark.column == 0 && ((parser.buffer[parser.buffer_pos+0] == '-' && parser.buffer[parser.buffer_pos+1] == '-' && parser.buffer[parser.buffer_pos+2] == '-') || (parser.buffer[parser.buffer_pos+0] == '.' && parser.buffer[parser.buffer_pos+1] == '.' && parser.buffer[parser.buffer_pos+2] == '.')) && is_blankz(parser.buffer, parser.buffer_pos+3) { break } // Check for a comment. if parser.buffer[parser.buffer_pos] == '#' { break } // Consume non-blank characters. for !is_blankz(parser.buffer, parser.buffer_pos) { // Check for indicators that may end a plain scalar. if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) || (parser.flow_level > 0 && (parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || parser.buffer[parser.buffer_pos] == '}')) { break } // Check if we need to join whitespaces and breaks. if leading_blanks || len(whitespaces) > 0 { if leading_blanks { // Do we need to fold line breaks? if leading_break[0] == '\n' { if len(trailing_breaks) == 0 { s = append(s, ' ') } else { s = append(s, trailing_breaks...) } } else { s = append(s, leading_break...) s = append(s, trailing_breaks...) } trailing_breaks = trailing_breaks[:0] leading_break = leading_break[:0] leading_blanks = false } else { s = append(s, whitespaces...) whitespaces = whitespaces[:0] } } // Copy the character. s = read(parser, s) end_mark = parser.mark if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { return false } } // Is it the end? if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) { break } // Consume blank characters. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { if is_blank(parser.buffer, parser.buffer_pos) { // Check for tab characters that abuse indentation. if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) { yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", start_mark, "found a tab character that violates indentation") return false } // Consume a space or a tab character. if !leading_blanks { whitespaces = read(parser, whitespaces) } else { skip(parser) } } else { if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { return false } // Check if it is a first line break. if !leading_blanks { whitespaces = whitespaces[:0] leading_break = read_line(parser, leading_break) leading_blanks = true } else { trailing_breaks = read_line(parser, trailing_breaks) } } if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false } } // Check indentation level. if parser.flow_level == 0 && parser.mark.column < indent { break } } // Create a token. *token = yaml_token_t{ typ: yaml_SCALAR_TOKEN, start_mark: start_mark, end_mark: end_mark, value: s, style: yaml_PLAIN_SCALAR_STYLE, } // Note that we change the 'simple_key_allowed' flag. if leading_blanks { parser.simple_key_allowed = true } return true } ================================================ FILE: vendor/gopkg.in/yaml.v2/sorter.go ================================================ package yaml import ( "reflect" "unicode" ) type keyList []reflect.Value func (l keyList) Len() int { return len(l) } func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } func (l keyList) Less(i, j int) bool { a := l[i] b := l[j] ak := a.Kind() bk := b.Kind() for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { a = a.Elem() ak = a.Kind() } for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { b = b.Elem() bk = b.Kind() } af, aok := keyFloat(a) bf, bok := keyFloat(b) if aok && bok { if af != bf { return af < bf } if ak != bk { return ak < bk } return numLess(a, b) } if ak != reflect.String || bk != reflect.String { return ak < bk } ar, br := []rune(a.String()), []rune(b.String()) for i := 0; i < len(ar) && i < len(br); i++ { if ar[i] == br[i] { continue } al := unicode.IsLetter(ar[i]) bl := unicode.IsLetter(br[i]) if al && bl { return ar[i] < br[i] } if al || bl { return bl } var ai, bi int var an, bn int64 if ar[i] == '0' || br[i] == '0' { for j := i-1; j >= 0 && unicode.IsDigit(ar[j]); j-- { if ar[j] != '0' { an = 1 bn = 1 break } } } for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { an = an*10 + int64(ar[ai]-'0') } for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { bn = bn*10 + int64(br[bi]-'0') } if an != bn { return an < bn } if ai != bi { return ai < bi } return ar[i] < br[i] } return len(ar) < len(br) } // keyFloat returns a float value for v if it is a number/bool // and whether it is a number/bool or not. func keyFloat(v reflect.Value) (f float64, ok bool) { switch v.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return float64(v.Int()), true case reflect.Float32, reflect.Float64: return v.Float(), true case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return float64(v.Uint()), true case reflect.Bool: if v.Bool() { return 1, true } return 0, true } return 0, false } // numLess returns whether a < b. // a and b must necessarily have the same kind. func numLess(a, b reflect.Value) bool { switch a.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return a.Int() < b.Int() case reflect.Float32, reflect.Float64: return a.Float() < b.Float() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return a.Uint() < b.Uint() case reflect.Bool: return !a.Bool() && b.Bool() } panic("not a number") } ================================================ FILE: vendor/gopkg.in/yaml.v2/writerc.go ================================================ package yaml // Set the writer error and return false. func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { emitter.error = yaml_WRITER_ERROR emitter.problem = problem return false } // Flush the output buffer. func yaml_emitter_flush(emitter *yaml_emitter_t) bool { if emitter.write_handler == nil { panic("write handler not set") } // Check if the buffer is empty. if emitter.buffer_pos == 0 { return true } if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) } emitter.buffer_pos = 0 return true } ================================================ FILE: vendor/gopkg.in/yaml.v2/yaml.go ================================================ // Package yaml implements YAML support for the Go language. // // Source code and other details for the project are available at GitHub: // // https://github.com/go-yaml/yaml // package yaml import ( "errors" "fmt" "io" "reflect" "strings" "sync" ) // MapSlice encodes and decodes as a YAML map. // The order of keys is preserved when encoding and decoding. type MapSlice []MapItem // MapItem is an item in a MapSlice. type MapItem struct { Key, Value interface{} } // The Unmarshaler interface may be implemented by types to customize their // behavior when being unmarshaled from a YAML document. The UnmarshalYAML // method receives a function that may be called to unmarshal the original // YAML value into a field or variable. It is safe to call the unmarshal // function parameter more than once if necessary. type Unmarshaler interface { UnmarshalYAML(unmarshal func(interface{}) error) error } // The Marshaler interface may be implemented by types to customize their // behavior when being marshaled into a YAML document. The returned value // is marshaled in place of the original value implementing Marshaler. // // If an error is returned by MarshalYAML, the marshaling procedure stops // and returns with the provided error. type Marshaler interface { MarshalYAML() (interface{}, error) } // Unmarshal decodes the first document found within the in byte slice // and assigns decoded values into the out value. // // Maps and pointers (to a struct, string, int, etc) are accepted as out // values. If an internal pointer within a struct is not initialized, // the yaml package will initialize it if necessary for unmarshalling // the provided data. The out parameter must not be nil. // // The type of the decoded values should be compatible with the respective // values in out. If one or more values cannot be decoded due to a type // mismatches, decoding continues partially until the end of the YAML // content, and a *yaml.TypeError is returned with details for all // missed values. // // Struct fields are only unmarshalled if they are exported (have an // upper case first letter), and are unmarshalled using the field name // lowercased as the default key. Custom keys may be defined via the // "yaml" name in the field tag: the content preceding the first comma // is used as the key, and the following comma-separated options are // used to tweak the marshalling process (see Marshal). // Conflicting names result in a runtime error. // // For example: // // type T struct { // F int `yaml:"a,omitempty"` // B int // } // var t T // yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) // // See the documentation of Marshal for the format of tags and a list of // supported tag options. // func Unmarshal(in []byte, out interface{}) (err error) { return unmarshal(in, out, false) } // UnmarshalStrict is like Unmarshal except that any fields that are found // in the data that do not have corresponding struct members, or mapping // keys that are duplicates, will result in // an error. func UnmarshalStrict(in []byte, out interface{}) (err error) { return unmarshal(in, out, true) } // A Decorder reads and decodes YAML values from an input stream. type Decoder struct { strict bool parser *parser } // NewDecoder returns a new decoder that reads from r. // // The decoder introduces its own buffering and may read // data from r beyond the YAML values requested. func NewDecoder(r io.Reader) *Decoder { return &Decoder{ parser: newParserFromReader(r), } } // SetStrict sets whether strict decoding behaviour is enabled when // decoding items in the data (see UnmarshalStrict). By default, decoding is not strict. func (dec *Decoder) SetStrict(strict bool) { dec.strict = strict } // Decode reads the next YAML-encoded value from its input // and stores it in the value pointed to by v. // // See the documentation for Unmarshal for details about the // conversion of YAML into a Go value. func (dec *Decoder) Decode(v interface{}) (err error) { d := newDecoder(dec.strict) defer handleErr(&err) node := dec.parser.parse() if node == nil { return io.EOF } out := reflect.ValueOf(v) if out.Kind() == reflect.Ptr && !out.IsNil() { out = out.Elem() } d.unmarshal(node, out) if len(d.terrors) > 0 { return &TypeError{d.terrors} } return nil } func unmarshal(in []byte, out interface{}, strict bool) (err error) { defer handleErr(&err) d := newDecoder(strict) p := newParser(in) defer p.destroy() node := p.parse() if node != nil { v := reflect.ValueOf(out) if v.Kind() == reflect.Ptr && !v.IsNil() { v = v.Elem() } d.unmarshal(node, v) } if len(d.terrors) > 0 { return &TypeError{d.terrors} } return nil } // Marshal serializes the value provided into a YAML document. The structure // of the generated document will reflect the structure of the value itself. // Maps and pointers (to struct, string, int, etc) are accepted as the in value. // // Struct fields are only marshalled if they are exported (have an upper case // first letter), and are marshalled using the field name lowercased as the // default key. Custom keys may be defined via the "yaml" name in the field // tag: the content preceding the first comma is used as the key, and the // following comma-separated options are used to tweak the marshalling process. // Conflicting names result in a runtime error. // // The field tag format accepted is: // // `(...) yaml:"[][,[,]]" (...)` // // 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. // Zero valued structs will be omitted if all their public // fields are zero, unless they implement an IsZero // method (see the IsZeroer interface type), in which // case the field will be included if that method returns true. // // flow Marshal using a flow style (useful for structs, // sequences and maps). // // 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 yaml keys of other struct fields. // // In addition, if the key is "-", the field is ignored. // // For example: // // type T struct { // F int `yaml:"a,omitempty"` // B int // } // yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" // yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n" // func Marshal(in interface{}) (out []byte, err error) { defer handleErr(&err) e := newEncoder() defer e.destroy() e.marshalDoc("", reflect.ValueOf(in)) e.finish() out = e.out return } // An Encoder writes YAML values to an output stream. type Encoder struct { encoder *encoder } // NewEncoder returns a new encoder that writes to w. // The Encoder should be closed after use to flush all data // to w. func NewEncoder(w io.Writer) *Encoder { return &Encoder{ encoder: newEncoderWithWriter(w), } } // Encode writes the YAML encoding of v to the stream. // If multiple items are encoded to the stream, the // second and subsequent document will be preceded // with a "---" document separator, but the first will not. // // See the documentation for Marshal for details about the conversion of Go // values to YAML. func (e *Encoder) Encode(v interface{}) (err error) { defer handleErr(&err) e.encoder.marshalDoc("", reflect.ValueOf(v)) return nil } // Close closes the encoder by writing any remaining data. // It does not write a stream terminating string "...". func (e *Encoder) Close() (err error) { defer handleErr(&err) e.encoder.finish() return nil } func handleErr(err *error) { if v := recover(); v != nil { if e, ok := v.(yamlError); ok { *err = e.err } else { panic(v) } } } type yamlError struct { err error } func fail(err error) { panic(yamlError{err}) } func failf(format string, args ...interface{}) { panic(yamlError{fmt.Errorf("yaml: "+format, args...)}) } // A TypeError is returned by Unmarshal when one or more fields in // the YAML document cannot be properly decoded into the requested // types. When this error is returned, the value is still // unmarshaled partially. type TypeError struct { Errors []string } func (e *TypeError) Error() string { return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n ")) } // -------------------------------------------------------------------------- // Maintain a mapping of keys to structure field indexes // The code in this section was copied from mgo/bson. // structInfo holds details for the serialization of fields of // a given struct. type structInfo struct { FieldsMap map[string]fieldInfo FieldsList []fieldInfo // InlineMap is the number of the field in the struct that // contains an ,inline map, or -1 if there's none. InlineMap int } type fieldInfo struct { Key string Num int OmitEmpty bool Flow bool // Id holds the unique field identifier, so we can cheaply // check for field duplicates without maintaining an extra map. Id int // Inline holds the field index if the field is part of an inlined struct. Inline []int } var structMap = make(map[reflect.Type]*structInfo) var fieldMapMutex sync.RWMutex func getStructInfo(st reflect.Type) (*structInfo, error) { fieldMapMutex.RLock() sinfo, found := structMap[st] fieldMapMutex.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("yaml") 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 "flow": info.Flow = true case "inline": inline = true default: return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st)) } } 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...) } finfo.Id = len(fieldsList) fieldsMap[finfo.Key] = finfo fieldsList = append(fieldsList, finfo) } default: //return nil, errors.New("Option ,inline needs a struct value or map field") return nil, errors.New("Option ,inline needs a struct value 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) } info.Id = len(fieldsList) fieldsList = append(fieldsList, info) fieldsMap[info.Key] = info } sinfo = &structInfo{ FieldsMap: fieldsMap, FieldsList: fieldsList, InlineMap: inlineMap, } fieldMapMutex.Lock() structMap[st] = sinfo fieldMapMutex.Unlock() return sinfo, nil } // IsZeroer is used to check whether an object is zero to // determine whether it should be omitted when marshaling // with the omitempty flag. One notable implementation // is time.Time. type IsZeroer interface { IsZero() bool } func isZero(v reflect.Value) bool { kind := v.Kind() if z, ok := v.Interface().(IsZeroer); ok { if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() { return true } return z.IsZero() } switch kind { case reflect.String: return len(v.String()) == 0 case reflect.Interface, reflect.Ptr: 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.Float32, reflect.Float64: return v.Float() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return v.Uint() == 0 case reflect.Bool: return !v.Bool() case reflect.Struct: vt := v.Type() for i := v.NumField() - 1; i >= 0; i-- { if vt.Field(i).PkgPath != "" { continue // Private field } if !isZero(v.Field(i)) { return false } } return true } return false } ================================================ FILE: vendor/gopkg.in/yaml.v2/yamlh.go ================================================ package yaml import ( "fmt" "io" ) // The version directive data. type yaml_version_directive_t struct { major int8 // The major version number. minor int8 // The minor version number. } // The tag directive data. type yaml_tag_directive_t struct { handle []byte // The tag handle. prefix []byte // The tag prefix. } type yaml_encoding_t int // The stream encoding. const ( // Let the parser choose the encoding. yaml_ANY_ENCODING yaml_encoding_t = iota yaml_UTF8_ENCODING // The default UTF-8 encoding. yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM. yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM. ) type yaml_break_t int // Line break types. const ( // Let the parser choose the break type. yaml_ANY_BREAK yaml_break_t = iota yaml_CR_BREAK // Use CR for line breaks (Mac style). yaml_LN_BREAK // Use LN for line breaks (Unix style). yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style). ) type yaml_error_type_t int // Many bad things could happen with the parser and emitter. const ( // No error is produced. yaml_NO_ERROR yaml_error_type_t = iota yaml_MEMORY_ERROR // Cannot allocate or reallocate a block of memory. yaml_READER_ERROR // Cannot read or decode the input stream. yaml_SCANNER_ERROR // Cannot scan the input stream. yaml_PARSER_ERROR // Cannot parse the input stream. yaml_COMPOSER_ERROR // Cannot compose a YAML document. yaml_WRITER_ERROR // Cannot write to the output stream. yaml_EMITTER_ERROR // Cannot emit a YAML stream. ) // The pointer position. type yaml_mark_t struct { index int // The position index. line int // The position line. column int // The position column. } // Node Styles type yaml_style_t int8 type yaml_scalar_style_t yaml_style_t // Scalar styles. const ( // Let the emitter choose the style. yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = iota yaml_PLAIN_SCALAR_STYLE // The plain scalar style. yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style. yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style. yaml_LITERAL_SCALAR_STYLE // The literal scalar style. yaml_FOLDED_SCALAR_STYLE // The folded scalar style. ) type yaml_sequence_style_t yaml_style_t // Sequence styles. const ( // Let the emitter choose the style. yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota yaml_BLOCK_SEQUENCE_STYLE // The block sequence style. yaml_FLOW_SEQUENCE_STYLE // The flow sequence style. ) type yaml_mapping_style_t yaml_style_t // Mapping styles. const ( // Let the emitter choose the style. yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota yaml_BLOCK_MAPPING_STYLE // The block mapping style. yaml_FLOW_MAPPING_STYLE // The flow mapping style. ) // Tokens type yaml_token_type_t int // Token types. const ( // An empty token. yaml_NO_TOKEN yaml_token_type_t = iota yaml_STREAM_START_TOKEN // A STREAM-START token. yaml_STREAM_END_TOKEN // A STREAM-END token. yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token. yaml_TAG_DIRECTIVE_TOKEN // A TAG-DIRECTIVE token. yaml_DOCUMENT_START_TOKEN // A DOCUMENT-START token. yaml_DOCUMENT_END_TOKEN // A DOCUMENT-END token. yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token. yaml_BLOCK_MAPPING_START_TOKEN // A BLOCK-SEQUENCE-END token. yaml_BLOCK_END_TOKEN // A BLOCK-END token. yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token. yaml_FLOW_SEQUENCE_END_TOKEN // A FLOW-SEQUENCE-END token. yaml_FLOW_MAPPING_START_TOKEN // A FLOW-MAPPING-START token. yaml_FLOW_MAPPING_END_TOKEN // A FLOW-MAPPING-END token. yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token. yaml_FLOW_ENTRY_TOKEN // A FLOW-ENTRY token. yaml_KEY_TOKEN // A KEY token. yaml_VALUE_TOKEN // A VALUE token. yaml_ALIAS_TOKEN // An ALIAS token. yaml_ANCHOR_TOKEN // An ANCHOR token. yaml_TAG_TOKEN // A TAG token. yaml_SCALAR_TOKEN // A SCALAR token. ) func (tt yaml_token_type_t) String() string { switch tt { case yaml_NO_TOKEN: return "yaml_NO_TOKEN" case yaml_STREAM_START_TOKEN: return "yaml_STREAM_START_TOKEN" case yaml_STREAM_END_TOKEN: return "yaml_STREAM_END_TOKEN" case yaml_VERSION_DIRECTIVE_TOKEN: return "yaml_VERSION_DIRECTIVE_TOKEN" case yaml_TAG_DIRECTIVE_TOKEN: return "yaml_TAG_DIRECTIVE_TOKEN" case yaml_DOCUMENT_START_TOKEN: return "yaml_DOCUMENT_START_TOKEN" case yaml_DOCUMENT_END_TOKEN: return "yaml_DOCUMENT_END_TOKEN" case yaml_BLOCK_SEQUENCE_START_TOKEN: return "yaml_BLOCK_SEQUENCE_START_TOKEN" case yaml_BLOCK_MAPPING_START_TOKEN: return "yaml_BLOCK_MAPPING_START_TOKEN" case yaml_BLOCK_END_TOKEN: return "yaml_BLOCK_END_TOKEN" case yaml_FLOW_SEQUENCE_START_TOKEN: return "yaml_FLOW_SEQUENCE_START_TOKEN" case yaml_FLOW_SEQUENCE_END_TOKEN: return "yaml_FLOW_SEQUENCE_END_TOKEN" case yaml_FLOW_MAPPING_START_TOKEN: return "yaml_FLOW_MAPPING_START_TOKEN" case yaml_FLOW_MAPPING_END_TOKEN: return "yaml_FLOW_MAPPING_END_TOKEN" case yaml_BLOCK_ENTRY_TOKEN: return "yaml_BLOCK_ENTRY_TOKEN" case yaml_FLOW_ENTRY_TOKEN: return "yaml_FLOW_ENTRY_TOKEN" case yaml_KEY_TOKEN: return "yaml_KEY_TOKEN" case yaml_VALUE_TOKEN: return "yaml_VALUE_TOKEN" case yaml_ALIAS_TOKEN: return "yaml_ALIAS_TOKEN" case yaml_ANCHOR_TOKEN: return "yaml_ANCHOR_TOKEN" case yaml_TAG_TOKEN: return "yaml_TAG_TOKEN" case yaml_SCALAR_TOKEN: return "yaml_SCALAR_TOKEN" } return "" } // The token structure. type yaml_token_t struct { // The token type. typ yaml_token_type_t // The start/end of the token. start_mark, end_mark yaml_mark_t // The stream encoding (for yaml_STREAM_START_TOKEN). encoding yaml_encoding_t // The alias/anchor/scalar value or tag/tag directive handle // (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN). value []byte // The tag suffix (for yaml_TAG_TOKEN). suffix []byte // The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN). prefix []byte // The scalar style (for yaml_SCALAR_TOKEN). style yaml_scalar_style_t // The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN). major, minor int8 } // Events type yaml_event_type_t int8 // Event types. const ( // An empty event. yaml_NO_EVENT yaml_event_type_t = iota yaml_STREAM_START_EVENT // A STREAM-START event. yaml_STREAM_END_EVENT // A STREAM-END event. yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event. yaml_DOCUMENT_END_EVENT // A DOCUMENT-END event. yaml_ALIAS_EVENT // An ALIAS event. yaml_SCALAR_EVENT // A SCALAR event. yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event. yaml_SEQUENCE_END_EVENT // A SEQUENCE-END event. yaml_MAPPING_START_EVENT // A MAPPING-START event. yaml_MAPPING_END_EVENT // A MAPPING-END event. ) var eventStrings = []string{ yaml_NO_EVENT: "none", yaml_STREAM_START_EVENT: "stream start", yaml_STREAM_END_EVENT: "stream end", yaml_DOCUMENT_START_EVENT: "document start", yaml_DOCUMENT_END_EVENT: "document end", yaml_ALIAS_EVENT: "alias", yaml_SCALAR_EVENT: "scalar", yaml_SEQUENCE_START_EVENT: "sequence start", yaml_SEQUENCE_END_EVENT: "sequence end", yaml_MAPPING_START_EVENT: "mapping start", yaml_MAPPING_END_EVENT: "mapping end", } func (e yaml_event_type_t) String() string { if e < 0 || int(e) >= len(eventStrings) { return fmt.Sprintf("unknown event %d", e) } return eventStrings[e] } // The event structure. type yaml_event_t struct { // The event type. typ yaml_event_type_t // The start and end of the event. start_mark, end_mark yaml_mark_t // The document encoding (for yaml_STREAM_START_EVENT). encoding yaml_encoding_t // The version directive (for yaml_DOCUMENT_START_EVENT). version_directive *yaml_version_directive_t // The list of tag directives (for yaml_DOCUMENT_START_EVENT). tag_directives []yaml_tag_directive_t // The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT). anchor []byte // The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). tag []byte // The scalar value (for yaml_SCALAR_EVENT). value []byte // Is the document start/end indicator implicit, or the tag optional? // (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT). implicit bool // Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT). quoted_implicit bool // The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). style yaml_style_t } func (e *yaml_event_t) scalar_style() yaml_scalar_style_t { return yaml_scalar_style_t(e.style) } func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) } func (e *yaml_event_t) mapping_style() yaml_mapping_style_t { return yaml_mapping_style_t(e.style) } // Nodes const ( yaml_NULL_TAG = "tag:yaml.org,2002:null" // The tag !!null with the only possible value: null. yaml_BOOL_TAG = "tag:yaml.org,2002:bool" // The tag !!bool with the values: true and false. yaml_STR_TAG = "tag:yaml.org,2002:str" // The tag !!str for string values. yaml_INT_TAG = "tag:yaml.org,2002:int" // The tag !!int for integer values. yaml_FLOAT_TAG = "tag:yaml.org,2002:float" // The tag !!float for float values. yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values. yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences. yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping. // Not in original libyaml. yaml_BINARY_TAG = "tag:yaml.org,2002:binary" yaml_MERGE_TAG = "tag:yaml.org,2002:merge" yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str. yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq. yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map. ) type yaml_node_type_t int // Node types. const ( // An empty node. yaml_NO_NODE yaml_node_type_t = iota yaml_SCALAR_NODE // A scalar node. yaml_SEQUENCE_NODE // A sequence node. yaml_MAPPING_NODE // A mapping node. ) // An element of a sequence node. type yaml_node_item_t int // An element of a mapping node. type yaml_node_pair_t struct { key int // The key of the element. value int // The value of the element. } // The node structure. type yaml_node_t struct { typ yaml_node_type_t // The node type. tag []byte // The node tag. // The node data. // The scalar parameters (for yaml_SCALAR_NODE). scalar struct { value []byte // The scalar value. length int // The length of the scalar value. style yaml_scalar_style_t // The scalar style. } // The sequence parameters (for YAML_SEQUENCE_NODE). sequence struct { items_data []yaml_node_item_t // The stack of sequence items. style yaml_sequence_style_t // The sequence style. } // The mapping parameters (for yaml_MAPPING_NODE). mapping struct { pairs_data []yaml_node_pair_t // The stack of mapping pairs (key, value). pairs_start *yaml_node_pair_t // The beginning of the stack. pairs_end *yaml_node_pair_t // The end of the stack. pairs_top *yaml_node_pair_t // The top of the stack. style yaml_mapping_style_t // The mapping style. } start_mark yaml_mark_t // The beginning of the node. end_mark yaml_mark_t // The end of the node. } // The document structure. type yaml_document_t struct { // The document nodes. nodes []yaml_node_t // The version directive. version_directive *yaml_version_directive_t // The list of tag directives. tag_directives_data []yaml_tag_directive_t tag_directives_start int // The beginning of the tag directives list. tag_directives_end int // The end of the tag directives list. start_implicit int // Is the document start indicator implicit? end_implicit int // Is the document end indicator implicit? // The start/end of the document. start_mark, end_mark yaml_mark_t } // The prototype of a read handler. // // The read handler is called when the parser needs to read more bytes from the // source. The handler should write not more than size bytes to the buffer. // The number of written bytes should be set to the size_read variable. // // [in,out] data A pointer to an application data specified by // yaml_parser_set_input(). // [out] buffer The buffer to write the data from the source. // [in] size The size of the buffer. // [out] size_read The actual number of bytes read from the source. // // On success, the handler should return 1. If the handler failed, // the returned value should be 0. On EOF, the handler should set the // size_read to 0 and return 1. type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error) // This structure holds information about a potential simple key. type yaml_simple_key_t struct { possible bool // Is a simple key possible? required bool // Is a simple key required? token_number int // The number of the token. mark yaml_mark_t // The position mark. } // The states of the parser. type yaml_parser_state_t int const ( yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE // Expect the beginning of an implicit document. yaml_PARSE_DOCUMENT_START_STATE // Expect DOCUMENT-START. yaml_PARSE_DOCUMENT_CONTENT_STATE // Expect the content of a document. yaml_PARSE_DOCUMENT_END_STATE // Expect DOCUMENT-END. yaml_PARSE_BLOCK_NODE_STATE // Expect a block node. yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence. yaml_PARSE_FLOW_NODE_STATE // Expect a flow node. yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a block sequence. yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE // Expect an entry of a block sequence. yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE // Expect an entry of an indentless sequence. yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. yaml_PARSE_BLOCK_MAPPING_KEY_STATE // Expect a block mapping key. yaml_PARSE_BLOCK_MAPPING_VALUE_STATE // Expect a block mapping value. yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a flow sequence. yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE // Expect an entry of a flow sequence. yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE // Expect a key of an ordered mapping. yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping. yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE // Expect the and of an ordered mapping entry. yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. yaml_PARSE_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. yaml_PARSE_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE // Expect an empty value of a flow mapping. yaml_PARSE_END_STATE // Expect nothing. ) func (ps yaml_parser_state_t) String() string { switch ps { case yaml_PARSE_STREAM_START_STATE: return "yaml_PARSE_STREAM_START_STATE" case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE" case yaml_PARSE_DOCUMENT_START_STATE: return "yaml_PARSE_DOCUMENT_START_STATE" case yaml_PARSE_DOCUMENT_CONTENT_STATE: return "yaml_PARSE_DOCUMENT_CONTENT_STATE" case yaml_PARSE_DOCUMENT_END_STATE: return "yaml_PARSE_DOCUMENT_END_STATE" case yaml_PARSE_BLOCK_NODE_STATE: return "yaml_PARSE_BLOCK_NODE_STATE" case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE" case yaml_PARSE_FLOW_NODE_STATE: return "yaml_PARSE_FLOW_NODE_STATE" case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE" case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE" case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE" case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE" case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE" case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE" case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE" case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE" case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE" case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE" case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE" case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE" case yaml_PARSE_FLOW_MAPPING_KEY_STATE: return "yaml_PARSE_FLOW_MAPPING_KEY_STATE" case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE" case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE" case yaml_PARSE_END_STATE: return "yaml_PARSE_END_STATE" } return "" } // This structure holds aliases data. type yaml_alias_data_t struct { anchor []byte // The anchor. index int // The node id. mark yaml_mark_t // The anchor mark. } // The parser structure. // // All members are internal. Manage the structure using the // yaml_parser_ family of functions. type yaml_parser_t struct { // Error handling error yaml_error_type_t // Error type. problem string // Error description. // The byte about which the problem occurred. problem_offset int problem_value int problem_mark yaml_mark_t // The error context. context string context_mark yaml_mark_t // Reader stuff read_handler yaml_read_handler_t // Read handler. input_reader io.Reader // File input data. input []byte // String input data. input_pos int eof bool // EOF flag buffer []byte // The working buffer. buffer_pos int // The current position of the buffer. unread int // The number of unread characters in the buffer. raw_buffer []byte // The raw buffer. raw_buffer_pos int // The current position of the buffer. encoding yaml_encoding_t // The input encoding. offset int // The offset of the current position (in bytes). mark yaml_mark_t // The mark of the current position. // Scanner stuff stream_start_produced bool // Have we started to scan the input stream? stream_end_produced bool // Have we reached the end of the input stream? flow_level int // The number of unclosed '[' and '{' indicators. tokens []yaml_token_t // The tokens queue. tokens_head int // The head of the tokens queue. tokens_parsed int // The number of tokens fetched from the queue. token_available bool // Does the tokens queue contain a token ready for dequeueing. indent int // The current indentation level. indents []int // The indentation levels stack. simple_key_allowed bool // May a simple key occur at the current position? simple_keys []yaml_simple_key_t // The stack of simple keys. // Parser stuff state yaml_parser_state_t // The current parser state. states []yaml_parser_state_t // The parser states stack. marks []yaml_mark_t // The stack of marks. tag_directives []yaml_tag_directive_t // The list of TAG directives. // Dumper stuff aliases []yaml_alias_data_t // The alias data. document *yaml_document_t // The currently parsed document. } // Emitter Definitions // The prototype of a write handler. // // The write handler is called when the emitter needs to flush the accumulated // characters to the output. The handler should write @a size bytes of the // @a buffer to the output. // // @param[in,out] data A pointer to an application data specified by // yaml_emitter_set_output(). // @param[in] buffer The buffer with bytes to be written. // @param[in] size The size of the buffer. // // @returns On success, the handler should return @c 1. If the handler failed, // the returned value should be @c 0. // type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error type yaml_emitter_state_t int // The emitter states. const ( // Expect STREAM-START. yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota yaml_EMIT_FIRST_DOCUMENT_START_STATE // Expect the first DOCUMENT-START or STREAM-END. yaml_EMIT_DOCUMENT_START_STATE // Expect DOCUMENT-START or STREAM-END. yaml_EMIT_DOCUMENT_CONTENT_STATE // Expect the content of a document. yaml_EMIT_DOCUMENT_END_STATE // Expect DOCUMENT-END. yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a flow sequence. yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE // Expect an item of a flow sequence. yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. yaml_EMIT_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a flow mapping. yaml_EMIT_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a block sequence. yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE // Expect an item of a block sequence. yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. yaml_EMIT_BLOCK_MAPPING_KEY_STATE // Expect the key of a block mapping. yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping. yaml_EMIT_BLOCK_MAPPING_VALUE_STATE // Expect a value of a block mapping. yaml_EMIT_END_STATE // Expect nothing. ) // The emitter structure. // // All members are internal. Manage the structure using the @c yaml_emitter_ // family of functions. type yaml_emitter_t struct { // Error handling error yaml_error_type_t // Error type. problem string // Error description. // Writer stuff write_handler yaml_write_handler_t // Write handler. output_buffer *[]byte // String output data. output_writer io.Writer // File output data. buffer []byte // The working buffer. buffer_pos int // The current position of the buffer. raw_buffer []byte // The raw buffer. raw_buffer_pos int // The current position of the buffer. encoding yaml_encoding_t // The stream encoding. // Emitter stuff canonical bool // If the output is in the canonical style? best_indent int // The number of indentation spaces. best_width int // The preferred width of the output lines. unicode bool // Allow unescaped non-ASCII characters? line_break yaml_break_t // The preferred line break. state yaml_emitter_state_t // The current emitter state. states []yaml_emitter_state_t // The stack of states. events []yaml_event_t // The event queue. events_head int // The head of the event queue. indents []int // The stack of indentation levels. tag_directives []yaml_tag_directive_t // The list of tag directives. indent int // The current indentation level. flow_level int // The current flow level. root_context bool // Is it the document root context? sequence_context bool // Is it a sequence context? mapping_context bool // Is it a mapping context? simple_key_context bool // Is it a simple mapping key context? line int // The current line. column int // The current column. whitespace bool // If the last character was a whitespace? indention bool // If the last character was an indentation character (' ', '-', '?', ':')? open_ended bool // If an explicit document end is required? // Anchor analysis. anchor_data struct { anchor []byte // The anchor value. alias bool // Is it an alias? } // Tag analysis. tag_data struct { handle []byte // The tag handle. suffix []byte // The tag suffix. } // Scalar analysis. scalar_data struct { value []byte // The scalar value. multiline bool // Does the scalar contain line breaks? flow_plain_allowed bool // Can the scalar be expessed in the flow plain style? block_plain_allowed bool // Can the scalar be expressed in the block plain style? single_quoted_allowed bool // Can the scalar be expressed in the single quoted style? block_allowed bool // Can the scalar be expressed in the literal or folded styles? style yaml_scalar_style_t // The output style. } // Dumper stuff opened bool // If the stream was already opened? closed bool // If the stream was already closed? // The information associated with the document nodes. anchors *struct { references int // The number of references. anchor int // The anchor id. serialized bool // If the node has been emitted? } last_anchor_id int // The last assigned anchor id. document *yaml_document_t // The currently emitted document. } ================================================ FILE: vendor/gopkg.in/yaml.v2/yamlprivateh.go ================================================ package yaml const ( // The size of the input raw buffer. input_raw_buffer_size = 512 // The size of the input buffer. // It should be possible to decode the whole raw buffer. input_buffer_size = input_raw_buffer_size * 3 // The size of the output buffer. output_buffer_size = 128 // The size of the output raw buffer. // It should be possible to encode the whole output buffer. output_raw_buffer_size = (output_buffer_size*2 + 2) // The size of other stacks and queues. initial_stack_size = 16 initial_queue_size = 16 initial_string_size = 16 ) // Check if the character at the specified position is an alphabetical // character, a digit, '_', or '-'. func is_alpha(b []byte, i int) bool { return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-' } // Check if the character at the specified position is a digit. func is_digit(b []byte, i int) bool { return b[i] >= '0' && b[i] <= '9' } // Get the value of a digit. func as_digit(b []byte, i int) int { return int(b[i]) - '0' } // Check if the character at the specified position is a hex-digit. func is_hex(b []byte, i int) bool { return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f' } // Get the value of a hex-digit. func as_hex(b []byte, i int) int { bi := b[i] if bi >= 'A' && bi <= 'F' { return int(bi) - 'A' + 10 } if bi >= 'a' && bi <= 'f' { return int(bi) - 'a' + 10 } return int(bi) - '0' } // Check if the character is ASCII. func is_ascii(b []byte, i int) bool { return b[i] <= 0x7F } // Check if the character at the start of the buffer can be printed unescaped. func is_printable(b []byte, i int) bool { return ((b[i] == 0x0A) || // . == #x0A (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF (b[i] > 0xC2 && b[i] < 0xED) || (b[i] == 0xED && b[i+1] < 0xA0) || (b[i] == 0xEE) || (b[i] == 0xEF && // #xE000 <= . <= #xFFFD !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF)))) } // Check if the character at the specified position is NUL. func is_z(b []byte, i int) bool { return b[i] == 0x00 } // Check if the beginning of the buffer is a BOM. func is_bom(b []byte, i int) bool { return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF } // Check if the character at the specified position is space. func is_space(b []byte, i int) bool { return b[i] == ' ' } // Check if the character at the specified position is tab. func is_tab(b []byte, i int) bool { return b[i] == '\t' } // Check if the character at the specified position is blank (space or tab). func is_blank(b []byte, i int) bool { //return is_space(b, i) || is_tab(b, i) return b[i] == ' ' || b[i] == '\t' } // Check if the character at the specified position is a line break. func is_break(b []byte, i int) bool { return (b[i] == '\r' || // CR (#xD) b[i] == '\n' || // LF (#xA) b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029) } func is_crlf(b []byte, i int) bool { return b[i] == '\r' && b[i+1] == '\n' } // Check if the character is a line break or NUL. func is_breakz(b []byte, i int) bool { //return is_break(b, i) || is_z(b, i) return ( // is_break: b[i] == '\r' || // CR (#xD) b[i] == '\n' || // LF (#xA) b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) // is_z: b[i] == 0) } // Check if the character is a line break, space, or NUL. func is_spacez(b []byte, i int) bool { //return is_space(b, i) || is_breakz(b, i) return ( // is_space: b[i] == ' ' || // is_breakz: b[i] == '\r' || // CR (#xD) b[i] == '\n' || // LF (#xA) b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) b[i] == 0) } // Check if the character is a line break, space, tab, or NUL. func is_blankz(b []byte, i int) bool { //return is_blank(b, i) || is_breakz(b, i) return ( // is_blank: b[i] == ' ' || b[i] == '\t' || // is_breakz: b[i] == '\r' || // CR (#xD) b[i] == '\n' || // LF (#xA) b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) b[i] == 0) } // Determine the width of the character. func width(b byte) int { // Don't replace these by a switch without first // confirming that it is being inlined. if b&0x80 == 0x00 { return 1 } if b&0xE0 == 0xC0 { return 2 } if b&0xF0 == 0xE0 { return 3 } if b&0xF8 == 0xF0 { return 4 } return 0 } ================================================ FILE: vendor/modules.txt ================================================ # github.com/360EntSecGroup-Skylar/excelize v1.3.1-0.20180527032555-9e463b461434 github.com/360EntSecGroup-Skylar/excelize # github.com/PuerkitoBio/purell v1.1.1-0.20180310210909-975f53781597 github.com/PuerkitoBio/purell # github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 github.com/PuerkitoBio/urlesc # github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/alecthomas/template github.com/alecthomas/template/parse # github.com/astaxie/beego v1.9.3-0.20171218111859-f16688817aa4 github.com/astaxie/beego/validation # github.com/boombuler/barcode v1.0.1-0.20180315051053-3c06908149f7 github.com/boombuler/barcode github.com/boombuler/barcode/qr github.com/boombuler/barcode/utils # github.com/dgrijalva/jwt-go v3.1.0+incompatible github.com/dgrijalva/jwt-go # github.com/gin-contrib/sse v0.1.0 github.com/gin-contrib/sse # github.com/gin-gonic/gin v1.4.0 github.com/gin-gonic/gin github.com/gin-gonic/gin/binding github.com/gin-gonic/gin/internal/json github.com/gin-gonic/gin/render # github.com/go-ini/ini v1.32.1-0.20180214101753-32e4be5f41bb github.com/go-ini/ini # github.com/go-openapi/jsonpointer v0.17.0 github.com/go-openapi/jsonpointer # github.com/go-openapi/jsonreference v0.19.0 github.com/go-openapi/jsonreference # github.com/go-openapi/spec v0.19.0 github.com/go-openapi/spec # github.com/go-openapi/swag v0.17.0 github.com/go-openapi/swag # github.com/go-sql-driver/mysql v1.4.1-0.20190510102335-877a9775f068 github.com/go-sql-driver/mysql # github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 github.com/golang/freetype github.com/golang/freetype/raster github.com/golang/freetype/truetype # github.com/golang/protobuf v1.3.1 github.com/golang/protobuf/proto # github.com/gomodule/redigo v2.0.1-0.20180401191855-9352ab68be13+incompatible github.com/gomodule/redigo/internal github.com/gomodule/redigo/redis # github.com/jinzhu/gorm v0.0.0-20180213101209-6e1387b44c64 github.com/jinzhu/gorm github.com/jinzhu/gorm/dialects/mysql # github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d github.com/jinzhu/inflection # github.com/json-iterator/go v1.1.7 github.com/json-iterator/go # github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 github.com/mailru/easyjson/buffer github.com/mailru/easyjson/jlexer github.com/mailru/easyjson/jwriter # github.com/mattn/go-isatty v0.0.8 github.com/mattn/go-isatty # github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd github.com/modern-go/concurrent # github.com/modern-go/reflect2 v1.0.1 github.com/modern-go/reflect2 # github.com/pkg/errors v0.8.1 github.com/pkg/errors # github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/gin-swagger github.com/swaggo/gin-swagger/swaggerFiles # github.com/swaggo/swag v1.5.1 github.com/swaggo/swag # github.com/tealeg/xlsx v1.0.4-0.20180419195153-f36fa3be8893 github.com/tealeg/xlsx # github.com/ugorji/go/codec v1.1.5-pre github.com/ugorji/go/codec # github.com/unknwon/com v1.0.1 github.com/unknwon/com # golang.org/x/image v0.0.0-20180628062038-cc896f830ced golang.org/x/image/font golang.org/x/image/math/fixed # golang.org/x/net v0.0.0-20190611141213-3f473d35a33a golang.org/x/net/context golang.org/x/net/idna golang.org/x/net/webdav golang.org/x/net/webdav/internal/xml # golang.org/x/sys v0.0.0-20190921204832-2dccfee4fd3e golang.org/x/sys/unix # golang.org/x/text v0.3.2 golang.org/x/text/secure/bidirule golang.org/x/text/transform golang.org/x/text/unicode/bidi golang.org/x/text/unicode/norm golang.org/x/text/width # golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b golang.org/x/tools/go/ast/astutil golang.org/x/tools/go/buildutil golang.org/x/tools/go/internal/cgo golang.org/x/tools/go/loader # google.golang.org/appengine v1.6.3 google.golang.org/appengine/cloudsql # gopkg.in/go-playground/validator.v8 v8.18.2 gopkg.in/go-playground/validator.v8 # gopkg.in/yaml.v2 v2.2.2 gopkg.in/yaml.v2