summaryrefslogtreecommitdiff
path: root/examples/docker
diff options
context:
space:
mode:
Diffstat (limited to 'examples/docker')
-rw-r--r--examples/docker/README.md52
-rw-r--r--examples/docker/admin/.dockerignore8
-rw-r--r--examples/docker/admin/.gitignore5
-rw-r--r--examples/docker/admin/Dockerfile15
-rw-r--r--examples/docker/admin/addons/github.com/bosssauce/reference/LICENSE29
-rw-r--r--examples/docker/admin/addons/github.com/bosssauce/reference/README.md3
-rw-r--r--examples/docker/admin/addons/github.com/bosssauce/reference/reference.go150
-rw-r--r--examples/docker/admin/cmd/ponzu/LICENSE29
-rw-r--r--examples/docker/admin/cmd/ponzu/add.go167
-rw-r--r--examples/docker/admin/cmd/ponzu/cli_test.go65
-rw-r--r--examples/docker/admin/cmd/ponzu/generate.go263
-rw-r--r--examples/docker/admin/cmd/ponzu/main.go293
-rw-r--r--examples/docker/admin/cmd/ponzu/options.go489
-rw-r--r--examples/docker/admin/cmd/ponzu/paths.go44
-rw-r--r--examples/docker/admin/cmd/ponzu/ponzu.json3
-rw-r--r--examples/docker/admin/cmd/ponzu/templates/gen-checkbox.tmpl5
-rw-r--r--examples/docker/admin/cmd/ponzu/templates/gen-content.tmpl39
-rw-r--r--examples/docker/admin/cmd/ponzu/templates/gen-custom.tmpl6
-rw-r--r--examples/docker/admin/cmd/ponzu/templates/gen-file.tmpl4
-rw-r--r--examples/docker/admin/cmd/ponzu/templates/gen-hidden.tmpl3
-rw-r--r--examples/docker/admin/cmd/ponzu/templates/gen-input.tmpl5
-rw-r--r--examples/docker/admin/cmd/ponzu/templates/gen-richtext.tmpl4
-rw-r--r--examples/docker/admin/cmd/ponzu/templates/gen-select.tmpl5
-rw-r--r--examples/docker/admin/cmd/ponzu/templates/gen-tags.tmpl4
-rw-r--r--examples/docker/admin/cmd/ponzu/templates/gen-textarea.tmpl4
-rw-r--r--examples/docker/admin/cmd/ponzu/usage.go201
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/.gitignore4
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/LICENSE20
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/Makefile18
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/README.md858
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/appveyor.yml18
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_386.go10
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_amd64.go10
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm.go28
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm64.go12
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_linux.go10
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_openbsd.go27
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc.go9
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64.go9
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64le.go12
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_s390x.go12
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix.go89
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix_solaris.go90
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_windows.go144
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/boltsync_unix.go8
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket.go778
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket_test.go1909
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main.go1740
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main_test.go356
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor.go400
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor_test.go817
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db.go1036
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db_test.go1706
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/doc.go44
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/errors.go71
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist.go248
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist_test.go158
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node.go604
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node_test.go156
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page.go178
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page_test.go72
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/quick_test.go79
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/simulation_test.go329
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx.go682
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx_test.go716
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/LICENSE29
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/README.md3
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/reference.go150
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/.travis.yml19
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/LICENSE27
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/README.md66
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/cache.go261
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/converter.go145
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder.go343
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder_test.go1460
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/doc.go148
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/LICENSE21
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/README.md51
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email.go119
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email_test.go19
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/LICENSE19
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/README.md43
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/doc.go40
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/jwt.go204
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/content/.hold0
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/content/song.go73
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/dom.go297
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/editor.go267
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/elements.go520
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/repeaters.go442
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/values.go78
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/manager/manager.go154
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/addon/addon.go239
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/addon/api.go80
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/addon/manager.go117
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/admin.go629
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/config/config.go186
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/filesystem.go35
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/handlers.go2277
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/server.go59
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/common/js/jquery-2.1.4.min.js4
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/common/js/util.js86
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/css/admin.css249
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/css/material-icons.css23
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/css/materialize.min.css16
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/icons-regular.woff2bin46736 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.eotbin20966 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.ttfbin127744 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.woffbin62876 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.woff2bin49976 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.eotbin20940 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.ttfbin126792 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.woffbin62316 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.woff2bin49380 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.eotbin21364 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.ttfbin127488 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.woffbin62980 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.woff2bin50224 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.eotbin21320 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.ttfbin126072 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.woffbin61736 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.woff2bin49236 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.eotbin21659 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.ttfbin127584 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.woffbin61628 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.woff2bin48524 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/img/ponzu-file.pngbin25752 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/js/chart.bundle.min.js15
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/js/materialize.min.js10
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/css/materialNote.css2160
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/css/materialNote.css.map7
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Bold.ttfbin127744 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Bold.woffbin62876 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Bold.woff2bin49976 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Light.ttfbin126792 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Light.woffbin62316 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Light.woff2bin49380 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Medium.ttfbin127488 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Medium.woffbin62980 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Medium.woff2bin50224 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Regular.ttfbin126072 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Regular.woffbin61736 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Regular.woff2bin49236 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Thin.ttfbin127584 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Thin.woffbin61628 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Thin.woff2bin48524 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/js/ckMaterializeOverrides.js172
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/js/materialNote.js7473
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/license.txt21
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_buttons.scss157
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_cards.scss152
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_collapsible.scss85
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_color.scss412
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_dropdown.scss40
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_form.scss886
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_global.scss718
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_grid.scss117
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_icons-material-design.scss3257
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_materialbox.scss41
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_mixins.scss5
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_modal.scss90
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_navbar.scss144
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_normalize.scss427
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_prefixer.scss376
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_preloader.scss332
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_roboto.scss38
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_sideNav.scss111
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_slider.scss92
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_table_of_contents.scss33
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_tabs.scss47
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_toast.scss63
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_tooltip.scss34
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_typography.scss58
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_variables.scss152
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_waves.scss167
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/date_picker/_default.date.scss435
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/date_picker/_default.scss201
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/date_picker/_default.time.scss125
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/materialNote.scss734
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/materialize.scss38
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/upload/backup.go113
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/upload/upload.go96
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/user/auth.go145
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/analytics/backup.go26
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/analytics/batch.go98
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/analytics/init.go349
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/cors.go74
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/create.go230
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/delete.go140
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/gzip.go64
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/handlers.go196
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/hide.go27
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/json.go57
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/omit.go41
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/push.go52
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/record.go16
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/search.go82
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/server.go18
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/update.go224
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/auth.go34
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/addon.go165
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/backup.go26
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/cache.go56
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/config.go256
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/content.go722
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/index.go85
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/init.go121
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/search.go145
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/user.go266
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/item/item.go287
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/item/types.go39
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/tls/devcerts.go148
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/tls/enable.go78
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/tls/enabledev.go29
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/.travis.yml21
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/LICENSE20
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/README.md65
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/benchmarks_test.go123
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/uuid.go481
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/uuid_test.go633
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/LICENSE20
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/README.md371
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/gjson.go1942
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/logo.pngbin15936 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/.travis.yml1
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/LICENSE21
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/README.md278
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/logo.pngbin16874 -> 0 bytes
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/sjson.go653
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert.go776
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert_test.go390
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache.go130
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache_test.go58
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal.go125
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal_test.go190
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/bcrypt/base64.go35
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/bcrypt/bcrypt.go294
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go226
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/context.go156
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/context_test.go583
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go74
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go28
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go147
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go79
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go105
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/go17.go72
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/pre_go17.go300
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/withtimeout_test.go26
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/.gitignore2
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/Dockerfile51
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/Makefile3
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/README20
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/client_conn_pool.go256
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/configure_transport.go80
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/errors.go130
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/errors_test.go24
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/fixed_buffer.go60
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/fixed_buffer_test.go128
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/flow.go50
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/flow_test.go53
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/frame.go1556
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/frame_test.go1102
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go16.go43
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go17.go106
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go17_not18.go36
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go18.go50
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go18_test.go66
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/gotrack.go170
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/gotrack_test.go33
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/.gitignore5
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/Makefile8
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/README16
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/h2demo.go486
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/launch.go302
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/rootCA.key27
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/rootCA.pem26
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/rootCA.srl1
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/server.crt20
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/server.key27
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2i/README.md97
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2i/h2i.go509
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/headermap.go78
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/encode.go251
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/encode_test.go330
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/hpack.go542
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/hpack_test.go854
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/huffman.go212
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/tables.go352
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/http2.go387
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/http2_test.go199
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/not_go16.go46
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/not_go17.go87
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/not_go18.go27
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/pipe.go153
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/pipe_test.go109
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/server.go2753
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/server_push_test.go521
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/server_test.go3610
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/testdata/draft-ietf-httpbis-http2.xml5021
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/transport.go2129
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/transport_test.go2916
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/write.go370
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched.go242
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_priority.go452
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_priority_test.go541
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_random.go72
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_random_test.go44
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_test.go125
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/z_spec_test.go356
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/transform/examples_test.go37
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/transform/transform.go705
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/transform/transform_test.go1317
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/composition.go514
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/composition_test.go130
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/example_iter_test.go82
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/example_test.go27
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/forminfo.go256
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/forminfo_test.go54
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/input.go105
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/iter.go450
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/iter_test.go98
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/maketables.go978
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/norm_test.go14
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/normalize.go608
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/normalize_test.go1226
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/readwriter.go126
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/readwriter_test.go56
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/tables.go7627
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/transform.go88
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/transform_test.go101
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/trie.go54
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/triegen.go117
-rw-r--r--examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/ucd_test.go275
-rw-r--r--examples/docker/admin/content/.hold0
-rw-r--r--examples/docker/admin/content/song.go73
-rw-r--r--examples/docker/admin/deployment/README.md11
-rw-r--r--examples/docker/admin/deployment/sysv/ponzu-server68
-rwxr-xr-xexamples/docker/admin/start_admin.sh26
-rw-r--r--examples/docker/docker-compose.yml32
-rw-r--r--examples/docker/web/Dockerfile2
-rw-r--r--examples/docker/web/nginx.conf34
-rw-r--r--examples/docker/web/public/css/main.css22
-rw-r--r--examples/docker/web/public/css/normalize.css427
-rw-r--r--examples/docker/web/public/css/skeleton.css418
-rw-r--r--examples/docker/web/public/index.html34
-rw-r--r--examples/docker/web/public/js/main.js43
346 files changed, 0 insertions, 101270 deletions
diff --git a/examples/docker/README.md b/examples/docker/README.md
deleted file mode 100644
index 55566b1..0000000
--- a/examples/docker/README.md
+++ /dev/null
@@ -1,52 +0,0 @@
-## Example of Running Ponzu with Docker
-
-This docker-compose contains 2 docker containers:
-
-1. web - a basic nginx front end, with Javascript ajax accessing the /api
-2. admin - an example ponzu container
-
-The admin contain is based on the official Ponzu Docker image **NEEDS LINK**
-
-### Running the example
-
-```bash
-# build the containers
-docker-compose build
-
-#start the containers in the background
-docker-compose start -d
-```
-
-#### Then follow these steps:
-1. Visit the http://localhost:3000/admin to configure Ponzu.
-2. Add several songs http://localhost:3000/admin/contents?type=Song
-3. Visit http://localhost:3000/ to see the rest service accessed via AJAX
-
-Stop the containers:
-```
-docker-compose stop
-```
-
-### Web Container
-This nginx web container takes any incoming requests and if it matches `/api*` or `/admin*` it will then route it to the exposed ports :8080 on the ponzu container
-
-### Ponzu - Admin Container
-
-The ponzu container has a small [startup script](./admin/start_admin_.sh) which symlinks and logs or database files into a Docker Volume. If you need access to the ponzu logs, it is exposed a Volume.
-
-#### Accessing the Ponzu terminal in Development
-
-Make sure you have no running docker images `docker ps`. Then use the following command to start an interactive shell into the docker container.
-
-```bash
-# make sure the containers are built
-docker-compose build
-
-# start and tty into the container
-docker run -v $(pwd)/admin:/go/src/project -it docker_admin
-
-# run a ponzu command
-ponzu generate content message title:"string" description:"string"
-```
-
-After the above generate command `message.go` content type is now available in your local filesystem. Use `docker-compose build` then `docker-compose up -d` to see the new model in the admin.
diff --git a/examples/docker/admin/.dockerignore b/examples/docker/admin/.dockerignore
deleted file mode 100644
index 771d49f..0000000
--- a/examples/docker/admin/.dockerignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# These directories should not be copied over from the local machine
-uploads
-search
-system.db
-analytics.db
-
-# ponzu-server should be built from each startup
-ponzu-server \ No newline at end of file
diff --git a/examples/docker/admin/.gitignore b/examples/docker/admin/.gitignore
deleted file mode 100644
index bcc10dc..0000000
--- a/examples/docker/admin/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-search
-uploads
-analytics.db
-system.db
-ponzu-server \ No newline at end of file
diff --git a/examples/docker/admin/Dockerfile b/examples/docker/admin/Dockerfile
deleted file mode 100644
index 5130818..0000000
--- a/examples/docker/admin/Dockerfile
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM krismeister/ponzu
-
-ENV PONZU_SHARE /ponzu-share
-
-# This is where you want to mount your project:
-ENV PROJECT_FOLDER /go/src/project
-
-VOLUME $PONZU_SHARE
-RUN mkdir $PROJECT_FOLDER
-
-WORKDIR $PROJECT_FOLDER
-EXPOSE 8080
-
-# its better to run this in compose
-# CMD [ "bash" , "/go/src/project/start_admin.sh start" ] \ No newline at end of file
diff --git a/examples/docker/admin/addons/github.com/bosssauce/reference/LICENSE b/examples/docker/admin/addons/github.com/bosssauce/reference/LICENSE
deleted file mode 100644
index 720d6cd..0000000
--- a/examples/docker/admin/addons/github.com/bosssauce/reference/LICENSE
+++ /dev/null
@@ -1,29 +0,0 @@
-BSD 3-Clause License
-
-Copyright (c) 2016 Boss Sauce Creative, LLC.
-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. \ No newline at end of file
diff --git a/examples/docker/admin/addons/github.com/bosssauce/reference/README.md b/examples/docker/admin/addons/github.com/bosssauce/reference/README.md
deleted file mode 100644
index 57f008c..0000000
--- a/examples/docker/admin/addons/github.com/bosssauce/reference/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Reference
-
-A Ponzu addon to embed a reference to a content type from within another content type in the CMS.
diff --git a/examples/docker/admin/addons/github.com/bosssauce/reference/reference.go b/examples/docker/admin/addons/github.com/bosssauce/reference/reference.go
deleted file mode 100644
index 753fa41..0000000
--- a/examples/docker/admin/addons/github.com/bosssauce/reference/reference.go
+++ /dev/null
@@ -1,150 +0,0 @@
-// Package reference is a Ponzu addon to enable content editors to create
-// references to other content types which are stored as query strings within
-// the referencer's content DB
-package reference
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "html/template"
- "log"
- "strings"
-
- "github.com/ponzu-cms/ponzu/management/editor"
- "github.com/ponzu-cms/ponzu/system/addon"
-)
-
-// Select returns the []byte of a <select> HTML element plus internal <options> with a label.
-// IMPORTANT:
-// The `fieldName` argument will cause a panic if it is not exactly the string
-// form of the struct field that this editor input is representing
-func Select(fieldName string, p interface{}, attrs map[string]string, contentType, tmplString string) []byte {
- options, err := encodeDataToOptions(contentType, tmplString)
- if err != nil {
- log.Println("Error encoding data to options for", contentType, err)
- return nil
- }
-
- return editor.Select(fieldName, p, attrs, options)
-}
-
-// SelectRepeater returns the []byte of a <select> HTML element plus internal <options> with a label.
-// It also includes repeat controllers (+ / -) so the element can be
-// dynamically multiplied or reduced.
-// IMPORTANT:
-// The `fieldName` argument will cause a panic if it is not exactly the string
-// form of the struct field that this editor input is representing
-func SelectRepeater(fieldName string, p interface{}, attrs map[string]string, contentType, tmplString string) []byte {
- scope := editor.TagNameFromStructField(fieldName, p)
- html := bytes.Buffer{}
- _, err := html.WriteString(`<span class="__ponzu-repeat ` + scope + `">`)
- if err != nil {
- log.Println("Error writing HTML string to SelectRepeater buffer")
- return nil
- }
-
- if _, ok := attrs["class"]; ok {
- attrs["class"] += " browser-default"
- } else {
- attrs["class"] = "browser-default"
- }
-
- // find the field values in p to determine if an option is pre-selected
- fieldVals := editor.ValueFromStructField(fieldName, p)
- vals := strings.Split(fieldVals, "__ponzu")
-
- options, err := encodeDataToOptions(contentType, tmplString)
- if err != nil {
- log.Println("Error encoding data to options for", contentType, err)
- return nil
- }
-
- for _, val := range vals {
- sel := editor.NewElement("select", attrs["label"], fieldName, p, attrs)
- var opts []*editor.Element
-
- // provide a call to action for the select element
- cta := &editor.Element{
- TagName: "option",
- Attrs: map[string]string{"disabled": "true", "selected": "true"},
- Data: "Select an option...",
- ViewBuf: &bytes.Buffer{},
- }
-
- // provide a selection reset (will store empty string in db)
- reset := &editor.Element{
- TagName: "option",
- Attrs: map[string]string{"value": ""},
- Data: "None",
- ViewBuf: &bytes.Buffer{},
- }
-
- opts = append(opts, cta, reset)
-
- for k, v := range options {
- optAttrs := map[string]string{"value": k}
- if k == val {
- optAttrs["selected"] = "true"
- }
- opt := &editor.Element{
- TagName: "option",
- Attrs: optAttrs,
- Data: v,
- ViewBuf: &bytes.Buffer{},
- }
-
- opts = append(opts, opt)
- }
-
- _, err := html.Write(editor.DOMElementWithChildrenSelect(sel, opts))
- if err != nil {
- log.Println("Error writing DOMElementWithChildrenSelect to SelectRepeater buffer")
- return nil
- }
- }
-
- _, err = html.WriteString("</span>")
- if err != nil {
- log.Println("Error writing HTML string to SelectRepeater buffer")
- return nil
- }
-
- return append(html.Bytes(), editor.RepeatController(fieldName, p, "select", ".input-field")...)
-}
-
-func encodeDataToOptions(contentType, tmplString string) (map[string]string, error) {
- // encode all content type from db into options map
- // options in form of map["/api/content?type=<contentType>&id=<id>"]t.String()
- options := make(map[string]string)
-
- var all map[string]interface{}
- j := addon.ContentAll(contentType)
-
- err := json.Unmarshal(j, &all)
- if err != nil {
- return nil, err
- }
-
- // make template for option html display
- tmpl := template.Must(template.New(contentType).Parse(tmplString))
-
- // make data something usable to iterate over and assign options
- data := all["data"].([]interface{})
-
- for i := range data {
- item := data[i].(map[string]interface{})
- k := fmt.Sprintf("/api/content?type=%s&id=%.0f", contentType, item["id"].(float64))
- v := &bytes.Buffer{}
- err := tmpl.Execute(v, item)
- if err != nil {
- return nil, fmt.Errorf(
- "Error executing template for reference of %s: %s",
- contentType, err.Error())
- }
-
- options[k] = v.String()
- }
-
- return options, nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/LICENSE b/examples/docker/admin/cmd/ponzu/LICENSE
deleted file mode 100644
index 720d6cd..0000000
--- a/examples/docker/admin/cmd/ponzu/LICENSE
+++ /dev/null
@@ -1,29 +0,0 @@
-BSD 3-Clause License
-
-Copyright (c) 2016 Boss Sauce Creative, LLC.
-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. \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/add.go b/examples/docker/admin/cmd/ponzu/add.go
deleted file mode 100644
index 05d6f16..0000000
--- a/examples/docker/admin/cmd/ponzu/add.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package main
-
-import (
- "errors"
- "fmt"
- "io"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
-)
-
-// use `go get` to download addon and add to $GOPATH/src, useful
-// for IDE auto-import and code completion, then copy entire directory
-// tree to project's ./addons folder
-func getAddon(args []string) error {
-
- var cmdOptions []string
- var addonPath = args[1]
-
- // Go get
- cmdOptions = append(cmdOptions, "get", addonPath)
- get := exec.Command(gocmd, cmdOptions...)
- get.Stderr = os.Stderr
- get.Stdout = os.Stdout
-
- err := get.Start()
- if err != nil {
- return addError(err)
- }
- err = get.Wait()
- if err != nil {
- return addError(err)
- }
-
- // copy to ./addons folder
- // resolve GOPATH
- gopath, err := getGOPATH()
- if err != nil {
- return addError(err)
- }
-
- pwd, err := os.Getwd()
- if err != nil {
- return addError(err)
- }
-
- src := filepath.Join(gopath, "src", addonPath)
-
- // Need to strip the addon name for copyAll?
- last := filepath.Base(addonPath)
- dest := filepath.Join(pwd, "addons", strings.Replace(addonPath, last, "", 1))
-
- err = replicateAll(src, dest)
- if err != nil {
- return addError(err)
- }
- return nil
-}
-
-// this is distinct from copyAll() in that files are copied, not moved,
-// since we also need them to remain in $GOPATH/src
-// thanks to @markc of stack overflow for the copyFile and copyFileContents functions
-func replicateAll(src, dst string) error {
- err := filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
-
- sep := string(filepath.Separator)
-
- // base == the ponzu project dir + string(filepath.Separator)
- parts := strings.Split(src, sep)
- base := strings.Join(parts[:len(parts)-1], sep)
- base += sep
-
- target := filepath.Join(dst, path[len(base):])
-
- // if its a directory, make dir in dst
- if info.IsDir() {
- err := os.MkdirAll(target, os.ModeDir|os.ModePerm)
- if err != nil {
- return err
- }
- } else {
- // if its a file, copy file to dir of dst
- err = copyFile(path, target)
- if err != nil {
- return err
- }
- }
-
- return nil
- })
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// copyFile copies a file from src to dst. if src and dst files exist, and are
-// the same, then return success. Otherise, attempt to create a hard link
-// between the two files. If that fail, copy the file contents from src to dst.
-// thanks to Stack Overflow
-func copyFile(src, dst string) (err error) {
- sfi, err := os.Stat(src)
- if err != nil {
- return
- }
- if !sfi.Mode().IsRegular() {
- // cannot copy non-regular files (e.g., directories,
- // symlinks, devices, etc.)
- return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
- }
- dfi, err := os.Stat(dst)
- if err != nil {
- if !os.IsNotExist(err) {
- return
- }
- } else {
- if !(dfi.Mode().IsRegular()) {
- return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
- }
- if os.SameFile(sfi, dfi) {
- return
- }
- }
- if err = os.Link(src, dst); err == nil {
- return
- }
- err = copyFileContents(src, dst)
- return
-}
-
-// copyFileContents copies the contents of the file named src to the file named
-// by dst. The file will be created if it does not already exist. If the
-// destination file exists, all it's contents will be replaced by the contents
-// of the source file.
-// Thanks for Stack Overflow
-func copyFileContents(src, dst string) (err error) {
- in, err := os.Open(src)
- if err != nil {
- return
- }
- defer in.Close()
- out, err := os.Create(dst)
- if err != nil {
- return
- }
- defer func() {
- cerr := out.Close()
- if err == nil {
- err = cerr
- }
- }()
- if _, err = io.Copy(out, in); err != nil {
- return
- }
- err = out.Sync()
- return
-}
-
-// generic error return
-func addError(err error) error {
- return errors.New("Ponzu add failed. " + "\n" + err.Error())
-}
diff --git a/examples/docker/admin/cmd/ponzu/cli_test.go b/examples/docker/admin/cmd/ponzu/cli_test.go
deleted file mode 100644
index 76feac3..0000000
--- a/examples/docker/admin/cmd/ponzu/cli_test.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package main
-
-import "testing"
-
-func TestParseType(t *testing.T) {
- // blog title:string Author:string PostCategory:string content:string some_thing:int
- args := []string{
- "blog", "title:string", "Author:string",
- "PostCategory:string", "content:string",
- "some_thing:int", "Some_otherThing:float64",
- }
-
- gt, err := parseType(args)
- if err != nil {
- t.Errorf("Failed: %s", err.Error())
- }
-
- if gt.Name != "Blog" {
- t.Errorf("Expected %s, got: %s", "Blog", gt.Name)
- }
-}
-
-func TestFieldJSONName(t *testing.T) {
- cases := map[string]string{
- "_T": "t",
- "T": "t",
- "_tT_": "t_t_",
- "TestCapsNoSym": "test_caps_no_sym",
- "test_Some_caps_Sym": "test_some_caps_sym",
- "testnocaps": "testnocaps",
- "_Test_Caps_Sym_odd": "test_caps_sym_odd",
- "test-hyphen": "test-hyphen",
- "Test-hyphen-Caps": "test-hyphen-caps",
- "Test-Hyphen_Sym-Caps": "test-hyphen_sym-caps",
- }
-
- for input, expected := range cases {
- output := fieldJSONName(input)
- if output != expected {
- t.Errorf("Expected: %s, got: %s", expected, output)
- }
- }
-}
-
-func TestFieldName(t *testing.T) {
- cases := map[string]string{
- "_T": "T",
- "T": "T",
- "_tT_": "TT",
- "TestCapsNoSym": "TestCapsNoSym",
- "test_Some_caps_Sym": "TestSomeCapsSym",
- "testnocaps": "Testnocaps",
- "_Test_Caps_Sym_odd": "TestCapsSymOdd",
- "test-hyphen": "TestHyphen",
- "Test-hyphen-Caps": "TestHyphenCaps",
- "Test-Hyphen_Sym-Caps": "TestHyphenSymCaps",
- }
-
- for input, expected := range cases {
- output := fieldName(input)
- if output != expected {
- t.Errorf("Expected: %s, got: %s", expected, output)
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/generate.go b/examples/docker/admin/cmd/ponzu/generate.go
deleted file mode 100644
index a4a9d2c..0000000
--- a/examples/docker/admin/cmd/ponzu/generate.go
+++ /dev/null
@@ -1,263 +0,0 @@
-package main
-
-import (
- "bytes"
- "fmt"
- "go/format"
- "os"
- "path/filepath"
- "strings"
- "text/template"
-)
-
-type generateType struct {
- Name string
- Initial string
- Fields []generateField
-}
-
-type generateField struct {
- Name string
- Initial string
- TypeName string
- JSONName string
- View string
-}
-
-// blog title:string Author:string PostCategory:string content:string some_thing:int
-func parseType(args []string) (generateType, error) {
- t := generateType{
- Name: fieldName(args[0]),
- }
- t.Initial = strings.ToLower(string(t.Name[0]))
-
- fields := args[1:]
- for _, field := range fields {
- f, err := parseField(field, t)
- if err != nil {
- return generateType{}, err
- }
- // NEW
- // set initial (1st character of the type's name) on field so we don't need
- // to set the template variable like was done in prior version
- f.Initial = t.Initial
-
- t.Fields = append(t.Fields, f)
- }
-
- return t, nil
-}
-
-func parseField(raw string, gt generateType) (generateField, error) {
- // contents:string or // contents:string:richtext
- if !strings.Contains(raw, ":") {
- return generateField{}, fmt.Errorf("Invalid generate argument. [%s]", raw)
- }
-
- data := strings.Split(raw, ":")
-
- field := generateField{
- Name: fieldName(data[0]),
- Initial: gt.Initial,
- TypeName: strings.ToLower(data[1]),
- JSONName: fieldJSONName(data[0]),
- }
-
- fieldType := "input"
- if len(data) == 3 {
- fieldType = data[2]
- }
-
- err := setFieldView(&field, fieldType)
- if err != nil {
- return generateField{}, err
- }
-
- return field, nil
-}
-
-// get the initial field name passed and check it for all possible cases
-// MyTitle:string myTitle:string my_title:string -> MyTitle
-// error-message:string -> ErrorMessage
-func fieldName(name string) string {
- // remove _ or - if first character
- if name[0] == '-' || name[0] == '_' {
- name = name[1:]
- }
-
- // remove _ or - if last character
- if name[len(name)-1] == '-' || name[len(name)-1] == '_' {
- name = name[:len(name)-1]
- }
-
- // upcase the first character
- name = strings.ToUpper(string(name[0])) + name[1:]
-
- // remove _ or - character, and upcase the character immediately following
- for i := 0; i < len(name); i++ {
- r := rune(name[i])
- if isUnderscore(r) || isHyphen(r) {
- up := strings.ToUpper(string(name[i+1]))
- name = name[:i] + up + name[i+2:]
- }
- }
-
- return name
-}
-
-// get the initial field name passed and convert to json-like name
-// MyTitle:string myTitle:string my_title:string -> my_title
-// error-message:string -> error-message
-func fieldJSONName(name string) string {
- // remove _ or - if first character
- if name[0] == '-' || name[0] == '_' {
- name = name[1:]
- }
-
- // downcase the first character
- name = strings.ToLower(string(name[0])) + name[1:]
-
- // check for uppercase character, downcase and insert _ before it if i-1
- // isn't already _ or -
- for i := 0; i < len(name); i++ {
- r := rune(name[i])
- if isUpper(r) {
- low := strings.ToLower(string(r))
- if name[i-1] == '_' || name[i-1] == '-' {
- name = name[:i] + low + name[i+1:]
- } else {
- name = name[:i] + "_" + low + name[i+1:]
- }
- }
- }
-
- return name
-}
-
-// set the specified view inside the editor field for a generated field for a type
-func setFieldView(field *generateField, viewType string) error {
- var err error
- var tmpl *template.Template
- buf := &bytes.Buffer{}
-
- pwd, err := os.Getwd()
- if err != nil {
- return err
- }
-
- tmplDir := filepath.Join(pwd, "cmd", "ponzu", "templates")
- tmplFrom := func(filename string) (*template.Template, error) {
- return template.ParseFiles(filepath.Join(tmplDir, filename))
- }
-
- viewType = strings.ToLower(viewType)
- switch viewType {
- case "checkbox":
- tmpl, err = tmplFrom("gen-checkbox.tmpl")
- case "custom":
- tmpl, err = tmplFrom("gen-custom.tmpl")
- case "file":
- tmpl, err = tmplFrom("gen-file.tmpl")
- case "hidden":
- tmpl, err = tmplFrom("gen-hidden.tmpl")
- case "input", "text":
- tmpl, err = tmplFrom("gen-input.tmpl")
- case "richtext":
- tmpl, err = tmplFrom("gen-richtext.tmpl")
- case "select":
- tmpl, err = tmplFrom("gen-select.tmpl")
- case "textarea":
- tmpl, err = tmplFrom("gen-textarea.tmpl")
- case "tags":
- tmpl, err = tmplFrom("gen-tags.tmpl")
- default:
- msg := fmt.Sprintf("'%s' is not a recognized view type. Using 'input' instead.", viewType)
- fmt.Println(msg)
- tmpl, err = tmplFrom("gen-input.tmpl")
- }
-
- if err != nil {
- return err
- }
-
- err = tmpl.Execute(buf, field)
- if err != nil {
- return err
- }
-
- field.View = buf.String()
-
- return nil
-}
-
-func isUpper(char rune) bool {
- if char >= 'A' && char <= 'Z' {
- return true
- }
-
- return false
-}
-
-func isUnderscore(char rune) bool {
- return char == '_'
-}
-
-func isHyphen(char rune) bool {
- return char == '-'
-}
-
-func generateContentType(args []string) error {
- name := args[0]
- fileName := strings.ToLower(name) + ".go"
-
- // open file in ./content/ dir
- // if exists, alert user of conflict
- pwd, err := os.Getwd()
- if err != nil {
- return err
- }
-
- contentDir := filepath.Join(pwd, "content")
- filePath := filepath.Join(contentDir, fileName)
-
- if _, err := os.Stat(filePath); !os.IsNotExist(err) {
- return fmt.Errorf("Please remove '%s' before executing this command.", fileName)
- }
-
- // no file exists.. ok to write new one
- file, err := os.Create(filePath)
- defer file.Close()
- if err != nil {
- return err
- }
-
- // parse type info from args
- gt, err := parseType(args)
- if err != nil {
- return fmt.Errorf("Failed to parse type args: %s", err.Error())
- }
-
- tmplPath := filepath.Join(pwd, "cmd", "ponzu", "templates", "gen-content.tmpl")
- tmpl, err := template.ParseFiles(tmplPath)
- if err != nil {
- return fmt.Errorf("Failed to parse template: %s", err.Error())
- }
-
- buf := &bytes.Buffer{}
- err = tmpl.Execute(buf, gt)
- if err != nil {
- return fmt.Errorf("Failed to execute template: %s", err.Error())
- }
-
- fmtBuf, err := format.Source(buf.Bytes())
- if err != nil {
- return fmt.Errorf("Failed to format template: %s", err.Error())
- }
-
- _, err = file.Write(fmtBuf)
- if err != nil {
- return fmt.Errorf("Failed to write generated file buffer: %s", err.Error())
- }
-
- return nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/main.go b/examples/docker/admin/cmd/ponzu/main.go
deleted file mode 100644
index b3dc708..0000000
--- a/examples/docker/admin/cmd/ponzu/main.go
+++ /dev/null
@@ -1,293 +0,0 @@
-package main
-
-import (
- "flag"
- "fmt"
- "log"
- "net/http"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
-
- "github.com/ponzu-cms/ponzu/system/admin"
- "github.com/ponzu-cms/ponzu/system/api"
- "github.com/ponzu-cms/ponzu/system/api/analytics"
- "github.com/ponzu-cms/ponzu/system/db"
- "github.com/ponzu-cms/ponzu/system/tls"
-
- _ "github.com/ponzu-cms/ponzu/content"
-)
-
-var (
- usage = usageHeader + usageNew + usageGenerate +
- usageBuild + usageRun + usageUpgrade + usageAdd + usageVersion
- port int
- httpsport int
- https bool
- devhttps bool
- cli bool
-
- // for ponzu internal / core development
- dev bool
- fork string
- gocmd string
-)
-
-func main() {
- flag.Usage = func() {
- fmt.Println(usage)
- }
-
- flag.IntVar(&port, "port", 8080, "port for ponzu to bind its HTTP listener")
- flag.IntVar(&httpsport, "httpsport", 443, "port for ponzu to bind its HTTPS listener")
- flag.BoolVar(&https, "https", false, "enable automatic TLS/SSL certificate management")
- flag.BoolVar(&devhttps, "devhttps", false, "[dev environment] enable automatic TLS/SSL certificate management")
- flag.BoolVar(&dev, "dev", false, "modify environment for Ponzu core development")
- flag.BoolVar(&cli, "cli", false, "specify that information should be returned about the CLI, not project")
- flag.StringVar(&fork, "fork", "", "modify repo source for Ponzu core development")
- flag.StringVar(&gocmd, "gocmd", "go", "custom go command if using beta or new release of Go")
- flag.Parse()
-
- args := flag.Args()
-
- if len(args) < 1 {
- fmt.Println(usage)
- os.Exit(0)
- }
-
- switch args[0] {
- case "help", "h":
- if len(args) < 2 {
- fmt.Println(usageHelp)
- fmt.Println(usage)
- os.Exit(0)
- }
-
- switch args[1] {
- case "new":
- fmt.Println(usageNew)
- os.Exit(0)
-
- case "generate", "gen", "g":
- fmt.Println(usageGenerate)
- os.Exit(0)
-
- case "build":
- fmt.Println(usageBuild)
- os.Exit(0)
-
- case "run":
- fmt.Println(usageRun)
- os.Exit(0)
-
- case "upgrade":
- fmt.Println(usageUpgrade)
- os.Exit(0)
-
- case "version", "v":
- fmt.Println(usageVersion)
- os.Exit(0)
-
- case "add", "a":
- fmt.Println(usageAdd)
- os.Exit(0)
- }
-
- case "new":
- if len(args) < 2 {
- fmt.Println(usageNew)
- os.Exit(0)
- }
-
- err := newProjectInDir(args[1])
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
-
- case "generate", "gen", "g":
- if len(args) < 3 {
- fmt.Println(usageGenerate)
- os.Exit(0)
- }
-
- // check what we are asked to generate
- switch args[1] {
- case "content", "c":
- err := generateContentType(args[2:])
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
- default:
- msg := fmt.Sprintf("Generator '%s' is not implemented.", args[1])
- fmt.Println(msg)
- }
-
- case "build":
- err := buildPonzuServer(args)
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
-
- case "run":
- var addTLS string
- if https {
- addTLS = "--https"
- } else {
- addTLS = "--https=false"
- }
-
- if devhttps {
- addTLS = "--devhttps"
- }
-
- var services string
- if len(args) > 1 {
- services = args[1]
- } else {
- services = "admin,api"
- }
-
- name := buildOutputName()
- buildPathName := strings.Join([]string{".", name}, string(filepath.Separator))
- serve := exec.Command(buildPathName,
- fmt.Sprintf("--port=%d", port),
- fmt.Sprintf("--httpsport=%d", httpsport),
- addTLS,
- "serve",
- services,
- )
- serve.Stderr = os.Stderr
- serve.Stdout = os.Stdout
-
- err := serve.Run()
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
-
- case "serve", "s":
- db.Init()
- defer db.Close()
-
- analytics.Init()
- defer analytics.Close()
-
- if len(args) > 1 {
- services := strings.Split(args[1], ",")
-
- for _, service := range services {
- if service == "api" {
- api.Run()
- } else if service == "admin" {
- admin.Run()
- } else {
- fmt.Println("To execute 'ponzu serve', you must specify which service to run.")
- fmt.Println("$ ponzu --help")
- os.Exit(1)
- }
- }
- }
-
- // save the https port the system is listening on
- err := db.PutConfig("https_port", fmt.Sprintf("%d", httpsport))
- if err != nil {
- log.Fatalln("System failed to save config. Please try to run again.", err)
- }
-
- // cannot run production HTTPS and development HTTPS together
- if devhttps {
- fmt.Println("Enabling self-signed HTTPS... [DEV]")
-
- go tls.EnableDev()
- fmt.Println("Server listening on https://localhost:10443 for requests... [DEV]")
- fmt.Println("----")
- fmt.Println("If your browser rejects HTTPS requests, try allowing insecure connections on localhost.")
- fmt.Println("on Chrome, visit chrome://flags/#allow-insecure-localhost")
-
- } else if https {
- fmt.Println("Enabling HTTPS...")
-
- go tls.Enable()
- fmt.Printf("Server listening on :%s for HTTPS requests...\n", db.ConfigCache("https_port").(string))
- }
-
- // save the https port the system is listening on so internal system can make
- // HTTP api calls while in dev or production w/o adding more cli flags
- err = db.PutConfig("http_port", fmt.Sprintf("%d", port))
- if err != nil {
- log.Fatalln("System failed to save config. Please try to run again.", err)
- }
-
- fmt.Printf("Server listening on :%d for HTTP requests...\n", port)
- fmt.Println("\nvisit `/admin` to get started.")
- log.Fatalln(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
-
- case "version", "v":
- // read ponzu.json value to Stdout
-
- p, err := ponzu(cli)
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
-
- fmt.Fprintf(os.Stdout, "Ponzu v%s\n", p["version"])
-
- case "upgrade":
- // confirm since upgrade will replace Ponzu core files
- path, err := os.Getwd()
- if err != nil {
- fmt.Println("Failed to find current directory.", err)
- os.Exit(1)
- }
-
- fmt.Println("Only files you added to this directory, 'addons' and 'content' will be preserved.")
- fmt.Println("Upgrade this project? (y/N):")
-
- answer, err := getAnswer()
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
-
- switch answer {
- case "n", "no", "\r\n", "\n", "":
- fmt.Println("")
-
- case "y", "yes":
- err := upgradePonzuProjectDir(path)
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
-
- default:
- fmt.Println("Input not recognized. No upgrade made. Answer as 'y' or 'n' only.")
- }
-
- case "add", "a":
- // expecting two args, add and the go gettable package uri
- if len(args) < 2 {
- fmt.Println(usageAdd)
- os.Exit(0)
- }
-
- err := getAddon(args)
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
-
- case "":
- fmt.Println(usage)
- fmt.Println(usageHelp)
-
- default:
- fmt.Println(usage)
- fmt.Println(usageHelp)
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/options.go b/examples/docker/admin/cmd/ponzu/options.go
deleted file mode 100644
index 77e842c..0000000
--- a/examples/docker/admin/cmd/ponzu/options.go
+++ /dev/null
@@ -1,489 +0,0 @@
-package main
-
-import (
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
- "time"
-)
-
-func newProjectInDir(path string) error {
- // set path to be nested inside $GOPATH/src
- gopath, err := getGOPATH()
- if err != nil {
- return err
- }
- path = filepath.Join(gopath, "src", path)
-
- // check if anything exists at the path, ask if it should be overwritten
- if _, err = os.Stat(path); !os.IsNotExist(err) {
- fmt.Println("Path exists, overwrite contents? (y/N):")
-
- answer, err := getAnswer()
- if err != nil {
- return err
- }
-
- switch answer {
- case "n", "no", "\r\n", "\n", "":
- fmt.Println("")
-
- case "y", "yes":
- err := os.RemoveAll(path)
- if err != nil {
- return fmt.Errorf("Failed to overwrite %s. \n%s", path, err)
- }
-
- return createProjectInDir(path)
-
- default:
- fmt.Println("Input not recognized. No files overwritten. Answer as 'y' or 'n' only.")
- }
-
- return nil
- }
-
- return createProjectInDir(path)
-}
-
-var ponzuRepo = []string{"github.com", "ponzu-cms", "ponzu"}
-
-func getAnswer() (string, error) {
- var answer string
- _, err := fmt.Scanf("%s\n", &answer)
- if err != nil {
- if err.Error() == "unexpected newline" {
- answer = ""
- } else {
- return "", err
- }
- }
-
- answer = strings.ToLower(answer)
-
- return answer, nil
-}
-
-func createProjectInDir(path string) error {
- gopath, err := getGOPATH()
- if err != nil {
- return err
- }
- repo := ponzuRepo
- local := filepath.Join(gopath, "src", filepath.Join(repo...))
- network := "https://" + strings.Join(repo, "/") + ".git"
- if !strings.HasPrefix(path, gopath) {
- path = filepath.Join(gopath, path)
- }
-
- // create the directory or overwrite it
- err = os.MkdirAll(path, os.ModeDir|os.ModePerm)
- if err != nil {
- return err
- }
-
- if dev {
- if fork != "" {
- local = filepath.Join(gopath, "src", fork)
- }
-
- devClone := exec.Command("git", "clone", local, "--branch", "ponzu-dev", "--single-branch", path)
- devClone.Stdout = os.Stdout
- devClone.Stderr = os.Stderr
-
- err = devClone.Start()
- if err != nil {
- return err
- }
-
- err = devClone.Wait()
- if err != nil {
- return err
- }
-
- err = vendorCorePackages(path)
- if err != nil {
- return err
- }
-
- fmt.Println("Dev build cloned from " + local + ":ponzu-dev")
- return nil
- }
-
- // try to git clone the repository from the local machine's $GOPATH
- localClone := exec.Command("git", "clone", local, path)
- localClone.Stdout = os.Stdout
- localClone.Stderr = os.Stderr
-
- err = localClone.Start()
- if err != nil {
- return err
- }
- err = localClone.Wait()
- if err != nil {
- fmt.Println("Couldn't clone from", local, "- trying network...")
-
- // try to git clone the repository over the network
- networkClone := exec.Command("git", "clone", network, path)
- networkClone.Stdout = os.Stdout
- networkClone.Stderr = os.Stderr
-
- err = networkClone.Start()
- if err != nil {
- fmt.Println("Network clone failed to start. Try again and make sure you have a network connection.")
- return err
- }
- err = networkClone.Wait()
- if err != nil {
- fmt.Println("Network clone failure.")
- // failed
- return fmt.Errorf("Failed to clone files from local machine [%s] and over the network [%s].\n%s", local, network, err)
- }
- }
-
- // create an internal vendor directory in ./cmd/ponzu and move content,
- // management and system packages into it
- err = vendorCorePackages(path)
- if err != nil {
- return err
- }
-
- gitDir := filepath.Join(path, ".git")
- err = os.RemoveAll(gitDir)
- if err != nil {
- fmt.Println("Failed to remove .git directory from your project path. Consider removing it manually.")
- }
-
- fmt.Println("New ponzu project created at", path)
- return nil
-}
-
-func vendorCorePackages(path string) error {
- vendorPath := filepath.Join(path, "cmd", "ponzu", "vendor", "github.com", "ponzu-cms", "ponzu")
- err := os.MkdirAll(vendorPath, os.ModeDir|os.ModePerm)
- if err != nil {
- return err
- }
-
- dirs := []string{"content", "management", "system"}
- for _, dir := range dirs {
- err = os.Rename(filepath.Join(path, dir), filepath.Join(vendorPath, dir))
- if err != nil {
- return err
- }
- }
-
- // create a user content directory at project root
- contentPath := filepath.Join(path, "content")
- err = os.Mkdir(contentPath, os.ModeDir|os.ModePerm)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func copyFileNoRoot(src, dst string) error {
- noRoot := strings.Split(src, string(filepath.Separator))[1:]
- path := filepath.Join(noRoot...)
- dstFile, err := os.Create(filepath.Join(dst, path))
- defer dstFile.Close()
- if err != nil {
- return err
- }
-
- srcFile, err := os.Open(src)
- defer srcFile.Close()
- if err != nil {
- return err
- }
-
- _, err = io.Copy(dstFile, srcFile)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func copyFilesWarnConflicts(srcDir, dstDir string, conflicts []string) error {
- err := filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
-
- for _, conflict := range conflicts {
- if info.Name() == conflict {
- fmt.Println("Ponzu couldn't fully build your project:")
- fmt.Println("You must rename the following file, as it conflicts with Ponzu core:")
- fmt.Println(path)
- fmt.Println("")
- fmt.Println("Once the files above have been renamed, run '$ ponzu build' to retry.")
- return errors.New("Ponzu has very few internal conflicts, sorry for the inconvenience.")
- }
- }
-
- if info.IsDir() {
- // don't copy root directory
- if path == srcDir {
- return nil
- }
-
- if len(path) > len(srcDir) {
- path = path[len(srcDir)+1:]
- }
- dir := filepath.Join(dstDir, path)
- err := os.MkdirAll(dir, os.ModeDir|os.ModePerm)
- if err != nil {
- return err
- }
-
- return nil
- }
-
- err = copyFileNoRoot(path, dstDir)
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func emptyDir(path string) error {
- d, err := os.Open(path)
- if err != nil {
- return err
- }
- defer d.Close()
-
- names, err := d.Readdirnames(-1)
- if err != nil {
- return err
- }
- for _, name := range names {
- err = os.RemoveAll(filepath.Join(path, name))
- if err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func buildPonzuServer(args []string) error {
- pwd, err := os.Getwd()
- if err != nil {
- return err
- }
-
- // copy all ./content files to internal vendor directory
- src := "content"
- dst := filepath.Join("cmd", "ponzu", "vendor", "github.com", "ponzu-cms", "ponzu", "content")
- err = emptyDir(dst)
- if err != nil {
- return err
- }
- err = copyFilesWarnConflicts(src, dst, []string{"doc.go"})
- if err != nil {
- return err
- }
-
- // copy all ./addons files & dirs to internal vendor directory
- src = "addons"
- dst = filepath.Join("cmd", "ponzu", "vendor")
- err = copyFilesWarnConflicts(src, dst, nil)
- if err != nil {
- return err
- }
-
- // execute go build -o ponzu-cms cmd/ponzu/*.go
- buildOptions := []string{"build", "-o", buildOutputName()}
- cmdBuildFiles := []string{
- "main.go", "options.go", "generate.go",
- "usage.go", "paths.go", "add.go",
- }
- var cmdBuildFilePaths []string
- for _, file := range cmdBuildFiles {
- p := filepath.Join(pwd, "cmd", "ponzu", file)
- cmdBuildFilePaths = append(cmdBuildFilePaths, p)
- }
-
- build := exec.Command(gocmd, append(buildOptions, cmdBuildFilePaths...)...)
- build.Stderr = os.Stderr
- build.Stdout = os.Stdout
-
- err = build.Start()
- if err != nil {
- return errors.New("Ponzu build step failed. Please try again. " + "\n" + err.Error())
-
- }
- err = build.Wait()
- if err != nil {
- return errors.New("Ponzu build step failed. Please try again. " + "\n" + err.Error())
-
- }
-
- return nil
-}
-
-func copyAll(src, dst string) error {
- err := filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
-
- sep := string(filepath.Separator)
-
- // base == the ponzu project dir + string(filepath.Separator)
- parts := strings.Split(src, sep)
- base := strings.Join(parts[:len(parts)-1], sep)
- base += sep
-
- target := filepath.Join(dst, path[len(base):])
-
- // if its a directory, make dir in dst
- if info.IsDir() {
- err := os.MkdirAll(target, os.ModeDir|os.ModePerm)
- if err != nil {
- return err
- }
- } else {
- // if its a file, move file to dir of dst
- err = os.Rename(path, target)
- if err != nil {
- return err
- }
- }
-
- return nil
- })
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func upgradePonzuProjectDir(path string) error {
- core := []string{
- ".gitattributes",
- "LICENSE",
- "ponzu-banner.png",
- "README.md",
- "cmd",
- "deployment",
- "management",
- "system",
- }
-
- stamp := fmt.Sprintf("ponzu-%d.bak", time.Now().Unix())
- temp := filepath.Join(os.TempDir(), stamp)
- err := os.Mkdir(temp, os.ModeDir|os.ModePerm)
- if err != nil {
- return err
- }
-
- // track non-Ponzu core items (added by user)
- var user []os.FileInfo
- list, err := ioutil.ReadDir(path)
- if err != nil {
- return err
- }
-
- for _, item := range list {
- // check if in core
- var isCore bool
- for _, name := range core {
- if item.Name() == name {
- isCore = true
- break
- }
- }
-
- if !isCore {
- user = append(user, item)
- }
- }
-
- // move non-Ponzu files to temp location
- fmt.Println("Preserving files to be restored after upgrade...")
- for _, item := range user {
- src := filepath.Join(path, item.Name())
- if item.IsDir() {
- err := os.Mkdir(filepath.Join(temp, item.Name()), os.ModeDir|os.ModePerm)
- if err != nil {
- return err
- }
- }
-
- err := copyAll(src, temp)
- if err != nil {
- return err
- }
-
- fmt.Println(" [-]", item.Name())
-
- }
-
- // remove all files in path
- for _, item := range list {
- err := os.RemoveAll(filepath.Join(path, item.Name()))
- if err != nil {
- return fmt.Errorf("Failed to remove old Ponzu files.\n%s", err)
- }
- }
-
- err = createProjectInDir(path)
- if err != nil {
- fmt.Println("")
- fmt.Println("Upgrade failed...")
- fmt.Println("Your code is backed up at the following location:")
- fmt.Println(temp)
- fmt.Println("")
- fmt.Println("Manually create a new Ponzu project here and copy those files within it to fully restore.")
- fmt.Println("")
- return err
- }
-
- // move non-Ponzu files from temp location backed
- restore, err := ioutil.ReadDir(temp)
- if err != nil {
- return err
- }
-
- fmt.Println("Restoring files preserved before upgrade...")
- for _, r := range restore {
- p := filepath.Join(temp, r.Name())
- err = copyAll(p, path)
- if err != nil {
- fmt.Println("Couldn't merge your previous project files with upgraded one.")
- fmt.Println("Manually copy your files from the following directory:")
- fmt.Println(temp)
- return err
- }
-
- fmt.Println(" [+]", r.Name())
- }
-
- // clean-up
- backups := []string{filepath.Join(path, stamp), temp}
- for _, bak := range backups {
- err := os.RemoveAll(bak)
- if err != nil {
- return err
- }
- }
-
- return nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/paths.go b/examples/docker/admin/cmd/ponzu/paths.go
deleted file mode 100644
index 8d5407f..0000000
--- a/examples/docker/admin/cmd/ponzu/paths.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package main
-
-import (
- "os"
- "os/user"
- "path/filepath"
- "runtime"
- "strings"
-)
-
-// buildOutputName returns the correct ponzu-server file name
-// based on the host Operating System
-func buildOutputName() string {
- if runtime.GOOS == "windows" {
- return "ponzu-server.exe"
- }
-
- return "ponzu-server"
-}
-
-// resolve GOPATH. In 1.8 can be default, or custom. A custom GOPATH can
-// also contain multiple paths, in which case 'go get' uses the first
-func getGOPATH() (string, error) {
- var gopath string
- gopath = os.Getenv("GOPATH")
- if gopath == "" {
- // not set, find the default
- usr, err := user.Current()
- if err != nil {
- return gopath, err
- }
- gopath = filepath.Join(usr.HomeDir, "go")
- } else {
- // parse out in case of multiple, retain first
- if runtime.GOOS == "windows" {
- gopaths := strings.Split(gopath, ";")
- gopath = gopaths[0]
- } else {
- gopaths := strings.Split(gopath, ":")
- gopath = gopaths[0]
- }
- }
- return gopath, nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/ponzu.json b/examples/docker/admin/cmd/ponzu/ponzu.json
deleted file mode 100644
index 3b76ad7..0000000
--- a/examples/docker/admin/cmd/ponzu/ponzu.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "version": "0.9.1"
-}
diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-checkbox.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-checkbox.tmpl
deleted file mode 100644
index 23713dc..0000000
--- a/examples/docker/admin/cmd/ponzu/templates/gen-checkbox.tmpl
+++ /dev/null
@@ -1,5 +0,0 @@
-View: editor.Checkbox("{{ .Name }}", {{ .Initial }}, map[string]string{
- "label": "{{ .Name }}",
-}, map[string]string{
- // "value": "Display Name",
-}), \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-content.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-content.tmpl
deleted file mode 100644
index 2d92b88..0000000
--- a/examples/docker/admin/cmd/ponzu/templates/gen-content.tmpl
+++ /dev/null
@@ -1,39 +0,0 @@
-package content
-
-import (
- "fmt"
-
- "github.com/ponzu-cms/ponzu/management/editor"
- "github.com/ponzu-cms/ponzu/system/item"
-)
-
-type {{ .Name }} struct {
- item.Item
-
- {{ range .Fields }}{{ .Name }} {{ .TypeName }} `json:"{{ .JSONName }}"`
- {{ end }}
-}
-
-// MarshalEditor writes a buffer of html to edit a {{ .Name }} within the CMS
-// and implements editor.Editable
-func ({{ .Initial }} *{{ .Name }}) MarshalEditor() ([]byte, error) {
- view, err := editor.Form({{ .Initial }},
- // Take note that the first argument to these Input-like functions
- // is the string version of each {{ .Name }} field, and must follow
- // this pattern for auto-decoding and auto-encoding reasons:
- {{ range .Fields }}editor.Field{
- {{ .View }}
- },
- {{ end }}
- )
-
- if err != nil {
- return nil, fmt.Errorf("Failed to render {{ .Name }} editor view: %s", err.Error())
- }
-
- return view, nil
-}
-
-func init() {
- item.Types["{{ .Name }}"] = func() interface{} { return new({{ .Name }}) }
-} \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-custom.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-custom.tmpl
deleted file mode 100644
index 6079f8b..0000000
--- a/examples/docker/admin/cmd/ponzu/templates/gen-custom.tmpl
+++ /dev/null
@@ -1,6 +0,0 @@
-View: []byte(`
- <div class="input-field col s12">
- <label class="active">{{ .Name }}</label>
- <!-- Add your custom editor field view here. -->
- </div>
- `), \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-file.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-file.tmpl
deleted file mode 100644
index 7bcaa4c..0000000
--- a/examples/docker/admin/cmd/ponzu/templates/gen-file.tmpl
+++ /dev/null
@@ -1,4 +0,0 @@
-View: editor.File("{{ .Name }}", {{ .Initial }}, map[string]string{
- "label": "{{ .Name }}",
- "placeholder": "Upload the {{ .Name }} here",
-}), \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-hidden.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-hidden.tmpl
deleted file mode 100644
index 4b00456..0000000
--- a/examples/docker/admin/cmd/ponzu/templates/gen-hidden.tmpl
+++ /dev/null
@@ -1,3 +0,0 @@
-View: editor.Input("{{ .Name }}", {{ .Initial }}, map[string]string{
- "type": "hidden",
-}), \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-input.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-input.tmpl
deleted file mode 100644
index 8bea12a..0000000
--- a/examples/docker/admin/cmd/ponzu/templates/gen-input.tmpl
+++ /dev/null
@@ -1,5 +0,0 @@
-View: editor.Input("{{ .Name }}", {{ .Initial }}, map[string]string{
- "label": "{{ .Name }}",
- "type": "text",
- "placeholder": "Enter the {{ .Name }} here",
-}), \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-richtext.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-richtext.tmpl
deleted file mode 100644
index c7ec18c..0000000
--- a/examples/docker/admin/cmd/ponzu/templates/gen-richtext.tmpl
+++ /dev/null
@@ -1,4 +0,0 @@
-View: editor.Richtext("{{ .Name }}", {{ .Initial }}, map[string]string{
- "label": "{{ .Name }}",
- "placeholder": "Enter the {{ .Name }} here",
-}), \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-select.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-select.tmpl
deleted file mode 100644
index 509eb30..0000000
--- a/examples/docker/admin/cmd/ponzu/templates/gen-select.tmpl
+++ /dev/null
@@ -1,5 +0,0 @@
-View: editor.Select("{{ .Name }}", {{ .Initial }}, map[string]string{
- "label": "{{ .Name }}",
-}, map[string]string{
- // "value": "Display Name",
-}), \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-tags.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-tags.tmpl
deleted file mode 100644
index ca92c94..0000000
--- a/examples/docker/admin/cmd/ponzu/templates/gen-tags.tmpl
+++ /dev/null
@@ -1,4 +0,0 @@
-View: editor.Tags("{{ .Name }}", {{ .Initial }}, map[string]string{
- "label": "{{ .Name }}",
- "placeholder": "+{{ .Name }}",
-}), \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-textarea.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-textarea.tmpl
deleted file mode 100644
index af3dad8..0000000
--- a/examples/docker/admin/cmd/ponzu/templates/gen-textarea.tmpl
+++ /dev/null
@@ -1,4 +0,0 @@
-View: editor.Textarea("{{ .Name }}", {{ .Initial }}, map[string]string{
- "label": "{{ .Name }}",
- "placeholder": "Enter the {{ .Name }} here",
-}), \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/usage.go b/examples/docker/admin/cmd/ponzu/usage.go
deleted file mode 100644
index 939b0c0..0000000
--- a/examples/docker/admin/cmd/ponzu/usage.go
+++ /dev/null
@@ -1,201 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "fmt"
- "io/ioutil"
- "path/filepath"
- "time"
-)
-
-var year = fmt.Sprintf("%d", time.Now().Year())
-
-var usageHeader = `
-$ ponzu [flags] command <params>
-
-Ponzu is a powerful and efficient open-source HTTP server framework and CMS. It
-provides automatic, free, and secure HTTP/2 over TLS (certificates obtained via
-[Let's Encrypt](https://letsencrypt.org)), a useful CMS and scaffolding to
-generate set-up code, and a fast HTTP API on which to build modern applications.
-
-Ponzu is released under the BSD-3-Clause license (see LICENSE).
-(c) 2016 - ` + year + ` Boss Sauce Creative, LLC
-
-COMMANDS:
-
-`
-
-var usageHelp = `
-help, h (command)
-
- Help command will print the usage for Ponzu, or if a command is entered, it
- will show only the usage for that specific command.
-
- Example:
- $ ponzu help generate
-
-
-`
-
-var usageNew = `
-new <directory>
-
- Creates a 'ponzu' directory, or one by the name supplied as a parameter
- immediately following the 'new' option in the $GOPATH/src directory. Note:
- 'new' depends on the program 'git' and possibly a network connection. If
- there is no local repository to clone from at the local machine's $GOPATH,
- 'new' will attempt to clone the 'github.com/ponzu-cms/ponzu' package from
- over the network.
-
- Example:
- $ ponzu new myProject
- > New ponzu project created at $GOPATH/src/myProject
-
- Errors will be reported, but successful commands retrun nothing.
-
-
-`
-
-var usageGenerate = `
-generate, gen, g <generator type (,...fields)>
-
- Generate boilerplate code for various Ponzu components, such as 'content'.
-
- Example:
- $ ponzu gen content review title:"string" body:"string" rating:"int" tags:"[]string"
-
- The command above will generate a file 'content/review.go' with boilerplate
- methods, as well as struct definition, and corresponding field tags like:
-
- type Review struct {
- Title string ` + "`json:" + `"title"` + "`" + `
- Body string ` + "`json:" + `"body"` + "`" + `
- Rating int ` + "`json:" + `"rating"` + "`" + `
- Tags []string ` + "`json:" + `"tags"` + "`" + `
- }
-
- The generate command will intelligently parse more sophisticated field names
- such as 'field_name' and convert it to 'FieldName' and vice versa, only where
- appropriate as per common Go idioms. Errors will be reported, but successful
- generate commands retrun nothing.
-
-
-`
-
-var usageBuild = `
-[-gocmd=go] build
-
- From within your Ponzu project directory, running build will copy and move
- the necessary files from your workspace into the vendored directory, and
- will build/compile the project to then be run.
-
- Example:
- $ ponzu build
- (or)
- $ ponzu -gocmd=go1.8rc1 build
-
- By providing the 'gocmd' flag, you can specify which Go command to build the
- project, if testing a different release of Go.
-
- Errors will be reported, but successful build commands return nothing.
-
-
-`
-
-var usageRun = `
-[[-port=8080] [--https|--devhttps]] run <service(,service)>
-
- Starts the 'ponzu' HTTP server for the JSON API, Admin System, or both.
- The segments, separated by a comma, describe which services to start, either
- 'admin' (Admin System / CMS backend) or 'api' (JSON API), and, optionally,
- if the server should utilize TLS encryption - served over HTTPS, which is
- automatically managed using Let's Encrypt (https://letsencrypt.org)
-
- Example:
- $ ponzu run
- (or)
- $ ponzu -port=8080 --https run admin,api
- (or)
- $ ponzu run admin
- (or)
- $ ponzu -port=8888 run api
-
- Defaults to '-port=8080 run admin,api' (running Admin & API on port 8080, without TLS)
-
- Note:
- Admin and API cannot run on separate processes unless you use a copy of the
- database, since the first process to open it receives a lock. If you intend
- to run the Admin and API on separate processes, you must call them with the
- 'ponzu' command independently.
-
-
-`
-
-var usageUpgrade = `
-upgrade
-
- Will backup your own custom project code (like content, addons, uploads, etc) so
- we can safely re-clone Ponzu from the latest version you have or from the network
- if necessary. Before running '$ ponzu upgrade', you should update the 'ponzu'
- package by running '$ go get -u github.com/ponzu-cms/ponzu/...'
-
- Example:
- $ ponzu upgrade
-
-
-`
-
-var usageVersion = `
-[--cli] version, v
-
- Prints the version of Ponzu your project is using. Must be called from
- within a Ponzu project directory.
-
- Example:
- $ ponzu version
- > Ponzu v0.7.1
- (or)
- $ ponzu --cli version
- > Ponzu v0.7.2
-
-
-`
-
-var usageAdd = `
-add, a <import path>
-
- Downloads addon from specified import path to $GOPATH/src and copys it to the
- current project's ./addons directory. Must be called from within a
- Ponzu project directory.
-
- Example:
- $ ponzu add github.com/bosssauce/fbscheduler
-
-
-`
-
-func ponzu(isCLI bool) (map[string]interface{}, error) {
- kv := make(map[string]interface{})
-
- info := filepath.Join("cmd", "ponzu", "ponzu.json")
- if isCLI {
- gopath, err := getGOPATH()
- if err != nil {
- return nil, err
- }
- repo := filepath.Join(gopath, "src", "github.com", "ponzu-cms", "ponzu")
- info = filepath.Join(repo, "cmd", "ponzu", "ponzu.json")
- }
-
- b, err := ioutil.ReadFile(info)
- if err != nil {
- return nil, err
- }
-
- err = json.Unmarshal(b, &kv)
- if err != nil {
- return nil, err
- }
-
- return kv, nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/.gitignore b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/.gitignore
deleted file mode 100644
index c7bd2b7..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-*.prof
-*.test
-*.swp
-/bin/
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/LICENSE b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/LICENSE
deleted file mode 100644
index 004e77f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2013 Ben Johnson
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/Makefile b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/Makefile
deleted file mode 100644
index e035e63..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-BRANCH=`git rev-parse --abbrev-ref HEAD`
-COMMIT=`git rev-parse --short HEAD`
-GOLDFLAGS="-X main.branch $(BRANCH) -X main.commit $(COMMIT)"
-
-default: build
-
-race:
- @go test -v -race -test.run="TestSimulate_(100op|1000op)"
-
-# go get github.com/kisielk/errcheck
-errcheck:
- @errcheck -ignorepkg=bytes -ignore=os:Remove github.com/boltdb/bolt
-
-test:
- @go test -v -cover .
- @go test -v ./cmd/bolt
-
-.PHONY: fmt test
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/README.md b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/README.md
deleted file mode 100644
index b654502..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/README.md
+++ /dev/null
@@ -1,858 +0,0 @@
-Bolt [![Coverage Status](https://coveralls.io/repos/boltdb/bolt/badge.svg?branch=master)](https://coveralls.io/r/boltdb/bolt?branch=master) [![GoDoc](https://godoc.org/github.com/boltdb/bolt?status.svg)](https://godoc.org/github.com/boltdb/bolt) ![Version](https://img.shields.io/badge/version-1.2.1-green.svg)
-====
-
-Bolt is a pure Go key/value store inspired by [Howard Chu's][hyc_symas]
-[LMDB project][lmdb]. The goal of the project is to provide a simple,
-fast, and reliable database for projects that don't require a full database
-server such as Postgres or MySQL.
-
-Since Bolt is meant to be used as such a low-level piece of functionality,
-simplicity is key. The API will be small and only focus on getting values
-and setting values. That's it.
-
-[hyc_symas]: https://twitter.com/hyc_symas
-[lmdb]: http://symas.com/mdb/
-
-## Project Status
-
-Bolt is stable, the API is fixed, and the file format is fixed. Full unit
-test coverage and randomized black box testing are used to ensure database
-consistency and thread safety. Bolt is currently used in high-load production
-environments serving databases as large as 1TB. Many companies such as
-Shopify and Heroku use Bolt-backed services every day.
-
-## Table of Contents
-
-- [Getting Started](#getting-started)
- - [Installing](#installing)
- - [Opening a database](#opening-a-database)
- - [Transactions](#transactions)
- - [Read-write transactions](#read-write-transactions)
- - [Read-only transactions](#read-only-transactions)
- - [Batch read-write transactions](#batch-read-write-transactions)
- - [Managing transactions manually](#managing-transactions-manually)
- - [Using buckets](#using-buckets)
- - [Using key/value pairs](#using-keyvalue-pairs)
- - [Autoincrementing integer for the bucket](#autoincrementing-integer-for-the-bucket)
- - [Iterating over keys](#iterating-over-keys)
- - [Prefix scans](#prefix-scans)
- - [Range scans](#range-scans)
- - [ForEach()](#foreach)
- - [Nested buckets](#nested-buckets)
- - [Database backups](#database-backups)
- - [Statistics](#statistics)
- - [Read-Only Mode](#read-only-mode)
- - [Mobile Use (iOS/Android)](#mobile-use-iosandroid)
-- [Resources](#resources)
-- [Comparison with other databases](#comparison-with-other-databases)
- - [Postgres, MySQL, & other relational databases](#postgres-mysql--other-relational-databases)
- - [LevelDB, RocksDB](#leveldb-rocksdb)
- - [LMDB](#lmdb)
-- [Caveats & Limitations](#caveats--limitations)
-- [Reading the Source](#reading-the-source)
-- [Other Projects Using Bolt](#other-projects-using-bolt)
-
-## Getting Started
-
-### Installing
-
-To start using Bolt, install Go and run `go get`:
-
-```sh
-$ go get github.com/boltdb/bolt/...
-```
-
-This will retrieve the library and install the `bolt` command line utility into
-your `$GOBIN` path.
-
-
-### Opening a database
-
-The top-level object in Bolt is a `DB`. It is represented as a single file on
-your disk and represents a consistent snapshot of your data.
-
-To open your database, simply use the `bolt.Open()` function:
-
-```go
-package main
-
-import (
- "log"
-
- "github.com/boltdb/bolt"
-)
-
-func main() {
- // Open the my.db data file in your current directory.
- // It will be created if it doesn't exist.
- db, err := bolt.Open("my.db", 0600, nil)
- if err != nil {
- log.Fatal(err)
- }
- defer db.Close()
-
- ...
-}
-```
-
-Please note that Bolt obtains a file lock on the data file so multiple processes
-cannot open the same database at the same time. Opening an already open Bolt
-database will cause it to hang until the other process closes it. To prevent
-an indefinite wait you can pass a timeout option to the `Open()` function:
-
-```go
-db, err := bolt.Open("my.db", 0600, &bolt.Options{Timeout: 1 * time.Second})
-```
-
-
-### Transactions
-
-Bolt allows only one read-write transaction at a time but allows as many
-read-only transactions as you want at a time. Each transaction has a consistent
-view of the data as it existed when the transaction started.
-
-Individual transactions and all objects created from them (e.g. buckets, keys)
-are not thread safe. To work with data in multiple goroutines you must start
-a transaction for each one or use locking to ensure only one goroutine accesses
-a transaction at a time. Creating transaction from the `DB` is thread safe.
-
-Read-only transactions and read-write transactions should not depend on one
-another and generally shouldn't be opened simultaneously in the same goroutine.
-This can cause a deadlock as the read-write transaction needs to periodically
-re-map the data file but it cannot do so while a read-only transaction is open.
-
-
-#### Read-write transactions
-
-To start a read-write transaction, you can use the `DB.Update()` function:
-
-```go
-err := db.Update(func(tx *bolt.Tx) error {
- ...
- return nil
-})
-```
-
-Inside the closure, you have a consistent view of the database. You commit the
-transaction by returning `nil` at the end. You can also rollback the transaction
-at any point by returning an error. All database operations are allowed inside
-a read-write transaction.
-
-Always check the return error as it will report any disk failures that can cause
-your transaction to not complete. If you return an error within your closure
-it will be passed through.
-
-
-#### Read-only transactions
-
-To start a read-only transaction, you can use the `DB.View()` function:
-
-```go
-err := db.View(func(tx *bolt.Tx) error {
- ...
- return nil
-})
-```
-
-You also get a consistent view of the database within this closure, however,
-no mutating operations are allowed within a read-only transaction. You can only
-retrieve buckets, retrieve values, and copy the database within a read-only
-transaction.
-
-
-#### Batch read-write transactions
-
-Each `DB.Update()` waits for disk to commit the writes. This overhead
-can be minimized by combining multiple updates with the `DB.Batch()`
-function:
-
-```go
-err := db.Batch(func(tx *bolt.Tx) error {
- ...
- return nil
-})
-```
-
-Concurrent Batch calls are opportunistically combined into larger
-transactions. Batch is only useful when there are multiple goroutines
-calling it.
-
-The trade-off is that `Batch` can call the given
-function multiple times, if parts of the transaction fail. The
-function must be idempotent and side effects must take effect only
-after a successful return from `DB.Batch()`.
-
-For example: don't display messages from inside the function, instead
-set variables in the enclosing scope:
-
-```go
-var id uint64
-err := db.Batch(func(tx *bolt.Tx) error {
- // Find last key in bucket, decode as bigendian uint64, increment
- // by one, encode back to []byte, and add new key.
- ...
- id = newValue
- return nil
-})
-if err != nil {
- return ...
-}
-fmt.Println("Allocated ID %d", id)
-```
-
-
-#### Managing transactions manually
-
-The `DB.View()` and `DB.Update()` functions are wrappers around the `DB.Begin()`
-function. These helper functions will start the transaction, execute a function,
-and then safely close your transaction if an error is returned. This is the
-recommended way to use Bolt transactions.
-
-However, sometimes you may want to manually start and end your transactions.
-You can use the `DB.Begin()` function directly but **please** be sure to close
-the transaction.
-
-```go
-// Start a writable transaction.
-tx, err := db.Begin(true)
-if err != nil {
- return err
-}
-defer tx.Rollback()
-
-// Use the transaction...
-_, err := tx.CreateBucket([]byte("MyBucket"))
-if err != nil {
- return err
-}
-
-// Commit the transaction and check for error.
-if err := tx.Commit(); err != nil {
- return err
-}
-```
-
-The first argument to `DB.Begin()` is a boolean stating if the transaction
-should be writable.
-
-
-### Using buckets
-
-Buckets are collections of key/value pairs within the database. All keys in a
-bucket must be unique. You can create a bucket using the `DB.CreateBucket()`
-function:
-
-```go
-db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("MyBucket"))
- if err != nil {
- return fmt.Errorf("create bucket: %s", err)
- }
- return nil
-})
-```
-
-You can also create a bucket only if it doesn't exist by using the
-`Tx.CreateBucketIfNotExists()` function. It's a common pattern to call this
-function for all your top-level buckets after you open your database so you can
-guarantee that they exist for future transactions.
-
-To delete a bucket, simply call the `Tx.DeleteBucket()` function.
-
-
-### Using key/value pairs
-
-To save a key/value pair to a bucket, use the `Bucket.Put()` function:
-
-```go
-db.Update(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("MyBucket"))
- err := b.Put([]byte("answer"), []byte("42"))
- return err
-})
-```
-
-This will set the value of the `"answer"` key to `"42"` in the `MyBucket`
-bucket. To retrieve this value, we can use the `Bucket.Get()` function:
-
-```go
-db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("MyBucket"))
- v := b.Get([]byte("answer"))
- fmt.Printf("The answer is: %s\n", v)
- return nil
-})
-```
-
-The `Get()` function does not return an error because its operation is
-guaranteed to work (unless there is some kind of system failure). If the key
-exists then it will return its byte slice value. If it doesn't exist then it
-will return `nil`. It's important to note that you can have a zero-length value
-set to a key which is different than the key not existing.
-
-Use the `Bucket.Delete()` function to delete a key from the bucket.
-
-Please note that values returned from `Get()` are only valid while the
-transaction is open. If you need to use a value outside of the transaction
-then you must use `copy()` to copy it to another byte slice.
-
-
-### Autoincrementing integer for the bucket
-By using the `NextSequence()` function, you can let Bolt determine a sequence
-which can be used as the unique identifier for your key/value pairs. See the
-example below.
-
-```go
-// CreateUser saves u to the store. The new user ID is set on u once the data is persisted.
-func (s *Store) CreateUser(u *User) error {
- return s.db.Update(func(tx *bolt.Tx) error {
- // Retrieve the users bucket.
- // This should be created when the DB is first opened.
- b := tx.Bucket([]byte("users"))
-
- // Generate ID for the user.
- // This returns an error only if the Tx is closed or not writeable.
- // That can't happen in an Update() call so I ignore the error check.
- id, _ := b.NextSequence()
- u.ID = int(id)
-
- // Marshal user data into bytes.
- buf, err := json.Marshal(u)
- if err != nil {
- return err
- }
-
- // Persist bytes to users bucket.
- return b.Put(itob(u.ID), buf)
- })
-}
-
-// itob returns an 8-byte big endian representation of v.
-func itob(v int) []byte {
- b := make([]byte, 8)
- binary.BigEndian.PutUint64(b, uint64(v))
- return b
-}
-
-type User struct {
- ID int
- ...
-}
-```
-
-### Iterating over keys
-
-Bolt stores its keys in byte-sorted order within a bucket. This makes sequential
-iteration over these keys extremely fast. To iterate over keys we'll use a
-`Cursor`:
-
-```go
-db.View(func(tx *bolt.Tx) error {
- // Assume bucket exists and has keys
- b := tx.Bucket([]byte("MyBucket"))
-
- c := b.Cursor()
-
- for k, v := c.First(); k != nil; k, v = c.Next() {
- fmt.Printf("key=%s, value=%s\n", k, v)
- }
-
- return nil
-})
-```
-
-The cursor allows you to move to a specific point in the list of keys and move
-forward or backward through the keys one at a time.
-
-The following functions are available on the cursor:
-
-```
-First() Move to the first key.
-Last() Move to the last key.
-Seek() Move to a specific key.
-Next() Move to the next key.
-Prev() Move to the previous key.
-```
-
-Each of those functions has a return signature of `(key []byte, value []byte)`.
-When you have iterated to the end of the cursor then `Next()` will return a
-`nil` key. You must seek to a position using `First()`, `Last()`, or `Seek()`
-before calling `Next()` or `Prev()`. If you do not seek to a position then
-these functions will return a `nil` key.
-
-During iteration, if the key is non-`nil` but the value is `nil`, that means
-the key refers to a bucket rather than a value. Use `Bucket.Bucket()` to
-access the sub-bucket.
-
-
-#### Prefix scans
-
-To iterate over a key prefix, you can combine `Seek()` and `bytes.HasPrefix()`:
-
-```go
-db.View(func(tx *bolt.Tx) error {
- // Assume bucket exists and has keys
- c := tx.Bucket([]byte("MyBucket")).Cursor()
-
- prefix := []byte("1234")
- for k, v := c.Seek(prefix); bytes.HasPrefix(k, prefix); k, v = c.Next() {
- fmt.Printf("key=%s, value=%s\n", k, v)
- }
-
- return nil
-})
-```
-
-#### Range scans
-
-Another common use case is scanning over a range such as a time range. If you
-use a sortable time encoding such as RFC3339 then you can query a specific
-date range like this:
-
-```go
-db.View(func(tx *bolt.Tx) error {
- // Assume our events bucket exists and has RFC3339 encoded time keys.
- c := tx.Bucket([]byte("Events")).Cursor()
-
- // Our time range spans the 90's decade.
- min := []byte("1990-01-01T00:00:00Z")
- max := []byte("2000-01-01T00:00:00Z")
-
- // Iterate over the 90's.
- for k, v := c.Seek(min); k != nil && bytes.Compare(k, max) <= 0; k, v = c.Next() {
- fmt.Printf("%s: %s\n", k, v)
- }
-
- return nil
-})
-```
-
-Note that, while RFC3339 is sortable, the Golang implementation of RFC3339Nano does not use a fixed number of digits after the decimal point and is therefore not sortable.
-
-
-#### ForEach()
-
-You can also use the function `ForEach()` if you know you'll be iterating over
-all the keys in a bucket:
-
-```go
-db.View(func(tx *bolt.Tx) error {
- // Assume bucket exists and has keys
- b := tx.Bucket([]byte("MyBucket"))
-
- b.ForEach(func(k, v []byte) error {
- fmt.Printf("key=%s, value=%s\n", k, v)
- return nil
- })
- return nil
-})
-```
-
-Please note that keys and values in `ForEach()` are only valid while
-the transaction is open. If you need to use a key or value outside of
-the transaction, you must use `copy()` to copy it to another byte
-slice.
-
-### Nested buckets
-
-You can also store a bucket in a key to create nested buckets. The API is the
-same as the bucket management API on the `DB` object:
-
-```go
-func (*Bucket) CreateBucket(key []byte) (*Bucket, error)
-func (*Bucket) CreateBucketIfNotExists(key []byte) (*Bucket, error)
-func (*Bucket) DeleteBucket(key []byte) error
-```
-
-
-### Database backups
-
-Bolt is a single file so it's easy to backup. You can use the `Tx.WriteTo()`
-function to write a consistent view of the database to a writer. If you call
-this from a read-only transaction, it will perform a hot backup and not block
-your other database reads and writes.
-
-By default, it will use a regular file handle which will utilize the operating
-system's page cache. See the [`Tx`](https://godoc.org/github.com/boltdb/bolt#Tx)
-documentation for information about optimizing for larger-than-RAM datasets.
-
-One common use case is to backup over HTTP so you can use tools like `cURL` to
-do database backups:
-
-```go
-func BackupHandleFunc(w http.ResponseWriter, req *http.Request) {
- err := db.View(func(tx *bolt.Tx) error {
- w.Header().Set("Content-Type", "application/octet-stream")
- w.Header().Set("Content-Disposition", `attachment; filename="my.db"`)
- w.Header().Set("Content-Length", strconv.Itoa(int(tx.Size())))
- _, err := tx.WriteTo(w)
- return err
- })
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- }
-}
-```
-
-Then you can backup using this command:
-
-```sh
-$ curl http://localhost/backup > my.db
-```
-
-Or you can open your browser to `http://localhost/backup` and it will download
-automatically.
-
-If you want to backup to another file you can use the `Tx.CopyFile()` helper
-function.
-
-
-### Statistics
-
-The database keeps a running count of many of the internal operations it
-performs so you can better understand what's going on. By grabbing a snapshot
-of these stats at two points in time we can see what operations were performed
-in that time range.
-
-For example, we could start a goroutine to log stats every 10 seconds:
-
-```go
-go func() {
- // Grab the initial stats.
- prev := db.Stats()
-
- for {
- // Wait for 10s.
- time.Sleep(10 * time.Second)
-
- // Grab the current stats and diff them.
- stats := db.Stats()
- diff := stats.Sub(&prev)
-
- // Encode stats to JSON and print to STDERR.
- json.NewEncoder(os.Stderr).Encode(diff)
-
- // Save stats for the next loop.
- prev = stats
- }
-}()
-```
-
-It's also useful to pipe these stats to a service such as statsd for monitoring
-or to provide an HTTP endpoint that will perform a fixed-length sample.
-
-
-### Read-Only Mode
-
-Sometimes it is useful to create a shared, read-only Bolt database. To this,
-set the `Options.ReadOnly` flag when opening your database. Read-only mode
-uses a shared lock to allow multiple processes to read from the database but
-it will block any processes from opening the database in read-write mode.
-
-```go
-db, err := bolt.Open("my.db", 0666, &bolt.Options{ReadOnly: true})
-if err != nil {
- log.Fatal(err)
-}
-```
-
-### Mobile Use (iOS/Android)
-
-Bolt is able to run on mobile devices by leveraging the binding feature of the
-[gomobile](https://github.com/golang/mobile) tool. Create a struct that will
-contain your database logic and a reference to a `*bolt.DB` with a initializing
-constructor that takes in a filepath where the database file will be stored.
-Neither Android nor iOS require extra permissions or cleanup from using this method.
-
-```go
-func NewBoltDB(filepath string) *BoltDB {
- db, err := bolt.Open(filepath+"/demo.db", 0600, nil)
- if err != nil {
- log.Fatal(err)
- }
-
- return &BoltDB{db}
-}
-
-type BoltDB struct {
- db *bolt.DB
- ...
-}
-
-func (b *BoltDB) Path() string {
- return b.db.Path()
-}
-
-func (b *BoltDB) Close() {
- b.db.Close()
-}
-```
-
-Database logic should be defined as methods on this wrapper struct.
-
-To initialize this struct from the native language (both platforms now sync
-their local storage to the cloud. These snippets disable that functionality for the
-database file):
-
-#### Android
-
-```java
-String path;
-if (android.os.Build.VERSION.SDK_INT >=android.os.Build.VERSION_CODES.LOLLIPOP){
- path = getNoBackupFilesDir().getAbsolutePath();
-} else{
- path = getFilesDir().getAbsolutePath();
-}
-Boltmobiledemo.BoltDB boltDB = Boltmobiledemo.NewBoltDB(path)
-```
-
-#### iOS
-
-```objc
-- (void)demo {
- NSString* path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
- NSUserDomainMask,
- YES) objectAtIndex:0];
- GoBoltmobiledemoBoltDB * demo = GoBoltmobiledemoNewBoltDB(path);
- [self addSkipBackupAttributeToItemAtPath:demo.path];
- //Some DB Logic would go here
- [demo close];
-}
-
-- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *) filePathString
-{
- NSURL* URL= [NSURL fileURLWithPath: filePathString];
- assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
-
- NSError *error = nil;
- BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
- forKey: NSURLIsExcludedFromBackupKey error: &error];
- if(!success){
- NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
- }
- return success;
-}
-
-```
-
-## Resources
-
-For more information on getting started with Bolt, check out the following articles:
-
-* [Intro to BoltDB: Painless Performant Persistence](http://npf.io/2014/07/intro-to-boltdb-painless-performant-persistence/) by [Nate Finch](https://github.com/natefinch).
-* [Bolt -- an embedded key/value database for Go](https://www.progville.com/go/bolt-embedded-db-golang/) by Progville
-
-
-## Comparison with other databases
-
-### Postgres, MySQL, & other relational databases
-
-Relational databases structure data into rows and are only accessible through
-the use of SQL. This approach provides flexibility in how you store and query
-your data but also incurs overhead in parsing and planning SQL statements. Bolt
-accesses all data by a byte slice key. This makes Bolt fast to read and write
-data by key but provides no built-in support for joining values together.
-
-Most relational databases (with the exception of SQLite) are standalone servers
-that run separately from your application. This gives your systems
-flexibility to connect multiple application servers to a single database
-server but also adds overhead in serializing and transporting data over the
-network. Bolt runs as a library included in your application so all data access
-has to go through your application's process. This brings data closer to your
-application but limits multi-process access to the data.
-
-
-### LevelDB, RocksDB
-
-LevelDB and its derivatives (RocksDB, HyperLevelDB) are similar to Bolt in that
-they are libraries bundled into the application, however, their underlying
-structure is a log-structured merge-tree (LSM tree). An LSM tree optimizes
-random writes by using a write ahead log and multi-tiered, sorted files called
-SSTables. Bolt uses a B+tree internally and only a single file. Both approaches
-have trade-offs.
-
-If you require a high random write throughput (>10,000 w/sec) or you need to use
-spinning disks then LevelDB could be a good choice. If your application is
-read-heavy or does a lot of range scans then Bolt could be a good choice.
-
-One other important consideration is that LevelDB does not have transactions.
-It supports batch writing of key/values pairs and it supports read snapshots
-but it will not give you the ability to do a compare-and-swap operation safely.
-Bolt supports fully serializable ACID transactions.
-
-
-### LMDB
-
-Bolt was originally a port of LMDB so it is architecturally similar. Both use
-a B+tree, have ACID semantics with fully serializable transactions, and support
-lock-free MVCC using a single writer and multiple readers.
-
-The two projects have somewhat diverged. LMDB heavily focuses on raw performance
-while Bolt has focused on simplicity and ease of use. For example, LMDB allows
-several unsafe actions such as direct writes for the sake of performance. Bolt
-opts to disallow actions which can leave the database in a corrupted state. The
-only exception to this in Bolt is `DB.NoSync`.
-
-There are also a few differences in API. LMDB requires a maximum mmap size when
-opening an `mdb_env` whereas Bolt will handle incremental mmap resizing
-automatically. LMDB overloads the getter and setter functions with multiple
-flags whereas Bolt splits these specialized cases into their own functions.
-
-
-## Caveats & Limitations
-
-It's important to pick the right tool for the job and Bolt is no exception.
-Here are a few things to note when evaluating and using Bolt:
-
-* Bolt is good for read intensive workloads. Sequential write performance is
- also fast but random writes can be slow. You can use `DB.Batch()` or add a
- write-ahead log to help mitigate this issue.
-
-* Bolt uses a B+tree internally so there can be a lot of random page access.
- SSDs provide a significant performance boost over spinning disks.
-
-* Try to avoid long running read transactions. Bolt uses copy-on-write so
- old pages cannot be reclaimed while an old transaction is using them.
-
-* Byte slices returned from Bolt are only valid during a transaction. Once the
- transaction has been committed or rolled back then the memory they point to
- can be reused by a new page or can be unmapped from virtual memory and you'll
- see an `unexpected fault address` panic when accessing it.
-
-* Be careful when using `Bucket.FillPercent`. Setting a high fill percent for
- buckets that have random inserts will cause your database to have very poor
- page utilization.
-
-* Use larger buckets in general. Smaller buckets causes poor page utilization
- once they become larger than the page size (typically 4KB).
-
-* Bulk loading a lot of random writes into a new bucket can be slow as the
- page will not split until the transaction is committed. Randomly inserting
- more than 100,000 key/value pairs into a single new bucket in a single
- transaction is not advised.
-
-* Bolt uses a memory-mapped file so the underlying operating system handles the
- caching of the data. Typically, the OS will cache as much of the file as it
- can in memory and will release memory as needed to other processes. This means
- that Bolt can show very high memory usage when working with large databases.
- However, this is expected and the OS will release memory as needed. Bolt can
- handle databases much larger than the available physical RAM, provided its
- memory-map fits in the process virtual address space. It may be problematic
- on 32-bits systems.
-
-* The data structures in the Bolt database are memory mapped so the data file
- will be endian specific. This means that you cannot copy a Bolt file from a
- little endian machine to a big endian machine and have it work. For most
- users this is not a concern since most modern CPUs are little endian.
-
-* Because of the way pages are laid out on disk, Bolt cannot truncate data files
- and return free pages back to the disk. Instead, Bolt maintains a free list
- of unused pages within its data file. These free pages can be reused by later
- transactions. This works well for many use cases as databases generally tend
- to grow. However, it's important to note that deleting large chunks of data
- will not allow you to reclaim that space on disk.
-
- For more information on page allocation, [see this comment][page-allocation].
-
-[page-allocation]: https://github.com/boltdb/bolt/issues/308#issuecomment-74811638
-
-
-## Reading the Source
-
-Bolt is a relatively small code base (<3KLOC) for an embedded, serializable,
-transactional key/value database so it can be a good starting point for people
-interested in how databases work.
-
-The best places to start are the main entry points into Bolt:
-
-- `Open()` - Initializes the reference to the database. It's responsible for
- creating the database if it doesn't exist, obtaining an exclusive lock on the
- file, reading the meta pages, & memory-mapping the file.
-
-- `DB.Begin()` - Starts a read-only or read-write transaction depending on the
- value of the `writable` argument. This requires briefly obtaining the "meta"
- lock to keep track of open transactions. Only one read-write transaction can
- exist at a time so the "rwlock" is acquired during the life of a read-write
- transaction.
-
-- `Bucket.Put()` - Writes a key/value pair into a bucket. After validating the
- arguments, a cursor is used to traverse the B+tree to the page and position
- where they key & value will be written. Once the position is found, the bucket
- materializes the underlying page and the page's parent pages into memory as
- "nodes". These nodes are where mutations occur during read-write transactions.
- These changes get flushed to disk during commit.
-
-- `Bucket.Get()` - Retrieves a key/value pair from a bucket. This uses a cursor
- to move to the page & position of a key/value pair. During a read-only
- transaction, the key and value data is returned as a direct reference to the
- underlying mmap file so there's no allocation overhead. For read-write
- transactions, this data may reference the mmap file or one of the in-memory
- node values.
-
-- `Cursor` - This object is simply for traversing the B+tree of on-disk pages
- or in-memory nodes. It can seek to a specific key, move to the first or last
- value, or it can move forward or backward. The cursor handles the movement up
- and down the B+tree transparently to the end user.
-
-- `Tx.Commit()` - Converts the in-memory dirty nodes and the list of free pages
- into pages to be written to disk. Writing to disk then occurs in two phases.
- First, the dirty pages are written to disk and an `fsync()` occurs. Second, a
- new meta page with an incremented transaction ID is written and another
- `fsync()` occurs. This two phase write ensures that partially written data
- pages are ignored in the event of a crash since the meta page pointing to them
- is never written. Partially written meta pages are invalidated because they
- are written with a checksum.
-
-If you have additional notes that could be helpful for others, please submit
-them via pull request.
-
-
-## Other Projects Using Bolt
-
-Below is a list of public, open source projects that use Bolt:
-
-* [BoltDbWeb](https://github.com/evnix/boltdbweb) - A web based GUI for BoltDB files.
-* [Operation Go: A Routine Mission](http://gocode.io) - An online programming game for Golang using Bolt for user accounts and a leaderboard.
-* [Bazil](https://bazil.org/) - A file system that lets your data reside where it is most convenient for it to reside.
-* [DVID](https://github.com/janelia-flyem/dvid) - Added Bolt as optional storage engine and testing it against Basho-tuned leveldb.
-* [Skybox Analytics](https://github.com/skybox/skybox) - A standalone funnel analysis tool for web analytics.
-* [Scuttlebutt](https://github.com/benbjohnson/scuttlebutt) - Uses Bolt to store and process all Twitter mentions of GitHub projects.
-* [Wiki](https://github.com/peterhellberg/wiki) - A tiny wiki using Goji, BoltDB and Blackfriday.
-* [ChainStore](https://github.com/pressly/chainstore) - Simple key-value interface to a variety of storage engines organized as a chain of operations.
-* [MetricBase](https://github.com/msiebuhr/MetricBase) - Single-binary version of Graphite.
-* [Gitchain](https://github.com/gitchain/gitchain) - Decentralized, peer-to-peer Git repositories aka "Git meets Bitcoin".
-* [event-shuttle](https://github.com/sclasen/event-shuttle) - A Unix system service to collect and reliably deliver messages to Kafka.
-* [ipxed](https://github.com/kelseyhightower/ipxed) - Web interface and api for ipxed.
-* [BoltStore](https://github.com/yosssi/boltstore) - Session store using Bolt.
-* [photosite/session](https://godoc.org/bitbucket.org/kardianos/photosite/session) - Sessions for a photo viewing site.
-* [LedisDB](https://github.com/siddontang/ledisdb) - A high performance NoSQL, using Bolt as optional storage.
-* [ipLocator](https://github.com/AndreasBriese/ipLocator) - A fast ip-geo-location-server using bolt with bloom filters.
-* [cayley](https://github.com/google/cayley) - Cayley is an open-source graph database using Bolt as optional backend.
-* [bleve](http://www.blevesearch.com/) - A pure Go search engine similar to ElasticSearch that uses Bolt as the default storage backend.
-* [tentacool](https://github.com/optiflows/tentacool) - REST api server to manage system stuff (IP, DNS, Gateway...) on a linux server.
-* [Seaweed File System](https://github.com/chrislusf/seaweedfs) - Highly scalable distributed key~file system with O(1) disk read.
-* [InfluxDB](https://influxdata.com) - Scalable datastore for metrics, events, and real-time analytics.
-* [Freehold](http://tshannon.bitbucket.org/freehold/) - An open, secure, and lightweight platform for your files and data.
-* [Prometheus Annotation Server](https://github.com/oliver006/prom_annotation_server) - Annotation server for PromDash & Prometheus service monitoring system.
-* [Consul](https://github.com/hashicorp/consul) - Consul is service discovery and configuration made easy. Distributed, highly available, and datacenter-aware.
-* [Kala](https://github.com/ajvb/kala) - Kala is a modern job scheduler optimized to run on a single node. It is persistent, JSON over HTTP API, ISO 8601 duration notation, and dependent jobs.
-* [drive](https://github.com/odeke-em/drive) - drive is an unofficial Google Drive command line client for \*NIX operating systems.
-* [stow](https://github.com/djherbis/stow) - a persistence manager for objects
- backed by boltdb.
-* [buckets](https://github.com/joyrexus/buckets) - a bolt wrapper streamlining
- simple tx and key scans.
-* [mbuckets](https://github.com/abhigupta912/mbuckets) - A Bolt wrapper that allows easy operations on multi level (nested) buckets.
-* [Request Baskets](https://github.com/darklynx/request-baskets) - A web service to collect arbitrary HTTP requests and inspect them via REST API or simple web UI, similar to [RequestBin](http://requestb.in/) service
-* [Go Report Card](https://goreportcard.com/) - Go code quality report cards as a (free and open source) service.
-* [Boltdb Boilerplate](https://github.com/bobintornado/boltdb-boilerplate) - Boilerplate wrapper around bolt aiming to make simple calls one-liners.
-* [lru](https://github.com/crowdriff/lru) - Easy to use Bolt-backed Least-Recently-Used (LRU) read-through cache with chainable remote stores.
-* [Storm](https://github.com/asdine/storm) - Simple and powerful ORM for BoltDB.
-* [GoWebApp](https://github.com/josephspurrier/gowebapp) - A basic MVC web application in Go using BoltDB.
-* [SimpleBolt](https://github.com/xyproto/simplebolt) - A simple way to use BoltDB. Deals mainly with strings.
-* [Algernon](https://github.com/xyproto/algernon) - A HTTP/2 web server with built-in support for Lua. Uses BoltDB as the default database backend.
-* [MuLiFS](https://github.com/dankomiocevic/mulifs) - Music Library Filesystem creates a filesystem to organise your music files.
-* [GoShort](https://github.com/pankajkhairnar/goShort) - GoShort is a URL shortener written in Golang and BoltDB for persistent key/value storage and for routing it's using high performent HTTPRouter.
-* [torrent](https://github.com/anacrolix/torrent) - Full-featured BitTorrent client package and utilities in Go. BoltDB is a storage backend in development.
-* [gopherpit](https://github.com/gopherpit/gopherpit) - A web service to manage Go remote import paths with custom domains
-
-If you are using Bolt in a project please send a pull request to add it to the list.
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/appveyor.yml b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/appveyor.yml
deleted file mode 100644
index 6e26e94..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/appveyor.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-version: "{build}"
-
-os: Windows Server 2012 R2
-
-clone_folder: c:\gopath\src\github.com\boltdb\bolt
-
-environment:
- GOPATH: c:\gopath
-
-install:
- - echo %PATH%
- - echo %GOPATH%
- - go version
- - go env
- - go get -v -t ./...
-
-build_script:
- - go test -v ./...
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_386.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_386.go
deleted file mode 100644
index 820d533..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_386.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package bolt
-
-// maxMapSize represents the largest mmap size supported by Bolt.
-const maxMapSize = 0x7FFFFFFF // 2GB
-
-// maxAllocSize is the size used when creating array pointers.
-const maxAllocSize = 0xFFFFFFF
-
-// Are unaligned load/stores broken on this arch?
-var brokenUnaligned = false
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_amd64.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_amd64.go
deleted file mode 100644
index 98fafdb..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_amd64.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package bolt
-
-// maxMapSize represents the largest mmap size supported by Bolt.
-const maxMapSize = 0xFFFFFFFFFFFF // 256TB
-
-// maxAllocSize is the size used when creating array pointers.
-const maxAllocSize = 0x7FFFFFFF
-
-// Are unaligned load/stores broken on this arch?
-var brokenUnaligned = false
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm.go
deleted file mode 100644
index 7e5cb4b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package bolt
-
-import "unsafe"
-
-// maxMapSize represents the largest mmap size supported by Bolt.
-const maxMapSize = 0x7FFFFFFF // 2GB
-
-// maxAllocSize is the size used when creating array pointers.
-const maxAllocSize = 0xFFFFFFF
-
-// Are unaligned load/stores broken on this arch?
-var brokenUnaligned bool
-
-func init() {
- // Simple check to see whether this arch handles unaligned load/stores
- // correctly.
-
- // ARM9 and older devices require load/stores to be from/to aligned
- // addresses. If not, the lower 2 bits are cleared and that address is
- // read in a jumbled up order.
-
- // See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html
-
- raw := [6]byte{0xfe, 0xef, 0x11, 0x22, 0x22, 0x11}
- val := *(*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(&raw)) + 2))
-
- brokenUnaligned = val != 0x11222211
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm64.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm64.go
deleted file mode 100644
index b26d84f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm64.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build arm64
-
-package bolt
-
-// maxMapSize represents the largest mmap size supported by Bolt.
-const maxMapSize = 0xFFFFFFFFFFFF // 256TB
-
-// maxAllocSize is the size used when creating array pointers.
-const maxAllocSize = 0x7FFFFFFF
-
-// Are unaligned load/stores broken on this arch?
-var brokenUnaligned = false
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_linux.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_linux.go
deleted file mode 100644
index 2b67666..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_linux.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package bolt
-
-import (
- "syscall"
-)
-
-// fdatasync flushes written data to a file descriptor.
-func fdatasync(db *DB) error {
- return syscall.Fdatasync(int(db.file.Fd()))
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_openbsd.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_openbsd.go
deleted file mode 100644
index 7058c3d..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_openbsd.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package bolt
-
-import (
- "syscall"
- "unsafe"
-)
-
-const (
- msAsync = 1 << iota // perform asynchronous writes
- msSync // perform synchronous writes
- msInvalidate // invalidate cached data
-)
-
-func msync(db *DB) error {
- _, _, errno := syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(db.data)), uintptr(db.datasz), msInvalidate)
- if errno != 0 {
- return errno
- }
- return nil
-}
-
-func fdatasync(db *DB) error {
- if db.data != nil {
- return msync(db)
- }
- return db.file.Sync()
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc.go
deleted file mode 100644
index 645ddc3..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// +build ppc
-
-package bolt
-
-// maxMapSize represents the largest mmap size supported by Bolt.
-const maxMapSize = 0x7FFFFFFF // 2GB
-
-// maxAllocSize is the size used when creating array pointers.
-const maxAllocSize = 0xFFFFFFF
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64.go
deleted file mode 100644
index 2dc6be0..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// +build ppc64
-
-package bolt
-
-// maxMapSize represents the largest mmap size supported by Bolt.
-const maxMapSize = 0xFFFFFFFFFFFF // 256TB
-
-// maxAllocSize is the size used when creating array pointers.
-const maxAllocSize = 0x7FFFFFFF
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64le.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64le.go
deleted file mode 100644
index 8c143bc..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64le.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build ppc64le
-
-package bolt
-
-// maxMapSize represents the largest mmap size supported by Bolt.
-const maxMapSize = 0xFFFFFFFFFFFF // 256TB
-
-// maxAllocSize is the size used when creating array pointers.
-const maxAllocSize = 0x7FFFFFFF
-
-// Are unaligned load/stores broken on this arch?
-var brokenUnaligned = false
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_s390x.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_s390x.go
deleted file mode 100644
index d7c39af..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_s390x.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build s390x
-
-package bolt
-
-// maxMapSize represents the largest mmap size supported by Bolt.
-const maxMapSize = 0xFFFFFFFFFFFF // 256TB
-
-// maxAllocSize is the size used when creating array pointers.
-const maxAllocSize = 0x7FFFFFFF
-
-// Are unaligned load/stores broken on this arch?
-var brokenUnaligned = false
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix.go
deleted file mode 100644
index cad62dd..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix.go
+++ /dev/null
@@ -1,89 +0,0 @@
-// +build !windows,!plan9,!solaris
-
-package bolt
-
-import (
- "fmt"
- "os"
- "syscall"
- "time"
- "unsafe"
-)
-
-// flock acquires an advisory lock on a file descriptor.
-func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error {
- var t time.Time
- for {
- // If we're beyond our timeout then return an error.
- // This can only occur after we've attempted a flock once.
- if t.IsZero() {
- t = time.Now()
- } else if timeout > 0 && time.Since(t) > timeout {
- return ErrTimeout
- }
- flag := syscall.LOCK_SH
- if exclusive {
- flag = syscall.LOCK_EX
- }
-
- // Otherwise attempt to obtain an exclusive lock.
- err := syscall.Flock(int(db.file.Fd()), flag|syscall.LOCK_NB)
- if err == nil {
- return nil
- } else if err != syscall.EWOULDBLOCK {
- return err
- }
-
- // Wait for a bit and try again.
- time.Sleep(50 * time.Millisecond)
- }
-}
-
-// funlock releases an advisory lock on a file descriptor.
-func funlock(db *DB) error {
- return syscall.Flock(int(db.file.Fd()), syscall.LOCK_UN)
-}
-
-// mmap memory maps a DB's data file.
-func mmap(db *DB, sz int) error {
- // Map the data file to memory.
- b, err := syscall.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
- if err != nil {
- return err
- }
-
- // Advise the kernel that the mmap is accessed randomly.
- if err := madvise(b, syscall.MADV_RANDOM); err != nil {
- return fmt.Errorf("madvise: %s", err)
- }
-
- // Save the original byte slice and convert to a byte array pointer.
- db.dataref = b
- db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
- db.datasz = sz
- return nil
-}
-
-// munmap unmaps a DB's data file from memory.
-func munmap(db *DB) error {
- // Ignore the unmap if we have no mapped data.
- if db.dataref == nil {
- return nil
- }
-
- // Unmap using the original byte slice.
- err := syscall.Munmap(db.dataref)
- db.dataref = nil
- db.data = nil
- db.datasz = 0
- return err
-}
-
-// NOTE: This function is copied from stdlib because it is not available on darwin.
-func madvise(b []byte, advice int) (err error) {
- _, _, e1 := syscall.Syscall(syscall.SYS_MADVISE, uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), uintptr(advice))
- if e1 != 0 {
- err = e1
- }
- return
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix_solaris.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix_solaris.go
deleted file mode 100644
index 307bf2b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix_solaris.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package bolt
-
-import (
- "fmt"
- "os"
- "syscall"
- "time"
- "unsafe"
-
- "golang.org/x/sys/unix"
-)
-
-// flock acquires an advisory lock on a file descriptor.
-func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error {
- var t time.Time
- for {
- // If we're beyond our timeout then return an error.
- // This can only occur after we've attempted a flock once.
- if t.IsZero() {
- t = time.Now()
- } else if timeout > 0 && time.Since(t) > timeout {
- return ErrTimeout
- }
- var lock syscall.Flock_t
- lock.Start = 0
- lock.Len = 0
- lock.Pid = 0
- lock.Whence = 0
- lock.Pid = 0
- if exclusive {
- lock.Type = syscall.F_WRLCK
- } else {
- lock.Type = syscall.F_RDLCK
- }
- err := syscall.FcntlFlock(db.file.Fd(), syscall.F_SETLK, &lock)
- if err == nil {
- return nil
- } else if err != syscall.EAGAIN {
- return err
- }
-
- // Wait for a bit and try again.
- time.Sleep(50 * time.Millisecond)
- }
-}
-
-// funlock releases an advisory lock on a file descriptor.
-func funlock(db *DB) error {
- var lock syscall.Flock_t
- lock.Start = 0
- lock.Len = 0
- lock.Type = syscall.F_UNLCK
- lock.Whence = 0
- return syscall.FcntlFlock(uintptr(db.file.Fd()), syscall.F_SETLK, &lock)
-}
-
-// mmap memory maps a DB's data file.
-func mmap(db *DB, sz int) error {
- // Map the data file to memory.
- b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
- if err != nil {
- return err
- }
-
- // Advise the kernel that the mmap is accessed randomly.
- if err := unix.Madvise(b, syscall.MADV_RANDOM); err != nil {
- return fmt.Errorf("madvise: %s", err)
- }
-
- // Save the original byte slice and convert to a byte array pointer.
- db.dataref = b
- db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0]))
- db.datasz = sz
- return nil
-}
-
-// munmap unmaps a DB's data file from memory.
-func munmap(db *DB) error {
- // Ignore the unmap if we have no mapped data.
- if db.dataref == nil {
- return nil
- }
-
- // Unmap using the original byte slice.
- err := unix.Munmap(db.dataref)
- db.dataref = nil
- db.data = nil
- db.datasz = 0
- return err
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_windows.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_windows.go
deleted file mode 100644
index b00fb07..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_windows.go
+++ /dev/null
@@ -1,144 +0,0 @@
-package bolt
-
-import (
- "fmt"
- "os"
- "syscall"
- "time"
- "unsafe"
-)
-
-// LockFileEx code derived from golang build filemutex_windows.go @ v1.5.1
-var (
- modkernel32 = syscall.NewLazyDLL("kernel32.dll")
- procLockFileEx = modkernel32.NewProc("LockFileEx")
- procUnlockFileEx = modkernel32.NewProc("UnlockFileEx")
-)
-
-const (
- lockExt = ".lock"
-
- // see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
- flagLockExclusive = 2
- flagLockFailImmediately = 1
-
- // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
- errLockViolation syscall.Errno = 0x21
-)
-
-func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
- r, _, err := procLockFileEx.Call(uintptr(h), uintptr(flags), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)))
- if r == 0 {
- return err
- }
- return nil
-}
-
-func unlockFileEx(h syscall.Handle, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
- r, _, err := procUnlockFileEx.Call(uintptr(h), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)), 0)
- if r == 0 {
- return err
- }
- return nil
-}
-
-// fdatasync flushes written data to a file descriptor.
-func fdatasync(db *DB) error {
- return db.file.Sync()
-}
-
-// flock acquires an advisory lock on a file descriptor.
-func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error {
- // Create a separate lock file on windows because a process
- // cannot share an exclusive lock on the same file. This is
- // needed during Tx.WriteTo().
- f, err := os.OpenFile(db.path+lockExt, os.O_CREATE, mode)
- if err != nil {
- return err
- }
- db.lockfile = f
-
- var t time.Time
- for {
- // If we're beyond our timeout then return an error.
- // This can only occur after we've attempted a flock once.
- if t.IsZero() {
- t = time.Now()
- } else if timeout > 0 && time.Since(t) > timeout {
- return ErrTimeout
- }
-
- var flag uint32 = flagLockFailImmediately
- if exclusive {
- flag |= flagLockExclusive
- }
-
- err := lockFileEx(syscall.Handle(db.lockfile.Fd()), flag, 0, 1, 0, &syscall.Overlapped{})
- if err == nil {
- return nil
- } else if err != errLockViolation {
- return err
- }
-
- // Wait for a bit and try again.
- time.Sleep(50 * time.Millisecond)
- }
-}
-
-// funlock releases an advisory lock on a file descriptor.
-func funlock(db *DB) error {
- err := unlockFileEx(syscall.Handle(db.lockfile.Fd()), 0, 1, 0, &syscall.Overlapped{})
- db.lockfile.Close()
- os.Remove(db.path + lockExt)
- return err
-}
-
-// mmap memory maps a DB's data file.
-// Based on: https://github.com/edsrzf/mmap-go
-func mmap(db *DB, sz int) error {
- if !db.readOnly {
- // Truncate the database to the size of the mmap.
- if err := db.file.Truncate(int64(sz)); err != nil {
- return fmt.Errorf("truncate: %s", err)
- }
- }
-
- // Open a file mapping handle.
- sizelo := uint32(sz >> 32)
- sizehi := uint32(sz) & 0xffffffff
- h, errno := syscall.CreateFileMapping(syscall.Handle(db.file.Fd()), nil, syscall.PAGE_READONLY, sizelo, sizehi, nil)
- if h == 0 {
- return os.NewSyscallError("CreateFileMapping", errno)
- }
-
- // Create the memory map.
- addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, uintptr(sz))
- if addr == 0 {
- return os.NewSyscallError("MapViewOfFile", errno)
- }
-
- // Close mapping handle.
- if err := syscall.CloseHandle(syscall.Handle(h)); err != nil {
- return os.NewSyscallError("CloseHandle", err)
- }
-
- // Convert to a byte array.
- db.data = ((*[maxMapSize]byte)(unsafe.Pointer(addr)))
- db.datasz = sz
-
- return nil
-}
-
-// munmap unmaps a pointer from a file.
-// Based on: https://github.com/edsrzf/mmap-go
-func munmap(db *DB) error {
- if db.data == nil {
- return nil
- }
-
- addr := (uintptr)(unsafe.Pointer(&db.data[0]))
- if err := syscall.UnmapViewOfFile(addr); err != nil {
- return os.NewSyscallError("UnmapViewOfFile", err)
- }
- return nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/boltsync_unix.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/boltsync_unix.go
deleted file mode 100644
index f504425..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/boltsync_unix.go
+++ /dev/null
@@ -1,8 +0,0 @@
-// +build !windows,!plan9,!linux,!openbsd
-
-package bolt
-
-// fdatasync flushes written data to a file descriptor.
-func fdatasync(db *DB) error {
- return db.file.Sync()
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket.go
deleted file mode 100644
index 511ce72..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket.go
+++ /dev/null
@@ -1,778 +0,0 @@
-package bolt
-
-import (
- "bytes"
- "fmt"
- "unsafe"
-)
-
-const (
- // MaxKeySize is the maximum length of a key, in bytes.
- MaxKeySize = 32768
-
- // MaxValueSize is the maximum length of a value, in bytes.
- MaxValueSize = (1 << 31) - 2
-)
-
-const (
- maxUint = ^uint(0)
- minUint = 0
- maxInt = int(^uint(0) >> 1)
- minInt = -maxInt - 1
-)
-
-const bucketHeaderSize = int(unsafe.Sizeof(bucket{}))
-
-const (
- minFillPercent = 0.1
- maxFillPercent = 1.0
-)
-
-// DefaultFillPercent is the percentage that split pages are filled.
-// This value can be changed by setting Bucket.FillPercent.
-const DefaultFillPercent = 0.5
-
-// Bucket represents a collection of key/value pairs inside the database.
-type Bucket struct {
- *bucket
- tx *Tx // the associated transaction
- buckets map[string]*Bucket // subbucket cache
- page *page // inline page reference
- rootNode *node // materialized node for the root page.
- nodes map[pgid]*node // node cache
-
- // Sets the threshold for filling nodes when they split. By default,
- // the bucket will fill to 50% but it can be useful to increase this
- // amount if you know that your write workloads are mostly append-only.
- //
- // This is non-persisted across transactions so it must be set in every Tx.
- FillPercent float64
-}
-
-// bucket represents the on-file representation of a bucket.
-// This is stored as the "value" of a bucket key. If the bucket is small enough,
-// then its root page can be stored inline in the "value", after the bucket
-// header. In the case of inline buckets, the "root" will be 0.
-type bucket struct {
- root pgid // page id of the bucket's root-level page
- sequence uint64 // monotonically incrementing, used by NextSequence()
-}
-
-// newBucket returns a new bucket associated with a transaction.
-func newBucket(tx *Tx) Bucket {
- var b = Bucket{tx: tx, FillPercent: DefaultFillPercent}
- if tx.writable {
- b.buckets = make(map[string]*Bucket)
- b.nodes = make(map[pgid]*node)
- }
- return b
-}
-
-// Tx returns the tx of the bucket.
-func (b *Bucket) Tx() *Tx {
- return b.tx
-}
-
-// Root returns the root of the bucket.
-func (b *Bucket) Root() pgid {
- return b.root
-}
-
-// Writable returns whether the bucket is writable.
-func (b *Bucket) Writable() bool {
- return b.tx.writable
-}
-
-// Cursor creates a cursor associated with the bucket.
-// The cursor is only valid as long as the transaction is open.
-// Do not use a cursor after the transaction is closed.
-func (b *Bucket) Cursor() *Cursor {
- // Update transaction statistics.
- b.tx.stats.CursorCount++
-
- // Allocate and return a cursor.
- return &Cursor{
- bucket: b,
- stack: make([]elemRef, 0),
- }
-}
-
-// Bucket retrieves a nested bucket by name.
-// Returns nil if the bucket does not exist.
-// The bucket instance is only valid for the lifetime of the transaction.
-func (b *Bucket) Bucket(name []byte) *Bucket {
- if b.buckets != nil {
- if child := b.buckets[string(name)]; child != nil {
- return child
- }
- }
-
- // Move cursor to key.
- c := b.Cursor()
- k, v, flags := c.seek(name)
-
- // Return nil if the key doesn't exist or it is not a bucket.
- if !bytes.Equal(name, k) || (flags&bucketLeafFlag) == 0 {
- return nil
- }
-
- // Otherwise create a bucket and cache it.
- var child = b.openBucket(v)
- if b.buckets != nil {
- b.buckets[string(name)] = child
- }
-
- return child
-}
-
-// Helper method that re-interprets a sub-bucket value
-// from a parent into a Bucket
-func (b *Bucket) openBucket(value []byte) *Bucket {
- var child = newBucket(b.tx)
-
- // If unaligned load/stores are broken on this arch and value is
- // unaligned simply clone to an aligned byte array.
- unaligned := brokenUnaligned && uintptr(unsafe.Pointer(&value[0]))&3 != 0
-
- if unaligned {
- value = cloneBytes(value)
- }
-
- // If this is a writable transaction then we need to copy the bucket entry.
- // Read-only transactions can point directly at the mmap entry.
- if b.tx.writable && !unaligned {
- child.bucket = &bucket{}
- *child.bucket = *(*bucket)(unsafe.Pointer(&value[0]))
- } else {
- child.bucket = (*bucket)(unsafe.Pointer(&value[0]))
- }
-
- // Save a reference to the inline page if the bucket is inline.
- if child.root == 0 {
- child.page = (*page)(unsafe.Pointer(&value[bucketHeaderSize]))
- }
-
- return &child
-}
-
-// CreateBucket creates a new bucket at the given key and returns the new bucket.
-// Returns an error if the key already exists, if the bucket name is blank, or if the bucket name is too long.
-// The bucket instance is only valid for the lifetime of the transaction.
-func (b *Bucket) CreateBucket(key []byte) (*Bucket, error) {
- if b.tx.db == nil {
- return nil, ErrTxClosed
- } else if !b.tx.writable {
- return nil, ErrTxNotWritable
- } else if len(key) == 0 {
- return nil, ErrBucketNameRequired
- }
-
- // Move cursor to correct position.
- c := b.Cursor()
- k, _, flags := c.seek(key)
-
- // Return an error if there is an existing key.
- if bytes.Equal(key, k) {
- if (flags & bucketLeafFlag) != 0 {
- return nil, ErrBucketExists
- } else {
- return nil, ErrIncompatibleValue
- }
- }
-
- // Create empty, inline bucket.
- var bucket = Bucket{
- bucket: &bucket{},
- rootNode: &node{isLeaf: true},
- FillPercent: DefaultFillPercent,
- }
- var value = bucket.write()
-
- // Insert into node.
- key = cloneBytes(key)
- c.node().put(key, key, value, 0, bucketLeafFlag)
-
- // Since subbuckets are not allowed on inline buckets, we need to
- // dereference the inline page, if it exists. This will cause the bucket
- // to be treated as a regular, non-inline bucket for the rest of the tx.
- b.page = nil
-
- return b.Bucket(key), nil
-}
-
-// CreateBucketIfNotExists creates a new bucket if it doesn't already exist and returns a reference to it.
-// Returns an error if the bucket name is blank, or if the bucket name is too long.
-// The bucket instance is only valid for the lifetime of the transaction.
-func (b *Bucket) CreateBucketIfNotExists(key []byte) (*Bucket, error) {
- child, err := b.CreateBucket(key)
- if err == ErrBucketExists {
- return b.Bucket(key), nil
- } else if err != nil {
- return nil, err
- }
- return child, nil
-}
-
-// DeleteBucket deletes a bucket at the given key.
-// Returns an error if the bucket does not exists, or if the key represents a non-bucket value.
-func (b *Bucket) DeleteBucket(key []byte) error {
- if b.tx.db == nil {
- return ErrTxClosed
- } else if !b.Writable() {
- return ErrTxNotWritable
- }
-
- // Move cursor to correct position.
- c := b.Cursor()
- k, _, flags := c.seek(key)
-
- // Return an error if bucket doesn't exist or is not a bucket.
- if !bytes.Equal(key, k) {
- return ErrBucketNotFound
- } else if (flags & bucketLeafFlag) == 0 {
- return ErrIncompatibleValue
- }
-
- // Recursively delete all child buckets.
- child := b.Bucket(key)
- err := child.ForEach(func(k, v []byte) error {
- if v == nil {
- if err := child.DeleteBucket(k); err != nil {
- return fmt.Errorf("delete bucket: %s", err)
- }
- }
- return nil
- })
- if err != nil {
- return err
- }
-
- // Remove cached copy.
- delete(b.buckets, string(key))
-
- // Release all bucket pages to freelist.
- child.nodes = nil
- child.rootNode = nil
- child.free()
-
- // Delete the node if we have a matching key.
- c.node().del(key)
-
- return nil
-}
-
-// Get retrieves the value for a key in the bucket.
-// Returns a nil value if the key does not exist or if the key is a nested bucket.
-// The returned value is only valid for the life of the transaction.
-func (b *Bucket) Get(key []byte) []byte {
- k, v, flags := b.Cursor().seek(key)
-
- // Return nil if this is a bucket.
- if (flags & bucketLeafFlag) != 0 {
- return nil
- }
-
- // If our target node isn't the same key as what's passed in then return nil.
- if !bytes.Equal(key, k) {
- return nil
- }
- return v
-}
-
-// Put sets the value for a key in the bucket.
-// If the key exist then its previous value will be overwritten.
-// Supplied value must remain valid for the life of the transaction.
-// Returns an error if the bucket was created from a read-only transaction, if the key is blank, if the key is too large, or if the value is too large.
-func (b *Bucket) Put(key []byte, value []byte) error {
- if b.tx.db == nil {
- return ErrTxClosed
- } else if !b.Writable() {
- return ErrTxNotWritable
- } else if len(key) == 0 {
- return ErrKeyRequired
- } else if len(key) > MaxKeySize {
- return ErrKeyTooLarge
- } else if int64(len(value)) > MaxValueSize {
- return ErrValueTooLarge
- }
-
- // Move cursor to correct position.
- c := b.Cursor()
- k, _, flags := c.seek(key)
-
- // Return an error if there is an existing key with a bucket value.
- if bytes.Equal(key, k) && (flags&bucketLeafFlag) != 0 {
- return ErrIncompatibleValue
- }
-
- // Insert into node.
- key = cloneBytes(key)
- c.node().put(key, key, value, 0, 0)
-
- return nil
-}
-
-// Delete removes a key from the bucket.
-// If the key does not exist then nothing is done and a nil error is returned.
-// Returns an error if the bucket was created from a read-only transaction.
-func (b *Bucket) Delete(key []byte) error {
- if b.tx.db == nil {
- return ErrTxClosed
- } else if !b.Writable() {
- return ErrTxNotWritable
- }
-
- // Move cursor to correct position.
- c := b.Cursor()
- _, _, flags := c.seek(key)
-
- // Return an error if there is already existing bucket value.
- if (flags & bucketLeafFlag) != 0 {
- return ErrIncompatibleValue
- }
-
- // Delete the node if we have a matching key.
- c.node().del(key)
-
- return nil
-}
-
-// Sequence returns the current integer for the bucket without incrementing it.
-func (b *Bucket) Sequence() uint64 { return b.bucket.sequence }
-
-// SetSequence updates the sequence number for the bucket.
-func (b *Bucket) SetSequence(v uint64) error {
- if b.tx.db == nil {
- return ErrTxClosed
- } else if !b.Writable() {
- return ErrTxNotWritable
- }
-
- // Materialize the root node if it hasn't been already so that the
- // bucket will be saved during commit.
- if b.rootNode == nil {
- _ = b.node(b.root, nil)
- }
-
- // Increment and return the sequence.
- b.bucket.sequence = v
- return nil
-}
-
-// NextSequence returns an autoincrementing integer for the bucket.
-func (b *Bucket) NextSequence() (uint64, error) {
- if b.tx.db == nil {
- return 0, ErrTxClosed
- } else if !b.Writable() {
- return 0, ErrTxNotWritable
- }
-
- // Materialize the root node if it hasn't been already so that the
- // bucket will be saved during commit.
- if b.rootNode == nil {
- _ = b.node(b.root, nil)
- }
-
- // Increment and return the sequence.
- b.bucket.sequence++
- return b.bucket.sequence, nil
-}
-
-// ForEach executes a function for each key/value pair in a bucket.
-// If the provided function returns an error then the iteration is stopped and
-// the error is returned to the caller. The provided function must not modify
-// the bucket; this will result in undefined behavior.
-func (b *Bucket) ForEach(fn func(k, v []byte) error) error {
- if b.tx.db == nil {
- return ErrTxClosed
- }
- c := b.Cursor()
- for k, v := c.First(); k != nil; k, v = c.Next() {
- if err := fn(k, v); err != nil {
- return err
- }
- }
- return nil
-}
-
-// Stat returns stats on a bucket.
-func (b *Bucket) Stats() BucketStats {
- var s, subStats BucketStats
- pageSize := b.tx.db.pageSize
- s.BucketN += 1
- if b.root == 0 {
- s.InlineBucketN += 1
- }
- b.forEachPage(func(p *page, depth int) {
- if (p.flags & leafPageFlag) != 0 {
- s.KeyN += int(p.count)
-
- // used totals the used bytes for the page
- used := pageHeaderSize
-
- if p.count != 0 {
- // If page has any elements, add all element headers.
- used += leafPageElementSize * int(p.count-1)
-
- // Add all element key, value sizes.
- // The computation takes advantage of the fact that the position
- // of the last element's key/value equals to the total of the sizes
- // of all previous elements' keys and values.
- // It also includes the last element's header.
- lastElement := p.leafPageElement(p.count - 1)
- used += int(lastElement.pos + lastElement.ksize + lastElement.vsize)
- }
-
- if b.root == 0 {
- // For inlined bucket just update the inline stats
- s.InlineBucketInuse += used
- } else {
- // For non-inlined bucket update all the leaf stats
- s.LeafPageN++
- s.LeafInuse += used
- s.LeafOverflowN += int(p.overflow)
-
- // Collect stats from sub-buckets.
- // Do that by iterating over all element headers
- // looking for the ones with the bucketLeafFlag.
- for i := uint16(0); i < p.count; i++ {
- e := p.leafPageElement(i)
- if (e.flags & bucketLeafFlag) != 0 {
- // For any bucket element, open the element value
- // and recursively call Stats on the contained bucket.
- subStats.Add(b.openBucket(e.value()).Stats())
- }
- }
- }
- } else if (p.flags & branchPageFlag) != 0 {
- s.BranchPageN++
- lastElement := p.branchPageElement(p.count - 1)
-
- // used totals the used bytes for the page
- // Add header and all element headers.
- used := pageHeaderSize + (branchPageElementSize * int(p.count-1))
-
- // Add size of all keys and values.
- // Again, use the fact that last element's position equals to
- // the total of key, value sizes of all previous elements.
- used += int(lastElement.pos + lastElement.ksize)
- s.BranchInuse += used
- s.BranchOverflowN += int(p.overflow)
- }
-
- // Keep track of maximum page depth.
- if depth+1 > s.Depth {
- s.Depth = (depth + 1)
- }
- })
-
- // Alloc stats can be computed from page counts and pageSize.
- s.BranchAlloc = (s.BranchPageN + s.BranchOverflowN) * pageSize
- s.LeafAlloc = (s.LeafPageN + s.LeafOverflowN) * pageSize
-
- // Add the max depth of sub-buckets to get total nested depth.
- s.Depth += subStats.Depth
- // Add the stats for all sub-buckets
- s.Add(subStats)
- return s
-}
-
-// forEachPage iterates over every page in a bucket, including inline pages.
-func (b *Bucket) forEachPage(fn func(*page, int)) {
- // If we have an inline page then just use that.
- if b.page != nil {
- fn(b.page, 0)
- return
- }
-
- // Otherwise traverse the page hierarchy.
- b.tx.forEachPage(b.root, 0, fn)
-}
-
-// forEachPageNode iterates over every page (or node) in a bucket.
-// This also includes inline pages.
-func (b *Bucket) forEachPageNode(fn func(*page, *node, int)) {
- // If we have an inline page or root node then just use that.
- if b.page != nil {
- fn(b.page, nil, 0)
- return
- }
- b._forEachPageNode(b.root, 0, fn)
-}
-
-func (b *Bucket) _forEachPageNode(pgid pgid, depth int, fn func(*page, *node, int)) {
- var p, n = b.pageNode(pgid)
-
- // Execute function.
- fn(p, n, depth)
-
- // Recursively loop over children.
- if p != nil {
- if (p.flags & branchPageFlag) != 0 {
- for i := 0; i < int(p.count); i++ {
- elem := p.branchPageElement(uint16(i))
- b._forEachPageNode(elem.pgid, depth+1, fn)
- }
- }
- } else {
- if !n.isLeaf {
- for _, inode := range n.inodes {
- b._forEachPageNode(inode.pgid, depth+1, fn)
- }
- }
- }
-}
-
-// spill writes all the nodes for this bucket to dirty pages.
-func (b *Bucket) spill() error {
- // Spill all child buckets first.
- for name, child := range b.buckets {
- // If the child bucket is small enough and it has no child buckets then
- // write it inline into the parent bucket's page. Otherwise spill it
- // like a normal bucket and make the parent value a pointer to the page.
- var value []byte
- if child.inlineable() {
- child.free()
- value = child.write()
- } else {
- if err := child.spill(); err != nil {
- return err
- }
-
- // Update the child bucket header in this bucket.
- value = make([]byte, unsafe.Sizeof(bucket{}))
- var bucket = (*bucket)(unsafe.Pointer(&value[0]))
- *bucket = *child.bucket
- }
-
- // Skip writing the bucket if there are no materialized nodes.
- if child.rootNode == nil {
- continue
- }
-
- // Update parent node.
- var c = b.Cursor()
- k, _, flags := c.seek([]byte(name))
- if !bytes.Equal([]byte(name), k) {
- panic(fmt.Sprintf("misplaced bucket header: %x -> %x", []byte(name), k))
- }
- if flags&bucketLeafFlag == 0 {
- panic(fmt.Sprintf("unexpected bucket header flag: %x", flags))
- }
- c.node().put([]byte(name), []byte(name), value, 0, bucketLeafFlag)
- }
-
- // Ignore if there's not a materialized root node.
- if b.rootNode == nil {
- return nil
- }
-
- // Spill nodes.
- if err := b.rootNode.spill(); err != nil {
- return err
- }
- b.rootNode = b.rootNode.root()
-
- // Update the root node for this bucket.
- if b.rootNode.pgid >= b.tx.meta.pgid {
- panic(fmt.Sprintf("pgid (%d) above high water mark (%d)", b.rootNode.pgid, b.tx.meta.pgid))
- }
- b.root = b.rootNode.pgid
-
- return nil
-}
-
-// inlineable returns true if a bucket is small enough to be written inline
-// and if it contains no subbuckets. Otherwise returns false.
-func (b *Bucket) inlineable() bool {
- var n = b.rootNode
-
- // Bucket must only contain a single leaf node.
- if n == nil || !n.isLeaf {
- return false
- }
-
- // Bucket is not inlineable if it contains subbuckets or if it goes beyond
- // our threshold for inline bucket size.
- var size = pageHeaderSize
- for _, inode := range n.inodes {
- size += leafPageElementSize + len(inode.key) + len(inode.value)
-
- if inode.flags&bucketLeafFlag != 0 {
- return false
- } else if size > b.maxInlineBucketSize() {
- return false
- }
- }
-
- return true
-}
-
-// Returns the maximum total size of a bucket to make it a candidate for inlining.
-func (b *Bucket) maxInlineBucketSize() int {
- return b.tx.db.pageSize / 4
-}
-
-// write allocates and writes a bucket to a byte slice.
-func (b *Bucket) write() []byte {
- // Allocate the appropriate size.
- var n = b.rootNode
- var value = make([]byte, bucketHeaderSize+n.size())
-
- // Write a bucket header.
- var bucket = (*bucket)(unsafe.Pointer(&value[0]))
- *bucket = *b.bucket
-
- // Convert byte slice to a fake page and write the root node.
- var p = (*page)(unsafe.Pointer(&value[bucketHeaderSize]))
- n.write(p)
-
- return value
-}
-
-// rebalance attempts to balance all nodes.
-func (b *Bucket) rebalance() {
- for _, n := range b.nodes {
- n.rebalance()
- }
- for _, child := range b.buckets {
- child.rebalance()
- }
-}
-
-// node creates a node from a page and associates it with a given parent.
-func (b *Bucket) node(pgid pgid, parent *node) *node {
- _assert(b.nodes != nil, "nodes map expected")
-
- // Retrieve node if it's already been created.
- if n := b.nodes[pgid]; n != nil {
- return n
- }
-
- // Otherwise create a node and cache it.
- n := &node{bucket: b, parent: parent}
- if parent == nil {
- b.rootNode = n
- } else {
- parent.children = append(parent.children, n)
- }
-
- // Use the inline page if this is an inline bucket.
- var p = b.page
- if p == nil {
- p = b.tx.page(pgid)
- }
-
- // Read the page into the node and cache it.
- n.read(p)
- b.nodes[pgid] = n
-
- // Update statistics.
- b.tx.stats.NodeCount++
-
- return n
-}
-
-// free recursively frees all pages in the bucket.
-func (b *Bucket) free() {
- if b.root == 0 {
- return
- }
-
- var tx = b.tx
- b.forEachPageNode(func(p *page, n *node, _ int) {
- if p != nil {
- tx.db.freelist.free(tx.meta.txid, p)
- } else {
- n.free()
- }
- })
- b.root = 0
-}
-
-// dereference removes all references to the old mmap.
-func (b *Bucket) dereference() {
- if b.rootNode != nil {
- b.rootNode.root().dereference()
- }
-
- for _, child := range b.buckets {
- child.dereference()
- }
-}
-
-// pageNode returns the in-memory node, if it exists.
-// Otherwise returns the underlying page.
-func (b *Bucket) pageNode(id pgid) (*page, *node) {
- // Inline buckets have a fake page embedded in their value so treat them
- // differently. We'll return the rootNode (if available) or the fake page.
- if b.root == 0 {
- if id != 0 {
- panic(fmt.Sprintf("inline bucket non-zero page access(2): %d != 0", id))
- }
- if b.rootNode != nil {
- return nil, b.rootNode
- }
- return b.page, nil
- }
-
- // Check the node cache for non-inline buckets.
- if b.nodes != nil {
- if n := b.nodes[id]; n != nil {
- return nil, n
- }
- }
-
- // Finally lookup the page from the transaction if no node is materialized.
- return b.tx.page(id), nil
-}
-
-// BucketStats records statistics about resources used by a bucket.
-type BucketStats struct {
- // Page count statistics.
- BranchPageN int // number of logical branch pages
- BranchOverflowN int // number of physical branch overflow pages
- LeafPageN int // number of logical leaf pages
- LeafOverflowN int // number of physical leaf overflow pages
-
- // Tree statistics.
- KeyN int // number of keys/value pairs
- Depth int // number of levels in B+tree
-
- // Page size utilization.
- BranchAlloc int // bytes allocated for physical branch pages
- BranchInuse int // bytes actually used for branch data
- LeafAlloc int // bytes allocated for physical leaf pages
- LeafInuse int // bytes actually used for leaf data
-
- // Bucket statistics
- BucketN int // total number of buckets including the top bucket
- InlineBucketN int // total number on inlined buckets
- InlineBucketInuse int // bytes used for inlined buckets (also accounted for in LeafInuse)
-}
-
-func (s *BucketStats) Add(other BucketStats) {
- s.BranchPageN += other.BranchPageN
- s.BranchOverflowN += other.BranchOverflowN
- s.LeafPageN += other.LeafPageN
- s.LeafOverflowN += other.LeafOverflowN
- s.KeyN += other.KeyN
- if s.Depth < other.Depth {
- s.Depth = other.Depth
- }
- s.BranchAlloc += other.BranchAlloc
- s.BranchInuse += other.BranchInuse
- s.LeafAlloc += other.LeafAlloc
- s.LeafInuse += other.LeafInuse
-
- s.BucketN += other.BucketN
- s.InlineBucketN += other.InlineBucketN
- s.InlineBucketInuse += other.InlineBucketInuse
-}
-
-// cloneBytes returns a copy of a given slice.
-func cloneBytes(v []byte) []byte {
- var clone = make([]byte, len(v))
- copy(clone, v)
- return clone
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket_test.go
deleted file mode 100644
index cddbe27..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket_test.go
+++ /dev/null
@@ -1,1909 +0,0 @@
-package bolt_test
-
-import (
- "bytes"
- "encoding/binary"
- "errors"
- "fmt"
- "log"
- "math/rand"
- "os"
- "strconv"
- "strings"
- "testing"
- "testing/quick"
-
- "github.com/boltdb/bolt"
-)
-
-// Ensure that a bucket that gets a non-existent key returns nil.
-func TestBucket_Get_NonExistent(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if v := b.Get([]byte("foo")); v != nil {
- t.Fatal("expected nil value")
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a bucket can read a value that is not flushed yet.
-func TestBucket_Get_FromNode(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
- if v := b.Get([]byte("foo")); !bytes.Equal(v, []byte("bar")) {
- t.Fatalf("unexpected value: %v", v)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a bucket retrieved via Get() returns a nil.
-func TestBucket_Get_IncompatibleValue(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
-
- if _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")); err != nil {
- t.Fatal(err)
- }
-
- if tx.Bucket([]byte("widgets")).Get([]byte("foo")) != nil {
- t.Fatal("expected nil value")
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a slice returned from a bucket has a capacity equal to its length.
-// This also allows slices to be appended to since it will require a realloc by Go.
-//
-// https://github.com/boltdb/bolt/issues/544
-func TestBucket_Get_Capacity(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- // Write key to a bucket.
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("bucket"))
- if err != nil {
- return err
- }
- return b.Put([]byte("key"), []byte("val"))
- }); err != nil {
- t.Fatal(err)
- }
-
- // Retrieve value and attempt to append to it.
- if err := db.Update(func(tx *bolt.Tx) error {
- k, v := tx.Bucket([]byte("bucket")).Cursor().First()
-
- // Verify capacity.
- if len(k) != cap(k) {
- t.Fatalf("unexpected key slice capacity: %d", cap(k))
- } else if len(v) != cap(v) {
- t.Fatalf("unexpected value slice capacity: %d", cap(v))
- }
-
- // Ensure slice can be appended to without a segfault.
- k = append(k, []byte("123")...)
- v = append(v, []byte("123")...)
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a bucket can write a key/value.
-func TestBucket_Put(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
-
- v := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
- if !bytes.Equal([]byte("bar"), v) {
- t.Fatalf("unexpected value: %v", v)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a bucket can rewrite a key in the same transaction.
-func TestBucket_Put_Repeat(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("baz")); err != nil {
- t.Fatal(err)
- }
-
- value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
- if !bytes.Equal([]byte("baz"), value) {
- t.Fatalf("unexpected value: %v", value)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a bucket can write a bunch of large values.
-func TestBucket_Put_Large(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- count, factor := 100, 200
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- for i := 1; i < count; i++ {
- if err := b.Put([]byte(strings.Repeat("0", i*factor)), []byte(strings.Repeat("X", (count-i)*factor))); err != nil {
- t.Fatal(err)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("widgets"))
- for i := 1; i < count; i++ {
- value := b.Get([]byte(strings.Repeat("0", i*factor)))
- if !bytes.Equal(value, []byte(strings.Repeat("X", (count-i)*factor))) {
- t.Fatalf("unexpected value: %v", value)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a database can perform multiple large appends safely.
-func TestDB_Put_VeryLarge(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping test in short mode.")
- }
-
- n, batchN := 400000, 200000
- ksize, vsize := 8, 500
-
- db := MustOpenDB()
- defer db.MustClose()
-
- for i := 0; i < n; i += batchN {
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucketIfNotExists([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- for j := 0; j < batchN; j++ {
- k, v := make([]byte, ksize), make([]byte, vsize)
- binary.BigEndian.PutUint32(k, uint32(i+j))
- if err := b.Put(k, v); err != nil {
- t.Fatal(err)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- }
-}
-
-// Ensure that a setting a value on a key with a bucket value returns an error.
-func TestBucket_Put_IncompatibleValue(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b0, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
-
- if _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")); err != nil {
- t.Fatal(err)
- }
- if err := b0.Put([]byte("foo"), []byte("bar")); err != bolt.ErrIncompatibleValue {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a setting a value while the transaction is closed returns an error.
-func TestBucket_Put_Closed(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- tx, err := db.Begin(true)
- if err != nil {
- t.Fatal(err)
- }
-
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
-
- if err := tx.Rollback(); err != nil {
- t.Fatal(err)
- }
-
- if err := b.Put([]byte("foo"), []byte("bar")); err != bolt.ErrTxClosed {
- t.Fatalf("unexpected error: %s", err)
- }
-}
-
-// Ensure that setting a value on a read-only bucket returns an error.
-func TestBucket_Put_ReadOnly(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("widgets"))
- if err := b.Put([]byte("foo"), []byte("bar")); err != bolt.ErrTxNotWritable {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a bucket can delete an existing key.
-func TestBucket_Delete(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
- if err := b.Delete([]byte("foo")); err != nil {
- t.Fatal(err)
- }
- if v := b.Get([]byte("foo")); v != nil {
- t.Fatalf("unexpected value: %v", v)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that deleting a large set of keys will work correctly.
-func TestBucket_Delete_Large(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
-
- for i := 0; i < 100; i++ {
- if err := b.Put([]byte(strconv.Itoa(i)), []byte(strings.Repeat("*", 1024))); err != nil {
- t.Fatal(err)
- }
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("widgets"))
- for i := 0; i < 100; i++ {
- if err := b.Delete([]byte(strconv.Itoa(i))); err != nil {
- t.Fatal(err)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("widgets"))
- for i := 0; i < 100; i++ {
- if v := b.Get([]byte(strconv.Itoa(i))); v != nil {
- t.Fatalf("unexpected value: %v, i=%d", v, i)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Deleting a very large list of keys will cause the freelist to use overflow.
-func TestBucket_Delete_FreelistOverflow(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping test in short mode.")
- }
-
- db := MustOpenDB()
- defer db.MustClose()
-
- k := make([]byte, 16)
- for i := uint64(0); i < 10000; i++ {
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucketIfNotExists([]byte("0"))
- if err != nil {
- t.Fatalf("bucket error: %s", err)
- }
-
- for j := uint64(0); j < 1000; j++ {
- binary.BigEndian.PutUint64(k[:8], i)
- binary.BigEndian.PutUint64(k[8:], j)
- if err := b.Put(k, nil); err != nil {
- t.Fatalf("put error: %s", err)
- }
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- }
-
- // Delete all of them in one large transaction
- if err := db.Update(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("0"))
- c := b.Cursor()
- for k, _ := c.First(); k != nil; k, _ = c.Next() {
- if err := c.Delete(); err != nil {
- t.Fatal(err)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that accessing and updating nested buckets is ok across transactions.
-func TestBucket_Nested(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- // Create a widgets bucket.
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
-
- // Create a widgets/foo bucket.
- _, err = b.CreateBucket([]byte("foo"))
- if err != nil {
- t.Fatal(err)
- }
-
- // Create a widgets/bar key.
- if err := b.Put([]byte("bar"), []byte("0000")); err != nil {
- t.Fatal(err)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- db.MustCheck()
-
- // Update widgets/bar.
- if err := db.Update(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("widgets"))
- if err := b.Put([]byte("bar"), []byte("xxxx")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- db.MustCheck()
-
- // Cause a split.
- if err := db.Update(func(tx *bolt.Tx) error {
- var b = tx.Bucket([]byte("widgets"))
- for i := 0; i < 10000; i++ {
- if err := b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil {
- t.Fatal(err)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- db.MustCheck()
-
- // Insert into widgets/foo/baz.
- if err := db.Update(func(tx *bolt.Tx) error {
- var b = tx.Bucket([]byte("widgets"))
- if err := b.Bucket([]byte("foo")).Put([]byte("baz"), []byte("yyyy")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- db.MustCheck()
-
- // Verify.
- if err := db.View(func(tx *bolt.Tx) error {
- var b = tx.Bucket([]byte("widgets"))
- if v := b.Bucket([]byte("foo")).Get([]byte("baz")); !bytes.Equal(v, []byte("yyyy")) {
- t.Fatalf("unexpected value: %v", v)
- }
- if v := b.Get([]byte("bar")); !bytes.Equal(v, []byte("xxxx")) {
- t.Fatalf("unexpected value: %v", v)
- }
- for i := 0; i < 10000; i++ {
- if v := b.Get([]byte(strconv.Itoa(i))); !bytes.Equal(v, []byte(strconv.Itoa(i))) {
- t.Fatalf("unexpected value: %v", v)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that deleting a bucket using Delete() returns an error.
-func TestBucket_Delete_Bucket(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if _, err := b.CreateBucket([]byte("foo")); err != nil {
- t.Fatal(err)
- }
- if err := b.Delete([]byte("foo")); err != bolt.ErrIncompatibleValue {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that deleting a key on a read-only bucket returns an error.
-func TestBucket_Delete_ReadOnly(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.View(func(tx *bolt.Tx) error {
- if err := tx.Bucket([]byte("widgets")).Delete([]byte("foo")); err != bolt.ErrTxNotWritable {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a deleting value while the transaction is closed returns an error.
-func TestBucket_Delete_Closed(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- tx, err := db.Begin(true)
- if err != nil {
- t.Fatal(err)
- }
-
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
-
- if err := tx.Rollback(); err != nil {
- t.Fatal(err)
- }
- if err := b.Delete([]byte("foo")); err != bolt.ErrTxClosed {
- t.Fatalf("unexpected error: %s", err)
- }
-}
-
-// Ensure that deleting a bucket causes nested buckets to be deleted.
-func TestBucket_DeleteBucket_Nested(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- widgets, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
-
- foo, err := widgets.CreateBucket([]byte("foo"))
- if err != nil {
- t.Fatal(err)
- }
-
- bar, err := foo.CreateBucket([]byte("bar"))
- if err != nil {
- t.Fatal(err)
- }
- if err := bar.Put([]byte("baz"), []byte("bat")); err != nil {
- t.Fatal(err)
- }
- if err := tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that deleting a bucket causes nested buckets to be deleted after they have been committed.
-func TestBucket_DeleteBucket_Nested2(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- widgets, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
-
- foo, err := widgets.CreateBucket([]byte("foo"))
- if err != nil {
- t.Fatal(err)
- }
-
- bar, err := foo.CreateBucket([]byte("bar"))
- if err != nil {
- t.Fatal(err)
- }
-
- if err := bar.Put([]byte("baz"), []byte("bat")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.Update(func(tx *bolt.Tx) error {
- widgets := tx.Bucket([]byte("widgets"))
- if widgets == nil {
- t.Fatal("expected widgets bucket")
- }
-
- foo := widgets.Bucket([]byte("foo"))
- if foo == nil {
- t.Fatal("expected foo bucket")
- }
-
- bar := foo.Bucket([]byte("bar"))
- if bar == nil {
- t.Fatal("expected bar bucket")
- }
-
- if v := bar.Get([]byte("baz")); !bytes.Equal(v, []byte("bat")) {
- t.Fatalf("unexpected value: %v", v)
- }
- if err := tx.DeleteBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.View(func(tx *bolt.Tx) error {
- if tx.Bucket([]byte("widgets")) != nil {
- t.Fatal("expected bucket to be deleted")
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that deleting a child bucket with multiple pages causes all pages to get collected.
-// NOTE: Consistency check in bolt_test.DB.Close() will panic if pages not freed properly.
-func TestBucket_DeleteBucket_Large(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- widgets, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
-
- foo, err := widgets.CreateBucket([]byte("foo"))
- if err != nil {
- t.Fatal(err)
- }
-
- for i := 0; i < 1000; i++ {
- if err := foo.Put([]byte(fmt.Sprintf("%d", i)), []byte(fmt.Sprintf("%0100d", i))); err != nil {
- t.Fatal(err)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.Update(func(tx *bolt.Tx) error {
- if err := tx.DeleteBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a simple value retrieved via Bucket() returns a nil.
-func TestBucket_Bucket_IncompatibleValue(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- widgets, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
-
- if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
- if b := tx.Bucket([]byte("widgets")).Bucket([]byte("foo")); b != nil {
- t.Fatal("expected nil bucket")
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that creating a bucket on an existing non-bucket key returns an error.
-func TestBucket_CreateBucket_IncompatibleValue(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- widgets, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
-
- if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
- if _, err := widgets.CreateBucket([]byte("foo")); err != bolt.ErrIncompatibleValue {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that deleting a bucket on an existing non-bucket key returns an error.
-func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- widgets, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
- if err := tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")); err != bolt.ErrIncompatibleValue {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure bucket can set and update its sequence number.
-func TestBucket_Sequence(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- bkt, err := tx.CreateBucket([]byte("0"))
- if err != nil {
- t.Fatal(err)
- }
-
- // Retrieve sequence.
- if v := bkt.Sequence(); v != 0 {
- t.Fatalf("unexpected sequence: %d", v)
- }
-
- // Update sequence.
- if err := bkt.SetSequence(1000); err != nil {
- t.Fatal(err)
- }
-
- // Read sequence again.
- if v := bkt.Sequence(); v != 1000 {
- t.Fatalf("unexpected sequence: %d", v)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- // Verify sequence in separate transaction.
- if err := db.View(func(tx *bolt.Tx) error {
- if v := tx.Bucket([]byte("0")).Sequence(); v != 1000 {
- t.Fatalf("unexpected sequence: %d", v)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a bucket can return an autoincrementing sequence.
-func TestBucket_NextSequence(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- widgets, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- woojits, err := tx.CreateBucket([]byte("woojits"))
- if err != nil {
- t.Fatal(err)
- }
-
- // Make sure sequence increments.
- if seq, err := widgets.NextSequence(); err != nil {
- t.Fatal(err)
- } else if seq != 1 {
- t.Fatalf("unexpecte sequence: %d", seq)
- }
-
- if seq, err := widgets.NextSequence(); err != nil {
- t.Fatal(err)
- } else if seq != 2 {
- t.Fatalf("unexpected sequence: %d", seq)
- }
-
- // Buckets should be separate.
- if seq, err := woojits.NextSequence(); err != nil {
- t.Fatal(err)
- } else if seq != 1 {
- t.Fatalf("unexpected sequence: %d", 1)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a bucket will persist an autoincrementing sequence even if its
-// the only thing updated on the bucket.
-// https://github.com/boltdb/bolt/issues/296
-func TestBucket_NextSequence_Persist(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.Bucket([]byte("widgets")).NextSequence(); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.Update(func(tx *bolt.Tx) error {
- seq, err := tx.Bucket([]byte("widgets")).NextSequence()
- if err != nil {
- t.Fatalf("unexpected error: %s", err)
- } else if seq != 2 {
- t.Fatalf("unexpected sequence: %d", seq)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that retrieving the next sequence on a read-only bucket returns an error.
-func TestBucket_NextSequence_ReadOnly(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.View(func(tx *bolt.Tx) error {
- _, err := tx.Bucket([]byte("widgets")).NextSequence()
- if err != bolt.ErrTxNotWritable {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that retrieving the next sequence for a bucket on a closed database return an error.
-func TestBucket_NextSequence_Closed(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- tx, err := db.Begin(true)
- if err != nil {
- t.Fatal(err)
- }
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := tx.Rollback(); err != nil {
- t.Fatal(err)
- }
- if _, err := b.NextSequence(); err != bolt.ErrTxClosed {
- t.Fatal(err)
- }
-}
-
-// Ensure a user can loop over all key/value pairs in a bucket.
-func TestBucket_ForEach(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("0000")); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("baz"), []byte("0001")); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("bar"), []byte("0002")); err != nil {
- t.Fatal(err)
- }
-
- var index int
- if err := b.ForEach(func(k, v []byte) error {
- switch index {
- case 0:
- if !bytes.Equal(k, []byte("bar")) {
- t.Fatalf("unexpected key: %v", k)
- } else if !bytes.Equal(v, []byte("0002")) {
- t.Fatalf("unexpected value: %v", v)
- }
- case 1:
- if !bytes.Equal(k, []byte("baz")) {
- t.Fatalf("unexpected key: %v", k)
- } else if !bytes.Equal(v, []byte("0001")) {
- t.Fatalf("unexpected value: %v", v)
- }
- case 2:
- if !bytes.Equal(k, []byte("foo")) {
- t.Fatalf("unexpected key: %v", k)
- } else if !bytes.Equal(v, []byte("0000")) {
- t.Fatalf("unexpected value: %v", v)
- }
- }
- index++
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if index != 3 {
- t.Fatalf("unexpected index: %d", index)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure a database can stop iteration early.
-func TestBucket_ForEach_ShortCircuit(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("bar"), []byte("0000")); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("baz"), []byte("0000")); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("0000")); err != nil {
- t.Fatal(err)
- }
-
- var index int
- if err := tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error {
- index++
- if bytes.Equal(k, []byte("baz")) {
- return errors.New("marker")
- }
- return nil
- }); err == nil || err.Error() != "marker" {
- t.Fatalf("unexpected error: %s", err)
- }
- if index != 2 {
- t.Fatalf("unexpected index: %d", index)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that looping over a bucket on a closed database returns an error.
-func TestBucket_ForEach_Closed(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- tx, err := db.Begin(true)
- if err != nil {
- t.Fatal(err)
- }
-
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
-
- if err := tx.Rollback(); err != nil {
- t.Fatal(err)
- }
-
- if err := b.ForEach(func(k, v []byte) error { return nil }); err != bolt.ErrTxClosed {
- t.Fatalf("unexpected error: %s", err)
- }
-}
-
-// Ensure that an error is returned when inserting with an empty key.
-func TestBucket_Put_EmptyKey(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte(""), []byte("bar")); err != bolt.ErrKeyRequired {
- t.Fatalf("unexpected error: %s", err)
- }
- if err := b.Put(nil, []byte("bar")); err != bolt.ErrKeyRequired {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that an error is returned when inserting with a key that's too large.
-func TestBucket_Put_KeyTooLarge(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put(make([]byte, 32769), []byte("bar")); err != bolt.ErrKeyTooLarge {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that an error is returned when inserting a value that's too large.
-func TestBucket_Put_ValueTooLarge(t *testing.T) {
- // Skip this test on DroneCI because the machine is resource constrained.
- if os.Getenv("DRONE") == "true" {
- t.Skip("not enough RAM for test")
- }
-
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), make([]byte, bolt.MaxValueSize+1)); err != bolt.ErrValueTooLarge {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure a bucket can calculate stats.
-func TestBucket_Stats(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- // Add bucket with fewer keys but one big value.
- bigKey := []byte("really-big-value")
- for i := 0; i < 500; i++ {
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucketIfNotExists([]byte("woojits"))
- if err != nil {
- t.Fatal(err)
- }
-
- if err := b.Put([]byte(fmt.Sprintf("%03d", i)), []byte(strconv.Itoa(i))); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- }
- if err := db.Update(func(tx *bolt.Tx) error {
- if err := tx.Bucket([]byte("woojits")).Put(bigKey, []byte(strings.Repeat("*", 10000))); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- db.MustCheck()
-
- if err := db.View(func(tx *bolt.Tx) error {
- stats := tx.Bucket([]byte("woojits")).Stats()
- if stats.BranchPageN != 1 {
- t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
- } else if stats.BranchOverflowN != 0 {
- t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
- } else if stats.LeafPageN != 7 {
- t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
- } else if stats.LeafOverflowN != 2 {
- t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
- } else if stats.KeyN != 501 {
- t.Fatalf("unexpected KeyN: %d", stats.KeyN)
- } else if stats.Depth != 2 {
- t.Fatalf("unexpected Depth: %d", stats.Depth)
- }
-
- branchInuse := 16 // branch page header
- branchInuse += 7 * 16 // branch elements
- branchInuse += 7 * 3 // branch keys (6 3-byte keys)
- if stats.BranchInuse != branchInuse {
- t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
- }
-
- leafInuse := 7 * 16 // leaf page header
- leafInuse += 501 * 16 // leaf elements
- leafInuse += 500*3 + len(bigKey) // leaf keys
- leafInuse += 1*10 + 2*90 + 3*400 + 10000 // leaf values
- if stats.LeafInuse != leafInuse {
- t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
- }
-
- // Only check allocations for 4KB pages.
- if os.Getpagesize() == 4096 {
- if stats.BranchAlloc != 4096 {
- t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
- } else if stats.LeafAlloc != 36864 {
- t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
- }
- }
-
- if stats.BucketN != 1 {
- t.Fatalf("unexpected BucketN: %d", stats.BucketN)
- } else if stats.InlineBucketN != 0 {
- t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN)
- } else if stats.InlineBucketInuse != 0 {
- t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure a bucket with random insertion utilizes fill percentage correctly.
-func TestBucket_Stats_RandomFill(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping test in short mode.")
- } else if os.Getpagesize() != 4096 {
- t.Skip("invalid page size for test")
- }
-
- db := MustOpenDB()
- defer db.MustClose()
-
- // Add a set of values in random order. It will be the same random
- // order so we can maintain consistency between test runs.
- var count int
- rand := rand.New(rand.NewSource(42))
- for _, i := range rand.Perm(1000) {
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucketIfNotExists([]byte("woojits"))
- if err != nil {
- t.Fatal(err)
- }
- b.FillPercent = 0.9
- for _, j := range rand.Perm(100) {
- index := (j * 10000) + i
- if err := b.Put([]byte(fmt.Sprintf("%d000000000000000", index)), []byte("0000000000")); err != nil {
- t.Fatal(err)
- }
- count++
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- }
-
- db.MustCheck()
-
- if err := db.View(func(tx *bolt.Tx) error {
- stats := tx.Bucket([]byte("woojits")).Stats()
- if stats.KeyN != 100000 {
- t.Fatalf("unexpected KeyN: %d", stats.KeyN)
- }
-
- if stats.BranchPageN != 98 {
- t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
- } else if stats.BranchOverflowN != 0 {
- t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
- } else if stats.BranchInuse != 130984 {
- t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
- } else if stats.BranchAlloc != 401408 {
- t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
- }
-
- if stats.LeafPageN != 3412 {
- t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
- } else if stats.LeafOverflowN != 0 {
- t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
- } else if stats.LeafInuse != 4742482 {
- t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
- } else if stats.LeafAlloc != 13975552 {
- t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure a bucket can calculate stats.
-func TestBucket_Stats_Small(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- // Add a bucket that fits on a single root leaf.
- b, err := tx.CreateBucket([]byte("whozawhats"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- db.MustCheck()
-
- if err := db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("whozawhats"))
- stats := b.Stats()
- if stats.BranchPageN != 0 {
- t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
- } else if stats.BranchOverflowN != 0 {
- t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
- } else if stats.LeafPageN != 0 {
- t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
- } else if stats.LeafOverflowN != 0 {
- t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
- } else if stats.KeyN != 1 {
- t.Fatalf("unexpected KeyN: %d", stats.KeyN)
- } else if stats.Depth != 1 {
- t.Fatalf("unexpected Depth: %d", stats.Depth)
- } else if stats.BranchInuse != 0 {
- t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
- } else if stats.LeafInuse != 0 {
- t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
- }
-
- if os.Getpagesize() == 4096 {
- if stats.BranchAlloc != 0 {
- t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
- } else if stats.LeafAlloc != 0 {
- t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
- }
- }
-
- if stats.BucketN != 1 {
- t.Fatalf("unexpected BucketN: %d", stats.BucketN)
- } else if stats.InlineBucketN != 1 {
- t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN)
- } else if stats.InlineBucketInuse != 16+16+6 {
- t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestBucket_Stats_EmptyBucket(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- // Add a bucket that fits on a single root leaf.
- if _, err := tx.CreateBucket([]byte("whozawhats")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- db.MustCheck()
-
- if err := db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("whozawhats"))
- stats := b.Stats()
- if stats.BranchPageN != 0 {
- t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
- } else if stats.BranchOverflowN != 0 {
- t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
- } else if stats.LeafPageN != 0 {
- t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
- } else if stats.LeafOverflowN != 0 {
- t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
- } else if stats.KeyN != 0 {
- t.Fatalf("unexpected KeyN: %d", stats.KeyN)
- } else if stats.Depth != 1 {
- t.Fatalf("unexpected Depth: %d", stats.Depth)
- } else if stats.BranchInuse != 0 {
- t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
- } else if stats.LeafInuse != 0 {
- t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
- }
-
- if os.Getpagesize() == 4096 {
- if stats.BranchAlloc != 0 {
- t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
- } else if stats.LeafAlloc != 0 {
- t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
- }
- }
-
- if stats.BucketN != 1 {
- t.Fatalf("unexpected BucketN: %d", stats.BucketN)
- } else if stats.InlineBucketN != 1 {
- t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN)
- } else if stats.InlineBucketInuse != 16 {
- t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure a bucket can calculate stats.
-func TestBucket_Stats_Nested(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("foo"))
- if err != nil {
- t.Fatal(err)
- }
- for i := 0; i < 100; i++ {
- if err := b.Put([]byte(fmt.Sprintf("%02d", i)), []byte(fmt.Sprintf("%02d", i))); err != nil {
- t.Fatal(err)
- }
- }
-
- bar, err := b.CreateBucket([]byte("bar"))
- if err != nil {
- t.Fatal(err)
- }
- for i := 0; i < 10; i++ {
- if err := bar.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil {
- t.Fatal(err)
- }
- }
-
- baz, err := bar.CreateBucket([]byte("baz"))
- if err != nil {
- t.Fatal(err)
- }
- for i := 0; i < 10; i++ {
- if err := baz.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil {
- t.Fatal(err)
- }
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- db.MustCheck()
-
- if err := db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("foo"))
- stats := b.Stats()
- if stats.BranchPageN != 0 {
- t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
- } else if stats.BranchOverflowN != 0 {
- t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
- } else if stats.LeafPageN != 2 {
- t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
- } else if stats.LeafOverflowN != 0 {
- t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
- } else if stats.KeyN != 122 {
- t.Fatalf("unexpected KeyN: %d", stats.KeyN)
- } else if stats.Depth != 3 {
- t.Fatalf("unexpected Depth: %d", stats.Depth)
- } else if stats.BranchInuse != 0 {
- t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
- }
-
- foo := 16 // foo (pghdr)
- foo += 101 * 16 // foo leaf elements
- foo += 100*2 + 100*2 // foo leaf key/values
- foo += 3 + 16 // foo -> bar key/value
-
- bar := 16 // bar (pghdr)
- bar += 11 * 16 // bar leaf elements
- bar += 10 + 10 // bar leaf key/values
- bar += 3 + 16 // bar -> baz key/value
-
- baz := 16 // baz (inline) (pghdr)
- baz += 10 * 16 // baz leaf elements
- baz += 10 + 10 // baz leaf key/values
-
- if stats.LeafInuse != foo+bar+baz {
- t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
- }
-
- if os.Getpagesize() == 4096 {
- if stats.BranchAlloc != 0 {
- t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
- } else if stats.LeafAlloc != 8192 {
- t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
- }
- }
-
- if stats.BucketN != 3 {
- t.Fatalf("unexpected BucketN: %d", stats.BucketN)
- } else if stats.InlineBucketN != 1 {
- t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN)
- } else if stats.InlineBucketInuse != baz {
- t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure a large bucket can calculate stats.
-func TestBucket_Stats_Large(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping test in short mode.")
- }
-
- db := MustOpenDB()
- defer db.MustClose()
-
- var index int
- for i := 0; i < 100; i++ {
- // Add bucket with lots of keys.
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucketIfNotExists([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- for i := 0; i < 1000; i++ {
- if err := b.Put([]byte(strconv.Itoa(index)), []byte(strconv.Itoa(index))); err != nil {
- t.Fatal(err)
- }
- index++
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- }
-
- db.MustCheck()
-
- if err := db.View(func(tx *bolt.Tx) error {
- stats := tx.Bucket([]byte("widgets")).Stats()
- if stats.BranchPageN != 13 {
- t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
- } else if stats.BranchOverflowN != 0 {
- t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
- } else if stats.LeafPageN != 1196 {
- t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
- } else if stats.LeafOverflowN != 0 {
- t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
- } else if stats.KeyN != 100000 {
- t.Fatalf("unexpected KeyN: %d", stats.KeyN)
- } else if stats.Depth != 3 {
- t.Fatalf("unexpected Depth: %d", stats.Depth)
- } else if stats.BranchInuse != 25257 {
- t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
- } else if stats.LeafInuse != 2596916 {
- t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
- }
-
- if os.Getpagesize() == 4096 {
- if stats.BranchAlloc != 53248 {
- t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
- } else if stats.LeafAlloc != 4898816 {
- t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
- }
- }
-
- if stats.BucketN != 1 {
- t.Fatalf("unexpected BucketN: %d", stats.BucketN)
- } else if stats.InlineBucketN != 0 {
- t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN)
- } else if stats.InlineBucketInuse != 0 {
- t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a bucket can write random keys and values across multiple transactions.
-func TestBucket_Put_Single(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping test in short mode.")
- }
-
- index := 0
- if err := quick.Check(func(items testdata) bool {
- db := MustOpenDB()
- defer db.MustClose()
-
- m := make(map[string][]byte)
-
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- for _, item := range items {
- if err := db.Update(func(tx *bolt.Tx) error {
- if err := tx.Bucket([]byte("widgets")).Put(item.Key, item.Value); err != nil {
- panic("put error: " + err.Error())
- }
- m[string(item.Key)] = item.Value
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- // Verify all key/values so far.
- if err := db.View(func(tx *bolt.Tx) error {
- i := 0
- for k, v := range m {
- value := tx.Bucket([]byte("widgets")).Get([]byte(k))
- if !bytes.Equal(value, v) {
- t.Logf("value mismatch [run %d] (%d of %d):\nkey: %x\ngot: %x\nexp: %x", index, i, len(m), []byte(k), value, v)
- db.CopyTempFile()
- t.FailNow()
- }
- i++
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- }
-
- index++
- return true
- }, nil); err != nil {
- t.Error(err)
- }
-}
-
-// Ensure that a transaction can insert multiple key/value pairs at once.
-func TestBucket_Put_Multiple(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping test in short mode.")
- }
-
- if err := quick.Check(func(items testdata) bool {
- db := MustOpenDB()
- defer db.MustClose()
-
- // Bulk insert all values.
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("widgets"))
- for _, item := range items {
- if err := b.Put(item.Key, item.Value); err != nil {
- t.Fatal(err)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- // Verify all items exist.
- if err := db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("widgets"))
- for _, item := range items {
- value := b.Get(item.Key)
- if !bytes.Equal(item.Value, value) {
- db.CopyTempFile()
- t.Fatalf("exp=%x; got=%x", item.Value, value)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- return true
- }, qconfig()); err != nil {
- t.Error(err)
- }
-}
-
-// Ensure that a transaction can delete all key/value pairs and return to a single leaf page.
-func TestBucket_Delete_Quick(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping test in short mode.")
- }
-
- if err := quick.Check(func(items testdata) bool {
- db := MustOpenDB()
- defer db.MustClose()
-
- // Bulk insert all values.
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("widgets"))
- for _, item := range items {
- if err := b.Put(item.Key, item.Value); err != nil {
- t.Fatal(err)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- // Remove items one at a time and check consistency.
- for _, item := range items {
- if err := db.Update(func(tx *bolt.Tx) error {
- return tx.Bucket([]byte("widgets")).Delete(item.Key)
- }); err != nil {
- t.Fatal(err)
- }
- }
-
- // Anything before our deletion index should be nil.
- if err := db.View(func(tx *bolt.Tx) error {
- if err := tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error {
- t.Fatalf("bucket should be empty; found: %06x", trunc(k, 3))
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- return true
- }, qconfig()); err != nil {
- t.Error(err)
- }
-}
-
-func ExampleBucket_Put() {
- // Open the database.
- db, err := bolt.Open(tempfile(), 0666, nil)
- if err != nil {
- log.Fatal(err)
- }
- defer os.Remove(db.Path())
-
- // Start a write transaction.
- if err := db.Update(func(tx *bolt.Tx) error {
- // Create a bucket.
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- return err
- }
-
- // Set the value "bar" for the key "foo".
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- return err
- }
- return nil
- }); err != nil {
- log.Fatal(err)
- }
-
- // Read value back in a different read-only transaction.
- if err := db.View(func(tx *bolt.Tx) error {
- value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
- fmt.Printf("The value of 'foo' is: %s\n", value)
- return nil
- }); err != nil {
- log.Fatal(err)
- }
-
- // Close database to release file lock.
- if err := db.Close(); err != nil {
- log.Fatal(err)
- }
-
- // Output:
- // The value of 'foo' is: bar
-}
-
-func ExampleBucket_Delete() {
- // Open the database.
- db, err := bolt.Open(tempfile(), 0666, nil)
- if err != nil {
- log.Fatal(err)
- }
- defer os.Remove(db.Path())
-
- // Start a write transaction.
- if err := db.Update(func(tx *bolt.Tx) error {
- // Create a bucket.
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- return err
- }
-
- // Set the value "bar" for the key "foo".
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- return err
- }
-
- // Retrieve the key back from the database and verify it.
- value := b.Get([]byte("foo"))
- fmt.Printf("The value of 'foo' was: %s\n", value)
-
- return nil
- }); err != nil {
- log.Fatal(err)
- }
-
- // Delete the key in a different write transaction.
- if err := db.Update(func(tx *bolt.Tx) error {
- return tx.Bucket([]byte("widgets")).Delete([]byte("foo"))
- }); err != nil {
- log.Fatal(err)
- }
-
- // Retrieve the key again.
- if err := db.View(func(tx *bolt.Tx) error {
- value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
- if value == nil {
- fmt.Printf("The value of 'foo' is now: nil\n")
- }
- return nil
- }); err != nil {
- log.Fatal(err)
- }
-
- // Close database to release file lock.
- if err := db.Close(); err != nil {
- log.Fatal(err)
- }
-
- // Output:
- // The value of 'foo' was: bar
- // The value of 'foo' is now: nil
-}
-
-func ExampleBucket_ForEach() {
- // Open the database.
- db, err := bolt.Open(tempfile(), 0666, nil)
- if err != nil {
- log.Fatal(err)
- }
- defer os.Remove(db.Path())
-
- // Insert data into a bucket.
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("animals"))
- if err != nil {
- return err
- }
-
- if err := b.Put([]byte("dog"), []byte("fun")); err != nil {
- return err
- }
- if err := b.Put([]byte("cat"), []byte("lame")); err != nil {
- return err
- }
- if err := b.Put([]byte("liger"), []byte("awesome")); err != nil {
- return err
- }
-
- // Iterate over items in sorted key order.
- if err := b.ForEach(func(k, v []byte) error {
- fmt.Printf("A %s is %s.\n", k, v)
- return nil
- }); err != nil {
- return err
- }
-
- return nil
- }); err != nil {
- log.Fatal(err)
- }
-
- // Close database to release file lock.
- if err := db.Close(); err != nil {
- log.Fatal(err)
- }
-
- // Output:
- // A cat is lame.
- // A dog is fun.
- // A liger is awesome.
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main.go
deleted file mode 100644
index 29e393f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main.go
+++ /dev/null
@@ -1,1740 +0,0 @@
-package main
-
-import (
- "bytes"
- "encoding/binary"
- "errors"
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "math/rand"
- "os"
- "runtime"
- "runtime/pprof"
- "strconv"
- "strings"
- "time"
- "unicode"
- "unicode/utf8"
- "unsafe"
-
- "github.com/boltdb/bolt"
-)
-
-var (
- // ErrUsage is returned when a usage message was printed and the process
- // should simply exit with an error.
- ErrUsage = errors.New("usage")
-
- // ErrUnknownCommand is returned when a CLI command is not specified.
- ErrUnknownCommand = errors.New("unknown command")
-
- // ErrPathRequired is returned when the path to a Bolt database is not specified.
- ErrPathRequired = errors.New("path required")
-
- // ErrFileNotFound is returned when a Bolt database does not exist.
- ErrFileNotFound = errors.New("file not found")
-
- // ErrInvalidValue is returned when a benchmark reads an unexpected value.
- ErrInvalidValue = errors.New("invalid value")
-
- // ErrCorrupt is returned when a checking a data file finds errors.
- ErrCorrupt = errors.New("invalid value")
-
- // ErrNonDivisibleBatchSize is returned when the batch size can't be evenly
- // divided by the iteration count.
- ErrNonDivisibleBatchSize = errors.New("number of iterations must be divisible by the batch size")
-
- // ErrPageIDRequired is returned when a required page id is not specified.
- ErrPageIDRequired = errors.New("page id required")
-
- // ErrPageNotFound is returned when specifying a page above the high water mark.
- ErrPageNotFound = errors.New("page not found")
-
- // ErrPageFreed is returned when reading a page that has already been freed.
- ErrPageFreed = errors.New("page freed")
-)
-
-// PageHeaderSize represents the size of the bolt.page header.
-const PageHeaderSize = 16
-
-func main() {
- m := NewMain()
- if err := m.Run(os.Args[1:]...); err == ErrUsage {
- os.Exit(2)
- } else if err != nil {
- fmt.Println(err.Error())
- os.Exit(1)
- }
-}
-
-// Main represents the main program execution.
-type Main struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
-// NewMain returns a new instance of Main connect to the standard input/output.
-func NewMain() *Main {
- return &Main{
- Stdin: os.Stdin,
- Stdout: os.Stdout,
- Stderr: os.Stderr,
- }
-}
-
-// Run executes the program.
-func (m *Main) Run(args ...string) error {
- // Require a command at the beginning.
- if len(args) == 0 || strings.HasPrefix(args[0], "-") {
- fmt.Fprintln(m.Stderr, m.Usage())
- return ErrUsage
- }
-
- // Execute command.
- switch args[0] {
- case "help":
- fmt.Fprintln(m.Stderr, m.Usage())
- return ErrUsage
- case "bench":
- return newBenchCommand(m).Run(args[1:]...)
- case "check":
- return newCheckCommand(m).Run(args[1:]...)
- case "compact":
- return newCompactCommand(m).Run(args[1:]...)
- case "dump":
- return newDumpCommand(m).Run(args[1:]...)
- case "info":
- return newInfoCommand(m).Run(args[1:]...)
- case "page":
- return newPageCommand(m).Run(args[1:]...)
- case "pages":
- return newPagesCommand(m).Run(args[1:]...)
- case "stats":
- return newStatsCommand(m).Run(args[1:]...)
- default:
- return ErrUnknownCommand
- }
-}
-
-// Usage returns the help message.
-func (m *Main) Usage() string {
- return strings.TrimLeft(`
-Bolt is a tool for inspecting bolt databases.
-
-Usage:
-
- bolt command [arguments]
-
-The commands are:
-
- bench run synthetic benchmark against bolt
- check verifies integrity of bolt database
- compact copies a bolt database, compacting it in the process
- info print basic info
- help print this screen
- pages print list of pages with their types
- stats iterate over all pages and generate usage stats
-
-Use "bolt [command] -h" for more information about a command.
-`, "\n")
-}
-
-// CheckCommand represents the "check" command execution.
-type CheckCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
-// NewCheckCommand returns a CheckCommand.
-func newCheckCommand(m *Main) *CheckCommand {
- return &CheckCommand{
- Stdin: m.Stdin,
- Stdout: m.Stdout,
- Stderr: m.Stderr,
- }
-}
-
-// Run executes the command.
-func (cmd *CheckCommand) Run(args ...string) error {
- // Parse flags.
- fs := flag.NewFlagSet("", flag.ContinueOnError)
- help := fs.Bool("h", false, "")
- if err := fs.Parse(args); err != nil {
- return err
- } else if *help {
- fmt.Fprintln(cmd.Stderr, cmd.Usage())
- return ErrUsage
- }
-
- // Require database path.
- path := fs.Arg(0)
- if path == "" {
- return ErrPathRequired
- } else if _, err := os.Stat(path); os.IsNotExist(err) {
- return ErrFileNotFound
- }
-
- // Open database.
- db, err := bolt.Open(path, 0666, nil)
- if err != nil {
- return err
- }
- defer db.Close()
-
- // Perform consistency check.
- return db.View(func(tx *bolt.Tx) error {
- var count int
- ch := tx.Check()
- loop:
- for {
- select {
- case err, ok := <-ch:
- if !ok {
- break loop
- }
- fmt.Fprintln(cmd.Stdout, err)
- count++
- }
- }
-
- // Print summary of errors.
- if count > 0 {
- fmt.Fprintf(cmd.Stdout, "%d errors found\n", count)
- return ErrCorrupt
- }
-
- // Notify user that database is valid.
- fmt.Fprintln(cmd.Stdout, "OK")
- return nil
- })
-}
-
-// Usage returns the help message.
-func (cmd *CheckCommand) Usage() string {
- return strings.TrimLeft(`
-usage: bolt check PATH
-
-Check opens a database at PATH and runs an exhaustive check to verify that
-all pages are accessible or are marked as freed. It also verifies that no
-pages are double referenced.
-
-Verification errors will stream out as they are found and the process will
-return after all pages have been checked.
-`, "\n")
-}
-
-// InfoCommand represents the "info" command execution.
-type InfoCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
-// NewInfoCommand returns a InfoCommand.
-func newInfoCommand(m *Main) *InfoCommand {
- return &InfoCommand{
- Stdin: m.Stdin,
- Stdout: m.Stdout,
- Stderr: m.Stderr,
- }
-}
-
-// Run executes the command.
-func (cmd *InfoCommand) Run(args ...string) error {
- // Parse flags.
- fs := flag.NewFlagSet("", flag.ContinueOnError)
- help := fs.Bool("h", false, "")
- if err := fs.Parse(args); err != nil {
- return err
- } else if *help {
- fmt.Fprintln(cmd.Stderr, cmd.Usage())
- return ErrUsage
- }
-
- // Require database path.
- path := fs.Arg(0)
- if path == "" {
- return ErrPathRequired
- } else if _, err := os.Stat(path); os.IsNotExist(err) {
- return ErrFileNotFound
- }
-
- // Open the database.
- db, err := bolt.Open(path, 0666, nil)
- if err != nil {
- return err
- }
- defer db.Close()
-
- // Print basic database info.
- info := db.Info()
- fmt.Fprintf(cmd.Stdout, "Page Size: %d\n", info.PageSize)
-
- return nil
-}
-
-// Usage returns the help message.
-func (cmd *InfoCommand) Usage() string {
- return strings.TrimLeft(`
-usage: bolt info PATH
-
-Info prints basic information about the Bolt database at PATH.
-`, "\n")
-}
-
-// DumpCommand represents the "dump" command execution.
-type DumpCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
-// newDumpCommand returns a DumpCommand.
-func newDumpCommand(m *Main) *DumpCommand {
- return &DumpCommand{
- Stdin: m.Stdin,
- Stdout: m.Stdout,
- Stderr: m.Stderr,
- }
-}
-
-// Run executes the command.
-func (cmd *DumpCommand) Run(args ...string) error {
- // Parse flags.
- fs := flag.NewFlagSet("", flag.ContinueOnError)
- help := fs.Bool("h", false, "")
- if err := fs.Parse(args); err != nil {
- return err
- } else if *help {
- fmt.Fprintln(cmd.Stderr, cmd.Usage())
- return ErrUsage
- }
-
- // Require database path and page id.
- path := fs.Arg(0)
- if path == "" {
- return ErrPathRequired
- } else if _, err := os.Stat(path); os.IsNotExist(err) {
- return ErrFileNotFound
- }
-
- // Read page ids.
- pageIDs, err := atois(fs.Args()[1:])
- if err != nil {
- return err
- } else if len(pageIDs) == 0 {
- return ErrPageIDRequired
- }
-
- // Open database to retrieve page size.
- pageSize, err := ReadPageSize(path)
- if err != nil {
- return err
- }
-
- // Open database file handler.
- f, err := os.Open(path)
- if err != nil {
- return err
- }
- defer func() { _ = f.Close() }()
-
- // Print each page listed.
- for i, pageID := range pageIDs {
- // Print a separator.
- if i > 0 {
- fmt.Fprintln(cmd.Stdout, "===============================================")
- }
-
- // Print page to stdout.
- if err := cmd.PrintPage(cmd.Stdout, f, pageID, pageSize); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-// PrintPage prints a given page as hexidecimal.
-func (cmd *DumpCommand) PrintPage(w io.Writer, r io.ReaderAt, pageID int, pageSize int) error {
- const bytesPerLineN = 16
-
- // Read page into buffer.
- buf := make([]byte, pageSize)
- addr := pageID * pageSize
- if n, err := r.ReadAt(buf, int64(addr)); err != nil {
- return err
- } else if n != pageSize {
- return io.ErrUnexpectedEOF
- }
-
- // Write out to writer in 16-byte lines.
- var prev []byte
- var skipped bool
- for offset := 0; offset < pageSize; offset += bytesPerLineN {
- // Retrieve current 16-byte line.
- line := buf[offset : offset+bytesPerLineN]
- isLastLine := (offset == (pageSize - bytesPerLineN))
-
- // If it's the same as the previous line then print a skip.
- if bytes.Equal(line, prev) && !isLastLine {
- if !skipped {
- fmt.Fprintf(w, "%07x *\n", addr+offset)
- skipped = true
- }
- } else {
- // Print line as hexadecimal in 2-byte groups.
- fmt.Fprintf(w, "%07x %04x %04x %04x %04x %04x %04x %04x %04x\n", addr+offset,
- line[0:2], line[2:4], line[4:6], line[6:8],
- line[8:10], line[10:12], line[12:14], line[14:16],
- )
-
- skipped = false
- }
-
- // Save the previous line.
- prev = line
- }
- fmt.Fprint(w, "\n")
-
- return nil
-}
-
-// Usage returns the help message.
-func (cmd *DumpCommand) Usage() string {
- return strings.TrimLeft(`
-usage: bolt dump -page PAGEID PATH
-
-Dump prints a hexidecimal dump of a single page.
-`, "\n")
-}
-
-// PageCommand represents the "page" command execution.
-type PageCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
-// newPageCommand returns a PageCommand.
-func newPageCommand(m *Main) *PageCommand {
- return &PageCommand{
- Stdin: m.Stdin,
- Stdout: m.Stdout,
- Stderr: m.Stderr,
- }
-}
-
-// Run executes the command.
-func (cmd *PageCommand) Run(args ...string) error {
- // Parse flags.
- fs := flag.NewFlagSet("", flag.ContinueOnError)
- help := fs.Bool("h", false, "")
- if err := fs.Parse(args); err != nil {
- return err
- } else if *help {
- fmt.Fprintln(cmd.Stderr, cmd.Usage())
- return ErrUsage
- }
-
- // Require database path and page id.
- path := fs.Arg(0)
- if path == "" {
- return ErrPathRequired
- } else if _, err := os.Stat(path); os.IsNotExist(err) {
- return ErrFileNotFound
- }
-
- // Read page ids.
- pageIDs, err := atois(fs.Args()[1:])
- if err != nil {
- return err
- } else if len(pageIDs) == 0 {
- return ErrPageIDRequired
- }
-
- // Open database file handler.
- f, err := os.Open(path)
- if err != nil {
- return err
- }
- defer func() { _ = f.Close() }()
-
- // Print each page listed.
- for i, pageID := range pageIDs {
- // Print a separator.
- if i > 0 {
- fmt.Fprintln(cmd.Stdout, "===============================================")
- }
-
- // Retrieve page info and page size.
- p, buf, err := ReadPage(path, pageID)
- if err != nil {
- return err
- }
-
- // Print basic page info.
- fmt.Fprintf(cmd.Stdout, "Page ID: %d\n", p.id)
- fmt.Fprintf(cmd.Stdout, "Page Type: %s\n", p.Type())
- fmt.Fprintf(cmd.Stdout, "Total Size: %d bytes\n", len(buf))
-
- // Print type-specific data.
- switch p.Type() {
- case "meta":
- err = cmd.PrintMeta(cmd.Stdout, buf)
- case "leaf":
- err = cmd.PrintLeaf(cmd.Stdout, buf)
- case "branch":
- err = cmd.PrintBranch(cmd.Stdout, buf)
- case "freelist":
- err = cmd.PrintFreelist(cmd.Stdout, buf)
- }
- if err != nil {
- return err
- }
- }
-
- return nil
-}
-
-// PrintMeta prints the data from the meta page.
-func (cmd *PageCommand) PrintMeta(w io.Writer, buf []byte) error {
- m := (*meta)(unsafe.Pointer(&buf[PageHeaderSize]))
- fmt.Fprintf(w, "Version: %d\n", m.version)
- fmt.Fprintf(w, "Page Size: %d bytes\n", m.pageSize)
- fmt.Fprintf(w, "Flags: %08x\n", m.flags)
- fmt.Fprintf(w, "Root: <pgid=%d>\n", m.root.root)
- fmt.Fprintf(w, "Freelist: <pgid=%d>\n", m.freelist)
- fmt.Fprintf(w, "HWM: <pgid=%d>\n", m.pgid)
- fmt.Fprintf(w, "Txn ID: %d\n", m.txid)
- fmt.Fprintf(w, "Checksum: %016x\n", m.checksum)
- fmt.Fprintf(w, "\n")
- return nil
-}
-
-// PrintLeaf prints the data for a leaf page.
-func (cmd *PageCommand) PrintLeaf(w io.Writer, buf []byte) error {
- p := (*page)(unsafe.Pointer(&buf[0]))
-
- // Print number of items.
- fmt.Fprintf(w, "Item Count: %d\n", p.count)
- fmt.Fprintf(w, "\n")
-
- // Print each key/value.
- for i := uint16(0); i < p.count; i++ {
- e := p.leafPageElement(i)
-
- // Format key as string.
- var k string
- if isPrintable(string(e.key())) {
- k = fmt.Sprintf("%q", string(e.key()))
- } else {
- k = fmt.Sprintf("%x", string(e.key()))
- }
-
- // Format value as string.
- var v string
- if (e.flags & uint32(bucketLeafFlag)) != 0 {
- b := (*bucket)(unsafe.Pointer(&e.value()[0]))
- v = fmt.Sprintf("<pgid=%d,seq=%d>", b.root, b.sequence)
- } else if isPrintable(string(e.value())) {
- v = fmt.Sprintf("%q", string(e.value()))
- } else {
- v = fmt.Sprintf("%x", string(e.value()))
- }
-
- fmt.Fprintf(w, "%s: %s\n", k, v)
- }
- fmt.Fprintf(w, "\n")
- return nil
-}
-
-// PrintBranch prints the data for a leaf page.
-func (cmd *PageCommand) PrintBranch(w io.Writer, buf []byte) error {
- p := (*page)(unsafe.Pointer(&buf[0]))
-
- // Print number of items.
- fmt.Fprintf(w, "Item Count: %d\n", p.count)
- fmt.Fprintf(w, "\n")
-
- // Print each key/value.
- for i := uint16(0); i < p.count; i++ {
- e := p.branchPageElement(i)
-
- // Format key as string.
- var k string
- if isPrintable(string(e.key())) {
- k = fmt.Sprintf("%q", string(e.key()))
- } else {
- k = fmt.Sprintf("%x", string(e.key()))
- }
-
- fmt.Fprintf(w, "%s: <pgid=%d>\n", k, e.pgid)
- }
- fmt.Fprintf(w, "\n")
- return nil
-}
-
-// PrintFreelist prints the data for a freelist page.
-func (cmd *PageCommand) PrintFreelist(w io.Writer, buf []byte) error {
- p := (*page)(unsafe.Pointer(&buf[0]))
-
- // Print number of items.
- fmt.Fprintf(w, "Item Count: %d\n", p.count)
- fmt.Fprintf(w, "\n")
-
- // Print each page in the freelist.
- ids := (*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr))
- for i := uint16(0); i < p.count; i++ {
- fmt.Fprintf(w, "%d\n", ids[i])
- }
- fmt.Fprintf(w, "\n")
- return nil
-}
-
-// PrintPage prints a given page as hexidecimal.
-func (cmd *PageCommand) PrintPage(w io.Writer, r io.ReaderAt, pageID int, pageSize int) error {
- const bytesPerLineN = 16
-
- // Read page into buffer.
- buf := make([]byte, pageSize)
- addr := pageID * pageSize
- if n, err := r.ReadAt(buf, int64(addr)); err != nil {
- return err
- } else if n != pageSize {
- return io.ErrUnexpectedEOF
- }
-
- // Write out to writer in 16-byte lines.
- var prev []byte
- var skipped bool
- for offset := 0; offset < pageSize; offset += bytesPerLineN {
- // Retrieve current 16-byte line.
- line := buf[offset : offset+bytesPerLineN]
- isLastLine := (offset == (pageSize - bytesPerLineN))
-
- // If it's the same as the previous line then print a skip.
- if bytes.Equal(line, prev) && !isLastLine {
- if !skipped {
- fmt.Fprintf(w, "%07x *\n", addr+offset)
- skipped = true
- }
- } else {
- // Print line as hexadecimal in 2-byte groups.
- fmt.Fprintf(w, "%07x %04x %04x %04x %04x %04x %04x %04x %04x\n", addr+offset,
- line[0:2], line[2:4], line[4:6], line[6:8],
- line[8:10], line[10:12], line[12:14], line[14:16],
- )
-
- skipped = false
- }
-
- // Save the previous line.
- prev = line
- }
- fmt.Fprint(w, "\n")
-
- return nil
-}
-
-// Usage returns the help message.
-func (cmd *PageCommand) Usage() string {
- return strings.TrimLeft(`
-usage: bolt page -page PATH pageid [pageid...]
-
-Page prints one or more pages in human readable format.
-`, "\n")
-}
-
-// PagesCommand represents the "pages" command execution.
-type PagesCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
-// NewPagesCommand returns a PagesCommand.
-func newPagesCommand(m *Main) *PagesCommand {
- return &PagesCommand{
- Stdin: m.Stdin,
- Stdout: m.Stdout,
- Stderr: m.Stderr,
- }
-}
-
-// Run executes the command.
-func (cmd *PagesCommand) Run(args ...string) error {
- // Parse flags.
- fs := flag.NewFlagSet("", flag.ContinueOnError)
- help := fs.Bool("h", false, "")
- if err := fs.Parse(args); err != nil {
- return err
- } else if *help {
- fmt.Fprintln(cmd.Stderr, cmd.Usage())
- return ErrUsage
- }
-
- // Require database path.
- path := fs.Arg(0)
- if path == "" {
- return ErrPathRequired
- } else if _, err := os.Stat(path); os.IsNotExist(err) {
- return ErrFileNotFound
- }
-
- // Open database.
- db, err := bolt.Open(path, 0666, nil)
- if err != nil {
- return err
- }
- defer func() { _ = db.Close() }()
-
- // Write header.
- fmt.Fprintln(cmd.Stdout, "ID TYPE ITEMS OVRFLW")
- fmt.Fprintln(cmd.Stdout, "======== ========== ====== ======")
-
- return db.Update(func(tx *bolt.Tx) error {
- var id int
- for {
- p, err := tx.Page(id)
- if err != nil {
- return &PageError{ID: id, Err: err}
- } else if p == nil {
- break
- }
-
- // Only display count and overflow if this is a non-free page.
- var count, overflow string
- if p.Type != "free" {
- count = strconv.Itoa(p.Count)
- if p.OverflowCount > 0 {
- overflow = strconv.Itoa(p.OverflowCount)
- }
- }
-
- // Print table row.
- fmt.Fprintf(cmd.Stdout, "%-8d %-10s %-6s %-6s\n", p.ID, p.Type, count, overflow)
-
- // Move to the next non-overflow page.
- id += 1
- if p.Type != "free" {
- id += p.OverflowCount
- }
- }
- return nil
- })
-}
-
-// Usage returns the help message.
-func (cmd *PagesCommand) Usage() string {
- return strings.TrimLeft(`
-usage: bolt pages PATH
-
-Pages prints a table of pages with their type (meta, leaf, branch, freelist).
-Leaf and branch pages will show a key count in the "items" column while the
-freelist will show the number of free pages in the "items" column.
-
-The "overflow" column shows the number of blocks that the page spills over
-into. Normally there is no overflow but large keys and values can cause
-a single page to take up multiple blocks.
-`, "\n")
-}
-
-// StatsCommand represents the "stats" command execution.
-type StatsCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
-// NewStatsCommand returns a StatsCommand.
-func newStatsCommand(m *Main) *StatsCommand {
- return &StatsCommand{
- Stdin: m.Stdin,
- Stdout: m.Stdout,
- Stderr: m.Stderr,
- }
-}
-
-// Run executes the command.
-func (cmd *StatsCommand) Run(args ...string) error {
- // Parse flags.
- fs := flag.NewFlagSet("", flag.ContinueOnError)
- help := fs.Bool("h", false, "")
- if err := fs.Parse(args); err != nil {
- return err
- } else if *help {
- fmt.Fprintln(cmd.Stderr, cmd.Usage())
- return ErrUsage
- }
-
- // Require database path.
- path, prefix := fs.Arg(0), fs.Arg(1)
- if path == "" {
- return ErrPathRequired
- } else if _, err := os.Stat(path); os.IsNotExist(err) {
- return ErrFileNotFound
- }
-
- // Open database.
- db, err := bolt.Open(path, 0666, nil)
- if err != nil {
- return err
- }
- defer db.Close()
-
- return db.View(func(tx *bolt.Tx) error {
- var s bolt.BucketStats
- var count int
- if err := tx.ForEach(func(name []byte, b *bolt.Bucket) error {
- if bytes.HasPrefix(name, []byte(prefix)) {
- s.Add(b.Stats())
- count += 1
- }
- return nil
- }); err != nil {
- return err
- }
-
- fmt.Fprintf(cmd.Stdout, "Aggregate statistics for %d buckets\n\n", count)
-
- fmt.Fprintln(cmd.Stdout, "Page count statistics")
- fmt.Fprintf(cmd.Stdout, "\tNumber of logical branch pages: %d\n", s.BranchPageN)
- fmt.Fprintf(cmd.Stdout, "\tNumber of physical branch overflow pages: %d\n", s.BranchOverflowN)
- fmt.Fprintf(cmd.Stdout, "\tNumber of logical leaf pages: %d\n", s.LeafPageN)
- fmt.Fprintf(cmd.Stdout, "\tNumber of physical leaf overflow pages: %d\n", s.LeafOverflowN)
-
- fmt.Fprintln(cmd.Stdout, "Tree statistics")
- fmt.Fprintf(cmd.Stdout, "\tNumber of keys/value pairs: %d\n", s.KeyN)
- fmt.Fprintf(cmd.Stdout, "\tNumber of levels in B+tree: %d\n", s.Depth)
-
- fmt.Fprintln(cmd.Stdout, "Page size utilization")
- fmt.Fprintf(cmd.Stdout, "\tBytes allocated for physical branch pages: %d\n", s.BranchAlloc)
- var percentage int
- if s.BranchAlloc != 0 {
- percentage = int(float32(s.BranchInuse) * 100.0 / float32(s.BranchAlloc))
- }
- fmt.Fprintf(cmd.Stdout, "\tBytes actually used for branch data: %d (%d%%)\n", s.BranchInuse, percentage)
- fmt.Fprintf(cmd.Stdout, "\tBytes allocated for physical leaf pages: %d\n", s.LeafAlloc)
- percentage = 0
- if s.LeafAlloc != 0 {
- percentage = int(float32(s.LeafInuse) * 100.0 / float32(s.LeafAlloc))
- }
- fmt.Fprintf(cmd.Stdout, "\tBytes actually used for leaf data: %d (%d%%)\n", s.LeafInuse, percentage)
-
- fmt.Fprintln(cmd.Stdout, "Bucket statistics")
- fmt.Fprintf(cmd.Stdout, "\tTotal number of buckets: %d\n", s.BucketN)
- percentage = 0
- if s.BucketN != 0 {
- percentage = int(float32(s.InlineBucketN) * 100.0 / float32(s.BucketN))
- }
- fmt.Fprintf(cmd.Stdout, "\tTotal number on inlined buckets: %d (%d%%)\n", s.InlineBucketN, percentage)
- percentage = 0
- if s.LeafInuse != 0 {
- percentage = int(float32(s.InlineBucketInuse) * 100.0 / float32(s.LeafInuse))
- }
- fmt.Fprintf(cmd.Stdout, "\tBytes used for inlined buckets: %d (%d%%)\n", s.InlineBucketInuse, percentage)
-
- return nil
- })
-}
-
-// Usage returns the help message.
-func (cmd *StatsCommand) Usage() string {
- return strings.TrimLeft(`
-usage: bolt stats PATH
-
-Stats performs an extensive search of the database to track every page
-reference. It starts at the current meta page and recursively iterates
-through every accessible bucket.
-
-The following errors can be reported:
-
- already freed
- The page is referenced more than once in the freelist.
-
- unreachable unfreed
- The page is not referenced by a bucket or in the freelist.
-
- reachable freed
- The page is referenced by a bucket but is also in the freelist.
-
- out of bounds
- A page is referenced that is above the high water mark.
-
- multiple references
- A page is referenced by more than one other page.
-
- invalid type
- The page type is not "meta", "leaf", "branch", or "freelist".
-
-No errors should occur in your database. However, if for some reason you
-experience corruption, please submit a ticket to the Bolt project page:
-
- https://github.com/boltdb/bolt/issues
-`, "\n")
-}
-
-var benchBucketName = []byte("bench")
-
-// BenchCommand represents the "bench" command execution.
-type BenchCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-}
-
-// NewBenchCommand returns a BenchCommand using the
-func newBenchCommand(m *Main) *BenchCommand {
- return &BenchCommand{
- Stdin: m.Stdin,
- Stdout: m.Stdout,
- Stderr: m.Stderr,
- }
-}
-
-// Run executes the "bench" command.
-func (cmd *BenchCommand) Run(args ...string) error {
- // Parse CLI arguments.
- options, err := cmd.ParseFlags(args)
- if err != nil {
- return err
- }
-
- // Remove path if "-work" is not set. Otherwise keep path.
- if options.Work {
- fmt.Fprintf(cmd.Stdout, "work: %s\n", options.Path)
- } else {
- defer os.Remove(options.Path)
- }
-
- // Create database.
- db, err := bolt.Open(options.Path, 0666, nil)
- if err != nil {
- return err
- }
- db.NoSync = options.NoSync
- defer db.Close()
-
- // Write to the database.
- var results BenchResults
- if err := cmd.runWrites(db, options, &results); err != nil {
- return fmt.Errorf("write: %v", err)
- }
-
- // Read from the database.
- if err := cmd.runReads(db, options, &results); err != nil {
- return fmt.Errorf("bench: read: %s", err)
- }
-
- // Print results.
- fmt.Fprintf(os.Stderr, "# Write\t%v\t(%v/op)\t(%v op/sec)\n", results.WriteDuration, results.WriteOpDuration(), results.WriteOpsPerSecond())
- fmt.Fprintf(os.Stderr, "# Read\t%v\t(%v/op)\t(%v op/sec)\n", results.ReadDuration, results.ReadOpDuration(), results.ReadOpsPerSecond())
- fmt.Fprintln(os.Stderr, "")
- return nil
-}
-
-// ParseFlags parses the command line flags.
-func (cmd *BenchCommand) ParseFlags(args []string) (*BenchOptions, error) {
- var options BenchOptions
-
- // Parse flagset.
- fs := flag.NewFlagSet("", flag.ContinueOnError)
- fs.StringVar(&options.ProfileMode, "profile-mode", "rw", "")
- fs.StringVar(&options.WriteMode, "write-mode", "seq", "")
- fs.StringVar(&options.ReadMode, "read-mode", "seq", "")
- fs.IntVar(&options.Iterations, "count", 1000, "")
- fs.IntVar(&options.BatchSize, "batch-size", 0, "")
- fs.IntVar(&options.KeySize, "key-size", 8, "")
- fs.IntVar(&options.ValueSize, "value-size", 32, "")
- fs.StringVar(&options.CPUProfile, "cpuprofile", "", "")
- fs.StringVar(&options.MemProfile, "memprofile", "", "")
- fs.StringVar(&options.BlockProfile, "blockprofile", "", "")
- fs.Float64Var(&options.FillPercent, "fill-percent", bolt.DefaultFillPercent, "")
- fs.BoolVar(&options.NoSync, "no-sync", false, "")
- fs.BoolVar(&options.Work, "work", false, "")
- fs.StringVar(&options.Path, "path", "", "")
- fs.SetOutput(cmd.Stderr)
- if err := fs.Parse(args); err != nil {
- return nil, err
- }
-
- // Set batch size to iteration size if not set.
- // Require that batch size can be evenly divided by the iteration count.
- if options.BatchSize == 0 {
- options.BatchSize = options.Iterations
- } else if options.Iterations%options.BatchSize != 0 {
- return nil, ErrNonDivisibleBatchSize
- }
-
- // Generate temp path if one is not passed in.
- if options.Path == "" {
- f, err := ioutil.TempFile("", "bolt-bench-")
- if err != nil {
- return nil, fmt.Errorf("temp file: %s", err)
- }
- f.Close()
- os.Remove(f.Name())
- options.Path = f.Name()
- }
-
- return &options, nil
-}
-
-// Writes to the database.
-func (cmd *BenchCommand) runWrites(db *bolt.DB, options *BenchOptions, results *BenchResults) error {
- // Start profiling for writes.
- if options.ProfileMode == "rw" || options.ProfileMode == "w" {
- cmd.startProfiling(options)
- }
-
- t := time.Now()
-
- var err error
- switch options.WriteMode {
- case "seq":
- err = cmd.runWritesSequential(db, options, results)
- case "rnd":
- err = cmd.runWritesRandom(db, options, results)
- case "seq-nest":
- err = cmd.runWritesSequentialNested(db, options, results)
- case "rnd-nest":
- err = cmd.runWritesRandomNested(db, options, results)
- default:
- return fmt.Errorf("invalid write mode: %s", options.WriteMode)
- }
-
- // Save time to write.
- results.WriteDuration = time.Since(t)
-
- // Stop profiling for writes only.
- if options.ProfileMode == "w" {
- cmd.stopProfiling()
- }
-
- return err
-}
-
-func (cmd *BenchCommand) runWritesSequential(db *bolt.DB, options *BenchOptions, results *BenchResults) error {
- var i = uint32(0)
- return cmd.runWritesWithSource(db, options, results, func() uint32 { i++; return i })
-}
-
-func (cmd *BenchCommand) runWritesRandom(db *bolt.DB, options *BenchOptions, results *BenchResults) error {
- r := rand.New(rand.NewSource(time.Now().UnixNano()))
- return cmd.runWritesWithSource(db, options, results, func() uint32 { return r.Uint32() })
-}
-
-func (cmd *BenchCommand) runWritesSequentialNested(db *bolt.DB, options *BenchOptions, results *BenchResults) error {
- var i = uint32(0)
- return cmd.runWritesWithSource(db, options, results, func() uint32 { i++; return i })
-}
-
-func (cmd *BenchCommand) runWritesRandomNested(db *bolt.DB, options *BenchOptions, results *BenchResults) error {
- r := rand.New(rand.NewSource(time.Now().UnixNano()))
- return cmd.runWritesWithSource(db, options, results, func() uint32 { return r.Uint32() })
-}
-
-func (cmd *BenchCommand) runWritesWithSource(db *bolt.DB, options *BenchOptions, results *BenchResults, keySource func() uint32) error {
- results.WriteOps = options.Iterations
-
- for i := 0; i < options.Iterations; i += options.BatchSize {
- if err := db.Update(func(tx *bolt.Tx) error {
- b, _ := tx.CreateBucketIfNotExists(benchBucketName)
- b.FillPercent = options.FillPercent
-
- for j := 0; j < options.BatchSize; j++ {
- key := make([]byte, options.KeySize)
- value := make([]byte, options.ValueSize)
-
- // Write key as uint32.
- binary.BigEndian.PutUint32(key, keySource())
-
- // Insert key/value.
- if err := b.Put(key, value); err != nil {
- return err
- }
- }
-
- return nil
- }); err != nil {
- return err
- }
- }
- return nil
-}
-
-func (cmd *BenchCommand) runWritesNestedWithSource(db *bolt.DB, options *BenchOptions, results *BenchResults, keySource func() uint32) error {
- results.WriteOps = options.Iterations
-
- for i := 0; i < options.Iterations; i += options.BatchSize {
- if err := db.Update(func(tx *bolt.Tx) error {
- top, err := tx.CreateBucketIfNotExists(benchBucketName)
- if err != nil {
- return err
- }
- top.FillPercent = options.FillPercent
-
- // Create bucket key.
- name := make([]byte, options.KeySize)
- binary.BigEndian.PutUint32(name, keySource())
-
- // Create bucket.
- b, err := top.CreateBucketIfNotExists(name)
- if err != nil {
- return err
- }
- b.FillPercent = options.FillPercent
-
- for j := 0; j < options.BatchSize; j++ {
- var key = make([]byte, options.KeySize)
- var value = make([]byte, options.ValueSize)
-
- // Generate key as uint32.
- binary.BigEndian.PutUint32(key, keySource())
-
- // Insert value into subbucket.
- if err := b.Put(key, value); err != nil {
- return err
- }
- }
-
- return nil
- }); err != nil {
- return err
- }
- }
- return nil
-}
-
-// Reads from the database.
-func (cmd *BenchCommand) runReads(db *bolt.DB, options *BenchOptions, results *BenchResults) error {
- // Start profiling for reads.
- if options.ProfileMode == "r" {
- cmd.startProfiling(options)
- }
-
- t := time.Now()
-
- var err error
- switch options.ReadMode {
- case "seq":
- switch options.WriteMode {
- case "seq-nest", "rnd-nest":
- err = cmd.runReadsSequentialNested(db, options, results)
- default:
- err = cmd.runReadsSequential(db, options, results)
- }
- default:
- return fmt.Errorf("invalid read mode: %s", options.ReadMode)
- }
-
- // Save read time.
- results.ReadDuration = time.Since(t)
-
- // Stop profiling for reads.
- if options.ProfileMode == "rw" || options.ProfileMode == "r" {
- cmd.stopProfiling()
- }
-
- return err
-}
-
-func (cmd *BenchCommand) runReadsSequential(db *bolt.DB, options *BenchOptions, results *BenchResults) error {
- return db.View(func(tx *bolt.Tx) error {
- t := time.Now()
-
- for {
- var count int
-
- c := tx.Bucket(benchBucketName).Cursor()
- for k, v := c.First(); k != nil; k, v = c.Next() {
- if v == nil {
- return errors.New("invalid value")
- }
- count++
- }
-
- if options.WriteMode == "seq" && count != options.Iterations {
- return fmt.Errorf("read seq: iter mismatch: expected %d, got %d", options.Iterations, count)
- }
-
- results.ReadOps += count
-
- // Make sure we do this for at least a second.
- if time.Since(t) >= time.Second {
- break
- }
- }
-
- return nil
- })
-}
-
-func (cmd *BenchCommand) runReadsSequentialNested(db *bolt.DB, options *BenchOptions, results *BenchResults) error {
- return db.View(func(tx *bolt.Tx) error {
- t := time.Now()
-
- for {
- var count int
- var top = tx.Bucket(benchBucketName)
- if err := top.ForEach(func(name, _ []byte) error {
- c := top.Bucket(name).Cursor()
- for k, v := c.First(); k != nil; k, v = c.Next() {
- if v == nil {
- return ErrInvalidValue
- }
- count++
- }
- return nil
- }); err != nil {
- return err
- }
-
- if options.WriteMode == "seq-nest" && count != options.Iterations {
- return fmt.Errorf("read seq-nest: iter mismatch: expected %d, got %d", options.Iterations, count)
- }
-
- results.ReadOps += count
-
- // Make sure we do this for at least a second.
- if time.Since(t) >= time.Second {
- break
- }
- }
-
- return nil
- })
-}
-
-// File handlers for the various profiles.
-var cpuprofile, memprofile, blockprofile *os.File
-
-// Starts all profiles set on the options.
-func (cmd *BenchCommand) startProfiling(options *BenchOptions) {
- var err error
-
- // Start CPU profiling.
- if options.CPUProfile != "" {
- cpuprofile, err = os.Create(options.CPUProfile)
- if err != nil {
- fmt.Fprintf(cmd.Stderr, "bench: could not create cpu profile %q: %v\n", options.CPUProfile, err)
- os.Exit(1)
- }
- pprof.StartCPUProfile(cpuprofile)
- }
-
- // Start memory profiling.
- if options.MemProfile != "" {
- memprofile, err = os.Create(options.MemProfile)
- if err != nil {
- fmt.Fprintf(cmd.Stderr, "bench: could not create memory profile %q: %v\n", options.MemProfile, err)
- os.Exit(1)
- }
- runtime.MemProfileRate = 4096
- }
-
- // Start fatal profiling.
- if options.BlockProfile != "" {
- blockprofile, err = os.Create(options.BlockProfile)
- if err != nil {
- fmt.Fprintf(cmd.Stderr, "bench: could not create block profile %q: %v\n", options.BlockProfile, err)
- os.Exit(1)
- }
- runtime.SetBlockProfileRate(1)
- }
-}
-
-// Stops all profiles.
-func (cmd *BenchCommand) stopProfiling() {
- if cpuprofile != nil {
- pprof.StopCPUProfile()
- cpuprofile.Close()
- cpuprofile = nil
- }
-
- if memprofile != nil {
- pprof.Lookup("heap").WriteTo(memprofile, 0)
- memprofile.Close()
- memprofile = nil
- }
-
- if blockprofile != nil {
- pprof.Lookup("block").WriteTo(blockprofile, 0)
- blockprofile.Close()
- blockprofile = nil
- runtime.SetBlockProfileRate(0)
- }
-}
-
-// BenchOptions represents the set of options that can be passed to "bolt bench".
-type BenchOptions struct {
- ProfileMode string
- WriteMode string
- ReadMode string
- Iterations int
- BatchSize int
- KeySize int
- ValueSize int
- CPUProfile string
- MemProfile string
- BlockProfile string
- StatsInterval time.Duration
- FillPercent float64
- NoSync bool
- Work bool
- Path string
-}
-
-// BenchResults represents the performance results of the benchmark.
-type BenchResults struct {
- WriteOps int
- WriteDuration time.Duration
- ReadOps int
- ReadDuration time.Duration
-}
-
-// Returns the duration for a single write operation.
-func (r *BenchResults) WriteOpDuration() time.Duration {
- if r.WriteOps == 0 {
- return 0
- }
- return r.WriteDuration / time.Duration(r.WriteOps)
-}
-
-// Returns average number of write operations that can be performed per second.
-func (r *BenchResults) WriteOpsPerSecond() int {
- var op = r.WriteOpDuration()
- if op == 0 {
- return 0
- }
- return int(time.Second) / int(op)
-}
-
-// Returns the duration for a single read operation.
-func (r *BenchResults) ReadOpDuration() time.Duration {
- if r.ReadOps == 0 {
- return 0
- }
- return r.ReadDuration / time.Duration(r.ReadOps)
-}
-
-// Returns average number of read operations that can be performed per second.
-func (r *BenchResults) ReadOpsPerSecond() int {
- var op = r.ReadOpDuration()
- if op == 0 {
- return 0
- }
- return int(time.Second) / int(op)
-}
-
-type PageError struct {
- ID int
- Err error
-}
-
-func (e *PageError) Error() string {
- return fmt.Sprintf("page error: id=%d, err=%s", e.ID, e.Err)
-}
-
-// isPrintable returns true if the string is valid unicode and contains only printable runes.
-func isPrintable(s string) bool {
- if !utf8.ValidString(s) {
- return false
- }
- for _, ch := range s {
- if !unicode.IsPrint(ch) {
- return false
- }
- }
- return true
-}
-
-// ReadPage reads page info & full page data from a path.
-// This is not transactionally safe.
-func ReadPage(path string, pageID int) (*page, []byte, error) {
- // Find page size.
- pageSize, err := ReadPageSize(path)
- if err != nil {
- return nil, nil, fmt.Errorf("read page size: %s", err)
- }
-
- // Open database file.
- f, err := os.Open(path)
- if err != nil {
- return nil, nil, err
- }
- defer f.Close()
-
- // Read one block into buffer.
- buf := make([]byte, pageSize)
- if n, err := f.ReadAt(buf, int64(pageID*pageSize)); err != nil {
- return nil, nil, err
- } else if n != len(buf) {
- return nil, nil, io.ErrUnexpectedEOF
- }
-
- // Determine total number of blocks.
- p := (*page)(unsafe.Pointer(&buf[0]))
- overflowN := p.overflow
-
- // Re-read entire page (with overflow) into buffer.
- buf = make([]byte, (int(overflowN)+1)*pageSize)
- if n, err := f.ReadAt(buf, int64(pageID*pageSize)); err != nil {
- return nil, nil, err
- } else if n != len(buf) {
- return nil, nil, io.ErrUnexpectedEOF
- }
- p = (*page)(unsafe.Pointer(&buf[0]))
-
- return p, buf, nil
-}
-
-// ReadPageSize reads page size a path.
-// This is not transactionally safe.
-func ReadPageSize(path string) (int, error) {
- // Open database file.
- f, err := os.Open(path)
- if err != nil {
- return 0, err
- }
- defer f.Close()
-
- // Read 4KB chunk.
- buf := make([]byte, 4096)
- if _, err := io.ReadFull(f, buf); err != nil {
- return 0, err
- }
-
- // Read page size from metadata.
- m := (*meta)(unsafe.Pointer(&buf[PageHeaderSize]))
- return int(m.pageSize), nil
-}
-
-// atois parses a slice of strings into integers.
-func atois(strs []string) ([]int, error) {
- var a []int
- for _, str := range strs {
- i, err := strconv.Atoi(str)
- if err != nil {
- return nil, err
- }
- a = append(a, i)
- }
- return a, nil
-}
-
-// DO NOT EDIT. Copied from the "bolt" package.
-const maxAllocSize = 0xFFFFFFF
-
-// DO NOT EDIT. Copied from the "bolt" package.
-const (
- branchPageFlag = 0x01
- leafPageFlag = 0x02
- metaPageFlag = 0x04
- freelistPageFlag = 0x10
-)
-
-// DO NOT EDIT. Copied from the "bolt" package.
-const bucketLeafFlag = 0x01
-
-// DO NOT EDIT. Copied from the "bolt" package.
-type pgid uint64
-
-// DO NOT EDIT. Copied from the "bolt" package.
-type txid uint64
-
-// DO NOT EDIT. Copied from the "bolt" package.
-type meta struct {
- magic uint32
- version uint32
- pageSize uint32
- flags uint32
- root bucket
- freelist pgid
- pgid pgid
- txid txid
- checksum uint64
-}
-
-// DO NOT EDIT. Copied from the "bolt" package.
-type bucket struct {
- root pgid
- sequence uint64
-}
-
-// DO NOT EDIT. Copied from the "bolt" package.
-type page struct {
- id pgid
- flags uint16
- count uint16
- overflow uint32
- ptr uintptr
-}
-
-// DO NOT EDIT. Copied from the "bolt" package.
-func (p *page) Type() string {
- if (p.flags & branchPageFlag) != 0 {
- return "branch"
- } else if (p.flags & leafPageFlag) != 0 {
- return "leaf"
- } else if (p.flags & metaPageFlag) != 0 {
- return "meta"
- } else if (p.flags & freelistPageFlag) != 0 {
- return "freelist"
- }
- return fmt.Sprintf("unknown<%02x>", p.flags)
-}
-
-// DO NOT EDIT. Copied from the "bolt" package.
-func (p *page) leafPageElement(index uint16) *leafPageElement {
- n := &((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[index]
- return n
-}
-
-// DO NOT EDIT. Copied from the "bolt" package.
-func (p *page) branchPageElement(index uint16) *branchPageElement {
- return &((*[0x7FFFFFF]branchPageElement)(unsafe.Pointer(&p.ptr)))[index]
-}
-
-// DO NOT EDIT. Copied from the "bolt" package.
-type branchPageElement struct {
- pos uint32
- ksize uint32
- pgid pgid
-}
-
-// DO NOT EDIT. Copied from the "bolt" package.
-func (n *branchPageElement) key() []byte {
- buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
- return buf[n.pos : n.pos+n.ksize]
-}
-
-// DO NOT EDIT. Copied from the "bolt" package.
-type leafPageElement struct {
- flags uint32
- pos uint32
- ksize uint32
- vsize uint32
-}
-
-// DO NOT EDIT. Copied from the "bolt" package.
-func (n *leafPageElement) key() []byte {
- buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
- return buf[n.pos : n.pos+n.ksize]
-}
-
-// DO NOT EDIT. Copied from the "bolt" package.
-func (n *leafPageElement) value() []byte {
- buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
- return buf[n.pos+n.ksize : n.pos+n.ksize+n.vsize]
-}
-
-// CompactCommand represents the "compact" command execution.
-type CompactCommand struct {
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-
- SrcPath string
- DstPath string
- TxMaxSize int64
-}
-
-// newCompactCommand returns a CompactCommand.
-func newCompactCommand(m *Main) *CompactCommand {
- return &CompactCommand{
- Stdin: m.Stdin,
- Stdout: m.Stdout,
- Stderr: m.Stderr,
- }
-}
-
-// Run executes the command.
-func (cmd *CompactCommand) Run(args ...string) (err error) {
- // Parse flags.
- fs := flag.NewFlagSet("", flag.ContinueOnError)
- fs.SetOutput(ioutil.Discard)
- fs.StringVar(&cmd.DstPath, "o", "", "")
- fs.Int64Var(&cmd.TxMaxSize, "tx-max-size", 65536, "")
- if err := fs.Parse(args); err == flag.ErrHelp {
- fmt.Fprintln(cmd.Stderr, cmd.Usage())
- return ErrUsage
- } else if err != nil {
- return err
- } else if cmd.DstPath == "" {
- return fmt.Errorf("output file required")
- }
-
- // Require database paths.
- cmd.SrcPath = fs.Arg(0)
- if cmd.SrcPath == "" {
- return ErrPathRequired
- }
-
- // Ensure source file exists.
- fi, err := os.Stat(cmd.SrcPath)
- if os.IsNotExist(err) {
- return ErrFileNotFound
- } else if err != nil {
- return err
- }
- initialSize := fi.Size()
-
- // Open source database.
- src, err := bolt.Open(cmd.SrcPath, 0444, nil)
- if err != nil {
- return err
- }
- defer src.Close()
-
- // Open destination database.
- dst, err := bolt.Open(cmd.DstPath, fi.Mode(), nil)
- if err != nil {
- return err
- }
- defer dst.Close()
-
- // Run compaction.
- if err := cmd.compact(dst, src); err != nil {
- return err
- }
-
- // Report stats on new size.
- fi, err = os.Stat(cmd.DstPath)
- if err != nil {
- return err
- } else if fi.Size() == 0 {
- return fmt.Errorf("zero db size")
- }
- fmt.Fprintf(cmd.Stdout, "%d -> %d bytes (gain=%.2fx)\n", initialSize, fi.Size(), float64(initialSize)/float64(fi.Size()))
-
- return nil
-}
-
-func (cmd *CompactCommand) compact(dst, src *bolt.DB) error {
- // commit regularly, or we'll run out of memory for large datasets if using one transaction.
- var size int64
- tx, err := dst.Begin(true)
- if err != nil {
- return err
- }
- defer tx.Rollback()
-
- if err := cmd.walk(src, func(keys [][]byte, k, v []byte, seq uint64) error {
- // On each key/value, check if we have exceeded tx size.
- sz := int64(len(k) + len(v))
- if size+sz > cmd.TxMaxSize && cmd.TxMaxSize != 0 {
- // Commit previous transaction.
- if err := tx.Commit(); err != nil {
- return err
- }
-
- // Start new transaction.
- tx, err = dst.Begin(true)
- if err != nil {
- return err
- }
- size = 0
- }
- size += sz
-
- // Create bucket on the root transaction if this is the first level.
- nk := len(keys)
- if nk == 0 {
- bkt, err := tx.CreateBucket(k)
- if err != nil {
- return err
- }
- if err := bkt.SetSequence(seq); err != nil {
- return err
- }
- return nil
- }
-
- // Create buckets on subsequent levels, if necessary.
- b := tx.Bucket(keys[0])
- if nk > 1 {
- for _, k := range keys[1:] {
- b = b.Bucket(k)
- }
- }
-
- // If there is no value then this is a bucket call.
- if v == nil {
- bkt, err := b.CreateBucket(k)
- if err != nil {
- return err
- }
- if err := bkt.SetSequence(seq); err != nil {
- return err
- }
- return nil
- }
-
- // Otherwise treat it as a key/value pair.
- return b.Put(k, v)
- }); err != nil {
- return err
- }
-
- return tx.Commit()
-}
-
-// walkFunc is the type of the function called for keys (buckets and "normal"
-// values) discovered by Walk. keys is the list of keys to descend to the bucket
-// owning the discovered key/value pair k/v.
-type walkFunc func(keys [][]byte, k, v []byte, seq uint64) error
-
-// walk walks recursively the bolt database db, calling walkFn for each key it finds.
-func (cmd *CompactCommand) walk(db *bolt.DB, walkFn walkFunc) error {
- return db.View(func(tx *bolt.Tx) error {
- return tx.ForEach(func(name []byte, b *bolt.Bucket) error {
- return cmd.walkBucket(b, nil, name, nil, b.Sequence(), walkFn)
- })
- })
-}
-
-func (cmd *CompactCommand) walkBucket(b *bolt.Bucket, keypath [][]byte, k, v []byte, seq uint64, fn walkFunc) error {
- // Execute callback.
- if err := fn(keypath, k, v, seq); err != nil {
- return err
- }
-
- // If this is not a bucket then stop.
- if v != nil {
- return nil
- }
-
- // Iterate over each child key/value.
- keypath = append(keypath, k)
- return b.ForEach(func(k, v []byte) error {
- if v == nil {
- bkt := b.Bucket(k)
- return cmd.walkBucket(bkt, keypath, k, nil, bkt.Sequence(), fn)
- }
- return cmd.walkBucket(b, keypath, k, v, b.Sequence(), fn)
- })
-}
-
-// Usage returns the help message.
-func (cmd *CompactCommand) Usage() string {
- return strings.TrimLeft(`
-usage: bolt compact [options] -o DST SRC
-
-Compact opens a database at SRC path and walks it recursively, copying keys
-as they are found from all buckets, to a newly created database at DST path.
-
-The original database is left untouched.
-
-Additional options include:
-
- -tx-max-size NUM
- Specifies the maximum size of individual transactions.
- Defaults to 64KB.
-`, "\n")
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main_test.go
deleted file mode 100644
index 0a11ff3..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main_test.go
+++ /dev/null
@@ -1,356 +0,0 @@
-package main_test
-
-import (
- "bytes"
- crypto "crypto/rand"
- "encoding/binary"
- "fmt"
- "io"
- "io/ioutil"
- "math/rand"
- "os"
- "strconv"
- "testing"
-
- "github.com/boltdb/bolt"
- "github.com/boltdb/bolt/cmd/bolt"
-)
-
-// Ensure the "info" command can print information about a database.
-func TestInfoCommand_Run(t *testing.T) {
- db := MustOpen(0666, nil)
- db.DB.Close()
- defer db.Close()
-
- // Run the info command.
- m := NewMain()
- if err := m.Run("info", db.Path); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure the "stats" command executes correctly with an empty database.
-func TestStatsCommand_Run_EmptyDatabase(t *testing.T) {
- // Ignore
- if os.Getpagesize() != 4096 {
- t.Skip("system does not use 4KB page size")
- }
-
- db := MustOpen(0666, nil)
- defer db.Close()
- db.DB.Close()
-
- // Generate expected result.
- exp := "Aggregate statistics for 0 buckets\n\n" +
- "Page count statistics\n" +
- "\tNumber of logical branch pages: 0\n" +
- "\tNumber of physical branch overflow pages: 0\n" +
- "\tNumber of logical leaf pages: 0\n" +
- "\tNumber of physical leaf overflow pages: 0\n" +
- "Tree statistics\n" +
- "\tNumber of keys/value pairs: 0\n" +
- "\tNumber of levels in B+tree: 0\n" +
- "Page size utilization\n" +
- "\tBytes allocated for physical branch pages: 0\n" +
- "\tBytes actually used for branch data: 0 (0%)\n" +
- "\tBytes allocated for physical leaf pages: 0\n" +
- "\tBytes actually used for leaf data: 0 (0%)\n" +
- "Bucket statistics\n" +
- "\tTotal number of buckets: 0\n" +
- "\tTotal number on inlined buckets: 0 (0%)\n" +
- "\tBytes used for inlined buckets: 0 (0%)\n"
-
- // Run the command.
- m := NewMain()
- if err := m.Run("stats", db.Path); err != nil {
- t.Fatal(err)
- } else if m.Stdout.String() != exp {
- t.Fatalf("unexpected stdout:\n\n%s", m.Stdout.String())
- }
-}
-
-// Ensure the "stats" command can execute correctly.
-func TestStatsCommand_Run(t *testing.T) {
- // Ignore
- if os.Getpagesize() != 4096 {
- t.Skip("system does not use 4KB page size")
- }
-
- db := MustOpen(0666, nil)
- defer db.Close()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- // Create "foo" bucket.
- b, err := tx.CreateBucket([]byte("foo"))
- if err != nil {
- return err
- }
- for i := 0; i < 10; i++ {
- if err := b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil {
- return err
- }
- }
-
- // Create "bar" bucket.
- b, err = tx.CreateBucket([]byte("bar"))
- if err != nil {
- return err
- }
- for i := 0; i < 100; i++ {
- if err := b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil {
- return err
- }
- }
-
- // Create "baz" bucket.
- b, err = tx.CreateBucket([]byte("baz"))
- if err != nil {
- return err
- }
- if err := b.Put([]byte("key"), []byte("value")); err != nil {
- return err
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- db.DB.Close()
-
- // Generate expected result.
- exp := "Aggregate statistics for 3 buckets\n\n" +
- "Page count statistics\n" +
- "\tNumber of logical branch pages: 0\n" +
- "\tNumber of physical branch overflow pages: 0\n" +
- "\tNumber of logical leaf pages: 1\n" +
- "\tNumber of physical leaf overflow pages: 0\n" +
- "Tree statistics\n" +
- "\tNumber of keys/value pairs: 111\n" +
- "\tNumber of levels in B+tree: 1\n" +
- "Page size utilization\n" +
- "\tBytes allocated for physical branch pages: 0\n" +
- "\tBytes actually used for branch data: 0 (0%)\n" +
- "\tBytes allocated for physical leaf pages: 4096\n" +
- "\tBytes actually used for leaf data: 1996 (48%)\n" +
- "Bucket statistics\n" +
- "\tTotal number of buckets: 3\n" +
- "\tTotal number on inlined buckets: 2 (66%)\n" +
- "\tBytes used for inlined buckets: 236 (11%)\n"
-
- // Run the command.
- m := NewMain()
- if err := m.Run("stats", db.Path); err != nil {
- t.Fatal(err)
- } else if m.Stdout.String() != exp {
- t.Fatalf("unexpected stdout:\n\n%s", m.Stdout.String())
- }
-}
-
-// Main represents a test wrapper for main.Main that records output.
-type Main struct {
- *main.Main
- Stdin bytes.Buffer
- Stdout bytes.Buffer
- Stderr bytes.Buffer
-}
-
-// NewMain returns a new instance of Main.
-func NewMain() *Main {
- m := &Main{Main: main.NewMain()}
- m.Main.Stdin = &m.Stdin
- m.Main.Stdout = &m.Stdout
- m.Main.Stderr = &m.Stderr
- return m
-}
-
-// MustOpen creates a Bolt database in a temporary location.
-func MustOpen(mode os.FileMode, options *bolt.Options) *DB {
- // Create temporary path.
- f, _ := ioutil.TempFile("", "bolt-")
- f.Close()
- os.Remove(f.Name())
-
- db, err := bolt.Open(f.Name(), mode, options)
- if err != nil {
- panic(err.Error())
- }
- return &DB{DB: db, Path: f.Name()}
-}
-
-// DB is a test wrapper for bolt.DB.
-type DB struct {
- *bolt.DB
- Path string
-}
-
-// Close closes and removes the database.
-func (db *DB) Close() error {
- defer os.Remove(db.Path)
- return db.DB.Close()
-}
-
-func TestCompactCommand_Run(t *testing.T) {
- var s int64
- if err := binary.Read(crypto.Reader, binary.BigEndian, &s); err != nil {
- t.Fatal(err)
- }
- rand.Seed(s)
-
- dstdb := MustOpen(0666, nil)
- dstdb.Close()
-
- // fill the db
- db := MustOpen(0666, nil)
- if err := db.Update(func(tx *bolt.Tx) error {
- n := 2 + rand.Intn(5)
- for i := 0; i < n; i++ {
- k := []byte(fmt.Sprintf("b%d", i))
- b, err := tx.CreateBucketIfNotExists(k)
- if err != nil {
- return err
- }
- if err := b.SetSequence(uint64(i)); err != nil {
- return err
- }
- if err := fillBucket(b, append(k, '.')); err != nil {
- return err
- }
- }
- return nil
- }); err != nil {
- db.Close()
- t.Fatal(err)
- }
-
- // make the db grow by adding large values, and delete them.
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucketIfNotExists([]byte("large_vals"))
- if err != nil {
- return err
- }
- n := 5 + rand.Intn(5)
- for i := 0; i < n; i++ {
- v := make([]byte, 1000*1000*(1+rand.Intn(5)))
- _, err := crypto.Read(v)
- if err != nil {
- return err
- }
- if err := b.Put([]byte(fmt.Sprintf("l%d", i)), v); err != nil {
- return err
- }
- }
- return nil
- }); err != nil {
- db.Close()
- t.Fatal(err)
- }
- if err := db.Update(func(tx *bolt.Tx) error {
- c := tx.Bucket([]byte("large_vals")).Cursor()
- for k, _ := c.First(); k != nil; k, _ = c.Next() {
- if err := c.Delete(); err != nil {
- return err
- }
- }
- return tx.DeleteBucket([]byte("large_vals"))
- }); err != nil {
- db.Close()
- t.Fatal(err)
- }
- db.DB.Close()
- defer db.Close()
- defer dstdb.Close()
-
- dbChk, err := chkdb(db.Path)
- if err != nil {
- t.Fatal(err)
- }
-
- m := NewMain()
- if err := m.Run("compact", "-o", dstdb.Path, db.Path); err != nil {
- t.Fatal(err)
- }
-
- dbChkAfterCompact, err := chkdb(db.Path)
- if err != nil {
- t.Fatal(err)
- }
-
- dstdbChk, err := chkdb(dstdb.Path)
- if err != nil {
- t.Fatal(err)
- }
-
- if !bytes.Equal(dbChk, dbChkAfterCompact) {
- t.Error("the original db has been touched")
- }
- if !bytes.Equal(dbChk, dstdbChk) {
- t.Error("the compacted db data isn't the same than the original db")
- }
-}
-
-func fillBucket(b *bolt.Bucket, prefix []byte) error {
- n := 10 + rand.Intn(50)
- for i := 0; i < n; i++ {
- v := make([]byte, 10*(1+rand.Intn(4)))
- _, err := crypto.Read(v)
- if err != nil {
- return err
- }
- k := append(prefix, []byte(fmt.Sprintf("k%d", i))...)
- if err := b.Put(k, v); err != nil {
- return err
- }
- }
- // limit depth of subbuckets
- s := 2 + rand.Intn(4)
- if len(prefix) > (2*s + 1) {
- return nil
- }
- n = 1 + rand.Intn(3)
- for i := 0; i < n; i++ {
- k := append(prefix, []byte(fmt.Sprintf("b%d", i))...)
- sb, err := b.CreateBucket(k)
- if err != nil {
- return err
- }
- if err := fillBucket(sb, append(k, '.')); err != nil {
- return err
- }
- }
- return nil
-}
-
-func chkdb(path string) ([]byte, error) {
- db, err := bolt.Open(path, 0666, nil)
- if err != nil {
- return nil, err
- }
- defer db.Close()
- var buf bytes.Buffer
- err = db.View(func(tx *bolt.Tx) error {
- return tx.ForEach(func(name []byte, b *bolt.Bucket) error {
- return walkBucket(b, name, nil, &buf)
- })
- })
- if err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
-}
-
-func walkBucket(parent *bolt.Bucket, k []byte, v []byte, w io.Writer) error {
- if _, err := fmt.Fprintf(w, "%d:%x=%x\n", parent.Sequence(), k, v); err != nil {
- return err
- }
-
- // not a bucket, exit.
- if v != nil {
- return nil
- }
- return parent.ForEach(func(k, v []byte) error {
- if v == nil {
- return walkBucket(parent.Bucket(k), k, nil, w)
- }
- return walkBucket(parent, k, v, w)
- })
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor.go
deleted file mode 100644
index 1be9f35..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor.go
+++ /dev/null
@@ -1,400 +0,0 @@
-package bolt
-
-import (
- "bytes"
- "fmt"
- "sort"
-)
-
-// Cursor represents an iterator that can traverse over all key/value pairs in a bucket in sorted order.
-// Cursors see nested buckets with value == nil.
-// Cursors can be obtained from a transaction and are valid as long as the transaction is open.
-//
-// Keys and values returned from the cursor are only valid for the life of the transaction.
-//
-// Changing data while traversing with a cursor may cause it to be invalidated
-// and return unexpected keys and/or values. You must reposition your cursor
-// after mutating data.
-type Cursor struct {
- bucket *Bucket
- stack []elemRef
-}
-
-// Bucket returns the bucket that this cursor was created from.
-func (c *Cursor) Bucket() *Bucket {
- return c.bucket
-}
-
-// First moves the cursor to the first item in the bucket and returns its key and value.
-// If the bucket is empty then a nil key and value are returned.
-// The returned key and value are only valid for the life of the transaction.
-func (c *Cursor) First() (key []byte, value []byte) {
- _assert(c.bucket.tx.db != nil, "tx closed")
- c.stack = c.stack[:0]
- p, n := c.bucket.pageNode(c.bucket.root)
- c.stack = append(c.stack, elemRef{page: p, node: n, index: 0})
- c.first()
-
- // If we land on an empty page then move to the next value.
- // https://github.com/boltdb/bolt/issues/450
- if c.stack[len(c.stack)-1].count() == 0 {
- c.next()
- }
-
- k, v, flags := c.keyValue()
- if (flags & uint32(bucketLeafFlag)) != 0 {
- return k, nil
- }
- return k, v
-
-}
-
-// Last moves the cursor to the last item in the bucket and returns its key and value.
-// If the bucket is empty then a nil key and value are returned.
-// The returned key and value are only valid for the life of the transaction.
-func (c *Cursor) Last() (key []byte, value []byte) {
- _assert(c.bucket.tx.db != nil, "tx closed")
- c.stack = c.stack[:0]
- p, n := c.bucket.pageNode(c.bucket.root)
- ref := elemRef{page: p, node: n}
- ref.index = ref.count() - 1
- c.stack = append(c.stack, ref)
- c.last()
- k, v, flags := c.keyValue()
- if (flags & uint32(bucketLeafFlag)) != 0 {
- return k, nil
- }
- return k, v
-}
-
-// Next moves the cursor to the next item in the bucket and returns its key and value.
-// If the cursor is at the end of the bucket then a nil key and value are returned.
-// The returned key and value are only valid for the life of the transaction.
-func (c *Cursor) Next() (key []byte, value []byte) {
- _assert(c.bucket.tx.db != nil, "tx closed")
- k, v, flags := c.next()
- if (flags & uint32(bucketLeafFlag)) != 0 {
- return k, nil
- }
- return k, v
-}
-
-// Prev moves the cursor to the previous item in the bucket and returns its key and value.
-// If the cursor is at the beginning of the bucket then a nil key and value are returned.
-// The returned key and value are only valid for the life of the transaction.
-func (c *Cursor) Prev() (key []byte, value []byte) {
- _assert(c.bucket.tx.db != nil, "tx closed")
-
- // Attempt to move back one element until we're successful.
- // Move up the stack as we hit the beginning of each page in our stack.
- for i := len(c.stack) - 1; i >= 0; i-- {
- elem := &c.stack[i]
- if elem.index > 0 {
- elem.index--
- break
- }
- c.stack = c.stack[:i]
- }
-
- // If we've hit the end then return nil.
- if len(c.stack) == 0 {
- return nil, nil
- }
-
- // Move down the stack to find the last element of the last leaf under this branch.
- c.last()
- k, v, flags := c.keyValue()
- if (flags & uint32(bucketLeafFlag)) != 0 {
- return k, nil
- }
- return k, v
-}
-
-// Seek moves the cursor to a given key and returns it.
-// If the key does not exist then the next key is used. If no keys
-// follow, a nil key is returned.
-// The returned key and value are only valid for the life of the transaction.
-func (c *Cursor) Seek(seek []byte) (key []byte, value []byte) {
- k, v, flags := c.seek(seek)
-
- // If we ended up after the last element of a page then move to the next one.
- if ref := &c.stack[len(c.stack)-1]; ref.index >= ref.count() {
- k, v, flags = c.next()
- }
-
- if k == nil {
- return nil, nil
- } else if (flags & uint32(bucketLeafFlag)) != 0 {
- return k, nil
- }
- return k, v
-}
-
-// Delete removes the current key/value under the cursor from the bucket.
-// Delete fails if current key/value is a bucket or if the transaction is not writable.
-func (c *Cursor) Delete() error {
- if c.bucket.tx.db == nil {
- return ErrTxClosed
- } else if !c.bucket.Writable() {
- return ErrTxNotWritable
- }
-
- key, _, flags := c.keyValue()
- // Return an error if current value is a bucket.
- if (flags & bucketLeafFlag) != 0 {
- return ErrIncompatibleValue
- }
- c.node().del(key)
-
- return nil
-}
-
-// seek moves the cursor to a given key and returns it.
-// If the key does not exist then the next key is used.
-func (c *Cursor) seek(seek []byte) (key []byte, value []byte, flags uint32) {
- _assert(c.bucket.tx.db != nil, "tx closed")
-
- // Start from root page/node and traverse to correct page.
- c.stack = c.stack[:0]
- c.search(seek, c.bucket.root)
- ref := &c.stack[len(c.stack)-1]
-
- // If the cursor is pointing to the end of page/node then return nil.
- if ref.index >= ref.count() {
- return nil, nil, 0
- }
-
- // If this is a bucket then return a nil value.
- return c.keyValue()
-}
-
-// first moves the cursor to the first leaf element under the last page in the stack.
-func (c *Cursor) first() {
- for {
- // Exit when we hit a leaf page.
- var ref = &c.stack[len(c.stack)-1]
- if ref.isLeaf() {
- break
- }
-
- // Keep adding pages pointing to the first element to the stack.
- var pgid pgid
- if ref.node != nil {
- pgid = ref.node.inodes[ref.index].pgid
- } else {
- pgid = ref.page.branchPageElement(uint16(ref.index)).pgid
- }
- p, n := c.bucket.pageNode(pgid)
- c.stack = append(c.stack, elemRef{page: p, node: n, index: 0})
- }
-}
-
-// last moves the cursor to the last leaf element under the last page in the stack.
-func (c *Cursor) last() {
- for {
- // Exit when we hit a leaf page.
- ref := &c.stack[len(c.stack)-1]
- if ref.isLeaf() {
- break
- }
-
- // Keep adding pages pointing to the last element in the stack.
- var pgid pgid
- if ref.node != nil {
- pgid = ref.node.inodes[ref.index].pgid
- } else {
- pgid = ref.page.branchPageElement(uint16(ref.index)).pgid
- }
- p, n := c.bucket.pageNode(pgid)
-
- var nextRef = elemRef{page: p, node: n}
- nextRef.index = nextRef.count() - 1
- c.stack = append(c.stack, nextRef)
- }
-}
-
-// next moves to the next leaf element and returns the key and value.
-// If the cursor is at the last leaf element then it stays there and returns nil.
-func (c *Cursor) next() (key []byte, value []byte, flags uint32) {
- for {
- // Attempt to move over one element until we're successful.
- // Move up the stack as we hit the end of each page in our stack.
- var i int
- for i = len(c.stack) - 1; i >= 0; i-- {
- elem := &c.stack[i]
- if elem.index < elem.count()-1 {
- elem.index++
- break
- }
- }
-
- // If we've hit the root page then stop and return. This will leave the
- // cursor on the last element of the last page.
- if i == -1 {
- return nil, nil, 0
- }
-
- // Otherwise start from where we left off in the stack and find the
- // first element of the first leaf page.
- c.stack = c.stack[:i+1]
- c.first()
-
- // If this is an empty page then restart and move back up the stack.
- // https://github.com/boltdb/bolt/issues/450
- if c.stack[len(c.stack)-1].count() == 0 {
- continue
- }
-
- return c.keyValue()
- }
-}
-
-// search recursively performs a binary search against a given page/node until it finds a given key.
-func (c *Cursor) search(key []byte, pgid pgid) {
- p, n := c.bucket.pageNode(pgid)
- if p != nil && (p.flags&(branchPageFlag|leafPageFlag)) == 0 {
- panic(fmt.Sprintf("invalid page type: %d: %x", p.id, p.flags))
- }
- e := elemRef{page: p, node: n}
- c.stack = append(c.stack, e)
-
- // If we're on a leaf page/node then find the specific node.
- if e.isLeaf() {
- c.nsearch(key)
- return
- }
-
- if n != nil {
- c.searchNode(key, n)
- return
- }
- c.searchPage(key, p)
-}
-
-func (c *Cursor) searchNode(key []byte, n *node) {
- var exact bool
- index := sort.Search(len(n.inodes), func(i int) bool {
- // TODO(benbjohnson): Optimize this range search. It's a bit hacky right now.
- // sort.Search() finds the lowest index where f() != -1 but we need the highest index.
- ret := bytes.Compare(n.inodes[i].key, key)
- if ret == 0 {
- exact = true
- }
- return ret != -1
- })
- if !exact && index > 0 {
- index--
- }
- c.stack[len(c.stack)-1].index = index
-
- // Recursively search to the next page.
- c.search(key, n.inodes[index].pgid)
-}
-
-func (c *Cursor) searchPage(key []byte, p *page) {
- // Binary search for the correct range.
- inodes := p.branchPageElements()
-
- var exact bool
- index := sort.Search(int(p.count), func(i int) bool {
- // TODO(benbjohnson): Optimize this range search. It's a bit hacky right now.
- // sort.Search() finds the lowest index where f() != -1 but we need the highest index.
- ret := bytes.Compare(inodes[i].key(), key)
- if ret == 0 {
- exact = true
- }
- return ret != -1
- })
- if !exact && index > 0 {
- index--
- }
- c.stack[len(c.stack)-1].index = index
-
- // Recursively search to the next page.
- c.search(key, inodes[index].pgid)
-}
-
-// nsearch searches the leaf node on the top of the stack for a key.
-func (c *Cursor) nsearch(key []byte) {
- e := &c.stack[len(c.stack)-1]
- p, n := e.page, e.node
-
- // If we have a node then search its inodes.
- if n != nil {
- index := sort.Search(len(n.inodes), func(i int) bool {
- return bytes.Compare(n.inodes[i].key, key) != -1
- })
- e.index = index
- return
- }
-
- // If we have a page then search its leaf elements.
- inodes := p.leafPageElements()
- index := sort.Search(int(p.count), func(i int) bool {
- return bytes.Compare(inodes[i].key(), key) != -1
- })
- e.index = index
-}
-
-// keyValue returns the key and value of the current leaf element.
-func (c *Cursor) keyValue() ([]byte, []byte, uint32) {
- ref := &c.stack[len(c.stack)-1]
- if ref.count() == 0 || ref.index >= ref.count() {
- return nil, nil, 0
- }
-
- // Retrieve value from node.
- if ref.node != nil {
- inode := &ref.node.inodes[ref.index]
- return inode.key, inode.value, inode.flags
- }
-
- // Or retrieve value from page.
- elem := ref.page.leafPageElement(uint16(ref.index))
- return elem.key(), elem.value(), elem.flags
-}
-
-// node returns the node that the cursor is currently positioned on.
-func (c *Cursor) node() *node {
- _assert(len(c.stack) > 0, "accessing a node with a zero-length cursor stack")
-
- // If the top of the stack is a leaf node then just return it.
- if ref := &c.stack[len(c.stack)-1]; ref.node != nil && ref.isLeaf() {
- return ref.node
- }
-
- // Start from root and traverse down the hierarchy.
- var n = c.stack[0].node
- if n == nil {
- n = c.bucket.node(c.stack[0].page.id, nil)
- }
- for _, ref := range c.stack[:len(c.stack)-1] {
- _assert(!n.isLeaf, "expected branch node")
- n = n.childAt(int(ref.index))
- }
- _assert(n.isLeaf, "expected leaf node")
- return n
-}
-
-// elemRef represents a reference to an element on a given page/node.
-type elemRef struct {
- page *page
- node *node
- index int
-}
-
-// isLeaf returns whether the ref is pointing at a leaf page/node.
-func (r *elemRef) isLeaf() bool {
- if r.node != nil {
- return r.node.isLeaf
- }
- return (r.page.flags & leafPageFlag) != 0
-}
-
-// count returns the number of inodes or page elements.
-func (r *elemRef) count() int {
- if r.node != nil {
- return len(r.node.inodes)
- }
- return int(r.page.count)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor_test.go
deleted file mode 100644
index 562d60f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor_test.go
+++ /dev/null
@@ -1,817 +0,0 @@
-package bolt_test
-
-import (
- "bytes"
- "encoding/binary"
- "fmt"
- "log"
- "os"
- "reflect"
- "sort"
- "testing"
- "testing/quick"
-
- "github.com/boltdb/bolt"
-)
-
-// Ensure that a cursor can return a reference to the bucket that created it.
-func TestCursor_Bucket(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if cb := b.Cursor().Bucket(); !reflect.DeepEqual(cb, b) {
- t.Fatal("cursor bucket mismatch")
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a Tx cursor can seek to the appropriate keys.
-func TestCursor_Seek(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("0001")); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("bar"), []byte("0002")); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("baz"), []byte("0003")); err != nil {
- t.Fatal(err)
- }
-
- if _, err := b.CreateBucket([]byte("bkt")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.View(func(tx *bolt.Tx) error {
- c := tx.Bucket([]byte("widgets")).Cursor()
-
- // Exact match should go to the key.
- if k, v := c.Seek([]byte("bar")); !bytes.Equal(k, []byte("bar")) {
- t.Fatalf("unexpected key: %v", k)
- } else if !bytes.Equal(v, []byte("0002")) {
- t.Fatalf("unexpected value: %v", v)
- }
-
- // Inexact match should go to the next key.
- if k, v := c.Seek([]byte("bas")); !bytes.Equal(k, []byte("baz")) {
- t.Fatalf("unexpected key: %v", k)
- } else if !bytes.Equal(v, []byte("0003")) {
- t.Fatalf("unexpected value: %v", v)
- }
-
- // Low key should go to the first key.
- if k, v := c.Seek([]byte("")); !bytes.Equal(k, []byte("bar")) {
- t.Fatalf("unexpected key: %v", k)
- } else if !bytes.Equal(v, []byte("0002")) {
- t.Fatalf("unexpected value: %v", v)
- }
-
- // High key should return no key.
- if k, v := c.Seek([]byte("zzz")); k != nil {
- t.Fatalf("expected nil key: %v", k)
- } else if v != nil {
- t.Fatalf("expected nil value: %v", v)
- }
-
- // Buckets should return their key but no value.
- if k, v := c.Seek([]byte("bkt")); !bytes.Equal(k, []byte("bkt")) {
- t.Fatalf("unexpected key: %v", k)
- } else if v != nil {
- t.Fatalf("expected nil value: %v", v)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestCursor_Delete(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- const count = 1000
-
- // Insert every other key between 0 and $count.
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- for i := 0; i < count; i += 1 {
- k := make([]byte, 8)
- binary.BigEndian.PutUint64(k, uint64(i))
- if err := b.Put(k, make([]byte, 100)); err != nil {
- t.Fatal(err)
- }
- }
- if _, err := b.CreateBucket([]byte("sub")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.Update(func(tx *bolt.Tx) error {
- c := tx.Bucket([]byte("widgets")).Cursor()
- bound := make([]byte, 8)
- binary.BigEndian.PutUint64(bound, uint64(count/2))
- for key, _ := c.First(); bytes.Compare(key, bound) < 0; key, _ = c.Next() {
- if err := c.Delete(); err != nil {
- t.Fatal(err)
- }
- }
-
- c.Seek([]byte("sub"))
- if err := c.Delete(); err != bolt.ErrIncompatibleValue {
- t.Fatalf("unexpected error: %s", err)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.View(func(tx *bolt.Tx) error {
- stats := tx.Bucket([]byte("widgets")).Stats()
- if stats.KeyN != count/2+1 {
- t.Fatalf("unexpected KeyN: %d", stats.KeyN)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a Tx cursor can seek to the appropriate keys when there are a
-// large number of keys. This test also checks that seek will always move
-// forward to the next key.
-//
-// Related: https://github.com/boltdb/bolt/pull/187
-func TestCursor_Seek_Large(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- var count = 10000
-
- // Insert every other key between 0 and $count.
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
-
- for i := 0; i < count; i += 100 {
- for j := i; j < i+100; j += 2 {
- k := make([]byte, 8)
- binary.BigEndian.PutUint64(k, uint64(j))
- if err := b.Put(k, make([]byte, 100)); err != nil {
- t.Fatal(err)
- }
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.View(func(tx *bolt.Tx) error {
- c := tx.Bucket([]byte("widgets")).Cursor()
- for i := 0; i < count; i++ {
- seek := make([]byte, 8)
- binary.BigEndian.PutUint64(seek, uint64(i))
-
- k, _ := c.Seek(seek)
-
- // The last seek is beyond the end of the the range so
- // it should return nil.
- if i == count-1 {
- if k != nil {
- t.Fatal("expected nil key")
- }
- continue
- }
-
- // Otherwise we should seek to the exact key or the next key.
- num := binary.BigEndian.Uint64(k)
- if i%2 == 0 {
- if num != uint64(i) {
- t.Fatalf("unexpected num: %d", num)
- }
- } else {
- if num != uint64(i+1) {
- t.Fatalf("unexpected num: %d", num)
- }
- }
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a cursor can iterate over an empty bucket without error.
-func TestCursor_EmptyBucket(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucket([]byte("widgets"))
- return err
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.View(func(tx *bolt.Tx) error {
- c := tx.Bucket([]byte("widgets")).Cursor()
- k, v := c.First()
- if k != nil {
- t.Fatalf("unexpected key: %v", k)
- } else if v != nil {
- t.Fatalf("unexpected value: %v", v)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a Tx cursor can reverse iterate over an empty bucket without error.
-func TestCursor_EmptyBucketReverse(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucket([]byte("widgets"))
- return err
- }); err != nil {
- t.Fatal(err)
- }
- if err := db.View(func(tx *bolt.Tx) error {
- c := tx.Bucket([]byte("widgets")).Cursor()
- k, v := c.Last()
- if k != nil {
- t.Fatalf("unexpected key: %v", k)
- } else if v != nil {
- t.Fatalf("unexpected value: %v", v)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a Tx cursor can iterate over a single root with a couple elements.
-func TestCursor_Iterate_Leaf(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("baz"), []byte{}); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte{0}); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("bar"), []byte{1}); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- tx, err := db.Begin(false)
- if err != nil {
- t.Fatal(err)
- }
- defer func() { _ = tx.Rollback() }()
-
- c := tx.Bucket([]byte("widgets")).Cursor()
-
- k, v := c.First()
- if !bytes.Equal(k, []byte("bar")) {
- t.Fatalf("unexpected key: %v", k)
- } else if !bytes.Equal(v, []byte{1}) {
- t.Fatalf("unexpected value: %v", v)
- }
-
- k, v = c.Next()
- if !bytes.Equal(k, []byte("baz")) {
- t.Fatalf("unexpected key: %v", k)
- } else if !bytes.Equal(v, []byte{}) {
- t.Fatalf("unexpected value: %v", v)
- }
-
- k, v = c.Next()
- if !bytes.Equal(k, []byte("foo")) {
- t.Fatalf("unexpected key: %v", k)
- } else if !bytes.Equal(v, []byte{0}) {
- t.Fatalf("unexpected value: %v", v)
- }
-
- k, v = c.Next()
- if k != nil {
- t.Fatalf("expected nil key: %v", k)
- } else if v != nil {
- t.Fatalf("expected nil value: %v", v)
- }
-
- k, v = c.Next()
- if k != nil {
- t.Fatalf("expected nil key: %v", k)
- } else if v != nil {
- t.Fatalf("expected nil value: %v", v)
- }
-
- if err := tx.Rollback(); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a Tx cursor can iterate in reverse over a single root with a couple elements.
-func TestCursor_LeafRootReverse(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("baz"), []byte{}); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte{0}); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("bar"), []byte{1}); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- tx, err := db.Begin(false)
- if err != nil {
- t.Fatal(err)
- }
- c := tx.Bucket([]byte("widgets")).Cursor()
-
- if k, v := c.Last(); !bytes.Equal(k, []byte("foo")) {
- t.Fatalf("unexpected key: %v", k)
- } else if !bytes.Equal(v, []byte{0}) {
- t.Fatalf("unexpected value: %v", v)
- }
-
- if k, v := c.Prev(); !bytes.Equal(k, []byte("baz")) {
- t.Fatalf("unexpected key: %v", k)
- } else if !bytes.Equal(v, []byte{}) {
- t.Fatalf("unexpected value: %v", v)
- }
-
- if k, v := c.Prev(); !bytes.Equal(k, []byte("bar")) {
- t.Fatalf("unexpected key: %v", k)
- } else if !bytes.Equal(v, []byte{1}) {
- t.Fatalf("unexpected value: %v", v)
- }
-
- if k, v := c.Prev(); k != nil {
- t.Fatalf("expected nil key: %v", k)
- } else if v != nil {
- t.Fatalf("expected nil value: %v", v)
- }
-
- if k, v := c.Prev(); k != nil {
- t.Fatalf("expected nil key: %v", k)
- } else if v != nil {
- t.Fatalf("expected nil value: %v", v)
- }
-
- if err := tx.Rollback(); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a Tx cursor can restart from the beginning.
-func TestCursor_Restart(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("bar"), []byte{}); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte{}); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- tx, err := db.Begin(false)
- if err != nil {
- t.Fatal(err)
- }
- c := tx.Bucket([]byte("widgets")).Cursor()
-
- if k, _ := c.First(); !bytes.Equal(k, []byte("bar")) {
- t.Fatalf("unexpected key: %v", k)
- }
- if k, _ := c.Next(); !bytes.Equal(k, []byte("foo")) {
- t.Fatalf("unexpected key: %v", k)
- }
-
- if k, _ := c.First(); !bytes.Equal(k, []byte("bar")) {
- t.Fatalf("unexpected key: %v", k)
- }
- if k, _ := c.Next(); !bytes.Equal(k, []byte("foo")) {
- t.Fatalf("unexpected key: %v", k)
- }
-
- if err := tx.Rollback(); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a cursor can skip over empty pages that have been deleted.
-func TestCursor_First_EmptyPages(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- // Create 1000 keys in the "widgets" bucket.
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
-
- for i := 0; i < 1000; i++ {
- if err := b.Put(u64tob(uint64(i)), []byte{}); err != nil {
- t.Fatal(err)
- }
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- // Delete half the keys and then try to iterate.
- if err := db.Update(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("widgets"))
- for i := 0; i < 600; i++ {
- if err := b.Delete(u64tob(uint64(i))); err != nil {
- t.Fatal(err)
- }
- }
-
- c := b.Cursor()
- var n int
- for k, _ := c.First(); k != nil; k, _ = c.Next() {
- n++
- }
- if n != 400 {
- t.Fatalf("unexpected key count: %d", n)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a Tx can iterate over all elements in a bucket.
-func TestCursor_QuickCheck(t *testing.T) {
- f := func(items testdata) bool {
- db := MustOpenDB()
- defer db.MustClose()
-
- // Bulk insert all values.
- tx, err := db.Begin(true)
- if err != nil {
- t.Fatal(err)
- }
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- for _, item := range items {
- if err := b.Put(item.Key, item.Value); err != nil {
- t.Fatal(err)
- }
- }
- if err := tx.Commit(); err != nil {
- t.Fatal(err)
- }
-
- // Sort test data.
- sort.Sort(items)
-
- // Iterate over all items and check consistency.
- var index = 0
- tx, err = db.Begin(false)
- if err != nil {
- t.Fatal(err)
- }
-
- c := tx.Bucket([]byte("widgets")).Cursor()
- for k, v := c.First(); k != nil && index < len(items); k, v = c.Next() {
- if !bytes.Equal(k, items[index].Key) {
- t.Fatalf("unexpected key: %v", k)
- } else if !bytes.Equal(v, items[index].Value) {
- t.Fatalf("unexpected value: %v", v)
- }
- index++
- }
- if len(items) != index {
- t.Fatalf("unexpected item count: %v, expected %v", len(items), index)
- }
-
- if err := tx.Rollback(); err != nil {
- t.Fatal(err)
- }
-
- return true
- }
- if err := quick.Check(f, qconfig()); err != nil {
- t.Error(err)
- }
-}
-
-// Ensure that a transaction can iterate over all elements in a bucket in reverse.
-func TestCursor_QuickCheck_Reverse(t *testing.T) {
- f := func(items testdata) bool {
- db := MustOpenDB()
- defer db.MustClose()
-
- // Bulk insert all values.
- tx, err := db.Begin(true)
- if err != nil {
- t.Fatal(err)
- }
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- for _, item := range items {
- if err := b.Put(item.Key, item.Value); err != nil {
- t.Fatal(err)
- }
- }
- if err := tx.Commit(); err != nil {
- t.Fatal(err)
- }
-
- // Sort test data.
- sort.Sort(revtestdata(items))
-
- // Iterate over all items and check consistency.
- var index = 0
- tx, err = db.Begin(false)
- if err != nil {
- t.Fatal(err)
- }
- c := tx.Bucket([]byte("widgets")).Cursor()
- for k, v := c.Last(); k != nil && index < len(items); k, v = c.Prev() {
- if !bytes.Equal(k, items[index].Key) {
- t.Fatalf("unexpected key: %v", k)
- } else if !bytes.Equal(v, items[index].Value) {
- t.Fatalf("unexpected value: %v", v)
- }
- index++
- }
- if len(items) != index {
- t.Fatalf("unexpected item count: %v, expected %v", len(items), index)
- }
-
- if err := tx.Rollback(); err != nil {
- t.Fatal(err)
- }
-
- return true
- }
- if err := quick.Check(f, qconfig()); err != nil {
- t.Error(err)
- }
-}
-
-// Ensure that a Tx cursor can iterate over subbuckets.
-func TestCursor_QuickCheck_BucketsOnly(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if _, err := b.CreateBucket([]byte("foo")); err != nil {
- t.Fatal(err)
- }
- if _, err := b.CreateBucket([]byte("bar")); err != nil {
- t.Fatal(err)
- }
- if _, err := b.CreateBucket([]byte("baz")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.View(func(tx *bolt.Tx) error {
- var names []string
- c := tx.Bucket([]byte("widgets")).Cursor()
- for k, v := c.First(); k != nil; k, v = c.Next() {
- names = append(names, string(k))
- if v != nil {
- t.Fatalf("unexpected value: %v", v)
- }
- }
- if !reflect.DeepEqual(names, []string{"bar", "baz", "foo"}) {
- t.Fatalf("unexpected names: %+v", names)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a Tx cursor can reverse iterate over subbuckets.
-func TestCursor_QuickCheck_BucketsOnly_Reverse(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if _, err := b.CreateBucket([]byte("foo")); err != nil {
- t.Fatal(err)
- }
- if _, err := b.CreateBucket([]byte("bar")); err != nil {
- t.Fatal(err)
- }
- if _, err := b.CreateBucket([]byte("baz")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.View(func(tx *bolt.Tx) error {
- var names []string
- c := tx.Bucket([]byte("widgets")).Cursor()
- for k, v := c.Last(); k != nil; k, v = c.Prev() {
- names = append(names, string(k))
- if v != nil {
- t.Fatalf("unexpected value: %v", v)
- }
- }
- if !reflect.DeepEqual(names, []string{"foo", "baz", "bar"}) {
- t.Fatalf("unexpected names: %+v", names)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-func ExampleCursor() {
- // Open the database.
- db, err := bolt.Open(tempfile(), 0666, nil)
- if err != nil {
- log.Fatal(err)
- }
- defer os.Remove(db.Path())
-
- // Start a read-write transaction.
- if err := db.Update(func(tx *bolt.Tx) error {
- // Create a new bucket.
- b, err := tx.CreateBucket([]byte("animals"))
- if err != nil {
- return err
- }
-
- // Insert data into a bucket.
- if err := b.Put([]byte("dog"), []byte("fun")); err != nil {
- log.Fatal(err)
- }
- if err := b.Put([]byte("cat"), []byte("lame")); err != nil {
- log.Fatal(err)
- }
- if err := b.Put([]byte("liger"), []byte("awesome")); err != nil {
- log.Fatal(err)
- }
-
- // Create a cursor for iteration.
- c := b.Cursor()
-
- // Iterate over items in sorted key order. This starts from the
- // first key/value pair and updates the k/v variables to the
- // next key/value on each iteration.
- //
- // The loop finishes at the end of the cursor when a nil key is returned.
- for k, v := c.First(); k != nil; k, v = c.Next() {
- fmt.Printf("A %s is %s.\n", k, v)
- }
-
- return nil
- }); err != nil {
- log.Fatal(err)
- }
-
- if err := db.Close(); err != nil {
- log.Fatal(err)
- }
-
- // Output:
- // A cat is lame.
- // A dog is fun.
- // A liger is awesome.
-}
-
-func ExampleCursor_reverse() {
- // Open the database.
- db, err := bolt.Open(tempfile(), 0666, nil)
- if err != nil {
- log.Fatal(err)
- }
- defer os.Remove(db.Path())
-
- // Start a read-write transaction.
- if err := db.Update(func(tx *bolt.Tx) error {
- // Create a new bucket.
- b, err := tx.CreateBucket([]byte("animals"))
- if err != nil {
- return err
- }
-
- // Insert data into a bucket.
- if err := b.Put([]byte("dog"), []byte("fun")); err != nil {
- log.Fatal(err)
- }
- if err := b.Put([]byte("cat"), []byte("lame")); err != nil {
- log.Fatal(err)
- }
- if err := b.Put([]byte("liger"), []byte("awesome")); err != nil {
- log.Fatal(err)
- }
-
- // Create a cursor for iteration.
- c := b.Cursor()
-
- // Iterate over items in reverse sorted key order. This starts
- // from the last key/value pair and updates the k/v variables to
- // the previous key/value on each iteration.
- //
- // The loop finishes at the beginning of the cursor when a nil key
- // is returned.
- for k, v := c.Last(); k != nil; k, v = c.Prev() {
- fmt.Printf("A %s is %s.\n", k, v)
- }
-
- return nil
- }); err != nil {
- log.Fatal(err)
- }
-
- // Close the database to release the file lock.
- if err := db.Close(); err != nil {
- log.Fatal(err)
- }
-
- // Output:
- // A liger is awesome.
- // A dog is fun.
- // A cat is lame.
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db.go
deleted file mode 100644
index 48da059..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db.go
+++ /dev/null
@@ -1,1036 +0,0 @@
-package bolt
-
-import (
- "errors"
- "fmt"
- "hash/fnv"
- "log"
- "os"
- "runtime"
- "runtime/debug"
- "strings"
- "sync"
- "time"
- "unsafe"
-)
-
-// The largest step that can be taken when remapping the mmap.
-const maxMmapStep = 1 << 30 // 1GB
-
-// The data file format version.
-const version = 2
-
-// Represents a marker value to indicate that a file is a Bolt DB.
-const magic uint32 = 0xED0CDAED
-
-// IgnoreNoSync specifies whether the NoSync field of a DB is ignored when
-// syncing changes to a file. This is required as some operating systems,
-// such as OpenBSD, do not have a unified buffer cache (UBC) and writes
-// must be synchronized using the msync(2) syscall.
-const IgnoreNoSync = runtime.GOOS == "openbsd"
-
-// Default values if not set in a DB instance.
-const (
- DefaultMaxBatchSize int = 1000
- DefaultMaxBatchDelay = 10 * time.Millisecond
- DefaultAllocSize = 16 * 1024 * 1024
-)
-
-// default page size for db is set to the OS page size.
-var defaultPageSize = os.Getpagesize()
-
-// DB represents a collection of buckets persisted to a file on disk.
-// All data access is performed through transactions which can be obtained through the DB.
-// All the functions on DB will return a ErrDatabaseNotOpen if accessed before Open() is called.
-type DB struct {
- // When enabled, the database will perform a Check() after every commit.
- // A panic is issued if the database is in an inconsistent state. This
- // flag has a large performance impact so it should only be used for
- // debugging purposes.
- StrictMode bool
-
- // Setting the NoSync flag will cause the database to skip fsync()
- // calls after each commit. This can be useful when bulk loading data
- // into a database and you can restart the bulk load in the event of
- // a system failure or database corruption. Do not set this flag for
- // normal use.
- //
- // If the package global IgnoreNoSync constant is true, this value is
- // ignored. See the comment on that constant for more details.
- //
- // THIS IS UNSAFE. PLEASE USE WITH CAUTION.
- NoSync bool
-
- // When true, skips the truncate call when growing the database.
- // Setting this to true is only safe on non-ext3/ext4 systems.
- // Skipping truncation avoids preallocation of hard drive space and
- // bypasses a truncate() and fsync() syscall on remapping.
- //
- // https://github.com/boltdb/bolt/issues/284
- NoGrowSync bool
-
- // If you want to read the entire database fast, you can set MmapFlag to
- // syscall.MAP_POPULATE on Linux 2.6.23+ for sequential read-ahead.
- MmapFlags int
-
- // MaxBatchSize is the maximum size of a batch. Default value is
- // copied from DefaultMaxBatchSize in Open.
- //
- // If <=0, disables batching.
- //
- // Do not change concurrently with calls to Batch.
- MaxBatchSize int
-
- // MaxBatchDelay is the maximum delay before a batch starts.
- // Default value is copied from DefaultMaxBatchDelay in Open.
- //
- // If <=0, effectively disables batching.
- //
- // Do not change concurrently with calls to Batch.
- MaxBatchDelay time.Duration
-
- // AllocSize is the amount of space allocated when the database
- // needs to create new pages. This is done to amortize the cost
- // of truncate() and fsync() when growing the data file.
- AllocSize int
-
- path string
- file *os.File
- lockfile *os.File // windows only
- dataref []byte // mmap'ed readonly, write throws SEGV
- data *[maxMapSize]byte
- datasz int
- filesz int // current on disk file size
- meta0 *meta
- meta1 *meta
- pageSize int
- opened bool
- rwtx *Tx
- txs []*Tx
- freelist *freelist
- stats Stats
-
- pagePool sync.Pool
-
- batchMu sync.Mutex
- batch *batch
-
- rwlock sync.Mutex // Allows only one writer at a time.
- metalock sync.Mutex // Protects meta page access.
- mmaplock sync.RWMutex // Protects mmap access during remapping.
- statlock sync.RWMutex // Protects stats access.
-
- ops struct {
- writeAt func(b []byte, off int64) (n int, err error)
- }
-
- // Read only mode.
- // When true, Update() and Begin(true) return ErrDatabaseReadOnly immediately.
- readOnly bool
-}
-
-// Path returns the path to currently open database file.
-func (db *DB) Path() string {
- return db.path
-}
-
-// GoString returns the Go string representation of the database.
-func (db *DB) GoString() string {
- return fmt.Sprintf("bolt.DB{path:%q}", db.path)
-}
-
-// String returns the string representation of the database.
-func (db *DB) String() string {
- return fmt.Sprintf("DB<%q>", db.path)
-}
-
-// Open creates and opens a database at the given path.
-// If the file does not exist then it will be created automatically.
-// Passing in nil options will cause Bolt to open the database with the default options.
-func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
- var db = &DB{opened: true}
-
- // Set default options if no options are provided.
- if options == nil {
- options = DefaultOptions
- }
- db.NoGrowSync = options.NoGrowSync
- db.MmapFlags = options.MmapFlags
-
- // Set default values for later DB operations.
- db.MaxBatchSize = DefaultMaxBatchSize
- db.MaxBatchDelay = DefaultMaxBatchDelay
- db.AllocSize = DefaultAllocSize
-
- flag := os.O_RDWR
- if options.ReadOnly {
- flag = os.O_RDONLY
- db.readOnly = true
- }
-
- // Open data file and separate sync handler for metadata writes.
- db.path = path
- var err error
- if db.file, err = os.OpenFile(db.path, flag|os.O_CREATE, mode); err != nil {
- _ = db.close()
- return nil, err
- }
-
- // Lock file so that other processes using Bolt in read-write mode cannot
- // use the database at the same time. This would cause corruption since
- // the two processes would write meta pages and free pages separately.
- // The database file is locked exclusively (only one process can grab the lock)
- // if !options.ReadOnly.
- // The database file is locked using the shared lock (more than one process may
- // hold a lock at the same time) otherwise (options.ReadOnly is set).
- if err := flock(db, mode, !db.readOnly, options.Timeout); err != nil {
- _ = db.close()
- return nil, err
- }
-
- // Default values for test hooks
- db.ops.writeAt = db.file.WriteAt
-
- // Initialize the database if it doesn't exist.
- if info, err := db.file.Stat(); err != nil {
- return nil, err
- } else if info.Size() == 0 {
- // Initialize new files with meta pages.
- if err := db.init(); err != nil {
- return nil, err
- }
- } else {
- // Read the first meta page to determine the page size.
- var buf [0x1000]byte
- if _, err := db.file.ReadAt(buf[:], 0); err == nil {
- m := db.pageInBuffer(buf[:], 0).meta()
- if err := m.validate(); err != nil {
- // If we can't read the page size, we can assume it's the same
- // as the OS -- since that's how the page size was chosen in the
- // first place.
- //
- // If the first page is invalid and this OS uses a different
- // page size than what the database was created with then we
- // are out of luck and cannot access the database.
- db.pageSize = os.Getpagesize()
- } else {
- db.pageSize = int(m.pageSize)
- }
- }
- }
-
- // Initialize page pool.
- db.pagePool = sync.Pool{
- New: func() interface{} {
- return make([]byte, db.pageSize)
- },
- }
-
- // Memory map the data file.
- if err := db.mmap(options.InitialMmapSize); err != nil {
- _ = db.close()
- return nil, err
- }
-
- // Read in the freelist.
- db.freelist = newFreelist()
- db.freelist.read(db.page(db.meta().freelist))
-
- // Mark the database as opened and return.
- return db, nil
-}
-
-// mmap opens the underlying memory-mapped file and initializes the meta references.
-// minsz is the minimum size that the new mmap can be.
-func (db *DB) mmap(minsz int) error {
- db.mmaplock.Lock()
- defer db.mmaplock.Unlock()
-
- info, err := db.file.Stat()
- if err != nil {
- return fmt.Errorf("mmap stat error: %s", err)
- } else if int(info.Size()) < db.pageSize*2 {
- return fmt.Errorf("file size too small")
- }
-
- // Ensure the size is at least the minimum size.
- var size = int(info.Size())
- if size < minsz {
- size = minsz
- }
- size, err = db.mmapSize(size)
- if err != nil {
- return err
- }
-
- // Dereference all mmap references before unmapping.
- if db.rwtx != nil {
- db.rwtx.root.dereference()
- }
-
- // Unmap existing data before continuing.
- if err := db.munmap(); err != nil {
- return err
- }
-
- // Memory-map the data file as a byte slice.
- if err := mmap(db, size); err != nil {
- return err
- }
-
- // Save references to the meta pages.
- db.meta0 = db.page(0).meta()
- db.meta1 = db.page(1).meta()
-
- // Validate the meta pages. We only return an error if both meta pages fail
- // validation, since meta0 failing validation means that it wasn't saved
- // properly -- but we can recover using meta1. And vice-versa.
- err0 := db.meta0.validate()
- err1 := db.meta1.validate()
- if err0 != nil && err1 != nil {
- return err0
- }
-
- return nil
-}
-
-// munmap unmaps the data file from memory.
-func (db *DB) munmap() error {
- if err := munmap(db); err != nil {
- return fmt.Errorf("unmap error: " + err.Error())
- }
- return nil
-}
-
-// mmapSize determines the appropriate size for the mmap given the current size
-// of the database. The minimum size is 32KB and doubles until it reaches 1GB.
-// Returns an error if the new mmap size is greater than the max allowed.
-func (db *DB) mmapSize(size int) (int, error) {
- // Double the size from 32KB until 1GB.
- for i := uint(15); i <= 30; i++ {
- if size <= 1<<i {
- return 1 << i, nil
- }
- }
-
- // Verify the requested size is not above the maximum allowed.
- if size > maxMapSize {
- return 0, fmt.Errorf("mmap too large")
- }
-
- // If larger than 1GB then grow by 1GB at a time.
- sz := int64(size)
- if remainder := sz % int64(maxMmapStep); remainder > 0 {
- sz += int64(maxMmapStep) - remainder
- }
-
- // Ensure that the mmap size is a multiple of the page size.
- // This should always be true since we're incrementing in MBs.
- pageSize := int64(db.pageSize)
- if (sz % pageSize) != 0 {
- sz = ((sz / pageSize) + 1) * pageSize
- }
-
- // If we've exceeded the max size then only grow up to the max size.
- if sz > maxMapSize {
- sz = maxMapSize
- }
-
- return int(sz), nil
-}
-
-// init creates a new database file and initializes its meta pages.
-func (db *DB) init() error {
- // Set the page size to the OS page size.
- db.pageSize = os.Getpagesize()
-
- // Create two meta pages on a buffer.
- buf := make([]byte, db.pageSize*4)
- for i := 0; i < 2; i++ {
- p := db.pageInBuffer(buf[:], pgid(i))
- p.id = pgid(i)
- p.flags = metaPageFlag
-
- // Initialize the meta page.
- m := p.meta()
- m.magic = magic
- m.version = version
- m.pageSize = uint32(db.pageSize)
- m.freelist = 2
- m.root = bucket{root: 3}
- m.pgid = 4
- m.txid = txid(i)
- m.checksum = m.sum64()
- }
-
- // Write an empty freelist at page 3.
- p := db.pageInBuffer(buf[:], pgid(2))
- p.id = pgid(2)
- p.flags = freelistPageFlag
- p.count = 0
-
- // Write an empty leaf page at page 4.
- p = db.pageInBuffer(buf[:], pgid(3))
- p.id = pgid(3)
- p.flags = leafPageFlag
- p.count = 0
-
- // Write the buffer to our data file.
- if _, err := db.ops.writeAt(buf, 0); err != nil {
- return err
- }
- if err := fdatasync(db); err != nil {
- return err
- }
-
- return nil
-}
-
-// Close releases all database resources.
-// All transactions must be closed before closing the database.
-func (db *DB) Close() error {
- db.rwlock.Lock()
- defer db.rwlock.Unlock()
-
- db.metalock.Lock()
- defer db.metalock.Unlock()
-
- db.mmaplock.RLock()
- defer db.mmaplock.RUnlock()
-
- return db.close()
-}
-
-func (db *DB) close() error {
- if !db.opened {
- return nil
- }
-
- db.opened = false
-
- db.freelist = nil
-
- // Clear ops.
- db.ops.writeAt = nil
-
- // Close the mmap.
- if err := db.munmap(); err != nil {
- return err
- }
-
- // Close file handles.
- if db.file != nil {
- // No need to unlock read-only file.
- if !db.readOnly {
- // Unlock the file.
- if err := funlock(db); err != nil {
- log.Printf("bolt.Close(): funlock error: %s", err)
- }
- }
-
- // Close the file descriptor.
- if err := db.file.Close(); err != nil {
- return fmt.Errorf("db file close: %s", err)
- }
- db.file = nil
- }
-
- db.path = ""
- return nil
-}
-
-// Begin starts a new transaction.
-// Multiple read-only transactions can be used concurrently but only one
-// write transaction can be used at a time. Starting multiple write transactions
-// will cause the calls to block and be serialized until the current write
-// transaction finishes.
-//
-// Transactions should not be dependent on one another. Opening a read
-// transaction and a write transaction in the same goroutine can cause the
-// writer to deadlock because the database periodically needs to re-mmap itself
-// as it grows and it cannot do that while a read transaction is open.
-//
-// If a long running read transaction (for example, a snapshot transaction) is
-// needed, you might want to set DB.InitialMmapSize to a large enough value
-// to avoid potential blocking of write transaction.
-//
-// IMPORTANT: You must close read-only transactions after you are finished or
-// else the database will not reclaim old pages.
-func (db *DB) Begin(writable bool) (*Tx, error) {
- if writable {
- return db.beginRWTx()
- }
- return db.beginTx()
-}
-
-func (db *DB) beginTx() (*Tx, error) {
- // Lock the meta pages while we initialize the transaction. We obtain
- // the meta lock before the mmap lock because that's the order that the
- // write transaction will obtain them.
- db.metalock.Lock()
-
- // Obtain a read-only lock on the mmap. When the mmap is remapped it will
- // obtain a write lock so all transactions must finish before it can be
- // remapped.
- db.mmaplock.RLock()
-
- // Exit if the database is not open yet.
- if !db.opened {
- db.mmaplock.RUnlock()
- db.metalock.Unlock()
- return nil, ErrDatabaseNotOpen
- }
-
- // Create a transaction associated with the database.
- t := &Tx{}
- t.init(db)
-
- // Keep track of transaction until it closes.
- db.txs = append(db.txs, t)
- n := len(db.txs)
-
- // Unlock the meta pages.
- db.metalock.Unlock()
-
- // Update the transaction stats.
- db.statlock.Lock()
- db.stats.TxN++
- db.stats.OpenTxN = n
- db.statlock.Unlock()
-
- return t, nil
-}
-
-func (db *DB) beginRWTx() (*Tx, error) {
- // If the database was opened with Options.ReadOnly, return an error.
- if db.readOnly {
- return nil, ErrDatabaseReadOnly
- }
-
- // Obtain writer lock. This is released by the transaction when it closes.
- // This enforces only one writer transaction at a time.
- db.rwlock.Lock()
-
- // Once we have the writer lock then we can lock the meta pages so that
- // we can set up the transaction.
- db.metalock.Lock()
- defer db.metalock.Unlock()
-
- // Exit if the database is not open yet.
- if !db.opened {
- db.rwlock.Unlock()
- return nil, ErrDatabaseNotOpen
- }
-
- // Create a transaction associated with the database.
- t := &Tx{writable: true}
- t.init(db)
- db.rwtx = t
-
- // Free any pages associated with closed read-only transactions.
- var minid txid = 0xFFFFFFFFFFFFFFFF
- for _, t := range db.txs {
- if t.meta.txid < minid {
- minid = t.meta.txid
- }
- }
- if minid > 0 {
- db.freelist.release(minid - 1)
- }
-
- return t, nil
-}
-
-// removeTx removes a transaction from the database.
-func (db *DB) removeTx(tx *Tx) {
- // Release the read lock on the mmap.
- db.mmaplock.RUnlock()
-
- // Use the meta lock to restrict access to the DB object.
- db.metalock.Lock()
-
- // Remove the transaction.
- for i, t := range db.txs {
- if t == tx {
- db.txs = append(db.txs[:i], db.txs[i+1:]...)
- break
- }
- }
- n := len(db.txs)
-
- // Unlock the meta pages.
- db.metalock.Unlock()
-
- // Merge statistics.
- db.statlock.Lock()
- db.stats.OpenTxN = n
- db.stats.TxStats.add(&tx.stats)
- db.statlock.Unlock()
-}
-
-// Update executes a function within the context of a read-write managed transaction.
-// If no error is returned from the function then the transaction is committed.
-// If an error is returned then the entire transaction is rolled back.
-// Any error that is returned from the function or returned from the commit is
-// returned from the Update() method.
-//
-// Attempting to manually commit or rollback within the function will cause a panic.
-func (db *DB) Update(fn func(*Tx) error) error {
- t, err := db.Begin(true)
- if err != nil {
- return err
- }
-
- // Make sure the transaction rolls back in the event of a panic.
- defer func() {
- if t.db != nil {
- t.rollback()
- }
- }()
-
- // Mark as a managed tx so that the inner function cannot manually commit.
- t.managed = true
-
- // If an error is returned from the function then rollback and return error.
- err = fn(t)
- t.managed = false
- if err != nil {
- _ = t.Rollback()
- return err
- }
-
- return t.Commit()
-}
-
-// View executes a function within the context of a managed read-only transaction.
-// Any error that is returned from the function is returned from the View() method.
-//
-// Attempting to manually rollback within the function will cause a panic.
-func (db *DB) View(fn func(*Tx) error) error {
- t, err := db.Begin(false)
- if err != nil {
- return err
- }
-
- // Make sure the transaction rolls back in the event of a panic.
- defer func() {
- if t.db != nil {
- t.rollback()
- }
- }()
-
- // Mark as a managed tx so that the inner function cannot manually rollback.
- t.managed = true
-
- // If an error is returned from the function then pass it through.
- err = fn(t)
- t.managed = false
- if err != nil {
- _ = t.Rollback()
- return err
- }
-
- if err := t.Rollback(); err != nil {
- return err
- }
-
- return nil
-}
-
-// Batch calls fn as part of a batch. It behaves similar to Update,
-// except:
-//
-// 1. concurrent Batch calls can be combined into a single Bolt
-// transaction.
-//
-// 2. the function passed to Batch may be called multiple times,
-// regardless of whether it returns error or not.
-//
-// This means that Batch function side effects must be idempotent and
-// take permanent effect only after a successful return is seen in
-// caller.
-//
-// The maximum batch size and delay can be adjusted with DB.MaxBatchSize
-// and DB.MaxBatchDelay, respectively.
-//
-// Batch is only useful when there are multiple goroutines calling it.
-func (db *DB) Batch(fn func(*Tx) error) error {
- errCh := make(chan error, 1)
-
- db.batchMu.Lock()
- if (db.batch == nil) || (db.batch != nil && len(db.batch.calls) >= db.MaxBatchSize) {
- // There is no existing batch, or the existing batch is full; start a new one.
- db.batch = &batch{
- db: db,
- }
- db.batch.timer = time.AfterFunc(db.MaxBatchDelay, db.batch.trigger)
- }
- db.batch.calls = append(db.batch.calls, call{fn: fn, err: errCh})
- if len(db.batch.calls) >= db.MaxBatchSize {
- // wake up batch, it's ready to run
- go db.batch.trigger()
- }
- db.batchMu.Unlock()
-
- err := <-errCh
- if err == trySolo {
- err = db.Update(fn)
- }
- return err
-}
-
-type call struct {
- fn func(*Tx) error
- err chan<- error
-}
-
-type batch struct {
- db *DB
- timer *time.Timer
- start sync.Once
- calls []call
-}
-
-// trigger runs the batch if it hasn't already been run.
-func (b *batch) trigger() {
- b.start.Do(b.run)
-}
-
-// run performs the transactions in the batch and communicates results
-// back to DB.Batch.
-func (b *batch) run() {
- b.db.batchMu.Lock()
- b.timer.Stop()
- // Make sure no new work is added to this batch, but don't break
- // other batches.
- if b.db.batch == b {
- b.db.batch = nil
- }
- b.db.batchMu.Unlock()
-
-retry:
- for len(b.calls) > 0 {
- var failIdx = -1
- err := b.db.Update(func(tx *Tx) error {
- for i, c := range b.calls {
- if err := safelyCall(c.fn, tx); err != nil {
- failIdx = i
- return err
- }
- }
- return nil
- })
-
- if failIdx >= 0 {
- // take the failing transaction out of the batch. it's
- // safe to shorten b.calls here because db.batch no longer
- // points to us, and we hold the mutex anyway.
- c := b.calls[failIdx]
- b.calls[failIdx], b.calls = b.calls[len(b.calls)-1], b.calls[:len(b.calls)-1]
- // tell the submitter re-run it solo, continue with the rest of the batch
- c.err <- trySolo
- continue retry
- }
-
- // pass success, or bolt internal errors, to all callers
- for _, c := range b.calls {
- if c.err != nil {
- c.err <- err
- }
- }
- break retry
- }
-}
-
-// trySolo is a special sentinel error value used for signaling that a
-// transaction function should be re-run. It should never be seen by
-// callers.
-var trySolo = errors.New("batch function returned an error and should be re-run solo")
-
-type panicked struct {
- reason interface{}
-}
-
-func (p panicked) Error() string {
- if err, ok := p.reason.(error); ok {
- return err.Error()
- }
- return fmt.Sprintf("panic: %v", p.reason)
-}
-
-func safelyCall(fn func(*Tx) error, tx *Tx) (err error) {
- defer func() {
- if p := recover(); p != nil {
- err = panicked{p}
- }
- }()
- return fn(tx)
-}
-
-// Sync executes fdatasync() against the database file handle.
-//
-// This is not necessary under normal operation, however, if you use NoSync
-// then it allows you to force the database file to sync against the disk.
-func (db *DB) Sync() error { return fdatasync(db) }
-
-// Stats retrieves ongoing performance stats for the database.
-// This is only updated when a transaction closes.
-func (db *DB) Stats() Stats {
- db.statlock.RLock()
- defer db.statlock.RUnlock()
- return db.stats
-}
-
-// This is for internal access to the raw data bytes from the C cursor, use
-// carefully, or not at all.
-func (db *DB) Info() *Info {
- return &Info{uintptr(unsafe.Pointer(&db.data[0])), db.pageSize}
-}
-
-// page retrieves a page reference from the mmap based on the current page size.
-func (db *DB) page(id pgid) *page {
- pos := id * pgid(db.pageSize)
- return (*page)(unsafe.Pointer(&db.data[pos]))
-}
-
-// pageInBuffer retrieves a page reference from a given byte array based on the current page size.
-func (db *DB) pageInBuffer(b []byte, id pgid) *page {
- return (*page)(unsafe.Pointer(&b[id*pgid(db.pageSize)]))
-}
-
-// meta retrieves the current meta page reference.
-func (db *DB) meta() *meta {
- // We have to return the meta with the highest txid which doesn't fail
- // validation. Otherwise, we can cause errors when in fact the database is
- // in a consistent state. metaA is the one with the higher txid.
- metaA := db.meta0
- metaB := db.meta1
- if db.meta1.txid > db.meta0.txid {
- metaA = db.meta1
- metaB = db.meta0
- }
-
- // Use higher meta page if valid. Otherwise fallback to previous, if valid.
- if err := metaA.validate(); err == nil {
- return metaA
- } else if err := metaB.validate(); err == nil {
- return metaB
- }
-
- // This should never be reached, because both meta1 and meta0 were validated
- // on mmap() and we do fsync() on every write.
- panic("bolt.DB.meta(): invalid meta pages")
-}
-
-// allocate returns a contiguous block of memory starting at a given page.
-func (db *DB) allocate(count int) (*page, error) {
- // Allocate a temporary buffer for the page.
- var buf []byte
- if count == 1 {
- buf = db.pagePool.Get().([]byte)
- } else {
- buf = make([]byte, count*db.pageSize)
- }
- p := (*page)(unsafe.Pointer(&buf[0]))
- p.overflow = uint32(count - 1)
-
- // Use pages from the freelist if they are available.
- if p.id = db.freelist.allocate(count); p.id != 0 {
- return p, nil
- }
-
- // Resize mmap() if we're at the end.
- p.id = db.rwtx.meta.pgid
- var minsz = int((p.id+pgid(count))+1) * db.pageSize
- if minsz >= db.datasz {
- if err := db.mmap(minsz); err != nil {
- return nil, fmt.Errorf("mmap allocate error: %s", err)
- }
- }
-
- // Move the page id high water mark.
- db.rwtx.meta.pgid += pgid(count)
-
- return p, nil
-}
-
-// grow grows the size of the database to the given sz.
-func (db *DB) grow(sz int) error {
- // Ignore if the new size is less than available file size.
- if sz <= db.filesz {
- return nil
- }
-
- // If the data is smaller than the alloc size then only allocate what's needed.
- // Once it goes over the allocation size then allocate in chunks.
- if db.datasz < db.AllocSize {
- sz = db.datasz
- } else {
- sz += db.AllocSize
- }
-
- // Truncate and fsync to ensure file size metadata is flushed.
- // https://github.com/boltdb/bolt/issues/284
- if !db.NoGrowSync && !db.readOnly {
- if runtime.GOOS != "windows" {
- if err := db.file.Truncate(int64(sz)); err != nil {
- return fmt.Errorf("file resize error: %s", err)
- }
- }
- if err := db.file.Sync(); err != nil {
- return fmt.Errorf("file sync error: %s", err)
- }
- }
-
- db.filesz = sz
- return nil
-}
-
-func (db *DB) IsReadOnly() bool {
- return db.readOnly
-}
-
-// Options represents the options that can be set when opening a database.
-type Options struct {
- // Timeout is the amount of time to wait to obtain a file lock.
- // When set to zero it will wait indefinitely. This option is only
- // available on Darwin and Linux.
- Timeout time.Duration
-
- // Sets the DB.NoGrowSync flag before memory mapping the file.
- NoGrowSync bool
-
- // Open database in read-only mode. Uses flock(..., LOCK_SH |LOCK_NB) to
- // grab a shared lock (UNIX).
- ReadOnly bool
-
- // Sets the DB.MmapFlags flag before memory mapping the file.
- MmapFlags int
-
- // InitialMmapSize is the initial mmap size of the database
- // in bytes. Read transactions won't block write transaction
- // if the InitialMmapSize is large enough to hold database mmap
- // size. (See DB.Begin for more information)
- //
- // If <=0, the initial map size is 0.
- // If initialMmapSize is smaller than the previous database size,
- // it takes no effect.
- InitialMmapSize int
-}
-
-// DefaultOptions represent the options used if nil options are passed into Open().
-// No timeout is used which will cause Bolt to wait indefinitely for a lock.
-var DefaultOptions = &Options{
- Timeout: 0,
- NoGrowSync: false,
-}
-
-// Stats represents statistics about the database.
-type Stats struct {
- // Freelist stats
- FreePageN int // total number of free pages on the freelist
- PendingPageN int // total number of pending pages on the freelist
- FreeAlloc int // total bytes allocated in free pages
- FreelistInuse int // total bytes used by the freelist
-
- // Transaction stats
- TxN int // total number of started read transactions
- OpenTxN int // number of currently open read transactions
-
- TxStats TxStats // global, ongoing stats.
-}
-
-// Sub calculates and returns the difference between two sets of database stats.
-// This is useful when obtaining stats at two different points and time and
-// you need the performance counters that occurred within that time span.
-func (s *Stats) Sub(other *Stats) Stats {
- if other == nil {
- return *s
- }
- var diff Stats
- diff.FreePageN = s.FreePageN
- diff.PendingPageN = s.PendingPageN
- diff.FreeAlloc = s.FreeAlloc
- diff.FreelistInuse = s.FreelistInuse
- diff.TxN = s.TxN - other.TxN
- diff.TxStats = s.TxStats.Sub(&other.TxStats)
- return diff
-}
-
-func (s *Stats) add(other *Stats) {
- s.TxStats.add(&other.TxStats)
-}
-
-type Info struct {
- Data uintptr
- PageSize int
-}
-
-type meta struct {
- magic uint32
- version uint32
- pageSize uint32
- flags uint32
- root bucket
- freelist pgid
- pgid pgid
- txid txid
- checksum uint64
-}
-
-// validate checks the marker bytes and version of the meta page to ensure it matches this binary.
-func (m *meta) validate() error {
- if m.magic != magic {
- return ErrInvalid
- } else if m.version != version {
- return ErrVersionMismatch
- } else if m.checksum != 0 && m.checksum != m.sum64() {
- return ErrChecksum
- }
- return nil
-}
-
-// copy copies one meta object to another.
-func (m *meta) copy(dest *meta) {
- *dest = *m
-}
-
-// write writes the meta onto a page.
-func (m *meta) write(p *page) {
- if m.root.root >= m.pgid {
- panic(fmt.Sprintf("root bucket pgid (%d) above high water mark (%d)", m.root.root, m.pgid))
- } else if m.freelist >= m.pgid {
- panic(fmt.Sprintf("freelist pgid (%d) above high water mark (%d)", m.freelist, m.pgid))
- }
-
- // Page id is either going to be 0 or 1 which we can determine by the transaction ID.
- p.id = pgid(m.txid % 2)
- p.flags |= metaPageFlag
-
- // Calculate the checksum.
- m.checksum = m.sum64()
-
- m.copy(p.meta())
-}
-
-// generates the checksum for the meta.
-func (m *meta) sum64() uint64 {
- var h = fnv.New64a()
- _, _ = h.Write((*[unsafe.Offsetof(meta{}.checksum)]byte)(unsafe.Pointer(m))[:])
- return h.Sum64()
-}
-
-// _assert will panic with a given formatted message if the given condition is false.
-func _assert(condition bool, msg string, v ...interface{}) {
- if !condition {
- panic(fmt.Sprintf("assertion failed: "+msg, v...))
- }
-}
-
-func warn(v ...interface{}) { fmt.Fprintln(os.Stderr, v...) }
-func warnf(msg string, v ...interface{}) { fmt.Fprintf(os.Stderr, msg+"\n", v...) }
-
-func printstack() {
- stack := strings.Join(strings.Split(string(debug.Stack()), "\n")[2:], "\n")
- fmt.Fprintln(os.Stderr, stack)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db_test.go
deleted file mode 100644
index 74ff93a..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db_test.go
+++ /dev/null
@@ -1,1706 +0,0 @@
-package bolt_test
-
-import (
- "bytes"
- "encoding/binary"
- "errors"
- "flag"
- "fmt"
- "hash/fnv"
- "io/ioutil"
- "log"
- "os"
- "path/filepath"
- "regexp"
- "runtime"
- "sort"
- "strings"
- "sync"
- "testing"
- "time"
- "unsafe"
-
- "github.com/boltdb/bolt"
-)
-
-var statsFlag = flag.Bool("stats", false, "show performance stats")
-
-// version is the data file format version.
-const version = 2
-
-// magic is the marker value to indicate that a file is a Bolt DB.
-const magic uint32 = 0xED0CDAED
-
-// pageSize is the size of one page in the data file.
-const pageSize = 4096
-
-// pageHeaderSize is the size of a page header.
-const pageHeaderSize = 16
-
-// meta represents a simplified version of a database meta page for testing.
-type meta struct {
- magic uint32
- version uint32
- _ uint32
- _ uint32
- _ [16]byte
- _ uint64
- pgid uint64
- _ uint64
- checksum uint64
-}
-
-// Ensure that a database can be opened without error.
-func TestOpen(t *testing.T) {
- path := tempfile()
- db, err := bolt.Open(path, 0666, nil)
- if err != nil {
- t.Fatal(err)
- } else if db == nil {
- t.Fatal("expected db")
- }
-
- if s := db.Path(); s != path {
- t.Fatalf("unexpected path: %s", s)
- }
-
- if err := db.Close(); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that opening a database with a blank path returns an error.
-func TestOpen_ErrPathRequired(t *testing.T) {
- _, err := bolt.Open("", 0666, nil)
- if err == nil {
- t.Fatalf("expected error")
- }
-}
-
-// Ensure that opening a database with a bad path returns an error.
-func TestOpen_ErrNotExists(t *testing.T) {
- _, err := bolt.Open(filepath.Join(tempfile(), "bad-path"), 0666, nil)
- if err == nil {
- t.Fatal("expected error")
- }
-}
-
-// Ensure that opening a file that is not a Bolt database returns ErrInvalid.
-func TestOpen_ErrInvalid(t *testing.T) {
- path := tempfile()
-
- f, err := os.Create(path)
- if err != nil {
- t.Fatal(err)
- }
- if _, err := fmt.Fprintln(f, "this is not a bolt database"); err != nil {
- t.Fatal(err)
- }
- if err := f.Close(); err != nil {
- t.Fatal(err)
- }
- defer os.Remove(path)
-
- if _, err := bolt.Open(path, 0666, nil); err != bolt.ErrInvalid {
- t.Fatalf("unexpected error: %s", err)
- }
-}
-
-// Ensure that opening a file with two invalid versions returns ErrVersionMismatch.
-func TestOpen_ErrVersionMismatch(t *testing.T) {
- if pageSize != os.Getpagesize() {
- t.Skip("page size mismatch")
- }
-
- // Create empty database.
- db := MustOpenDB()
- path := db.Path()
- defer db.MustClose()
-
- // Close database.
- if err := db.DB.Close(); err != nil {
- t.Fatal(err)
- }
-
- // Read data file.
- buf, err := ioutil.ReadFile(path)
- if err != nil {
- t.Fatal(err)
- }
-
- // Rewrite meta pages.
- meta0 := (*meta)(unsafe.Pointer(&buf[pageHeaderSize]))
- meta0.version++
- meta1 := (*meta)(unsafe.Pointer(&buf[pageSize+pageHeaderSize]))
- meta1.version++
- if err := ioutil.WriteFile(path, buf, 0666); err != nil {
- t.Fatal(err)
- }
-
- // Reopen data file.
- if _, err := bolt.Open(path, 0666, nil); err != bolt.ErrVersionMismatch {
- t.Fatalf("unexpected error: %s", err)
- }
-}
-
-// Ensure that opening a file with two invalid checksums returns ErrChecksum.
-func TestOpen_ErrChecksum(t *testing.T) {
- if pageSize != os.Getpagesize() {
- t.Skip("page size mismatch")
- }
-
- // Create empty database.
- db := MustOpenDB()
- path := db.Path()
- defer db.MustClose()
-
- // Close database.
- if err := db.DB.Close(); err != nil {
- t.Fatal(err)
- }
-
- // Read data file.
- buf, err := ioutil.ReadFile(path)
- if err != nil {
- t.Fatal(err)
- }
-
- // Rewrite meta pages.
- meta0 := (*meta)(unsafe.Pointer(&buf[pageHeaderSize]))
- meta0.pgid++
- meta1 := (*meta)(unsafe.Pointer(&buf[pageSize+pageHeaderSize]))
- meta1.pgid++
- if err := ioutil.WriteFile(path, buf, 0666); err != nil {
- t.Fatal(err)
- }
-
- // Reopen data file.
- if _, err := bolt.Open(path, 0666, nil); err != bolt.ErrChecksum {
- t.Fatalf("unexpected error: %s", err)
- }
-}
-
-// Ensure that opening an already open database file will timeout.
-func TestOpen_Timeout(t *testing.T) {
- if runtime.GOOS == "solaris" {
- t.Skip("solaris fcntl locks don't support intra-process locking")
- }
-
- path := tempfile()
-
- // Open a data file.
- db0, err := bolt.Open(path, 0666, nil)
- if err != nil {
- t.Fatal(err)
- } else if db0 == nil {
- t.Fatal("expected database")
- }
-
- // Attempt to open the database again.
- start := time.Now()
- db1, err := bolt.Open(path, 0666, &bolt.Options{Timeout: 100 * time.Millisecond})
- if err != bolt.ErrTimeout {
- t.Fatalf("unexpected timeout: %s", err)
- } else if db1 != nil {
- t.Fatal("unexpected database")
- } else if time.Since(start) <= 100*time.Millisecond {
- t.Fatal("expected to wait at least timeout duration")
- }
-
- if err := db0.Close(); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that opening an already open database file will wait until its closed.
-func TestOpen_Wait(t *testing.T) {
- if runtime.GOOS == "solaris" {
- t.Skip("solaris fcntl locks don't support intra-process locking")
- }
-
- path := tempfile()
-
- // Open a data file.
- db0, err := bolt.Open(path, 0666, nil)
- if err != nil {
- t.Fatal(err)
- }
-
- // Close it in just a bit.
- time.AfterFunc(100*time.Millisecond, func() { _ = db0.Close() })
-
- // Attempt to open the database again.
- start := time.Now()
- db1, err := bolt.Open(path, 0666, &bolt.Options{Timeout: 200 * time.Millisecond})
- if err != nil {
- t.Fatal(err)
- } else if time.Since(start) <= 100*time.Millisecond {
- t.Fatal("expected to wait at least timeout duration")
- }
-
- if err := db1.Close(); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that opening a database does not increase its size.
-// https://github.com/boltdb/bolt/issues/291
-func TestOpen_Size(t *testing.T) {
- // Open a data file.
- db := MustOpenDB()
- path := db.Path()
- defer db.MustClose()
-
- pagesize := db.Info().PageSize
-
- // Insert until we get above the minimum 4MB size.
- if err := db.Update(func(tx *bolt.Tx) error {
- b, _ := tx.CreateBucketIfNotExists([]byte("data"))
- for i := 0; i < 10000; i++ {
- if err := b.Put([]byte(fmt.Sprintf("%04d", i)), make([]byte, 1000)); err != nil {
- t.Fatal(err)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- // Close database and grab the size.
- if err := db.DB.Close(); err != nil {
- t.Fatal(err)
- }
- sz := fileSize(path)
- if sz == 0 {
- t.Fatalf("unexpected new file size: %d", sz)
- }
-
- // Reopen database, update, and check size again.
- db0, err := bolt.Open(path, 0666, nil)
- if err != nil {
- t.Fatal(err)
- }
- if err := db0.Update(func(tx *bolt.Tx) error {
- if err := tx.Bucket([]byte("data")).Put([]byte{0}, []byte{0}); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- if err := db0.Close(); err != nil {
- t.Fatal(err)
- }
- newSz := fileSize(path)
- if newSz == 0 {
- t.Fatalf("unexpected new file size: %d", newSz)
- }
-
- // Compare the original size with the new size.
- // db size might increase by a few page sizes due to the new small update.
- if sz < newSz-5*int64(pagesize) {
- t.Fatalf("unexpected file growth: %d => %d", sz, newSz)
- }
-}
-
-// Ensure that opening a database beyond the max step size does not increase its size.
-// https://github.com/boltdb/bolt/issues/303
-func TestOpen_Size_Large(t *testing.T) {
- if testing.Short() {
- t.Skip("short mode")
- }
-
- // Open a data file.
- db := MustOpenDB()
- path := db.Path()
- defer db.MustClose()
-
- pagesize := db.Info().PageSize
-
- // Insert until we get above the minimum 4MB size.
- var index uint64
- for i := 0; i < 10000; i++ {
- if err := db.Update(func(tx *bolt.Tx) error {
- b, _ := tx.CreateBucketIfNotExists([]byte("data"))
- for j := 0; j < 1000; j++ {
- if err := b.Put(u64tob(index), make([]byte, 50)); err != nil {
- t.Fatal(err)
- }
- index++
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- }
-
- // Close database and grab the size.
- if err := db.DB.Close(); err != nil {
- t.Fatal(err)
- }
- sz := fileSize(path)
- if sz == 0 {
- t.Fatalf("unexpected new file size: %d", sz)
- } else if sz < (1 << 30) {
- t.Fatalf("expected larger initial size: %d", sz)
- }
-
- // Reopen database, update, and check size again.
- db0, err := bolt.Open(path, 0666, nil)
- if err != nil {
- t.Fatal(err)
- }
- if err := db0.Update(func(tx *bolt.Tx) error {
- return tx.Bucket([]byte("data")).Put([]byte{0}, []byte{0})
- }); err != nil {
- t.Fatal(err)
- }
- if err := db0.Close(); err != nil {
- t.Fatal(err)
- }
-
- newSz := fileSize(path)
- if newSz == 0 {
- t.Fatalf("unexpected new file size: %d", newSz)
- }
-
- // Compare the original size with the new size.
- // db size might increase by a few page sizes due to the new small update.
- if sz < newSz-5*int64(pagesize) {
- t.Fatalf("unexpected file growth: %d => %d", sz, newSz)
- }
-}
-
-// Ensure that a re-opened database is consistent.
-func TestOpen_Check(t *testing.T) {
- path := tempfile()
-
- db, err := bolt.Open(path, 0666, nil)
- if err != nil {
- t.Fatal(err)
- }
- if err := db.View(func(tx *bolt.Tx) error { return <-tx.Check() }); err != nil {
- t.Fatal(err)
- }
- if err := db.Close(); err != nil {
- t.Fatal(err)
- }
-
- db, err = bolt.Open(path, 0666, nil)
- if err != nil {
- t.Fatal(err)
- }
- if err := db.View(func(tx *bolt.Tx) error { return <-tx.Check() }); err != nil {
- t.Fatal(err)
- }
- if err := db.Close(); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that write errors to the meta file handler during initialization are returned.
-func TestOpen_MetaInitWriteError(t *testing.T) {
- t.Skip("pending")
-}
-
-// Ensure that a database that is too small returns an error.
-func TestOpen_FileTooSmall(t *testing.T) {
- path := tempfile()
-
- db, err := bolt.Open(path, 0666, nil)
- if err != nil {
- t.Fatal(err)
- }
- if err := db.Close(); err != nil {
- t.Fatal(err)
- }
-
- // corrupt the database
- if err := os.Truncate(path, int64(os.Getpagesize())); err != nil {
- t.Fatal(err)
- }
-
- db, err = bolt.Open(path, 0666, nil)
- if err == nil || err.Error() != "file size too small" {
- t.Fatalf("unexpected error: %s", err)
- }
-}
-
-// Ensure that a database can be opened in read-only mode by multiple processes
-// and that a database can not be opened in read-write mode and in read-only
-// mode at the same time.
-func TestOpen_ReadOnly(t *testing.T) {
- if runtime.GOOS == "solaris" {
- t.Skip("solaris fcntl locks don't support intra-process locking")
- }
-
- bucket, key, value := []byte(`bucket`), []byte(`key`), []byte(`value`)
-
- path := tempfile()
-
- // Open in read-write mode.
- db, err := bolt.Open(path, 0666, nil)
- if err != nil {
- t.Fatal(err)
- } else if db.IsReadOnly() {
- t.Fatal("db should not be in read only mode")
- }
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket(bucket)
- if err != nil {
- return err
- }
- if err := b.Put(key, value); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- if err := db.Close(); err != nil {
- t.Fatal(err)
- }
-
- // Open in read-only mode.
- db0, err := bolt.Open(path, 0666, &bolt.Options{ReadOnly: true})
- if err != nil {
- t.Fatal(err)
- }
-
- // Opening in read-write mode should return an error.
- if _, err = bolt.Open(path, 0666, &bolt.Options{Timeout: time.Millisecond * 100}); err == nil {
- t.Fatal("expected error")
- }
-
- // And again (in read-only mode).
- db1, err := bolt.Open(path, 0666, &bolt.Options{ReadOnly: true})
- if err != nil {
- t.Fatal(err)
- }
-
- // Verify both read-only databases are accessible.
- for _, db := range []*bolt.DB{db0, db1} {
- // Verify is is in read only mode indeed.
- if !db.IsReadOnly() {
- t.Fatal("expected read only mode")
- }
-
- // Read-only databases should not allow updates.
- if err := db.Update(func(*bolt.Tx) error {
- panic(`should never get here`)
- }); err != bolt.ErrDatabaseReadOnly {
- t.Fatalf("unexpected error: %s", err)
- }
-
- // Read-only databases should not allow beginning writable txns.
- if _, err := db.Begin(true); err != bolt.ErrDatabaseReadOnly {
- t.Fatalf("unexpected error: %s", err)
- }
-
- // Verify the data.
- if err := db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket(bucket)
- if b == nil {
- return fmt.Errorf("expected bucket `%s`", string(bucket))
- }
-
- got := string(b.Get(key))
- expected := string(value)
- if got != expected {
- return fmt.Errorf("expected `%s`, got `%s`", expected, got)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- }
-
- if err := db0.Close(); err != nil {
- t.Fatal(err)
- }
- if err := db1.Close(); err != nil {
- t.Fatal(err)
- }
-}
-
-// TestDB_Open_InitialMmapSize tests if having InitialMmapSize large enough
-// to hold data from concurrent write transaction resolves the issue that
-// read transaction blocks the write transaction and causes deadlock.
-// This is a very hacky test since the mmap size is not exposed.
-func TestDB_Open_InitialMmapSize(t *testing.T) {
- path := tempfile()
- defer os.Remove(path)
-
- initMmapSize := 1 << 31 // 2GB
- testWriteSize := 1 << 27 // 134MB
-
- db, err := bolt.Open(path, 0666, &bolt.Options{InitialMmapSize: initMmapSize})
- if err != nil {
- t.Fatal(err)
- }
-
- // create a long-running read transaction
- // that never gets closed while writing
- rtx, err := db.Begin(false)
- if err != nil {
- t.Fatal(err)
- }
-
- // create a write transaction
- wtx, err := db.Begin(true)
- if err != nil {
- t.Fatal(err)
- }
-
- b, err := wtx.CreateBucket([]byte("test"))
- if err != nil {
- t.Fatal(err)
- }
-
- // and commit a large write
- err = b.Put([]byte("foo"), make([]byte, testWriteSize))
- if err != nil {
- t.Fatal(err)
- }
-
- done := make(chan struct{})
-
- go func() {
- if err := wtx.Commit(); err != nil {
- t.Fatal(err)
- }
- done <- struct{}{}
- }()
-
- select {
- case <-time.After(5 * time.Second):
- t.Errorf("unexpected that the reader blocks writer")
- case <-done:
- }
-
- if err := rtx.Rollback(); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a database cannot open a transaction when it's not open.
-func TestDB_Begin_ErrDatabaseNotOpen(t *testing.T) {
- var db bolt.DB
- if _, err := db.Begin(false); err != bolt.ErrDatabaseNotOpen {
- t.Fatalf("unexpected error: %s", err)
- }
-}
-
-// Ensure that a read-write transaction can be retrieved.
-func TestDB_BeginRW(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- tx, err := db.Begin(true)
- if err != nil {
- t.Fatal(err)
- } else if tx == nil {
- t.Fatal("expected tx")
- }
-
- if tx.DB() != db.DB {
- t.Fatal("unexpected tx database")
- } else if !tx.Writable() {
- t.Fatal("expected writable tx")
- }
-
- if err := tx.Commit(); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that opening a transaction while the DB is closed returns an error.
-func TestDB_BeginRW_Closed(t *testing.T) {
- var db bolt.DB
- if _, err := db.Begin(true); err != bolt.ErrDatabaseNotOpen {
- t.Fatalf("unexpected error: %s", err)
- }
-}
-
-func TestDB_Close_PendingTx_RW(t *testing.T) { testDB_Close_PendingTx(t, true) }
-func TestDB_Close_PendingTx_RO(t *testing.T) { testDB_Close_PendingTx(t, false) }
-
-// Ensure that a database cannot close while transactions are open.
-func testDB_Close_PendingTx(t *testing.T, writable bool) {
- db := MustOpenDB()
- defer db.MustClose()
-
- // Start transaction.
- tx, err := db.Begin(true)
- if err != nil {
- t.Fatal(err)
- }
-
- // Open update in separate goroutine.
- done := make(chan struct{})
- go func() {
- if err := db.Close(); err != nil {
- t.Fatal(err)
- }
- close(done)
- }()
-
- // Ensure database hasn't closed.
- time.Sleep(100 * time.Millisecond)
- select {
- case <-done:
- t.Fatal("database closed too early")
- default:
- }
-
- // Commit transaction.
- if err := tx.Commit(); err != nil {
- t.Fatal(err)
- }
-
- // Ensure database closed now.
- time.Sleep(100 * time.Millisecond)
- select {
- case <-done:
- default:
- t.Fatal("database did not close")
- }
-}
-
-// Ensure a database can provide a transactional block.
-func TestDB_Update(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("baz"), []byte("bat")); err != nil {
- t.Fatal(err)
- }
- if err := b.Delete([]byte("foo")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- if err := db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("widgets"))
- if v := b.Get([]byte("foo")); v != nil {
- t.Fatalf("expected nil value, got: %v", v)
- }
- if v := b.Get([]byte("baz")); !bytes.Equal(v, []byte("bat")) {
- t.Fatalf("unexpected value: %v", v)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure a closed database returns an error while running a transaction block
-func TestDB_Update_Closed(t *testing.T) {
- var db bolt.DB
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != bolt.ErrDatabaseNotOpen {
- t.Fatalf("unexpected error: %s", err)
- }
-}
-
-// Ensure a panic occurs while trying to commit a managed transaction.
-func TestDB_Update_ManualCommit(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- var panicked bool
- if err := db.Update(func(tx *bolt.Tx) error {
- func() {
- defer func() {
- if r := recover(); r != nil {
- panicked = true
- }
- }()
-
- if err := tx.Commit(); err != nil {
- t.Fatal(err)
- }
- }()
- return nil
- }); err != nil {
- t.Fatal(err)
- } else if !panicked {
- t.Fatal("expected panic")
- }
-}
-
-// Ensure a panic occurs while trying to rollback a managed transaction.
-func TestDB_Update_ManualRollback(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- var panicked bool
- if err := db.Update(func(tx *bolt.Tx) error {
- func() {
- defer func() {
- if r := recover(); r != nil {
- panicked = true
- }
- }()
-
- if err := tx.Rollback(); err != nil {
- t.Fatal(err)
- }
- }()
- return nil
- }); err != nil {
- t.Fatal(err)
- } else if !panicked {
- t.Fatal("expected panic")
- }
-}
-
-// Ensure a panic occurs while trying to commit a managed transaction.
-func TestDB_View_ManualCommit(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- var panicked bool
- if err := db.View(func(tx *bolt.Tx) error {
- func() {
- defer func() {
- if r := recover(); r != nil {
- panicked = true
- }
- }()
-
- if err := tx.Commit(); err != nil {
- t.Fatal(err)
- }
- }()
- return nil
- }); err != nil {
- t.Fatal(err)
- } else if !panicked {
- t.Fatal("expected panic")
- }
-}
-
-// Ensure a panic occurs while trying to rollback a managed transaction.
-func TestDB_View_ManualRollback(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- var panicked bool
- if err := db.View(func(tx *bolt.Tx) error {
- func() {
- defer func() {
- if r := recover(); r != nil {
- panicked = true
- }
- }()
-
- if err := tx.Rollback(); err != nil {
- t.Fatal(err)
- }
- }()
- return nil
- }); err != nil {
- t.Fatal(err)
- } else if !panicked {
- t.Fatal("expected panic")
- }
-}
-
-// Ensure a write transaction that panics does not hold open locks.
-func TestDB_Update_Panic(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- // Panic during update but recover.
- func() {
- defer func() {
- if r := recover(); r != nil {
- t.Log("recover: update", r)
- }
- }()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- panic("omg")
- }); err != nil {
- t.Fatal(err)
- }
- }()
-
- // Verify we can update again.
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- // Verify that our change persisted.
- if err := db.Update(func(tx *bolt.Tx) error {
- if tx.Bucket([]byte("widgets")) == nil {
- t.Fatal("expected bucket")
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure a database can return an error through a read-only transactional block.
-func TestDB_View_Error(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.View(func(tx *bolt.Tx) error {
- return errors.New("xxx")
- }); err == nil || err.Error() != "xxx" {
- t.Fatalf("unexpected error: %s", err)
- }
-}
-
-// Ensure a read transaction that panics does not hold open locks.
-func TestDB_View_Panic(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- // Panic during view transaction but recover.
- func() {
- defer func() {
- if r := recover(); r != nil {
- t.Log("recover: view", r)
- }
- }()
-
- if err := db.View(func(tx *bolt.Tx) error {
- if tx.Bucket([]byte("widgets")) == nil {
- t.Fatal("expected bucket")
- }
- panic("omg")
- }); err != nil {
- t.Fatal(err)
- }
- }()
-
- // Verify that we can still use read transactions.
- if err := db.View(func(tx *bolt.Tx) error {
- if tx.Bucket([]byte("widgets")) == nil {
- t.Fatal("expected bucket")
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that DB stats can be returned.
-func TestDB_Stats(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucket([]byte("widgets"))
- return err
- }); err != nil {
- t.Fatal(err)
- }
-
- stats := db.Stats()
- if stats.TxStats.PageCount != 2 {
- t.Fatalf("unexpected TxStats.PageCount: %d", stats.TxStats.PageCount)
- } else if stats.FreePageN != 0 {
- t.Fatalf("unexpected FreePageN != 0: %d", stats.FreePageN)
- } else if stats.PendingPageN != 2 {
- t.Fatalf("unexpected PendingPageN != 2: %d", stats.PendingPageN)
- }
-}
-
-// Ensure that database pages are in expected order and type.
-func TestDB_Consistency(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucket([]byte("widgets"))
- return err
- }); err != nil {
- t.Fatal(err)
- }
-
- for i := 0; i < 10; i++ {
- if err := db.Update(func(tx *bolt.Tx) error {
- if err := tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- }
-
- if err := db.Update(func(tx *bolt.Tx) error {
- if p, _ := tx.Page(0); p == nil {
- t.Fatal("expected page")
- } else if p.Type != "meta" {
- t.Fatalf("unexpected page type: %s", p.Type)
- }
-
- if p, _ := tx.Page(1); p == nil {
- t.Fatal("expected page")
- } else if p.Type != "meta" {
- t.Fatalf("unexpected page type: %s", p.Type)
- }
-
- if p, _ := tx.Page(2); p == nil {
- t.Fatal("expected page")
- } else if p.Type != "free" {
- t.Fatalf("unexpected page type: %s", p.Type)
- }
-
- if p, _ := tx.Page(3); p == nil {
- t.Fatal("expected page")
- } else if p.Type != "free" {
- t.Fatalf("unexpected page type: %s", p.Type)
- }
-
- if p, _ := tx.Page(4); p == nil {
- t.Fatal("expected page")
- } else if p.Type != "leaf" {
- t.Fatalf("unexpected page type: %s", p.Type)
- }
-
- if p, _ := tx.Page(5); p == nil {
- t.Fatal("expected page")
- } else if p.Type != "freelist" {
- t.Fatalf("unexpected page type: %s", p.Type)
- }
-
- if p, _ := tx.Page(6); p != nil {
- t.Fatal("unexpected page")
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that DB stats can be subtracted from one another.
-func TestDBStats_Sub(t *testing.T) {
- var a, b bolt.Stats
- a.TxStats.PageCount = 3
- a.FreePageN = 4
- b.TxStats.PageCount = 10
- b.FreePageN = 14
- diff := b.Sub(&a)
- if diff.TxStats.PageCount != 7 {
- t.Fatalf("unexpected TxStats.PageCount: %d", diff.TxStats.PageCount)
- }
-
- // free page stats are copied from the receiver and not subtracted
- if diff.FreePageN != 14 {
- t.Fatalf("unexpected FreePageN: %d", diff.FreePageN)
- }
-}
-
-// Ensure two functions can perform updates in a single batch.
-func TestDB_Batch(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- // Iterate over multiple updates in separate goroutines.
- n := 2
- ch := make(chan error)
- for i := 0; i < n; i++ {
- go func(i int) {
- ch <- db.Batch(func(tx *bolt.Tx) error {
- return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{})
- })
- }(i)
- }
-
- // Check all responses to make sure there's no error.
- for i := 0; i < n; i++ {
- if err := <-ch; err != nil {
- t.Fatal(err)
- }
- }
-
- // Ensure data is correct.
- if err := db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("widgets"))
- for i := 0; i < n; i++ {
- if v := b.Get(u64tob(uint64(i))); v == nil {
- t.Errorf("key not found: %d", i)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestDB_Batch_Panic(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- var sentinel int
- var bork = &sentinel
- var problem interface{}
- var err error
-
- // Execute a function inside a batch that panics.
- func() {
- defer func() {
- if p := recover(); p != nil {
- problem = p
- }
- }()
- err = db.Batch(func(tx *bolt.Tx) error {
- panic(bork)
- })
- }()
-
- // Verify there is no error.
- if g, e := err, error(nil); g != e {
- t.Fatalf("wrong error: %v != %v", g, e)
- }
- // Verify the panic was captured.
- if g, e := problem, bork; g != e {
- t.Fatalf("wrong error: %v != %v", g, e)
- }
-}
-
-func TestDB_BatchFull(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucket([]byte("widgets"))
- return err
- }); err != nil {
- t.Fatal(err)
- }
-
- const size = 3
- // buffered so we never leak goroutines
- ch := make(chan error, size)
- put := func(i int) {
- ch <- db.Batch(func(tx *bolt.Tx) error {
- return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{})
- })
- }
-
- db.MaxBatchSize = size
- // high enough to never trigger here
- db.MaxBatchDelay = 1 * time.Hour
-
- go put(1)
- go put(2)
-
- // Give the batch a chance to exhibit bugs.
- time.Sleep(10 * time.Millisecond)
-
- // not triggered yet
- select {
- case <-ch:
- t.Fatalf("batch triggered too early")
- default:
- }
-
- go put(3)
-
- // Check all responses to make sure there's no error.
- for i := 0; i < size; i++ {
- if err := <-ch; err != nil {
- t.Fatal(err)
- }
- }
-
- // Ensure data is correct.
- if err := db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("widgets"))
- for i := 1; i <= size; i++ {
- if v := b.Get(u64tob(uint64(i))); v == nil {
- t.Errorf("key not found: %d", i)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestDB_BatchTime(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucket([]byte("widgets"))
- return err
- }); err != nil {
- t.Fatal(err)
- }
-
- const size = 1
- // buffered so we never leak goroutines
- ch := make(chan error, size)
- put := func(i int) {
- ch <- db.Batch(func(tx *bolt.Tx) error {
- return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{})
- })
- }
-
- db.MaxBatchSize = 1000
- db.MaxBatchDelay = 0
-
- go put(1)
-
- // Batch must trigger by time alone.
-
- // Check all responses to make sure there's no error.
- for i := 0; i < size; i++ {
- if err := <-ch; err != nil {
- t.Fatal(err)
- }
- }
-
- // Ensure data is correct.
- if err := db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("widgets"))
- for i := 1; i <= size; i++ {
- if v := b.Get(u64tob(uint64(i))); v == nil {
- t.Errorf("key not found: %d", i)
- }
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-func ExampleDB_Update() {
- // Open the database.
- db, err := bolt.Open(tempfile(), 0666, nil)
- if err != nil {
- log.Fatal(err)
- }
- defer os.Remove(db.Path())
-
- // Execute several commands within a read-write transaction.
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- return err
- }
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- return err
- }
- return nil
- }); err != nil {
- log.Fatal(err)
- }
-
- // Read the value back from a separate read-only transaction.
- if err := db.View(func(tx *bolt.Tx) error {
- value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
- fmt.Printf("The value of 'foo' is: %s\n", value)
- return nil
- }); err != nil {
- log.Fatal(err)
- }
-
- // Close database to release the file lock.
- if err := db.Close(); err != nil {
- log.Fatal(err)
- }
-
- // Output:
- // The value of 'foo' is: bar
-}
-
-func ExampleDB_View() {
- // Open the database.
- db, err := bolt.Open(tempfile(), 0666, nil)
- if err != nil {
- log.Fatal(err)
- }
- defer os.Remove(db.Path())
-
- // Insert data into a bucket.
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("people"))
- if err != nil {
- return err
- }
- if err := b.Put([]byte("john"), []byte("doe")); err != nil {
- return err
- }
- if err := b.Put([]byte("susy"), []byte("que")); err != nil {
- return err
- }
- return nil
- }); err != nil {
- log.Fatal(err)
- }
-
- // Access data from within a read-only transactional block.
- if err := db.View(func(tx *bolt.Tx) error {
- v := tx.Bucket([]byte("people")).Get([]byte("john"))
- fmt.Printf("John's last name is %s.\n", v)
- return nil
- }); err != nil {
- log.Fatal(err)
- }
-
- // Close database to release the file lock.
- if err := db.Close(); err != nil {
- log.Fatal(err)
- }
-
- // Output:
- // John's last name is doe.
-}
-
-func ExampleDB_Begin_ReadOnly() {
- // Open the database.
- db, err := bolt.Open(tempfile(), 0666, nil)
- if err != nil {
- log.Fatal(err)
- }
- defer os.Remove(db.Path())
-
- // Create a bucket using a read-write transaction.
- if err := db.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucket([]byte("widgets"))
- return err
- }); err != nil {
- log.Fatal(err)
- }
-
- // Create several keys in a transaction.
- tx, err := db.Begin(true)
- if err != nil {
- log.Fatal(err)
- }
- b := tx.Bucket([]byte("widgets"))
- if err := b.Put([]byte("john"), []byte("blue")); err != nil {
- log.Fatal(err)
- }
- if err := b.Put([]byte("abby"), []byte("red")); err != nil {
- log.Fatal(err)
- }
- if err := b.Put([]byte("zephyr"), []byte("purple")); err != nil {
- log.Fatal(err)
- }
- if err := tx.Commit(); err != nil {
- log.Fatal(err)
- }
-
- // Iterate over the values in sorted key order.
- tx, err = db.Begin(false)
- if err != nil {
- log.Fatal(err)
- }
- c := tx.Bucket([]byte("widgets")).Cursor()
- for k, v := c.First(); k != nil; k, v = c.Next() {
- fmt.Printf("%s likes %s\n", k, v)
- }
-
- if err := tx.Rollback(); err != nil {
- log.Fatal(err)
- }
-
- if err := db.Close(); err != nil {
- log.Fatal(err)
- }
-
- // Output:
- // abby likes red
- // john likes blue
- // zephyr likes purple
-}
-
-func BenchmarkDBBatchAutomatic(b *testing.B) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucket([]byte("bench"))
- return err
- }); err != nil {
- b.Fatal(err)
- }
-
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- start := make(chan struct{})
- var wg sync.WaitGroup
-
- for round := 0; round < 1000; round++ {
- wg.Add(1)
-
- go func(id uint32) {
- defer wg.Done()
- <-start
-
- h := fnv.New32a()
- buf := make([]byte, 4)
- binary.LittleEndian.PutUint32(buf, id)
- _, _ = h.Write(buf[:])
- k := h.Sum(nil)
- insert := func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("bench"))
- return b.Put(k, []byte("filler"))
- }
- if err := db.Batch(insert); err != nil {
- b.Error(err)
- return
- }
- }(uint32(round))
- }
- close(start)
- wg.Wait()
- }
-
- b.StopTimer()
- validateBatchBench(b, db)
-}
-
-func BenchmarkDBBatchSingle(b *testing.B) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucket([]byte("bench"))
- return err
- }); err != nil {
- b.Fatal(err)
- }
-
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- start := make(chan struct{})
- var wg sync.WaitGroup
-
- for round := 0; round < 1000; round++ {
- wg.Add(1)
- go func(id uint32) {
- defer wg.Done()
- <-start
-
- h := fnv.New32a()
- buf := make([]byte, 4)
- binary.LittleEndian.PutUint32(buf, id)
- _, _ = h.Write(buf[:])
- k := h.Sum(nil)
- insert := func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("bench"))
- return b.Put(k, []byte("filler"))
- }
- if err := db.Update(insert); err != nil {
- b.Error(err)
- return
- }
- }(uint32(round))
- }
- close(start)
- wg.Wait()
- }
-
- b.StopTimer()
- validateBatchBench(b, db)
-}
-
-func BenchmarkDBBatchManual10x100(b *testing.B) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucket([]byte("bench"))
- return err
- }); err != nil {
- b.Fatal(err)
- }
-
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- start := make(chan struct{})
- var wg sync.WaitGroup
-
- for major := 0; major < 10; major++ {
- wg.Add(1)
- go func(id uint32) {
- defer wg.Done()
- <-start
-
- insert100 := func(tx *bolt.Tx) error {
- h := fnv.New32a()
- buf := make([]byte, 4)
- for minor := uint32(0); minor < 100; minor++ {
- binary.LittleEndian.PutUint32(buf, uint32(id*100+minor))
- h.Reset()
- _, _ = h.Write(buf[:])
- k := h.Sum(nil)
- b := tx.Bucket([]byte("bench"))
- if err := b.Put(k, []byte("filler")); err != nil {
- return err
- }
- }
- return nil
- }
- if err := db.Update(insert100); err != nil {
- b.Fatal(err)
- }
- }(uint32(major))
- }
- close(start)
- wg.Wait()
- }
-
- b.StopTimer()
- validateBatchBench(b, db)
-}
-
-func validateBatchBench(b *testing.B, db *DB) {
- var rollback = errors.New("sentinel error to cause rollback")
- validate := func(tx *bolt.Tx) error {
- bucket := tx.Bucket([]byte("bench"))
- h := fnv.New32a()
- buf := make([]byte, 4)
- for id := uint32(0); id < 1000; id++ {
- binary.LittleEndian.PutUint32(buf, id)
- h.Reset()
- _, _ = h.Write(buf[:])
- k := h.Sum(nil)
- v := bucket.Get(k)
- if v == nil {
- b.Errorf("not found id=%d key=%x", id, k)
- continue
- }
- if g, e := v, []byte("filler"); !bytes.Equal(g, e) {
- b.Errorf("bad value for id=%d key=%x: %s != %q", id, k, g, e)
- }
- if err := bucket.Delete(k); err != nil {
- return err
- }
- }
- // should be empty now
- c := bucket.Cursor()
- for k, v := c.First(); k != nil; k, v = c.Next() {
- b.Errorf("unexpected key: %x = %q", k, v)
- }
- return rollback
- }
- if err := db.Update(validate); err != nil && err != rollback {
- b.Error(err)
- }
-}
-
-// DB is a test wrapper for bolt.DB.
-type DB struct {
- *bolt.DB
-}
-
-// MustOpenDB returns a new, open DB at a temporary location.
-func MustOpenDB() *DB {
- db, err := bolt.Open(tempfile(), 0666, nil)
- if err != nil {
- panic(err)
- }
- return &DB{db}
-}
-
-// Close closes the database and deletes the underlying file.
-func (db *DB) Close() error {
- // Log statistics.
- if *statsFlag {
- db.PrintStats()
- }
-
- // Check database consistency after every test.
- db.MustCheck()
-
- // Close database and remove file.
- defer os.Remove(db.Path())
- return db.DB.Close()
-}
-
-// MustClose closes the database and deletes the underlying file. Panic on error.
-func (db *DB) MustClose() {
- if err := db.Close(); err != nil {
- panic(err)
- }
-}
-
-// PrintStats prints the database stats
-func (db *DB) PrintStats() {
- var stats = db.Stats()
- fmt.Printf("[db] %-20s %-20s %-20s\n",
- fmt.Sprintf("pg(%d/%d)", stats.TxStats.PageCount, stats.TxStats.PageAlloc),
- fmt.Sprintf("cur(%d)", stats.TxStats.CursorCount),
- fmt.Sprintf("node(%d/%d)", stats.TxStats.NodeCount, stats.TxStats.NodeDeref),
- )
- fmt.Printf(" %-20s %-20s %-20s\n",
- fmt.Sprintf("rebal(%d/%v)", stats.TxStats.Rebalance, truncDuration(stats.TxStats.RebalanceTime)),
- fmt.Sprintf("spill(%d/%v)", stats.TxStats.Spill, truncDuration(stats.TxStats.SpillTime)),
- fmt.Sprintf("w(%d/%v)", stats.TxStats.Write, truncDuration(stats.TxStats.WriteTime)),
- )
-}
-
-// MustCheck runs a consistency check on the database and panics if any errors are found.
-func (db *DB) MustCheck() {
- if err := db.Update(func(tx *bolt.Tx) error {
- // Collect all the errors.
- var errors []error
- for err := range tx.Check() {
- errors = append(errors, err)
- if len(errors) > 10 {
- break
- }
- }
-
- // If errors occurred, copy the DB and print the errors.
- if len(errors) > 0 {
- var path = tempfile()
- if err := tx.CopyFile(path, 0600); err != nil {
- panic(err)
- }
-
- // Print errors.
- fmt.Print("\n\n")
- fmt.Printf("consistency check failed (%d errors)\n", len(errors))
- for _, err := range errors {
- fmt.Println(err)
- }
- fmt.Println("")
- fmt.Println("db saved to:")
- fmt.Println(path)
- fmt.Print("\n\n")
- os.Exit(-1)
- }
-
- return nil
- }); err != nil && err != bolt.ErrDatabaseNotOpen {
- panic(err)
- }
-}
-
-// CopyTempFile copies a database to a temporary file.
-func (db *DB) CopyTempFile() {
- path := tempfile()
- if err := db.View(func(tx *bolt.Tx) error {
- return tx.CopyFile(path, 0600)
- }); err != nil {
- panic(err)
- }
- fmt.Println("db copied to: ", path)
-}
-
-// tempfile returns a temporary file path.
-func tempfile() string {
- f, err := ioutil.TempFile("", "bolt-")
- if err != nil {
- panic(err)
- }
- if err := f.Close(); err != nil {
- panic(err)
- }
- if err := os.Remove(f.Name()); err != nil {
- panic(err)
- }
- return f.Name()
-}
-
-// mustContainKeys checks that a bucket contains a given set of keys.
-func mustContainKeys(b *bolt.Bucket, m map[string]string) {
- found := make(map[string]string)
- if err := b.ForEach(func(k, _ []byte) error {
- found[string(k)] = ""
- return nil
- }); err != nil {
- panic(err)
- }
-
- // Check for keys found in bucket that shouldn't be there.
- var keys []string
- for k, _ := range found {
- if _, ok := m[string(k)]; !ok {
- keys = append(keys, k)
- }
- }
- if len(keys) > 0 {
- sort.Strings(keys)
- panic(fmt.Sprintf("keys found(%d): %s", len(keys), strings.Join(keys, ",")))
- }
-
- // Check for keys not found in bucket that should be there.
- for k, _ := range m {
- if _, ok := found[string(k)]; !ok {
- keys = append(keys, k)
- }
- }
- if len(keys) > 0 {
- sort.Strings(keys)
- panic(fmt.Sprintf("keys not found(%d): %s", len(keys), strings.Join(keys, ",")))
- }
-}
-
-func trunc(b []byte, length int) []byte {
- if length < len(b) {
- return b[:length]
- }
- return b
-}
-
-func truncDuration(d time.Duration) string {
- return regexp.MustCompile(`^(\d+)(\.\d+)`).ReplaceAllString(d.String(), "$1")
-}
-
-func fileSize(path string) int64 {
- fi, err := os.Stat(path)
- if err != nil {
- return 0
- }
- return fi.Size()
-}
-
-func warn(v ...interface{}) { fmt.Fprintln(os.Stderr, v...) }
-func warnf(msg string, v ...interface{}) { fmt.Fprintf(os.Stderr, msg+"\n", v...) }
-
-// u64tob converts a uint64 into an 8-byte slice.
-func u64tob(v uint64) []byte {
- b := make([]byte, 8)
- binary.BigEndian.PutUint64(b, v)
- return b
-}
-
-// btou64 converts an 8-byte slice into an uint64.
-func btou64(b []byte) uint64 { return binary.BigEndian.Uint64(b) }
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/doc.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/doc.go
deleted file mode 100644
index cc93784..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/doc.go
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-Package bolt implements a low-level key/value store in pure Go. It supports
-fully serializable transactions, ACID semantics, and lock-free MVCC with
-multiple readers and a single writer. Bolt can be used for projects that
-want a simple data store without the need to add large dependencies such as
-Postgres or MySQL.
-
-Bolt is a single-level, zero-copy, B+tree data store. This means that Bolt is
-optimized for fast read access and does not require recovery in the event of a
-system crash. Transactions which have not finished committing will simply be
-rolled back in the event of a crash.
-
-The design of Bolt is based on Howard Chu's LMDB database project.
-
-Bolt currently works on Windows, Mac OS X, and Linux.
-
-
-Basics
-
-There are only a few types in Bolt: DB, Bucket, Tx, and Cursor. The DB is
-a collection of buckets and is represented by a single file on disk. A bucket is
-a collection of unique keys that are associated with values.
-
-Transactions provide either read-only or read-write access to the database.
-Read-only transactions can retrieve key/value pairs and can use Cursors to
-iterate over the dataset sequentially. Read-write transactions can create and
-delete buckets and can insert and remove keys. Only one read-write transaction
-is allowed at a time.
-
-
-Caveats
-
-The database uses a read-only, memory-mapped data file to ensure that
-applications cannot corrupt the database, however, this means that keys and
-values returned from Bolt cannot be changed. Writing to a read-only byte slice
-will cause Go to panic.
-
-Keys and values retrieved from the database are only valid for the life of
-the transaction. When used outside the transaction, these byte slices can
-point to different data or can point to invalid memory which will cause a panic.
-
-
-*/
-package bolt
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/errors.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/errors.go
deleted file mode 100644
index a3620a3..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/errors.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package bolt
-
-import "errors"
-
-// These errors can be returned when opening or calling methods on a DB.
-var (
- // ErrDatabaseNotOpen is returned when a DB instance is accessed before it
- // is opened or after it is closed.
- ErrDatabaseNotOpen = errors.New("database not open")
-
- // ErrDatabaseOpen is returned when opening a database that is
- // already open.
- ErrDatabaseOpen = errors.New("database already open")
-
- // ErrInvalid is returned when both meta pages on a database are invalid.
- // This typically occurs when a file is not a bolt database.
- ErrInvalid = errors.New("invalid database")
-
- // ErrVersionMismatch is returned when the data file was created with a
- // different version of Bolt.
- ErrVersionMismatch = errors.New("version mismatch")
-
- // ErrChecksum is returned when either meta page checksum does not match.
- ErrChecksum = errors.New("checksum error")
-
- // ErrTimeout is returned when a database cannot obtain an exclusive lock
- // on the data file after the timeout passed to Open().
- ErrTimeout = errors.New("timeout")
-)
-
-// These errors can occur when beginning or committing a Tx.
-var (
- // ErrTxNotWritable is returned when performing a write operation on a
- // read-only transaction.
- ErrTxNotWritable = errors.New("tx not writable")
-
- // ErrTxClosed is returned when committing or rolling back a transaction
- // that has already been committed or rolled back.
- ErrTxClosed = errors.New("tx closed")
-
- // ErrDatabaseReadOnly is returned when a mutating transaction is started on a
- // read-only database.
- ErrDatabaseReadOnly = errors.New("database is in read-only mode")
-)
-
-// These errors can occur when putting or deleting a value or a bucket.
-var (
- // ErrBucketNotFound is returned when trying to access a bucket that has
- // not been created yet.
- ErrBucketNotFound = errors.New("bucket not found")
-
- // ErrBucketExists is returned when creating a bucket that already exists.
- ErrBucketExists = errors.New("bucket already exists")
-
- // ErrBucketNameRequired is returned when creating a bucket with a blank name.
- ErrBucketNameRequired = errors.New("bucket name required")
-
- // ErrKeyRequired is returned when inserting a zero-length key.
- ErrKeyRequired = errors.New("key required")
-
- // ErrKeyTooLarge is returned when inserting a key that is larger than MaxKeySize.
- ErrKeyTooLarge = errors.New("key too large")
-
- // ErrValueTooLarge is returned when inserting a value that is larger than MaxValueSize.
- ErrValueTooLarge = errors.New("value too large")
-
- // ErrIncompatibleValue is returned when trying create or delete a bucket
- // on an existing non-bucket key or when trying to create or delete a
- // non-bucket key on an existing bucket key.
- ErrIncompatibleValue = errors.New("incompatible value")
-)
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist.go
deleted file mode 100644
index d32f6cd..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist.go
+++ /dev/null
@@ -1,248 +0,0 @@
-package bolt
-
-import (
- "fmt"
- "sort"
- "unsafe"
-)
-
-// freelist represents a list of all pages that are available for allocation.
-// It also tracks pages that have been freed but are still in use by open transactions.
-type freelist struct {
- ids []pgid // all free and available free page ids.
- pending map[txid][]pgid // mapping of soon-to-be free page ids by tx.
- cache map[pgid]bool // fast lookup of all free and pending page ids.
-}
-
-// newFreelist returns an empty, initialized freelist.
-func newFreelist() *freelist {
- return &freelist{
- pending: make(map[txid][]pgid),
- cache: make(map[pgid]bool),
- }
-}
-
-// size returns the size of the page after serialization.
-func (f *freelist) size() int {
- return pageHeaderSize + (int(unsafe.Sizeof(pgid(0))) * f.count())
-}
-
-// count returns count of pages on the freelist
-func (f *freelist) count() int {
- return f.free_count() + f.pending_count()
-}
-
-// free_count returns count of free pages
-func (f *freelist) free_count() int {
- return len(f.ids)
-}
-
-// pending_count returns count of pending pages
-func (f *freelist) pending_count() int {
- var count int
- for _, list := range f.pending {
- count += len(list)
- }
- return count
-}
-
-// all returns a list of all free ids and all pending ids in one sorted list.
-func (f *freelist) all() []pgid {
- m := make(pgids, 0)
-
- for _, list := range f.pending {
- m = append(m, list...)
- }
-
- sort.Sort(m)
- return pgids(f.ids).merge(m)
-}
-
-// allocate returns the starting page id of a contiguous list of pages of a given size.
-// If a contiguous block cannot be found then 0 is returned.
-func (f *freelist) allocate(n int) pgid {
- if len(f.ids) == 0 {
- return 0
- }
-
- var initial, previd pgid
- for i, id := range f.ids {
- if id <= 1 {
- panic(fmt.Sprintf("invalid page allocation: %d", id))
- }
-
- // Reset initial page if this is not contiguous.
- if previd == 0 || id-previd != 1 {
- initial = id
- }
-
- // If we found a contiguous block then remove it and return it.
- if (id-initial)+1 == pgid(n) {
- // If we're allocating off the beginning then take the fast path
- // and just adjust the existing slice. This will use extra memory
- // temporarily but the append() in free() will realloc the slice
- // as is necessary.
- if (i + 1) == n {
- f.ids = f.ids[i+1:]
- } else {
- copy(f.ids[i-n+1:], f.ids[i+1:])
- f.ids = f.ids[:len(f.ids)-n]
- }
-
- // Remove from the free cache.
- for i := pgid(0); i < pgid(n); i++ {
- delete(f.cache, initial+i)
- }
-
- return initial
- }
-
- previd = id
- }
- return 0
-}
-
-// free releases a page and its overflow for a given transaction id.
-// If the page is already free then a panic will occur.
-func (f *freelist) free(txid txid, p *page) {
- if p.id <= 1 {
- panic(fmt.Sprintf("cannot free page 0 or 1: %d", p.id))
- }
-
- // Free page and all its overflow pages.
- var ids = f.pending[txid]
- for id := p.id; id <= p.id+pgid(p.overflow); id++ {
- // Verify that page is not already free.
- if f.cache[id] {
- panic(fmt.Sprintf("page %d already freed", id))
- }
-
- // Add to the freelist and cache.
- ids = append(ids, id)
- f.cache[id] = true
- }
- f.pending[txid] = ids
-}
-
-// release moves all page ids for a transaction id (or older) to the freelist.
-func (f *freelist) release(txid txid) {
- m := make(pgids, 0)
- for tid, ids := range f.pending {
- if tid <= txid {
- // Move transaction's pending pages to the available freelist.
- // Don't remove from the cache since the page is still free.
- m = append(m, ids...)
- delete(f.pending, tid)
- }
- }
- sort.Sort(m)
- f.ids = pgids(f.ids).merge(m)
-}
-
-// rollback removes the pages from a given pending tx.
-func (f *freelist) rollback(txid txid) {
- // Remove page ids from cache.
- for _, id := range f.pending[txid] {
- delete(f.cache, id)
- }
-
- // Remove pages from pending list.
- delete(f.pending, txid)
-}
-
-// freed returns whether a given page is in the free list.
-func (f *freelist) freed(pgid pgid) bool {
- return f.cache[pgid]
-}
-
-// read initializes the freelist from a freelist page.
-func (f *freelist) read(p *page) {
- // If the page.count is at the max uint16 value (64k) then it's considered
- // an overflow and the size of the freelist is stored as the first element.
- idx, count := 0, int(p.count)
- if count == 0xFFFF {
- idx = 1
- count = int(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[0])
- }
-
- // Copy the list of page ids from the freelist.
- if count == 0 {
- f.ids = nil
- } else {
- ids := ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[idx:count]
- f.ids = make([]pgid, len(ids))
- copy(f.ids, ids)
-
- // Make sure they're sorted.
- sort.Sort(pgids(f.ids))
- }
-
- // Rebuild the page cache.
- f.reindex()
-}
-
-// write writes the page ids onto a freelist page. All free and pending ids are
-// saved to disk since in the event of a program crash, all pending ids will
-// become free.
-func (f *freelist) write(p *page) error {
- // Combine the old free pgids and pgids waiting on an open transaction.
- ids := f.all()
-
- // Update the header flag.
- p.flags |= freelistPageFlag
-
- // The page.count can only hold up to 64k elements so if we overflow that
- // number then we handle it by putting the size in the first element.
- if len(ids) == 0 {
- p.count = uint16(len(ids))
- } else if len(ids) < 0xFFFF {
- p.count = uint16(len(ids))
- copy(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[:], ids)
- } else {
- p.count = 0xFFFF
- ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[0] = pgid(len(ids))
- copy(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[1:], ids)
- }
-
- return nil
-}
-
-// reload reads the freelist from a page and filters out pending items.
-func (f *freelist) reload(p *page) {
- f.read(p)
-
- // Build a cache of only pending pages.
- pcache := make(map[pgid]bool)
- for _, pendingIDs := range f.pending {
- for _, pendingID := range pendingIDs {
- pcache[pendingID] = true
- }
- }
-
- // Check each page in the freelist and build a new available freelist
- // with any pages not in the pending lists.
- var a []pgid
- for _, id := range f.ids {
- if !pcache[id] {
- a = append(a, id)
- }
- }
- f.ids = a
-
- // Once the available list is rebuilt then rebuild the free cache so that
- // it includes the available and pending free pages.
- f.reindex()
-}
-
-// reindex rebuilds the free cache based on available and pending free lists.
-func (f *freelist) reindex() {
- f.cache = make(map[pgid]bool, len(f.ids))
- for _, id := range f.ids {
- f.cache[id] = true
- }
- for _, pendingIDs := range f.pending {
- for _, pendingID := range pendingIDs {
- f.cache[pendingID] = true
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist_test.go
deleted file mode 100644
index 4e9b3a8..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist_test.go
+++ /dev/null
@@ -1,158 +0,0 @@
-package bolt
-
-import (
- "math/rand"
- "reflect"
- "sort"
- "testing"
- "unsafe"
-)
-
-// Ensure that a page is added to a transaction's freelist.
-func TestFreelist_free(t *testing.T) {
- f := newFreelist()
- f.free(100, &page{id: 12})
- if !reflect.DeepEqual([]pgid{12}, f.pending[100]) {
- t.Fatalf("exp=%v; got=%v", []pgid{12}, f.pending[100])
- }
-}
-
-// Ensure that a page and its overflow is added to a transaction's freelist.
-func TestFreelist_free_overflow(t *testing.T) {
- f := newFreelist()
- f.free(100, &page{id: 12, overflow: 3})
- if exp := []pgid{12, 13, 14, 15}; !reflect.DeepEqual(exp, f.pending[100]) {
- t.Fatalf("exp=%v; got=%v", exp, f.pending[100])
- }
-}
-
-// Ensure that a transaction's free pages can be released.
-func TestFreelist_release(t *testing.T) {
- f := newFreelist()
- f.free(100, &page{id: 12, overflow: 1})
- f.free(100, &page{id: 9})
- f.free(102, &page{id: 39})
- f.release(100)
- f.release(101)
- if exp := []pgid{9, 12, 13}; !reflect.DeepEqual(exp, f.ids) {
- t.Fatalf("exp=%v; got=%v", exp, f.ids)
- }
-
- f.release(102)
- if exp := []pgid{9, 12, 13, 39}; !reflect.DeepEqual(exp, f.ids) {
- t.Fatalf("exp=%v; got=%v", exp, f.ids)
- }
-}
-
-// Ensure that a freelist can find contiguous blocks of pages.
-func TestFreelist_allocate(t *testing.T) {
- f := &freelist{ids: []pgid{3, 4, 5, 6, 7, 9, 12, 13, 18}}
- if id := int(f.allocate(3)); id != 3 {
- t.Fatalf("exp=3; got=%v", id)
- }
- if id := int(f.allocate(1)); id != 6 {
- t.Fatalf("exp=6; got=%v", id)
- }
- if id := int(f.allocate(3)); id != 0 {
- t.Fatalf("exp=0; got=%v", id)
- }
- if id := int(f.allocate(2)); id != 12 {
- t.Fatalf("exp=12; got=%v", id)
- }
- if id := int(f.allocate(1)); id != 7 {
- t.Fatalf("exp=7; got=%v", id)
- }
- if id := int(f.allocate(0)); id != 0 {
- t.Fatalf("exp=0; got=%v", id)
- }
- if id := int(f.allocate(0)); id != 0 {
- t.Fatalf("exp=0; got=%v", id)
- }
- if exp := []pgid{9, 18}; !reflect.DeepEqual(exp, f.ids) {
- t.Fatalf("exp=%v; got=%v", exp, f.ids)
- }
-
- if id := int(f.allocate(1)); id != 9 {
- t.Fatalf("exp=9; got=%v", id)
- }
- if id := int(f.allocate(1)); id != 18 {
- t.Fatalf("exp=18; got=%v", id)
- }
- if id := int(f.allocate(1)); id != 0 {
- t.Fatalf("exp=0; got=%v", id)
- }
- if exp := []pgid{}; !reflect.DeepEqual(exp, f.ids) {
- t.Fatalf("exp=%v; got=%v", exp, f.ids)
- }
-}
-
-// Ensure that a freelist can deserialize from a freelist page.
-func TestFreelist_read(t *testing.T) {
- // Create a page.
- var buf [4096]byte
- page := (*page)(unsafe.Pointer(&buf[0]))
- page.flags = freelistPageFlag
- page.count = 2
-
- // Insert 2 page ids.
- ids := (*[3]pgid)(unsafe.Pointer(&page.ptr))
- ids[0] = 23
- ids[1] = 50
-
- // Deserialize page into a freelist.
- f := newFreelist()
- f.read(page)
-
- // Ensure that there are two page ids in the freelist.
- if exp := []pgid{23, 50}; !reflect.DeepEqual(exp, f.ids) {
- t.Fatalf("exp=%v; got=%v", exp, f.ids)
- }
-}
-
-// Ensure that a freelist can serialize into a freelist page.
-func TestFreelist_write(t *testing.T) {
- // Create a freelist and write it to a page.
- var buf [4096]byte
- f := &freelist{ids: []pgid{12, 39}, pending: make(map[txid][]pgid)}
- f.pending[100] = []pgid{28, 11}
- f.pending[101] = []pgid{3}
- p := (*page)(unsafe.Pointer(&buf[0]))
- if err := f.write(p); err != nil {
- t.Fatal(err)
- }
-
- // Read the page back out.
- f2 := newFreelist()
- f2.read(p)
-
- // Ensure that the freelist is correct.
- // All pages should be present and in reverse order.
- if exp := []pgid{3, 11, 12, 28, 39}; !reflect.DeepEqual(exp, f2.ids) {
- t.Fatalf("exp=%v; got=%v", exp, f2.ids)
- }
-}
-
-func Benchmark_FreelistRelease10K(b *testing.B) { benchmark_FreelistRelease(b, 10000) }
-func Benchmark_FreelistRelease100K(b *testing.B) { benchmark_FreelistRelease(b, 100000) }
-func Benchmark_FreelistRelease1000K(b *testing.B) { benchmark_FreelistRelease(b, 1000000) }
-func Benchmark_FreelistRelease10000K(b *testing.B) { benchmark_FreelistRelease(b, 10000000) }
-
-func benchmark_FreelistRelease(b *testing.B, size int) {
- ids := randomPgids(size)
- pending := randomPgids(len(ids) / 400)
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- f := &freelist{ids: ids, pending: map[txid][]pgid{1: pending}}
- f.release(1)
- }
-}
-
-func randomPgids(n int) []pgid {
- rand.Seed(42)
- pgids := make(pgids, n)
- for i := range pgids {
- pgids[i] = pgid(rand.Int63())
- }
- sort.Sort(pgids)
- return pgids
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node.go
deleted file mode 100644
index 159318b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node.go
+++ /dev/null
@@ -1,604 +0,0 @@
-package bolt
-
-import (
- "bytes"
- "fmt"
- "sort"
- "unsafe"
-)
-
-// node represents an in-memory, deserialized page.
-type node struct {
- bucket *Bucket
- isLeaf bool
- unbalanced bool
- spilled bool
- key []byte
- pgid pgid
- parent *node
- children nodes
- inodes inodes
-}
-
-// root returns the top-level node this node is attached to.
-func (n *node) root() *node {
- if n.parent == nil {
- return n
- }
- return n.parent.root()
-}
-
-// minKeys returns the minimum number of inodes this node should have.
-func (n *node) minKeys() int {
- if n.isLeaf {
- return 1
- }
- return 2
-}
-
-// size returns the size of the node after serialization.
-func (n *node) size() int {
- sz, elsz := pageHeaderSize, n.pageElementSize()
- for i := 0; i < len(n.inodes); i++ {
- item := &n.inodes[i]
- sz += elsz + len(item.key) + len(item.value)
- }
- return sz
-}
-
-// sizeLessThan returns true if the node is less than a given size.
-// This is an optimization to avoid calculating a large node when we only need
-// to know if it fits inside a certain page size.
-func (n *node) sizeLessThan(v int) bool {
- sz, elsz := pageHeaderSize, n.pageElementSize()
- for i := 0; i < len(n.inodes); i++ {
- item := &n.inodes[i]
- sz += elsz + len(item.key) + len(item.value)
- if sz >= v {
- return false
- }
- }
- return true
-}
-
-// pageElementSize returns the size of each page element based on the type of node.
-func (n *node) pageElementSize() int {
- if n.isLeaf {
- return leafPageElementSize
- }
- return branchPageElementSize
-}
-
-// childAt returns the child node at a given index.
-func (n *node) childAt(index int) *node {
- if n.isLeaf {
- panic(fmt.Sprintf("invalid childAt(%d) on a leaf node", index))
- }
- return n.bucket.node(n.inodes[index].pgid, n)
-}
-
-// childIndex returns the index of a given child node.
-func (n *node) childIndex(child *node) int {
- index := sort.Search(len(n.inodes), func(i int) bool { return bytes.Compare(n.inodes[i].key, child.key) != -1 })
- return index
-}
-
-// numChildren returns the number of children.
-func (n *node) numChildren() int {
- return len(n.inodes)
-}
-
-// nextSibling returns the next node with the same parent.
-func (n *node) nextSibling() *node {
- if n.parent == nil {
- return nil
- }
- index := n.parent.childIndex(n)
- if index >= n.parent.numChildren()-1 {
- return nil
- }
- return n.parent.childAt(index + 1)
-}
-
-// prevSibling returns the previous node with the same parent.
-func (n *node) prevSibling() *node {
- if n.parent == nil {
- return nil
- }
- index := n.parent.childIndex(n)
- if index == 0 {
- return nil
- }
- return n.parent.childAt(index - 1)
-}
-
-// put inserts a key/value.
-func (n *node) put(oldKey, newKey, value []byte, pgid pgid, flags uint32) {
- if pgid >= n.bucket.tx.meta.pgid {
- panic(fmt.Sprintf("pgid (%d) above high water mark (%d)", pgid, n.bucket.tx.meta.pgid))
- } else if len(oldKey) <= 0 {
- panic("put: zero-length old key")
- } else if len(newKey) <= 0 {
- panic("put: zero-length new key")
- }
-
- // Find insertion index.
- index := sort.Search(len(n.inodes), func(i int) bool { return bytes.Compare(n.inodes[i].key, oldKey) != -1 })
-
- // Add capacity and shift nodes if we don't have an exact match and need to insert.
- exact := (len(n.inodes) > 0 && index < len(n.inodes) && bytes.Equal(n.inodes[index].key, oldKey))
- if !exact {
- n.inodes = append(n.inodes, inode{})
- copy(n.inodes[index+1:], n.inodes[index:])
- }
-
- inode := &n.inodes[index]
- inode.flags = flags
- inode.key = newKey
- inode.value = value
- inode.pgid = pgid
- _assert(len(inode.key) > 0, "put: zero-length inode key")
-}
-
-// del removes a key from the node.
-func (n *node) del(key []byte) {
- // Find index of key.
- index := sort.Search(len(n.inodes), func(i int) bool { return bytes.Compare(n.inodes[i].key, key) != -1 })
-
- // Exit if the key isn't found.
- if index >= len(n.inodes) || !bytes.Equal(n.inodes[index].key, key) {
- return
- }
-
- // Delete inode from the node.
- n.inodes = append(n.inodes[:index], n.inodes[index+1:]...)
-
- // Mark the node as needing rebalancing.
- n.unbalanced = true
-}
-
-// read initializes the node from a page.
-func (n *node) read(p *page) {
- n.pgid = p.id
- n.isLeaf = ((p.flags & leafPageFlag) != 0)
- n.inodes = make(inodes, int(p.count))
-
- for i := 0; i < int(p.count); i++ {
- inode := &n.inodes[i]
- if n.isLeaf {
- elem := p.leafPageElement(uint16(i))
- inode.flags = elem.flags
- inode.key = elem.key()
- inode.value = elem.value()
- } else {
- elem := p.branchPageElement(uint16(i))
- inode.pgid = elem.pgid
- inode.key = elem.key()
- }
- _assert(len(inode.key) > 0, "read: zero-length inode key")
- }
-
- // Save first key so we can find the node in the parent when we spill.
- if len(n.inodes) > 0 {
- n.key = n.inodes[0].key
- _assert(len(n.key) > 0, "read: zero-length node key")
- } else {
- n.key = nil
- }
-}
-
-// write writes the items onto one or more pages.
-func (n *node) write(p *page) {
- // Initialize page.
- if n.isLeaf {
- p.flags |= leafPageFlag
- } else {
- p.flags |= branchPageFlag
- }
-
- if len(n.inodes) >= 0xFFFF {
- panic(fmt.Sprintf("inode overflow: %d (pgid=%d)", len(n.inodes), p.id))
- }
- p.count = uint16(len(n.inodes))
-
- // Stop here if there are no items to write.
- if p.count == 0 {
- return
- }
-
- // Loop over each item and write it to the page.
- b := (*[maxAllocSize]byte)(unsafe.Pointer(&p.ptr))[n.pageElementSize()*len(n.inodes):]
- for i, item := range n.inodes {
- _assert(len(item.key) > 0, "write: zero-length inode key")
-
- // Write the page element.
- if n.isLeaf {
- elem := p.leafPageElement(uint16(i))
- elem.pos = uint32(uintptr(unsafe.Pointer(&b[0])) - uintptr(unsafe.Pointer(elem)))
- elem.flags = item.flags
- elem.ksize = uint32(len(item.key))
- elem.vsize = uint32(len(item.value))
- } else {
- elem := p.branchPageElement(uint16(i))
- elem.pos = uint32(uintptr(unsafe.Pointer(&b[0])) - uintptr(unsafe.Pointer(elem)))
- elem.ksize = uint32(len(item.key))
- elem.pgid = item.pgid
- _assert(elem.pgid != p.id, "write: circular dependency occurred")
- }
-
- // If the length of key+value is larger than the max allocation size
- // then we need to reallocate the byte array pointer.
- //
- // See: https://github.com/boltdb/bolt/pull/335
- klen, vlen := len(item.key), len(item.value)
- if len(b) < klen+vlen {
- b = (*[maxAllocSize]byte)(unsafe.Pointer(&b[0]))[:]
- }
-
- // Write data for the element to the end of the page.
- copy(b[0:], item.key)
- b = b[klen:]
- copy(b[0:], item.value)
- b = b[vlen:]
- }
-
- // DEBUG ONLY: n.dump()
-}
-
-// split breaks up a node into multiple smaller nodes, if appropriate.
-// This should only be called from the spill() function.
-func (n *node) split(pageSize int) []*node {
- var nodes []*node
-
- node := n
- for {
- // Split node into two.
- a, b := node.splitTwo(pageSize)
- nodes = append(nodes, a)
-
- // If we can't split then exit the loop.
- if b == nil {
- break
- }
-
- // Set node to b so it gets split on the next iteration.
- node = b
- }
-
- return nodes
-}
-
-// splitTwo breaks up a node into two smaller nodes, if appropriate.
-// This should only be called from the split() function.
-func (n *node) splitTwo(pageSize int) (*node, *node) {
- // Ignore the split if the page doesn't have at least enough nodes for
- // two pages or if the nodes can fit in a single page.
- if len(n.inodes) <= (minKeysPerPage*2) || n.sizeLessThan(pageSize) {
- return n, nil
- }
-
- // Determine the threshold before starting a new node.
- var fillPercent = n.bucket.FillPercent
- if fillPercent < minFillPercent {
- fillPercent = minFillPercent
- } else if fillPercent > maxFillPercent {
- fillPercent = maxFillPercent
- }
- threshold := int(float64(pageSize) * fillPercent)
-
- // Determine split position and sizes of the two pages.
- splitIndex, _ := n.splitIndex(threshold)
-
- // Split node into two separate nodes.
- // If there's no parent then we'll need to create one.
- if n.parent == nil {
- n.parent = &node{bucket: n.bucket, children: []*node{n}}
- }
-
- // Create a new node and add it to the parent.
- next := &node{bucket: n.bucket, isLeaf: n.isLeaf, parent: n.parent}
- n.parent.children = append(n.parent.children, next)
-
- // Split inodes across two nodes.
- next.inodes = n.inodes[splitIndex:]
- n.inodes = n.inodes[:splitIndex]
-
- // Update the statistics.
- n.bucket.tx.stats.Split++
-
- return n, next
-}
-
-// splitIndex finds the position where a page will fill a given threshold.
-// It returns the index as well as the size of the first page.
-// This is only be called from split().
-func (n *node) splitIndex(threshold int) (index, sz int) {
- sz = pageHeaderSize
-
- // Loop until we only have the minimum number of keys required for the second page.
- for i := 0; i < len(n.inodes)-minKeysPerPage; i++ {
- index = i
- inode := n.inodes[i]
- elsize := n.pageElementSize() + len(inode.key) + len(inode.value)
-
- // If we have at least the minimum number of keys and adding another
- // node would put us over the threshold then exit and return.
- if i >= minKeysPerPage && sz+elsize > threshold {
- break
- }
-
- // Add the element size to the total size.
- sz += elsize
- }
-
- return
-}
-
-// spill writes the nodes to dirty pages and splits nodes as it goes.
-// Returns an error if dirty pages cannot be allocated.
-func (n *node) spill() error {
- var tx = n.bucket.tx
- if n.spilled {
- return nil
- }
-
- // Spill child nodes first. Child nodes can materialize sibling nodes in
- // the case of split-merge so we cannot use a range loop. We have to check
- // the children size on every loop iteration.
- sort.Sort(n.children)
- for i := 0; i < len(n.children); i++ {
- if err := n.children[i].spill(); err != nil {
- return err
- }
- }
-
- // We no longer need the child list because it's only used for spill tracking.
- n.children = nil
-
- // Split nodes into appropriate sizes. The first node will always be n.
- var nodes = n.split(tx.db.pageSize)
- for _, node := range nodes {
- // Add node's page to the freelist if it's not new.
- if node.pgid > 0 {
- tx.db.freelist.free(tx.meta.txid, tx.page(node.pgid))
- node.pgid = 0
- }
-
- // Allocate contiguous space for the node.
- p, err := tx.allocate((node.size() / tx.db.pageSize) + 1)
- if err != nil {
- return err
- }
-
- // Write the node.
- if p.id >= tx.meta.pgid {
- panic(fmt.Sprintf("pgid (%d) above high water mark (%d)", p.id, tx.meta.pgid))
- }
- node.pgid = p.id
- node.write(p)
- node.spilled = true
-
- // Insert into parent inodes.
- if node.parent != nil {
- var key = node.key
- if key == nil {
- key = node.inodes[0].key
- }
-
- node.parent.put(key, node.inodes[0].key, nil, node.pgid, 0)
- node.key = node.inodes[0].key
- _assert(len(node.key) > 0, "spill: zero-length node key")
- }
-
- // Update the statistics.
- tx.stats.Spill++
- }
-
- // If the root node split and created a new root then we need to spill that
- // as well. We'll clear out the children to make sure it doesn't try to respill.
- if n.parent != nil && n.parent.pgid == 0 {
- n.children = nil
- return n.parent.spill()
- }
-
- return nil
-}
-
-// rebalance attempts to combine the node with sibling nodes if the node fill
-// size is below a threshold or if there are not enough keys.
-func (n *node) rebalance() {
- if !n.unbalanced {
- return
- }
- n.unbalanced = false
-
- // Update statistics.
- n.bucket.tx.stats.Rebalance++
-
- // Ignore if node is above threshold (25%) and has enough keys.
- var threshold = n.bucket.tx.db.pageSize / 4
- if n.size() > threshold && len(n.inodes) > n.minKeys() {
- return
- }
-
- // Root node has special handling.
- if n.parent == nil {
- // If root node is a branch and only has one node then collapse it.
- if !n.isLeaf && len(n.inodes) == 1 {
- // Move root's child up.
- child := n.bucket.node(n.inodes[0].pgid, n)
- n.isLeaf = child.isLeaf
- n.inodes = child.inodes[:]
- n.children = child.children
-
- // Reparent all child nodes being moved.
- for _, inode := range n.inodes {
- if child, ok := n.bucket.nodes[inode.pgid]; ok {
- child.parent = n
- }
- }
-
- // Remove old child.
- child.parent = nil
- delete(n.bucket.nodes, child.pgid)
- child.free()
- }
-
- return
- }
-
- // If node has no keys then just remove it.
- if n.numChildren() == 0 {
- n.parent.del(n.key)
- n.parent.removeChild(n)
- delete(n.bucket.nodes, n.pgid)
- n.free()
- n.parent.rebalance()
- return
- }
-
- _assert(n.parent.numChildren() > 1, "parent must have at least 2 children")
-
- // Destination node is right sibling if idx == 0, otherwise left sibling.
- var target *node
- var useNextSibling = (n.parent.childIndex(n) == 0)
- if useNextSibling {
- target = n.nextSibling()
- } else {
- target = n.prevSibling()
- }
-
- // If both this node and the target node are too small then merge them.
- if useNextSibling {
- // Reparent all child nodes being moved.
- for _, inode := range target.inodes {
- if child, ok := n.bucket.nodes[inode.pgid]; ok {
- child.parent.removeChild(child)
- child.parent = n
- child.parent.children = append(child.parent.children, child)
- }
- }
-
- // Copy over inodes from target and remove target.
- n.inodes = append(n.inodes, target.inodes...)
- n.parent.del(target.key)
- n.parent.removeChild(target)
- delete(n.bucket.nodes, target.pgid)
- target.free()
- } else {
- // Reparent all child nodes being moved.
- for _, inode := range n.inodes {
- if child, ok := n.bucket.nodes[inode.pgid]; ok {
- child.parent.removeChild(child)
- child.parent = target
- child.parent.children = append(child.parent.children, child)
- }
- }
-
- // Copy over inodes to target and remove node.
- target.inodes = append(target.inodes, n.inodes...)
- n.parent.del(n.key)
- n.parent.removeChild(n)
- delete(n.bucket.nodes, n.pgid)
- n.free()
- }
-
- // Either this node or the target node was deleted from the parent so rebalance it.
- n.parent.rebalance()
-}
-
-// removes a node from the list of in-memory children.
-// This does not affect the inodes.
-func (n *node) removeChild(target *node) {
- for i, child := range n.children {
- if child == target {
- n.children = append(n.children[:i], n.children[i+1:]...)
- return
- }
- }
-}
-
-// dereference causes the node to copy all its inode key/value references to heap memory.
-// This is required when the mmap is reallocated so inodes are not pointing to stale data.
-func (n *node) dereference() {
- if n.key != nil {
- key := make([]byte, len(n.key))
- copy(key, n.key)
- n.key = key
- _assert(n.pgid == 0 || len(n.key) > 0, "dereference: zero-length node key on existing node")
- }
-
- for i := range n.inodes {
- inode := &n.inodes[i]
-
- key := make([]byte, len(inode.key))
- copy(key, inode.key)
- inode.key = key
- _assert(len(inode.key) > 0, "dereference: zero-length inode key")
-
- value := make([]byte, len(inode.value))
- copy(value, inode.value)
- inode.value = value
- }
-
- // Recursively dereference children.
- for _, child := range n.children {
- child.dereference()
- }
-
- // Update statistics.
- n.bucket.tx.stats.NodeDeref++
-}
-
-// free adds the node's underlying page to the freelist.
-func (n *node) free() {
- if n.pgid != 0 {
- n.bucket.tx.db.freelist.free(n.bucket.tx.meta.txid, n.bucket.tx.page(n.pgid))
- n.pgid = 0
- }
-}
-
-// dump writes the contents of the node to STDERR for debugging purposes.
-/*
-func (n *node) dump() {
- // Write node header.
- var typ = "branch"
- if n.isLeaf {
- typ = "leaf"
- }
- warnf("[NODE %d {type=%s count=%d}]", n.pgid, typ, len(n.inodes))
-
- // Write out abbreviated version of each item.
- for _, item := range n.inodes {
- if n.isLeaf {
- if item.flags&bucketLeafFlag != 0 {
- bucket := (*bucket)(unsafe.Pointer(&item.value[0]))
- warnf("+L %08x -> (bucket root=%d)", trunc(item.key, 4), bucket.root)
- } else {
- warnf("+L %08x -> %08x", trunc(item.key, 4), trunc(item.value, 4))
- }
- } else {
- warnf("+B %08x -> pgid=%d", trunc(item.key, 4), item.pgid)
- }
- }
- warn("")
-}
-*/
-
-type nodes []*node
-
-func (s nodes) Len() int { return len(s) }
-func (s nodes) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-func (s nodes) Less(i, j int) bool { return bytes.Compare(s[i].inodes[0].key, s[j].inodes[0].key) == -1 }
-
-// inode represents an internal node inside of a node.
-// It can be used to point to elements in a page or point
-// to an element which hasn't been added to a page yet.
-type inode struct {
- flags uint32
- pgid pgid
- key []byte
- value []byte
-}
-
-type inodes []inode
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node_test.go
deleted file mode 100644
index fa5d10f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node_test.go
+++ /dev/null
@@ -1,156 +0,0 @@
-package bolt
-
-import (
- "testing"
- "unsafe"
-)
-
-// Ensure that a node can insert a key/value.
-func TestNode_put(t *testing.T) {
- n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{meta: &meta{pgid: 1}}}}
- n.put([]byte("baz"), []byte("baz"), []byte("2"), 0, 0)
- n.put([]byte("foo"), []byte("foo"), []byte("0"), 0, 0)
- n.put([]byte("bar"), []byte("bar"), []byte("1"), 0, 0)
- n.put([]byte("foo"), []byte("foo"), []byte("3"), 0, leafPageFlag)
-
- if len(n.inodes) != 3 {
- t.Fatalf("exp=3; got=%d", len(n.inodes))
- }
- if k, v := n.inodes[0].key, n.inodes[0].value; string(k) != "bar" || string(v) != "1" {
- t.Fatalf("exp=<bar,1>; got=<%s,%s>", k, v)
- }
- if k, v := n.inodes[1].key, n.inodes[1].value; string(k) != "baz" || string(v) != "2" {
- t.Fatalf("exp=<baz,2>; got=<%s,%s>", k, v)
- }
- if k, v := n.inodes[2].key, n.inodes[2].value; string(k) != "foo" || string(v) != "3" {
- t.Fatalf("exp=<foo,3>; got=<%s,%s>", k, v)
- }
- if n.inodes[2].flags != uint32(leafPageFlag) {
- t.Fatalf("not a leaf: %d", n.inodes[2].flags)
- }
-}
-
-// Ensure that a node can deserialize from a leaf page.
-func TestNode_read_LeafPage(t *testing.T) {
- // Create a page.
- var buf [4096]byte
- page := (*page)(unsafe.Pointer(&buf[0]))
- page.flags = leafPageFlag
- page.count = 2
-
- // Insert 2 elements at the beginning. sizeof(leafPageElement) == 16
- nodes := (*[3]leafPageElement)(unsafe.Pointer(&page.ptr))
- nodes[0] = leafPageElement{flags: 0, pos: 32, ksize: 3, vsize: 4} // pos = sizeof(leafPageElement) * 2
- nodes[1] = leafPageElement{flags: 0, pos: 23, ksize: 10, vsize: 3} // pos = sizeof(leafPageElement) + 3 + 4
-
- // Write data for the nodes at the end.
- data := (*[4096]byte)(unsafe.Pointer(&nodes[2]))
- copy(data[:], []byte("barfooz"))
- copy(data[7:], []byte("helloworldbye"))
-
- // Deserialize page into a leaf.
- n := &node{}
- n.read(page)
-
- // Check that there are two inodes with correct data.
- if !n.isLeaf {
- t.Fatal("expected leaf")
- }
- if len(n.inodes) != 2 {
- t.Fatalf("exp=2; got=%d", len(n.inodes))
- }
- if k, v := n.inodes[0].key, n.inodes[0].value; string(k) != "bar" || string(v) != "fooz" {
- t.Fatalf("exp=<bar,fooz>; got=<%s,%s>", k, v)
- }
- if k, v := n.inodes[1].key, n.inodes[1].value; string(k) != "helloworld" || string(v) != "bye" {
- t.Fatalf("exp=<helloworld,bye>; got=<%s,%s>", k, v)
- }
-}
-
-// Ensure that a node can serialize into a leaf page.
-func TestNode_write_LeafPage(t *testing.T) {
- // Create a node.
- n := &node{isLeaf: true, inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}}
- n.put([]byte("susy"), []byte("susy"), []byte("que"), 0, 0)
- n.put([]byte("ricki"), []byte("ricki"), []byte("lake"), 0, 0)
- n.put([]byte("john"), []byte("john"), []byte("johnson"), 0, 0)
-
- // Write it to a page.
- var buf [4096]byte
- p := (*page)(unsafe.Pointer(&buf[0]))
- n.write(p)
-
- // Read the page back in.
- n2 := &node{}
- n2.read(p)
-
- // Check that the two pages are the same.
- if len(n2.inodes) != 3 {
- t.Fatalf("exp=3; got=%d", len(n2.inodes))
- }
- if k, v := n2.inodes[0].key, n2.inodes[0].value; string(k) != "john" || string(v) != "johnson" {
- t.Fatalf("exp=<john,johnson>; got=<%s,%s>", k, v)
- }
- if k, v := n2.inodes[1].key, n2.inodes[1].value; string(k) != "ricki" || string(v) != "lake" {
- t.Fatalf("exp=<ricki,lake>; got=<%s,%s>", k, v)
- }
- if k, v := n2.inodes[2].key, n2.inodes[2].value; string(k) != "susy" || string(v) != "que" {
- t.Fatalf("exp=<susy,que>; got=<%s,%s>", k, v)
- }
-}
-
-// Ensure that a node can split into appropriate subgroups.
-func TestNode_split(t *testing.T) {
- // Create a node.
- n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}}
- n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0)
- n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0)
- n.put([]byte("00000003"), []byte("00000003"), []byte("0123456701234567"), 0, 0)
- n.put([]byte("00000004"), []byte("00000004"), []byte("0123456701234567"), 0, 0)
- n.put([]byte("00000005"), []byte("00000005"), []byte("0123456701234567"), 0, 0)
-
- // Split between 2 & 3.
- n.split(100)
-
- var parent = n.parent
- if len(parent.children) != 2 {
- t.Fatalf("exp=2; got=%d", len(parent.children))
- }
- if len(parent.children[0].inodes) != 2 {
- t.Fatalf("exp=2; got=%d", len(parent.children[0].inodes))
- }
- if len(parent.children[1].inodes) != 3 {
- t.Fatalf("exp=3; got=%d", len(parent.children[1].inodes))
- }
-}
-
-// Ensure that a page with the minimum number of inodes just returns a single node.
-func TestNode_split_MinKeys(t *testing.T) {
- // Create a node.
- n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}}
- n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0)
- n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0)
-
- // Split.
- n.split(20)
- if n.parent != nil {
- t.Fatalf("expected nil parent")
- }
-}
-
-// Ensure that a node that has keys that all fit on a page just returns one leaf.
-func TestNode_split_SinglePage(t *testing.T) {
- // Create a node.
- n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}}
- n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0)
- n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0)
- n.put([]byte("00000003"), []byte("00000003"), []byte("0123456701234567"), 0, 0)
- n.put([]byte("00000004"), []byte("00000004"), []byte("0123456701234567"), 0, 0)
- n.put([]byte("00000005"), []byte("00000005"), []byte("0123456701234567"), 0, 0)
-
- // Split.
- n.split(4096)
- if n.parent != nil {
- t.Fatalf("expected nil parent")
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page.go
deleted file mode 100644
index 7651a6b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page.go
+++ /dev/null
@@ -1,178 +0,0 @@
-package bolt
-
-import (
- "fmt"
- "os"
- "sort"
- "unsafe"
-)
-
-const pageHeaderSize = int(unsafe.Offsetof(((*page)(nil)).ptr))
-
-const minKeysPerPage = 2
-
-const branchPageElementSize = int(unsafe.Sizeof(branchPageElement{}))
-const leafPageElementSize = int(unsafe.Sizeof(leafPageElement{}))
-
-const (
- branchPageFlag = 0x01
- leafPageFlag = 0x02
- metaPageFlag = 0x04
- freelistPageFlag = 0x10
-)
-
-const (
- bucketLeafFlag = 0x01
-)
-
-type pgid uint64
-
-type page struct {
- id pgid
- flags uint16
- count uint16
- overflow uint32
- ptr uintptr
-}
-
-// typ returns a human readable page type string used for debugging.
-func (p *page) typ() string {
- if (p.flags & branchPageFlag) != 0 {
- return "branch"
- } else if (p.flags & leafPageFlag) != 0 {
- return "leaf"
- } else if (p.flags & metaPageFlag) != 0 {
- return "meta"
- } else if (p.flags & freelistPageFlag) != 0 {
- return "freelist"
- }
- return fmt.Sprintf("unknown<%02x>", p.flags)
-}
-
-// meta returns a pointer to the metadata section of the page.
-func (p *page) meta() *meta {
- return (*meta)(unsafe.Pointer(&p.ptr))
-}
-
-// leafPageElement retrieves the leaf node by index
-func (p *page) leafPageElement(index uint16) *leafPageElement {
- n := &((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[index]
- return n
-}
-
-// leafPageElements retrieves a list of leaf nodes.
-func (p *page) leafPageElements() []leafPageElement {
- if p.count == 0 {
- return nil
- }
- return ((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[:]
-}
-
-// branchPageElement retrieves the branch node by index
-func (p *page) branchPageElement(index uint16) *branchPageElement {
- return &((*[0x7FFFFFF]branchPageElement)(unsafe.Pointer(&p.ptr)))[index]
-}
-
-// branchPageElements retrieves a list of branch nodes.
-func (p *page) branchPageElements() []branchPageElement {
- if p.count == 0 {
- return nil
- }
- return ((*[0x7FFFFFF]branchPageElement)(unsafe.Pointer(&p.ptr)))[:]
-}
-
-// dump writes n bytes of the page to STDERR as hex output.
-func (p *page) hexdump(n int) {
- buf := (*[maxAllocSize]byte)(unsafe.Pointer(p))[:n]
- fmt.Fprintf(os.Stderr, "%x\n", buf)
-}
-
-type pages []*page
-
-func (s pages) Len() int { return len(s) }
-func (s pages) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-func (s pages) Less(i, j int) bool { return s[i].id < s[j].id }
-
-// branchPageElement represents a node on a branch page.
-type branchPageElement struct {
- pos uint32
- ksize uint32
- pgid pgid
-}
-
-// key returns a byte slice of the node key.
-func (n *branchPageElement) key() []byte {
- buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
- return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos]))[:n.ksize]
-}
-
-// leafPageElement represents a node on a leaf page.
-type leafPageElement struct {
- flags uint32
- pos uint32
- ksize uint32
- vsize uint32
-}
-
-// key returns a byte slice of the node key.
-func (n *leafPageElement) key() []byte {
- buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
- return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos]))[:n.ksize:n.ksize]
-}
-
-// value returns a byte slice of the node value.
-func (n *leafPageElement) value() []byte {
- buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
- return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos+n.ksize]))[:n.vsize:n.vsize]
-}
-
-// PageInfo represents human readable information about a page.
-type PageInfo struct {
- ID int
- Type string
- Count int
- OverflowCount int
-}
-
-type pgids []pgid
-
-func (s pgids) Len() int { return len(s) }
-func (s pgids) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-func (s pgids) Less(i, j int) bool { return s[i] < s[j] }
-
-// merge returns the sorted union of a and b.
-func (a pgids) merge(b pgids) pgids {
- // Return the opposite slice if one is nil.
- if len(a) == 0 {
- return b
- } else if len(b) == 0 {
- return a
- }
-
- // Create a list to hold all elements from both lists.
- merged := make(pgids, 0, len(a)+len(b))
-
- // Assign lead to the slice with a lower starting value, follow to the higher value.
- lead, follow := a, b
- if b[0] < a[0] {
- lead, follow = b, a
- }
-
- // Continue while there are elements in the lead.
- for len(lead) > 0 {
- // Merge largest prefix of lead that is ahead of follow[0].
- n := sort.Search(len(lead), func(i int) bool { return lead[i] > follow[0] })
- merged = append(merged, lead[:n]...)
- if n >= len(lead) {
- break
- }
-
- // Swap lead and follow.
- lead, follow = follow, lead[n:]
- }
-
- // Append what's left in follow.
- merged = append(merged, follow...)
-
- return merged
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page_test.go
deleted file mode 100644
index 59f4a30..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page_test.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package bolt
-
-import (
- "reflect"
- "sort"
- "testing"
- "testing/quick"
-)
-
-// Ensure that the page type can be returned in human readable format.
-func TestPage_typ(t *testing.T) {
- if typ := (&page{flags: branchPageFlag}).typ(); typ != "branch" {
- t.Fatalf("exp=branch; got=%v", typ)
- }
- if typ := (&page{flags: leafPageFlag}).typ(); typ != "leaf" {
- t.Fatalf("exp=leaf; got=%v", typ)
- }
- if typ := (&page{flags: metaPageFlag}).typ(); typ != "meta" {
- t.Fatalf("exp=meta; got=%v", typ)
- }
- if typ := (&page{flags: freelistPageFlag}).typ(); typ != "freelist" {
- t.Fatalf("exp=freelist; got=%v", typ)
- }
- if typ := (&page{flags: 20000}).typ(); typ != "unknown<4e20>" {
- t.Fatalf("exp=unknown<4e20>; got=%v", typ)
- }
-}
-
-// Ensure that the hexdump debugging function doesn't blow up.
-func TestPage_dump(t *testing.T) {
- (&page{id: 256}).hexdump(16)
-}
-
-func TestPgids_merge(t *testing.T) {
- a := pgids{4, 5, 6, 10, 11, 12, 13, 27}
- b := pgids{1, 3, 8, 9, 25, 30}
- c := a.merge(b)
- if !reflect.DeepEqual(c, pgids{1, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 25, 27, 30}) {
- t.Errorf("mismatch: %v", c)
- }
-
- a = pgids{4, 5, 6, 10, 11, 12, 13, 27, 35, 36}
- b = pgids{8, 9, 25, 30}
- c = a.merge(b)
- if !reflect.DeepEqual(c, pgids{4, 5, 6, 8, 9, 10, 11, 12, 13, 25, 27, 30, 35, 36}) {
- t.Errorf("mismatch: %v", c)
- }
-}
-
-func TestPgids_merge_quick(t *testing.T) {
- if err := quick.Check(func(a, b pgids) bool {
- // Sort incoming lists.
- sort.Sort(a)
- sort.Sort(b)
-
- // Merge the two lists together.
- got := a.merge(b)
-
- // The expected value should be the two lists combined and sorted.
- exp := append(a, b...)
- sort.Sort(exp)
-
- if !reflect.DeepEqual(exp, got) {
- t.Errorf("\nexp=%+v\ngot=%+v\n", exp, got)
- return false
- }
-
- return true
- }, nil); err != nil {
- t.Fatal(err)
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/quick_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/quick_test.go
deleted file mode 100644
index 4da5817..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/quick_test.go
+++ /dev/null
@@ -1,79 +0,0 @@
-package bolt_test
-
-import (
- "bytes"
- "flag"
- "fmt"
- "math/rand"
- "os"
- "reflect"
- "testing/quick"
- "time"
-)
-
-// testing/quick defaults to 5 iterations and a random seed.
-// You can override these settings from the command line:
-//
-// -quick.count The number of iterations to perform.
-// -quick.seed The seed to use for randomizing.
-// -quick.maxitems The maximum number of items to insert into a DB.
-// -quick.maxksize The maximum size of a key.
-// -quick.maxvsize The maximum size of a value.
-//
-
-var qcount, qseed, qmaxitems, qmaxksize, qmaxvsize int
-
-func init() {
- flag.IntVar(&qcount, "quick.count", 5, "")
- flag.IntVar(&qseed, "quick.seed", int(time.Now().UnixNano())%100000, "")
- flag.IntVar(&qmaxitems, "quick.maxitems", 1000, "")
- flag.IntVar(&qmaxksize, "quick.maxksize", 1024, "")
- flag.IntVar(&qmaxvsize, "quick.maxvsize", 1024, "")
- flag.Parse()
- fmt.Fprintln(os.Stderr, "seed:", qseed)
- fmt.Fprintf(os.Stderr, "quick settings: count=%v, items=%v, ksize=%v, vsize=%v\n", qcount, qmaxitems, qmaxksize, qmaxvsize)
-}
-
-func qconfig() *quick.Config {
- return &quick.Config{
- MaxCount: qcount,
- Rand: rand.New(rand.NewSource(int64(qseed))),
- }
-}
-
-type testdata []testdataitem
-
-func (t testdata) Len() int { return len(t) }
-func (t testdata) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
-func (t testdata) Less(i, j int) bool { return bytes.Compare(t[i].Key, t[j].Key) == -1 }
-
-func (t testdata) Generate(rand *rand.Rand, size int) reflect.Value {
- n := rand.Intn(qmaxitems-1) + 1
- items := make(testdata, n)
- for i := 0; i < n; i++ {
- item := &items[i]
- item.Key = randByteSlice(rand, 1, qmaxksize)
- item.Value = randByteSlice(rand, 0, qmaxvsize)
- }
- return reflect.ValueOf(items)
-}
-
-type revtestdata []testdataitem
-
-func (t revtestdata) Len() int { return len(t) }
-func (t revtestdata) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
-func (t revtestdata) Less(i, j int) bool { return bytes.Compare(t[i].Key, t[j].Key) == 1 }
-
-type testdataitem struct {
- Key []byte
- Value []byte
-}
-
-func randByteSlice(rand *rand.Rand, minSize, maxSize int) []byte {
- n := rand.Intn(maxSize-minSize) + minSize
- b := make([]byte, n)
- for i := 0; i < n; i++ {
- b[i] = byte(rand.Intn(255))
- }
- return b
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/simulation_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/simulation_test.go
deleted file mode 100644
index 3831016..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/simulation_test.go
+++ /dev/null
@@ -1,329 +0,0 @@
-package bolt_test
-
-import (
- "bytes"
- "fmt"
- "math/rand"
- "sync"
- "testing"
-
- "github.com/boltdb/bolt"
-)
-
-func TestSimulate_1op_1p(t *testing.T) { testSimulate(t, 1, 1) }
-func TestSimulate_10op_1p(t *testing.T) { testSimulate(t, 10, 1) }
-func TestSimulate_100op_1p(t *testing.T) { testSimulate(t, 100, 1) }
-func TestSimulate_1000op_1p(t *testing.T) { testSimulate(t, 1000, 1) }
-func TestSimulate_10000op_1p(t *testing.T) { testSimulate(t, 10000, 1) }
-
-func TestSimulate_10op_10p(t *testing.T) { testSimulate(t, 10, 10) }
-func TestSimulate_100op_10p(t *testing.T) { testSimulate(t, 100, 10) }
-func TestSimulate_1000op_10p(t *testing.T) { testSimulate(t, 1000, 10) }
-func TestSimulate_10000op_10p(t *testing.T) { testSimulate(t, 10000, 10) }
-
-func TestSimulate_100op_100p(t *testing.T) { testSimulate(t, 100, 100) }
-func TestSimulate_1000op_100p(t *testing.T) { testSimulate(t, 1000, 100) }
-func TestSimulate_10000op_100p(t *testing.T) { testSimulate(t, 10000, 100) }
-
-func TestSimulate_10000op_1000p(t *testing.T) { testSimulate(t, 10000, 1000) }
-
-// Randomly generate operations on a given database with multiple clients to ensure consistency and thread safety.
-func testSimulate(t *testing.T, threadCount, parallelism int) {
- if testing.Short() {
- t.Skip("skipping test in short mode.")
- }
-
- rand.Seed(int64(qseed))
-
- // A list of operations that readers and writers can perform.
- var readerHandlers = []simulateHandler{simulateGetHandler}
- var writerHandlers = []simulateHandler{simulateGetHandler, simulatePutHandler}
-
- var versions = make(map[int]*QuickDB)
- versions[1] = NewQuickDB()
-
- db := MustOpenDB()
- defer db.MustClose()
-
- var mutex sync.Mutex
-
- // Run n threads in parallel, each with their own operation.
- var wg sync.WaitGroup
- var threads = make(chan bool, parallelism)
- var i int
- for {
- threads <- true
- wg.Add(1)
- writable := ((rand.Int() % 100) < 20) // 20% writers
-
- // Choose an operation to execute.
- var handler simulateHandler
- if writable {
- handler = writerHandlers[rand.Intn(len(writerHandlers))]
- } else {
- handler = readerHandlers[rand.Intn(len(readerHandlers))]
- }
-
- // Execute a thread for the given operation.
- go func(writable bool, handler simulateHandler) {
- defer wg.Done()
-
- // Start transaction.
- tx, err := db.Begin(writable)
- if err != nil {
- t.Fatal("tx begin: ", err)
- }
-
- // Obtain current state of the dataset.
- mutex.Lock()
- var qdb = versions[tx.ID()]
- if writable {
- qdb = versions[tx.ID()-1].Copy()
- }
- mutex.Unlock()
-
- // Make sure we commit/rollback the tx at the end and update the state.
- if writable {
- defer func() {
- mutex.Lock()
- versions[tx.ID()] = qdb
- mutex.Unlock()
-
- if err := tx.Commit(); err != nil {
- t.Fatal(err)
- }
- }()
- } else {
- defer func() { _ = tx.Rollback() }()
- }
-
- // Ignore operation if we don't have data yet.
- if qdb == nil {
- return
- }
-
- // Execute handler.
- handler(tx, qdb)
-
- // Release a thread back to the scheduling loop.
- <-threads
- }(writable, handler)
-
- i++
- if i > threadCount {
- break
- }
- }
-
- // Wait until all threads are done.
- wg.Wait()
-}
-
-type simulateHandler func(tx *bolt.Tx, qdb *QuickDB)
-
-// Retrieves a key from the database and verifies that it is what is expected.
-func simulateGetHandler(tx *bolt.Tx, qdb *QuickDB) {
- // Randomly retrieve an existing exist.
- keys := qdb.Rand()
- if len(keys) == 0 {
- return
- }
-
- // Retrieve root bucket.
- b := tx.Bucket(keys[0])
- if b == nil {
- panic(fmt.Sprintf("bucket[0] expected: %08x\n", trunc(keys[0], 4)))
- }
-
- // Drill into nested buckets.
- for _, key := range keys[1 : len(keys)-1] {
- b = b.Bucket(key)
- if b == nil {
- panic(fmt.Sprintf("bucket[n] expected: %v -> %v\n", keys, key))
- }
- }
-
- // Verify key/value on the final bucket.
- expected := qdb.Get(keys)
- actual := b.Get(keys[len(keys)-1])
- if !bytes.Equal(actual, expected) {
- fmt.Println("=== EXPECTED ===")
- fmt.Println(expected)
- fmt.Println("=== ACTUAL ===")
- fmt.Println(actual)
- fmt.Println("=== END ===")
- panic("value mismatch")
- }
-}
-
-// Inserts a key into the database.
-func simulatePutHandler(tx *bolt.Tx, qdb *QuickDB) {
- var err error
- keys, value := randKeys(), randValue()
-
- // Retrieve root bucket.
- b := tx.Bucket(keys[0])
- if b == nil {
- b, err = tx.CreateBucket(keys[0])
- if err != nil {
- panic("create bucket: " + err.Error())
- }
- }
-
- // Create nested buckets, if necessary.
- for _, key := range keys[1 : len(keys)-1] {
- child := b.Bucket(key)
- if child != nil {
- b = child
- } else {
- b, err = b.CreateBucket(key)
- if err != nil {
- panic("create bucket: " + err.Error())
- }
- }
- }
-
- // Insert into database.
- if err := b.Put(keys[len(keys)-1], value); err != nil {
- panic("put: " + err.Error())
- }
-
- // Insert into in-memory database.
- qdb.Put(keys, value)
-}
-
-// QuickDB is an in-memory database that replicates the functionality of the
-// Bolt DB type except that it is entirely in-memory. It is meant for testing
-// that the Bolt database is consistent.
-type QuickDB struct {
- sync.RWMutex
- m map[string]interface{}
-}
-
-// NewQuickDB returns an instance of QuickDB.
-func NewQuickDB() *QuickDB {
- return &QuickDB{m: make(map[string]interface{})}
-}
-
-// Get retrieves the value at a key path.
-func (db *QuickDB) Get(keys [][]byte) []byte {
- db.RLock()
- defer db.RUnlock()
-
- m := db.m
- for _, key := range keys[:len(keys)-1] {
- value := m[string(key)]
- if value == nil {
- return nil
- }
- switch value := value.(type) {
- case map[string]interface{}:
- m = value
- case []byte:
- return nil
- }
- }
-
- // Only return if it's a simple value.
- if value, ok := m[string(keys[len(keys)-1])].([]byte); ok {
- return value
- }
- return nil
-}
-
-// Put inserts a value into a key path.
-func (db *QuickDB) Put(keys [][]byte, value []byte) {
- db.Lock()
- defer db.Unlock()
-
- // Build buckets all the way down the key path.
- m := db.m
- for _, key := range keys[:len(keys)-1] {
- if _, ok := m[string(key)].([]byte); ok {
- return // Keypath intersects with a simple value. Do nothing.
- }
-
- if m[string(key)] == nil {
- m[string(key)] = make(map[string]interface{})
- }
- m = m[string(key)].(map[string]interface{})
- }
-
- // Insert value into the last key.
- m[string(keys[len(keys)-1])] = value
-}
-
-// Rand returns a random key path that points to a simple value.
-func (db *QuickDB) Rand() [][]byte {
- db.RLock()
- defer db.RUnlock()
- if len(db.m) == 0 {
- return nil
- }
- var keys [][]byte
- db.rand(db.m, &keys)
- return keys
-}
-
-func (db *QuickDB) rand(m map[string]interface{}, keys *[][]byte) {
- i, index := 0, rand.Intn(len(m))
- for k, v := range m {
- if i == index {
- *keys = append(*keys, []byte(k))
- if v, ok := v.(map[string]interface{}); ok {
- db.rand(v, keys)
- }
- return
- }
- i++
- }
- panic("quickdb rand: out-of-range")
-}
-
-// Copy copies the entire database.
-func (db *QuickDB) Copy() *QuickDB {
- db.RLock()
- defer db.RUnlock()
- return &QuickDB{m: db.copy(db.m)}
-}
-
-func (db *QuickDB) copy(m map[string]interface{}) map[string]interface{} {
- clone := make(map[string]interface{}, len(m))
- for k, v := range m {
- switch v := v.(type) {
- case map[string]interface{}:
- clone[k] = db.copy(v)
- default:
- clone[k] = v
- }
- }
- return clone
-}
-
-func randKey() []byte {
- var min, max = 1, 1024
- n := rand.Intn(max-min) + min
- b := make([]byte, n)
- for i := 0; i < n; i++ {
- b[i] = byte(rand.Intn(255))
- }
- return b
-}
-
-func randKeys() [][]byte {
- var keys [][]byte
- var count = rand.Intn(2) + 2
- for i := 0; i < count; i++ {
- keys = append(keys, randKey())
- }
- return keys
-}
-
-func randValue() []byte {
- n := rand.Intn(8192)
- b := make([]byte, n)
- for i := 0; i < n; i++ {
- b[i] = byte(rand.Intn(255))
- }
- return b
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx.go
deleted file mode 100644
index 1cfb4cd..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx.go
+++ /dev/null
@@ -1,682 +0,0 @@
-package bolt
-
-import (
- "fmt"
- "io"
- "os"
- "sort"
- "strings"
- "time"
- "unsafe"
-)
-
-// txid represents the internal transaction identifier.
-type txid uint64
-
-// Tx represents a read-only or read/write transaction on the database.
-// Read-only transactions can be used for retrieving values for keys and creating cursors.
-// Read/write transactions can create and remove buckets and create and remove keys.
-//
-// IMPORTANT: You must commit or rollback transactions when you are done with
-// them. Pages can not be reclaimed by the writer until no more transactions
-// are using them. A long running read transaction can cause the database to
-// quickly grow.
-type Tx struct {
- writable bool
- managed bool
- db *DB
- meta *meta
- root Bucket
- pages map[pgid]*page
- stats TxStats
- commitHandlers []func()
-
- // WriteFlag specifies the flag for write-related methods like WriteTo().
- // Tx opens the database file with the specified flag to copy the data.
- //
- // By default, the flag is unset, which works well for mostly in-memory
- // workloads. For databases that are much larger than available RAM,
- // set the flag to syscall.O_DIRECT to avoid trashing the page cache.
- WriteFlag int
-}
-
-// init initializes the transaction.
-func (tx *Tx) init(db *DB) {
- tx.db = db
- tx.pages = nil
-
- // Copy the meta page since it can be changed by the writer.
- tx.meta = &meta{}
- db.meta().copy(tx.meta)
-
- // Copy over the root bucket.
- tx.root = newBucket(tx)
- tx.root.bucket = &bucket{}
- *tx.root.bucket = tx.meta.root
-
- // Increment the transaction id and add a page cache for writable transactions.
- if tx.writable {
- tx.pages = make(map[pgid]*page)
- tx.meta.txid += txid(1)
- }
-}
-
-// ID returns the transaction id.
-func (tx *Tx) ID() int {
- return int(tx.meta.txid)
-}
-
-// DB returns a reference to the database that created the transaction.
-func (tx *Tx) DB() *DB {
- return tx.db
-}
-
-// Size returns current database size in bytes as seen by this transaction.
-func (tx *Tx) Size() int64 {
- return int64(tx.meta.pgid) * int64(tx.db.pageSize)
-}
-
-// Writable returns whether the transaction can perform write operations.
-func (tx *Tx) Writable() bool {
- return tx.writable
-}
-
-// Cursor creates a cursor associated with the root bucket.
-// All items in the cursor will return a nil value because all root bucket keys point to buckets.
-// The cursor is only valid as long as the transaction is open.
-// Do not use a cursor after the transaction is closed.
-func (tx *Tx) Cursor() *Cursor {
- return tx.root.Cursor()
-}
-
-// Stats retrieves a copy of the current transaction statistics.
-func (tx *Tx) Stats() TxStats {
- return tx.stats
-}
-
-// Bucket retrieves a bucket by name.
-// Returns nil if the bucket does not exist.
-// The bucket instance is only valid for the lifetime of the transaction.
-func (tx *Tx) Bucket(name []byte) *Bucket {
- return tx.root.Bucket(name)
-}
-
-// CreateBucket creates a new bucket.
-// Returns an error if the bucket already exists, if the bucket name is blank, or if the bucket name is too long.
-// The bucket instance is only valid for the lifetime of the transaction.
-func (tx *Tx) CreateBucket(name []byte) (*Bucket, error) {
- return tx.root.CreateBucket(name)
-}
-
-// CreateBucketIfNotExists creates a new bucket if it doesn't already exist.
-// Returns an error if the bucket name is blank, or if the bucket name is too long.
-// The bucket instance is only valid for the lifetime of the transaction.
-func (tx *Tx) CreateBucketIfNotExists(name []byte) (*Bucket, error) {
- return tx.root.CreateBucketIfNotExists(name)
-}
-
-// DeleteBucket deletes a bucket.
-// Returns an error if the bucket cannot be found or if the key represents a non-bucket value.
-func (tx *Tx) DeleteBucket(name []byte) error {
- return tx.root.DeleteBucket(name)
-}
-
-// ForEach executes a function for each bucket in the root.
-// If the provided function returns an error then the iteration is stopped and
-// the error is returned to the caller.
-func (tx *Tx) ForEach(fn func(name []byte, b *Bucket) error) error {
- return tx.root.ForEach(func(k, v []byte) error {
- if err := fn(k, tx.root.Bucket(k)); err != nil {
- return err
- }
- return nil
- })
-}
-
-// OnCommit adds a handler function to be executed after the transaction successfully commits.
-func (tx *Tx) OnCommit(fn func()) {
- tx.commitHandlers = append(tx.commitHandlers, fn)
-}
-
-// Commit writes all changes to disk and updates the meta page.
-// Returns an error if a disk write error occurs, or if Commit is
-// called on a read-only transaction.
-func (tx *Tx) Commit() error {
- _assert(!tx.managed, "managed tx commit not allowed")
- if tx.db == nil {
- return ErrTxClosed
- } else if !tx.writable {
- return ErrTxNotWritable
- }
-
- // TODO(benbjohnson): Use vectorized I/O to write out dirty pages.
-
- // Rebalance nodes which have had deletions.
- var startTime = time.Now()
- tx.root.rebalance()
- if tx.stats.Rebalance > 0 {
- tx.stats.RebalanceTime += time.Since(startTime)
- }
-
- // spill data onto dirty pages.
- startTime = time.Now()
- if err := tx.root.spill(); err != nil {
- tx.rollback()
- return err
- }
- tx.stats.SpillTime += time.Since(startTime)
-
- // Free the old root bucket.
- tx.meta.root.root = tx.root.root
-
- opgid := tx.meta.pgid
-
- // Free the freelist and allocate new pages for it. This will overestimate
- // the size of the freelist but not underestimate the size (which would be bad).
- tx.db.freelist.free(tx.meta.txid, tx.db.page(tx.meta.freelist))
- p, err := tx.allocate((tx.db.freelist.size() / tx.db.pageSize) + 1)
- if err != nil {
- tx.rollback()
- return err
- }
- if err := tx.db.freelist.write(p); err != nil {
- tx.rollback()
- return err
- }
- tx.meta.freelist = p.id
-
- // If the high water mark has moved up then attempt to grow the database.
- if tx.meta.pgid > opgid {
- if err := tx.db.grow(int(tx.meta.pgid+1) * tx.db.pageSize); err != nil {
- tx.rollback()
- return err
- }
- }
-
- // Write dirty pages to disk.
- startTime = time.Now()
- if err := tx.write(); err != nil {
- tx.rollback()
- return err
- }
-
- // If strict mode is enabled then perform a consistency check.
- // Only the first consistency error is reported in the panic.
- if tx.db.StrictMode {
- ch := tx.Check()
- var errs []string
- for {
- err, ok := <-ch
- if !ok {
- break
- }
- errs = append(errs, err.Error())
- }
- if len(errs) > 0 {
- panic("check fail: " + strings.Join(errs, "\n"))
- }
- }
-
- // Write meta to disk.
- if err := tx.writeMeta(); err != nil {
- tx.rollback()
- return err
- }
- tx.stats.WriteTime += time.Since(startTime)
-
- // Finalize the transaction.
- tx.close()
-
- // Execute commit handlers now that the locks have been removed.
- for _, fn := range tx.commitHandlers {
- fn()
- }
-
- return nil
-}
-
-// Rollback closes the transaction and ignores all previous updates. Read-only
-// transactions must be rolled back and not committed.
-func (tx *Tx) Rollback() error {
- _assert(!tx.managed, "managed tx rollback not allowed")
- if tx.db == nil {
- return ErrTxClosed
- }
- tx.rollback()
- return nil
-}
-
-func (tx *Tx) rollback() {
- if tx.db == nil {
- return
- }
- if tx.writable {
- tx.db.freelist.rollback(tx.meta.txid)
- tx.db.freelist.reload(tx.db.page(tx.db.meta().freelist))
- }
- tx.close()
-}
-
-func (tx *Tx) close() {
- if tx.db == nil {
- return
- }
- if tx.writable {
- // Grab freelist stats.
- var freelistFreeN = tx.db.freelist.free_count()
- var freelistPendingN = tx.db.freelist.pending_count()
- var freelistAlloc = tx.db.freelist.size()
-
- // Remove transaction ref & writer lock.
- tx.db.rwtx = nil
- tx.db.rwlock.Unlock()
-
- // Merge statistics.
- tx.db.statlock.Lock()
- tx.db.stats.FreePageN = freelistFreeN
- tx.db.stats.PendingPageN = freelistPendingN
- tx.db.stats.FreeAlloc = (freelistFreeN + freelistPendingN) * tx.db.pageSize
- tx.db.stats.FreelistInuse = freelistAlloc
- tx.db.stats.TxStats.add(&tx.stats)
- tx.db.statlock.Unlock()
- } else {
- tx.db.removeTx(tx)
- }
-
- // Clear all references.
- tx.db = nil
- tx.meta = nil
- tx.root = Bucket{tx: tx}
- tx.pages = nil
-}
-
-// Copy writes the entire database to a writer.
-// This function exists for backwards compatibility. Use WriteTo() instead.
-func (tx *Tx) Copy(w io.Writer) error {
- _, err := tx.WriteTo(w)
- return err
-}
-
-// WriteTo writes the entire database to a writer.
-// If err == nil then exactly tx.Size() bytes will be written into the writer.
-func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) {
- // Attempt to open reader with WriteFlag
- f, err := os.OpenFile(tx.db.path, os.O_RDONLY|tx.WriteFlag, 0)
- if err != nil {
- return 0, err
- }
- defer func() { _ = f.Close() }()
-
- // Generate a meta page. We use the same page data for both meta pages.
- buf := make([]byte, tx.db.pageSize)
- page := (*page)(unsafe.Pointer(&buf[0]))
- page.flags = metaPageFlag
- *page.meta() = *tx.meta
-
- // Write meta 0.
- page.id = 0
- page.meta().checksum = page.meta().sum64()
- nn, err := w.Write(buf)
- n += int64(nn)
- if err != nil {
- return n, fmt.Errorf("meta 0 copy: %s", err)
- }
-
- // Write meta 1 with a lower transaction id.
- page.id = 1
- page.meta().txid -= 1
- page.meta().checksum = page.meta().sum64()
- nn, err = w.Write(buf)
- n += int64(nn)
- if err != nil {
- return n, fmt.Errorf("meta 1 copy: %s", err)
- }
-
- // Move past the meta pages in the file.
- if _, err := f.Seek(int64(tx.db.pageSize*2), os.SEEK_SET); err != nil {
- return n, fmt.Errorf("seek: %s", err)
- }
-
- // Copy data pages.
- wn, err := io.CopyN(w, f, tx.Size()-int64(tx.db.pageSize*2))
- n += wn
- if err != nil {
- return n, err
- }
-
- return n, f.Close()
-}
-
-// CopyFile copies the entire database to file at the given path.
-// A reader transaction is maintained during the copy so it is safe to continue
-// using the database while a copy is in progress.
-func (tx *Tx) CopyFile(path string, mode os.FileMode) error {
- f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode)
- if err != nil {
- return err
- }
-
- err = tx.Copy(f)
- if err != nil {
- _ = f.Close()
- return err
- }
- return f.Close()
-}
-
-// Check performs several consistency checks on the database for this transaction.
-// An error is returned if any inconsistency is found.
-//
-// It can be safely run concurrently on a writable transaction. However, this
-// incurs a high cost for large databases and databases with a lot of subbuckets
-// because of caching. This overhead can be removed if running on a read-only
-// transaction, however, it is not safe to execute other writer transactions at
-// the same time.
-func (tx *Tx) Check() <-chan error {
- ch := make(chan error)
- go tx.check(ch)
- return ch
-}
-
-func (tx *Tx) check(ch chan error) {
- // Check if any pages are double freed.
- freed := make(map[pgid]bool)
- for _, id := range tx.db.freelist.all() {
- if freed[id] {
- ch <- fmt.Errorf("page %d: already freed", id)
- }
- freed[id] = true
- }
-
- // Track every reachable page.
- reachable := make(map[pgid]*page)
- reachable[0] = tx.page(0) // meta0
- reachable[1] = tx.page(1) // meta1
- for i := uint32(0); i <= tx.page(tx.meta.freelist).overflow; i++ {
- reachable[tx.meta.freelist+pgid(i)] = tx.page(tx.meta.freelist)
- }
-
- // Recursively check buckets.
- tx.checkBucket(&tx.root, reachable, freed, ch)
-
- // Ensure all pages below high water mark are either reachable or freed.
- for i := pgid(0); i < tx.meta.pgid; i++ {
- _, isReachable := reachable[i]
- if !isReachable && !freed[i] {
- ch <- fmt.Errorf("page %d: unreachable unfreed", int(i))
- }
- }
-
- // Close the channel to signal completion.
- close(ch)
-}
-
-func (tx *Tx) checkBucket(b *Bucket, reachable map[pgid]*page, freed map[pgid]bool, ch chan error) {
- // Ignore inline buckets.
- if b.root == 0 {
- return
- }
-
- // Check every page used by this bucket.
- b.tx.forEachPage(b.root, 0, func(p *page, _ int) {
- if p.id > tx.meta.pgid {
- ch <- fmt.Errorf("page %d: out of bounds: %d", int(p.id), int(b.tx.meta.pgid))
- }
-
- // Ensure each page is only referenced once.
- for i := pgid(0); i <= pgid(p.overflow); i++ {
- var id = p.id + i
- if _, ok := reachable[id]; ok {
- ch <- fmt.Errorf("page %d: multiple references", int(id))
- }
- reachable[id] = p
- }
-
- // We should only encounter un-freed leaf and branch pages.
- if freed[p.id] {
- ch <- fmt.Errorf("page %d: reachable freed", int(p.id))
- } else if (p.flags&branchPageFlag) == 0 && (p.flags&leafPageFlag) == 0 {
- ch <- fmt.Errorf("page %d: invalid type: %s", int(p.id), p.typ())
- }
- })
-
- // Check each bucket within this bucket.
- _ = b.ForEach(func(k, v []byte) error {
- if child := b.Bucket(k); child != nil {
- tx.checkBucket(child, reachable, freed, ch)
- }
- return nil
- })
-}
-
-// allocate returns a contiguous block of memory starting at a given page.
-func (tx *Tx) allocate(count int) (*page, error) {
- p, err := tx.db.allocate(count)
- if err != nil {
- return nil, err
- }
-
- // Save to our page cache.
- tx.pages[p.id] = p
-
- // Update statistics.
- tx.stats.PageCount++
- tx.stats.PageAlloc += count * tx.db.pageSize
-
- return p, nil
-}
-
-// write writes any dirty pages to disk.
-func (tx *Tx) write() error {
- // Sort pages by id.
- pages := make(pages, 0, len(tx.pages))
- for _, p := range tx.pages {
- pages = append(pages, p)
- }
- // Clear out page cache early.
- tx.pages = make(map[pgid]*page)
- sort.Sort(pages)
-
- // Write pages to disk in order.
- for _, p := range pages {
- size := (int(p.overflow) + 1) * tx.db.pageSize
- offset := int64(p.id) * int64(tx.db.pageSize)
-
- // Write out page in "max allocation" sized chunks.
- ptr := (*[maxAllocSize]byte)(unsafe.Pointer(p))
- for {
- // Limit our write to our max allocation size.
- sz := size
- if sz > maxAllocSize-1 {
- sz = maxAllocSize - 1
- }
-
- // Write chunk to disk.
- buf := ptr[:sz]
- if _, err := tx.db.ops.writeAt(buf, offset); err != nil {
- return err
- }
-
- // Update statistics.
- tx.stats.Write++
-
- // Exit inner for loop if we've written all the chunks.
- size -= sz
- if size == 0 {
- break
- }
-
- // Otherwise move offset forward and move pointer to next chunk.
- offset += int64(sz)
- ptr = (*[maxAllocSize]byte)(unsafe.Pointer(&ptr[sz]))
- }
- }
-
- // Ignore file sync if flag is set on DB.
- if !tx.db.NoSync || IgnoreNoSync {
- if err := fdatasync(tx.db); err != nil {
- return err
- }
- }
-
- // Put small pages back to page pool.
- for _, p := range pages {
- // Ignore page sizes over 1 page.
- // These are allocated using make() instead of the page pool.
- if int(p.overflow) != 0 {
- continue
- }
-
- buf := (*[maxAllocSize]byte)(unsafe.Pointer(p))[:tx.db.pageSize]
-
- // See https://go.googlesource.com/go/+/f03c9202c43e0abb130669852082117ca50aa9b1
- for i := range buf {
- buf[i] = 0
- }
- tx.db.pagePool.Put(buf)
- }
-
- return nil
-}
-
-// writeMeta writes the meta to the disk.
-func (tx *Tx) writeMeta() error {
- // Create a temporary buffer for the meta page.
- buf := make([]byte, tx.db.pageSize)
- p := tx.db.pageInBuffer(buf, 0)
- tx.meta.write(p)
-
- // Write the meta page to file.
- if _, err := tx.db.ops.writeAt(buf, int64(p.id)*int64(tx.db.pageSize)); err != nil {
- return err
- }
- if !tx.db.NoSync || IgnoreNoSync {
- if err := fdatasync(tx.db); err != nil {
- return err
- }
- }
-
- // Update statistics.
- tx.stats.Write++
-
- return nil
-}
-
-// page returns a reference to the page with a given id.
-// If page has been written to then a temporary buffered page is returned.
-func (tx *Tx) page(id pgid) *page {
- // Check the dirty pages first.
- if tx.pages != nil {
- if p, ok := tx.pages[id]; ok {
- return p
- }
- }
-
- // Otherwise return directly from the mmap.
- return tx.db.page(id)
-}
-
-// forEachPage iterates over every page within a given page and executes a function.
-func (tx *Tx) forEachPage(pgid pgid, depth int, fn func(*page, int)) {
- p := tx.page(pgid)
-
- // Execute function.
- fn(p, depth)
-
- // Recursively loop over children.
- if (p.flags & branchPageFlag) != 0 {
- for i := 0; i < int(p.count); i++ {
- elem := p.branchPageElement(uint16(i))
- tx.forEachPage(elem.pgid, depth+1, fn)
- }
- }
-}
-
-// Page returns page information for a given page number.
-// This is only safe for concurrent use when used by a writable transaction.
-func (tx *Tx) Page(id int) (*PageInfo, error) {
- if tx.db == nil {
- return nil, ErrTxClosed
- } else if pgid(id) >= tx.meta.pgid {
- return nil, nil
- }
-
- // Build the page info.
- p := tx.db.page(pgid(id))
- info := &PageInfo{
- ID: id,
- Count: int(p.count),
- OverflowCount: int(p.overflow),
- }
-
- // Determine the type (or if it's free).
- if tx.db.freelist.freed(pgid(id)) {
- info.Type = "free"
- } else {
- info.Type = p.typ()
- }
-
- return info, nil
-}
-
-// TxStats represents statistics about the actions performed by the transaction.
-type TxStats struct {
- // Page statistics.
- PageCount int // number of page allocations
- PageAlloc int // total bytes allocated
-
- // Cursor statistics.
- CursorCount int // number of cursors created
-
- // Node statistics
- NodeCount int // number of node allocations
- NodeDeref int // number of node dereferences
-
- // Rebalance statistics.
- Rebalance int // number of node rebalances
- RebalanceTime time.Duration // total time spent rebalancing
-
- // Split/Spill statistics.
- Split int // number of nodes split
- Spill int // number of nodes spilled
- SpillTime time.Duration // total time spent spilling
-
- // Write statistics.
- Write int // number of writes performed
- WriteTime time.Duration // total time spent writing to disk
-}
-
-func (s *TxStats) add(other *TxStats) {
- s.PageCount += other.PageCount
- s.PageAlloc += other.PageAlloc
- s.CursorCount += other.CursorCount
- s.NodeCount += other.NodeCount
- s.NodeDeref += other.NodeDeref
- s.Rebalance += other.Rebalance
- s.RebalanceTime += other.RebalanceTime
- s.Split += other.Split
- s.Spill += other.Spill
- s.SpillTime += other.SpillTime
- s.Write += other.Write
- s.WriteTime += other.WriteTime
-}
-
-// Sub calculates and returns the difference between two sets of transaction stats.
-// This is useful when obtaining stats at two different points and time and
-// you need the performance counters that occurred within that time span.
-func (s *TxStats) Sub(other *TxStats) TxStats {
- var diff TxStats
- diff.PageCount = s.PageCount - other.PageCount
- diff.PageAlloc = s.PageAlloc - other.PageAlloc
- diff.CursorCount = s.CursorCount - other.CursorCount
- diff.NodeCount = s.NodeCount - other.NodeCount
- diff.NodeDeref = s.NodeDeref - other.NodeDeref
- diff.Rebalance = s.Rebalance - other.Rebalance
- diff.RebalanceTime = s.RebalanceTime - other.RebalanceTime
- diff.Split = s.Split - other.Split
- diff.Spill = s.Spill - other.Spill
- diff.SpillTime = s.SpillTime - other.SpillTime
- diff.Write = s.Write - other.Write
- diff.WriteTime = s.WriteTime - other.WriteTime
- return diff
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx_test.go
deleted file mode 100644
index 2201e79..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx_test.go
+++ /dev/null
@@ -1,716 +0,0 @@
-package bolt_test
-
-import (
- "bytes"
- "errors"
- "fmt"
- "log"
- "os"
- "testing"
-
- "github.com/boltdb/bolt"
-)
-
-// Ensure that committing a closed transaction returns an error.
-func TestTx_Commit_ErrTxClosed(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- tx, err := db.Begin(true)
- if err != nil {
- t.Fatal(err)
- }
-
- if _, err := tx.CreateBucket([]byte("foo")); err != nil {
- t.Fatal(err)
- }
-
- if err := tx.Commit(); err != nil {
- t.Fatal(err)
- }
-
- if err := tx.Commit(); err != bolt.ErrTxClosed {
- t.Fatalf("unexpected error: %s", err)
- }
-}
-
-// Ensure that rolling back a closed transaction returns an error.
-func TestTx_Rollback_ErrTxClosed(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- tx, err := db.Begin(true)
- if err != nil {
- t.Fatal(err)
- }
-
- if err := tx.Rollback(); err != nil {
- t.Fatal(err)
- }
- if err := tx.Rollback(); err != bolt.ErrTxClosed {
- t.Fatalf("unexpected error: %s", err)
- }
-}
-
-// Ensure that committing a read-only transaction returns an error.
-func TestTx_Commit_ErrTxNotWritable(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- tx, err := db.Begin(false)
- if err != nil {
- t.Fatal(err)
- }
- if err := tx.Commit(); err != bolt.ErrTxNotWritable {
- t.Fatal(err)
- }
-}
-
-// Ensure that a transaction can retrieve a cursor on the root bucket.
-func TestTx_Cursor(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
-
- if _, err := tx.CreateBucket([]byte("woojits")); err != nil {
- t.Fatal(err)
- }
-
- c := tx.Cursor()
- if k, v := c.First(); !bytes.Equal(k, []byte("widgets")) {
- t.Fatalf("unexpected key: %v", k)
- } else if v != nil {
- t.Fatalf("unexpected value: %v", v)
- }
-
- if k, v := c.Next(); !bytes.Equal(k, []byte("woojits")) {
- t.Fatalf("unexpected key: %v", k)
- } else if v != nil {
- t.Fatalf("unexpected value: %v", v)
- }
-
- if k, v := c.Next(); k != nil {
- t.Fatalf("unexpected key: %v", k)
- } else if v != nil {
- t.Fatalf("unexpected value: %v", k)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that creating a bucket with a read-only transaction returns an error.
-func TestTx_CreateBucket_ErrTxNotWritable(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.View(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucket([]byte("foo"))
- if err != bolt.ErrTxNotWritable {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that creating a bucket on a closed transaction returns an error.
-func TestTx_CreateBucket_ErrTxClosed(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- tx, err := db.Begin(true)
- if err != nil {
- t.Fatal(err)
- }
- if err := tx.Commit(); err != nil {
- t.Fatal(err)
- }
-
- if _, err := tx.CreateBucket([]byte("foo")); err != bolt.ErrTxClosed {
- t.Fatalf("unexpected error: %s", err)
- }
-}
-
-// Ensure that a Tx can retrieve a bucket.
-func TestTx_Bucket(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- if tx.Bucket([]byte("widgets")) == nil {
- t.Fatal("expected bucket")
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a Tx retrieving a non-existent key returns nil.
-func TestTx_Get_NotFound(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
-
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
- if b.Get([]byte("no_such_key")) != nil {
- t.Fatal("expected nil value")
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a bucket can be created and retrieved.
-func TestTx_CreateBucket(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- // Create a bucket.
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- } else if b == nil {
- t.Fatal("expected bucket")
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- // Read the bucket through a separate transaction.
- if err := db.View(func(tx *bolt.Tx) error {
- if tx.Bucket([]byte("widgets")) == nil {
- t.Fatal("expected bucket")
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a bucket can be created if it doesn't already exist.
-func TestTx_CreateBucketIfNotExists(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- // Create bucket.
- if b, err := tx.CreateBucketIfNotExists([]byte("widgets")); err != nil {
- t.Fatal(err)
- } else if b == nil {
- t.Fatal("expected bucket")
- }
-
- // Create bucket again.
- if b, err := tx.CreateBucketIfNotExists([]byte("widgets")); err != nil {
- t.Fatal(err)
- } else if b == nil {
- t.Fatal("expected bucket")
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- // Read the bucket through a separate transaction.
- if err := db.View(func(tx *bolt.Tx) error {
- if tx.Bucket([]byte("widgets")) == nil {
- t.Fatal("expected bucket")
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure transaction returns an error if creating an unnamed bucket.
-func TestTx_CreateBucketIfNotExists_ErrBucketNameRequired(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucketIfNotExists([]byte{}); err != bolt.ErrBucketNameRequired {
- t.Fatalf("unexpected error: %s", err)
- }
-
- if _, err := tx.CreateBucketIfNotExists(nil); err != bolt.ErrBucketNameRequired {
- t.Fatalf("unexpected error: %s", err)
- }
-
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a bucket cannot be created twice.
-func TestTx_CreateBucket_ErrBucketExists(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- // Create a bucket.
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- // Create the same bucket again.
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket([]byte("widgets")); err != bolt.ErrBucketExists {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a bucket is created with a non-blank name.
-func TestTx_CreateBucket_ErrBucketNameRequired(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- if _, err := tx.CreateBucket(nil); err != bolt.ErrBucketNameRequired {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that a bucket can be deleted.
-func TestTx_DeleteBucket(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- // Create a bucket and add a value.
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- // Delete the bucket and make sure we can't get the value.
- if err := db.Update(func(tx *bolt.Tx) error {
- if err := tx.DeleteBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- if tx.Bucket([]byte("widgets")) != nil {
- t.Fatal("unexpected bucket")
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.Update(func(tx *bolt.Tx) error {
- // Create the bucket again and make sure there's not a phantom value.
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if v := b.Get([]byte("foo")); v != nil {
- t.Fatalf("unexpected phantom value: %v", v)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that deleting a bucket on a closed transaction returns an error.
-func TestTx_DeleteBucket_ErrTxClosed(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- tx, err := db.Begin(true)
- if err != nil {
- t.Fatal(err)
- }
- if err := tx.Commit(); err != nil {
- t.Fatal(err)
- }
- if err := tx.DeleteBucket([]byte("foo")); err != bolt.ErrTxClosed {
- t.Fatalf("unexpected error: %s", err)
- }
-}
-
-// Ensure that deleting a bucket with a read-only transaction returns an error.
-func TestTx_DeleteBucket_ReadOnly(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.View(func(tx *bolt.Tx) error {
- if err := tx.DeleteBucket([]byte("foo")); err != bolt.ErrTxNotWritable {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that nothing happens when deleting a bucket that doesn't exist.
-func TestTx_DeleteBucket_NotFound(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- if err := tx.DeleteBucket([]byte("widgets")); err != bolt.ErrBucketNotFound {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that no error is returned when a tx.ForEach function does not return
-// an error.
-func TestTx_ForEach_NoError(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
-
- if err := tx.ForEach(func(name []byte, b *bolt.Bucket) error {
- return nil
- }); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that an error is returned when a tx.ForEach function returns an error.
-func TestTx_ForEach_WithError(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
-
- marker := errors.New("marker")
- if err := tx.ForEach(func(name []byte, b *bolt.Bucket) error {
- return marker
- }); err != marker {
- t.Fatalf("unexpected error: %s", err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-}
-
-// Ensure that Tx commit handlers are called after a transaction successfully commits.
-func TestTx_OnCommit(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- var x int
- if err := db.Update(func(tx *bolt.Tx) error {
- tx.OnCommit(func() { x += 1 })
- tx.OnCommit(func() { x += 2 })
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- } else if x != 3 {
- t.Fatalf("unexpected x: %d", x)
- }
-}
-
-// Ensure that Tx commit handlers are NOT called after a transaction rolls back.
-func TestTx_OnCommit_Rollback(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- var x int
- if err := db.Update(func(tx *bolt.Tx) error {
- tx.OnCommit(func() { x += 1 })
- tx.OnCommit(func() { x += 2 })
- if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
- t.Fatal(err)
- }
- return errors.New("rollback this commit")
- }); err == nil || err.Error() != "rollback this commit" {
- t.Fatalf("unexpected error: %s", err)
- } else if x != 0 {
- t.Fatalf("unexpected x: %d", x)
- }
-}
-
-// Ensure that the database can be copied to a file path.
-func TestTx_CopyFile(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
-
- path := tempfile()
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("baz"), []byte("bat")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.View(func(tx *bolt.Tx) error {
- return tx.CopyFile(path, 0600)
- }); err != nil {
- t.Fatal(err)
- }
-
- db2, err := bolt.Open(path, 0600, nil)
- if err != nil {
- t.Fatal(err)
- }
-
- if err := db2.View(func(tx *bolt.Tx) error {
- if v := tx.Bucket([]byte("widgets")).Get([]byte("foo")); !bytes.Equal(v, []byte("bar")) {
- t.Fatalf("unexpected value: %v", v)
- }
- if v := tx.Bucket([]byte("widgets")).Get([]byte("baz")); !bytes.Equal(v, []byte("bat")) {
- t.Fatalf("unexpected value: %v", v)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db2.Close(); err != nil {
- t.Fatal(err)
- }
-}
-
-type failWriterError struct{}
-
-func (failWriterError) Error() string {
- return "error injected for tests"
-}
-
-type failWriter struct {
- // fail after this many bytes
- After int
-}
-
-func (f *failWriter) Write(p []byte) (n int, err error) {
- n = len(p)
- if n > f.After {
- n = f.After
- err = failWriterError{}
- }
- f.After -= n
- return n, err
-}
-
-// Ensure that Copy handles write errors right.
-func TestTx_CopyFile_Error_Meta(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("baz"), []byte("bat")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.View(func(tx *bolt.Tx) error {
- return tx.Copy(&failWriter{})
- }); err == nil || err.Error() != "meta 0 copy: error injected for tests" {
- t.Fatalf("unexpected error: %v", err)
- }
-}
-
-// Ensure that Copy handles write errors right.
-func TestTx_CopyFile_Error_Normal(t *testing.T) {
- db := MustOpenDB()
- defer db.MustClose()
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- t.Fatal(err)
- }
- if err := b.Put([]byte("baz"), []byte("bat")); err != nil {
- t.Fatal(err)
- }
- return nil
- }); err != nil {
- t.Fatal(err)
- }
-
- if err := db.View(func(tx *bolt.Tx) error {
- return tx.Copy(&failWriter{3 * db.Info().PageSize})
- }); err == nil || err.Error() != "error injected for tests" {
- t.Fatalf("unexpected error: %v", err)
- }
-}
-
-func ExampleTx_Rollback() {
- // Open the database.
- db, err := bolt.Open(tempfile(), 0666, nil)
- if err != nil {
- log.Fatal(err)
- }
- defer os.Remove(db.Path())
-
- // Create a bucket.
- if err := db.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucket([]byte("widgets"))
- return err
- }); err != nil {
- log.Fatal(err)
- }
-
- // Set a value for a key.
- if err := db.Update(func(tx *bolt.Tx) error {
- return tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
- }); err != nil {
- log.Fatal(err)
- }
-
- // Update the key but rollback the transaction so it never saves.
- tx, err := db.Begin(true)
- if err != nil {
- log.Fatal(err)
- }
- b := tx.Bucket([]byte("widgets"))
- if err := b.Put([]byte("foo"), []byte("baz")); err != nil {
- log.Fatal(err)
- }
- if err := tx.Rollback(); err != nil {
- log.Fatal(err)
- }
-
- // Ensure that our original value is still set.
- if err := db.View(func(tx *bolt.Tx) error {
- value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
- fmt.Printf("The value for 'foo' is still: %s\n", value)
- return nil
- }); err != nil {
- log.Fatal(err)
- }
-
- // Close database to release file lock.
- if err := db.Close(); err != nil {
- log.Fatal(err)
- }
-
- // Output:
- // The value for 'foo' is still: bar
-}
-
-func ExampleTx_CopyFile() {
- // Open the database.
- db, err := bolt.Open(tempfile(), 0666, nil)
- if err != nil {
- log.Fatal(err)
- }
- defer os.Remove(db.Path())
-
- // Create a bucket and a key.
- if err := db.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucket([]byte("widgets"))
- if err != nil {
- return err
- }
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- return err
- }
- return nil
- }); err != nil {
- log.Fatal(err)
- }
-
- // Copy the database to another file.
- toFile := tempfile()
- if err := db.View(func(tx *bolt.Tx) error {
- return tx.CopyFile(toFile, 0666)
- }); err != nil {
- log.Fatal(err)
- }
- defer os.Remove(toFile)
-
- // Open the cloned database.
- db2, err := bolt.Open(toFile, 0666, nil)
- if err != nil {
- log.Fatal(err)
- }
-
- // Ensure that the key exists in the copy.
- if err := db2.View(func(tx *bolt.Tx) error {
- value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
- fmt.Printf("The value for 'foo' in the clone is: %s\n", value)
- return nil
- }); err != nil {
- log.Fatal(err)
- }
-
- // Close database to release file lock.
- if err := db.Close(); err != nil {
- log.Fatal(err)
- }
-
- if err := db2.Close(); err != nil {
- log.Fatal(err)
- }
-
- // Output:
- // The value for 'foo' in the clone is: bar
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/LICENSE b/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/LICENSE
deleted file mode 100644
index 720d6cd..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/LICENSE
+++ /dev/null
@@ -1,29 +0,0 @@
-BSD 3-Clause License
-
-Copyright (c) 2016 Boss Sauce Creative, LLC.
-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. \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/README.md b/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/README.md
deleted file mode 100644
index 57f008c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Reference
-
-A Ponzu addon to embed a reference to a content type from within another content type in the CMS.
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/reference.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/reference.go
deleted file mode 100644
index 753fa41..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/reference.go
+++ /dev/null
@@ -1,150 +0,0 @@
-// Package reference is a Ponzu addon to enable content editors to create
-// references to other content types which are stored as query strings within
-// the referencer's content DB
-package reference
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "html/template"
- "log"
- "strings"
-
- "github.com/ponzu-cms/ponzu/management/editor"
- "github.com/ponzu-cms/ponzu/system/addon"
-)
-
-// Select returns the []byte of a <select> HTML element plus internal <options> with a label.
-// IMPORTANT:
-// The `fieldName` argument will cause a panic if it is not exactly the string
-// form of the struct field that this editor input is representing
-func Select(fieldName string, p interface{}, attrs map[string]string, contentType, tmplString string) []byte {
- options, err := encodeDataToOptions(contentType, tmplString)
- if err != nil {
- log.Println("Error encoding data to options for", contentType, err)
- return nil
- }
-
- return editor.Select(fieldName, p, attrs, options)
-}
-
-// SelectRepeater returns the []byte of a <select> HTML element plus internal <options> with a label.
-// It also includes repeat controllers (+ / -) so the element can be
-// dynamically multiplied or reduced.
-// IMPORTANT:
-// The `fieldName` argument will cause a panic if it is not exactly the string
-// form of the struct field that this editor input is representing
-func SelectRepeater(fieldName string, p interface{}, attrs map[string]string, contentType, tmplString string) []byte {
- scope := editor.TagNameFromStructField(fieldName, p)
- html := bytes.Buffer{}
- _, err := html.WriteString(`<span class="__ponzu-repeat ` + scope + `">`)
- if err != nil {
- log.Println("Error writing HTML string to SelectRepeater buffer")
- return nil
- }
-
- if _, ok := attrs["class"]; ok {
- attrs["class"] += " browser-default"
- } else {
- attrs["class"] = "browser-default"
- }
-
- // find the field values in p to determine if an option is pre-selected
- fieldVals := editor.ValueFromStructField(fieldName, p)
- vals := strings.Split(fieldVals, "__ponzu")
-
- options, err := encodeDataToOptions(contentType, tmplString)
- if err != nil {
- log.Println("Error encoding data to options for", contentType, err)
- return nil
- }
-
- for _, val := range vals {
- sel := editor.NewElement("select", attrs["label"], fieldName, p, attrs)
- var opts []*editor.Element
-
- // provide a call to action for the select element
- cta := &editor.Element{
- TagName: "option",
- Attrs: map[string]string{"disabled": "true", "selected": "true"},
- Data: "Select an option...",
- ViewBuf: &bytes.Buffer{},
- }
-
- // provide a selection reset (will store empty string in db)
- reset := &editor.Element{
- TagName: "option",
- Attrs: map[string]string{"value": ""},
- Data: "None",
- ViewBuf: &bytes.Buffer{},
- }
-
- opts = append(opts, cta, reset)
-
- for k, v := range options {
- optAttrs := map[string]string{"value": k}
- if k == val {
- optAttrs["selected"] = "true"
- }
- opt := &editor.Element{
- TagName: "option",
- Attrs: optAttrs,
- Data: v,
- ViewBuf: &bytes.Buffer{},
- }
-
- opts = append(opts, opt)
- }
-
- _, err := html.Write(editor.DOMElementWithChildrenSelect(sel, opts))
- if err != nil {
- log.Println("Error writing DOMElementWithChildrenSelect to SelectRepeater buffer")
- return nil
- }
- }
-
- _, err = html.WriteString("</span>")
- if err != nil {
- log.Println("Error writing HTML string to SelectRepeater buffer")
- return nil
- }
-
- return append(html.Bytes(), editor.RepeatController(fieldName, p, "select", ".input-field")...)
-}
-
-func encodeDataToOptions(contentType, tmplString string) (map[string]string, error) {
- // encode all content type from db into options map
- // options in form of map["/api/content?type=<contentType>&id=<id>"]t.String()
- options := make(map[string]string)
-
- var all map[string]interface{}
- j := addon.ContentAll(contentType)
-
- err := json.Unmarshal(j, &all)
- if err != nil {
- return nil, err
- }
-
- // make template for option html display
- tmpl := template.Must(template.New(contentType).Parse(tmplString))
-
- // make data something usable to iterate over and assign options
- data := all["data"].([]interface{})
-
- for i := range data {
- item := data[i].(map[string]interface{})
- k := fmt.Sprintf("/api/content?type=%s&id=%.0f", contentType, item["id"].(float64))
- v := &bytes.Buffer{}
- err := tmpl.Execute(v, item)
- if err != nil {
- return nil, fmt.Errorf(
- "Error executing template for reference of %s: %s",
- contentType, err.Error())
- }
-
- options[k] = v.String()
- }
-
- return options, nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/.travis.yml b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/.travis.yml
deleted file mode 100644
index 6f440f1..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/.travis.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-language: go
-sudo: false
-
-matrix:
- include:
- - go: 1.3
- - go: 1.4
- - go: 1.5
- - go: 1.6
- - go: 1.7
- - go: tip
- allow_failures:
- - go: tip
-
-script:
- - go get -t -v ./...
- - diff -u <(echo -n) <(gofmt -d .)
- - go vet $(go list ./... | grep -v /vendor/)
- - go test -v -race ./...
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/LICENSE b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/LICENSE
deleted file mode 100644
index 0e5fb87..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/README.md b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/README.md
deleted file mode 100644
index e9936d9..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/README.md
+++ /dev/null
@@ -1,66 +0,0 @@
-schema
-======
-[![GoDoc](https://godoc.org/github.com/gorilla/schema?status.svg)](https://godoc.org/github.com/gorilla/schema) [![Build Status](https://travis-ci.org/gorilla/schema.png?branch=master)](https://travis-ci.org/gorilla/schema)
-
-Package gorilla/schema fills a struct with form values.
-
-## Example
-
-Here's a quick example: we parse POST form values and then decode them into a struct:
-
-```go
-// Set a Decoder instance as a package global, because it caches
-// meta-data about structs, and an instance can be shared safely.
-var decoder = schema.NewDecoder()
-
-type Person struct {
- Name string
- Phone string
-}
-
-func MyHandler(w http.ResponseWriter, r *http.Request) {
- err := r.ParseForm()
- if err != nil {
- // Handle error
- }
-
- var person Person
-
- // r.PostForm is a map of our POST form values
- err := decoder.Decode(&person, r.PostForm)
- if err != nil {
- // Handle error
- }
-
- // Do something with person.Name or person.Phone
-}
-```
-
-To define custom names for fields, use a struct tag "schema". To not populate certain fields, use a dash for the name and it will be ignored:
-
-```go
-type Person struct {
- Name string `schema:"name"` // custom name
- Phone string `schema:"phone"` // custom name
- Admin bool `schema:"-"` // this field is never set
-}
-```
-
-The supported field types in the destination struct are:
-
-* bool
-* float variants (float32, float64)
-* int variants (int, int8, int16, int32, int64)
-* string
-* uint variants (uint, uint8, uint16, uint32, uint64)
-* struct
-* a pointer to one of the above types
-* a slice or a pointer to a slice of one of the above types
-
-Unsupported types are simply ignored, however custom types can be registered to be converted.
-
-More examples are available on the Gorilla website: http://www.gorillatoolkit.org/pkg/schema
-
-## License
-
-BSD licensed. See the LICENSE file for details.
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/cache.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/cache.go
deleted file mode 100644
index e0f7566..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/cache.go
+++ /dev/null
@@ -1,261 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package schema
-
-import (
- "errors"
- "reflect"
- "strconv"
- "strings"
- "sync"
-)
-
-var invalidPath = errors.New("schema: invalid path")
-
-// newCache returns a new cache.
-func newCache() *cache {
- c := cache{
- m: make(map[reflect.Type]*structInfo),
- conv: make(map[reflect.Kind]Converter),
- regconv: make(map[reflect.Type]Converter),
- tag: "schema",
- }
- for k, v := range converters {
- c.conv[k] = v
- }
- return &c
-}
-
-// cache caches meta-data about a struct.
-type cache struct {
- l sync.RWMutex
- m map[reflect.Type]*structInfo
- conv map[reflect.Kind]Converter
- regconv map[reflect.Type]Converter
- tag string
-}
-
-// parsePath parses a path in dotted notation verifying that it is a valid
-// path to a struct field.
-//
-// It returns "path parts" which contain indices to fields to be used by
-// reflect.Value.FieldByString(). Multiple parts are required for slices of
-// structs.
-func (c *cache) parsePath(p string, t reflect.Type) ([]pathPart, error) {
- var struc *structInfo
- var field *fieldInfo
- var index64 int64
- var err error
- parts := make([]pathPart, 0)
- path := make([]string, 0)
- keys := strings.Split(p, ".")
- for i := 0; i < len(keys); i++ {
- if t.Kind() != reflect.Struct {
- return nil, invalidPath
- }
- if struc = c.get(t); struc == nil {
- return nil, invalidPath
- }
- if field = struc.get(keys[i]); field == nil {
- return nil, invalidPath
- }
- // Valid field. Append index.
- path = append(path, field.name)
- if field.ss {
- // Parse a special case: slices of structs.
- // i+1 must be the slice index.
- //
- // Now that struct can implements TextUnmarshaler interface,
- // we don't need to force the struct's fields to appear in the path.
- // So checking i+2 is not necessary anymore.
- i++
- if i+1 > len(keys) {
- return nil, invalidPath
- }
- if index64, err = strconv.ParseInt(keys[i], 10, 0); err != nil {
- return nil, invalidPath
- }
- parts = append(parts, pathPart{
- path: path,
- field: field,
- index: int(index64),
- })
- path = make([]string, 0)
-
- // Get the next struct type, dropping ptrs.
- if field.typ.Kind() == reflect.Ptr {
- t = field.typ.Elem()
- } else {
- t = field.typ
- }
- if t.Kind() == reflect.Slice {
- t = t.Elem()
- if t.Kind() == reflect.Ptr {
- t = t.Elem()
- }
- }
- } else if field.typ.Kind() == reflect.Ptr {
- t = field.typ.Elem()
- } else {
- t = field.typ
- }
- }
- // Add the remaining.
- parts = append(parts, pathPart{
- path: path,
- field: field,
- index: -1,
- })
- return parts, nil
-}
-
-// get returns a cached structInfo, creating it if necessary.
-func (c *cache) get(t reflect.Type) *structInfo {
- c.l.RLock()
- info := c.m[t]
- c.l.RUnlock()
- if info == nil {
- info = c.create(t, nil)
- c.l.Lock()
- c.m[t] = info
- c.l.Unlock()
- }
- return info
-}
-
-// create creates a structInfo with meta-data about a struct.
-func (c *cache) create(t reflect.Type, info *structInfo) *structInfo {
- if info == nil {
- info = &structInfo{fields: []*fieldInfo{}}
- }
- for i := 0; i < t.NumField(); i++ {
- field := t.Field(i)
- if field.Anonymous {
- ft := field.Type
- if ft.Kind() == reflect.Ptr {
- ft = ft.Elem()
- }
- if ft.Kind() == reflect.Struct {
- c.create(ft, info)
- }
- }
- c.createField(field, info)
- }
- return info
-}
-
-// createField creates a fieldInfo for the given field.
-func (c *cache) createField(field reflect.StructField, info *structInfo) {
- alias, options := fieldAlias(field, c.tag)
- if alias == "-" {
- // Ignore this field.
- return
- }
- // Check if the type is supported and don't cache it if not.
- // First let's get the basic type.
- isSlice, isStruct := false, false
- ft := field.Type
- if ft.Kind() == reflect.Ptr {
- ft = ft.Elem()
- }
- if isSlice = ft.Kind() == reflect.Slice; isSlice {
- ft = ft.Elem()
- if ft.Kind() == reflect.Ptr {
- ft = ft.Elem()
- }
- }
- if ft.Kind() == reflect.Array {
- ft = ft.Elem()
- if ft.Kind() == reflect.Ptr {
- ft = ft.Elem()
- }
- }
- if isStruct = ft.Kind() == reflect.Struct; !isStruct {
- if conv := c.conv[ft.Kind()]; conv == nil {
- // Type is not supported.
- return
- }
- }
-
- info.fields = append(info.fields, &fieldInfo{
- typ: field.Type,
- name: field.Name,
- ss: isSlice && isStruct,
- alias: alias,
- required: options.Contains("required"),
- })
-}
-
-// converter returns the converter for a type.
-func (c *cache) converter(t reflect.Type) Converter {
- conv := c.regconv[t]
- if conv == nil {
- conv = c.conv[t.Kind()]
- }
- return conv
-}
-
-// ----------------------------------------------------------------------------
-
-type structInfo struct {
- fields []*fieldInfo
-}
-
-func (i *structInfo) get(alias string) *fieldInfo {
- for _, field := range i.fields {
- if strings.EqualFold(field.alias, alias) {
- return field
- }
- }
- return nil
-}
-
-type fieldInfo struct {
- typ reflect.Type
- name string // field name in the struct.
- ss bool // true if this is a slice of structs.
- alias string
- required bool // tag option
-}
-
-type pathPart struct {
- field *fieldInfo
- path []string // path to the field: walks structs using field names.
- index int // struct index in slices of structs.
-}
-
-// ----------------------------------------------------------------------------
-
-// fieldAlias parses a field tag to get a field alias.
-func fieldAlias(field reflect.StructField, tagName string) (alias string, options tagOptions) {
- if tag := field.Tag.Get(tagName); tag != "" {
- alias, options = parseTag(tag)
- }
- if alias == "" {
- alias = field.Name
- }
- return alias, options
-}
-
-// tagOptions is the string following a comma in a struct field's tag, or
-// the empty string. It does not include the leading comma.
-type tagOptions []string
-
-// parseTag splits a struct field's url tag into its name and comma-separated
-// options.
-func parseTag(tag string) (string, tagOptions) {
- s := strings.Split(tag, ",")
- return s[0], s[1:]
-}
-
-// Contains checks whether the tagOptions contains the specified option.
-func (o tagOptions) Contains(option string) bool {
- for _, s := range o {
- if s == option {
- return true
- }
- }
- return false
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/converter.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/converter.go
deleted file mode 100644
index b33e942..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/converter.go
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package schema
-
-import (
- "reflect"
- "strconv"
-)
-
-type Converter func(string) reflect.Value
-
-var (
- invalidValue = reflect.Value{}
- boolType = reflect.Bool
- float32Type = reflect.Float32
- float64Type = reflect.Float64
- intType = reflect.Int
- int8Type = reflect.Int8
- int16Type = reflect.Int16
- int32Type = reflect.Int32
- int64Type = reflect.Int64
- stringType = reflect.String
- uintType = reflect.Uint
- uint8Type = reflect.Uint8
- uint16Type = reflect.Uint16
- uint32Type = reflect.Uint32
- uint64Type = reflect.Uint64
-)
-
-// Default converters for basic types.
-var converters = map[reflect.Kind]Converter{
- boolType: convertBool,
- float32Type: convertFloat32,
- float64Type: convertFloat64,
- intType: convertInt,
- int8Type: convertInt8,
- int16Type: convertInt16,
- int32Type: convertInt32,
- int64Type: convertInt64,
- stringType: convertString,
- uintType: convertUint,
- uint8Type: convertUint8,
- uint16Type: convertUint16,
- uint32Type: convertUint32,
- uint64Type: convertUint64,
-}
-
-func convertBool(value string) reflect.Value {
- if value == "on" {
- return reflect.ValueOf(true)
- } else if v, err := strconv.ParseBool(value); err == nil {
- return reflect.ValueOf(v)
- }
- return invalidValue
-}
-
-func convertFloat32(value string) reflect.Value {
- if v, err := strconv.ParseFloat(value, 32); err == nil {
- return reflect.ValueOf(float32(v))
- }
- return invalidValue
-}
-
-func convertFloat64(value string) reflect.Value {
- if v, err := strconv.ParseFloat(value, 64); err == nil {
- return reflect.ValueOf(v)
- }
- return invalidValue
-}
-
-func convertInt(value string) reflect.Value {
- if v, err := strconv.ParseInt(value, 10, 0); err == nil {
- return reflect.ValueOf(int(v))
- }
- return invalidValue
-}
-
-func convertInt8(value string) reflect.Value {
- if v, err := strconv.ParseInt(value, 10, 8); err == nil {
- return reflect.ValueOf(int8(v))
- }
- return invalidValue
-}
-
-func convertInt16(value string) reflect.Value {
- if v, err := strconv.ParseInt(value, 10, 16); err == nil {
- return reflect.ValueOf(int16(v))
- }
- return invalidValue
-}
-
-func convertInt32(value string) reflect.Value {
- if v, err := strconv.ParseInt(value, 10, 32); err == nil {
- return reflect.ValueOf(int32(v))
- }
- return invalidValue
-}
-
-func convertInt64(value string) reflect.Value {
- if v, err := strconv.ParseInt(value, 10, 64); err == nil {
- return reflect.ValueOf(v)
- }
- return invalidValue
-}
-
-func convertString(value string) reflect.Value {
- return reflect.ValueOf(value)
-}
-
-func convertUint(value string) reflect.Value {
- if v, err := strconv.ParseUint(value, 10, 0); err == nil {
- return reflect.ValueOf(uint(v))
- }
- return invalidValue
-}
-
-func convertUint8(value string) reflect.Value {
- if v, err := strconv.ParseUint(value, 10, 8); err == nil {
- return reflect.ValueOf(uint8(v))
- }
- return invalidValue
-}
-
-func convertUint16(value string) reflect.Value {
- if v, err := strconv.ParseUint(value, 10, 16); err == nil {
- return reflect.ValueOf(uint16(v))
- }
- return invalidValue
-}
-
-func convertUint32(value string) reflect.Value {
- if v, err := strconv.ParseUint(value, 10, 32); err == nil {
- return reflect.ValueOf(uint32(v))
- }
- return invalidValue
-}
-
-func convertUint64(value string) reflect.Value {
- if v, err := strconv.ParseUint(value, 10, 64); err == nil {
- return reflect.ValueOf(v)
- }
- return invalidValue
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder.go
deleted file mode 100644
index 7ebe1b1..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder.go
+++ /dev/null
@@ -1,343 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package schema
-
-import (
- "encoding"
- "errors"
- "fmt"
- "reflect"
- "strings"
-)
-
-// NewDecoder returns a new Decoder.
-func NewDecoder() *Decoder {
- return &Decoder{cache: newCache()}
-}
-
-// Decoder decodes values from a map[string][]string to a struct.
-type Decoder struct {
- cache *cache
- zeroEmpty bool
- ignoreUnknownKeys bool
-}
-
-// SetAliasTag changes the tag used to locate custom field aliases.
-// The default tag is "schema".
-func (d *Decoder) SetAliasTag(tag string) {
- d.cache.tag = tag
-}
-
-// ZeroEmpty controls the behaviour when the decoder encounters empty values
-// in a map.
-// If z is true and a key in the map has the empty string as a value
-// then the corresponding struct field is set to the zero value.
-// If z is false then empty strings are ignored.
-//
-// The default value is false, that is empty values do not change
-// the value of the struct field.
-func (d *Decoder) ZeroEmpty(z bool) {
- d.zeroEmpty = z
-}
-
-// IgnoreUnknownKeys controls the behaviour when the decoder encounters unknown
-// keys in the map.
-// If i is true and an unknown field is encountered, it is ignored. This is
-// similar to how unknown keys are handled by encoding/json.
-// If i is false then Decode will return an error. Note that any valid keys
-// will still be decoded in to the target struct.
-//
-// To preserve backwards compatibility, the default value is false.
-func (d *Decoder) IgnoreUnknownKeys(i bool) {
- d.ignoreUnknownKeys = i
-}
-
-// RegisterConverter registers a converter function for a custom type.
-func (d *Decoder) RegisterConverter(value interface{}, converterFunc Converter) {
- d.cache.regconv[reflect.TypeOf(value)] = converterFunc
-}
-
-// Decode decodes a map[string][]string to a struct.
-//
-// The first parameter must be a pointer to a struct.
-//
-// The second parameter is a map, typically url.Values from an HTTP request.
-// Keys are "paths" in dotted notation to the struct fields and nested structs.
-//
-// See the package documentation for a full explanation of the mechanics.
-func (d *Decoder) Decode(dst interface{}, src map[string][]string) error {
- v := reflect.ValueOf(dst)
- if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
- return errors.New("schema: interface must be a pointer to struct")
- }
- v = v.Elem()
- t := v.Type()
- errors := MultiError{}
- for path, values := range src {
- if parts, err := d.cache.parsePath(path, t); err == nil {
- if err = d.decode(v, path, parts, values); err != nil {
- errors[path] = err
- }
- } else if !d.ignoreUnknownKeys {
- errors[path] = fmt.Errorf("schema: invalid path %q", path)
- }
- }
- if len(errors) > 0 {
- return errors
- }
- return d.checkRequired(t, src, "")
-}
-
-// checkRequired checks whether requred field empty
-//
-// check type t recursively if t has struct fields, and prefix is same as parsePath: in dotted notation
-//
-// src is the source map for decoding, we use it here to see if those required fields are included in src
-func (d *Decoder) checkRequired(t reflect.Type, src map[string][]string, prefix string) error {
- struc := d.cache.get(t)
- if struc == nil {
- // unexpect, cache.get never return nil
- return errors.New("cache fail")
- }
-
- for _, f := range struc.fields {
- if f.typ.Kind() == reflect.Struct {
- err := d.checkRequired(f.typ, src, prefix+f.alias+".")
- if err != nil {
- return err
- }
- }
- if f.required {
- key := f.alias
- if prefix != "" {
- key = prefix + key
- }
- if isEmpty(f.typ, src[key]) {
- return fmt.Errorf("%v is empty", key)
- }
- }
- }
- return nil
-}
-
-// isEmpty returns true if value is empty for specific type
-func isEmpty(t reflect.Type, value []string) bool {
- if len(value) == 0 {
- return true
- }
- switch t.Kind() {
- case boolType, float32Type, float64Type, intType, int8Type, int32Type, int64Type, stringType, uint8Type, uint16Type, uint32Type, uint64Type:
- return len(value[0]) == 0
- }
- return false
-}
-
-// decode fills a struct field using a parsed path.
-func (d *Decoder) decode(v reflect.Value, path string, parts []pathPart, values []string) error {
- // Get the field walking the struct fields by index.
- for _, name := range parts[0].path {
- if v.Type().Kind() == reflect.Ptr {
- if v.IsNil() {
- v.Set(reflect.New(v.Type().Elem()))
- }
- v = v.Elem()
- }
- v = v.FieldByName(name)
- }
-
- // Don't even bother for unexported fields.
- if !v.CanSet() {
- return nil
- }
-
- // Dereference if needed.
- t := v.Type()
- if t.Kind() == reflect.Ptr {
- t = t.Elem()
- if v.IsNil() {
- v.Set(reflect.New(t))
- }
- v = v.Elem()
- }
-
- // Slice of structs. Let's go recursive.
- if len(parts) > 1 {
- idx := parts[0].index
- if v.IsNil() || v.Len() < idx+1 {
- value := reflect.MakeSlice(t, idx+1, idx+1)
- if v.Len() < idx+1 {
- // Resize it.
- reflect.Copy(value, v)
- }
- v.Set(value)
- }
- return d.decode(v.Index(idx), path, parts[1:], values)
- }
-
- // Get the converter early in case there is one for a slice type.
- conv := d.cache.converter(t)
- if conv == nil && t.Kind() == reflect.Slice {
- var items []reflect.Value
- elemT := t.Elem()
- isPtrElem := elemT.Kind() == reflect.Ptr
- if isPtrElem {
- elemT = elemT.Elem()
- }
-
- // Try to get a converter for the element type.
- conv := d.cache.converter(elemT)
- if conv == nil {
- // As we are not dealing with slice of structs here, we don't need to check if the type
- // implements TextUnmarshaler interface
- return fmt.Errorf("schema: converter not found for %v", elemT)
- }
-
- for key, value := range values {
- if value == "" {
- if d.zeroEmpty {
- items = append(items, reflect.Zero(elemT))
- }
- } else if item := conv(value); item.IsValid() {
- if isPtrElem {
- ptr := reflect.New(elemT)
- ptr.Elem().Set(item)
- item = ptr
- }
- if item.Type() != elemT && !isPtrElem {
- item = item.Convert(elemT)
- }
- items = append(items, item)
- } else {
- if strings.Contains(value, ",") {
- values := strings.Split(value, ",")
- for _, value := range values {
- if value == "" {
- if d.zeroEmpty {
- items = append(items, reflect.Zero(elemT))
- }
- } else if item := conv(value); item.IsValid() {
- if isPtrElem {
- ptr := reflect.New(elemT)
- ptr.Elem().Set(item)
- item = ptr
- }
- if item.Type() != elemT && !isPtrElem {
- item = item.Convert(elemT)
- }
- items = append(items, item)
- } else {
- return ConversionError{
- Key: path,
- Type: elemT,
- Index: key,
- }
- }
- }
- } else {
- return ConversionError{
- Key: path,
- Type: elemT,
- Index: key,
- }
- }
- }
- }
- value := reflect.Append(reflect.MakeSlice(t, 0, 0), items...)
- v.Set(value)
- } else {
- val := ""
- // Use the last value provided if any values were provided
- if len(values) > 0 {
- val = values[len(values)-1]
- }
-
- if val == "" {
- if d.zeroEmpty {
- v.Set(reflect.Zero(t))
- }
- } else if conv != nil {
- if value := conv(val); value.IsValid() {
- v.Set(value.Convert(t))
- } else {
- return ConversionError{
- Key: path,
- Type: t,
- Index: -1,
- }
- }
- } else {
- // When there's no registered conversion for the custom type, we will check if the type
- // implements the TextUnmarshaler interface. As the UnmarshalText function should be applied
- // to the pointer of the type, we convert the value to pointer.
- if v.CanAddr() {
- v = v.Addr()
- }
-
- if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
- if err := u.UnmarshalText([]byte(val)); err != nil {
- return ConversionError{
- Key: path,
- Type: t,
- Index: -1,
- Err: err,
- }
- }
-
- } else {
- return fmt.Errorf("schema: converter not found for %v", t)
- }
- }
- }
- return nil
-}
-
-// Errors ---------------------------------------------------------------------
-
-// ConversionError stores information about a failed conversion.
-type ConversionError struct {
- Key string // key from the source map.
- Type reflect.Type // expected type of elem
- Index int // index for multi-value fields; -1 for single-value fields.
- Err error // low-level error (when it exists)
-}
-
-func (e ConversionError) Error() string {
- var output string
-
- if e.Index < 0 {
- output = fmt.Sprintf("schema: error converting value for %q", e.Key)
- } else {
- output = fmt.Sprintf("schema: error converting value for index %d of %q",
- e.Index, e.Key)
- }
-
- if e.Err != nil {
- output = fmt.Sprintf("%s. Details: %s", output, e.Err)
- }
-
- return output
-}
-
-// MultiError stores multiple decoding errors.
-//
-// Borrowed from the App Engine SDK.
-type MultiError map[string]error
-
-func (e MultiError) Error() string {
- s := ""
- for _, err := range e {
- s = err.Error()
- break
- }
- switch len(e) {
- case 0:
- return "(0 errors)"
- case 1:
- return s
- case 2:
- return s + " (and 1 other error)"
- }
- return fmt.Sprintf("%s (and %d other errors)", s, len(e)-1)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder_test.go
deleted file mode 100644
index 4593916..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder_test.go
+++ /dev/null
@@ -1,1460 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package schema
-
-import (
- "encoding/hex"
- "errors"
- "reflect"
- "strings"
- "testing"
- "time"
-)
-
-type IntAlias int
-
-// All cases we want to cover, in a nutshell.
-type S1 struct {
- F01 int `schema:"f1"`
- F02 *int `schema:"f2"`
- F03 []int `schema:"f3"`
- F04 []*int `schema:"f4"`
- F05 *[]int `schema:"f5"`
- F06 *[]*int `schema:"f6"`
- F07 S2 `schema:"f7"`
- F08 *S1 `schema:"f8"`
- F09 int `schema:"-"`
- F10 []S1 `schema:"f10"`
- F11 []*S1 `schema:"f11"`
- F12 *[]S1 `schema:"f12"`
- F13 *[]*S1 `schema:"f13"`
- F14 int `schema:"f14"`
- F15 IntAlias `schema:"f15"`
- F16 []IntAlias `schema:"f16"`
- F17 S19 `schema:"f17"`
-}
-
-type S2 struct {
- F01 *[]*int `schema:"f1"`
-}
-
-type S19 [2]byte
-
-func (id *S19) UnmarshalText(text []byte) error {
- buf, err := hex.DecodeString(string(text))
- if err != nil {
- return err
- }
- if len(buf) > len(*id) {
- return errors.New("out of range")
- }
- for i := range buf {
- (*id)[i] = buf[i]
- }
- return nil
-}
-
-func TestAll(t *testing.T) {
- v := map[string][]string{
- "f1": {"1"},
- "f2": {"2"},
- "f3": {"31", "32"},
- "f4": {"41", "42"},
- "f5": {"51", "52"},
- "f6": {"61", "62"},
- "f7.f1": {"71", "72"},
- "f8.f8.f7.f1": {"81", "82"},
- "f9": {"9"},
- "f10.0.f10.0.f6": {"101", "102"},
- "f10.0.f10.1.f6": {"103", "104"},
- "f11.0.f11.0.f6": {"111", "112"},
- "f11.0.f11.1.f6": {"113", "114"},
- "f12.0.f12.0.f6": {"121", "122"},
- "f12.0.f12.1.f6": {"123", "124"},
- "f13.0.f13.0.f6": {"131", "132"},
- "f13.0.f13.1.f6": {"133", "134"},
- "f14": {},
- "f15": {"151"},
- "f16": {"161", "162"},
- "f17": {"1a2b"},
- }
- f2 := 2
- f41, f42 := 41, 42
- f61, f62 := 61, 62
- f71, f72 := 71, 72
- f81, f82 := 81, 82
- f101, f102, f103, f104 := 101, 102, 103, 104
- f111, f112, f113, f114 := 111, 112, 113, 114
- f121, f122, f123, f124 := 121, 122, 123, 124
- f131, f132, f133, f134 := 131, 132, 133, 134
- var f151 IntAlias = 151
- var f161, f162 IntAlias = 161, 162
- e := S1{
- F01: 1,
- F02: &f2,
- F03: []int{31, 32},
- F04: []*int{&f41, &f42},
- F05: &[]int{51, 52},
- F06: &[]*int{&f61, &f62},
- F07: S2{
- F01: &[]*int{&f71, &f72},
- },
- F08: &S1{
- F08: &S1{
- F07: S2{
- F01: &[]*int{&f81, &f82},
- },
- },
- },
- F09: 0,
- F10: []S1{
- S1{
- F10: []S1{
- S1{F06: &[]*int{&f101, &f102}},
- S1{F06: &[]*int{&f103, &f104}},
- },
- },
- },
- F11: []*S1{
- &S1{
- F11: []*S1{
- &S1{F06: &[]*int{&f111, &f112}},
- &S1{F06: &[]*int{&f113, &f114}},
- },
- },
- },
- F12: &[]S1{
- S1{
- F12: &[]S1{
- S1{F06: &[]*int{&f121, &f122}},
- S1{F06: &[]*int{&f123, &f124}},
- },
- },
- },
- F13: &[]*S1{
- &S1{
- F13: &[]*S1{
- &S1{F06: &[]*int{&f131, &f132}},
- &S1{F06: &[]*int{&f133, &f134}},
- },
- },
- },
- F14: 0,
- F15: f151,
- F16: []IntAlias{f161, f162},
- F17: S19{0x1a, 0x2b},
- }
-
- s := &S1{}
- _ = NewDecoder().Decode(s, v)
-
- vals := func(values []*int) []int {
- r := make([]int, len(values))
- for k, v := range values {
- r[k] = *v
- }
- return r
- }
-
- if s.F01 != e.F01 {
- t.Errorf("f1: expected %v, got %v", e.F01, s.F01)
- }
- if s.F02 == nil {
- t.Errorf("f2: expected %v, got nil", *e.F02)
- } else if *s.F02 != *e.F02 {
- t.Errorf("f2: expected %v, got %v", *e.F02, *s.F02)
- }
- if s.F03 == nil {
- t.Errorf("f3: expected %v, got nil", e.F03)
- } else if len(s.F03) != 2 || s.F03[0] != e.F03[0] || s.F03[1] != e.F03[1] {
- t.Errorf("f3: expected %v, got %v", e.F03, s.F03)
- }
- if s.F04 == nil {
- t.Errorf("f4: expected %v, got nil", e.F04)
- } else {
- if len(s.F04) != 2 || *(s.F04)[0] != *(e.F04)[0] || *(s.F04)[1] != *(e.F04)[1] {
- t.Errorf("f4: expected %v, got %v", vals(e.F04), vals(s.F04))
- }
- }
- if s.F05 == nil {
- t.Errorf("f5: expected %v, got nil", e.F05)
- } else {
- sF05, eF05 := *s.F05, *e.F05
- if len(sF05) != 2 || sF05[0] != eF05[0] || sF05[1] != eF05[1] {
- t.Errorf("f5: expected %v, got %v", eF05, sF05)
- }
- }
- if s.F06 == nil {
- t.Errorf("f6: expected %v, got nil", vals(*e.F06))
- } else {
- sF06, eF06 := *s.F06, *e.F06
- if len(sF06) != 2 || *(sF06)[0] != *(eF06)[0] || *(sF06)[1] != *(eF06)[1] {
- t.Errorf("f6: expected %v, got %v", vals(eF06), vals(sF06))
- }
- }
- if s.F07.F01 == nil {
- t.Errorf("f7.f1: expected %v, got nil", vals(*e.F07.F01))
- } else {
- sF07, eF07 := *s.F07.F01, *e.F07.F01
- if len(sF07) != 2 || *(sF07)[0] != *(eF07)[0] || *(sF07)[1] != *(eF07)[1] {
- t.Errorf("f7.f1: expected %v, got %v", vals(eF07), vals(sF07))
- }
- }
- if s.F08 == nil {
- t.Errorf("f8: got nil")
- } else if s.F08.F08 == nil {
- t.Errorf("f8.f8: got nil")
- } else if s.F08.F08.F07.F01 == nil {
- t.Errorf("f8.f8.f7.f1: expected %v, got nil", vals(*e.F08.F08.F07.F01))
- } else {
- sF08, eF08 := *s.F08.F08.F07.F01, *e.F08.F08.F07.F01
- if len(sF08) != 2 || *(sF08)[0] != *(eF08)[0] || *(sF08)[1] != *(eF08)[1] {
- t.Errorf("f8.f8.f7.f1: expected %v, got %v", vals(eF08), vals(sF08))
- }
- }
- if s.F09 != e.F09 {
- t.Errorf("f9: expected %v, got %v", e.F09, s.F09)
- }
- if s.F10 == nil {
- t.Errorf("f10: got nil")
- } else if len(s.F10) != 1 {
- t.Errorf("f10: expected 1 element, got %v", s.F10)
- } else {
- if len(s.F10[0].F10) != 2 {
- t.Errorf("f10.0.f10: expected 1 element, got %v", s.F10[0].F10)
- } else {
- sF10, eF10 := *s.F10[0].F10[0].F06, *e.F10[0].F10[0].F06
- if sF10 == nil {
- t.Errorf("f10.0.f10.0.f6: expected %v, got nil", vals(eF10))
- } else {
- if len(sF10) != 2 || *(sF10)[0] != *(eF10)[0] || *(sF10)[1] != *(eF10)[1] {
- t.Errorf("f10.0.f10.0.f6: expected %v, got %v", vals(eF10), vals(sF10))
- }
- }
- sF10, eF10 = *s.F10[0].F10[1].F06, *e.F10[0].F10[1].F06
- if sF10 == nil {
- t.Errorf("f10.0.f10.0.f6: expected %v, got nil", vals(eF10))
- } else {
- if len(sF10) != 2 || *(sF10)[0] != *(eF10)[0] || *(sF10)[1] != *(eF10)[1] {
- t.Errorf("f10.0.f10.0.f6: expected %v, got %v", vals(eF10), vals(sF10))
- }
- }
- }
- }
- if s.F11 == nil {
- t.Errorf("f11: got nil")
- } else if len(s.F11) != 1 {
- t.Errorf("f11: expected 1 element, got %v", s.F11)
- } else {
- if len(s.F11[0].F11) != 2 {
- t.Errorf("f11.0.f11: expected 1 element, got %v", s.F11[0].F11)
- } else {
- sF11, eF11 := *s.F11[0].F11[0].F06, *e.F11[0].F11[0].F06
- if sF11 == nil {
- t.Errorf("f11.0.f11.0.f6: expected %v, got nil", vals(eF11))
- } else {
- if len(sF11) != 2 || *(sF11)[0] != *(eF11)[0] || *(sF11)[1] != *(eF11)[1] {
- t.Errorf("f11.0.f11.0.f6: expected %v, got %v", vals(eF11), vals(sF11))
- }
- }
- sF11, eF11 = *s.F11[0].F11[1].F06, *e.F11[0].F11[1].F06
- if sF11 == nil {
- t.Errorf("f11.0.f11.0.f6: expected %v, got nil", vals(eF11))
- } else {
- if len(sF11) != 2 || *(sF11)[0] != *(eF11)[0] || *(sF11)[1] != *(eF11)[1] {
- t.Errorf("f11.0.f11.0.f6: expected %v, got %v", vals(eF11), vals(sF11))
- }
- }
- }
- }
- if s.F12 == nil {
- t.Errorf("f12: got nil")
- } else if len(*s.F12) != 1 {
- t.Errorf("f12: expected 1 element, got %v", *s.F12)
- } else {
- sF12, eF12 := *(s.F12), *(e.F12)
- if len(*sF12[0].F12) != 2 {
- t.Errorf("f12.0.f12: expected 1 element, got %v", *sF12[0].F12)
- } else {
- sF122, eF122 := *(*sF12[0].F12)[0].F06, *(*eF12[0].F12)[0].F06
- if sF122 == nil {
- t.Errorf("f12.0.f12.0.f6: expected %v, got nil", vals(eF122))
- } else {
- if len(sF122) != 2 || *(sF122)[0] != *(eF122)[0] || *(sF122)[1] != *(eF122)[1] {
- t.Errorf("f12.0.f12.0.f6: expected %v, got %v", vals(eF122), vals(sF122))
- }
- }
- sF122, eF122 = *(*sF12[0].F12)[1].F06, *(*eF12[0].F12)[1].F06
- if sF122 == nil {
- t.Errorf("f12.0.f12.0.f6: expected %v, got nil", vals(eF122))
- } else {
- if len(sF122) != 2 || *(sF122)[0] != *(eF122)[0] || *(sF122)[1] != *(eF122)[1] {
- t.Errorf("f12.0.f12.0.f6: expected %v, got %v", vals(eF122), vals(sF122))
- }
- }
- }
- }
- if s.F13 == nil {
- t.Errorf("f13: got nil")
- } else if len(*s.F13) != 1 {
- t.Errorf("f13: expected 1 element, got %v", *s.F13)
- } else {
- sF13, eF13 := *(s.F13), *(e.F13)
- if len(*sF13[0].F13) != 2 {
- t.Errorf("f13.0.f13: expected 1 element, got %v", *sF13[0].F13)
- } else {
- sF132, eF132 := *(*sF13[0].F13)[0].F06, *(*eF13[0].F13)[0].F06
- if sF132 == nil {
- t.Errorf("f13.0.f13.0.f6: expected %v, got nil", vals(eF132))
- } else {
- if len(sF132) != 2 || *(sF132)[0] != *(eF132)[0] || *(sF132)[1] != *(eF132)[1] {
- t.Errorf("f13.0.f13.0.f6: expected %v, got %v", vals(eF132), vals(sF132))
- }
- }
- sF132, eF132 = *(*sF13[0].F13)[1].F06, *(*eF13[0].F13)[1].F06
- if sF132 == nil {
- t.Errorf("f13.0.f13.0.f6: expected %v, got nil", vals(eF132))
- } else {
- if len(sF132) != 2 || *(sF132)[0] != *(eF132)[0] || *(sF132)[1] != *(eF132)[1] {
- t.Errorf("f13.0.f13.0.f6: expected %v, got %v", vals(eF132), vals(sF132))
- }
- }
- }
- }
- if s.F14 != e.F14 {
- t.Errorf("f14: expected %v, got %v", e.F14, s.F14)
- }
- if s.F15 != e.F15 {
- t.Errorf("f15: expected %v, got %v", e.F15, s.F15)
- }
- if s.F16 == nil {
- t.Errorf("f16: nil")
- } else if len(s.F16) != len(e.F16) {
- t.Errorf("f16: expected len %d, got %d", len(e.F16), len(s.F16))
- } else if !reflect.DeepEqual(s.F16, e.F16) {
- t.Errorf("f16: expected %v, got %v", e.F16, s.F16)
- }
- if s.F17 != e.F17 {
- t.Errorf("f17: expected %v, got %v", e.F17, s.F17)
- }
-}
-
-func BenchmarkAll(b *testing.B) {
- v := map[string][]string{
- "f1": {"1"},
- "f2": {"2"},
- "f3": {"31", "32"},
- "f4": {"41", "42"},
- "f5": {"51", "52"},
- "f6": {"61", "62"},
- "f7.f1": {"71", "72"},
- "f8.f8.f7.f1": {"81", "82"},
- "f9": {"9"},
- "f10.0.f10.0.f6": {"101", "102"},
- "f10.0.f10.1.f6": {"103", "104"},
- "f11.0.f11.0.f6": {"111", "112"},
- "f11.0.f11.1.f6": {"113", "114"},
- "f12.0.f12.0.f6": {"121", "122"},
- "f12.0.f12.1.f6": {"123", "124"},
- "f13.0.f13.0.f6": {"131", "132"},
- "f13.0.f13.1.f6": {"133", "134"},
- }
-
- b.ResetTimer()
-
- for i := 0; i < b.N; i++ {
- s := &S1{}
- _ = NewDecoder().Decode(s, v)
- }
-}
-
-// ----------------------------------------------------------------------------
-
-type S3 struct {
- F01 bool
- F02 float32
- F03 float64
- F04 int
- F05 int8
- F06 int16
- F07 int32
- F08 int64
- F09 string
- F10 uint
- F11 uint8
- F12 uint16
- F13 uint32
- F14 uint64
-}
-
-func TestDefaultConverters(t *testing.T) {
- v := map[string][]string{
- "F01": {"true"},
- "F02": {"4.2"},
- "F03": {"4.3"},
- "F04": {"-42"},
- "F05": {"-43"},
- "F06": {"-44"},
- "F07": {"-45"},
- "F08": {"-46"},
- "F09": {"foo"},
- "F10": {"42"},
- "F11": {"43"},
- "F12": {"44"},
- "F13": {"45"},
- "F14": {"46"},
- }
- e := S3{
- F01: true,
- F02: 4.2,
- F03: 4.3,
- F04: -42,
- F05: -43,
- F06: -44,
- F07: -45,
- F08: -46,
- F09: "foo",
- F10: 42,
- F11: 43,
- F12: 44,
- F13: 45,
- F14: 46,
- }
- s := &S3{}
- _ = NewDecoder().Decode(s, v)
- if s.F01 != e.F01 {
- t.Errorf("F01: expected %v, got %v", e.F01, s.F01)
- }
- if s.F02 != e.F02 {
- t.Errorf("F02: expected %v, got %v", e.F02, s.F02)
- }
- if s.F03 != e.F03 {
- t.Errorf("F03: expected %v, got %v", e.F03, s.F03)
- }
- if s.F04 != e.F04 {
- t.Errorf("F04: expected %v, got %v", e.F04, s.F04)
- }
- if s.F05 != e.F05 {
- t.Errorf("F05: expected %v, got %v", e.F05, s.F05)
- }
- if s.F06 != e.F06 {
- t.Errorf("F06: expected %v, got %v", e.F06, s.F06)
- }
- if s.F07 != e.F07 {
- t.Errorf("F07: expected %v, got %v", e.F07, s.F07)
- }
- if s.F08 != e.F08 {
- t.Errorf("F08: expected %v, got %v", e.F08, s.F08)
- }
- if s.F09 != e.F09 {
- t.Errorf("F09: expected %v, got %v", e.F09, s.F09)
- }
- if s.F10 != e.F10 {
- t.Errorf("F10: expected %v, got %v", e.F10, s.F10)
- }
- if s.F11 != e.F11 {
- t.Errorf("F11: expected %v, got %v", e.F11, s.F11)
- }
- if s.F12 != e.F12 {
- t.Errorf("F12: expected %v, got %v", e.F12, s.F12)
- }
- if s.F13 != e.F13 {
- t.Errorf("F13: expected %v, got %v", e.F13, s.F13)
- }
- if s.F14 != e.F14 {
- t.Errorf("F14: expected %v, got %v", e.F14, s.F14)
- }
-}
-
-func TestOn(t *testing.T) {
- v := map[string][]string{
- "F01": {"on"},
- }
- s := S3{}
- err := NewDecoder().Decode(&s, v)
- if err != nil {
- t.Fatal(err)
- }
- if !s.F01 {
- t.Fatal("Value was not set to true")
- }
-}
-
-// ----------------------------------------------------------------------------
-
-func TestInlineStruct(t *testing.T) {
- s1 := &struct {
- F01 bool
- }{}
- s2 := &struct {
- F01 int
- }{}
- v1 := map[string][]string{
- "F01": {"true"},
- }
- v2 := map[string][]string{
- "F01": {"42"},
- }
- decoder := NewDecoder()
- _ = decoder.Decode(s1, v1)
- if s1.F01 != true {
- t.Errorf("s1: expected %v, got %v", true, s1.F01)
- }
- _ = decoder.Decode(s2, v2)
- if s2.F01 != 42 {
- t.Errorf("s2: expected %v, got %v", 42, s2.F01)
- }
-}
-
-// ----------------------------------------------------------------------------
-
-type Foo struct {
- F01 int
- F02 Bar
- Bif []Baz
-}
-
-type Bar struct {
- F01 string
- F02 string
- F03 string
- F14 string
- S05 string
- Str string
-}
-
-type Baz struct {
- F99 []string
-}
-
-func TestSimpleExample(t *testing.T) {
- data := map[string][]string{
- "F01": {"1"},
- "F02.F01": {"S1"},
- "F02.F02": {"S2"},
- "F02.F03": {"S3"},
- "F02.F14": {"S4"},
- "F02.S05": {"S5"},
- "F02.Str": {"Str"},
- "Bif.0.F99": {"A", "B", "C"},
- }
-
- e := &Foo{
- F01: 1,
- F02: Bar{
- F01: "S1",
- F02: "S2",
- F03: "S3",
- F14: "S4",
- S05: "S5",
- Str: "Str",
- },
- Bif: []Baz{{
- F99: []string{"A", "B", "C"}},
- },
- }
-
- s := &Foo{}
- _ = NewDecoder().Decode(s, data)
-
- if s.F01 != e.F01 {
- t.Errorf("F01: expected %v, got %v", e.F01, s.F01)
- }
- if s.F02.F01 != e.F02.F01 {
- t.Errorf("F02.F01: expected %v, got %v", e.F02.F01, s.F02.F01)
- }
- if s.F02.F02 != e.F02.F02 {
- t.Errorf("F02.F02: expected %v, got %v", e.F02.F02, s.F02.F02)
- }
- if s.F02.F03 != e.F02.F03 {
- t.Errorf("F02.F03: expected %v, got %v", e.F02.F03, s.F02.F03)
- }
- if s.F02.F14 != e.F02.F14 {
- t.Errorf("F02.F14: expected %v, got %v", e.F02.F14, s.F02.F14)
- }
- if s.F02.S05 != e.F02.S05 {
- t.Errorf("F02.S05: expected %v, got %v", e.F02.S05, s.F02.S05)
- }
- if s.F02.Str != e.F02.Str {
- t.Errorf("F02.Str: expected %v, got %v", e.F02.Str, s.F02.Str)
- }
- if len(s.Bif) != len(e.Bif) {
- t.Errorf("Bif len: expected %d, got %d", len(e.Bif), len(s.Bif))
- } else {
- if len(s.Bif[0].F99) != len(e.Bif[0].F99) {
- t.Errorf("Bif[0].F99 len: expected %d, got %d", len(e.Bif[0].F99), len(s.Bif[0].F99))
- }
- }
-}
-
-// ----------------------------------------------------------------------------
-
-type S4 struct {
- F01 int64
- F02 float64
- F03 bool
-}
-
-func TestConversionError(t *testing.T) {
- data := map[string][]string{
- "F01": {"foo"},
- "F02": {"bar"},
- "F03": {"baz"},
- }
- s := &S4{}
- e := NewDecoder().Decode(s, data)
-
- m := e.(MultiError)
- if len(m) != 3 {
- t.Errorf("Expected 3 errors, got %v", m)
- }
-}
-
-// ----------------------------------------------------------------------------
-
-type S5 struct {
- F01 []string
-}
-
-func TestEmptyValue(t *testing.T) {
- data := map[string][]string{
- "F01": {"", "foo"},
- }
- s := &S5{}
- NewDecoder().Decode(s, data)
- if len(s.F01) != 1 {
- t.Errorf("Expected 1 values in F01")
- }
-}
-
-func TestEmptyValueZeroEmpty(t *testing.T) {
- data := map[string][]string{
- "F01": {"", "foo"},
- }
- s := S5{}
- d := NewDecoder()
- d.ZeroEmpty(true)
- err := d.Decode(&s, data)
- if err != nil {
- t.Fatal(err)
- }
- if len(s.F01) != 2 {
- t.Errorf("Expected 1 values in F01")
- }
-}
-
-// ----------------------------------------------------------------------------
-
-type S6 struct {
- id string
-}
-
-func TestUnexportedField(t *testing.T) {
- data := map[string][]string{
- "id": {"identifier"},
- }
- s := &S6{}
- NewDecoder().Decode(s, data)
- if s.id != "" {
- t.Errorf("Unexported field expected to be ignored")
- }
-}
-
-// ----------------------------------------------------------------------------
-
-type S7 struct {
- ID string
-}
-
-func TestMultipleValues(t *testing.T) {
- data := map[string][]string{
- "ID": {"0", "1"},
- }
-
- s := S7{}
- NewDecoder().Decode(&s, data)
- if s.ID != "1" {
- t.Errorf("Last defined value must be used when multiple values for same field are provided")
- }
-}
-
-type S8 struct {
- ID string `json:"id"`
-}
-
-func TestSetAliasTag(t *testing.T) {
- data := map[string][]string{
- "id": {"foo"},
- }
-
- s := S8{}
- dec := NewDecoder()
- dec.SetAliasTag("json")
- dec.Decode(&s, data)
- if s.ID != "foo" {
- t.Fatalf("Bad value: got %q, want %q", s.ID, "foo")
- }
-}
-
-func TestZeroEmpty(t *testing.T) {
- data := map[string][]string{
- "F01": {""},
- "F03": {"true"},
- }
- s := S4{1, 1, false}
- d := NewDecoder()
- d.ZeroEmpty(true)
-
- err := d.Decode(&s, data)
- if err != nil {
- t.Fatal(err)
- }
- if s.F01 != 0 {
- t.Errorf("F01: got %v, want %v", s.F01, 0)
- }
- if s.F02 != 1 {
- t.Errorf("F02: got %v, want %v", s.F02, 1)
- }
- if s.F03 != true {
- t.Errorf("F03: got %v, want %v", s.F03, true)
- }
-}
-
-func TestNoZeroEmpty(t *testing.T) {
- data := map[string][]string{
- "F01": {""},
- "F03": {"true"},
- }
- s := S4{1, 1, false}
- d := NewDecoder()
- d.ZeroEmpty(false)
- err := d.Decode(&s, data)
- if err != nil {
- t.Fatal(err)
- }
- if s.F01 != 1 {
- t.Errorf("F01: got %v, want %v", s.F01, 1)
- }
- if s.F02 != 1 {
- t.Errorf("F02: got %v, want %v", s.F02, 1)
- }
- if s.F03 != true {
- t.Errorf("F03: got %v, want %v", s.F03, true)
- }
-}
-
-// ----------------------------------------------------------------------------
-
-type S9 struct {
- Id string
-}
-
-type S10 struct {
- S9
-}
-
-func TestEmbeddedField(t *testing.T) {
- data := map[string][]string{
- "Id": {"identifier"},
- }
- s := &S10{}
- NewDecoder().Decode(s, data)
- if s.Id != "identifier" {
- t.Errorf("Missing support for embedded fields")
- }
-}
-
-type S11 struct {
- S10
-}
-
-func TestMultipleLevelEmbeddedField(t *testing.T) {
- data := map[string][]string{
- "Id": {"identifier"},
- }
- s := &S11{}
- err := NewDecoder().Decode(s, data)
- if s.Id != "identifier" {
- t.Errorf("Missing support for multiple-level embedded fields (%v)", err)
- }
-}
-
-func TestInvalidPath(t *testing.T) {
- data := map[string][]string{
- "Foo.Bar": {"baz"},
- }
- s := S9{}
- err := NewDecoder().Decode(&s, data)
- expectedErr := `schema: invalid path "Foo.Bar"`
- if err.Error() != expectedErr {
- t.Fatalf("got %q, want %q", err, expectedErr)
- }
-}
-
-func TestInvalidPathIgnoreUnknownKeys(t *testing.T) {
- data := map[string][]string{
- "Foo.Bar": {"baz"},
- }
- s := S9{}
- dec := NewDecoder()
- dec.IgnoreUnknownKeys(true)
- err := dec.Decode(&s, data)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-// ----------------------------------------------------------------------------
-
-type S1NT struct {
- F1 int
- F2 *int
- F3 []int
- F4 []*int
- F5 *[]int
- F6 *[]*int
- F7 S2
- F8 *S1
- F9 int `schema:"-"`
- F10 []S1
- F11 []*S1
- F12 *[]S1
- F13 *[]*S1
-}
-
-func TestAllNT(t *testing.T) {
- v := map[string][]string{
- "f1": {"1"},
- "f2": {"2"},
- "f3": {"31", "32"},
- "f4": {"41", "42"},
- "f5": {"51", "52"},
- "f6": {"61", "62"},
- "f7.f1": {"71", "72"},
- "f8.f8.f7.f1": {"81", "82"},
- "f9": {"9"},
- "f10.0.f10.0.f6": {"101", "102"},
- "f10.0.f10.1.f6": {"103", "104"},
- "f11.0.f11.0.f6": {"111", "112"},
- "f11.0.f11.1.f6": {"113", "114"},
- "f12.0.f12.0.f6": {"121", "122"},
- "f12.0.f12.1.f6": {"123", "124"},
- "f13.0.f13.0.f6": {"131", "132"},
- "f13.0.f13.1.f6": {"133", "134"},
- }
- f2 := 2
- f41, f42 := 41, 42
- f61, f62 := 61, 62
- f71, f72 := 71, 72
- f81, f82 := 81, 82
- f101, f102, f103, f104 := 101, 102, 103, 104
- f111, f112, f113, f114 := 111, 112, 113, 114
- f121, f122, f123, f124 := 121, 122, 123, 124
- f131, f132, f133, f134 := 131, 132, 133, 134
- e := S1NT{
- F1: 1,
- F2: &f2,
- F3: []int{31, 32},
- F4: []*int{&f41, &f42},
- F5: &[]int{51, 52},
- F6: &[]*int{&f61, &f62},
- F7: S2{
- F01: &[]*int{&f71, &f72},
- },
- F8: &S1{
- F08: &S1{
- F07: S2{
- F01: &[]*int{&f81, &f82},
- },
- },
- },
- F9: 0,
- F10: []S1{
- S1{
- F10: []S1{
- S1{F06: &[]*int{&f101, &f102}},
- S1{F06: &[]*int{&f103, &f104}},
- },
- },
- },
- F11: []*S1{
- &S1{
- F11: []*S1{
- &S1{F06: &[]*int{&f111, &f112}},
- &S1{F06: &[]*int{&f113, &f114}},
- },
- },
- },
- F12: &[]S1{
- S1{
- F12: &[]S1{
- S1{F06: &[]*int{&f121, &f122}},
- S1{F06: &[]*int{&f123, &f124}},
- },
- },
- },
- F13: &[]*S1{
- &S1{
- F13: &[]*S1{
- &S1{F06: &[]*int{&f131, &f132}},
- &S1{F06: &[]*int{&f133, &f134}},
- },
- },
- },
- }
-
- s := &S1NT{}
- _ = NewDecoder().Decode(s, v)
-
- vals := func(values []*int) []int {
- r := make([]int, len(values))
- for k, v := range values {
- r[k] = *v
- }
- return r
- }
-
- if s.F1 != e.F1 {
- t.Errorf("f1: expected %v, got %v", e.F1, s.F1)
- }
- if s.F2 == nil {
- t.Errorf("f2: expected %v, got nil", *e.F2)
- } else if *s.F2 != *e.F2 {
- t.Errorf("f2: expected %v, got %v", *e.F2, *s.F2)
- }
- if s.F3 == nil {
- t.Errorf("f3: expected %v, got nil", e.F3)
- } else if len(s.F3) != 2 || s.F3[0] != e.F3[0] || s.F3[1] != e.F3[1] {
- t.Errorf("f3: expected %v, got %v", e.F3, s.F3)
- }
- if s.F4 == nil {
- t.Errorf("f4: expected %v, got nil", e.F4)
- } else {
- if len(s.F4) != 2 || *(s.F4)[0] != *(e.F4)[0] || *(s.F4)[1] != *(e.F4)[1] {
- t.Errorf("f4: expected %v, got %v", vals(e.F4), vals(s.F4))
- }
- }
- if s.F5 == nil {
- t.Errorf("f5: expected %v, got nil", e.F5)
- } else {
- sF5, eF5 := *s.F5, *e.F5
- if len(sF5) != 2 || sF5[0] != eF5[0] || sF5[1] != eF5[1] {
- t.Errorf("f5: expected %v, got %v", eF5, sF5)
- }
- }
- if s.F6 == nil {
- t.Errorf("f6: expected %v, got nil", vals(*e.F6))
- } else {
- sF6, eF6 := *s.F6, *e.F6
- if len(sF6) != 2 || *(sF6)[0] != *(eF6)[0] || *(sF6)[1] != *(eF6)[1] {
- t.Errorf("f6: expected %v, got %v", vals(eF6), vals(sF6))
- }
- }
- if s.F7.F01 == nil {
- t.Errorf("f7.f1: expected %v, got nil", vals(*e.F7.F01))
- } else {
- sF7, eF7 := *s.F7.F01, *e.F7.F01
- if len(sF7) != 2 || *(sF7)[0] != *(eF7)[0] || *(sF7)[1] != *(eF7)[1] {
- t.Errorf("f7.f1: expected %v, got %v", vals(eF7), vals(sF7))
- }
- }
- if s.F8 == nil {
- t.Errorf("f8: got nil")
- } else if s.F8.F08 == nil {
- t.Errorf("f8.f8: got nil")
- } else if s.F8.F08.F07.F01 == nil {
- t.Errorf("f8.f8.f7.f1: expected %v, got nil", vals(*e.F8.F08.F07.F01))
- } else {
- sF8, eF8 := *s.F8.F08.F07.F01, *e.F8.F08.F07.F01
- if len(sF8) != 2 || *(sF8)[0] != *(eF8)[0] || *(sF8)[1] != *(eF8)[1] {
- t.Errorf("f8.f8.f7.f1: expected %v, got %v", vals(eF8), vals(sF8))
- }
- }
- if s.F9 != e.F9 {
- t.Errorf("f9: expected %v, got %v", e.F9, s.F9)
- }
- if s.F10 == nil {
- t.Errorf("f10: got nil")
- } else if len(s.F10) != 1 {
- t.Errorf("f10: expected 1 element, got %v", s.F10)
- } else {
- if len(s.F10[0].F10) != 2 {
- t.Errorf("f10.0.f10: expected 1 element, got %v", s.F10[0].F10)
- } else {
- sF10, eF10 := *s.F10[0].F10[0].F06, *e.F10[0].F10[0].F06
- if sF10 == nil {
- t.Errorf("f10.0.f10.0.f6: expected %v, got nil", vals(eF10))
- } else {
- if len(sF10) != 2 || *(sF10)[0] != *(eF10)[0] || *(sF10)[1] != *(eF10)[1] {
- t.Errorf("f10.0.f10.0.f6: expected %v, got %v", vals(eF10), vals(sF10))
- }
- }
- sF10, eF10 = *s.F10[0].F10[1].F06, *e.F10[0].F10[1].F06
- if sF10 == nil {
- t.Errorf("f10.0.f10.0.f6: expected %v, got nil", vals(eF10))
- } else {
- if len(sF10) != 2 || *(sF10)[0] != *(eF10)[0] || *(sF10)[1] != *(eF10)[1] {
- t.Errorf("f10.0.f10.0.f6: expected %v, got %v", vals(eF10), vals(sF10))
- }
- }
- }
- }
- if s.F11 == nil {
- t.Errorf("f11: got nil")
- } else if len(s.F11) != 1 {
- t.Errorf("f11: expected 1 element, got %v", s.F11)
- } else {
- if len(s.F11[0].F11) != 2 {
- t.Errorf("f11.0.f11: expected 1 element, got %v", s.F11[0].F11)
- } else {
- sF11, eF11 := *s.F11[0].F11[0].F06, *e.F11[0].F11[0].F06
- if sF11 == nil {
- t.Errorf("f11.0.f11.0.f6: expected %v, got nil", vals(eF11))
- } else {
- if len(sF11) != 2 || *(sF11)[0] != *(eF11)[0] || *(sF11)[1] != *(eF11)[1] {
- t.Errorf("f11.0.f11.0.f6: expected %v, got %v", vals(eF11), vals(sF11))
- }
- }
- sF11, eF11 = *s.F11[0].F11[1].F06, *e.F11[0].F11[1].F06
- if sF11 == nil {
- t.Errorf("f11.0.f11.0.f6: expected %v, got nil", vals(eF11))
- } else {
- if len(sF11) != 2 || *(sF11)[0] != *(eF11)[0] || *(sF11)[1] != *(eF11)[1] {
- t.Errorf("f11.0.f11.0.f6: expected %v, got %v", vals(eF11), vals(sF11))
- }
- }
- }
- }
- if s.F12 == nil {
- t.Errorf("f12: got nil")
- } else if len(*s.F12) != 1 {
- t.Errorf("f12: expected 1 element, got %v", *s.F12)
- } else {
- sF12, eF12 := *(s.F12), *(e.F12)
- if len(*sF12[0].F12) != 2 {
- t.Errorf("f12.0.f12: expected 1 element, got %v", *sF12[0].F12)
- } else {
- sF122, eF122 := *(*sF12[0].F12)[0].F06, *(*eF12[0].F12)[0].F06
- if sF122 == nil {
- t.Errorf("f12.0.f12.0.f6: expected %v, got nil", vals(eF122))
- } else {
- if len(sF122) != 2 || *(sF122)[0] != *(eF122)[0] || *(sF122)[1] != *(eF122)[1] {
- t.Errorf("f12.0.f12.0.f6: expected %v, got %v", vals(eF122), vals(sF122))
- }
- }
- sF122, eF122 = *(*sF12[0].F12)[1].F06, *(*eF12[0].F12)[1].F06
- if sF122 == nil {
- t.Errorf("f12.0.f12.0.f6: expected %v, got nil", vals(eF122))
- } else {
- if len(sF122) != 2 || *(sF122)[0] != *(eF122)[0] || *(sF122)[1] != *(eF122)[1] {
- t.Errorf("f12.0.f12.0.f6: expected %v, got %v", vals(eF122), vals(sF122))
- }
- }
- }
- }
- if s.F13 == nil {
- t.Errorf("f13: got nil")
- } else if len(*s.F13) != 1 {
- t.Errorf("f13: expected 1 element, got %v", *s.F13)
- } else {
- sF13, eF13 := *(s.F13), *(e.F13)
- if len(*sF13[0].F13) != 2 {
- t.Errorf("f13.0.f13: expected 1 element, got %v", *sF13[0].F13)
- } else {
- sF132, eF132 := *(*sF13[0].F13)[0].F06, *(*eF13[0].F13)[0].F06
- if sF132 == nil {
- t.Errorf("f13.0.f13.0.f6: expected %v, got nil", vals(eF132))
- } else {
- if len(sF132) != 2 || *(sF132)[0] != *(eF132)[0] || *(sF132)[1] != *(eF132)[1] {
- t.Errorf("f13.0.f13.0.f6: expected %v, got %v", vals(eF132), vals(sF132))
- }
- }
- sF132, eF132 = *(*sF13[0].F13)[1].F06, *(*eF13[0].F13)[1].F06
- if sF132 == nil {
- t.Errorf("f13.0.f13.0.f6: expected %v, got nil", vals(eF132))
- } else {
- if len(sF132) != 2 || *(sF132)[0] != *(eF132)[0] || *(sF132)[1] != *(eF132)[1] {
- t.Errorf("f13.0.f13.0.f6: expected %v, got %v", vals(eF132), vals(sF132))
- }
- }
- }
- }
-}
-
-// ----------------------------------------------------------------------------
-
-type S12A struct {
- ID []int
-}
-
-func TestCSVSlice(t *testing.T) {
- data := map[string][]string{
- "ID": {"0,1"},
- }
-
- s := S12A{}
- NewDecoder().Decode(&s, data)
- if len(s.ID) != 2 {
- t.Errorf("Expected two values in the result list, got %+v", s.ID)
- }
- if s.ID[0] != 0 || s.ID[1] != 1 {
- t.Errorf("Expected []{0, 1} got %+v", s)
- }
-}
-
-type S12B struct {
- ID []string
-}
-
-//Decode should not split on , into a slice for string only
-func TestCSVStringSlice(t *testing.T) {
- data := map[string][]string{
- "ID": {"0,1"},
- }
-
- s := S12B{}
- NewDecoder().Decode(&s, data)
- if len(s.ID) != 1 {
- t.Errorf("Expected one value in the result list, got %+v", s.ID)
- }
- if s.ID[0] != "0,1" {
- t.Errorf("Expected []{0, 1} got %+v", s)
- }
-}
-
-//Invalid data provided by client should not panic (github issue 33)
-func TestInvalidDataProvidedByClient(t *testing.T) {
- defer func() {
- if r := recover(); r != nil {
- t.Errorf("Panicked calling decoder.Decode: %v", r)
- }
- }()
-
- type S struct {
- f string
- }
-
- data := map[string][]string{
- "f.f": {"v"},
- }
-
- err := NewDecoder().Decode(new(S), data)
- if err == nil {
- t.Errorf("invalid path in decoder.Decode should return an error.")
- }
-}
-
-// underlying cause of error in issue 33
-func TestInvalidPathInCacheParsePath(t *testing.T) {
- type S struct {
- f string
- }
-
- typ := reflect.ValueOf(new(S)).Elem().Type()
- c := newCache()
- _, err := c.parsePath("f.f", typ)
- if err == nil {
- t.Errorf("invalid path in cache.parsePath should return an error.")
- }
-}
-
-// issue 32
-func TestDecodeToTypedField(t *testing.T) {
- type Aa bool
- s1 := &struct{ Aa }{}
- v1 := map[string][]string{"Aa": {"true"}}
- NewDecoder().Decode(s1, v1)
- if s1.Aa != Aa(true) {
- t.Errorf("s1: expected %v, got %v", true, s1.Aa)
- }
-}
-
-// issue 37
-func TestRegisterConverter(t *testing.T) {
- type Aa int
- type Bb int
- s1 := &struct {
- Aa
- Bb
- }{}
- decoder := NewDecoder()
-
- decoder.RegisterConverter(s1.Aa, func(s string) reflect.Value { return reflect.ValueOf(1) })
- decoder.RegisterConverter(s1.Bb, func(s string) reflect.Value { return reflect.ValueOf(2) })
-
- v1 := map[string][]string{"Aa": {"4"}, "Bb": {"5"}}
- decoder.Decode(s1, v1)
-
- if s1.Aa != Aa(1) {
- t.Errorf("s1.Aa: expected %v, got %v", 1, s1.Aa)
- }
- if s1.Bb != Bb(2) {
- t.Errorf("s1.Bb: expected %v, got %v", 2, s1.Bb)
- }
-}
-
-// Issue #40
-func TestRegisterConverterSlice(t *testing.T) {
- decoder := NewDecoder()
- decoder.RegisterConverter([]string{}, func(input string) reflect.Value {
- return reflect.ValueOf(strings.Split(input, ","))
- })
-
- result := struct {
- Multiple []string `schema:"multiple"`
- }{}
-
- expected := []string{"one", "two", "three"}
- decoder.Decode(&result, map[string][]string{
- "multiple": []string{"one,two,three"},
- })
- for i := range expected {
- if got, want := expected[i], result.Multiple[i]; got != want {
- t.Errorf("%d: got %s, want %s", i, got, want)
- }
- }
-}
-
-type S13 struct {
- Value []S14
-}
-
-type S14 struct {
- F1 string
- F2 string
-}
-
-func (n *S14) UnmarshalText(text []byte) error {
- textParts := strings.Split(string(text), " ")
- if len(textParts) < 2 {
- return errors.New("Not a valid name!")
- }
-
- n.F1, n.F2 = textParts[0], textParts[len(textParts)-1]
- return nil
-}
-
-type S15 struct {
- Value []S16
-}
-
-type S16 struct {
- F1 string
- F2 string
-}
-
-func TestCustomTypeSlice(t *testing.T) {
- data := map[string][]string{
- "Value.0": []string{"Louisa May Alcott"},
- "Value.1": []string{"Florence Nightingale"},
- "Value.2": []string{"Clara Barton"},
- }
-
- s := S13{}
- decoder := NewDecoder()
-
- if err := decoder.Decode(&s, data); err != nil {
- t.Fatal(err)
- }
-
- if len(s.Value) != 3 {
- t.Fatalf("Expected 3 values in the result list, got %+v", s.Value)
- }
- if s.Value[0].F1 != "Louisa" || s.Value[0].F2 != "Alcott" {
- t.Errorf("Expected S14{'Louisa', 'Alcott'} got %+v", s.Value[0])
- }
- if s.Value[1].F1 != "Florence" || s.Value[1].F2 != "Nightingale" {
- t.Errorf("Expected S14{'Florence', 'Nightingale'} got %+v", s.Value[1])
- }
- if s.Value[2].F1 != "Clara" || s.Value[2].F2 != "Barton" {
- t.Errorf("Expected S14{'Clara', 'Barton'} got %+v", s.Value[2])
- }
-}
-
-func TestCustomTypeSliceWithError(t *testing.T) {
- data := map[string][]string{
- "Value.0": []string{"Louisa May Alcott"},
- "Value.1": []string{"Florence Nightingale"},
- "Value.2": []string{"Clara"},
- }
-
- s := S13{}
- decoder := NewDecoder()
-
- if err := decoder.Decode(&s, data); err == nil {
- t.Error("Not detecting error in conversion")
- }
-}
-
-func TestNoTextUnmarshalerTypeSlice(t *testing.T) {
- data := map[string][]string{
- "Value.0": []string{"Louisa May Alcott"},
- "Value.1": []string{"Florence Nightingale"},
- "Value.2": []string{"Clara Barton"},
- }
-
- s := S15{}
- decoder := NewDecoder()
-
- if err := decoder.Decode(&s, data); err == nil {
- t.Error("Not detecting when there's no converter")
- }
-}
-
-// ----------------------------------------------------------------------------
-
-type S17 struct {
- Value S14
-}
-
-type S18 struct {
- Value S16
-}
-
-func TestCustomType(t *testing.T) {
- data := map[string][]string{
- "Value": []string{"Louisa May Alcott"},
- }
-
- s := S17{}
- decoder := NewDecoder()
-
- if err := decoder.Decode(&s, data); err != nil {
- t.Fatal(err)
- }
-
- if s.Value.F1 != "Louisa" || s.Value.F2 != "Alcott" {
- t.Errorf("Expected S14{'Louisa', 'Alcott'} got %+v", s.Value)
- }
-}
-
-func TestCustomTypeWithError(t *testing.T) {
- data := map[string][]string{
- "Value": []string{"Louisa"},
- }
-
- s := S17{}
- decoder := NewDecoder()
-
- if err := decoder.Decode(&s, data); err == nil {
- t.Error("Not detecting error in conversion")
- }
-}
-
-func TestNoTextUnmarshalerType(t *testing.T) {
- data := map[string][]string{
- "Value": []string{"Louisa May Alcott"},
- }
-
- s := S18{}
- decoder := NewDecoder()
-
- if err := decoder.Decode(&s, data); err == nil {
- t.Error("Not detecting when there's no converter")
- }
-}
-
-func TestExpectedType(t *testing.T) {
- data := map[string][]string{
- "bools": []string{"1", "a"},
- "date": []string{"invalid"},
- "Foo.Bar": []string{"a", "b"},
- }
-
- type B struct {
- Bar *int
- }
- type A struct {
- Bools []bool `schema:"bools"`
- Date time.Time `schema:"date"`
- Foo B
- }
-
- a := A{}
-
- err := NewDecoder().Decode(&a, data)
-
- e := err.(MultiError)["bools"].(ConversionError)
- if e.Type != reflect.TypeOf(false) && e.Index == 1 {
- t.Errorf("Expected bool, index: 1 got %+v, index: %d", e.Type, e.Index)
- }
- e = err.(MultiError)["date"].(ConversionError)
- if e.Type != reflect.TypeOf(time.Time{}) {
- t.Errorf("Expected time.Time got %+v", e.Type)
- }
- e = err.(MultiError)["Foo.Bar"].(ConversionError)
- if e.Type != reflect.TypeOf(0) {
- t.Errorf("Expected int got %+v", e.Type)
- }
-}
-
-type R1 struct {
- A string `schema:"a,required"`
- B struct {
- C int `schema:"c,required"`
- D float64 `schema:"d"`
- E string `schema:"e,required"`
- } `schema:"b"`
- F []string `schema:"f,required"`
- G []int `schema:"g,othertag"`
- H bool `schema:"h,required"`
-}
-
-func TestRequiredField(t *testing.T) {
- var a R1
- v := map[string][]string{
- "a": []string{"bbb"},
- "b.c": []string{"88"},
- "b.d": []string{"9"},
- "f": []string{""},
- "h": []string{"true"},
- }
- err := NewDecoder().Decode(&a, v)
- if err == nil {
- t.Errorf("error nil, b.e is empty expect")
- return
- }
- // b.e empty
- v["b.e"] = []string{""} // empty string
- err = NewDecoder().Decode(&a, v)
- if err == nil {
- t.Errorf("error nil, b.e is empty expect")
- return
- }
-
- // all fields ok
- v["b.e"] = []string{"nonempty"}
- err = NewDecoder().Decode(&a, v)
- if err != nil {
- t.Errorf("error: %v", err)
- return
- }
-
- // set f empty
- v["f"] = []string{}
- err = NewDecoder().Decode(&a, v)
- if err == nil {
- t.Errorf("error nil, f is empty expect")
- return
- }
- v["f"] = []string{"nonempty"}
-
- // b.c type int with empty string
- v["b.c"] = []string{""}
- err = NewDecoder().Decode(&a, v)
- if err == nil {
- t.Errorf("error nil, b.c is empty expect")
- return
- }
- v["b.c"] = []string{"3"}
-
- // h type bool with empty string
- v["h"] = []string{""}
- err = NewDecoder().Decode(&a, v)
- if err == nil {
- t.Errorf("error nil, h is empty expect")
- return
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/doc.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/doc.go
deleted file mode 100644
index a95e87b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/doc.go
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Package gorilla/schema fills a struct with form values.
-
-The basic usage is really simple. Given this struct:
-
- type Person struct {
- Name string
- Phone string
- }
-
-...we can fill it passing a map to the Decode() function:
-
- values := map[string][]string{
- "Name": {"John"},
- "Phone": {"999-999-999"},
- }
- person := new(Person)
- decoder := schema.NewDecoder()
- decoder.Decode(person, values)
-
-This is just a simple example and it doesn't make a lot of sense to create
-the map manually. Typically it will come from a http.Request object and
-will be of type url.Values: http.Request.Form or http.Request.MultipartForm:
-
- func MyHandler(w http.ResponseWriter, r *http.Request) {
- err := r.ParseForm()
-
- if err != nil {
- // Handle error
- }
-
- decoder := schema.NewDecoder()
- // r.PostForm is a map of our POST form values
- err := decoder.Decode(person, r.PostForm)
-
- if err != nil {
- // Handle error
- }
-
- // Do something with person.Name or person.Phone
- }
-
-Note: it is a good idea to set a Decoder instance as a package global,
-because it caches meta-data about structs, and a instance can be shared safely:
-
- var decoder = schema.NewDecoder()
-
-To define custom names for fields, use a struct tag "schema". To not populate
-certain fields, use a dash for the name and it will be ignored:
-
- type Person struct {
- Name string `schema:"name"` // custom name
- Phone string `schema:"phone"` // custom name
- Admin bool `schema:"-"` // this field is never set
- }
-
-The supported field types in the destination struct are:
-
- * bool
- * float variants (float32, float64)
- * int variants (int, int8, int16, int32, int64)
- * string
- * uint variants (uint, uint8, uint16, uint32, uint64)
- * struct
- * a pointer to one of the above types
- * a slice or a pointer to a slice of one of the above types
-
-Non-supported types are simply ignored, however custom types can be registered
-to be converted.
-
-To fill nested structs, keys must use a dotted notation as the "path" for the
-field. So for example, to fill the struct Person below:
-
- type Phone struct {
- Label string
- Number string
- }
-
- type Person struct {
- Name string
- Phone Phone
- }
-
-...the source map must have the keys "Name", "Phone.Label" and "Phone.Number".
-This means that an HTML form to fill a Person struct must look like this:
-
- <form>
- <input type="text" name="Name">
- <input type="text" name="Phone.Label">
- <input type="text" name="Phone.Number">
- </form>
-
-Single values are filled using the first value for a key from the source map.
-Slices are filled using all values for a key from the source map. So to fill
-a Person with multiple Phone values, like:
-
- type Person struct {
- Name string
- Phones []Phone
- }
-
-...an HTML form that accepts three Phone values would look like this:
-
- <form>
- <input type="text" name="Name">
- <input type="text" name="Phones.0.Label">
- <input type="text" name="Phones.0.Number">
- <input type="text" name="Phones.1.Label">
- <input type="text" name="Phones.1.Number">
- <input type="text" name="Phones.2.Label">
- <input type="text" name="Phones.2.Number">
- </form>
-
-Notice that only for slices of structs the slice index is required.
-This is needed for disambiguation: if the nested struct also had a slice
-field, we could not translate multiple values to it if we did not use an
-index for the parent struct.
-
-There's also the possibility to create a custom type that implements the
-TextUnmarshaler interface, and in this case there's no need to registry
-a converter, like:
-
- type Person struct {
- Emails []Email
- }
-
- type Email struct {
- *mail.Address
- }
-
- func (e *Email) UnmarshalText(text []byte) (err error) {
- e.Address, err = mail.ParseAddress(string(text))
- return
- }
-
-...an HTML form that accepts three Email values would look like this:
-
- <form>
- <input type="email" name="Emails.0">
- <input type="email" name="Emails.1">
- <input type="email" name="Emails.2">
- </form>
-*/
-package schema
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/LICENSE b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/LICENSE
deleted file mode 100644
index 6ac9da6..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2016 Steve Manuel
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/README.md b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/README.md
deleted file mode 100644
index 190c61f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/README.md
+++ /dev/null
@@ -1,51 +0,0 @@
-## Email
-
-I needed a way to send email from a [Ponzu](https://ponzu-cms.org) installation
-running on all kinds of systems without shelling out. `sendmail` or `postfix` et
-al are not standard on all systems, and I didn't want to force users to add API
-keys from a third-party just to send something like an account recovery email.
-
-### Usage:
-`$ go get github.com/nilslice/email`
-
-```go
-package main
-
-import (
- "fmt"
- "github.com/nilslice/email"
-)
-
-func main() {
- msg := email.Message{
- To: "you@server.name", // do not add < > or name in quotes
- From: "me@server.name", // do not add < > or name in quotes
- Subject: "A simple email",
- Body: "Plain text email body. HTML not yet supported, but send a PR!",
- }
-
- err := msg.Send()
- if err != nil {
- fmt.Println(err)
- }
-}
-
-```
-
-### Under the hood
-`email` looks at a `Message`'s `To` field, splits the string on the @ symbol and
-issues an MX lookup to find the mail exchange server(s). Then it iterates over
-all the possibilities in combination with commonly used SMTP ports for non-SSL
-clients: `25, 2525, & 587`
-
-It stops once it has an active client connected to a mail server and sends the
-initial information, the message, and then closes the connection.
-
-Currently, this doesn't support any additional headers or `To` field formatting
-(the recipient's email must be the only string `To` takes). Although these would
-be fairly strightforward to implement, I don't need them yet.. so feel free to
-contribute anything you find useful.
-
-#### Warning
-Be cautious of how often you run this locally or in testing, as it's quite
-likely your IP will be blocked/blacklisted if it is not already. \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email.go
deleted file mode 100644
index 15f0a49..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package email
-
-import (
- "fmt"
- "net"
- "net/smtp"
- "strings"
-)
-
-// Message creates a email to be sent
-type Message struct {
- To string
- From string
- Subject string
- Body string
-}
-
-var (
- ports = []int{25, 2525, 587}
-)
-
-// Send sends a message to recipient(s) listed in the 'To' field of a Message
-func (m Message) Send() error {
- if !strings.Contains(m.To, "@") {
- return fmt.Errorf("Invalid recipient address: <%s>", m.To)
- }
-
- host := strings.Split(m.To, "@")[1]
- addrs, err := net.LookupMX(host)
- if err != nil {
- return err
- }
-
- c, err := newClient(addrs, ports)
- if err != nil {
- return err
- }
-
- err = send(m, c)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func newClient(mx []*net.MX, ports []int) (*smtp.Client, error) {
- for i := range mx {
- for j := range ports {
- server := strings.TrimSuffix(mx[i].Host, ".")
- hostPort := fmt.Sprintf("%s:%d", server, ports[j])
- client, err := smtp.Dial(hostPort)
- if err != nil {
- if j == len(ports)-1 {
- return nil, err
- }
-
- continue
- }
-
- return client, nil
- }
- }
-
- return nil, fmt.Errorf("Couldn't connect to servers %v on any common port.", mx)
-}
-
-func send(m Message, c *smtp.Client) error {
- if err := c.Mail(m.From); err != nil {
- return err
- }
-
- if err := c.Rcpt(m.To); err != nil {
- return err
- }
-
- msg, err := c.Data()
- if err != nil {
- return err
- }
-
- if m.Subject != "" {
- _, err = msg.Write([]byte("Subject: " + m.Subject + "\r\n"))
- if err != nil {
- return err
- }
- }
-
- if m.From != "" {
- _, err = msg.Write([]byte("From: <" + m.From + ">\r\n"))
- if err != nil {
- return err
- }
- }
-
- if m.To != "" {
- _, err = msg.Write([]byte("To: <" + m.To + ">\r\n"))
- if err != nil {
- return err
- }
- }
-
- _, err = fmt.Fprint(msg, m.Body)
- if err != nil {
- return err
- }
-
- err = msg.Close()
- if err != nil {
- return err
- }
-
- err = c.Quit()
- if err != nil {
- return err
- }
-
- return nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email_test.go
deleted file mode 100644
index 3576a79..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email_test.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package email
-
-import (
- "testing"
-)
-
-func TestSend(t *testing.T) {
- m := Message{
- To: "",
- From: "",
- Subject: "",
- Body: "",
- }
-
- err := m.Send()
- if err != nil {
- t.Fatal("Send returned error:", err)
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/LICENSE b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/LICENSE
deleted file mode 100644
index f67119e..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (C) 2015 Steve Manuel <stevenhmanuel@gmail.com>
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/README.md b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/README.md
deleted file mode 100644
index a384dd1..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/README.md
+++ /dev/null
@@ -1,43 +0,0 @@
-# JWT
-
-### Usage
- $ go get github.com/nilslice/jwt
-
-package jwt provides methods to create and check JSON Web Tokens. It only implements HMAC 256 encryption and has a very small footprint, ideal for simple usage when authorizing clients
-
-```go
- package main
-
- import (
- auth "github.com/nilslice/jwt"
- "fmt"
- "net/http"
- "strings"
- )
-
- func main() {
- http.HandleFunc("/auth/new", func(res http.ResponseWriter, req *http.Request) {
- claims := map[string]interface{}{"exp": time.Now().Add(time.Hour * 24).Unix()}
- token, err := auth.New(claims)
- if err != nil {
- http.Error(res, "Error", 500)
- return
- }
- res.Header().Add("Authorization", "Bearer "+token)
-
- res.WriteHeader(http.StatusOK)
- })
-
- http.HandleFunc("/auth", func(res http.ResponseWriter, req *http.Request) {
- userToken := strings.Split(req.Header.Get("Authorization"), " ")[1]
-
- if auth.Passes(userToken) {
- fmt.Println("ok")
- } else {
- fmt.Println("no")
- }
- })
-
- http.ListenAndServe(":8080", nil)
- }
-```
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/doc.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/doc.go
deleted file mode 100644
index aa9a5c8..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/doc.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// Package jwt provides methods to create and check JSON Web Tokens (JWT). It only implements HMAC 256 encryption and has a very small footprint, ideal for simple usage when authorizing clients
-/*
-
- package main
-
- import (
- auth "github.com/nilslice/jwt"
- "fmt"
- "net/http"
- "strings"
- "time"
- )
-
- func main() {
- http.HandleFunc("/auth/new", func(res http.ResponseWriter, req *http.Request) {
- claims := map[string]interface{}{"exp": time.Now().Add(time.Hour * 24).Unix()}
- token, err := auth.New(claims)
- if err != nil {
- http.Error(res, "Error", 500)
- return
- }
- res.Header().Add("Authorization", "Bearer "+token)
-
- res.WriteHeader(http.StatusOK)
- })
-
- http.HandleFunc("/auth", func(res http.ResponseWriter, req *http.Request) {
- userToken := strings.Split(req.Header.Get("Authorization"), " ")[1]
-
- if auth.Passes(userToken) {
- fmt.Println("ok")
- } else {
- fmt.Println("no")
- }
- })
-
- http.ListenAndServe(":8080", nil)
- }
-*/
-package jwt
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/jwt.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/jwt.go
deleted file mode 100644
index 6d7eaa3..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/jwt.go
+++ /dev/null
@@ -1,204 +0,0 @@
-package jwt
-
-import (
- "crypto/hmac"
- "crypto/sha256"
- "encoding/base64"
- "encoding/json"
- "errors"
- "fmt"
- "strings"
-)
-
-var (
- privateKey = []byte("")
- defaultHeader = header{Typ: "JWT", Alg: "HS256"}
- registeredClaims = []string{"iss", "sub", "aud", "exp", "nbf", "iat", "jti"}
-)
-
-type header struct {
- Typ string `json:"typ"`
- Alg string `json:"alg"`
-}
-
-type payload map[string]interface{}
-
-type encoded struct {
- token string
-}
-type decoded struct {
- header string
- payload string
-}
-
-type signedDecoded struct {
- decoded
- signature string
-}
-
-func newEncoded(claims map[string]interface{}) (encoded, error) {
- header, err := json.Marshal(defaultHeader)
- if err != nil {
- return encoded{}, err
- }
-
- for _, claim := range registeredClaims {
- if _, ok := claims[claim]; !ok {
- claims[claim] = nil
- }
- }
-
- payload, err := json.Marshal(claims)
- if err != nil {
- return encoded{}, err
- }
-
- d := decoded{header: string(header), payload: string(payload)}
-
- d.encodeInternal()
- signed, err := d.sign()
- if err != nil {
- return encoded{}, err
- }
-
- token := signed.token()
- e := encoded{token: token}
- return e, nil
-}
-
-func newDecoded(token string) (decoded, error) {
- e := encoded{token: token}
- d, err := e.parseToken()
- if err != nil {
- return d, nil
- }
-
- return d, nil
-}
-
-func encodeToString(src []byte) string {
- return base64.RawURLEncoding.EncodeToString(src)
-}
-
-func (d decoded) getHeader() []byte {
- return []byte(d.header)
-}
-
-func (d decoded) getPayload() []byte {
- return []byte(d.payload)
-}
-
-func (sd signedDecoded) getSignature() []byte {
- return []byte(sd.signature)
-}
-
-func (d *decoded) encodeInternal() {
- d.header = encodeToString(d.getHeader())
- d.payload = encodeToString(d.getPayload())
-}
-
-func (d decoded) dot(internals ...string) string {
- return strings.Join(internals, ".")
-}
-
-func (d *decoded) sign() (signedDecoded, error) {
- if d.header == "" || d.payload == "" {
- return signedDecoded{}, errors.New("Missing header or payload on Decoded")
- }
-
- unsigned := d.dot(d.header, d.payload)
-
- hash := hmac.New(sha256.New, privateKey)
- _, err := hash.Write([]byte(unsigned))
- if err != nil {
- return signedDecoded{}, err
- }
-
- signed := signedDecoded{decoded: *d}
- signed.signature = encodeToString(hash.Sum(nil))
-
- return signed, nil
-}
-
-func (sd signedDecoded) token() string {
- return fmt.Sprintf("%s.%s.%s", sd.getHeader(), sd.getPayload(), sd.getSignature())
-}
-
-func (sd signedDecoded) verify(enc encoded) bool {
- if sd.token() == enc.token {
- return true
- }
- return false
-}
-
-func (e encoded) parseToken() (decoded, error) {
- parts := strings.Split(e.token, ".")
- if len(parts) != 3 {
- return decoded{}, errors.New("Error: incorrect # of results from string parsing")
- }
-
- d := decoded{
- header: parts[0],
- payload: parts[1],
- }
-
- return d, nil
-}
-
-// New returns a token (string) and error. The token is a fully qualified JWT to be sent to a client via HTTP Header or other method. Error returned will be from the newEncoded unexported function.
-func New(claims map[string]interface{}) (string, error) {
- enc, err := newEncoded(claims)
- if err != nil {
- return "", err
- }
-
- return enc.token, nil
-}
-
-// Passes returns a bool indicating whether a token (string) provided has been signed by our server. If true, the client is authenticated and may proceed.
-func Passes(token string) bool {
- dec, err := newDecoded(token)
- if err != nil {
- // may want to log some error here so we have visibility
- // intentionally simplifying return type to bool for ease
- // of use in API. Caller should only do `if auth.Passes(str) {}`
- return false
- }
- signed, err := dec.sign()
- if err != nil {
- return false
- }
-
- return signed.verify(encoded{token: token})
-}
-
-// GetClaims() returns a token's claims, allowing
-// you to check the values to make sure they match
-func GetClaims(token string) map[string]interface{} {
- // decode the token
- dec, err := newDecoded(token)
- if err != nil {
- return nil
- }
-
- // base64 decode payload
- payload, err := base64.RawURLEncoding.DecodeString(dec.payload)
- if err != nil {
- return nil
- }
-
- dst := map[string]interface{}{}
- err = json.Unmarshal(payload, &dst)
- if err != nil {
- return nil
- }
-
- return dst
-
-}
-
-// Secret is a helper function to set the unexported privateKey variable used when signing and verifying tokens.
-// Its argument is type []byte since we expect users to read this value from a file which can be excluded from source code.
-func Secret(key []byte) {
- privateKey = key
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/content/.hold b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/content/.hold
deleted file mode 100644
index e69de29..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/content/.hold
+++ /dev/null
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/content/song.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/content/song.go
deleted file mode 100644
index fa5e802..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/content/song.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package content
-
-import (
- "fmt"
-
- "github.com/ponzu-cms/ponzu/management/editor"
- "github.com/ponzu-cms/ponzu/system/item"
-)
-
-type Song struct {
- item.Item
-
- Title string `json:"title"`
- Artist string `json:"artist"`
- Rating int `json:"rating"`
- Opinion string `json:"opinion"`
- SpotifyUrl string `json:"spotify_url"`
-}
-
-// MarshalEditor writes a buffer of html to edit a Song within the CMS
-// and implements editor.Editable
-func (s *Song) MarshalEditor() ([]byte, error) {
- view, err := editor.Form(s,
- // Take note that the first argument to these Input-like functions
- // is the string version of each Song field, and must follow
- // this pattern for auto-decoding and auto-encoding reasons:
- editor.Field{
- View: editor.Input("Title", s, map[string]string{
- "label": "Title",
- "type": "text",
- "placeholder": "Enter the Title here",
- }),
- },
- editor.Field{
- View: editor.Input("Artist", s, map[string]string{
- "label": "Artist",
- "type": "text",
- "placeholder": "Enter the Artist here",
- }),
- },
- editor.Field{
- View: editor.Input("Rating", s, map[string]string{
- "label": "Rating",
- "type": "text",
- "placeholder": "Enter the Rating here",
- }),
- },
- editor.Field{
- View: editor.Input("Opinion", s, map[string]string{
- "label": "Opinion",
- "type": "text",
- "placeholder": "Enter the Opinion here",
- }),
- },
- editor.Field{
- View: editor.Input("SpotifyUrl", s, map[string]string{
- "label": "SpotifyUrl",
- "type": "text",
- "placeholder": "Enter the SpotifyUrl here",
- }),
- },
- )
-
- if err != nil {
- return nil, fmt.Errorf("Failed to render Song editor view: %s", err.Error())
- }
-
- return view, nil
-}
-
-func init() {
- item.Types["Song"] = func() interface{} { return new(Song) }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/dom.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/dom.go
deleted file mode 100644
index 5888db5..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/dom.go
+++ /dev/null
@@ -1,297 +0,0 @@
-package editor
-
-import (
- "bytes"
- "html"
- "log"
- "strings"
-)
-
-// Element is a basic struct for representing DOM elements
-type Element struct {
- TagName string
- Attrs map[string]string
- Name string
- Label string
- Data string
- ViewBuf *bytes.Buffer
-}
-
-// NewElement returns an Element with Name and Data already processed from the
-// fieldName and content interface provided
-func NewElement(tagName, label, fieldName string, p interface{}, attrs map[string]string) *Element {
- return &Element{
- TagName: tagName,
- Attrs: attrs,
- Name: TagNameFromStructField(fieldName, p),
- Label: label,
- Data: ValueFromStructField(fieldName, p),
- ViewBuf: &bytes.Buffer{},
- }
-}
-
-// DOMElementSelfClose is a special DOM element which is parsed as a
-// self-closing tag and thus needs to be created differently
-func DOMElementSelfClose(e *Element) []byte {
- _, err := e.ViewBuf.WriteString(`<div class="input-field col s12">`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementSelfClose")
- return nil
- }
-
- if e.Label != "" {
- _, err = e.ViewBuf.WriteString(
- `<label class="active" for="` +
- strings.Join(strings.Split(e.Label, " "), "-") + `">` + e.Label +
- `</label>`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementSelfClose")
- return nil
- }
- }
-
- _, err = e.ViewBuf.WriteString(`<` + e.TagName + ` value="`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementSelfClose")
- return nil
- }
-
- _, err = e.ViewBuf.WriteString(html.EscapeString(e.Data) + `" `)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementSelfClose")
- return nil
- }
-
- for attr, value := range e.Attrs {
- _, err := e.ViewBuf.WriteString(attr + `="` + value + `" `)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementSelfClose")
- return nil
- }
- }
- _, err = e.ViewBuf.WriteString(` name="` + e.Name + `" />`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementSelfClose")
- return nil
- }
-
- _, err = e.ViewBuf.WriteString(`</div>`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementSelfClose")
- return nil
- }
-
- return e.ViewBuf.Bytes()
-}
-
-// DOMElementCheckbox is a special DOM element which is parsed as a
-// checkbox input tag and thus needs to be created differently
-func DOMElementCheckbox(e *Element) []byte {
- _, err := e.ViewBuf.WriteString(`<p class="col s6">`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementCheckbox")
- return nil
- }
-
- _, err = e.ViewBuf.WriteString(`<` + e.TagName + ` `)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementCheckbox")
- return nil
- }
-
- for attr, value := range e.Attrs {
- _, err := e.ViewBuf.WriteString(attr + `="` + value + `" `)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementCheckbox")
- return nil
- }
- }
- _, err = e.ViewBuf.WriteString(` name="` + e.Name + `" />`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementCheckbox")
- return nil
- }
-
- if e.Label != "" {
- _, err = e.ViewBuf.WriteString(
- `<label for="` +
- strings.Join(strings.Split(e.Label, " "), "-") + `">` +
- e.Label + `</label>`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementCheckbox")
- return nil
- }
- }
-
- _, err = e.ViewBuf.WriteString(`</p>`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementCheckbox")
- return nil
- }
-
- return e.ViewBuf.Bytes()
-}
-
-// DOMElement creates a DOM element
-func DOMElement(e *Element) []byte {
- _, err := e.ViewBuf.WriteString(`<div class="input-field col s12">`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElement")
- return nil
- }
-
- if e.Label != "" {
- _, err = e.ViewBuf.WriteString(
- `<label class="active" for="` +
- strings.Join(strings.Split(e.Label, " "), "-") + `">` + e.Label +
- `</label>`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElement")
- return nil
- }
- }
-
- _, err = e.ViewBuf.WriteString(`<` + e.TagName + ` `)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElement")
- return nil
- }
-
- for attr, value := range e.Attrs {
- _, err = e.ViewBuf.WriteString(attr + `="` + string(value) + `" `)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElement")
- return nil
- }
- }
- _, err = e.ViewBuf.WriteString(` name="` + e.Name + `" >`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElement")
- return nil
- }
-
- _, err = e.ViewBuf.WriteString(html.EscapeString(e.Data))
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElement")
- return nil
- }
-
- _, err = e.ViewBuf.WriteString(`</` + e.TagName + `>`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElement")
- return nil
- }
-
- _, err = e.ViewBuf.WriteString(`</div>`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElement")
- return nil
- }
-
- return e.ViewBuf.Bytes()
-}
-
-func DOMElementWithChildrenSelect(e *Element, children []*Element) []byte {
- _, err := e.ViewBuf.WriteString(`<div class="input-field col s6">`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementWithChildrenSelect")
- return nil
- }
-
- _, err = e.ViewBuf.WriteString(`<` + e.TagName + ` `)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementWithChildrenSelect")
- return nil
- }
-
- for attr, value := range e.Attrs {
- _, err = e.ViewBuf.WriteString(attr + `="` + value + `" `)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementWithChildrenSelect")
- return nil
- }
- }
- _, err = e.ViewBuf.WriteString(` name="` + e.Name + `" >`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementWithChildrenSelect")
- return nil
- }
-
- // loop over children and create DOMElement for each child
- for _, child := range children {
- _, err = e.ViewBuf.Write(DOMElement(child))
- if err != nil {
- log.Println("Error writing HTML DOMElement to buffer: DOMElementWithChildrenSelect")
- return nil
- }
- }
-
- _, err = e.ViewBuf.WriteString(`</` + e.TagName + `>`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementWithChildrenSelect")
- return nil
- }
-
- if e.Label != "" {
- _, err = e.ViewBuf.WriteString(`<label class="active">` + e.Label + `</label>`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementWithChildrenSelect")
- return nil
- }
- }
-
- _, err = e.ViewBuf.WriteString(`</div>`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementWithChildrenSelect")
- return nil
- }
-
- return e.ViewBuf.Bytes()
-}
-
-func DOMElementWithChildrenCheckbox(e *Element, children []*Element) []byte {
- _, err := e.ViewBuf.WriteString(`<` + e.TagName + ` `)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementWithChildrenCheckbox")
- return nil
- }
-
- for attr, value := range e.Attrs {
- _, err = e.ViewBuf.WriteString(attr + `="` + value + `" `)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementWithChildrenCheckbox")
- return nil
- }
- }
-
- _, err = e.ViewBuf.WriteString(` >`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementWithChildrenCheckbox")
- return nil
- }
-
- if e.Label != "" {
- _, err = e.ViewBuf.WriteString(`<label class="active">` + e.Label + `</label>`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementWithChildrenCheckbox")
- return nil
- }
- }
-
- // loop over children and create DOMElement for each child
- for _, child := range children {
- _, err = e.ViewBuf.Write(DOMElementCheckbox(child))
- if err != nil {
- log.Println("Error writing HTML DOMElementCheckbox to buffer: DOMElementWithChildrenCheckbox")
- return nil
- }
- }
-
- _, err = e.ViewBuf.WriteString(`</` + e.TagName + `><div class="clear padding">&nbsp;</div>`)
- if err != nil {
- log.Println("Error writing HTML string to buffer: DOMElementWithChildrenCheckbox")
- return nil
- }
-
- return e.ViewBuf.Bytes()
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/editor.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/editor.go
deleted file mode 100644
index 39bb25f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/editor.go
+++ /dev/null
@@ -1,267 +0,0 @@
-// Package editor enables users to create edit views from their content
-// structs so that admins can manage content
-package editor
-
-import (
- "bytes"
- "log"
- "net/http"
-)
-
-// Editable ensures data is editable
-type Editable interface {
- MarshalEditor() ([]byte, error)
-}
-
-// Mergeable allows external post content to be approved and published through
-// the public-facing API
-type Mergeable interface {
- // Approve copies an external post to the internal collection and triggers
- // a re-sort of its content type posts
- Approve(http.ResponseWriter, *http.Request) error
-}
-
-// Editor is a view containing fields to manage content
-type Editor struct {
- ViewBuf *bytes.Buffer
-}
-
-// Field is used to create the editable view for a field
-// within a particular content struct
-type Field struct {
- View []byte
-}
-
-// Form takes editable content and any number of Field funcs to describe the edit
-// page for any content struct added by a user
-func Form(post Editable, fields ...Field) ([]byte, error) {
- editor := &Editor{}
-
- editor.ViewBuf = &bytes.Buffer{}
- _, err := editor.ViewBuf.WriteString(`<table><tbody class="row"><tr class="col s8 editor-fields"><td class="col s12">`)
- if err != nil {
- log.Println("Error writing HTML string to editor Form buffer")
- return nil, err
- }
-
- for _, f := range fields {
- addFieldToEditorView(editor, f)
- }
-
- _, err = editor.ViewBuf.WriteString(`</td></tr>`)
- if err != nil {
- log.Println("Error writing HTML string to editor Form buffer")
- return nil, err
- }
-
- // content items with Item embedded have some default fields we need to render
- _, err = editor.ViewBuf.WriteString(`<tr class="col s4 default-fields"><td class="col s12">`)
- if err != nil {
- log.Println("Error writing HTML string to editor Form buffer")
- return nil, err
- }
-
- publishTime := `
-<div class="row content-only __ponzu">
- <div class="input-field col s6">
- <label class="active">MM</label>
- <select class="month __ponzu browser-default">
- <option value="1">Jan - 01</option>
- <option value="2">Feb - 02</option>
- <option value="3">Mar - 03</option>
- <option value="4">Apr - 04</option>
- <option value="5">May - 05</option>
- <option value="6">Jun - 06</option>
- <option value="7">Jul - 07</option>
- <option value="8">Aug - 08</option>
- <option value="9">Sep - 09</option>
- <option value="10">Oct - 10</option>
- <option value="11">Nov - 11</option>
- <option value="12">Dec - 12</option>
- </select>
- </div>
- <div class="input-field col s2">
- <label class="active">DD</label>
- <input value="" class="day __ponzu" maxlength="2" type="text" placeholder="DD" />
- </div>
- <div class="input-field col s4">
- <label class="active">YYYY</label>
- <input value="" class="year __ponzu" maxlength="4" type="text" placeholder="YYYY" />
- </div>
-</div>
-
-<div class="row content-only __ponzu">
- <div class="input-field col s3">
- <label class="active">HH</label>
- <input value="" class="hour __ponzu" maxlength="2" type="text" placeholder="HH" />
- </div>
- <div class="col s1">:</div>
- <div class="input-field col s3">
- <label class="active">MM</label>
- <input value="" class="minute __ponzu" maxlength="2" type="text" placeholder="MM" />
- </div>
- <div class="input-field col s4">
- <label class="active">Period</label>
- <select class="period __ponzu browser-default">
- <option value="AM">AM</option>
- <option value="PM">PM</option>
- </select>
- </div>
-</div>
- `
-
- _, err = editor.ViewBuf.WriteString(publishTime)
- if err != nil {
- log.Println("Error writing HTML string to editor Form buffer")
- return nil, err
- }
-
- err = addPostDefaultFieldsToEditorView(post, editor)
- if err != nil {
- return nil, err
- }
-
- submit := `
-<div class="input-field post-controls">
- <button class="right waves-effect waves-light btn green save-post" type="submit">Save</button>
- <button class="right waves-effect waves-light btn red delete-post" type="submit">Delete</button>
-</div>
-`
- _, ok := post.(Mergeable)
- if ok {
- submit +=
- `
-<div class="row external post-controls">
- <div class="col s12 input-field">
- <button class="right waves-effect waves-light btn blue approve-post" type="submit">Approve</button>
- <button class="right waves-effect waves-light btn grey darken-2 reject-post" type="submit">Reject</button>
- </div>
- <label class="approve-details right-align col s12">This content is pending approval. By clicking 'Approve', it will be immediately published. By clicking 'Reject', it will be deleted.</label>
-</div>
-`
- }
-
- script := `
-<script>
- $(function() {
- var form = $('form'),
- save = form.find('button.save-post'),
- del = form.find('button.delete-post'),
- external = form.find('.post-controls.external'),
- id = form.find('input[name=id]'),
- timestamp = $('.__ponzu.content-only'),
- slug = $('input[name=slug]');
-
- // hide if this is a new post, or a non-post editor page
- if (id.val() === '-1' || form.attr('action') !== '/admin/edit') {
- del.hide();
- external.hide();
- }
-
- // hide approval if not on a pending content item
- if (getParam('status') !== 'pending') {
- external.hide();
- }
-
- // no timestamp, slug visible on addons
- if (form.attr('action') === '/admin/addon') {
- timestamp.hide();
- slug.parent().hide();
- }
-
- save.on('click', function(e) {
- e.preventDefault();
-
- if (getParam('status') === 'pending') {
- var action = form.attr('action');
- form.attr('action', action + '?status=pending')
- }
-
- form.submit();
- });
-
- del.on('click', function(e) {
- e.preventDefault();
- var action = form.attr('action');
- action = action + '/delete';
- form.attr('action', action);
-
- if (confirm("[Ponzu] Please confirm:\n\nAre you sure you want to delete this post?\nThis cannot be undone.")) {
- form.submit();
- }
- });
-
- external.find('button.approve-post').on('click', function(e) {
- e.preventDefault();
- var action = form.attr('action');
- action = action + '/approve';
- form.attr('action', action);
-
- form.submit();
- });
-
- external.find('button.reject-post').on('click', function(e) {
- e.preventDefault();
- var action = form.attr('action');
- action = action + '/delete?reject=true';
- form.attr('action', action);
-
- if (confirm("[Ponzu] Please confirm:\n\nAre you sure you want to reject this post?\nDoing so will delete it, and cannot be undone.")) {
- form.submit();
- }
- });
- });
-</script>
-`
- _, err = editor.ViewBuf.WriteString(submit + script + `</td></tr></tbody></table>`)
- if err != nil {
- log.Println("Error writing HTML string to editor Form buffer")
- return nil, err
- }
-
- return editor.ViewBuf.Bytes(), nil
-}
-
-func addFieldToEditorView(e *Editor, f Field) error {
- _, err := e.ViewBuf.Write(f.View)
- if err != nil {
- log.Println("Error writing field view to editor view buffer")
- return err
- }
-
- return nil
-}
-
-func addPostDefaultFieldsToEditorView(p Editable, e *Editor) error {
- defaults := []Field{
- {
- View: Input("Slug", p, map[string]string{
- "label": "URL Slug",
- "type": "text",
- "disabled": "true",
- "placeholder": "Will be set automatically",
- }),
- },
- {
- View: Timestamp("Timestamp", p, map[string]string{
- "type": "hidden",
- "class": "timestamp __ponzu",
- }),
- },
- {
- View: Timestamp("Updated", p, map[string]string{
- "type": "hidden",
- "class": "updated __ponzu",
- }),
- },
- }
-
- for _, f := range defaults {
- err := addFieldToEditorView(e, f)
- if err != nil {
- return err
- }
- }
-
- return nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/elements.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/elements.go
deleted file mode 100644
index b179960..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/elements.go
+++ /dev/null
@@ -1,520 +0,0 @@
-package editor
-
-import (
- "bytes"
- "html"
- "strings"
-)
-
-// Input returns the []byte of an <input> HTML element with a label.
-// IMPORTANT:
-// The `fieldName` argument will cause a panic if it is not exactly the string
-// form of the struct field that this editor input is representing
-// type Person struct {
-// item.Item
-// editor editor.Editor
-//
-// Name string `json:"name"`
-// //...
-// }
-//
-// func (p *Person) MarshalEditor() ([]byte, error) {
-// view, err := editor.Form(p,
-// editor.Field{
-// View: editor.Input("Name", p, map[string]string{
-// "label": "Name",
-// "type": "text",
-// "placeholder": "Enter the Name here",
-// }),
-// }
-// )
-// }
-func Input(fieldName string, p interface{}, attrs map[string]string) []byte {
- e := NewElement("input", attrs["label"], fieldName, p, attrs)
-
- return DOMElementSelfClose(e)
-}
-
-// Textarea returns the []byte of a <textarea> HTML element with a label.
-// IMPORTANT:
-// The `fieldName` argument will cause a panic if it is not exactly the string
-// form of the struct field that this editor input is representing
-func Textarea(fieldName string, p interface{}, attrs map[string]string) []byte {
- // add materialize css class to make UI correct
- className := "materialize-textarea"
- if _, ok := attrs["class"]; ok {
- class := attrs["class"]
- attrs["class"] = class + " " + className
- } else {
- attrs["class"] = className
- }
-
- e := NewElement("textarea", attrs["label"], fieldName, p, attrs)
-
- return DOMElement(e)
-}
-
-// Timestamp returns the []byte of an <input> HTML element with a label.
-// IMPORTANT:
-// The `fieldName` argument will cause a panic if it is not exactly the string
-// form of the struct field that this editor input is representing
-func Timestamp(fieldName string, p interface{}, attrs map[string]string) []byte {
- var data string
- val := ValueFromStructField(fieldName, p)
- if val == "0" {
- data = ""
- } else {
- data = val
- }
-
- e := &Element{
- TagName: "input",
- Attrs: attrs,
- Name: TagNameFromStructField(fieldName, p),
- Label: attrs["label"],
- Data: data,
- ViewBuf: &bytes.Buffer{},
- }
-
- return DOMElementSelfClose(e)
-}
-
-// File returns the []byte of a <input type="file"> HTML element with a label.
-// IMPORTANT:
-// The `fieldName` argument will cause a panic if it is not exactly the string
-// form of the struct field that this editor input is representing
-func File(fieldName string, p interface{}, attrs map[string]string) []byte {
- name := TagNameFromStructField(fieldName, p)
- value := ValueFromStructField(fieldName, p)
- tmpl :=
- `<div class="file-input ` + name + ` input-field col s12">
- <label class="active">` + attrs["label"] + `</label>
- <div class="file-field input-field">
- <div class="btn">
- <span>Upload</span>
- <input class="upload" type="file">
- </div>
- <div class="file-path-wrapper">
- <input class="file-path validate" placeholder="` + attrs["label"] + `" type="text">
- </div>
- </div>
- <div class="preview"><div class="img-clip"></div></div>
- <input class="store ` + name + `" type="hidden" name="` + name + `" value="` + value + `" />
- </div>`
-
- script :=
- `<script>
- $(function() {
- var $file = $('.file-input.` + name + `'),
- upload = $file.find('input.upload'),
- store = $file.find('input.store'),
- preview = $file.find('.preview'),
- clip = preview.find('.img-clip'),
- reset = document.createElement('div'),
- img = document.createElement('img'),
- video = document.createElement('video'),
- unknown = document.createElement('div'),
- viewLink = document.createElement('a'),
- viewLinkText = document.createTextNode('Download / View '),
- iconLaunch = document.createElement('i'),
- iconLaunchText = document.createTextNode('launch'),
- uploadSrc = store.val();
- video.setAttribute
- preview.hide();
- viewLink.setAttribute('href', '` + value + `');
- viewLink.setAttribute('target', '_blank');
- viewLink.appendChild(viewLinkText);
- viewLink.style.display = 'block';
- viewLink.style.marginRight = '10px';
- viewLink.style.textAlign = 'right';
- iconLaunch.className = 'material-icons tiny';
- iconLaunch.style.position = 'relative';
- iconLaunch.style.top = '3px';
- iconLaunch.appendChild(iconLaunchText);
- viewLink.appendChild(iconLaunch);
- preview.append(viewLink);
-
- // when ` + name + ` input changes (file is selected), remove
- // the 'name' and 'value' attrs from the hidden store input.
- // add the 'name' attr to ` + name + ` input
- upload.on('change', function(e) {
- resetImage();
- });
-
- if (uploadSrc.length > 0) {
- var ext = uploadSrc.substring(uploadSrc.lastIndexOf('.'));
- ext = ext.toLowerCase();
- switch (ext) {
- case '.jpg':
- case '.jpeg':
- case '.webp':
- case '.gif':
- case '.png':
- $(img).attr('src', store.val());
- clip.append(img);
- break;
- case '.mp4':
- case '.webm':
- $(video)
- .attr('src', store.val())
- .attr('type', 'video/'+ext.substring(1))
- .attr('controls', true)
- .css('width', '100%');
- clip.append(video);
- break;
- default:
- $(img).attr('src', '/admin/static/dashboard/img/ponzu-file.png');
- $(unknown)
- .css({
- position: 'absolute',
- top: '10px',
- left: '10px',
- border: 'solid 1px #ddd',
- padding: '7px 7px 5px 12px',
- fontWeight: 'bold',
- background: '#888',
- color: '#fff',
- textTransform: 'uppercase',
- letterSpacing: '2px'
- })
- .text(ext);
- clip.append(img);
- clip.append(unknown);
- clip.css('maxWidth', '200px');
- }
- preview.show();
-
- $(reset).addClass('reset ` + name + ` btn waves-effect waves-light grey');
- $(reset).html('<i class="material-icons tiny">clear<i>');
- $(reset).on('click', function(e) {
- e.preventDefault();
- preview.animate({"opacity": 0.1}, 200, function() {
- preview.slideUp(250, function() {
- resetImage();
- });
- })
-
- });
- clip.append(reset);
- }
-
- function resetImage() {
- store.val('');
- store.attr('name', '');
- upload.attr('name', '` + name + `');
- clip.empty();
- }
- });
- </script>`
-
- return []byte(tmpl + script)
-}
-
-// Richtext returns the []byte of a rich text editor (provided by http://summernote.org/) with a label.
-// IMPORTANT:
-// The `fieldName` argument will cause a panic if it is not exactly the string
-// form of the struct field that this editor input is representing
-func Richtext(fieldName string, p interface{}, attrs map[string]string) []byte {
- // create wrapper for richtext editor, which isolates the editor's css
- iso := []byte(`<div class="iso-texteditor input-field col s12"><label>` + attrs["label"] + `</label>`)
- isoClose := []byte(`</div>`)
-
- if _, ok := attrs["class"]; ok {
- attrs["class"] += "richtext " + fieldName
- } else {
- attrs["class"] = "richtext " + fieldName
- }
-
- if _, ok := attrs["id"]; ok {
- attrs["id"] += "richtext-" + fieldName
- } else {
- attrs["id"] = "richtext-" + fieldName
- }
-
- // create the target element for the editor to attach itself
- div := &Element{
- TagName: "div",
- Attrs: attrs,
- Name: "",
- Label: "",
- Data: "",
- ViewBuf: &bytes.Buffer{},
- }
-
- // create a hidden input to store the value from the struct
- val := ValueFromStructField(fieldName, p)
- name := TagNameFromStructField(fieldName, p)
- input := `<input type="hidden" name="` + name + `" class="richtext-value ` + fieldName + `" value="` + html.EscapeString(val) + `"/>`
-
- // build the dom tree for the entire richtext component
- iso = append(iso, DOMElement(div)...)
- iso = append(iso, []byte(input)...)
- iso = append(iso, isoClose...)
-
- script := `
- <script>
- $(function() {
- var _editor = $('.richtext.` + fieldName + `');
- var hidden = $('.richtext-value.` + fieldName + `');
-
- _editor.materialnote({
- height: 250,
- placeholder: '` + attrs["placeholder"] + `',
- toolbar: [
- ['style', ['bold', 'italic', 'underline', 'clear']],
- ['font', ['strikethrough', 'superscript', 'subscript']],
- ['fontsize', ['fontsize']],
- ['color', ['color']],
- ['insert', ['link', 'picture', 'video', 'hr']],
- ['para', ['ul', 'ol', 'paragraph']],
- ['height', ['height']],
- ['misc', ['codeview']]
- ],
- // intercept file insertion, upload and insert img with new src
- onImageUpload: function(files) {
- var data = new FormData();
- data.append("file", files[0]);
- $.ajax({
- data: data,
- type: 'POST',
- url: '/admin/edit/upload',
- cache: false,
- contentType: false,
- processData: false,
- success: function(resp) {
- var img = document.createElement('img');
- img.setAttribute('src', resp.data[0].url);
- _editor.materialnote('insertNode', img);
- },
- error: function(xhr, status, err) {
- console.log(status, err);
- }
- })
-
- }
- });
-
- // inject content into editor
- if (hidden.val() !== "") {
- _editor.code(hidden.val());
- }
-
- // update hidden input with encoded value on different events
- _editor.on('materialnote.change', function(e, content, $editable) {
- hidden.val(replaceBadChars(content));
- });
-
- _editor.on('materialnote.paste', function(e) {
- hidden.val(replaceBadChars(_editor.code()));
- });
-
- // bit of a hack to stop the editor buttons from causing a refresh when clicked
- $('.note-toolbar').find('button, i, a').on('click', function(e) { e.preventDefault(); });
- });
- </script>`
-
- return append(iso, []byte(script)...)
-}
-
-// Select returns the []byte of a <select> HTML element plus internal <options> with a label.
-// IMPORTANT:
-// The `fieldName` argument will cause a panic if it is not exactly the string
-// form of the struct field that this editor input is representing
-func Select(fieldName string, p interface{}, attrs, options map[string]string) []byte {
- // options are the value attr and the display value, i.e.
- // <option value="{map key}">{map value}</option>
-
- // find the field value in p to determine if an option is pre-selected
- fieldVal := ValueFromStructField(fieldName, p)
-
- if _, ok := attrs["class"]; ok {
- attrs["class"] += " browser-default"
- } else {
- attrs["class"] = "browser-default"
- }
-
- sel := NewElement("select", attrs["label"], fieldName, p, attrs)
- var opts []*Element
-
- // provide a call to action for the select element
- cta := &Element{
- TagName: "option",
- Attrs: map[string]string{"disabled": "true", "selected": "true"},
- Data: "Select an option...",
- ViewBuf: &bytes.Buffer{},
- }
-
- // provide a selection reset (will store empty string in db)
- reset := &Element{
- TagName: "option",
- Attrs: map[string]string{"value": ""},
- Data: "None",
- ViewBuf: &bytes.Buffer{},
- }
-
- opts = append(opts, cta, reset)
-
- for k, v := range options {
- optAttrs := map[string]string{"value": k}
- if k == fieldVal {
- optAttrs["selected"] = "true"
- }
- opt := &Element{
- TagName: "option",
- Attrs: optAttrs,
- Data: v,
- ViewBuf: &bytes.Buffer{},
- }
-
- opts = append(opts, opt)
- }
-
- return DOMElementWithChildrenSelect(sel, opts)
-}
-
-// Checkbox returns the []byte of a set of <input type="checkbox"> HTML elements
-// wrapped in a <div> with a label.
-// IMPORTANT:
-// The `fieldName` argument will cause a panic if it is not exactly the string
-// form of the struct field that this editor input is representing
-func Checkbox(fieldName string, p interface{}, attrs, options map[string]string) []byte {
- if _, ok := attrs["class"]; ok {
- attrs["class"] += "input-field col s12"
- } else {
- attrs["class"] = "input-field col s12"
- }
-
- div := NewElement("div", attrs["label"], fieldName, p, attrs)
-
- var opts []*Element
-
- // get the pre-checked options if this is already an existing post
- checkedVals := ValueFromStructField(fieldName, p)
- checked := strings.Split(checkedVals, "__ponzu")
-
- i := 0
- for k, v := range options {
- inputAttrs := map[string]string{
- "type": "checkbox",
- "value": k,
- "id": strings.Join(strings.Split(v, " "), "-"),
- }
-
- // check if k is in the pre-checked values and set to checked
- for _, x := range checked {
- if k == x {
- inputAttrs["checked"] = "checked"
- }
- }
-
- // create a *element manually using the modified TagNameFromStructFieldMulti
- // func since this is for a multi-value name
- input := &Element{
- TagName: "input",
- Attrs: inputAttrs,
- Name: TagNameFromStructFieldMulti(fieldName, i, p),
- Label: v,
- Data: "",
- ViewBuf: &bytes.Buffer{},
- }
-
- opts = append(opts, input)
- i++
- }
-
- return DOMElementWithChildrenCheckbox(div, opts)
-}
-
-// Tags returns the []byte of a tag input (in the style of Materialze 'Chips') with a label.
-// IMPORTANT:
-// The `fieldName` argument will cause a panic if it is not exactly the string
-// form of the struct field that this editor input is representing
-func Tags(fieldName string, p interface{}, attrs map[string]string) []byte {
- name := TagNameFromStructField(fieldName, p)
-
- // get the saved tags if this is already an existing post
- values := ValueFromStructField(fieldName, p)
- var tags []string
- if strings.Contains(values, "__ponzu") {
- tags = strings.Split(values, "__ponzu")
- }
-
- // case where there is only one tag stored, thus has no separator
- if len(values) > 0 && !strings.Contains(values, "__ponzu") {
- tags = append(tags, values)
- }
-
- html := `
- <div class="col s12 __ponzu-tags ` + name + `">
- <label class="active">` + attrs["label"] + ` (Type and press "Enter")</label>
- <div class="chips ` + name + `"></div>
- `
-
- var initial []string
- i := 0
- for _, tag := range tags {
- tagName := TagNameFromStructFieldMulti(fieldName, i, p)
- html += `<input type="hidden" class="__ponzu-tag ` + tag + `" name=` + tagName + ` value="` + tag + `"/>`
- initial = append(initial, `{tag: '`+tag+`'}`)
- i++
- }
-
- script := `
- <script>
- $(function() {
- var tags = $('.__ponzu-tags.` + name + `');
- $('.chips.` + name + `').material_chip({
- data: [` + strings.Join(initial, ",") + `],
- secondaryPlaceholder: '+` + name + `'
- });
-
- // handle events specific to tags
- var chips = tags.find('.chips');
-
- chips.on('chip.add', function(e, chip) {
- chips.parent().find('.empty-tag').remove();
-
- var input = $('<input>');
- input.attr({
- class: '__ponzu-tag '+chip.tag.split(' ').join('__'),
- name: '` + name + `.'+String(tags.find('input[type=hidden]').length),
- value: chip.tag,
- type: 'hidden'
- });
-
- tags.append(input);
- });
-
- chips.on('chip.delete', function(e, chip) {
- // convert tag string to class-like selector "some tag" -> ".some.tag"
- var sel = '.__ponzu-tag.' + chip.tag.split(' ').join('__');
- chips.parent().find(sel).remove();
-
- // iterate through all hidden tag inputs to re-name them with the correct ` + name + `.index
- var hidden = chips.parent().find('input[type=hidden]');
-
- // if there are no tags, set a blank
- if (hidden.length === 0) {
- var input = $('<input>');
- input.attr({
- class: 'empty-tag',
- name: '` + name + `',
- type: 'hidden'
- });
-
- tags.append(input);
- }
-
- // re-name hidden storage elements in necessary format
- for (var i = 0; i < hidden.length; i++) {
- $(hidden[i]).attr('name', '` + name + `.'+String(i));
- }
- });
- });
- </script>
- `
-
- html += `</div>`
-
- return []byte(html + script)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/repeaters.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/repeaters.go
deleted file mode 100644
index 250f2d2..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/repeaters.go
+++ /dev/null
@@ -1,442 +0,0 @@
-package editor
-
-import (
- "bytes"
- "fmt"
- "log"
- "strings"
-)
-
-// InputRepeater returns the []byte of an <input> HTML element with a label.
-// It also includes repeat controllers (+ / -) so the element can be
-// dynamically multiplied or reduced.
-// IMPORTANT:
-// The `fieldName` argument will cause a panic if it is not exactly the string
-// form of the struct field that this editor input is representing
-// type Person struct {
-// item.Item
-// editor editor.Editor
-//
-// Names []string `json:"names"`
-// //...
-// }
-//
-// func (p *Person) MarshalEditor() ([]byte, error) {
-// view, err := editor.Form(p,
-// editor.Field{
-// View: editor.InputRepeater("Names", p, map[string]string{
-// "label": "Names",
-// "type": "text",
-// "placeholder": "Enter a Name here",
-// }),
-// }
-// )
-// }
-func InputRepeater(fieldName string, p interface{}, attrs map[string]string) []byte {
- // find the field values in p to determine pre-filled inputs
- fieldVals := ValueFromStructField(fieldName, p)
- vals := strings.Split(fieldVals, "__ponzu")
-
- scope := TagNameFromStructField(fieldName, p)
- html := bytes.Buffer{}
-
- _, err := html.WriteString(`<span class="__ponzu-repeat ` + scope + `">`)
- if err != nil {
- log.Println("Error writing HTML string to InputRepeater buffer")
- return nil
- }
-
- for i, val := range vals {
- el := &Element{
- TagName: "input",
- Attrs: attrs,
- Name: TagNameFromStructFieldMulti(fieldName, i, p),
- Data: val,
- ViewBuf: &bytes.Buffer{},
- }
-
- // only add the label to the first input in repeated list
- if i == 0 {
- el.Label = attrs["label"]
- }
-
- _, err := html.Write(DOMElementSelfClose(el))
- if err != nil {
- log.Println("Error writing DOMElementSelfClose to InputRepeater buffer")
- return nil
- }
- }
- _, err = html.WriteString(`</span>`)
- if err != nil {
- log.Println("Error writing HTML string to InputRepeater buffer")
- return nil
- }
-
- return append(html.Bytes(), RepeatController(fieldName, p, "input", ".input-field")...)
-}
-
-// SelectRepeater returns the []byte of a <select> HTML element plus internal <options> with a label.
-// It also includes repeat controllers (+ / -) so the element can be
-// dynamically multiplied or reduced.
-// IMPORTANT:
-// The `fieldName` argument will cause a panic if it is not exactly the string
-// form of the struct field that this editor input is representing
-func SelectRepeater(fieldName string, p interface{}, attrs, options map[string]string) []byte {
- // options are the value attr and the display value, i.e.
- // <option value="{map key}">{map value}</option>
- scope := TagNameFromStructField(fieldName, p)
- html := bytes.Buffer{}
- _, err := html.WriteString(`<span class="__ponzu-repeat ` + scope + `">`)
- if err != nil {
- log.Println("Error writing HTML string to SelectRepeater buffer")
- return nil
- }
-
- // find the field values in p to determine if an option is pre-selected
- fieldVals := ValueFromStructField(fieldName, p)
- vals := strings.Split(fieldVals, "__ponzu")
-
- if _, ok := attrs["class"]; ok {
- attrs["class"] += " browser-default"
- } else {
- attrs["class"] = "browser-default"
- }
-
- // loop through vals and create selects and options for each, adding to html
- if len(vals) > 0 {
- for i, val := range vals {
- sel := &Element{
- TagName: "select",
- Attrs: attrs,
- Name: TagNameFromStructFieldMulti(fieldName, i, p),
- ViewBuf: &bytes.Buffer{},
- }
-
- // only add the label to the first select in repeated list
- if i == 0 {
- sel.Label = attrs["label"]
- }
-
- // create options for select element
- var opts []*Element
-
- // provide a call to action for the select element
- cta := &Element{
- TagName: "option",
- Attrs: map[string]string{"disabled": "true", "selected": "true"},
- Data: "Select an option...",
- ViewBuf: &bytes.Buffer{},
- }
-
- // provide a selection reset (will store empty string in db)
- reset := &Element{
- TagName: "option",
- Attrs: map[string]string{"value": ""},
- Data: "None",
- ViewBuf: &bytes.Buffer{},
- }
-
- opts = append(opts, cta, reset)
-
- for k, v := range options {
- optAttrs := map[string]string{"value": k}
- if k == val {
- optAttrs["selected"] = "true"
- }
- opt := &Element{
- TagName: "option",
- Attrs: optAttrs,
- Data: v,
- ViewBuf: &bytes.Buffer{},
- }
-
- opts = append(opts, opt)
- }
-
- _, err := html.Write(DOMElementWithChildrenSelect(sel, opts))
- if err != nil {
- log.Println("Error writing DOMElementWithChildrenSelect to SelectRepeater buffer")
- return nil
- }
- }
- }
-
- _, err = html.WriteString(`</span>`)
- if err != nil {
- log.Println("Error writing HTML string to SelectRepeater buffer")
- return nil
- }
-
- return append(html.Bytes(), RepeatController(fieldName, p, "select", ".input-field")...)
-}
-
-// FileRepeater returns the []byte of a <input type="file"> HTML element with a label.
-// It also includes repeat controllers (+ / -) so the element can be
-// dynamically multiplied or reduced.
-// IMPORTANT:
-// The `fieldName` argument will cause a panic if it is not exactly the string
-// form of the struct field that this editor input is representing
-func FileRepeater(fieldName string, p interface{}, attrs map[string]string) []byte {
- // find the field values in p to determine if an option is pre-selected
- fieldVals := ValueFromStructField(fieldName, p)
- vals := strings.Split(fieldVals, "__ponzu")
-
- addLabelFirst := func(i int, label string) string {
- if i == 0 {
- return `<label class="active">` + label + `</label>`
- }
-
- return ""
- }
-
- tmpl :=
- `<div class="file-input %[5]s %[4]s input-field col s12">
- %[2]s
- <div class="file-field input-field">
- <div class="btn">
- <span>Upload</span>
- <input class="upload %[4]s" type="file" />
- </div>
- <div class="file-path-wrapper">
- <input class="file-path validate" placeholder="Add %[5]s" type="text" />
- </div>
- </div>
- <div class="preview"><div class="img-clip"></div></div>
- <input class="store %[4]s" type="hidden" name="%[1]s" value="%[3]s" />
- </div>`
- // 1=nameidx, 2=addLabelFirst, 3=val, 4=className, 5=fieldName
- script :=
- `<script>
- $(function() {
- var $file = $('.file-input.%[2]s'),
- upload = $file.find('input.upload'),
- store = $file.find('input.store'),
- preview = $file.find('.preview'),
- clip = preview.find('.img-clip'),
- reset = document.createElement('div'),
- img = document.createElement('img'),
- uploadSrc = store.val();
- preview.hide();
-
- // when %[2]s input changes (file is selected), remove
- // the 'name' and 'value' attrs from the hidden store input.
- // add the 'name' attr to %[2]s input
- upload.on('change', function(e) {
- resetImage();
- });
-
- if (uploadSrc.length > 0) {
- $(img).attr('src', store.val());
- clip.append(img);
- preview.show();
-
- $(reset).addClass('reset %[2]s btn waves-effect waves-light grey');
- $(reset).html('<i class="material-icons tiny">clear<i>');
- $(reset).on('click', function(e) {
- e.preventDefault();
- var preview = $(this).parent().closest('.preview');
- preview.animate({"opacity": 0.1}, 200, function() {
- preview.slideUp(250, function() {
- resetImage();
- });
- })
-
- });
- clip.append(reset);
- }
-
- function resetImage() {
- store.val('');
- store.attr('name', '');
- upload.attr('name', '%[1]s');
- clip.empty();
- }
- });
- </script>`
- // 1=nameidx, 2=className
-
- name := TagNameFromStructField(fieldName, p)
-
- html := bytes.Buffer{}
- _, err := html.WriteString(`<span class="__ponzu-repeat ` + name + `">`)
- if err != nil {
- log.Println("Error writing HTML string to FileRepeater buffer")
- return nil
- }
-
- for i, val := range vals {
- className := fmt.Sprintf("%s-%d", name, i)
- nameidx := TagNameFromStructFieldMulti(fieldName, i, p)
-
- _, err := html.WriteString(fmt.Sprintf(tmpl, nameidx, addLabelFirst(i, attrs["label"]), val, className, fieldName))
- if err != nil {
- log.Println("Error writing HTML string to FileRepeater buffer")
- return nil
- }
-
- _, err = html.WriteString(fmt.Sprintf(script, nameidx, className))
- if err != nil {
- log.Println("Error writing HTML string to FileRepeater buffer")
- return nil
- }
- }
- _, err = html.WriteString(`</span>`)
- if err != nil {
- log.Println("Error writing HTML string to FileRepeater buffer")
- return nil
- }
-
- return append(html.Bytes(), RepeatController(fieldName, p, "input.upload", "div.file-input."+fieldName)...)
-}
-
-// RepeatController generates the javascript to control any repeatable form
-// element in an editor based on its type, field name and HTML tag name
-func RepeatController(fieldName string, p interface{}, inputSelector, cloneSelector string) []byte {
- scope := TagNameFromStructField(fieldName, p)
- script := `
- <script>
- $(function() {
- // define the scope of the repeater
- var scope = $('.__ponzu-repeat.` + scope + `');
-
- var getChildren = function() {
- return scope.find('` + cloneSelector + `')
- }
-
- var resetFieldNames = function() {
- // loop through children, set its name to the fieldName.i where
- // i is the current index number of children array
- var children = getChildren();
-
- for (var i = 0; i < children.length; i++) {
- var preset = false;
- var $el = children.eq(i);
- var name = '` + scope + `.'+String(i);
-
- $el.find('` + inputSelector + `').attr('name', name);
-
- // ensure no other input-like elements besides ` + inputSelector + `
- // get the new name by setting it to an empty string
- $el.find('input, select, textarea').each(function(i, elem) {
- var $elem = $(elem);
-
- // if the elem is not ` + inputSelector + ` and has no value
- // set the name to an empty string
- if (!$elem.is('` + inputSelector + `')) {
- if ($elem.val() === '' || $elem.is('.file-path')) {
- $elem.attr('name', '');
- } else {
- $elem.attr('name', name);
- preset = true;
- }
- }
- });
-
- // if there is a preset value, remove the name attr from the
- // ` + inputSelector + ` element so it doesn't overwrite db
- if (preset) {
- $el.find('` + inputSelector + `').attr('name', '');
- }
-
- // reset controllers
- $el.find('.controls').remove();
- }
-
- applyRepeatControllers();
- }
-
- var addRepeater = function(e) {
- e.preventDefault();
-
- var add = e.target;
-
- // find and clone the repeatable input-like element
- var source = $(add).parent().closest('` + cloneSelector + `');
- var clone = source.clone();
-
- // if clone has label, remove it
- clone.find('label').remove();
-
- // remove the pre-filled value from clone
- clone.find('` + inputSelector + `').val('');
- clone.find('input').val('');
-
- // remove controls from clone if already present
- clone.find('.controls').remove();
-
- // remove input preview on clone if copied from source
- clone.find('.preview').remove();
-
- // add clone to scope and reset field name attributes
- scope.append(clone);
-
- resetFieldNames();
- }
-
- var delRepeater = function(e) {
- e.preventDefault();
-
- // do nothing if the input is the only child
- var children = getChildren();
- if (children.length === 1) {
- return;
- }
-
- var del = e.target;
-
- // pass label onto next input-like element if del 0 index
- var wrapper = $(del).parent().closest('` + cloneSelector + `');
- if (wrapper.find('` + inputSelector + `').attr('name') === '` + scope + `.0') {
- wrapper.next().append(wrapper.find('label'))
- }
-
- wrapper.remove();
-
- resetFieldNames();
- }
-
- var createControls = function() {
- // create + / - controls for each input-like child element of scope
- var add = $('<button>+</button>');
- add.addClass('repeater-add');
- add.addClass('btn-flat waves-effect waves-green');
-
- var del = $('<button>-</button>');
- del.addClass('repeater-del');
- del.addClass('btn-flat waves-effect waves-red');
-
- var controls = $('<span></span>');
- controls.addClass('controls');
- controls.addClass('right');
-
- // bind listeners to child's controls
- add.on('click', addRepeater);
- del.on('click', delRepeater);
-
- controls.append(add);
- controls.append(del);
-
- return controls;
- }
-
- var applyRepeatControllers = function() {
- // add controls to each child
- var children = getChildren()
- for (var i = 0; i < children.length; i++) {
- var el = children[i];
-
- $(el).find('` + inputSelector + `').parent().find('.controls').remove();
-
- var controls = createControls();
- $(el).append(controls);
- }
- }
-
- resetFieldNames();
- });
-
- </script>
- `
-
- return []byte(script)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/values.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/values.go
deleted file mode 100644
index bc97f99..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/values.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package editor
-
-import (
- "fmt"
- "reflect"
- "strings"
-)
-
-// TagNameFromStructField does a lookup on the `json` struct tag for a given
-// field of a struct
-func TagNameFromStructField(name string, post interface{}) string {
- // sometimes elements in these environments will not have a name,
- // and thus no tag name in the struct which correlates to it.
- if name == "" {
- return name
- }
-
- field, ok := reflect.TypeOf(post).Elem().FieldByName(name)
- if !ok {
- panic("Couldn't get struct field for: " + name + ". Make sure you pass the right field name to editor field elements.")
- }
-
- tag, ok := field.Tag.Lookup("json")
- if !ok {
- panic("Couldn't get json struct tag for: " + name + ". Struct fields for content types must have 'json' tags.")
- }
-
- return tag
-}
-
-// TagNameFromStructFieldMulti calls TagNameFromStructField and formats is for
-// use with gorilla/schema
-// due to the format in which gorilla/schema expects form names to be when
-// one is associated with multiple values, we need to output the name as such.
-// Ex. 'category.0', 'category.1', 'category.2' and so on.
-func TagNameFromStructFieldMulti(name string, i int, post interface{}) string {
- tag := TagNameFromStructField(name, post)
-
- return fmt.Sprintf("%s.%d", tag, i)
-}
-
-// ValueFromStructField returns the string value of a field in a struct
-func ValueFromStructField(name string, post interface{}) string {
- field := reflect.Indirect(reflect.ValueOf(post)).FieldByName(name)
-
- switch field.Kind() {
- case reflect.String:
- return field.String()
-
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return fmt.Sprintf("%v", field.Int())
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- return fmt.Sprintf("%v", field.Uint())
-
- case reflect.Bool:
- return fmt.Sprintf("%t", field.Bool())
-
- case reflect.Complex64, reflect.Complex128:
- return fmt.Sprintf("%v", field.Complex())
-
- case reflect.Float32, reflect.Float64:
- return fmt.Sprintf("%v", field.Float())
-
- case reflect.Slice:
- s := []string{}
-
- for i := 0; i < field.Len(); i++ {
- pos := field.Index(i)
- s = append(s, fmt.Sprintf("%v", pos))
- }
-
- return strings.Join(s, "__ponzu")
-
- default:
- panic(fmt.Sprintf("Ponzu: Type '%s' for field '%s' not supported.", field.Type(), name))
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/manager/manager.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/manager/manager.go
deleted file mode 100644
index 93c3315..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/manager/manager.go
+++ /dev/null
@@ -1,154 +0,0 @@
-package manager
-
-import (
- "bytes"
- "fmt"
- "html/template"
-
- "github.com/ponzu-cms/ponzu/management/editor"
- "github.com/ponzu-cms/ponzu/system/item"
-
- uuid "github.com/satori/go.uuid"
-)
-
-const managerHTML = `
-<div class="card editor">
- <form method="post" action="/admin/edit" enctype="multipart/form-data">
- <input type="hidden" name="uuid" value="{{.UUID}}"/>
- <input type="hidden" name="id" value="{{.ID}}"/>
- <input type="hidden" name="type" value="{{.Kind}}"/>
- <input type="hidden" name="slug" value="{{.Slug}}"/>
- {{ .Editor }}
- </form>
- <script>
- $(function() {
- // remove all bad chars from all inputs in the form, except file fields
- $('form input:not([type=file]), form textarea').on('blur', function(e) {
- var val = e.target.value;
- e.target.value = replaceBadChars(val);
- });
-
- var updateTimestamp = function(dt, $ts) {
- var year = parseInt(dt.year.val()),
- month = parseInt(dt.month.val())-1,
- day = parseInt(dt.day.val()),
- hour = parseInt(dt.hour.val()),
- minute = parseInt(dt.minute.val());
-
- if (dt.period.val() === "PM") {
- hour = hour + 12;
- }
-
- // add seconds to Date() to differentiate times more precisely,
- // although not 100% accurately
- var sec = (new Date()).getSeconds();
- var date = new Date(year, month, day, hour, minute, sec);
-
- $ts.val(date.getTime());
- }
-
- var setDefaultTimeAndDate = function(dt, unix) {
- var time = getPartialTime(unix),
- date = getPartialDate(unix);
-
- dt.hour.val(time.hh);
- dt.minute.val(time.mm);
- dt.period.val(time.pd);
- dt.year.val(date.yyyy);
- dt.month.val(date.mm);
- dt.day.val(date.dd);
- }
-
- // set time time and date inputs using the hidden timestamp input.
- // if it is empty, set it to now and use that value for time and date
- var publish_time_hh = $('input.__ponzu.hour'),
- publish_time_mm = $('input.__ponzu.minute'),
- publish_time_pd = $('select.__ponzu.period'),
- publish_date_yyyy = $('input.__ponzu.year'),
- publish_date_mm = $('select.__ponzu.month'),
- publish_date_dd = $('input.__ponzu.day'),
- timestamp = $('input.__ponzu.timestamp'),
- updated = $('input.__ponzu.updated'),
- getFields = function() {
- return {
- hour: publish_time_hh,
- minute: publish_time_mm,
- period: publish_time_pd,
- year: publish_date_yyyy,
- month: publish_date_mm,
- day: publish_date_dd
- }
- },
- time;
-
- if (timestamp.val() !== "") {
- time = parseInt(timestamp.val());
- } else {
- time = (new Date()).getTime();
- }
-
- setDefaultTimeAndDate(getFields(), time);
-
- var timeUpdated = false;
- $('form').on('submit', function(e) {
- if (timeUpdated === true) {
- timeUpdated = false;
- return;
- }
-
- e.preventDefault();
-
- updateTimestamp(getFields(), timestamp);
- updated.val((new Date()).getTime());
-
- timeUpdated = true;
- $('form').submit();
- });
- });
-
- </script>
-</div>
-`
-
-var managerTmpl = template.Must(template.New("manager").Parse(managerHTML))
-
-type manager struct {
- ID int
- UUID uuid.UUID
- Kind string
- Slug string
- Editor template.HTML
-}
-
-// Manage ...
-func Manage(e editor.Editable, typeName string) ([]byte, error) {
- v, err := e.MarshalEditor()
- if err != nil {
- return nil, fmt.Errorf("Couldn't marshal editor for content %s. %s", typeName, err.Error())
- }
-
- i, ok := e.(item.Identifiable)
- if !ok {
- return nil, fmt.Errorf("Content type %s does not implement item.Identifiable.", typeName)
- }
-
- s, ok := e.(item.Sluggable)
- if !ok {
- return nil, fmt.Errorf("Content type %s does not implement item.Sluggable.", typeName)
- }
-
- m := manager{
- ID: i.ItemID(),
- UUID: i.UniqueID(),
- Kind: typeName,
- Slug: s.ItemSlug(),
- Editor: template.HTML(v),
- }
-
- // execute html template into buffer for func return val
- buf := &bytes.Buffer{}
- if err := managerTmpl.Execute(buf, m); err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/addon/addon.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/addon/addon.go
deleted file mode 100644
index 5414d6f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/addon/addon.go
+++ /dev/null
@@ -1,239 +0,0 @@
-package addon
-
-import (
- "encoding/json"
- "fmt"
- "net/url"
- "strings"
-
- "github.com/ponzu-cms/ponzu/system/db"
- "github.com/ponzu-cms/ponzu/system/item"
-
- "github.com/tidwall/sjson"
-)
-
-var (
- // Types is a record of addons, like content types, of addon_reverse_dns:interface{}
- Types = make(map[string]func() interface{})
-)
-
-const (
- // StatusEnabled defines string status for Addon enabled state
- StatusEnabled = "enabled"
- // StatusDisabled defines string status for Addon disabled state
- StatusDisabled = "disabled"
-)
-
-// Meta contains the basic information about the addon
-type Meta struct {
- PonzuAddonName string `json:"addon_name"`
- PonzuAddonAuthor string `json:"addon_author"`
- PonzuAddonAuthorURL string `json:"addon_author_url"`
- PonzuAddonVersion string `json:"addon_version"`
- PonzuAddonReverseDNS string `json:"addon_reverse_dns"`
- PonzuAddonStatus string `json:"addon_status"`
-}
-
-// Addon contains information about a provided addon to the system
-type Addon struct {
- item.Item
- Meta
-}
-
-// Register constructs a new addon and registers it with the system. Meta is a
-// addon.Meta and fn is a closure returning a pointer to your own addon type
-func Register(m Meta, fn func() interface{}) Addon {
- // get or create the reverse DNS identifier
- if m.PonzuAddonReverseDNS == "" {
- revDNS, err := reverseDNS(m)
- if err != nil {
- panic(err)
- }
-
- m.PonzuAddonReverseDNS = revDNS
- }
-
- Types[m.PonzuAddonReverseDNS] = fn
-
- a := Addon{Meta: m}
-
- err := register(a)
- if err != nil {
- panic(err)
- }
-
- return a
-}
-
-// register sets up the system to use the Addon by:
-// 1. Validating the Addon struct
-// 2. Saving it to the __addons bucket in DB with id/key = addon_reverse_dns
-func register(a Addon) error {
- if a.PonzuAddonName == "" {
- return fmt.Errorf(`Addon must have valid Meta struct embedded: missing %s field.`, "PonzuAddonName")
- }
- if a.PonzuAddonAuthor == "" {
- return fmt.Errorf(`Addon must have valid Meta struct embedded: missing %s field.`, "PonzuAddonAuthor")
- }
- if a.PonzuAddonAuthorURL == "" {
- return fmt.Errorf(`Addon must have valid Meta struct embedded: missing %s field.`, "PonzuAddonAuthorURL")
- }
- if a.PonzuAddonVersion == "" {
- return fmt.Errorf(`Addon must have valid Meta struct embedded: missing %s field.`, "PonzuAddonVersion")
- }
-
- if _, ok := Types[a.PonzuAddonReverseDNS]; !ok {
- return fmt.Errorf(`Addon "%s" has no record in the addons.Types map`, a.PonzuAddonName)
- }
-
- // check if addon is already registered in db as addon_reverse_dns
- if db.AddonExists(a.PonzuAddonReverseDNS) {
- return nil
- }
-
- // convert a.Item into usable data, Item{} => []byte(json) => map[string]interface{}
- kv := make(map[string]interface{})
-
- data, err := json.Marshal(a.Item)
- if err != nil {
- return err
- }
-
- err = json.Unmarshal(data, &kv)
- if err != nil {
- return err
- }
-
- // save new addon to db
- vals := make(url.Values)
- for k, v := range kv {
- vals.Set(k, fmt.Sprintf("%v", v))
- }
-
- vals.Set("addon_name", a.PonzuAddonName)
- vals.Set("addon_author", a.PonzuAddonAuthor)
- vals.Set("addon_author_url", a.PonzuAddonAuthorURL)
- vals.Set("addon_version", a.PonzuAddonVersion)
- vals.Set("addon_reverse_dns", a.PonzuAddonReverseDNS)
- vals.Set("addon_status", StatusDisabled)
-
- // db.SetAddon is like SetContent, but rather than the key being an int64 ID,
- // we need it to be a string based on the addon_reverse_dns
- kind, ok := Types[a.PonzuAddonReverseDNS]
- if !ok {
- return fmt.Errorf("Error: no addon to set with id: %s", a.PonzuAddonReverseDNS)
- }
-
- err = db.SetAddon(vals, kind())
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// Deregister removes an addon from the system. `key` is the addon_reverse_dns
-func Deregister(key string) error {
- err := db.DeleteAddon(key)
- if err != nil {
- return err
- }
-
- delete(Types, key)
- return nil
-}
-
-// Enable sets the addon status to `enabled`. `key` is the addon_reverse_dns
-func Enable(key string) error {
- err := setStatus(key, StatusEnabled)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// Disable sets the addon status to `disabled`. `key` is the addon_reverse_dns
-func Disable(key string) error {
- err := setStatus(key, StatusDisabled)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// KeyFromMeta creates a unique string identifier for an addon based on its url and name
-func KeyFromMeta(meta Meta) (string, error) {
- return reverseDNS(meta)
-}
-
-func setStatus(key, status string) error {
- a, err := db.Addon(key)
- if err != nil {
- return err
- }
-
- a, err = sjson.SetBytes(a, "addon_status", status)
- if err != nil {
- return err
- }
-
- kind, ok := Types[key]
- if !ok {
- return fmt.Errorf("Error: no addon to set with id: %s", key)
- }
-
- // convert json => map[string]interface{} => url.Values
- var kv map[string]interface{}
- err = json.Unmarshal(a, &kv)
- if err != nil {
- return err
- }
-
- vals := make(url.Values)
- for k, v := range kv {
- switch v.(type) {
- case []string:
- s := v.([]string)
- for i := range s {
- if i == 0 {
- vals.Set(k, s[i])
- }
-
- vals.Add(k, s[i])
- }
- default:
- vals.Set(k, fmt.Sprintf("%v", v))
- }
- }
-
- err = db.SetAddon(vals, kind())
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func reverseDNS(meta Meta) (string, error) {
- u, err := url.Parse(meta.PonzuAddonAuthorURL)
- if err != nil {
- return "", nil
- }
-
- if u.Host == "" {
- return "", fmt.Errorf(`Error parsing Addon Author URL: %s. Ensure URL is formatted as "scheme://hostname/path?query" (path & query optional)`, meta.PonzuAddonAuthorURL)
- }
-
- name := strings.Replace(meta.PonzuAddonName, " ", "", -1)
-
- // reverse the host name parts, split on '.', ex. bosssauce.it => it.bosssauce
- parts := strings.Split(u.Host, ".")
- strap := make([]string, 0, len(parts))
- for i := len(parts) - 1; i >= 0; i-- {
- strap = append(strap, parts[i])
- }
-
- return strings.Join(append(strap, name), "."), nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/addon/api.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/addon/api.go
deleted file mode 100644
index cd792aa..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/addon/api.go
+++ /dev/null
@@ -1,80 +0,0 @@
-// Package addon provides an API for Ponzu addons to interface with the system
-package addon
-
-import (
- "bytes"
- "fmt"
- "io/ioutil"
- "log"
- "net/http"
- "time"
-
- "github.com/ponzu-cms/ponzu/system/db"
-)
-
-// QueryOptions is a mirror of the same struct in db package and are re-declared
-// here only to make the API simpler for the caller
-type QueryOptions db.QueryOptions
-
-// ContentAll retrives all items from the HTTP API within the provided namespace
-func ContentAll(namespace string) []byte {
- host := db.ConfigCache("domain").(string)
- port := db.ConfigCache("http_port").(string)
- endpoint := "http://%s:%s/api/contents?type=%s&count=-1"
- URL := fmt.Sprintf(endpoint, host, port, namespace)
-
- j, err := Get(URL)
- if err != nil {
- log.Println("Error in ContentAll for reference HTTP request:", URL)
- return nil
- }
-
- return j
-}
-
-// Query retrieves a set of content from the HTTP API based on options
-// and returns the total number of content in the namespace and the content
-func Query(namespace string, opts QueryOptions) []byte {
- host := db.ConfigCache("domain").(string)
- port := db.ConfigCache("http_port").(string)
- endpoint := "http://%s:%s/api/contents?type=%s&count=%d&offset=%d&order=%s"
- URL := fmt.Sprintf(endpoint, host, port, namespace, opts.Count, opts.Offset, opts.Order)
-
- j, err := Get(URL)
- if err != nil {
- log.Println("Error in Query for reference HTTP request:", URL)
- return nil
- }
-
- return j
-}
-
-// Get is a helper function to make a HTTP call from an addon
-func Get(endpoint string) ([]byte, error) {
- buf := []byte{}
- r := bytes.NewReader(buf)
-
- req, err := http.NewRequest(http.MethodGet, endpoint, r)
- if err != nil {
- log.Println("Error creating reference HTTP request:", endpoint)
- return nil, err
- }
-
- c := http.Client{
- Timeout: time.Duration(time.Second * 5),
- }
- res, err := c.Do(req)
- if err != nil {
- log.Println("Error making reference HTTP request:", endpoint)
- return nil, err
- }
- defer res.Body.Close()
-
- j, err := ioutil.ReadAll(res.Body)
- if err != nil {
- log.Println("Error reading body for reference HTTP request:", endpoint)
- return nil, err
- }
-
- return j, nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/addon/manager.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/addon/manager.go
deleted file mode 100644
index d3c9673..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/addon/manager.go
+++ /dev/null
@@ -1,117 +0,0 @@
-package addon
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "html/template"
- "net/url"
-
- "github.com/ponzu-cms/ponzu/management/editor"
-
- "github.com/gorilla/schema"
- "github.com/tidwall/gjson"
-)
-
-const defaultInput = `<input type="hidden" name="%s" value="%s"/>`
-
-const managerHTML = `
-<div class="card editor">
- <form method="post" action="/admin/addon" enctype="multipart/form-data">
- <div class="card-content">
- <div class="card-title">{{ .AddonName }}</div>
- </div>
- {{ .DefaultInputs }}
- {{ .Editor }}
- </form>
-</div>
-`
-
-type manager struct {
- DefaultInputs template.HTML
- Editor template.HTML
- AddonName string
-}
-
-// Manage ...
-func Manage(data []byte, reverseDNS string) ([]byte, error) {
- a, ok := Types[reverseDNS]
- if !ok {
- return nil, fmt.Errorf("Addon has not been added to addon.Types map")
- }
-
- // convert json => map[string]interface{} => url.Values
- var kv map[string]interface{}
- err := json.Unmarshal(data, &kv)
- if err != nil {
- return nil, err
- }
-
- vals := make(url.Values)
- for k, v := range kv {
- switch v.(type) {
- case []string:
- s := v.([]string)
- for i := range s {
- if i == 0 {
- vals.Set(k, s[i])
- }
-
- vals.Add(k, s[i])
- }
- default:
- vals.Set(k, fmt.Sprintf("%v", v))
- }
- }
-
- at := a()
-
- dec := schema.NewDecoder()
- dec.IgnoreUnknownKeys(true)
- dec.SetAliasTag("json")
- err = dec.Decode(at, vals)
- if err != nil {
- return nil, err
- }
-
- e, ok := at.(editor.Editable)
- if !ok {
- return nil, fmt.Errorf("Addon is not editable - must implement editor.Editable: %T", at)
- }
-
- v, err := e.MarshalEditor()
- if err != nil {
- return nil, fmt.Errorf("Couldn't marshal editor for addon: %s", err.Error())
- }
-
- inputs := &bytes.Buffer{}
- fields := []string{
- "addon_name",
- "addon_author",
- "addon_author_url",
- "addon_version",
- "addon_reverse_dns",
- "addon_status",
- }
-
- for _, f := range fields {
- input := fmt.Sprintf(defaultInput, f, gjson.GetBytes(data, f).String())
- _, err := inputs.WriteString(input)
- if err != nil {
- return nil, fmt.Errorf("Failed to write input for addon view: %s", f)
- }
- }
-
- m := manager{
- DefaultInputs: template.HTML(inputs.Bytes()),
- Editor: template.HTML(v),
- AddonName: gjson.GetBytes(data, "addon_name").String(),
- }
-
- // execute html template into buffer for func return val
- buf := &bytes.Buffer{}
- tmpl := template.Must(template.New("manager").Parse(managerHTML))
- tmpl.Execute(buf, m)
-
- return buf.Bytes(), nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/admin.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/admin.go
deleted file mode 100644
index 7761e71..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/admin.go
+++ /dev/null
@@ -1,629 +0,0 @@
-// Package admin desrcibes the admin view containing references to
-// various managers and editors
-package admin
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "html/template"
- "net/http"
-
- "github.com/ponzu-cms/ponzu/system/admin/user"
- "github.com/ponzu-cms/ponzu/system/api/analytics"
- "github.com/ponzu-cms/ponzu/system/db"
- "github.com/ponzu-cms/ponzu/system/item"
-)
-
-var startAdminHTML = `<!doctype html>
-<html lang="en">
- <head>
- <title>{{ .Logo }}</title>
- <script type="text/javascript" src="/admin/static/common/js/jquery-2.1.4.min.js"></script>
- <script type="text/javascript" src="/admin/static/common/js/util.js"></script>
- <script type="text/javascript" src="/admin/static/dashboard/js/materialize.min.js"></script>
- <script type="text/javascript" src="/admin/static/dashboard/js/chart.bundle.min.js"></script>
- <script type="text/javascript" src="/admin/static/editor/js/materialNote.js"></script>
- <script type="text/javascript" src="/admin/static/editor/js/ckMaterializeOverrides.js"></script>
-
- <link rel="stylesheet" href="/admin/static/dashboard/css/material-icons.css" />
- <link rel="stylesheet" href="/admin/static/dashboard/css/materialize.min.css" />
- <link rel="stylesheet" href="/admin/static/editor/css/materialNote.css" />
- <link rel="stylesheet" href="/admin/static/dashboard/css/admin.css" />
-
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- </head>
- <body class="grey lighten-4">
- <div class="navbar-fixed">
- <nav class="grey darken-2">
- <div class="nav-wrapper">
- <a class="brand-logo" href="/admin">{{ .Logo }}</a>
-
- <ul class="right">
- <li><a href="/admin/logout">Logout</a></li>
- </ul>
- </div>
- </nav>
- </div>
-
- <div class="admin-ui row">`
-
-var mainAdminHTML = `
- <div class="left-nav col s3">
- <div class="card">
- <ul class="card-content collection">
- <div class="card-title">Content</div>
-
- {{ range $t, $f := .Types }}
- <div class="row collection-item">
- <li><a class="col s12" href="/admin/contents?type={{ $t }}"><i class="tiny left material-icons">playlist_add</i>{{ $t }}</a></li>
- </div>
- {{ end }}
-
- <div class="card-title">System</div>
- <div class="row collection-item">
- <li><a class="col s12" href="/admin/configure"><i class="tiny left material-icons">settings</i>Configuration</a></li>
- <li><a class="col s12" href="/admin/configure/users"><i class="tiny left material-icons">supervisor_account</i>Admin Users</a></li>
- <li><a class="col s12" href="/admin/addons"><i class="tiny left material-icons">settings_input_svideo</i>Addons</a></li>
- </div>
- </ul>
- </div>
- </div>
- {{ if .Subview}}
- <div class="subview col s9">
- {{ .Subview }}
- </div>
- {{ end }}`
-
-var endAdminHTML = `
- </div>
- <footer class="row">
- <div class="col s12">
- <p class="center-align">Powered by &copy; <a target="_blank" href="https://ponzu-cms.org">Ponzu</a> &nbsp;&vert;&nbsp; open-sourced by <a target="_blank" href="https://www.bosssauce.it">Boss Sauce Creative</a></p>
- </div>
- </footer>
- </body>
-</html>`
-
-type admin struct {
- Logo string
- Types map[string]func() interface{}
- Subview template.HTML
-}
-
-// Admin ...
-func Admin(view []byte) (_ []byte, err error) {
- cfg, err := db.Config("name")
- if err != nil {
- return
- }
-
- if cfg == nil {
- cfg = []byte("")
- }
-
- a := admin{
- Logo: string(cfg),
- Types: item.Types,
- Subview: template.HTML(view),
- }
-
- buf := &bytes.Buffer{}
- html := startAdminHTML + mainAdminHTML + endAdminHTML
- tmpl := template.Must(template.New("admin").Parse(html))
- err = tmpl.Execute(buf, a)
- if err != nil {
- return
- }
-
- return buf.Bytes(), nil
-}
-
-var initAdminHTML = `
-<div class="init col s5">
-<div class="card">
-<div class="card-content">
- <div class="card-title">Welcome!</div>
- <blockquote>You need to initialize your system by filling out the form below. All of
- this information can be updated later on, but you will not be able to start
- without first completing this step.</blockquote>
- <form method="post" action="/admin/init" class="row">
- <div>Configuration</div>
- <div class="input-field col s12">
- <input placeholder="Enter the name of your site (interal use only)" class="validate required" type="text" id="name" name="name"/>
- <label for="name" class="active">Site Name</label>
- </div>
- <div class="input-field col s12">
- <input placeholder="Used for acquiring SSL certificate (e.g. www.example.com or example.com)" class="validate" type="text" id="domain" name="domain"/>
- <label for="domain" class="active">Domain</label>
- </div>
- <div>Admin Details</div>
- <div class="input-field col s12">
- <input placeholder="Your email address e.g. you@example.com" class="validate required" type="email" id="email" name="email"/>
- <label for="email" class="active">Email</label>
- </div>
- <div class="input-field col s12">
- <input placeholder="Enter a strong password" class="validate required" type="password" id="password" name="password"/>
- <label for="password" class="active">Password</label>
- </div>
- <button class="btn waves-effect waves-light right">Start</button>
- </form>
-</div>
-</div>
-</div>
-<script>
- $(function() {
- $('.nav-wrapper ul.right').hide();
-
- var logo = $('a.brand-logo');
- var name = $('input#name');
-
- name.on('change', function(e) {
- logo.text(e.target.value);
- });
- });
-</script>
-`
-
-// Init ...
-func Init() ([]byte, error) {
- html := startAdminHTML + initAdminHTML + endAdminHTML
-
- name, err := db.Config("name")
- if err != nil {
- return nil, err
- }
-
- if name == nil {
- name = []byte("")
- }
-
- a := admin{
- Logo: string(name),
- }
-
- buf := &bytes.Buffer{}
- tmpl := template.Must(template.New("init").Parse(html))
- err = tmpl.Execute(buf, a)
- if err != nil {
- return nil, err
- }
-
- return buf.Bytes(), nil
-}
-
-var loginAdminHTML = `
-<div class="init col s5">
-<div class="card">
-<div class="card-content">
- <div class="card-title">Welcome!</div>
- <blockquote>Please log in to the system using your email address and password.</blockquote>
- <form method="post" action="/admin/login" class="row">
- <div class="input-field col s12">
- <input placeholder="Enter your email address e.g. you@example.com" class="validate required" type="email" id="email" name="email"/>
- <label for="email" class="active">Email</label>
- </div>
- <div class="input-field col s12">
- <input placeholder="Enter your password" class="validate required" type="password" id="password" name="password"/>
- <a href="/admin/recover">Forgot password?</a>
- <label for="password" class="active">Password</label>
- </div>
- <button class="btn waves-effect waves-light right">Log in</button>
- </form>
-</div>
-</div>
-</div>
-<script>
- $(function() {
- $('.nav-wrapper ul.right').hide();
- });
-</script>
-`
-
-// Login ...
-func Login() ([]byte, error) {
- html := startAdminHTML + loginAdminHTML + endAdminHTML
-
- cfg, err := db.Config("name")
- if err != nil {
- return nil, err
- }
-
- if cfg == nil {
- cfg = []byte("")
- }
-
- a := admin{
- Logo: string(cfg),
- }
-
- buf := &bytes.Buffer{}
- tmpl := template.Must(template.New("login").Parse(html))
- err = tmpl.Execute(buf, a)
- if err != nil {
- return nil, err
- }
-
- return buf.Bytes(), nil
-}
-
-var forgotPasswordHTML = `
-<div class="init col s5">
-<div class="card">
-<div class="card-content">
- <div class="card-title">Account Recovery</div>
- <blockquote>Please enter the email for your account and a recovery message will be sent to you at this address. Check your spam folder in case the message was flagged.</blockquote>
- <form method="post" action="/admin/recover" class="row" enctype="multipart/form-data">
- <div class="input-field col s12">
- <input placeholder="Enter your email address e.g. you@example.com" class="validate required" type="email" id="email" name="email"/>
- <label for="email" class="active">Email</label>
- </div>
-
- <a href="/admin/recover/key">Already have a recovery key?</a>
- <button class="btn waves-effect waves-light right">Send Recovery Email</button>
- </form>
-</div>
-</div>
-</div>
-<script>
- $(function() {
- $('.nav-wrapper ul.right').hide();
- });
-</script>
-`
-
-// ForgotPassword ...
-func ForgotPassword() ([]byte, error) {
- html := startAdminHTML + forgotPasswordHTML + endAdminHTML
-
- cfg, err := db.Config("name")
- if err != nil {
- return nil, err
- }
-
- if cfg == nil {
- cfg = []byte("")
- }
-
- a := admin{
- Logo: string(cfg),
- }
-
- buf := &bytes.Buffer{}
- tmpl := template.Must(template.New("forgotPassword").Parse(html))
- err = tmpl.Execute(buf, a)
- if err != nil {
- return nil, err
- }
-
- return buf.Bytes(), nil
-}
-
-var recoveryKeyHTML = `
-<div class="init col s5">
-<div class="card">
-<div class="card-content">
- <div class="card-title">Account Recovery</div>
- <blockquote>Please check for your recovery key inside an email sent to the address you provided. Check your spam folder in case the message was flagged.</blockquote>
- <form method="post" action="/admin/recover/key" class="row" enctype="multipart/form-data">
- <div class="input-field col s12">
- <input placeholder="Enter your recovery key" class="validate required" type="text" id="key" name="key"/>
- <label for="key" class="active">Recovery Key</label>
- </div>
-
- <div class="input-field col s12">
- <input placeholder="Enter your email address e.g. you@example.com" class="validate required" type="email" id="email" name="email"/>
- <label for="email" class="active">Email</label>
- </div>
-
- <div class="input-field col s12">
- <input placeholder="Enter your password" class="validate required" type="password" id="password" name="password"/>
- <label for="password" class="active">New Password</label>
- </div>
-
- <button class="btn waves-effect waves-light right">Update Account</button>
- </form>
-</div>
-</div>
-</div>
-<script>
- $(function() {
- $('.nav-wrapper ul.right').hide();
- });
-</script>
-`
-
-// RecoveryKey ...
-func RecoveryKey() ([]byte, error) {
- html := startAdminHTML + recoveryKeyHTML + endAdminHTML
-
- cfg, err := db.Config("name")
- if err != nil {
- return nil, err
- }
-
- if cfg == nil {
- cfg = []byte("")
- }
-
- a := admin{
- Logo: string(cfg),
- }
-
- buf := &bytes.Buffer{}
- tmpl := template.Must(template.New("recoveryKey").Parse(html))
- err = tmpl.Execute(buf, a)
- if err != nil {
- return nil, err
- }
-
- return buf.Bytes(), nil
-}
-
-// UsersList ...
-func UsersList(req *http.Request) ([]byte, error) {
- html := `
- <div class="card user-management">
- <div class="card-title">Edit your account:</div>
- <form class="row" enctype="multipart/form-data" action="/admin/configure/users/edit" method="post">
- <div class="input-feild col s9">
- <label class="active">Email Address</label>
- <input type="email" name="email" value="{{ .User.Email }}"/>
- </div>
-
- <div class="input-feild col s9">
- <div>To approve changes, enter your password:</div>
-
- <label class="active">Current Password</label>
- <input type="password" name="password"/>
- </div>
-
- <div class="input-feild col s9">
- <label class="active">New Password: (leave blank if no password change needed)</label>
- <input name="new_password" type="password"/>
- </div>
-
- <div class="input-feild col s9">
- <button class="btn waves-effect waves-light green right" type="submit">Save</button>
- </div>
- </form>
-
- <div class="card-title">Add a new user:</div>
- <form class="row" enctype="multipart/form-data" action="/admin/configure/users" method="post">
- <div class="input-feild col s9">
- <label class="active">Email Address</label>
- <input type="email" name="email" value=""/>
- </div>
-
- <div class="input-feild col s9">
- <label class="active">Password</label>
- <input type="password" name="password"/>
- </div>
-
- <div class="input-feild col s9">
- <button class="btn waves-effect waves-light green right" type="submit">Add User</button>
- </div>
- </form>
-
- <div class="card-title">Remove Admin Users</div>
- <ul class="users row">
- {{ range .Users }}
- <li class="col s9">
- {{ .Email }}
- <form enctype="multipart/form-data" class="delete-user __ponzu right" action="/admin/configure/users/delete" method="post">
- <span>Delete</span>
- <input type="hidden" name="email" value="{{ .Email }}"/>
- <input type="hidden" name="id" value="{{ .ID }}"/>
- </form>
- </li>
- {{ end }}
- </ul>
- </div>
- `
- script := `
- <script>
- $(function() {
- var del = $('.delete-user.__ponzu span');
- del.on('click', function(e) {
- if (confirm("[Ponzu] Please confirm:\n\nAre you sure you want to delete this user?\nThis cannot be undone.")) {
- $(e.target).parent().submit();
- }
- });
- });
- </script>
- `
- // get current user out to pass as data to execute template
- j, err := db.CurrentUser(req)
- if err != nil {
- return nil, err
- }
-
- var usr user.User
- err = json.Unmarshal(j, &usr)
- if err != nil {
- return nil, err
- }
-
- // get all users to list
- jj, err := db.UserAll()
- if err != nil {
- return nil, err
- }
-
- var usrs []user.User
- for i := range jj {
- var u user.User
- err = json.Unmarshal(jj[i], &u)
- if err != nil {
- return nil, err
- }
- if u.Email != usr.Email {
- usrs = append(usrs, u)
- }
- }
-
- // make buffer to execute html into then pass buffer's bytes to Admin
- buf := &bytes.Buffer{}
- tmpl := template.Must(template.New("users").Parse(html + script))
- data := map[string]interface{}{
- "User": usr,
- "Users": usrs,
- }
-
- err = tmpl.Execute(buf, data)
- if err != nil {
- return nil, err
- }
-
- return Admin(buf.Bytes())
-}
-
-var analyticsHTML = `
-<div class="analytics">
-<div class="card">
-<div class="card-content">
- <p class="right">Data range: {{ .from }} - {{ .to }} (UTC)</p>
- <div class="card-title">API Requests</div>
- <canvas id="analytics-chart"></canvas>
- <script>
- var target = document.getElementById("analytics-chart");
- Chart.defaults.global.defaultFontColor = '#212121';
- Chart.defaults.global.defaultFontFamily = "'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', 'sans-serif'";
- Chart.defaults.global.title.position = 'right';
- var chart = new Chart(target, {
- type: 'bar',
- data: {
- labels: [{{ range $date := .dates }} "{{ $date }}", {{ end }}],
- datasets: [{
- type: 'line',
- label: 'Unique Clients',
- data: $.parseJSON({{ .unique }}),
- backgroundColor: 'rgba(76, 175, 80, 0.2)',
- borderColor: 'rgba(76, 175, 80, 1)',
- borderWidth: 1
- },
- {
- type: 'bar',
- label: 'Total Requests',
- data: $.parseJSON({{ .total }}),
- backgroundColor: 'rgba(33, 150, 243, 0.2)',
- borderColor: 'rgba(33, 150, 243, 1)',
- borderWidth: 1
- }]
- },
- options: {
- scales: {
- yAxes: [{
- ticks: {
- beginAtZero:true
- }
- }]
- }
- }
- });
- </script>
-</div>
-</div>
-</div>
-`
-
-// Dashboard returns the admin view with analytics dashboard
-func Dashboard() ([]byte, error) {
- buf := &bytes.Buffer{}
- data, err := analytics.ChartData()
- if err != nil {
- return nil, err
- }
-
- tmpl := template.Must(template.New("analytics").Parse(analyticsHTML))
- err = tmpl.Execute(buf, data)
- if err != nil {
- return nil, err
- }
- return Admin(buf.Bytes())
-}
-
-var err400HTML = []byte(`
-<div class="error-page e400 col s6">
-<div class="card">
-<div class="card-content">
- <div class="card-title"><b>400</b> Error: Bad Request</div>
- <blockquote>Sorry, the request was unable to be completed.</blockquote>
-</div>
-</div>
-</div>
-`)
-
-// Error400 creates a subview for a 400 error page
-func Error400() ([]byte, error) {
- return Admin(err400HTML)
-}
-
-var err404HTML = []byte(`
-<div class="error-page e404 col s6">
-<div class="card">
-<div class="card-content">
- <div class="card-title"><b>404</b> Error: Not Found</div>
- <blockquote>Sorry, the page you requested could not be found.</blockquote>
-</div>
-</div>
-</div>
-`)
-
-// Error404 creates a subview for a 404 error page
-func Error404() ([]byte, error) {
- return Admin(err404HTML)
-}
-
-var err405HTML = []byte(`
-<div class="error-page e405 col s6">
-<div class="card">
-<div class="card-content">
- <div class="card-title"><b>405</b> Error: Method Not Allowed</div>
- <blockquote>Sorry, the method of your request is not allowed.</blockquote>
-</div>
-</div>
-</div>
-`)
-
-// Error405 creates a subview for a 405 error page
-func Error405() ([]byte, error) {
- return Admin(err405HTML)
-}
-
-var err500HTML = []byte(`
-<div class="error-page e500 col s6">
-<div class="card">
-<div class="card-content">
- <div class="card-title"><b>500</b> Error: Internal Service Error</div>
- <blockquote>Sorry, something unexpectedly went wrong.</blockquote>
-</div>
-</div>
-</div>
-`)
-
-// Error500 creates a subview for a 500 error page
-func Error500() ([]byte, error) {
- return Admin(err500HTML)
-}
-
-var errMessageHTML = `
-<div class="error-page eMsg col s6">
-<div class="card">
-<div class="card-content">
- <div class="card-title"><b>Error:&nbsp;</b>%s</div>
- <blockquote>%s</blockquote>
-</div>
-</div>
-</div>
-`
-
-// ErrorMessage is a generic error message container, similar to Error500() and
-// others in this package, ecxept it expects the caller to provide a title and
-// message to describe to a view why the error is being shown
-func ErrorMessage(title, message string) ([]byte, error) {
- eHTML := fmt.Sprintf(errMessageHTML, title, message)
- return Admin([]byte(eHTML))
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/config/config.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/config/config.go
deleted file mode 100644
index 015c081..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/config/config.go
+++ /dev/null
@@ -1,186 +0,0 @@
-package config
-
-import (
- "github.com/ponzu-cms/ponzu/management/editor"
- "github.com/ponzu-cms/ponzu/system/item"
-)
-
-// Config represents the confirgurable options of the system
-type Config struct {
- item.Item
-
- Name string `json:"name"`
- Domain string `json:"domain"`
- HTTPPort string `json:"http_port"`
- HTTPSPort string `json:"https_port"`
- AdminEmail string `json:"admin_email"`
- ClientSecret string `json:"client_secret"`
- Etag string `json:"etag"`
- DisableCORS bool `json:"cors_disabled"`
- DisableGZIP bool `json:"gzip_disabled"`
- DisableHTTPCache bool `json:"cache_disabled"`
- CacheMaxAge int64 `json:"cache_max_age"`
- CacheInvalidate []string `json:"cache"`
- BackupBasicAuthUser string `json:"backup_basic_auth_user"`
- BackupBasicAuthPassword string `json:"backup_basic_auth_password"`
-}
-
-const (
- dbBackupInfo = `
- <p class="flow-text">Database Backup Credentials:</p>
- <p>Add a user name and password to download a backup of your data via HTTP.</p>
- `
-)
-
-// String partially implements item.Identifiable and overrides Item's String()
-func (c *Config) String() string { return c.Name }
-
-// MarshalEditor writes a buffer of html to edit a Post and partially implements editor.Editable
-func (c *Config) MarshalEditor() ([]byte, error) {
- view, err := editor.Form(c,
- editor.Field{
- View: editor.Input("Name", c, map[string]string{
- "label": "Site Name",
- "placeholder": "Add a name to this site (internal use only)",
- }),
- },
- editor.Field{
- View: editor.Input("Domain", c, map[string]string{
- "label": "Domain Name (required for SSL certificate)",
- "placeholder": "e.g. www.example.com or example.com",
- }),
- },
- editor.Field{
- View: editor.Input("HTTPPort", c, map[string]string{
- "type": "hidden",
- }),
- },
- editor.Field{
- View: editor.Input("HTTPSPort", c, map[string]string{
- "type": "hidden",
- }),
- },
- editor.Field{
- View: editor.Input("AdminEmail", c, map[string]string{
- "label": "Administrator Email (notified of internal system information)",
- }),
- },
- editor.Field{
- View: editor.Input("ClientSecret", c, map[string]string{
- "label": "Client Secret (used to validate requests, DO NOT SHARE)",
- "disabled": "true",
- }),
- },
- editor.Field{
- View: editor.Input("ClientSecret", c, map[string]string{
- "type": "hidden",
- }),
- },
- editor.Field{
- View: editor.Input("Etag", c, map[string]string{
- "label": "Etag Header (used to cache resources)",
- "disabled": "true",
- }),
- },
- editor.Field{
- View: editor.Input("Etag", c, map[string]string{
- "type": "hidden",
- }),
- },
- editor.Field{
- View: editor.Checkbox("DisableCORS", c, map[string]string{
- "label": "Disable CORS (so only " + c.Domain + " can fetch your data)",
- }, map[string]string{
- "true": "Disable CORS",
- }),
- },
- editor.Field{
- View: editor.Checkbox("DisableGZIP", c, map[string]string{
- "label": "Disable GZIP (will increase server speed, but also bandwidth)",
- }, map[string]string{
- "true": "Disable GZIP",
- }),
- },
- editor.Field{
- View: editor.Checkbox("DisableHTTPCache", c, map[string]string{
- "label": "Disable HTTP Cache (overrides 'Cache-Control' header)",
- }, map[string]string{
- "true": "Disable HTTP Cache",
- }),
- },
- editor.Field{
- View: editor.Input("CacheMaxAge", c, map[string]string{
- "label": "Max-Age value for HTTP caching (in seconds, 0 = 2592000)",
- "type": "text",
- }),
- },
- editor.Field{
- View: editor.Checkbox("CacheInvalidate", c, map[string]string{
- "label": "Invalidate cache on save",
- }, map[string]string{
- "invalidate": "Invalidate Cache",
- }),
- },
- editor.Field{
- View: []byte(dbBackupInfo),
- },
- editor.Field{
- View: editor.Input("BackupBasicAuthUser", c, map[string]string{
- "label": "HTTP Basic Auth User",
- "placeholder": "Enter a user name for Basic Auth access",
- "type": "text",
- }),
- },
- editor.Field{
- View: editor.Input("BackupBasicAuthPassword", c, map[string]string{
- "label": "HTTP Basic Auth Password",
- "placeholder": "Enter a password for Basic Auth access",
- "type": "password",
- }),
- },
- )
- if err != nil {
- return nil, err
- }
-
- open := []byte(`
- <div class="card">
- <div class="card-content">
- <div class="card-title">System Configuration</div>
- </div>
- <form action="/admin/configure" method="post">
- `)
- close := []byte(`</form></div>`)
- script := []byte(`
- <script>
- $(function() {
- // hide default fields & labels unnecessary for the config
- var fields = $('.default-fields');
- fields.css('position', 'relative');
- fields.find('input:not([type=submit])').remove();
- fields.find('label').remove();
- fields.find('button').css({
- position: 'absolute',
- top: '-10px',
- right: '0px'
- });
-
- var contentOnly = $('.content-only.__ponzu');
- contentOnly.hide();
- contentOnly.find('input, textarea, select').attr('name', '');
-
- // adjust layout of td so save button is in same location as usual
- fields.find('td').css('float', 'right');
-
- // stop some fixed config settings from being modified
- fields.find('input[name=client_secret]').attr('name', '');
- });
- </script>
- `)
-
- view = append(open, view...)
- view = append(view, close...)
- view = append(view, script...)
-
- return view, nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/filesystem.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/filesystem.go
deleted file mode 100644
index 77c721e..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/filesystem.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package admin
-
-import (
- "net/http"
- "os"
-)
-
-func restrict(dir http.Dir) justFilesFilesystem {
- return justFilesFilesystem{dir}
-}
-
-// the code below removes the open directory listing when accessing a URL which
-// normally would point to a directory. code from golang-nuts mailing list:
-// https://groups.google.com/d/msg/golang-nuts/bStLPdIVM6w/hidTJgDZpHcJ
-// credit: Brad Fitzpatrick (c) 2012
-
-type justFilesFilesystem struct {
- fs http.FileSystem
-}
-
-func (fs justFilesFilesystem) Open(name string) (http.File, error) {
- f, err := fs.fs.Open(name)
- if err != nil {
- return nil, err
- }
- return neuteredReaddirFile{f}, nil
-}
-
-type neuteredReaddirFile struct {
- http.File
-}
-
-func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) {
- return nil, nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/handlers.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/handlers.go
deleted file mode 100644
index c2d67e9..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/handlers.go
+++ /dev/null
@@ -1,2277 +0,0 @@
-package admin
-
-import (
- "bytes"
- "context"
- "encoding/base64"
- "encoding/json"
- "fmt"
- "log"
- "net/http"
- "strconv"
- "strings"
- "time"
-
- "github.com/ponzu-cms/ponzu/management/editor"
- "github.com/ponzu-cms/ponzu/management/manager"
- "github.com/ponzu-cms/ponzu/system/addon"
- "github.com/ponzu-cms/ponzu/system/admin/config"
- "github.com/ponzu-cms/ponzu/system/admin/upload"
- "github.com/ponzu-cms/ponzu/system/admin/user"
- "github.com/ponzu-cms/ponzu/system/api"
- "github.com/ponzu-cms/ponzu/system/api/analytics"
- "github.com/ponzu-cms/ponzu/system/db"
- "github.com/ponzu-cms/ponzu/system/item"
-
- "github.com/gorilla/schema"
- emailer "github.com/nilslice/email"
- "github.com/nilslice/jwt"
- "github.com/tidwall/gjson"
-)
-
-func adminHandler(res http.ResponseWriter, req *http.Request) {
- view, err := Dashboard()
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- res.Header().Set("Content-Type", "text/html")
- res.Write(view)
-}
-
-func initHandler(res http.ResponseWriter, req *http.Request) {
- if db.SystemInitComplete() {
- http.Redirect(res, req, req.URL.Scheme+req.URL.Host+"/admin", http.StatusFound)
- return
- }
-
- switch req.Method {
- case http.MethodGet:
- view, err := Init()
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
- res.Header().Set("Content-Type", "text/html")
- res.Write(view)
-
- case http.MethodPost:
- err := req.ParseForm()
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- // get the site name from post to encode and use as secret
- name := []byte(req.FormValue("name"))
- secret := base64.StdEncoding.EncodeToString(name)
- req.Form.Set("client_secret", secret)
-
- // generate an Etag to use for response caching
- etag := db.NewEtag()
- req.Form.Set("etag", etag)
-
- // create and save admin user
- email := strings.ToLower(req.FormValue("email"))
- password := req.FormValue("password")
- usr, err := user.New(email, password)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- _, err = db.SetUser(usr)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- // set HTTP port which should be previously added to config cache
- port := db.ConfigCache("http_port").(string)
- req.Form.Set("http_port", port)
-
- // set initial user email as admin_email and make config
- req.Form.Set("admin_email", email)
- err = db.SetConfig(req.Form)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- // add _token cookie for login persistence
- week := time.Now().Add(time.Hour * 24 * 7)
- claims := map[string]interface{}{
- "exp": week.Unix(),
- "user": usr.Email,
- }
-
- jwt.Secret([]byte(secret))
- token, err := jwt.New(claims)
-
- http.SetCookie(res, &http.Cookie{
- Name: "_token",
- Value: token,
- Expires: week,
- Path: "/",
- })
-
- redir := strings.TrimSuffix(req.URL.String(), "/init")
- http.Redirect(res, req, redir, http.StatusFound)
-
- default:
- res.WriteHeader(http.StatusMethodNotAllowed)
- }
-}
-
-func configHandler(res http.ResponseWriter, req *http.Request) {
- switch req.Method {
- case http.MethodGet:
- data, err := db.ConfigAll()
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- c := &config.Config{}
-
- err = json.Unmarshal(data, c)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- cfg, err := c.MarshalEditor()
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- adminView, err := Admin(cfg)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- res.Header().Set("Content-Type", "text/html")
- res.Write(adminView)
-
- case http.MethodPost:
- err := req.ParseForm()
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- err = db.SetConfig(req.Form)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- http.Redirect(res, req, req.URL.String(), http.StatusFound)
-
- default:
- res.WriteHeader(http.StatusMethodNotAllowed)
- }
-
-}
-
-func backupHandler(res http.ResponseWriter, req *http.Request) {
- switch req.URL.Query().Get("source") {
- case "system":
- err := db.Backup(res)
- if err != nil {
- log.Println("Failed to run backup on system:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- case "analytics":
- err := analytics.Backup(res)
- if err != nil {
- log.Println("Failed to run backup on analytics:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- case "uploads":
- err := upload.Backup(res)
- if err != nil {
- log.Println("Failed to run backup on uploads:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- default:
- res.WriteHeader(http.StatusBadRequest)
- }
-}
-
-func configUsersHandler(res http.ResponseWriter, req *http.Request) {
- switch req.Method {
- case http.MethodGet:
- view, err := UsersList(req)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- res.Write(view)
-
- case http.MethodPost:
- // create new user
- err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- email := strings.ToLower(req.FormValue("email"))
- password := req.PostFormValue("password")
-
- if email == "" || password == "" {
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- usr, err := user.New(email, password)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- _, err = db.SetUser(usr)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- http.Redirect(res, req, req.URL.String(), http.StatusFound)
-
- default:
- res.WriteHeader(http.StatusMethodNotAllowed)
- }
-}
-
-func configUsersEditHandler(res http.ResponseWriter, req *http.Request) {
- switch req.Method {
- case http.MethodPost:
- err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- // check if user to be edited is current user
- j, err := db.CurrentUser(req)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- usr := &user.User{}
- err = json.Unmarshal(j, usr)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- // check if password matches
- password := req.PostFormValue("password")
-
- if !user.IsUser(usr, password) {
- log.Println("Unexpected user/password combination for", usr.Email)
- res.WriteHeader(http.StatusBadRequest)
- errView, err := Error405()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- email := strings.ToLower(req.PostFormValue("email"))
- newPassword := req.PostFormValue("new_password")
- var updatedUser *user.User
- if newPassword != "" {
- updatedUser, err = user.New(email, newPassword)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
- } else {
- updatedUser, err = user.New(email, password)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
- }
-
- // set the ID to the same ID as current user
- updatedUser.ID = usr.ID
-
- // set user in db
- err = db.UpdateUser(usr, updatedUser)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- // create new token
- week := time.Now().Add(time.Hour * 24 * 7)
- claims := map[string]interface{}{
- "exp": week,
- "user": updatedUser.Email,
- }
- token, err := jwt.New(claims)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- // add token to cookie +1 week expiration
- cookie := &http.Cookie{
- Name: "_token",
- Value: token,
- Expires: week,
- Path: "/",
- }
- http.SetCookie(res, cookie)
-
- // add new token cookie to the request
- req.AddCookie(cookie)
-
- http.Redirect(res, req, strings.TrimSuffix(req.URL.String(), "/edit"), http.StatusFound)
-
- default:
- res.WriteHeader(http.StatusMethodNotAllowed)
- }
-}
-
-func configUsersDeleteHandler(res http.ResponseWriter, req *http.Request) {
- switch req.Method {
- case http.MethodPost:
- err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- // do not allow current user to delete themselves
- j, err := db.CurrentUser(req)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- usr := &user.User{}
- err = json.Unmarshal(j, &usr)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- email := strings.ToLower(req.PostFormValue("email"))
-
- if usr.Email == email {
- log.Println(err)
- res.WriteHeader(http.StatusBadRequest)
- errView, err := Error405()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- // delete existing user
- err = db.DeleteUser(email)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- http.Redirect(res, req, strings.TrimSuffix(req.URL.String(), "/delete"), http.StatusFound)
-
- default:
- res.WriteHeader(http.StatusMethodNotAllowed)
- }
-}
-
-func loginHandler(res http.ResponseWriter, req *http.Request) {
- if !db.SystemInitComplete() {
- redir := req.URL.Scheme + req.URL.Host + "/admin/init"
- http.Redirect(res, req, redir, http.StatusFound)
- return
- }
-
- switch req.Method {
- case http.MethodGet:
- if user.IsValid(req) {
- http.Redirect(res, req, req.URL.Scheme+req.URL.Host+"/admin", http.StatusFound)
- return
- }
-
- view, err := Login()
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- res.Header().Set("Content-Type", "text/html")
- res.Write(view)
-
- case http.MethodPost:
- if user.IsValid(req) {
- http.Redirect(res, req, req.URL.Scheme+req.URL.Host+"/admin", http.StatusFound)
- return
- }
-
- err := req.ParseForm()
- if err != nil {
- log.Println(err)
- http.Redirect(res, req, req.URL.String(), http.StatusFound)
- return
- }
-
- // check email & password
- j, err := db.User(strings.ToLower(req.FormValue("email")))
- if err != nil {
- log.Println(err)
- http.Redirect(res, req, req.URL.String(), http.StatusFound)
- return
- }
-
- if j == nil {
- http.Redirect(res, req, req.URL.String(), http.StatusFound)
- return
- }
-
- usr := &user.User{}
- err = json.Unmarshal(j, usr)
- if err != nil {
- log.Println(err)
- http.Redirect(res, req, req.URL.String(), http.StatusFound)
- return
- }
-
- if !user.IsUser(usr, req.FormValue("password")) {
- http.Redirect(res, req, req.URL.String(), http.StatusFound)
- return
- }
- // create new token
- week := time.Now().Add(time.Hour * 24 * 7)
- claims := map[string]interface{}{
- "exp": week,
- "user": usr.Email,
- }
- token, err := jwt.New(claims)
- if err != nil {
- log.Println(err)
- http.Redirect(res, req, req.URL.String(), http.StatusFound)
- return
- }
-
- // add it to cookie +1 week expiration
- http.SetCookie(res, &http.Cookie{
- Name: "_token",
- Value: token,
- Expires: week,
- Path: "/",
- })
-
- http.Redirect(res, req, strings.TrimSuffix(req.URL.String(), "/login"), http.StatusFound)
- }
-}
-
-func logoutHandler(res http.ResponseWriter, req *http.Request) {
- http.SetCookie(res, &http.Cookie{
- Name: "_token",
- Expires: time.Unix(0, 0),
- Value: "",
- Path: "/",
- })
-
- http.Redirect(res, req, req.URL.Scheme+req.URL.Host+"/admin/login", http.StatusFound)
-}
-
-func forgotPasswordHandler(res http.ResponseWriter, req *http.Request) {
- switch req.Method {
- case http.MethodGet:
- view, err := ForgotPassword()
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- res.Write(view)
-
- case http.MethodPost:
- err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- // check email for user, if no user return Error
- email := strings.ToLower(req.FormValue("email"))
- if email == "" {
- res.WriteHeader(http.StatusBadRequest)
- log.Println("Failed account recovery. No email address submitted.")
- return
- }
-
- _, err = db.User(email)
- if err == db.ErrNoUserExists {
- res.WriteHeader(http.StatusBadRequest)
- log.Println("No user exists.", err)
- return
- }
-
- if err != db.ErrNoUserExists && err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- log.Println("Error:", err)
- return
- }
-
- // create temporary key to verify user
- key, err := db.SetRecoveryKey(email)
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- log.Println("Failed to set account recovery key.", err)
- return
- }
-
- domain, err := db.Config("domain")
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- log.Println("Failed to get domain from configuration.", err)
- return
- }
-
- body := fmt.Sprintf(`
-There has been an account recovery request made for the user with email:
-%s
-
-To recover your account, please go to http://%s/admin/recover/key and enter
-this email address along with the following secret key:
-
-%s
-
-If you did not make the request, ignore this message and your password
-will remain as-is.
-
-
-Thank you,
-Ponzu CMS at %s
-
-`, email, domain, key, domain)
-
- msg := emailer.Message{
- To: email,
- From: fmt.Sprintf("ponzu@%s", domain),
- Subject: fmt.Sprintf("Account Recovery [%s]", domain),
- Body: body,
- }
-
- go func() {
- err = msg.Send()
- if err != nil {
- log.Println("Failed to send message to:", msg.To, "about", msg.Subject, "Error:", err)
- }
- }()
-
- // redirect to /admin/recover/key and send email with key and URL
- http.Redirect(res, req, req.URL.Scheme+req.URL.Host+"/admin/recover/key", http.StatusFound)
-
- default:
- res.WriteHeader(http.StatusMethodNotAllowed)
- errView, err := Error405()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-}
-
-func recoveryKeyHandler(res http.ResponseWriter, req *http.Request) {
- switch req.Method {
- case http.MethodGet:
- view, err := RecoveryKey()
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- res.Write(view)
-
- case http.MethodPost:
- err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB
- if err != nil {
- log.Println("Error parsing recovery key form:", err)
-
- res.WriteHeader(http.StatusInternalServerError)
- res.Write([]byte("Error, please go back and try again."))
- return
- }
-
- // check for email & key match
- email := strings.ToLower(req.FormValue("email"))
- key := req.FormValue("key")
-
- var actual string
- if actual, err = db.RecoveryKey(email); err != nil || actual == "" {
- log.Println("Error getting recovery key from database:", err)
-
- res.WriteHeader(http.StatusInternalServerError)
- res.Write([]byte("Error, please go back and try again."))
- return
- }
-
- if key != actual {
- log.Println("Bad recovery key submitted:", key)
-
- res.WriteHeader(http.StatusBadRequest)
- res.Write([]byte("Error, please go back and try again."))
- return
- }
-
- // set user with new password
- password := req.FormValue("password")
- usr := &user.User{}
- u, err := db.User(email)
- if err != nil {
- log.Println("Error finding user by email:", email, err)
-
- res.WriteHeader(http.StatusInternalServerError)
- res.Write([]byte("Error, please go back and try again."))
- return
- }
-
- if u == nil {
- log.Println("No user found with email:", email)
-
- res.WriteHeader(http.StatusBadRequest)
- res.Write([]byte("Error, please go back and try again."))
- return
- }
-
- err = json.Unmarshal(u, usr)
- if err != nil {
- log.Println("Error decoding user from database:", err)
-
- res.WriteHeader(http.StatusInternalServerError)
- res.Write([]byte("Error, please go back and try again."))
- return
- }
-
- update, err := user.New(email, password)
- if err != nil {
- log.Println(err)
-
- res.WriteHeader(http.StatusInternalServerError)
- res.Write([]byte("Error, please go back and try again."))
- return
- }
-
- update.ID = usr.ID
-
- err = db.UpdateUser(usr, update)
- if err != nil {
- log.Println("Error updating user:", err)
-
- res.WriteHeader(http.StatusInternalServerError)
- res.Write([]byte("Error, please go back and try again."))
- return
- }
-
- // redirect to /admin/login
- redir := req.URL.Scheme + req.URL.Host + "/admin/login"
- http.Redirect(res, req, redir, http.StatusFound)
-
- default:
- res.WriteHeader(http.StatusMethodNotAllowed)
- return
- }
-}
-
-func contentsHandler(res http.ResponseWriter, req *http.Request) {
- q := req.URL.Query()
- t := q.Get("type")
- if t == "" {
- res.WriteHeader(http.StatusBadRequest)
- errView, err := Error400()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- order := strings.ToLower(q.Get("order"))
- if order != "asc" {
- order = "desc"
- }
-
- status := q.Get("status")
-
- if _, ok := item.Types[t]; !ok {
- res.WriteHeader(http.StatusBadRequest)
- errView, err := Error400()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- pt := item.Types[t]()
-
- p, ok := pt.(editor.Editable)
- if !ok {
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- var hasExt bool
- _, ok = pt.(api.Createable)
- if ok {
- hasExt = true
- }
-
- count, err := strconv.Atoi(q.Get("count")) // int: determines number of posts to return (10 default, -1 is all)
- if err != nil {
- if q.Get("count") == "" {
- count = 10
- } else {
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
- }
-
- offset, err := strconv.Atoi(q.Get("offset")) // int: multiplier of count for pagination (0 default)
- if err != nil {
- if q.Get("offset") == "" {
- offset = 0
- } else {
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
- }
-
- opts := db.QueryOptions{
- Count: count,
- Offset: offset,
- Order: order,
- }
-
- var specifier string
- if status == "public" || status == "" {
- specifier = "__sorted"
- } else if status == "pending" {
- specifier = "__pending"
- }
-
- b := &bytes.Buffer{}
- var total int
- var posts [][]byte
-
- html := `<div class="col s9 card">
- <div class="card-content">
- <div class="row">
- <div class="col s8">
- <div class="row">
- <div class="card-title col s7">` + t + ` Items</div>
- <div class="col s5 input-field inline">
- <select class="browser-default __ponzu sort-order">
- <option value="DESC">New to Old</option>
- <option value="ASC">Old to New</option>
- </select>
- <label class="active">Sort:</label>
- </div>
- <script>
- $(function() {
- var sort = $('select.__ponzu.sort-order');
-
- sort.on('change', function() {
- var path = window.location.pathname;
- var s = sort.val();
- var t = getParam('type');
- var status = getParam('status');
-
- if (status == "") {
- status = "public";
- }
-
- window.location.replace(path + '?type=' + t + '&order=' + s + '&status=' + status);
- });
-
- var order = getParam('order');
- if (order !== '') {
- sort.val(order);
- }
-
- });
- </script>
- </div>
- </div>
- <form class="col s4" action="/admin/contents/search" method="get">
- <div class="input-field post-search inline">
- <label class="active">Search:</label>
- <i class="right material-icons search-icon">search</i>
- <input class="search" name="q" type="text" placeholder="Within all ` + t + ` fields" class="search"/>
- <input type="hidden" name="type" value="` + t + `" />
- <input type="hidden" name="status" value="` + status + `" />
- </div>
- </form>
- </div>`
- if hasExt {
- if status == "" {
- q.Set("status", "public")
- }
-
- // always start from top of results when changing public/pending
- q.Del("count")
- q.Del("offset")
-
- q.Set("status", "public")
- publicURL := req.URL.Path + "?" + q.Encode()
-
- q.Set("status", "pending")
- pendingURL := req.URL.Path + "?" + q.Encode()
-
- switch status {
- case "public", "":
- // get __sorted posts of type t from the db
- total, posts = db.Query(t+specifier, opts)
-
- html += `<div class="row externalable">
- <span class="description">Status:</span>
- <span class="active">Public</span>
- &nbsp;&vert;&nbsp;
- <a href="` + pendingURL + `">Pending</a>
- </div>`
-
- for i := range posts {
- err := json.Unmarshal(posts[i], &p)
- if err != nil {
- log.Println("Error unmarshal json into", t, err, string(posts[i]))
-
- post := `<li class="col s12">Error decoding data. Possible file corruption.</li>`
- _, err := b.Write([]byte(post))
- if err != nil {
- log.Println(err)
-
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- }
-
- res.Write(errView)
- return
- }
-
- continue
- }
-
- post := adminPostListItem(p, t, status)
- _, err = b.Write(post)
- if err != nil {
- log.Println(err)
-
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- }
-
- res.Write(errView)
- return
- }
- }
-
- case "pending":
- // get __pending posts of type t from the db
- total, posts = db.Query(t+"__pending", opts)
-
- html += `<div class="row externalable">
- <span class="description">Status:</span>
- <a href="` + publicURL + `">Public</a>
- &nbsp;&vert;&nbsp;
- <span class="active">Pending</span>
- </div>`
-
- for i := len(posts) - 1; i >= 0; i-- {
- err := json.Unmarshal(posts[i], &p)
- if err != nil {
- log.Println("Error unmarshal json into", t, err, string(posts[i]))
-
- post := `<li class="col s12">Error decoding data. Possible file corruption.</li>`
- _, err := b.Write([]byte(post))
- if err != nil {
- log.Println(err)
-
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- }
-
- res.Write(errView)
- return
- }
- continue
- }
-
- post := adminPostListItem(p, t, status)
- _, err = b.Write(post)
- if err != nil {
- log.Println(err)
-
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- }
-
- res.Write(errView)
- return
- }
- }
- }
-
- } else {
- total, posts = db.Query(t+specifier, opts)
-
- for i := range posts {
- err := json.Unmarshal(posts[i], &p)
- if err != nil {
- log.Println("Error unmarshal json into", t, err, string(posts[i]))
-
- post := `<li class="col s12">Error decoding data. Possible file corruption.</li>`
- _, err := b.Write([]byte(post))
- if err != nil {
- log.Println(err)
-
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- }
-
- res.Write(errView)
- return
- }
- continue
- }
-
- post := adminPostListItem(p, t, status)
- _, err = b.Write(post)
- if err != nil {
- log.Println(err)
-
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- }
-
- res.Write(errView)
- return
- }
- }
- }
-
- html += `<ul class="posts row">`
-
- _, err = b.Write([]byte(`</ul>`))
- if err != nil {
- log.Println(err)
-
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- }
-
- res.Write(errView)
- return
- }
-
- statusDisabled := "disabled"
- prevStatus := ""
- nextStatus := ""
- // total may be less than 10 (default count), so reset count to match total
- if total < count {
- count = total
- }
- // nothing previous to current list
- if offset == 0 {
- prevStatus = statusDisabled
- }
- // nothing after current list
- if (offset+1)*count >= total {
- nextStatus = statusDisabled
- }
-
- // set up pagination values
- urlFmt := req.URL.Path + "?count=%d&offset=%d&&order=%s&status=%s&type=%s"
- prevURL := fmt.Sprintf(urlFmt, count, offset-1, order, status, t)
- nextURL := fmt.Sprintf(urlFmt, count, offset+1, order, status, t)
- start := 1 + count*offset
- end := start + count - 1
-
- if total < end {
- end = total
- }
-
- pagination := fmt.Sprintf(`
- <ul class="pagination row">
- <li class="col s2 waves-effect %s"><a href="%s"><i class="material-icons">chevron_left</i></a></li>
- <li class="col s8">%d to %d of %d</li>
- <li class="col s2 waves-effect %s"><a href="%s"><i class="material-icons">chevron_right</i></a></li>
- </ul>
- `, prevStatus, prevURL, start, end, total, nextStatus, nextURL)
-
- // show indicator that a collection of items will be listed implicitly, but
- // that none are created yet
- if total < 1 {
- pagination = `
- <ul class="pagination row">
- <li class="col s2 waves-effect disabled"><a href="#"><i class="material-icons">chevron_left</i></a></li>
- <li class="col s8">0 to 0 of 0</li>
- <li class="col s2 waves-effect disabled"><a href="#"><i class="material-icons">chevron_right</i></a></li>
- </ul>
- `
- }
-
- _, err = b.Write([]byte(pagination + `</div></div>`))
- if err != nil {
- log.Println(err)
-
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- }
-
- res.Write(errView)
- return
- }
-
- script := `
- <script>
- $(function() {
- var del = $('.quick-delete-post.__ponzu span');
- del.on('click', function(e) {
- if (confirm("[Ponzu] Please confirm:\n\nAre you sure you want to delete this post?\nThis cannot be undone.")) {
- $(e.target).parent().submit();
- }
- });
- });
-
- // disable link from being clicked if parent is 'disabled'
- $(function() {
- $('ul.pagination li.disabled a').on('click', function(e) {
- e.preventDefault();
- });
- });
- </script>
- `
-
- btn := `<div class="col s3"><a href="/admin/edit?type=` + t + `" class="btn new-post waves-effect waves-light">New ` + t + `</a></div></div>`
- html = html + b.String() + script + btn
-
- adminView, err := Admin([]byte(html))
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- res.Header().Set("Content-Type", "text/html")
- res.Write(adminView)
-}
-
-// adminPostListItem is a helper to create the li containing a post.
-// p is the asserted post as an Editable, t is the Type of the post.
-// specifier is passed to append a name to a namespace like __pending
-func adminPostListItem(e editor.Editable, typeName, status string) []byte {
- s, ok := e.(item.Sortable)
- if !ok {
- log.Println("Content type", typeName, "doesn't implement item.Sortable")
- post := `<li class="col s12">Error retreiving data. Your data type doesn't implement necessary interfaces. (item.Sortable)</li>`
- return []byte(post)
- }
-
- i, ok := e.(item.Identifiable)
- if !ok {
- log.Println("Content type", typeName, "doesn't implement item.Identifiable")
- post := `<li class="col s12">Error retreiving data. Your data type doesn't implement necessary interfaces. (item.Identifiable)</li>`
- return []byte(post)
- }
-
- // use sort to get other info to display in admin UI post list
- tsTime := time.Unix(int64(s.Time()/1000), 0)
- upTime := time.Unix(int64(s.Touch()/1000), 0)
- updatedTime := upTime.Format("01/02/06 03:04 PM")
- publishTime := tsTime.Format("01/02/06")
-
- cid := fmt.Sprintf("%d", i.ItemID())
-
- switch status {
- case "public", "":
- status = ""
- default:
- status = "__" + status
- }
-
- post := `
- <li class="col s12">
- <a href="/admin/edit?type=` + typeName + `&status=` + strings.TrimPrefix(status, "__") + `&id=` + cid + `">` + i.String() + `</a>
- <span class="post-detail">Updated: ` + updatedTime + `</span>
- <span class="publish-date right">` + publishTime + `</span>
-
- <form enctype="multipart/form-data" class="quick-delete-post __ponzu right" action="/admin/edit/delete" method="post">
- <span>Delete</span>
- <input type="hidden" name="id" value="` + cid + `" />
- <input type="hidden" name="type" value="` + typeName + status + `" />
- </form>
- </li>`
-
- return []byte(post)
-}
-
-func approveContentHandler(res http.ResponseWriter, req *http.Request) {
- if req.Method != http.MethodPost {
- res.WriteHeader(http.StatusMethodNotAllowed)
- errView, err := Error405()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- pendingID := req.FormValue("id")
-
- t := req.FormValue("type")
- if strings.Contains(t, "__") {
- t = strings.Split(t, "__")[0]
- }
-
- post := item.Types[t]()
-
- // run hooks
- hook, ok := post.(item.Hookable)
- if !ok {
- log.Println("Type", t, "does not implement item.Hookable or embed item.Item.")
- res.WriteHeader(http.StatusBadRequest)
- errView, err := Error400()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- // check if we have a Mergeable
- m, ok := post.(editor.Mergeable)
- if !ok {
- log.Println("Content type", t, "must implement editor.Mergeable before it can be approved.")
- res.WriteHeader(http.StatusBadRequest)
- errView, err := Error400()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- dec := schema.NewDecoder()
- dec.IgnoreUnknownKeys(true)
- dec.SetAliasTag("json")
- err = dec.Decode(post, req.Form)
- if err != nil {
- log.Println("Error decoding post form for content approval:", t, err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- err = hook.BeforeApprove(res, req)
- if err != nil {
- log.Println("Error running BeforeApprove hook in approveContentHandler for:", t, err)
- return
- }
-
- // call its Approve method
- err = m.Approve(res, req)
- if err != nil {
- log.Println("Error running Approve method in approveContentHandler for:", t, err)
- return
- }
-
- err = hook.AfterApprove(res, req)
- if err != nil {
- log.Println("Error running AfterApprove hook in approveContentHandler for:", t, err)
- return
- }
-
- err = hook.BeforeSave(res, req)
- if err != nil {
- log.Println("Error running BeforeSave hook in approveContentHandler for:", t, err)
- return
- }
-
- // Store the content in the bucket t
- id, err := db.SetContent(t+":-1", req.Form)
- if err != nil {
- log.Println("Error storing content in approveContentHandler for:", t, err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- // set the target in the context so user can get saved value from db in hook
- ctx := context.WithValue(req.Context(), "target", fmt.Sprintf("%s:%d", t, id))
- req = req.WithContext(ctx)
-
- err = hook.AfterSave(res, req)
- if err != nil {
- log.Println("Error running AfterSave hook in approveContentHandler for:", t, err)
- return
- }
-
- if pendingID != "" {
- err = db.DeleteContent(req.FormValue("type") + ":" + pendingID)
- if err != nil {
- log.Println("Failed to remove content after approval:", err)
- }
- }
-
- // redirect to the new approved content's editor
- redir := req.URL.Scheme + req.URL.Host + strings.TrimSuffix(req.URL.Path, "/approve")
- redir += fmt.Sprintf("?type=%s&id=%d", t, id)
- http.Redirect(res, req, redir, http.StatusFound)
-}
-
-func editHandler(res http.ResponseWriter, req *http.Request) {
- switch req.Method {
- case http.MethodGet:
- q := req.URL.Query()
- i := q.Get("id")
- t := q.Get("type")
- status := q.Get("status")
-
- contentType, ok := item.Types[t]
- if !ok {
- fmt.Fprintf(res, item.ErrTypeNotRegistered.Error(), t)
- return
- }
- post := contentType()
-
- if i != "" {
- if status == "pending" {
- t = t + "__pending"
- }
-
- data, err := db.Content(t + ":" + i)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- if len(data) < 1 || data == nil {
- res.WriteHeader(http.StatusNotFound)
- errView, err := Error404()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- err = json.Unmarshal(data, post)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
- } else {
- item, ok := post.(item.Identifiable)
- if !ok {
- log.Println("Content type", t, "doesn't implement item.Identifiable")
- return
- }
-
- item.SetItemID(-1)
- }
-
- m, err := manager.Manage(post.(editor.Editable), t)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- adminView, err := Admin(m)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- res.Header().Set("Content-Type", "text/html")
- res.Write(adminView)
-
- case http.MethodPost:
- err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- cid := req.FormValue("id")
- t := req.FormValue("type")
- ts := req.FormValue("timestamp")
- up := req.FormValue("updated")
-
- // create a timestamp if one was not set
- if ts == "" {
- ts = fmt.Sprintf("%d", int64(time.Nanosecond)*time.Now().UTC().UnixNano()/int64(time.Millisecond))
- req.PostForm.Set("timestamp", ts)
- }
-
- if up == "" {
- req.PostForm.Set("updated", ts)
- }
-
- urlPaths, err := upload.StoreFiles(req)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- for name, urlPath := range urlPaths {
- req.PostForm.Set(name, urlPath)
- }
-
- // check for any multi-value fields (ex. checkbox fields)
- // and correctly format for db storage. Essentially, we need
- // fieldX.0: value1, fieldX.1: value2 => fieldX: []string{value1, value2}
- fieldOrderValue := make(map[string]map[string][]string)
- ordVal := make(map[string][]string)
- for k, v := range req.PostForm {
- if strings.Contains(k, ".") {
- fo := strings.Split(k, ".")
-
- // put the order and the field value into map
- field := string(fo[0])
- order := string(fo[1])
- fieldOrderValue[field] = ordVal
-
- // orderValue is 0:[?type=Thing&id=1]
- orderValue := fieldOrderValue[field]
- orderValue[order] = v
- fieldOrderValue[field] = orderValue
-
- // discard the post form value with name.N
- req.PostForm.Del(k)
- }
-
- }
-
- // add/set the key & value to the post form in order
- for f, ov := range fieldOrderValue {
- for i := 0; i < len(ov); i++ {
- position := fmt.Sprintf("%d", i)
- fieldValue := ov[position]
-
- if req.PostForm.Get(f) == "" {
- for i, fv := range fieldValue {
- if i == 0 {
- req.PostForm.Set(f, fv)
- } else {
- req.PostForm.Add(f, fv)
- }
- }
- } else {
- for _, fv := range fieldValue {
- req.PostForm.Add(f, fv)
- }
- }
- }
- }
-
- pt := t
- if strings.Contains(t, "__") {
- pt = strings.Split(t, "__")[0]
- }
-
- p, ok := item.Types[pt]
- if !ok {
- log.Println("Type", t, "is not a content type. Cannot edit or save.")
- res.WriteHeader(http.StatusBadRequest)
- errView, err := Error400()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- post := p()
- hook, ok := post.(item.Hookable)
- if !ok {
- log.Println("Type", pt, "does not implement item.Hookable or embed item.Item.")
- res.WriteHeader(http.StatusBadRequest)
- errView, err := Error400()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- err = hook.BeforeSave(res, req)
- if err != nil {
- log.Println("Error running BeforeSave method in editHandler for:", t, err)
- return
- }
-
- id, err := db.SetContent(t+":"+cid, req.PostForm)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- // set the target in the context so user can get saved value from db in hook
- ctx := context.WithValue(req.Context(), "target", fmt.Sprintf("%s:%d", t, id))
- req = req.WithContext(ctx)
-
- err = hook.AfterSave(res, req)
- if err != nil {
- log.Println("Error running AfterSave method in editHandler for:", t, err)
- return
- }
-
- scheme := req.URL.Scheme
- host := req.URL.Host
- path := req.URL.Path
- sid := fmt.Sprintf("%d", id)
- redir := scheme + host + path + "?type=" + pt + "&id=" + sid
-
- if req.URL.Query().Get("status") == "pending" {
- redir += "&status=pending"
- }
-
- http.Redirect(res, req, redir, http.StatusFound)
-
- default:
- res.WriteHeader(http.StatusMethodNotAllowed)
- }
-}
-
-func deleteHandler(res http.ResponseWriter, req *http.Request) {
- if req.Method != http.MethodPost {
- res.WriteHeader(http.StatusMethodNotAllowed)
- return
- }
-
- err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- id := req.FormValue("id")
- t := req.FormValue("type")
- ct := t
-
- if id == "" || t == "" {
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- // catch specifier suffix from delete form value
- if strings.Contains(t, "__") {
- spec := strings.Split(t, "__")
- ct = spec[0]
- }
-
- p, ok := item.Types[ct]
- if !ok {
- log.Println("Type", t, "does not implement item.Hookable or embed item.Item.")
- res.WriteHeader(http.StatusBadRequest)
- errView, err := Error400()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- post := p()
- hook, ok := post.(item.Hookable)
- if !ok {
- log.Println("Type", t, "does not implement item.Hookable or embed item.Item.")
- res.WriteHeader(http.StatusBadRequest)
- errView, err := Error400()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- reject := req.URL.Query().Get("reject")
- if reject == "true" {
- err = hook.BeforeReject(res, req)
- if err != nil {
- log.Println("Error running BeforeReject method in deleteHandler for:", t, err)
- return
- }
- }
-
- err = hook.BeforeDelete(res, req)
- if err != nil {
- log.Println("Error running BeforeDelete method in deleteHandler for:", t, err)
- return
- }
-
- err = db.DeleteContent(t + ":" + id)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- err = hook.AfterDelete(res, req)
- if err != nil {
- log.Println("Error running AfterDelete method in deleteHandler for:", t, err)
- return
- }
-
- if reject == "true" {
- err = hook.AfterReject(res, req)
- if err != nil {
- log.Println("Error running AfterReject method in deleteHandler for:", t, err)
- return
- }
- }
-
- redir := strings.TrimSuffix(req.URL.Scheme+req.URL.Host+req.URL.Path, "/edit/delete")
- redir = redir + "/contents?type=" + ct
- http.Redirect(res, req, redir, http.StatusFound)
-}
-
-func editUploadHandler(res http.ResponseWriter, req *http.Request) {
- if req.Method != http.MethodPost {
- res.WriteHeader(http.StatusMethodNotAllowed)
- return
- }
-
- urlPaths, err := upload.StoreFiles(req)
- if err != nil {
- log.Println("Couldn't store file uploads.", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- res.Header().Set("Content-Type", "application/json")
- res.Write([]byte(`{"data": [{"url": "` + urlPaths["file"] + `"}]}`))
-}
-
-func searchHandler(res http.ResponseWriter, req *http.Request) {
- q := req.URL.Query()
- t := q.Get("type")
- search := q.Get("q")
- status := q.Get("status")
- var specifier string
-
- if t == "" || search == "" {
- http.Redirect(res, req, req.URL.Scheme+req.URL.Host+"/admin", http.StatusFound)
- return
- }
-
- if status == "pending" {
- specifier = "__" + status
- }
-
- posts := db.ContentAll(t + specifier)
- b := &bytes.Buffer{}
- p := item.Types[t]().(editor.Editable)
-
- html := `<div class="col s9 card">
- <div class="card-content">
- <div class="row">
- <div class="card-title col s7">` + t + ` Results</div>
- <form class="col s4" action="/admin/contents/search" method="get">
- <div class="input-field post-search inline">
- <label class="active">Search:</label>
- <i class="right material-icons search-icon">search</i>
- <input class="search" name="q" type="text" placeholder="Within all ` + t + ` fields" class="search"/>
- <input type="hidden" name="type" value="` + t + `" />
- <input type="hidden" name="status" value="` + status + `" />
- </div>
- </form>
- </div>
- <ul class="posts row">`
-
- for i := range posts {
- // skip posts that don't have any matching search criteria
- match := strings.ToLower(search)
- all := strings.ToLower(string(posts[i]))
- if !strings.Contains(all, match) {
- continue
- }
-
- err := json.Unmarshal(posts[i], &p)
- if err != nil {
- log.Println("Error unmarshal search result json into", t, err, posts[i])
-
- post := `<li class="col s12">Error decoding data. Possible file corruption.</li>`
- _, err = b.Write([]byte(post))
- if err != nil {
- log.Println(err)
-
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- }
-
- res.Write(errView)
- return
- }
- continue
- }
-
- post := adminPostListItem(p, t, status)
- _, err = b.Write([]byte(post))
- if err != nil {
- log.Println(err)
-
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- }
-
- res.Write(errView)
- return
- }
- }
-
- _, err := b.WriteString(`</ul></div></div>`)
- if err != nil {
- log.Println(err)
-
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- }
-
- res.Write(errView)
- return
- }
-
- btn := `<div class="col s3"><a href="/admin/edit?type=` + t + `" class="btn new-post waves-effect waves-light">New ` + t + `</a></div></div>`
- html = html + b.String() + btn
-
- adminView, err := Admin([]byte(html))
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- res.Header().Set("Content-Type", "text/html")
- res.Write(adminView)
-}
-
-func addonsHandler(res http.ResponseWriter, req *http.Request) {
- switch req.Method {
- case http.MethodGet:
- all := db.AddonAll()
- list := &bytes.Buffer{}
-
- for i := range all {
- v := adminAddonListItem(all[i])
- _, err := list.Write(v)
- if err != nil {
- log.Println("Error writing bytes to addon list view:", err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- return
- }
-
- res.Write(errView)
- return
- }
- }
-
- html := &bytes.Buffer{}
- open := `<div class="col s9 card">
- <div class="card-content">
- <div class="row">
- <div class="card-title col s7">Addons</div>
- </div>
- <ul class="posts row">`
-
- _, err := html.WriteString(open)
- if err != nil {
- log.Println("Error writing open html to addon html view:", err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- return
- }
-
- res.Write(errView)
- return
- }
-
- _, err = html.Write(list.Bytes())
- if err != nil {
- log.Println("Error writing list bytes to addon html view:", err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- return
- }
-
- res.Write(errView)
- return
- }
-
- _, err = html.WriteString(`</ul></div></div>`)
- if err != nil {
- log.Println("Error writing close html to addon html view:", err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- return
- }
-
- res.Write(errView)
- return
- }
-
- if html.Len() == 0 {
- _, err := html.WriteString(`<p>No addons available.</p>`)
- if err != nil {
- log.Println("Error writing default addon html to admin view:", err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- return
- }
-
- res.Write(errView)
- return
- }
- }
-
- view, err := Admin(html.Bytes())
- if err != nil {
- log.Println("Error writing addon html to admin view:", err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- log.Println(err)
- return
- }
-
- res.Write(errView)
- return
- }
-
- res.Write(view)
-
- case http.MethodPost:
- err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- id := req.PostFormValue("id")
- action := strings.ToLower(req.PostFormValue("action"))
-
- _, err = db.Addon(id)
- if err == db.ErrNoAddonExists {
- log.Println(err)
- res.WriteHeader(http.StatusNotFound)
- errView, err := Error404()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- switch action {
- case "enable":
- err := addon.Enable(id)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
- case "disable":
- err := addon.Disable(id)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
- default:
- res.WriteHeader(http.StatusBadRequest)
- errView, err := Error400()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- http.Redirect(res, req, req.URL.String(), http.StatusFound)
-
- default:
- res.WriteHeader(http.StatusBadRequest)
- errView, err := Error400()
- if err != nil {
- log.Println(err)
- return
- }
-
- res.Write(errView)
- return
- }
-}
-
-func addonHandler(res http.ResponseWriter, req *http.Request) {
- switch req.Method {
- case http.MethodGet:
- id := req.FormValue("id")
-
- data, err := db.Addon(id)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- _, ok := addon.Types[id]
- if !ok {
- log.Println("Addon: ", id, "is not found in addon.Types map")
- res.WriteHeader(http.StatusNotFound)
- errView, err := Error404()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- m, err := addon.Manage(data, id)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- addonView, err := Admin(m)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- res.Header().Set("Content-Type", "text/html")
- res.Write(addonView)
-
- case http.MethodPost:
- // save req.Form
- err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- name := req.FormValue("addon_name")
- id := req.FormValue("addon_reverse_dns")
-
- at, ok := addon.Types[id]
- if !ok {
- log.Println("Error: addon", name, "has no record in addon.Types map at", id)
- res.WriteHeader(http.StatusBadRequest)
- errView, err := Error400()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- // if Hookable, call BeforeSave prior to saving
- h, ok := at().(item.Hookable)
- if ok {
- err := h.BeforeSave(res, req)
- if err != nil {
- log.Println("Error running BeforeSave method in addonHandler for:", id, err)
- return
- }
- }
-
- err = db.SetAddon(req.Form, at())
- if err != nil {
- log.Println("Error saving addon:", name, err)
- res.WriteHeader(http.StatusInternalServerError)
- errView, err := Error500()
- if err != nil {
- return
- }
-
- res.Write(errView)
- return
- }
-
- http.Redirect(res, req, "/admin/addon?id="+id, http.StatusFound)
-
- default:
- res.WriteHeader(http.StatusBadRequest)
- errView, err := Error405()
- if err != nil {
- log.Println(err)
- return
- }
-
- res.Write(errView)
- return
- }
-}
-
-func adminAddonListItem(data []byte) []byte {
- id := gjson.GetBytes(data, "addon_reverse_dns").String()
- status := gjson.GetBytes(data, "addon_status").String()
- name := gjson.GetBytes(data, "addon_name").String()
- author := gjson.GetBytes(data, "addon_author").String()
- authorURL := gjson.GetBytes(data, "addon_author_url").String()
- version := gjson.GetBytes(data, "addon_version").String()
-
- var action string
- var buttonClass string
- if status != addon.StatusEnabled {
- action = "Enable"
- buttonClass = "green"
- } else {
- action = "Disable"
- buttonClass = "red"
- }
-
- a := `
- <li class="col s12">
- <div class="row">
- <div class="col s9">
- <a class="addon-name" href="/admin/addon?id=` + id + `" alt="Configure '` + name + `'">` + name + `</a>
- <span class="addon-meta addon-author">by: <a href="` + authorURL + `">` + author + `</a></span>
- <span class="addon-meta addon-version">version: ` + version + `</span>
- </div>
-
- <div class="col s3">
- <form enctype="multipart/form-data" class="quick-` + strings.ToLower(action) + `-addon __ponzu right" action="/admin/addons" method="post">
- <button class="btn waves-effect waves-effect-light ` + buttonClass + `">` + action + `</button>
- <input type="hidden" name="id" value="` + id + `" />
- <input type="hidden" name="action" value="` + action + `" />
- </form>
- </div>
- </div>
- </li>`
-
- return []byte(a)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/server.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/server.go
deleted file mode 100644
index df00c21..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/server.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package admin
-
-import (
- "log"
- "net/http"
- "os"
- "path/filepath"
-
- "github.com/ponzu-cms/ponzu/system"
- "github.com/ponzu-cms/ponzu/system/admin/user"
- "github.com/ponzu-cms/ponzu/system/api"
- "github.com/ponzu-cms/ponzu/system/db"
-)
-
-// Run adds Handlers to default http listener for Admin
-func Run() {
- http.HandleFunc("/admin", user.Auth(adminHandler))
-
- http.HandleFunc("/admin/init", initHandler)
-
- http.HandleFunc("/admin/login", loginHandler)
- http.HandleFunc("/admin/logout", logoutHandler)
-
- http.HandleFunc("/admin/recover", forgotPasswordHandler)
- http.HandleFunc("/admin/recover/key", recoveryKeyHandler)
-
- http.HandleFunc("/admin/addons", user.Auth(addonsHandler))
- http.HandleFunc("/admin/addon", user.Auth(addonHandler))
-
- http.HandleFunc("/admin/configure", user.Auth(configHandler))
- http.HandleFunc("/admin/configure/users", user.Auth(configUsersHandler))
- http.HandleFunc("/admin/configure/users/edit", user.Auth(configUsersEditHandler))
- http.HandleFunc("/admin/configure/users/delete", user.Auth(configUsersDeleteHandler))
-
- http.HandleFunc("/admin/contents", user.Auth(contentsHandler))
- http.HandleFunc("/admin/contents/search", user.Auth(searchHandler))
-
- http.HandleFunc("/admin/edit", user.Auth(editHandler))
- http.HandleFunc("/admin/edit/delete", user.Auth(deleteHandler))
- http.HandleFunc("/admin/edit/approve", user.Auth(approveContentHandler))
- http.HandleFunc("/admin/edit/upload", user.Auth(editUploadHandler))
-
- pwd, err := os.Getwd()
- if err != nil {
- log.Fatalln("Couldn't find current directory for file server.")
- }
-
- staticDir := filepath.Join(pwd, "cmd", "ponzu", "vendor", "github.com", "ponzu-cms", "ponzu", "system")
- http.Handle("/admin/static/", db.CacheControl(http.FileServer(restrict(http.Dir(staticDir)))))
-
- // API path needs to be registered within server package so that it is handled
- // even if the API server is not running. Otherwise, images/files uploaded
- // through the editor will not load within the admin system.
- uploadsDir := filepath.Join(pwd, "uploads")
- http.Handle("/api/uploads/", api.Record(api.CORS(db.CacheControl(http.StripPrefix("/api/uploads/", http.FileServer(restrict(http.Dir(uploadsDir))))))))
-
- // Database & uploads backup via HTTP route registered with Basic Auth middleware.
- http.HandleFunc("/admin/backup", system.BasicAuth(backupHandler))
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/common/js/jquery-2.1.4.min.js b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/common/js/jquery-2.1.4.min.js
deleted file mode 100644
index fc356ee..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/common/js/jquery-2.1.4.min.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/*! jQuery v2.1.4 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */
-!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b="length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\f]' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function qa(){}qa.prototype=d.filters=d.pseudos,d.setFilters=new qa,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function ra(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){
-return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=l.createDocumentFragment(),b=a.appendChild(l.createElement("div")),c=l.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||l,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=l),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&n.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?Z:$):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=Z,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return n().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,ba=/<([\w:]+)/,ca=/<|&#?\w+;/,da=/<(?:script|style|link)/i,ea=/checked\s*(?:[^=]|=\s*.checked.)/i,fa=/^$|\/(?:java|ecma)script/i,ga=/^true\/(.*)/,ha=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ia={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ia.optgroup=ia.option,ia.tbody=ia.tfoot=ia.colgroup=ia.caption=ia.thead,ia.th=ia.td;function ja(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function ka(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function la(a){var b=ga.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function ma(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function na(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function oa(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pa(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=oa(h),f=oa(a),d=0,e=f.length;e>d;d++)pa(f[d],g[d]);if(b)if(c)for(f=f||oa(a),g=g||oa(h),d=0,e=f.length;e>d;d++)na(f[d],g[d]);else na(a,h);return g=oa(h,"script"),g.length>0&&ma(g,!i&&oa(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(ca.test(e)){f=f||k.appendChild(b.createElement("div")),g=(ba.exec(e)||["",""])[1].toLowerCase(),h=ia[g]||ia._default,f.innerHTML=h[1]+e.replace(aa,"<$1></$2>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=oa(k.appendChild(e),"script"),i&&ma(f),c)){j=0;while(e=f[j++])fa.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(oa(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&ma(oa(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(oa(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!da.test(a)&&!ia[(ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(aa,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(oa(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(oa(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&ea.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(oa(c,"script"),ka),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,oa(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,la),j=0;g>j;j++)h=f[j],fa.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(ha,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qa,ra={};function sa(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function ta(a){var b=l,c=ra[a];return c||(c=sa(a,b),"none"!==c&&c||(qa=(qa||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qa[0].contentDocument,b.write(),b.close(),c=sa(a,b),qa.detach()),ra[a]=c),c}var ua=/^margin/,va=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wa=function(b){return b.ownerDocument.defaultView.opener?b.ownerDocument.defaultView.getComputedStyle(b,null):a.getComputedStyle(b,null)};function xa(a,b,c){var d,e,f,g,h=a.style;return c=c||wa(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),va.test(g)&&ua.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function ya(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d=l.documentElement,e=l.createElement("div"),f=l.createElement("div");if(f.style){f.style.backgroundClip="content-box",f.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===f.style.backgroundClip,e.style.cssText="border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;position:absolute",e.appendChild(f);function g(){f.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",f.innerHTML="",d.appendChild(e);var g=a.getComputedStyle(f,null);b="1%"!==g.top,c="4px"===g.width,d.removeChild(e)}a.getComputedStyle&&n.extend(k,{pixelPosition:function(){return g(),b},boxSizingReliable:function(){return null==c&&g(),c},reliableMarginRight:function(){var b,c=f.appendChild(l.createElement("div"));return c.style.cssText=f.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",c.style.marginRight=c.style.width="0",f.style.width="1px",d.appendChild(e),b=!parseFloat(a.getComputedStyle(c,null).marginRight),d.removeChild(e),f.removeChild(c),b}})}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var za=/^(none|table(?!-c[ea]).+)/,Aa=new RegExp("^("+Q+")(.*)$","i"),Ba=new RegExp("^([+-])=("+Q+")","i"),Ca={position:"absolute",visibility:"hidden",display:"block"},Da={letterSpacing:"0",fontWeight:"400"},Ea=["Webkit","O","Moz","ms"];function Fa(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Ea.length;while(e--)if(b=Ea[e]+c,b in a)return b;return d}function Ga(a,b,c){var d=Aa.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Ha(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+R[f]+"Width",!0,e))):(g+=n.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ia(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wa(a),g="border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xa(a,b,f),(0>e||null==e)&&(e=a.style[b]),va.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Ha(a,b,c||(g?"border":"content"),d,f)+"px"}function Ja(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",ta(d.nodeName)))):(e=S(d),"none"===c&&e||L.set(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xa(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;return b=n.cssProps[h]||(n.cssProps[h]=Fa(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Ba.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Fa(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xa(a,b,d)),"normal"===e&&b in Da&&(e=Da[b]),""===c||c?(f=parseFloat(e),c===!0||n.isNumeric(f)?f||0:e):e}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?za.test(n.css(a,"display"))&&0===a.offsetWidth?n.swap(a,Ca,function(){return Ia(a,b,d)}):Ia(a,b,d):void 0},set:function(a,c,d){var e=d&&wa(a);return Ga(a,c,d?Ha(a,b,d,"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),n.cssHooks.marginRight=ya(k.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},xa,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ua.test(a)||(n.cssHooks[a+b].set=Ga)}),n.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=wa(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return Ja(this,!0)},hide:function(){return Ja(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?n(this).show():n(this).hide()})}});function Ka(a,b,c,d,e){return new Ka.prototype.init(a,b,c,d,e)}n.Tween=Ka,Ka.prototype={constructor:Ka,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=Ka.propHooks[this.prop];return a&&a.get?a.get(this):Ka.propHooks._default.get(this)},run:function(a){var b,c=Ka.propHooks[this.prop];return this.options.duration?this.pos=b=n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Ka.propHooks._default.set(this),this}},Ka.prototype.init.prototype=Ka.prototype,Ka.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Ka.propHooks.scrollTop=Ka.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=Ka.prototype.init,n.fx.step={};var La,Ma,Na=/^(?:toggle|show|hide)$/,Oa=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pa=/queueHooks$/,Qa=[Va],Ra={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Oa.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&Oa.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sa(){return setTimeout(function(){La=void 0}),La=n.now()}function Ta(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ua(a,b,c){for(var d,e=(Ra[b]||[]).concat(Ra["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Va(a,b,c){var d,e,f,g,h,i,j,k,l=this,m={},o=a.style,p=a.nodeType&&S(a),q=L.get(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,l.always(function(){l.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=n.css(a,"display"),k="none"===j?L.get(a,"olddisplay")||ta(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(o.display="inline-block")),c.overflow&&(o.overflow="hidden",l.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Na.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}m[d]=q&&q[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(m))"inline"===("none"===j?ta(a.nodeName):j)&&(o.display=j);else{q?"hidden"in q&&(p=q.hidden):q=L.access(a,"fxshow",{}),f&&(q.hidden=!p),p?n(a).show():l.done(function(){n(a).hide()}),l.done(function(){var b;L.remove(a,"fxshow");for(b in m)n.style(a,b,m[b])});for(d in m)g=Ua(p?q[d]:0,d,l),d in q||(q[d]=g.start,p&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wa(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xa(a,b,c){var d,e,f=0,g=Qa.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=La||Sa(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:La||Sa(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wa(k,j.opts.specialEasing);g>f;f++)if(d=Qa[f].call(j,a,k,j.opts))return d;return n.map(k,Ua,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(Xa,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Ra[c]=Ra[c]||[],Ra[c].unshift(b)},prefilter:function(a,b){b?Qa.unshift(a):Qa.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=Xa(this,n.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pa.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Ta(b,!0),a,d,e)}}),n.each({slideDown:Ta("show"),slideUp:Ta("hide"),slideToggle:Ta("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=0,c=n.timers;for(La=n.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||n.fx.stop(),La=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){Ma||(Ma=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(Ma),Ma=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=l.createElement("input"),b=l.createElement("select"),c=b.appendChild(l.createElement("option"));a.type="checkbox",k.checkOn=""!==a.value,k.optSelected=c.selected,b.disabled=!0,k.optDisabled=!c.disabled,a=l.createElement("input"),a.value="t",a.type="radio",k.radioValue="t"===a.value}();var Ya,Za,$a=n.expr.attrHandle;n.fn.extend({attr:function(a,b){return J(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?Za:Ya)),
-void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Za={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$a[b]||n.find.attr;$a[b]=function(a,b,d){var e,f;return d||(f=$a[b],$a[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$a[b]=f),e}});var _a=/^(?:input|select|textarea|button)$/i;n.fn.extend({prop:function(a,b){return J(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_a.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),k.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var ab=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ab," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ab," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ab," ").indexOf(b)>=0)return!0;return!1}});var bb=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bb,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(d.value,f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},k.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cb=n.now(),db=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&n.error("Invalid XML: "+a),b};var eb=/#.*$/,fb=/([?&])_=[^&]*/,gb=/^(.*?):[ \t]*([^\r\n]*)$/gm,hb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,ib=/^(?:GET|HEAD)$/,jb=/^\/\//,kb=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,lb={},mb={},nb="*/".concat("*"),ob=a.location.href,pb=kb.exec(ob.toLowerCase())||[];function qb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function rb(a,b,c,d){var e={},f=a===mb;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function sb(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function tb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function ub(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:ob,type:"GET",isLocal:hb.test(pb[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":nb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?sb(sb(a,n.ajaxSettings),b):sb(n.ajaxSettings,a)},ajaxPrefilter:qb(lb),ajaxTransport:qb(mb),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=gb.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||ob)+"").replace(eb,"").replace(jb,pb[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=kb.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===pb[1]&&h[2]===pb[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(pb[3]||("http:"===pb[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),rb(lb,k,b,v),2===t)return v;i=n.event&&k.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!ib.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(db.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=fb.test(d)?d.replace(fb,"$1_="+cb++):d+(db.test(d)?"&":"?")+"_="+cb++)),k.ifModified&&(n.lastModified[d]&&v.setRequestHeader("If-Modified-Since",n.lastModified[d]),n.etag[d]&&v.setRequestHeader("If-None-Match",n.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+nb+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=rb(mb,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=tb(k,v,f)),u=ub(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(n.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var vb=/%20/g,wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&").replace(vb,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Bb=0,Cb={},Db={0:200,1223:204},Eb=n.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in Cb)Cb[a]()}),k.cors=!!Eb&&"withCredentials"in Eb,k.ajax=Eb=!!Eb,n.ajaxTransport(function(a){var b;return k.cors||Eb&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Bb;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Cb[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Db[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Cb[g]=b("abort");try{f.send(a.hasContent&&a.data||null)}catch(h){if(b)throw h}},abort:function(){b&&b()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=n("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),l.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Fb=[],Gb=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Fb.pop()||n.expando+"_"+cb++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Gb.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Gb.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Gb,"$1"+e):b.jsonp!==!1&&(b.url+=(db.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Fb.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||l;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var Hb=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&Hb)return Hb.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=n.trim(a.slice(h)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var Ib=a.document.documentElement;function Jb(a){return n.isWindow(a)?a:9===a.nodeType&&a.defaultView}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,n.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Jb(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===n.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(d=a.offset()),d.top+=n.css(a[0],"borderTopWidth",!0),d.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-n.css(c,"marginTop",!0),left:b.left-d.left-n.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Ib;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Ib})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;n.fn[b]=function(e){return J(this,function(b,e,f){var g=Jb(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=ya(k.pixelPosition,function(a,c){return c?(c=xa(a,b),va.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var Kb=a.jQuery,Lb=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=Lb),b&&a.jQuery===n&&(a.jQuery=Kb),n},typeof b===U&&(a.jQuery=a.$=n),n}); \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/common/js/util.js b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/common/js/util.js
deleted file mode 100644
index 8d5e74b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/common/js/util.js
+++ /dev/null
@@ -1,86 +0,0 @@
-// Replaces commonly-used Windows 1252 encoded chars that do not exist in ASCII or ISO-8859-1 with ISO-8859-1 cognates.
-// modified from http://www.andornot.com/blog/post/Replace-MS-Word-special-characters-in-javascript-and-C.aspx
-function replaceBadChars(text) {
- var s = text;
- // smart single quotes and apostrophe
- s = s.replace(/[\u2018\u2019\u201A]/g, "\'");
- // smart double quotes
- s = s.replace(/[\u201C\u201D\u201E]/g, "\"");
- // ellipsis
- s = s.replace(/\u2026/g, "...");
- // dashes
- s = s.replace(/[\u2013\u2014]/g, "-");
- // circumflex
- s = s.replace(/\u02C6/g, "^");
- // open angle bracket
- s = s.replace(/\u2039/g, "<");
- // close angle bracket
- s = s.replace(/\u203A/g, ">");
- // spaces
- s = s.replace(/[\u02DC\u00A0]/g, " ");
-
- return s;
-}
-
-
-// Returns a local partial time object based on unix timestamp
-function getPartialTime(unix) {
- var date = new Date(unix);
- var t = {};
- var hours = date.getHours();
- if (hours < 10) {
- hours = "0" + String(hours);
- }
-
- t.hh = hours;
- if (hours > 12) {
- t.hh = hours - 12;
- t.pd = "PM";
- } else if (hours === 12) {
- t.pd = "PM";
- } else if (hours < 12) {
- t.pd = "AM";
- }
-
- var minutes = date.getMinutes();
- if (minutes < 10) {
- minutes = "0" + String(minutes);
- }
- t.mm = minutes;
-
- return t;
-}
-
-// Returns a local partial date object based on unix timestamp
-function getPartialDate(unix) {
- var date = new Date(unix);
- var d = {};
-
- d.yyyy = date.getFullYear();
-
- d.mm = date.getMonth()+1;
-
- var day = date.getDate();
- if (day < 10) {
- day = "0" + String(day);
- }
- d.dd = day;
-
- return d;
-}
-
-// Returns a part of the window URL 'search' string
-function getParam(param) {
- var qs = window.location.search.substring(1);
- var qp = qs.split('&');
- var t = '';
-
- for (var i = 0; i < qp.length; i++) {
- var p = qp[i].split('=')
- if (p[0] === param) {
- t = p[1];
- }
- }
-
- return t;
-} \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/css/admin.css b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/css/admin.css
deleted file mode 100644
index 06df137..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/css/admin.css
+++ /dev/null
@@ -1,249 +0,0 @@
-.navbar-fixed {
- z-index: 10000 !important;
-}
-
-.nav-wrapper {
- width: 95%;
- max-width: 1300px;
- margin: auto;
-}
-
-.nav-wrapper a:hover {
- color: inherit !important;
-}
-
-.admin-ui {
- width: 95%;
- max-width: 1300px;
- margin: 1% auto;
-}
-
-.init {
- float: none !important;
- margin: auto !important;
-}
-
-.manager {
- margin-bottom: 2%;
-}
-
-.left-nav .row li a {
- padding: 10px 0;
- transition: color 0.3s ease;
-}
-
-.left-nav .card-title {
- margin-top: 10px !important;
-}
-
-.left-nav .card-title:first-child {
- margin-top: 0px !important;
-}
-
-.col.card-title {
- padding: 0px !important;
-}
-
-ul.posts li, ul.users li {
- display: block;
- margin: 0 0 20px 0;
- padding: 0 0 20px 0 !important;
- border-bottom: solid 1px #e0e0e0;
-}
-
-ul.posts li:last-child {
- border-bottom: none;
- margin: 0 !important;
- padding: 0 !important;
-}
-
-.post-search .search {
- margin: 0px !important;
-}
-
-
-.post-search .search-icon {
- position: absolute;
- top: 0px;
- right: 0px;
-}
-
-.post-search {
- position: relative;
-}
-
-li a {
- transition: color 0.3s ease;
-}
-
-li a:hover {
- color: #333;
- transition: color 0.3s ease;
-}
-
-a.new-post {
- margin: 0.5rem 0 1rem 0.75rem;
-}
-
-textarea {
- margin: 20px auto;
- display: block;
-}
-
-.material-icons {
- line-height: 1.4;
-}
-
-.clear {
- clear: both;
- display: block;
-}
-
-.clear.padding {
- padding: 10px 0;
-}
-
-select.browser-default {
- margin: 10px 0;
-}
-
-.iso-texteditor {
- position: relative;
- margin: 20px 0;
- padding: 0px !important;
-}
-
-.file-input .preview {
- display: inline-block;
- position: relative;
- margin: 0.5rem 0 1rem 0;
- background-color:#fff;
- border: 1px solid #e0e0e0;
- border-radius: 2px;
-}
-
-.file-input .preview .img-clip {
- overflow: hidden;
- max-width: 300px;
- margin: 10px;
-}
-
-.file-input .preview img {
- width: 100%;
-}
-
-.file-input .preview .reset {
- padding: 0 8px;
- position: absolute;
- top: -5%;
- right: -5%;
- display: block;
- border-radius: 50%;
- z-index: 100;
- opacity: 0;
- transition: opacity 0.3s ease;
-}
-
-.file-input .preview:hover .reset {
- opacity: 1;
- transition: opacity 0.3s ease;
-}
-
-footer p {
- color: #9e9e9e;
-}
-
-.post-controls .save-post, .post-controls .approve-post {
- margin-left: 10px;
-}
-
-span.post-detail {
- font-size: 11px;
- color: #9e9e9e;
- font-style: italic;
-}
-
-.quick-delete-post, .delete-user {
- display: none;
-}
-
-li:hover .quick-delete-post, li:hover .delete-user {
- display: inline-block;
-}
-
-.quick-delete-post span, .delete-user span {
- cursor: pointer;
- color: #F44336;
- text-transform: uppercase;
- font-size: 11px;
- font-weight: bold;
- margin-right: 20px;
-}
-
-.user-management {
- padding: 20px;
-}
-
-.controls button {
- padding: 0px 10px 5px 10px;
- position: relative;
- top: -10px;
-}
-
-tr.default-fields, tr.editor-fields {
- margin-top: 20px;
- margin-bottom: 20px;
-}
-
-.addon-meta a {
- color: #7e7e7e;
- text-decoration: underline;
- font-style: italic;
-}
-
-.addon-meta {
- display: block;
- color: #9e9e9e;
- font-size: 12px;
-}
-
-/* OVERRIDE Bootstrap + Materialize conflicts */
-.iso-texteditor.input-field label {
- color: #9e9e9e;
- position: absolute;
- top: 0.8rem;
- left: 0.75rem;
- font-size: 0.8rem;
- display: block;
- font-weight: normal !important;
- cursor: text;
- transition: .2s ease-out;
- -webkit-transform: translateY(-140%);
- -moz-transform: translateY(-140%);
- -ms-transform: translateY(-140%);
- -o-transform: translateY(-140%);
- transform: translateY(-140%);
-}
-
-.chips {
- margin-top: 10px;
-}
-
-.external.post-controls .col.input-field {
- margin-top: 40px;
- padding: 0;
-}
-
-.approve-details {
- text-align: right;
- padding: 10px 0 !important;
-}
-
-select {
- border: 1px solid #e2e2e2;
- height: 2.5rem;
-}
-
-.note-editor * {
- max-width: 100%;
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/css/material-icons.css b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/css/material-icons.css
deleted file mode 100644
index c5d8be2..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/css/material-icons.css
+++ /dev/null
@@ -1,23 +0,0 @@
-/* fallback */
-@font-face {
- font-family: 'Material Icons';
- font-style: normal;
- font-weight: 400;
- src: local('Material Icons'), local('MaterialIcons-Regular'), url('../fonts/icons-regular.woff2') format('woff2');
-}
-
-.material-icons {
- font-family: 'Material Icons';
- font-weight: normal;
- font-style: normal;
- font-size: 24px;
- line-height: 1;
- letter-spacing: normal;
- text-transform: none;
- display: inline-block;
- white-space: nowrap;
- word-wrap: normal;
- direction: ltr;
- -webkit-font-feature-settings: 'liga';
- -webkit-font-smoothing: antialiased;
-} \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/css/materialize.min.css b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/css/materialize.min.css
deleted file mode 100644
index b98c20e..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/css/materialize.min.css
+++ /dev/null
@@ -1,16 +0,0 @@
-/*!
- * Materialize v0.97.7 (http://materializecss.com)
- * Copyright 2014-2015 Materialize
- * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE)
- */
-.materialize-red{background-color:#e51c23 !important}.materialize-red-text{color:#e51c23 !important}.materialize-red.lighten-5{background-color:#fdeaeb !important}.materialize-red-text.text-lighten-5{color:#fdeaeb !important}.materialize-red.lighten-4{background-color:#f8c1c3 !important}.materialize-red-text.text-lighten-4{color:#f8c1c3 !important}.materialize-red.lighten-3{background-color:#f3989b !important}.materialize-red-text.text-lighten-3{color:#f3989b !important}.materialize-red.lighten-2{background-color:#ee6e73 !important}.materialize-red-text.text-lighten-2{color:#ee6e73 !important}.materialize-red.lighten-1{background-color:#ea454b !important}.materialize-red-text.text-lighten-1{color:#ea454b !important}.materialize-red.darken-1{background-color:#d0181e !important}.materialize-red-text.text-darken-1{color:#d0181e !important}.materialize-red.darken-2{background-color:#b9151b !important}.materialize-red-text.text-darken-2{color:#b9151b !important}.materialize-red.darken-3{background-color:#a21318 !important}.materialize-red-text.text-darken-3{color:#a21318 !important}.materialize-red.darken-4{background-color:#8b1014 !important}.materialize-red-text.text-darken-4{color:#8b1014 !important}.red{background-color:#F44336 !important}.red-text{color:#F44336 !important}.red.lighten-5{background-color:#FFEBEE !important}.red-text.text-lighten-5{color:#FFEBEE !important}.red.lighten-4{background-color:#FFCDD2 !important}.red-text.text-lighten-4{color:#FFCDD2 !important}.red.lighten-3{background-color:#EF9A9A !important}.red-text.text-lighten-3{color:#EF9A9A !important}.red.lighten-2{background-color:#E57373 !important}.red-text.text-lighten-2{color:#E57373 !important}.red.lighten-1{background-color:#EF5350 !important}.red-text.text-lighten-1{color:#EF5350 !important}.red.darken-1{background-color:#E53935 !important}.red-text.text-darken-1{color:#E53935 !important}.red.darken-2{background-color:#D32F2F !important}.red-text.text-darken-2{color:#D32F2F !important}.red.darken-3{background-color:#C62828 !important}.red-text.text-darken-3{color:#C62828 !important}.red.darken-4{background-color:#B71C1C !important}.red-text.text-darken-4{color:#B71C1C !important}.red.accent-1{background-color:#FF8A80 !important}.red-text.text-accent-1{color:#FF8A80 !important}.red.accent-2{background-color:#FF5252 !important}.red-text.text-accent-2{color:#FF5252 !important}.red.accent-3{background-color:#FF1744 !important}.red-text.text-accent-3{color:#FF1744 !important}.red.accent-4{background-color:#D50000 !important}.red-text.text-accent-4{color:#D50000 !important}.pink{background-color:#e91e63 !important}.pink-text{color:#e91e63 !important}.pink.lighten-5{background-color:#fce4ec !important}.pink-text.text-lighten-5{color:#fce4ec !important}.pink.lighten-4{background-color:#f8bbd0 !important}.pink-text.text-lighten-4{color:#f8bbd0 !important}.pink.lighten-3{background-color:#f48fb1 !important}.pink-text.text-lighten-3{color:#f48fb1 !important}.pink.lighten-2{background-color:#f06292 !important}.pink-text.text-lighten-2{color:#f06292 !important}.pink.lighten-1{background-color:#ec407a !important}.pink-text.text-lighten-1{color:#ec407a !important}.pink.darken-1{background-color:#d81b60 !important}.pink-text.text-darken-1{color:#d81b60 !important}.pink.darken-2{background-color:#c2185b !important}.pink-text.text-darken-2{color:#c2185b !important}.pink.darken-3{background-color:#ad1457 !important}.pink-text.text-darken-3{color:#ad1457 !important}.pink.darken-4{background-color:#880e4f !important}.pink-text.text-darken-4{color:#880e4f !important}.pink.accent-1{background-color:#ff80ab !important}.pink-text.text-accent-1{color:#ff80ab !important}.pink.accent-2{background-color:#ff4081 !important}.pink-text.text-accent-2{color:#ff4081 !important}.pink.accent-3{background-color:#f50057 !important}.pink-text.text-accent-3{color:#f50057 !important}.pink.accent-4{background-color:#c51162 !important}.pink-text.text-accent-4{color:#c51162 !important}.purple{background-color:#9c27b0 !important}.purple-text{color:#9c27b0 !important}.purple.lighten-5{background-color:#f3e5f5 !important}.purple-text.text-lighten-5{color:#f3e5f5 !important}.purple.lighten-4{background-color:#e1bee7 !important}.purple-text.text-lighten-4{color:#e1bee7 !important}.purple.lighten-3{background-color:#ce93d8 !important}.purple-text.text-lighten-3{color:#ce93d8 !important}.purple.lighten-2{background-color:#ba68c8 !important}.purple-text.text-lighten-2{color:#ba68c8 !important}.purple.lighten-1{background-color:#ab47bc !important}.purple-text.text-lighten-1{color:#ab47bc !important}.purple.darken-1{background-color:#8e24aa !important}.purple-text.text-darken-1{color:#8e24aa !important}.purple.darken-2{background-color:#7b1fa2 !important}.purple-text.text-darken-2{color:#7b1fa2 !important}.purple.darken-3{background-color:#6a1b9a !important}.purple-text.text-darken-3{color:#6a1b9a !important}.purple.darken-4{background-color:#4a148c !important}.purple-text.text-darken-4{color:#4a148c !important}.purple.accent-1{background-color:#ea80fc !important}.purple-text.text-accent-1{color:#ea80fc !important}.purple.accent-2{background-color:#e040fb !important}.purple-text.text-accent-2{color:#e040fb !important}.purple.accent-3{background-color:#d500f9 !important}.purple-text.text-accent-3{color:#d500f9 !important}.purple.accent-4{background-color:#a0f !important}.purple-text.text-accent-4{color:#a0f !important}.deep-purple{background-color:#673ab7 !important}.deep-purple-text{color:#673ab7 !important}.deep-purple.lighten-5{background-color:#ede7f6 !important}.deep-purple-text.text-lighten-5{color:#ede7f6 !important}.deep-purple.lighten-4{background-color:#d1c4e9 !important}.deep-purple-text.text-lighten-4{color:#d1c4e9 !important}.deep-purple.lighten-3{background-color:#b39ddb !important}.deep-purple-text.text-lighten-3{color:#b39ddb !important}.deep-purple.lighten-2{background-color:#9575cd !important}.deep-purple-text.text-lighten-2{color:#9575cd !important}.deep-purple.lighten-1{background-color:#7e57c2 !important}.deep-purple-text.text-lighten-1{color:#7e57c2 !important}.deep-purple.darken-1{background-color:#5e35b1 !important}.deep-purple-text.text-darken-1{color:#5e35b1 !important}.deep-purple.darken-2{background-color:#512da8 !important}.deep-purple-text.text-darken-2{color:#512da8 !important}.deep-purple.darken-3{background-color:#4527a0 !important}.deep-purple-text.text-darken-3{color:#4527a0 !important}.deep-purple.darken-4{background-color:#311b92 !important}.deep-purple-text.text-darken-4{color:#311b92 !important}.deep-purple.accent-1{background-color:#b388ff !important}.deep-purple-text.text-accent-1{color:#b388ff !important}.deep-purple.accent-2{background-color:#7c4dff !important}.deep-purple-text.text-accent-2{color:#7c4dff !important}.deep-purple.accent-3{background-color:#651fff !important}.deep-purple-text.text-accent-3{color:#651fff !important}.deep-purple.accent-4{background-color:#6200ea !important}.deep-purple-text.text-accent-4{color:#6200ea !important}.indigo{background-color:#3f51b5 !important}.indigo-text{color:#3f51b5 !important}.indigo.lighten-5{background-color:#e8eaf6 !important}.indigo-text.text-lighten-5{color:#e8eaf6 !important}.indigo.lighten-4{background-color:#c5cae9 !important}.indigo-text.text-lighten-4{color:#c5cae9 !important}.indigo.lighten-3{background-color:#9fa8da !important}.indigo-text.text-lighten-3{color:#9fa8da !important}.indigo.lighten-2{background-color:#7986cb !important}.indigo-text.text-lighten-2{color:#7986cb !important}.indigo.lighten-1{background-color:#5c6bc0 !important}.indigo-text.text-lighten-1{color:#5c6bc0 !important}.indigo.darken-1{background-color:#3949ab !important}.indigo-text.text-darken-1{color:#3949ab !important}.indigo.darken-2{background-color:#303f9f !important}.indigo-text.text-darken-2{color:#303f9f !important}.indigo.darken-3{background-color:#283593 !important}.indigo-text.text-darken-3{color:#283593 !important}.indigo.darken-4{background-color:#1a237e !important}.indigo-text.text-darken-4{color:#1a237e !important}.indigo.accent-1{background-color:#8c9eff !important}.indigo-text.text-accent-1{color:#8c9eff !important}.indigo.accent-2{background-color:#536dfe !important}.indigo-text.text-accent-2{color:#536dfe !important}.indigo.accent-3{background-color:#3d5afe !important}.indigo-text.text-accent-3{color:#3d5afe !important}.indigo.accent-4{background-color:#304ffe !important}.indigo-text.text-accent-4{color:#304ffe !important}.blue{background-color:#2196F3 !important}.blue-text{color:#2196F3 !important}.blue.lighten-5{background-color:#E3F2FD !important}.blue-text.text-lighten-5{color:#E3F2FD !important}.blue.lighten-4{background-color:#BBDEFB !important}.blue-text.text-lighten-4{color:#BBDEFB !important}.blue.lighten-3{background-color:#90CAF9 !important}.blue-text.text-lighten-3{color:#90CAF9 !important}.blue.lighten-2{background-color:#64B5F6 !important}.blue-text.text-lighten-2{color:#64B5F6 !important}.blue.lighten-1{background-color:#42A5F5 !important}.blue-text.text-lighten-1{color:#42A5F5 !important}.blue.darken-1{background-color:#1E88E5 !important}.blue-text.text-darken-1{color:#1E88E5 !important}.blue.darken-2{background-color:#1976D2 !important}.blue-text.text-darken-2{color:#1976D2 !important}.blue.darken-3{background-color:#1565C0 !important}.blue-text.text-darken-3{color:#1565C0 !important}.blue.darken-4{background-color:#0D47A1 !important}.blue-text.text-darken-4{color:#0D47A1 !important}.blue.accent-1{background-color:#82B1FF !important}.blue-text.text-accent-1{color:#82B1FF !important}.blue.accent-2{background-color:#448AFF !important}.blue-text.text-accent-2{color:#448AFF !important}.blue.accent-3{background-color:#2979FF !important}.blue-text.text-accent-3{color:#2979FF !important}.blue.accent-4{background-color:#2962FF !important}.blue-text.text-accent-4{color:#2962FF !important}.light-blue{background-color:#03a9f4 !important}.light-blue-text{color:#03a9f4 !important}.light-blue.lighten-5{background-color:#e1f5fe !important}.light-blue-text.text-lighten-5{color:#e1f5fe !important}.light-blue.lighten-4{background-color:#b3e5fc !important}.light-blue-text.text-lighten-4{color:#b3e5fc !important}.light-blue.lighten-3{background-color:#81d4fa !important}.light-blue-text.text-lighten-3{color:#81d4fa !important}.light-blue.lighten-2{background-color:#4fc3f7 !important}.light-blue-text.text-lighten-2{color:#4fc3f7 !important}.light-blue.lighten-1{background-color:#29b6f6 !important}.light-blue-text.text-lighten-1{color:#29b6f6 !important}.light-blue.darken-1{background-color:#039be5 !important}.light-blue-text.text-darken-1{color:#039be5 !important}.light-blue.darken-2{background-color:#0288d1 !important}.light-blue-text.text-darken-2{color:#0288d1 !important}.light-blue.darken-3{background-color:#0277bd !important}.light-blue-text.text-darken-3{color:#0277bd !important}.light-blue.darken-4{background-color:#01579b !important}.light-blue-text.text-darken-4{color:#01579b !important}.light-blue.accent-1{background-color:#80d8ff !important}.light-blue-text.text-accent-1{color:#80d8ff !important}.light-blue.accent-2{background-color:#40c4ff !important}.light-blue-text.text-accent-2{color:#40c4ff !important}.light-blue.accent-3{background-color:#00b0ff !important}.light-blue-text.text-accent-3{color:#00b0ff !important}.light-blue.accent-4{background-color:#0091ea !important}.light-blue-text.text-accent-4{color:#0091ea !important}.cyan{background-color:#00bcd4 !important}.cyan-text{color:#00bcd4 !important}.cyan.lighten-5{background-color:#e0f7fa !important}.cyan-text.text-lighten-5{color:#e0f7fa !important}.cyan.lighten-4{background-color:#b2ebf2 !important}.cyan-text.text-lighten-4{color:#b2ebf2 !important}.cyan.lighten-3{background-color:#80deea !important}.cyan-text.text-lighten-3{color:#80deea !important}.cyan.lighten-2{background-color:#4dd0e1 !important}.cyan-text.text-lighten-2{color:#4dd0e1 !important}.cyan.lighten-1{background-color:#26c6da !important}.cyan-text.text-lighten-1{color:#26c6da !important}.cyan.darken-1{background-color:#00acc1 !important}.cyan-text.text-darken-1{color:#00acc1 !important}.cyan.darken-2{background-color:#0097a7 !important}.cyan-text.text-darken-2{color:#0097a7 !important}.cyan.darken-3{background-color:#00838f !important}.cyan-text.text-darken-3{color:#00838f !important}.cyan.darken-4{background-color:#006064 !important}.cyan-text.text-darken-4{color:#006064 !important}.cyan.accent-1{background-color:#84ffff !important}.cyan-text.text-accent-1{color:#84ffff !important}.cyan.accent-2{background-color:#18ffff !important}.cyan-text.text-accent-2{color:#18ffff !important}.cyan.accent-3{background-color:#00e5ff !important}.cyan-text.text-accent-3{color:#00e5ff !important}.cyan.accent-4{background-color:#00b8d4 !important}.cyan-text.text-accent-4{color:#00b8d4 !important}.teal{background-color:#009688 !important}.teal-text{color:#009688 !important}.teal.lighten-5{background-color:#e0f2f1 !important}.teal-text.text-lighten-5{color:#e0f2f1 !important}.teal.lighten-4{background-color:#b2dfdb !important}.teal-text.text-lighten-4{color:#b2dfdb !important}.teal.lighten-3{background-color:#80cbc4 !important}.teal-text.text-lighten-3{color:#80cbc4 !important}.teal.lighten-2{background-color:#4db6ac !important}.teal-text.text-lighten-2{color:#4db6ac !important}.teal.lighten-1{background-color:#26a69a !important}.teal-text.text-lighten-1{color:#26a69a !important}.teal.darken-1{background-color:#00897b !important}.teal-text.text-darken-1{color:#00897b !important}.teal.darken-2{background-color:#00796b !important}.teal-text.text-darken-2{color:#00796b !important}.teal.darken-3{background-color:#00695c !important}.teal-text.text-darken-3{color:#00695c !important}.teal.darken-4{background-color:#004d40 !important}.teal-text.text-darken-4{color:#004d40 !important}.teal.accent-1{background-color:#a7ffeb !important}.teal-text.text-accent-1{color:#a7ffeb !important}.teal.accent-2{background-color:#64ffda !important}.teal-text.text-accent-2{color:#64ffda !important}.teal.accent-3{background-color:#1de9b6 !important}.teal-text.text-accent-3{color:#1de9b6 !important}.teal.accent-4{background-color:#00bfa5 !important}.teal-text.text-accent-4{color:#00bfa5 !important}.green{background-color:#4CAF50 !important}.green-text{color:#4CAF50 !important}.green.lighten-5{background-color:#E8F5E9 !important}.green-text.text-lighten-5{color:#E8F5E9 !important}.green.lighten-4{background-color:#C8E6C9 !important}.green-text.text-lighten-4{color:#C8E6C9 !important}.green.lighten-3{background-color:#A5D6A7 !important}.green-text.text-lighten-3{color:#A5D6A7 !important}.green.lighten-2{background-color:#81C784 !important}.green-text.text-lighten-2{color:#81C784 !important}.green.lighten-1{background-color:#66BB6A !important}.green-text.text-lighten-1{color:#66BB6A !important}.green.darken-1{background-color:#43A047 !important}.green-text.text-darken-1{color:#43A047 !important}.green.darken-2{background-color:#388E3C !important}.green-text.text-darken-2{color:#388E3C !important}.green.darken-3{background-color:#2E7D32 !important}.green-text.text-darken-3{color:#2E7D32 !important}.green.darken-4{background-color:#1B5E20 !important}.green-text.text-darken-4{color:#1B5E20 !important}.green.accent-1{background-color:#B9F6CA !important}.green-text.text-accent-1{color:#B9F6CA !important}.green.accent-2{background-color:#69F0AE !important}.green-text.text-accent-2{color:#69F0AE !important}.green.accent-3{background-color:#00E676 !important}.green-text.text-accent-3{color:#00E676 !important}.green.accent-4{background-color:#00C853 !important}.green-text.text-accent-4{color:#00C853 !important}.light-green{background-color:#8bc34a !important}.light-green-text{color:#8bc34a !important}.light-green.lighten-5{background-color:#f1f8e9 !important}.light-green-text.text-lighten-5{color:#f1f8e9 !important}.light-green.lighten-4{background-color:#dcedc8 !important}.light-green-text.text-lighten-4{color:#dcedc8 !important}.light-green.lighten-3{background-color:#c5e1a5 !important}.light-green-text.text-lighten-3{color:#c5e1a5 !important}.light-green.lighten-2{background-color:#aed581 !important}.light-green-text.text-lighten-2{color:#aed581 !important}.light-green.lighten-1{background-color:#9ccc65 !important}.light-green-text.text-lighten-1{color:#9ccc65 !important}.light-green.darken-1{background-color:#7cb342 !important}.light-green-text.text-darken-1{color:#7cb342 !important}.light-green.darken-2{background-color:#689f38 !important}.light-green-text.text-darken-2{color:#689f38 !important}.light-green.darken-3{background-color:#558b2f !important}.light-green-text.text-darken-3{color:#558b2f !important}.light-green.darken-4{background-color:#33691e !important}.light-green-text.text-darken-4{color:#33691e !important}.light-green.accent-1{background-color:#ccff90 !important}.light-green-text.text-accent-1{color:#ccff90 !important}.light-green.accent-2{background-color:#b2ff59 !important}.light-green-text.text-accent-2{color:#b2ff59 !important}.light-green.accent-3{background-color:#76ff03 !important}.light-green-text.text-accent-3{color:#76ff03 !important}.light-green.accent-4{background-color:#64dd17 !important}.light-green-text.text-accent-4{color:#64dd17 !important}.lime{background-color:#cddc39 !important}.lime-text{color:#cddc39 !important}.lime.lighten-5{background-color:#f9fbe7 !important}.lime-text.text-lighten-5{color:#f9fbe7 !important}.lime.lighten-4{background-color:#f0f4c3 !important}.lime-text.text-lighten-4{color:#f0f4c3 !important}.lime.lighten-3{background-color:#e6ee9c !important}.lime-text.text-lighten-3{color:#e6ee9c !important}.lime.lighten-2{background-color:#dce775 !important}.lime-text.text-lighten-2{color:#dce775 !important}.lime.lighten-1{background-color:#d4e157 !important}.lime-text.text-lighten-1{color:#d4e157 !important}.lime.darken-1{background-color:#c0ca33 !important}.lime-text.text-darken-1{color:#c0ca33 !important}.lime.darken-2{background-color:#afb42b !important}.lime-text.text-darken-2{color:#afb42b !important}.lime.darken-3{background-color:#9e9d24 !important}.lime-text.text-darken-3{color:#9e9d24 !important}.lime.darken-4{background-color:#827717 !important}.lime-text.text-darken-4{color:#827717 !important}.lime.accent-1{background-color:#f4ff81 !important}.lime-text.text-accent-1{color:#f4ff81 !important}.lime.accent-2{background-color:#eeff41 !important}.lime-text.text-accent-2{color:#eeff41 !important}.lime.accent-3{background-color:#c6ff00 !important}.lime-text.text-accent-3{color:#c6ff00 !important}.lime.accent-4{background-color:#aeea00 !important}.lime-text.text-accent-4{color:#aeea00 !important}.yellow{background-color:#ffeb3b !important}.yellow-text{color:#ffeb3b !important}.yellow.lighten-5{background-color:#fffde7 !important}.yellow-text.text-lighten-5{color:#fffde7 !important}.yellow.lighten-4{background-color:#fff9c4 !important}.yellow-text.text-lighten-4{color:#fff9c4 !important}.yellow.lighten-3{background-color:#fff59d !important}.yellow-text.text-lighten-3{color:#fff59d !important}.yellow.lighten-2{background-color:#fff176 !important}.yellow-text.text-lighten-2{color:#fff176 !important}.yellow.lighten-1{background-color:#ffee58 !important}.yellow-text.text-lighten-1{color:#ffee58 !important}.yellow.darken-1{background-color:#fdd835 !important}.yellow-text.text-darken-1{color:#fdd835 !important}.yellow.darken-2{background-color:#fbc02d !important}.yellow-text.text-darken-2{color:#fbc02d !important}.yellow.darken-3{background-color:#f9a825 !important}.yellow-text.text-darken-3{color:#f9a825 !important}.yellow.darken-4{background-color:#f57f17 !important}.yellow-text.text-darken-4{color:#f57f17 !important}.yellow.accent-1{background-color:#ffff8d !important}.yellow-text.text-accent-1{color:#ffff8d !important}.yellow.accent-2{background-color:#ff0 !important}.yellow-text.text-accent-2{color:#ff0 !important}.yellow.accent-3{background-color:#ffea00 !important}.yellow-text.text-accent-3{color:#ffea00 !important}.yellow.accent-4{background-color:#ffd600 !important}.yellow-text.text-accent-4{color:#ffd600 !important}.amber{background-color:#ffc107 !important}.amber-text{color:#ffc107 !important}.amber.lighten-5{background-color:#fff8e1 !important}.amber-text.text-lighten-5{color:#fff8e1 !important}.amber.lighten-4{background-color:#ffecb3 !important}.amber-text.text-lighten-4{color:#ffecb3 !important}.amber.lighten-3{background-color:#ffe082 !important}.amber-text.text-lighten-3{color:#ffe082 !important}.amber.lighten-2{background-color:#ffd54f !important}.amber-text.text-lighten-2{color:#ffd54f !important}.amber.lighten-1{background-color:#ffca28 !important}.amber-text.text-lighten-1{color:#ffca28 !important}.amber.darken-1{background-color:#ffb300 !important}.amber-text.text-darken-1{color:#ffb300 !important}.amber.darken-2{background-color:#ffa000 !important}.amber-text.text-darken-2{color:#ffa000 !important}.amber.darken-3{background-color:#ff8f00 !important}.amber-text.text-darken-3{color:#ff8f00 !important}.amber.darken-4{background-color:#ff6f00 !important}.amber-text.text-darken-4{color:#ff6f00 !important}.amber.accent-1{background-color:#ffe57f !important}.amber-text.text-accent-1{color:#ffe57f !important}.amber.accent-2{background-color:#ffd740 !important}.amber-text.text-accent-2{color:#ffd740 !important}.amber.accent-3{background-color:#ffc400 !important}.amber-text.text-accent-3{color:#ffc400 !important}.amber.accent-4{background-color:#ffab00 !important}.amber-text.text-accent-4{color:#ffab00 !important}.orange{background-color:#ff9800 !important}.orange-text{color:#ff9800 !important}.orange.lighten-5{background-color:#fff3e0 !important}.orange-text.text-lighten-5{color:#fff3e0 !important}.orange.lighten-4{background-color:#ffe0b2 !important}.orange-text.text-lighten-4{color:#ffe0b2 !important}.orange.lighten-3{background-color:#ffcc80 !important}.orange-text.text-lighten-3{color:#ffcc80 !important}.orange.lighten-2{background-color:#ffb74d !important}.orange-text.text-lighten-2{color:#ffb74d !important}.orange.lighten-1{background-color:#ffa726 !important}.orange-text.text-lighten-1{color:#ffa726 !important}.orange.darken-1{background-color:#fb8c00 !important}.orange-text.text-darken-1{color:#fb8c00 !important}.orange.darken-2{background-color:#f57c00 !important}.orange-text.text-darken-2{color:#f57c00 !important}.orange.darken-3{background-color:#ef6c00 !important}.orange-text.text-darken-3{color:#ef6c00 !important}.orange.darken-4{background-color:#e65100 !important}.orange-text.text-darken-4{color:#e65100 !important}.orange.accent-1{background-color:#ffd180 !important}.orange-text.text-accent-1{color:#ffd180 !important}.orange.accent-2{background-color:#ffab40 !important}.orange-text.text-accent-2{color:#ffab40 !important}.orange.accent-3{background-color:#ff9100 !important}.orange-text.text-accent-3{color:#ff9100 !important}.orange.accent-4{background-color:#ff6d00 !important}.orange-text.text-accent-4{color:#ff6d00 !important}.deep-orange{background-color:#ff5722 !important}.deep-orange-text{color:#ff5722 !important}.deep-orange.lighten-5{background-color:#fbe9e7 !important}.deep-orange-text.text-lighten-5{color:#fbe9e7 !important}.deep-orange.lighten-4{background-color:#ffccbc !important}.deep-orange-text.text-lighten-4{color:#ffccbc !important}.deep-orange.lighten-3{background-color:#ffab91 !important}.deep-orange-text.text-lighten-3{color:#ffab91 !important}.deep-orange.lighten-2{background-color:#ff8a65 !important}.deep-orange-text.text-lighten-2{color:#ff8a65 !important}.deep-orange.lighten-1{background-color:#ff7043 !important}.deep-orange-text.text-lighten-1{color:#ff7043 !important}.deep-orange.darken-1{background-color:#f4511e !important}.deep-orange-text.text-darken-1{color:#f4511e !important}.deep-orange.darken-2{background-color:#e64a19 !important}.deep-orange-text.text-darken-2{color:#e64a19 !important}.deep-orange.darken-3{background-color:#d84315 !important}.deep-orange-text.text-darken-3{color:#d84315 !important}.deep-orange.darken-4{background-color:#bf360c !important}.deep-orange-text.text-darken-4{color:#bf360c !important}.deep-orange.accent-1{background-color:#ff9e80 !important}.deep-orange-text.text-accent-1{color:#ff9e80 !important}.deep-orange.accent-2{background-color:#ff6e40 !important}.deep-orange-text.text-accent-2{color:#ff6e40 !important}.deep-orange.accent-3{background-color:#ff3d00 !important}.deep-orange-text.text-accent-3{color:#ff3d00 !important}.deep-orange.accent-4{background-color:#dd2c00 !important}.deep-orange-text.text-accent-4{color:#dd2c00 !important}.brown{background-color:#795548 !important}.brown-text{color:#795548 !important}.brown.lighten-5{background-color:#efebe9 !important}.brown-text.text-lighten-5{color:#efebe9 !important}.brown.lighten-4{background-color:#d7ccc8 !important}.brown-text.text-lighten-4{color:#d7ccc8 !important}.brown.lighten-3{background-color:#bcaaa4 !important}.brown-text.text-lighten-3{color:#bcaaa4 !important}.brown.lighten-2{background-color:#a1887f !important}.brown-text.text-lighten-2{color:#a1887f !important}.brown.lighten-1{background-color:#8d6e63 !important}.brown-text.text-lighten-1{color:#8d6e63 !important}.brown.darken-1{background-color:#6d4c41 !important}.brown-text.text-darken-1{color:#6d4c41 !important}.brown.darken-2{background-color:#5d4037 !important}.brown-text.text-darken-2{color:#5d4037 !important}.brown.darken-3{background-color:#4e342e !important}.brown-text.text-darken-3{color:#4e342e !important}.brown.darken-4{background-color:#3e2723 !important}.brown-text.text-darken-4{color:#3e2723 !important}.blue-grey{background-color:#607d8b !important}.blue-grey-text{color:#607d8b !important}.blue-grey.lighten-5{background-color:#eceff1 !important}.blue-grey-text.text-lighten-5{color:#eceff1 !important}.blue-grey.lighten-4{background-color:#cfd8dc !important}.blue-grey-text.text-lighten-4{color:#cfd8dc !important}.blue-grey.lighten-3{background-color:#b0bec5 !important}.blue-grey-text.text-lighten-3{color:#b0bec5 !important}.blue-grey.lighten-2{background-color:#90a4ae !important}.blue-grey-text.text-lighten-2{color:#90a4ae !important}.blue-grey.lighten-1{background-color:#78909c !important}.blue-grey-text.text-lighten-1{color:#78909c !important}.blue-grey.darken-1{background-color:#546e7a !important}.blue-grey-text.text-darken-1{color:#546e7a !important}.blue-grey.darken-2{background-color:#455a64 !important}.blue-grey-text.text-darken-2{color:#455a64 !important}.blue-grey.darken-3{background-color:#37474f !important}.blue-grey-text.text-darken-3{color:#37474f !important}.blue-grey.darken-4{background-color:#263238 !important}.blue-grey-text.text-darken-4{color:#263238 !important}.grey{background-color:#9e9e9e !important}.grey-text{color:#9e9e9e !important}.grey.lighten-5{background-color:#fafafa !important}.grey-text.text-lighten-5{color:#fafafa !important}.grey.lighten-4{background-color:#f5f5f5 !important}.grey-text.text-lighten-4{color:#f5f5f5 !important}.grey.lighten-3{background-color:#eee !important}.grey-text.text-lighten-3{color:#eee !important}.grey.lighten-2{background-color:#e0e0e0 !important}.grey-text.text-lighten-2{color:#e0e0e0 !important}.grey.lighten-1{background-color:#bdbdbd !important}.grey-text.text-lighten-1{color:#bdbdbd !important}.grey.darken-1{background-color:#757575 !important}.grey-text.text-darken-1{color:#757575 !important}.grey.darken-2{background-color:#616161 !important}.grey-text.text-darken-2{color:#616161 !important}.grey.darken-3{background-color:#424242 !important}.grey-text.text-darken-3{color:#424242 !important}.grey.darken-4{background-color:#212121 !important}.grey-text.text-darken-4{color:#212121 !important}.black{background-color:#000 !important}.black-text{color:#000 !important}.white{background-color:#fff !important}.white-text{color:#fff !important}.transparent{background-color:transparent !important}.transparent-text{color:transparent !important}/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}ul{padding:0;list-style-type:none}ul.browser-default,ul.browser-default li{list-style-type:initial}ul li{list-style-type:none}a{color:#039be5;text-decoration:none;-webkit-tap-highlight-color:transparent}.valign-wrapper{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-ms-flex-align:center;align-items:center}.valign-wrapper .valign{display:block}.clearfix{clear:both}.z-depth-0{box-shadow:none !important}.z-depth-1,nav,.card-panel,.card,.toast,.btn,.btn-large,.btn-floating,.dropdown-content,.collapsible,.side-nav{box-shadow:0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12)}.z-depth-1-half,.btn:hover,.btn-large:hover,.btn-floating:hover{box-shadow:0 5px 11px 0 rgba(0,0,0,0.18),0 4px 15px 0 rgba(0,0,0,0.15)}.z-depth-2{box-shadow:0 8px 17px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}.z-depth-3{box-shadow:0 12px 15px 0 rgba(0,0,0,0.24),0 17px 50px 0 rgba(0,0,0,0.19)}.z-depth-4,.modal{box-shadow:0 16px 28px 0 rgba(0,0,0,0.22),0 25px 55px 0 rgba(0,0,0,0.21)}.z-depth-5{box-shadow:0 27px 24px 0 rgba(0,0,0,0.2),0 40px 77px 0 rgba(0,0,0,0.22)}.hoverable{transition:box-shadow .25s;box-shadow:0}.hoverable:hover{transition:box-shadow .25s;box-shadow:0 8px 17px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}.divider{height:1px;overflow:hidden;background-color:#e0e0e0}blockquote{margin:20px 0;padding-left:1.5rem;border-left:5px solid #ee6e73}i{line-height:inherit}i.left{float:left;margin-right:15px}i.right{float:right;margin-left:15px}i.tiny{font-size:1rem}i.small{font-size:2rem}i.medium{font-size:4rem}i.large{font-size:6rem}img.responsive-img,video.responsive-video{max-width:100%;height:auto}.pagination li{display:inline-block;border-radius:2px;text-align:center;vertical-align:top;height:30px}.pagination li a{color:#444;display:inline-block;font-size:1.2rem;padding:0 10px;line-height:30px}.pagination li.active a{color:#fff}.pagination li.active{background-color:#ee6e73}.pagination li.disabled a{cursor:default;color:#999}.pagination li i{font-size:2rem}.pagination li.pages ul li{display:inline-block;float:none}@media only screen and (max-width: 992px){.pagination{width:100%}.pagination li.prev,.pagination li.next{width:10%}.pagination li.pages{width:80%;overflow:hidden;white-space:nowrap}}.breadcrumb{font-size:18px;color:rgba(255,255,255,0.7)}.breadcrumb i,.breadcrumb [class^="mdi-"],.breadcrumb [class*="mdi-"],.breadcrumb i.material-icons{display:inline-block;float:left;font-size:24px}.breadcrumb:before{content:'\E5CC';color:rgba(255,255,255,0.7);vertical-align:top;display:inline-block;font-family:'Material Icons';font-weight:normal;font-style:normal;font-size:25px;margin:0 10px 0 8px;-webkit-font-smoothing:antialiased}.breadcrumb:first-child:before{display:none}.breadcrumb:last-child{color:#fff}.parallax-container{position:relative;overflow:hidden;height:500px}.parallax{position:absolute;top:0;left:0;right:0;bottom:0;z-index:-1}.parallax img{display:none;position:absolute;left:50%;bottom:0;min-width:100%;min-height:100%;-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);-webkit-transform:translateX(-50%);transform:translateX(-50%)}.pin-top,.pin-bottom{position:relative}.pinned{position:fixed !important}ul.staggered-list li{opacity:0}.fade-in{opacity:0;-webkit-transform-origin:0 50%;transform-origin:0 50%}@media only screen and (max-width: 600px){.hide-on-small-only,.hide-on-small-and-down{display:none !important}}@media only screen and (max-width: 992px){.hide-on-med-and-down{display:none !important}}@media only screen and (min-width: 601px){.hide-on-med-and-up{display:none !important}}@media only screen and (min-width: 600px) and (max-width: 992px){.hide-on-med-only{display:none !important}}@media only screen and (min-width: 993px){.hide-on-large-only{display:none !important}}@media only screen and (min-width: 993px){.show-on-large{display:block !important}}@media only screen and (min-width: 600px) and (max-width: 992px){.show-on-medium{display:block !important}}@media only screen and (max-width: 600px){.show-on-small{display:block !important}}@media only screen and (min-width: 601px){.show-on-medium-and-up{display:block !important}}@media only screen and (max-width: 992px){.show-on-medium-and-down{display:block !important}}@media only screen and (max-width: 600px){.center-on-small-only{text-align:center}}footer.page-footer{margin-top:20px;padding-top:20px;background-color:#ee6e73}footer.page-footer .footer-copyright{overflow:hidden;height:50px;line-height:50px;color:rgba(255,255,255,0.8);background-color:rgba(51,51,51,0.08)}table,th,td{border:none}table{width:100%;display:table}table.bordered>thead>tr,table.bordered>tbody>tr{border-bottom:1px solid #d0d0d0}table.striped>tbody>tr:nth-child(odd){background-color:#f2f2f2}table.striped>tbody>tr>td{border-radius:0}table.highlight>tbody>tr{transition:background-color .25s ease}table.highlight>tbody>tr:hover{background-color:#f2f2f2}table.centered thead tr th,table.centered tbody tr td{text-align:center}thead{border-bottom:1px solid #d0d0d0}td,th{padding:15px 5px;display:table-cell;text-align:left;vertical-align:middle;border-radius:2px}@media only screen and (max-width: 992px){table.responsive-table{width:100%;border-collapse:collapse;border-spacing:0;display:block;position:relative}table.responsive-table td:empty:before{content:'\00a0'}table.responsive-table th,table.responsive-table td{margin:0;vertical-align:top}table.responsive-table th{text-align:left}table.responsive-table thead{display:block;float:left}table.responsive-table thead tr{display:block;padding:0 10px 0 0}table.responsive-table thead tr th::before{content:"\00a0"}table.responsive-table tbody{display:block;width:auto;position:relative;overflow-x:auto;white-space:nowrap}table.responsive-table tbody tr{display:inline-block;vertical-align:top}table.responsive-table th{display:block;text-align:right}table.responsive-table td{display:block;min-height:1.25em;text-align:left}table.responsive-table tr{padding:0 10px}table.responsive-table thead{border:0;border-right:1px solid #d0d0d0}table.responsive-table.bordered th{border-bottom:0;border-left:0}table.responsive-table.bordered td{border-left:0;border-right:0;border-bottom:0}table.responsive-table.bordered tr{border:0}table.responsive-table.bordered tbody tr{border-right:1px solid #d0d0d0}}.collection{margin:0.5rem 0 1rem 0;border:1px solid #e0e0e0;border-radius:2px;overflow:hidden;position:relative}.collection .collection-item{background-color:#fff;line-height:1.5rem;padding:10px 20px;margin:0;border-bottom:1px solid #e0e0e0}.collection .collection-item.avatar{min-height:84px;padding-left:72px;position:relative}.collection .collection-item.avatar .circle{position:absolute;width:42px;height:42px;overflow:hidden;left:15px;display:inline-block;vertical-align:middle}.collection .collection-item.avatar i.circle{font-size:18px;line-height:42px;color:#fff;background-color:#999;text-align:center}.collection .collection-item.avatar .title{font-size:16px}.collection .collection-item.avatar p{margin:0}.collection .collection-item.avatar .secondary-content{position:absolute;top:16px;right:16px}.collection .collection-item:last-child{border-bottom:none}.collection .collection-item.active{background-color:#26a69a;color:#eafaf9}.collection .collection-item.active .secondary-content{color:#fff}.collection a.collection-item{display:block;transition:.25s;color:#26a69a}.collection a.collection-item:not(.active):hover{background-color:#ddd}.collection.with-header .collection-header{background-color:#fff;border-bottom:1px solid #e0e0e0;padding:10px 20px}.collection.with-header .collection-item{padding-left:30px}.collection.with-header .collection-item.avatar{padding-left:72px}.secondary-content{float:right;color:#26a69a}.collapsible .collection{margin:0;border:none}span.badge{min-width:3rem;padding:0 6px;text-align:center;font-size:1rem;line-height:inherit;color:#757575;position:absolute;right:15px;box-sizing:border-box}span.badge.new{font-weight:300;font-size:0.8rem;color:#fff;background-color:#26a69a;border-radius:2px}span.badge.new:after{content:" new"}span.badge[data-badge-caption]::after{content:" " attr(data-badge-caption)}nav ul a span.badge{position:static;margin-left:4px;line-height:0}.video-container{position:relative;padding-bottom:56.25%;height:0;overflow:hidden}.video-container iframe,.video-container object,.video-container embed{position:absolute;top:0;left:0;width:100%;height:100%}.progress{position:relative;height:4px;display:block;width:100%;background-color:#acece6;border-radius:2px;margin:0.5rem 0 1rem 0;overflow:hidden}.progress .determinate{position:absolute;top:0;left:0;bottom:0;background-color:#26a69a;transition:width .3s linear}.progress .indeterminate{background-color:#26a69a}.progress .indeterminate:before{content:'';position:absolute;background-color:inherit;top:0;left:0;bottom:0;will-change:left, right;-webkit-animation:indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;animation:indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite}.progress .indeterminate:after{content:'';position:absolute;background-color:inherit;top:0;left:0;bottom:0;will-change:left, right;-webkit-animation:indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;animation:indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;-webkit-animation-delay:1.15s;animation-delay:1.15s}@-webkit-keyframes indeterminate{0%{left:-35%;right:100%}60%{left:100%;right:-90%}100%{left:100%;right:-90%}}@keyframes indeterminate{0%{left:-35%;right:100%}60%{left:100%;right:-90%}100%{left:100%;right:-90%}}@-webkit-keyframes indeterminate-short{0%{left:-200%;right:100%}60%{left:107%;right:-8%}100%{left:107%;right:-8%}}@keyframes indeterminate-short{0%{left:-200%;right:100%}60%{left:107%;right:-8%}100%{left:107%;right:-8%}}.hide{display:none !important}.left-align{text-align:left}.right-align{text-align:right}.center,.center-align{text-align:center}.left{float:left !important}.right{float:right !important}.no-select,input[type=range],input[type=range]+.thumb{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.circle{border-radius:50%}.center-block{display:block;margin-left:auto;margin-right:auto}.truncate{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.no-padding{padding:0 !important}.material-icons{text-rendering:optimizeLegibility;-webkit-font-feature-settings:'liga';-moz-font-feature-settings:'liga';font-feature-settings:'liga'}.container{margin:0 auto;max-width:1280px;width:90%}@media only screen and (min-width: 601px){.container{width:85%}}@media only screen and (min-width: 993px){.container{width:70%}}.container .row{margin-left:-0.75rem;margin-right:-0.75rem}.section{padding-top:1rem;padding-bottom:1rem}.section.no-pad{padding:0}.section.no-pad-bot{padding-bottom:0}.section.no-pad-top{padding-top:0}.row{margin-left:auto;margin-right:auto;margin-bottom:20px}.row:after{content:"";display:table;clear:both}.row .col{float:left;box-sizing:border-box;padding:0 0.75rem;min-height:1px}.row .col[class*="push-"],.row .col[class*="pull-"]{position:relative}.row .col.s1{width:8.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s2{width:16.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s3{width:25%;margin-left:auto;left:auto;right:auto}.row .col.s4{width:33.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s5{width:41.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s6{width:50%;margin-left:auto;left:auto;right:auto}.row .col.s7{width:58.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s8{width:66.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s9{width:75%;margin-left:auto;left:auto;right:auto}.row .col.s10{width:83.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s11{width:91.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s12{width:100%;margin-left:auto;left:auto;right:auto}.row .col.offset-s1{margin-left:8.3333333333%}.row .col.pull-s1{right:8.3333333333%}.row .col.push-s1{left:8.3333333333%}.row .col.offset-s2{margin-left:16.6666666667%}.row .col.pull-s2{right:16.6666666667%}.row .col.push-s2{left:16.6666666667%}.row .col.offset-s3{margin-left:25%}.row .col.pull-s3{right:25%}.row .col.push-s3{left:25%}.row .col.offset-s4{margin-left:33.3333333333%}.row .col.pull-s4{right:33.3333333333%}.row .col.push-s4{left:33.3333333333%}.row .col.offset-s5{margin-left:41.6666666667%}.row .col.pull-s5{right:41.6666666667%}.row .col.push-s5{left:41.6666666667%}.row .col.offset-s6{margin-left:50%}.row .col.pull-s6{right:50%}.row .col.push-s6{left:50%}.row .col.offset-s7{margin-left:58.3333333333%}.row .col.pull-s7{right:58.3333333333%}.row .col.push-s7{left:58.3333333333%}.row .col.offset-s8{margin-left:66.6666666667%}.row .col.pull-s8{right:66.6666666667%}.row .col.push-s8{left:66.6666666667%}.row .col.offset-s9{margin-left:75%}.row .col.pull-s9{right:75%}.row .col.push-s9{left:75%}.row .col.offset-s10{margin-left:83.3333333333%}.row .col.pull-s10{right:83.3333333333%}.row .col.push-s10{left:83.3333333333%}.row .col.offset-s11{margin-left:91.6666666667%}.row .col.pull-s11{right:91.6666666667%}.row .col.push-s11{left:91.6666666667%}.row .col.offset-s12{margin-left:100%}.row .col.pull-s12{right:100%}.row .col.push-s12{left:100%}@media only screen and (min-width: 601px){.row .col.m1{width:8.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m2{width:16.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m3{width:25%;margin-left:auto;left:auto;right:auto}.row .col.m4{width:33.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m5{width:41.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m6{width:50%;margin-left:auto;left:auto;right:auto}.row .col.m7{width:58.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m8{width:66.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m9{width:75%;margin-left:auto;left:auto;right:auto}.row .col.m10{width:83.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m11{width:91.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m12{width:100%;margin-left:auto;left:auto;right:auto}.row .col.offset-m1{margin-left:8.3333333333%}.row .col.pull-m1{right:8.3333333333%}.row .col.push-m1{left:8.3333333333%}.row .col.offset-m2{margin-left:16.6666666667%}.row .col.pull-m2{right:16.6666666667%}.row .col.push-m2{left:16.6666666667%}.row .col.offset-m3{margin-left:25%}.row .col.pull-m3{right:25%}.row .col.push-m3{left:25%}.row .col.offset-m4{margin-left:33.3333333333%}.row .col.pull-m4{right:33.3333333333%}.row .col.push-m4{left:33.3333333333%}.row .col.offset-m5{margin-left:41.6666666667%}.row .col.pull-m5{right:41.6666666667%}.row .col.push-m5{left:41.6666666667%}.row .col.offset-m6{margin-left:50%}.row .col.pull-m6{right:50%}.row .col.push-m6{left:50%}.row .col.offset-m7{margin-left:58.3333333333%}.row .col.pull-m7{right:58.3333333333%}.row .col.push-m7{left:58.3333333333%}.row .col.offset-m8{margin-left:66.6666666667%}.row .col.pull-m8{right:66.6666666667%}.row .col.push-m8{left:66.6666666667%}.row .col.offset-m9{margin-left:75%}.row .col.pull-m9{right:75%}.row .col.push-m9{left:75%}.row .col.offset-m10{margin-left:83.3333333333%}.row .col.pull-m10{right:83.3333333333%}.row .col.push-m10{left:83.3333333333%}.row .col.offset-m11{margin-left:91.6666666667%}.row .col.pull-m11{right:91.6666666667%}.row .col.push-m11{left:91.6666666667%}.row .col.offset-m12{margin-left:100%}.row .col.pull-m12{right:100%}.row .col.push-m12{left:100%}}@media only screen and (min-width: 993px){.row .col.l1{width:8.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l2{width:16.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l3{width:25%;margin-left:auto;left:auto;right:auto}.row .col.l4{width:33.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l5{width:41.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l6{width:50%;margin-left:auto;left:auto;right:auto}.row .col.l7{width:58.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l8{width:66.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l9{width:75%;margin-left:auto;left:auto;right:auto}.row .col.l10{width:83.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l11{width:91.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l12{width:100%;margin-left:auto;left:auto;right:auto}.row .col.offset-l1{margin-left:8.3333333333%}.row .col.pull-l1{right:8.3333333333%}.row .col.push-l1{left:8.3333333333%}.row .col.offset-l2{margin-left:16.6666666667%}.row .col.pull-l2{right:16.6666666667%}.row .col.push-l2{left:16.6666666667%}.row .col.offset-l3{margin-left:25%}.row .col.pull-l3{right:25%}.row .col.push-l3{left:25%}.row .col.offset-l4{margin-left:33.3333333333%}.row .col.pull-l4{right:33.3333333333%}.row .col.push-l4{left:33.3333333333%}.row .col.offset-l5{margin-left:41.6666666667%}.row .col.pull-l5{right:41.6666666667%}.row .col.push-l5{left:41.6666666667%}.row .col.offset-l6{margin-left:50%}.row .col.pull-l6{right:50%}.row .col.push-l6{left:50%}.row .col.offset-l7{margin-left:58.3333333333%}.row .col.pull-l7{right:58.3333333333%}.row .col.push-l7{left:58.3333333333%}.row .col.offset-l8{margin-left:66.6666666667%}.row .col.pull-l8{right:66.6666666667%}.row .col.push-l8{left:66.6666666667%}.row .col.offset-l9{margin-left:75%}.row .col.pull-l9{right:75%}.row .col.push-l9{left:75%}.row .col.offset-l10{margin-left:83.3333333333%}.row .col.pull-l10{right:83.3333333333%}.row .col.push-l10{left:83.3333333333%}.row .col.offset-l11{margin-left:91.6666666667%}.row .col.pull-l11{right:91.6666666667%}.row .col.push-l11{left:91.6666666667%}.row .col.offset-l12{margin-left:100%}.row .col.pull-l12{right:100%}.row .col.push-l12{left:100%}}nav{color:#fff;background-color:#ee6e73;width:100%;height:56px;line-height:56px}nav a{color:#fff}nav i,nav [class^="mdi-"],nav [class*="mdi-"],nav i.material-icons{display:block;font-size:2rem;height:56px;line-height:56px}nav .nav-wrapper{position:relative;height:100%}@media only screen and (min-width: 993px){nav a.button-collapse{display:none}}nav .button-collapse{float:left;position:relative;z-index:1;height:56px}nav .button-collapse i{font-size:2.7rem;height:56px;line-height:56px}nav .brand-logo{position:absolute;color:#fff;display:inline-block;font-size:2.1rem;padding:0;white-space:nowrap}nav .brand-logo.center{left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}@media only screen and (max-width: 992px){nav .brand-logo{left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}nav .brand-logo.left,nav .brand-logo.right{padding:0;-webkit-transform:none;transform:none}nav .brand-logo.left{left:0.5rem}nav .brand-logo.right{right:0.5rem;left:auto}}nav .brand-logo.right{right:0.5rem;padding:0}nav .brand-logo i,nav .brand-logo [class^="mdi-"],nav .brand-logo [class*="mdi-"],nav .brand-logo i.material-icons{float:left;margin-right:15px}nav ul{margin:0}nav ul li{transition:background-color .3s;float:left;padding:0}nav ul li.active{background-color:rgba(0,0,0,0.1)}nav ul a{transition:background-color .3s;font-size:1rem;color:#fff;display:block;padding:0 15px;cursor:pointer}nav ul a.btn,nav ul a.btn-large,nav ul a.btn-large,nav ul a.btn-flat,nav ul a.btn-floating{margin-top:-2px;margin-left:15px;margin-right:15px}nav ul a:hover{background-color:rgba(0,0,0,0.1)}nav ul.left{float:left}nav form{height:100%}nav .input-field{margin:0;height:100%}nav .input-field input{height:100%;font-size:1.2rem;border:none;padding-left:2rem}nav .input-field input:focus,nav .input-field input[type=text]:valid,nav .input-field input[type=password]:valid,nav .input-field input[type=email]:valid,nav .input-field input[type=url]:valid,nav .input-field input[type=date]:valid{border:none;box-shadow:none}nav .input-field label{top:0;left:0}nav .input-field label i{color:rgba(255,255,255,0.7);transition:color .3s}nav .input-field label.active i{color:#fff}nav .input-field label.active{-webkit-transform:translateY(0);transform:translateY(0)}.navbar-fixed{position:relative;height:56px;z-index:998}.navbar-fixed nav{position:fixed}@media only screen and (min-width: 601px){nav,nav .nav-wrapper i,nav a.button-collapse,nav a.button-collapse i{height:64px;line-height:64px}.navbar-fixed{height:64px}}@font-face{font-family:"Roboto";src:local(Roboto Thin),url("../fonts/roboto/Roboto-Thin.eot");src:url("../fonts/roboto/Roboto-Thin.eot?#iefix") format("embedded-opentype"),url("../fonts/roboto/Roboto-Thin.woff2") format("woff2"),url("../fonts/roboto/Roboto-Thin.woff") format("woff"),url("../fonts/roboto/Roboto-Thin.ttf") format("truetype");font-weight:200}@font-face{font-family:"Roboto";src:local(Roboto Light),url("../fonts/roboto/Roboto-Light.eot");src:url("../fonts/roboto/Roboto-Light.eot?#iefix") format("embedded-opentype"),url("../fonts/roboto/Roboto-Light.woff2") format("woff2"),url("../fonts/roboto/Roboto-Light.woff") format("woff"),url("../fonts/roboto/Roboto-Light.ttf") format("truetype");font-weight:300}@font-face{font-family:"Roboto";src:local(Roboto Regular),url("../fonts/roboto/Roboto-Regular.eot");src:url("../fonts/roboto/Roboto-Regular.eot?#iefix") format("embedded-opentype"),url("../fonts/roboto/Roboto-Regular.woff2") format("woff2"),url("../fonts/roboto/Roboto-Regular.woff") format("woff"),url("../fonts/roboto/Roboto-Regular.ttf") format("truetype");font-weight:400}@font-face{font-family:"Roboto";src:url("../fonts/roboto/Roboto-Medium.eot");src:url("../fonts/roboto/Roboto-Medium.eot?#iefix") format("embedded-opentype"),url("../fonts/roboto/Roboto-Medium.woff2") format("woff2"),url("../fonts/roboto/Roboto-Medium.woff") format("woff"),url("../fonts/roboto/Roboto-Medium.ttf") format("truetype");font-weight:500}@font-face{font-family:"Roboto";src:url("../fonts/roboto/Roboto-Bold.eot");src:url("../fonts/roboto/Roboto-Bold.eot?#iefix") format("embedded-opentype"),url("../fonts/roboto/Roboto-Bold.woff2") format("woff2"),url("../fonts/roboto/Roboto-Bold.woff") format("woff"),url("../fonts/roboto/Roboto-Bold.ttf") format("truetype");font-weight:700}a{text-decoration:none}html{line-height:1.5;font-family:"Roboto", sans-serif;font-weight:normal;color:rgba(0,0,0,0.87)}@media only screen and (min-width: 0){html{font-size:14px}}@media only screen and (min-width: 992px){html{font-size:14.5px}}@media only screen and (min-width: 1200px){html{font-size:15px}}h1,h2,h3,h4,h5,h6{font-weight:400;line-height:1.1}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{font-weight:inherit}h1{font-size:4.2rem;line-height:110%;margin:2.1rem 0 1.68rem 0}h2{font-size:3.56rem;line-height:110%;margin:1.78rem 0 1.424rem 0}h3{font-size:2.92rem;line-height:110%;margin:1.46rem 0 1.168rem 0}h4{font-size:2.28rem;line-height:110%;margin:1.14rem 0 0.912rem 0}h5{font-size:1.64rem;line-height:110%;margin:0.82rem 0 0.656rem 0}h6{font-size:1rem;line-height:110%;margin:0.5rem 0 0.4rem 0}em{font-style:italic}strong{font-weight:500}small{font-size:75%}.light,footer.page-footer .footer-copyright{font-weight:300}.thin{font-weight:200}.flow-text{font-weight:300}@media only screen and (min-width: 360px){.flow-text{font-size:1.2rem}}@media only screen and (min-width: 390px){.flow-text{font-size:1.224rem}}@media only screen and (min-width: 420px){.flow-text{font-size:1.248rem}}@media only screen and (min-width: 450px){.flow-text{font-size:1.272rem}}@media only screen and (min-width: 480px){.flow-text{font-size:1.296rem}}@media only screen and (min-width: 510px){.flow-text{font-size:1.32rem}}@media only screen and (min-width: 540px){.flow-text{font-size:1.344rem}}@media only screen and (min-width: 570px){.flow-text{font-size:1.368rem}}@media only screen and (min-width: 600px){.flow-text{font-size:1.392rem}}@media only screen and (min-width: 630px){.flow-text{font-size:1.416rem}}@media only screen and (min-width: 660px){.flow-text{font-size:1.44rem}}@media only screen and (min-width: 690px){.flow-text{font-size:1.464rem}}@media only screen and (min-width: 720px){.flow-text{font-size:1.488rem}}@media only screen and (min-width: 750px){.flow-text{font-size:1.512rem}}@media only screen and (min-width: 780px){.flow-text{font-size:1.536rem}}@media only screen and (min-width: 810px){.flow-text{font-size:1.56rem}}@media only screen and (min-width: 840px){.flow-text{font-size:1.584rem}}@media only screen and (min-width: 870px){.flow-text{font-size:1.608rem}}@media only screen and (min-width: 900px){.flow-text{font-size:1.632rem}}@media only screen and (min-width: 930px){.flow-text{font-size:1.656rem}}@media only screen and (min-width: 960px){.flow-text{font-size:1.68rem}}@media only screen and (max-width: 360px){.flow-text{font-size:1.2rem}}.card-panel{transition:box-shadow .25s;padding:20px;margin:0.5rem 0 1rem 0;border-radius:2px;background-color:#fff}.card{position:relative;margin:0.5rem 0 1rem 0;background-color:#fff;transition:box-shadow .25s;border-radius:2px}.card .card-title{font-size:24px;font-weight:300}.card .card-title.activator{cursor:pointer}.card.small,.card.medium,.card.large{position:relative}.card.small .card-image,.card.medium .card-image,.card.large .card-image{max-height:60%;overflow:hidden}.card.small .card-image+.card-content,.card.medium .card-image+.card-content,.card.large .card-image+.card-content{max-height:40%}.card.small .card-content,.card.medium .card-content,.card.large .card-content{max-height:100%;overflow:hidden}.card.small .card-action,.card.medium .card-action,.card.large .card-action{position:absolute;bottom:0;left:0;right:0}.card.small{height:300px}.card.medium{height:400px}.card.large{height:500px}.card.horizontal{display:-webkit-flex;display:-ms-flexbox;display:flex}.card.horizontal.small .card-image,.card.horizontal.medium .card-image,.card.horizontal.large .card-image{height:100%;max-height:none;overflow:visible}.card.horizontal.small .card-image img,.card.horizontal.medium .card-image img,.card.horizontal.large .card-image img{height:100%}.card.horizontal .card-image{max-width:50%}.card.horizontal .card-image img{max-width:100%;width:auto}.card.horizontal .card-stacked{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-flex:1;-ms-flex:1;flex:1;position:relative}.card.horizontal .card-stacked .card-content{-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.card.sticky-action .card-action{z-index:2}.card.sticky-action .card-reveal{z-index:1;padding-bottom:64px}.card .card-image{position:relative}.card .card-image img{display:block;border-radius:2px 2px 0 0;position:relative;left:0;right:0;top:0;bottom:0;width:100%}.card .card-image .card-title{color:#fff;position:absolute;bottom:0;left:0;padding:20px}.card .card-content{padding:20px;border-radius:0 0 2px 2px}.card .card-content p{margin:0;color:inherit}.card .card-content .card-title{line-height:48px}.card .card-action{position:relative;background-color:inherit;border-top:1px solid rgba(160,160,160,0.2);padding:20px}.card .card-action a:not(.btn):not(.btn-large):not(.btn-floating){color:#ffab40;margin-right:20px;transition:color .3s ease;text-transform:uppercase}.card .card-action a:not(.btn):not(.btn-large):not(.btn-floating):hover{color:#ffd8a6}.card .card-reveal{padding:20px;position:absolute;background-color:#fff;width:100%;overflow-y:auto;top:100%;height:100%;z-index:3;display:none}.card .card-reveal .card-title{cursor:pointer;display:block}#toast-container{display:block;position:fixed;z-index:10000}@media only screen and (max-width: 600px){#toast-container{min-width:100%;bottom:0%}}@media only screen and (min-width: 601px) and (max-width: 992px){#toast-container{left:5%;bottom:7%;max-width:90%}}@media only screen and (min-width: 993px){#toast-container{top:10%;right:7%;max-width:86%}}.toast{border-radius:2px;top:0;width:auto;clear:both;margin-top:10px;position:relative;max-width:100%;height:auto;min-height:48px;line-height:1.5em;word-break:break-all;background-color:#323232;padding:10px 25px;font-size:1.1rem;font-weight:300;color:#fff;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}.toast .btn,.toast .btn-large,.toast .btn-flat{margin:0;margin-left:3rem}.toast.rounded{border-radius:24px}@media only screen and (max-width: 600px){.toast{width:100%;border-radius:0}}@media only screen and (min-width: 601px) and (max-width: 992px){.toast{float:left}}@media only screen and (min-width: 993px){.toast{float:right}}.tabs{display:-webkit-flex;display:-ms-flexbox;display:flex;position:relative;overflow-x:auto;overflow-y:hidden;height:48px;background-color:#fff;margin:0 auto;width:100%;white-space:nowrap}.tabs .tab{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;display:block;float:left;text-align:center;line-height:48px;height:48px;padding:0;margin:0;text-transform:uppercase;text-overflow:ellipsis;overflow:hidden;letter-spacing:.8px;width:15%;min-width:80px}.tabs .tab a{color:#ee6e73;display:block;width:100%;height:100%;text-overflow:ellipsis;overflow:hidden;transition:color .28s ease}.tabs .tab a:hover{color:#f9c9cb}.tabs .tab.disabled a{color:#f9c9cb;cursor:default}.tabs .indicator{position:absolute;bottom:0;height:2px;background-color:#f6b2b5;will-change:left, right}.material-tooltip{padding:10px 8px;font-size:1rem;z-index:2000;background-color:transparent;border-radius:2px;color:#fff;min-height:36px;line-height:120%;opacity:0;display:none;position:absolute;text-align:center;max-width:calc(100% - 4px);overflow:hidden;left:0;top:0;pointer-events:none}.backdrop{position:absolute;opacity:0;display:none;height:7px;width:14px;border-radius:0 0 50% 50%;background-color:#323232;z-index:-1;-webkit-transform-origin:50% 0%;transform-origin:50% 0%;-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}.btn,.btn-large,.btn-flat{border:none;border-radius:2px;display:inline-block;height:36px;line-height:36px;outline:0;padding:0 2rem;text-transform:uppercase;vertical-align:middle;-webkit-tap-highlight-color:transparent}.btn.disabled,.disabled.btn-large,.btn-floating.disabled,.btn-large.disabled,.btn:disabled,.btn-large:disabled,.btn-large:disabled,.btn-floating:disabled,.btn[disabled],[disabled].btn-large,.btn-large[disabled],.btn-floating[disabled]{background-color:#DFDFDF !important;box-shadow:none;color:#9F9F9F !important;cursor:default}.btn.disabled *,.disabled.btn-large *,.btn-floating.disabled *,.btn-large.disabled *,.btn:disabled *,.btn-large:disabled *,.btn-large:disabled *,.btn-floating:disabled *,.btn[disabled] *,[disabled].btn-large *,.btn-large[disabled] *,.btn-floating[disabled] *{pointer-events:none}.btn.disabled:hover,.disabled.btn-large:hover,.btn-floating.disabled:hover,.btn-large.disabled:hover,.btn:disabled:hover,.btn-large:disabled:hover,.btn-large:disabled:hover,.btn-floating:disabled:hover,.btn[disabled]:hover,[disabled].btn-large:hover,.btn-large[disabled]:hover,.btn-floating[disabled]:hover{background-color:#DFDFDF !important;color:#9F9F9F !important}.btn i,.btn-large i,.btn-floating i,.btn-large i,.btn-flat i{font-size:1.3rem;line-height:inherit}.btn,.btn-large{text-decoration:none;color:#fff;background-color:#26a69a;text-align:center;letter-spacing:.5px;transition:.2s ease-out;cursor:pointer}.btn:hover,.btn-large:hover{background-color:#2bbbad}.btn-floating{display:inline-block;color:#fff;position:relative;overflow:hidden;z-index:1;width:37px;height:37px;line-height:37px;padding:0;background-color:#26a69a;border-radius:50%;transition:.3s;cursor:pointer;vertical-align:middle}.btn-floating i{width:inherit;display:inline-block;text-align:center;color:#fff;font-size:1.6rem;line-height:37px}.btn-floating:hover{background-color:#26a69a}.btn-floating:before{border-radius:0}.btn-floating.btn-large{width:55.5px;height:55.5px}.btn-floating.btn-large i{line-height:55.5px}button.btn-floating{border:none}.fixed-action-btn{position:fixed;right:23px;bottom:23px;padding-top:15px;margin-bottom:0;z-index:998}.fixed-action-btn.active ul{visibility:visible}.fixed-action-btn.horizontal{padding:0 0 0 15px}.fixed-action-btn.horizontal ul{text-align:right;right:64px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);height:100%;left:auto;width:500px}.fixed-action-btn.horizontal ul li{display:inline-block;margin:15px 15px 0 0}.fixed-action-btn ul{left:0;right:0;text-align:center;position:absolute;bottom:64px;margin:0;visibility:hidden}.fixed-action-btn ul li{margin-bottom:15px}.fixed-action-btn ul a.btn-floating{opacity:0}.btn-flat{box-shadow:none;background-color:transparent;color:#343434;cursor:pointer;transition:background-color .2s}.btn-flat:focus,.btn-flat:active{background-color:transparent}.btn-flat:hover{background-color:rgba(0,0,0,0.1);box-shadow:none}.btn-flat.disabled{color:#b3b3b3;cursor:default}.btn-large{height:54px;line-height:54px}.btn-large i{font-size:1.6rem}.btn-block{display:block}.dropdown-content{background-color:#fff;margin:0;display:none;min-width:100px;max-height:650px;overflow-y:auto;opacity:0;position:absolute;z-index:999;will-change:width, height}.dropdown-content li{clear:both;color:rgba(0,0,0,0.87);cursor:pointer;min-height:50px;line-height:1.5rem;width:100%;text-align:left;text-transform:none}.dropdown-content li:hover,.dropdown-content li.active,.dropdown-content li.selected{background-color:#eee}.dropdown-content li.active.selected{background-color:#e1e1e1}.dropdown-content li.divider{min-height:0;height:1px}.dropdown-content li>a,.dropdown-content li>span{font-size:16px;color:#26a69a;display:block;line-height:22px;padding:14px 16px}.dropdown-content li>span>label{top:1px;left:3px;height:18px}.dropdown-content li>a>i{height:inherit;line-height:inherit}/*!
- * Waves v0.6.0
- * http://fian.my.id/Waves
- *
- * Copyright 2014 Alfiana E. Sibuea and other contributors
- * Released under the MIT license
- * https://github.com/fians/Waves/blob/master/LICENSE
- */.waves-effect{position:relative;cursor:pointer;display:inline-block;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;vertical-align:middle;z-index:1;will-change:opacity, transform;transition:all .3s ease-out}.waves-effect .waves-ripple{position:absolute;border-radius:50%;width:20px;height:20px;margin-top:-10px;margin-left:-10px;opacity:0;background:rgba(0,0,0,0.2);transition:all 0.7s ease-out;transition-property:opacity, -webkit-transform;transition-property:transform, opacity;transition-property:transform, opacity, -webkit-transform;-webkit-transform:scale(0);transform:scale(0);pointer-events:none}.waves-effect.waves-light .waves-ripple{background-color:rgba(255,255,255,0.45)}.waves-effect.waves-red .waves-ripple{background-color:rgba(244,67,54,0.7)}.waves-effect.waves-yellow .waves-ripple{background-color:rgba(255,235,59,0.7)}.waves-effect.waves-orange .waves-ripple{background-color:rgba(255,152,0,0.7)}.waves-effect.waves-purple .waves-ripple{background-color:rgba(156,39,176,0.7)}.waves-effect.waves-green .waves-ripple{background-color:rgba(76,175,80,0.7)}.waves-effect.waves-teal .waves-ripple{background-color:rgba(0,150,136,0.7)}.waves-effect input[type="button"],.waves-effect input[type="reset"],.waves-effect input[type="submit"]{border:0;font-style:normal;font-size:inherit;text-transform:inherit;background:none}.waves-effect img{position:relative;z-index:-1}.waves-notransition{transition:none !important}.waves-circle{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-mask-image:-webkit-radial-gradient(circle, #fff 100%, #000 100%)}.waves-input-wrapper{border-radius:0.2em;vertical-align:bottom}.waves-input-wrapper .waves-button-input{position:relative;top:0;left:0;z-index:1}.waves-circle{text-align:center;width:2.5em;height:2.5em;line-height:2.5em;border-radius:50%;-webkit-mask-image:none}.waves-block{display:block}.waves-effect .waves-ripple{z-index:-1}.modal{display:none;position:fixed;left:0;right:0;background-color:#fafafa;padding:0;max-height:70%;width:55%;margin:auto;overflow-y:auto;border-radius:2px;will-change:top, opacity}@media only screen and (max-width: 992px){.modal{width:80%}}.modal h1,.modal h2,.modal h3,.modal h4{margin-top:0}.modal .modal-content{padding:24px}.modal .modal-close{cursor:pointer}.modal .modal-footer{border-radius:0 0 2px 2px;background-color:#fafafa;padding:4px 6px;height:56px;width:100%}.modal .modal-footer .btn,.modal .modal-footer .btn-large,.modal .modal-footer .btn-flat{float:right;margin:6px 0}.lean-overlay{position:fixed;z-index:999;top:-100px;left:0;bottom:0;right:0;height:125%;width:100%;background:#000;display:none;will-change:opacity}.modal.modal-fixed-footer{padding:0;height:70%}.modal.modal-fixed-footer .modal-content{position:absolute;height:calc(100% - 56px);max-height:100%;width:100%;overflow-y:auto}.modal.modal-fixed-footer .modal-footer{border-top:1px solid rgba(0,0,0,0.1);position:absolute;bottom:0}.modal.bottom-sheet{top:auto;bottom:-100%;margin:0;width:100%;max-height:45%;border-radius:0;will-change:bottom, opacity}.collapsible{border-top:1px solid #ddd;border-right:1px solid #ddd;border-left:1px solid #ddd;margin:0.5rem 0 1rem 0}.collapsible-header{display:block;cursor:pointer;min-height:3rem;line-height:3rem;padding:0 1rem;background-color:#fff;border-bottom:1px solid #ddd}.collapsible-header i{width:2rem;font-size:1.6rem;line-height:3rem;display:block;float:left;text-align:center;margin-right:1rem}.collapsible-body{display:none;border-bottom:1px solid #ddd;box-sizing:border-box}.collapsible-body p{margin:0;padding:2rem}.side-nav .collapsible,.side-nav.fixed .collapsible{border:none;box-shadow:none}.side-nav .collapsible li,.side-nav.fixed .collapsible li{padding:0}.side-nav .collapsible-header,.side-nav.fixed .collapsible-header{background-color:transparent;border:none;line-height:inherit;height:inherit;padding:0 16px}.side-nav .collapsible-header:hover,.side-nav.fixed .collapsible-header:hover{background-color:rgba(0,0,0,0.05)}.side-nav .collapsible-header i,.side-nav.fixed .collapsible-header i{line-height:inherit}.side-nav .collapsible-body,.side-nav.fixed .collapsible-body{border:0;background-color:#fff}.side-nav .collapsible-body li a,.side-nav.fixed .collapsible-body li a{padding:0 23.5px 0 31px}.collapsible.popout{border:none;box-shadow:none}.collapsible.popout>li{box-shadow:0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12);margin:0 24px;transition:margin 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94)}.collapsible.popout>li.active{box-shadow:0 5px 11px 0 rgba(0,0,0,0.18),0 4px 15px 0 rgba(0,0,0,0.15);margin:16px 0}.chip{display:inline-block;height:32px;font-size:13px;font-weight:500;color:rgba(0,0,0,0.6);line-height:32px;padding:0 12px;border-radius:16px;background-color:#e4e4e4;margin-bottom:5px;margin-right:5px}.chip img{float:left;margin:0 8px 0 -12px;height:32px;width:32px;border-radius:50%}.chip .close{cursor:pointer;float:right;font-size:16px;line-height:32px;padding-left:8px}.chips{border:none;border-bottom:1px solid #9e9e9e;box-shadow:none;margin-bottom:30px;min-height:45px;outline:none;padding-bottom:5px;transition:all .3s}.chips.focus{border-bottom:1px solid #26a69a;box-shadow:0 1px 0 0 #26a69a}.chips:hover{cursor:text}.chips .chip.selected{background-color:#26a69a;color:#fff}.chips .input{background:none;border:0;color:rgba(0,0,0,0.6);display:inline-block;font-size:13px;font-weight:500;height:32px;margin-right:20px;line-height:32px;outline:0;padding:0 !important;width:120px !important}.chips .input:focus{border:0 !important;box-shadow:none !important}.materialboxed{display:block;cursor:-webkit-zoom-in;cursor:zoom-in;position:relative;transition:opacity .4s}.materialboxed:hover{will-change:left, top, width, height}.materialboxed:hover:not(.active){opacity:.8}.materialboxed.active{cursor:-webkit-zoom-out;cursor:zoom-out}#materialbox-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background-color:#292929;z-index:1000;will-change:opacity}.materialbox-caption{position:fixed;display:none;color:#fff;line-height:50px;bottom:0;width:100%;text-align:center;padding:0% 15%;height:50px;z-index:1000;-webkit-font-smoothing:antialiased}select:focus{outline:1px solid #c9f3ef}button:focus{outline:none;background-color:#2ab7a9}label{font-size:0.8rem;color:#9e9e9e}::-webkit-input-placeholder{color:#d1d1d1}:-moz-placeholder{color:#d1d1d1}::-moz-placeholder{color:#d1d1d1}:-ms-input-placeholder{color:#d1d1d1}input:not([type]),input[type=text],input[type=password],input[type=email],input[type=url],input[type=time],input[type=date],input[type=datetime],input[type=datetime-local],input[type=tel],input[type=number],input[type=search],textarea.materialize-textarea{background-color:transparent;border:none;border-bottom:1px solid #9e9e9e;border-radius:0;outline:none;height:3rem;width:100%;font-size:1rem;margin:0 0 20px 0;padding:0;box-shadow:none;box-sizing:content-box;transition:all 0.3s}input:not([type]):disabled,input:not([type])[readonly="readonly"],input[type=text]:disabled,input[type=text][readonly="readonly"],input[type=password]:disabled,input[type=password][readonly="readonly"],input[type=email]:disabled,input[type=email][readonly="readonly"],input[type=url]:disabled,input[type=url][readonly="readonly"],input[type=time]:disabled,input[type=time][readonly="readonly"],input[type=date]:disabled,input[type=date][readonly="readonly"],input[type=datetime]:disabled,input[type=datetime][readonly="readonly"],input[type=datetime-local]:disabled,input[type=datetime-local][readonly="readonly"],input[type=tel]:disabled,input[type=tel][readonly="readonly"],input[type=number]:disabled,input[type=number][readonly="readonly"],input[type=search]:disabled,input[type=search][readonly="readonly"],textarea.materialize-textarea:disabled,textarea.materialize-textarea[readonly="readonly"]{color:rgba(0,0,0,0.26);border-bottom:1px dotted rgba(0,0,0,0.26)}input:not([type]):disabled+label,input:not([type])[readonly="readonly"]+label,input[type=text]:disabled+label,input[type=text][readonly="readonly"]+label,input[type=password]:disabled+label,input[type=password][readonly="readonly"]+label,input[type=email]:disabled+label,input[type=email][readonly="readonly"]+label,input[type=url]:disabled+label,input[type=url][readonly="readonly"]+label,input[type=time]:disabled+label,input[type=time][readonly="readonly"]+label,input[type=date]:disabled+label,input[type=date][readonly="readonly"]+label,input[type=datetime]:disabled+label,input[type=datetime][readonly="readonly"]+label,input[type=datetime-local]:disabled+label,input[type=datetime-local][readonly="readonly"]+label,input[type=tel]:disabled+label,input[type=tel][readonly="readonly"]+label,input[type=number]:disabled+label,input[type=number][readonly="readonly"]+label,input[type=search]:disabled+label,input[type=search][readonly="readonly"]+label,textarea.materialize-textarea:disabled+label,textarea.materialize-textarea[readonly="readonly"]+label{color:rgba(0,0,0,0.26)}input:not([type]):focus:not([readonly]),input[type=text]:focus:not([readonly]),input[type=password]:focus:not([readonly]),input[type=email]:focus:not([readonly]),input[type=url]:focus:not([readonly]),input[type=time]:focus:not([readonly]),input[type=date]:focus:not([readonly]),input[type=datetime]:focus:not([readonly]),input[type=datetime-local]:focus:not([readonly]),input[type=tel]:focus:not([readonly]),input[type=number]:focus:not([readonly]),input[type=search]:focus:not([readonly]),textarea.materialize-textarea:focus:not([readonly]){border-bottom:1px solid #26a69a;box-shadow:0 1px 0 0 #26a69a}input:not([type]):focus:not([readonly])+label,input[type=text]:focus:not([readonly])+label,input[type=password]:focus:not([readonly])+label,input[type=email]:focus:not([readonly])+label,input[type=url]:focus:not([readonly])+label,input[type=time]:focus:not([readonly])+label,input[type=date]:focus:not([readonly])+label,input[type=datetime]:focus:not([readonly])+label,input[type=datetime-local]:focus:not([readonly])+label,input[type=tel]:focus:not([readonly])+label,input[type=number]:focus:not([readonly])+label,input[type=search]:focus:not([readonly])+label,textarea.materialize-textarea:focus:not([readonly])+label{color:#26a69a}input:not([type]).valid,input:not([type]):focus.valid,input[type=text].valid,input[type=text]:focus.valid,input[type=password].valid,input[type=password]:focus.valid,input[type=email].valid,input[type=email]:focus.valid,input[type=url].valid,input[type=url]:focus.valid,input[type=time].valid,input[type=time]:focus.valid,input[type=date].valid,input[type=date]:focus.valid,input[type=datetime].valid,input[type=datetime]:focus.valid,input[type=datetime-local].valid,input[type=datetime-local]:focus.valid,input[type=tel].valid,input[type=tel]:focus.valid,input[type=number].valid,input[type=number]:focus.valid,input[type=search].valid,input[type=search]:focus.valid,textarea.materialize-textarea.valid,textarea.materialize-textarea:focus.valid{border-bottom:1px solid #4CAF50;box-shadow:0 1px 0 0 #4CAF50}input:not([type]).valid+label:after,input:not([type]):focus.valid+label:after,input[type=text].valid+label:after,input[type=text]:focus.valid+label:after,input[type=password].valid+label:after,input[type=password]:focus.valid+label:after,input[type=email].valid+label:after,input[type=email]:focus.valid+label:after,input[type=url].valid+label:after,input[type=url]:focus.valid+label:after,input[type=time].valid+label:after,input[type=time]:focus.valid+label:after,input[type=date].valid+label:after,input[type=date]:focus.valid+label:after,input[type=datetime].valid+label:after,input[type=datetime]:focus.valid+label:after,input[type=datetime-local].valid+label:after,input[type=datetime-local]:focus.valid+label:after,input[type=tel].valid+label:after,input[type=tel]:focus.valid+label:after,input[type=number].valid+label:after,input[type=number]:focus.valid+label:after,input[type=search].valid+label:after,input[type=search]:focus.valid+label:after,textarea.materialize-textarea.valid+label:after,textarea.materialize-textarea:focus.valid+label:after{content:attr(data-success);color:#4CAF50;opacity:1}input:not([type]).invalid,input:not([type]):focus.invalid,input[type=text].invalid,input[type=text]:focus.invalid,input[type=password].invalid,input[type=password]:focus.invalid,input[type=email].invalid,input[type=email]:focus.invalid,input[type=url].invalid,input[type=url]:focus.invalid,input[type=time].invalid,input[type=time]:focus.invalid,input[type=date].invalid,input[type=date]:focus.invalid,input[type=datetime].invalid,input[type=datetime]:focus.invalid,input[type=datetime-local].invalid,input[type=datetime-local]:focus.invalid,input[type=tel].invalid,input[type=tel]:focus.invalid,input[type=number].invalid,input[type=number]:focus.invalid,input[type=search].invalid,input[type=search]:focus.invalid,textarea.materialize-textarea.invalid,textarea.materialize-textarea:focus.invalid{border-bottom:1px solid #F44336;box-shadow:0 1px 0 0 #F44336}input:not([type]).invalid+label:after,input:not([type]):focus.invalid+label:after,input[type=text].invalid+label:after,input[type=text]:focus.invalid+label:after,input[type=password].invalid+label:after,input[type=password]:focus.invalid+label:after,input[type=email].invalid+label:after,input[type=email]:focus.invalid+label:after,input[type=url].invalid+label:after,input[type=url]:focus.invalid+label:after,input[type=time].invalid+label:after,input[type=time]:focus.invalid+label:after,input[type=date].invalid+label:after,input[type=date]:focus.invalid+label:after,input[type=datetime].invalid+label:after,input[type=datetime]:focus.invalid+label:after,input[type=datetime-local].invalid+label:after,input[type=datetime-local]:focus.invalid+label:after,input[type=tel].invalid+label:after,input[type=tel]:focus.invalid+label:after,input[type=number].invalid+label:after,input[type=number]:focus.invalid+label:after,input[type=search].invalid+label:after,input[type=search]:focus.invalid+label:after,textarea.materialize-textarea.invalid+label:after,textarea.materialize-textarea:focus.invalid+label:after{content:attr(data-error);color:#F44336;opacity:1}input:not([type]).validate+label,input[type=text].validate+label,input[type=password].validate+label,input[type=email].validate+label,input[type=url].validate+label,input[type=time].validate+label,input[type=date].validate+label,input[type=datetime].validate+label,input[type=datetime-local].validate+label,input[type=tel].validate+label,input[type=number].validate+label,input[type=search].validate+label,textarea.materialize-textarea.validate+label{width:100%;pointer-events:none}input:not([type])+label:after,input[type=text]+label:after,input[type=password]+label:after,input[type=email]+label:after,input[type=url]+label:after,input[type=time]+label:after,input[type=date]+label:after,input[type=datetime]+label:after,input[type=datetime-local]+label:after,input[type=tel]+label:after,input[type=number]+label:after,input[type=search]+label:after,textarea.materialize-textarea+label:after{display:block;content:"";position:absolute;top:60px;opacity:0;transition:.2s opacity ease-out, .2s color ease-out}.input-field{position:relative;margin-top:1rem}.input-field.col label{left:0.75rem}.input-field.col .prefix ~ label,.input-field.col .prefix ~ .validate ~ label{width:calc(100% - 3rem - 1.5rem)}.input-field label{color:#9e9e9e;position:absolute;top:0.8rem;font-size:1rem;cursor:text;transition:.2s ease-out}.input-field label.active{font-size:0.8rem;-webkit-transform:translateY(-140%);transform:translateY(-140%)}.input-field .prefix{position:absolute;width:3rem;font-size:2rem;transition:color .2s}.input-field .prefix.active{color:#26a69a}.input-field .prefix ~ input,.input-field .prefix ~ textarea,.input-field .prefix ~ label,.input-field .prefix ~ .validate ~ label,.input-field .prefix ~ .autocomplete-content{margin-left:3rem;width:92%;width:calc(100% - 3rem)}.input-field .prefix ~ label{margin-left:3rem}@media only screen and (max-width: 992px){.input-field .prefix ~ input{width:86%;width:calc(100% - 3rem)}}@media only screen and (max-width: 600px){.input-field .prefix ~ input{width:80%;width:calc(100% - 3rem)}}.input-field input[type=search]{display:block;line-height:inherit;padding-left:4rem;width:calc(100% - 4rem)}.input-field input[type=search]:focus{background-color:#fff;border:0;box-shadow:none;color:#444}.input-field input[type=search]:focus+label i,.input-field input[type=search]:focus ~ .mdi-navigation-close,.input-field input[type=search]:focus ~ .material-icons{color:#444}.input-field input[type=search]+label{left:1rem}.input-field input[type=search] ~ .mdi-navigation-close,.input-field input[type=search] ~ .material-icons{position:absolute;top:0;right:1rem;color:transparent;cursor:pointer;font-size:2rem;transition:.3s color}textarea{width:100%;height:3rem;background-color:transparent}textarea.materialize-textarea{overflow-y:hidden;padding:.8rem 0 1.6rem 0;resize:none;min-height:3rem}.hiddendiv{display:none;white-space:pre-wrap;word-wrap:break-word;overflow-wrap:break-word;padding-top:1.2rem}.autocomplete-content{margin-top:-15px;display:block;opacity:1;position:static}.autocomplete-content li .highlight{color:#444}.autocomplete-content li img{height:40px;width:40px;margin:5px 15px}[type="radio"]:not(:checked),[type="radio"]:checked{position:absolute;left:-9999px;opacity:0}[type="radio"]:not(:checked)+label,[type="radio"]:checked+label{position:relative;padding-left:35px;cursor:pointer;display:inline-block;height:25px;line-height:25px;font-size:1rem;transition:.28s ease;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}[type="radio"]+label:before,[type="radio"]+label:after{content:'';position:absolute;left:0;top:0;margin:4px;width:16px;height:16px;z-index:0;transition:.28s ease}[type="radio"]:not(:checked)+label:before,[type="radio"]:not(:checked)+label:after,[type="radio"]:checked+label:before,[type="radio"]:checked+label:after,[type="radio"].with-gap:checked+label:before,[type="radio"].with-gap:checked+label:after{border-radius:50%}[type="radio"]:not(:checked)+label:before,[type="radio"]:not(:checked)+label:after{border:2px solid #5a5a5a}[type="radio"]:not(:checked)+label:after{z-index:-1;-webkit-transform:scale(0);transform:scale(0)}[type="radio"]:checked+label:before{border:2px solid transparent}[type="radio"]:checked+label:after,[type="radio"].with-gap:checked+label:before,[type="radio"].with-gap:checked+label:after{border:2px solid #26a69a}[type="radio"]:checked+label:after,[type="radio"].with-gap:checked+label:after{background-color:#26a69a;z-index:0}[type="radio"]:checked+label:after{-webkit-transform:scale(1.02);transform:scale(1.02)}[type="radio"].with-gap:checked+label:after{-webkit-transform:scale(0.5);transform:scale(0.5)}[type="radio"].tabbed:focus+label:before{box-shadow:0 0 0 10px rgba(0,0,0,0.1)}[type="radio"].with-gap:disabled:checked+label:before{border:2px solid rgba(0,0,0,0.26)}[type="radio"].with-gap:disabled:checked+label:after{border:none;background-color:rgba(0,0,0,0.26)}[type="radio"]:disabled:not(:checked)+label:before,[type="radio"]:disabled:checked+label:before{background-color:transparent;border-color:rgba(0,0,0,0.26)}[type="radio"]:disabled+label{color:rgba(0,0,0,0.26)}[type="radio"]:disabled:not(:checked)+label:before{border-color:rgba(0,0,0,0.26)}[type="radio"]:disabled:checked+label:after{background-color:rgba(0,0,0,0.26);border-color:#BDBDBD}form p{margin-bottom:10px;text-align:left}form p:last-child{margin-bottom:0}[type="checkbox"]:not(:checked),[type="checkbox"]:checked{position:absolute;left:-9999px;opacity:0}[type="checkbox"]+label{position:relative;padding-left:35px;cursor:pointer;display:inline-block;height:25px;line-height:25px;font-size:1rem;-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-ms-user-select:none}[type="checkbox"]+label:before,[type="checkbox"]:not(.filled-in)+label:after{content:'';position:absolute;top:0;left:0;width:18px;height:18px;z-index:0;border:2px solid #5a5a5a;border-radius:1px;margin-top:2px;transition:.2s}[type="checkbox"]:not(.filled-in)+label:after{border:0;-webkit-transform:scale(0);transform:scale(0)}[type="checkbox"]:not(:checked):disabled+label:before{border:none;background-color:rgba(0,0,0,0.26)}[type="checkbox"].tabbed:focus+label:after{-webkit-transform:scale(1);transform:scale(1);border:0;border-radius:50%;box-shadow:0 0 0 10px rgba(0,0,0,0.1);background-color:rgba(0,0,0,0.1)}[type="checkbox"]:checked+label:before{top:-4px;left:-5px;width:12px;height:22px;border-top:2px solid transparent;border-left:2px solid transparent;border-right:2px solid #26a69a;border-bottom:2px solid #26a69a;-webkit-transform:rotate(40deg);transform:rotate(40deg);-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform-origin:100% 100%;transform-origin:100% 100%}[type="checkbox"]:checked:disabled+label:before{border-right:2px solid rgba(0,0,0,0.26);border-bottom:2px solid rgba(0,0,0,0.26)}[type="checkbox"]:indeterminate+label:before{top:-11px;left:-12px;width:10px;height:22px;border-top:none;border-left:none;border-right:2px solid #26a69a;border-bottom:none;-webkit-transform:rotate(90deg);transform:rotate(90deg);-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform-origin:100% 100%;transform-origin:100% 100%}[type="checkbox"]:indeterminate:disabled+label:before{border-right:2px solid rgba(0,0,0,0.26);background-color:transparent}[type="checkbox"].filled-in+label:after{border-radius:2px}[type="checkbox"].filled-in+label:before,[type="checkbox"].filled-in+label:after{content:'';left:0;position:absolute;transition:border .25s, background-color .25s, width .20s .1s, height .20s .1s, top .20s .1s, left .20s .1s;z-index:1}[type="checkbox"].filled-in:not(:checked)+label:before{width:0;height:0;border:3px solid transparent;left:6px;top:10px;-webkit-transform:rotateZ(37deg);transform:rotateZ(37deg);-webkit-transform-origin:20% 40%;transform-origin:100% 100%}[type="checkbox"].filled-in:not(:checked)+label:after{height:20px;width:20px;background-color:transparent;border:2px solid #5a5a5a;top:0px;z-index:0}[type="checkbox"].filled-in:checked+label:before{top:0;left:1px;width:8px;height:13px;border-top:2px solid transparent;border-left:2px solid transparent;border-right:2px solid #fff;border-bottom:2px solid #fff;-webkit-transform:rotateZ(37deg);transform:rotateZ(37deg);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}[type="checkbox"].filled-in:checked+label:after{top:0;width:20px;height:20px;border:2px solid #26a69a;background-color:#26a69a;z-index:0}[type="checkbox"].filled-in.tabbed:focus+label:after{border-radius:2px;border-color:#5a5a5a;background-color:rgba(0,0,0,0.1)}[type="checkbox"].filled-in.tabbed:checked:focus+label:after{border-radius:2px;background-color:#26a69a;border-color:#26a69a}[type="checkbox"].filled-in:disabled:not(:checked)+label:before{background-color:transparent;border:2px solid transparent}[type="checkbox"].filled-in:disabled:not(:checked)+label:after{border-color:transparent;background-color:#BDBDBD}[type="checkbox"].filled-in:disabled:checked+label:before{background-color:transparent}[type="checkbox"].filled-in:disabled:checked+label:after{background-color:#BDBDBD;border-color:#BDBDBD}.switch,.switch *{-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-ms-user-select:none}.switch label{cursor:pointer}.switch label input[type=checkbox]{opacity:0;width:0;height:0}.switch label input[type=checkbox]:checked+.lever{background-color:#84c7c1}.switch label input[type=checkbox]:checked+.lever:after{background-color:#26a69a;left:24px}.switch label .lever{content:"";display:inline-block;position:relative;width:40px;height:15px;background-color:#818181;border-radius:15px;margin-right:10px;transition:background 0.3s ease;vertical-align:middle;margin:0 16px}.switch label .lever:after{content:"";position:absolute;display:inline-block;width:21px;height:21px;background-color:#F1F1F1;border-radius:21px;box-shadow:0 1px 3px 1px rgba(0,0,0,0.4);left:-5px;top:-3px;transition:left 0.3s ease, background .3s ease, box-shadow 0.1s ease}input[type=checkbox]:checked:not(:disabled) ~ .lever:active::after,input[type=checkbox]:checked:not(:disabled).tabbed:focus ~ .lever::after{box-shadow:0 1px 3px 1px rgba(0,0,0,0.4),0 0 0 15px rgba(38,166,154,0.1)}input[type=checkbox]:not(:disabled) ~ .lever:active:after,input[type=checkbox]:not(:disabled).tabbed:focus ~ .lever::after{box-shadow:0 1px 3px 1px rgba(0,0,0,0.4),0 0 0 15px rgba(0,0,0,0.08)}.switch input[type=checkbox][disabled]+.lever{cursor:default}.switch label input[type=checkbox][disabled]+.lever:after,.switch label input[type=checkbox][disabled]:checked+.lever:after{background-color:#BDBDBD}select{display:none}select.browser-default{display:block}select{background-color:rgba(255,255,255,0.9);width:100%;padding:5px;border:1px solid #f2f2f2;border-radius:2px;height:3rem}.select-label{position:absolute}.select-wrapper{position:relative}.select-wrapper input.select-dropdown{position:relative;cursor:pointer;background-color:transparent;border:none;border-bottom:1px solid #9e9e9e;outline:none;height:3rem;line-height:3rem;width:100%;font-size:1rem;margin:0 0 20px 0;padding:0;display:block}.select-wrapper span.caret{color:initial;position:absolute;right:0;top:16px;font-size:10px}.select-wrapper span.caret.disabled{color:rgba(0,0,0,0.26)}.select-wrapper+label{position:absolute;top:-14px;font-size:0.8rem}select:disabled{color:rgba(0,0,0,0.3)}.select-wrapper input.select-dropdown:disabled{color:rgba(0,0,0,0.3);cursor:default;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;border-bottom:1px solid rgba(0,0,0,0.3)}.select-wrapper i{color:rgba(0,0,0,0.3)}.select-dropdown li.disabled,.select-dropdown li.disabled>span,.select-dropdown li.optgroup{color:rgba(0,0,0,0.3);background-color:transparent}.prefix ~ .select-wrapper{margin-left:3rem;width:92%;width:calc(100% - 3rem)}.prefix ~ label{margin-left:3rem}.select-dropdown li img{height:40px;width:40px;margin:5px 15px;float:right}.select-dropdown li.optgroup{border-top:1px solid #eee}.select-dropdown li.optgroup.selected>span{color:rgba(0,0,0,0.7)}.select-dropdown li.optgroup>span{color:rgba(0,0,0,0.4)}.select-dropdown li.optgroup ~ li.optgroup-option{padding-left:1rem}.file-field{position:relative}.file-field .file-path-wrapper{overflow:hidden;padding-left:10px}.file-field input.file-path{width:100%}.file-field .btn,.file-field .btn-large{float:left;height:3rem;line-height:3rem}.file-field span{cursor:pointer}.file-field input[type=file]{position:absolute;top:0;right:0;left:0;bottom:0;width:100%;margin:0;padding:0;font-size:20px;cursor:pointer;opacity:0;filter:alpha(opacity=0)}.range-field{position:relative}input[type=range],input[type=range]+.thumb{cursor:pointer}input[type=range]{position:relative;background-color:transparent;border:none;outline:none;width:100%;margin:15px 0;padding:0}input[type=range]:focus{outline:none}input[type=range]+.thumb{position:absolute;border:none;height:0;width:0;border-radius:50%;background-color:#26a69a;top:10px;margin-left:-6px;-webkit-transform-origin:50% 50%;transform-origin:50% 50%;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}input[type=range]+.thumb .value{display:block;width:30px;text-align:center;color:#26a69a;font-size:0;-webkit-transform:rotate(45deg);transform:rotate(45deg)}input[type=range]+.thumb.active{border-radius:50% 50% 50% 0}input[type=range]+.thumb.active .value{color:#fff;margin-left:-1px;margin-top:8px;font-size:10px}input[type=range]{-webkit-appearance:none}input[type=range]::-webkit-slider-runnable-track{height:3px;background:#c2c0c2;border:none}input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;border:none;height:14px;width:14px;border-radius:50%;background-color:#26a69a;-webkit-transform-origin:50% 50%;transform-origin:50% 50%;margin:-5px 0 0 0;transition:.3s}input[type=range]:focus::-webkit-slider-runnable-track{background:#ccc}input[type=range]{border:1px solid white}input[type=range]::-moz-range-track{height:3px;background:#ddd;border:none}input[type=range]::-moz-range-thumb{border:none;height:14px;width:14px;border-radius:50%;background:#26a69a;margin-top:-5px}input[type=range]:-moz-focusring{outline:1px solid #fff;outline-offset:-1px}input[type=range]:focus::-moz-range-track{background:#ccc}input[type=range]::-ms-track{height:3px;background:transparent;border-color:transparent;border-width:6px 0;color:transparent}input[type=range]::-ms-fill-lower{background:#777}input[type=range]::-ms-fill-upper{background:#ddd}input[type=range]::-ms-thumb{border:none;height:14px;width:14px;border-radius:50%;background:#26a69a}input[type=range]:focus::-ms-fill-lower{background:#888}input[type=range]:focus::-ms-fill-upper{background:#ccc}.table-of-contents.fixed{position:fixed}.table-of-contents li{padding:2px 0}.table-of-contents a{display:inline-block;font-weight:300;color:#757575;padding-left:20px;height:1.5rem;line-height:1.5rem;letter-spacing:.4;display:inline-block}.table-of-contents a:hover{color:#a8a8a8;padding-left:19px;border-left:1px solid #ea4a4f}.table-of-contents a.active{font-weight:500;padding-left:18px;border-left:2px solid #ea4a4f}.side-nav{position:fixed;width:300px;left:0;top:0;margin:0;-webkit-transform:translateX(-100%);transform:translateX(-100%);height:100%;height:calc(100% + 60px);height:-moz-calc(100%);padding-bottom:60px;background-color:#fff;z-index:999;-webkit-backface-visibility:hidden;backface-visibility:hidden;overflow-y:auto;will-change:transform;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translateX(-105%);transform:translateX(-105%)}.side-nav.right-aligned{right:0;-webkit-transform:translateX(105%);transform:translateX(105%);left:auto;-webkit-transform:translateX(100%);transform:translateX(100%)}.side-nav .collapsible{margin:0}.side-nav li{float:none;line-height:48px}.side-nav li.active{background-color:rgba(0,0,0,0.05)}.side-nav a{color:rgba(0,0,0,0.87);display:block;font-size:14px;font-weight:500;height:48px;line-height:48px;padding:0 32px}.side-nav a:hover{background-color:rgba(0,0,0,0.05)}.side-nav a.btn,.side-nav a.btn-large,.side-nav a.btn-large,.side-nav a.btn-flat,.side-nav a.btn-floating{margin:10px 15px}.side-nav a.btn,.side-nav a.btn-large,.side-nav a.btn-large,.side-nav a.btn-floating{color:#fff}.side-nav a.btn-flat{color:#343434}.side-nav a.btn:hover,.side-nav a.btn-large:hover,.side-nav a.btn-large:hover{background-color:#2bbbad}.side-nav a.btn-floating:hover{background-color:#26a69a}.side-nav li>a>i,.side-nav li>a>[class^="mdi-"],.side-nav li>a>[class*="mdi-"],.side-nav li>a>i.material-icons{float:left;line-height:48px;margin:0 32px 0 0;width:24px;color:rgba(0,0,0,0.54)}.side-nav .divider{margin:8px 0 0 0}.side-nav .subheader{cursor:initial;pointer-events:none;color:rgba(0,0,0,0.54);font-size:14px;font-weight:500;line-height:48px}.side-nav .subheader:hover{background-color:transparent}.side-nav .userView{overflow:hidden;position:relative;padding:32px 32px 0;margin-bottom:8px}.side-nav .userView a{height:auto;padding:0}.side-nav .userView a:hover{background-color:transparent}.side-nav .userView .background{position:absolute;top:0;right:0;bottom:0;left:0;z-index:-1}.side-nav .userView .circle,.side-nav .userView .name,.side-nav .userView .email{display:block}.side-nav .userView .circle{height:64px;width:64px}.side-nav .userView .name,.side-nav .userView .email{font-weight:14px;line-height:24px}.side-nav .userView .name{margin-top:16px;font-weight:500}.side-nav .userView .email{padding-bottom:16px;font-weight:400}.drag-target{height:100%;width:10px;position:fixed;top:0;z-index:998}.side-nav.fixed a{display:block;padding:0 16px;color:rgba(0,0,0,0.87)}.side-nav.fixed{left:0;-webkit-transform:translateX(0);transform:translateX(0);position:fixed}.side-nav.fixed.right-aligned{right:0;left:auto}@media only screen and (max-width: 992px){.side-nav.fixed{-webkit-transform:translateX(-105%);transform:translateX(-105%)}.side-nav.fixed.right-aligned{-webkit-transform:translateX(105%);transform:translateX(105%)}.side-nav a{padding:0 16px}.side-nav .userView{padding:16px 16px 0}}.side-nav .collapsible-body li.active,.side-nav.fixed .collapsible-body li.active{background-color:#ee6e73}.side-nav .collapsible-body li.active a,.side-nav.fixed .collapsible-body li.active a{color:#fff}#sidenav-overlay{position:fixed;top:0;left:0;right:0;height:120vh;background-color:rgba(0,0,0,0.5);z-index:997;will-change:opacity}.preloader-wrapper{display:inline-block;position:relative;width:48px;height:48px}.preloader-wrapper.small{width:36px;height:36px}.preloader-wrapper.big{width:64px;height:64px}.preloader-wrapper.active{-webkit-animation:container-rotate 1568ms linear infinite;animation:container-rotate 1568ms linear infinite}@-webkit-keyframes container-rotate{to{-webkit-transform:rotate(360deg)}}@keyframes container-rotate{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.spinner-layer{position:absolute;width:100%;height:100%;opacity:0;border-color:#26a69a}.spinner-blue,.spinner-blue-only{border-color:#4285f4}.spinner-red,.spinner-red-only{border-color:#db4437}.spinner-yellow,.spinner-yellow-only{border-color:#f4b400}.spinner-green,.spinner-green-only{border-color:#0f9d58}.active .spinner-layer.spinner-blue{-webkit-animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,blue-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,blue-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.active .spinner-layer.spinner-red{-webkit-animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,red-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,red-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.active .spinner-layer.spinner-yellow{-webkit-animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,yellow-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,yellow-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.active .spinner-layer.spinner-green{-webkit-animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,green-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,green-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.active .spinner-layer,.active .spinner-layer.spinner-blue-only,.active .spinner-layer.spinner-red-only,.active .spinner-layer.spinner-yellow-only,.active .spinner-layer.spinner-green-only{opacity:1;-webkit-animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}@-webkit-keyframes fill-unfill-rotate{12.5%{-webkit-transform:rotate(135deg)}25%{-webkit-transform:rotate(270deg)}37.5%{-webkit-transform:rotate(405deg)}50%{-webkit-transform:rotate(540deg)}62.5%{-webkit-transform:rotate(675deg)}75%{-webkit-transform:rotate(810deg)}87.5%{-webkit-transform:rotate(945deg)}to{-webkit-transform:rotate(1080deg)}}@keyframes fill-unfill-rotate{12.5%{-webkit-transform:rotate(135deg);transform:rotate(135deg)}25%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}37.5%{-webkit-transform:rotate(405deg);transform:rotate(405deg)}50%{-webkit-transform:rotate(540deg);transform:rotate(540deg)}62.5%{-webkit-transform:rotate(675deg);transform:rotate(675deg)}75%{-webkit-transform:rotate(810deg);transform:rotate(810deg)}87.5%{-webkit-transform:rotate(945deg);transform:rotate(945deg)}to{-webkit-transform:rotate(1080deg);transform:rotate(1080deg)}}@-webkit-keyframes blue-fade-in-out{from{opacity:1}25%{opacity:1}26%{opacity:0}89%{opacity:0}90%{opacity:1}100%{opacity:1}}@keyframes blue-fade-in-out{from{opacity:1}25%{opacity:1}26%{opacity:0}89%{opacity:0}90%{opacity:1}100%{opacity:1}}@-webkit-keyframes red-fade-in-out{from{opacity:0}15%{opacity:0}25%{opacity:1}50%{opacity:1}51%{opacity:0}}@keyframes red-fade-in-out{from{opacity:0}15%{opacity:0}25%{opacity:1}50%{opacity:1}51%{opacity:0}}@-webkit-keyframes yellow-fade-in-out{from{opacity:0}40%{opacity:0}50%{opacity:1}75%{opacity:1}76%{opacity:0}}@keyframes yellow-fade-in-out{from{opacity:0}40%{opacity:0}50%{opacity:1}75%{opacity:1}76%{opacity:0}}@-webkit-keyframes green-fade-in-out{from{opacity:0}65%{opacity:0}75%{opacity:1}90%{opacity:1}100%{opacity:0}}@keyframes green-fade-in-out{from{opacity:0}65%{opacity:0}75%{opacity:1}90%{opacity:1}100%{opacity:0}}.gap-patch{position:absolute;top:0;left:45%;width:10%;height:100%;overflow:hidden;border-color:inherit}.gap-patch .circle{width:1000%;left:-450%}.circle-clipper{display:inline-block;position:relative;width:50%;height:100%;overflow:hidden;border-color:inherit}.circle-clipper .circle{width:200%;height:100%;border-width:3px;border-style:solid;border-color:inherit;border-bottom-color:transparent !important;border-radius:50%;-webkit-animation:none;animation:none;position:absolute;top:0;right:0;bottom:0}.circle-clipper.left .circle{left:0;border-right-color:transparent !important;-webkit-transform:rotate(129deg);transform:rotate(129deg)}.circle-clipper.right .circle{left:-100%;border-left-color:transparent !important;-webkit-transform:rotate(-129deg);transform:rotate(-129deg)}.active .circle-clipper.left .circle{-webkit-animation:left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.active .circle-clipper.right .circle{-webkit-animation:right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}@-webkit-keyframes left-spin{from{-webkit-transform:rotate(130deg)}50%{-webkit-transform:rotate(-5deg)}to{-webkit-transform:rotate(130deg)}}@keyframes left-spin{from{-webkit-transform:rotate(130deg);transform:rotate(130deg)}50%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(130deg);transform:rotate(130deg)}}@-webkit-keyframes right-spin{from{-webkit-transform:rotate(-130deg)}50%{-webkit-transform:rotate(5deg)}to{-webkit-transform:rotate(-130deg)}}@keyframes right-spin{from{-webkit-transform:rotate(-130deg);transform:rotate(-130deg)}50%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}to{-webkit-transform:rotate(-130deg);transform:rotate(-130deg)}}#spinnerContainer.cooldown{-webkit-animation:container-rotate 1568ms linear infinite,fade-out 400ms cubic-bezier(0.4, 0, 0.2, 1);animation:container-rotate 1568ms linear infinite,fade-out 400ms cubic-bezier(0.4, 0, 0.2, 1)}@-webkit-keyframes fade-out{from{opacity:1}to{opacity:0}}@keyframes fade-out{from{opacity:1}to{opacity:0}}.slider{position:relative;height:400px;width:100%}.slider.fullscreen{height:100%;width:100%;position:absolute;top:0;left:0;right:0;bottom:0}.slider.fullscreen ul.slides{height:100%}.slider.fullscreen ul.indicators{z-index:2;bottom:30px}.slider .slides{background-color:#9e9e9e;margin:0;height:400px}.slider .slides li{opacity:0;position:absolute;top:0;left:0;z-index:1;width:100%;height:inherit;overflow:hidden}.slider .slides li img{height:100%;width:100%;background-size:cover;background-position:center}.slider .slides li .caption{color:#fff;position:absolute;top:15%;left:15%;width:70%;opacity:0}.slider .slides li .caption p{color:#e0e0e0}.slider .slides li.active{z-index:2}.slider .indicators{position:absolute;text-align:center;left:0;right:0;bottom:0;margin:0}.slider .indicators .indicator-item{display:inline-block;position:relative;cursor:pointer;height:16px;width:16px;margin:0 12px;background-color:#e0e0e0;transition:background-color .3s;border-radius:50%}.slider .indicators .indicator-item.active{background-color:#4CAF50}.carousel{overflow:hidden;position:relative;width:100%;height:400px;-webkit-perspective:500px;perspective:500px;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;-webkit-transform-origin:0% 50%;transform-origin:0% 50%}.carousel.carousel-slider{top:0;left:0;height:0}.carousel.carousel-slider .carousel-fixed-item{position:absolute;left:0;right:0;bottom:20px;z-index:1}.carousel.carousel-slider .carousel-fixed-item.with-indicators{bottom:68px}.carousel.carousel-slider .carousel-item{width:100%;height:100%;min-height:400px;position:absolute;top:0;left:0}.carousel.carousel-slider .carousel-item h2{font-size:24px;font-weight:500;line-height:32px}.carousel.carousel-slider .carousel-item p{font-size:15px}.carousel .carousel-item{display:none;width:200px;height:400px;position:absolute;top:0;left:0}.carousel .carousel-item img{width:100%}.carousel .indicators{position:absolute;text-align:center;left:0;right:0;bottom:0;margin:0}.carousel .indicators .indicator-item{display:inline-block;position:relative;cursor:pointer;height:8px;width:8px;margin:24px 4px;background-color:rgba(255,255,255,0.5);transition:background-color .3s;border-radius:50%}.carousel .indicators .indicator-item.active{background-color:#fff}.picker{font-size:16px;text-align:left;line-height:1.2;color:#000000;position:absolute;z-index:10000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.picker__input{cursor:default}.picker__input.picker__input--active{border-color:#0089ec}.picker__holder{width:100%;overflow-y:auto;-webkit-overflow-scrolling:touch}/*!
- * Default mobile-first, responsive styling for pickadate.js
- * Demo: http://amsul.github.io/pickadate.js
- */.picker__holder,.picker__frame{bottom:0;left:0;right:0;top:100%}.picker__holder{position:fixed;transition:background 0.15s ease-out, top 0s 0.15s;-webkit-backface-visibility:hidden}.picker__frame{position:absolute;margin:0 auto;min-width:256px;width:300px;max-height:350px;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:alpha(opacity=0);-moz-opacity:0;opacity:0;transition:all 0.15s ease-out}@media (min-height: 28.875em){.picker__frame{overflow:visible;top:auto;bottom:-100%;max-height:80%}}@media (min-height: 40.125em){.picker__frame{margin-bottom:7.5%}}.picker__wrap{display:table;width:100%;height:100%}@media (min-height: 28.875em){.picker__wrap{display:block}}.picker__box{background:#ffffff;display:table-cell;vertical-align:middle}@media (min-height: 28.875em){.picker__box{display:block;border:1px solid #777777;border-top-color:#898989;border-bottom-width:0;border-radius:5px 5px 0 0;box-shadow:0 12px 36px 16px rgba(0,0,0,0.24)}}.picker--opened .picker__holder{top:0;background:transparent;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E000000,endColorstr=#1E000000)";zoom:1;background:rgba(0,0,0,0.32);transition:background 0.15s ease-out}.picker--opened .picker__frame{top:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";filter:alpha(opacity=100);-moz-opacity:1;opacity:1}@media (min-height: 35.875em){.picker--opened .picker__frame{top:10%;bottom:auto}}.picker__input.picker__input--active{border-color:#E3F2FD}.picker__frame{margin:0 auto;max-width:325px}@media (min-height: 38.875em){.picker--opened .picker__frame{top:10%;bottom:auto}}.picker__box{padding:0 1em}.picker__header{text-align:center;position:relative;margin-top:.75em}.picker__month,.picker__year{display:inline-block;margin-left:.25em;margin-right:.25em}.picker__select--month,.picker__select--year{height:2em;padding:0;margin-left:.25em;margin-right:.25em}.picker__select--month.browser-default{display:inline;background-color:#FFFFFF;width:40%}.picker__select--year.browser-default{display:inline;background-color:#FFFFFF;width:26%}.picker__select--month:focus,.picker__select--year:focus{border-color:rgba(0,0,0,0.05)}.picker__nav--prev,.picker__nav--next{position:absolute;padding:.5em 1.25em;width:1em;height:1em;box-sizing:content-box;top:-0.25em}.picker__nav--prev{left:-1em;padding-right:1.25em}.picker__nav--next{right:-1em;padding-left:1.25em}.picker__nav--disabled,.picker__nav--disabled:hover,.picker__nav--disabled:before,.picker__nav--disabled:before:hover{cursor:default;background:none;border-right-color:#f5f5f5;border-left-color:#f5f5f5}.picker__table{text-align:center;border-collapse:collapse;border-spacing:0;table-layout:fixed;font-size:1rem;width:100%;margin-top:.75em;margin-bottom:.5em}.picker__table th,.picker__table td{text-align:center}.picker__table td{margin:0;padding:0}.picker__weekday{width:14.285714286%;font-size:.75em;padding-bottom:.25em;color:#999999;font-weight:500}@media (min-height: 33.875em){.picker__weekday{padding-bottom:.5em}}.picker__day--today{position:relative;color:#595959;letter-spacing:-.3;padding:.75rem 0;font-weight:400;border:1px solid transparent}.picker__day--disabled:before{border-top-color:#aaaaaa}.picker__day--infocus:hover{cursor:pointer;color:#000;font-weight:500}.picker__day--outfocus{display:none;padding:.75rem 0;color:#fff}.picker__day--outfocus:hover{cursor:pointer;color:#dddddd;font-weight:500}.picker__day--highlighted:hover,.picker--focused .picker__day--highlighted{cursor:pointer}.picker__day--selected,.picker__day--selected:hover,.picker--focused .picker__day--selected{border-radius:50%;-webkit-transform:scale(0.75);transform:scale(0.75);background:#0089ec;color:#ffffff}.picker__day--disabled,.picker__day--disabled:hover,.picker--focused .picker__day--disabled{background:#f5f5f5;border-color:#f5f5f5;color:#dddddd;cursor:default}.picker__day--highlighted.picker__day--disabled,.picker__day--highlighted.picker__day--disabled:hover{background:#bbbbbb}.picker__footer{text-align:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}.picker__button--today,.picker__button--clear,.picker__button--close{border:1px solid #ffffff;background:#ffffff;font-size:.8em;padding:.66em 0;font-weight:bold;width:33%;display:inline-block;vertical-align:bottom}.picker__button--today:hover,.picker__button--clear:hover,.picker__button--close:hover{cursor:pointer;color:#000000;background:#b1dcfb;border-bottom-color:#b1dcfb}.picker__button--today:focus,.picker__button--clear:focus,.picker__button--close:focus{background:#b1dcfb;border-color:rgba(0,0,0,0.05);outline:none}.picker__button--today:before,.picker__button--clear:before,.picker__button--close:before{position:relative;display:inline-block;height:0}.picker__button--today:before,.picker__button--clear:before{content:" ";margin-right:.45em}.picker__button--today:before{top:-0.05em;width:0;border-top:0.66em solid #0059bc;border-left:.66em solid transparent}.picker__button--clear:before{top:-0.25em;width:.66em;border-top:3px solid #ee2200}.picker__button--close:before{content:"\D7";top:-0.1em;vertical-align:top;font-size:1.1em;margin-right:.35em;color:#777777}.picker__button--today[disabled],.picker__button--today[disabled]:hover{background:#f5f5f5;border-color:#f5f5f5;color:#dddddd;cursor:default}.picker__button--today[disabled]:before{border-top-color:#aaaaaa}.picker__box{border-radius:2px;overflow:hidden}.picker__date-display{text-align:center;background-color:#26a69a;color:#fff;padding-bottom:15px;font-weight:300}.picker__nav--prev:hover,.picker__nav--next:hover{cursor:pointer;color:#000000;background:#a1ded8}.picker__weekday-display{background-color:#1f897f;padding:10px;font-weight:200;letter-spacing:.5;font-size:1rem;margin-bottom:15px}.picker__month-display{text-transform:uppercase;font-size:2rem}.picker__day-display{font-size:4.5rem;font-weight:400}.picker__year-display{font-size:1.8rem;color:rgba(255,255,255,0.4)}.picker__box{padding:0}.picker__calendar-container{padding:0 1rem}.picker__calendar-container thead{border:none}.picker__table{margin-top:0;margin-bottom:.5em}.picker__day--infocus{color:#595959;letter-spacing:-.3;padding:.75rem 0;font-weight:400;border:1px solid transparent}.picker__day.picker__day--today{color:#26a69a}.picker__day.picker__day--today.picker__day--selected{color:#fff}.picker__weekday{font-size:.9rem}.picker__day--selected,.picker__day--selected:hover,.picker--focused .picker__day--selected{border-radius:50%;-webkit-transform:scale(0.9);transform:scale(0.9);background-color:#26a69a;color:#ffffff}.picker__day--selected.picker__day--outfocus,.picker__day--selected:hover.picker__day--outfocus,.picker--focused .picker__day--selected.picker__day--outfocus{background-color:#a1ded8}.picker__footer{text-align:right;padding:5px 10px}.picker__close,.picker__today{font-size:1.1rem;padding:0 1rem;color:#26a69a}.picker__nav--prev:before,.picker__nav--next:before{content:" ";border-top:.5em solid transparent;border-bottom:.5em solid transparent;border-right:0.75em solid #676767;width:0;height:0;display:block;margin:0 auto}.picker__nav--next:before{border-right:0;border-left:0.75em solid #676767}button.picker__today:focus,button.picker__clear:focus,button.picker__close:focus{background-color:#a1ded8}.picker__list{list-style:none;padding:0.75em 0 4.2em;margin:0}.picker__list-item{border-bottom:1px solid #dddddd;border-top:1px solid #dddddd;margin-bottom:-1px;position:relative;background:#ffffff;padding:.75em 1.25em}@media (min-height: 46.75em){.picker__list-item{padding:.5em 1em}}.picker__list-item:hover{cursor:pointer;color:#000000;background:#b1dcfb;border-color:#0089ec;z-index:10}.picker__list-item--highlighted{border-color:#0089ec;z-index:10}.picker__list-item--highlighted:hover,.picker--focused .picker__list-item--highlighted{cursor:pointer;color:#000000;background:#b1dcfb}.picker__list-item--selected,.picker__list-item--selected:hover,.picker--focused .picker__list-item--selected{background:#0089ec;color:#ffffff;z-index:10}.picker__list-item--disabled,.picker__list-item--disabled:hover,.picker--focused .picker__list-item--disabled{background:#f5f5f5;border-color:#f5f5f5;color:#dddddd;cursor:default;border-color:#dddddd;z-index:auto}.picker--time .picker__button--clear{display:block;width:80%;margin:1em auto 0;padding:1em 1.25em;background:none;border:0;font-weight:500;font-size:.67em;text-align:center;text-transform:uppercase;color:#666}.picker--time .picker__button--clear:hover,.picker--time .picker__button--clear:focus{color:#000000;background:#b1dcfb;background:#ee2200;border-color:#ee2200;cursor:pointer;color:#ffffff;outline:none}.picker--time .picker__button--clear:before{top:-0.25em;color:#666;font-size:1.25em;font-weight:bold}.picker--time .picker__button--clear:hover:before,.picker--time .picker__button--clear:focus:before{color:#ffffff}.picker--time .picker__frame{min-width:256px;max-width:320px}.picker--time .picker__box{font-size:1em;background:#f2f2f2;padding:0}@media (min-height: 40.125em){.picker--time .picker__box{margin-bottom:5em}}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/icons-regular.woff2 b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/icons-regular.woff2
deleted file mode 100644
index 5c17f4b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/icons-regular.woff2
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.eot b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.eot
deleted file mode 100644
index b73776e..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.eot
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.ttf b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.ttf
deleted file mode 100644
index 68822ca..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.woff b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.woff
deleted file mode 100644
index 1f75afd..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.woff
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.woff2 b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.woff2
deleted file mode 100644
index 350d1c3..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.woff2
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.eot b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.eot
deleted file mode 100644
index 072cdc4..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.eot
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.ttf b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.ttf
deleted file mode 100644
index aa45340..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.ttf
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.woff b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.woff
deleted file mode 100644
index 3480c6c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.woff
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.woff2 b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.woff2
deleted file mode 100644
index 9a4d98c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.woff2
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.eot b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.eot
deleted file mode 100644
index f9ad995..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.eot
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.ttf b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.ttf
deleted file mode 100644
index a3c1a1f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.ttf
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.woff b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.woff
deleted file mode 100644
index 1186773..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.woff
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.woff2 b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.woff2
deleted file mode 100644
index d10a592..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.woff2
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.eot b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.eot
deleted file mode 100644
index 9b5e8e4..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.eot
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.ttf b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.ttf
deleted file mode 100644
index 0e58508..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.woff b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.woff
deleted file mode 100644
index f823258..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.woff
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.woff2 b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.woff2
deleted file mode 100644
index b7082ef..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.woff2
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.eot b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.eot
deleted file mode 100644
index 2284a3b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.eot
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.ttf b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.ttf
deleted file mode 100644
index 8779333..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.ttf
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.woff b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.woff
deleted file mode 100644
index 2a98c1e..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.woff
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.woff2 b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.woff2
deleted file mode 100644
index a38025a..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.woff2
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/img/ponzu-file.png b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/img/ponzu-file.png
deleted file mode 100644
index ee3663c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/img/ponzu-file.png
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/js/chart.bundle.min.js b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/js/chart.bundle.min.js
deleted file mode 100644
index 792c8e1..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/js/chart.bundle.min.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/*!
- * Chart.js
- * http://chartjs.org/
- * Version: 2.3.0
- *
- * Copyright 2016 Nick Downie
- * Released under the MIT license
- * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md
- */
-!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.Chart=t()}}(function(){var t;return function e(t,n,i){function a(r,s){if(!n[r]){if(!t[r]){var l="function"==typeof require&&require;if(!s&&l)return l(r,!0);if(o)return o(r,!0);var d=new Error("Cannot find module '"+r+"'");throw d.code="MODULE_NOT_FOUND",d}var u=n[r]={exports:{}};t[r][0].call(u.exports,function(e){var n=t[r][1][e];return a(n?n:e)},u,u.exports,e,t,n,i)}return n[r].exports}for(var o="function"==typeof require&&require,r=0;r<i.length;r++)a(i[r]);return a}({1:[function(t,e,n){function i(t){if(t){var e=/^#([a-fA-F0-9]{3})$/,n=/^#([a-fA-F0-9]{6})$/,i=/^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,a=/^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,o=/(\w+)/,r=[0,0,0],s=1,l=t.match(e);if(l){l=l[1];for(var d=0;d<r.length;d++)r[d]=parseInt(l[d]+l[d],16)}else if(l=t.match(n)){l=l[1];for(var d=0;d<r.length;d++)r[d]=parseInt(l.slice(2*d,2*d+2),16)}else if(l=t.match(i)){for(var d=0;d<r.length;d++)r[d]=parseInt(l[d+1]);s=parseFloat(l[4])}else if(l=t.match(a)){for(var d=0;d<r.length;d++)r[d]=Math.round(2.55*parseFloat(l[d+1]));s=parseFloat(l[4])}else if(l=t.match(o)){if("transparent"==l[1])return[0,0,0,0];if(r=x[l[1]],!r)return}for(var d=0;d<r.length;d++)r[d]=b(r[d],0,255);return s=s||0==s?b(s,0,1):1,r[3]=s,r}}function a(t){if(t){var e=/^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/,n=t.match(e);if(n){var i=parseFloat(n[4]),a=b(parseInt(n[1]),0,360),o=b(parseFloat(n[2]),0,100),r=b(parseFloat(n[3]),0,100),s=b(isNaN(i)?1:i,0,1);return[a,o,r,s]}}}function o(t){if(t){var e=/^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/,n=t.match(e);if(n){var i=parseFloat(n[4]),a=b(parseInt(n[1]),0,360),o=b(parseFloat(n[2]),0,100),r=b(parseFloat(n[3]),0,100),s=b(isNaN(i)?1:i,0,1);return[a,o,r,s]}}}function r(t){var e=i(t);return e&&e.slice(0,3)}function s(t){var e=a(t);return e&&e.slice(0,3)}function l(t){var e=i(t);return e?e[3]:(e=a(t))?e[3]:(e=o(t))?e[3]:void 0}function d(t){return"#"+y(t[0])+y(t[1])+y(t[2])}function u(t,e){return 1>e||t[3]&&t[3]<1?c(t,e):"rgb("+t[0]+", "+t[1]+", "+t[2]+")"}function c(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"rgba("+t[0]+", "+t[1]+", "+t[2]+", "+e+")"}function h(t,e){if(1>e||t[3]&&t[3]<1)return f(t,e);var n=Math.round(t[0]/255*100),i=Math.round(t[1]/255*100),a=Math.round(t[2]/255*100);return"rgb("+n+"%, "+i+"%, "+a+"%)"}function f(t,e){var n=Math.round(t[0]/255*100),i=Math.round(t[1]/255*100),a=Math.round(t[2]/255*100);return"rgba("+n+"%, "+i+"%, "+a+"%, "+(e||t[3]||1)+")"}function g(t,e){return 1>e||t[3]&&t[3]<1?m(t,e):"hsl("+t[0]+", "+t[1]+"%, "+t[2]+"%)"}function m(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hsla("+t[0]+", "+t[1]+"%, "+t[2]+"%, "+e+")"}function p(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hwb("+t[0]+", "+t[1]+"%, "+t[2]+"%"+(void 0!==e&&1!==e?", "+e:"")+")"}function v(t){return k[t.slice(0,3)]}function b(t,e,n){return Math.min(Math.max(e,t),n)}function y(t){var e=t.toString(16).toUpperCase();return e.length<2?"0"+e:e}var x=t(5);e.exports={getRgba:i,getHsla:a,getRgb:r,getHsl:s,getHwb:o,getAlpha:l,hexString:d,rgbString:u,rgbaString:c,percentString:h,percentaString:f,hslString:g,hslaString:m,hwbString:p,keyword:v};var k={};for(var S in x)k[x[S]]=S},{5:5}],2:[function(t,e,n){var i=t(4),a=t(1),o=function(t){if(t instanceof o)return t;if(!(this instanceof o))return new o(t);this.values={rgb:[0,0,0],hsl:[0,0,0],hsv:[0,0,0],hwb:[0,0,0],cmyk:[0,0,0,0],alpha:1};var e;if("string"==typeof t)if(e=a.getRgba(t))this.setValues("rgb",e);else if(e=a.getHsla(t))this.setValues("hsl",e);else{if(!(e=a.getHwb(t)))throw new Error('Unable to parse color from string "'+t+'"');this.setValues("hwb",e)}else if("object"==typeof t)if(e=t,void 0!==e.r||void 0!==e.red)this.setValues("rgb",e);else if(void 0!==e.l||void 0!==e.lightness)this.setValues("hsl",e);else if(void 0!==e.v||void 0!==e.value)this.setValues("hsv",e);else if(void 0!==e.w||void 0!==e.whiteness)this.setValues("hwb",e);else{if(void 0===e.c&&void 0===e.cyan)throw new Error("Unable to parse color from object "+JSON.stringify(t));this.setValues("cmyk",e)}};o.prototype={rgb:function(){return this.setSpace("rgb",arguments)},hsl:function(){return this.setSpace("hsl",arguments)},hsv:function(){return this.setSpace("hsv",arguments)},hwb:function(){return this.setSpace("hwb",arguments)},cmyk:function(){return this.setSpace("cmyk",arguments)},rgbArray:function(){return this.values.rgb},hslArray:function(){return this.values.hsl},hsvArray:function(){return this.values.hsv},hwbArray:function(){var t=this.values;return 1!==t.alpha?t.hwb.concat([t.alpha]):t.hwb},cmykArray:function(){return this.values.cmyk},rgbaArray:function(){var t=this.values;return t.rgb.concat([t.alpha])},hslaArray:function(){var t=this.values;return t.hsl.concat([t.alpha])},alpha:function(t){return void 0===t?this.values.alpha:(this.setValues("alpha",t),this)},red:function(t){return this.setChannel("rgb",0,t)},green:function(t){return this.setChannel("rgb",1,t)},blue:function(t){return this.setChannel("rgb",2,t)},hue:function(t){return t&&(t%=360,t=0>t?360+t:t),this.setChannel("hsl",0,t)},saturation:function(t){return this.setChannel("hsl",1,t)},lightness:function(t){return this.setChannel("hsl",2,t)},saturationv:function(t){return this.setChannel("hsv",1,t)},whiteness:function(t){return this.setChannel("hwb",1,t)},blackness:function(t){return this.setChannel("hwb",2,t)},value:function(t){return this.setChannel("hsv",2,t)},cyan:function(t){return this.setChannel("cmyk",0,t)},magenta:function(t){return this.setChannel("cmyk",1,t)},yellow:function(t){return this.setChannel("cmyk",2,t)},black:function(t){return this.setChannel("cmyk",3,t)},hexString:function(){return a.hexString(this.values.rgb)},rgbString:function(){return a.rgbString(this.values.rgb,this.values.alpha)},rgbaString:function(){return a.rgbaString(this.values.rgb,this.values.alpha)},percentString:function(){return a.percentString(this.values.rgb,this.values.alpha)},hslString:function(){return a.hslString(this.values.hsl,this.values.alpha)},hslaString:function(){return a.hslaString(this.values.hsl,this.values.alpha)},hwbString:function(){return a.hwbString(this.values.hwb,this.values.alpha)},keyword:function(){return a.keyword(this.values.rgb,this.values.alpha)},rgbNumber:function(){var t=this.values.rgb;return t[0]<<16|t[1]<<8|t[2]},luminosity:function(){for(var t=this.values.rgb,e=[],n=0;n<t.length;n++){var i=t[n]/255;e[n]=.03928>=i?i/12.92:Math.pow((i+.055)/1.055,2.4)}return.2126*e[0]+.7152*e[1]+.0722*e[2]},contrast:function(t){var e=this.luminosity(),n=t.luminosity();return e>n?(e+.05)/(n+.05):(n+.05)/(e+.05)},level:function(t){var e=this.contrast(t);return e>=7.1?"AAA":e>=4.5?"AA":""},dark:function(){var t=this.values.rgb,e=(299*t[0]+587*t[1]+114*t[2])/1e3;return 128>e},light:function(){return!this.dark()},negate:function(){for(var t=[],e=0;3>e;e++)t[e]=255-this.values.rgb[e];return this.setValues("rgb",t),this},lighten:function(t){var e=this.values.hsl;return e[2]+=e[2]*t,this.setValues("hsl",e),this},darken:function(t){var e=this.values.hsl;return e[2]-=e[2]*t,this.setValues("hsl",e),this},saturate:function(t){var e=this.values.hsl;return e[1]+=e[1]*t,this.setValues("hsl",e),this},desaturate:function(t){var e=this.values.hsl;return e[1]-=e[1]*t,this.setValues("hsl",e),this},whiten:function(t){var e=this.values.hwb;return e[1]+=e[1]*t,this.setValues("hwb",e),this},blacken:function(t){var e=this.values.hwb;return e[2]+=e[2]*t,this.setValues("hwb",e),this},greyscale:function(){var t=this.values.rgb,e=.3*t[0]+.59*t[1]+.11*t[2];return this.setValues("rgb",[e,e,e]),this},clearer:function(t){var e=this.values.alpha;return this.setValues("alpha",e-e*t),this},opaquer:function(t){var e=this.values.alpha;return this.setValues("alpha",e+e*t),this},rotate:function(t){var e=this.values.hsl,n=(e[0]+t)%360;return e[0]=0>n?360+n:n,this.setValues("hsl",e),this},mix:function(t,e){var n=this,i=t,a=void 0===e?.5:e,o=2*a-1,r=n.alpha()-i.alpha(),s=((o*r===-1?o:(o+r)/(1+o*r))+1)/2,l=1-s;return this.rgb(s*n.red()+l*i.red(),s*n.green()+l*i.green(),s*n.blue()+l*i.blue()).alpha(n.alpha()*a+i.alpha()*(1-a))},toJSON:function(){return this.rgb()},clone:function(){var t,e,n=new o,i=this.values,a=n.values;for(var r in i)i.hasOwnProperty(r)&&(t=i[r],e={}.toString.call(t),"[object Array]"===e?a[r]=t.slice(0):"[object Number]"===e?a[r]=t:console.error("unexpected color value:",t));return n}},o.prototype.spaces={rgb:["red","green","blue"],hsl:["hue","saturation","lightness"],hsv:["hue","saturation","value"],hwb:["hue","whiteness","blackness"],cmyk:["cyan","magenta","yellow","black"]},o.prototype.maxes={rgb:[255,255,255],hsl:[360,100,100],hsv:[360,100,100],hwb:[360,100,100],cmyk:[100,100,100,100]},o.prototype.getValues=function(t){for(var e=this.values,n={},i=0;i<t.length;i++)n[t.charAt(i)]=e[t][i];return 1!==e.alpha&&(n.a=e.alpha),n},o.prototype.setValues=function(t,e){var n,a=this.values,o=this.spaces,r=this.maxes,s=1;if("alpha"===t)s=e;else if(e.length)a[t]=e.slice(0,t.length),s=e[t.length];else if(void 0!==e[t.charAt(0)]){for(n=0;n<t.length;n++)a[t][n]=e[t.charAt(n)];s=e.a}else if(void 0!==e[o[t][0]]){var l=o[t];for(n=0;n<t.length;n++)a[t][n]=e[l[n]];s=e.alpha}if(a.alpha=Math.max(0,Math.min(1,void 0===s?a.alpha:s)),"alpha"===t)return!1;var d;for(n=0;n<t.length;n++)d=Math.max(0,Math.min(r[t][n],a[t][n])),a[t][n]=Math.round(d);for(var u in o)u!==t&&(a[u]=i[t][u](a[t]));return!0},o.prototype.setSpace=function(t,e){var n=e[0];return void 0===n?this.getValues(t):("number"==typeof n&&(n=Array.prototype.slice.call(e)),this.setValues(t,n),this)},o.prototype.setChannel=function(t,e,n){var i=this.values[t];return void 0===n?i[e]:n===i[e]?this:(i[e]=n,this.setValues(t,i),this)},"undefined"!=typeof window&&(window.Color=o),e.exports=o},{1:1,4:4}],3:[function(t,e,n){function i(t){var e,n,i,a=t[0]/255,o=t[1]/255,r=t[2]/255,s=Math.min(a,o,r),l=Math.max(a,o,r),d=l-s;return l==s?e=0:a==l?e=(o-r)/d:o==l?e=2+(r-a)/d:r==l&&(e=4+(a-o)/d),e=Math.min(60*e,360),0>e&&(e+=360),i=(s+l)/2,n=l==s?0:.5>=i?d/(l+s):d/(2-l-s),[e,100*n,100*i]}function a(t){var e,n,i,a=t[0],o=t[1],r=t[2],s=Math.min(a,o,r),l=Math.max(a,o,r),d=l-s;return n=0==l?0:d/l*1e3/10,l==s?e=0:a==l?e=(o-r)/d:o==l?e=2+(r-a)/d:r==l&&(e=4+(a-o)/d),e=Math.min(60*e,360),0>e&&(e+=360),i=l/255*1e3/10,[e,n,i]}function o(t){var e=t[0],n=t[1],a=t[2],o=i(t)[0],r=1/255*Math.min(e,Math.min(n,a)),a=1-1/255*Math.max(e,Math.max(n,a));return[o,100*r,100*a]}function s(t){var e,n,i,a,o=t[0]/255,r=t[1]/255,s=t[2]/255;return a=Math.min(1-o,1-r,1-s),e=(1-o-a)/(1-a)||0,n=(1-r-a)/(1-a)||0,i=(1-s-a)/(1-a)||0,[100*e,100*n,100*i,100*a]}function l(t){return K[JSON.stringify(t)]}function d(t){var e=t[0]/255,n=t[1]/255,i=t[2]/255;e=e>.04045?Math.pow((e+.055)/1.055,2.4):e/12.92,n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92,i=i>.04045?Math.pow((i+.055)/1.055,2.4):i/12.92;var a=.4124*e+.3576*n+.1805*i,o=.2126*e+.7152*n+.0722*i,r=.0193*e+.1192*n+.9505*i;return[100*a,100*o,100*r]}function u(t){var e,n,i,a=d(t),o=a[0],r=a[1],s=a[2];return o/=95.047,r/=100,s/=108.883,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,r=r>.008856?Math.pow(r,1/3):7.787*r+16/116,s=s>.008856?Math.pow(s,1/3):7.787*s+16/116,e=116*r-16,n=500*(o-r),i=200*(r-s),[e,n,i]}function c(t){return B(u(t))}function h(t){var e,n,i,a,o,r=t[0]/360,s=t[1]/100,l=t[2]/100;if(0==s)return o=255*l,[o,o,o];n=.5>l?l*(1+s):l+s-l*s,e=2*l-n,a=[0,0,0];for(var d=0;3>d;d++)i=r+1/3*-(d-1),0>i&&i++,i>1&&i--,o=1>6*i?e+6*(n-e)*i:1>2*i?n:2>3*i?e+(n-e)*(2/3-i)*6:e,a[d]=255*o;return a}function f(t){var e,n,i=t[0],a=t[1]/100,o=t[2]/100;return 0===o?[0,0,0]:(o*=2,a*=1>=o?o:2-o,n=(o+a)/2,e=2*a/(o+a),[i,100*e,100*n])}function m(t){return o(h(t))}function p(t){return s(h(t))}function v(t){return l(h(t))}function y(t){var e=t[0]/60,n=t[1]/100,i=t[2]/100,a=Math.floor(e)%6,o=e-Math.floor(e),r=255*i*(1-n),s=255*i*(1-n*o),l=255*i*(1-n*(1-o)),i=255*i;switch(a){case 0:return[i,l,r];case 1:return[s,i,r];case 2:return[r,i,l];case 3:return[r,s,i];case 4:return[l,r,i];case 5:return[i,r,s]}}function x(t){var e,n,i=t[0],a=t[1]/100,o=t[2]/100;return n=(2-a)*o,e=a*o,e/=1>=n?n:2-n,e=e||0,n/=2,[i,100*e,100*n]}function k(t){return o(y(t))}function S(t){return s(y(t))}function w(t){return l(y(t))}function _(t){var e,n,i,a,o=t[0]/360,s=t[1]/100,l=t[2]/100,d=s+l;switch(d>1&&(s/=d,l/=d),e=Math.floor(6*o),n=1-l,i=6*o-e,0!=(1&e)&&(i=1-i),a=s+i*(n-s),e){default:case 6:case 0:r=n,g=a,b=s;break;case 1:r=a,g=n,b=s;break;case 2:r=s,g=n,b=a;break;case 3:r=s,g=a,b=n;break;case 4:r=a,g=s,b=n;break;case 5:r=n,g=s,b=a}return[255*r,255*g,255*b]}function M(t){return i(_(t))}function D(t){return a(_(t))}function C(t){return s(_(t))}function T(t){return l(_(t))}function P(t){var e,n,i,a=t[0]/100,o=t[1]/100,r=t[2]/100,s=t[3]/100;return e=1-Math.min(1,a*(1-s)+s),n=1-Math.min(1,o*(1-s)+s),i=1-Math.min(1,r*(1-s)+s),[255*e,255*n,255*i]}function F(t){return i(P(t))}function I(t){return a(P(t))}function A(t){return o(P(t))}function O(t){return l(P(t))}function R(t){var e,n,i,a=t[0]/100,o=t[1]/100,r=t[2]/100;return e=3.2406*a+-1.5372*o+r*-.4986,n=a*-.9689+1.8758*o+.0415*r,i=.0557*a+o*-.204+1.057*r,e=e>.0031308?1.055*Math.pow(e,1/2.4)-.055:e=12.92*e,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:n=12.92*n,i=i>.0031308?1.055*Math.pow(i,1/2.4)-.055:i=12.92*i,e=Math.min(Math.max(0,e),1),n=Math.min(Math.max(0,n),1),i=Math.min(Math.max(0,i),1),[255*e,255*n,255*i]}function W(t){var e,n,i,a=t[0],o=t[1],r=t[2];return a/=95.047,o/=100,r/=108.883,a=a>.008856?Math.pow(a,1/3):7.787*a+16/116,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,r=r>.008856?Math.pow(r,1/3):7.787*r+16/116,e=116*o-16,n=500*(a-o),i=200*(o-r),[e,n,i]}function L(t){return B(W(t))}function V(t){var e,n,i,a,o=t[0],r=t[1],s=t[2];return 8>=o?(n=100*o/903.3,a=7.787*(n/100)+16/116):(n=100*Math.pow((o+16)/116,3),a=Math.pow(n/100,1/3)),e=.008856>=e/95.047?e=95.047*(r/500+a-16/116)/7.787:95.047*Math.pow(r/500+a,3),i=.008859>=i/108.883?i=108.883*(a-s/200-16/116)/7.787:108.883*Math.pow(a-s/200,3),[e,n,i]}function B(t){var e,n,i,a=t[0],o=t[1],r=t[2];return e=Math.atan2(r,o),n=360*e/2/Math.PI,0>n&&(n+=360),i=Math.sqrt(o*o+r*r),[a,i,n]}function Y(t){return R(V(t))}function z(t){var e,n,i,a=t[0],o=t[1],r=t[2];return i=r/360*2*Math.PI,e=o*Math.cos(i),n=o*Math.sin(i),[a,e,n]}function H(t){return V(z(t))}function N(t){return Y(z(t))}function E(t){return X[t]}function U(t){return i(E(t))}function j(t){return a(E(t))}function G(t){return o(E(t))}function q(t){return s(E(t))}function Z(t){return u(E(t))}function J(t){return d(E(t))}e.exports={rgb2hsl:i,rgb2hsv:a,rgb2hwb:o,rgb2cmyk:s,rgb2keyword:l,rgb2xyz:d,rgb2lab:u,rgb2lch:c,hsl2rgb:h,hsl2hsv:f,hsl2hwb:m,hsl2cmyk:p,hsl2keyword:v,hsv2rgb:y,hsv2hsl:x,hsv2hwb:k,hsv2cmyk:S,hsv2keyword:w,hwb2rgb:_,hwb2hsl:M,hwb2hsv:D,hwb2cmyk:C,hwb2keyword:T,cmyk2rgb:P,cmyk2hsl:F,cmyk2hsv:I,cmyk2hwb:A,cmyk2keyword:O,keyword2rgb:E,keyword2hsl:U,keyword2hsv:j,keyword2hwb:G,keyword2cmyk:q,keyword2lab:Z,keyword2xyz:J,xyz2rgb:R,xyz2lab:W,xyz2lch:L,lab2xyz:V,lab2rgb:Y,lab2lch:B,lch2lab:z,lch2xyz:H,lch2rgb:N};var X={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},K={};for(var Q in X)K[JSON.stringify(X[Q])]=Q},{}],4:[function(t,e,n){var i=t(3),a=function(){return new d};for(var o in i){a[o+"Raw"]=function(t){return function(e){return"number"==typeof e&&(e=Array.prototype.slice.call(arguments)),i[t](e)}}(o);var r=/(\w+)2(\w+)/.exec(o),s=r[1],l=r[2];a[s]=a[s]||{},a[s][l]=a[o]=function(t){return function(e){"number"==typeof e&&(e=Array.prototype.slice.call(arguments));var n=i[t](e);if("string"==typeof n||void 0===n)return n;for(var a=0;a<n.length;a++)n[a]=Math.round(n[a]);return n}}(o)}var d=function(){this.convs={}};d.prototype.routeSpace=function(t,e){var n=e[0];return void 0===n?this.getValues(t):("number"==typeof n&&(n=Array.prototype.slice.call(e)),this.setValues(t,n))},d.prototype.setValues=function(t,e){return this.space=t,this.convs={},this.convs[t]=e,this},d.prototype.getValues=function(t){var e=this.convs[t];if(!e){var n=this.space,i=this.convs[n];e=a[n][t](i),this.convs[t]=e}return e},["rgb","hsl","hsv","cmyk","keyword"].forEach(function(t){d.prototype[t]=function(e){return this.routeSpace(t,arguments)}}),e.exports=a},{3:3}],5:[function(t,e,n){e.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}},{}],6:[function(e,n,i){!function(e,a){"object"==typeof i&&"undefined"!=typeof n?n.exports=a():"function"==typeof t&&t.amd?t(a):e.moment=a()}(this,function(){"use strict";function t(){return mi.apply(null,arguments)}function i(t){mi=t}function a(t){return t instanceof Array||"[object Array]"===Object.prototype.toString.call(t)}function o(t){return null!=t&&"[object Object]"===Object.prototype.toString.call(t)}function r(t){var e;for(e in t)return!1;return!0}function s(t){return t instanceof Date||"[object Date]"===Object.prototype.toString.call(t)}function l(t,e){var n,i=[];for(n=0;n<t.length;++n)i.push(e(t[n],n));return i}function d(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function u(t,e){for(var n in e)d(e,n)&&(t[n]=e[n]);return d(e,"toString")&&(t.toString=e.toString),d(e,"valueOf")&&(t.valueOf=e.valueOf),t}function c(t,e,n,i){return be(t,e,n,i,!0).utc()}function h(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null}}function f(t){return null==t._pf&&(t._pf=h()),t._pf}function g(t){if(null==t._isValid){var e=f(t),n=pi.call(e.parsedDateParts,function(t){return null!=t}),i=!isNaN(t._d.getTime())&&e.overflow<0&&!e.empty&&!e.invalidMonth&&!e.invalidWeekday&&!e.nullInput&&!e.invalidFormat&&!e.userInvalidated&&(!e.meridiem||e.meridiem&&n);if(t._strict&&(i=i&&0===e.charsLeftOver&&0===e.unusedTokens.length&&void 0===e.bigHour),null!=Object.isFrozen&&Object.isFrozen(t))return i;t._isValid=i}return t._isValid}function m(t){var e=c(NaN);return null!=t?u(f(e),t):f(e).userInvalidated=!0,e}function p(t){return void 0===t}function v(t,e){var n,i,a;if(p(e._isAMomentObject)||(t._isAMomentObject=e._isAMomentObject),p(e._i)||(t._i=e._i),p(e._f)||(t._f=e._f),p(e._l)||(t._l=e._l),p(e._strict)||(t._strict=e._strict),p(e._tzm)||(t._tzm=e._tzm),p(e._isUTC)||(t._isUTC=e._isUTC),p(e._offset)||(t._offset=e._offset),p(e._pf)||(t._pf=f(e)),p(e._locale)||(t._locale=e._locale),vi.length>0)for(n in vi)i=vi[n],a=e[i],p(a)||(t[i]=a);return t}function b(e){v(this,e),this._d=new Date(null!=e._d?e._d.getTime():NaN),bi===!1&&(bi=!0,t.updateOffset(this),bi=!1)}function y(t){return t instanceof b||null!=t&&null!=t._isAMomentObject}function x(t){return 0>t?Math.ceil(t)||0:Math.floor(t)}function k(t){var e=+t,n=0;return 0!==e&&isFinite(e)&&(n=x(e)),n}function S(t,e,n){var i,a=Math.min(t.length,e.length),o=Math.abs(t.length-e.length),r=0;for(i=0;a>i;i++)(n&&t[i]!==e[i]||!n&&k(t[i])!==k(e[i]))&&r++;return r+o}function w(e){t.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+e)}function _(e,n){var i=!0;return u(function(){if(null!=t.deprecationHandler&&t.deprecationHandler(null,e),i){for(var a,o=[],r=0;r<arguments.length;r++){if(a="","object"==typeof arguments[r]){a+="\n["+r+"] ";for(var s in arguments[0])a+=s+": "+arguments[0][s]+", ";a=a.slice(0,-2)}else a=arguments[r];o.push(a)}w(e+"\nArguments: "+Array.prototype.slice.call(o).join("")+"\n"+(new Error).stack),i=!1}return n.apply(this,arguments)},n)}function M(e,n){null!=t.deprecationHandler&&t.deprecationHandler(e,n),yi[e]||(w(n),yi[e]=!0)}function D(t){return t instanceof Function||"[object Function]"===Object.prototype.toString.call(t)}function C(t){var e,n;for(n in t)e=t[n],D(e)?this[n]=e:this["_"+n]=e;this._config=t,this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function T(t,e){var n,i=u({},t);for(n in e)d(e,n)&&(o(t[n])&&o(e[n])?(i[n]={},u(i[n],t[n]),u(i[n],e[n])):null!=e[n]?i[n]=e[n]:delete i[n]);for(n in t)d(t,n)&&!d(e,n)&&o(t[n])&&(i[n]=u({},i[n]));return i}function P(t){null!=t&&this.set(t)}function F(t,e,n){var i=this._calendar[t]||this._calendar.sameElse;return D(i)?i.call(e,n):i}function I(t){var e=this._longDateFormat[t],n=this._longDateFormat[t.toUpperCase()];return e||!n?e:(this._longDateFormat[t]=n.replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t])}function A(){return this._invalidDate}function O(t){return this._ordinal.replace("%d",t)}function R(t,e,n,i){var a=this._relativeTime[n];return D(a)?a(t,e,n,i):a.replace(/%d/i,t)}function W(t,e){var n=this._relativeTime[t>0?"future":"past"];return D(n)?n(e):n.replace(/%s/i,e)}function L(t,e){var n=t.toLowerCase();Ti[n]=Ti[n+"s"]=Ti[e]=t}function V(t){return"string"==typeof t?Ti[t]||Ti[t.toLowerCase()]:void 0}function B(t){var e,n,i={};for(n in t)d(t,n)&&(e=V(n),e&&(i[e]=t[n]));return i}function Y(t,e){Pi[t]=e}function z(t){var e=[];for(var n in t)e.push({unit:n,priority:Pi[n]});return e.sort(function(t,e){return t.priority-e.priority}),e}function H(e,n){return function(i){return null!=i?(E(this,e,i),t.updateOffset(this,n),this):N(this,e)}}function N(t,e){return t.isValid()?t._d["get"+(t._isUTC?"UTC":"")+e]():NaN}function E(t,e,n){t.isValid()&&t._d["set"+(t._isUTC?"UTC":"")+e](n)}function U(t){return t=V(t),D(this[t])?this[t]():this}function j(t,e){if("object"==typeof t){t=B(t);for(var n=z(t),i=0;i<n.length;i++)this[n[i].unit](t[n[i].unit])}else if(t=V(t),D(this[t]))return this[t](e);return this}function G(t,e,n){var i=""+Math.abs(t),a=e-i.length,o=t>=0;return(o?n?"+":"":"-")+Math.pow(10,Math.max(0,a)).toString().substr(1)+i}function q(t,e,n,i){var a=i;"string"==typeof i&&(a=function(){return this[i]()}),t&&(Oi[t]=a),e&&(Oi[e[0]]=function(){return G(a.apply(this,arguments),e[1],e[2])}),n&&(Oi[n]=function(){return this.localeData().ordinal(a.apply(this,arguments),t)})}function Z(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function J(t){var e,n,i=t.match(Fi);for(e=0,n=i.length;n>e;e++)Oi[i[e]]?i[e]=Oi[i[e]]:i[e]=Z(i[e]);return function(e){var a,o="";for(a=0;n>a;a++)o+=i[a]instanceof Function?i[a].call(e,t):i[a];return o}}function X(t,e){return t.isValid()?(e=K(e,t.localeData()),Ai[e]=Ai[e]||J(e),Ai[e](t)):t.localeData().invalidDate()}function K(t,e){function n(t){return e.longDateFormat(t)||t}var i=5;for(Ii.lastIndex=0;i>=0&&Ii.test(t);)t=t.replace(Ii,n),Ii.lastIndex=0,i-=1;return t}function Q(t,e,n){Ki[t]=D(e)?e:function(t,i){return t&&n?n:e}}function $(t,e){return d(Ki,t)?Ki[t](e._strict,e._locale):new RegExp(tt(t))}function tt(t){return et(t.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,n,i,a){return e||n||i||a}))}function et(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function nt(t,e){var n,i=e;for("string"==typeof t&&(t=[t]),"number"==typeof e&&(i=function(t,n){n[e]=k(t)}),n=0;n<t.length;n++)Qi[t[n]]=i}function it(t,e){nt(t,function(t,n,i,a){i._w=i._w||{},e(t,i._w,i,a)})}function at(t,e,n){null!=e&&d(Qi,t)&&Qi[t](e,n._a,n,t)}function ot(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function rt(t,e){return t?a(this._months)?this._months[t.month()]:this._months[(this._months.isFormat||la).test(e)?"format":"standalone"][t.month()]:this._months}function st(t,e){return t?a(this._monthsShort)?this._monthsShort[t.month()]:this._monthsShort[la.test(e)?"format":"standalone"][t.month()]:this._monthsShort}function lt(t,e,n){var i,a,o,r=t.toLocaleLowerCase();if(!this._monthsParse)for(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[],i=0;12>i;++i)o=c([2e3,i]),this._shortMonthsParse[i]=this.monthsShort(o,"").toLocaleLowerCase(),this._longMonthsParse[i]=this.months(o,"").toLocaleLowerCase();return n?"MMM"===e?(a=ki.call(this._shortMonthsParse,r),-1!==a?a:null):(a=ki.call(this._longMonthsParse,r),-1!==a?a:null):"MMM"===e?(a=ki.call(this._shortMonthsParse,r),-1!==a?a:(a=ki.call(this._longMonthsParse,r),-1!==a?a:null)):(a=ki.call(this._longMonthsParse,r),-1!==a?a:(a=ki.call(this._shortMonthsParse,r),-1!==a?a:null))}function dt(t,e,n){var i,a,o;if(this._monthsParseExact)return lt.call(this,t,e,n);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),i=0;12>i;i++){if(a=c([2e3,i]),n&&!this._longMonthsParse[i]&&(this._longMonthsParse[i]=new RegExp("^"+this.months(a,"").replace(".","")+"$","i"),this._shortMonthsParse[i]=new RegExp("^"+this.monthsShort(a,"").replace(".","")+"$","i")),n||this._monthsParse[i]||(o="^"+this.months(a,"")+"|^"+this.monthsShort(a,""),this._monthsParse[i]=new RegExp(o.replace(".",""),"i")),n&&"MMMM"===e&&this._longMonthsParse[i].test(t))return i;if(n&&"MMM"===e&&this._shortMonthsParse[i].test(t))return i;if(!n&&this._monthsParse[i].test(t))return i}}function ut(t,e){var n;if(!t.isValid())return t;if("string"==typeof e)if(/^\d+$/.test(e))e=k(e);else if(e=t.localeData().monthsParse(e),"number"!=typeof e)return t;return n=Math.min(t.date(),ot(t.year(),e)),t._d["set"+(t._isUTC?"UTC":"")+"Month"](e,n),t}function ct(e){return null!=e?(ut(this,e),
-t.updateOffset(this,!0),this):N(this,"Month")}function ht(){return ot(this.year(),this.month())}function ft(t){return this._monthsParseExact?(d(this,"_monthsRegex")||mt.call(this),t?this._monthsShortStrictRegex:this._monthsShortRegex):(d(this,"_monthsShortRegex")||(this._monthsShortRegex=ca),this._monthsShortStrictRegex&&t?this._monthsShortStrictRegex:this._monthsShortRegex)}function gt(t){return this._monthsParseExact?(d(this,"_monthsRegex")||mt.call(this),t?this._monthsStrictRegex:this._monthsRegex):(d(this,"_monthsRegex")||(this._monthsRegex=ha),this._monthsStrictRegex&&t?this._monthsStrictRegex:this._monthsRegex)}function mt(){function t(t,e){return e.length-t.length}var e,n,i=[],a=[],o=[];for(e=0;12>e;e++)n=c([2e3,e]),i.push(this.monthsShort(n,"")),a.push(this.months(n,"")),o.push(this.months(n,"")),o.push(this.monthsShort(n,""));for(i.sort(t),a.sort(t),o.sort(t),e=0;12>e;e++)i[e]=et(i[e]),a[e]=et(a[e]);for(e=0;24>e;e++)o[e]=et(o[e]);this._monthsRegex=new RegExp("^("+o.join("|")+")","i"),this._monthsShortRegex=this._monthsRegex,this._monthsStrictRegex=new RegExp("^("+a.join("|")+")","i"),this._monthsShortStrictRegex=new RegExp("^("+i.join("|")+")","i")}function pt(t){return vt(t)?366:365}function vt(t){return t%4===0&&t%100!==0||t%400===0}function bt(){return vt(this.year())}function yt(t,e,n,i,a,o,r){var s=new Date(t,e,n,i,a,o,r);return 100>t&&t>=0&&isFinite(s.getFullYear())&&s.setFullYear(t),s}function xt(t){var e=new Date(Date.UTC.apply(null,arguments));return 100>t&&t>=0&&isFinite(e.getUTCFullYear())&&e.setUTCFullYear(t),e}function kt(t,e,n){var i=7+e-n,a=(7+xt(t,0,i).getUTCDay()-e)%7;return-a+i-1}function St(t,e,n,i,a){var o,r,s=(7+n-i)%7,l=kt(t,i,a),d=1+7*(e-1)+s+l;return 0>=d?(o=t-1,r=pt(o)+d):d>pt(t)?(o=t+1,r=d-pt(t)):(o=t,r=d),{year:o,dayOfYear:r}}function wt(t,e,n){var i,a,o=kt(t.year(),e,n),r=Math.floor((t.dayOfYear()-o-1)/7)+1;return 1>r?(a=t.year()-1,i=r+_t(a,e,n)):r>_t(t.year(),e,n)?(i=r-_t(t.year(),e,n),a=t.year()+1):(a=t.year(),i=r),{week:i,year:a}}function _t(t,e,n){var i=kt(t,e,n),a=kt(t+1,e,n);return(pt(t)-i+a)/7}function Mt(t){return wt(t,this._week.dow,this._week.doy).week}function Dt(){return this._week.dow}function Ct(){return this._week.doy}function Tt(t){var e=this.localeData().week(this);return null==t?e:this.add(7*(t-e),"d")}function Pt(t){var e=wt(this,1,4).week;return null==t?e:this.add(7*(t-e),"d")}function Ft(t,e){return"string"!=typeof t?t:isNaN(t)?(t=e.weekdaysParse(t),"number"==typeof t?t:null):parseInt(t,10)}function It(t,e){return"string"==typeof t?e.weekdaysParse(t)%7||7:isNaN(t)?null:t}function At(t,e){return t?a(this._weekdays)?this._weekdays[t.day()]:this._weekdays[this._weekdays.isFormat.test(e)?"format":"standalone"][t.day()]:this._weekdays}function Ot(t){return t?this._weekdaysShort[t.day()]:this._weekdaysShort}function Rt(t){return t?this._weekdaysMin[t.day()]:this._weekdaysMin}function Wt(t,e,n){var i,a,o,r=t.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],i=0;7>i;++i)o=c([2e3,1]).day(i),this._minWeekdaysParse[i]=this.weekdaysMin(o,"").toLocaleLowerCase(),this._shortWeekdaysParse[i]=this.weekdaysShort(o,"").toLocaleLowerCase(),this._weekdaysParse[i]=this.weekdays(o,"").toLocaleLowerCase();return n?"dddd"===e?(a=ki.call(this._weekdaysParse,r),-1!==a?a:null):"ddd"===e?(a=ki.call(this._shortWeekdaysParse,r),-1!==a?a:null):(a=ki.call(this._minWeekdaysParse,r),-1!==a?a:null):"dddd"===e?(a=ki.call(this._weekdaysParse,r),-1!==a?a:(a=ki.call(this._shortWeekdaysParse,r),-1!==a?a:(a=ki.call(this._minWeekdaysParse,r),-1!==a?a:null))):"ddd"===e?(a=ki.call(this._shortWeekdaysParse,r),-1!==a?a:(a=ki.call(this._weekdaysParse,r),-1!==a?a:(a=ki.call(this._minWeekdaysParse,r),-1!==a?a:null))):(a=ki.call(this._minWeekdaysParse,r),-1!==a?a:(a=ki.call(this._weekdaysParse,r),-1!==a?a:(a=ki.call(this._shortWeekdaysParse,r),-1!==a?a:null)))}function Lt(t,e,n){var i,a,o;if(this._weekdaysParseExact)return Wt.call(this,t,e,n);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),i=0;7>i;i++){if(a=c([2e3,1]).day(i),n&&!this._fullWeekdaysParse[i]&&(this._fullWeekdaysParse[i]=new RegExp("^"+this.weekdays(a,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[i]=new RegExp("^"+this.weekdaysShort(a,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[i]=new RegExp("^"+this.weekdaysMin(a,"").replace(".",".?")+"$","i")),this._weekdaysParse[i]||(o="^"+this.weekdays(a,"")+"|^"+this.weekdaysShort(a,"")+"|^"+this.weekdaysMin(a,""),this._weekdaysParse[i]=new RegExp(o.replace(".",""),"i")),n&&"dddd"===e&&this._fullWeekdaysParse[i].test(t))return i;if(n&&"ddd"===e&&this._shortWeekdaysParse[i].test(t))return i;if(n&&"dd"===e&&this._minWeekdaysParse[i].test(t))return i;if(!n&&this._weekdaysParse[i].test(t))return i}}function Vt(t){if(!this.isValid())return null!=t?this:NaN;var e=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=t?(t=Ft(t,this.localeData()),this.add(t-e,"d")):e}function Bt(t){if(!this.isValid())return null!=t?this:NaN;var e=(this.day()+7-this.localeData()._week.dow)%7;return null==t?e:this.add(t-e,"d")}function Yt(t){if(!this.isValid())return null!=t?this:NaN;if(null!=t){var e=It(t,this.localeData());return this.day(this.day()%7?e:e-7)}return this.day()||7}function zt(t){return this._weekdaysParseExact?(d(this,"_weekdaysRegex")||Et.call(this),t?this._weekdaysStrictRegex:this._weekdaysRegex):(d(this,"_weekdaysRegex")||(this._weekdaysRegex=ba),this._weekdaysStrictRegex&&t?this._weekdaysStrictRegex:this._weekdaysRegex)}function Ht(t){return this._weekdaysParseExact?(d(this,"_weekdaysRegex")||Et.call(this),t?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(d(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=ya),this._weekdaysShortStrictRegex&&t?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Nt(t){return this._weekdaysParseExact?(d(this,"_weekdaysRegex")||Et.call(this),t?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(d(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=xa),this._weekdaysMinStrictRegex&&t?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function Et(){function t(t,e){return e.length-t.length}var e,n,i,a,o,r=[],s=[],l=[],d=[];for(e=0;7>e;e++)n=c([2e3,1]).day(e),i=this.weekdaysMin(n,""),a=this.weekdaysShort(n,""),o=this.weekdays(n,""),r.push(i),s.push(a),l.push(o),d.push(i),d.push(a),d.push(o);for(r.sort(t),s.sort(t),l.sort(t),d.sort(t),e=0;7>e;e++)s[e]=et(s[e]),l[e]=et(l[e]),d[e]=et(d[e]);this._weekdaysRegex=new RegExp("^("+d.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+l.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+s.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+r.join("|")+")","i")}function Ut(){return this.hours()%12||12}function jt(){return this.hours()||24}function Gt(t,e){q(t,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),e)})}function qt(t,e){return e._meridiemParse}function Zt(t){return"p"===(t+"").toLowerCase().charAt(0)}function Jt(t,e,n){return t>11?n?"pm":"PM":n?"am":"AM"}function Xt(t){return t?t.toLowerCase().replace("_","-"):t}function Kt(t){for(var e,n,i,a,o=0;o<t.length;){for(a=Xt(t[o]).split("-"),e=a.length,n=Xt(t[o+1]),n=n?n.split("-"):null;e>0;){if(i=Qt(a.slice(0,e).join("-")))return i;if(n&&n.length>=e&&S(a,n,!0)>=e-1)break;e--}o++}return null}function Qt(t){var i=null;if(!Ma[t]&&"undefined"!=typeof n&&n&&n.exports)try{i=ka._abbr,e("./locale/"+t),$t(i)}catch(a){}return Ma[t]}function $t(t,e){var n;return t&&(n=p(e)?ne(t):te(t,e),n&&(ka=n)),ka._abbr}function te(t,e){if(null!==e){var n=_a;return e.abbr=t,null!=Ma[t]?(M("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),n=Ma[t]._config):null!=e.parentLocale&&(null!=Ma[e.parentLocale]?n=Ma[e.parentLocale]._config:M("parentLocaleUndefined","specified parentLocale is not defined yet. See http://momentjs.com/guides/#/warnings/parent-locale/")),Ma[t]=new P(T(n,e)),$t(t),Ma[t]}return delete Ma[t],null}function ee(t,e){if(null!=e){var n,i=_a;null!=Ma[t]&&(i=Ma[t]._config),e=T(i,e),n=new P(e),n.parentLocale=Ma[t],Ma[t]=n,$t(t)}else null!=Ma[t]&&(null!=Ma[t].parentLocale?Ma[t]=Ma[t].parentLocale:null!=Ma[t]&&delete Ma[t]);return Ma[t]}function ne(t){var e;if(t&&t._locale&&t._locale._abbr&&(t=t._locale._abbr),!t)return ka;if(!a(t)){if(e=Qt(t))return e;t=[t]}return Kt(t)}function ie(){return xi(Ma)}function ae(t){var e,n=t._a;return n&&-2===f(t).overflow&&(e=n[ta]<0||n[ta]>11?ta:n[ea]<1||n[ea]>ot(n[$i],n[ta])?ea:n[na]<0||n[na]>24||24===n[na]&&(0!==n[ia]||0!==n[aa]||0!==n[oa])?na:n[ia]<0||n[ia]>59?ia:n[aa]<0||n[aa]>59?aa:n[oa]<0||n[oa]>999?oa:-1,f(t)._overflowDayOfYear&&($i>e||e>ea)&&(e=ea),f(t)._overflowWeeks&&-1===e&&(e=ra),f(t)._overflowWeekday&&-1===e&&(e=sa),f(t).overflow=e),t}function oe(t){var e,n,i,a,o,r,s=t._i,l=Da.exec(s)||Ca.exec(s);if(l){for(f(t).iso=!0,e=0,n=Pa.length;n>e;e++)if(Pa[e][1].exec(l[1])){a=Pa[e][0],i=Pa[e][2]!==!1;break}if(null==a)return void(t._isValid=!1);if(l[3]){for(e=0,n=Fa.length;n>e;e++)if(Fa[e][1].exec(l[3])){o=(l[2]||" ")+Fa[e][0];break}if(null==o)return void(t._isValid=!1)}if(!i&&null!=o)return void(t._isValid=!1);if(l[4]){if(!Ta.exec(l[4]))return void(t._isValid=!1);r="Z"}t._f=a+(o||"")+(r||""),ce(t)}else t._isValid=!1}function re(e){var n=Ia.exec(e._i);return null!==n?void(e._d=new Date(+n[1])):(oe(e),void(e._isValid===!1&&(delete e._isValid,t.createFromInputFallback(e))))}function se(t,e,n){return null!=t?t:null!=e?e:n}function le(e){var n=new Date(t.now());return e._useUTC?[n.getUTCFullYear(),n.getUTCMonth(),n.getUTCDate()]:[n.getFullYear(),n.getMonth(),n.getDate()]}function de(t){var e,n,i,a,o=[];if(!t._d){for(i=le(t),t._w&&null==t._a[ea]&&null==t._a[ta]&&ue(t),t._dayOfYear&&(a=se(t._a[$i],i[$i]),t._dayOfYear>pt(a)&&(f(t)._overflowDayOfYear=!0),n=xt(a,0,t._dayOfYear),t._a[ta]=n.getUTCMonth(),t._a[ea]=n.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=o[e]=i[e];for(;7>e;e++)t._a[e]=o[e]=null==t._a[e]?2===e?1:0:t._a[e];24===t._a[na]&&0===t._a[ia]&&0===t._a[aa]&&0===t._a[oa]&&(t._nextDay=!0,t._a[na]=0),t._d=(t._useUTC?xt:yt).apply(null,o),null!=t._tzm&&t._d.setUTCMinutes(t._d.getUTCMinutes()-t._tzm),t._nextDay&&(t._a[na]=24)}}function ue(t){var e,n,i,a,o,r,s,l;e=t._w,null!=e.GG||null!=e.W||null!=e.E?(o=1,r=4,n=se(e.GG,t._a[$i],wt(ye(),1,4).year),i=se(e.W,1),a=se(e.E,1),(1>a||a>7)&&(l=!0)):(o=t._locale._week.dow,r=t._locale._week.doy,n=se(e.gg,t._a[$i],wt(ye(),o,r).year),i=se(e.w,1),null!=e.d?(a=e.d,(0>a||a>6)&&(l=!0)):null!=e.e?(a=e.e+o,(e.e<0||e.e>6)&&(l=!0)):a=o),1>i||i>_t(n,o,r)?f(t)._overflowWeeks=!0:null!=l?f(t)._overflowWeekday=!0:(s=St(n,i,a,o,r),t._a[$i]=s.year,t._dayOfYear=s.dayOfYear)}function ce(e){if(e._f===t.ISO_8601)return void oe(e);e._a=[],f(e).empty=!0;var n,i,a,o,r,s=""+e._i,l=s.length,d=0;for(a=K(e._f,e._locale).match(Fi)||[],n=0;n<a.length;n++)o=a[n],i=(s.match($(o,e))||[])[0],i&&(r=s.substr(0,s.indexOf(i)),r.length>0&&f(e).unusedInput.push(r),s=s.slice(s.indexOf(i)+i.length),d+=i.length),Oi[o]?(i?f(e).empty=!1:f(e).unusedTokens.push(o),at(o,i,e)):e._strict&&!i&&f(e).unusedTokens.push(o);f(e).charsLeftOver=l-d,s.length>0&&f(e).unusedInput.push(s),e._a[na]<=12&&f(e).bigHour===!0&&e._a[na]>0&&(f(e).bigHour=void 0),f(e).parsedDateParts=e._a.slice(0),f(e).meridiem=e._meridiem,e._a[na]=he(e._locale,e._a[na],e._meridiem),de(e),ae(e)}function he(t,e,n){var i;return null==n?e:null!=t.meridiemHour?t.meridiemHour(e,n):null!=t.isPM?(i=t.isPM(n),i&&12>e&&(e+=12),i||12!==e||(e=0),e):e}function fe(t){var e,n,i,a,o;if(0===t._f.length)return f(t).invalidFormat=!0,void(t._d=new Date(NaN));for(a=0;a<t._f.length;a++)o=0,e=v({},t),null!=t._useUTC&&(e._useUTC=t._useUTC),e._f=t._f[a],ce(e),g(e)&&(o+=f(e).charsLeftOver,o+=10*f(e).unusedTokens.length,f(e).score=o,(null==i||i>o)&&(i=o,n=e));u(t,n||e)}function ge(t){if(!t._d){var e=B(t._i);t._a=l([e.year,e.month,e.day||e.date,e.hour,e.minute,e.second,e.millisecond],function(t){return t&&parseInt(t,10)}),de(t)}}function me(t){var e=new b(ae(pe(t)));return e._nextDay&&(e.add(1,"d"),e._nextDay=void 0),e}function pe(t){var e=t._i,n=t._f;return t._locale=t._locale||ne(t._l),null===e||void 0===n&&""===e?m({nullInput:!0}):("string"==typeof e&&(t._i=e=t._locale.preparse(e)),y(e)?new b(ae(e)):(a(n)?fe(t):s(e)?t._d=e:n?ce(t):ve(t),g(t)||(t._d=null),t))}function ve(e){var n=e._i;void 0===n?e._d=new Date(t.now()):s(n)?e._d=new Date(n.valueOf()):"string"==typeof n?re(e):a(n)?(e._a=l(n.slice(0),function(t){return parseInt(t,10)}),de(e)):"object"==typeof n?ge(e):"number"==typeof n?e._d=new Date(n):t.createFromInputFallback(e)}function be(t,e,n,i,s){var l={};return"boolean"==typeof n&&(i=n,n=void 0),(o(t)&&r(t)||a(t)&&0===t.length)&&(t=void 0),l._isAMomentObject=!0,l._useUTC=l._isUTC=s,l._l=n,l._i=t,l._f=e,l._strict=i,me(l)}function ye(t,e,n,i){return be(t,e,n,i,!1)}function xe(t,e){var n,i;if(1===e.length&&a(e[0])&&(e=e[0]),!e.length)return ye();for(n=e[0],i=1;i<e.length;++i)(!e[i].isValid()||e[i][t](n))&&(n=e[i]);return n}function ke(){var t=[].slice.call(arguments,0);return xe("isBefore",t)}function Se(){var t=[].slice.call(arguments,0);return xe("isAfter",t)}function we(t){var e=B(t),n=e.year||0,i=e.quarter||0,a=e.month||0,o=e.week||0,r=e.day||0,s=e.hour||0,l=e.minute||0,d=e.second||0,u=e.millisecond||0;this._milliseconds=+u+1e3*d+6e4*l+1e3*s*60*60,this._days=+r+7*o,this._months=+a+3*i+12*n,this._data={},this._locale=ne(),this._bubble()}function _e(t){return t instanceof we}function Me(t){return 0>t?-1*Math.round(-1*t):Math.round(t)}function De(t,e){q(t,0,0,function(){var t=this.utcOffset(),n="+";return 0>t&&(t=-t,n="-"),n+G(~~(t/60),2)+e+G(~~t%60,2)})}function Ce(t,e){var n=(e||"").match(t)||[],i=n[n.length-1]||[],a=(i+"").match(Wa)||["-",0,0],o=+(60*a[1])+k(a[2]);return"+"===a[0]?o:-o}function Te(e,n){var i,a;return n._isUTC?(i=n.clone(),a=(y(e)||s(e)?e.valueOf():ye(e).valueOf())-i.valueOf(),i._d.setTime(i._d.valueOf()+a),t.updateOffset(i,!1),i):ye(e).local()}function Pe(t){return 15*-Math.round(t._d.getTimezoneOffset()/15)}function Fe(e,n){var i,a=this._offset||0;return this.isValid()?null!=e?("string"==typeof e?e=Ce(Zi,e):Math.abs(e)<16&&(e=60*e),!this._isUTC&&n&&(i=Pe(this)),this._offset=e,this._isUTC=!0,null!=i&&this.add(i,"m"),a!==e&&(!n||this._changeInProgress?Ge(this,He(e-a,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,t.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?a:Pe(this):null!=e?this:NaN}function Ie(t,e){return null!=t?("string"!=typeof t&&(t=-t),this.utcOffset(t,e),this):-this.utcOffset()}function Ae(t){return this.utcOffset(0,t)}function Oe(t){return this._isUTC&&(this.utcOffset(0,t),this._isUTC=!1,t&&this.subtract(Pe(this),"m")),this}function Re(){if(this._tzm)this.utcOffset(this._tzm);else if("string"==typeof this._i){var t=Ce(qi,this._i);0===t?this.utcOffset(0,!0):this.utcOffset(Ce(qi,this._i))}return this}function We(t){return this.isValid()?(t=t?ye(t).utcOffset():0,(this.utcOffset()-t)%60===0):!1}function Le(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Ve(){if(!p(this._isDSTShifted))return this._isDSTShifted;var t={};if(v(t,this),t=pe(t),t._a){var e=t._isUTC?c(t._a):ye(t._a);this._isDSTShifted=this.isValid()&&S(t._a,e.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Be(){return this.isValid()?!this._isUTC:!1}function Ye(){return this.isValid()?this._isUTC:!1}function ze(){return this.isValid()?this._isUTC&&0===this._offset:!1}function He(t,e){var n,i,a,o=t,r=null;return _e(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(r=La.exec(t))?(n="-"===r[1]?-1:1,o={y:0,d:k(r[ea])*n,h:k(r[na])*n,m:k(r[ia])*n,s:k(r[aa])*n,ms:k(Me(1e3*r[oa]))*n}):(r=Va.exec(t))?(n="-"===r[1]?-1:1,o={y:Ne(r[2],n),M:Ne(r[3],n),w:Ne(r[4],n),d:Ne(r[5],n),h:Ne(r[6],n),m:Ne(r[7],n),s:Ne(r[8],n)}):null==o?o={}:"object"==typeof o&&("from"in o||"to"in o)&&(a=Ue(ye(o.from),ye(o.to)),o={},o.ms=a.milliseconds,o.M=a.months),i=new we(o),_e(t)&&d(t,"_locale")&&(i._locale=t._locale),i}function Ne(t,e){var n=t&&parseFloat(t.replace(",","."));return(isNaN(n)?0:n)*e}function Ee(t,e){var n={milliseconds:0,months:0};return n.months=e.month()-t.month()+12*(e.year()-t.year()),t.clone().add(n.months,"M").isAfter(e)&&--n.months,n.milliseconds=+e-+t.clone().add(n.months,"M"),n}function Ue(t,e){var n;return t.isValid()&&e.isValid()?(e=Te(e,t),t.isBefore(e)?n=Ee(t,e):(n=Ee(e,t),n.milliseconds=-n.milliseconds,n.months=-n.months),n):{milliseconds:0,months:0}}function je(t,e){return function(n,i){var a,o;return null===i||isNaN(+i)||(M(e,"moment()."+e+"(period, number) is deprecated. Please use moment()."+e+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),o=n,n=i,i=o),n="string"==typeof n?+n:n,a=He(n,i),Ge(this,a,t),this}}function Ge(e,n,i,a){var o=n._milliseconds,r=Me(n._days),s=Me(n._months);e.isValid()&&(a=null==a?!0:a,o&&e._d.setTime(e._d.valueOf()+o*i),r&&E(e,"Date",N(e,"Date")+r*i),s&&ut(e,N(e,"Month")+s*i),a&&t.updateOffset(e,r||s))}function qe(t,e){var n=t.diff(e,"days",!0);return-6>n?"sameElse":-1>n?"lastWeek":0>n?"lastDay":1>n?"sameDay":2>n?"nextDay":7>n?"nextWeek":"sameElse"}function Ze(e,n){var i=e||ye(),a=Te(i,this).startOf("day"),o=t.calendarFormat(this,a)||"sameElse",r=n&&(D(n[o])?n[o].call(this,i):n[o]);return this.format(r||this.localeData().calendar(o,this,ye(i)))}function Je(){return new b(this)}function Xe(t,e){var n=y(t)?t:ye(t);return this.isValid()&&n.isValid()?(e=V(p(e)?"millisecond":e),"millisecond"===e?this.valueOf()>n.valueOf():n.valueOf()<this.clone().startOf(e).valueOf()):!1}function Ke(t,e){var n=y(t)?t:ye(t);return this.isValid()&&n.isValid()?(e=V(p(e)?"millisecond":e),"millisecond"===e?this.valueOf()<n.valueOf():this.clone().endOf(e).valueOf()<n.valueOf()):!1}function Qe(t,e,n,i){return i=i||"()",("("===i[0]?this.isAfter(t,n):!this.isBefore(t,n))&&(")"===i[1]?this.isBefore(e,n):!this.isAfter(e,n))}function $e(t,e){var n,i=y(t)?t:ye(t);return this.isValid()&&i.isValid()?(e=V(e||"millisecond"),"millisecond"===e?this.valueOf()===i.valueOf():(n=i.valueOf(),this.clone().startOf(e).valueOf()<=n&&n<=this.clone().endOf(e).valueOf())):!1}function tn(t,e){return this.isSame(t,e)||this.isAfter(t,e)}function en(t,e){return this.isSame(t,e)||this.isBefore(t,e)}function nn(t,e,n){var i,a,o,r;return this.isValid()?(i=Te(t,this),i.isValid()?(a=6e4*(i.utcOffset()-this.utcOffset()),e=V(e),"year"===e||"month"===e||"quarter"===e?(r=an(this,i),"quarter"===e?r/=3:"year"===e&&(r/=12)):(o=this-i,r="second"===e?o/1e3:"minute"===e?o/6e4:"hour"===e?o/36e5:"day"===e?(o-a)/864e5:"week"===e?(o-a)/6048e5:o),n?r:x(r)):NaN):NaN}function an(t,e){var n,i,a=12*(e.year()-t.year())+(e.month()-t.month()),o=t.clone().add(a,"months");return 0>e-o?(n=t.clone().add(a-1,"months"),i=(e-o)/(o-n)):(n=t.clone().add(a+1,"months"),i=(e-o)/(n-o)),-(a+i)||0}function on(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function rn(){var t=this.clone().utc();return 0<t.year()&&t.year()<=9999?D(Date.prototype.toISOString)?this.toDate().toISOString():X(t,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):X(t,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]")}function sn(e){e||(e=this.isUtc()?t.defaultFormatUtc:t.defaultFormat);var n=X(this,e);return this.localeData().postformat(n)}function ln(t,e){return this.isValid()&&(y(t)&&t.isValid()||ye(t).isValid())?He({to:this,from:t}).locale(this.locale()).humanize(!e):this.localeData().invalidDate()}function dn(t){return this.from(ye(),t)}function un(t,e){return this.isValid()&&(y(t)&&t.isValid()||ye(t).isValid())?He({from:this,to:t}).locale(this.locale()).humanize(!e):this.localeData().invalidDate()}function cn(t){return this.to(ye(),t)}function hn(t){var e;return void 0===t?this._locale._abbr:(e=ne(t),null!=e&&(this._locale=e),this)}function fn(){return this._locale}function gn(t){switch(t=V(t)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":case"date":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===t&&this.weekday(0),"isoWeek"===t&&this.isoWeekday(1),"quarter"===t&&this.month(3*Math.floor(this.month()/3)),this}function mn(t){return t=V(t),void 0===t||"millisecond"===t?this:("date"===t&&(t="day"),this.startOf(t).add(1,"isoWeek"===t?"week":t).subtract(1,"ms"))}function pn(){return this._d.valueOf()-6e4*(this._offset||0)}function vn(){return Math.floor(this.valueOf()/1e3)}function bn(){return new Date(this.valueOf())}function yn(){var t=this;return[t.year(),t.month(),t.date(),t.hour(),t.minute(),t.second(),t.millisecond()]}function xn(){var t=this;return{years:t.year(),months:t.month(),date:t.date(),hours:t.hours(),minutes:t.minutes(),seconds:t.seconds(),milliseconds:t.milliseconds()}}function kn(){return this.isValid()?this.toISOString():null}function Sn(){return g(this)}function wn(){return u({},f(this))}function _n(){return f(this).overflow}function Mn(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function Dn(t,e){q(0,[t,t.length],0,e)}function Cn(t){return In.call(this,t,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)}function Tn(t){return In.call(this,t,this.isoWeek(),this.isoWeekday(),1,4)}function Pn(){return _t(this.year(),1,4)}function Fn(){var t=this.localeData()._week;return _t(this.year(),t.dow,t.doy)}function In(t,e,n,i,a){var o;return null==t?wt(this,i,a).year:(o=_t(t,i,a),e>o&&(e=o),An.call(this,t,e,n,i,a))}function An(t,e,n,i,a){var o=St(t,e,n,i,a),r=xt(o.year,0,o.dayOfYear);return this.year(r.getUTCFullYear()),this.month(r.getUTCMonth()),this.date(r.getUTCDate()),this}function On(t){return null==t?Math.ceil((this.month()+1)/3):this.month(3*(t-1)+this.month()%3)}function Rn(t){var e=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==t?e:this.add(t-e,"d")}function Wn(t,e){e[oa]=k(1e3*("0."+t))}function Ln(){return this._isUTC?"UTC":""}function Vn(){return this._isUTC?"Coordinated Universal Time":""}function Bn(t){return ye(1e3*t)}function Yn(){return ye.apply(null,arguments).parseZone()}function zn(t){return t}function Hn(t,e,n,i){var a=ne(),o=c().set(i,e);return a[n](o,t)}function Nn(t,e,n){if("number"==typeof t&&(e=t,t=void 0),t=t||"",null!=e)return Hn(t,e,n,"month");var i,a=[];for(i=0;12>i;i++)a[i]=Hn(t,i,n,"month");return a}function En(t,e,n,i){"boolean"==typeof t?("number"==typeof e&&(n=e,e=void 0),e=e||""):(e=t,n=e,t=!1,"number"==typeof e&&(n=e,e=void 0),e=e||"");var a=ne(),o=t?a._week.dow:0;if(null!=n)return Hn(e,(n+o)%7,i,"day");var r,s=[];for(r=0;7>r;r++)s[r]=Hn(e,(r+o)%7,i,"day");return s}function Un(t,e){return Nn(t,e,"months")}function jn(t,e){return Nn(t,e,"monthsShort")}function Gn(t,e,n){return En(t,e,n,"weekdays")}function qn(t,e,n){return En(t,e,n,"weekdaysShort")}function Zn(t,e,n){return En(t,e,n,"weekdaysMin")}function Jn(){var t=this._data;return this._milliseconds=Ja(this._milliseconds),this._days=Ja(this._days),this._months=Ja(this._months),t.milliseconds=Ja(t.milliseconds),t.seconds=Ja(t.seconds),t.minutes=Ja(t.minutes),t.hours=Ja(t.hours),t.months=Ja(t.months),t.years=Ja(t.years),this}function Xn(t,e,n,i){var a=He(e,n);return t._milliseconds+=i*a._milliseconds,t._days+=i*a._days,t._months+=i*a._months,t._bubble()}function Kn(t,e){return Xn(this,t,e,1)}function Qn(t,e){return Xn(this,t,e,-1)}function $n(t){return 0>t?Math.floor(t):Math.ceil(t)}function ti(){var t,e,n,i,a,o=this._milliseconds,r=this._days,s=this._months,l=this._data;return o>=0&&r>=0&&s>=0||0>=o&&0>=r&&0>=s||(o+=864e5*$n(ni(s)+r),r=0,s=0),l.milliseconds=o%1e3,t=x(o/1e3),l.seconds=t%60,e=x(t/60),l.minutes=e%60,n=x(e/60),l.hours=n%24,r+=x(n/24),a=x(ei(r)),s+=a,r-=$n(ni(a)),i=x(s/12),s%=12,l.days=r,l.months=s,l.years=i,this}function ei(t){return 4800*t/146097}function ni(t){return 146097*t/4800}function ii(t){var e,n,i=this._milliseconds;if(t=V(t),"month"===t||"year"===t)return e=this._days+i/864e5,n=this._months+ei(e),"month"===t?n:n/12;switch(e=this._days+Math.round(ni(this._months)),t){case"week":return e/7+i/6048e5;case"day":return e+i/864e5;case"hour":return 24*e+i/36e5;case"minute":return 1440*e+i/6e4;case"second":return 86400*e+i/1e3;case"millisecond":return Math.floor(864e5*e)+i;default:throw new Error("Unknown unit "+t)}}function ai(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*k(this._months/12)}function oi(t){return function(){return this.as(t)}}function ri(t){return t=V(t),this[t+"s"]()}function si(t){return function(){return this._data[t]}}function li(){return x(this.days()/7)}function di(t,e,n,i,a){return a.relativeTime(e||1,!!n,t,i)}function ui(t,e,n){var i=He(t).abs(),a=ho(i.as("s")),o=ho(i.as("m")),r=ho(i.as("h")),s=ho(i.as("d")),l=ho(i.as("M")),d=ho(i.as("y")),u=a<fo.s&&["s",a]||1>=o&&["m"]||o<fo.m&&["mm",o]||1>=r&&["h"]||r<fo.h&&["hh",r]||1>=s&&["d"]||s<fo.d&&["dd",s]||1>=l&&["M"]||l<fo.M&&["MM",l]||1>=d&&["y"]||["yy",d];return u[2]=e,u[3]=+t>0,u[4]=n,di.apply(null,u)}function ci(t){return void 0===t?ho:"function"==typeof t?(ho=t,!0):!1}function hi(t,e){return void 0===fo[t]?!1:void 0===e?fo[t]:(fo[t]=e,!0)}function fi(t){var e=this.localeData(),n=ui(this,!t,e);return t&&(n=e.pastFuture(+this,n)),e.postformat(n)}function gi(){var t,e,n,i=go(this._milliseconds)/1e3,a=go(this._days),o=go(this._months);t=x(i/60),e=x(t/60),i%=60,t%=60,n=x(o/12),o%=12;var r=n,s=o,l=a,d=e,u=t,c=i,h=this.asSeconds();return h?(0>h?"-":"")+"P"+(r?r+"Y":"")+(s?s+"M":"")+(l?l+"D":"")+(d||u||c?"T":"")+(d?d+"H":"")+(u?u+"M":"")+(c?c+"S":""):"P0D"}var mi,pi;pi=Array.prototype.some?Array.prototype.some:function(t){for(var e=Object(this),n=e.length>>>0,i=0;n>i;i++)if(i in e&&t.call(this,e[i],i,e))return!0;return!1};var vi=t.momentProperties=[],bi=!1,yi={};t.suppressDeprecationWarnings=!1,t.deprecationHandler=null;var xi;xi=Object.keys?Object.keys:function(t){var e,n=[];for(e in t)d(t,e)&&n.push(e);return n};var ki,Si={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},wi={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},_i="Invalid date",Mi="%d",Di=/\d{1,2}/,Ci={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},Ti={},Pi={},Fi=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,Ii=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Ai={},Oi={},Ri=/\d/,Wi=/\d\d/,Li=/\d{3}/,Vi=/\d{4}/,Bi=/[+-]?\d{6}/,Yi=/\d\d?/,zi=/\d\d\d\d?/,Hi=/\d\d\d\d\d\d?/,Ni=/\d{1,3}/,Ei=/\d{1,4}/,Ui=/[+-]?\d{1,6}/,ji=/\d+/,Gi=/[+-]?\d+/,qi=/Z|[+-]\d\d:?\d\d/gi,Zi=/Z|[+-]\d\d(?::?\d\d)?/gi,Ji=/[+-]?\d+(\.\d{1,3})?/,Xi=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Ki={},Qi={},$i=0,ta=1,ea=2,na=3,ia=4,aa=5,oa=6,ra=7,sa=8;ki=Array.prototype.indexOf?Array.prototype.indexOf:function(t){var e;for(e=0;e<this.length;++e)if(this[e]===t)return e;return-1},q("M",["MM",2],"Mo",function(){return this.month()+1}),q("MMM",0,0,function(t){return this.localeData().monthsShort(this,t)}),q("MMMM",0,0,function(t){return this.localeData().months(this,t)}),L("month","M"),Y("month",8),Q("M",Yi),Q("MM",Yi,Wi),Q("MMM",function(t,e){return e.monthsShortRegex(t)}),Q("MMMM",function(t,e){return e.monthsRegex(t)}),nt(["M","MM"],function(t,e){e[ta]=k(t)-1}),nt(["MMM","MMMM"],function(t,e,n,i){var a=n._locale.monthsParse(t,i,n._strict);null!=a?e[ta]=a:f(n).invalidMonth=t});var la=/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/,da="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ua="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),ca=Xi,ha=Xi;q("Y",0,0,function(){var t=this.year();return 9999>=t?""+t:"+"+t}),q(0,["YY",2],0,function(){return this.year()%100}),q(0,["YYYY",4],0,"year"),q(0,["YYYYY",5],0,"year"),q(0,["YYYYYY",6,!0],0,"year"),L("year","y"),Y("year",1),Q("Y",Gi),Q("YY",Yi,Wi),Q("YYYY",Ei,Vi),Q("YYYYY",Ui,Bi),Q("YYYYYY",Ui,Bi),nt(["YYYYY","YYYYYY"],$i),nt("YYYY",function(e,n){n[$i]=2===e.length?t.parseTwoDigitYear(e):k(e)}),nt("YY",function(e,n){n[$i]=t.parseTwoDigitYear(e)}),nt("Y",function(t,e){e[$i]=parseInt(t,10)}),t.parseTwoDigitYear=function(t){return k(t)+(k(t)>68?1900:2e3)};var fa=H("FullYear",!0);q("w",["ww",2],"wo","week"),q("W",["WW",2],"Wo","isoWeek"),L("week","w"),L("isoWeek","W"),Y("week",5),Y("isoWeek",5),Q("w",Yi),Q("ww",Yi,Wi),Q("W",Yi),Q("WW",Yi,Wi),it(["w","ww","W","WW"],function(t,e,n,i){e[i.substr(0,1)]=k(t)});var ga={dow:0,doy:6};q("d",0,"do","day"),q("dd",0,0,function(t){return this.localeData().weekdaysMin(this,t)}),q("ddd",0,0,function(t){return this.localeData().weekdaysShort(this,t)}),q("dddd",0,0,function(t){return this.localeData().weekdays(this,t)}),q("e",0,0,"weekday"),q("E",0,0,"isoWeekday"),L("day","d"),L("weekday","e"),L("isoWeekday","E"),Y("day",11),Y("weekday",11),Y("isoWeekday",11),Q("d",Yi),Q("e",Yi),Q("E",Yi),Q("dd",function(t,e){return e.weekdaysMinRegex(t)}),Q("ddd",function(t,e){return e.weekdaysShortRegex(t)}),Q("dddd",function(t,e){return e.weekdaysRegex(t)}),it(["dd","ddd","dddd"],function(t,e,n,i){var a=n._locale.weekdaysParse(t,i,n._strict);null!=a?e.d=a:f(n).invalidWeekday=t}),it(["d","e","E"],function(t,e,n,i){e[i]=k(t)});var ma="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),pa="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),va="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),ba=Xi,ya=Xi,xa=Xi;q("H",["HH",2],0,"hour"),q("h",["hh",2],0,Ut),q("k",["kk",2],0,jt),q("hmm",0,0,function(){return""+Ut.apply(this)+G(this.minutes(),2)}),q("hmmss",0,0,function(){return""+Ut.apply(this)+G(this.minutes(),2)+G(this.seconds(),2)}),q("Hmm",0,0,function(){return""+this.hours()+G(this.minutes(),2)}),q("Hmmss",0,0,function(){return""+this.hours()+G(this.minutes(),2)+G(this.seconds(),2)}),Gt("a",!0),Gt("A",!1),L("hour","h"),Y("hour",13),Q("a",qt),Q("A",qt),Q("H",Yi),Q("h",Yi),Q("HH",Yi,Wi),Q("hh",Yi,Wi),Q("hmm",zi),Q("hmmss",Hi),Q("Hmm",zi),Q("Hmmss",Hi),nt(["H","HH"],na),nt(["a","A"],function(t,e,n){n._isPm=n._locale.isPM(t),n._meridiem=t}),nt(["h","hh"],function(t,e,n){e[na]=k(t),f(n).bigHour=!0}),nt("hmm",function(t,e,n){var i=t.length-2;e[na]=k(t.substr(0,i)),e[ia]=k(t.substr(i)),f(n).bigHour=!0}),nt("hmmss",function(t,e,n){var i=t.length-4,a=t.length-2;e[na]=k(t.substr(0,i)),e[ia]=k(t.substr(i,2)),e[aa]=k(t.substr(a)),f(n).bigHour=!0}),nt("Hmm",function(t,e,n){var i=t.length-2;e[na]=k(t.substr(0,i)),e[ia]=k(t.substr(i))}),nt("Hmmss",function(t,e,n){var i=t.length-4,a=t.length-2;e[na]=k(t.substr(0,i)),e[ia]=k(t.substr(i,2)),e[aa]=k(t.substr(a))});var ka,Sa=/[ap]\.?m?\.?/i,wa=H("Hours",!0),_a={calendar:Si,longDateFormat:wi,invalidDate:_i,ordinal:Mi,ordinalParse:Di,relativeTime:Ci,months:da,monthsShort:ua,week:ga,weekdays:ma,weekdaysMin:va,weekdaysShort:pa,meridiemParse:Sa},Ma={},Da=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/,Ca=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/,Ta=/Z|[+-]\d\d(?::?\d\d)?/,Pa=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],Fa=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Ia=/^\/?Date\((\-?\d+)/i;
-t.createFromInputFallback=_("value provided is not in a recognized ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(t){t._d=new Date(t._i+(t._useUTC?" UTC":""))}),t.ISO_8601=function(){};var Aa=_("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var t=ye.apply(null,arguments);return this.isValid()&&t.isValid()?this>t?this:t:m()}),Oa=_("moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var t=ye.apply(null,arguments);return this.isValid()&&t.isValid()?t>this?this:t:m()}),Ra=function(){return Date.now?Date.now():+new Date};De("Z",":"),De("ZZ",""),Q("Z",Zi),Q("ZZ",Zi),nt(["Z","ZZ"],function(t,e,n){n._useUTC=!0,n._tzm=Ce(Zi,t)});var Wa=/([\+\-]|\d\d)/gi;t.updateOffset=function(){};var La=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,Va=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;He.fn=we.prototype;var Ba=je(1,"add"),Ya=je(-1,"subtract");t.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",t.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var za=_("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(t){return void 0===t?this.localeData():this.locale(t)});q(0,["gg",2],0,function(){return this.weekYear()%100}),q(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Dn("gggg","weekYear"),Dn("ggggg","weekYear"),Dn("GGGG","isoWeekYear"),Dn("GGGGG","isoWeekYear"),L("weekYear","gg"),L("isoWeekYear","GG"),Y("weekYear",1),Y("isoWeekYear",1),Q("G",Gi),Q("g",Gi),Q("GG",Yi,Wi),Q("gg",Yi,Wi),Q("GGGG",Ei,Vi),Q("gggg",Ei,Vi),Q("GGGGG",Ui,Bi),Q("ggggg",Ui,Bi),it(["gggg","ggggg","GGGG","GGGGG"],function(t,e,n,i){e[i.substr(0,2)]=k(t)}),it(["gg","GG"],function(e,n,i,a){n[a]=t.parseTwoDigitYear(e)}),q("Q",0,"Qo","quarter"),L("quarter","Q"),Y("quarter",7),Q("Q",Ri),nt("Q",function(t,e){e[ta]=3*(k(t)-1)}),q("D",["DD",2],"Do","date"),L("date","D"),Y("date",9),Q("D",Yi),Q("DD",Yi,Wi),Q("Do",function(t,e){return t?e._ordinalParse:e._ordinalParseLenient}),nt(["D","DD"],ea),nt("Do",function(t,e){e[ea]=k(t.match(Yi)[0],10)});var Ha=H("Date",!0);q("DDD",["DDDD",3],"DDDo","dayOfYear"),L("dayOfYear","DDD"),Y("dayOfYear",4),Q("DDD",Ni),Q("DDDD",Li),nt(["DDD","DDDD"],function(t,e,n){n._dayOfYear=k(t)}),q("m",["mm",2],0,"minute"),L("minute","m"),Y("minute",14),Q("m",Yi),Q("mm",Yi,Wi),nt(["m","mm"],ia);var Na=H("Minutes",!1);q("s",["ss",2],0,"second"),L("second","s"),Y("second",15),Q("s",Yi),Q("ss",Yi,Wi),nt(["s","ss"],aa);var Ea=H("Seconds",!1);q("S",0,0,function(){return~~(this.millisecond()/100)}),q(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),q(0,["SSS",3],0,"millisecond"),q(0,["SSSS",4],0,function(){return 10*this.millisecond()}),q(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),q(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),q(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),q(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),q(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),L("millisecond","ms"),Y("millisecond",16),Q("S",Ni,Ri),Q("SS",Ni,Wi),Q("SSS",Ni,Li);var Ua;for(Ua="SSSS";Ua.length<=9;Ua+="S")Q(Ua,ji);for(Ua="S";Ua.length<=9;Ua+="S")nt(Ua,Wn);var ja=H("Milliseconds",!1);q("z",0,0,"zoneAbbr"),q("zz",0,0,"zoneName");var Ga=b.prototype;Ga.add=Ba,Ga.calendar=Ze,Ga.clone=Je,Ga.diff=nn,Ga.endOf=mn,Ga.format=sn,Ga.from=ln,Ga.fromNow=dn,Ga.to=un,Ga.toNow=cn,Ga.get=U,Ga.invalidAt=_n,Ga.isAfter=Xe,Ga.isBefore=Ke,Ga.isBetween=Qe,Ga.isSame=$e,Ga.isSameOrAfter=tn,Ga.isSameOrBefore=en,Ga.isValid=Sn,Ga.lang=za,Ga.locale=hn,Ga.localeData=fn,Ga.max=Oa,Ga.min=Aa,Ga.parsingFlags=wn,Ga.set=j,Ga.startOf=gn,Ga.subtract=Ya,Ga.toArray=yn,Ga.toObject=xn,Ga.toDate=bn,Ga.toISOString=rn,Ga.toJSON=kn,Ga.toString=on,Ga.unix=vn,Ga.valueOf=pn,Ga.creationData=Mn,Ga.year=fa,Ga.isLeapYear=bt,Ga.weekYear=Cn,Ga.isoWeekYear=Tn,Ga.quarter=Ga.quarters=On,Ga.month=ct,Ga.daysInMonth=ht,Ga.week=Ga.weeks=Tt,Ga.isoWeek=Ga.isoWeeks=Pt,Ga.weeksInYear=Fn,Ga.isoWeeksInYear=Pn,Ga.date=Ha,Ga.day=Ga.days=Vt,Ga.weekday=Bt,Ga.isoWeekday=Yt,Ga.dayOfYear=Rn,Ga.hour=Ga.hours=wa,Ga.minute=Ga.minutes=Na,Ga.second=Ga.seconds=Ea,Ga.millisecond=Ga.milliseconds=ja,Ga.utcOffset=Fe,Ga.utc=Ae,Ga.local=Oe,Ga.parseZone=Re,Ga.hasAlignedHourOffset=We,Ga.isDST=Le,Ga.isLocal=Be,Ga.isUtcOffset=Ye,Ga.isUtc=ze,Ga.isUTC=ze,Ga.zoneAbbr=Ln,Ga.zoneName=Vn,Ga.dates=_("dates accessor is deprecated. Use date instead.",Ha),Ga.months=_("months accessor is deprecated. Use month instead",ct),Ga.years=_("years accessor is deprecated. Use year instead",fa),Ga.zone=_("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",Ie),Ga.isDSTShifted=_("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",Ve);var qa=Ga,Za=P.prototype;Za.calendar=F,Za.longDateFormat=I,Za.invalidDate=A,Za.ordinal=O,Za.preparse=zn,Za.postformat=zn,Za.relativeTime=R,Za.pastFuture=W,Za.set=C,Za.months=rt,Za.monthsShort=st,Za.monthsParse=dt,Za.monthsRegex=gt,Za.monthsShortRegex=ft,Za.week=Mt,Za.firstDayOfYear=Ct,Za.firstDayOfWeek=Dt,Za.weekdays=At,Za.weekdaysMin=Rt,Za.weekdaysShort=Ot,Za.weekdaysParse=Lt,Za.weekdaysRegex=zt,Za.weekdaysShortRegex=Ht,Za.weekdaysMinRegex=Nt,Za.isPM=Zt,Za.meridiem=Jt,$t("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(t){var e=t%10,n=1===k(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+n}}),t.lang=_("moment.lang is deprecated. Use moment.locale instead.",$t),t.langData=_("moment.langData is deprecated. Use moment.localeData instead.",ne);var Ja=Math.abs,Xa=oi("ms"),Ka=oi("s"),Qa=oi("m"),$a=oi("h"),to=oi("d"),eo=oi("w"),no=oi("M"),io=oi("y"),ao=si("milliseconds"),oo=si("seconds"),ro=si("minutes"),so=si("hours"),lo=si("days"),uo=si("months"),co=si("years"),ho=Math.round,fo={s:45,m:45,h:22,d:26,M:11},go=Math.abs,mo=we.prototype;mo.abs=Jn,mo.add=Kn,mo.subtract=Qn,mo.as=ii,mo.asMilliseconds=Xa,mo.asSeconds=Ka,mo.asMinutes=Qa,mo.asHours=$a,mo.asDays=to,mo.asWeeks=eo,mo.asMonths=no,mo.asYears=io,mo.valueOf=ai,mo._bubble=ti,mo.get=ri,mo.milliseconds=ao,mo.seconds=oo,mo.minutes=ro,mo.hours=so,mo.days=lo,mo.weeks=li,mo.months=uo,mo.years=co,mo.humanize=fi,mo.toISOString=gi,mo.toString=gi,mo.toJSON=gi,mo.locale=hn,mo.localeData=fn,mo.toIsoString=_("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",gi),mo.lang=za,q("X",0,0,"unix"),q("x",0,0,"valueOf"),Q("x",Gi),Q("X",Ji),nt("X",function(t,e,n){n._d=new Date(1e3*parseFloat(t,10))}),nt("x",function(t,e,n){n._d=new Date(k(t))}),t.version="2.15.1",i(ye),t.fn=qa,t.min=ke,t.max=Se,t.now=Ra,t.utc=c,t.unix=Bn,t.months=Un,t.isDate=s,t.locale=$t,t.invalid=m,t.duration=He,t.isMoment=y,t.weekdays=Gn,t.parseZone=Yn,t.localeData=ne,t.isDuration=_e,t.monthsShort=jn,t.weekdaysMin=Zn,t.defineLocale=te,t.updateLocale=ee,t.locales=ie,t.weekdaysShort=qn,t.normalizeUnits=V,t.relativeTimeRounding=ci,t.relativeTimeThreshold=hi,t.calendarFormat=qe,t.prototype=qa;var po=t;return po})},{}],7:[function(t,e,n){var i=t(27)();t(26)(i),t(22)(i),t(25)(i),t(21)(i),t(23)(i),t(24)(i),t(28)(i),t(32)(i),t(30)(i),t(31)(i),t(33)(i),t(29)(i),t(34)(i),t(35)(i),t(36)(i),t(37)(i),t(38)(i),t(41)(i),t(39)(i),t(40)(i),t(42)(i),t(43)(i),t(44)(i),t(15)(i),t(16)(i),t(17)(i),t(18)(i),t(19)(i),t(20)(i),t(8)(i),t(9)(i),t(10)(i),t(11)(i),t(12)(i),t(13)(i),t(14)(i),window.Chart=e.exports=i},{10:10,11:11,12:12,13:13,14:14,15:15,16:16,17:17,18:18,19:19,20:20,21:21,22:22,23:23,24:24,25:25,26:26,27:27,28:28,29:29,30:30,31:31,32:32,33:33,34:34,35:35,36:36,37:37,38:38,39:39,40:40,41:41,42:42,43:43,44:44,8:8,9:9}],8:[function(t,e,n){"use strict";e.exports=function(t){t.Bar=function(e,n){return n.type="bar",new t(e,n)}}},{}],9:[function(t,e,n){"use strict";e.exports=function(t){t.Bubble=function(e,n){return n.type="bubble",new t(e,n)}}},{}],10:[function(t,e,n){"use strict";e.exports=function(t){t.Doughnut=function(e,n){return n.type="doughnut",new t(e,n)}}},{}],11:[function(t,e,n){"use strict";e.exports=function(t){t.Line=function(e,n){return n.type="line",new t(e,n)}}},{}],12:[function(t,e,n){"use strict";e.exports=function(t){t.PolarArea=function(e,n){return n.type="polarArea",new t(e,n)}}},{}],13:[function(t,e,n){"use strict";e.exports=function(t){t.Radar=function(e,n){return n.options=t.helpers.configMerge({aspectRatio:1},n.options),n.type="radar",new t(e,n)}}},{}],14:[function(t,e,n){"use strict";e.exports=function(t){var e={hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-1"}],yAxes:[{type:"linear",position:"left",id:"y-axis-1"}]},tooltips:{callbacks:{title:function(){return""},label:function(t){return"("+t.xLabel+", "+t.yLabel+")"}}}};t.defaults.scatter=e,t.controllers.scatter=t.controllers.line,t.Scatter=function(e,n){return n.type="scatter",new t(e,n)}}},{}],15:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.bar={hover:{mode:"label"},scales:{xAxes:[{type:"category",categoryPercentage:.8,barPercentage:.9,gridLines:{offsetGridLines:!0}}],yAxes:[{type:"linear"}]}},t.controllers.bar=t.DatasetController.extend({dataElementType:t.elements.Rectangle,initialize:function(e,n){t.DatasetController.prototype.initialize.call(this,e,n),this.getMeta().bar=!0},getBarCount:function(){var t=this,n=0;return e.each(t.chart.data.datasets,function(e,i){var a=t.chart.getDatasetMeta(i);a.bar&&t.chart.isDatasetVisible(i)&&++n},t),n},update:function(t){var n=this;e.each(n.getMeta().data,function(e,i){n.updateElement(e,i,t)},n)},updateElement:function(t,n,i){var a=this,o=a.getMeta(),r=a.getScaleForId(o.xAxisID),s=a.getScaleForId(o.yAxisID),l=s.getBasePixel(),d=a.chart.options.elements.rectangle,u=t.custom||{},c=a.getDataset();e.extend(t,{_xScale:r,_yScale:s,_datasetIndex:a.index,_index:n,_model:{x:a.calculateBarX(n,a.index),y:i?l:a.calculateBarY(n,a.index),label:a.chart.data.labels[n],datasetLabel:c.label,base:i?l:a.calculateBarBase(a.index,n),width:a.calculateBarWidth(n),backgroundColor:u.backgroundColor?u.backgroundColor:e.getValueAtIndexOrDefault(c.backgroundColor,n,d.backgroundColor),borderSkipped:u.borderSkipped?u.borderSkipped:d.borderSkipped,borderColor:u.borderColor?u.borderColor:e.getValueAtIndexOrDefault(c.borderColor,n,d.borderColor),borderWidth:u.borderWidth?u.borderWidth:e.getValueAtIndexOrDefault(c.borderWidth,n,d.borderWidth)}}),t.pivot()},calculateBarBase:function(t,e){var n=this,i=n.getMeta(),a=n.getScaleForId(i.yAxisID),o=0;if(a.options.stacked){for(var r=n.chart,s=r.data.datasets,l=Number(s[t].data[e]),d=0;t>d;d++){var u=s[d],c=r.getDatasetMeta(d);if(c.bar&&c.yAxisID===a.id&&r.isDatasetVisible(d)){var h=Number(u.data[e]);o+=0>l?Math.min(h,0):Math.max(h,0)}}return a.getPixelForValue(o)}return a.getBasePixel()},getRuler:function(t){var e,n=this,i=n.getMeta(),a=n.getScaleForId(i.xAxisID),o=n.getBarCount();e="category"===a.options.type?a.getPixelForTick(t+1)-a.getPixelForTick(t):a.width/a.ticks.length;var r=e*a.options.categoryPercentage,s=(e-e*a.options.categoryPercentage)/2,l=r/o;if(a.ticks.length!==n.chart.data.labels.length){var d=a.ticks.length/n.chart.data.labels.length;l*=d}var u=l*a.options.barPercentage,c=l-l*a.options.barPercentage;return{datasetCount:o,tickWidth:e,categoryWidth:r,categorySpacing:s,fullBarWidth:l,barWidth:u,barSpacing:c}},calculateBarWidth:function(t){var e=this.getScaleForId(this.getMeta().xAxisID);if(e.options.barThickness)return e.options.barThickness;var n=this.getRuler(t);return e.options.stacked?n.categoryWidth:n.barWidth},getBarIndex:function(t){var e,n,i=0;for(n=0;t>n;++n)e=this.chart.getDatasetMeta(n),e.bar&&this.chart.isDatasetVisible(n)&&++i;return i},calculateBarX:function(t,e){var n=this,i=n.getMeta(),a=n.getScaleForId(i.xAxisID),o=n.getBarIndex(e),r=n.getRuler(t),s=a.getPixelForValue(null,t,e,n.chart.isCombo);return s-=n.chart.isCombo?r.tickWidth/2:0,a.options.stacked?s+r.categoryWidth/2+r.categorySpacing:s+r.barWidth/2+r.categorySpacing+r.barWidth*o+r.barSpacing/2+r.barSpacing*o},calculateBarY:function(t,e){var n=this,i=n.getMeta(),a=n.getScaleForId(i.yAxisID),o=Number(n.getDataset().data[t]);if(a.options.stacked){for(var r=0,s=0,l=0;e>l;l++){var d=n.chart.data.datasets[l],u=n.chart.getDatasetMeta(l);if(u.bar&&u.yAxisID===a.id&&n.chart.isDatasetVisible(l)){var c=Number(d.data[t]);0>c?s+=c||0:r+=c||0}}return 0>o?a.getPixelForValue(s+o):a.getPixelForValue(r+o)}return a.getPixelForValue(o)},draw:function(t){var n=this,i=t||1;e.each(n.getMeta().data,function(t,e){var a=n.getDataset().data[e];null===a||void 0===a||isNaN(a)||t.transition(i).draw()},n)},setHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t._index,a=t.custom||{},o=t._model;o.backgroundColor=a.hoverBackgroundColor?a.hoverBackgroundColor:e.getValueAtIndexOrDefault(n.hoverBackgroundColor,i,e.getHoverColor(o.backgroundColor)),o.borderColor=a.hoverBorderColor?a.hoverBorderColor:e.getValueAtIndexOrDefault(n.hoverBorderColor,i,e.getHoverColor(o.borderColor)),o.borderWidth=a.hoverBorderWidth?a.hoverBorderWidth:e.getValueAtIndexOrDefault(n.hoverBorderWidth,i,o.borderWidth)},removeHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t._index,a=t.custom||{},o=t._model,r=this.chart.options.elements.rectangle;o.backgroundColor=a.backgroundColor?a.backgroundColor:e.getValueAtIndexOrDefault(n.backgroundColor,i,r.backgroundColor),o.borderColor=a.borderColor?a.borderColor:e.getValueAtIndexOrDefault(n.borderColor,i,r.borderColor),o.borderWidth=a.borderWidth?a.borderWidth:e.getValueAtIndexOrDefault(n.borderWidth,i,r.borderWidth)}}),t.defaults.horizontalBar={hover:{mode:"label"},scales:{xAxes:[{type:"linear",position:"bottom"}],yAxes:[{position:"left",type:"category",categoryPercentage:.8,barPercentage:.9,gridLines:{offsetGridLines:!0}}]},elements:{rectangle:{borderSkipped:"left"}},tooltips:{callbacks:{title:function(t,e){var n="";return t.length>0&&(t[0].yLabel?n=t[0].yLabel:e.labels.length>0&&t[0].index<e.labels.length&&(n=e.labels[t[0].index])),n},label:function(t,e){var n=e.datasets[t.datasetIndex].label||"";return n+": "+t.xLabel}}}},t.controllers.horizontalBar=t.controllers.bar.extend({updateElement:function(t,n,i){var a=this,o=a.getMeta(),r=a.getScaleForId(o.xAxisID),s=a.getScaleForId(o.yAxisID),l=r.getBasePixel(),d=t.custom||{},u=a.getDataset(),c=a.chart.options.elements.rectangle;e.extend(t,{_xScale:r,_yScale:s,_datasetIndex:a.index,_index:n,_model:{x:i?l:a.calculateBarX(n,a.index),y:a.calculateBarY(n,a.index),label:a.chart.data.labels[n],datasetLabel:u.label,base:i?l:a.calculateBarBase(a.index,n),height:a.calculateBarHeight(n),backgroundColor:d.backgroundColor?d.backgroundColor:e.getValueAtIndexOrDefault(u.backgroundColor,n,c.backgroundColor),borderSkipped:d.borderSkipped?d.borderSkipped:c.borderSkipped,borderColor:d.borderColor?d.borderColor:e.getValueAtIndexOrDefault(u.borderColor,n,c.borderColor),borderWidth:d.borderWidth?d.borderWidth:e.getValueAtIndexOrDefault(u.borderWidth,n,c.borderWidth)},draw:function(){function t(t){return l[(u+t)%4]}var e=this._chart.ctx,n=this._view,i=n.height/2,a=n.y-i,o=n.y+i,r=n.base-(n.base-n.x),s=n.borderWidth/2;n.borderWidth&&(a+=s,o-=s,r+=s),e.beginPath(),e.fillStyle=n.backgroundColor,e.strokeStyle=n.borderColor,e.lineWidth=n.borderWidth;var l=[[n.base,o],[n.base,a],[r,a],[r,o]],d=["bottom","left","top","right"],u=d.indexOf(n.borderSkipped,0);-1===u&&(u=0),e.moveTo.apply(e,t(0));for(var c=1;4>c;c++)e.lineTo.apply(e,t(c));e.fill(),n.borderWidth&&e.stroke()},inRange:function(t,e){var n=this._view,i=!1;return n&&(i=n.x<n.base?e>=n.y-n.height/2&&e<=n.y+n.height/2&&t>=n.x&&t<=n.base:e>=n.y-n.height/2&&e<=n.y+n.height/2&&t>=n.base&&t<=n.x),i}}),t.pivot()},calculateBarBase:function(t,e){var n=this,i=n.getMeta(),a=n.getScaleForId(i.xAxisID),o=0;if(a.options.stacked){for(var r=n.chart,s=r.data.datasets,l=Number(s[t].data[e]),d=0;t>d;d++){var u=s[d],c=r.getDatasetMeta(d);if(c.bar&&c.xAxisID===a.id&&r.isDatasetVisible(d)){var h=Number(u.data[e]);o+=0>l?Math.min(h,0):Math.max(h,0)}}return a.getPixelForValue(o)}return a.getBasePixel()},getRuler:function(t){var e,n=this,i=n.getMeta(),a=n.getScaleForId(i.yAxisID),o=n.getBarCount();e="category"===a.options.type?a.getPixelForTick(t+1)-a.getPixelForTick(t):a.width/a.ticks.length;var r=e*a.options.categoryPercentage,s=(e-e*a.options.categoryPercentage)/2,l=r/o;if(a.ticks.length!==n.chart.data.labels.length){var d=a.ticks.length/n.chart.data.labels.length;l*=d}var u=l*a.options.barPercentage,c=l-l*a.options.barPercentage;return{datasetCount:o,tickHeight:e,categoryHeight:r,categorySpacing:s,fullBarHeight:l,barHeight:u,barSpacing:c}},calculateBarHeight:function(t){var e=this,n=e.getScaleForId(e.getMeta().yAxisID);if(n.options.barThickness)return n.options.barThickness;var i=e.getRuler(t);return n.options.stacked?i.categoryHeight:i.barHeight},calculateBarX:function(t,e){var n=this,i=n.getMeta(),a=n.getScaleForId(i.xAxisID),o=Number(n.getDataset().data[t]);if(a.options.stacked){for(var r=0,s=0,l=0;e>l;l++){var d=n.chart.data.datasets[l],u=n.chart.getDatasetMeta(l);if(u.bar&&u.xAxisID===a.id&&n.chart.isDatasetVisible(l)){var c=Number(d.data[t]);0>c?s+=c||0:r+=c||0}}return 0>o?a.getPixelForValue(s+o):a.getPixelForValue(r+o)}return a.getPixelForValue(o)},calculateBarY:function(t,e){var n=this,i=n.getMeta(),a=n.getScaleForId(i.yAxisID),o=n.getBarIndex(e),r=n.getRuler(t),s=a.getPixelForValue(null,t,e,n.chart.isCombo);return s-=n.chart.isCombo?r.tickHeight/2:0,a.options.stacked?s+r.categoryHeight/2+r.categorySpacing:s+r.barHeight/2+r.categorySpacing+r.barHeight*o+r.barSpacing/2+r.barSpacing*o}})}},{}],16:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.bubble={hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-0"}],yAxes:[{type:"linear",position:"left",id:"y-axis-0"}]},tooltips:{callbacks:{title:function(){return""},label:function(t,e){var n=e.datasets[t.datasetIndex].label||"",i=e.datasets[t.datasetIndex].data[t.index];return n+": ("+i.x+", "+i.y+", "+i.r+")"}}}},t.controllers.bubble=t.DatasetController.extend({dataElementType:t.elements.Point,update:function(t){var n=this,i=n.getMeta(),a=i.data;e.each(a,function(e,i){n.updateElement(e,i,t)})},updateElement:function(n,i,a){var o=this,r=o.getMeta(),s=o.getScaleForId(r.xAxisID),l=o.getScaleForId(r.yAxisID),d=n.custom||{},u=o.getDataset(),c=u.data[i],h=o.chart.options.elements.point,f=o.index;e.extend(n,{_xScale:s,_yScale:l,_datasetIndex:f,_index:i,_model:{x:a?s.getPixelForDecimal(.5):s.getPixelForValue("object"==typeof c?c:NaN,i,f,o.chart.isCombo),y:a?l.getBasePixel():l.getPixelForValue(c,i,f),radius:a?0:d.radius?d.radius:o.getRadius(c),hitRadius:d.hitRadius?d.hitRadius:e.getValueAtIndexOrDefault(u.hitRadius,i,h.hitRadius)}}),t.DatasetController.prototype.removeHoverStyle.call(o,n,h);var g=n._model;g.skip=d.skip?d.skip:isNaN(g.x)||isNaN(g.y),n.pivot()},getRadius:function(t){return t.r||this.chart.options.elements.point.radius},setHoverStyle:function(n){var i=this;t.DatasetController.prototype.setHoverStyle.call(i,n);var a=i.chart.data.datasets[n._datasetIndex],o=n._index,r=n.custom||{},s=n._model;s.radius=r.hoverRadius?r.hoverRadius:e.getValueAtIndexOrDefault(a.hoverRadius,o,i.chart.options.elements.point.hoverRadius)+i.getRadius(a.data[o])},removeHoverStyle:function(e){var n=this;t.DatasetController.prototype.removeHoverStyle.call(n,e,n.chart.options.elements.point);var i=n.chart.data.datasets[e._datasetIndex].data[e._index],a=e.custom||{},o=e._model;o.radius=a.radius?a.radius:n.getRadius(i)}})}},{}],17:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=t.defaults;n.doughnut={animation:{animateRotate:!0,animateScale:!1},aspectRatio:1,hover:{mode:"single"},legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');var n=t.data,i=n.datasets,a=n.labels;if(i.length)for(var o=0;o<i[0].data.length;++o)e.push('<li><span style="background-color:'+i[0].backgroundColor[o]+'"></span>'),a[o]&&e.push(a[o]),e.push("</li>");return e.push("</ul>"),e.join("")},legend:{labels:{generateLabels:function(t){var n=t.data;return n.labels.length&&n.datasets.length?n.labels.map(function(i,a){var o=t.getDatasetMeta(0),r=n.datasets[0],s=o.data[a],l=s&&s.custom||{},d=e.getValueAtIndexOrDefault,u=t.options.elements.arc,c=l.backgroundColor?l.backgroundColor:d(r.backgroundColor,a,u.backgroundColor),h=l.borderColor?l.borderColor:d(r.borderColor,a,u.borderColor),f=l.borderWidth?l.borderWidth:d(r.borderWidth,a,u.borderWidth);return{text:i,fillStyle:c,strokeStyle:h,lineWidth:f,hidden:isNaN(r.data[a])||o.data[a].hidden,index:a}}):[]}},onClick:function(t,e){var n,i,a,o=e.index,r=this.chart;for(n=0,i=(r.data.datasets||[]).length;i>n;++n)a=r.getDatasetMeta(n),a.data[o]&&(a.data[o].hidden=!a.data[o].hidden);r.update()}},cutoutPercentage:50,rotation:Math.PI*-.5,circumference:2*Math.PI,tooltips:{callbacks:{title:function(){return""},label:function(t,e){return e.labels[t.index]+": "+e.datasets[t.datasetIndex].data[t.index]}}}},n.pie=e.clone(n.doughnut),e.extend(n.pie,{cutoutPercentage:0}),t.controllers.doughnut=t.controllers.pie=t.DatasetController.extend({dataElementType:t.elements.Arc,linkScales:e.noop,getRingIndex:function(t){for(var e=0,n=0;t>n;++n)this.chart.isDatasetVisible(n)&&++e;return e},update:function(t){var n=this,i=n.chart,a=i.chartArea,o=i.options,r=o.elements.arc,s=a.right-a.left-r.borderWidth,l=a.bottom-a.top-r.borderWidth,d=Math.min(s,l),u={x:0,y:0},c=n.getMeta(),h=o.cutoutPercentage,f=o.circumference;if(f<2*Math.PI){var g=o.rotation%(2*Math.PI);g+=2*Math.PI*(g>=Math.PI?-1:g<-Math.PI?1:0);var m=g+f,p={x:Math.cos(g),y:Math.sin(g)},v={x:Math.cos(m),y:Math.sin(m)},b=0>=g&&m>=0||g<=2*Math.PI&&2*Math.PI<=m,y=g<=.5*Math.PI&&.5*Math.PI<=m||g<=2.5*Math.PI&&2.5*Math.PI<=m,x=g<=-Math.PI&&-Math.PI<=m||g<=Math.PI&&Math.PI<=m,k=g<=.5*-Math.PI&&.5*-Math.PI<=m||g<=1.5*Math.PI&&1.5*Math.PI<=m,S=h/100,w={x:x?-1:Math.min(p.x*(p.x<0?1:S),v.x*(v.x<0?1:S)),y:k?-1:Math.min(p.y*(p.y<0?1:S),v.y*(v.y<0?1:S))},_={x:b?1:Math.max(p.x*(p.x>0?1:S),v.x*(v.x>0?1:S)),y:y?1:Math.max(p.y*(p.y>0?1:S),v.y*(v.y>0?1:S))},M={width:.5*(_.x-w.x),height:.5*(_.y-w.y)};d=Math.min(s/M.width,l/M.height),u={x:(_.x+w.x)*-.5,y:(_.y+w.y)*-.5}}i.borderWidth=n.getMaxBorderWidth(c.data),i.outerRadius=Math.max((d-i.borderWidth)/2,0),i.innerRadius=Math.max(h?i.outerRadius/100*h:1,0),i.radiusLength=(i.outerRadius-i.innerRadius)/i.getVisibleDatasetCount(),i.offsetX=u.x*i.outerRadius,i.offsetY=u.y*i.outerRadius,c.total=n.calculateTotal(),n.outerRadius=i.outerRadius-i.radiusLength*n.getRingIndex(n.index),n.innerRadius=n.outerRadius-i.radiusLength,e.each(c.data,function(e,i){n.updateElement(e,i,t)})},updateElement:function(t,n,i){var a=this,o=a.chart,r=o.chartArea,s=o.options,l=s.animation,d=(r.left+r.right)/2,u=(r.top+r.bottom)/2,c=s.rotation,h=s.rotation,f=a.getDataset(),g=i&&l.animateRotate?0:t.hidden?0:a.calculateCircumference(f.data[n])*(s.circumference/(2*Math.PI)),m=i&&l.animateScale?0:a.innerRadius,p=i&&l.animateScale?0:a.outerRadius,v=e.getValueAtIndexOrDefault;e.extend(t,{_datasetIndex:a.index,_index:n,_model:{x:d+o.offsetX,y:u+o.offsetY,startAngle:c,endAngle:h,circumference:g,outerRadius:p,innerRadius:m,label:v(f.label,n,o.data.labels[n])}});var b=t._model;this.removeHoverStyle(t),i&&l.animateRotate||(0===n?b.startAngle=s.rotation:b.startAngle=a.getMeta().data[n-1]._model.endAngle,b.endAngle=b.startAngle+b.circumference),t.pivot()},removeHoverStyle:function(e){t.DatasetController.prototype.removeHoverStyle.call(this,e,this.chart.options.elements.arc)},calculateTotal:function(){var t,n=this.getDataset(),i=this.getMeta(),a=0;return e.each(i.data,function(e,i){t=n.data[i],isNaN(t)||e.hidden||(a+=Math.abs(t))}),a},calculateCircumference:function(t){var e=this.getMeta().total;return e>0&&!isNaN(t)?2*Math.PI*(t/e):0},getMaxBorderWidth:function(t){for(var e,n,i=0,a=this.index,o=t.length,r=0;o>r;r++)e=t[r]._model?t[r]._model.borderWidth:0,n=t[r]._chart?t[r]._chart.config.data.datasets[a].hoverBorderWidth:0,i=e>i?e:i,i=n>i?n:i;return i}})}},{}],18:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return n.getValueOrDefault(t.showLine,e.showLines)}var n=t.helpers;t.defaults.line={showLines:!0,spanGaps:!1,hover:{mode:"label"},scales:{xAxes:[{type:"category",id:"x-axis-0"}],yAxes:[{type:"linear",id:"y-axis-0"}]}},t.controllers.line=t.DatasetController.extend({datasetElementType:t.elements.Line,dataElementType:t.elements.Point,addElementAndReset:function(n){var i=this,a=i.chart.options,o=i.getMeta();t.DatasetController.prototype.addElementAndReset.call(i,n),e(i.getDataset(),a)&&0!==o.dataset._model.tension&&i.updateBezierControlPoints()},update:function(t){var i,a,o,r=this,s=r.getMeta(),l=s.dataset,d=s.data||[],u=r.chart.options,c=u.elements.line,h=r.getScaleForId(s.yAxisID),f=r.getDataset(),g=e(f,u);for(g&&(o=l.custom||{},void 0!==f.tension&&void 0===f.lineTension&&(f.lineTension=f.tension),l._scale=h,l._datasetIndex=r.index,l._children=d,l._model={spanGaps:f.spanGaps?f.spanGaps:u.spanGaps,tension:o.tension?o.tension:n.getValueOrDefault(f.lineTension,c.tension),backgroundColor:o.backgroundColor?o.backgroundColor:f.backgroundColor||c.backgroundColor,borderWidth:o.borderWidth?o.borderWidth:f.borderWidth||c.borderWidth,borderColor:o.borderColor?o.borderColor:f.borderColor||c.borderColor,borderCapStyle:o.borderCapStyle?o.borderCapStyle:f.borderCapStyle||c.borderCapStyle,borderDash:o.borderDash?o.borderDash:f.borderDash||c.borderDash,borderDashOffset:o.borderDashOffset?o.borderDashOffset:f.borderDashOffset||c.borderDashOffset,borderJoinStyle:o.borderJoinStyle?o.borderJoinStyle:f.borderJoinStyle||c.borderJoinStyle,fill:o.fill?o.fill:void 0!==f.fill?f.fill:c.fill,steppedLine:o.steppedLine?o.steppedLine:n.getValueOrDefault(f.steppedLine,c.stepped),cubicInterpolationMode:o.cubicInterpolationMode?o.cubicInterpolationMode:n.getValueOrDefault(f.cubicInterpolationMode,c.cubicInterpolationMode),scaleTop:h.top,scaleBottom:h.bottom,scaleZero:h.getBasePixel()},l.pivot()),i=0,a=d.length;a>i;++i)r.updateElement(d[i],i,t);for(g&&0!==l._model.tension&&r.updateBezierControlPoints(),i=0,a=d.length;a>i;++i)d[i].pivot()},getPointBackgroundColor:function(t,e){var i=this.chart.options.elements.point.backgroundColor,a=this.getDataset(),o=t.custom||{};return o.backgroundColor?i=o.backgroundColor:a.pointBackgroundColor?i=n.getValueAtIndexOrDefault(a.pointBackgroundColor,e,i):a.backgroundColor&&(i=a.backgroundColor),i},getPointBorderColor:function(t,e){var i=this.chart.options.elements.point.borderColor,a=this.getDataset(),o=t.custom||{};return o.borderColor?i=o.borderColor:a.pointBorderColor?i=n.getValueAtIndexOrDefault(a.pointBorderColor,e,i):a.borderColor&&(i=a.borderColor),i},getPointBorderWidth:function(t,e){var i=this.chart.options.elements.point.borderWidth,a=this.getDataset(),o=t.custom||{};return o.borderWidth?i=o.borderWidth:a.pointBorderWidth?i=n.getValueAtIndexOrDefault(a.pointBorderWidth,e,i):a.borderWidth&&(i=a.borderWidth),i},updateElement:function(t,e,i){var a,o,r=this,s=r.getMeta(),l=t.custom||{},d=r.getDataset(),u=r.index,c=d.data[e],h=r.getScaleForId(s.yAxisID),f=r.getScaleForId(s.xAxisID),g=r.chart.options.elements.point,m=r.chart.data.labels||[],p=1===m.length||1===d.data.length||r.chart.isCombo;void 0!==d.radius&&void 0===d.pointRadius&&(d.pointRadius=d.radius),void 0!==d.hitRadius&&void 0===d.pointHitRadius&&(d.pointHitRadius=d.hitRadius),a=f.getPixelForValue("object"==typeof c?c:NaN,e,u,p),o=i?h.getBasePixel():r.calculatePointY(c,e,u),t._xScale=f,t._yScale=h,t._datasetIndex=u,t._index=e,t._model={x:a,y:o,skip:l.skip||isNaN(a)||isNaN(o),radius:l.radius||n.getValueAtIndexOrDefault(d.pointRadius,e,g.radius),pointStyle:l.pointStyle||n.getValueAtIndexOrDefault(d.pointStyle,e,g.pointStyle),backgroundColor:r.getPointBackgroundColor(t,e),borderColor:r.getPointBorderColor(t,e),borderWidth:r.getPointBorderWidth(t,e),tension:s.dataset._model?s.dataset._model.tension:0,steppedLine:s.dataset._model?s.dataset._model.steppedLine:!1,hitRadius:l.hitRadius||n.getValueAtIndexOrDefault(d.pointHitRadius,e,g.hitRadius)}},calculatePointY:function(t,e,n){var i,a,o,r=this,s=r.chart,l=r.getMeta(),d=r.getScaleForId(l.yAxisID),u=0,c=0;if(d.options.stacked){for(i=0;n>i;i++)if(a=s.data.datasets[i],o=s.getDatasetMeta(i),"line"===o.type&&o.yAxisID===d.id&&s.isDatasetVisible(i)){var h=Number(d.getRightValue(a.data[e]));0>h?c+=h||0:u+=h||0}var f=Number(d.getRightValue(t));return 0>f?d.getPixelForValue(c+f):d.getPixelForValue(u+f)}return d.getPixelForValue(t)},updateBezierControlPoints:function(){function t(t,e,n){return Math.max(Math.min(t,n),e)}var e,i,a,o,r,s=this,l=s.getMeta(),d=s.chart.chartArea,u=l.data||[];if(l.dataset._model.spanGaps&&(u=u.filter(function(t){return!t._model.skip})),"monotone"===l.dataset._model.cubicInterpolationMode)n.splineCurveMonotone(u);else for(e=0,i=u.length;i>e;++e)a=u[e],o=a._model,r=n.splineCurve(n.previousItem(u,e)._model,o,n.nextItem(u,e)._model,l.dataset._model.tension),o.controlPointPreviousX=r.previous.x,o.controlPointPreviousY=r.previous.y,o.controlPointNextX=r.next.x,o.controlPointNextY=r.next.y;if(s.chart.options.elements.line.capBezierPoints)for(e=0,i=u.length;i>e;++e)o=u[e]._model,o.controlPointPreviousX=t(o.controlPointPreviousX,d.left,d.right),o.controlPointPreviousY=t(o.controlPointPreviousY,d.top,d.bottom),o.controlPointNextX=t(o.controlPointNextX,d.left,d.right),o.controlPointNextY=t(o.controlPointNextY,d.top,d.bottom)},draw:function(t){var n,i,a=this,o=a.getMeta(),r=o.data||[],s=t||1;for(n=0,i=r.length;i>n;++n)r[n].transition(s);for(e(a.getDataset(),a.chart.options)&&o.dataset.transition(s).draw(),n=0,i=r.length;i>n;++n)r[n].draw()},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],i=t._index,a=t.custom||{},o=t._model;o.radius=a.hoverRadius||n.getValueAtIndexOrDefault(e.pointHoverRadius,i,this.chart.options.elements.point.hoverRadius),o.backgroundColor=a.hoverBackgroundColor||n.getValueAtIndexOrDefault(e.pointHoverBackgroundColor,i,n.getHoverColor(o.backgroundColor)),o.borderColor=a.hoverBorderColor||n.getValueAtIndexOrDefault(e.pointHoverBorderColor,i,n.getHoverColor(o.borderColor)),o.borderWidth=a.hoverBorderWidth||n.getValueAtIndexOrDefault(e.pointHoverBorderWidth,i,o.borderWidth)},removeHoverStyle:function(t){var e=this,i=e.chart.data.datasets[t._datasetIndex],a=t._index,o=t.custom||{},r=t._model;void 0!==i.radius&&void 0===i.pointRadius&&(i.pointRadius=i.radius),r.radius=o.radius||n.getValueAtIndexOrDefault(i.pointRadius,a,e.chart.options.elements.point.radius),r.backgroundColor=e.getPointBackgroundColor(t,a),r.borderColor=e.getPointBorderColor(t,a),r.borderWidth=e.getPointBorderWidth(t,a)}})}},{}],19:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.polarArea={scale:{type:"radialLinear",lineArc:!0,ticks:{beginAtZero:!0}},animation:{animateRotate:!0,animateScale:!0},startAngle:-.5*Math.PI,aspectRatio:1,legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');var n=t.data,i=n.datasets,a=n.labels;if(i.length)for(var o=0;o<i[0].data.length;++o)e.push('<li><span style="background-color:'+i[0].backgroundColor[o]+'">'),a[o]&&e.push(a[o]),e.push("</span></li>");return e.push("</ul>"),e.join("")},legend:{labels:{generateLabels:function(t){var n=t.data;return n.labels.length&&n.datasets.length?n.labels.map(function(i,a){var o=t.getDatasetMeta(0),r=n.datasets[0],s=o.data[a],l=s.custom||{},d=e.getValueAtIndexOrDefault,u=t.options.elements.arc,c=l.backgroundColor?l.backgroundColor:d(r.backgroundColor,a,u.backgroundColor),h=l.borderColor?l.borderColor:d(r.borderColor,a,u.borderColor),f=l.borderWidth?l.borderWidth:d(r.borderWidth,a,u.borderWidth);return{
-text:i,fillStyle:c,strokeStyle:h,lineWidth:f,hidden:isNaN(r.data[a])||o.data[a].hidden,index:a}}):[]}},onClick:function(t,e){var n,i,a,o=e.index,r=this.chart;for(n=0,i=(r.data.datasets||[]).length;i>n;++n)a=r.getDatasetMeta(n),a.data[o].hidden=!a.data[o].hidden;r.update()}},tooltips:{callbacks:{title:function(){return""},label:function(t,e){return e.labels[t.index]+": "+t.yLabel}}}},t.controllers.polarArea=t.DatasetController.extend({dataElementType:t.elements.Arc,linkScales:e.noop,update:function(t){var n=this,i=n.chart,a=i.chartArea,o=n.getMeta(),r=i.options,s=r.elements.arc,l=Math.min(a.right-a.left,a.bottom-a.top);i.outerRadius=Math.max((l-s.borderWidth/2)/2,0),i.innerRadius=Math.max(r.cutoutPercentage?i.outerRadius/100*r.cutoutPercentage:1,0),i.radiusLength=(i.outerRadius-i.innerRadius)/i.getVisibleDatasetCount(),n.outerRadius=i.outerRadius-i.radiusLength*n.index,n.innerRadius=n.outerRadius-i.radiusLength,o.count=n.countVisibleElements(),e.each(o.data,function(e,i){n.updateElement(e,i,t)})},updateElement:function(t,n,i){for(var a=this,o=a.chart,r=a.getDataset(),s=o.options,l=s.animation,d=o.scale,u=e.getValueAtIndexOrDefault,c=o.data.labels,h=a.calculateCircumference(r.data[n]),f=d.xCenter,g=d.yCenter,m=0,p=a.getMeta(),v=0;n>v;++v)isNaN(r.data[v])||p.data[v].hidden||++m;var b=s.startAngle,y=t.hidden?0:d.getDistanceFromCenterForValue(r.data[n]),x=b+h*m,k=x+(t.hidden?0:h),S=l.animateScale?0:d.getDistanceFromCenterForValue(r.data[n]);e.extend(t,{_datasetIndex:a.index,_index:n,_scale:d,_model:{x:f,y:g,innerRadius:0,outerRadius:i?S:y,startAngle:i&&l.animateRotate?b:x,endAngle:i&&l.animateRotate?b:k,label:u(c,n,c[n])}}),a.removeHoverStyle(t),t.pivot()},removeHoverStyle:function(e){t.DatasetController.prototype.removeHoverStyle.call(this,e,this.chart.options.elements.arc)},countVisibleElements:function(){var t=this.getDataset(),n=this.getMeta(),i=0;return e.each(n.data,function(e,n){isNaN(t.data[n])||e.hidden||i++}),i},calculateCircumference:function(t){var e=this.getMeta().count;return e>0&&!isNaN(t)?2*Math.PI/e:0}})}},{}],20:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.radar={scale:{type:"radialLinear"},elements:{line:{tension:0}}},t.controllers.radar=t.DatasetController.extend({datasetElementType:t.elements.Line,dataElementType:t.elements.Point,linkScales:e.noop,addElementAndReset:function(e){t.DatasetController.prototype.addElementAndReset.call(this,e),this.updateBezierControlPoints()},update:function(t){var n=this,i=n.getMeta(),a=i.dataset,o=i.data,r=a.custom||{},s=n.getDataset(),l=n.chart.options.elements.line,d=n.chart.scale;void 0!==s.tension&&void 0===s.lineTension&&(s.lineTension=s.tension),e.extend(i.dataset,{_datasetIndex:n.index,_children:o,_loop:!0,_model:{tension:r.tension?r.tension:e.getValueOrDefault(s.lineTension,l.tension),backgroundColor:r.backgroundColor?r.backgroundColor:s.backgroundColor||l.backgroundColor,borderWidth:r.borderWidth?r.borderWidth:s.borderWidth||l.borderWidth,borderColor:r.borderColor?r.borderColor:s.borderColor||l.borderColor,fill:r.fill?r.fill:void 0!==s.fill?s.fill:l.fill,borderCapStyle:r.borderCapStyle?r.borderCapStyle:s.borderCapStyle||l.borderCapStyle,borderDash:r.borderDash?r.borderDash:s.borderDash||l.borderDash,borderDashOffset:r.borderDashOffset?r.borderDashOffset:s.borderDashOffset||l.borderDashOffset,borderJoinStyle:r.borderJoinStyle?r.borderJoinStyle:s.borderJoinStyle||l.borderJoinStyle,scaleTop:d.top,scaleBottom:d.bottom,scaleZero:d.getBasePosition()}}),i.dataset.pivot(),e.each(o,function(e,i){n.updateElement(e,i,t)},n),n.updateBezierControlPoints()},updateElement:function(t,n,i){var a=this,o=t.custom||{},r=a.getDataset(),s=a.chart.scale,l=a.chart.options.elements.point,d=s.getPointPositionForValue(n,r.data[n]);e.extend(t,{_datasetIndex:a.index,_index:n,_scale:s,_model:{x:i?s.xCenter:d.x,y:i?s.yCenter:d.y,tension:o.tension?o.tension:e.getValueOrDefault(r.tension,a.chart.options.elements.line.tension),radius:o.radius?o.radius:e.getValueAtIndexOrDefault(r.pointRadius,n,l.radius),backgroundColor:o.backgroundColor?o.backgroundColor:e.getValueAtIndexOrDefault(r.pointBackgroundColor,n,l.backgroundColor),borderColor:o.borderColor?o.borderColor:e.getValueAtIndexOrDefault(r.pointBorderColor,n,l.borderColor),borderWidth:o.borderWidth?o.borderWidth:e.getValueAtIndexOrDefault(r.pointBorderWidth,n,l.borderWidth),pointStyle:o.pointStyle?o.pointStyle:e.getValueAtIndexOrDefault(r.pointStyle,n,l.pointStyle),hitRadius:o.hitRadius?o.hitRadius:e.getValueAtIndexOrDefault(r.hitRadius,n,l.hitRadius)}}),t._model.skip=o.skip?o.skip:isNaN(t._model.x)||isNaN(t._model.y)},updateBezierControlPoints:function(){var t=this.chart.chartArea,n=this.getMeta();e.each(n.data,function(i,a){var o=i._model,r=e.splineCurve(e.previousItem(n.data,a,!0)._model,o,e.nextItem(n.data,a,!0)._model,o.tension);o.controlPointPreviousX=Math.max(Math.min(r.previous.x,t.right),t.left),o.controlPointPreviousY=Math.max(Math.min(r.previous.y,t.bottom),t.top),o.controlPointNextX=Math.max(Math.min(r.next.x,t.right),t.left),o.controlPointNextY=Math.max(Math.min(r.next.y,t.bottom),t.top),i.pivot()})},draw:function(t){var n=this.getMeta(),i=t||1;e.each(n.data,function(t){t.transition(i)}),n.dataset.transition(i).draw(),e.each(n.data,function(t){t.draw()})},setHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t.custom||{},a=t._index,o=t._model;o.radius=i.hoverRadius?i.hoverRadius:e.getValueAtIndexOrDefault(n.pointHoverRadius,a,this.chart.options.elements.point.hoverRadius),o.backgroundColor=i.hoverBackgroundColor?i.hoverBackgroundColor:e.getValueAtIndexOrDefault(n.pointHoverBackgroundColor,a,e.getHoverColor(o.backgroundColor)),o.borderColor=i.hoverBorderColor?i.hoverBorderColor:e.getValueAtIndexOrDefault(n.pointHoverBorderColor,a,e.getHoverColor(o.borderColor)),o.borderWidth=i.hoverBorderWidth?i.hoverBorderWidth:e.getValueAtIndexOrDefault(n.pointHoverBorderWidth,a,o.borderWidth)},removeHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t.custom||{},a=t._index,o=t._model,r=this.chart.options.elements.point;o.radius=i.radius?i.radius:e.getValueAtIndexOrDefault(n.radius,a,r.radius),o.backgroundColor=i.backgroundColor?i.backgroundColor:e.getValueAtIndexOrDefault(n.pointBackgroundColor,a,r.backgroundColor),o.borderColor=i.borderColor?i.borderColor:e.getValueAtIndexOrDefault(n.pointBorderColor,a,r.borderColor),o.borderWidth=i.borderWidth?i.borderWidth:e.getValueAtIndexOrDefault(n.pointBorderWidth,a,r.borderWidth)}})}},{}],21:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.global.animation={duration:1e3,easing:"easeOutQuart",onProgress:e.noop,onComplete:e.noop},t.Animation=t.Element.extend({currentStep:null,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),t.animationService={frameDuration:17,animations:[],dropFrames:0,request:null,addAnimation:function(t,e,n,i){var a=this;i||(t.animating=!0);for(var o=0;o<a.animations.length;++o)if(a.animations[o].chartInstance===t)return void(a.animations[o].animationObject=e);a.animations.push({chartInstance:t,animationObject:e}),1===a.animations.length&&a.requestAnimationFrame()},cancelAnimation:function(t){var n=e.findIndex(this.animations,function(e){return e.chartInstance===t});-1!==n&&(this.animations.splice(n,1),t.animating=!1)},requestAnimationFrame:function(){var t=this;null===t.request&&(t.request=e.requestAnimFrame.call(window,function(){t.request=null,t.startDigest()}))},startDigest:function(){var t=this,e=Date.now(),n=0;t.dropFrames>1&&(n=Math.floor(t.dropFrames),t.dropFrames=t.dropFrames%1);for(var i=0;i<t.animations.length;)null===t.animations[i].animationObject.currentStep&&(t.animations[i].animationObject.currentStep=0),t.animations[i].animationObject.currentStep+=1+n,t.animations[i].animationObject.currentStep>t.animations[i].animationObject.numSteps&&(t.animations[i].animationObject.currentStep=t.animations[i].animationObject.numSteps),t.animations[i].animationObject.render(t.animations[i].chartInstance,t.animations[i].animationObject),t.animations[i].animationObject.onAnimationProgress&&t.animations[i].animationObject.onAnimationProgress.call&&t.animations[i].animationObject.onAnimationProgress.call(t.animations[i].chartInstance,t.animations[i]),t.animations[i].animationObject.currentStep===t.animations[i].animationObject.numSteps?(t.animations[i].animationObject.onAnimationComplete&&t.animations[i].animationObject.onAnimationComplete.call&&t.animations[i].animationObject.onAnimationComplete.call(t.animations[i].chartInstance,t.animations[i]),t.animations[i].chartInstance.animating=!1,t.animations.splice(i,1)):++i;var a=Date.now(),o=(a-e)/t.frameDuration;t.dropFrames+=o,t.animations.length>0&&t.requestAnimationFrame()}}}},{}],22:[function(t,e,n){"use strict";e.exports=function(t){var e=t.canvasHelpers={};e.drawPoint=function(t,e,n,i,a){var o,r,s,l,d,u;if("object"==typeof e&&(o=e.toString(),"[object HTMLImageElement]"===o||"[object HTMLCanvasElement]"===o))return void t.drawImage(e,i-e.width/2,a-e.height/2);if(!(isNaN(n)||0>=n)){switch(e){default:t.beginPath(),t.arc(i,a,n,0,2*Math.PI),t.closePath(),t.fill();break;case"triangle":t.beginPath(),r=3*n/Math.sqrt(3),d=r*Math.sqrt(3)/2,t.moveTo(i-r/2,a+d/3),t.lineTo(i+r/2,a+d/3),t.lineTo(i,a-2*d/3),t.closePath(),t.fill();break;case"rect":u=1/Math.SQRT2*n,t.beginPath(),t.fillRect(i-u,a-u,2*u,2*u),t.strokeRect(i-u,a-u,2*u,2*u);break;case"rectRot":u=1/Math.SQRT2*n,t.beginPath(),t.moveTo(i-u,a),t.lineTo(i,a+u),t.lineTo(i+u,a),t.lineTo(i,a-u),t.closePath(),t.fill();break;case"cross":t.beginPath(),t.moveTo(i,a+n),t.lineTo(i,a-n),t.moveTo(i-n,a),t.lineTo(i+n,a),t.closePath();break;case"crossRot":t.beginPath(),s=Math.cos(Math.PI/4)*n,l=Math.sin(Math.PI/4)*n,t.moveTo(i-s,a-l),t.lineTo(i+s,a+l),t.moveTo(i-s,a+l),t.lineTo(i+s,a-l),t.closePath();break;case"star":t.beginPath(),t.moveTo(i,a+n),t.lineTo(i,a-n),t.moveTo(i-n,a),t.lineTo(i+n,a),s=Math.cos(Math.PI/4)*n,l=Math.sin(Math.PI/4)*n,t.moveTo(i-s,a-l),t.lineTo(i+s,a+l),t.moveTo(i-s,a+l),t.lineTo(i+s,a-l),t.closePath();break;case"line":t.beginPath(),t.moveTo(i-n,a),t.lineTo(i+n,a),t.closePath();break;case"dash":t.beginPath(),t.moveTo(i,a),t.lineTo(i+n,a),t.closePath()}t.stroke()}}}},{}],23:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.types={},t.instances={},t.controllers={},t.Controller=function(n){return this.chart=n,this.config=n.config,this.options=this.config.options=e.configMerge(t.defaults.global,t.defaults[this.config.type],this.config.options||{}),this.id=e.uid(),Object.defineProperty(this,"data",{get:function(){return this.config.data}}),t.instances[this.id]=this,this.options.responsive&&this.resize(!0),this.initialize(),this},e.extend(t.Controller.prototype,{initialize:function(){var e=this;return t.plugins.notify("beforeInit",[e]),e.bindEvents(),e.ensureScalesHaveIDs(),e.buildOrUpdateControllers(),e.buildScales(),e.updateLayout(),e.resetElements(),e.initToolTip(),e.update(),t.plugins.notify("afterInit",[e]),e},clear:function(){return e.clear(this.chart),this},stop:function(){return t.animationService.cancelAnimation(this),this},resize:function(n){var i=this,a=i.chart,o=a.canvas,r=e.getMaximumWidth(o),s=a.aspectRatio,l=i.options.maintainAspectRatio&&isNaN(s)===!1&&isFinite(s)&&0!==s?r/s:e.getMaximumHeight(o),d=a.width!==r||a.height!==l;if(!d)return i;o.width=a.width=r,o.height=a.height=l,e.retinaScale(a);var u={width:r,height:l};return t.plugins.notify("resize",[i,u]),i.options.onResize&&i.options.onResize(i,u),n||(i.stop(),i.update(i.options.responsiveAnimationDuration)),i},ensureScalesHaveIDs:function(){var t=this.options,n=t.scales||{},i=t.scale;e.each(n.xAxes,function(t,e){t.id=t.id||"x-axis-"+e}),e.each(n.yAxes,function(t,e){t.id=t.id||"y-axis-"+e}),i&&(i.id=i.id||"scale")},buildScales:function(){var n=this,i=n.options,a=n.scales={},o=[];i.scales&&(o=o.concat((i.scales.xAxes||[]).map(function(t){return{options:t,dtype:"category"}}),(i.scales.yAxes||[]).map(function(t){return{options:t,dtype:"linear"}}))),i.scale&&o.push({options:i.scale,dtype:"radialLinear",isDefault:!0}),e.each(o,function(i){var o=i.options,r=e.getValueOrDefault(o.type,i.dtype),s=t.scaleService.getScaleConstructor(r);if(s){var l=new s({id:o.id,options:o,ctx:n.chart.ctx,chart:n});a[l.id]=l,i.isDefault&&(n.scale=l)}}),t.scaleService.addScalesToLayout(this)},updateLayout:function(){t.layoutService.update(this,this.chart.width,this.chart.height)},buildOrUpdateControllers:function(){var n=this,i=[],a=[];if(e.each(n.data.datasets,function(e,o){var r=n.getDatasetMeta(o);r.type||(r.type=e.type||n.config.type),i.push(r.type),r.controller?r.controller.updateIndex(o):(r.controller=new t.controllers[r.type](n,o),a.push(r.controller))},n),i.length>1)for(var o=1;o<i.length;o++)if(i[o]!==i[o-1]){n.isCombo=!0;break}return a},resetElements:function(){var t=this;e.each(t.data.datasets,function(e,n){t.getDatasetMeta(n).controller.reset()},t)},update:function(n,i){var a=this;t.plugins.notify("beforeUpdate",[a]),a.tooltip._data=a.data;var o=a.buildOrUpdateControllers();e.each(a.data.datasets,function(t,e){a.getDatasetMeta(e).controller.buildOrUpdateElements()},a),t.layoutService.update(a,a.chart.width,a.chart.height),t.plugins.notify("afterScaleUpdate",[a]),e.each(o,function(t){t.reset()}),a.updateDatasets(),t.plugins.notify("afterUpdate",[a]),a.render(n,i)},updateDatasets:function(){var e,n,i=this;if(t.plugins.notify("beforeDatasetsUpdate",[i])){for(e=0,n=i.data.datasets.length;n>e;++e)i.getDatasetMeta(e).controller.update();t.plugins.notify("afterDatasetsUpdate",[i])}},render:function(n,i){var a=this;t.plugins.notify("beforeRender",[a]);var o=a.options.animation;if(o&&("undefined"!=typeof n&&0!==n||"undefined"==typeof n&&0!==o.duration)){var r=new t.Animation;r.numSteps=(n||o.duration)/16.66,r.easing=o.easing,r.render=function(t,n){var i=e.easingEffects[n.easing],a=n.currentStep/n.numSteps,o=i(a);t.draw(o,a,n.currentStep)},r.onAnimationProgress=o.onProgress,r.onAnimationComplete=o.onComplete,t.animationService.addAnimation(a,r,n,i)}else a.draw(),o&&o.onComplete&&o.onComplete.call&&o.onComplete.call(a);return a},draw:function(n){var i=this,a=n||1;i.clear(),t.plugins.notify("beforeDraw",[i,a]),e.each(i.boxes,function(t){t.draw(i.chartArea)},i),i.scale&&i.scale.draw(),t.plugins.notify("beforeDatasetsDraw",[i,a]),e.each(i.data.datasets,function(t,e){i.isDatasetVisible(e)&&i.getDatasetMeta(e).controller.draw(n)},i,!0),t.plugins.notify("afterDatasetsDraw",[i,a]),i.tooltip.transition(a).draw(),t.plugins.notify("afterDraw",[i,a])},getElementAtEvent:function(t){var n=this,i=e.getRelativePosition(t,n.chart),a=[];return e.each(n.data.datasets,function(t,o){if(n.isDatasetVisible(o)){var r=n.getDatasetMeta(o);e.each(r.data,function(t){return t.inRange(i.x,i.y)?(a.push(t),a):void 0})}}),a.slice(0,1)},getElementsAtEvent:function(t){var n=this,i=e.getRelativePosition(t,n.chart),a=[],o=function(){if(n.data.datasets)for(var t=0;t<n.data.datasets.length;t++){var e=n.getDatasetMeta(t);if(n.isDatasetVisible(t))for(var a=0;a<e.data.length;a++)if(e.data[a].inRange(i.x,i.y))return e.data[a]}}.call(n);return o?(e.each(n.data.datasets,function(t,e){if(n.isDatasetVisible(e)){var i=n.getDatasetMeta(e),r=i.data[o._index];r&&!r._view.skip&&a.push(r)}},n),a):a},getElementsAtXAxis:function(t){var n=this,i=e.getRelativePosition(t,n.chart),a=[],o=function(){if(n.data.datasets)for(var t=0;t<n.data.datasets.length;t++){var e=n.getDatasetMeta(t);if(n.isDatasetVisible(t))for(var a=0;a<e.data.length;a++)if(e.data[a].inLabelRange(i.x,i.y))return e.data[a]}}.call(n);return o?(e.each(n.data.datasets,function(t,i){if(n.isDatasetVisible(i)){var r=n.getDatasetMeta(i),s=e.findIndex(r.data,function(t){return o._model.x===t._model.x});-1===s||r.data[s]._view.skip||a.push(r.data[s])}},n),a):a},getElementsAtEventForMode:function(t,e){var n=this;switch(e){case"single":return n.getElementAtEvent(t);case"label":return n.getElementsAtEvent(t);case"dataset":return n.getDatasetAtEvent(t);case"x-axis":return n.getElementsAtXAxis(t);default:return t}},getDatasetAtEvent:function(t){var e=this.getElementAtEvent(t);return e.length>0&&(e=this.getDatasetMeta(e[0]._datasetIndex).data),e},getDatasetMeta:function(t){var e=this,n=e.data.datasets[t];n._meta||(n._meta={});var i=n._meta[e.id];return i||(i=n._meta[e.id]={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null}),i},getVisibleDatasetCount:function(){for(var t=0,e=0,n=this.data.datasets.length;n>e;++e)this.isDatasetVisible(e)&&t++;return t},isDatasetVisible:function(t){var e=this.getDatasetMeta(t);return"boolean"==typeof e.hidden?!e.hidden:!this.data.datasets[t].hidden},generateLegend:function(){return this.options.legendCallback(this)},destroy:function(){var n=this;n.stop(),n.clear(),e.unbindEvents(n,n.events),e.removeResizeListener(n.chart.canvas.parentNode);var i=n.chart.canvas;i.width=n.chart.width,i.height=n.chart.height,void 0!==n.chart.originalDevicePixelRatio&&n.chart.ctx.scale(1/n.chart.originalDevicePixelRatio,1/n.chart.originalDevicePixelRatio),i.style.width=n.chart.originalCanvasStyleWidth,i.style.height=n.chart.originalCanvasStyleHeight,t.plugins.notify("destroy",[n]),delete t.instances[n.id]},toBase64Image:function(){return this.chart.canvas.toDataURL.apply(this.chart.canvas,arguments)},initToolTip:function(){var e=this;e.tooltip=new t.Tooltip({_chart:e.chart,_chartInstance:e,_data:e.data,_options:e.options.tooltips},e)},bindEvents:function(){var t=this;e.bindEvents(t,t.options.events,function(e){t.eventHandler(e)})},updateHoverStyle:function(t,e,n){var i,a,o,r=n?"setHoverStyle":"removeHoverStyle";switch(e){case"single":t=[t[0]];break;case"label":case"dataset":case"x-axis":break;default:return}for(a=0,o=t.length;o>a;++a)i=t[a],i&&this.getDatasetMeta(i._datasetIndex).controller[r](i)},eventHandler:function(t){var n=this,i=n.tooltip,a=n.options||{},o=a.hover,r=a.tooltips;return n.lastActive=n.lastActive||[],n.lastTooltipActive=n.lastTooltipActive||[],"mouseout"===t.type?(n.active=[],n.tooltipActive=[]):(n.active=n.getElementsAtEventForMode(t,o.mode),n.tooltipActive=n.getElementsAtEventForMode(t,r.mode)),o.onHover&&o.onHover.call(n,n.active),n.legend&&n.legend.handleEvent&&n.legend.handleEvent(t),("mouseup"===t.type||"click"===t.type)&&a.onClick&&a.onClick.call(n,t,n.active),n.lastActive.length&&n.updateHoverStyle(n.lastActive,o.mode,!1),n.active.length&&o.mode&&n.updateHoverStyle(n.active,o.mode,!0),(r.enabled||r.custom)&&(i.initialize(),i._active=n.tooltipActive,i.update(!0)),i.pivot(),n.animating||e.arrayEquals(n.active,n.lastActive)&&e.arrayEquals(n.tooltipActive,n.lastTooltipActive)||(n.stop(),(r.enabled||r.custom)&&i.update(!0),n.render(o.animationDuration,!0)),n.lastActive=n.active,n.lastTooltipActive=n.tooltipActive,n}})}},{}],24:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=e.noop;t.DatasetController=function(t,e){this.initialize(t,e)},e.extend(t.DatasetController.prototype,{datasetElementType:null,dataElementType:null,initialize:function(t,e){var n=this;n.chart=t,n.index=e,n.linkScales(),n.addElements()},updateIndex:function(t){this.index=t},linkScales:function(){var t=this,e=t.getMeta(),n=t.getDataset();null===e.xAxisID&&(e.xAxisID=n.xAxisID||t.chart.options.scales.xAxes[0].id),null===e.yAxisID&&(e.yAxisID=n.yAxisID||t.chart.options.scales.yAxes[0].id)},getDataset:function(){return this.chart.data.datasets[this.index]},getMeta:function(){return this.chart.getDatasetMeta(this.index)},getScaleForId:function(t){return this.chart.scales[t]},reset:function(){this.update(!0)},createMetaDataset:function(){var t=this,e=t.datasetElementType;return e&&new e({_chart:t.chart.chart,_datasetIndex:t.index})},createMetaData:function(t){var e=this,n=e.dataElementType;return n&&new n({_chart:e.chart.chart,_datasetIndex:e.index,_index:t})},addElements:function(){var t,e,n=this,i=n.getMeta(),a=n.getDataset().data||[],o=i.data;for(t=0,e=a.length;e>t;++t)o[t]=o[t]||n.createMetaData(i,t);i.dataset=i.dataset||n.createMetaDataset()},addElementAndReset:function(t){var e=this,n=e.createMetaData(t);e.getMeta().data.splice(t,0,n),e.updateElement(n,t,!0)},buildOrUpdateElements:function(){var t=this.getMeta(),e=t.data,n=this.getDataset().data.length,i=e.length;if(i>n)e.splice(n,i-n);else if(n>i)for(var a=i;n>a;++a)this.addElementAndReset(a)},update:n,draw:function(t){var n=t||1;e.each(this.getMeta().data,function(t){t.transition(n).draw()})},removeHoverStyle:function(t,n){var i=this.chart.data.datasets[t._datasetIndex],a=t._index,o=t.custom||{},r=e.getValueAtIndexOrDefault,s=t._model;s.backgroundColor=o.backgroundColor?o.backgroundColor:r(i.backgroundColor,a,n.backgroundColor),s.borderColor=o.borderColor?o.borderColor:r(i.borderColor,a,n.borderColor),s.borderWidth=o.borderWidth?o.borderWidth:r(i.borderWidth,a,n.borderWidth)},setHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t._index,a=t.custom||{},o=e.getValueAtIndexOrDefault,r=e.getHoverColor,s=t._model;s.backgroundColor=a.hoverBackgroundColor?a.hoverBackgroundColor:o(n.hoverBackgroundColor,i,r(s.backgroundColor)),s.borderColor=a.hoverBorderColor?a.hoverBorderColor:o(n.hoverBorderColor,i,r(s.borderColor)),s.borderWidth=a.hoverBorderWidth?a.hoverBorderWidth:o(n.hoverBorderWidth,i,s.borderWidth)}}),t.DatasetController.extend=e.inherits}},{}],25:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.elements={},t.Element=function(t){e.extend(this,t),this.initialize.apply(this,arguments)},e.extend(t.Element.prototype,{initialize:function(){this.hidden=!1},pivot:function(){var t=this;return t._view||(t._view=e.clone(t._model)),t._start=e.clone(t._view),t},transition:function(t){var n=this;return n._view||(n._view=e.clone(n._model)),1===t?(n._view=n._model,n._start=null,n):(n._start||n.pivot(),e.each(n._model,function(i,a){if("_"===a[0]);else if(n._view.hasOwnProperty(a))if(i===n._view[a]);else if("string"==typeof i)try{var o=e.color(n._model[a]).mix(e.color(n._start[a]),t);n._view[a]=o.rgbString()}catch(r){n._view[a]=i}else if("number"==typeof i){var s=void 0!==n._start[a]&&isNaN(n._start[a])===!1?n._start[a]:0;n._view[a]=(n._model[a]-s)*t+s}else n._view[a]=i;else"number"!=typeof i||isNaN(n._view[a])?n._view[a]=i:n._view[a]=i*t},n),n)},tooltipPosition:function(){return{x:this._model.x,y:this._model.y}},hasValue:function(){return e.isNumber(this._model.x)&&e.isNumber(this._model.y)}}),t.Element.extend=e.inherits}},{}],26:[function(t,e,n){"use strict";var i=t(2);e.exports=function(t){function e(t,e,n){var i;return"string"==typeof t?(i=parseInt(t,10),-1!==t.indexOf("%")&&(i=i/100*e.parentNode[n])):i=t,i}function n(t){return void 0!==t&&null!==t&&"none"!==t}function a(t,i,a){var o=document.defaultView,r=t.parentNode,s=o.getComputedStyle(t)[i],l=o.getComputedStyle(r)[i],d=n(s),u=n(l),c=Number.POSITIVE_INFINITY;return d||u?Math.min(d?e(s,t,a):c,u?e(l,r,a):c):"none"}var o=t.helpers={};o.each=function(t,e,n,i){var a,r;if(o.isArray(t))if(r=t.length,i)for(a=r-1;a>=0;a--)e.call(n,t[a],a);else for(a=0;r>a;a++)e.call(n,t[a],a);else if("object"==typeof t){var s=Object.keys(t);for(r=s.length,a=0;r>a;a++)e.call(n,t[s[a]],s[a])}},o.clone=function(t){var e={};return o.each(t,function(t,n){o.isArray(t)?e[n]=t.slice(0):"object"==typeof t&&null!==t?e[n]=o.clone(t):e[n]=t}),e},o.extend=function(t){for(var e=function(e,n){t[n]=e},n=1,i=arguments.length;i>n;n++)o.each(arguments[n],e);return t},o.configMerge=function(e){var n=o.clone(e);return o.each(Array.prototype.slice.call(arguments,1),function(e){o.each(e,function(e,i){if("scales"===i)n[i]=o.scaleMerge(n.hasOwnProperty(i)?n[i]:{},e);else if("scale"===i)n[i]=o.configMerge(n.hasOwnProperty(i)?n[i]:{},t.scaleService.getScaleDefaults(e.type),e);else if(n.hasOwnProperty(i)&&o.isArray(n[i])&&o.isArray(e)){var a=n[i];o.each(e,function(t,e){e<a.length?"object"==typeof a[e]&&null!==a[e]&&"object"==typeof t&&null!==t?a[e]=o.configMerge(a[e],t):a[e]=t:a.push(t)})}else n.hasOwnProperty(i)&&"object"==typeof n[i]&&null!==n[i]&&"object"==typeof e?n[i]=o.configMerge(n[i],e):n[i]=e})}),n},o.scaleMerge=function(e,n){var i=o.clone(e);return o.each(n,function(e,n){"xAxes"===n||"yAxes"===n?i.hasOwnProperty(n)?o.each(e,function(e,a){var r=o.getValueOrDefault(e.type,"xAxes"===n?"category":"linear"),s=t.scaleService.getScaleDefaults(r);a>=i[n].length||!i[n][a].type?i[n].push(o.configMerge(s,e)):e.type&&e.type!==i[n][a].type?i[n][a]=o.configMerge(i[n][a],s,e):i[n][a]=o.configMerge(i[n][a],e)}):(i[n]=[],o.each(e,function(e){var a=o.getValueOrDefault(e.type,"xAxes"===n?"category":"linear");i[n].push(o.configMerge(t.scaleService.getScaleDefaults(a),e))})):i.hasOwnProperty(n)&&"object"==typeof i[n]&&null!==i[n]&&"object"==typeof e?i[n]=o.configMerge(i[n],e):i[n]=e}),i},o.getValueAtIndexOrDefault=function(t,e,n){return void 0===t||null===t?n:o.isArray(t)?e<t.length?t[e]:n:t},o.getValueOrDefault=function(t,e){return void 0===t?e:t},o.indexOf=Array.prototype.indexOf?function(t,e){return t.indexOf(e)}:function(t,e){for(var n=0,i=t.length;i>n;++n)if(t[n]===e)return n;return-1},o.where=function(t,e){if(o.isArray(t)&&Array.prototype.filter)return t.filter(e);var n=[];return o.each(t,function(t){e(t)&&n.push(t)}),n},o.findIndex=Array.prototype.findIndex?function(t,e,n){return t.findIndex(e,n)}:function(t,e,n){n=void 0===n?t:n;for(var i=0,a=t.length;a>i;++i)if(e.call(n,t[i],i,t))return i;return-1},o.findNextWhere=function(t,e,n){(void 0===n||null===n)&&(n=-1);for(var i=n+1;i<t.length;i++){var a=t[i];if(e(a))return a}},o.findPreviousWhere=function(t,e,n){(void 0===n||null===n)&&(n=t.length);for(var i=n-1;i>=0;i--){var a=t[i];if(e(a))return a}},o.inherits=function(t){var e=this,n=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return e.apply(this,arguments)},i=function(){this.constructor=n};return i.prototype=e.prototype,n.prototype=new i,n.extend=o.inherits,t&&o.extend(n.prototype,t),n.__super__=e.prototype,n},o.noop=function(){},o.uid=function(){var t=0;return function(){return t++}}(),o.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},o.almostEquals=function(t,e,n){return Math.abs(t-e)<n},o.max=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.max(t,e)},Number.NEGATIVE_INFINITY)},o.min=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.min(t,e)},Number.POSITIVE_INFINITY)},o.sign=Math.sign?function(t){return Math.sign(t)}:function(t){return t=+t,0===t||isNaN(t)?t:t>0?1:-1},o.log10=Math.log10?function(t){return Math.log10(t)}:function(t){return Math.log(t)/Math.LN10},o.toRadians=function(t){return t*(Math.PI/180)},o.toDegrees=function(t){return t*(180/Math.PI)},o.getAngleFromPoint=function(t,e){var n=e.x-t.x,i=e.y-t.y,a=Math.sqrt(n*n+i*i),o=Math.atan2(i,n);return o<-.5*Math.PI&&(o+=2*Math.PI),{angle:o,distance:a}},o.aliasPixel=function(t){return t%2===0?0:.5},o.splineCurve=function(t,e,n,i){var a=t.skip?e:t,o=e,r=n.skip?e:n,s=Math.sqrt(Math.pow(o.x-a.x,2)+Math.pow(o.y-a.y,2)),l=Math.sqrt(Math.pow(r.x-o.x,2)+Math.pow(r.y-o.y,2)),d=s/(s+l),u=l/(s+l);d=isNaN(d)?0:d,u=isNaN(u)?0:u;var c=i*d,h=i*u;return{previous:{x:o.x-c*(r.x-a.x),y:o.y-c*(r.y-a.y)},next:{x:o.x+h*(r.x-a.x),y:o.y+h*(r.y-a.y)}}},o.EPSILON=Number.EPSILON||1e-14,o.splineCurveMonotone=function(t){var e,n,i,a,r=(t||[]).map(function(t){return{model:t._model,deltaK:0,mK:0}}),s=r.length;for(e=0;s>e;++e)i=r[e],i.model.skip||(n=e>0?r[e-1]:null,a=s-1>e?r[e+1]:null,a&&!a.model.skip&&(i.deltaK=(a.model.y-i.model.y)/(a.model.x-i.model.x)),!n||n.model.skip?i.mK=i.deltaK:!a||a.model.skip?i.mK=n.deltaK:this.sign(n.deltaK)!==this.sign(i.deltaK)?i.mK=0:i.mK=(n.deltaK+i.deltaK)/2);var l,d,u,c;for(e=0;s-1>e;++e)i=r[e],a=r[e+1],i.model.skip||a.model.skip||(o.almostEquals(i.deltaK,0,this.EPSILON)?i.mK=a.mK=0:(l=i.mK/i.deltaK,d=a.mK/i.deltaK,c=Math.pow(l,2)+Math.pow(d,2),9>=c||(u=3/Math.sqrt(c),i.mK=l*u*i.deltaK,a.mK=d*u*i.deltaK)));var h;for(e=0;s>e;++e)i=r[e],i.model.skip||(n=e>0?r[e-1]:null,a=s-1>e?r[e+1]:null,n&&!n.model.skip&&(h=(i.model.x-n.model.x)/3,i.model.controlPointPreviousX=i.model.x-h,i.model.controlPointPreviousY=i.model.y-h*i.mK),a&&!a.model.skip&&(h=(a.model.x-i.model.x)/3,i.model.controlPointNextX=i.model.x+h,i.model.controlPointNextY=i.model.y+h*i.mK))},o.nextItem=function(t,e,n){return n?e>=t.length-1?t[0]:t[e+1]:e>=t.length-1?t[t.length-1]:t[e+1]},o.previousItem=function(t,e,n){return n?0>=e?t[t.length-1]:t[e-1]:0>=e?t[0]:t[e-1]},o.niceNum=function(t,e){var n,i=Math.floor(o.log10(t)),a=t/Math.pow(10,i);return n=e?1.5>a?1:3>a?2:7>a?5:10:1>=a?1:2>=a?2:5>=a?5:10,n*Math.pow(10,i)};var r=o.easingEffects={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-1*t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-0.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return 1*((t=t/1-1)*t*t+1)},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-1*((t=t/1-1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-0.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return 1*(t/=1)*t*t*t*t},easeOutQuint:function(t){return 1*((t=t/1-1)*t*t*t*t+1)},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return-1*Math.cos(t/1*(Math.PI/2))+1},easeOutSine:function(t){return 1*Math.sin(t/1*(Math.PI/2))},easeInOutSine:function(t){return-0.5*(Math.cos(Math.PI*t/1)-1)},easeInExpo:function(t){return 0===t?1:1*Math.pow(2,10*(t/1-1))},easeOutExpo:function(t){return 1===t?1:1*(-Math.pow(2,-10*t/1)+1)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(-Math.pow(2,-10*--t)+2)},easeInCirc:function(t){return t>=1?t:-1*(Math.sqrt(1-(t/=1)*t)-1)},easeOutCirc:function(t){return 1*Math.sqrt(1-(t=t/1-1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-0.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:1===(t/=1)?1:(n||(n=.3),i<Math.abs(1)?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),-(i*Math.pow(2,10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/n)))},easeOutElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:1===(t/=1)?1:(n||(n=.3),i<Math.abs(1)?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),i*Math.pow(2,-10*t)*Math.sin((1*t-e)*(2*Math.PI)/n)+1)},easeInOutElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:2===(t/=.5)?1:(n||(n=1*(.3*1.5)),i<Math.abs(1)?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),1>t?-.5*(i*Math.pow(2,10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/n)):i*Math.pow(2,-10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/n)*.5+1)},easeInBack:function(t){var e=1.70158;return 1*(t/=1)*t*((e+1)*t-e)},easeOutBack:function(t){var e=1.70158;return 1*((t=t/1-1)*t*((e+1)*t+e)+1)},easeInOutBack:function(t){var e=1.70158;return(t/=.5)<1?.5*(t*t*(((e*=1.525)+1)*t-e)):.5*((t-=2)*t*(((e*=1.525)+1)*t+e)+2)},easeInBounce:function(t){return 1-r.easeOutBounce(1-t)},easeOutBounce:function(t){return(t/=1)<1/2.75?1*(7.5625*t*t):2/2.75>t?1*(7.5625*(t-=1.5/2.75)*t+.75):2.5/2.75>t?1*(7.5625*(t-=2.25/2.75)*t+.9375):1*(7.5625*(t-=2.625/2.75)*t+.984375)},easeInOutBounce:function(t){return.5>t?.5*r.easeInBounce(2*t):.5*r.easeOutBounce(2*t-1)+.5}};o.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)}}(),o.cancelAnimFrame=function(){return window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.oCancelAnimationFrame||window.msCancelAnimationFrame||function(t){return window.clearTimeout(t,1e3/60)}}(),o.getRelativePosition=function(t,e){var n,i,a=t.originalEvent||t,r=t.currentTarget||t.srcElement,s=r.getBoundingClientRect(),l=a.touches;l&&l.length>0?(n=l[0].clientX,i=l[0].clientY):(n=a.clientX,i=a.clientY);var d=parseFloat(o.getStyle(r,"padding-left")),u=parseFloat(o.getStyle(r,"padding-top")),c=parseFloat(o.getStyle(r,"padding-right")),h=parseFloat(o.getStyle(r,"padding-bottom")),f=s.right-s.left-d-c,g=s.bottom-s.top-u-h;
-return n=Math.round((n-s.left-d)/f*r.width/e.currentDevicePixelRatio),i=Math.round((i-s.top-u)/g*r.height/e.currentDevicePixelRatio),{x:n,y:i}},o.addEvent=function(t,e,n){t.addEventListener?t.addEventListener(e,n):t.attachEvent?t.attachEvent("on"+e,n):t["on"+e]=n},o.removeEvent=function(t,e,n){t.removeEventListener?t.removeEventListener(e,n,!1):t.detachEvent?t.detachEvent("on"+e,n):t["on"+e]=o.noop},o.bindEvents=function(t,e,n){var i=t.events=t.events||{};o.each(e,function(e){i[e]=function(){n.apply(t,arguments)},o.addEvent(t.chart.canvas,e,i[e])})},o.unbindEvents=function(t,e){var n=t.chart.canvas;o.each(e,function(t,e){o.removeEvent(n,e,t)})},o.getConstraintWidth=function(t){return a(t,"max-width","clientWidth")},o.getConstraintHeight=function(t){return a(t,"max-height","clientHeight")},o.getMaximumWidth=function(t){var e=t.parentNode,n=parseInt(o.getStyle(e,"padding-left"),10),i=parseInt(o.getStyle(e,"padding-right"),10),a=e.clientWidth-n-i,r=o.getConstraintWidth(t);return isNaN(r)?a:Math.min(a,r)},o.getMaximumHeight=function(t){var e=t.parentNode,n=parseInt(o.getStyle(e,"padding-top"),10),i=parseInt(o.getStyle(e,"padding-bottom"),10),a=e.clientHeight-n-i,r=o.getConstraintHeight(t);return isNaN(r)?a:Math.min(a,r)},o.getStyle=function(t,e){return t.currentStyle?t.currentStyle[e]:document.defaultView.getComputedStyle(t,null).getPropertyValue(e)},o.retinaScale=function(t){var e=t.ctx,n=t.canvas,i=n.width,a=n.height,o=t.currentDevicePixelRatio=window.devicePixelRatio||1;1!==o&&(n.height=a*o,n.width=i*o,e.scale(o,o),t.originalDevicePixelRatio=t.originalDevicePixelRatio||o),n.style.width=i+"px",n.style.height=a+"px"},o.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},o.fontString=function(t,e,n){return e+" "+t+"px "+n},o.longestText=function(t,e,n,i){i=i||{};var a=i.data=i.data||{},r=i.garbageCollect=i.garbageCollect||[];i.font!==e&&(a=i.data={},r=i.garbageCollect=[],i.font=e),t.font=e;var s=0;o.each(n,function(e){void 0!==e&&null!==e&&o.isArray(e)!==!0?s=o.measureText(t,a,r,s,e):o.isArray(e)&&o.each(e,function(e){void 0===e||null===e||o.isArray(e)||(s=o.measureText(t,a,r,s,e))})});var l=r.length/2;if(l>n.length){for(var d=0;l>d;d++)delete a[r[d]];r.splice(0,l)}return s},o.measureText=function(t,e,n,i,a){var o=e[a];return o||(o=e[a]=t.measureText(a).width,n.push(a)),o>i&&(i=o),i},o.numberOfLabelLines=function(t){var e=1;return o.each(t,function(t){o.isArray(t)&&t.length>e&&(e=t.length)}),e},o.drawRoundedRectangle=function(t,e,n,i,a,o){t.beginPath(),t.moveTo(e+o,n),t.lineTo(e+i-o,n),t.quadraticCurveTo(e+i,n,e+i,n+o),t.lineTo(e+i,n+a-o),t.quadraticCurveTo(e+i,n+a,e+i-o,n+a),t.lineTo(e+o,n+a),t.quadraticCurveTo(e,n+a,e,n+a-o),t.lineTo(e,n+o),t.quadraticCurveTo(e,n,e+o,n),t.closePath()},o.color=function(e){return i?i(e instanceof CanvasGradient?t.defaults.global.defaultColor:e):(console.error("Color.js not found!"),e)},o.addResizeListener=function(t,e){var n=document.createElement("iframe"),i="chartjs-hidden-iframe";n.classlist?n.classlist.add(i):n.setAttribute("class",i),n.tabIndex=-1;var a=n.style;a.width="100%",a.display="block",a.border=0,a.height=0,a.margin=0,a.position="absolute",a.left=0,a.right=0,a.top=0,a.bottom=0,t.insertBefore(n,t.firstChild),(n.contentWindow||n).onresize=function(){return e?e():void 0}},o.removeResizeListener=function(t){var e=t.querySelector(".chartjs-hidden-iframe");e&&e.parentNode.removeChild(e)},o.isArray=Array.isArray?function(t){return Array.isArray(t)}:function(t){return"[object Array]"===Object.prototype.toString.call(t)},o.arrayEquals=function(t,e){var n,i,a,r;if(!t||!e||t.length!==e.length)return!1;for(n=0,i=t.length;i>n;++n)if(a=t[n],r=e[n],a instanceof Array&&r instanceof Array){if(!o.arrayEquals(a,r))return!1}else if(a!==r)return!1;return!0},o.callCallback=function(t,e,n){t&&"function"==typeof t.call&&t.apply(n,e)},o.getHoverColor=function(t){return t instanceof CanvasPattern?t:o.color(t).saturate(.5).darken(.1).rgbString()}}},{2:2}],27:[function(t,e,n){"use strict";e.exports=function(){var t=function(e,n){var i=this,a=t.helpers;return i.config=n||{data:{datasets:[]}},e.length&&e[0].getContext&&(e=e[0]),e.getContext&&(e=e.getContext("2d")),i.ctx=e,i.canvas=e.canvas,e.canvas.style.display=e.canvas.style.display||"block",i.width=e.canvas.width||parseInt(a.getStyle(e.canvas,"width"),10)||a.getMaximumWidth(e.canvas),i.height=e.canvas.height||parseInt(a.getStyle(e.canvas,"height"),10)||a.getMaximumHeight(e.canvas),i.aspectRatio=i.width/i.height,(isNaN(i.aspectRatio)||isFinite(i.aspectRatio)===!1)&&(i.aspectRatio=void 0!==n.aspectRatio?n.aspectRatio:2),i.originalCanvasStyleWidth=e.canvas.style.width,i.originalCanvasStyleHeight=e.canvas.style.height,a.retinaScale(i),i.controller=new t.Controller(i),a.addResizeListener(e.canvas.parentNode,function(){i.controller&&i.controller.config.options.responsive&&i.controller.resize()}),i.controller?i.controller:i};return t.defaults={global:{responsive:!0,responsiveAnimationDuration:0,maintainAspectRatio:!0,events:["mousemove","mouseout","click","touchstart","touchmove"],hover:{onHover:null,mode:"single",animationDuration:400},onClick:null,defaultColor:"rgba(0,0,0,0.1)",defaultFontColor:"#666",defaultFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",defaultFontSize:12,defaultFontStyle:"normal",showLines:!0,elements:{},legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');for(var n=0;n<t.data.datasets.length;n++)e.push('<li><span style="background-color:'+t.data.datasets[n].backgroundColor+'"></span>'),t.data.datasets[n].label&&e.push(t.data.datasets[n].label),e.push("</li>");return e.push("</ul>"),e.join("")}}},t.Chart=t,t}},{}],28:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.layoutService={defaults:{},addBox:function(t,e){t.boxes||(t.boxes=[]),t.boxes.push(e)},removeBox:function(t,e){t.boxes&&t.boxes.splice(t.boxes.indexOf(e),1)},update:function(t,n,i){function a(t){var e,n=t.isHorizontal();n?(e=t.update(t.options.fullWidth?m:k,x),S-=e.height):(e=t.update(y,b),k-=e.width),w.push({horizontal:n,minSize:e,box:t})}function o(t){var n=e.findNextWhere(w,function(e){return e.box===t});if(n)if(t.isHorizontal()){var i={left:_,right:M,top:0,bottom:0};t.update(t.options.fullWidth?m:k,p/2,i)}else t.update(n.minSize.width,S)}function r(t){var n=e.findNextWhere(w,function(e){return e.box===t}),i={left:0,right:0,top:D,bottom:C};n&&t.update(n.minSize.width,S,i)}function s(t){t.isHorizontal()?(t.left=t.options.fullWidth?l:_,t.right=t.options.fullWidth?n-l:_+k,t.top=I,t.bottom=I+t.height,I=t.bottom):(t.left=F,t.right=F+t.width,t.top=D,t.bottom=D+S,F=t.right)}if(t){var l=0,d=0,u=e.where(t.boxes,function(t){return"left"===t.options.position}),c=e.where(t.boxes,function(t){return"right"===t.options.position}),h=e.where(t.boxes,function(t){return"top"===t.options.position}),f=e.where(t.boxes,function(t){return"bottom"===t.options.position}),g=e.where(t.boxes,function(t){return"chartArea"===t.options.position});h.sort(function(t,e){return(e.options.fullWidth?1:0)-(t.options.fullWidth?1:0)}),f.sort(function(t,e){return(t.options.fullWidth?1:0)-(e.options.fullWidth?1:0)});var m=n-2*l,p=i-2*d,v=m/2,b=p/2,y=(n-v)/(u.length+c.length),x=(i-b)/(h.length+f.length),k=m,S=p,w=[];e.each(u.concat(c,h,f),a);var _=l,M=l,D=d,C=d;e.each(u.concat(c),o),e.each(u,function(t){_+=t.width}),e.each(c,function(t){M+=t.width}),e.each(h.concat(f),o),e.each(h,function(t){D+=t.height}),e.each(f,function(t){C+=t.height}),e.each(u.concat(c),r),_=l,M=l,D=d,C=d,e.each(u,function(t){_+=t.width}),e.each(c,function(t){M+=t.width}),e.each(h,function(t){D+=t.height}),e.each(f,function(t){C+=t.height});var T=i-D-C,P=n-_-M;(P!==k||T!==S)&&(e.each(u,function(t){t.height=T}),e.each(c,function(t){t.height=T}),e.each(h,function(t){t.options.fullWidth||(t.width=P)}),e.each(f,function(t){t.options.fullWidth||(t.width=P)}),S=T,k=P);var F=l,I=d;e.each(u.concat(h),s),F+=k,I+=S,e.each(c,s),e.each(f,s),t.chartArea={left:_,top:D,right:_+k,bottom:D+S},e.each(g,function(e){e.left=t.chartArea.left,e.top=t.chartArea.top,e.right=t.chartArea.right,e.bottom=t.chartArea.bottom,e.update(k,S)})}}}}},{}],29:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=e.noop;t.defaults.global.legend={display:!0,position:"top",fullWidth:!0,reverse:!1,onClick:function(t,e){var n=e.datasetIndex,i=this.chart,a=i.getDatasetMeta(n);a.hidden=null===a.hidden?!i.data.datasets[n].hidden:null,i.update()},onHover:null,labels:{boxWidth:40,padding:10,generateLabels:function(t){var n=t.data;return e.isArray(n.datasets)?n.datasets.map(function(n,i){return{text:n.label,fillStyle:e.isArray(n.backgroundColor)?n.backgroundColor[0]:n.backgroundColor,hidden:!t.isDatasetVisible(i),lineCap:n.borderCapStyle,lineDash:n.borderDash,lineDashOffset:n.borderDashOffset,lineJoin:n.borderJoinStyle,lineWidth:n.borderWidth,strokeStyle:n.borderColor,pointStyle:n.pointStyle,datasetIndex:i}},this):[]}}},t.Legend=t.Element.extend({initialize:function(t){e.extend(this,t),this.legendHitBoxes=[],this.doughnutMode=!1},beforeUpdate:n,update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:n,beforeSetDimensions:n,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:n,beforeBuildLabels:n,buildLabels:function(){var t=this;t.legendItems=t.options.labels.generateLabels.call(t,t.chart),t.options.reverse&&t.legendItems.reverse()},afterBuildLabels:n,beforeFit:n,fit:function(){var n=this,i=n.options,a=i.labels,o=i.display,r=n.ctx,s=t.defaults.global,l=e.getValueOrDefault,d=l(a.fontSize,s.defaultFontSize),u=l(a.fontStyle,s.defaultFontStyle),c=l(a.fontFamily,s.defaultFontFamily),h=e.fontString(d,u,c),f=n.legendHitBoxes=[],g=n.minSize,m=n.isHorizontal();if(m?(g.width=n.maxWidth,g.height=o?10:0):(g.width=o?10:0,g.height=n.maxHeight),o)if(r.font=h,m){var p=n.lineWidths=[0],v=n.legendItems.length?d+a.padding:0;r.textAlign="left",r.textBaseline="top",e.each(n.legendItems,function(t,e){var i=a.usePointStyle?d*Math.sqrt(2):a.boxWidth,o=i+d/2+r.measureText(t.text).width;p[p.length-1]+o+a.padding>=n.width&&(v+=d+a.padding,p[p.length]=n.left),f[e]={left:0,top:0,width:o,height:d},p[p.length-1]+=o+a.padding}),g.height+=v}else{var b=a.padding,y=n.columnWidths=[],x=a.padding,k=0,S=0,w=d+b;e.each(n.legendItems,function(t,e){var n=a.usePointStyle?2*a.boxWidth:a.boxWidth,i=n+d/2+r.measureText(t.text).width;S+w>g.height&&(x+=k+a.padding,y.push(k),k=0,S=0),k=Math.max(k,i),S+=w,f[e]={left:0,top:0,width:i,height:d}}),x+=k,y.push(k),g.width+=x}n.width=g.width,n.height=g.height},afterFit:n,isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},draw:function(){var n=this,i=n.options,a=i.labels,o=t.defaults.global,r=o.elements.line,s=n.width,l=n.lineWidths;if(i.display){var d,u=n.ctx,c=e.getValueOrDefault,h=c(a.fontColor,o.defaultFontColor),f=c(a.fontSize,o.defaultFontSize),g=c(a.fontStyle,o.defaultFontStyle),m=c(a.fontFamily,o.defaultFontFamily),p=e.fontString(f,g,m);u.textAlign="left",u.textBaseline="top",u.lineWidth=.5,u.strokeStyle=h,u.fillStyle=h,u.font=p;var v=a.boxWidth,b=n.legendHitBoxes,y=function(e,n,a){if(!(isNaN(v)||0>=v)){u.save(),u.fillStyle=c(a.fillStyle,o.defaultColor),u.lineCap=c(a.lineCap,r.borderCapStyle),u.lineDashOffset=c(a.lineDashOffset,r.borderDashOffset),u.lineJoin=c(a.lineJoin,r.borderJoinStyle),u.lineWidth=c(a.lineWidth,r.borderWidth),u.strokeStyle=c(a.strokeStyle,o.defaultColor);var s=0===c(a.lineWidth,r.borderWidth);if(u.setLineDash&&u.setLineDash(c(a.lineDash,r.borderDash)),i.labels&&i.labels.usePointStyle){var l=f*Math.SQRT2/2,d=l/Math.SQRT2,h=e+d,g=n+d;t.canvasHelpers.drawPoint(u,a.pointStyle,l,h,g)}else s||u.strokeRect(e,n,v,f),u.fillRect(e,n,v,f);u.restore()}},x=function(t,e,n,i){u.fillText(n.text,v+f/2+t,e),n.hidden&&(u.beginPath(),u.lineWidth=2,u.moveTo(v+f/2+t,e+f/2),u.lineTo(v+f/2+t+i,e+f/2),u.stroke())},k=n.isHorizontal();d=k?{x:n.left+(s-l[0])/2,y:n.top+a.padding,line:0}:{x:n.left+a.padding,y:n.top+a.padding,line:0};var S=f+a.padding;e.each(n.legendItems,function(t,e){var i=u.measureText(t.text).width,o=a.usePointStyle?f+f/2+i:v+f/2+i,r=d.x,c=d.y;k?r+o>=s&&(c=d.y+=S,d.line++,r=d.x=n.left+(s-l[d.line])/2):c+S>n.bottom&&(r=d.x=r+n.columnWidths[d.line]+a.padding,c=d.y=n.top,d.line++),y(r,c,t),b[e].left=r,b[e].top=c,x(r,c,t,i),k?d.x+=o+a.padding:d.y+=S})}},handleEvent:function(t){var n=this,i=n.options,a="mouseup"===t.type?"click":t.type;if("mousemove"===a){if(!i.onHover)return}else{if("click"!==a)return;if(!i.onClick)return}var o=e.getRelativePosition(t,n.chart.chart),r=o.x,s=o.y;if(r>=n.left&&r<=n.right&&s>=n.top&&s<=n.bottom)for(var l=n.legendHitBoxes,d=0;d<l.length;++d){var u=l[d];if(r>=u.left&&r<=u.left+u.width&&s>=u.top&&s<=u.top+u.height){if("click"===a){i.onClick.call(n,t,n.legendItems[d]);break}if("mousemove"===a){i.onHover.call(n,t,n.legendItems[d]);break}}}}}),t.plugins.register({beforeInit:function(e){var n=e.options,i=n.legend;i&&(e.legend=new t.Legend({ctx:e.chart.ctx,options:i,chart:e}),t.layoutService.addBox(e,e.legend))}})}},{}],30:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers.noop;t.plugins={_plugins:[],register:function(t){var e=this._plugins;[].concat(t).forEach(function(t){-1===e.indexOf(t)&&e.push(t)})},unregister:function(t){var e=this._plugins;[].concat(t).forEach(function(t){var n=e.indexOf(t);-1!==n&&e.splice(n,1)})},clear:function(){this._plugins=[]},count:function(){return this._plugins.length},getAll:function(){return this._plugins},notify:function(t,e){var n,i,a=this._plugins,o=a.length;for(n=0;o>n;++n)if(i=a[n],"function"==typeof i[t]&&i[t].apply(i,e||[])===!1)return!1;return!0}},t.PluginBase=t.Element.extend({beforeInit:e,afterInit:e,beforeUpdate:e,afterUpdate:e,beforeDraw:e,afterDraw:e,destroy:e}),t.pluginService=t.plugins}},{}],31:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.scale={display:!0,position:"left",gridLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1,drawBorder:!0,drawOnChartArea:!0,drawTicks:!0,tickMarkLength:10,zeroLineWidth:1,zeroLineColor:"rgba(0,0,0,0.25)",offsetGridLines:!1,borderDash:[],borderDashOffset:0},scaleLabel:{labelString:"",display:!1},ticks:{beginAtZero:!1,minRotation:0,maxRotation:50,mirror:!1,padding:10,reverse:!1,display:!0,autoSkip:!0,autoSkipPadding:0,labelOffset:0,callback:function(t){return e.isArray(t)?t:""+t}}},t.Scale=t.Element.extend({beforeUpdate:function(){e.callCallback(this.options.beforeUpdate,[this])},update:function(t,n,i){var a=this;return a.beforeUpdate(),a.maxWidth=t,a.maxHeight=n,a.margins=e.extend({left:0,right:0,top:0,bottom:0},i),a.beforeSetDimensions(),a.setDimensions(),a.afterSetDimensions(),a.beforeDataLimits(),a.determineDataLimits(),a.afterDataLimits(),a.beforeBuildTicks(),a.buildTicks(),a.afterBuildTicks(),a.beforeTickToLabelConversion(),a.convertTicksToLabels(),a.afterTickToLabelConversion(),a.beforeCalculateTickRotation(),a.calculateTickRotation(),a.afterCalculateTickRotation(),a.beforeFit(),a.fit(),a.afterFit(),a.afterUpdate(),a.minSize},afterUpdate:function(){e.callCallback(this.options.afterUpdate,[this])},beforeSetDimensions:function(){e.callCallback(this.options.beforeSetDimensions,[this])},setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0},afterSetDimensions:function(){e.callCallback(this.options.afterSetDimensions,[this])},beforeDataLimits:function(){e.callCallback(this.options.beforeDataLimits,[this])},determineDataLimits:e.noop,afterDataLimits:function(){e.callCallback(this.options.afterDataLimits,[this])},beforeBuildTicks:function(){e.callCallback(this.options.beforeBuildTicks,[this])},buildTicks:e.noop,afterBuildTicks:function(){e.callCallback(this.options.afterBuildTicks,[this])},beforeTickToLabelConversion:function(){e.callCallback(this.options.beforeTickToLabelConversion,[this])},convertTicksToLabels:function(){var t=this;t.ticks=t.ticks.map(function(e,n,i){return t.options.ticks.userCallback?t.options.ticks.userCallback(e,n,i):t.options.ticks.callback(e,n,i)},t)},afterTickToLabelConversion:function(){e.callCallback(this.options.afterTickToLabelConversion,[this])},beforeCalculateTickRotation:function(){e.callCallback(this.options.beforeCalculateTickRotation,[this])},calculateTickRotation:function(){var n=this,i=n.ctx,a=t.defaults.global,o=n.options.ticks,r=e.getValueOrDefault(o.fontSize,a.defaultFontSize),s=e.getValueOrDefault(o.fontStyle,a.defaultFontStyle),l=e.getValueOrDefault(o.fontFamily,a.defaultFontFamily),d=e.fontString(r,s,l);i.font=d;var u,c=i.measureText(n.ticks[0]).width,h=i.measureText(n.ticks[n.ticks.length-1]).width;if(n.labelRotation=o.minRotation||0,n.paddingRight=0,n.paddingLeft=0,n.options.display&&n.isHorizontal()){n.paddingRight=h/2+3,n.paddingLeft=c/2+3,n.longestTextCache||(n.longestTextCache={});for(var f,g,m=e.longestText(i,d,n.ticks,n.longestTextCache),p=m,v=n.getPixelForTick(1)-n.getPixelForTick(0)-6;p>v&&n.labelRotation<o.maxRotation;){if(f=Math.cos(e.toRadians(n.labelRotation)),g=Math.sin(e.toRadians(n.labelRotation)),u=f*c,u+r/2>n.yLabelWidth&&(n.paddingLeft=u+r/2),n.paddingRight=r/2,g*m>n.maxHeight){n.labelRotation--;break}n.labelRotation++,p=f*m}}n.margins&&(n.paddingLeft=Math.max(n.paddingLeft-n.margins.left,0),n.paddingRight=Math.max(n.paddingRight-n.margins.right,0))},afterCalculateTickRotation:function(){e.callCallback(this.options.afterCalculateTickRotation,[this])},beforeFit:function(){e.callCallback(this.options.beforeFit,[this])},fit:function(){var n=this,i=n.minSize={width:0,height:0},a=n.options,o=t.defaults.global,r=a.ticks,s=a.scaleLabel,l=a.gridLines,d=a.display,u=n.isHorizontal(),c=e.getValueOrDefault(r.fontSize,o.defaultFontSize),h=e.getValueOrDefault(r.fontStyle,o.defaultFontStyle),f=e.getValueOrDefault(r.fontFamily,o.defaultFontFamily),g=e.fontString(c,h,f),m=e.getValueOrDefault(s.fontSize,o.defaultFontSize),p=a.gridLines.tickMarkLength;if(u?i.width=n.isFullWidth()?n.maxWidth-n.margins.left-n.margins.right:n.maxWidth:i.width=d&&l.drawTicks?p:0,u?i.height=d&&l.drawTicks?p:0:i.height=n.maxHeight,s.display&&d&&(u?i.height+=1.5*m:i.width+=1.5*m),r.display&&d){n.longestTextCache||(n.longestTextCache={});var v=e.longestText(n.ctx,g,n.ticks,n.longestTextCache),b=e.numberOfLabelLines(n.ticks),y=.5*c;if(u){n.longestLabelWidth=v;var x=Math.sin(e.toRadians(n.labelRotation))*n.longestLabelWidth+c*b+y*b;i.height=Math.min(n.maxHeight,i.height+x),n.ctx.font=g;var k=n.ctx.measureText(n.ticks[0]).width,S=n.ctx.measureText(n.ticks[n.ticks.length-1]).width,w=Math.cos(e.toRadians(n.labelRotation)),_=Math.sin(e.toRadians(n.labelRotation));n.paddingLeft=0!==n.labelRotation?w*k+3:k/2+3,n.paddingRight=0!==n.labelRotation?_*(c/2)+3:S/2+3}else{var M=n.maxWidth-i.width,D=r.mirror;D?v=0:v+=n.options.ticks.padding,M>v?i.width+=v:i.width=n.maxWidth,n.paddingTop=c/2,n.paddingBottom=c/2}}n.margins&&(n.paddingLeft=Math.max(n.paddingLeft-n.margins.left,0),n.paddingTop=Math.max(n.paddingTop-n.margins.top,0),n.paddingRight=Math.max(n.paddingRight-n.margins.right,0),n.paddingBottom=Math.max(n.paddingBottom-n.margins.bottom,0)),n.width=i.width,n.height=i.height},afterFit:function(){e.callCallback(this.options.afterFit,[this])},isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},isFullWidth:function(){return this.options.fullWidth},getRightValue:function(t){return null===t||"undefined"==typeof t?NaN:"number"==typeof t&&isNaN(t)?NaN:"object"==typeof t?t instanceof Date||t.isValid?t:this.getRightValue(this.isHorizontal()?t.x:t.y):t},getLabelForIndex:e.noop,getPixelForValue:e.noop,getValueForPixel:e.noop,getPixelForTick:function(t,e){var n=this;if(n.isHorizontal()){var i=n.width-(n.paddingLeft+n.paddingRight),a=i/Math.max(n.ticks.length-(n.options.gridLines.offsetGridLines?0:1),1),o=a*t+n.paddingLeft;e&&(o+=a/2);var r=n.left+Math.round(o);return r+=n.isFullWidth()?n.margins.left:0}var s=n.height-(n.paddingTop+n.paddingBottom);return n.top+t*(s/(n.ticks.length-1))},getPixelForDecimal:function(t){var e=this;if(e.isHorizontal()){var n=e.width-(e.paddingLeft+e.paddingRight),i=n*t+e.paddingLeft,a=e.left+Math.round(i);return a+=e.isFullWidth()?e.margins.left:0}return e.top+t*e.height},getBasePixel:function(){var t=this,e=t.min,n=t.max;return t.getPixelForValue(t.beginAtZero?0:0>e&&0>n?n:e>0&&n>0?e:0)},draw:function(n){var i=this,a=i.options;if(a.display){var o,r,s=i.ctx,l=t.defaults.global,d=a.ticks,u=a.gridLines,c=a.scaleLabel,h=0!==i.labelRotation,f=d.autoSkip,g=i.isHorizontal();d.maxTicksLimit&&(r=d.maxTicksLimit);var m=e.getValueOrDefault(d.fontColor,l.defaultFontColor),p=e.getValueOrDefault(d.fontSize,l.defaultFontSize),v=e.getValueOrDefault(d.fontStyle,l.defaultFontStyle),b=e.getValueOrDefault(d.fontFamily,l.defaultFontFamily),y=e.fontString(p,v,b),x=u.tickMarkLength,k=e.getValueOrDefault(u.borderDash,l.borderDash),S=e.getValueOrDefault(u.borderDashOffset,l.borderDashOffset),w=e.getValueOrDefault(c.fontColor,l.defaultFontColor),_=e.getValueOrDefault(c.fontSize,l.defaultFontSize),M=e.getValueOrDefault(c.fontStyle,l.defaultFontStyle),D=e.getValueOrDefault(c.fontFamily,l.defaultFontFamily),C=e.fontString(_,M,D),T=e.toRadians(i.labelRotation),P=Math.cos(T),F=i.longestLabelWidth*P;s.fillStyle=m;var I=[];if(g){if(o=!1,h&&(F/=2),(F+d.autoSkipPadding)*i.ticks.length>i.width-(i.paddingLeft+i.paddingRight)&&(o=1+Math.floor((F+d.autoSkipPadding)*i.ticks.length/(i.width-(i.paddingLeft+i.paddingRight)))),r&&i.ticks.length>r)for(;!o||i.ticks.length/(o||1)>r;)o||(o=1),o+=1;f||(o=!1)}var A="right"===a.position?i.left:i.right-x,O="right"===a.position?i.left+x:i.right,R="bottom"===a.position?i.top:i.bottom-x,W="bottom"===a.position?i.top+x:i.bottom;if(e.each(i.ticks,function(t,r){if(void 0!==t&&null!==t){var s=i.ticks.length===r+1,l=o>1&&r%o>0||r%o===0&&r+o>=i.ticks.length;if((!l||s)&&void 0!==t&&null!==t){var c,f;r===("undefined"!=typeof i.zeroLineIndex?i.zeroLineIndex:0)?(c=u.zeroLineWidth,f=u.zeroLineColor):(c=e.getValueAtIndexOrDefault(u.lineWidth,r),f=e.getValueAtIndexOrDefault(u.color,r));var m,p,v,b,y,w,_,M,D,C,P="middle",F="middle";if(g){h||(F="top"===a.position?"bottom":"top"),P=h?"right":"center";var L=i.getPixelForTick(r)+e.aliasPixel(c);D=i.getPixelForTick(r,u.offsetGridLines)+d.labelOffset,C=h?i.top+12:"top"===a.position?i.bottom-x:i.top+x,m=v=y=_=L,p=R,b=W,w=n.top,M=n.bottom}else{"left"===a.position?d.mirror?(D=i.right+d.padding,P="left"):(D=i.right-d.padding,P="right"):d.mirror?(D=i.left-d.padding,P="right"):(D=i.left+d.padding,P="left");var V=i.getPixelForTick(r);V+=e.aliasPixel(c),C=i.getPixelForTick(r,u.offsetGridLines),m=A,v=O,y=n.left,_=n.right,p=b=w=M=V}I.push({tx1:m,ty1:p,tx2:v,ty2:b,x1:y,y1:w,x2:_,y2:M,labelX:D,labelY:C,glWidth:c,glColor:f,glBorderDash:k,glBorderDashOffset:S,rotation:-1*T,label:t,textBaseline:F,textAlign:P})}}}),e.each(I,function(t){if(u.display&&(s.save(),s.lineWidth=t.glWidth,s.strokeStyle=t.glColor,s.setLineDash&&(s.setLineDash(t.glBorderDash),s.lineDashOffset=t.glBorderDashOffset),s.beginPath(),u.drawTicks&&(s.moveTo(t.tx1,t.ty1),s.lineTo(t.tx2,t.ty2)),u.drawOnChartArea&&(s.moveTo(t.x1,t.y1),s.lineTo(t.x2,t.y2)),s.stroke(),s.restore()),d.display){s.save(),s.translate(t.labelX,t.labelY),s.rotate(t.rotation),s.font=y,s.textBaseline=t.textBaseline,s.textAlign=t.textAlign;var n=t.label;if(e.isArray(n))for(var i=0,a=-(n.length-1)*p*.75;i<n.length;++i)s.fillText(""+n[i],0,a),a+=1.5*p;else s.fillText(n,0,0);s.restore()}}),c.display){var L,V,B=0;if(g)L=i.left+(i.right-i.left)/2,V="bottom"===a.position?i.bottom-_/2:i.top+_/2;else{var Y="left"===a.position;L=Y?i.left+_/2:i.right-_/2,V=i.top+(i.bottom-i.top)/2,B=Y?-.5*Math.PI:.5*Math.PI}s.save(),s.translate(L,V),s.rotate(B),s.textAlign="center",s.textBaseline="middle",s.fillStyle=w,s.font=C,s.fillText(c.labelString,0,0),s.restore()}if(u.drawBorder){s.lineWidth=e.getValueAtIndexOrDefault(u.lineWidth,0),s.strokeStyle=e.getValueAtIndexOrDefault(u.color,0);var z=i.left,H=i.right,N=i.top,E=i.bottom,U=e.aliasPixel(s.lineWidth);g?(N=E="top"===a.position?i.bottom:i.top,N+=U,E+=U):(z=H="left"===a.position?i.right:i.left,z+=U,H+=U),s.beginPath(),s.moveTo(z,N),s.lineTo(H,E),s.stroke()}}}})}},{}],32:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.scaleService={constructors:{},defaults:{},registerScaleType:function(t,n,i){this.constructors[t]=n,this.defaults[t]=e.clone(i)},getScaleConstructor:function(t){return this.constructors.hasOwnProperty(t)?this.constructors[t]:void 0},getScaleDefaults:function(n){return this.defaults.hasOwnProperty(n)?e.scaleMerge(t.defaults.scale,this.defaults[n]):{}},updateScaleDefaults:function(t,n){var i=this.defaults;i.hasOwnProperty(t)&&(i[t]=e.extend(i[t],n))},addScalesToLayout:function(n){e.each(n.scales,function(e){t.layoutService.addBox(n,e)})}}}},{}],33:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.global.title={display:!1,position:"top",fullWidth:!0,fontStyle:"bold",padding:10,text:""};var n=e.noop;t.Title=t.Element.extend({initialize:function(n){var i=this;e.extend(i,n),i.options=e.configMerge(t.defaults.global.title,n.options),i.legendHitBoxes=[]},beforeUpdate:function(){var n=this.chart.options;n&&n.title&&(this.options=e.configMerge(t.defaults.global.title,n.title))},update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:n,beforeSetDimensions:n,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:n,beforeBuildLabels:n,buildLabels:n,afterBuildLabels:n,beforeFit:n,fit:function(){var n=this,i=e.getValueOrDefault,a=n.options,o=t.defaults.global,r=a.display,s=i(a.fontSize,o.defaultFontSize),l=n.minSize;n.isHorizontal()?(l.width=n.maxWidth,l.height=r?s+2*a.padding:0):(l.width=r?s+2*a.padding:0,l.height=n.maxHeight),n.width=l.width,n.height=l.height},afterFit:n,isHorizontal:function(){var t=this.options.position;return"top"===t||"bottom"===t},draw:function(){var n=this,i=n.ctx,a=e.getValueOrDefault,o=n.options,r=t.defaults.global;if(o.display){var s,l,d=a(o.fontSize,r.defaultFontSize),u=a(o.fontStyle,r.defaultFontStyle),c=a(o.fontFamily,r.defaultFontFamily),h=e.fontString(d,u,c),f=0,g=n.top,m=n.left,p=n.bottom,v=n.right;i.fillStyle=a(o.fontColor,r.defaultFontColor),i.font=h,n.isHorizontal()?(s=m+(v-m)/2,l=g+(p-g)/2):(s="left"===o.position?m+d/2:v-d/2,l=g+(p-g)/2,f=Math.PI*("left"===o.position?-.5:.5)),i.save(),i.translate(s,l),i.rotate(f),i.textAlign="center",i.textBaseline="middle",i.fillText(o.text,0,0),i.restore()}}}),t.plugins.register({beforeInit:function(e){var n=e.options,i=n.title;i&&(e.titleBlock=new t.Title({ctx:e.chart.ctx,options:i,chart:e}),t.layoutService.addBox(e,e.titleBlock))}})}},{}],34:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return e&&(a.isArray(e)?Array.prototype.push.apply(t,e):t.push(e)),t}function n(t){if(!t.length)return!1;var e,n,i=[],a=[];for(e=0,n=t.length;n>e;++e){var o=t[e];if(o&&o.hasValue()){var r=o.tooltipPosition();i.push(r.x),a.push(r.y)}}var s=0,l=0;for(e=0;e<i.length;++e)i[e]&&(s+=i[e],l+=a[e]);return{x:Math.round(s/i.length),y:Math.round(l/i.length)}}function i(t){var e=t._xScale,n=t._yScale||t._scale,i=t._index,a=t._datasetIndex;return{xLabel:e?e.getLabelForIndex(i,a):"",yLabel:n?n.getLabelForIndex(i,a):"",index:i,datasetIndex:a}}var a=t.helpers;t.defaults.global.tooltips={enabled:!0,custom:null,mode:"single",backgroundColor:"rgba(0,0,0,0.8)",titleFontStyle:"bold",titleSpacing:2,titleMarginBottom:6,titleFontColor:"#fff",titleAlign:"left",bodySpacing:2,bodyFontColor:"#fff",bodyAlign:"left",footerFontStyle:"bold",footerSpacing:2,footerMarginTop:6,footerFontColor:"#fff",footerAlign:"left",yPadding:6,xPadding:6,yAlign:"center",xAlign:"center",caretSize:5,cornerRadius:6,multiKeyBackground:"#fff",callbacks:{beforeTitle:a.noop,title:function(t,e){var n="",i=e.labels,a=i?i.length:0;if(t.length>0){var o=t[0];o.xLabel?n=o.xLabel:a>0&&o.index<a&&(n=i[o.index])}return n},afterTitle:a.noop,beforeBody:a.noop,beforeLabel:a.noop,label:function(t,e){var n=e.datasets[t.datasetIndex].label||"";return n+": "+t.yLabel},labelColor:function(t,e){var n=e.getDatasetMeta(t.datasetIndex),i=n.data[t.index],a=i._view;return{borderColor:a.borderColor,backgroundColor:a.backgroundColor}},afterLabel:a.noop,afterBody:a.noop,beforeFooter:a.noop,footer:a.noop,afterFooter:a.noop}},t.Tooltip=t.Element.extend({initialize:function(){var e=this,n=t.defaults.global,i=e._options,o=a.getValueOrDefault;a.extend(e,{_model:{xPadding:i.xPadding,yPadding:i.yPadding,xAlign:i.xAlign,yAlign:i.yAlign,bodyFontColor:i.bodyFontColor,_bodyFontFamily:o(i.bodyFontFamily,n.defaultFontFamily),_bodyFontStyle:o(i.bodyFontStyle,n.defaultFontStyle),_bodyAlign:i.bodyAlign,bodyFontSize:o(i.bodyFontSize,n.defaultFontSize),bodySpacing:i.bodySpacing,titleFontColor:i.titleFontColor,_titleFontFamily:o(i.titleFontFamily,n.defaultFontFamily),_titleFontStyle:o(i.titleFontStyle,n.defaultFontStyle),titleFontSize:o(i.titleFontSize,n.defaultFontSize),_titleAlign:i.titleAlign,titleSpacing:i.titleSpacing,titleMarginBottom:i.titleMarginBottom,footerFontColor:i.footerFontColor,_footerFontFamily:o(i.footerFontFamily,n.defaultFontFamily),_footerFontStyle:o(i.footerFontStyle,n.defaultFontStyle),footerFontSize:o(i.footerFontSize,n.defaultFontSize),_footerAlign:i.footerAlign,footerSpacing:i.footerSpacing,footerMarginTop:i.footerMarginTop,caretSize:i.caretSize,cornerRadius:i.cornerRadius,backgroundColor:i.backgroundColor,opacity:0,legendColorBackground:i.multiKeyBackground}})},getTitle:function(){var t=this,n=t._options,i=n.callbacks,a=i.beforeTitle.apply(t,arguments),o=i.title.apply(t,arguments),r=i.afterTitle.apply(t,arguments),s=[];return s=e(s,a),s=e(s,o),s=e(s,r)},getBeforeBody:function(){var t=this._options.callbacks.beforeBody.apply(this,arguments);return a.isArray(t)?t:void 0!==t?[t]:[]},getBody:function(t,n){var i=this,o=i._options.callbacks,r=[];return a.each(t,function(t){var a={before:[],lines:[],after:[]};e(a.before,o.beforeLabel.call(i,t,n)),e(a.lines,o.label.call(i,t,n)),e(a.after,o.afterLabel.call(i,t,n)),r.push(a)}),r},getAfterBody:function(){var t=this._options.callbacks.afterBody.apply(this,arguments);return a.isArray(t)?t:void 0!==t?[t]:[]},getFooter:function(){var t=this,n=t._options.callbacks,i=n.beforeFooter.apply(t,arguments),a=n.footer.apply(t,arguments),o=n.afterFooter.apply(t,arguments),r=[];return r=e(r,i),r=e(r,a),r=e(r,o)},update:function(t){var e,o,r=this,s=r._options,l=r._model,d=r._active,u=r._data,c=r._chartInstance;if(d.length){l.opacity=1;var h=[],f=n(d),g=[];for(e=0,o=d.length;o>e;++e)g.push(i(d[e]));s.itemSort&&(g=g.sort(function(t,e){return s.itemSort(t,e,u)})),d.length>1&&a.each(g,function(t){h.push(s.callbacks.labelColor.call(r,t,c))}),a.extend(l,{title:r.getTitle(g,u),beforeBody:r.getBeforeBody(g,u),body:r.getBody(g,u),afterBody:r.getAfterBody(g,u),footer:r.getFooter(g,u),x:Math.round(f.x),y:Math.round(f.y),caretPadding:a.getValueOrDefault(f.padding,2),labelColors:h});var m=r.getTooltipSize(l);r.determineAlignment(m),a.extend(l,r.getBackgroundPoint(l,m))}else r._model.opacity=0;return t&&s.custom&&s.custom.call(r,l),r},getTooltipSize:function(t){var e=this._chart.ctx,n={height:2*t.yPadding,width:0},i=t.body,o=i.reduce(function(t,e){
-return t+e.before.length+e.lines.length+e.after.length},0);o+=t.beforeBody.length+t.afterBody.length;var r=t.title.length,s=t.footer.length,l=t.titleFontSize,d=t.bodyFontSize,u=t.footerFontSize;n.height+=r*l,n.height+=(r-1)*t.titleSpacing,n.height+=r?t.titleMarginBottom:0,n.height+=o*d,n.height+=o?(o-1)*t.bodySpacing:0,n.height+=s?t.footerMarginTop:0,n.height+=s*u,n.height+=s?(s-1)*t.footerSpacing:0;var c=0,h=function(t){n.width=Math.max(n.width,e.measureText(t).width+c)};return e.font=a.fontString(l,t._titleFontStyle,t._titleFontFamily),a.each(t.title,h),e.font=a.fontString(d,t._bodyFontStyle,t._bodyFontFamily),a.each(t.beforeBody.concat(t.afterBody),h),c=i.length>1?d+2:0,a.each(i,function(t){a.each(t.before,h),a.each(t.lines,h),a.each(t.after,h)}),c=0,e.font=a.fontString(u,t._footerFontStyle,t._footerFontFamily),a.each(t.footer,h),n.width+=2*t.xPadding,n},determineAlignment:function(t){var e=this,n=e._model,i=e._chart,a=e._chartInstance.chartArea;n.y<t.height?n.yAlign="top":n.y>i.height-t.height&&(n.yAlign="bottom");var o,r,s,l,d,u=(a.left+a.right)/2,c=(a.top+a.bottom)/2;"center"===n.yAlign?(o=function(t){return u>=t},r=function(t){return t>u}):(o=function(e){return e<=t.width/2},r=function(e){return e>=i.width-t.width/2}),s=function(e){return e+t.width>i.width},l=function(e){return e-t.width<0},d=function(t){return c>=t?"top":"bottom"},o(n.x)?(n.xAlign="left",s(n.x)&&(n.xAlign="center",n.yAlign=d(n.y))):r(n.x)&&(n.xAlign="right",l(n.x)&&(n.xAlign="center",n.yAlign=d(n.y)))},getBackgroundPoint:function(t,e){var n={x:t.x,y:t.y},i=t.caretSize,a=t.caretPadding,o=t.cornerRadius,r=t.xAlign,s=t.yAlign,l=i+a,d=o+a;return"right"===r?n.x-=e.width:"center"===r&&(n.x-=e.width/2),"top"===s?n.y+=l:"bottom"===s?n.y-=e.height+l:n.y-=e.height/2,"center"===s?"left"===r?n.x+=l:"right"===r&&(n.x-=l):"left"===r?n.x-=d:"right"===r&&(n.x+=d),n},drawCaret:function(t,e,n){var i,o,r,s,l,d,u=this._view,c=this._chart.ctx,h=u.caretSize,f=u.cornerRadius,g=u.xAlign,m=u.yAlign,p=t.x,v=t.y,b=e.width,y=e.height;"center"===m?("left"===g?(i=p,o=i-h,r=i):(i=p+b,o=i+h,r=i),l=v+y/2,s=l-h,d=l+h):("left"===g?(i=p+f,o=i+h,r=o+h):"right"===g?(i=p+b-f,o=i-h,r=o-h):(o=p+b/2,i=o-h,r=o+h),"top"===m?(s=v,l=s-h,d=s):(s=v+y,l=s+h,d=s));var x=a.color(u.backgroundColor);c.fillStyle=x.alpha(n*x.alpha()).rgbString(),c.beginPath(),c.moveTo(i,s),c.lineTo(o,l),c.lineTo(r,d),c.closePath(),c.fill()},drawTitle:function(t,e,n,i){var o=e.title;if(o.length){n.textAlign=e._titleAlign,n.textBaseline="top";var r=e.titleFontSize,s=e.titleSpacing,l=a.color(e.titleFontColor);n.fillStyle=l.alpha(i*l.alpha()).rgbString(),n.font=a.fontString(r,e._titleFontStyle,e._titleFontFamily);var d,u;for(d=0,u=o.length;u>d;++d)n.fillText(o[d],t.x,t.y),t.y+=r+s,d+1===o.length&&(t.y+=e.titleMarginBottom-s)}},drawBody:function(t,e,n,i){var o=e.bodyFontSize,r=e.bodySpacing,s=e.body;n.textAlign=e._bodyAlign,n.textBaseline="top";var l=a.color(e.bodyFontColor),d=l.alpha(i*l.alpha()).rgbString();n.fillStyle=d,n.font=a.fontString(o,e._bodyFontStyle,e._bodyFontFamily);var u=0,c=function(e){n.fillText(e,t.x+u,t.y),t.y+=o+r};a.each(e.beforeBody,c);var h=s.length>1;u=h?o+2:0,a.each(s,function(r,s){a.each(r.before,c),a.each(r.lines,function(r){h&&(n.fillStyle=a.color(e.legendColorBackground).alpha(i).rgbaString(),n.fillRect(t.x,t.y,o,o),n.strokeStyle=a.color(e.labelColors[s].borderColor).alpha(i).rgbaString(),n.strokeRect(t.x,t.y,o,o),n.fillStyle=a.color(e.labelColors[s].backgroundColor).alpha(i).rgbaString(),n.fillRect(t.x+1,t.y+1,o-2,o-2),n.fillStyle=d),c(r)}),a.each(r.after,c)}),u=0,a.each(e.afterBody,c),t.y-=r},drawFooter:function(t,e,n,i){var o=e.footer;if(o.length){t.y+=e.footerMarginTop,n.textAlign=e._footerAlign,n.textBaseline="top";var r=a.color(e.footerFontColor);n.fillStyle=r.alpha(i*r.alpha()).rgbString(),n.font=a.fontString(e.footerFontSize,e._footerFontStyle,e._footerFontFamily),a.each(o,function(i){n.fillText(i,t.x,t.y),t.y+=e.footerFontSize+e.footerSpacing})}},draw:function(){var t=this._chart.ctx,e=this._view;if(0!==e.opacity){var n=this.getTooltipSize(e),i={x:e.x,y:e.y},o=Math.abs(e.opacity<.001)?0:e.opacity;if(this._options.enabled){var r=a.color(e.backgroundColor);t.fillStyle=r.alpha(o*r.alpha()).rgbString(),a.drawRoundedRectangle(t,i.x,i.y,n.width,n.height,e.cornerRadius),t.fill(),this.drawCaret(i,n,o),i.x+=e.xPadding,i.y+=e.yPadding,this.drawTitle(i,e,t,o),this.drawBody(i,e,t,o),this.drawFooter(i,e,t,o)}}}})}},{}],35:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=t.defaults.global;n.elements.arc={backgroundColor:n.defaultColor,borderColor:"#fff",borderWidth:2},t.elements.Arc=t.Element.extend({inLabelRange:function(t){var e=this._view;return e?Math.pow(t-e.x,2)<Math.pow(e.radius+e.hoverRadius,2):!1},inRange:function(t,n){var i=this._view;if(i){for(var a=e.getAngleFromPoint(i,{x:t,y:n}),o=a.angle,r=a.distance,s=i.startAngle,l=i.endAngle;s>l;)l+=2*Math.PI;for(;o>l;)o-=2*Math.PI;for(;s>o;)o+=2*Math.PI;var d=o>=s&&l>=o,u=r>=i.innerRadius&&r<=i.outerRadius;return d&&u}return!1},tooltipPosition:function(){var t=this._view,e=t.startAngle+(t.endAngle-t.startAngle)/2,n=(t.outerRadius-t.innerRadius)/2+t.innerRadius;return{x:t.x+Math.cos(e)*n,y:t.y+Math.sin(e)*n}},draw:function(){var t=this._chart.ctx,e=this._view,n=e.startAngle,i=e.endAngle;t.beginPath(),t.arc(e.x,e.y,e.outerRadius,n,i),t.arc(e.x,e.y,e.innerRadius,i,n,!0),t.closePath(),t.strokeStyle=e.borderColor,t.lineWidth=e.borderWidth,t.fillStyle=e.backgroundColor,t.fill(),t.lineJoin="bevel",e.borderWidth&&t.stroke()}})}},{}],36:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=t.defaults.global;t.defaults.global.elements.line={tension:.4,backgroundColor:n.defaultColor,borderWidth:3,borderColor:n.defaultColor,borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",capBezierPoints:!0,fill:!0},t.elements.Line=t.Element.extend({draw:function(){function t(t,e){var n=e._view;e._view.steppedLine===!0?(l.lineTo(n.x,t._view.y),l.lineTo(n.x,n.y)):0===e._view.tension?l.lineTo(n.x,n.y):l.bezierCurveTo(t._view.controlPointNextX,t._view.controlPointNextY,n.controlPointPreviousX,n.controlPointPreviousY,n.x,n.y)}var i=this,a=i._view,o=a.spanGaps,r=a.scaleZero,s=i._loop,l=i._chart.ctx;l.save();var d=i._children.slice(),u=-1;s&&d.length&&d.push(d[0]);var c,h,f,g;if(d.length&&a.fill){for(l.beginPath(),c=0;c<d.length;++c)h=d[c],f=e.previousItem(d,c),g=h._view,0===c?(s?l.moveTo(r.x,r.y):l.moveTo(g.x,r),g.skip||(u=c,l.lineTo(g.x,g.y))):(f=-1===u?f:d[u],g.skip?o||u!==c-1||(s?l.lineTo(r.x,r.y):l.lineTo(f._view.x,r)):(u!==c-1?o&&-1!==u?t(f,h):s?l.lineTo(g.x,g.y):(l.lineTo(g.x,r),l.lineTo(g.x,g.y)):t(f,h),u=c));s||-1===u||l.lineTo(d[u]._view.x,r),l.fillStyle=a.backgroundColor||n.defaultColor,l.closePath(),l.fill()}var m=n.elements.line;for(l.lineCap=a.borderCapStyle||m.borderCapStyle,l.setLineDash&&l.setLineDash(a.borderDash||m.borderDash),l.lineDashOffset=a.borderDashOffset||m.borderDashOffset,l.lineJoin=a.borderJoinStyle||m.borderJoinStyle,l.lineWidth=a.borderWidth||m.borderWidth,l.strokeStyle=a.borderColor||n.defaultColor,l.beginPath(),u=-1,c=0;c<d.length;++c)h=d[c],f=e.previousItem(d,c),g=h._view,0===c?g.skip||(l.moveTo(g.x,g.y),u=c):(f=-1===u?f:d[u],g.skip||(u!==c-1&&!o||-1===u?l.moveTo(g.x,g.y):t(f,h),u=c));l.stroke(),l.restore()}})}},{}],37:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=t.defaults.global,i=n.defaultColor;n.elements.point={radius:3,pointStyle:"circle",backgroundColor:i,borderWidth:1,borderColor:i,hitRadius:1,hoverRadius:4,hoverBorderWidth:1},t.elements.Point=t.Element.extend({inRange:function(t,e){var n=this._view;return n?Math.pow(t-n.x,2)+Math.pow(e-n.y,2)<Math.pow(n.hitRadius+n.radius,2):!1},inLabelRange:function(t){var e=this._view;return e?Math.pow(t-e.x,2)<Math.pow(e.radius+e.hitRadius,2):!1},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y,padding:t.radius+t.borderWidth}},draw:function(){var a=this._view,o=this._chart.ctx,r=a.pointStyle,s=a.radius,l=a.x,d=a.y;a.skip||(o.strokeStyle=a.borderColor||i,o.lineWidth=e.getValueOrDefault(a.borderWidth,n.elements.point.borderWidth),o.fillStyle=a.backgroundColor||i,t.canvasHelpers.drawPoint(o,r,s,l,d))}})}},{}],38:[function(t,e,n){"use strict";e.exports=function(t){var e=t.defaults.global;e.elements.rectangle={backgroundColor:e.defaultColor,borderWidth:0,borderColor:e.defaultColor,borderSkipped:"bottom"},t.elements.Rectangle=t.Element.extend({draw:function(){function t(t){return l[(u+t)%4]}var e=this._chart.ctx,n=this._view,i=n.width/2,a=n.x-i,o=n.x+i,r=n.base-(n.base-n.y),s=n.borderWidth/2;n.borderWidth&&(a+=s,o-=s,r+=s),e.beginPath(),e.fillStyle=n.backgroundColor,e.strokeStyle=n.borderColor,e.lineWidth=n.borderWidth;var l=[[a,n.base],[a,r],[o,r],[o,n.base]],d=["bottom","left","top","right"],u=d.indexOf(n.borderSkipped,0);-1===u&&(u=0),e.moveTo.apply(e,t(0));for(var c=1;4>c;c++)e.lineTo.apply(e,t(c));e.fill(),n.borderWidth&&e.stroke()},height:function(){var t=this._view;return t.base-t.y},inRange:function(t,e){var n=this._view;return n?n.y<n.base?t>=n.x-n.width/2&&t<=n.x+n.width/2&&e>=n.y&&e<=n.base:t>=n.x-n.width/2&&t<=n.x+n.width/2&&e>=n.base&&e<=n.y:!1},inLabelRange:function(t){var e=this._view;return e?t>=e.x-e.width/2&&t<=e.x+e.width/2:!1},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y}}})}},{}],39:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n={position:"bottom"},i=t.Scale.extend({getLabels:function(){var t=this.chart.data;return(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels},determineDataLimits:function(){var t=this,n=t.getLabels();t.minIndex=0,t.maxIndex=n.length-1;var i;void 0!==t.options.ticks.min&&(i=e.indexOf(n,t.options.ticks.min),t.minIndex=-1!==i?i:t.minIndex),void 0!==t.options.ticks.max&&(i=e.indexOf(n,t.options.ticks.max),t.maxIndex=-1!==i?i:t.maxIndex),t.min=n[t.minIndex],t.max=n[t.maxIndex]},buildTicks:function(){var t=this,e=t.getLabels();t.ticks=0===t.minIndex&&t.maxIndex===e.length-1?e:e.slice(t.minIndex,t.maxIndex+1)},getLabelForIndex:function(t,e){var n=this,i=n.chart.data,a=n.isHorizontal();return i.xLabels&&a||i.yLabels&&!a?n.getRightValue(i.datasets[e].data[t]):n.ticks[t]},getPixelForValue:function(t,e,n,i){var a=this,o=Math.max(a.maxIndex+1-a.minIndex-(a.options.gridLines.offsetGridLines?0:1),1);if(void 0!==t&&isNaN(e)){var r=a.getLabels(),s=r.indexOf(t);e=-1!==s?s:e}if(a.isHorizontal()){var l=a.width-(a.paddingLeft+a.paddingRight),d=l/o,u=d*(e-a.minIndex)+a.paddingLeft;return(a.options.gridLines.offsetGridLines&&i||a.maxIndex===a.minIndex&&i)&&(u+=d/2),a.left+Math.round(u)}var c=a.height-(a.paddingTop+a.paddingBottom),h=c/o,f=h*(e-a.minIndex)+a.paddingTop;return a.options.gridLines.offsetGridLines&&i&&(f+=h/2),a.top+Math.round(f)},getPixelForTick:function(t,e){return this.getPixelForValue(this.ticks[t],t+this.minIndex,null,e)},getValueForPixel:function(t){var e,n=this,i=Math.max(n.ticks.length-(n.options.gridLines.offsetGridLines?0:1),1),a=n.isHorizontal(),o=a?n.width-(n.paddingLeft+n.paddingRight):n.height-(n.paddingTop+n.paddingBottom),r=o/i;return t-=a?n.left:n.top,n.options.gridLines.offsetGridLines&&(t-=r/2),t-=a?n.paddingLeft:n.paddingTop,e=0>=t?0:Math.round(t/r)},getBasePixel:function(){return this.bottom}});t.scaleService.registerScaleType("category",i,n)}},{}],40:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n={position:"left",ticks:{callback:function(t,n,i){var a=i.length>3?i[2]-i[1]:i[1]-i[0];Math.abs(a)>1&&t!==Math.floor(t)&&(a=t-Math.floor(t));var o=e.log10(Math.abs(a)),r="";if(0!==t){var s=-1*Math.floor(o);s=Math.max(Math.min(s,20),0),r=t.toFixed(s)}else r="0";return r}}},i=t.LinearScaleBase.extend({determineDataLimits:function(){function t(t){return s?t.xAxisID===n.id:t.yAxisID===n.id}var n=this,i=n.options,a=n.chart,o=a.data,r=o.datasets,s=n.isHorizontal();if(n.min=null,n.max=null,i.stacked){var l={};e.each(r,function(o,r){var s=a.getDatasetMeta(r);void 0===l[s.type]&&(l[s.type]={positiveValues:[],negativeValues:[]});var d=l[s.type].positiveValues,u=l[s.type].negativeValues;a.isDatasetVisible(r)&&t(s)&&e.each(o.data,function(t,e){var a=+n.getRightValue(t);isNaN(a)||s.data[e].hidden||(d[e]=d[e]||0,u[e]=u[e]||0,i.relativePoints?d[e]=100:0>a?u[e]+=a:d[e]+=a)})}),e.each(l,function(t){var i=t.positiveValues.concat(t.negativeValues),a=e.min(i),o=e.max(i);n.min=null===n.min?a:Math.min(n.min,a),n.max=null===n.max?o:Math.max(n.max,o)})}else e.each(r,function(i,o){var r=a.getDatasetMeta(o);a.isDatasetVisible(o)&&t(r)&&e.each(i.data,function(t,e){var i=+n.getRightValue(t);isNaN(i)||r.data[e].hidden||(null===n.min?n.min=i:i<n.min&&(n.min=i),null===n.max?n.max=i:i>n.max&&(n.max=i))})});this.handleTickRangeOptions()},getTickLimit:function(){var n,i=this,a=i.options.ticks;if(i.isHorizontal())n=Math.min(a.maxTicksLimit?a.maxTicksLimit:11,Math.ceil(i.width/50));else{var o=e.getValueOrDefault(a.fontSize,t.defaults.global.defaultFontSize);n=Math.min(a.maxTicksLimit?a.maxTicksLimit:11,Math.ceil(i.height/(2*o)))}return n},handleDirectionalChanges:function(){this.isHorizontal()||this.ticks.reverse()},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForValue:function(t){var e,n,i=this,a=i.paddingLeft,o=i.paddingBottom,r=i.start,s=+i.getRightValue(t),l=i.end-r;return i.isHorizontal()?(n=i.width-(a+i.paddingRight),e=i.left+n/l*(s-r),Math.round(e+a)):(n=i.height-(i.paddingTop+o),e=i.bottom-o-n/l*(s-r),Math.round(e))},getValueForPixel:function(t){var e=this,n=e.isHorizontal(),i=e.paddingLeft,a=e.paddingBottom,o=n?e.width-(i+e.paddingRight):e.height-(e.paddingTop+a),r=(n?t-e.left-i:e.bottom-a-t)/o;return e.start+(e.end-e.start)*r},getPixelForTick:function(t){return this.getPixelForValue(this.ticksAsNumbers[t])}});t.scaleService.registerScaleType("linear",i,n)}},{}],41:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=e.noop;t.LinearScaleBase=t.Scale.extend({handleTickRangeOptions:function(){var t=this,n=t.options,i=n.ticks;if(i.beginAtZero){var a=e.sign(t.min),o=e.sign(t.max);0>a&&0>o?t.max=0:a>0&&o>0&&(t.min=0)}void 0!==i.min?t.min=i.min:void 0!==i.suggestedMin&&(t.min=Math.min(t.min,i.suggestedMin)),void 0!==i.max?t.max=i.max:void 0!==i.suggestedMax&&(t.max=Math.max(t.max,i.suggestedMax)),t.min===t.max&&(t.max++,i.beginAtZero||t.min--)},getTickLimit:n,handleDirectionalChanges:n,buildTicks:function(){var t=this,n=t.options,i=t.ticks=[],a=n.ticks,o=e.getValueOrDefault,r=t.getTickLimit();r=Math.max(2,r);var s,l=a.fixedStepSize&&a.fixedStepSize>0||a.stepSize&&a.stepSize>0;if(l)s=o(a.fixedStepSize,a.stepSize);else{var d=e.niceNum(t.max-t.min,!1);s=e.niceNum(d/(r-1),!0)}var u=Math.floor(t.min/s)*s,c=Math.ceil(t.max/s)*s,h=(c-u)/s;h=e.almostEquals(h,Math.round(h),s/1e3)?Math.round(h):Math.ceil(h),i.push(void 0!==a.min?a.min:u);for(var f=1;h>f;++f)i.push(u+f*s);i.push(void 0!==a.max?a.max:c),t.handleDirectionalChanges(),t.max=e.max(i),t.min=e.min(i),a.reverse?(i.reverse(),t.start=t.max,t.end=t.min):(t.start=t.min,t.end=t.max)},convertTicksToLabels:function(){var e=this;e.ticksAsNumbers=e.ticks.slice(),e.zeroLineIndex=e.ticks.indexOf(0),t.Scale.prototype.convertTicksToLabels.call(e)}})}},{}],42:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n={position:"left",ticks:{callback:function(t,n,i){var a=t/Math.pow(10,Math.floor(e.log10(t)));return 0===t?"0":1===a||2===a||5===a||0===n||n===i.length-1?t.toExponential():""}}},i=t.Scale.extend({determineDataLimits:function(){function t(t){return d?t.xAxisID===n.id:t.yAxisID===n.id}var n=this,i=n.options,a=i.ticks,o=n.chart,r=o.data,s=r.datasets,l=e.getValueOrDefault,d=n.isHorizontal();if(n.min=null,n.max=null,n.minNotZero=null,i.stacked){var u={};e.each(s,function(a,r){var s=o.getDatasetMeta(r);o.isDatasetVisible(r)&&t(s)&&(void 0===u[s.type]&&(u[s.type]=[]),e.each(a.data,function(t,e){var a=u[s.type],o=+n.getRightValue(t);isNaN(o)||s.data[e].hidden||(a[e]=a[e]||0,i.relativePoints?a[e]=100:a[e]+=o)}))}),e.each(u,function(t){var i=e.min(t),a=e.max(t);n.min=null===n.min?i:Math.min(n.min,i),n.max=null===n.max?a:Math.max(n.max,a)})}else e.each(s,function(i,a){var r=o.getDatasetMeta(a);o.isDatasetVisible(a)&&t(r)&&e.each(i.data,function(t,e){var i=+n.getRightValue(t);isNaN(i)||r.data[e].hidden||(null===n.min?n.min=i:i<n.min&&(n.min=i),null===n.max?n.max=i:i>n.max&&(n.max=i),0!==i&&(null===n.minNotZero||i<n.minNotZero)&&(n.minNotZero=i))})});n.min=l(a.min,n.min),n.max=l(a.max,n.max),n.min===n.max&&(0!==n.min&&null!==n.min?(n.min=Math.pow(10,Math.floor(e.log10(n.min))-1),n.max=Math.pow(10,Math.floor(e.log10(n.max))+1)):(n.min=1,n.max=10))},buildTicks:function(){for(var t=this,n=t.options,i=n.ticks,a=e.getValueOrDefault,o=t.ticks=[],r=a(i.min,Math.pow(10,Math.floor(e.log10(t.min))));r<t.max;){o.push(r);var s,l;0===r?(s=Math.floor(e.log10(t.minNotZero)),l=Math.round(t.minNotZero/Math.pow(10,s))):(s=Math.floor(e.log10(r)),l=Math.floor(r/Math.pow(10,s))+1),10===l&&(l=1,++s),r=l*Math.pow(10,s)}var d=a(i.max,r);o.push(d),t.isHorizontal()||o.reverse(),t.max=e.max(o),t.min=e.min(o),i.reverse?(o.reverse(),t.start=t.max,t.end=t.min):(t.start=t.min,t.end=t.max)},convertTicksToLabels:function(){this.tickValues=this.ticks.slice(),t.Scale.prototype.convertTicksToLabels.call(this)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForTick:function(t){return this.getPixelForValue(this.tickValues[t])},getPixelForValue:function(t){var n,i,a,o=this,r=o.start,s=+o.getRightValue(t),l=o.paddingTop,d=o.paddingBottom,u=o.paddingLeft,c=o.options,h=c.ticks;return o.isHorizontal()?(a=e.log10(o.end)-e.log10(r),0===s?i=o.left+u:(n=o.width-(u+o.paddingRight),i=o.left+n/a*(e.log10(s)-e.log10(r)),i+=u)):(n=o.height-(l+d),0!==r||h.reverse?0===o.end&&h.reverse?(a=e.log10(o.start)-e.log10(o.minNotZero),i=s===o.end?o.top+l:s===o.minNotZero?o.top+l+.02*n:o.top+l+.02*n+.98*n/a*(e.log10(s)-e.log10(o.minNotZero))):(a=e.log10(o.end)-e.log10(r),n=o.height-(l+d),i=o.bottom-d-n/a*(e.log10(s)-e.log10(r))):(a=e.log10(o.end)-e.log10(o.minNotZero),i=s===r?o.bottom-d:s===o.minNotZero?o.bottom-d-.02*n:o.bottom-d-.02*n-.98*n/a*(e.log10(s)-e.log10(o.minNotZero)))),i},getValueForPixel:function(t){var n,i,a=this,o=e.log10(a.end)-e.log10(a.start);return a.isHorizontal()?(i=a.width-(a.paddingLeft+a.paddingRight),n=a.start*Math.pow(10,(t-a.left-a.paddingLeft)*o/i)):(i=a.height-(a.paddingTop+a.paddingBottom),n=Math.pow(10,(a.bottom-a.paddingBottom-t)*o/i)/a.start),n}});t.scaleService.registerScaleType("logarithmic",i,n)}},{}],43:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=t.defaults.global,i={display:!0,animate:!0,lineArc:!1,position:"chartArea",angleLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1},ticks:{showLabelBackdrop:!0,backdropColor:"rgba(255,255,255,0.75)",backdropPaddingY:2,backdropPaddingX:2},pointLabels:{fontSize:10,callback:function(t){return t}}},a=t.LinearScaleBase.extend({getValueCount:function(){return this.chart.data.labels.length},setDimensions:function(){var t=this,i=t.options,a=i.ticks;t.width=t.maxWidth,t.height=t.maxHeight,t.xCenter=Math.round(t.width/2),t.yCenter=Math.round(t.height/2);var o=e.min([t.height,t.width]),r=e.getValueOrDefault(a.fontSize,n.defaultFontSize);t.drawingArea=i.display?o/2-(r/2+a.backdropPaddingY):o/2},determineDataLimits:function(){var t=this,n=t.chart;t.min=null,t.max=null,e.each(n.data.datasets,function(i,a){if(n.isDatasetVisible(a)){var o=n.getDatasetMeta(a);e.each(i.data,function(e,n){var i=+t.getRightValue(e);isNaN(i)||o.data[n].hidden||(null===t.min?t.min=i:i<t.min&&(t.min=i),null===t.max?t.max=i:i>t.max&&(t.max=i))})}}),t.handleTickRangeOptions()},getTickLimit:function(){var t=this.options.ticks,i=e.getValueOrDefault(t.fontSize,n.defaultFontSize);return Math.min(t.maxTicksLimit?t.maxTicksLimit:11,Math.ceil(this.drawingArea/(1.5*i)))},convertTicksToLabels:function(){var e=this;t.LinearScaleBase.prototype.convertTicksToLabels.call(e),e.pointLabels=e.chart.data.labels.map(e.options.pointLabels.callback,e)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},fit:function(){var t,i,a,o,r,s,l,d,u,c,h,f,g=this.options.pointLabels,m=e.getValueOrDefault(g.fontSize,n.defaultFontSize),p=e.getValueOrDefault(g.fontStyle,n.defaultFontStyle),v=e.getValueOrDefault(g.fontFamily,n.defaultFontFamily),b=e.fontString(m,p,v),y=e.min([this.height/2-m-5,this.width/2]),x=this.width,k=0;for(this.ctx.font=b,i=0;i<this.getValueCount();i++){t=this.getPointPosition(i,y),a=this.ctx.measureText(this.pointLabels[i]?this.pointLabels[i]:"").width+5;var S=this.getIndexAngle(i)+Math.PI/2,w=360*S/(2*Math.PI)%360;0===w||180===w?(o=a/2,t.x+o>x&&(x=t.x+o,r=i),t.x-o<k&&(k=t.x-o,l=i)):180>w?t.x+a>x&&(x=t.x+a,r=i):t.x-a<k&&(k=t.x-a,l=i)}u=k,c=Math.ceil(x-this.width),s=this.getIndexAngle(r),d=this.getIndexAngle(l),h=c/Math.sin(s+Math.PI/2),f=u/Math.sin(d+Math.PI/2),h=e.isNumber(h)?h:0,f=e.isNumber(f)?f:0,this.drawingArea=Math.round(y-(f+h)/2),this.setCenterPoint(f,h)},setCenterPoint:function(t,e){var n=this,i=n.width-e-n.drawingArea,a=t+n.drawingArea;n.xCenter=Math.round((a+i)/2+n.left),n.yCenter=Math.round(n.height/2+n.top)},getIndexAngle:function(t){var e=2*Math.PI/this.getValueCount(),n=this.chart.options&&this.chart.options.startAngle?this.chart.options.startAngle:0,i=n*Math.PI*2/360;return t*e-Math.PI/2+i},getDistanceFromCenterForValue:function(t){var e=this;if(null===t)return 0;var n=e.drawingArea/(e.max-e.min);return e.options.reverse?(e.max-t)*n:(t-e.min)*n},getPointPosition:function(t,e){var n=this,i=n.getIndexAngle(t);return{x:Math.round(Math.cos(i)*e)+n.xCenter,y:Math.round(Math.sin(i)*e)+n.yCenter}},getPointPositionForValue:function(t,e){return this.getPointPosition(t,this.getDistanceFromCenterForValue(e))},getBasePosition:function(){var t=this,e=t.min,n=t.max;return t.getPointPositionForValue(0,t.beginAtZero?0:0>e&&0>n?n:e>0&&n>0?e:0)},draw:function(){var t=this,i=t.options,a=i.gridLines,o=i.ticks,r=i.angleLines,s=i.pointLabels,l=e.getValueOrDefault;if(i.display){var d=t.ctx,u=l(o.fontSize,n.defaultFontSize),c=l(o.fontStyle,n.defaultFontStyle),h=l(o.fontFamily,n.defaultFontFamily),f=e.fontString(u,c,h);if(e.each(t.ticks,function(r,s){if(s>0||i.reverse){var c=t.getDistanceFromCenterForValue(t.ticksAsNumbers[s]),h=t.yCenter-c;if(a.display&&0!==s)if(d.strokeStyle=e.getValueAtIndexOrDefault(a.color,s-1),d.lineWidth=e.getValueAtIndexOrDefault(a.lineWidth,s-1),i.lineArc)d.beginPath(),d.arc(t.xCenter,t.yCenter,c,0,2*Math.PI),d.closePath(),d.stroke();else{d.beginPath();for(var g=0;g<t.getValueCount();g++){var m=t.getPointPosition(g,c);0===g?d.moveTo(m.x,m.y):d.lineTo(m.x,m.y)}d.closePath(),d.stroke()}if(o.display){var p=l(o.fontColor,n.defaultFontColor);if(d.font=f,o.showLabelBackdrop){var v=d.measureText(r).width;d.fillStyle=o.backdropColor,d.fillRect(t.xCenter-v/2-o.backdropPaddingX,h-u/2-o.backdropPaddingY,v+2*o.backdropPaddingX,u+2*o.backdropPaddingY)}d.textAlign="center",d.textBaseline="middle",d.fillStyle=p,d.fillText(r,t.xCenter,h)}}}),!i.lineArc){d.lineWidth=r.lineWidth,d.strokeStyle=r.color;for(var g=t.getDistanceFromCenterForValue(i.reverse?t.min:t.max),m=l(s.fontSize,n.defaultFontSize),p=l(s.fontStyle,n.defaultFontStyle),v=l(s.fontFamily,n.defaultFontFamily),b=e.fontString(m,p,v),y=t.getValueCount()-1;y>=0;y--){if(r.display){var x=t.getPointPosition(y,g);d.beginPath(),d.moveTo(t.xCenter,t.yCenter),d.lineTo(x.x,x.y),d.stroke(),d.closePath()}var k=t.getPointPosition(y,g+5),S=l(s.fontColor,n.defaultFontColor);d.font=b,d.fillStyle=S;var w=t.pointLabels,_=this.getIndexAngle(y)+Math.PI/2,M=360*_/(2*Math.PI)%360;0===M||180===M?d.textAlign="center":180>M?d.textAlign="left":d.textAlign="right",90===M||270===M?d.textBaseline="middle":M>270||90>M?d.textBaseline="bottom":d.textBaseline="top",d.fillText(w[y]?w[y]:"",k.x,k.y)}}}}});t.scaleService.registerScaleType("radialLinear",a,i)}},{}],44:[function(t,e,n){"use strict";var i=t(6);i="function"==typeof i?i:window.moment,e.exports=function(t){var e=t.helpers,n={units:[{name:"millisecond",steps:[1,2,5,10,20,50,100,250,500]},{name:"second",steps:[1,2,5,10,30]},{name:"minute",steps:[1,2,5,10,30]},{name:"hour",steps:[1,2,3,6,12]},{name:"day",steps:[1,2,5]},{name:"week",maxStep:4},{name:"month",maxStep:3},{name:"quarter",maxStep:4},{name:"year",maxStep:!1}]},a={position:"bottom",time:{parser:!1,format:!1,unit:!1,round:!1,displayFormat:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm:ss a",hour:"MMM D, hA",day:"ll",week:"ll",month:"MMM YYYY",quarter:"[Q]Q - YYYY",year:"YYYY"}},ticks:{autoSkip:!1}},o=t.Scale.extend({initialize:function(){if(!i)throw new Error("Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com");t.Scale.prototype.initialize.call(this)},getLabelMoment:function(t,e){return null===t||null===e?null:"undefined"!=typeof this.labelMoments[t]?this.labelMoments[t][e]:null},getLabelDiff:function(t,e){var n=this;return null===t||null===e?null:(void 0===n.labelDiffs&&n.buildLabelDiffs(),"undefined"!=typeof n.labelDiffs[t]?n.labelDiffs[t][e]:null)},getMomentStartOf:function(t){var e=this;return"week"===e.options.time.unit&&e.options.time.isoWeekday!==!1?t.clone().startOf("isoWeek").isoWeekday(e.options.time.isoWeekday):t.clone().startOf(e.tickUnit)},determineDataLimits:function(){var t=this;t.labelMoments=[];var n=[];t.chart.data.labels&&t.chart.data.labels.length>0?(e.each(t.chart.data.labels,function(e){var i=t.parseTime(e);i.isValid()&&(t.options.time.round&&i.startOf(t.options.time.round),n.push(i))},t),t.firstTick=i.min.call(t,n),t.lastTick=i.max.call(t,n)):(t.firstTick=null,t.lastTick=null),e.each(t.chart.data.datasets,function(a,o){var r=[],s=t.chart.isDatasetVisible(o);"object"==typeof a.data[0]&&null!==a.data[0]?e.each(a.data,function(e){var n=t.parseTime(t.getRightValue(e));n.isValid()&&(t.options.time.round&&n.startOf(t.options.time.round),r.push(n),s&&(t.firstTick=null!==t.firstTick?i.min(t.firstTick,n):n,t.lastTick=null!==t.lastTick?i.max(t.lastTick,n):n))},t):r=n,t.labelMoments.push(r)},t),t.options.time.min&&(t.firstTick=t.parseTime(t.options.time.min)),t.options.time.max&&(t.lastTick=t.parseTime(t.options.time.max)),t.firstTick=(t.firstTick||i()).clone(),t.lastTick=(t.lastTick||i()).clone()},buildLabelDiffs:function(){var t=this;t.labelDiffs=[];var n=[];t.chart.data.labels&&t.chart.data.labels.length>0&&e.each(t.chart.data.labels,function(e){var i=t.parseTime(e);i.isValid()&&(t.options.time.round&&i.startOf(t.options.time.round),n.push(i.diff(t.firstTick,t.tickUnit,!0)))},t),e.each(t.chart.data.datasets,function(i){var a=[];"object"==typeof i.data[0]&&null!==i.data[0]?e.each(i.data,function(e){var n=t.parseTime(t.getRightValue(e));n.isValid()&&(t.options.time.round&&n.startOf(t.options.time.round),a.push(n.diff(t.firstTick,t.tickUnit,!0)))},t):a=n,t.labelDiffs.push(a)},t)},buildTicks:function(){var i=this;i.ctx.save();var a=e.getValueOrDefault(i.options.ticks.fontSize,t.defaults.global.defaultFontSize),o=e.getValueOrDefault(i.options.ticks.fontStyle,t.defaults.global.defaultFontStyle),r=e.getValueOrDefault(i.options.ticks.fontFamily,t.defaults.global.defaultFontFamily),s=e.fontString(a,o,r);if(i.ctx.font=s,i.ticks=[],i.unitScale=1,i.scaleSizeInUnits=0,i.options.time.unit)i.tickUnit=i.options.time.unit||"day",i.displayFormat=i.options.time.displayFormats[i.tickUnit],i.scaleSizeInUnits=i.lastTick.diff(i.firstTick,i.tickUnit,!0),i.unitScale=e.getValueOrDefault(i.options.time.unitStepSize,1);else{var l=i.isHorizontal()?i.width-(i.paddingLeft+i.paddingRight):i.height-(i.paddingTop+i.paddingBottom),d=i.tickFormatFunction(i.firstTick,0,[]),u=i.ctx.measureText(d).width,c=Math.cos(e.toRadians(i.options.ticks.maxRotation)),h=Math.sin(e.toRadians(i.options.ticks.maxRotation));u=u*c+a*h;var f=l/u;i.tickUnit=i.options.time.minUnit,i.scaleSizeInUnits=i.lastTick.diff(i.firstTick,i.tickUnit,!0),i.displayFormat=i.options.time.displayFormats[i.tickUnit];for(var g=0,m=n.units[g];g<n.units.length;){if(i.unitScale=1,e.isArray(m.steps)&&Math.ceil(i.scaleSizeInUnits/f)<e.max(m.steps)){for(var p=0;p<m.steps.length;++p)if(m.steps[p]>=Math.ceil(i.scaleSizeInUnits/f)){i.unitScale=e.getValueOrDefault(i.options.time.unitStepSize,m.steps[p]);break}break}if(m.maxStep===!1||Math.ceil(i.scaleSizeInUnits/f)<m.maxStep){i.unitScale=e.getValueOrDefault(i.options.time.unitStepSize,Math.ceil(i.scaleSizeInUnits/f));break}++g,m=n.units[g],i.tickUnit=m.name;var v=i.firstTick.diff(i.getMomentStartOf(i.firstTick),i.tickUnit,!0),b=i.getMomentStartOf(i.lastTick.clone().add(1,i.tickUnit)).diff(i.lastTick,i.tickUnit,!0);i.scaleSizeInUnits=i.lastTick.diff(i.firstTick,i.tickUnit,!0)+v+b,i.displayFormat=i.options.time.displayFormats[m.name]}}var y;if(i.options.time.min?y=i.getMomentStartOf(i.firstTick):(i.firstTick=i.getMomentStartOf(i.firstTick),y=i.firstTick),!i.options.time.max){var x=i.getMomentStartOf(i.lastTick),k=x.diff(i.lastTick,i.tickUnit,!0);0>k?i.lastTick=i.getMomentStartOf(i.lastTick.add(1,i.tickUnit)):k>=0&&(i.lastTick=x),i.scaleSizeInUnits=i.lastTick.diff(i.firstTick,i.tickUnit,!0)}i.options.time.displayFormat&&(i.displayFormat=i.options.time.displayFormat),i.ticks.push(i.firstTick.clone());for(var S=1;S<=i.scaleSizeInUnits;++S){var w=y.clone().add(S,i.tickUnit);if(i.options.time.max&&w.diff(i.lastTick,i.tickUnit,!0)>=0)break;S%i.unitScale===0&&i.ticks.push(w)}var _=i.ticks[i.ticks.length-1].diff(i.lastTick,i.tickUnit);(0!==_||0===i.scaleSizeInUnits)&&(i.options.time.max?(i.ticks.push(i.lastTick.clone()),i.scaleSizeInUnits=i.lastTick.diff(i.ticks[0],i.tickUnit,!0)):(i.ticks.push(i.lastTick.clone()),i.scaleSizeInUnits=i.lastTick.diff(i.firstTick,i.tickUnit,!0))),i.ctx.restore(),i.labelDiffs=void 0},getLabelForIndex:function(t,e){var n=this,i=n.chart.data.labels&&t<n.chart.data.labels.length?n.chart.data.labels[t]:"";return"object"==typeof n.chart.data.datasets[e].data[0]&&(i=n.getRightValue(n.chart.data.datasets[e].data[t])),n.options.time.tooltipFormat&&(i=n.parseTime(i).format(n.options.time.tooltipFormat)),i},tickFormatFunction:function(t,n,i){var a=t.format(this.displayFormat),o=this.options.ticks,r=e.getValueOrDefault(o.callback,o.userCallback);return r?r(a,n,i):a},convertTicksToLabels:function(){var t=this;t.tickMoments=t.ticks,t.ticks=t.ticks.map(t.tickFormatFunction,t)},getPixelForValue:function(t,e,n){var i=this,a=null;if(void 0!==e&&void 0!==n&&(a=i.getLabelDiff(n,e)),null===a&&(t&&t.isValid||(t=i.parseTime(i.getRightValue(t))),t&&t.isValid&&t.isValid()&&(a=t.diff(i.firstTick,i.tickUnit,!0))),null!==a){var o=0!==a?a/i.scaleSizeInUnits:a;if(i.isHorizontal()){var r=i.width-(i.paddingLeft+i.paddingRight),s=r*o+i.paddingLeft;return i.left+Math.round(s)}var l=i.height-(i.paddingTop+i.paddingBottom),d=l*o+i.paddingTop;return i.top+Math.round(d)}},getPixelForTick:function(t){return this.getPixelForValue(this.tickMoments[t],null,null)},getValueForPixel:function(t){var e=this,n=e.isHorizontal()?e.width-(e.paddingLeft+e.paddingRight):e.height-(e.paddingTop+e.paddingBottom),a=(t-(e.isHorizontal()?e.left+e.paddingLeft:e.top+e.paddingTop))/n;return a*=e.scaleSizeInUnits,e.firstTick.clone().add(i.duration(a,e.tickUnit).asSeconds(),"seconds")},parseTime:function(t){var e=this;return"string"==typeof e.options.time.parser?i(t,e.options.time.parser):"function"==typeof e.options.time.parser?e.options.time.parser(t):"function"==typeof t.getMonth||"number"==typeof t?i(t):t.isValid&&t.isValid()?t:"string"!=typeof e.options.time.format&&e.options.time.format.call?(console.warn("options.time.format is deprecated and replaced by options.time.parser. See http://nnnick.github.io/Chart.js/docs-v2/#scales-time-scale"),e.options.time.format(t)):i(t,e.options.time.format)}});t.scaleService.registerScaleType("time",o,a)}},{6:6}]},{},[7])(7)}); \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/js/materialize.min.js b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/js/materialize.min.js
deleted file mode 100644
index 1a2cf1a..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/js/materialize.min.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/*!
- * Materialize v0.97.7 (http://materializecss.com)
- * Copyright 2014-2015 Materialize
- * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE)
- */
-if("undefined"==typeof jQuery){var jQuery;jQuery="function"==typeof require?$=require("jquery"):$}jQuery.easing.jswing=jQuery.easing.swing,jQuery.extend(jQuery.easing,{def:"easeOutQuad",swing:function(a,b,c,d,e){return jQuery.easing[jQuery.easing.def](a,b,c,d,e)},easeInQuad:function(a,b,c,d,e){return d*(b/=e)*b+c},easeOutQuad:function(a,b,c,d,e){return-d*(b/=e)*(b-2)+c},easeInOutQuad:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b+c:-d/2*(--b*(b-2)-1)+c},easeInCubic:function(a,b,c,d,e){return d*(b/=e)*b*b+c},easeOutCubic:function(a,b,c,d,e){return d*((b=b/e-1)*b*b+1)+c},easeInOutCubic:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b*b+c:d/2*((b-=2)*b*b+2)+c},easeInQuart:function(a,b,c,d,e){return d*(b/=e)*b*b*b+c},easeOutQuart:function(a,b,c,d,e){return-d*((b=b/e-1)*b*b*b-1)+c},easeInOutQuart:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b*b*b+c:-d/2*((b-=2)*b*b*b-2)+c},easeInQuint:function(a,b,c,d,e){return d*(b/=e)*b*b*b*b+c},easeOutQuint:function(a,b,c,d,e){return d*((b=b/e-1)*b*b*b*b+1)+c},easeInOutQuint:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b*b*b*b+c:d/2*((b-=2)*b*b*b*b+2)+c},easeInSine:function(a,b,c,d,e){return-d*Math.cos(b/e*(Math.PI/2))+d+c},easeOutSine:function(a,b,c,d,e){return d*Math.sin(b/e*(Math.PI/2))+c},easeInOutSine:function(a,b,c,d,e){return-d/2*(Math.cos(Math.PI*b/e)-1)+c},easeInExpo:function(a,b,c,d,e){return 0==b?c:d*Math.pow(2,10*(b/e-1))+c},easeOutExpo:function(a,b,c,d,e){return b==e?c+d:d*(-Math.pow(2,-10*b/e)+1)+c},easeInOutExpo:function(a,b,c,d,e){return 0==b?c:b==e?c+d:(b/=e/2)<1?d/2*Math.pow(2,10*(b-1))+c:d/2*(-Math.pow(2,-10*--b)+2)+c},easeInCirc:function(a,b,c,d,e){return-d*(Math.sqrt(1-(b/=e)*b)-1)+c},easeOutCirc:function(a,b,c,d,e){return d*Math.sqrt(1-(b=b/e-1)*b)+c},easeInOutCirc:function(a,b,c,d,e){return(b/=e/2)<1?-d/2*(Math.sqrt(1-b*b)-1)+c:d/2*(Math.sqrt(1-(b-=2)*b)+1)+c},easeInElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(0==b)return c;if(1==(b/=e))return c+d;if(g||(g=.3*e),h<Math.abs(d)){h=d;var f=g/4}else var f=g/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(b-=1))*Math.sin((b*e-f)*(2*Math.PI)/g))+c},easeOutElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(0==b)return c;if(1==(b/=e))return c+d;if(g||(g=.3*e),h<Math.abs(d)){h=d;var f=g/4}else var f=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*b)*Math.sin((b*e-f)*(2*Math.PI)/g)+d+c},easeInOutElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(0==b)return c;if(2==(b/=e/2))return c+d;if(g||(g=e*(.3*1.5)),h<Math.abs(d)){h=d;var f=g/4}else var f=g/(2*Math.PI)*Math.asin(d/h);return 1>b?-.5*(h*Math.pow(2,10*(b-=1))*Math.sin((b*e-f)*(2*Math.PI)/g))+c:h*Math.pow(2,-10*(b-=1))*Math.sin((b*e-f)*(2*Math.PI)/g)*.5+d+c},easeInBack:function(a,b,c,d,e,f){return void 0==f&&(f=1.70158),d*(b/=e)*b*((f+1)*b-f)+c},easeOutBack:function(a,b,c,d,e,f){return void 0==f&&(f=1.70158),d*((b=b/e-1)*b*((f+1)*b+f)+1)+c},easeInOutBack:function(a,b,c,d,e,f){return void 0==f&&(f=1.70158),(b/=e/2)<1?d/2*(b*b*(((f*=1.525)+1)*b-f))+c:d/2*((b-=2)*b*(((f*=1.525)+1)*b+f)+2)+c},easeInBounce:function(a,b,c,d,e){return d-jQuery.easing.easeOutBounce(a,e-b,0,d,e)+c},easeOutBounce:function(a,b,c,d,e){return(b/=e)<1/2.75?d*(7.5625*b*b)+c:2/2.75>b?d*(7.5625*(b-=1.5/2.75)*b+.75)+c:2.5/2.75>b?d*(7.5625*(b-=2.25/2.75)*b+.9375)+c:d*(7.5625*(b-=2.625/2.75)*b+.984375)+c},easeInOutBounce:function(a,b,c,d,e){return e/2>b?.5*jQuery.easing.easeInBounce(a,2*b,0,d,e)+c:.5*jQuery.easing.easeOutBounce(a,2*b-e,0,d,e)+.5*d+c}}),jQuery.extend(jQuery.easing,{easeInOutMaterial:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b+c:d/4*((b-=2)*b*b+2)+c}}),jQuery.Velocity?console.log("Velocity is already loaded. You may be needlessly importing Velocity again; note that Materialize includes Velocity."):(!function(a){function b(a){var b=a.length,d=c.type(a);return"function"===d||c.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===d||0===b||"number"==typeof b&&b>0&&b-1 in a}if(!a.jQuery){var c=function(a,b){return new c.fn.init(a,b)};c.isWindow=function(a){return null!=a&&a==a.window},c.type=function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?e[g.call(a)]||"object":typeof a},c.isArray=Array.isArray||function(a){return"array"===c.type(a)},c.isPlainObject=function(a){var b;if(!a||"object"!==c.type(a)||a.nodeType||c.isWindow(a))return!1;try{if(a.constructor&&!f.call(a,"constructor")&&!f.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(d){return!1}for(b in a);return void 0===b||f.call(a,b)},c.each=function(a,c,d){var e,f=0,g=a.length,h=b(a);if(d){if(h)for(;g>f&&(e=c.apply(a[f],d),e!==!1);f++);else for(f in a)if(e=c.apply(a[f],d),e===!1)break}else if(h)for(;g>f&&(e=c.call(a[f],f,a[f]),e!==!1);f++);else for(f in a)if(e=c.call(a[f],f,a[f]),e===!1)break;return a},c.data=function(a,b,e){if(void 0===e){var f=a[c.expando],g=f&&d[f];if(void 0===b)return g;if(g&&b in g)return g[b]}else if(void 0!==b){var f=a[c.expando]||(a[c.expando]=++c.uuid);return d[f]=d[f]||{},d[f][b]=e,e}},c.removeData=function(a,b){var e=a[c.expando],f=e&&d[e];f&&c.each(b,function(a,b){delete f[b]})},c.extend=function(){var a,b,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;for("boolean"==typeof h&&(k=h,h=arguments[i]||{},i++),"object"!=typeof h&&"function"!==c.type(h)&&(h={}),i===j&&(h=this,i--);j>i;i++)if(null!=(f=arguments[i]))for(e in f)a=h[e],d=f[e],h!==d&&(k&&d&&(c.isPlainObject(d)||(b=c.isArray(d)))?(b?(b=!1,g=a&&c.isArray(a)?a:[]):g=a&&c.isPlainObject(a)?a:{},h[e]=c.extend(k,g,d)):void 0!==d&&(h[e]=d));return h},c.queue=function(a,d,e){function f(a,c){var d=c||[];return null!=a&&(b(Object(a))?!function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;)a[e++]=b[d++];if(c!==c)for(;void 0!==b[d];)a[e++]=b[d++];return a.length=e,a}(d,"string"==typeof a?[a]:a):[].push.call(d,a)),d}if(a){d=(d||"fx")+"queue";var g=c.data(a,d);return e?(!g||c.isArray(e)?g=c.data(a,d,f(e)):g.push(e),g):g||[]}},c.dequeue=function(a,b){c.each(a.nodeType?[a]:a,function(a,d){b=b||"fx";var e=c.queue(d,b),f=e.shift();"inprogress"===f&&(f=e.shift()),f&&("fx"===b&&e.unshift("inprogress"),f.call(d,function(){c.dequeue(d,b)}))})},c.fn=c.prototype={init:function(a){if(a.nodeType)return this[0]=a,this;throw new Error("Not a DOM node.")},offset:function(){var b=this[0].getBoundingClientRect?this[0].getBoundingClientRect():{top:0,left:0};return{top:b.top+(a.pageYOffset||document.scrollTop||0)-(document.clientTop||0),left:b.left+(a.pageXOffset||document.scrollLeft||0)-(document.clientLeft||0)}},position:function(){function a(){for(var a=this.offsetParent||document;a&&"html"===!a.nodeType.toLowerCase&&"static"===a.style.position;)a=a.offsetParent;return a||document}var b=this[0],a=a.apply(b),d=this.offset(),e=/^(?:body|html)$/i.test(a.nodeName)?{top:0,left:0}:c(a).offset();return d.top-=parseFloat(b.style.marginTop)||0,d.left-=parseFloat(b.style.marginLeft)||0,a.style&&(e.top+=parseFloat(a.style.borderTopWidth)||0,e.left+=parseFloat(a.style.borderLeftWidth)||0),{top:d.top-e.top,left:d.left-e.left}}};var d={};c.expando="velocity"+(new Date).getTime(),c.uuid=0;for(var e={},f=e.hasOwnProperty,g=e.toString,h="Boolean Number String Function Array Date RegExp Object Error".split(" "),i=0;i<h.length;i++)e["[object "+h[i]+"]"]=h[i].toLowerCase();c.fn.init.prototype=c.fn,a.Velocity={Utilities:c}}}(window),function(a){"object"==typeof module&&"object"==typeof module.exports?module.exports=a():"function"==typeof define&&define.amd?define(a):a()}(function(){return function(a,b,c,d){function e(a){for(var b=-1,c=a?a.length:0,d=[];++b<c;){var e=a[b];e&&d.push(e)}return d}function f(a){return p.isWrapped(a)?a=[].slice.call(a):p.isNode(a)&&(a=[a]),a}function g(a){var b=m.data(a,"velocity");return null===b?d:b}function h(a){return function(b){return Math.round(b*a)*(1/a)}}function i(a,c,d,e){function f(a,b){return 1-3*b+3*a}function g(a,b){return 3*b-6*a}function h(a){return 3*a}function i(a,b,c){return((f(b,c)*a+g(b,c))*a+h(b))*a}function j(a,b,c){return 3*f(b,c)*a*a+2*g(b,c)*a+h(b)}function k(b,c){for(var e=0;p>e;++e){var f=j(c,a,d);if(0===f)return c;var g=i(c,a,d)-b;c-=g/f}return c}function l(){for(var b=0;t>b;++b)x[b]=i(b*u,a,d)}function m(b,c,e){var f,g,h=0;do g=c+(e-c)/2,f=i(g,a,d)-b,f>0?e=g:c=g;while(Math.abs(f)>r&&++h<s);return g}function n(b){for(var c=0,e=1,f=t-1;e!=f&&x[e]<=b;++e)c+=u;--e;var g=(b-x[e])/(x[e+1]-x[e]),h=c+g*u,i=j(h,a,d);return i>=q?k(b,h):0==i?h:m(b,c,c+u)}function o(){y=!0,(a!=c||d!=e)&&l()}var p=4,q=.001,r=1e-7,s=10,t=11,u=1/(t-1),v="Float32Array"in b;if(4!==arguments.length)return!1;for(var w=0;4>w;++w)if("number"!=typeof arguments[w]||isNaN(arguments[w])||!isFinite(arguments[w]))return!1;a=Math.min(a,1),d=Math.min(d,1),a=Math.max(a,0),d=Math.max(d,0);var x=v?new Float32Array(t):new Array(t),y=!1,z=function(b){return y||o(),a===c&&d===e?b:0===b?0:1===b?1:i(n(b),c,e)};z.getControlPoints=function(){return[{x:a,y:c},{x:d,y:e}]};var A="generateBezier("+[a,c,d,e]+")";return z.toString=function(){return A},z}function j(a,b){var c=a;return p.isString(a)?t.Easings[a]||(c=!1):c=p.isArray(a)&&1===a.length?h.apply(null,a):p.isArray(a)&&2===a.length?u.apply(null,a.concat([b])):p.isArray(a)&&4===a.length?i.apply(null,a):!1,c===!1&&(c=t.Easings[t.defaults.easing]?t.defaults.easing:s),c}function k(a){if(a){var b=(new Date).getTime(),c=t.State.calls.length;c>1e4&&(t.State.calls=e(t.State.calls));for(var f=0;c>f;f++)if(t.State.calls[f]){var h=t.State.calls[f],i=h[0],j=h[2],n=h[3],o=!!n,q=null;n||(n=t.State.calls[f][3]=b-16);for(var r=Math.min((b-n)/j.duration,1),s=0,u=i.length;u>s;s++){var w=i[s],y=w.element;if(g(y)){var z=!1;if(j.display!==d&&null!==j.display&&"none"!==j.display){if("flex"===j.display){var A=["-webkit-box","-moz-box","-ms-flexbox","-webkit-flex"];m.each(A,function(a,b){v.setPropertyValue(y,"display",b)})}v.setPropertyValue(y,"display",j.display)}j.visibility!==d&&"hidden"!==j.visibility&&v.setPropertyValue(y,"visibility",j.visibility);for(var B in w)if("element"!==B){var C,D=w[B],E=p.isString(D.easing)?t.Easings[D.easing]:D.easing;if(1===r)C=D.endValue;else{var F=D.endValue-D.startValue;if(C=D.startValue+F*E(r,j,F),!o&&C===D.currentValue)continue}if(D.currentValue=C,"tween"===B)q=C;else{if(v.Hooks.registered[B]){var G=v.Hooks.getRoot(B),H=g(y).rootPropertyValueCache[G];H&&(D.rootPropertyValue=H)}var I=v.setPropertyValue(y,B,D.currentValue+(0===parseFloat(C)?"":D.unitType),D.rootPropertyValue,D.scrollData);v.Hooks.registered[B]&&(g(y).rootPropertyValueCache[G]=v.Normalizations.registered[G]?v.Normalizations.registered[G]("extract",null,I[1]):I[1]),"transform"===I[0]&&(z=!0)}}j.mobileHA&&g(y).transformCache.translate3d===d&&(g(y).transformCache.translate3d="(0px, 0px, 0px)",z=!0),z&&v.flushTransformCache(y)}}j.display!==d&&"none"!==j.display&&(t.State.calls[f][2].display=!1),j.visibility!==d&&"hidden"!==j.visibility&&(t.State.calls[f][2].visibility=!1),j.progress&&j.progress.call(h[1],h[1],r,Math.max(0,n+j.duration-b),n,q),1===r&&l(f)}}t.State.isTicking&&x(k)}function l(a,b){if(!t.State.calls[a])return!1;for(var c=t.State.calls[a][0],e=t.State.calls[a][1],f=t.State.calls[a][2],h=t.State.calls[a][4],i=!1,j=0,k=c.length;k>j;j++){var l=c[j].element;if(b||f.loop||("none"===f.display&&v.setPropertyValue(l,"display",f.display),"hidden"===f.visibility&&v.setPropertyValue(l,"visibility",f.visibility)),f.loop!==!0&&(m.queue(l)[1]===d||!/\.velocityQueueEntryFlag/i.test(m.queue(l)[1]))&&g(l)){g(l).isAnimating=!1,g(l).rootPropertyValueCache={};var n=!1;m.each(v.Lists.transforms3D,function(a,b){var c=/^scale/.test(b)?1:0,e=g(l).transformCache[b];g(l).transformCache[b]!==d&&new RegExp("^\\("+c+"[^.]").test(e)&&(n=!0,delete g(l).transformCache[b])}),f.mobileHA&&(n=!0,delete g(l).transformCache.translate3d),n&&v.flushTransformCache(l),v.Values.removeClass(l,"velocity-animating")}if(!b&&f.complete&&!f.loop&&j===k-1)try{f.complete.call(e,e)}catch(o){setTimeout(function(){throw o},1)}h&&f.loop!==!0&&h(e),g(l)&&f.loop===!0&&!b&&(m.each(g(l).tweensContainer,function(a,b){/^rotate/.test(a)&&360===parseFloat(b.endValue)&&(b.endValue=0,b.startValue=360),/^backgroundPosition/.test(a)&&100===parseFloat(b.endValue)&&"%"===b.unitType&&(b.endValue=0,b.startValue=100)}),t(l,"reverse",{loop:!0,delay:f.delay})),f.queue!==!1&&m.dequeue(l,f.queue)}t.State.calls[a]=!1;for(var p=0,q=t.State.calls.length;q>p;p++)if(t.State.calls[p]!==!1){i=!0;break}i===!1&&(t.State.isTicking=!1,delete t.State.calls,t.State.calls=[])}var m,n=function(){if(c.documentMode)return c.documentMode;for(var a=7;a>4;a--){var b=c.createElement("div");if(b.innerHTML="<!--[if IE "+a+"]><span></span><![endif]-->",b.getElementsByTagName("span").length)return b=null,a}return d}(),o=function(){var a=0;return b.webkitRequestAnimationFrame||b.mozRequestAnimationFrame||function(b){var c,d=(new Date).getTime();return c=Math.max(0,16-(d-a)),a=d+c,setTimeout(function(){b(d+c)},c)}}(),p={isString:function(a){return"string"==typeof a},isArray:Array.isArray||function(a){return"[object Array]"===Object.prototype.toString.call(a)},isFunction:function(a){return"[object Function]"===Object.prototype.toString.call(a)},isNode:function(a){return a&&a.nodeType},isNodeList:function(a){return"object"==typeof a&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(Object.prototype.toString.call(a))&&a.length!==d&&(0===a.length||"object"==typeof a[0]&&a[0].nodeType>0)},isWrapped:function(a){return a&&(a.jquery||b.Zepto&&b.Zepto.zepto.isZ(a))},isSVG:function(a){return b.SVGElement&&a instanceof b.SVGElement},isEmptyObject:function(a){for(var b in a)return!1;return!0}},q=!1;if(a.fn&&a.fn.jquery?(m=a,q=!0):m=b.Velocity.Utilities,8>=n&&!q)throw new Error("Velocity: IE8 and below require jQuery to be loaded before Velocity.");if(7>=n)return void(jQuery.fn.velocity=jQuery.fn.animate);var r=400,s="swing",t={State:{isMobile:/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),isAndroid:/Android/i.test(navigator.userAgent),isGingerbread:/Android 2\.3\.[3-7]/i.test(navigator.userAgent),isChrome:b.chrome,isFirefox:/Firefox/i.test(navigator.userAgent),prefixElement:c.createElement("div"),prefixMatches:{},scrollAnchor:null,scrollPropertyLeft:null,scrollPropertyTop:null,isTicking:!1,calls:[]},CSS:{},Utilities:m,Redirects:{},Easings:{},Promise:b.Promise,defaults:{queue:"",duration:r,easing:s,begin:d,complete:d,progress:d,display:d,visibility:d,loop:!1,delay:!1,mobileHA:!0,_cacheValues:!0},init:function(a){m.data(a,"velocity",{isSVG:p.isSVG(a),isAnimating:!1,computedStyle:null,tweensContainer:null,rootPropertyValueCache:{},transformCache:{}})},hook:null,mock:!1,version:{major:1,minor:2,patch:2},debug:!1};b.pageYOffset!==d?(t.State.scrollAnchor=b,t.State.scrollPropertyLeft="pageXOffset",t.State.scrollPropertyTop="pageYOffset"):(t.State.scrollAnchor=c.documentElement||c.body.parentNode||c.body,t.State.scrollPropertyLeft="scrollLeft",t.State.scrollPropertyTop="scrollTop");var u=function(){function a(a){return-a.tension*a.x-a.friction*a.v}function b(b,c,d){var e={x:b.x+d.dx*c,v:b.v+d.dv*c,tension:b.tension,friction:b.friction};return{dx:e.v,dv:a(e)}}function c(c,d){var e={dx:c.v,dv:a(c)},f=b(c,.5*d,e),g=b(c,.5*d,f),h=b(c,d,g),i=1/6*(e.dx+2*(f.dx+g.dx)+h.dx),j=1/6*(e.dv+2*(f.dv+g.dv)+h.dv);return c.x=c.x+i*d,c.v=c.v+j*d,c}return function d(a,b,e){var f,g,h,i={x:-1,v:0,tension:null,friction:null},j=[0],k=0,l=1e-4,m=.016;for(a=parseFloat(a)||500,b=parseFloat(b)||20,e=e||null,i.tension=a,i.friction=b,f=null!==e,f?(k=d(a,b),g=k/e*m):g=m;h=c(h||i,g),j.push(1+h.x),k+=16,Math.abs(h.x)>l&&Math.abs(h.v)>l;);return f?function(a){return j[a*(j.length-1)|0]}:k}}();t.Easings={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},spring:function(a){return 1-Math.cos(4.5*a*Math.PI)*Math.exp(6*-a)}},m.each([["ease",[.25,.1,.25,1]],["ease-in",[.42,0,1,1]],["ease-out",[0,0,.58,1]],["ease-in-out",[.42,0,.58,1]],["easeInSine",[.47,0,.745,.715]],["easeOutSine",[.39,.575,.565,1]],["easeInOutSine",[.445,.05,.55,.95]],["easeInQuad",[.55,.085,.68,.53]],["easeOutQuad",[.25,.46,.45,.94]],["easeInOutQuad",[.455,.03,.515,.955]],["easeInCubic",[.55,.055,.675,.19]],["easeOutCubic",[.215,.61,.355,1]],["easeInOutCubic",[.645,.045,.355,1]],["easeInQuart",[.895,.03,.685,.22]],["easeOutQuart",[.165,.84,.44,1]],["easeInOutQuart",[.77,0,.175,1]],["easeInQuint",[.755,.05,.855,.06]],["easeOutQuint",[.23,1,.32,1]],["easeInOutQuint",[.86,0,.07,1]],["easeInExpo",[.95,.05,.795,.035]],["easeOutExpo",[.19,1,.22,1]],["easeInOutExpo",[1,0,0,1]],["easeInCirc",[.6,.04,.98,.335]],["easeOutCirc",[.075,.82,.165,1]],["easeInOutCirc",[.785,.135,.15,.86]]],function(a,b){t.Easings[b[0]]=i.apply(null,b[1])});var v=t.CSS={RegEx:{isHex:/^#([A-f\d]{3}){1,2}$/i,valueUnwrap:/^[A-z]+\((.*)\)$/i,wrappedValueAlreadyExtracted:/[0-9.]+ [0-9.]+ [0-9.]+( [0-9.]+)?/,valueSplit:/([A-z]+\(.+\))|(([A-z0-9#-.]+?)(?=\s|$))/gi},Lists:{colors:["fill","stroke","stopColor","color","backgroundColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor","outlineColor"],transformsBase:["translateX","translateY","scale","scaleX","scaleY","skewX","skewY","rotateZ"],transforms3D:["transformPerspective","translateZ","scaleZ","rotateX","rotateY"]},Hooks:{templates:{textShadow:["Color X Y Blur","black 0px 0px 0px"],boxShadow:["Color X Y Blur Spread","black 0px 0px 0px 0px"],clip:["Top Right Bottom Left","0px 0px 0px 0px"],backgroundPosition:["X Y","0% 0%"],transformOrigin:["X Y Z","50% 50% 0px"],perspectiveOrigin:["X Y","50% 50%"]},registered:{},register:function(){for(var a=0;a<v.Lists.colors.length;a++){var b="color"===v.Lists.colors[a]?"0 0 0 1":"255 255 255 1";v.Hooks.templates[v.Lists.colors[a]]=["Red Green Blue Alpha",b]}var c,d,e;if(n)for(c in v.Hooks.templates){d=v.Hooks.templates[c],e=d[0].split(" ");var f=d[1].match(v.RegEx.valueSplit);"Color"===e[0]&&(e.push(e.shift()),f.push(f.shift()),v.Hooks.templates[c]=[e.join(" "),f.join(" ")])}for(c in v.Hooks.templates){d=v.Hooks.templates[c],e=d[0].split(" ");for(var a in e){var g=c+e[a],h=a;v.Hooks.registered[g]=[c,h]}}},getRoot:function(a){var b=v.Hooks.registered[a];return b?b[0]:a},cleanRootPropertyValue:function(a,b){return v.RegEx.valueUnwrap.test(b)&&(b=b.match(v.RegEx.valueUnwrap)[1]),v.Values.isCSSNullValue(b)&&(b=v.Hooks.templates[a][1]),b},extractValue:function(a,b){var c=v.Hooks.registered[a];if(c){var d=c[0],e=c[1];return b=v.Hooks.cleanRootPropertyValue(d,b),b.toString().match(v.RegEx.valueSplit)[e]}return b},injectValue:function(a,b,c){var d=v.Hooks.registered[a];if(d){var e,f,g=d[0],h=d[1];return c=v.Hooks.cleanRootPropertyValue(g,c),e=c.toString().match(v.RegEx.valueSplit),e[h]=b,f=e.join(" ")}return c}},Normalizations:{registered:{clip:function(a,b,c){switch(a){case"name":return"clip";case"extract":var d;return v.RegEx.wrappedValueAlreadyExtracted.test(c)?d=c:(d=c.toString().match(v.RegEx.valueUnwrap),d=d?d[1].replace(/,(\s+)?/g," "):c),d;case"inject":return"rect("+c+")"}},blur:function(a,b,c){switch(a){case"name":return t.State.isFirefox?"filter":"-webkit-filter";case"extract":var d=parseFloat(c);if(!d&&0!==d){var e=c.toString().match(/blur\(([0-9]+[A-z]+)\)/i);d=e?e[1]:0}return d;case"inject":return parseFloat(c)?"blur("+c+")":"none"}},opacity:function(a,b,c){if(8>=n)switch(a){case"name":return"filter";case"extract":var d=c.toString().match(/alpha\(opacity=(.*)\)/i);return c=d?d[1]/100:1;case"inject":return b.style.zoom=1,parseFloat(c)>=1?"":"alpha(opacity="+parseInt(100*parseFloat(c),10)+")"}else switch(a){case"name":return"opacity";case"extract":return c;case"inject":return c}}},register:function(){9>=n||t.State.isGingerbread||(v.Lists.transformsBase=v.Lists.transformsBase.concat(v.Lists.transforms3D));for(var a=0;a<v.Lists.transformsBase.length;a++)!function(){var b=v.Lists.transformsBase[a];v.Normalizations.registered[b]=function(a,c,e){switch(a){case"name":return"transform";case"extract":return g(c)===d||g(c).transformCache[b]===d?/^scale/i.test(b)?1:0:g(c).transformCache[b].replace(/[()]/g,"");case"inject":var f=!1;switch(b.substr(0,b.length-1)){case"translate":f=!/(%|px|em|rem|vw|vh|\d)$/i.test(e);break;case"scal":case"scale":t.State.isAndroid&&g(c).transformCache[b]===d&&1>e&&(e=1),f=!/(\d)$/i.test(e);break;case"skew":f=!/(deg|\d)$/i.test(e);break;case"rotate":f=!/(deg|\d)$/i.test(e)}return f||(g(c).transformCache[b]="("+e+")"),g(c).transformCache[b]}}}();for(var a=0;a<v.Lists.colors.length;a++)!function(){var b=v.Lists.colors[a];v.Normalizations.registered[b]=function(a,c,e){switch(a){case"name":return b;case"extract":var f;if(v.RegEx.wrappedValueAlreadyExtracted.test(e))f=e;else{var g,h={black:"rgb(0, 0, 0)",blue:"rgb(0, 0, 255)",gray:"rgb(128, 128, 128)",green:"rgb(0, 128, 0)",red:"rgb(255, 0, 0)",white:"rgb(255, 255, 255)"};/^[A-z]+$/i.test(e)?g=h[e]!==d?h[e]:h.black:v.RegEx.isHex.test(e)?g="rgb("+v.Values.hexToRgb(e).join(" ")+")":/^rgba?\(/i.test(e)||(g=h.black),f=(g||e).toString().match(v.RegEx.valueUnwrap)[1].replace(/,(\s+)?/g," ")}return 8>=n||3!==f.split(" ").length||(f+=" 1"),f;case"inject":return 8>=n?4===e.split(" ").length&&(e=e.split(/\s+/).slice(0,3).join(" ")):3===e.split(" ").length&&(e+=" 1"),(8>=n?"rgb":"rgba")+"("+e.replace(/\s+/g,",").replace(/\.(\d)+(?=,)/g,"")+")"}}}()}},Names:{camelCase:function(a){return a.replace(/-(\w)/g,function(a,b){return b.toUpperCase()})},SVGAttribute:function(a){var b="width|height|x|y|cx|cy|r|rx|ry|x1|x2|y1|y2";return(n||t.State.isAndroid&&!t.State.isChrome)&&(b+="|transform"),new RegExp("^("+b+")$","i").test(a)},prefixCheck:function(a){if(t.State.prefixMatches[a])return[t.State.prefixMatches[a],!0];for(var b=["","Webkit","Moz","ms","O"],c=0,d=b.length;d>c;c++){var e;if(e=0===c?a:b[c]+a.replace(/^\w/,function(a){return a.toUpperCase()}),p.isString(t.State.prefixElement.style[e]))return t.State.prefixMatches[a]=e,[e,!0]}return[a,!1]}},Values:{hexToRgb:function(a){var b,c=/^#?([a-f\d])([a-f\d])([a-f\d])$/i,d=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;return a=a.replace(c,function(a,b,c,d){return b+b+c+c+d+d}),b=d.exec(a),b?[parseInt(b[1],16),parseInt(b[2],16),parseInt(b[3],16)]:[0,0,0]},isCSSNullValue:function(a){return 0==a||/^(none|auto|transparent|(rgba\(0, ?0, ?0, ?0\)))$/i.test(a)},getUnitType:function(a){return/^(rotate|skew)/i.test(a)?"deg":/(^(scale|scaleX|scaleY|scaleZ|alpha|flexGrow|flexHeight|zIndex|fontWeight)$)|((opacity|red|green|blue|alpha)$)/i.test(a)?"":"px"},getDisplayType:function(a){var b=a&&a.tagName.toString().toLowerCase();return/^(b|big|i|small|tt|abbr|acronym|cite|code|dfn|em|kbd|strong|samp|var|a|bdo|br|img|map|object|q|script|span|sub|sup|button|input|label|select|textarea)$/i.test(b)?"inline":/^(li)$/i.test(b)?"list-item":/^(tr)$/i.test(b)?"table-row":/^(table)$/i.test(b)?"table":/^(tbody)$/i.test(b)?"table-row-group":"block"},addClass:function(a,b){a.classList?a.classList.add(b):a.className+=(a.className.length?" ":"")+b},removeClass:function(a,b){a.classList?a.classList.remove(b):a.className=a.className.toString().replace(new RegExp("(^|\\s)"+b.split(" ").join("|")+"(\\s|$)","gi")," ")}},getPropertyValue:function(a,c,e,f){function h(a,c){function e(){j&&v.setPropertyValue(a,"display","none")}var i=0;if(8>=n)i=m.css(a,c);else{var j=!1;if(/^(width|height)$/.test(c)&&0===v.getPropertyValue(a,"display")&&(j=!0,v.setPropertyValue(a,"display",v.Values.getDisplayType(a))),!f){if("height"===c&&"border-box"!==v.getPropertyValue(a,"boxSizing").toString().toLowerCase()){var k=a.offsetHeight-(parseFloat(v.getPropertyValue(a,"borderTopWidth"))||0)-(parseFloat(v.getPropertyValue(a,"borderBottomWidth"))||0)-(parseFloat(v.getPropertyValue(a,"paddingTop"))||0)-(parseFloat(v.getPropertyValue(a,"paddingBottom"))||0);return e(),k}if("width"===c&&"border-box"!==v.getPropertyValue(a,"boxSizing").toString().toLowerCase()){var l=a.offsetWidth-(parseFloat(v.getPropertyValue(a,"borderLeftWidth"))||0)-(parseFloat(v.getPropertyValue(a,"borderRightWidth"))||0)-(parseFloat(v.getPropertyValue(a,"paddingLeft"))||0)-(parseFloat(v.getPropertyValue(a,"paddingRight"))||0);return e(),l}}var o;o=g(a)===d?b.getComputedStyle(a,null):g(a).computedStyle?g(a).computedStyle:g(a).computedStyle=b.getComputedStyle(a,null),"borderColor"===c&&(c="borderTopColor"),i=9===n&&"filter"===c?o.getPropertyValue(c):o[c],(""===i||null===i)&&(i=a.style[c]),e()}if("auto"===i&&/^(top|right|bottom|left)$/i.test(c)){var p=h(a,"position");("fixed"===p||"absolute"===p&&/top|left/i.test(c))&&(i=m(a).position()[c]+"px")}return i}var i;if(v.Hooks.registered[c]){var j=c,k=v.Hooks.getRoot(j);e===d&&(e=v.getPropertyValue(a,v.Names.prefixCheck(k)[0])),v.Normalizations.registered[k]&&(e=v.Normalizations.registered[k]("extract",a,e)),i=v.Hooks.extractValue(j,e)}else if(v.Normalizations.registered[c]){var l,o;l=v.Normalizations.registered[c]("name",a),"transform"!==l&&(o=h(a,v.Names.prefixCheck(l)[0]),v.Values.isCSSNullValue(o)&&v.Hooks.templates[c]&&(o=v.Hooks.templates[c][1])),i=v.Normalizations.registered[c]("extract",a,o)}if(!/^[\d-]/.test(i))if(g(a)&&g(a).isSVG&&v.Names.SVGAttribute(c))if(/^(height|width)$/i.test(c))try{i=a.getBBox()[c]}catch(p){i=0}else i=a.getAttribute(c);else i=h(a,v.Names.prefixCheck(c)[0]);return v.Values.isCSSNullValue(i)&&(i=0),t.debug>=2&&console.log("Get "+c+": "+i),i},setPropertyValue:function(a,c,d,e,f){var h=c;if("scroll"===c)f.container?f.container["scroll"+f.direction]=d:"Left"===f.direction?b.scrollTo(d,f.alternateValue):b.scrollTo(f.alternateValue,d);else if(v.Normalizations.registered[c]&&"transform"===v.Normalizations.registered[c]("name",a))v.Normalizations.registered[c]("inject",a,d),h="transform",d=g(a).transformCache[c];else{if(v.Hooks.registered[c]){var i=c,j=v.Hooks.getRoot(c);e=e||v.getPropertyValue(a,j),d=v.Hooks.injectValue(i,d,e),c=j}if(v.Normalizations.registered[c]&&(d=v.Normalizations.registered[c]("inject",a,d),c=v.Normalizations.registered[c]("name",a)),h=v.Names.prefixCheck(c)[0],8>=n)try{a.style[h]=d}catch(k){t.debug&&console.log("Browser does not support ["+d+"] for ["+h+"]")}else g(a)&&g(a).isSVG&&v.Names.SVGAttribute(c)?a.setAttribute(c,d):a.style[h]=d;t.debug>=2&&console.log("Set "+c+" ("+h+"): "+d)}return[h,d]},flushTransformCache:function(a){function b(b){return parseFloat(v.getPropertyValue(a,b))}var c="";if((n||t.State.isAndroid&&!t.State.isChrome)&&g(a).isSVG){var d={translate:[b("translateX"),b("translateY")],skewX:[b("skewX")],skewY:[b("skewY")],scale:1!==b("scale")?[b("scale"),b("scale")]:[b("scaleX"),b("scaleY")],rotate:[b("rotateZ"),0,0]};m.each(g(a).transformCache,function(a){/^translate/i.test(a)?a="translate":/^scale/i.test(a)?a="scale":/^rotate/i.test(a)&&(a="rotate"),d[a]&&(c+=a+"("+d[a].join(" ")+") ",delete d[a])})}else{var e,f;m.each(g(a).transformCache,function(b){return e=g(a).transformCache[b],"transformPerspective"===b?(f=e,!0):(9===n&&"rotateZ"===b&&(b="rotate"),void(c+=b+e+" "))}),f&&(c="perspective"+f+" "+c)}v.setPropertyValue(a,"transform",c)}};v.Hooks.register(),v.Normalizations.register(),t.hook=function(a,b,c){var e=d;return a=f(a),m.each(a,function(a,f){if(g(f)===d&&t.init(f),c===d)e===d&&(e=t.CSS.getPropertyValue(f,b));else{var h=t.CSS.setPropertyValue(f,b,c);"transform"===h[0]&&t.CSS.flushTransformCache(f),e=h}}),e};var w=function(){function a(){return h?B.promise||null:i}function e(){function a(a){function l(a,b){var c=d,e=d,g=d;return p.isArray(a)?(c=a[0],!p.isArray(a[1])&&/^[\d-]/.test(a[1])||p.isFunction(a[1])||v.RegEx.isHex.test(a[1])?g=a[1]:(p.isString(a[1])&&!v.RegEx.isHex.test(a[1])||p.isArray(a[1]))&&(e=b?a[1]:j(a[1],h.duration),a[2]!==d&&(g=a[2]))):c=a,b||(e=e||h.easing),p.isFunction(c)&&(c=c.call(f,y,x)),p.isFunction(g)&&(g=g.call(f,y,x)),[c||0,e,g]}function n(a,b){var c,d;return d=(b||"0").toString().toLowerCase().replace(/[%A-z]+$/,function(a){return c=a,""}),c||(c=v.Values.getUnitType(a)),[d,c]}function r(){var a={myParent:f.parentNode||c.body,position:v.getPropertyValue(f,"position"),fontSize:v.getPropertyValue(f,"fontSize")},d=a.position===I.lastPosition&&a.myParent===I.lastParent,e=a.fontSize===I.lastFontSize;I.lastParent=a.myParent,I.lastPosition=a.position,I.lastFontSize=a.fontSize;var h=100,i={};if(e&&d)i.emToPx=I.lastEmToPx,i.percentToPxWidth=I.lastPercentToPxWidth,i.percentToPxHeight=I.lastPercentToPxHeight;else{var j=g(f).isSVG?c.createElementNS("http://www.w3.org/2000/svg","rect"):c.createElement("div");t.init(j),a.myParent.appendChild(j),m.each(["overflow","overflowX","overflowY"],function(a,b){t.CSS.setPropertyValue(j,b,"hidden")}),t.CSS.setPropertyValue(j,"position",a.position),t.CSS.setPropertyValue(j,"fontSize",a.fontSize),t.CSS.setPropertyValue(j,"boxSizing","content-box"),m.each(["minWidth","maxWidth","width","minHeight","maxHeight","height"],function(a,b){t.CSS.setPropertyValue(j,b,h+"%")}),t.CSS.setPropertyValue(j,"paddingLeft",h+"em"),i.percentToPxWidth=I.lastPercentToPxWidth=(parseFloat(v.getPropertyValue(j,"width",null,!0))||1)/h,i.percentToPxHeight=I.lastPercentToPxHeight=(parseFloat(v.getPropertyValue(j,"height",null,!0))||1)/h,i.emToPx=I.lastEmToPx=(parseFloat(v.getPropertyValue(j,"paddingLeft"))||1)/h,a.myParent.removeChild(j)}return null===I.remToPx&&(I.remToPx=parseFloat(v.getPropertyValue(c.body,"fontSize"))||16),null===I.vwToPx&&(I.vwToPx=parseFloat(b.innerWidth)/100,I.vhToPx=parseFloat(b.innerHeight)/100),i.remToPx=I.remToPx,i.vwToPx=I.vwToPx,i.vhToPx=I.vhToPx,t.debug>=1&&console.log("Unit ratios: "+JSON.stringify(i),f),i}if(h.begin&&0===y)try{h.begin.call(o,o)}catch(u){setTimeout(function(){throw u},1)}if("scroll"===C){var w,z,A,D=/^x$/i.test(h.axis)?"Left":"Top",E=parseFloat(h.offset)||0;h.container?p.isWrapped(h.container)||p.isNode(h.container)?(h.container=h.container[0]||h.container,w=h.container["scroll"+D],A=w+m(f).position()[D.toLowerCase()]+E):h.container=null:(w=t.State.scrollAnchor[t.State["scrollProperty"+D]],z=t.State.scrollAnchor[t.State["scrollProperty"+("Left"===D?"Top":"Left")]],A=m(f).offset()[D.toLowerCase()]+E),i={scroll:{rootPropertyValue:!1,startValue:w,currentValue:w,endValue:A,unitType:"",easing:h.easing,scrollData:{container:h.container,direction:D,alternateValue:z}},element:f},t.debug&&console.log("tweensContainer (scroll): ",i.scroll,f)}else if("reverse"===C){if(!g(f).tweensContainer)return void m.dequeue(f,h.queue);"none"===g(f).opts.display&&(g(f).opts.display="auto"),"hidden"===g(f).opts.visibility&&(g(f).opts.visibility="visible"),g(f).opts.loop=!1,g(f).opts.begin=null,g(f).opts.complete=null,s.easing||delete h.easing,s.duration||delete h.duration,h=m.extend({},g(f).opts,h);var F=m.extend(!0,{},g(f).tweensContainer);for(var G in F)if("element"!==G){var H=F[G].startValue;F[G].startValue=F[G].currentValue=F[G].endValue,F[G].endValue=H,p.isEmptyObject(s)||(F[G].easing=h.easing),t.debug&&console.log("reverse tweensContainer ("+G+"): "+JSON.stringify(F[G]),f)}i=F}else if("start"===C){var F;g(f).tweensContainer&&g(f).isAnimating===!0&&(F=g(f).tweensContainer),m.each(q,function(a,b){if(RegExp("^"+v.Lists.colors.join("$|^")+"$").test(a)){var c=l(b,!0),e=c[0],f=c[1],g=c[2];if(v.RegEx.isHex.test(e)){for(var h=["Red","Green","Blue"],i=v.Values.hexToRgb(e),j=g?v.Values.hexToRgb(g):d,k=0;k<h.length;k++){var m=[i[k]];f&&m.push(f),j!==d&&m.push(j[k]),q[a+h[k]]=m}delete q[a]}}});for(var K in q){var L=l(q[K]),M=L[0],N=L[1],O=L[2];K=v.Names.camelCase(K);var P=v.Hooks.getRoot(K),Q=!1;if(g(f).isSVG||"tween"===P||v.Names.prefixCheck(P)[1]!==!1||v.Normalizations.registered[P]!==d){(h.display!==d&&null!==h.display&&"none"!==h.display||h.visibility!==d&&"hidden"!==h.visibility)&&/opacity|filter/.test(K)&&!O&&0!==M&&(O=0),h._cacheValues&&F&&F[K]?(O===d&&(O=F[K].endValue+F[K].unitType),Q=g(f).rootPropertyValueCache[P]):v.Hooks.registered[K]?O===d?(Q=v.getPropertyValue(f,P),O=v.getPropertyValue(f,K,Q)):Q=v.Hooks.templates[P][1]:O===d&&(O=v.getPropertyValue(f,K));var R,S,T,U=!1;if(R=n(K,O),O=R[0],T=R[1],R=n(K,M),M=R[0].replace(/^([+-\/*])=/,function(a,b){return U=b,""}),S=R[1],O=parseFloat(O)||0,M=parseFloat(M)||0,"%"===S&&(/^(fontSize|lineHeight)$/.test(K)?(M/=100,S="em"):/^scale/.test(K)?(M/=100,S=""):/(Red|Green|Blue)$/i.test(K)&&(M=M/100*255,S="")),/[\/*]/.test(U))S=T;else if(T!==S&&0!==O)if(0===M)S=T;else{e=e||r();var V=/margin|padding|left|right|width|text|word|letter/i.test(K)||/X$/.test(K)||"x"===K?"x":"y";
-switch(T){case"%":O*="x"===V?e.percentToPxWidth:e.percentToPxHeight;break;case"px":break;default:O*=e[T+"ToPx"]}switch(S){case"%":O*=1/("x"===V?e.percentToPxWidth:e.percentToPxHeight);break;case"px":break;default:O*=1/e[S+"ToPx"]}}switch(U){case"+":M=O+M;break;case"-":M=O-M;break;case"*":M=O*M;break;case"/":M=O/M}i[K]={rootPropertyValue:Q,startValue:O,currentValue:O,endValue:M,unitType:S,easing:N},t.debug&&console.log("tweensContainer ("+K+"): "+JSON.stringify(i[K]),f)}else t.debug&&console.log("Skipping ["+P+"] due to a lack of browser support.")}i.element=f}i.element&&(v.Values.addClass(f,"velocity-animating"),J.push(i),""===h.queue&&(g(f).tweensContainer=i,g(f).opts=h),g(f).isAnimating=!0,y===x-1?(t.State.calls.push([J,o,h,null,B.resolver]),t.State.isTicking===!1&&(t.State.isTicking=!0,k())):y++)}var e,f=this,h=m.extend({},t.defaults,s),i={};switch(g(f)===d&&t.init(f),parseFloat(h.delay)&&h.queue!==!1&&m.queue(f,h.queue,function(a){t.velocityQueueEntryFlag=!0,g(f).delayTimer={setTimeout:setTimeout(a,parseFloat(h.delay)),next:a}}),h.duration.toString().toLowerCase()){case"fast":h.duration=200;break;case"normal":h.duration=r;break;case"slow":h.duration=600;break;default:h.duration=parseFloat(h.duration)||1}t.mock!==!1&&(t.mock===!0?h.duration=h.delay=1:(h.duration*=parseFloat(t.mock)||1,h.delay*=parseFloat(t.mock)||1)),h.easing=j(h.easing,h.duration),h.begin&&!p.isFunction(h.begin)&&(h.begin=null),h.progress&&!p.isFunction(h.progress)&&(h.progress=null),h.complete&&!p.isFunction(h.complete)&&(h.complete=null),h.display!==d&&null!==h.display&&(h.display=h.display.toString().toLowerCase(),"auto"===h.display&&(h.display=t.CSS.Values.getDisplayType(f))),h.visibility!==d&&null!==h.visibility&&(h.visibility=h.visibility.toString().toLowerCase()),h.mobileHA=h.mobileHA&&t.State.isMobile&&!t.State.isGingerbread,h.queue===!1?h.delay?setTimeout(a,h.delay):a():m.queue(f,h.queue,function(b,c){return c===!0?(B.promise&&B.resolver(o),!0):(t.velocityQueueEntryFlag=!0,void a(b))}),""!==h.queue&&"fx"!==h.queue||"inprogress"===m.queue(f)[0]||m.dequeue(f)}var h,i,n,o,q,s,u=arguments[0]&&(arguments[0].p||m.isPlainObject(arguments[0].properties)&&!arguments[0].properties.names||p.isString(arguments[0].properties));if(p.isWrapped(this)?(h=!1,n=0,o=this,i=this):(h=!0,n=1,o=u?arguments[0].elements||arguments[0].e:arguments[0]),o=f(o)){u?(q=arguments[0].properties||arguments[0].p,s=arguments[0].options||arguments[0].o):(q=arguments[n],s=arguments[n+1]);var x=o.length,y=0;if(!/^(stop|finish)$/i.test(q)&&!m.isPlainObject(s)){var z=n+1;s={};for(var A=z;A<arguments.length;A++)p.isArray(arguments[A])||!/^(fast|normal|slow)$/i.test(arguments[A])&&!/^\d/.test(arguments[A])?p.isString(arguments[A])||p.isArray(arguments[A])?s.easing=arguments[A]:p.isFunction(arguments[A])&&(s.complete=arguments[A]):s.duration=arguments[A]}var B={promise:null,resolver:null,rejecter:null};h&&t.Promise&&(B.promise=new t.Promise(function(a,b){B.resolver=a,B.rejecter=b}));var C;switch(q){case"scroll":C="scroll";break;case"reverse":C="reverse";break;case"finish":case"stop":m.each(o,function(a,b){g(b)&&g(b).delayTimer&&(clearTimeout(g(b).delayTimer.setTimeout),g(b).delayTimer.next&&g(b).delayTimer.next(),delete g(b).delayTimer)});var D=[];return m.each(t.State.calls,function(a,b){b&&m.each(b[1],function(c,e){var f=s===d?"":s;return f===!0||b[2].queue===f||s===d&&b[2].queue===!1?void m.each(o,function(c,d){d===e&&((s===!0||p.isString(s))&&(m.each(m.queue(d,p.isString(s)?s:""),function(a,b){p.isFunction(b)&&b(null,!0)}),m.queue(d,p.isString(s)?s:"",[])),"stop"===q?(g(d)&&g(d).tweensContainer&&f!==!1&&m.each(g(d).tweensContainer,function(a,b){b.endValue=b.currentValue}),D.push(a)):"finish"===q&&(b[2].duration=1))}):!0})}),"stop"===q&&(m.each(D,function(a,b){l(b,!0)}),B.promise&&B.resolver(o)),a();default:if(!m.isPlainObject(q)||p.isEmptyObject(q)){if(p.isString(q)&&t.Redirects[q]){var E=m.extend({},s),F=E.duration,G=E.delay||0;return E.backwards===!0&&(o=m.extend(!0,[],o).reverse()),m.each(o,function(a,b){parseFloat(E.stagger)?E.delay=G+parseFloat(E.stagger)*a:p.isFunction(E.stagger)&&(E.delay=G+E.stagger.call(b,a,x)),E.drag&&(E.duration=parseFloat(F)||(/^(callout|transition)/.test(q)?1e3:r),E.duration=Math.max(E.duration*(E.backwards?1-a/x:(a+1)/x),.75*E.duration,200)),t.Redirects[q].call(b,b,E||{},a,x,o,B.promise?B:d)}),a()}var H="Velocity: First argument ("+q+") was not a property map, a known action, or a registered redirect. Aborting.";return B.promise?B.rejecter(new Error(H)):console.log(H),a()}C="start"}var I={lastParent:null,lastPosition:null,lastFontSize:null,lastPercentToPxWidth:null,lastPercentToPxHeight:null,lastEmToPx:null,remToPx:null,vwToPx:null,vhToPx:null},J=[];m.each(o,function(a,b){p.isNode(b)&&e.call(b)});var K,E=m.extend({},t.defaults,s);if(E.loop=parseInt(E.loop),K=2*E.loop-1,E.loop)for(var L=0;K>L;L++){var M={delay:E.delay,progress:E.progress};L===K-1&&(M.display=E.display,M.visibility=E.visibility,M.complete=E.complete),w(o,"reverse",M)}return a()}};t=m.extend(w,t),t.animate=w;var x=b.requestAnimationFrame||o;return t.State.isMobile||c.hidden===d||c.addEventListener("visibilitychange",function(){c.hidden?(x=function(a){return setTimeout(function(){a(!0)},16)},k()):x=b.requestAnimationFrame||o}),a.Velocity=t,a!==b&&(a.fn.velocity=w,a.fn.velocity.defaults=t.defaults),m.each(["Down","Up"],function(a,b){t.Redirects["slide"+b]=function(a,c,e,f,g,h){var i=m.extend({},c),j=i.begin,k=i.complete,l={height:"",marginTop:"",marginBottom:"",paddingTop:"",paddingBottom:""},n={};i.display===d&&(i.display="Down"===b?"inline"===t.CSS.Values.getDisplayType(a)?"inline-block":"block":"none"),i.begin=function(){j&&j.call(g,g);for(var c in l){n[c]=a.style[c];var d=t.CSS.getPropertyValue(a,c);l[c]="Down"===b?[d,0]:[0,d]}n.overflow=a.style.overflow,a.style.overflow="hidden"},i.complete=function(){for(var b in n)a.style[b]=n[b];k&&k.call(g,g),h&&h.resolver(g)},t(a,l,i)}}),m.each(["In","Out"],function(a,b){t.Redirects["fade"+b]=function(a,c,e,f,g,h){var i=m.extend({},c),j={opacity:"In"===b?1:0},k=i.complete;i.complete=e!==f-1?i.begin=null:function(){k&&k.call(g,g),h&&h.resolver(g)},i.display===d&&(i.display="In"===b?"auto":"none"),t(this,j,i)}}),t}(window.jQuery||window.Zepto||window,window,document)})),!function(a,b,c,d){"use strict";function e(a,b,c){return setTimeout(k(a,c),b)}function f(a,b,c){return Array.isArray(a)?(g(a,c[b],c),!0):!1}function g(a,b,c){var e;if(a)if(a.forEach)a.forEach(b,c);else if(a.length!==d)for(e=0;e<a.length;)b.call(c,a[e],e,a),e++;else for(e in a)a.hasOwnProperty(e)&&b.call(c,a[e],e,a)}function h(a,b,c){for(var e=Object.keys(b),f=0;f<e.length;)(!c||c&&a[e[f]]===d)&&(a[e[f]]=b[e[f]]),f++;return a}function i(a,b){return h(a,b,!0)}function j(a,b,c){var d,e=b.prototype;d=a.prototype=Object.create(e),d.constructor=a,d._super=e,c&&h(d,c)}function k(a,b){return function(){return a.apply(b,arguments)}}function l(a,b){return typeof a==ka?a.apply(b?b[0]||d:d,b):a}function m(a,b){return a===d?b:a}function n(a,b,c){g(r(b),function(b){a.addEventListener(b,c,!1)})}function o(a,b,c){g(r(b),function(b){a.removeEventListener(b,c,!1)})}function p(a,b){for(;a;){if(a==b)return!0;a=a.parentNode}return!1}function q(a,b){return a.indexOf(b)>-1}function r(a){return a.trim().split(/\s+/g)}function s(a,b,c){if(a.indexOf&&!c)return a.indexOf(b);for(var d=0;d<a.length;){if(c&&a[d][c]==b||!c&&a[d]===b)return d;d++}return-1}function t(a){return Array.prototype.slice.call(a,0)}function u(a,b,c){for(var d=[],e=[],f=0;f<a.length;){var g=b?a[f][b]:a[f];s(e,g)<0&&d.push(a[f]),e[f]=g,f++}return c&&(d=b?d.sort(function(a,c){return a[b]>c[b]}):d.sort()),d}function v(a,b){for(var c,e,f=b[0].toUpperCase()+b.slice(1),g=0;g<ia.length;){if(c=ia[g],e=c?c+f:b,e in a)return e;g++}return d}function w(){return oa++}function x(a){var b=a.ownerDocument;return b.defaultView||b.parentWindow}function y(a,b){var c=this;this.manager=a,this.callback=b,this.element=a.element,this.target=a.options.inputTarget,this.domHandler=function(b){l(a.options.enable,[a])&&c.handler(b)},this.init()}function z(a){var b,c=a.options.inputClass;return new(b=c?c:ra?N:sa?Q:qa?S:M)(a,A)}function A(a,b,c){var d=c.pointers.length,e=c.changedPointers.length,f=b&ya&&0===d-e,g=b&(Aa|Ba)&&0===d-e;c.isFirst=!!f,c.isFinal=!!g,f&&(a.session={}),c.eventType=b,B(a,c),a.emit("hammer.input",c),a.recognize(c),a.session.prevInput=c}function B(a,b){var c=a.session,d=b.pointers,e=d.length;c.firstInput||(c.firstInput=E(b)),e>1&&!c.firstMultiple?c.firstMultiple=E(b):1===e&&(c.firstMultiple=!1);var f=c.firstInput,g=c.firstMultiple,h=g?g.center:f.center,i=b.center=F(d);b.timeStamp=na(),b.deltaTime=b.timeStamp-f.timeStamp,b.angle=J(h,i),b.distance=I(h,i),C(c,b),b.offsetDirection=H(b.deltaX,b.deltaY),b.scale=g?L(g.pointers,d):1,b.rotation=g?K(g.pointers,d):0,D(c,b);var j=a.element;p(b.srcEvent.target,j)&&(j=b.srcEvent.target),b.target=j}function C(a,b){var c=b.center,d=a.offsetDelta||{},e=a.prevDelta||{},f=a.prevInput||{};(b.eventType===ya||f.eventType===Aa)&&(e=a.prevDelta={x:f.deltaX||0,y:f.deltaY||0},d=a.offsetDelta={x:c.x,y:c.y}),b.deltaX=e.x+(c.x-d.x),b.deltaY=e.y+(c.y-d.y)}function D(a,b){var c,e,f,g,h=a.lastInterval||b,i=b.timeStamp-h.timeStamp;if(b.eventType!=Ba&&(i>xa||h.velocity===d)){var j=h.deltaX-b.deltaX,k=h.deltaY-b.deltaY,l=G(i,j,k);e=l.x,f=l.y,c=ma(l.x)>ma(l.y)?l.x:l.y,g=H(j,k),a.lastInterval=b}else c=h.velocity,e=h.velocityX,f=h.velocityY,g=h.direction;b.velocity=c,b.velocityX=e,b.velocityY=f,b.direction=g}function E(a){for(var b=[],c=0;c<a.pointers.length;)b[c]={clientX:la(a.pointers[c].clientX),clientY:la(a.pointers[c].clientY)},c++;return{timeStamp:na(),pointers:b,center:F(b),deltaX:a.deltaX,deltaY:a.deltaY}}function F(a){var b=a.length;if(1===b)return{x:la(a[0].clientX),y:la(a[0].clientY)};for(var c=0,d=0,e=0;b>e;)c+=a[e].clientX,d+=a[e].clientY,e++;return{x:la(c/b),y:la(d/b)}}function G(a,b,c){return{x:b/a||0,y:c/a||0}}function H(a,b){return a===b?Ca:ma(a)>=ma(b)?a>0?Da:Ea:b>0?Fa:Ga}function I(a,b,c){c||(c=Ka);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return Math.sqrt(d*d+e*e)}function J(a,b,c){c||(c=Ka);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return 180*Math.atan2(e,d)/Math.PI}function K(a,b){return J(b[1],b[0],La)-J(a[1],a[0],La)}function L(a,b){return I(b[0],b[1],La)/I(a[0],a[1],La)}function M(){this.evEl=Na,this.evWin=Oa,this.allow=!0,this.pressed=!1,y.apply(this,arguments)}function N(){this.evEl=Ra,this.evWin=Sa,y.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function O(){this.evTarget=Ua,this.evWin=Va,this.started=!1,y.apply(this,arguments)}function P(a,b){var c=t(a.touches),d=t(a.changedTouches);return b&(Aa|Ba)&&(c=u(c.concat(d),"identifier",!0)),[c,d]}function Q(){this.evTarget=Xa,this.targetIds={},y.apply(this,arguments)}function R(a,b){var c=t(a.touches),d=this.targetIds;if(b&(ya|za)&&1===c.length)return d[c[0].identifier]=!0,[c,c];var e,f,g=t(a.changedTouches),h=[],i=this.target;if(f=c.filter(function(a){return p(a.target,i)}),b===ya)for(e=0;e<f.length;)d[f[e].identifier]=!0,e++;for(e=0;e<g.length;)d[g[e].identifier]&&h.push(g[e]),b&(Aa|Ba)&&delete d[g[e].identifier],e++;return h.length?[u(f.concat(h),"identifier",!0),h]:void 0}function S(){y.apply(this,arguments);var a=k(this.handler,this);this.touch=new Q(this.manager,a),this.mouse=new M(this.manager,a)}function T(a,b){this.manager=a,this.set(b)}function U(a){if(q(a,bb))return bb;var b=q(a,cb),c=q(a,db);return b&&c?cb+" "+db:b||c?b?cb:db:q(a,ab)?ab:_a}function V(a){this.id=w(),this.manager=null,this.options=i(a||{},this.defaults),this.options.enable=m(this.options.enable,!0),this.state=eb,this.simultaneous={},this.requireFail=[]}function W(a){return a&jb?"cancel":a&hb?"end":a&gb?"move":a&fb?"start":""}function X(a){return a==Ga?"down":a==Fa?"up":a==Da?"left":a==Ea?"right":""}function Y(a,b){var c=b.manager;return c?c.get(a):a}function Z(){V.apply(this,arguments)}function $(){Z.apply(this,arguments),this.pX=null,this.pY=null}function _(){Z.apply(this,arguments)}function aa(){V.apply(this,arguments),this._timer=null,this._input=null}function ba(){Z.apply(this,arguments)}function ca(){Z.apply(this,arguments)}function da(){V.apply(this,arguments),this.pTime=!1,this.pCenter=!1,this._timer=null,this._input=null,this.count=0}function ea(a,b){return b=b||{},b.recognizers=m(b.recognizers,ea.defaults.preset),new fa(a,b)}function fa(a,b){b=b||{},this.options=i(b,ea.defaults),this.options.inputTarget=this.options.inputTarget||a,this.handlers={},this.session={},this.recognizers=[],this.element=a,this.input=z(this),this.touchAction=new T(this,this.options.touchAction),ga(this,!0),g(b.recognizers,function(a){var b=this.add(new a[0](a[1]));a[2]&&b.recognizeWith(a[2]),a[3]&&b.requireFailure(a[3])},this)}function ga(a,b){var c=a.element;g(a.options.cssProps,function(a,d){c.style[v(c.style,d)]=b?a:""})}function ha(a,c){var d=b.createEvent("Event");d.initEvent(a,!0,!0),d.gesture=c,c.target.dispatchEvent(d)}var ia=["","webkit","moz","MS","ms","o"],ja=b.createElement("div"),ka="function",la=Math.round,ma=Math.abs,na=Date.now,oa=1,pa=/mobile|tablet|ip(ad|hone|od)|android/i,qa="ontouchstart"in a,ra=v(a,"PointerEvent")!==d,sa=qa&&pa.test(navigator.userAgent),ta="touch",ua="pen",va="mouse",wa="kinect",xa=25,ya=1,za=2,Aa=4,Ba=8,Ca=1,Da=2,Ea=4,Fa=8,Ga=16,Ha=Da|Ea,Ia=Fa|Ga,Ja=Ha|Ia,Ka=["x","y"],La=["clientX","clientY"];y.prototype={handler:function(){},init:function(){this.evEl&&n(this.element,this.evEl,this.domHandler),this.evTarget&&n(this.target,this.evTarget,this.domHandler),this.evWin&&n(x(this.element),this.evWin,this.domHandler)},destroy:function(){this.evEl&&o(this.element,this.evEl,this.domHandler),this.evTarget&&o(this.target,this.evTarget,this.domHandler),this.evWin&&o(x(this.element),this.evWin,this.domHandler)}};var Ma={mousedown:ya,mousemove:za,mouseup:Aa},Na="mousedown",Oa="mousemove mouseup";j(M,y,{handler:function(a){var b=Ma[a.type];b&ya&&0===a.button&&(this.pressed=!0),b&za&&1!==a.which&&(b=Aa),this.pressed&&this.allow&&(b&Aa&&(this.pressed=!1),this.callback(this.manager,b,{pointers:[a],changedPointers:[a],pointerType:va,srcEvent:a}))}});var Pa={pointerdown:ya,pointermove:za,pointerup:Aa,pointercancel:Ba,pointerout:Ba},Qa={2:ta,3:ua,4:va,5:wa},Ra="pointerdown",Sa="pointermove pointerup pointercancel";a.MSPointerEvent&&(Ra="MSPointerDown",Sa="MSPointerMove MSPointerUp MSPointerCancel"),j(N,y,{handler:function(a){var b=this.store,c=!1,d=a.type.toLowerCase().replace("ms",""),e=Pa[d],f=Qa[a.pointerType]||a.pointerType,g=f==ta,h=s(b,a.pointerId,"pointerId");e&ya&&(0===a.button||g)?0>h&&(b.push(a),h=b.length-1):e&(Aa|Ba)&&(c=!0),0>h||(b[h]=a,this.callback(this.manager,e,{pointers:b,changedPointers:[a],pointerType:f,srcEvent:a}),c&&b.splice(h,1))}});var Ta={touchstart:ya,touchmove:za,touchend:Aa,touchcancel:Ba},Ua="touchstart",Va="touchstart touchmove touchend touchcancel";j(O,y,{handler:function(a){var b=Ta[a.type];if(b===ya&&(this.started=!0),this.started){var c=P.call(this,a,b);b&(Aa|Ba)&&0===c[0].length-c[1].length&&(this.started=!1),this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:ta,srcEvent:a})}}});var Wa={touchstart:ya,touchmove:za,touchend:Aa,touchcancel:Ba},Xa="touchstart touchmove touchend touchcancel";j(Q,y,{handler:function(a){var b=Wa[a.type],c=R.call(this,a,b);c&&this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:ta,srcEvent:a})}}),j(S,y,{handler:function(a,b,c){var d=c.pointerType==ta,e=c.pointerType==va;if(d)this.mouse.allow=!1;else if(e&&!this.mouse.allow)return;b&(Aa|Ba)&&(this.mouse.allow=!0),this.callback(a,b,c)},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var Ya=v(ja.style,"touchAction"),Za=Ya!==d,$a="compute",_a="auto",ab="manipulation",bb="none",cb="pan-x",db="pan-y";T.prototype={set:function(a){a==$a&&(a=this.compute()),Za&&(this.manager.element.style[Ya]=a),this.actions=a.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var a=[];return g(this.manager.recognizers,function(b){l(b.options.enable,[b])&&(a=a.concat(b.getTouchAction()))}),U(a.join(" "))},preventDefaults:function(a){if(!Za){var b=a.srcEvent,c=a.offsetDirection;if(this.manager.session.prevented)return void b.preventDefault();var d=this.actions,e=q(d,bb),f=q(d,db),g=q(d,cb);return e||f&&c&Ha||g&&c&Ia?this.preventSrc(b):void 0}},preventSrc:function(a){this.manager.session.prevented=!0,a.preventDefault()}};var eb=1,fb=2,gb=4,hb=8,ib=hb,jb=16,kb=32;V.prototype={defaults:{},set:function(a){return h(this.options,a),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(a){if(f(a,"recognizeWith",this))return this;var b=this.simultaneous;return a=Y(a,this),b[a.id]||(b[a.id]=a,a.recognizeWith(this)),this},dropRecognizeWith:function(a){return f(a,"dropRecognizeWith",this)?this:(a=Y(a,this),delete this.simultaneous[a.id],this)},requireFailure:function(a){if(f(a,"requireFailure",this))return this;var b=this.requireFail;return a=Y(a,this),-1===s(b,a)&&(b.push(a),a.requireFailure(this)),this},dropRequireFailure:function(a){if(f(a,"dropRequireFailure",this))return this;a=Y(a,this);var b=s(this.requireFail,a);return b>-1&&this.requireFail.splice(b,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(a){return!!this.simultaneous[a.id]},emit:function(a){function b(b){c.manager.emit(c.options.event+(b?W(d):""),a)}var c=this,d=this.state;hb>d&&b(!0),b(),d>=hb&&b(!0)},tryEmit:function(a){return this.canEmit()?this.emit(a):void(this.state=kb)},canEmit:function(){for(var a=0;a<this.requireFail.length;){if(!(this.requireFail[a].state&(kb|eb)))return!1;a++}return!0},recognize:function(a){var b=h({},a);return l(this.options.enable,[this,b])?(this.state&(ib|jb|kb)&&(this.state=eb),this.state=this.process(b),void(this.state&(fb|gb|hb|jb)&&this.tryEmit(b))):(this.reset(),void(this.state=kb))},process:function(){},getTouchAction:function(){},reset:function(){}},j(Z,V,{defaults:{pointers:1},attrTest:function(a){var b=this.options.pointers;return 0===b||a.pointers.length===b},process:function(a){var b=this.state,c=a.eventType,d=b&(fb|gb),e=this.attrTest(a);return d&&(c&Ba||!e)?b|jb:d||e?c&Aa?b|hb:b&fb?b|gb:fb:kb}}),j($,Z,{defaults:{event:"pan",threshold:10,pointers:1,direction:Ja},getTouchAction:function(){var a=this.options.direction,b=[];return a&Ha&&b.push(db),a&Ia&&b.push(cb),b},directionTest:function(a){var b=this.options,c=!0,d=a.distance,e=a.direction,f=a.deltaX,g=a.deltaY;return e&b.direction||(b.direction&Ha?(e=0===f?Ca:0>f?Da:Ea,c=f!=this.pX,d=Math.abs(a.deltaX)):(e=0===g?Ca:0>g?Fa:Ga,c=g!=this.pY,d=Math.abs(a.deltaY))),a.direction=e,c&&d>b.threshold&&e&b.direction},attrTest:function(a){return Z.prototype.attrTest.call(this,a)&&(this.state&fb||!(this.state&fb)&&this.directionTest(a))},emit:function(a){this.pX=a.deltaX,this.pY=a.deltaY;var b=X(a.direction);b&&this.manager.emit(this.options.event+b,a),this._super.emit.call(this,a)}}),j(_,Z,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[bb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.scale-1)>this.options.threshold||this.state&fb)},emit:function(a){if(this._super.emit.call(this,a),1!==a.scale){var b=a.scale<1?"in":"out";this.manager.emit(this.options.event+b,a)}}}),j(aa,V,{defaults:{event:"press",pointers:1,time:500,threshold:5},getTouchAction:function(){return[_a]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance<b.threshold,f=a.deltaTime>b.time;if(this._input=a,!d||!c||a.eventType&(Aa|Ba)&&!f)this.reset();else if(a.eventType&ya)this.reset(),this._timer=e(function(){this.state=ib,this.tryEmit()},b.time,this);else if(a.eventType&Aa)return ib;return kb},reset:function(){clearTimeout(this._timer)},emit:function(a){this.state===ib&&(a&&a.eventType&Aa?this.manager.emit(this.options.event+"up",a):(this._input.timeStamp=na(),this.manager.emit(this.options.event,this._input)))}}),j(ba,Z,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[bb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.rotation)>this.options.threshold||this.state&fb)}}),j(ca,Z,{defaults:{event:"swipe",threshold:10,velocity:.65,direction:Ha|Ia,pointers:1},getTouchAction:function(){return $.prototype.getTouchAction.call(this)},attrTest:function(a){var b,c=this.options.direction;return c&(Ha|Ia)?b=a.velocity:c&Ha?b=a.velocityX:c&Ia&&(b=a.velocityY),this._super.attrTest.call(this,a)&&c&a.direction&&a.distance>this.options.threshold&&ma(b)>this.options.velocity&&a.eventType&Aa},emit:function(a){var b=X(a.direction);b&&this.manager.emit(this.options.event+b,a),this.manager.emit(this.options.event,a)}}),j(da,V,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:2,posThreshold:10},getTouchAction:function(){return[ab]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance<b.threshold,f=a.deltaTime<b.time;if(this.reset(),a.eventType&ya&&0===this.count)return this.failTimeout();if(d&&f&&c){if(a.eventType!=Aa)return this.failTimeout();var g=this.pTime?a.timeStamp-this.pTime<b.interval:!0,h=!this.pCenter||I(this.pCenter,a.center)<b.posThreshold;this.pTime=a.timeStamp,this.pCenter=a.center,h&&g?this.count+=1:this.count=1,this._input=a;var i=this.count%b.taps;if(0===i)return this.hasRequireFailures()?(this._timer=e(function(){this.state=ib,this.tryEmit()},b.interval,this),fb):ib}return kb},failTimeout:function(){return this._timer=e(function(){this.state=kb},this.options.interval,this),kb},reset:function(){clearTimeout(this._timer)},emit:function(){this.state==ib&&(this._input.tapCount=this.count,this.manager.emit(this.options.event,this._input))}}),ea.VERSION="2.0.4",ea.defaults={domEvents:!1,touchAction:$a,enable:!0,inputTarget:null,inputClass:null,preset:[[ba,{enable:!1}],[_,{enable:!1},["rotate"]],[ca,{direction:Ha}],[$,{direction:Ha},["swipe"]],[da],[da,{event:"doubletap",taps:2},["tap"]],[aa]],cssProps:{userSelect:"default",touchSelect:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}};var lb=1,mb=2;fa.prototype={set:function(a){return h(this.options,a),a.touchAction&&this.touchAction.update(),a.inputTarget&&(this.input.destroy(),this.input.target=a.inputTarget,this.input.init()),this},stop:function(a){this.session.stopped=a?mb:lb},recognize:function(a){var b=this.session;if(!b.stopped){this.touchAction.preventDefaults(a);var c,d=this.recognizers,e=b.curRecognizer;(!e||e&&e.state&ib)&&(e=b.curRecognizer=null);for(var f=0;f<d.length;)c=d[f],b.stopped===mb||e&&c!=e&&!c.canRecognizeWith(e)?c.reset():c.recognize(a),!e&&c.state&(fb|gb|hb)&&(e=b.curRecognizer=c),f++}},get:function(a){if(a instanceof V)return a;for(var b=this.recognizers,c=0;c<b.length;c++)if(b[c].options.event==a)return b[c];return null},add:function(a){if(f(a,"add",this))return this;var b=this.get(a.options.event);return b&&this.remove(b),this.recognizers.push(a),a.manager=this,this.touchAction.update(),a},remove:function(a){if(f(a,"remove",this))return this;var b=this.recognizers;return a=this.get(a),b.splice(s(b,a),1),this.touchAction.update(),this},on:function(a,b){var c=this.handlers;return g(r(a),function(a){c[a]=c[a]||[],c[a].push(b)}),this},off:function(a,b){var c=this.handlers;return g(r(a),function(a){b?c[a].splice(s(c[a],b),1):delete c[a]}),this},emit:function(a,b){this.options.domEvents&&ha(a,b);var c=this.handlers[a]&&this.handlers[a].slice();if(c&&c.length){b.type=a,b.preventDefault=function(){b.srcEvent.preventDefault()};for(var d=0;d<c.length;)c[d](b),d++}},destroy:function(){this.element&&ga(this,!1),this.handlers={},this.session={},this.input.destroy(),this.element=null}},h(ea,{INPUT_START:ya,INPUT_MOVE:za,INPUT_END:Aa,INPUT_CANCEL:Ba,STATE_POSSIBLE:eb,STATE_BEGAN:fb,STATE_CHANGED:gb,STATE_ENDED:hb,STATE_RECOGNIZED:ib,STATE_CANCELLED:jb,STATE_FAILED:kb,DIRECTION_NONE:Ca,DIRECTION_LEFT:Da,DIRECTION_RIGHT:Ea,DIRECTION_UP:Fa,DIRECTION_DOWN:Ga,DIRECTION_HORIZONTAL:Ha,DIRECTION_VERTICAL:Ia,DIRECTION_ALL:Ja,Manager:fa,Input:y,TouchAction:T,TouchInput:Q,MouseInput:M,PointerEventInput:N,TouchMouseInput:S,SingleTouchInput:O,Recognizer:V,AttrRecognizer:Z,Tap:da,Pan:$,Swipe:ca,Pinch:_,Rotate:ba,Press:aa,on:n,off:o,each:g,merge:i,extend:h,inherit:j,bindFn:k,prefixed:v}),typeof define==ka&&define.amd?define(function(){return ea}):"undefined"!=typeof module&&module.exports?module.exports=ea:a[c]=ea}(window,document,"Hammer"),function(a){"function"==typeof define&&define.amd?define(["jquery","hammerjs"],a):"object"==typeof exports?a(require("jquery"),require("hammerjs")):a(jQuery,Hammer)}(function(a,b){function c(c,d){var e=a(c);e.data("hammer")||e.data("hammer",new b(e[0],d))}a.fn.hammer=function(a){return this.each(function(){c(this,a)})},b.Manager.prototype.emit=function(b){return function(c,d){b.call(this,c,d),a(this.element).trigger({type:c,gesture:d})}}(b.Manager.prototype.emit)}),function(a){a.Package?Materialize={}:a.Materialize={}}(window),Materialize.guid=function(){function a(){return Math.floor(65536*(1+Math.random())).toString(16).substring(1)}return function(){return a()+a()+"-"+a()+"-"+a()+"-"+a()+"-"+a()+a()+a()}}(),Materialize.elementOrParentIsFixed=function(a){var b=$(a),c=b.add(b.parents()),d=!1;return c.each(function(){return"fixed"===$(this).css("position")?(d=!0,!1):void 0}),d};var Vel;Vel=$?$.Velocity:jQuery?jQuery.Velocity:Velocity,function(a){a.fn.collapsible=function(b){var c={accordion:void 0};return b=a.extend(c,b),this.each(function(){function c(b){h=g.find("> li > .collapsible-header"),b.hasClass("active")?b.parent().addClass("active"):b.parent().removeClass("active"),b.parent().hasClass("active")?b.siblings(".collapsible-body").stop(!0,!1).slideDown({duration:350,easing:"easeOutQuart",queue:!1,complete:function(){a(this).css("height","")}}):b.siblings(".collapsible-body").stop(!0,!1).slideUp({duration:350,easing:"easeOutQuart",queue:!1,complete:function(){a(this).css("height","")}}),h.not(b).removeClass("active").parent().removeClass("active"),h.not(b).parent().children(".collapsible-body").stop(!0,!1).slideUp({duration:350,easing:"easeOutQuart",queue:!1,complete:function(){a(this).css("height","")}})}function d(b){b.hasClass("active")?b.parent().addClass("active"):b.parent().removeClass("active"),b.parent().hasClass("active")?b.siblings(".collapsible-body").stop(!0,!1).slideDown({duration:350,easing:"easeOutQuart",queue:!1,complete:function(){a(this).css("height","")}}):b.siblings(".collapsible-body").stop(!0,!1).slideUp({duration:350,easing:"easeOutQuart",queue:!1,complete:function(){a(this).css("height","")}})}function e(a){var b=f(a);return b.length>0}function f(a){return a.closest("li > .collapsible-header")}var g=a(this),h=a(this).find("> li > .collapsible-header"),i=g.data("collapsible");g.off("click.collapse","> li > .collapsible-header"),h.off("click.collapse"),g.on("click.collapse","> li > .collapsible-header",function(g){var h=a(this),j=a(g.target);e(j)&&(j=f(j)),j.toggleClass("active"),b.accordion||"accordion"===i||void 0===i?c(j):(d(j),h.hasClass("active")&&d(h))});var h=g.find("> li > .collapsible-header");b.accordion||"accordion"===i||void 0===i?c(h.filter(".active").first()):h.filter(".active").each(function(){d(a(this))})})},a(document).ready(function(){a(".collapsible").collapsible()})}(jQuery),function(a){a.fn.scrollTo=function(b){return a(this).scrollTop(a(this).scrollTop()-a(this).offset().top+a(b).offset().top),this},a.fn.dropdown=function(b){var c={inDuration:300,outDuration:225,constrain_width:!0,hover:!1,gutter:0,belowOrigin:!1,alignment:"left",stopPropagation:!1};return"open"===b?(this.each(function(){a(this).trigger("open")}),!1):"close"===b?(this.each(function(){a(this).trigger("close")}),!1):void this.each(function(){function b(){void 0!==f.data("induration")&&(g.inDuration=f.data("induration")),void 0!==f.data("outduration")&&(g.outDuration=f.data("outduration")),void 0!==f.data("constrainwidth")&&(g.constrain_width=f.data("constrainwidth")),void 0!==f.data("hover")&&(g.hover=f.data("hover")),void 0!==f.data("gutter")&&(g.gutter=f.data("gutter")),void 0!==f.data("beloworigin")&&(g.belowOrigin=f.data("beloworigin")),void 0!==f.data("alignment")&&(g.alignment=f.data("alignment")),void 0!==f.data("stoppropagation")&&(g.stopPropagation=f.data("stoppropagation"))}function d(c){"focus"===c&&(h=!0),b(),i.addClass("active"),f.addClass("active"),g.constrain_width===!0?i.css("width",f.outerWidth()):i.css("white-space","nowrap");var d=window.innerHeight,e=f.innerHeight(),j=f.offset().left,k=f.offset().top-a(window).scrollTop(),l=g.alignment,m=0,n=0,o=0;g.belowOrigin===!0&&(o=e);var p=0,q=0,r=f.parent();if(r.is("body")||(r[0].scrollHeight>r[0].clientHeight&&(p=r[0].scrollTop),r[0].scrollWidth>r[0].clientWidth&&(q=r[0].scrollLeft)),j+i.innerWidth()>a(window).width()?l="right":j-i.innerWidth()+f.innerWidth()<0&&(l="left"),k+i.innerHeight()>d)if(k+e-i.innerHeight()<0){var s=d-k-o;i.css("max-height",s)}else o||(o+=e),o-=i.innerHeight();if("left"===l)m=g.gutter,n=f.position().left+m;else if("right"===l){var t=f.position().left+f.outerWidth()-i.outerWidth();m=-g.gutter,n=t+m}i.css({position:"absolute",top:f.position().top+o+p,left:n+q}),i.stop(!0,!0).css("opacity",0).slideDown({queue:!1,duration:g.inDuration,easing:"easeOutCubic",complete:function(){a(this).css("height","")}}).animate({opacity:1},{queue:!1,duration:g.inDuration,easing:"easeOutSine"})}function e(){h=!1,i.fadeOut(g.outDuration),i.removeClass("active"),f.removeClass("active"),setTimeout(function(){i.css("max-height","")},g.outDuration)}var f=a(this),g=a.extend({},c,g),h=!1,i=a("#"+f.attr("data-activates"));if(b(),f.after(i),g.hover){var j=!1;f.unbind("click."+f.attr("id")),f.on("mouseenter",function(a){j===!1&&(d(),j=!0)}),f.on("mouseleave",function(b){var c=b.toElement||b.relatedTarget;a(c).closest(".dropdown-content").is(i)||(i.stop(!0,!0),e(),j=!1)}),i.on("mouseleave",function(b){var c=b.toElement||b.relatedTarget;a(c).closest(".dropdown-button").is(f)||(i.stop(!0,!0),e(),j=!1)})}else f.unbind("click."+f.attr("id")),f.bind("click."+f.attr("id"),function(b){h||(f[0]!=b.currentTarget||f.hasClass("active")||0!==a(b.target).closest(".dropdown-content").length?f.hasClass("active")&&(e(),a(document).unbind("click."+i.attr("id")+" touchstart."+i.attr("id"))):(b.preventDefault(),g.stopPropagation&&b.stopPropagation(),d("click")),i.hasClass("active")&&a(document).bind("click."+i.attr("id")+" touchstart."+i.attr("id"),function(b){i.is(b.target)||f.is(b.target)||f.find(b.target).length||(e(),a(document).unbind("click."+i.attr("id")+" touchstart."+i.attr("id")))}))});f.on("open",function(a,b){d(b)}),f.on("close",e)})},a(document).ready(function(){a(".dropdown-button").dropdown()})}(jQuery),function(a){var b=0,c=0,d=function(){return c++,"materialize-lean-overlay-"+c};a.fn.extend({openModal:function(c){var e=a("body"),f=e.innerWidth();e.css("overflow","hidden"),e.width(f);var g={opacity:.5,in_duration:350,out_duration:250,ready:void 0,complete:void 0,dismissible:!0,starting_top:"4%",ending_top:"10%"},h=a(this);if(!h.hasClass("open")){var i=d(),j=a('<div class="lean-overlay"></div>');lStack=++b,j.attr("id",i).css("z-index",1e3+2*lStack),h.data("overlay-id",i).css("z-index",1e3+2*lStack+1),h.addClass("open"),a("body").append(j),c=a.extend(g,c),c.dismissible&&(j.click(function(){h.closeModal(c)}),a(document).on("keyup.leanModal"+i,function(a){27===a.keyCode&&h.closeModal(c)})),h.find(".modal-close").on("click.close",function(a){h.closeModal(c)}),j.css({display:"block",opacity:0}),h.css({display:"block",opacity:0}),j.velocity({opacity:c.opacity},{duration:c.in_duration,queue:!1,ease:"easeOutCubic"}),h.data("associated-overlay",j[0]),h.hasClass("bottom-sheet")?h.velocity({bottom:"0",opacity:1},{duration:c.in_duration,queue:!1,ease:"easeOutCubic",complete:function(){"function"==typeof c.ready&&c.ready()}}):(a.Velocity.hook(h,"scaleX",.7),h.css({top:c.starting_top}),h.velocity({top:c.ending_top,opacity:1,scaleX:"1"},{duration:c.in_duration,queue:!1,ease:"easeOutCubic",
-complete:function(){"function"==typeof c.ready&&c.ready()}}))}}}),a.fn.extend({closeModal:function(c){var d={out_duration:250,complete:void 0},e=a(this),f=e.data("overlay-id"),g=a("#"+f);e.removeClass("open"),c=a.extend(d,c),a("body").css({overflow:"",width:""}),e.find(".modal-close").off("click.close"),a(document).off("keyup.leanModal"+f),g.velocity({opacity:0},{duration:c.out_duration,queue:!1,ease:"easeOutQuart"}),e.hasClass("bottom-sheet")?e.velocity({bottom:"-100%",opacity:0},{duration:c.out_duration,queue:!1,ease:"easeOutCubic",complete:function(){g.css({display:"none"}),"function"==typeof c.complete&&c.complete(),g.remove(),b--}}):e.velocity({top:c.starting_top,opacity:0,scaleX:.7},{duration:c.out_duration,complete:function(){a(this).css("display","none"),"function"==typeof c.complete&&c.complete(),g.remove(),b--}})}}),a.fn.extend({leanModal:function(b){return this.each(function(){var c={starting_top:"4%"},d=a.extend(c,b);a(this).click(function(b){d.starting_top=(a(this).offset().top-a(window).scrollTop())/1.15;var c=a(this).attr("href")||"#"+a(this).data("target");a(c).openModal(d),b.preventDefault()})})}})}(jQuery),function(a){a.fn.materialbox=function(){return this.each(function(){function b(){f=!1;var b=i.parent(".material-placeholder"),d=(window.innerWidth,window.innerHeight,i.data("width")),g=i.data("height");i.velocity("stop",!0),a("#materialbox-overlay").velocity("stop",!0),a(".materialbox-caption").velocity("stop",!0),a("#materialbox-overlay").velocity({opacity:0},{duration:h,queue:!1,easing:"easeOutQuad",complete:function(){e=!1,a(this).remove()}}),i.velocity({width:d,height:g,left:0,top:0},{duration:h,queue:!1,easing:"easeOutQuad"}),a(".materialbox-caption").velocity({opacity:0},{duration:h,queue:!1,easing:"easeOutQuad",complete:function(){b.css({height:"",width:"",position:"",top:"",left:""}),i.css({height:"",top:"",left:"",width:"","max-width":"",position:"","z-index":""}),i.removeClass("active"),f=!0,a(this).remove(),c&&c.css("overflow","")}})}if(!a(this).hasClass("initialized")){a(this).addClass("initialized");var c,d,e=!1,f=!0,g=275,h=200,i=a(this),j=a("<div></div>").addClass("material-placeholder");i.wrap(j),i.on("click",function(){var h=i.parent(".material-placeholder"),j=window.innerWidth,k=window.innerHeight,l=i.width(),m=i.height();if(f===!1)return b(),!1;if(e&&f===!0)return b(),!1;f=!1,i.addClass("active"),e=!0,h.css({width:h[0].getBoundingClientRect().width,height:h[0].getBoundingClientRect().height,position:"relative",top:0,left:0}),c=void 0,d=h[0].parentNode;for(;null!==d&&!a(d).is(document);){var n=a(d);"visible"!==n.css("overflow")&&(n.css("overflow","visible"),c=void 0===c?n:c.add(n)),d=d.parentNode}i.css({position:"absolute","z-index":1e3}).data("width",l).data("height",m);var o=a('<div id="materialbox-overlay"></div>').css({opacity:0}).click(function(){f===!0&&b()});if(i.before(o),o.velocity({opacity:1},{duration:g,queue:!1,easing:"easeOutQuad"}),""!==i.data("caption")){var p=a('<div class="materialbox-caption"></div>');p.text(i.data("caption")),a("body").append(p),p.css({display:"inline"}),p.velocity({opacity:1},{duration:g,queue:!1,easing:"easeOutQuad"})}var q=0,r=l/j,s=m/k,t=0,u=0;r>s?(q=m/l,t=.9*j,u=.9*j*q):(q=l/m,t=.9*k*q,u=.9*k),i.hasClass("responsive-img")?i.velocity({"max-width":t,width:l},{duration:0,queue:!1,complete:function(){i.css({left:0,top:0}).velocity({height:u,width:t,left:a(document).scrollLeft()+j/2-i.parent(".material-placeholder").offset().left-t/2,top:a(document).scrollTop()+k/2-i.parent(".material-placeholder").offset().top-u/2},{duration:g,queue:!1,easing:"easeOutQuad",complete:function(){f=!0}})}}):i.css("left",0).css("top",0).velocity({height:u,width:t,left:a(document).scrollLeft()+j/2-i.parent(".material-placeholder").offset().left-t/2,top:a(document).scrollTop()+k/2-i.parent(".material-placeholder").offset().top-u/2},{duration:g,queue:!1,easing:"easeOutQuad",complete:function(){f=!0}})}),a(window).scroll(function(){e&&b()}),a(document).keyup(function(a){27===a.keyCode&&f===!0&&e&&b()})}})},a(document).ready(function(){a(".materialboxed").materialbox()})}(jQuery),function(a){a.fn.parallax=function(){var b=a(window).width();return this.each(function(c){function d(c){var d;d=601>b?e.height()>0?e.height():e.children("img").height():e.height()>0?e.height():500;var f=e.children("img").first(),g=f.height(),h=g-d,i=e.offset().top+d,j=e.offset().top,k=a(window).scrollTop(),l=window.innerHeight,m=k+l,n=(m-j)/(d+l),o=Math.round(h*n);c&&f.css("display","block"),i>k&&k+l>j&&f.css("transform","translate3D(-50%,"+o+"px, 0)")}var e=a(this);e.addClass("parallax"),e.children("img").one("load",function(){d(!0)}).each(function(){this.complete&&a(this).load()}),a(window).scroll(function(){b=a(window).width(),d(!1)}),a(window).resize(function(){b=a(window).width(),d(!1)})})}}(jQuery),function(a){var b={init:function(b){var c={onShow:null};return b=a.extend(c,b),this.each(function(){var c=a(this);a(window).width();c.width("100%");var d,e,f=c.find("li.tab a"),g=c.width(),h=Math.max(g,c[0].scrollWidth)/f.length,i=0;d=a(f.filter('[href="'+location.hash+'"]')),0===d.length&&(d=a(this).find("li.tab a.active").first()),0===d.length&&(d=a(this).find("li.tab a").first()),d.addClass("active"),i=f.index(d),0>i&&(i=0),void 0!==d[0]&&(e=a(d[0].hash)),c.append('<div class="indicator"></div>');var j=c.find(".indicator");c.is(":visible")&&(j.css({right:g-(i+1)*h}),j.css({left:i*h})),a(window).resize(function(){g=c.width(),h=Math.max(g,c[0].scrollWidth)/f.length,0>i&&(i=0),0!==h&&0!==g&&(j.css({right:g-(i+1)*h}),j.css({left:i*h}))}),f.not(d).each(function(){a(this.hash).hide()}),c.on("click","a",function(k){if(a(this).parent().hasClass("disabled"))return void k.preventDefault();if(!a(this).attr("target")){g=c.width(),h=Math.max(g,c[0].scrollWidth)/f.length,d.removeClass("active"),void 0!==e&&e.hide(),d=a(this),e=a(this.hash),f=c.find("li.tab a"),d.addClass("active");var l=i;i=f.index(a(this)),0>i&&(i=0),void 0!==e&&(e.show(),"function"==typeof b.onShow&&b.onShow.call(this,e)),i-l>=0?(j.velocity({right:g-(i+1)*h},{duration:300,queue:!1,easing:"easeOutQuad"}),j.velocity({left:i*h},{duration:300,queue:!1,easing:"easeOutQuad",delay:90})):(j.velocity({left:i*h},{duration:300,queue:!1,easing:"easeOutQuad"}),j.velocity({right:g-(i+1)*h},{duration:300,queue:!1,easing:"easeOutQuad",delay:90})),k.preventDefault()}})})},select_tab:function(a){this.find('a[href="#'+a+'"]').trigger("click")}};a.fn.tabs=function(c){return b[c]?b[c].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof c&&c?void a.error("Method "+c+" does not exist on jQuery.tooltip"):b.init.apply(this,arguments)},a(document).ready(function(){a("ul.tabs").tabs()})}(jQuery),function(a){a.fn.tooltip=function(c){var d=5,e={delay:350,tooltip:"",position:"bottom",html:!1};return"remove"===c?(this.each(function(){a("#"+a(this).attr("data-tooltip-id")).remove(),a(this).off("mouseenter.tooltip mouseleave.tooltip")}),!1):(c=a.extend(e,c),this.each(function(){var e=Materialize.guid(),f=a(this);f.attr("data-tooltip-id",e);var g,h,i,j,k,l,m=function(){g=f.attr("data-html")?"true"===f.attr("data-html"):c.html,h=f.attr("data-delay"),h=void 0===h||""===h?c.delay:h,i=f.attr("data-position"),i=void 0===i||""===i?c.position:i,j=f.attr("data-tooltip"),j=void 0===j||""===j?c.tooltip:j};m();var n=function(){var b=a('<div class="material-tooltip"></div>');return j=g?a("<span></span>").html(j):a("<span></span>").text(j),b.append(j).appendTo(a("body")).attr("id",e),l=a('<div class="backdrop"></div>'),l.appendTo(b),b};k=n(),f.off("mouseenter.tooltip mouseleave.tooltip");var o,p=!1;f.on({"mouseenter.tooltip":function(a){var c=function(){m(),p=!0,k.velocity("stop"),l.velocity("stop"),k.css({display:"block",left:"0px",top:"0px"});var a,c,e,g=f.outerWidth(),h=f.outerHeight(),j=k.outerHeight(),n=k.outerWidth(),o="0px",q="0px",r=8,s=8;"top"===i?(a=f.offset().top-j-d,c=f.offset().left+g/2-n/2,e=b(c,a,n,j),o="-10px",l.css({bottom:0,left:0,borderRadius:"14px 14px 0 0",transformOrigin:"50% 100%",marginTop:j,marginLeft:n/2-l.width()/2})):"left"===i?(a=f.offset().top+h/2-j/2,c=f.offset().left-n-d,e=b(c,a,n,j),q="-10px",l.css({top:"-7px",right:0,width:"14px",height:"14px",borderRadius:"14px 0 0 14px",transformOrigin:"95% 50%",marginTop:j/2,marginLeft:n})):"right"===i?(a=f.offset().top+h/2-j/2,c=f.offset().left+g+d,e=b(c,a,n,j),q="+10px",l.css({top:"-7px",left:0,width:"14px",height:"14px",borderRadius:"0 14px 14px 0",transformOrigin:"5% 50%",marginTop:j/2,marginLeft:"0px"})):(a=f.offset().top+f.outerHeight()+d,c=f.offset().left+g/2-n/2,e=b(c,a,n,j),o="+10px",l.css({top:0,left:0,marginLeft:n/2-l.width()/2})),k.css({top:e.y,left:e.x}),r=Math.SQRT2*n/parseInt(l.css("width")),s=Math.SQRT2*j/parseInt(l.css("height")),k.velocity({marginTop:o,marginLeft:q},{duration:350,queue:!1}).velocity({opacity:1},{duration:300,delay:50,queue:!1}),l.css({display:"block"}).velocity({opacity:1},{duration:55,delay:0,queue:!1}).velocity({scaleX:r,scaleY:s},{duration:300,delay:0,queue:!1,easing:"easeInOutQuad"})};o=setTimeout(c,h)},"mouseleave.tooltip":function(){p=!1,clearTimeout(o),setTimeout(function(){p!==!0&&(k.velocity({opacity:0,marginTop:0,marginLeft:0},{duration:225,queue:!1}),l.velocity({opacity:0,scaleX:1,scaleY:1},{duration:225,queue:!1,complete:function(){l.css("display","none"),k.css("display","none"),p=!1}}))},225)}})}))};var b=function(b,c,d,e){var f=b,g=c;return 0>f?f=4:f+d>window.innerWidth&&(f-=f+d-window.innerWidth),0>g?g=4:g+e>window.innerHeight+a(window).scrollTop&&(g-=g+e-window.innerHeight),{x:f,y:g}};a(document).ready(function(){a(".tooltipped").tooltip()})}(jQuery),function(a){"use strict";function b(a){return null!==a&&a===a.window}function c(a){return b(a)?a:9===a.nodeType&&a.defaultView}function d(a){var b,d,e={top:0,left:0},f=a&&a.ownerDocument;return b=f.documentElement,"undefined"!=typeof a.getBoundingClientRect&&(e=a.getBoundingClientRect()),d=c(f),{top:e.top+d.pageYOffset-b.clientTop,left:e.left+d.pageXOffset-b.clientLeft}}function e(a){var b="";for(var c in a)a.hasOwnProperty(c)&&(b+=c+":"+a[c]+";");return b}function f(a){if(k.allowEvent(a)===!1)return null;for(var b=null,c=a.target||a.srcElement;null!==c.parentElement;){if(!(c instanceof SVGElement||-1===c.className.indexOf("waves-effect"))){b=c;break}if(c.classList.contains("waves-effect")){b=c;break}c=c.parentElement}return b}function g(b){var c=f(b);null!==c&&(j.show(b,c),"ontouchstart"in a&&(c.addEventListener("touchend",j.hide,!1),c.addEventListener("touchcancel",j.hide,!1)),c.addEventListener("mouseup",j.hide,!1),c.addEventListener("mouseleave",j.hide,!1))}var h=h||{},i=document.querySelectorAll.bind(document),j={duration:750,show:function(a,b){if(2===a.button)return!1;var c=b||this,f=document.createElement("div");f.className="waves-ripple",c.appendChild(f);var g=d(c),h=a.pageY-g.top,i=a.pageX-g.left,k="scale("+c.clientWidth/100*10+")";"touches"in a&&(h=a.touches[0].pageY-g.top,i=a.touches[0].pageX-g.left),f.setAttribute("data-hold",Date.now()),f.setAttribute("data-scale",k),f.setAttribute("data-x",i),f.setAttribute("data-y",h);var l={top:h+"px",left:i+"px"};f.className=f.className+" waves-notransition",f.setAttribute("style",e(l)),f.className=f.className.replace("waves-notransition",""),l["-webkit-transform"]=k,l["-moz-transform"]=k,l["-ms-transform"]=k,l["-o-transform"]=k,l.transform=k,l.opacity="1",l["-webkit-transition-duration"]=j.duration+"ms",l["-moz-transition-duration"]=j.duration+"ms",l["-o-transition-duration"]=j.duration+"ms",l["transition-duration"]=j.duration+"ms",l["-webkit-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",l["-moz-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",l["-o-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",l["transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",f.setAttribute("style",e(l))},hide:function(a){k.touchup(a);var b=this,c=(1.4*b.clientWidth,null),d=b.getElementsByClassName("waves-ripple");if(!(d.length>0))return!1;c=d[d.length-1];var f=c.getAttribute("data-x"),g=c.getAttribute("data-y"),h=c.getAttribute("data-scale"),i=Date.now()-Number(c.getAttribute("data-hold")),l=350-i;0>l&&(l=0),setTimeout(function(){var a={top:g+"px",left:f+"px",opacity:"0","-webkit-transition-duration":j.duration+"ms","-moz-transition-duration":j.duration+"ms","-o-transition-duration":j.duration+"ms","transition-duration":j.duration+"ms","-webkit-transform":h,"-moz-transform":h,"-ms-transform":h,"-o-transform":h,transform:h};c.setAttribute("style",e(a)),setTimeout(function(){try{b.removeChild(c)}catch(a){return!1}},j.duration)},l)},wrapInput:function(a){for(var b=0;b<a.length;b++){var c=a[b];if("input"===c.tagName.toLowerCase()){var d=c.parentNode;if("i"===d.tagName.toLowerCase()&&-1!==d.className.indexOf("waves-effect"))continue;var e=document.createElement("i");e.className=c.className+" waves-input-wrapper";var f=c.getAttribute("style");f||(f=""),e.setAttribute("style",f),c.className="waves-button-input",c.removeAttribute("style"),d.replaceChild(e,c),e.appendChild(c)}}}},k={touches:0,allowEvent:function(a){var b=!0;return"touchstart"===a.type?k.touches+=1:"touchend"===a.type||"touchcancel"===a.type?setTimeout(function(){k.touches>0&&(k.touches-=1)},500):"mousedown"===a.type&&k.touches>0&&(b=!1),b},touchup:function(a){k.allowEvent(a)}};h.displayEffect=function(b){b=b||{},"duration"in b&&(j.duration=b.duration),j.wrapInput(i(".waves-effect")),"ontouchstart"in a&&document.body.addEventListener("touchstart",g,!1),document.body.addEventListener("mousedown",g,!1)},h.attach=function(b){"input"===b.tagName.toLowerCase()&&(j.wrapInput([b]),b=b.parentElement),"ontouchstart"in a&&b.addEventListener("touchstart",g,!1),b.addEventListener("mousedown",g,!1)},a.Waves=h,document.addEventListener("DOMContentLoaded",function(){h.displayEffect()},!1)}(window),Materialize.toast=function(a,b,c,d){function e(a){var b=document.createElement("div");if(b.classList.add("toast"),c)for(var e=c.split(" "),f=0,g=e.length;g>f;f++)b.classList.add(e[f]);("object"==typeof HTMLElement?a instanceof HTMLElement:a&&"object"==typeof a&&null!==a&&1===a.nodeType&&"string"==typeof a.nodeName)?b.appendChild(a):a instanceof jQuery?b.appendChild(a[0]):b.innerHTML=a;var h=new Hammer(b,{prevent_default:!1});return h.on("pan",function(a){var c=a.deltaX,d=80;b.classList.contains("panning")||b.classList.add("panning");var e=1-Math.abs(c/d);0>e&&(e=0),Vel(b,{left:c,opacity:e},{duration:50,queue:!1,easing:"easeOutQuad"})}),h.on("panend",function(a){var c=a.deltaX,e=80;Math.abs(c)>e?Vel(b,{marginTop:"-40px"},{duration:375,easing:"easeOutExpo",queue:!1,complete:function(){"function"==typeof d&&d(),b.parentNode.removeChild(b)}}):(b.classList.remove("panning"),Vel(b,{left:0,opacity:1},{duration:300,easing:"easeOutExpo",queue:!1}))}),b}c=c||"";var f=document.getElementById("toast-container");null===f&&(f=document.createElement("div"),f.id="toast-container",document.body.appendChild(f));var g=e(a);a&&f.appendChild(g),g.style.top="35px",g.style.opacity=0,Vel(g,{top:"0px",opacity:1},{duration:300,easing:"easeOutCubic",queue:!1});var h=b,i=setInterval(function(){null===g.parentNode&&window.clearInterval(i),g.classList.contains("panning")||(h-=20),0>=h&&(Vel(g,{opacity:0,marginTop:"-40px"},{duration:375,easing:"easeOutExpo",queue:!1,complete:function(){"function"==typeof d&&d(),this[0].parentNode.removeChild(this[0])}}),window.clearInterval(i))},20)},function(a){var b={init:function(b){var c={menuWidth:300,edge:"left",closeOnClick:!1};b=a.extend(c,b),a(this).each(function(){function c(c){g=!1,h=!1,a("body").css({overflow:"",width:""}),a("#sidenav-overlay").velocity({opacity:0},{duration:200,queue:!1,easing:"easeOutQuad",complete:function(){a(this).remove()}}),"left"===b.edge?(f.css({width:"",right:"",left:"0"}),e.velocity({translateX:"-100%"},{duration:200,queue:!1,easing:"easeOutCubic",complete:function(){c===!0&&(e.removeAttr("style"),e.css("width",b.menuWidth))}})):(f.css({width:"",right:"0",left:""}),e.velocity({translateX:"100%"},{duration:200,queue:!1,easing:"easeOutCubic",complete:function(){c===!0&&(e.removeAttr("style"),e.css("width",b.menuWidth))}}))}var d=a(this),e=a("#"+d.attr("data-activates"));300!=b.menuWidth&&e.css("width",b.menuWidth);var f=a('<div class="drag-target"></div>');a("body").append(f),"left"==b.edge?(e.css("transform","translateX(-100%)"),f.css({left:0})):(e.addClass("right-aligned").css("transform","translateX(100%)"),f.css({right:0})),e.hasClass("fixed")&&window.innerWidth>992&&e.css("transform","translateX(0)"),e.hasClass("fixed")&&a(window).resize(function(){window.innerWidth>992?0!==a("#sidenav-overlay").length&&h?c(!0):e.css("transform","translateX(0%)"):h===!1&&("left"===b.edge?e.css("transform","translateX(-100%)"):e.css("transform","translateX(100%)"))}),b.closeOnClick===!0&&e.on("click.itemclick","a:not(.collapsible-header)",function(){c()});var g=!1,h=!1;f.on("click",function(){h&&c()}),f.hammer({prevent_default:!1}).bind("pan",function(d){if("touch"==d.gesture.pointerType){var f=(d.gesture.direction,d.gesture.center.x),g=(d.gesture.center.y,d.gesture.velocityX,a("body")),i=g.innerWidth();if(g.css("overflow","hidden"),g.width(i),0===a("#sidenav-overlay").length){var j=a('<div id="sidenav-overlay"></div>');j.css("opacity",0).click(function(){c()}),a("body").append(j)}if("left"===b.edge&&(f>b.menuWidth?f=b.menuWidth:0>f&&(f=0)),"left"===b.edge)f<b.menuWidth/2?h=!1:f>=b.menuWidth/2&&(h=!0),e.css("transform","translateX("+(f-b.menuWidth)+"px)");else{f<window.innerWidth-b.menuWidth/2?h=!0:f>=window.innerWidth-b.menuWidth/2&&(h=!1);var k=f-b.menuWidth/2;0>k&&(k=0),e.css("transform","translateX("+k+"px)")}var l;"left"===b.edge?(l=f/b.menuWidth,a("#sidenav-overlay").velocity({opacity:l},{duration:10,queue:!1,easing:"easeOutQuad"})):(l=Math.abs((f-window.innerWidth)/b.menuWidth),a("#sidenav-overlay").velocity({opacity:l},{duration:10,queue:!1,easing:"easeOutQuad"}))}}).bind("panend",function(c){if("touch"==c.gesture.pointerType){var d=c.gesture.velocityX,i=c.gesture.center.x,j=i-b.menuWidth,k=i-b.menuWidth/2;j>0&&(j=0),0>k&&(k=0),g=!1,"left"===b.edge?h&&.3>=d||-.5>d?(0!==j&&e.velocity({translateX:[0,j]},{duration:300,queue:!1,easing:"easeOutQuad"}),a("#sidenav-overlay").velocity({opacity:1},{duration:50,queue:!1,easing:"easeOutQuad"}),f.css({width:"50%",right:0,left:""}),h=!0):(!h||d>.3)&&(a("body").css({overflow:"",width:""}),e.velocity({translateX:[-1*b.menuWidth-10,j]},{duration:200,queue:!1,easing:"easeOutQuad"}),a("#sidenav-overlay").velocity({opacity:0},{duration:200,queue:!1,easing:"easeOutQuad",complete:function(){a(this).remove()}}),f.css({width:"10px",right:"",left:0})):h&&d>=-.3||d>.5?(0!==k&&e.velocity({translateX:[0,k]},{duration:300,queue:!1,easing:"easeOutQuad"}),a("#sidenav-overlay").velocity({opacity:1},{duration:50,queue:!1,easing:"easeOutQuad"}),f.css({width:"50%",right:"",left:0}),h=!0):(!h||-.3>d)&&(a("body").css({overflow:"",width:""}),e.velocity({translateX:[b.menuWidth+10,k]},{duration:200,queue:!1,easing:"easeOutQuad"}),a("#sidenav-overlay").velocity({opacity:0},{duration:200,queue:!1,easing:"easeOutQuad",complete:function(){a(this).remove()}}),f.css({width:"10px",right:0,left:""}))}}),d.click(function(){if(h===!0)h=!1,g=!1,c();else{var d=a("body"),i=d.innerWidth();d.css("overflow","hidden"),d.width(i),a("body").append(f),"left"===b.edge?(f.css({width:"50%",right:0,left:""}),e.velocity({translateX:[0,-1*b.menuWidth]},{duration:300,queue:!1,easing:"easeOutQuad"})):(f.css({width:"50%",right:"",left:0}),e.velocity({translateX:[0,b.menuWidth]},{duration:300,queue:!1,easing:"easeOutQuad"}));var j=a('<div id="sidenav-overlay"></div>');j.css("opacity",0).click(function(){h=!1,g=!1,c(),j.velocity({opacity:0},{duration:300,queue:!1,easing:"easeOutQuad",complete:function(){a(this).remove()}})}),a("body").append(j),j.velocity({opacity:1},{duration:300,queue:!1,easing:"easeOutQuad",complete:function(){h=!0,g=!1}})}return!1})})},show:function(){this.trigger("click")},hide:function(){a("#sidenav-overlay").trigger("click")}};a.fn.sideNav=function(c){return b[c]?b[c].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof c&&c?void a.error("Method "+c+" does not exist on jQuery.sideNav"):b.init.apply(this,arguments)}}(jQuery),function(a){function b(b,c,d,e){var f=a();return a.each(g,function(a,g){if(g.height()>0){var h=g.offset().top,i=g.offset().left,j=i+g.width(),k=h+g.height(),l=!(i>c||e>j||h>d||b>k);l&&f.push(g)}}),f}function c(){++j;var c=f.scrollTop(),d=f.scrollLeft(),e=d+f.width(),g=c+f.height(),i=b(c+k.top+200,e+k.right,g+k.bottom,d+k.left);a.each(i,function(a,b){var c=b.data("scrollSpy:ticks");"number"!=typeof c&&b.triggerHandler("scrollSpy:enter"),b.data("scrollSpy:ticks",j)}),a.each(h,function(a,b){var c=b.data("scrollSpy:ticks");"number"==typeof c&&c!==j&&(b.triggerHandler("scrollSpy:exit"),b.data("scrollSpy:ticks",null))}),h=i}function d(){f.trigger("scrollSpy:winSize")}function e(a,b,c){var d,e,f,g=null,h=0;c||(c={});var i=function(){h=c.leading===!1?0:l(),g=null,f=a.apply(d,e),d=e=null};return function(){var j=l();h||c.leading!==!1||(h=j);var k=b-(j-h);return d=this,e=arguments,0>=k?(clearTimeout(g),g=null,h=j,f=a.apply(d,e),d=e=null):g||c.trailing===!1||(g=setTimeout(i,k)),f}}var f=a(window),g=[],h=[],i=!1,j=0,k={top:0,right:0,bottom:0,left:0},l=Date.now||function(){return(new Date).getTime()};a.scrollSpy=function(b,d){var h={throttle:100,scrollOffset:200};d=a.extend(h,d);var j=[];b=a(b),b.each(function(b,c){g.push(a(c)),a(c).data("scrollSpy:id",b),a('a[href="#'+a(c).attr("id")+'"]').click(function(b){b.preventDefault();var c=a(this.hash).offset().top+1;a("html, body").animate({scrollTop:c-d.scrollOffset},{duration:400,queue:!1,easing:"easeOutCubic"})})}),k.top=d.offsetTop||0,k.right=d.offsetRight||0,k.bottom=d.offsetBottom||0,k.left=d.offsetLeft||0;var l=e(c,d.throttle||100),m=function(){a(document).ready(l)};return i||(f.on("scroll",m),f.on("resize",m),i=!0),setTimeout(m,0),b.on("scrollSpy:enter",function(){j=a.grep(j,function(a){return 0!=a.height()});var b=a(this);j[0]?(a('a[href="#'+j[0].attr("id")+'"]').removeClass("active"),b.data("scrollSpy:id")<j[0].data("scrollSpy:id")?j.unshift(a(this)):j.push(a(this))):j.push(a(this)),a('a[href="#'+j[0].attr("id")+'"]').addClass("active")}),b.on("scrollSpy:exit",function(){if(j=a.grep(j,function(a){return 0!=a.height()}),j[0]){a('a[href="#'+j[0].attr("id")+'"]').removeClass("active");var b=a(this);j=a.grep(j,function(a){return a.attr("id")!=b.attr("id")}),j[0]&&a('a[href="#'+j[0].attr("id")+'"]').addClass("active")}}),b},a.winSizeSpy=function(b){return a.winSizeSpy=function(){return f},b=b||{throttle:100},f.on("resize",e(d,b.throttle||100))},a.fn.scrollSpy=function(b){return a.scrollSpy(a(this),b)}}(jQuery),function(a){a(document).ready(function(){function b(b){var c=b.css("font-family"),d=b.css("font-size"),f=b.css("line-height");d&&e.css("font-size",d),c&&e.css("font-family",c),f&&e.css("line-height",f),"off"===b.attr("wrap")&&e.css("overflow-wrap","normal").css("white-space","pre"),e.text(b.val()+"\n");var g=e.html().replace(/\n/g,"<br>");e.html(g),b.is(":visible")?e.css("width",b.width()):e.css("width",a(window).width()/2),b.css("height",e.height())}Materialize.updateTextFields=function(){var b="input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea";a(b).each(function(b,c){a(c).val().length>0||c.autofocus||void 0!==a(this).attr("placeholder")||a(c)[0].validity.badInput===!0?a(this).siblings("label").addClass("active"):a(this).siblings("label").removeClass("active")})};var c="input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea";a(document).on("change",c,function(){(0!==a(this).val().length||void 0!==a(this).attr("placeholder"))&&a(this).siblings("label").addClass("active"),validate_field(a(this))}),a(document).ready(function(){Materialize.updateTextFields()}),a(document).on("reset",function(b){var d=a(b.target);d.is("form")&&(d.find(c).removeClass("valid").removeClass("invalid"),d.find(c).each(function(){""===a(this).attr("value")&&a(this).siblings("label").removeClass("active")}),d.find("select.initialized").each(function(){var a=d.find("option[selected]").text();d.siblings("input.select-dropdown").val(a)}))}),a(document).on("focus",c,function(){a(this).siblings("label, .prefix").addClass("active")}),a(document).on("blur",c,function(){var b=a(this),c=".prefix";0===b.val().length&&b[0].validity.badInput!==!0&&void 0===b.attr("placeholder")&&(c+=", label"),b.siblings(c).removeClass("active"),validate_field(b)}),window.validate_field=function(a){var b=void 0!==a.attr("length"),c=parseInt(a.attr("length")),d=a.val().length;0===a.val().length&&a[0].validity.badInput===!1?a.hasClass("validate")&&(a.removeClass("valid"),a.removeClass("invalid")):a.hasClass("validate")&&(a.is(":valid")&&b&&c>=d||a.is(":valid")&&!b?(a.removeClass("invalid"),a.addClass("valid")):(a.removeClass("valid"),a.addClass("invalid")))};var d="input[type=radio], input[type=checkbox]";a(document).on("keyup.radio",d,function(b){if(9===b.which){a(this).addClass("tabbed");var c=a(this);return void c.one("blur",function(b){a(this).removeClass("tabbed")})}});var e=a(".hiddendiv").first();e.length||(e=a('<div class="hiddendiv common"></div>'),a("body").append(e));var f=".materialize-textarea";a(f).each(function(){var c=a(this);c.val().length&&b(c)}),a("body").on("keyup keydown autoresize",f,function(){b(a(this))}),a(document).on("change",'.file-field input[type="file"]',function(){for(var b=a(this).closest(".file-field"),c=b.find("input.file-path"),d=a(this)[0].files,e=[],f=0;f<d.length;f++)e.push(d[f].name);c.val(e.join(", ")),c.trigger("change")});var g,h="input[type=range]",i=!1;a(h).each(function(){var b=a('<span class="thumb"><span class="value"></span></span>');a(this).after(b)});var j=".range-field";a(document).on("change",h,function(b){var c=a(this).siblings(".thumb");c.find(".value").html(a(this).val())}),a(document).on("input mousedown touchstart",h,function(b){var c=a(this).siblings(".thumb"),d=a(this).outerWidth();c.length<=0&&(c=a('<span class="thumb"><span class="value"></span></span>'),a(this).after(c)),c.find(".value").html(a(this).val()),i=!0,a(this).addClass("active"),c.hasClass("active")||c.velocity({height:"30px",width:"30px",top:"-20px",marginLeft:"-15px"},{duration:300,easing:"easeOutExpo"}),"input"!==b.type&&(g=void 0===b.pageX||null===b.pageX?b.originalEvent.touches[0].pageX-a(this).offset().left:b.pageX-a(this).offset().left,0>g?g=0:g>d&&(g=d),c.addClass("active").css("left",g)),c.find(".value").html(a(this).val())}),a(document).on("mouseup touchend",j,function(){i=!1,a(this).removeClass("active")}),a(document).on("mousemove touchmove",j,function(b){var c,d=a(this).children(".thumb");if(i){d.hasClass("active")||d.velocity({height:"30px",width:"30px",top:"-20px",marginLeft:"-15px"},{duration:300,easing:"easeOutExpo"}),c=void 0===b.pageX||null===b.pageX?b.originalEvent.touches[0].pageX-a(this).offset().left:b.pageX-a(this).offset().left;var e=a(this).outerWidth();0>c?c=0:c>e&&(c=e),d.addClass("active").css("left",c),d.find(".value").html(d.siblings(h).val())}}),a(document).on("mouseout touchleave",j,function(){if(!i){var b=a(this).children(".thumb");b.hasClass("active")&&b.velocity({height:"0",width:"0",top:"10px",marginLeft:"-6px"},{duration:100}),b.removeClass("active")}}),a.fn.autocomplete=function(b){var c={data:{}};return b=a.extend(c,b),this.each(function(){var c=a(this),d=b.data,e=c.closest(".input-field");if(!a.isEmptyObject(d)){var f=a('<ul class="autocomplete-content dropdown-content"></ul>');e.length?e.append(f):c.after(f);var g=function(a,b){var c=b.find("img"),d=b.text().toLowerCase().indexOf(""+a.toLowerCase()),e=d+a.length-1,f=b.text().slice(0,d),g=b.text().slice(d,e+1),h=b.text().slice(e+1);b.html("<span>"+f+"<span class='highlight'>"+g+"</span>"+h+"</span>"),c.length&&b.prepend(c)};c.on("keyup",function(b){if(13===b.which)return void f.find("li").first().click();var e=c.val().toLowerCase();if(f.empty(),""!==e)for(var h in d)if(d.hasOwnProperty(h)&&-1!==h.toLowerCase().indexOf(e)&&h.toLowerCase()!==e){var i=a("<li></li>");d[h]?i.append('<img src="'+d[h]+'" class="right circle"><span>'+h+"</span>"):i.append("<span>"+h+"</span>"),f.append(i),g(e,i)}}),f.on("click","li",function(){c.val(a(this).text().trim()),f.empty()})}})}}),a.fn.material_select=function(b){function c(a,b,c){var e=a.indexOf(b),f=-1===e;return f?a.push(b):a.splice(e,1),c.siblings("ul.dropdown-content").find("li").eq(b).toggleClass("active"),c.find("option").eq(b).prop("selected",f),d(a,c),f}function d(a,b){for(var c="",d=0,e=a.length;e>d;d++){var f=b.find("option").eq(a[d]).text();c+=0===d?f:", "+f}""===c&&(c=b.find("option:disabled").eq(0).text()),b.siblings("input.select-dropdown").val(c)}a(this).each(function(){var d=a(this);if(!d.hasClass("browser-default")){var e=d.attr("multiple")?!0:!1,f=d.data("select-id");if(f&&(d.parent().find("span.caret").remove(),d.parent().find("input").remove(),d.unwrap(),a("ul#select-options-"+f).remove()),"destroy"===b)return void d.data("select-id",null).removeClass("initialized");var g=Materialize.guid();d.data("select-id",g);var h=a('<div class="select-wrapper"></div>');h.addClass(d.attr("class"));var i=a('<ul id="select-options-'+g+'" class="dropdown-content select-dropdown '+(e?"multiple-select-dropdown":"")+'"></ul>'),j=d.children("option, optgroup"),k=[],l=!1,m=d.find("option:selected").html()||d.find("option:first").html()||"",n=function(b,c,d){var e=c.is(":disabled")?"disabled ":"",f="optgroup-option"===d?"optgroup-option ":"",g=c.data("icon"),h=c.attr("class");if(g){var j="";return h&&(j=' class="'+h+'"'),"multiple"===d?i.append(a('<li class="'+e+'"><img src="'+g+'"'+j+'><span><input type="checkbox"'+e+"/><label></label>"+c.html()+"</span></li>")):i.append(a('<li class="'+e+f+'"><img src="'+g+'"'+j+"><span>"+c.html()+"</span></li>")),!0}"multiple"===d?i.append(a('<li class="'+e+'"><span><input type="checkbox"'+e+"/><label></label>"+c.html()+"</span></li>")):i.append(a('<li class="'+e+f+'"><span>'+c.html()+"</span></li>"))};j.length&&j.each(function(){if(a(this).is("option"))e?n(d,a(this),"multiple"):n(d,a(this));else if(a(this).is("optgroup")){var b=a(this).children("option");i.append(a('<li class="optgroup"><span>'+a(this).attr("label")+"</span></li>")),b.each(function(){n(d,a(this),"optgroup-option")})}}),i.find("li:not(.optgroup)").each(function(f){a(this).click(function(g){if(!a(this).hasClass("disabled")&&!a(this).hasClass("optgroup")){var h=!0;e?(a('input[type="checkbox"]',this).prop("checked",function(a,b){return!b}),h=c(k,a(this).index(),d),q.trigger("focus")):(i.find("li").removeClass("active"),a(this).toggleClass("active"),q.val(a(this).text())),r(i,a(this)),d.find("option").eq(f).prop("selected",h),d.trigger("change"),"undefined"!=typeof b&&b()}g.stopPropagation()})}),d.wrap(h);var o=a('<span class="caret">&#9660;</span>');d.is(":disabled")&&o.addClass("disabled");var p=m.replace(/"/g,"&quot;"),q=a('<input type="text" class="select-dropdown" readonly="true" '+(d.is(":disabled")?"disabled":"")+' data-activates="select-options-'+g+'" value="'+p+'"/>');d.before(q),q.before(o),q.after(i),d.is(":disabled")||q.dropdown({hover:!1,closeOnClick:!1}),d.attr("tabindex")&&a(q[0]).attr("tabindex",d.attr("tabindex")),d.addClass("initialized"),q.on({focus:function(){if(a("ul.select-dropdown").not(i[0]).is(":visible")&&a("input.select-dropdown").trigger("close"),!i.is(":visible")){a(this).trigger("open",["focus"]);var b=a(this).val(),c=i.find("li").filter(function(){return a(this).text().toLowerCase()===b.toLowerCase()})[0];r(i,c)}},click:function(a){a.stopPropagation()}}),q.on("blur",function(){e||a(this).trigger("close"),i.find("li.selected").removeClass("selected")}),i.hover(function(){l=!0},function(){l=!1}),a(window).on({click:function(){e&&(l||q.trigger("close"))}}),e&&d.find("option:selected:not(:disabled)").each(function(){
-var b=a(this).index();c(k,b,d),i.find("li").eq(b).find(":checkbox").prop("checked",!0)});var r=function(b,c){if(c){b.find("li.selected").removeClass("selected");var d=a(c);d.addClass("selected"),i.scrollTo(d)}},s=[],t=function(b){if(9==b.which)return void q.trigger("close");if(40==b.which&&!i.is(":visible"))return void q.trigger("open");if(13!=b.which||i.is(":visible")){b.preventDefault();var c=String.fromCharCode(b.which).toLowerCase(),d=[9,13,27,38,40];if(c&&-1===d.indexOf(b.which)){s.push(c);var f=s.join(""),g=i.find("li").filter(function(){return 0===a(this).text().toLowerCase().indexOf(f)})[0];g&&r(i,g)}if(13==b.which){var h=i.find("li.selected:not(.disabled)")[0];h&&(a(h).trigger("click"),e||q.trigger("close"))}40==b.which&&(g=i.find("li.selected").length?i.find("li.selected").next("li:not(.disabled)")[0]:i.find("li:not(.disabled)")[0],r(i,g)),27==b.which&&q.trigger("close"),38==b.which&&(g=i.find("li.selected").prev("li:not(.disabled)")[0],g&&r(i,g)),setTimeout(function(){s=[]},1e3)}};q.on("keydown",t)}})}}(jQuery),function(a){var b={init:function(b){var c={indicators:!0,height:400,transition:500,interval:6e3};return b=a.extend(c,b),this.each(function(){function c(a,b){a.hasClass("center-align")?a.velocity({opacity:0,translateY:-100},{duration:b,queue:!1}):a.hasClass("right-align")?a.velocity({opacity:0,translateX:100},{duration:b,queue:!1}):a.hasClass("left-align")&&a.velocity({opacity:0,translateX:-100},{duration:b,queue:!1})}function d(a){a>=j.length?a=0:0>a&&(a=j.length-1),k=i.find(".active").index(),k!=a&&(e=j.eq(k),$caption=e.find(".caption"),e.removeClass("active"),e.velocity({opacity:0},{duration:b.transition,queue:!1,easing:"easeOutQuad",complete:function(){j.not(".active").velocity({opacity:0,translateX:0,translateY:0},{duration:0,queue:!1})}}),c($caption,b.transition),b.indicators&&f.eq(k).removeClass("active"),j.eq(a).velocity({opacity:1},{duration:b.transition,queue:!1,easing:"easeOutQuad"}),j.eq(a).find(".caption").velocity({opacity:1,translateX:0,translateY:0},{duration:b.transition,delay:b.transition,queue:!1,easing:"easeOutQuad"}),j.eq(a).addClass("active"),b.indicators&&f.eq(a).addClass("active"))}var e,f,g,h=a(this),i=h.find("ul.slides").first(),j=i.find("> li"),k=i.find(".active").index();-1!=k&&(e=j.eq(k)),h.hasClass("fullscreen")||(b.indicators?h.height(b.height+40):h.height(b.height),i.height(b.height)),j.find(".caption").each(function(){c(a(this),0)}),j.find("img").each(function(){var b="data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";a(this).attr("src")!==b&&(a(this).css("background-image","url("+a(this).attr("src")+")"),a(this).attr("src",b))}),b.indicators&&(f=a('<ul class="indicators"></ul>'),j.each(function(c){var e=a('<li class="indicator-item"></li>');e.click(function(){var c=i.parent(),e=c.find(a(this)).index();d(e),clearInterval(g),g=setInterval(function(){k=i.find(".active").index(),j.length==k+1?k=0:k+=1,d(k)},b.transition+b.interval)}),f.append(e)}),h.append(f),f=h.find("ul.indicators").find("li.indicator-item")),e?e.show():(j.first().addClass("active").velocity({opacity:1},{duration:b.transition,queue:!1,easing:"easeOutQuad"}),k=0,e=j.eq(k),b.indicators&&f.eq(k).addClass("active")),e.find("img").each(function(){e.find(".caption").velocity({opacity:1,translateX:0,translateY:0},{duration:b.transition,queue:!1,easing:"easeOutQuad"})}),g=setInterval(function(){k=i.find(".active").index(),d(k+1)},b.transition+b.interval);var l=!1,m=!1,n=!1;h.hammer({prevent_default:!1}).bind("pan",function(a){if("touch"===a.gesture.pointerType){clearInterval(g);var b=a.gesture.direction,c=a.gesture.deltaX,d=a.gesture.velocityX;$curr_slide=i.find(".active"),$curr_slide.velocity({translateX:c},{duration:50,queue:!1,easing:"easeOutQuad"}),4===b&&(c>h.innerWidth()/2||-.65>d)?n=!0:2===b&&(c<-1*h.innerWidth()/2||d>.65)&&(m=!0);var e;m&&(e=$curr_slide.next(),0===e.length&&(e=j.first()),e.velocity({opacity:1},{duration:300,queue:!1,easing:"easeOutQuad"})),n&&(e=$curr_slide.prev(),0===e.length&&(e=j.last()),e.velocity({opacity:1},{duration:300,queue:!1,easing:"easeOutQuad"}))}}).bind("panend",function(a){"touch"===a.gesture.pointerType&&($curr_slide=i.find(".active"),l=!1,curr_index=i.find(".active").index(),!n&&!m||j.length<=1?$curr_slide.velocity({translateX:0},{duration:300,queue:!1,easing:"easeOutQuad"}):m?(d(curr_index+1),$curr_slide.velocity({translateX:-1*h.innerWidth()},{duration:300,queue:!1,easing:"easeOutQuad",complete:function(){$curr_slide.velocity({opacity:0,translateX:0},{duration:0,queue:!1})}})):n&&(d(curr_index-1),$curr_slide.velocity({translateX:h.innerWidth()},{duration:300,queue:!1,easing:"easeOutQuad",complete:function(){$curr_slide.velocity({opacity:0,translateX:0},{duration:0,queue:!1})}})),m=!1,n=!1,clearInterval(g),g=setInterval(function(){k=i.find(".active").index(),j.length==k+1?k=0:k+=1,d(k)},b.transition+b.interval))}),h.on("sliderPause",function(){clearInterval(g)}),h.on("sliderStart",function(){clearInterval(g),g=setInterval(function(){k=i.find(".active").index(),j.length==k+1?k=0:k+=1,d(k)},b.transition+b.interval)}),h.on("sliderNext",function(){k=i.find(".active").index(),d(k+1)}),h.on("sliderPrev",function(){k=i.find(".active").index(),d(k-1)})})},pause:function(){a(this).trigger("sliderPause")},start:function(){a(this).trigger("sliderStart")},next:function(){a(this).trigger("sliderNext")},prev:function(){a(this).trigger("sliderPrev")}};a.fn.slider=function(c){return b[c]?b[c].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof c&&c?void a.error("Method "+c+" does not exist on jQuery.tooltip"):b.init.apply(this,arguments)}}(jQuery),function(a){a(document).ready(function(){a(document).on("click.card",".card",function(b){a(this).find("> .card-reveal").length&&(a(b.target).is(a(".card-reveal .card-title"))||a(b.target).is(a(".card-reveal .card-title i"))?a(this).find(".card-reveal").velocity({translateY:0},{duration:225,queue:!1,easing:"easeInOutQuad",complete:function(){a(this).css({display:"none"})}}):(a(b.target).is(a(".card .activator"))||a(b.target).is(a(".card .activator i")))&&(a(b.target).closest(".card").css("overflow","hidden"),a(this).find(".card-reveal").css({display:"block"}).velocity("stop",!1).velocity({translateY:"-100%"},{duration:300,queue:!1,easing:"easeInOutQuad"})))})})}(jQuery),function(a){var b=!1,c={data:[],placeholder:"",secondaryPlaceholder:""};a(document).ready(function(){a(document).on("click",".chip .close",function(b){var c=a(this).closest(".chips");c.data("initialized")||a(this).closest(".chip").remove()})}),a.fn.material_chip=function(d){var e=this;return this.$el=a(this),this.$document=a(document),this.SELS={CHIPS:".chips",CHIP:".chip",INPUT:"input",DELETE:".material-icons",SELECTED_CHIP:".selected"},"data"===d?this.$el.data("chips"):"options"===d?this.$el.data("options"):(this.$el.data("options",a.extend({},c,d)),this.init=function(){var b=0;e.$el.each(function(){var c=a(this);if(!c.data("initialized")){var d=c.data("options");(!d.data||!d.data instanceof Array)&&(d.data=[]),c.data("chips",d.data),c.data("index",b),c.data("initialized",!0),c.hasClass(e.SELS.CHIPS)||c.addClass("chips"),e.chips(c),b++}})},this.handleEvents=function(){var b=e.SELS;e.$document.on("click",b.CHIPS,function(c){a(c.target).find(b.INPUT).focus()}),e.$document.on("click",b.CHIP,function(c){a(b.CHIP).removeClass("selected"),a(this).toggleClass("selected")}),e.$document.on("keydown",function(c){if(!a(c.target).is("input, textarea")){var d,f=e.$document.find(b.CHIP+b.SELECTED_CHIP),g=f.closest(b.CHIPS),h=f.siblings(b.CHIP).length;if(f.length)if(8===c.which||46===c.which){c.preventDefault();var i=g.data("index");d=f.index(),e.deleteChip(i,d,g);var j=null;h>d+1?j=d:(d===h||d+1===h)&&(j=h-1),0>j&&(j=null),null!==j&&e.selectChip(i,j,g),h||g.find("input").focus()}else if(37===c.which){if(d=f.index()-1,0>d)return;a(b.CHIP).removeClass("selected"),e.selectChip(g.data("index"),d,g)}else if(39===c.which){if(d=f.index()+1,a(b.CHIP).removeClass("selected"),d>h)return void g.find("input").focus();e.selectChip(g.data("index"),d,g)}}}),e.$document.on("focusin",b.CHIPS+" "+b.INPUT,function(c){a(c.target).closest(b.CHIPS).addClass("focus"),a(b.CHIP).removeClass("selected")}),e.$document.on("focusout",b.CHIPS+" "+b.INPUT,function(c){a(c.target).closest(b.CHIPS).removeClass("focus")}),e.$document.on("keydown",b.CHIPS+" "+b.INPUT,function(c){var d=a(c.target),f=d.closest(b.CHIPS),g=f.data("index"),h=f.children(b.CHIP).length;return 13===c.which?(c.preventDefault(),e.addChip(g,{tag:d.val()},f),void d.val("")):8!==c.keyCode&&37!==c.keyCode||""!==d.val()||!h?void 0:(e.selectChip(g,h-1,f),void d.blur())}),e.$document.on("click",b.CHIPS+" "+b.DELETE,function(c){var d=a(c.target),f=d.closest(b.CHIPS),g=d.closest(b.CHIP);c.stopPropagation(),e.deleteChip(f.data("index"),g.index(),f),f.find("input").focus()})},this.chips=function(a){var b="";a.data("options");a.data("chips").forEach(function(a){b+=e.renderChip(a)}),b+='<input class="input" placeholder="">',a.html(b),e.setPlaceholder(a)},this.renderChip=function(a){if(a.tag){var b='<div class="chip">'+a.tag;return a.image&&(b+=' <img src="'+a.image+'"> '),b+='<i class="material-icons close">close</i>',b+="</div>"}},this.setPlaceholder=function(a){var b=a.data("options");a.data("chips").length&&b.placeholder?a.find("input").prop("placeholder",b.placeholder):!a.data("chips").length&&b.secondaryPlaceholder&&a.find("input").prop("placeholder",b.secondaryPlaceholder)},this.isValid=function(a,b){for(var c=a.data("chips"),d=!1,e=0;e<c.length;e++)if(c[e].tag===b.tag)return void(d=!0);return""!==b.tag&&!d},this.addChip=function(b,c,d){if(e.isValid(d,c)){var f=(d.data("options"),e.renderChip(c));d.data("chips").push(c),a(f).insertBefore(d.find("input")),d.trigger("chip.add",c),e.setPlaceholder(d)}},this.deleteChip=function(a,b,c){var d=c.data("chips")[b];c.find(".chip").eq(b).remove(),c.data("chips").splice(b,1),c.trigger("chip.delete",d),e.setPlaceholder(c)},this.selectChip=function(a,b,c){var d=c.find(".chip").eq(b);d&&!1===d.hasClass("selected")&&(d.addClass("selected"),c.trigger("chip.select",c.data("chips")[b]))},this.getChipsElement=function(a,b){return b.eq(a)},this.init(),void(b||(this.handleEvents(),b=!0)))}}(jQuery),function(a){a.fn.pushpin=function(b){var c={top:0,bottom:1/0,offset:0};return"remove"===b?(this.each(function(){(id=a(this).data("pushpin-id"))&&(a(window).off("scroll."+id),a(this).removeData("pushpin-id").removeClass("pin-top pinned pin-bottom").removeAttr("style"))}),!1):(b=a.extend(c,b),$index=0,this.each(function(){function c(a){a.removeClass("pin-top"),a.removeClass("pinned"),a.removeClass("pin-bottom")}function d(d,e){d.each(function(){b.top<=e&&b.bottom>=e&&!a(this).hasClass("pinned")&&(c(a(this)),a(this).css("top",b.offset),a(this).addClass("pinned")),e<b.top&&!a(this).hasClass("pin-top")&&(c(a(this)),a(this).css("top",0),a(this).addClass("pin-top")),e>b.bottom&&!a(this).hasClass("pin-bottom")&&(c(a(this)),a(this).addClass("pin-bottom"),a(this).css("top",b.bottom-g))})}var e=Materialize.guid(),f=a(this),g=a(this).offset().top;a(this).data("pushpin-id",e),d(f,a(window).scrollTop()),a(window).on("scroll."+e,function(){var c=a(window).scrollTop()+b.offset;d(f,c)})}))}}(jQuery),function(a){a(document).ready(function(){a.fn.reverse=[].reverse,a(document).on("mouseenter.fixedActionBtn",".fixed-action-btn:not(.click-to-toggle)",function(c){var d=a(this);b(d)}),a(document).on("mouseleave.fixedActionBtn",".fixed-action-btn:not(.click-to-toggle)",function(b){var d=a(this);c(d)}),a(document).on("click.fixedActionBtn",".fixed-action-btn.click-to-toggle > a",function(d){var e=a(this),f=e.parent();f.hasClass("active")?c(f):b(f)})}),a.fn.extend({openFAB:function(){b(a(this))},closeFAB:function(){c(a(this))}});var b=function(b){if($this=b,$this.hasClass("active")===!1){var c,d,e=$this.hasClass("horizontal");e===!0?d=40:c=40,$this.addClass("active"),$this.find("ul .btn-floating").velocity({scaleY:".4",scaleX:".4",translateY:c+"px",translateX:d+"px"},{duration:0});var f=0;$this.find("ul .btn-floating").reverse().each(function(){a(this).velocity({opacity:"1",scaleX:"1",scaleY:"1",translateY:"0",translateX:"0"},{duration:80,delay:f}),f+=40})}},c=function(a){$this=a;var b,c,d=$this.hasClass("horizontal");d===!0?c=40:b=40,$this.removeClass("active");$this.find("ul .btn-floating").velocity("stop",!0),$this.find("ul .btn-floating").velocity({opacity:"0",scaleX:".4",scaleY:".4",translateY:b+"px",translateX:c+"px"},{duration:80})}}(jQuery),function(a){Materialize.fadeInImage=function(b){var c;if("string"==typeof b)c=a(b);else{if("object"!=typeof b)return;c=b}c.css({opacity:0}),a(c).velocity({opacity:1},{duration:650,queue:!1,easing:"easeOutSine"}),a(c).velocity({opacity:1},{duration:1300,queue:!1,easing:"swing",step:function(b,c){c.start=100;var d=b/100,e=150-(100-b)/1.75;100>e&&(e=100),b>=0&&a(this).css({"-webkit-filter":"grayscale("+d+")brightness("+e+"%)",filter:"grayscale("+d+")brightness("+e+"%)"})}})},Materialize.showStaggeredList=function(b){var c;if("string"==typeof b)c=a(b);else{if("object"!=typeof b)return;c=b}var d=0;c.find("li").velocity({translateX:"-100px"},{duration:0}),c.find("li").each(function(){a(this).velocity({opacity:"1",translateX:"0"},{duration:800,delay:d,easing:[60,10]}),d+=120})},a(document).ready(function(){var b=!1,c=!1;a(".dismissable").each(function(){a(this).hammer({prevent_default:!1}).bind("pan",function(d){if("touch"===d.gesture.pointerType){var e=a(this),f=d.gesture.direction,g=d.gesture.deltaX,h=d.gesture.velocityX;e.velocity({translateX:g},{duration:50,queue:!1,easing:"easeOutQuad"}),4===f&&(g>e.innerWidth()/2||-.75>h)&&(b=!0),2===f&&(g<-1*e.innerWidth()/2||h>.75)&&(c=!0)}}).bind("panend",function(d){if(Math.abs(d.gesture.deltaX)<a(this).innerWidth()/2&&(c=!1,b=!1),"touch"===d.gesture.pointerType){var e=a(this);if(b||c){var f;f=b?e.innerWidth():-1*e.innerWidth(),e.velocity({translateX:f},{duration:100,queue:!1,easing:"easeOutQuad",complete:function(){e.css("border","none"),e.velocity({height:0,padding:0},{duration:200,queue:!1,easing:"easeOutQuad",complete:function(){e.remove()}})}})}else e.velocity({translateX:0},{duration:100,queue:!1,easing:"easeOutQuad"});b=!1,c=!1}})})})}(jQuery),function(a){Materialize.scrollFire=function(a){var b=!1;window.addEventListener("scroll",function(){b=!0}),setInterval(function(){if(b){b=!1;for(var c=window.pageYOffset+window.innerHeight,d=0;d<a.length;d++){var e=a[d],f=e.selector,g=e.offset,h=e.callback,i=document.querySelector(f);if(null!==i){var j=i.getBoundingClientRect().top+window.pageYOffset;if(c>j+g&&e.done!==!0){if("function"==typeof h)h.call(this,i);else if("string"==typeof h){var k=new Function(h);k(i)}e.done=!0}}}}},100)}}(jQuery),function(a){"function"==typeof define&&define.amd?define("picker",["jquery"],a):"object"==typeof exports?module.exports=a(require("jquery")):this.Picker=a(jQuery)}(function(a){function b(f,g,i,l){function m(){return b._.node("div",b._.node("div",b._.node("div",b._.node("div",y.component.nodes(t.open),v.box),v.wrap),v.frame),v.holder)}function n(){w.data(g,y).addClass(v.input).attr("tabindex",-1).val(w.data("value")?y.get("select",u.format):f.value),u.editable||w.on("focus."+t.id+" click."+t.id,function(a){a.preventDefault(),y.$root.eq(0).focus()}).on("keydown."+t.id,q),e(f,{haspopup:!0,expanded:!1,readonly:!1,owns:f.id+"_root"})}function o(){y.$root.on({keydown:q,focusin:function(a){y.$root.removeClass(v.focused),a.stopPropagation()},"mousedown click":function(b){var c=b.target;c!=y.$root.children()[0]&&(b.stopPropagation(),"mousedown"!=b.type||a(c).is("input, select, textarea, button, option")||(b.preventDefault(),y.$root.eq(0).focus()))}}).on({focus:function(){w.addClass(v.target)},blur:function(){w.removeClass(v.target)}}).on("focus.toOpen",r).on("click","[data-pick], [data-nav], [data-clear], [data-close]",function(){var b=a(this),c=b.data(),d=b.hasClass(v.navDisabled)||b.hasClass(v.disabled),e=h();e=e&&(e.type||e.href),(d||e&&!a.contains(y.$root[0],e))&&y.$root.eq(0).focus(),!d&&c.nav?y.set("highlight",y.component.item.highlight,{nav:c.nav}):!d&&"pick"in c?y.set("select",c.pick):c.clear?y.clear().close(!0):c.close&&y.close(!0)}),e(y.$root[0],"hidden",!0)}function p(){var b;u.hiddenName===!0?(b=f.name,f.name=""):(b=["string"==typeof u.hiddenPrefix?u.hiddenPrefix:"","string"==typeof u.hiddenSuffix?u.hiddenSuffix:"_submit"],b=b[0]+f.name+b[1]),y._hidden=a('<input type=hidden name="'+b+'"'+(w.data("value")||f.value?' value="'+y.get("select",u.formatSubmit)+'"':"")+">")[0],w.on("change."+t.id,function(){y._hidden.value=f.value?y.get("select",u.formatSubmit):""}),u.container?a(u.container).append(y._hidden):w.after(y._hidden)}function q(a){var b=a.keyCode,c=/^(8|46)$/.test(b);return 27==b?(y.close(),!1):void((32==b||c||!t.open&&y.component.key[b])&&(a.preventDefault(),a.stopPropagation(),c?y.clear().close():y.open()))}function r(a){a.stopPropagation(),"focus"==a.type&&y.$root.addClass(v.focused),y.open()}if(!f)return b;var s=!1,t={id:f.id||"P"+Math.abs(~~(Math.random()*new Date))},u=i?a.extend(!0,{},i.defaults,l):l||{},v=a.extend({},b.klasses(),u.klass),w=a(f),x=function(){return this.start()},y=x.prototype={constructor:x,$node:w,start:function(){return t&&t.start?y:(t.methods={},t.start=!0,t.open=!1,t.type=f.type,f.autofocus=f==h(),f.readOnly=!u.editable,f.id=f.id||t.id,"text"!=f.type&&(f.type="text"),y.component=new i(y,u),y.$root=a(b._.node("div",m(),v.picker,'id="'+f.id+'_root" tabindex="0"')),o(),u.formatSubmit&&p(),n(),u.container?a(u.container).append(y.$root):w.after(y.$root),y.on({start:y.component.onStart,render:y.component.onRender,stop:y.component.onStop,open:y.component.onOpen,close:y.component.onClose,set:y.component.onSet}).on({start:u.onStart,render:u.onRender,stop:u.onStop,open:u.onOpen,close:u.onClose,set:u.onSet}),s=c(y.$root.children()[0]),f.autofocus&&y.open(),y.trigger("start").trigger("render"))},render:function(a){return a?y.$root.html(m()):y.$root.find("."+v.box).html(y.component.nodes(t.open)),y.trigger("render")},stop:function(){return t.start?(y.close(),y._hidden&&y._hidden.parentNode.removeChild(y._hidden),y.$root.remove(),w.removeClass(v.input).removeData(g),setTimeout(function(){w.off("."+t.id)},0),f.type=t.type,f.readOnly=!1,y.trigger("stop"),t.methods={},t.start=!1,y):y},open:function(c){return t.open?y:(w.addClass(v.active),e(f,"expanded",!0),setTimeout(function(){y.$root.addClass(v.opened),e(y.$root[0],"hidden",!1)},0),c!==!1&&(t.open=!0,s&&k.css("overflow","hidden").css("padding-right","+="+d()),y.$root.eq(0).focus(),j.on("click."+t.id+" focusin."+t.id,function(a){var b=a.target;b!=f&&b!=document&&3!=a.which&&y.close(b===y.$root.children()[0])}).on("keydown."+t.id,function(c){var d=c.keyCode,e=y.component.key[d],f=c.target;27==d?y.close(!0):f!=y.$root[0]||!e&&13!=d?a.contains(y.$root[0],f)&&13==d&&(c.preventDefault(),f.click()):(c.preventDefault(),e?b._.trigger(y.component.key.go,y,[b._.trigger(e)]):y.$root.find("."+v.highlighted).hasClass(v.disabled)||y.set("select",y.component.item.highlight).close())})),y.trigger("open"))},close:function(a){return a&&(y.$root.off("focus.toOpen").eq(0).focus(),setTimeout(function(){y.$root.on("focus.toOpen",r)},0)),w.removeClass(v.active),e(f,"expanded",!1),setTimeout(function(){y.$root.removeClass(v.opened+" "+v.focused),e(y.$root[0],"hidden",!0)},0),t.open?(t.open=!1,s&&k.css("overflow","").css("padding-right","-="+d()),j.off("."+t.id),y.trigger("close")):y},clear:function(a){return y.set("clear",null,a)},set:function(b,c,d){var e,f,g=a.isPlainObject(b),h=g?b:{};if(d=g&&a.isPlainObject(c)?c:d||{},b){g||(h[b]=c);for(e in h)f=h[e],e in y.component.item&&(void 0===f&&(f=null),y.component.set(e,f,d)),("select"==e||"clear"==e)&&w.val("clear"==e?"":y.get(e,u.format)).trigger("change");y.render()}return d.muted?y:y.trigger("set",h)},get:function(a,c){if(a=a||"value",null!=t[a])return t[a];if("valueSubmit"==a){if(y._hidden)return y._hidden.value;a="value"}if("value"==a)return f.value;if(a in y.component.item){if("string"==typeof c){var d=y.component.get(a);return d?b._.trigger(y.component.formats.toString,y.component,[c,d]):""}return y.component.get(a)}},on:function(b,c,d){var e,f,g=a.isPlainObject(b),h=g?b:{};if(b){g||(h[b]=c);for(e in h)f=h[e],d&&(e="_"+e),t.methods[e]=t.methods[e]||[],t.methods[e].push(f)}return y},off:function(){var a,b,c=arguments;for(a=0,namesCount=c.length;a<namesCount;a+=1)b=c[a],b in t.methods&&delete t.methods[b];return y},trigger:function(a,c){var d=function(a){var d=t.methods[a];d&&d.map(function(a){b._.trigger(a,y,[c])})};return d("_"+a),d(a),y}};return new x}function c(a){var b,c="position";return a.currentStyle?b=a.currentStyle[c]:window.getComputedStyle&&(b=getComputedStyle(a)[c]),"fixed"==b}function d(){if(k.height()<=i.height())return 0;var b=a('<div style="visibility:hidden;width:100px" />').appendTo("body"),c=b[0].offsetWidth;b.css("overflow","scroll");var d=a('<div style="width:100%" />').appendTo(b),e=d[0].offsetWidth;return b.remove(),c-e}function e(b,c,d){if(a.isPlainObject(c))for(var e in c)f(b,e,c[e]);else f(b,c,d)}function f(a,b,c){a.setAttribute(("role"==b?"":"aria-")+b,c)}function g(b,c){a.isPlainObject(b)||(b={attribute:c}),c="";for(var d in b){var e=("role"==d?"":"aria-")+d,f=b[d];c+=null==f?"":e+'="'+b[d]+'"'}return c}function h(){try{return document.activeElement}catch(a){}}var i=a(window),j=a(document),k=a(document.documentElement);return b.klasses=function(a){return a=a||"picker",{picker:a,opened:a+"--opened",focused:a+"--focused",input:a+"__input",active:a+"__input--active",target:a+"__input--target",holder:a+"__holder",frame:a+"__frame",wrap:a+"__wrap",box:a+"__box"}},b._={group:function(a){for(var c,d="",e=b._.trigger(a.min,a);e<=b._.trigger(a.max,a,[e]);e+=a.i)c=b._.trigger(a.item,a,[e]),d+=b._.node(a.node,c[0],c[1],c[2]);return d},node:function(b,c,d,e){return c?(c=a.isArray(c)?c.join(""):c,d=d?' class="'+d+'"':"",e=e?" "+e:"","<"+b+d+e+">"+c+"</"+b+">"):""},lead:function(a){return(10>a?"0":"")+a},trigger:function(a,b,c){return"function"==typeof a?a.apply(b,c||[]):a},digits:function(a){return/\d/.test(a[1])?2:1},isDate:function(a){return{}.toString.call(a).indexOf("Date")>-1&&this.isInteger(a.getDate())},isInteger:function(a){return{}.toString.call(a).indexOf("Number")>-1&&a%1===0},ariaAttr:g},b.extend=function(c,d){a.fn[c]=function(e,f){var g=this.data(c);return"picker"==e?g:g&&"string"==typeof e?b._.trigger(g[e],g,[f]):this.each(function(){var f=a(this);f.data(c)||new b(this,c,d,e)})},a.fn[c].defaults=d.defaults},b}),function(a){"function"==typeof define&&define.amd?define(["picker","jquery"],a):"object"==typeof exports?module.exports=a(require("./picker.js"),require("jquery")):a(Picker,jQuery)}(function(a,b){function c(a,b){var c=this,d=a.$node[0],e=d.value,f=a.$node.data("value"),g=f||e,h=f?b.formatSubmit:b.format,i=function(){return d.currentStyle?"rtl"==d.currentStyle.direction:"rtl"==getComputedStyle(a.$root[0]).direction};c.settings=b,c.$node=a.$node,c.queue={min:"measure create",max:"measure create",now:"now create",select:"parse create validate",highlight:"parse navigate create validate",view:"parse create validate viewset",disable:"deactivate",enable:"activate"},c.item={},c.item.clear=null,c.item.disable=(b.disable||[]).slice(0),c.item.enable=-function(a){return a[0]===!0?a.shift():-1}(c.item.disable),c.set("min",b.min).set("max",b.max).set("now"),g?c.set("select",g,{format:h}):c.set("select",null).set("highlight",c.item.now),c.key={40:7,38:-7,39:function(){return i()?-1:1},37:function(){return i()?1:-1},go:function(a){var b=c.item.highlight,d=new Date(b.year,b.month,b.date+a);c.set("highlight",d,{interval:a}),this.render()}},a.on("render",function(){a.$root.find("."+b.klass.selectMonth).on("change",function(){var c=this.value;c&&(a.set("highlight",[a.get("view").year,c,a.get("highlight").date]),a.$root.find("."+b.klass.selectMonth).trigger("focus"))}),a.$root.find("."+b.klass.selectYear).on("change",function(){var c=this.value;c&&(a.set("highlight",[c,a.get("view").month,a.get("highlight").date]),a.$root.find("."+b.klass.selectYear).trigger("focus"))})},1).on("open",function(){var d="";c.disabled(c.get("now"))&&(d=":not(."+b.klass.buttonToday+")"),a.$root.find("button"+d+", select").attr("disabled",!1)},1).on("close",function(){a.$root.find("button, select").attr("disabled",!0)},1)}var d=7,e=6,f=a._;c.prototype.set=function(a,b,c){var d=this,e=d.item;return null===b?("clear"==a&&(a="select"),e[a]=b,d):(e["enable"==a?"disable":"flip"==a?"enable":a]=d.queue[a].split(" ").map(function(e){return b=d[e](a,b,c)}).pop(),"select"==a?d.set("highlight",e.select,c):"highlight"==a?d.set("view",e.highlight,c):a.match(/^(flip|min|max|disable|enable)$/)&&(e.select&&d.disabled(e.select)&&d.set("select",e.select,c),e.highlight&&d.disabled(e.highlight)&&d.set("highlight",e.highlight,c)),d)},c.prototype.get=function(a){return this.item[a]},c.prototype.create=function(a,c,d){var e,g=this;return c=void 0===c?a:c,c==-(1/0)||c==1/0?e=c:b.isPlainObject(c)&&f.isInteger(c.pick)?c=c.obj:b.isArray(c)?(c=new Date(c[0],c[1],c[2]),c=f.isDate(c)?c:g.create().obj):c=f.isInteger(c)||f.isDate(c)?g.normalize(new Date(c),d):g.now(a,c,d),{year:e||c.getFullYear(),month:e||c.getMonth(),date:e||c.getDate(),day:e||c.getDay(),obj:e||c,pick:e||c.getTime()}},c.prototype.createRange=function(a,c){var d=this,e=function(a){return a===!0||b.isArray(a)||f.isDate(a)?d.create(a):a};return f.isInteger(a)||(a=e(a)),f.isInteger(c)||(c=e(c)),f.isInteger(a)&&b.isPlainObject(c)?a=[c.year,c.month,c.date+a]:f.isInteger(c)&&b.isPlainObject(a)&&(c=[a.year,a.month,a.date+c]),{from:e(a),to:e(c)}},c.prototype.withinRange=function(a,b){return a=this.createRange(a.from,a.to),b.pick>=a.from.pick&&b.pick<=a.to.pick},c.prototype.overlapRanges=function(a,b){var c=this;return a=c.createRange(a.from,a.to),b=c.createRange(b.from,b.to),c.withinRange(a,b.from)||c.withinRange(a,b.to)||c.withinRange(b,a.from)||c.withinRange(b,a.to)},c.prototype.now=function(a,b,c){return b=new Date,c&&c.rel&&b.setDate(b.getDate()+c.rel),this.normalize(b,c)},c.prototype.navigate=function(a,c,d){var e,f,g,h,i=b.isArray(c),j=b.isPlainObject(c),k=this.item.view;if(i||j){for(j?(f=c.year,g=c.month,h=c.date):(f=+c[0],g=+c[1],h=+c[2]),d&&d.nav&&k&&k.month!==g&&(f=k.year,g=k.month),e=new Date(f,g+(d&&d.nav?d.nav:0),1),f=e.getFullYear(),g=e.getMonth();new Date(f,g,h).getMonth()!==g;)h-=1;c=[f,g,h]}return c},c.prototype.normalize=function(a){return a.setHours(0,0,0,0),a},c.prototype.measure=function(a,b){var c=this;return b?"string"==typeof b?b=c.parse(a,b):f.isInteger(b)&&(b=c.now(a,b,{rel:b})):b="min"==a?-(1/0):1/0,b},c.prototype.viewset=function(a,b){return this.create([b.year,b.month,1])},c.prototype.validate=function(a,c,d){var e,g,h,i,j=this,k=c,l=d&&d.interval?d.interval:1,m=-1===j.item.enable,n=j.item.min,o=j.item.max,p=m&&j.item.disable.filter(function(a){if(b.isArray(a)){var d=j.create(a).pick;d<c.pick?e=!0:d>c.pick&&(g=!0)}return f.isInteger(a)}).length;if((!d||!d.nav)&&(!m&&j.disabled(c)||m&&j.disabled(c)&&(p||e||g)||!m&&(c.pick<=n.pick||c.pick>=o.pick)))for(m&&!p&&(!g&&l>0||!e&&0>l)&&(l*=-1);j.disabled(c)&&(Math.abs(l)>1&&(c.month<k.month||c.month>k.month)&&(c=k,l=l>0?1:-1),c.pick<=n.pick?(h=!0,l=1,c=j.create([n.year,n.month,n.date+(c.pick===n.pick?0:-1)])):c.pick>=o.pick&&(i=!0,l=-1,c=j.create([o.year,o.month,o.date+(c.pick===o.pick?0:1)])),!h||!i);)c=j.create([c.year,c.month,c.date+l]);return c},c.prototype.disabled=function(a){var c=this,d=c.item.disable.filter(function(d){return f.isInteger(d)?a.day===(c.settings.firstDay?d:d-1)%7:b.isArray(d)||f.isDate(d)?a.pick===c.create(d).pick:b.isPlainObject(d)?c.withinRange(d,a):void 0});return d=d.length&&!d.filter(function(a){return b.isArray(a)&&"inverted"==a[3]||b.isPlainObject(a)&&a.inverted}).length,-1===c.item.enable?!d:d||a.pick<c.item.min.pick||a.pick>c.item.max.pick},c.prototype.parse=function(a,b,c){var d=this,e={};return b&&"string"==typeof b?(c&&c.format||(c=c||{},c.format=d.settings.format),d.formats.toArray(c.format).map(function(a){var c=d.formats[a],g=c?f.trigger(c,d,[b,e]):a.replace(/^!/,"").length;c&&(e[a]=b.substr(0,g)),b=b.substr(g)}),[e.yyyy||e.yy,+(e.mm||e.m)-1,e.dd||e.d]):b},c.prototype.formats=function(){function a(a,b,c){var d=a.match(/\w+/)[0];return c.mm||c.m||(c.m=b.indexOf(d)+1),d.length}function b(a){return a.match(/\w+/)[0].length}return{d:function(a,b){return a?f.digits(a):b.date},dd:function(a,b){return a?2:f.lead(b.date)},ddd:function(a,c){return a?b(a):this.settings.weekdaysShort[c.day]},dddd:function(a,c){return a?b(a):this.settings.weekdaysFull[c.day]},m:function(a,b){return a?f.digits(a):b.month+1},mm:function(a,b){return a?2:f.lead(b.month+1)},mmm:function(b,c){var d=this.settings.monthsShort;return b?a(b,d,c):d[c.month]},mmmm:function(b,c){var d=this.settings.monthsFull;return b?a(b,d,c):d[c.month]},yy:function(a,b){return a?2:(""+b.year).slice(2)},yyyy:function(a,b){return a?4:b.year},toArray:function(a){return a.split(/(d{1,4}|m{1,4}|y{4}|yy|!.)/g)},toString:function(a,b){var c=this;return c.formats.toArray(a).map(function(a){return f.trigger(c.formats[a],c,[0,b])||a.replace(/^!/,"")}).join("")}}}(),c.prototype.isDateExact=function(a,c){var d=this;return f.isInteger(a)&&f.isInteger(c)||"boolean"==typeof a&&"boolean"==typeof c?a===c:(f.isDate(a)||b.isArray(a))&&(f.isDate(c)||b.isArray(c))?d.create(a).pick===d.create(c).pick:b.isPlainObject(a)&&b.isPlainObject(c)?d.isDateExact(a.from,c.from)&&d.isDateExact(a.to,c.to):!1},c.prototype.isDateOverlap=function(a,c){var d=this,e=d.settings.firstDay?1:0;return f.isInteger(a)&&(f.isDate(c)||b.isArray(c))?(a=a%7+e,a===d.create(c).day+1):f.isInteger(c)&&(f.isDate(a)||b.isArray(a))?(c=c%7+e,c===d.create(a).day+1):b.isPlainObject(a)&&b.isPlainObject(c)?d.overlapRanges(a,c):!1},c.prototype.flipEnable=function(a){var b=this.item;b.enable=a||(-1==b.enable?1:-1)},c.prototype.deactivate=function(a,c){var d=this,e=d.item.disable.slice(0);return"flip"==c?d.flipEnable():c===!1?(d.flipEnable(1),e=[]):c===!0?(d.flipEnable(-1),e=[]):c.map(function(a){for(var c,g=0;g<e.length;g+=1)if(d.isDateExact(a,e[g])){c=!0;break}c||(f.isInteger(a)||f.isDate(a)||b.isArray(a)||b.isPlainObject(a)&&a.from&&a.to)&&e.push(a)}),e},c.prototype.activate=function(a,c){var d=this,e=d.item.disable,g=e.length;return"flip"==c?d.flipEnable():c===!0?(d.flipEnable(1),e=[]):c===!1?(d.flipEnable(-1),e=[]):c.map(function(a){var c,h,i,j;for(i=0;g>i;i+=1){if(h=e[i],d.isDateExact(h,a)){c=e[i]=null,j=!0;break}if(d.isDateOverlap(h,a)){b.isPlainObject(a)?(a.inverted=!0,c=a):b.isArray(a)?(c=a,c[3]||c.push("inverted")):f.isDate(a)&&(c=[a.getFullYear(),a.getMonth(),a.getDate(),"inverted"]);break}}if(c)for(i=0;g>i;i+=1)if(d.isDateExact(e[i],a)){e[i]=null;break}if(j)for(i=0;g>i;i+=1)if(d.isDateOverlap(e[i],a)){e[i]=null;break}c&&e.push(c)}),e.filter(function(a){return null!=a})},c.prototype.nodes=function(a){var b=this,c=b.settings,g=b.item,h=g.now,i=g.select,j=g.highlight,k=g.view,l=g.disable,m=g.min,n=g.max,o=function(a,b){return c.firstDay&&(a.push(a.shift()),b.push(b.shift())),f.node("thead",f.node("tr",f.group({min:0,max:d-1,i:1,node:"th",item:function(d){return[a[d],c.klass.weekdays,'scope=col title="'+b[d]+'"']}})))}((c.showWeekdaysFull?c.weekdaysFull:c.weekdaysLetter).slice(0),c.weekdaysFull.slice(0)),p=function(a){return f.node("div"," ",c.klass["nav"+(a?"Next":"Prev")]+(a&&k.year>=n.year&&k.month>=n.month||!a&&k.year<=m.year&&k.month<=m.month?" "+c.klass.navDisabled:""),"data-nav="+(a||-1)+" "+f.ariaAttr({role:"button",controls:b.$node[0].id+"_table"})+' title="'+(a?c.labelMonthNext:c.labelMonthPrev)+'"')},q=function(d){var e=c.showMonthsShort?c.monthsShort:c.monthsFull;return"short_months"==d&&(e=c.monthsShort),c.selectMonths&&void 0==d?f.node("select",f.group({min:0,max:11,i:1,node:"option",item:function(a){return[e[a],0,"value="+a+(k.month==a?" selected":"")+(k.year==m.year&&a<m.month||k.year==n.year&&a>n.month?" disabled":"")]}}),c.klass.selectMonth+" browser-default",(a?"":"disabled")+" "+f.ariaAttr({controls:b.$node[0].id+"_table"
-})+' title="'+c.labelMonthSelect+'"'):"short_months"==d?null!=i?f.node("div",e[i.month]):f.node("div",e[k.month]):f.node("div",e[k.month],c.klass.month)},r=function(d){var e=k.year,g=c.selectYears===!0?5:~~(c.selectYears/2);if(g){var h=m.year,i=n.year,j=e-g,l=e+g;if(h>j&&(l+=h-j,j=h),l>i){var o=j-h,p=l-i;j-=o>p?p:o,l=i}if(c.selectYears&&void 0==d)return f.node("select",f.group({min:j,max:l,i:1,node:"option",item:function(a){return[a,0,"value="+a+(e==a?" selected":"")]}}),c.klass.selectYear+" browser-default",(a?"":"disabled")+" "+f.ariaAttr({controls:b.$node[0].id+"_table"})+' title="'+c.labelYearSelect+'"')}return"raw"==d?f.node("div",e):f.node("div",e,c.klass.year)};return createDayLabel=function(){return null!=i?f.node("div",i.date):f.node("div",h.date)},createWeekdayLabel=function(){var a;a=null!=i?i.day:h.day;var b=c.weekdaysFull[a];return b},f.node("div",f.node("div",createWeekdayLabel(),"picker__weekday-display")+f.node("div",q("short_months"),c.klass.month_display)+f.node("div",createDayLabel(),c.klass.day_display)+f.node("div",r("raw"),c.klass.year_display),c.klass.date_display)+f.node("div",f.node("div",(c.selectYears?q()+r():q()+r())+p()+p(1),c.klass.header)+f.node("table",o+f.node("tbody",f.group({min:0,max:e-1,i:1,node:"tr",item:function(a){var e=c.firstDay&&0===b.create([k.year,k.month,1]).day?-7:0;return[f.group({min:d*a-k.day+e+1,max:function(){return this.min+d-1},i:1,node:"td",item:function(a){a=b.create([k.year,k.month,a+(c.firstDay?1:0)]);var d=i&&i.pick==a.pick,e=j&&j.pick==a.pick,g=l&&b.disabled(a)||a.pick<m.pick||a.pick>n.pick,o=f.trigger(b.formats.toString,b,[c.format,a]);return[f.node("div",a.date,function(b){return b.push(k.month==a.month?c.klass.infocus:c.klass.outfocus),h.pick==a.pick&&b.push(c.klass.now),d&&b.push(c.klass.selected),e&&b.push(c.klass.highlighted),g&&b.push(c.klass.disabled),b.join(" ")}([c.klass.day]),"data-pick="+a.pick+" "+f.ariaAttr({role:"gridcell",label:o,selected:d&&b.$node.val()===o?!0:null,activedescendant:e?!0:null,disabled:g?!0:null})),"",f.ariaAttr({role:"presentation"})]}})]}})),c.klass.table,'id="'+b.$node[0].id+'_table" '+f.ariaAttr({role:"grid",controls:b.$node[0].id,readonly:!0})),c.klass.calendar_container)+f.node("div",f.node("button",c.today,"btn-flat picker__today","type=button data-pick="+h.pick+(a&&!b.disabled(h)?"":" disabled")+" "+f.ariaAttr({controls:b.$node[0].id}))+f.node("button",c.clear,"btn-flat picker__clear","type=button data-clear=1"+(a?"":" disabled")+" "+f.ariaAttr({controls:b.$node[0].id}))+f.node("button",c.close,"btn-flat picker__close","type=button data-close=true "+(a?"":" disabled")+" "+f.ariaAttr({controls:b.$node[0].id})),c.klass.footer)},c.defaults=function(a){return{labelMonthNext:"Next month",labelMonthPrev:"Previous month",labelMonthSelect:"Select a month",labelYearSelect:"Select a year",monthsFull:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],weekdaysFull:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],weekdaysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],weekdaysLetter:["S","M","T","W","T","F","S"],today:"Today",clear:"Clear",close:"Close",format:"d mmmm, yyyy",klass:{table:a+"table",header:a+"header",date_display:a+"date-display",day_display:a+"day-display",month_display:a+"month-display",year_display:a+"year-display",calendar_container:a+"calendar-container",navPrev:a+"nav--prev",navNext:a+"nav--next",navDisabled:a+"nav--disabled",month:a+"month",year:a+"year",selectMonth:a+"select--month",selectYear:a+"select--year",weekdays:a+"weekday",day:a+"day",disabled:a+"day--disabled",selected:a+"day--selected",highlighted:a+"day--highlighted",now:a+"day--today",infocus:a+"day--infocus",outfocus:a+"day--outfocus",footer:a+"footer",buttonClear:a+"button--clear",buttonToday:a+"button--today",buttonClose:a+"button--close"}}}(a.klasses().picker+"__"),a.extend("pickadate",c)}),function(a){function b(){var b=+a(this).attr("length"),c=+a(this).val().length,d=b>=c;a(this).parent().find('span[class="character-counter"]').html(c+"/"+b),e(d,a(this))}function c(b){var c=b.parent().find('span[class="character-counter"]');c.length||(c=a("<span/>").addClass("character-counter").css("float","right").css("font-size","12px").css("height",1),b.parent().append(c))}function d(){a(this).parent().find('span[class="character-counter"]').html("")}function e(a,b){var c=b.hasClass("invalid");a&&c?b.removeClass("invalid"):a||c||(b.removeClass("valid"),b.addClass("invalid"))}a.fn.characterCounter=function(){return this.each(function(){var e=a(this),f=e.parent().find('span[class="character-counter"]');if(!f.length){var g=void 0!==e.attr("length");g&&(e.on("input",b),e.on("focus",b),e.on("blur",d),c(e))}})},a(document).ready(function(){a("input, textarea").characterCounter()})}(jQuery),function(a){var b={init:function(b){var c={time_constant:200,dist:-100,shift:0,padding:0,full_width:!1,indicators:!1,no_wrap:!1};return b=a.extend(c,b),this.each(function(){function c(){"undefined"!=typeof window.ontouchstart&&(H[0].addEventListener("touchstart",l),H[0].addEventListener("touchmove",m),H[0].addEventListener("touchend",n)),H[0].addEventListener("mousedown",l),H[0].addEventListener("mousemove",m),H[0].addEventListener("mouseup",n),H[0].addEventListener("mouseleave",n),H[0].addEventListener("click",j)}function d(a){return a.targetTouches&&a.targetTouches.length>=1?a.targetTouches[0].clientX:a.clientX}function e(a){return a.targetTouches&&a.targetTouches.length>=1?a.targetTouches[0].clientY:a.clientY}function f(a){return a>=t?a%t:0>a?f(t+a%t):a}function g(a){var c,d,e,g,h,i,j;if(p="number"==typeof a?a:p,q=Math.floor((p+s/2)/s),e=p-q*s,g=0>e?1:-1,h=-g*e*2/s,d=t>>1,b.full_width?j="translateX(0)":(j="translateX("+(H[0].clientWidth-item_width)/2+"px) ",j+="translateY("+(H[0].clientHeight-item_width)/2+"px)"),I){var k=q%t,l=G.find(".indicator-item.active");l.index()!==k&&(l.removeClass("active"),G.find(".indicator-item").eq(k).addClass("active"))}for((!b.no_wrap||q>=0&&t>q)&&(i=o[f(q)],i.style[A]=j+" translateX("+-e/2+"px) translateX("+g*b.shift*h*c+"px) translateZ("+b.dist*h+"px)",i.style.zIndex=0,b.full_width?tweenedOpacity=1:tweenedOpacity=1-.2*h,i.style.opacity=tweenedOpacity,i.style.display="block"),c=1;d>=c;++c)b.full_width?(zTranslation=b.dist,tweenedOpacity=c===d&&0>e?1-h:1):(zTranslation=b.dist*(2*c+h*g),tweenedOpacity=1-.2*(2*c+h*g)),(!b.no_wrap||t>q+c)&&(i=o[f(q+c)],i.style[A]=j+" translateX("+(b.shift+(s*c-e)/2)+"px) translateZ("+zTranslation+"px)",i.style.zIndex=-c,i.style.opacity=tweenedOpacity,i.style.display="block"),b.full_width?(zTranslation=b.dist,tweenedOpacity=c===d&&e>0?1-h:1):(zTranslation=b.dist*(2*c-h*g),tweenedOpacity=1-.2*(2*c-h*g)),(!b.no_wrap||q-c>=0)&&(i=o[f(q-c)],i.style[A]=j+" translateX("+(-b.shift+(-s*c-e)/2)+"px) translateZ("+zTranslation+"px)",i.style.zIndex=-c,i.style.opacity=tweenedOpacity,i.style.display="block");(!b.no_wrap||q>=0&&t>q)&&(i=o[f(q)],i.style[A]=j+" translateX("+-e/2+"px) translateX("+g*b.shift*h+"px) translateZ("+b.dist*h+"px)",i.style.zIndex=0,b.full_width?tweenedOpacity=1:tweenedOpacity=1-.2*h,i.style.opacity=tweenedOpacity,i.style.display="block")}function h(){var a,b,c,d;a=Date.now(),b=a-C,C=a,c=p-B,B=p,d=1e3*c/(1+b),z=.8*d+.2*z}function i(){var a,c;w&&(a=Date.now()-C,c=w*Math.exp(-a/b.time_constant),c>2||-2>c?(g(x-c),requestAnimationFrame(i)):g(x))}function j(c){if(E)return c.preventDefault(),c.stopPropagation(),!1;if(!b.full_width){var d=a(c.target).closest(".carousel-item").index(),e=q%t-d;0!==e&&(c.preventDefault(),c.stopPropagation()),k(d)}}function k(a){var c=q%t-a;b.no_wrap||(0>c?Math.abs(c+t)<Math.abs(c)&&(c+=t):c>0&&Math.abs(c-t)<c&&(c-=t)),0>c?H.trigger("carouselNext",[Math.abs(c)]):c>0&&H.trigger("carouselPrev",[c])}function l(a){r=!0,E=!1,F=!1,u=d(a),v=e(a),z=w=0,B=p,C=Date.now(),clearInterval(D),D=setInterval(h,100)}function m(a){var b,c,f;if(r)if(b=d(a),y=e(a),c=u-b,f=Math.abs(v-y),30>f&&!F)(c>2||-2>c)&&(E=!0,u=b,g(p+c));else{if(E)return a.preventDefault(),a.stopPropagation(),!1;F=!0}return E?(a.preventDefault(),a.stopPropagation(),!1):void 0}function n(a){return r?(r=!1,clearInterval(D),x=p,(z>10||-10>z)&&(w=.9*z,x=p+w),x=Math.round(x/s)*s,b.no_wrap&&(x>=s*(t-1)?x=s*(t-1):0>x&&(x=0)),w=x-p,C=Date.now(),requestAnimationFrame(i),E&&(a.preventDefault(),a.stopPropagation()),!1):void 0}var o,p,q,r,s,t,u,v,w,x,z,A,B,C,D,E,F,G=a('<ul class="indicators"></ul>'),H=a(this),I=H.attr("data-indicators")||b.indicators;if(H.hasClass("initialized"))return a(this).trigger("carouselNext",[1e-6]),!0;if(b.full_width){b.dist=0;var J=H.find(".carousel-item img").first();J.length?imageHeight=J.load(function(){H.css("height",a(this).height())}):(imageHeight=H.find(".carousel-item").first().height(),H.css("height",imageHeight)),I&&H.find(".carousel-fixed-item").addClass("with-indicators")}H.addClass("initialized"),r=!1,p=x=0,o=[],item_width=H.find(".carousel-item").first().innerWidth(),s=2*item_width+b.padding,H.find(".carousel-item").each(function(b){if(o.push(a(this)[0]),I){var c=a('<li class="indicator-item"></li>');0===b&&c.addClass("active"),c.click(function(){var b=a(this).index();k(b)}),G.append(c)}}),I&&H.append(G),t=o.length,A="transform",["webkit","Moz","O","ms"].every(function(a){var b=a+"Transform";return"undefined"!=typeof document.body.style[b]?(A=b,!1):!0}),window.onresize=g,c(),g(p),a(this).on("carouselNext",function(a,b){void 0===b&&(b=1),x=p+s*b,p!==x&&(w=x-p,C=Date.now(),requestAnimationFrame(i))}),a(this).on("carouselPrev",function(a,b){void 0===b&&(b=1),x=p-s*b,p!==x&&(w=x-p,C=Date.now(),requestAnimationFrame(i))}),a(this).on("carouselSet",function(a,b){void 0===b&&(b=0),k(b)})})},next:function(b){a(this).trigger("carouselNext",[b])},prev:function(b){a(this).trigger("carouselPrev",[b])},set:function(b){a(this).trigger("carouselSet",[b])}};a.fn.carousel=function(c){return b[c]?b[c].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof c&&c?void a.error("Method "+c+" does not exist on jQuery.carousel"):b.init.apply(this,arguments)}}(jQuery); \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/css/materialNote.css b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/css/materialNote.css
deleted file mode 100644
index 6cbe90e..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/css/materialNote.css
+++ /dev/null
@@ -1,2160 +0,0 @@
-.materialize-red.lighten-5 {
- background-color: #fdeaeb !important; }
-
-.materialize-red-text.text-lighten-5 {
- color: #fdeaeb !important; }
-
-.materialize-red.lighten-4 {
- background-color: #f8c1c3 !important; }
-
-.materialize-red-text.text-lighten-4 {
- color: #f8c1c3 !important; }
-
-.materialize-red.lighten-3 {
- background-color: #f3989b !important; }
-
-.materialize-red-text.text-lighten-3 {
- color: #f3989b !important; }
-
-.materialize-red.lighten-2 {
- background-color: #ee6e73 !important; }
-
-.materialize-red-text.text-lighten-2 {
- color: #ee6e73 !important; }
-
-.materialize-red.lighten-1 {
- background-color: #ea454b !important; }
-
-.materialize-red-text.text-lighten-1 {
- color: #ea454b !important; }
-
-.materialize-red {
- background-color: #e51c23 !important; }
-
-.materialize-red-text {
- color: #e51c23 !important; }
-
-.materialize-red.darken-1 {
- background-color: #d0181e !important; }
-
-.materialize-red-text.text-darken-1 {
- color: #d0181e !important; }
-
-.materialize-red.darken-2 {
- background-color: #b9151b !important; }
-
-.materialize-red-text.text-darken-2 {
- color: #b9151b !important; }
-
-.materialize-red.darken-3 {
- background-color: #a21318 !important; }
-
-.materialize-red-text.text-darken-3 {
- color: #a21318 !important; }
-
-.materialize-red.darken-4 {
- background-color: #8b1014 !important; }
-
-.materialize-red-text.text-darken-4 {
- color: #8b1014 !important; }
-
-.red.lighten-5 {
- background-color: #FFEBEE !important; }
-
-.red-text.text-lighten-5 {
- color: #FFEBEE !important; }
-
-.red.lighten-4 {
- background-color: #FFCDD2 !important; }
-
-.red-text.text-lighten-4 {
- color: #FFCDD2 !important; }
-
-.red.lighten-3 {
- background-color: #EF9A9A !important; }
-
-.red-text.text-lighten-3 {
- color: #EF9A9A !important; }
-
-.red.lighten-2 {
- background-color: #E57373 !important; }
-
-.red-text.text-lighten-2 {
- color: #E57373 !important; }
-
-.red.lighten-1 {
- background-color: #EF5350 !important; }
-
-.red-text.text-lighten-1 {
- color: #EF5350 !important; }
-
-.red {
- background-color: #F44336 !important; }
-
-.red-text {
- color: #F44336 !important; }
-
-.red.darken-1 {
- background-color: #E53935 !important; }
-
-.red-text.text-darken-1 {
- color: #E53935 !important; }
-
-.red.darken-2 {
- background-color: #D32F2F !important; }
-
-.red-text.text-darken-2 {
- color: #D32F2F !important; }
-
-.red.darken-3 {
- background-color: #C62828 !important; }
-
-.red-text.text-darken-3 {
- color: #C62828 !important; }
-
-.red.darken-4 {
- background-color: #B71C1C !important; }
-
-.red-text.text-darken-4 {
- color: #B71C1C !important; }
-
-.red.accent-1 {
- background-color: #FF8A80 !important; }
-
-.red-text.text-accent-1 {
- color: #FF8A80 !important; }
-
-.red.accent-2 {
- background-color: #FF5252 !important; }
-
-.red-text.text-accent-2 {
- color: #FF5252 !important; }
-
-.red.accent-3 {
- background-color: #FF1744 !important; }
-
-.red-text.text-accent-3 {
- color: #FF1744 !important; }
-
-.red.accent-4 {
- background-color: #D50000 !important; }
-
-.red-text.text-accent-4 {
- color: #D50000 !important; }
-
-.pink.lighten-5 {
- background-color: #fce4ec !important; }
-
-.pink-text.text-lighten-5 {
- color: #fce4ec !important; }
-
-.pink.lighten-4 {
- background-color: #f8bbd0 !important; }
-
-.pink-text.text-lighten-4 {
- color: #f8bbd0 !important; }
-
-.pink.lighten-3 {
- background-color: #f48fb1 !important; }
-
-.pink-text.text-lighten-3 {
- color: #f48fb1 !important; }
-
-.pink.lighten-2 {
- background-color: #f06292 !important; }
-
-.pink-text.text-lighten-2 {
- color: #f06292 !important; }
-
-.pink.lighten-1 {
- background-color: #ec407a !important; }
-
-.pink-text.text-lighten-1 {
- color: #ec407a !important; }
-
-.pink {
- background-color: #e91e63 !important; }
-
-.pink-text {
- color: #e91e63 !important; }
-
-.pink.darken-1 {
- background-color: #d81b60 !important; }
-
-.pink-text.text-darken-1 {
- color: #d81b60 !important; }
-
-.pink.darken-2 {
- background-color: #c2185b !important; }
-
-.pink-text.text-darken-2 {
- color: #c2185b !important; }
-
-.pink.darken-3 {
- background-color: #ad1457 !important; }
-
-.pink-text.text-darken-3 {
- color: #ad1457 !important; }
-
-.pink.darken-4 {
- background-color: #880e4f !important; }
-
-.pink-text.text-darken-4 {
- color: #880e4f !important; }
-
-.pink.accent-1 {
- background-color: #ff80ab !important; }
-
-.pink-text.text-accent-1 {
- color: #ff80ab !important; }
-
-.pink.accent-2 {
- background-color: #ff4081 !important; }
-
-.pink-text.text-accent-2 {
- color: #ff4081 !important; }
-
-.pink.accent-3 {
- background-color: #f50057 !important; }
-
-.pink-text.text-accent-3 {
- color: #f50057 !important; }
-
-.pink.accent-4 {
- background-color: #c51162 !important; }
-
-.pink-text.text-accent-4 {
- color: #c51162 !important; }
-
-.purple.lighten-5 {
- background-color: #f3e5f5 !important; }
-
-.purple-text.text-lighten-5 {
- color: #f3e5f5 !important; }
-
-.purple.lighten-4 {
- background-color: #e1bee7 !important; }
-
-.purple-text.text-lighten-4 {
- color: #e1bee7 !important; }
-
-.purple.lighten-3 {
- background-color: #ce93d8 !important; }
-
-.purple-text.text-lighten-3 {
- color: #ce93d8 !important; }
-
-.purple.lighten-2 {
- background-color: #ba68c8 !important; }
-
-.purple-text.text-lighten-2 {
- color: #ba68c8 !important; }
-
-.purple.lighten-1 {
- background-color: #ab47bc !important; }
-
-.purple-text.text-lighten-1 {
- color: #ab47bc !important; }
-
-.purple {
- background-color: #9c27b0 !important; }
-
-.purple-text {
- color: #9c27b0 !important; }
-
-.purple.darken-1 {
- background-color: #8e24aa !important; }
-
-.purple-text.text-darken-1 {
- color: #8e24aa !important; }
-
-.purple.darken-2 {
- background-color: #7b1fa2 !important; }
-
-.purple-text.text-darken-2 {
- color: #7b1fa2 !important; }
-
-.purple.darken-3 {
- background-color: #6a1b9a !important; }
-
-.purple-text.text-darken-3 {
- color: #6a1b9a !important; }
-
-.purple.darken-4 {
- background-color: #4a148c !important; }
-
-.purple-text.text-darken-4 {
- color: #4a148c !important; }
-
-.purple.accent-1 {
- background-color: #ea80fc !important; }
-
-.purple-text.text-accent-1 {
- color: #ea80fc !important; }
-
-.purple.accent-2 {
- background-color: #e040fb !important; }
-
-.purple-text.text-accent-2 {
- color: #e040fb !important; }
-
-.purple.accent-3 {
- background-color: #d500f9 !important; }
-
-.purple-text.text-accent-3 {
- color: #d500f9 !important; }
-
-.purple.accent-4 {
- background-color: #aa00ff !important; }
-
-.purple-text.text-accent-4 {
- color: #aa00ff !important; }
-
-.deep-purple.lighten-5 {
- background-color: #ede7f6 !important; }
-
-.deep-purple-text.text-lighten-5 {
- color: #ede7f6 !important; }
-
-.deep-purple.lighten-4 {
- background-color: #d1c4e9 !important; }
-
-.deep-purple-text.text-lighten-4 {
- color: #d1c4e9 !important; }
-
-.deep-purple.lighten-3 {
- background-color: #b39ddb !important; }
-
-.deep-purple-text.text-lighten-3 {
- color: #b39ddb !important; }
-
-.deep-purple.lighten-2 {
- background-color: #9575cd !important; }
-
-.deep-purple-text.text-lighten-2 {
- color: #9575cd !important; }
-
-.deep-purple.lighten-1 {
- background-color: #7e57c2 !important; }
-
-.deep-purple-text.text-lighten-1 {
- color: #7e57c2 !important; }
-
-.deep-purple {
- background-color: #673ab7 !important; }
-
-.deep-purple-text {
- color: #673ab7 !important; }
-
-.deep-purple.darken-1 {
- background-color: #5e35b1 !important; }
-
-.deep-purple-text.text-darken-1 {
- color: #5e35b1 !important; }
-
-.deep-purple.darken-2 {
- background-color: #512da8 !important; }
-
-.deep-purple-text.text-darken-2 {
- color: #512da8 !important; }
-
-.deep-purple.darken-3 {
- background-color: #4527a0 !important; }
-
-.deep-purple-text.text-darken-3 {
- color: #4527a0 !important; }
-
-.deep-purple.darken-4 {
- background-color: #311b92 !important; }
-
-.deep-purple-text.text-darken-4 {
- color: #311b92 !important; }
-
-.deep-purple.accent-1 {
- background-color: #b388ff !important; }
-
-.deep-purple-text.text-accent-1 {
- color: #b388ff !important; }
-
-.deep-purple.accent-2 {
- background-color: #7c4dff !important; }
-
-.deep-purple-text.text-accent-2 {
- color: #7c4dff !important; }
-
-.deep-purple.accent-3 {
- background-color: #651fff !important; }
-
-.deep-purple-text.text-accent-3 {
- color: #651fff !important; }
-
-.deep-purple.accent-4 {
- background-color: #6200ea !important; }
-
-.deep-purple-text.text-accent-4 {
- color: #6200ea !important; }
-
-.indigo.lighten-5 {
- background-color: #e8eaf6 !important; }
-
-.indigo-text.text-lighten-5 {
- color: #e8eaf6 !important; }
-
-.indigo.lighten-4 {
- background-color: #c5cae9 !important; }
-
-.indigo-text.text-lighten-4 {
- color: #c5cae9 !important; }
-
-.indigo.lighten-3 {
- background-color: #9fa8da !important; }
-
-.indigo-text.text-lighten-3 {
- color: #9fa8da !important; }
-
-.indigo.lighten-2 {
- background-color: #7986cb !important; }
-
-.indigo-text.text-lighten-2 {
- color: #7986cb !important; }
-
-.indigo.lighten-1 {
- background-color: #5c6bc0 !important; }
-
-.indigo-text.text-lighten-1 {
- color: #5c6bc0 !important; }
-
-.indigo {
- background-color: #3f51b5 !important; }
-
-.indigo-text {
- color: #3f51b5 !important; }
-
-.indigo.darken-1 {
- background-color: #3949ab !important; }
-
-.indigo-text.text-darken-1 {
- color: #3949ab !important; }
-
-.indigo.darken-2 {
- background-color: #303f9f !important; }
-
-.indigo-text.text-darken-2 {
- color: #303f9f !important; }
-
-.indigo.darken-3 {
- background-color: #283593 !important; }
-
-.indigo-text.text-darken-3 {
- color: #283593 !important; }
-
-.indigo.darken-4 {
- background-color: #1a237e !important; }
-
-.indigo-text.text-darken-4 {
- color: #1a237e !important; }
-
-.indigo.accent-1 {
- background-color: #8c9eff !important; }
-
-.indigo-text.text-accent-1 {
- color: #8c9eff !important; }
-
-.indigo.accent-2 {
- background-color: #536dfe !important; }
-
-.indigo-text.text-accent-2 {
- color: #536dfe !important; }
-
-.indigo.accent-3 {
- background-color: #3d5afe !important; }
-
-.indigo-text.text-accent-3 {
- color: #3d5afe !important; }
-
-.indigo.accent-4 {
- background-color: #304ffe !important; }
-
-.indigo-text.text-accent-4 {
- color: #304ffe !important; }
-
-.blue.lighten-5 {
- background-color: #E3F2FD !important; }
-
-.blue-text.text-lighten-5 {
- color: #E3F2FD !important; }
-
-.blue.lighten-4 {
- background-color: #BBDEFB !important; }
-
-.blue-text.text-lighten-4 {
- color: #BBDEFB !important; }
-
-.blue.lighten-3 {
- background-color: #90CAF9 !important; }
-
-.blue-text.text-lighten-3 {
- color: #90CAF9 !important; }
-
-.blue.lighten-2 {
- background-color: #64B5F6 !important; }
-
-.blue-text.text-lighten-2 {
- color: #64B5F6 !important; }
-
-.blue.lighten-1 {
- background-color: #42A5F5 !important; }
-
-.blue-text.text-lighten-1 {
- color: #42A5F5 !important; }
-
-.blue {
- background-color: #2196F3 !important; }
-
-.blue-text {
- color: #2196F3 !important; }
-
-.blue.darken-1 {
- background-color: #1E88E5 !important; }
-
-.blue-text.text-darken-1 {
- color: #1E88E5 !important; }
-
-.blue.darken-2 {
- background-color: #1976D2 !important; }
-
-.blue-text.text-darken-2 {
- color: #1976D2 !important; }
-
-.blue.darken-3 {
- background-color: #1565C0 !important; }
-
-.blue-text.text-darken-3 {
- color: #1565C0 !important; }
-
-.blue.darken-4 {
- background-color: #0D47A1 !important; }
-
-.blue-text.text-darken-4 {
- color: #0D47A1 !important; }
-
-.blue.accent-1 {
- background-color: #82B1FF !important; }
-
-.blue-text.text-accent-1 {
- color: #82B1FF !important; }
-
-.blue.accent-2 {
- background-color: #448AFF !important; }
-
-.blue-text.text-accent-2 {
- color: #448AFF !important; }
-
-.blue.accent-3 {
- background-color: #2979FF !important; }
-
-.blue-text.text-accent-3 {
- color: #2979FF !important; }
-
-.blue.accent-4 {
- background-color: #2962FF !important; }
-
-.blue-text.text-accent-4 {
- color: #2962FF !important; }
-
-.light-blue.lighten-5 {
- background-color: #e1f5fe !important; }
-
-.light-blue-text.text-lighten-5 {
- color: #e1f5fe !important; }
-
-.light-blue.lighten-4 {
- background-color: #b3e5fc !important; }
-
-.light-blue-text.text-lighten-4 {
- color: #b3e5fc !important; }
-
-.light-blue.lighten-3 {
- background-color: #81d4fa !important; }
-
-.light-blue-text.text-lighten-3 {
- color: #81d4fa !important; }
-
-.light-blue.lighten-2 {
- background-color: #4fc3f7 !important; }
-
-.light-blue-text.text-lighten-2 {
- color: #4fc3f7 !important; }
-
-.light-blue.lighten-1 {
- background-color: #29b6f6 !important; }
-
-.light-blue-text.text-lighten-1 {
- color: #29b6f6 !important; }
-
-.light-blue {
- background-color: #03a9f4 !important; }
-
-.light-blue-text {
- color: #03a9f4 !important; }
-
-.light-blue.darken-1 {
- background-color: #039be5 !important; }
-
-.light-blue-text.text-darken-1 {
- color: #039be5 !important; }
-
-.light-blue.darken-2 {
- background-color: #0288d1 !important; }
-
-.light-blue-text.text-darken-2 {
- color: #0288d1 !important; }
-
-.light-blue.darken-3 {
- background-color: #0277bd !important; }
-
-.light-blue-text.text-darken-3 {
- color: #0277bd !important; }
-
-.light-blue.darken-4 {
- background-color: #01579b !important; }
-
-.light-blue-text.text-darken-4 {
- color: #01579b !important; }
-
-.light-blue.accent-1 {
- background-color: #80d8ff !important; }
-
-.light-blue-text.text-accent-1 {
- color: #80d8ff !important; }
-
-.light-blue.accent-2 {
- background-color: #40c4ff !important; }
-
-.light-blue-text.text-accent-2 {
- color: #40c4ff !important; }
-
-.light-blue.accent-3 {
- background-color: #00b0ff !important; }
-
-.light-blue-text.text-accent-3 {
- color: #00b0ff !important; }
-
-.light-blue.accent-4 {
- background-color: #0091ea !important; }
-
-.light-blue-text.text-accent-4 {
- color: #0091ea !important; }
-
-.cyan.lighten-5 {
- background-color: #e0f7fa !important; }
-
-.cyan-text.text-lighten-5 {
- color: #e0f7fa !important; }
-
-.cyan.lighten-4 {
- background-color: #b2ebf2 !important; }
-
-.cyan-text.text-lighten-4 {
- color: #b2ebf2 !important; }
-
-.cyan.lighten-3 {
- background-color: #80deea !important; }
-
-.cyan-text.text-lighten-3 {
- color: #80deea !important; }
-
-.cyan.lighten-2 {
- background-color: #4dd0e1 !important; }
-
-.cyan-text.text-lighten-2 {
- color: #4dd0e1 !important; }
-
-.cyan.lighten-1 {
- background-color: #26c6da !important; }
-
-.cyan-text.text-lighten-1 {
- color: #26c6da !important; }
-
-.cyan {
- background-color: #00bcd4 !important; }
-
-.cyan-text {
- color: #00bcd4 !important; }
-
-.cyan.darken-1 {
- background-color: #00acc1 !important; }
-
-.cyan-text.text-darken-1 {
- color: #00acc1 !important; }
-
-.cyan.darken-2 {
- background-color: #0097a7 !important; }
-
-.cyan-text.text-darken-2 {
- color: #0097a7 !important; }
-
-.cyan.darken-3 {
- background-color: #00838f !important; }
-
-.cyan-text.text-darken-3 {
- color: #00838f !important; }
-
-.cyan.darken-4 {
- background-color: #006064 !important; }
-
-.cyan-text.text-darken-4 {
- color: #006064 !important; }
-
-.cyan.accent-1 {
- background-color: #84ffff !important; }
-
-.cyan-text.text-accent-1 {
- color: #84ffff !important; }
-
-.cyan.accent-2 {
- background-color: #18ffff !important; }
-
-.cyan-text.text-accent-2 {
- color: #18ffff !important; }
-
-.cyan.accent-3 {
- background-color: #00e5ff !important; }
-
-.cyan-text.text-accent-3 {
- color: #00e5ff !important; }
-
-.cyan.accent-4 {
- background-color: #00b8d4 !important; }
-
-.cyan-text.text-accent-4 {
- color: #00b8d4 !important; }
-
-.teal.lighten-5 {
- background-color: #e0f2f1 !important; }
-
-.teal-text.text-lighten-5 {
- color: #e0f2f1 !important; }
-
-.teal.lighten-4 {
- background-color: #b2dfdb !important; }
-
-.teal-text.text-lighten-4 {
- color: #b2dfdb !important; }
-
-.teal.lighten-3 {
- background-color: #80cbc4 !important; }
-
-.teal-text.text-lighten-3 {
- color: #80cbc4 !important; }
-
-.teal.lighten-2 {
- background-color: #4db6ac !important; }
-
-.teal-text.text-lighten-2 {
- color: #4db6ac !important; }
-
-.teal.lighten-1 {
- background-color: #26a69a !important; }
-
-.teal-text.text-lighten-1 {
- color: #26a69a !important; }
-
-.teal {
- background-color: #009688 !important; }
-
-.teal-text {
- color: #009688 !important; }
-
-.teal.darken-1 {
- background-color: #00897b !important; }
-
-.teal-text.text-darken-1 {
- color: #00897b !important; }
-
-.teal.darken-2 {
- background-color: #00796b !important; }
-
-.teal-text.text-darken-2 {
- color: #00796b !important; }
-
-.teal.darken-3 {
- background-color: #00695c !important; }
-
-.teal-text.text-darken-3 {
- color: #00695c !important; }
-
-.teal.darken-4 {
- background-color: #004d40 !important; }
-
-.teal-text.text-darken-4 {
- color: #004d40 !important; }
-
-.teal.accent-1 {
- background-color: #a7ffeb !important; }
-
-.teal-text.text-accent-1 {
- color: #a7ffeb !important; }
-
-.teal.accent-2 {
- background-color: #64ffda !important; }
-
-.teal-text.text-accent-2 {
- color: #64ffda !important; }
-
-.teal.accent-3 {
- background-color: #1de9b6 !important; }
-
-.teal-text.text-accent-3 {
- color: #1de9b6 !important; }
-
-.teal.accent-4 {
- background-color: #00bfa5 !important; }
-
-.teal-text.text-accent-4 {
- color: #00bfa5 !important; }
-
-.green.lighten-5 {
- background-color: #E8F5E9 !important; }
-
-.green-text.text-lighten-5 {
- color: #E8F5E9 !important; }
-
-.green.lighten-4 {
- background-color: #C8E6C9 !important; }
-
-.green-text.text-lighten-4 {
- color: #C8E6C9 !important; }
-
-.green.lighten-3 {
- background-color: #A5D6A7 !important; }
-
-.green-text.text-lighten-3 {
- color: #A5D6A7 !important; }
-
-.green.lighten-2 {
- background-color: #81C784 !important; }
-
-.green-text.text-lighten-2 {
- color: #81C784 !important; }
-
-.green.lighten-1 {
- background-color: #66BB6A !important; }
-
-.green-text.text-lighten-1 {
- color: #66BB6A !important; }
-
-.green {
- background-color: #4CAF50 !important; }
-
-.green-text {
- color: #4CAF50 !important; }
-
-.green.darken-1 {
- background-color: #43A047 !important; }
-
-.green-text.text-darken-1 {
- color: #43A047 !important; }
-
-.green.darken-2 {
- background-color: #388E3C !important; }
-
-.green-text.text-darken-2 {
- color: #388E3C !important; }
-
-.green.darken-3 {
- background-color: #2E7D32 !important; }
-
-.green-text.text-darken-3 {
- color: #2E7D32 !important; }
-
-.green.darken-4 {
- background-color: #1B5E20 !important; }
-
-.green-text.text-darken-4 {
- color: #1B5E20 !important; }
-
-.green.accent-1 {
- background-color: #B9F6CA !important; }
-
-.green-text.text-accent-1 {
- color: #B9F6CA !important; }
-
-.green.accent-2 {
- background-color: #69F0AE !important; }
-
-.green-text.text-accent-2 {
- color: #69F0AE !important; }
-
-.green.accent-3 {
- background-color: #00E676 !important; }
-
-.green-text.text-accent-3 {
- color: #00E676 !important; }
-
-.green.accent-4 {
- background-color: #00C853 !important; }
-
-.green-text.text-accent-4 {
- color: #00C853 !important; }
-
-.light-green.lighten-5 {
- background-color: #f1f8e9 !important; }
-
-.light-green-text.text-lighten-5 {
- color: #f1f8e9 !important; }
-
-.light-green.lighten-4 {
- background-color: #dcedc8 !important; }
-
-.light-green-text.text-lighten-4 {
- color: #dcedc8 !important; }
-
-.light-green.lighten-3 {
- background-color: #c5e1a5 !important; }
-
-.light-green-text.text-lighten-3 {
- color: #c5e1a5 !important; }
-
-.light-green.lighten-2 {
- background-color: #aed581 !important; }
-
-.light-green-text.text-lighten-2 {
- color: #aed581 !important; }
-
-.light-green.lighten-1 {
- background-color: #9ccc65 !important; }
-
-.light-green-text.text-lighten-1 {
- color: #9ccc65 !important; }
-
-.light-green {
- background-color: #8bc34a !important; }
-
-.light-green-text {
- color: #8bc34a !important; }
-
-.light-green.darken-1 {
- background-color: #7cb342 !important; }
-
-.light-green-text.text-darken-1 {
- color: #7cb342 !important; }
-
-.light-green.darken-2 {
- background-color: #689f38 !important; }
-
-.light-green-text.text-darken-2 {
- color: #689f38 !important; }
-
-.light-green.darken-3 {
- background-color: #558b2f !important; }
-
-.light-green-text.text-darken-3 {
- color: #558b2f !important; }
-
-.light-green.darken-4 {
- background-color: #33691e !important; }
-
-.light-green-text.text-darken-4 {
- color: #33691e !important; }
-
-.light-green.accent-1 {
- background-color: #ccff90 !important; }
-
-.light-green-text.text-accent-1 {
- color: #ccff90 !important; }
-
-.light-green.accent-2 {
- background-color: #b2ff59 !important; }
-
-.light-green-text.text-accent-2 {
- color: #b2ff59 !important; }
-
-.light-green.accent-3 {
- background-color: #76ff03 !important; }
-
-.light-green-text.text-accent-3 {
- color: #76ff03 !important; }
-
-.light-green.accent-4 {
- background-color: #64dd17 !important; }
-
-.light-green-text.text-accent-4 {
- color: #64dd17 !important; }
-
-.lime.lighten-5 {
- background-color: #f9fbe7 !important; }
-
-.lime-text.text-lighten-5 {
- color: #f9fbe7 !important; }
-
-.lime.lighten-4 {
- background-color: #f0f4c3 !important; }
-
-.lime-text.text-lighten-4 {
- color: #f0f4c3 !important; }
-
-.lime.lighten-3 {
- background-color: #e6ee9c !important; }
-
-.lime-text.text-lighten-3 {
- color: #e6ee9c !important; }
-
-.lime.lighten-2 {
- background-color: #dce775 !important; }
-
-.lime-text.text-lighten-2 {
- color: #dce775 !important; }
-
-.lime.lighten-1 {
- background-color: #d4e157 !important; }
-
-.lime-text.text-lighten-1 {
- color: #d4e157 !important; }
-
-.lime {
- background-color: #cddc39 !important; }
-
-.lime-text {
- color: #cddc39 !important; }
-
-.lime.darken-1 {
- background-color: #c0ca33 !important; }
-
-.lime-text.text-darken-1 {
- color: #c0ca33 !important; }
-
-.lime.darken-2 {
- background-color: #afb42b !important; }
-
-.lime-text.text-darken-2 {
- color: #afb42b !important; }
-
-.lime.darken-3 {
- background-color: #9e9d24 !important; }
-
-.lime-text.text-darken-3 {
- color: #9e9d24 !important; }
-
-.lime.darken-4 {
- background-color: #827717 !important; }
-
-.lime-text.text-darken-4 {
- color: #827717 !important; }
-
-.lime.accent-1 {
- background-color: #f4ff81 !important; }
-
-.lime-text.text-accent-1 {
- color: #f4ff81 !important; }
-
-.lime.accent-2 {
- background-color: #eeff41 !important; }
-
-.lime-text.text-accent-2 {
- color: #eeff41 !important; }
-
-.lime.accent-3 {
- background-color: #c6ff00 !important; }
-
-.lime-text.text-accent-3 {
- color: #c6ff00 !important; }
-
-.lime.accent-4 {
- background-color: #aeea00 !important; }
-
-.lime-text.text-accent-4 {
- color: #aeea00 !important; }
-
-.yellow.lighten-5 {
- background-color: #fffde7 !important; }
-
-.yellow-text.text-lighten-5 {
- color: #fffde7 !important; }
-
-.yellow.lighten-4 {
- background-color: #fff9c4 !important; }
-
-.yellow-text.text-lighten-4 {
- color: #fff9c4 !important; }
-
-.yellow.lighten-3 {
- background-color: #fff59d !important; }
-
-.yellow-text.text-lighten-3 {
- color: #fff59d !important; }
-
-.yellow.lighten-2 {
- background-color: #fff176 !important; }
-
-.yellow-text.text-lighten-2 {
- color: #fff176 !important; }
-
-.yellow.lighten-1 {
- background-color: #ffee58 !important; }
-
-.yellow-text.text-lighten-1 {
- color: #ffee58 !important; }
-
-.yellow {
- background-color: #ffeb3b !important; }
-
-.yellow-text {
- color: #ffeb3b !important; }
-
-.yellow.darken-1 {
- background-color: #fdd835 !important; }
-
-.yellow-text.text-darken-1 {
- color: #fdd835 !important; }
-
-.yellow.darken-2 {
- background-color: #fbc02d !important; }
-
-.yellow-text.text-darken-2 {
- color: #fbc02d !important; }
-
-.yellow.darken-3 {
- background-color: #f9a825 !important; }
-
-.yellow-text.text-darken-3 {
- color: #f9a825 !important; }
-
-.yellow.darken-4 {
- background-color: #f57f17 !important; }
-
-.yellow-text.text-darken-4 {
- color: #f57f17 !important; }
-
-.yellow.accent-1 {
- background-color: #ffff8d !important; }
-
-.yellow-text.text-accent-1 {
- color: #ffff8d !important; }
-
-.yellow.accent-2 {
- background-color: #ffff00 !important; }
-
-.yellow-text.text-accent-2 {
- color: #ffff00 !important; }
-
-.yellow.accent-3 {
- background-color: #ffea00 !important; }
-
-.yellow-text.text-accent-3 {
- color: #ffea00 !important; }
-
-.yellow.accent-4 {
- background-color: #ffd600 !important; }
-
-.yellow-text.text-accent-4 {
- color: #ffd600 !important; }
-
-.amber.lighten-5 {
- background-color: #fff8e1 !important; }
-
-.amber-text.text-lighten-5 {
- color: #fff8e1 !important; }
-
-.amber.lighten-4 {
- background-color: #ffecb3 !important; }
-
-.amber-text.text-lighten-4 {
- color: #ffecb3 !important; }
-
-.amber.lighten-3 {
- background-color: #ffe082 !important; }
-
-.amber-text.text-lighten-3 {
- color: #ffe082 !important; }
-
-.amber.lighten-2 {
- background-color: #ffd54f !important; }
-
-.amber-text.text-lighten-2 {
- color: #ffd54f !important; }
-
-.amber.lighten-1 {
- background-color: #ffca28 !important; }
-
-.amber-text.text-lighten-1 {
- color: #ffca28 !important; }
-
-.amber {
- background-color: #ffc107 !important; }
-
-.amber-text {
- color: #ffc107 !important; }
-
-.amber.darken-1 {
- background-color: #ffb300 !important; }
-
-.amber-text.text-darken-1 {
- color: #ffb300 !important; }
-
-.amber.darken-2 {
- background-color: #ffa000 !important; }
-
-.amber-text.text-darken-2 {
- color: #ffa000 !important; }
-
-.amber.darken-3 {
- background-color: #ff8f00 !important; }
-
-.amber-text.text-darken-3 {
- color: #ff8f00 !important; }
-
-.amber.darken-4 {
- background-color: #ff6f00 !important; }
-
-.amber-text.text-darken-4 {
- color: #ff6f00 !important; }
-
-.amber.accent-1 {
- background-color: #ffe57f !important; }
-
-.amber-text.text-accent-1 {
- color: #ffe57f !important; }
-
-.amber.accent-2 {
- background-color: #ffd740 !important; }
-
-.amber-text.text-accent-2 {
- color: #ffd740 !important; }
-
-.amber.accent-3 {
- background-color: #ffc400 !important; }
-
-.amber-text.text-accent-3 {
- color: #ffc400 !important; }
-
-.amber.accent-4 {
- background-color: #ffab00 !important; }
-
-.amber-text.text-accent-4 {
- color: #ffab00 !important; }
-
-.orange.lighten-5 {
- background-color: #fff3e0 !important; }
-
-.orange-text.text-lighten-5 {
- color: #fff3e0 !important; }
-
-.orange.lighten-4 {
- background-color: #ffe0b2 !important; }
-
-.orange-text.text-lighten-4 {
- color: #ffe0b2 !important; }
-
-.orange.lighten-3 {
- background-color: #ffcc80 !important; }
-
-.orange-text.text-lighten-3 {
- color: #ffcc80 !important; }
-
-.orange.lighten-2 {
- background-color: #ffb74d !important; }
-
-.orange-text.text-lighten-2 {
- color: #ffb74d !important; }
-
-.orange.lighten-1 {
- background-color: #ffa726 !important; }
-
-.orange-text.text-lighten-1 {
- color: #ffa726 !important; }
-
-.orange {
- background-color: #ff9800 !important; }
-
-.orange-text {
- color: #ff9800 !important; }
-
-.orange.darken-1 {
- background-color: #fb8c00 !important; }
-
-.orange-text.text-darken-1 {
- color: #fb8c00 !important; }
-
-.orange.darken-2 {
- background-color: #f57c00 !important; }
-
-.orange-text.text-darken-2 {
- color: #f57c00 !important; }
-
-.orange.darken-3 {
- background-color: #ef6c00 !important; }
-
-.orange-text.text-darken-3 {
- color: #ef6c00 !important; }
-
-.orange.darken-4 {
- background-color: #e65100 !important; }
-
-.orange-text.text-darken-4 {
- color: #e65100 !important; }
-
-.orange.accent-1 {
- background-color: #ffd180 !important; }
-
-.orange-text.text-accent-1 {
- color: #ffd180 !important; }
-
-.orange.accent-2 {
- background-color: #ffab40 !important; }
-
-.orange-text.text-accent-2 {
- color: #ffab40 !important; }
-
-.orange.accent-3 {
- background-color: #ff9100 !important; }
-
-.orange-text.text-accent-3 {
- color: #ff9100 !important; }
-
-.orange.accent-4 {
- background-color: #ff6d00 !important; }
-
-.orange-text.text-accent-4 {
- color: #ff6d00 !important; }
-
-.deep-orange.lighten-5 {
- background-color: #fbe9e7 !important; }
-
-.deep-orange-text.text-lighten-5 {
- color: #fbe9e7 !important; }
-
-.deep-orange.lighten-4 {
- background-color: #ffccbc !important; }
-
-.deep-orange-text.text-lighten-4 {
- color: #ffccbc !important; }
-
-.deep-orange.lighten-3 {
- background-color: #ffab91 !important; }
-
-.deep-orange-text.text-lighten-3 {
- color: #ffab91 !important; }
-
-.deep-orange.lighten-2 {
- background-color: #ff8a65 !important; }
-
-.deep-orange-text.text-lighten-2 {
- color: #ff8a65 !important; }
-
-.deep-orange.lighten-1 {
- background-color: #ff7043 !important; }
-
-.deep-orange-text.text-lighten-1 {
- color: #ff7043 !important; }
-
-.deep-orange {
- background-color: #ff5722 !important; }
-
-.deep-orange-text {
- color: #ff5722 !important; }
-
-.deep-orange.darken-1 {
- background-color: #f4511e !important; }
-
-.deep-orange-text.text-darken-1 {
- color: #f4511e !important; }
-
-.deep-orange.darken-2 {
- background-color: #e64a19 !important; }
-
-.deep-orange-text.text-darken-2 {
- color: #e64a19 !important; }
-
-.deep-orange.darken-3 {
- background-color: #d84315 !important; }
-
-.deep-orange-text.text-darken-3 {
- color: #d84315 !important; }
-
-.deep-orange.darken-4 {
- background-color: #bf360c !important; }
-
-.deep-orange-text.text-darken-4 {
- color: #bf360c !important; }
-
-.deep-orange.accent-1 {
- background-color: #ff9e80 !important; }
-
-.deep-orange-text.text-accent-1 {
- color: #ff9e80 !important; }
-
-.deep-orange.accent-2 {
- background-color: #ff6e40 !important; }
-
-.deep-orange-text.text-accent-2 {
- color: #ff6e40 !important; }
-
-.deep-orange.accent-3 {
- background-color: #ff3d00 !important; }
-
-.deep-orange-text.text-accent-3 {
- color: #ff3d00 !important; }
-
-.deep-orange.accent-4 {
- background-color: #dd2c00 !important; }
-
-.deep-orange-text.text-accent-4 {
- color: #dd2c00 !important; }
-
-.brown.lighten-5 {
- background-color: #efebe9 !important; }
-
-.brown-text.text-lighten-5 {
- color: #efebe9 !important; }
-
-.brown.lighten-4 {
- background-color: #d7ccc8 !important; }
-
-.brown-text.text-lighten-4 {
- color: #d7ccc8 !important; }
-
-.brown.lighten-3 {
- background-color: #bcaaa4 !important; }
-
-.brown-text.text-lighten-3 {
- color: #bcaaa4 !important; }
-
-.brown.lighten-2 {
- background-color: #a1887f !important; }
-
-.brown-text.text-lighten-2 {
- color: #a1887f !important; }
-
-.brown.lighten-1 {
- background-color: #8d6e63 !important; }
-
-.brown-text.text-lighten-1 {
- color: #8d6e63 !important; }
-
-.brown {
- background-color: #795548 !important; }
-
-.brown-text {
- color: #795548 !important; }
-
-.brown.darken-1 {
- background-color: #6d4c41 !important; }
-
-.brown-text.text-darken-1 {
- color: #6d4c41 !important; }
-
-.brown.darken-2 {
- background-color: #5d4037 !important; }
-
-.brown-text.text-darken-2 {
- color: #5d4037 !important; }
-
-.brown.darken-3 {
- background-color: #4e342e !important; }
-
-.brown-text.text-darken-3 {
- color: #4e342e !important; }
-
-.brown.darken-4 {
- background-color: #3e2723 !important; }
-
-.brown-text.text-darken-4 {
- color: #3e2723 !important; }
-
-.blue-grey.lighten-5 {
- background-color: #eceff1 !important; }
-
-.blue-grey-text.text-lighten-5 {
- color: #eceff1 !important; }
-
-.blue-grey.lighten-4 {
- background-color: #cfd8dc !important; }
-
-.blue-grey-text.text-lighten-4 {
- color: #cfd8dc !important; }
-
-.blue-grey.lighten-3 {
- background-color: #b0bec5 !important; }
-
-.blue-grey-text.text-lighten-3 {
- color: #b0bec5 !important; }
-
-.blue-grey.lighten-2 {
- background-color: #90a4ae !important; }
-
-.blue-grey-text.text-lighten-2 {
- color: #90a4ae !important; }
-
-.blue-grey.lighten-1 {
- background-color: #78909c !important; }
-
-.blue-grey-text.text-lighten-1 {
- color: #78909c !important; }
-
-.blue-grey {
- background-color: #607d8b !important; }
-
-.blue-grey-text {
- color: #607d8b !important; }
-
-.blue-grey.darken-1 {
- background-color: #546e7a !important; }
-
-.blue-grey-text.text-darken-1 {
- color: #546e7a !important; }
-
-.blue-grey.darken-2 {
- background-color: #455a64 !important; }
-
-.blue-grey-text.text-darken-2 {
- color: #455a64 !important; }
-
-.blue-grey.darken-3 {
- background-color: #37474f !important; }
-
-.blue-grey-text.text-darken-3 {
- color: #37474f !important; }
-
-.blue-grey.darken-4 {
- background-color: #263238 !important; }
-
-.blue-grey-text.text-darken-4 {
- color: #263238 !important; }
-
-.grey.lighten-5 {
- background-color: #fafafa !important; }
-
-.grey-text.text-lighten-5 {
- color: #fafafa !important; }
-
-.grey.lighten-4 {
- background-color: #f5f5f5 !important; }
-
-.grey-text.text-lighten-4 {
- color: #f5f5f5 !important; }
-
-.grey.lighten-3 {
- background-color: #eeeeee !important; }
-
-.grey-text.text-lighten-3 {
- color: #eeeeee !important; }
-
-.grey.lighten-2 {
- background-color: #e0e0e0 !important; }
-
-.grey-text.text-lighten-2 {
- color: #e0e0e0 !important; }
-
-.grey.lighten-1 {
- background-color: #bdbdbd !important; }
-
-.grey-text.text-lighten-1 {
- color: #bdbdbd !important; }
-
-.grey {
- background-color: #9e9e9e !important; }
-
-.grey-text {
- color: #9e9e9e !important; }
-
-.grey.darken-1 {
- background-color: #757575 !important; }
-
-.grey-text.text-darken-1 {
- color: #757575 !important; }
-
-.grey.darken-2 {
- background-color: #616161 !important; }
-
-.grey-text.text-darken-2 {
- color: #616161 !important; }
-
-.grey.darken-3 {
- background-color: #424242 !important; }
-
-.grey-text.text-darken-3 {
- color: #424242 !important; }
-
-.grey.darken-4 {
- background-color: #212121 !important; }
-
-.grey-text.text-darken-4 {
- color: #212121 !important; }
-
-.shades.black {
- background-color: #000000 !important; }
-
-.shades-text.text-black {
- color: #000000 !important; }
-
-.shades.white {
- background-color: #FFFFFF !important; }
-
-.shades-text.text-white {
- color: #FFFFFF !important; }
-
-.shades.transparent {
- background-color: transparent !important; }
-
-.shades-text.text-transparent {
- color: transparent !important; }
-
-.black {
- background-color: #000000 !important; }
-
-.black-text {
- color: #000000 !important; }
-
-.white {
- background-color: #FFFFFF !important; }
-
-.white-text {
- color: #FFFFFF !important; }
-
-.transparent {
- background-color: transparent !important; }
-
-.transparent-text {
- color: transparent !important; }
-
-/*** Colors ***/
-/*** Badges ***/
-/*** Buttons ***/
-/*** Cards ***/
-/*** Collapsible ***/
-/*** Dropdown ***/
-/*** Fonts ***/
-/*** Forms ***/
-/*** Global ***/
-/*** Navbar ***/
-/*** SideNav ***/
-/*** Photo Slider ***/
-/*** Tabs ***/
-/*** Tables ***/
-/*** Toasts ***/
-/*** Typography ***/
-/*** Collections ***/
-/* Progress Bar */
-/* variables
-=================================================================================*/
-.editorDialogs .modal, .note-editor .modal {
- background-color: white;
- color: #424242;
- z-index: 1057 !important;
- backface-visibility: hidden; }
- .editorDialogs .modal .input-field input:not([readonly]), .editorDialogs .modal .input-field input.datepicker, .note-editor .modal .input-field input:not([readonly]), .note-editor .modal .input-field input.datepicker {
- border-color: #424242 !important; }
- .editorDialogs .modal .input-field input:focus:not([readonly]), .editorDialogs .modal .input-field input.datepicker:focus, .editorDialogs .modal textarea.materialize-textarea:focus:not([readonly]), .note-editor .modal .input-field input:focus:not([readonly]), .note-editor .modal .input-field input.datepicker:focus, .note-editor .modal textarea.materialize-textarea:focus:not([readonly]) {
- box-shadow: 0 1px 0 0 #2196F3 !important;
- border-color: #2196F3 !important; }
- .editorDialogs .modal label, .editorDialogs .modal .input-field input:not([readonly]) + label, .editorDialogs .modal .input-field input.datepicker + label, .editorDialogs .modal .input-field .prefix, .editorDialogs .modal .note-editor + label, .note-editor .modal label, .note-editor .modal .input-field input:not([readonly]) + label, .note-editor .modal .input-field input.datepicker + label, .note-editor .modal .input-field .prefix, .note-editor .modal .note-editor + label {
- color: #424242 !important; }
- .editorDialogs .modal .input-field input:focus:not([readonly]) + label, .editorDialogs .modal .input-field input.datepicker:focus + label, .editorDialogs .modal .input-field .prefix.active, .editorDialogs .modal textarea.materialize-textarea:focus:not([readonly]) + label, .note-editor .modal .input-field input:focus:not([readonly]) + label, .note-editor .modal .input-field input.datepicker:focus + label, .note-editor .modal .input-field .prefix.active, .note-editor .modal textarea.materialize-textarea:focus:not([readonly]) + label {
- color: #2196F3 !important; }
- .editorDialogs .modal .btn, .note-editor .modal .btn {
- background-color: #0D47A1;
- color: white !important; }
- .editorDialogs .modal .btn:hover, .note-editor .modal .btn:hover {
- background-color: #115cd0 !important; }
- .editorDialogs .modal .btn.disabled, .note-editor .modal .btn.disabled {
- background-color: #07285a !important; }
- .editorDialogs .modal .modal-footer, .note-editor .modal .modal-footer {
- background-color: #c7c7c7; }
- .editorDialogs .modal .modal-footer .btnClose, .note-editor .modal .modal-footer .btnClose {
- margin-right: 15px;
- background-color: #B71C1C; }
- .editorDialogs .modal .modal-footer .btnClose:hover, .note-editor .modal .modal-footer .btnClose:hover {
- background-color: #de2828 !important; }
- .editorDialogs .modal .canvasContainerEmpty, .note-editor .modal .canvasContainerEmpty {
- border: solid 5px #2196F3; }
-
-.note-editor .note-editable::-webkit-scrollbar, .editorDialogs .modal-content::-webkit-scrollbar, .note-editor .note-color-palette::-webkit-scrollbar, .note-editor .note-codable::-webkit-scrollbar, .modal.modal-fixed-footer .modal-content::-webkit-scrollbar {
- width: 17px !important; }
-.note-editor .note-editable::-webkit-scrollbar-track, .editorDialogs .modal-content::-webkit-scrollbar-track, .note-editor .note-color-palette::-webkit-scrollbar-track, .note-editor .note-codable::-webkit-scrollbar-track, .modal.modal-fixed-footer .modal-content::-webkit-scrollbar-track {
- background-color: #e0e0e0 !important; }
-.note-editor .note-editable::-webkit-scrollbar-thumb, .editorDialogs .modal-content::-webkit-scrollbar-thumb, .note-editor .note-color-palette::-webkit-scrollbar-thumb, .note-editor .note-codable::-webkit-scrollbar-thumb, .modal.modal-fixed-footer .modal-content::-webkit-scrollbar-thumb {
- background-color: white !important; }
-.note-editor .note-editable::-webkit-scrollbar-thumb:hover, .editorDialogs .modal-content::-webkit-scrollbar-thumb:hover, .note-editor .note-color-palette::-webkit-scrollbar-thumb:hover, .note-editor .note-codable::-webkit-scrollbar-thumb:hover, .modal.modal-fixed-footer .modal-content::-webkit-scrollbar-thumb:hover {
- background-color: white !important; }
-
-.note-editor {
- position: relative;
- border-left: 1px solid #e0e0e0;
- border-bottom: 1px solid #e0e0e0;
- border-right: 1px solid #e0e0e0; }
- .note-editor .img-circle {
- border-radius: 50%; }
- .note-editor .img-rounded {
- border-radius: 5%; }
- .note-editor .img-thumbnail {
- border: solid 2px #e0e0e0;
- height: 200px; }
- .note-editor .img-bordered {
- border: solid 5px #e0e0e0; }
- .note-editor .btn:hover {
- background-color: #fafafa !important; }
- .note-editor .btn.active {
- background-color: #2196F3; }
- .note-editor .note-editable ul li {
- list-style-type: square !important;
- display: list-item;
- list-style-position: inside; }
- .note-editor .note-dialog > div {
- display: none; }
- .note-editor .note-dialog .form-group {
- margin-right: 0;
- margin-left: 0; }
- .note-editor .note-dialog .note-modal-form {
- margin: 0; }
- .note-editor .note-dialog .note-image-dialog .note-dropzone {
- min-height: 100px;
- margin-bottom: 10px;
- font-size: 30px;
- line-height: 4;
- color: lightgray;
- text-align: center;
- border: 4px dashed lightgray; }
- .note-editor .transparent {
- opacity: 0; }
- .note-editor .note-resizebar {
- background-color: #e0e0e0;
- width: 100%;
- height: 13px;
- cursor: ns-resize;
- padding-top: 1px; }
- .note-editor .note-resizebar .note-icon-bar {
- width: 20px;
- margin: 2px auto;
- border-top: 2px solid white; }
- .note-editor .note-toolbar {
- position: relative;
- color: #424242;
- background-color: #e0e0e0;
- margin: 0;
- z-index: 1052; }
- .note-editor .note-toolbar ul {
- padding: 0; }
- .note-editor .note-toolbar .btn.disabled, .note-editor .note-toolbar button.disabled {
- display: none; }
- .note-editor .note-toolbar .dropdown {
- cursor: pointer; }
- .note-editor .note-toolbar .note-current-fontname {
- min-width: 134px;
- display: inline-block;
- text-align: left; }
- .note-editor .note-handle .note-control-selection {
- position: absolute;
- display: none;
- border: 2px solid #e0e0e0; }
- .note-editor .note-handle .note-control-selection .note-control-selection-bg {
- width: 100%;
- height: 100%;
- z-index: 3;
- background-color: rgba(117, 117, 117, 0.3); }
- .note-editor .note-handle .note-control-selection > div {
- position: absolute; }
- .note-editor .note-handle .note-control-selection .note-control-handle {
- width: 7px;
- height: 7px;
- border: 1px solid black; }
- .note-editor .note-handle .note-control-selection .note-control-holder {
- width: 7px;
- height: 7px;
- border: 1px solid black; }
- .note-editor .note-handle .note-control-selection .note-control-sizing {
- width: 15px;
- height: 15px;
- background-color: #e0e0e0;
- z-index: 5;
- cursor: se-resize; }
- .note-editor .note-handle .note-control-selection .note-control-nw {
- top: -5px;
- left: -5px;
- border-right: 0;
- border-bottom: 0; }
- .note-editor .note-handle .note-control-selection .note-control-ne {
- top: -5px;
- right: -5px;
- border-bottom: 0;
- border-left: none; }
- .note-editor .note-handle .note-control-selection .note-control-sw {
- bottom: -5px;
- left: -5px;
- border-top: 0;
- border-right: 0; }
- .note-editor .note-handle .note-control-selection .note-control-se {
- right: -5px;
- bottom: -5px; }
- .note-editor .note-handle .note-control-selection .note-control-selection-info {
- right: 0;
- bottom: 0;
- padding: 5px;
- margin: 17px;
- font-size: 15px;
- color: #424242;
- background-color: #e0e0e0;
- z-index: 5; }
-
-.note-dialog .note-help-dialog {
- color: #e0e0e0; }
- .note-dialog .note-help-dialog h4 {
- color: #424242; }
- .note-dialog .note-help-dialog thead {
- background-color: #2196F3; }
- .note-dialog .note-help-dialog tbody {
- background-color: #e0e0e0; }
-
-.note-editor .btn-group, .popover .btn-group {
- display: inline-block;
- margin-right: 10px;
- position: relative; }
- .note-editor .btn-group ul, .popover .btn-group ul {
- padding: 0; }
- .note-editor .btn-group .closeLeft, .popover .btn-group .closeLeft {
- padding-right: 0 !important;
- margin-right: 0 !important; }
- .note-editor .btn-group .closeLeft i, .popover .btn-group .closeLeft i {
- margin-right: 0 !important; }
- .note-editor .btn-group i.left, .popover .btn-group i.left {
- margin-right: 5px; }
-.note-editor .note-toolbar .btn, .popover .note-toolbar .btn {
- border-radius: 0 !important;
- box-shadow: none !important;
- padding: 0 9px !important;
- background-color: #e0e0e0; }
-.note-editor .btnSecond, .popover .btnSecond {
- background-color: #0D47A1 !important; }
-.note-editor .btnThird, .popover .btnThird {
- background-color: #B71C1C !important; }
-.note-editor note-toolbar button, .note-editor button, .note-editor .note-toolbar .btn, .popover note-toolbar button, .popover button, .popover .note-toolbar .btn {
- background-color: #e0e0e0;
- border: none;
- height: 36px;
- text-transform: uppercase;
- color: #424242 !important; }
-.note-editor [type="checkbox"]:checked + label:before, .note-editor [type="checkbox"]:checked + label:before, .popover [type="checkbox"]:checked + label:before, .popover [type="checkbox"]:checked + label:before {
- border-right-color: #0D47A1 !important;
- border-bottom-color: #0D47A1 !important; }
-.note-editor .note-palette-title, .popover .note-palette-title {
- padding: 0 !important; }
-.note-editor .colorName, .popover .colorName {
- display: inline-block;
- color: #424242; }
- @media only screen and (max-width: 600px) {
- .note-editor .colorName, .popover .colorName {
- display: none; } }
-.note-editor .note-color-palette, .popover .note-color-palette {
- line-height: 10px;
- border: solid 3px #e0e0e0;
- padding: 0 !important;
- overflow-x: scroll;
- overflow-y: hidden; }
- .note-editor .note-color-palette .note-color-row, .popover .note-color-palette .note-color-row {
- padding: 0 !important;
- min-width: 300px; }
- .note-editor .note-color-palette button.note-color-btn, .popover .note-color-palette button.note-color-btn {
- width: 20px;
- height: 20px;
- padding: 0;
- margin: 0; }
- .note-editor .note-color-palette .note-color-btn:hover:after, .popover .note-color-palette .note-color-btn:hover:after {
- position: absolute;
- width: 30px;
- height: 30px;
- content: "";
- background-color: inherit;
- margin-top: -15px;
- margin-left: -15px; }
-.note-editor .note-dimension-picker, .popover .note-dimension-picker {
- overflow: hidden; }
-.note-editor .largeDropdown, .popover .largeDropdown {
- width: 290px; }
-.note-editor .dropdown-menu, .popover .dropdown-menu {
- z-index: 1033; }
- .note-editor .dropdown-menu.note-check, .popover .dropdown-menu.note-check {
- min-width: 80px; }
- .note-editor .dropdown-menu label, .popover .dropdown-menu label {
- color: #424242 !important; }
-.note-editor ul.dropdown-menu, .popover ul.dropdown-menu {
- position: absolute;
- top: 20px;
- background-color: #fafafa;
- border-left: 3px solid #e0e0e0;
- border-bottom: 3px solid #e0e0e0;
- border-right: 3px solid #e0e0e0; }
- .note-editor ul.dropdown-menu#colors, .popover ul.dropdown-menu#colors {
- width: 342px; }
- .note-editor ul.dropdown-menu#colors .indicator, .popover ul.dropdown-menu#colors .indicator {
- width: 50%;
- left: 0; }
- .note-editor ul.dropdown-menu .colorTable, .popover ul.dropdown-menu .colorTable {
- padding: 3px 0; }
- .note-editor ul.dropdown-menu .tabs, .popover ul.dropdown-menu .tabs {
- background-color: #e0e0e0; }
- .note-editor ul.dropdown-menu .tabs:hover, .popover ul.dropdown-menu .tabs:hover {
- background-color: #e0e0e0; }
- .note-editor ul.dropdown-menu .tabs .tab a, .note-editor ul.dropdown-menu .tabs .tab a:hover, .popover ul.dropdown-menu .tabs .tab a, .popover ul.dropdown-menu .tabs .tab a:hover {
- color: #9e9e9e; }
- .note-editor ul.dropdown-menu .tabs .indicator, .popover ul.dropdown-menu .tabs .indicator {
- background-color: #9e9e9e; }
- .note-editor ul.dropdown-menu li, .popover ul.dropdown-menu li {
- list-style-type: none;
- padding: 0 !important; }
- .note-editor ul.dropdown-menu li div, .popover ul.dropdown-menu li div {
- padding: 3px 15px;
- cursor: pointer; }
-
-.note-popover .popover {
- position: absolute;
- max-width: none;
- color: #424242; }
- .note-popover .popover .arrow {
- width: 0;
- height: 0;
- border-style: solid;
- border-width: 0 10px 10px 10px;
- border-color: transparent transparent #e0e0e0 transparent; }
- .note-popover .popover .popover-content {
- background-color: #e0e0e0; }
- .note-popover .popover .popover-content > a {
- margin-left: 12px; }
- .note-popover .popover .popover-content a {
- display: inline-block;
- max-width: 200px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- vertical-align: middle; }
- .note-popover .popover .popover-content .arrow {
- left: 20px; }
- .note-popover .popover .popover-content .btn-group {
- display: inline-block; }
- .note-popover .popover .popover-content .btn-group .btn {
- border-radius: 0 !important;
- box-shadow: none !important;
- padding: 0 9px !important;
- background-color: #e0e0e0;
- color: #424242 !important; }
-
-.note-popover .popover .popover-content .note-para .dropdown-menu, .note-toolbar .note-para .dropdown-menu {
- min-width: 172px;
- padding: 5px; }
-
-.note-popover .popover .popover-content .note-para .dropdown-menu > div:first-child, .note-toolbar .note-para .dropdown-menu > div:first-child {
- margin-right: 5px; }
-
-.note-editor .note-dropzone {
- position: absolute;
- z-index: 100;
- display: none;
- color: #87cefa;
- background-color: white;
- border: 2px dashed #87cefa;
- opacity: .95;
- pointer-event: none; }
-
-.note-editor .note-dropzone .note-dropzone-message {
- display: table-cell;
- font-size: 28px;
- font-weight: bold;
- text-align: center;
- vertical-align: middle; }
-
-.note-editor .note-dropzone.hover {
- color: #098ddf;
- border: 2px dashed #098ddf; }
-
-.note-editor.dragover .note-dropzone {
- display: table; }
-
-.note-editor.fullscreen {
- position: fixed;
- top: 0;
- left: 0;
- z-index: 2021;
- width: 100%; }
-
-.note-editor.fullscreen .note-editable {
- background-color: white; }
-
-.note-editor.fullscreen .note-resizebar {
- display: none; }
-
-.note-editor.codeview .note-editable {
- display: none; }
-
-.note-editor.codeview .note-codable {
- display: block; }
-
-.note-editor .note-statusbar {
- background-color: #f5f5f5; }
-
-.note-editor .note-editable[contenteditable=true]:empty:not(:focus):before {
- color: #a9a9a9;
- content: attr(data-placeholder); }
-
-.note-editor .note-editable {
- padding: 10px;
- overflow: auto;
- outline: 0; }
-
-.note-editor .note-editable[contenteditable="false"] {
- background-color: #e5e5e5; }
-
-.note-editor .note-codable {
- display: none;
- width: 100%;
- padding: 10px;
- margin-bottom: 0;
- font-family: Menlo, Monaco, monospace, sans-serif;
- font-size: 14px;
- color: #ccc;
- background-color: #222;
- border: 0;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
- box-shadow: none;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- -ms-box-sizing: border-box;
- box-sizing: border-box;
- resize: none; }
-
-.note-air-editor {
- outline: 0; }
-
-.note-popover .popover .popover-content,
-.note-toolbar {
- padding: 0;
- margin: 0; }
-
-.note-popover .popover .popover-content > .btn-group,
-.note-toolbar > .btn-group {
- margin-top: 0;
- margin-right: 5px;
- margin-left: 0; }
-
-.note-popover .popover .popover-content .btn-group .note-table,
-.note-toolbar .btn-group .note-table {
- min-width: 0;
- padding: 5px; }
-
-.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker,
-.note-toolbar .btn-group .note-table .note-dimension-picker {
- font-size: 18px; }
-
-.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker .note-dimension-picker-mousecatcher,
-.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-mousecatcher {
- position: absolute !important;
- z-index: 3;
- width: 260px;
- height: 260px;
- cursor: pointer; }
-
-.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker .note-dimension-picker-unhighlighted,
-.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-unhighlighted {
- position: relative !important;
- z-index: 1;
- width: 312px;
- height: 130px;
- background-size: 26px 26px;
- background-image: repeating-linear-gradient(0deg, #3b3b3b, #3b3b3b 4px, transparent 4px, transparent 26px), repeating-linear-gradient(-90deg, transparent, transparent 4px, #fff 4px, #fff 26px); }
-
-.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker .note-dimension-picker-highlighted,
-.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-highlighted {
- position: absolute !important;
- z-index: 2;
- width: 26px;
- height: 26px;
- background-size: 26px 26px;
- background-image: repeating-linear-gradient(0deg, #3b3b3b, #3b3b3b 4px, transparent 4px, transparent 26px), repeating-linear-gradient(-90deg, transparent, transparent 4px, #2196F3 4px, #2196F3 26px); }
-
-.note-popover .popover .popover-content .note-style h1,
-.note-toolbar .note-style h1,
-.note-popover .popover .popover-content .note-style h2,
-.note-toolbar .note-style h2,
-.note-popover .popover .popover-content .note-style h3,
-.note-toolbar .note-style h3,
-.note-popover .popover .popover-content .note-style h4,
-.note-toolbar .note-style h4,
-.note-popover .popover .popover-content .note-style h5,
-.note-toolbar .note-style h5,
-.note-popover .popover .popover-content .note-style h6,
-.note-toolbar .note-style h6,
-.note-popover .popover .popover-content .note-style blockquote,
-.note-toolbar .note-style blockquote {
- margin: 0; }
-
-.note-popover .popover .popover-content .note-color .dropdown-toggle,
-.note-toolbar .note-color .dropdown-toggle {
- width: 20px;
- padding-left: 5px; }
-
-.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group,
-.note-toolbar .note-color .dropdown-menu .btn-group {
- margin: 0; }
-
-.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group:first-child,
-.note-toolbar .note-color .dropdown-menu .btn-group:first-child {
- margin: 0 5px; }
-
-.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-palette-title,
-.note-toolbar .note-color .dropdown-menu .btn-group .note-palette-title {
- margin: 2px 7px;
- font-size: 12px;
- text-align: center;
- border-bottom: 1px solid #eee; }
-
-.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-reset,
-.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset {
- padding: 0 3px;
- margin: 3px;
- font-size: 11px;
- cursor: pointer;
- -webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px; }
-
-.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-row,
-.note-toolbar .note-color .dropdown-menu .btn-group .note-color-row {
- height: 20px; }
-
-.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-reset:hover,
-.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset:hover {
- background: #eee; }
-
-/*.note-popover .popover .popover-content .dropdown-menu,
-.note-toolbar .dropdown-menu {
- min-width: 90px
-}*/
-.note-popover .popover .popover-content .dropdown-menu.right,
-.note-toolbar .dropdown-menu.right {
- right: 0;
- left: auto; }
-
-.note-popover .popover .popover-content .dropdown-menu.right::before,
-.note-toolbar .dropdown-menu.right::before {
- right: 9px;
- left: auto !important; }
-
-.note-popover .popover .popover-content .dropdown-menu.right::after,
-.note-toolbar .dropdown-menu.right::after {
- right: 10px;
- left: auto !important; }
-
-.note-popover .popover .popover-content .dropdown-menu.note-check li a i,
-.note-toolbar .dropdown-menu.note-check li a i {
- color: deepskyblue;
- visibility: hidden; }
-
-.note-popover .popover .popover-content .dropdown-menu.note-check li a.checked i,
-.note-toolbar .dropdown-menu.note-check li a.checked i {
- visibility: visible; }
-
-.note-popover .popover .popover-content .note-fontsize-10,
-.note-toolbar .note-fontsize-10 {
- font-size: 10px; }
-
-/*# sourceMappingURL=materialNote.css.map */
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/css/materialNote.css.map b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/css/materialNote.css.map
deleted file mode 100644
index 9c59b74..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/css/materialNote.css.map
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-"version": 3,
-"mappings": "AAyXM,0BAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,oCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,0BAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,oCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,0BAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,oCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,0BAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,oCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,0BAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,oCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,gBAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,qBAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,yBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,mCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,yBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,mCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,yBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,mCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,yBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,mCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,IAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,SAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,aAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,uBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,aAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,uBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,aAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,uBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,aAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,uBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,aAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,uBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,aAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,uBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,aAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,uBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,aAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,uBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,KAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,UAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,OAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,YAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,sBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,gCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,sBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,gCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,sBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,gCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,sBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,gCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,sBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,gCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,YAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,iBAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,OAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,YAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,KAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,UAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,WAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,gBAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,oBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,8BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,oBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,8BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,oBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,8BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,oBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,8BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,oBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,8BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,oBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,8BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,oBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,8BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,oBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,8BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,KAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,UAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,KAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,UAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,MAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,WAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,sBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,gCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,sBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,gCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,sBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,gCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,sBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,gCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,sBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,gCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,YAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,iBAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,KAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,UAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,OAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,YAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,MAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,WAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,iBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,2BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,OAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,YAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,sBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,gCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,sBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,gCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,sBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,gCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,sBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,gCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,sBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,gCAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,YAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,iBAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,qBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,+BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,gBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,0BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,MAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,WAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,oBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,8BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,oBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,8BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,oBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,8BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,oBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,8BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,oBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,8BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,UAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,eAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,mBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,6BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,mBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,6BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,mBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,6BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,mBAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,6BAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,eAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,yBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAZhC,KAAgB;EACd,gBAAgB,EAAE,kBAAuB;;AAE3C,UAAqB;EACnB,KAAK,EAAE,kBAAuB;;AAIhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,cAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,wBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,aAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,uBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,aAA+B;EAC7B,gBAAgB,EAAE,kBAAuB;;AAE3C,uBAAyC;EACvC,KAAK,EAAE,kBAAuB;;AAJhC,mBAA+B;EAC7B,gBAAgB,EAAE,sBAAuB;;AAE3C,6BAAyC;EACvC,KAAK,EAAE,sBAAuB;;AAQpC,MAAW;EACT,gBAAgB,EAAE,kBAAuB;;AAE3C,WAAgB;EACd,KAAK,EAAE,kBAAuB;;AAJhC,MAAW;EACT,gBAAgB,EAAE,kBAAuB;;AAE3C,WAAgB;EACd,KAAK,EAAE,kBAAuB;;AAJhC,YAAW;EACT,gBAAgB,EAAE,sBAAuB;;AAE3C,iBAAgB;EACd,KAAK,EAAE,sBAAuB;;ACzYlC,gBAAgB;AAUhB,gBAAgB;AAGhB,iBAAiB;AAYjB,eAAe;AAMf,qBAAqB;AAKrB,kBAAkB;AAKlB,eAAe;AAIf,eAAe;AA8Bf,gBAAgB;AAqBhB,gBAAgB;AAMhB,iBAAiB;AAIjB,sBAAsB;AAKtB,cAAc;AAKd,gBAAgB;AAIhB,gBAAgB;AAKhB,oBAAoB;AAkBpB,qBAAqB;AAOrB,kBAAkB;ACnJlB;mFACmF;AAwBnF,0CAA2C;EACvC,gBAAgB,EAAE,KAA4B;EAC9C,KAAK,EAxBU,OAAyB;EAyBxC,OAAO,EAAE,eAAe;EACxB,mBAAmB,EAAE,MAAM;EAE3B,wNAAkE;IAC9D,YAAY,EAAE,kBAA4B;EAE9C,oYAAmI;IAC/H,UAAU,EAAE,4BAAqC;IACjD,YAAY,EAAE,kBAA2B;EAE7C,4dAAqI;IACjI,KAAK,EAAE,kBAA4B;EAEvC,whBAAwL;IACpL,KAAK,EAAE,kBAA2B;EAGtC,oDAAK;IACD,gBAAgB,EArCJ,OAAyB;IAsCrC,KAAK,EAAE,gBAA2C;EAEtD,gEAAW;IACP,gBAAgB,EAAE,kBAA2C;EAGjE,sEAAc;IACV,gBAAgB,EAAE,kBAA0C;EAGhE,sEAAc;IACV,gBAAgB,EAAE,OAA0B;IAE5C,0FAAU;MACN,YAAY,EAAE,IAAI;MAClB,gBAAgB,EAnDT,OAAwB;IAsDnC,sGAAgB;MACZ,gBAAgB,EAAE,kBAA0C;EAIpE,sFAAsB;IAClB,MAAM,EAAE,iBAA0B;;AAMtC,iQAAqB;EACjB,KAAK,EAAE,eAAe;AAE1B,+RAA2B;EACvB,gBAAgB,EAAE,kBAAwB;AAE9C,+RAA2B;EACvB,gBAAgB,EAAE,gBAAsC;AAE5D,6TAAiC;EAC7B,gBAAgB,EAAE,gBAAsC;;AAIhE,YAAa;EACT,QAAQ,EAAE,QAAQ;EAEd,WAAI,EAAE,iBAAuB;EAC7B,aAAM,EAAE,iBAAuB;EAC/B,YAAK,EAAE,iBAAuB;EAGlC,wBAAY;IACR,aAAa,EAAE,GAAG;EAGtB,yBAAa;IACT,aAAa,EAAE,EAAE;EAGrB,2BAAe;IACX,MAAM,EAAE,iBAAuB;IAC/B,MAAM,EAAE,KAAK;EAGjB,0BAAc;IACV,MAAM,EAAE,iBAAuB;EAGnC,uBAAW;IACP,gBAAgB,EAAE,kBAA0C;EAGhE,wBAAY;IACR,gBAAgB,EA3GN,OAAqB;EA+G/B,iCAAM;IACF,eAAe,EAAE,iBAAiB;IAClC,OAAO,EAAE,SAAS;IAClB,mBAAmB,EAAE,MAAM;EAK/B,+BAAQ;IACJ,OAAO,EAAE,IAAI;EAEjB,qCAAY;IACR,YAAY,EAAE,CAAC;IACf,WAAW,EAAE,CAAC;EAElB,0CAAiB;IACb,MAAM,EAAE,CAAC;EAEb,2DAAkC;IAC9B,UAAU,EAAE,KAAK;IACjB,aAAa,EAAE,IAAI;IACnB,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,CAAC;IACd,KAAK,EAAE,SAAS;IAChB,UAAU,EAAE,MAAM;IAClB,MAAM,EAAE,oBACZ;EAGJ,yBAAa;IACT,OAAO,EAAE,CAAC;EAGd,4BAAgB;IACZ,gBAAgB,EA5IF,OAA0B;IA6IxC,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,MAAM,EAAE,SAAS;IACjB,WAAW,EAAE,GAAG;IAEhB,2CAAe;MACX,KAAK,EAAE,IAAI;MACX,MAAM,EAAE,QAAQ;MAChB,UAAU,EAAE,eAAqC;EAIzD,0BAAc;IACV,QAAQ,EAAE,QAAQ;IAClB,KAAK,EA3KM,OAAyB;IA4KpC,gBAAgB,EA5JF,OAA0B;IA6JxC,MAAM,EAAE,CAAC;IACT,OAAO,EAAE,IAAI;IAEb,6BAAG;MACC,OAAO,EAAE,CAAC;IAGd,oFAA+B;MAC3B,OAAO,EAAE,IAAI;IAGjB,oCAAU;MACN,MAAM,EAAE,OAAO;IAGnB,iDAAuB;MACnB,SAAS,EAAE,KAAK;MAChB,OAAO,EAAE,YAAY;MACrB,UAAU,EAAE,IAAI;EAKpB,iDAAwB;IACpB,QAAQ,EAAE,QAAQ;IAClB,OAAO,EAAE,IAAI;IACb,MAAM,EAAE,iBAA2B;IAEnC,4EAA2B;MACvB,KAAK,EAAE,IAAI;MACX,MAAM,EAAE,IAAI;MACZ,OAAO,EAAE,CAAC;MACV,gBAAgB,EAAE,wBAAoC;IAG1D,uDAAQ;MACJ,QAAQ,EAAE,QAAQ;IAEtB,sEAAqB;MACjB,KAAK,EAAE,GAAG;MACV,MAAM,EAAE,GAAG;MACX,MAAM,EAAE,eAAe;IAE3B,sEAAqB;MACjB,KAAK,EAAE,GAAG;MACV,MAAM,EAAE,GAAG;MACX,MAAM,EAAE,eAAe;IAE3B,sEAAqB;MACjB,KAAK,EAAE,IAAI;MACX,MAAM,EAAE,IAAI;MACZ,gBAAgB,EAhNV,OAA0B;MAiNhC,OAAO,EAAE,CAAC;MACV,MAAM,EAAE,SAAS;IAErB,kEAAiB;MACb,GAAG,EAAE,IAAI;MACT,IAAI,EAAE,IAAI;MACV,YAAY,EAAE,CAAC;MACf,aAAa,EAAE,CAAC;IAEpB,kEAAiB;MACb,GAAG,EAAE,IAAI;MACT,KAAK,EAAE,IAAI;MACX,aAAa,EAAE,CAAC;MAChB,WAAW,EAAE,IAAI;IAErB,kEAAiB;MACb,MAAM,EAAE,IAAI;MACZ,IAAI,EAAE,IAAI;MACV,UAAU,EAAE,CAAC;MACb,YAAY,EAAE,CAAC;IAEnB,kEAAiB;MACb,KAAK,EAAE,IAAI;MACX,MAAM,EAAE,IAAI;IAEhB,8EAA6B;MACzB,KAAK,EAAE,CAAC;MACR,MAAM,EAAE,CAAC;MACT,OAAO,EAAE,GAAG;MACZ,MAAM,EAAE,IAAI;MACZ,SAAS,EAAE,IAAI;MACf,KAAK,EAhQF,OAAyB;MAiQ5B,gBAAgB,EAjPV,OAA0B;MAkPhC,OAAO,EAAE,CAAC;;AAM1B,8BAA+B;EAC3B,KAAK,EAzPa,OAA0B;EA2P5C,iCAAG;IACC,KAAK,EA5QM,OAAyB;EA+QxC,oCAAM;IACF,gBAAgB,EArQN,OAAqB;EAwQnC,oCAAM;IACF,gBAAgB,EApQF,OAA0B;;AAyQ5C,4CAAW;EACP,OAAO,EAAE,YAAY;EACrB,YAAY,EAAE,IAAI;EAClB,QAAQ,EAAE,QAAQ;EAElB,kDAAG;IACC,OAAO,EAAE,CAAC;EAGd,kEAAW;IACP,aAAa,EAAE,YAAY;IAC3B,YAAY,EAAE,YAAY;IAE1B,sEAAE;MACE,YAAY,EAAE,YAAY;EAIlC,0DAAO;IACH,YAAY,EAAE,GAAG;AAIzB,4DAAmB;EACf,aAAa,EAAE,YAAY;EAC3B,UAAU,EAAE,eAAe;EAC3B,OAAO,EAAE,gBAAgB;EACzB,gBAAgB,EApSF,OAA0B;AAuS5C,4CAAW;EACP,gBAAgB,EAAE,kBAA6B;AAGnD,0CAAU;EACN,gBAAgB,EAAE,kBAA4B;AAGlD,kKAAiD;EAC7C,gBAAgB,EAhTF,OAA0B;EAiTxC,MAAM,EAAE,IAAI;EACZ,MAAM,EAAE,IAAI;EACZ,cAAc,EAAE,SAAS;EACzB,KAAK,EAAE,kBAA4B;AAGvC,kNAAmF;EAC/E,kBAAkB,EAAE,kBAA6B;EACjD,mBAAmB,EAAE,kBAA6B;AAGtD,8DAAoB;EAChB,OAAO,EAAE,YAAY;AAGzB,4CAAW;EACP,OAAO,EAAE,YAAY;EACrB,KAAK,EAlVM,OAAyB;EAoVpC,yCAA0B;IAJ9B,4CAAW;MAKH,OAAO,EAAE,IAAI;AAIrB,8DAAoB;EAChB,WAAW,EAAE,IAAI;EACjB,MAAM,EAAE,iBAAuB;EAC/B,OAAO,EAAE,YAAY;EACrB,UAAU,EAAE,MAAM;EAClB,UAAU,EAAE,MAAM;EAElB,8FAAgB;IACZ,OAAO,EAAE,YAAY;IACrB,SAAS,EAAE,KAAK;EAGpB,0GAAsB;IAClB,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,OAAO,EAAE,CAAC;IACV,MAAM,EAAE,CAAC;EAIT,sHAAQ;IACJ,QAAQ,EAAE,QAAQ;IAClB,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,OAAO,EAAE,EAAE;IACX,gBAAgB,EAAE,OAAO;IACzB,UAAU,EAAE,KAAK;IACjB,WAAW,EAAE,KAAK;AAK9B,oEAAuB;EACnB,QAAQ,EAAE,MAAM;AAGpB,oDAAe;EACX,KAAK,EAAE,KAAK;AAGhB,oDAAe;EACX,OAAO,EAAE,IAAI;EAEb,0EAAa;IACT,SAAS,EAAE,IAAI;EAGnB,gEAAM;IACF,KAAK,EAAE,kBAA4B;AAI3C,wDAAiB;EACb,QAAQ,EAAE,QAAQ;EAClB,GAAG,EAAE,IAAI;EACT,gBAAgB,EAAE,OAA2B;EAEzC,WAAI,EAAE,iBAAuB;EAC7B,aAAM,EAAE,iBAAuB;EAC/B,YAAK,EAAE,iBAAuB;EAGlC,sEAAS;IACL,KAAK,EAAE,KAAK;IAEZ,4FAAW;MACP,KAAK,EAAE,GAAG;MACV,IAAI,EAAE,CAAC;EAIf,gFAAY;IACR,OAAO,EAAE,KAAK;EAGlB,oEAAM;IACF,gBAAgB,EArZN,OAA0B;IAuZpC,gFAAQ;MACJ,gBAAgB,EAxZV,OAA0B;IA2ZpC,kLAAqB;MACjB,KAAK,EAhaF,OAAqB;IAma5B,0FAAW;MACP,gBAAgB,EApab,OAAqB;EAwahC,8DAAG;IACC,eAAe,EAAE,IAAI;IACrB,OAAO,EAAE,YAAY;IAErB,sEAAI;MACA,OAAO,EAAE,QAAQ;MACjB,MAAM,EAAE,OAAO;;AAM/B,sBAAuB;EACnB,QAAQ,EAAE,QAAQ;EAClB,SAAS,EAAE,IAAI;EACf,KAAK,EAncU,OAAyB;EAqcxC,6BAAO;IACH,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,CAAC;IACT,YAAY,EAAE,KAAK;IACnB,YAAY,EAAE,gBAAgB;IAC9B,YAAY,EAAE,2CAAqD;EAGvE,uCAAiB;IACb,gBAAgB,EA9bF,OAA0B;IAgcxC,2CAAM;MACF,WAAW,EAAE,IAAI;IAGrB,yCAAE;MACE,OAAO,EAAE,YAAY;MACrB,SAAS,EAAE,KAAK;MAChB,QAAQ,EAAE,MAAM;MAChB,aAAa,EAAE,QAAQ;MACvB,WAAW,EAAE,MAAM;MACnB,cAAc,EAAE,MAAM;IAG1B,8CAAO;MACH,IAAI,EAAE,IAAI;IAGd,kDAAW;MACP,OAAO,EAAE,YAAY;MAErB,uDAAK;QACD,aAAa,EAAE,YAAY;QAC3B,UAAU,EAAE,eAAe;QAC3B,OAAO,EAAE,gBAAgB;QACzB,gBAAgB,EAxdV,OAA0B;QAydhC,KAAK,EAAE,kBAA4B;;AAMnD,0GAA2G;EACvG,SAAS,EAAE,KAAK;EAChB,OAAO,EAAE,GAAG;;AAEhB,8IAA+I;EAC3I,YAAY,EAAE,GAAG;;AAUrB,2BAA4B;EACxB,QAAQ,EAAE,QAAQ;EAClB,OAAO,EAAE,GAAG;EACZ,OAAO,EAAE,IAAI;EACb,KAAK,EAAE,OAAO;EACd,gBAAgB,EAAE,KAAK;EACvB,MAAM,EAAE,kBAAkB;EAC1B,OAAO,EAAE,GAAG;EACZ,aAAa,EAAE,IAAI;;AAEvB,kDAAmD;EAC/C,OAAO,EAAE,UAAU;EACnB,SAAS,EAAE,IAAI;EACf,WAAW,EAAE,IAAI;EACjB,UAAU,EAAE,MAAM;EAClB,cAAc,EAAE,MAAM;;AAE1B,iCAAkC;EAC9B,KAAK,EAAE,OAAO;EACd,MAAM,EAAE,kBACZ;;AACA,oCAAqC;EACjC,OAAO,EAAE,KAAK;;AAGlB,uBAAwB;EACpB,QAAQ,EAAE,KAAK;EACf,GAAG,EAAE,CAAC;EACN,IAAI,EAAE,CAAC;EACP,OAAO,EAAE,IAAI;EACb,KAAK,EAAE,IAAI;;AAEf,sCAAuC;EACnC,gBAAgB,EAAE,KAAK;;AAE3B,uCAAwC;EACpC,OAAO,EAAE,IAAI;;AAEjB,oCAAqC;EACjC,OAAO,EAAE,IAAI;;AAEjB,mCAAoC;EAChC,OAAO,EAAE,KAAK;;AAElB,4BAA6B;EACzB,gBAAgB,EAAE,OAAO;;AAE7B,0EAA2E;EACvE,KAAK,EAAE,OAAO;EACd,OAAO,EAAE,sBACb;;AACA,2BAA4B;EACxB,OAAO,EAAE,IAAI;EACb,QAAQ,EAAE,IAAI;EACd,OAAO,EAAE,CAAC;;AAEd,oDAAqD;EACjD,gBAAgB,EAAE,OAAO;;AAE7B,0BAA2B;EACvB,OAAO,EAAE,IAAI;EACb,KAAK,EAAE,IAAI;EACX,OAAO,EAAE,IAAI;EACb,aAAa,EAAE,CAAC;EAChB,WAAW,EAAE,oCAAoC;EACjD,SAAS,EAAE,IAAI;EACf,KAAK,EAAE,IAAI;EACX,gBAAgB,EAAE,IAAI;EACtB,MAAM,EAAE,CAAC;EACT,qBAAqB,EAAE,CAAC;EACxB,kBAAkB,EAAE,CAAC;EACrB,aAAa,EAAE,CAAC;EAChB,UAAU,EAAE,IAAI;EAChB,kBAAkB,EAAE,UAAU;EAC9B,eAAe,EAAE,UAAU;EAC3B,cAAc,EAAE,UAAU;EAC1B,UAAU,EAAE,UAAU;EACtB,MAAM,EAAE,IAAI;;AAEhB,gBAAiB;EACb,OAAO,EAAE,CAAC;;AAGd;aACc;EACV,OAAO,EAAE,CAAC;EACV,MAAM,EAAE,CAAC;;AAEb;0BAC2B;EACvB,UAAU,EAAE,CAAC;EACb,YAAY,EAAE,GAAG;EACjB,WAAW,EAAE,CAAC;;AAElB;oCACqC;EACjC,SAAS,EAAE,CAAC;EACZ,OAAO,EAAE,GAAG;;AAEhB;2DAC4D;EACxD,SAAS,EAAE,IAAI;;AAEnB;+FACgG;EAC5F,QAAQ,EAAE,mBAAkB;EAC5B,OAAO,EAAE,CAAC;EACV,KAAK,EAAE,KAAc;EACrB,MAAM,EAAC,KAAc;EACrB,MAAM,EAAE,OAAO;;AAEnB;gGACiG;EAC7F,QAAQ,EAAE,mBAAmB;EAC7B,OAAO,EAAE,CAAC;EACV,KAAK,EAAE,KAAc;EACrB,MAAM,EAAE,KAAa;EACrB,eAAe,EAAE,SAAS;EAC1B,gBAAgB,EAAC,8KACuE;;AAE5F;8FAC+F;EAC3F,QAAQ,EAAE,mBAAmB;EAC7B,OAAO,EAAE,CAAC;EACV,KAAK,EAxmBE,IAAI;EAymBX,MAAM,EAzmBC,IAAI;EA0mBX,eAAe,EAAE,SAAS;EAC1B,gBAAgB,EAAC,oLAC+F;;AAGpH;;;;;;;;;;;;;oCAaqC;EACjC,MAAM,EAAE,CAAC;;AAEb;0CAC2C;EACvC,KAAK,EAAE,IAAI;EACX,YAAY,EAAE,GAAG;;AAErB;mDACoD;EAChD,MAAM,EAAE,CAAC;;AAEb;+DACgE;EAC5D,MAAM,EAAE,KACZ;;AACA;uEACwE;EACpE,MAAM,EAAE,OAAO;EACf,SAAS,EAAE,IAAI;EACf,UAAU,EAAE,MAAM;EAClB,aAAa,EAAE,cACnB;;AACA;qEACsE;EAClE,OAAO,EAAE,KAAK;EACd,MAAM,EAAE,GAAG;EACX,SAAS,EAAE,IAAI;EACf,MAAM,EAAE,OAAO;EACf,qBAAqB,EAAE,GAAG;EAC1B,kBAAkB,EAAE,GAAG;EACvB,aAAa,EAAE,GAAG;;AAEtB;mEACoE;EAChE,MAAM,EAAE,IAAI;;AAEhB;2EAC4E;EACxE,UAAU,EAAE,IAAI;;AAEpB;;;GAGG;AACH;kCACmC;EAC/B,KAAK,EAAE,CAAC;EACR,IAAI,EAAE,IAAI;;AAEd;0CAC2C;EACvC,KAAK,EAAE,GAAG;EACV,IAAI,EAAE,eACV;;AACA;yCAC0C;EACtC,KAAK,EAAE,IAAI;EACX,IAAI,EAAE,eACV;;AACA;8CAC+C;EAC3C,KAAK,EAAE,WAAW;EAClB,UAAU,EAAE,MAAM;;AAEtB;sDACuD;EACnD,UAAU,EAAE,OAAO;;AAEvB;+BACgC;EAC5B,SAAS,EAAE,IAAI",
-"sources": ["../sass/components/_color.scss","../sass/components/_variables.scss","../sass/materialNote.scss"],
-"names": [],
-"file": "materialNote.css"
-} \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Bold.ttf b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Bold.ttf
deleted file mode 100644
index 68822ca..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Bold.woff b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Bold.woff
deleted file mode 100644
index 1f75afd..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Bold.woff
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Bold.woff2 b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Bold.woff2
deleted file mode 100644
index 350d1c3..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Bold.woff2
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Light.ttf b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Light.ttf
deleted file mode 100644
index aa45340..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Light.ttf
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Light.woff b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Light.woff
deleted file mode 100644
index 3480c6c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Light.woff
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Light.woff2 b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Light.woff2
deleted file mode 100644
index 9a4d98c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Light.woff2
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Medium.ttf b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Medium.ttf
deleted file mode 100644
index a3c1a1f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Medium.ttf
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Medium.woff b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Medium.woff
deleted file mode 100644
index 1186773..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Medium.woff
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Medium.woff2 b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Medium.woff2
deleted file mode 100644
index d10a592..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Medium.woff2
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Regular.ttf b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Regular.ttf
deleted file mode 100644
index 0e58508..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Regular.woff b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Regular.woff
deleted file mode 100644
index f823258..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Regular.woff
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Regular.woff2 b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Regular.woff2
deleted file mode 100644
index b7082ef..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Regular.woff2
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Thin.ttf b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Thin.ttf
deleted file mode 100644
index 8779333..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Thin.ttf
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Thin.woff b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Thin.woff
deleted file mode 100644
index 2a98c1e..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Thin.woff
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Thin.woff2 b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Thin.woff2
deleted file mode 100644
index a38025a..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Thin.woff2
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/js/ckMaterializeOverrides.js b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/js/ckMaterializeOverrides.js
deleted file mode 100644
index fd1b2db..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/js/ckMaterializeOverrides.js
+++ /dev/null
@@ -1,172 +0,0 @@
-(function ($) {
- $.fn.ckTooltip = function (options) {
- var timeout = null,
- counter = null,
- started = false,
- counterInterval = null,
- margin = 5;
-
- // Defaults
- var defaults = {
- delay: 350
- };
- options = $.extend(defaults, options);
-
- return this.each(function(){
- var origin = $(this);
-
- // Create Text span
- var tooltip_text = $('<span></span>').text(origin.attr('data-tooltip'));
-
- // Create tooltip
- var newTooltip = $('<div></div>');
- newTooltip.addClass('material-tooltip').append(tooltip_text);
- newTooltip.appendTo($('body'));
-
- var backdrop = $('<div></div>').addClass('backdrop');
- backdrop.appendTo(newTooltip);
- backdrop.css({ top: 0, left:0 });
-
- //Destroy previously binded events
- //$(this).off('mouseenter mouseleave');
-
- $.event.special.destroyed = {
- remove: function(o) {
- if (o.handler) {
- o.handler();
- }
- }
- };
- $(this).bind('destroyed', function() {
- newTooltip.remove();
- });
-
- // Mouse In
- $(this).on({
- mouseenter: function(e) {
- var tooltip_delay = origin.data("delay");
-
- tooltip_delay = (tooltip_delay === undefined || tooltip_delay === '') ? options.delay : tooltip_delay;
- counter = 0;
- counterInterval = setInterval(function(){
- counter += 10;
-
- if (counter >= tooltip_delay && started === false) {
- started = true;
- newTooltip.css({ display: 'block', left: '0px', top: '0px' });
-
- // Set Tooltip text
- newTooltip.children('span').text(origin.attr('data-tooltip'));
-
- // Tooltip positioning
- var originWidth = origin.outerWidth();
- var originHeight = origin.outerHeight();
- var tooltipPosition = origin.attr('data-position');
- var tooltipHeight = newTooltip.outerHeight();
- var tooltipWidth = newTooltip.outerWidth();
- var tooltipVerticalMovement = '0px';
- var tooltipHorizontalMovement = '0px';
- var scale_factor = 8;
-
- if (tooltipPosition === "top") {
- // Top Position
- newTooltip.css({
- top: origin.offset().top - tooltipHeight - margin,
- left: origin.offset().left + originWidth/2 - tooltipWidth/2
- });
- tooltipVerticalMovement = '-10px';
- backdrop.css({
- borderRadius: '14px 14px 0 0',
- transformOrigin: '50% 90%',
- marginTop: tooltipHeight,
- marginLeft: (tooltipWidth/2) - (backdrop.width()/2)
-
- });
- }
- // Left Position
- else if (tooltipPosition === "left") {
- newTooltip.css({
- top: origin.offset().top + originHeight/2 - tooltipHeight/2,
- left: origin.offset().left - tooltipWidth - margin
- });
- tooltipHorizontalMovement = '-10px';
- backdrop.css({
- width: '14px',
- height: '14px',
- borderRadius: '14px 0 0 14px',
- transformOrigin: '95% 50%',
- marginTop: tooltipHeight/2,
- marginLeft: tooltipWidth
- });
- }
- // Right Position
- else if (tooltipPosition === "right") {
- newTooltip.css({
- top: origin.offset().top + originHeight/2 - tooltipHeight/2,
- left: origin.offset().left + originWidth + margin
- });
- tooltipHorizontalMovement = '+10px';
- backdrop.css({
- width: '14px',
- height: '14px',
- borderRadius: '0 14px 14px 0',
- transformOrigin: '5% 50%',
- marginTop: tooltipHeight/2,
- marginLeft: '0px'
- });
- }
- else {
- // Bottom Position
- newTooltip.css({
- top: origin.offset().top + origin.outerHeight() + margin,
- left: origin.offset().left + originWidth/2 - tooltipWidth/2
- });
- tooltipVerticalMovement = '+10px';
- backdrop.css({
- marginLeft: (tooltipWidth/2) - (backdrop.width()/2)
- });
- }
-
- // Calculate Scale to fill
- scale_factor = tooltipWidth / 8;
- if (scale_factor < 8) {
- scale_factor = 8;
- }
- if (tooltipPosition === "right" || tooltipPosition === "left") {
- scale_factor = tooltipWidth / 10;
- if (scale_factor < 6)
- scale_factor = 6;
- }
-
- newTooltip.velocity({ opacity: 1, marginTop: tooltipVerticalMovement, marginLeft: tooltipHorizontalMovement}, { duration: 150, queue: false });
- backdrop.css({ display: 'block' })
- .velocity({opacity:1},{duration: 50, delay: 0, queue: false})
- .velocity({scale: scale_factor}, {duration: 150, delay: 0, queue: false, easing: 'easeInOutQuad'});
- }
- }, 10); // End Interval
-
- // Mouse Out
- },
- mouseleave: function(){
- // Reset State
- clearInterval(counterInterval);
- counter = 0;
-
- // Animate back
- newTooltip.velocity({
- opacity: 0, marginTop: 0, marginLeft: 0}, { duration: 150, queue: false, delay: 50 }
- );
- backdrop.velocity({opacity: 0, scale: 1}, {
- duration:150,
- delay: 50, queue: false,
- complete: function(){
- backdrop.css('display', 'none');
- newTooltip.css('display', 'none');
- started = false;}
- });
- }
- });
- });
- };
-
-}(jQuery));
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/js/materialNote.js b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/js/materialNote.js
deleted file mode 100644
index fbb01cf..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/js/materialNote.js
+++ /dev/null
@@ -1,7473 +0,0 @@
-/**
- * MaterialNote v1.2.1
- * Super simple wysiwyg editor on Materialize
- * a fork of materialnote.js => http://materialnote.org/
- *
- * original summernote credits:
- * summernote.js
- * Copyright 2013-2015 Alan Hong. and other contributors
- * summernote (and so materialNote) may be freely distributed under the MIT license./
- * (https://raw.githubusercontent.com/Cerealkillerway/materialNote/master/license.txt)
- *
- * edited by CK (http://www.web-forge.info)
- * thanks to Tox for code review (http://emanuele.itoscano.com/)
- */
-(function(factory) {
- /* global define */
- if (typeof define === 'function' && define.amd) {
- // AMD. Register as an anonymous module.
- define(['jquery'], factory);
- } else {
- // Browser globals: jQuery
- factory(window.jQuery);
- }
-}(function($) {
-
- if (!Array.prototype.reduce) {
- /**
- * Array.prototype.reduce polyfill
- * @param {Function} callback
- * @param {Value} [initialValue]
- * @return {Value}
- * @see http://goo.gl/WNriQD
- */
- Array.prototype.reduce = function(callback) {
- var t = Object(this), len = t.length >>> 0, k = 0, value;
-
- if (arguments.length === 2) {
- value = arguments[1];
- } else {
- while (k < len && !(k in t)) {
- k++;
- }
- if (k >= len) {
- throw new TypeError('Reduce of empty array with no initial value');
- }
- value = t[k++];
- }
- for (; k < len; k++) {
- if (k in t) {
- value = callback(value, t[k], k, t);
- }
- }
- return value;
- };
- }
-
- if ('function' !== typeof Array.prototype.filter) {
- /**
- * Array.prototype.filter polyfill
- * @param {Function} func
- * @return {Array}
- * @see http://goo.gl/T1KFnq
- */
- Array.prototype.filter = function(func) {
- var t = Object(this), len = t.length >>> 0;
- var res = [];
- var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
-
- for (var i = 0; i < len; i++) {
- if (i in t) {
- var val = t[i];
-
- if (func.call(thisArg, val, i, t)) {
- res.push(val);
- }
- }
- }
- return res;
- };
- }
-
-var isSupportAmd = typeof define === 'function' && define.amd;
-
-/**
-* returns whether font is installed or not.
-* @param {String} fontName
-* @return {Boolean}
-*/
-var isFontInstalled = function(fontName) {
- if (fontName === "Roboto") return true;
- var testFontName = fontName === 'Comic Sans MS' ? 'Courier New' : 'Comic Sans MS';
- var $tester = $('<div>').css({
- position: 'absolute',
- left: '-9999px',
- top: '-9999px',
- fontSize: '200px'
- }).text('mmmmmmmmmwwwwwww').appendTo(document.body);
-
- var originalWidth = $tester.css('fontFamily', testFontName).width();
- var width = $tester.css('fontFamily', fontName + ',' + testFontName).width();
-
- $tester.remove();
-
- return originalWidth !== width;
-};
-
-
-var userAgent = navigator.userAgent;
-
-/**
-* @class core.agent
-* Object which check platform and agent
-* @singleton
-* @alternateClassName agent
-*/
-var agent = {
- /** @property {Boolean} [isMac=false] true if this agent is Mac */
- isMac: navigator.appVersion.indexOf('Mac') > -1,
- /** @property {Boolean} [isMSIE=false] true if this agent is a Internet Explorer */
- isMSIE: /MSIE|Trident/i.test(userAgent),
- /** @property {Boolean} [isFF=false] true if this agent is a Firefox */
- isFF: /firefox/i.test(userAgent),
- isWebkit: /webkit/i.test(userAgent),
- /** @property {Boolean} [isSafari=false] true if this agent is a Safari */
- isSafari: /safari/i.test(userAgent),
- /** @property {String} jqueryVersion current jQuery version string */
- jqueryVersion: parseFloat($.fn.jquery),
- isSupportAmd: isSupportAmd,
- hasCodeMirror: isSupportAmd ? require.specified('CodeMirror') : !!window.CodeMirror,
- isFontInstalled: isFontInstalled,
- isW3CRangeSupport: !!document.createRange
-};
-
-/**
-* @class core.func
-* func utils (for high-order func's arg)
-* @singleton
-* @alternateClassName func
-*/
-var func = (function() {
- var eq = function(itemA) {
- return function(itemB) {
- return itemA === itemB;
- };
- };
-
- var eq2 = function(itemA, itemB) {
- return itemA === itemB;
- };
-
- var peq2 = function(propName) {
- return function(itemA, itemB) {
- return itemA[propName] === itemB[propName];
- };
- };
-
- var ok = function() {
- return true;
- };
-
- var fail = function() {
- return false;
- };
-
- var not = function(f) {
- return function() {
- return !f.apply(f, arguments);
- };
- };
-
- var and = function(fA, fB) {
- return function(item) {
- return fA(item) && fB(item);
- };
- };
-
- var self = function(a) {
- return a;
- };
-
- var idCounter = 0;
-
- /**
- * generate a globally-unique id
- * @param {String} [prefix]
- */
- var uniqueId = function(prefix) {
- var id = ++idCounter + '';
-
- return prefix ? prefix + id : id;
- };
-
- /**
- * returns bnd (bounds) from rect
- * - IE Compatibility Issue: http://goo.gl/sRLOAo
- * - Scroll Issue: http://goo.gl/sNjUc
- * @param {Rect} rect
- * @return {Object} bounds
- * @return {Number} bounds.top
- * @return {Number} bounds.left
- * @return {Number} bounds.width
- * @return {Number} bounds.height
- */
- var rect2bnd = function(rect) {
- var $document = $(document);
- return {
- top: rect.top + $document.scrollTop(),
- left: rect.left + $document.scrollLeft(),
- width: rect.right - rect.left,
- height: rect.bottom - rect.top
- };
- };
-
- /**
- * returns a copy of the object where the keys have become the values and the values the keys.
- * @param {Object} obj
- * @return {Object}
- */
- var invertObject = function(obj) {
- var inverted = {};
-
- for (var key in obj) {
- if (obj.hasOwnProperty(key)) {
- inverted[obj[key]] = key;
- }
- }
- return inverted;
- };
-
- /**
- * @param {String} namespace
- * @param {String} [prefix]
- * @return {String}
- */
- var namespaceToCamel = function(namespace, prefix) {
- prefix = prefix || '';
- return prefix + namespace.split('.').map(function(name) {
- return name.substring(0, 1).toUpperCase() + name.substring(1);
- }).join('');
- };
-
- return {
- eq: eq,
- eq2: eq2,
- peq2: peq2,
- ok: ok,
- fail: fail,
- self: self,
- not: not,
- and: and,
- uniqueId: uniqueId,
- rect2bnd: rect2bnd,
- invertObject: invertObject,
- namespaceToCamel: namespaceToCamel
- };
-})(); //end func
-
-
-/**
-* @class core.list
-* list utils
-* @singleton
-* @alternateClassName list
-*/
-var list = (function() {
- /**
- * returns the first item of an array.
- * @param {Array} array
- */
- var head = function(array) {
- return array[0];
- };
-
- /**
- * returns the last item of an array.
- * @param {Array} array
- */
- var last = function(array) {
- return array[array.length - 1];
- };
-
- /**
- * returns everything but the last entry of the array.
- * @param {Array} array
- */
- var initial = function(array) {
- return array.slice(0, array.length - 1);
- };
-
- /**
- * returns the rest of the items in an array.
- * @param {Array} array
- */
- var tail = function(array) {
- return array.slice(1);
- };
-
- /**
- * returns item of array
- */
- var find = function(array, pred) {
- for (var idx = 0, len = array.length; idx < len; idx ++) {
- var item = array[idx];
-
- if (pred(item)) {
- return item;
- }
- }
- };
-
- /**
- * returns true if all of the values in the array pass the predicate truth test.
- */
- var all = function(array, pred) {
- for (var idx = 0, len = array.length; idx < len; idx ++) {
- if (!pred(array[idx])) {
- return false;
- }
- }
- return true;
- };
-
- /**
- * returns true if the value is present in the list.
- */
- var contains = function(array, item) {
- return $.inArray(item, array) !== -1;
- };
-
- /**
- * get sum from a list
- * @param {Array} array - array
- * @param {Function} fn - iterator
- */
- var sum = function(array, fn) {
- fn = fn || func.self;
- return array.reduce(function(memo, v) {
- return memo + fn(v);
- }, 0);
- };
-
- /**
- * returns a copy of the collection with array type.
- * @param {Collection} collection - collection eg) node.childNodes, ...
- */
- var from = function(collection) {
- var result = [], idx = -1, length = collection.length;
- while (++idx < length) {
- result[idx] = collection[idx];
- }
- return result;
- };
-
- /**
- * cluster elements by predicate function.
- * @param {Array} array - array
- * @param {Function} fn - predicate function for cluster rule
- * @param {Array[]}
- */
- var clusterBy = function(array, fn) {
- if (!array.length) { return []; }
- var aTail = tail(array);
-
- return aTail.reduce(function(memo, v) {
- var aLast = last(memo);
- if (fn(last(aLast), v)) {
- aLast[aLast.length] = v;
- } else {
- memo[memo.length] = [v];
- }
- return memo;
- }, [[head(array)]]);
- };
-
- /**
- * returns a copy of the array with all falsy values removed
- * @param {Array} array - array
- * @param {Function} fn - predicate function for cluster rule
- */
- var compact = function(array) {
- var aResult = [];
-
- for (var idx = 0, len = array.length; idx < len; idx ++) {
- if (array[idx]) { aResult.push(array[idx]); }
- }
- return aResult;
- };
-
- /**
- * produces a duplicate-free version of the array
- * @param {Array} array
- */
- var unique = function(array) {
- var results = [];
-
- for (var idx = 0, len = array.length; idx < len; idx ++) {
- if (!contains(results, array[idx])) {
- results.push(array[idx]);
- }
- }
- return results;
- };
-
- /**
- * returns next item.
- * @param {Array} array
- */
- var next = function(array, item) {
- var idx = array.indexOf(item);
-
- if (idx === -1) {return null;}
- return array[idx + 1];
- };
-
- /**
- * returns prev item.
- * @param {Array} array
- */
- var prev = function(array, item) {
- var idx = array.indexOf(item);
-
- if (idx === -1) {return null;}
- return array[idx - 1];
- };
-
-
- return {head: head, last: last, initial: initial, tail: tail, prev: prev, next: next, find: find, contains: contains, all: all, sum: sum, from: from, clusterBy: clusterBy, compact: compact, unique: unique};
-})(); //end list
-
-
-var NBSP_CHAR = String.fromCharCode(160);
-var ZERO_WIDTH_NBSP_CHAR = '\ufeff';
-
-/**
-* @class core.dom
-* Dom functions
-* @singleton
-* @alternateClassName dom
-*/
-var dom = (function() {
- /**
- * @method isEditable
- * returns whether node is `note-editable` or not.
- * @param {Node} node
- * @return {Boolean}
- */
- var isEditable = function(node) {
- return node && $(node).hasClass('note-editable');
- };
-
- /**
- * @method isControlSizing
- * returns whether node is `note-control-sizing` or not.
- * @param {Node} node
- * @return {Boolean}
- */
- var isControlSizing = function(node) {
- return node && $(node).hasClass('note-control-sizing');
- };
-
- /**
- * @method buildLayoutInfo
- * build layoutInfo from $editor(.note-editor)
- * @param {jQuery} $editor
- * @return {Object}
- * @return {Function} return.editor
- * @return {Node} return.dropzone
- * @return {Node} return.toolbar
- * @return {Node} return.editable
- * @return {Node} return.codable
- * @return {Node} return.popover
- * @return {Node} return.handle
- * @return {Node} return.dialog
- */
- var buildLayoutInfo = function($editor) {
- var makeFinder;
-
- // air mode
- if ($editor.hasClass('note-air-editor')) {
- var id = list.last($editor.attr('id').split('-'));
-
- makeFinder = function(sIdPrefix) {
- return function() { return $(sIdPrefix + id); };
- };
-
- return {
- editor: function() { return $editor; },
- holder : function() { return $editor.data('holder'); },
- editable: function() { return $editor; },
- popover: makeFinder('#note-popover-'),
- handle: makeFinder('#note-handle-'),
- dialog: makeFinder('#note-dialog-')
- };
- // frame mode
- } else {
- makeFinder = function(sClassName) {
- return function() { return $editor.find(sClassName); };
- };
- return {
- editor: function() { return $editor; },
- holder : function() { return $editor.data('holder'); },
- dropzone: makeFinder('.note-dropzone'),
- toolbar: makeFinder('.note-toolbar'),
- editable: makeFinder('.note-editable'),
- codable: makeFinder('.note-codable'),
- statusbar: makeFinder('.note-statusbar'),
- popover: makeFinder('.note-popover'),
- handle: makeFinder('.note-handle'),
- dialog: makeFinder('.note-dialog')
- };
- }
- };
-
- /**
- * returns makeLayoutInfo from editor's descendant node.
- * @private
- * @param {Node} descendant
- * @return {Object}
- */
- var makeLayoutInfo = function(descendant) {
- var $target = $(descendant).closest('.note-editor, .note-air-editor, .note-air-layout');
-
- if (!$target.length) {
- return null;
- }
- var $editor;
-
- if ($target.is('.note-editor, .note-air-editor')) {
- $editor = $target;
- } else {
- $editor = $('#note-editor-' + list.last($target.attr('id').split('-')));
- }
- return buildLayoutInfo($editor);
- };
-
- /**
- * @method makePredByNodeName
- * returns predicate which judge whether nodeName is same
- * @param {String} nodeName
- * @return {Function}
- */
- var makePredByNodeName = function(nodeName) {
- nodeName = nodeName.toUpperCase();
- return function(node) {
- return node && node.nodeName.toUpperCase() === nodeName;
- };
- };
-
- /**
- * @method isText
- * @param {Node} node
- * @return {Boolean} true if node's type is text(3)
- */
- var isText = function(node) {
- return node && node.nodeType === 3;
- };
-
- /**
- * ex) br, col, embed, hr, img, input, ...
- * @see http://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
- */
- var isVoid = function(node) {
- return node && /^BR|^IMG|^HR/.test(node.nodeName.toUpperCase());
- };
-
- var isPara = function(node) {
- if (isEditable(node)) {
- return false;
- }
- // Chrome(v31.0), FF(v25.0.1) use DIV for paragraph
- return node && /^DIV|^P|^LI|^H[1-7]/.test(node.nodeName.toUpperCase());
- };
-
- var isLi = makePredByNodeName('LI');
-
- var isPurePara = function(node) {
- return isPara(node) && !isLi(node);
- };
-
- var isTable = makePredByNodeName('TABLE');
-
- var isInline = function(node) {
- return !isBodyContainer(node) && !isList(node) && !isPara(node) && !isTable(node) && !isBlockquote(node);
- };
-
- var isList = function(node) {
- return node && /^UL|^OL/.test(node.nodeName.toUpperCase());
- };
-
- var isCell = function(node) {
- return node && /^TD|^TH/.test(node.nodeName.toUpperCase());
- };
-
- var isBlockquote = makePredByNodeName('BLOCKQUOTE');
-
- var isBodyContainer = function(node) {
- return isCell(node) || isBlockquote(node) || isEditable(node);
- };
-
- var isAnchor = makePredByNodeName('A');
-
- var isParaInline = function(node) {
- return isInline(node) && !!ancestor(node, isPara);
- };
-
- var isBodyInline = function(node) {
- return isInline(node) && !ancestor(node, isPara);
- };
-
- var isBody = makePredByNodeName('BODY');
-
- /**
- * returns whether nodeB is closest sibling of nodeA
- * @param {Node} nodeA
- * @param {Node} nodeB
- * @return {Boolean}
- */
- var isClosestSibling = function(nodeA, nodeB) {
- return nodeA.nextSibling === nodeB || nodeA.previousSibling === nodeB;
- };
-
- /**
- * returns array of closest siblings with node
- * @param {Node} node
- * @param {function} [pred] - predicate function
- * @return {Node[]}
- */
- var withClosestSiblings = function(node, pred) {
- pred = pred || func.ok;
- var siblings = [];
-
- if (node.previousSibling && pred(node.previousSibling)) {
- siblings.push(node.previousSibling);
- }
- siblings.push(node);
- if (node.nextSibling && pred(node.nextSibling)) {
- siblings.push(node.nextSibling);
- }
- return siblings;
- };
-
- /**
- * blank HTML for cursor position
- * - [workaround] for MSIE IE doesn't works with bogus br
- */
- var blankHTML = agent.isMSIE ? '&nbsp;' : '<br>';
-
- /**
- * @method nodeLength
- * returns #text's text size or element's childNodes size
- * @param {Node} node
- */
- var nodeLength = function(node) {
- if (isText(node)) {
- return node.nodeValue.length;
- }
- return node.childNodes.length;
- };
-
- /**
- * returns whether node is empty or not.
- * @param {Node} node
- * @return {Boolean}
- */
- var isEmpty = function(node) {
- var len = nodeLength(node);
-
- if (len === 0) {
- return true;
- } else if (!isText(node) && len === 1 && node.innerHTML === blankHTML) {
- return true;
- } else if (list.all(node.childNodes, isText) && node.innerHTML === '') {
- return true;
- }
- return false;
- };
-
- /**
- * padding blankHTML if node is empty (for cursor position)
- */
- var paddingBlankHTML = function(node) {
- if (!isVoid(node) && !nodeLength(node)) {
- node.innerHTML = blankHTML;
- }
- };
-
- /**
- * find nearest ancestor predicate hit
- *
- * @param {Node} node
- * @param {Function} pred - predicate function
- */
- var ancestor = function(node, pred) {
- while (node) {
- if (pred(node)) { return node; }
- if (isEditable(node)) { break; }
-
- node = node.parentNode;
- }
- return null;
- };
-
- /**
- * find nearest ancestor only single child blood line and predicate hit
- *
- * @param {Node} node
- * @param {Function} pred - predicate function
- */
- var singleChildAncestor = function(node, pred) {
- node = node.parentNode;
-
- while (node) {
- if (nodeLength(node) !== 1) { break; }
- if (pred(node)) { return node; }
- if (isEditable(node)) { break; }
-
- node = node.parentNode;
- }
- return null;
- };
-
- /**
- * returns new array of ancestor nodes (until predicate hit).
- *
- * @param {Node} node
- * @param {Function} [optional] pred - predicate function
- */
- var listAncestor = function(node, pred) {
- pred = pred || func.fail;
-
- var ancestors = [];
- ancestor(node, function(el) {
- if (!isEditable(el)) {
- ancestors.push(el);
- }
-
- return pred(el);
- });
- return ancestors;
- };
-
- /**
- * find farthest ancestor predicate hit
- */
- var lastAncestor = function(node, pred) {
- var ancestors = listAncestor(node);
- return list.last(ancestors.filter(pred));
- };
-
- /**
- * returns common ancestor node between two nodes.
- *
- * @param {Node} nodeA
- * @param {Node} nodeB
- */
- var commonAncestor = function(nodeA, nodeB) {
- var ancestors = listAncestor(nodeA);
- for (var n = nodeB; n; n = n.parentNode) {
- if ($.inArray(n, ancestors) > -1) { return n; }
- }
- return null; // difference document area
- };
-
- /**
- * listing all previous siblings (until predicate hit).
- *
- * @param {Node} node
- * @param {Function} [optional] pred - predicate function
- */
- var listPrev = function(node, pred) {
- pred = pred || func.fail;
-
- var nodes = [];
- while (node) {
- if (pred(node)) { break; }
- nodes.push(node);
- node = node.previousSibling;
- }
- return nodes;
- };
-
- /**
- * listing next siblings (until predicate hit).
- *
- * @param {Node} node
- * @param {Function} [pred] - predicate function
- */
- var listNext = function(node, pred) {
- pred = pred || func.fail;
-
- var nodes = [];
- while (node) {
- if (pred(node)) { break; }
- nodes.push(node);
- node = node.nextSibling;
- }
- return nodes;
- };
-
- /**
- * listing descendant nodes
- *
- * @param {Node} node
- * @param {Function} [pred] - predicate function
- */
- var listDescendant = function(node, pred) {
- var descendents = [];
- pred = pred || func.ok;
-
- // start DFS(depth first search) with node
- (function fnWalk(current) {
- if (node !== current && pred(current)) {
- descendents.push(current);
- }
- for (var idx = 0, len = current.childNodes.length; idx < len; idx++) {
- fnWalk(current.childNodes[idx]);
- }
- })(node);
-
- return descendents;
- };
-
- /**
- * wrap node with new tag.
- *
- * @param {Node} node
- * @param {Node} tagName of wrapper
- * @return {Node} - wrapper
- */
- var wrap = function(node, wrapperName) {
- var parent = node.parentNode;
- var wrapper = $('<' + wrapperName + '>')[0];
-
- parent.insertBefore(wrapper, node);
- wrapper.appendChild(node);
-
- return wrapper;
- };
-
- /**
- * insert node after preceding
- *
- * @param {Node} node
- * @param {Node} preceding - predicate function
- */
- var insertAfter = function(node, preceding) {
- var next = preceding.nextSibling, parent = preceding.parentNode;
- if (next) {
- parent.insertBefore(node, next);
- } else {
- parent.appendChild(node);
- }
- return node;
- };
-
- /**
- * append elements.
- *
- * @param {Node} node
- * @param {Collection} aChild
- */
- var appendChildNodes = function(node, aChild) {
- $.each(aChild, function(idx, child) {
- node.appendChild(child);
- });
- return node;
- };
-
- /**
- * returns whether boundaryPoint is left edge or not.
- *
- * @param {BoundaryPoint} point
- * @return {Boolean}
- */
- var isLeftEdgePoint = function(point) {
- return point.offset === 0;
- };
-
- /**
- * returns whether boundaryPoint is right edge or not.
- *
- * @param {BoundaryPoint} point
- * @return {Boolean}
- */
- var isRightEdgePoint = function(point) {
- return point.offset === nodeLength(point.node);
- };
-
- /**
- * returns whether boundaryPoint is edge or not.
- *
- * @param {BoundaryPoint} point
- * @return {Boolean}
- */
- var isEdgePoint = function(point) {
- return isLeftEdgePoint(point) || isRightEdgePoint(point);
- };
-
- /**
- * returns wheter node is left edge of ancestor or not.
- *
- * @param {Node} node
- * @param {Node} ancestor
- * @return {Boolean}
- */
- var isLeftEdgeOf = function(node, ancestor) {
- while (node && node !== ancestor) {
- if (position(node) !== 0) {
- return false;
- }
- node = node.parentNode;
- }
-
- return true;
- };
-
- /**
- * returns whether node is right edge of ancestor or not.
- *
- * @param {Node} node
- * @param {Node} ancestor
- * @return {Boolean}
- */
- var isRightEdgeOf = function(node, ancestor) {
- while (node && node !== ancestor) {
- if (position(node) !== nodeLength(node.parentNode) - 1) {
- return false;
- }
- node = node.parentNode;
- }
-
- return true;
- };
-
- /**
- * returns offset from parent.
- *
- * @param {Node} node
- */
- var position = function(node) {
- var offset = 0;
- while ((node = node.previousSibling)) {
- offset += 1;
- }
- return offset;
- };
-
- var hasChildren = function(node) {
- return !!(node && node.childNodes && node.childNodes.length);
- };
-
- /**
- * returns previous boundaryPoint
- *
- * @param {BoundaryPoint} point
- * @param {Boolean} isSkipInnerOffset
- * @return {BoundaryPoint}
- */
- var prevPoint = function(point, isSkipInnerOffset) {
- var node, offset;
-
- if (point.offset === 0) {
- if (isEditable(point.node)) {
- return null;
- }
-
- node = point.node.parentNode;
- offset = position(point.node);
- } else if (hasChildren(point.node)) {
- node = point.node.childNodes[point.offset - 1];
- offset = nodeLength(node);
- } else {
- node = point.node;
- offset = isSkipInnerOffset ? 0 : point.offset - 1;
- }
-
- return {
- node: node,
- offset: offset
- };
- };
-
- /**
- * returns next boundaryPoint
- *
- * @param {BoundaryPoint} point
- * @param {Boolean} isSkipInnerOffset
- * @return {BoundaryPoint}
- */
- var nextPoint = function(point, isSkipInnerOffset) {
- var node, offset;
-
- if (nodeLength(point.node) === point.offset) {
- if (isEditable(point.node)) {
- return null;
- }
-
- node = point.node.parentNode;
- offset = position(point.node) + 1;
- } else if (hasChildren(point.node)) {
- node = point.node.childNodes[point.offset];
- offset = 0;
- } else {
- node = point.node;
- offset = isSkipInnerOffset ? nodeLength(point.node) : point.offset + 1;
- }
-
- return {
- node: node,
- offset: offset
- };
- };
-
- /**
- * returns whether pointA and pointB is same or not.
- *
- * @param {BoundaryPoint} pointA
- * @param {BoundaryPoint} pointB
- * @return {Boolean}
- */
- var isSamePoint = function(pointA, pointB) {
- return pointA.node === pointB.node && pointA.offset === pointB.offset;
- };
-
- /**
- * returns whether point is visible (can set cursor) or not.
- *
- * @param {BoundaryPoint} point
- * @return {Boolean}
- */
- var isVisiblePoint = function(point) {
- if (isText(point.node) || !hasChildren(point.node) || isEmpty(point.node)) {
- return true;
- }
-
- var leftNode = point.node.childNodes[point.offset - 1];
- var rightNode = point.node.childNodes[point.offset];
- if ((!leftNode || isVoid(leftNode)) && (!rightNode || isVoid(rightNode))) {
- return true;
- }
-
- return false;
- };
-
- /**
- * @method prevPointUtil
- *
- * @param {BoundaryPoint} point
- * @param {Function} pred
- * @return {BoundaryPoint}
- */
- var prevPointUntil = function(point, pred) {
- while (point) {
- if (pred(point)) {
- return point;
- }
-
- point = prevPoint(point);
- }
-
- return null;
- };
-
- /**
- * @method nextPointUntil
- *
- * @param {BoundaryPoint} point
- * @param {Function} pred
- * @return {BoundaryPoint}
- */
- var nextPointUntil = function(point, pred) {
- while (point) {
- if (pred(point)) {
- return point;
- }
-
- point = nextPoint(point);
- }
-
- return null;
- };
-
- /**
- * returns whether point has character or not.
- *
- * @param {Point} point
- * @return {Boolean}
- */
- var isCharPoint = function(point) {
- if (!isText(point.node)) {
- return false;
- }
-
- var ch = point.node.nodeValue.charAt(point.offset - 1);
- return ch && (ch !== ' ' && ch !== NBSP_CHAR);
- };
-
- /**
- * @method walkPoint
- *
- * @param {BoundaryPoint} startPoint
- * @param {BoundaryPoint} endPoint
- * @param {Function} handler
- * @param {Boolean} isSkipInnerOffset
- */
- var walkPoint = function(startPoint, endPoint, handler, isSkipInnerOffset) {
- var point = startPoint;
-
- while (point) {
- handler(point);
-
- if (isSamePoint(point, endPoint)) {
- break;
- }
-
- var isSkipOffset = isSkipInnerOffset &&
- startPoint.node !== point.node &&
- endPoint.node !== point.node;
- point = nextPoint(point, isSkipOffset);
- }
- };
-
- /**
- * @method makeOffsetPath
- *
- * return offsetPath(array of offset) from ancestor
- *
- * @param {Node} ancestor - ancestor node
- * @param {Node} node
- */
- var makeOffsetPath = function(ancestor, node) {
- var ancestors = listAncestor(node, func.eq(ancestor));
- return $.map(ancestors, position).reverse();
- };
-
- /**
- * @method fromOffsetPath
- *
- * return element from offsetPath(array of offset)
- *
- * @param {Node} ancestor - ancestor node
- * @param {array} offsets - offsetPath
- */
- var fromOffsetPath = function(ancestor, offsets) {
- var current = ancestor;
- for (var i = 0, len = offsets.length; i < len; i++) {
- if (current.childNodes.length <= offsets[i]) {
- current = current.childNodes[current.childNodes.length - 1];
- } else {
- current = current.childNodes[offsets[i]];
- }
- }
- return current;
- };
-
- /**
- * @method splitNode
- *
- * split element or #text
- *
- * @param {BoundaryPoint} point
- * @param {Object} [options]
- * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false
- * @param {Boolean} [options.isNotSplitEdgePoint] - default: false
- * @return {Node} right node of boundaryPoint
- */
- var splitNode = function(point, options) {
- var isSkipPaddingBlankHTML = options && options.isSkipPaddingBlankHTML;
- var isNotSplitEdgePoint = options && options.isNotSplitEdgePoint;
-
- // edge case
- if (isEdgePoint(point) && (isText(point.node) || isNotSplitEdgePoint)) {
- if (isLeftEdgePoint(point)) {
- return point.node;
- } else if (isRightEdgePoint(point)) {
- return point.node.nextSibling;
- }
- }
-
- // split #text
- if (isText(point.node)) {
- return point.node.splitText(point.offset);
- } else {
- var childNode = point.node.childNodes[point.offset];
- var clone = insertAfter(point.node.cloneNode(false), point.node);
- appendChildNodes(clone, listNext(childNode));
-
- if (!isSkipPaddingBlankHTML) {
- paddingBlankHTML(point.node);
- paddingBlankHTML(clone);
- }
-
- return clone;
- }
- };
-
- /**
- * @method splitTree
- *
- * split tree by point
- *
- * @param {Node} root - split root
- * @param {BoundaryPoint} point
- * @param {Object} [options]
- * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false
- * @param {Boolean} [options.isNotSplitEdgePoint] - default: false
- * @return {Node} right node of boundaryPoint
- */
- var splitTree = function(root, point, options) {
- // ex) [#text, <span>, <p>]
- var ancestors = listAncestor(point.node, func.eq(root));
-
- if (!ancestors.length) {
- return null;
- } else if (ancestors.length === 1) {
- return splitNode(point, options);
- }
-
- return ancestors.reduce(function(node, parent) {
- if (node === point.node) {
- node = splitNode(point, options);
- }
-
- return splitNode({
- node: parent,
- offset: node ? dom.position(node) : nodeLength(parent)
- }, options);
- });
- };
-
- /**
- * split point
- *
- * @param {Point} point
- * @param {Boolean} isInline
- * @return {Object}
- */
- var splitPoint = function(point, isInline) {
- // find splitRoot, container
- // - inline: splitRoot is a child of paragraph
- // - block: splitRoot is a child of bodyContainer
- var pred = isInline ? isPara : isBodyContainer;
- var ancestors = listAncestor(point.node, pred);
- var topAncestor = list.last(ancestors) || point.node;
-
- var splitRoot, container;
- if (pred(topAncestor)) {
- splitRoot = ancestors[ancestors.length - 2];
- container = topAncestor;
- } else {
- splitRoot = topAncestor;
- container = splitRoot.parentNode;
- }
-
- // if splitRoot is exists, split with splitTree
- var pivot = splitRoot && splitTree(splitRoot, point, {
- isSkipPaddingBlankHTML: isInline,
- isNotSplitEdgePoint: isInline
- });
-
- // if container is point.node, find pivot with point.offset
- if (!pivot && container === point.node) {
- pivot = point.node.childNodes[point.offset];
- }
-
- return {
- rightNode: pivot,
- container: container
- };
- };
-
- var create = function(nodeName) {
- return document.createElement(nodeName);
- };
-
- var createText = function(text) {
- return document.createTextNode(text);
- };
-
- /**
- * @method remove
- *
- * remove node, (isRemoveChild: remove child or not)
- *
- * @param {Node} node
- * @param {Boolean} isRemoveChild
- */
- var remove = function(node, isRemoveChild) {
- if (!node || !node.parentNode) { return; }
- if (node.removeNode) { return node.removeNode(isRemoveChild); }
-
- var parent = node.parentNode;
- if (!isRemoveChild) {
- var nodes = [];
- var i, len;
- for (i = 0, len = node.childNodes.length; i < len; i++) {
- nodes.push(node.childNodes[i]);
- }
-
- for (i = 0, len = nodes.length; i < len; i++) {
- parent.insertBefore(nodes[i], node);
- }
- }
-
- parent.removeChild(node);
- };
-
- /**
- * @method removeWhile
- *
- * @param {Node} node
- * @param {Function} pred
- */
- var removeWhile = function(node, pred) {
- while (node) {
- if (isEditable(node) || !pred(node)) {
- break;
- }
-
- var parent = node.parentNode;
- remove(node);
- node = parent;
- }
- };
-
- /**
- * @method replace
- *
- * replace node with provided nodeName
- *
- * @param {Node} node
- * @param {String} nodeName
- * @return {Node} - new node
- */
- var replace = function(node, nodeName) {
- if (node.nodeName.toUpperCase() === nodeName.toUpperCase()) {
- return node;
- }
-
- var newNode = create(nodeName);
-
- if (node.style.cssText) {
- newNode.style.cssText = node.style.cssText;
- }
-
- appendChildNodes(newNode, list.from(node.childNodes));
- insertAfter(newNode, node);
- remove(node);
-
- return newNode;
- };
-
- var isTextarea = makePredByNodeName('TEXTAREA');
-
- /**
- * @param {jQuery} $node
- * @param {Boolean} [stripLinebreaks] - default: false
- */
- var value = function($node, stripLinebreaks) {
- var val = isTextarea($node[0]) ? $node.val() : $node.html();
- if (stripLinebreaks) {
- return val.replace(/[\n\r]/g, '');
- }
- return val;
- };
-
- /**
- * @method html
- *
- * get the HTML contents of node
- *
- * @param {jQuery} $node
- * @param {Boolean} [isNewlineOnBlock]
- */
- var html = function($node, isNewlineOnBlock) {
- var markup = value($node);
-
- if (isNewlineOnBlock) {
- var regexTag = /<(\/?)(\b(?!!)[^>\s]*)(.*?)(\s*\/?>)/g;
- markup = markup.replace(regexTag, function(match, endSlash, name) {
- name = name.toUpperCase();
- var isEndOfInlineContainer = /^DIV|^TD|^TH|^P|^LI|^H[1-7]/.test(name) &&
- !!endSlash;
- var isBlockNode = /^BLOCKQUOTE|^TABLE|^TBODY|^TR|^HR|^UL|^OL/.test(name);
-
- return match + ((isEndOfInlineContainer || isBlockNode) ? '\n' : '');
- });
- markup = $.trim(markup);
- }
-
- return markup;
- };
-
- return {
- /** @property {String} NBSP_CHAR */
- NBSP_CHAR: NBSP_CHAR,
- /** @property {String} ZERO_WIDTH_NBSP_CHAR */
- ZERO_WIDTH_NBSP_CHAR: ZERO_WIDTH_NBSP_CHAR,
- /** @property {String} blank */
- blank: blankHTML,
- /** @property {String} emptyPara */
- emptyPara: '<p>' + blankHTML + '</p>',
- makePredByNodeName: makePredByNodeName,
- isEditable: isEditable,
- isControlSizing: isControlSizing,
- buildLayoutInfo: buildLayoutInfo,
- makeLayoutInfo: makeLayoutInfo,
- isText: isText,
- isVoid: isVoid,
- isPara: isPara,
- isPurePara: isPurePara,
- isInline: isInline,
- isBlock: func.not(isInline),
- isBodyInline: isBodyInline,
- isBody: isBody,
- isParaInline: isParaInline,
- isList: isList,
- isTable: isTable,
- isCell: isCell,
- isBlockquote: isBlockquote,
- isBodyContainer: isBodyContainer,
- isAnchor: isAnchor,
- isDiv: makePredByNodeName('DIV'),
- isLi: isLi,
- isBR: makePredByNodeName('BR'),
- isSpan: makePredByNodeName('SPAN'),
- isB: makePredByNodeName('B'),
- isU: makePredByNodeName('U'),
- isS: makePredByNodeName('S'),
- isI: makePredByNodeName('I'),
- isImg: makePredByNodeName('IMG'),
- isTextarea: isTextarea,
- isEmpty: isEmpty,
- isEmptyAnchor: func.and(isAnchor, isEmpty),
- isClosestSibling: isClosestSibling,
- withClosestSiblings: withClosestSiblings,
- nodeLength: nodeLength,
- isLeftEdgePoint: isLeftEdgePoint,
- isRightEdgePoint: isRightEdgePoint,
- isEdgePoint: isEdgePoint,
- isLeftEdgeOf: isLeftEdgeOf,
- isRightEdgeOf: isRightEdgeOf,
- prevPoint: prevPoint,
- nextPoint: nextPoint,
- isSamePoint: isSamePoint,
- isVisiblePoint: isVisiblePoint,
- prevPointUntil: prevPointUntil,
- nextPointUntil: nextPointUntil,
- isCharPoint: isCharPoint,
- walkPoint: walkPoint,
- ancestor: ancestor,
- singleChildAncestor: singleChildAncestor,
- listAncestor: listAncestor,
- lastAncestor: lastAncestor,
- listNext: listNext,
- listPrev: listPrev,
- listDescendant: listDescendant,
- commonAncestor: commonAncestor,
- wrap: wrap,
- insertAfter: insertAfter,
- appendChildNodes: appendChildNodes,
- position: position,
- hasChildren: hasChildren,
- makeOffsetPath: makeOffsetPath,
- fromOffsetPath: fromOffsetPath,
- splitTree: splitTree,
- splitPoint: splitPoint,
- create: create,
- createText: createText,
- remove: remove,
- removeWhile: removeWhile,
- replace: replace,
- html: html,
- value: value
- };
- })();
-
-
- var range = (function() {
-
- /**
- * return boundaryPoint from TextRange, inspired by Andy Na's HuskyRange.js
- *
- * @param {TextRange} textRange
- * @param {Boolean} isStart
- * @return {BoundaryPoint}
- *
- * @see http://msdn.microsoft.com/en-us/library/ie/ms535872(v=vs.85).aspx
- */
- var textRangeToPoint = function(textRange, isStart) {
- var container = textRange.parentElement(), offset;
-
- var tester = document.body.createTextRange(), prevContainer;
- var childNodes = list.from(container.childNodes);
- for (offset = 0; offset < childNodes.length; offset++) {
- if (dom.isText(childNodes[offset])) {
- continue;
- }
- tester.moveToElementText(childNodes[offset]);
- if (tester.compareEndPoints('StartToStart', textRange) >= 0) {
- break;
- }
- prevContainer = childNodes[offset];
- }
-
- if (offset !== 0 && dom.isText(childNodes[offset - 1])) {
- var textRangeStart = document.body.createTextRange(), curTextNode = null;
- textRangeStart.moveToElementText(prevContainer || container);
- textRangeStart.collapse(!prevContainer);
- curTextNode = prevContainer ? prevContainer.nextSibling : container.firstChild;
-
- var pointTester = textRange.duplicate();
- pointTester.setEndPoint('StartToStart', textRangeStart);
- var textCount = pointTester.text.replace(/[\r\n]/g, '').length;
-
- while (textCount > curTextNode.nodeValue.length && curTextNode.nextSibling) {
- textCount -= curTextNode.nodeValue.length;
- curTextNode = curTextNode.nextSibling;
- }
-
- /* jshint ignore:start */
- var dummy = curTextNode.nodeValue; // enforce IE to re-reference curTextNode, hack
- /* jshint ignore:end */
-
- if (isStart && curTextNode.nextSibling && dom.isText(curTextNode.nextSibling) &&
- textCount === curTextNode.nodeValue.length) {
- textCount -= curTextNode.nodeValue.length;
- curTextNode = curTextNode.nextSibling;
- }
-
- container = curTextNode;
- offset = textCount;
- }
-
- return {
- cont: container,
- offset: offset
- };
- };
-
- /**
- * return TextRange from boundary point (inspired by google closure-library)
- * @param {BoundaryPoint} point
- * @return {TextRange}
- */
- var pointToTextRange = function(point) {
- var textRangeInfo = function(container, offset) {
- var node, isCollapseToStart;
-
- if (dom.isText(container)) {
- var prevTextNodes = dom.listPrev(container, func.not(dom.isText));
- var prevContainer = list.last(prevTextNodes).previousSibling;
- node = prevContainer || container.parentNode;
- offset += list.sum(list.tail(prevTextNodes), dom.nodeLength);
- isCollapseToStart = !prevContainer;
- } else {
- node = container.childNodes[offset] || container;
- if (dom.isText(node)) {
- return textRangeInfo(node, 0);
- }
-
- offset = 0;
- isCollapseToStart = false;
- }
-
- return {
- node: node,
- collapseToStart: isCollapseToStart,
- offset: offset
- };
- };
-
- var textRange = document.body.createTextRange();
- var info = textRangeInfo(point.node, point.offset);
-
- textRange.moveToElementText(info.node);
- textRange.collapse(info.collapseToStart);
- textRange.moveStart('character', info.offset);
- return textRange;
- };
-
- /**
- * Wrapped Range
- *
- * @constructor
- * @param {Node} sc - start container
- * @param {Number} so - start offset
- * @param {Node} ec - end container
- * @param {Number} eo - end offset
- */
- var WrappedRange = function(sc, so, ec, eo) {
- this.sc = sc;
- this.so = so;
- this.ec = ec;
- this.eo = eo;
-
- // nativeRange: get nativeRange from sc, so, ec, eo
- var nativeRange = function() {
- if (agent.isW3CRangeSupport) {
- var w3cRange = document.createRange();
- w3cRange.setStart(sc, so);
- w3cRange.setEnd(ec, eo);
-
- return w3cRange;
- } else {
- var textRange = pointToTextRange({
- node: sc,
- offset: so
- });
-
- textRange.setEndPoint('EndToEnd', pointToTextRange({
- node: ec,
- offset: eo
- }));
-
- return textRange;
- }
- };
-
- this.getPoints = function() {
- return {
- sc: sc,
- so: so,
- ec: ec,
- eo: eo
- };
- };
-
- this.getStartPoint = function() {
- return {
- node: sc,
- offset: so
- };
- };
-
- this.getEndPoint = function() {
- return {
- node: ec,
- offset: eo
- };
- };
-
- /**
- * select update visible range
- */
- this.select = function() {
- var nativeRng = nativeRange();
- if (agent.isW3CRangeSupport) {
- var selection = document.getSelection();
- if (selection.rangeCount > 0) {
- selection.removeAllRanges();
- }
- selection.addRange(nativeRng);
- } else {
- nativeRng.select();
- }
-
- return this;
- };
-
- /**
- * @return {WrappedRange}
- */
- this.normalize = function() {
-
- /**
- * @param {BoundaryPoint} point
- * @return {BoundaryPoint}
- */
- var getVisiblePoint = function(point) {
- if (!dom.isVisiblePoint(point)) {
- if (dom.isLeftEdgePoint(point)) {
- point = dom.nextPointUntil(point, dom.isVisiblePoint);
- } else {
- point = dom.prevPointUntil(point, dom.isVisiblePoint);
- }
- }
- return point;
- };
-
- var startPoint = getVisiblePoint(this.getStartPoint());
- var endPoint = getVisiblePoint(this.getEndPoint());
-
- return new WrappedRange(
- startPoint.node,
- startPoint.offset,
- endPoint.node,
- endPoint.offset
- );
- };
-
- /**
- * returns matched nodes on range
- *
- * @param {Function} [pred] - predicate function
- * @param {Object} [options]
- * @param {Boolean} [options.includeAncestor]
- * @param {Boolean} [options.fullyContains]
- * @return {Node[]}
- */
- this.nodes = function(pred, options) {
- pred = pred || func.ok;
-
- var includeAncestor = options && options.includeAncestor;
- var fullyContains = options && options.fullyContains;
-
- // TODO compare points and sort
- var startPoint = this.getStartPoint();
- var endPoint = this.getEndPoint();
-
- var nodes = [];
- var leftEdgeNodes = [];
-
- dom.walkPoint(startPoint, endPoint, function(point) {
- if (dom.isEditable(point.node)) {
- return;
- }
-
- var node;
- if (fullyContains) {
- if (dom.isLeftEdgePoint(point)) {
- leftEdgeNodes.push(point.node);
- }
- if (dom.isRightEdgePoint(point) && list.contains(leftEdgeNodes, point.node)) {
- node = point.node;
- }
- } else if (includeAncestor) {
- node = dom.ancestor(point.node, pred);
- } else {
- node = point.node;
- }
-
- if (node && pred(node)) {
- nodes.push(node);
- }
- }, true);
-
- return list.unique(nodes);
- };
-
- /**
- * returns commonAncestor of range
- * @return {Element} - commonAncestor
- */
- this.commonAncestor = function() {
- return dom.commonAncestor(sc, ec);
- };
-
- /**
- * returns expanded range by pred
- *
- * @param {Function} pred - predicate function
- * @return {WrappedRange}
- */
- this.expand = function(pred) {
- var startAncestor = dom.ancestor(sc, pred);
- var endAncestor = dom.ancestor(ec, pred);
-
- if (!startAncestor && !endAncestor) {
- return new WrappedRange(sc, so, ec, eo);
- }
-
- var boundaryPoints = this.getPoints();
-
- if (startAncestor) {
- boundaryPoints.sc = startAncestor;
- boundaryPoints.so = 0;
- }
-
- if (endAncestor) {
- boundaryPoints.ec = endAncestor;
- boundaryPoints.eo = dom.nodeLength(endAncestor);
- }
-
- return new WrappedRange(
- boundaryPoints.sc,
- boundaryPoints.so,
- boundaryPoints.ec,
- boundaryPoints.eo
- );
- };
-
- /**
- * @param {Boolean} isCollapseToStart
- * @return {WrappedRange}
- */
- this.collapse = function(isCollapseToStart) {
- if (isCollapseToStart) {
- return new WrappedRange(sc, so, sc, so);
- } else {
- return new WrappedRange(ec, eo, ec, eo);
- }
- };
-
- /**
- * splitText on range
- */
- this.splitText = function() {
- var isSameContainer = sc === ec;
- var boundaryPoints = this.getPoints();
-
- if (dom.isText(ec) && !dom.isEdgePoint(this.getEndPoint())) {
- ec.splitText(eo);
- }
-
- if (dom.isText(sc) && !dom.isEdgePoint(this.getStartPoint())) {
- boundaryPoints.sc = sc.splitText(so);
- boundaryPoints.so = 0;
-
- if (isSameContainer) {
- boundaryPoints.ec = boundaryPoints.sc;
- boundaryPoints.eo = eo - so;
- }
- }
-
- return new WrappedRange(
- boundaryPoints.sc,
- boundaryPoints.so,
- boundaryPoints.ec,
- boundaryPoints.eo
- );
- };
-
- /**
- * delete contents on range
- * @return {WrappedRange}
- */
- this.deleteContents = function() {
- if (this.isCollapsed()) {
- return this;
- }
-
- var rng = this.splitText();
- var nodes = rng.nodes(null, {
- fullyContains: true
- });
-
- // find new cursor point
- var point = dom.prevPointUntil(rng.getStartPoint(), function(point) {
- return !list.contains(nodes, point.node);
- });
-
- var emptyParents = [];
- $.each(nodes, function(idx, node) {
- // find empty parents
- var parent = node.parentNode;
- if (point.node !== parent && dom.nodeLength(parent) === 1) {
- emptyParents.push(parent);
- }
- dom.remove(node, false);
- });
-
- // remove empty parents
- $.each(emptyParents, function(idx, node) {
- dom.remove(node, false);
- });
-
- return new WrappedRange(
- point.node,
- point.offset,
- point.node,
- point.offset
- ).normalize();
- };
-
- /**
- * makeIsOn: return isOn(pred) function
- */
- var makeIsOn = function(pred) {
- return function() {
- var ancestor = dom.ancestor(sc, pred);
- return !!ancestor && (ancestor === dom.ancestor(ec, pred));
- };
- };
-
- // isOnEditable: judge whether range is on editable or not
- this.isOnEditable = makeIsOn(dom.isEditable);
- // isOnList: judge whether range is on list node or not
- this.isOnList = makeIsOn(dom.isList);
- // isOnAnchor: judge whether range is on anchor node or not
- this.isOnAnchor = makeIsOn(dom.isAnchor);
- // isOnAnchor: judge whether range is on cell node or not
- this.isOnCell = makeIsOn(dom.isCell);
-
- /**
- * @param {Function} pred
- * @return {Boolean}
- */
- this.isLeftEdgeOf = function(pred) {
- if (!dom.isLeftEdgePoint(this.getStartPoint())) {
- return false;
- }
-
- var node = dom.ancestor(this.sc, pred);
- return node && dom.isLeftEdgeOf(this.sc, node);
- };
-
- /**
- * returns whether range was collapsed or not
- */
- this.isCollapsed = function() {
- return sc === ec && so === eo;
- };
-
- /**
- * wrap inline nodes which children of body with paragraph
- *
- * @return {WrappedRange}
- */
- this.wrapBodyInlineWithPara = function() {
- if (dom.isBodyContainer(sc) && dom.isEmpty(sc)) {
- sc.innerHTML = dom.emptyPara;
- return new WrappedRange(sc.firstChild, 0, sc.firstChild, 0);
- }
-
- if (dom.isParaInline(sc) || dom.isPara(sc)) {
- return this.normalize();
- }
-
- // find inline top ancestor
- var topAncestor;
- if (dom.isInline(sc)) {
- var ancestors = dom.listAncestor(sc, func.not(dom.isInline));
- topAncestor = list.last(ancestors);
- if (!dom.isInline(topAncestor)) {
- topAncestor = ancestors[ancestors.length - 2] || sc.childNodes[so];
- }
- } else {
- topAncestor = sc.childNodes[so > 0 ? so - 1 : 0];
- }
-
- // siblings not in paragraph
- var inlineSiblings = dom.listPrev(topAncestor, dom.isParaInline).reverse();
- inlineSiblings = inlineSiblings.concat(dom.listNext(topAncestor.nextSibling, dom.isParaInline));
-
- // wrap with paragraph
- if (inlineSiblings.length) {
- var para = dom.wrap(list.head(inlineSiblings), 'p');
- dom.appendChildNodes(para, list.tail(inlineSiblings));
- }
-
- return this.normalize();
- };
-
- /**
- * insert node at current cursor
- *
- * @param {Node} node
- * @return {Node}
- */
- this.insertNode = function(node) {
- var rng = this.wrapBodyInlineWithPara().deleteContents();
- var info = dom.splitPoint(rng.getStartPoint(), dom.isInline(node));
-
- if (info.rightNode) {
- info.rightNode.parentNode.insertBefore(node, info.rightNode);
- } else {
- info.container.appendChild(node);
- }
-
- return node;
- };
-
-
- /**
- * insert html at current cursor
- */
- this.pasteHTML = function(markup) {
- var self = this;
- var contentsContainer = $('<div></div>').html(markup)[0];
- var childNodes = list.from(contentsContainer.childNodes);
-
- this.wrapBodyInlineWithPara().deleteContents();
-
- return $.map(childNodes.reverse(), function(childNode) {
- return self.insertNode(childNode);
- }).reverse();
- };
-
- /**
- * returns text in range
- *
- * @return {String}
- */
- this.toString = function() {
- var nativeRng = nativeRange();
- return agent.isW3CRangeSupport ? nativeRng.toString() : nativeRng.text;
- };
-
- /**
- * returns range for word before cursor
- *
- * @param {Boolean} [findAfter] - find after cursor, default: false
- * @return {WrappedRange}
- */
- this.getWordRange = function(findAfter) {
- var endPoint = this.getEndPoint();
-
- if (!dom.isCharPoint(endPoint)) {
- return this;
- }
-
- var startPoint = dom.prevPointUntil(endPoint, function(point) {
- return !dom.isCharPoint(point);
- });
-
- if (findAfter) {
- endPoint = dom.nextPointUntil(endPoint, function(point) {
- return !dom.isCharPoint(point);
- });
- }
-
- return new WrappedRange(
- startPoint.node,
- startPoint.offset,
- endPoint.node,
- endPoint.offset
- );
- };
-
- /**
- * create offsetPath bookmark
- *
- * @param {Node} editable
- */
- this.bookmark = function(editable) {
- return {
- s: {
- path: dom.makeOffsetPath(editable, sc),
- offset: so
- },
- e: {
- path: dom.makeOffsetPath(editable, ec),
- offset: eo
- }
- };
- };
-
- /**
- * create offsetPath bookmark base on paragraph
- *
- * @param {Node[]} paras
- */
- this.paraBookmark = function(paras) {
- return {
- s: {
- path: list.tail(dom.makeOffsetPath(list.head(paras), sc)),
- offset: so
- },
- e: {
- path: list.tail(dom.makeOffsetPath(list.last(paras), ec)),
- offset: eo
- }
- };
- };
-
- /**
- * getClientRects
- * @return {Rect[]}
- */
- this.getClientRects = function() {
- var nativeRng = nativeRange();
- return nativeRng.getClientRects();
- };
- };
-
- /**
- * @class core.range
- *
- * Data structure
- * * BoundaryPoint: a point of dom tree
- * * BoundaryPoints: two boundaryPoints corresponding to the start and the end of the Range
- *
- * See to http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Position
- *
- * @singleton
- * @alternateClassName range
- */
- return {
- /**
- * @method
- *
- * create Range Object From arguments or Browser Selection
- *
- * @param {Node} sc - start container
- * @param {Number} so - start offset
- * @param {Node} ec - end container
- * @param {Number} eo - end offset
- * @return {WrappedRange}
- */
- create : function(sc, so, ec, eo) {
- if (!arguments.length) { // from Browser Selection
- if (agent.isW3CRangeSupport) {
- var selection = document.getSelection();
- if (!selection || selection.rangeCount === 0) {
- return null;
- } else if (dom.isBody(selection.anchorNode)) {
- // Firefox: returns entire body as range on initialization. We won't never need it.
- return null;
- }
-
- var nativeRng = selection.getRangeAt(0);
- sc = nativeRng.startContainer;
- so = nativeRng.startOffset;
- ec = nativeRng.endContainer;
- eo = nativeRng.endOffset;
- } else { // IE8: TextRange
- var textRange = document.selection.createRange();
- var textRangeEnd = textRange.duplicate();
- textRangeEnd.collapse(false);
- var textRangeStart = textRange;
- textRangeStart.collapse(true);
-
- var startPoint = textRangeToPoint(textRangeStart, true),
- endPoint = textRangeToPoint(textRangeEnd, false);
-
- // same visible point case: range was collapsed.
- if (dom.isText(startPoint.node) && dom.isLeftEdgePoint(startPoint) &&
- dom.isTextNode(endPoint.node) && dom.isRightEdgePoint(endPoint) &&
- endPoint.node.nextSibling === startPoint.node) {
- startPoint = endPoint;
- }
-
- sc = startPoint.cont;
- so = startPoint.offset;
- ec = endPoint.cont;
- eo = endPoint.offset;
- }
- } else if (arguments.length === 2) { //collapsed
- ec = sc;
- eo = so;
- }
- return new WrappedRange(sc, so, ec, eo);
- },
-
- /**
- * @method
- *
- * create WrappedRange from node
- *
- * @param {Node} node
- * @return {WrappedRange}
- */
- createFromNode: function(node) {
- var sc = node;
- var so = 0;
- var ec = node;
- var eo = dom.nodeLength(ec);
-
- // browsers can't target a picture or void node
- if (dom.isVoid(sc)) {
- so = dom.listPrev(sc).length - 1;
- sc = sc.parentNode;
- }
- if (dom.isBR(ec)) {
- eo = dom.listPrev(ec).length - 1;
- ec = ec.parentNode;
- } else if (dom.isVoid(ec)) {
- eo = dom.listPrev(ec).length;
- ec = ec.parentNode;
- }
-
- return this.create(sc, so, ec, eo);
- },
-
- /**
- * create WrappedRange from node after position
- *
- * @param {Node} node
- * @return {WrappedRange}
- */
- createFromNodeBefore: function(node) {
- return this.createFromNode(node).collapse(true);
- },
-
- /**
- * create WrappedRange from node after position
- *
- * @param {Node} node
- * @return {WrappedRange}
- */
- createFromNodeAfter: function(node) {
- return this.createFromNode(node).collapse();
- },
-
- /**
- * @method
- *
- * create WrappedRange from bookmark
- *
- * @param {Node} editable
- * @param {Object} bookmark
- * @return {WrappedRange}
- */
- createFromBookmark : function(editable, bookmark) {
- var sc = dom.fromOffsetPath(editable, bookmark.s.path);
- var so = bookmark.s.offset;
- var ec = dom.fromOffsetPath(editable, bookmark.e.path);
- var eo = bookmark.e.offset;
- return new WrappedRange(sc, so, ec, eo);
- },
-
- /**
- * @method
- *
- * create WrappedRange from paraBookmark
- *
- * @param {Object} bookmark
- * @param {Node[]} paras
- * @return {WrappedRange}
- */
- createFromParaBookmark: function(bookmark, paras) {
- var so = bookmark.s.offset;
- var eo = bookmark.e.offset;
- var sc = dom.fromOffsetPath(list.head(paras), bookmark.s.path);
- var ec = dom.fromOffsetPath(list.last(paras), bookmark.e.path);
-
- return new WrappedRange(sc, so, ec, eo);
- }
- };
- })();
-
- /**
- * @class defaults
- * @singleton
- */
- // >>>>>>> CK
- var defaults = {
- /** @property */
- version: '0.6.9',
-
- /**
- * for event options, reference to EventHandler.attach
- * @property {Object} options
- * @property {String/Number} [options.width=null] set editor width
- * @property {String/Number} [options.height=null] set editor height, ex) 300
- * @property {String/Number} options.minHeight set minimum height of editor
- * @property {String/Number} options.maxHeight
- * @property {String/Number} options.focus
- * @property {Number} options.tabsize
- * @property {Boolean} options.styleWithSpan
- * @property {Object} options.codemirror
- * @property {Object} [options.codemirror.mode='text/html']
- * @property {Object} [options.codemirror.htmlMode=true]
- * @property {Object} [options.codemirror.lineNumbers=true]
- * @property {String} [options.lang=en-US] language 'en-US', 'ko-KR', ...
- * @property {String} [options.direction=null] text direction, ex) 'rtl'
- * @property {Array} [options.toolbar]
- * @property {Boolean} [options.airMode=false]
- * @property {Array} [options.airPopover]
- * @property {Function} [options.onInit] initialize
- * @property {Function} [options.onsubmit]
- */
- options: {
- // >>>>>>> CK extra options
- defaultTextColor: '#212121', // default text color (used by color tool)
- defaultBackColor: '#ddd', // default text color (used by color tool)
- followingToolbar: true, // make the toolbar follow on window scroll
- otherStaticBarClass: "staticTop", // default class for other static bars eventually used on webapp
-
- width: null, // set editor width
- height: null, // set editor height, ex) 300
-
- minHeight: null, // set minimum height of editor
- maxHeight: null, // set maximum height of editor
-
- focus: false, // set focus to editable area after initializing materialnote
-
- tabsize: 4, // size of tab ex) 2 or 4
- styleWithSpan: true, // style with span (Chrome and FF only)
-
- disableLinkTarget: false, // hide link Target Checkbox
- disableDragAndDrop: false, // disable drag and drop event
- disableResizeEditor: false, // disable resizing editor
-
- shortcuts: true, // enable keyboard shortcuts
-
- placeholder: false, // enable placeholder text
- prettifyHtml: true, // enable prettifying html while toggling codeview
-
- iconPrefix: '', // prefix for css icon classes
- icons: {
- font: {
- bold: 'format_bold',
- italic: 'format_italic',
- underline: 'format_underlined',
- clear: 'clear',
- height: 'format_size',
- strikethrough: 'strikethrough_s',
- superscript: 'vertical_align_top',
- subscript: 'vertical_align_bottom'
- },
- image: {
- image: 'image',
- floatLeft: 'format_align_left',
- floatRight: 'format_align_right',
- floatNone: 'format_align_justify',
- shapeRounded: 'crop_3_2',
- shapeCircle: 'panorama_fish_eye',
- shapeThumbnail: 'collections',
- bordered: 'border_outer',
- shapeNone: 'image',
- remove: 'delete'
- },
- link: {
- link: 'insert_link',
- unlink: 'clear',
- edit: 'create'
- },
- table: {
- table: 'border_all'
- },
- hr: {
- insert: 'add'
- },
- style: {
- style: 'border_color'
- },
- lists: {
- unordered: 'format_list_bulleted',
- ordered: 'format_list_numbered'
- },
- options: {
- help: 'help',
- fullscreen: 'settings_overscan',
- codeview: 'code'
- },
- paragraph: {
- paragraph: 'format_textdirection_l_to_r',
- outdent: 'format_indent_decrease',
- indent: 'format_indent_increase',
- left: 'format_align_left',
- center: 'format_align_center',
- right: 'format_align_right',
- justify: 'format_align_justify'
- },
- color: {
- recent: 'format_color_text'
- },
- history: {
- undo: 'undo',
- redo: 'redo'
- },
- misc: {
- check: 'check'
- }
- },
-
- codemirror: { // codemirror options
- mode: 'text/html',
- htmlMode: true,
- indentWithTabs: true,
- tabSize: 4,
- lineNumbers: true,
- theme: 'monokai',
- maxHighlightLength: 'Infinity'
- },
-
- // language
- lang: 'en-US', // language 'en-US', 'ko-KR', ...
- direction: null, // text direction, ex) 'rtl'
-
- // toolbar
- toolbar: [
- ['style', ['style']],
- ['font', ['bold', 'italic', 'underline', 'clear']],
- // ['font', ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'clear']],
- ['fontname', ['fontname']],
- ['fontsize', ['fontsize']],
- ['color', ['color']],
- ['para', ['ul', 'ol', 'paragraph']],
- ['height', ['height']],
- ['table', ['table']],
- ['insert', ['link', 'picture', 'hr']],
- ['view', ['fullscreen', 'codeview']],
- ['help', ['help']]
- ],
-
- plugin : {},
-
- // air mode: inline editor
- airMode: false,
- // airPopover: [
- // ['style', ['style']],
- // ['font', ['bold', 'italic', 'underline', 'clear']],
- // ['fontname', ['fontname']],
- // ['color', ['color']],
- // ['para', ['ul', 'ol', 'paragraph']],
- // ['height', ['height']],
- // ['table', ['table']],
- // ['insert', ['link', 'picture']],
- // ['help', ['help']]
- // ],
- airPopover: [
- ['color', ['color']],
- ['font', ['bold', 'underline', 'clear']],
- ['para', ['ul', 'paragraph']],
- ['table', ['table']],
- ['insert', ['link', 'picture']]
- ],
-
- // style tag
- styleTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
-
- // default fontName
- defaultFontName: 'Roboto',
-
- // fontName
- fontNames: [
- 'Roboto', 'Arial', 'Arial Black', 'Comic Sans MS', 'Courier New',
- 'Helvetica Neue', 'Helvetica', 'Impact', 'Times New Roman', 'Verdana'
- ],
- fontNamesIgnoreCheck: [],
-
- fontSizes: ['12', '13', '14', '15', '16', '17', '18', '25', '37'],
-
- // palette colors(n x n)
- colors: [//grey brown dpurple purple indigo blue cyan green lgreen yellow amber orange dorange red pink
- ['#fafafa', '#efebe9', '#7e57c2', '#ab47bc', '#5c6bc0', '#42a5f5', '#26c6da', '#66bb6a', '#9ccc65', '#ffee58', '#ffca28', '#ffa726', '#ff7043', '#ef5350', '#ec407a'],
- ['#f5f5f5', '#d7ccc8', '#673ab7', '#9c27b0', '#3f51b5', '#2196f3', '#00bcd4', '#4caf50', '#8bc34a', '#ffeb3b', '#ffc107', '#ff9800', '#ff5722', '#f44336', '#e91e63'],
- ['#eeeeee', '#bcaaa4', '#5e35b1', '#8e24aa', '#3949ab', '#1e88e5', '#00acc1', '#43a047', '#7cb342', '#fdd835', '#ffb300', '#fb8c00', '#f4511e', '#e53935', '#d81b60'],
- ['#e0e0e0', '#a1887f', '#512da8', '#7b1fa2', '#303f9f', '#1976d2', '#0097a7', '#388e3c', '#689f38', '#fbc02d', '#ffa000', '#f57c00', '#e64a19', '#d32f2f', '#c2185b'],
- ['#bdbdbd', '#8d6e63', '#4527a0', '#6a1b9a', '#283593', '#1565c0', '#00838f', '#2e7d32', '#558b2f', '#f9a825', '#ff8f00', '#ef6c00', '#d84315', '#c62828', '#ad1457'],
- ['#9e9e9e', '#795548', '#311b92', '#4a148c', '#1a237e', '#0d47a1', '#006064', '#1b5e20', '#33691e', '#f57f17', '#ff6f00', '#e65100', '#bf360c', '#b71c1c', '#880e4f'],
- ['#757575', '#6d4c41', '#b388ff', '#ea80fc', '#8c9eff', '#82b1ff', '#84ffff', '#b9f6ca', '#ccff90', '#ffff8d', '#ffe57f', '#ffd180', '#ff9e80', '#ff8a80', '#ff80ab'],
- ['#616161', '#5d4037', '#7c4dff', '#e040fb', '#536dfe', '#448aff', '#18ffff', '#69f0ae', '#b2ff59', '#ffff00', '#ffd740', '#ffab40', '#ff6e40', '#ff5252', '#ff4081'],
- ['#424242', '#4e342e', '#651fff', '#d500f9', '#3d5afe', '#2979ff', '#00e5ff', '#00e676', '#76ff03', '#ffea00', '#ffc400', '#ff9100', '#ff3d00', '#ff1744', '#f50057'],
- ['#212121', '#3e2723', '#6200ea', '#aa00ff', '#304ffe', '#2962ff', '#00b8d4', '#00c853', '#64dd17', '#ffd600', '#ffab00', '#ff6d00', '#dd2c00', '#d50000', '#c51162'],
- ],
- // palette colors(n x n)
- colorTitles: [
- //grey brown dpurple purple indigo blue cyan green lgreen yellow amber orange dorange red pink
- ['grey lighten5', 'brown lighten5', 'deep-purple lighten1', 'purple lighten1', 'indigo lighten1', 'blue lighten1', 'cyan lighten1', 'green lighten1', 'light-green lighten1', 'yellow lighten1', 'amber lighten1', 'orange lighten1', 'deep-orange lighten1', 'red lighten1', 'pink lighten1'],
- ['grey lighten4', 'brown lighten4', 'deep-purple', 'purple', 'indigo', 'blue', 'cyan', 'green', 'light-green', 'yellow', 'amber', 'orange', 'deep-orange', 'red', 'pink' ],
- ['grey lighten3', 'brown lighten3', 'deep-purple darken1', 'purple darken1', 'indigo darken1', 'blue darken1', 'cyan darken1', 'green darken1', 'light-green darken1', 'yellow darken1', 'amber darken1', 'orange darken1', 'deep-orange darken1', 'red darken1', 'pink darken1' ],
- ['grey lighten2', 'brown lighten2', 'deep-purple darken2', 'purple darken2', 'indigo darken2', 'blue darken2', 'cyan darken2', 'green darken2', 'light-green darken2', 'yellow darken2', 'amber darken2', 'orange darken2', 'deep-orange darken2', 'red darken2', 'pink darken2' ],
- ['grey lighten1', 'brown lighten1', 'deep-purple darken3', 'purple darken3', 'indigo darken3', 'blue darken3', 'cyan darken3', 'green darken3', 'light-green darken3', 'yellow darken3', 'amber darken3', 'orange darken3', 'deep-orange darken3', 'red darken3', 'pink darken3' ],
- ['grey', 'brown', 'deep-purple darken4', 'purple darken4', 'indigo darken4', 'blue darken4', 'cyan darken4', 'green darken4', 'light-green darken4', 'yellow darken4', 'amber darken4', 'orange darken4', 'deep-orange darken4', 'red darken4', 'pink darken4' ],
- ['grey darken1', 'brown darken1', 'deep-purple accent1', 'purple accent1', 'indigo accent1', 'blue accent1', 'cyan accent1', 'green accent1', 'light-green accent1', 'yellow accent1', 'amber accent1', 'orange accent1', 'deep-orange accent1', 'red accent1', 'pink accent1' ],
- ['grey darken2', 'brown darken2', 'deep-purple accent2', 'purple accent2', 'indigo accent2', 'blue accent2', 'cyan accent2', 'green accent2', 'light-green accent2', 'yellow accent2', 'amber accent2', 'orange accent2', 'deep-orange accent2', 'red accent2', 'pink accent2' ],
- ['grey darken3', 'brown darken3', 'deep-purple accent3', 'purple accent3', 'indigo accent3', 'blue accent3', 'cyan accent3', 'green accent3', 'light-green accent3', 'yellow accent3', 'amber accent3', 'orange accent3', 'deep-orange accent3', 'red accent3', 'pink accent3' ],
- ['grey darken4', 'brown darken4', 'deep-purple accent4', 'purple accent4', 'indigo accent4', 'blue accent4', 'cyan accent4', 'green accent4', 'light-green accent4', 'yellow accent4', 'amber accent4', 'orange accent4', 'deep-orange accent4', 'red accent4', 'pink accent4' ],
- ],
-
- // lineHeight
- lineHeights: ['1.0', '1.2', '1.4', '1.5', '1.6', '1.8', '2.0', '3.0'],
-
- // insertTable max size
- insertTableMaxSize: {
- col: 12,
- row: 10
- },
-
- // image
- maximumImageFileSize: null, // size in bytes, null = no limit
-
- // callbacks
- oninit: null, // initialize
- onfocus: null, // editable has focus
- onblur: null, // editable out of focus
- onenter: null, // enter key pressed
- onkeyup: null, // keyup
- onkeydown: null, // keydown
- onImageUpload: null, // imageUpload
- onImageUploadError: null, // imageUploadError
- onMediaDelete: null, // media delete
- onToolbarClick: null,
- onsubmit: null,
-
- /**
- * manipulate link address when user create link
- * @param {String} sLinkUrl
- * @return {String}
- */
- onCreateLink: function(sLinkUrl) {
- if (sLinkUrl.indexOf('@') !== -1 && sLinkUrl.indexOf(':') === -1) {
- sLinkUrl = 'mailto:' + sLinkUrl;
- }
-
- return sLinkUrl;
- },
-
- keyMap: {
- pc: {
- 'ENTER': 'insertParagraph',
- 'CTRL+Z': 'undo',
- 'CTRL+Y': 'redo',
- 'TAB': 'tab',
- 'SHIFT+TAB': 'untab',
- 'CTRL+B': 'bold',
- 'CTRL+I': 'italic',
- 'CTRL+U': 'underline',
- 'CTRL+SHIFT+S': 'strikethrough',
- 'CTRL+BACKSLASH': 'removeFormat',
- 'CTRL+SHIFT+L': 'justifyLeft',
- 'CTRL+SHIFT+E': 'justifyCenter',
- 'CTRL+SHIFT+R': 'justifyRight',
- 'CTRL+SHIFT+J': 'justifyFull',
- 'CTRL+SHIFT+NUM7': 'insertUnorderedList',
- 'CTRL+SHIFT+NUM8': 'insertOrderedList',
- 'CTRL+LEFTBRACKET': 'outdent',
- 'CTRL+RIGHTBRACKET': 'indent',
- 'CTRL+NUM0': 'formatPara',
- 'CTRL+NUM1': 'formatH1',
- 'CTRL+NUM2': 'formatH2',
- 'CTRL+NUM3': 'formatH3',
- 'CTRL+NUM4': 'formatH4',
- 'CTRL+NUM5': 'formatH5',
- 'CTRL+NUM6': 'formatH6',
- 'CTRL+ENTER': 'insertHorizontalRule',
- 'CTRL+K': 'showLinkDialog'
- },
-
- mac: {
- 'ENTER': 'insertParagraph',
- 'CMD+Z': 'undo',
- 'CMD+SHIFT+Z': 'redo',
- 'TAB': 'tab',
- 'SHIFT+TAB': 'untab',
- 'CMD+B': 'bold',
- 'CMD+I': 'italic',
- 'CMD+U': 'underline',
- 'CMD+SHIFT+S': 'strikethrough',
- 'CMD+BACKSLASH': 'removeFormat',
- 'CMD+SHIFT+L': 'justifyLeft',
- 'CMD+SHIFT+E': 'justifyCenter',
- 'CMD+SHIFT+R': 'justifyRight',
- 'CMD+SHIFT+J': 'justifyFull',
- 'CMD+SHIFT+NUM7': 'insertUnorderedList',
- 'CMD+SHIFT+NUM8': 'insertOrderedList',
- 'CMD+LEFTBRACKET': 'outdent',
- 'CMD+RIGHTBRACKET': 'indent',
- 'CMD+NUM0': 'formatPara',
- 'CMD+NUM1': 'formatH1',
- 'CMD+NUM2': 'formatH2',
- 'CMD+NUM3': 'formatH3',
- 'CMD+NUM4': 'formatH4',
- 'CMD+NUM5': 'formatH5',
- 'CMD+NUM6': 'formatH6',
- 'CMD+ENTER': 'insertHorizontalRule',
- 'CMD+K': 'showLinkDialog'
- }
- }
- },
-
- // default language: en-US
- lang: {
- 'en-US': {
- font: {
- bold: 'Bold',
- italic: 'Italic',
- underline: 'Underline',
- clear: 'Remove Font Style',
- height: 'Line Height',
- name: 'Font Family',
- strikethrough: 'Strikethrough',
- subscript: 'Subscript',
- superscript: 'Superscript',
- size: 'Font Size'
- },
- image: {
- image: 'Picture',
- insert: 'Insert Image',
- resizeFull: 'Resize Full',
- resizeHalf: 'Resize Half',
- resizeQuarter: 'Resize Quarter',
- floatLeft: 'Float Left',
- floatRight: 'Float Right',
- floatNone: 'Float None',
- shapeRounded: 'Shape: Rounded',
- shapeCircle: 'Shape: Circle',
- bordered: 'Bordered',
- shapeThumbnail: 'Shape: Thumbnail',
- shapeNone: 'Shape: None',
- dragImageHere: 'Drag image or text here',
- dropImage: 'Drop image or Text',
- selectFromFiles: 'Select from files',
- maximumFileSize: 'Maximum file size',
- maximumFileSizeError: 'Maximum file size exceeded.',
- url: 'Image URL',
- remove: 'Remove Image'
- },
- link: {
- link: 'Link',
- insert: 'Insert Link',
- unlink: 'Unlink',
- edit: 'Edit',
- textToDisplay: 'Text to display',
- url: 'To what URL should this link go?',
- openInNewWindow: 'Open in new window'
- },
- table: {
- table: 'Table',
- striped: 'Striped',
- hoverable: 'Hoverable',
- responsive: 'Responsive',
- bordered: 'Bordered'
- },
- hr: {
- insert: 'Insert Horizontal Rule'
- },
- style: {
- style: 'Style',
- normal: 'Normal',
- blockquote: 'Quote',
- pre: 'Code',
- h1: 'Header 1',
- h2: 'Header 2',
- h3: 'Header 3',
- h4: 'Header 4',
- h5: 'Header 5',
- h6: 'Header 6'
- },
- lists: {
- unordered: 'Unordered list',
- ordered: 'Ordered list'
- },
- options: {
- help: 'Help',
- fullscreen: 'Full Screen',
- codeview: 'Code View'
- },
- paragraph: {
- paragraph: 'Paragraph',
- outdent: 'Outdent',
- indent: 'Indent',
- left: 'Align left',
- center: 'Align center',
- right: 'Align right',
- justify: 'Justify full'
- },
- color: {
- recent: 'Recent Color',
- more: 'More Color',
- background: 'Back',
- foreground: 'Text',
- transparent: 'Transparent',
- setTransparent: 'Transparent',
- reset: 'Reset',
- resetToDefault: 'Default'
- },
- shortcut: {
- shortcuts: 'Keyboard shortcuts',
- close: 'Close',
- textFormatting: 'Text formatting',
- action: 'Action',
- paragraphFormatting: 'Paragraph formatting',
- documentStyle: 'Document Style',
- extraKeys: 'Extra keys'
- },
- history: {
- undo: 'Undo',
- redo: 'Redo'
- }
- }
- }
- };
-
- /**
- * @class core.async
- *
- * Async functions which returns `Promise`
- *
- * @singleton
- * @alternateClassName async
- */
- var async = (function() {
- /**
- * @method readFileAsDataURL
- *
- * read contents of file as representing URL
- *
- * @param {File} file
- * @return {Promise} - then: sDataUrl
- */
- var readFileAsDataURL = function(file) {
- return $.Deferred(function(deferred) {
- $.extend(new FileReader(), {
- onload: function(e) {
- var sDataURL = e.target.result;
- deferred.resolve(sDataURL);
- },
- onerror: function() {
- deferred.reject(this);
- }
- }).readAsDataURL(file);
- }).promise();
- };
-
- /**
- * @method createImage
- *
- * create `<image>` from url string
- *
- * @param {String} sUrl
- * @param {String} filename
- * @return {Promise} - then: $image
- */
- var createImage = function(sUrl, filename) {
- return $.Deferred(function(deferred) {
- var $img = $('<img>');
-
- $img.one('load', function() {
- $img.off('error abort');
- deferred.resolve($img);
- }).one('error abort', function() {
- $img.off('load').detach();
- deferred.reject($img);
- }).css({
- display: 'none'
- }).appendTo(document.body).attr({
- 'src': sUrl,
- 'data-filename': filename
- });
- }).promise();
- };
-
- return {
- readFileAsDataURL: readFileAsDataURL,
- createImage: createImage
- };
- })();
-
- /**
- * @class core.key
- *
- * Object for keycodes.
- *
- * @singleton
- * @alternateClassName key
- */
- var key = (function() {
- var keyMap = {
- 'BACKSPACE': 8,
- 'TAB': 9,
- 'ENTER': 13,
- 'SPACE': 32,
-
- // Number: 0-9
- 'NUM0': 48,
- 'NUM1': 49,
- 'NUM2': 50,
- 'NUM3': 51,
- 'NUM4': 52,
- 'NUM5': 53,
- 'NUM6': 54,
- 'NUM7': 55,
- 'NUM8': 56,
-
- // Alphabet: a-z
- 'B': 66,
- 'E': 69,
- 'I': 73,
- 'J': 74,
- 'K': 75,
- 'L': 76,
- 'R': 82,
- 'S': 83,
- 'U': 85,
- 'Y': 89,
- 'Z': 90,
-
- 'SLASH': 191,
- 'LEFTBRACKET': 219,
- 'BACKSLASH': 220,
- 'RIGHTBRACKET': 221
- };
-
- return {
- /**
- * @method isEdit
- *
- * @param {Number} keyCode
- * @return {Boolean}
- */
- isEdit: function(keyCode) {
- return list.contains([8, 9, 13, 32], keyCode);
- },
- /**
- * @method isMove
- *
- * @param {Number} keyCode
- * @return {Boolean}
- */
- isMove: function(keyCode) {
- return list.contains([37, 38, 39, 40], keyCode);
- },
- /**
- * @property {Object} nameFromCode
- * @property {String} nameFromCode.8 "BACKSPACE"
- */
- nameFromCode: func.invertObject(keyMap),
- code: keyMap
- };
- })();
-
- /**
- * @class editing.History
- *
- * Editor History
- *
- */
- var History = function($editable) {
- var stack = [], stackOffset = -1;
- var editable = $editable[0];
-
- var makeSnapshot = function() {
- var rng = range.create();
- var emptyBookmark = {s: {path: [], offset: 0}, e: {path: [], offset: 0}};
-
- return {
- contents: $editable.html(),
- bookmark: (rng ? rng.bookmark(editable) : emptyBookmark)
- };
- };
-
- var applySnapshot = function(snapshot) {
- if (snapshot.contents !== null) {
- $editable.html(snapshot.contents);
- }
- if (snapshot.bookmark !== null) {
- range.createFromBookmark(editable, snapshot.bookmark).select();
- }
- };
-
- /**
- * undo
- */
- this.undo = function() {
- if (0 < stackOffset) {
- stackOffset--;
- applySnapshot(stack[stackOffset]);
- }
- };
-
- /**
- * redo
- */
- this.redo = function() {
- if (stack.length - 1 > stackOffset) {
- stackOffset++;
- applySnapshot(stack[stackOffset]);
- }
- };
-
- /**
- * recorded undo
- */
- this.recordUndo = function() {
- stackOffset++;
-
- // Wash out stack after stackOffset
- if (stack.length > stackOffset) {
- stack = stack.slice(0, stackOffset);
- }
-
- // Create new snapshot and push it to the end
- stack.push(makeSnapshot());
- };
-
- // Create first undo stack
- this.recordUndo();
- };
-
- /**
- * @class editing.Style
- *
- * Style
- *
- */
- var Style = function() {
- /**
- * @method jQueryCSS
- *
- * [workaround] for old jQuery
- * passing an array of style properties to .css()
- * will result in an object of property-value pairs.
- * (compatibility with version < 1.9)
- *
- * @private
- * @param {jQuery} $obj
- * @param {Array} propertyNames - An array of one or more CSS properties.
- * @return {Object}
- */
- var jQueryCSS = function($obj, propertyNames) {
- if (agent.jqueryVersion < 1.9) {
- var result = {};
- $.each(propertyNames, function(idx, propertyName) {
- result[propertyName] = $obj.css(propertyName);
- });
- return result;
- }
- return $obj.css.call($obj, propertyNames);
- };
-
- /**
- * paragraph level style
- *
- * @param {WrappedRange} rng
- * @param {Object} styleInfo
- */
- this.stylePara = function(rng, styleInfo) {
- $.each(rng.nodes(dom.isPara, {
- includeAncestor: true
- }), function(idx, para) {
- $(para).css(styleInfo);
- });
- };
-
- /**
- * insert and returns styleNodes on range.
- *
- * @param {WrappedRange} rng
- * @param {Object} [options] - options for styleNodes
- * @param {String} [options.nodeName] - default: `SPAN`
- * @param {Boolean} [options.expandClosestSibling] - default: `false`
- * @param {Boolean} [options.onlyPartialContains] - default: `false`
- * @return {Node[]}
- */
- this.styleNodes = function(rng, options) {
- rng = rng.splitText();
-
- var nodeName = options && options.nodeName || 'SPAN';
- var expandClosestSibling = !!(options && options.expandClosestSibling);
- var onlyPartialContains = !!(options && options.onlyPartialContains);
-
- if (rng.isCollapsed()) {
- return [rng.insertNode(dom.create(nodeName))];
- }
-
- var pred = dom.makePredByNodeName(nodeName);
- var nodes = $.map(rng.nodes(dom.isText, {
- fullyContains: true
- }), function(text) {
- return dom.singleChildAncestor(text, pred) || dom.wrap(text, nodeName);
- });
-
- if (expandClosestSibling) {
- if (onlyPartialContains) {
- var nodesInRange = rng.nodes();
- // compose with partial contains predication
- pred = func.and(pred, function(node) {
- return list.contains(nodesInRange, node);
- });
- }
-
- return $.map(nodes, function(node) {
- var siblings = dom.withClosestSiblings(node, pred);
- var head = list.head(siblings);
- var tails = list.tail(siblings);
- $.each(tails, function(idx, elem) {
- dom.appendChildNodes(head, elem.childNodes);
- dom.remove(elem);
- });
- return list.head(siblings);
- });
- } else {
- return nodes;
- }
- };
-
- /**
- * get current style on cursor
- *
- * @param {WrappedRange} rng
- * @param {Node} target - target element on event
- * @return {Object} - object contains style properties.
- */
- this.current = function(rng, target) {
- var $cont = $(dom.isText(rng.sc) ? rng.sc.parentNode : rng.sc);
- var properties = ['font-family', 'font-size', 'text-align', 'list-style-type', 'line-height'];
- var styleInfo = jQueryCSS($cont, properties) || {};
-
- styleInfo['font-size'] = parseInt(styleInfo['font-size'], 10);
-
- // document.queryCommandState for toggle state
- styleInfo['font-bold'] = document.queryCommandState('bold') ? 'bold' : 'normal';
- styleInfo['font-italic'] = document.queryCommandState('italic') ? 'italic' : 'normal';
- styleInfo['font-underline'] = document.queryCommandState('underline') ? 'underline' : 'normal';
- styleInfo['font-strikethrough'] = document.queryCommandState('strikeThrough') ? 'strikethrough' : 'normal';
- styleInfo['font-superscript'] = document.queryCommandState('superscript') ? 'superscript' : 'normal';
- styleInfo['font-subscript'] = document.queryCommandState('subscript') ? 'subscript' : 'normal';
-
- // list-style-type to list-style(unordered, ordered)
- if (!rng.isOnList()) {
- styleInfo['list-style'] = 'none';
- } else {
- var aOrderedType = ['circle', 'disc', 'disc-leading-zero', 'square'];
- var isUnordered = $.inArray(styleInfo['list-style-type'], aOrderedType) > -1;
- styleInfo['list-style'] = isUnordered ? 'unordered' : 'ordered';
- }
-
- var para = dom.ancestor(rng.sc, dom.isPara);
- if (para && para.style['line-height']) {
- styleInfo['line-height'] = para.style.lineHeight;
- } else {
- var lineHeight = parseInt(styleInfo['line-height'], 10) / parseInt(styleInfo['font-size'], 10);
- styleInfo['line-height'] = lineHeight.toFixed(1);
- }
-
- styleInfo.image = dom.isImg(target) && target;
- styleInfo.anchor = rng.isOnAnchor() && dom.ancestor(rng.sc, dom.isAnchor);
- styleInfo.ancestors = dom.listAncestor(rng.sc, dom.isEditable);
- styleInfo.range = rng;
-
- return styleInfo;
- };
- };
-
-
- /**
- * @class editing.Bullet
- *
- * @alternateClassName Bullet
- */
- var Bullet = function() {
- /**
- * @method insertOrderedList
- *
- * toggle ordered list
- *
- * @type command
- */
- this.insertOrderedList = function() {
- this.toggleList('OL');
- };
-
- /**
- * @method insertUnorderedList
- *
- * toggle unordered list
- *
- * @type command
- */
- this.insertUnorderedList = function() {
- this.toggleList('UL');
- };
-
- /**
- * @method indent
- *
- * indent
- *
- * @type command
- */
- this.indent = function() {
- var self = this;
- var rng = range.create().wrapBodyInlineWithPara();
-
- var paras = rng.nodes(dom.isPara, { includeAncestor: true });
- var clustereds = list.clusterBy(paras, func.peq2('parentNode'));
-
- $.each(clustereds, function(idx, paras) {
- var head = list.head(paras);
- if (dom.isLi(head)) {
- self.wrapList(paras, head.parentNode.nodeName);
- } else {
- $.each(paras, function(idx, para) {
- $(para).css('marginLeft', function(idx, val) {
- return (parseInt(val, 10) || 0) + 25;
- });
- });
- }
- });
-
- rng.select();
- };
-
- /**
- * @method outdent
- *
- * outdent
- *
- * @type command
- */
- this.outdent = function() {
- var self = this;
- var rng = range.create().wrapBodyInlineWithPara();
-
- var paras = rng.nodes(dom.isPara, { includeAncestor: true });
- var clustereds = list.clusterBy(paras, func.peq2('parentNode'));
-
- $.each(clustereds, function(idx, paras) {
- var head = list.head(paras);
- if (dom.isLi(head)) {
- self.releaseList([paras]);
- } else {
- $.each(paras, function(idx, para) {
- $(para).css('marginLeft', function(idx, val) {
- val = (parseInt(val, 10) || 0);
- return val > 25 ? val - 25 : '';
- });
- });
- }
- });
-
- rng.select();
- };
-
- /**
- * @method toggleList
- *
- * toggle list
- *
- * @param {String} listName - OL or UL
- */
- this.toggleList = function(listName) {
- var self = this;
- var rng = range.create().wrapBodyInlineWithPara();
-
- var paras = rng.nodes(dom.isPara, { includeAncestor: true });
- var bookmark = rng.paraBookmark(paras);
- var clustereds = list.clusterBy(paras, func.peq2('parentNode'));
-
- // paragraph to list
- if (list.find(paras, dom.isPurePara)) {
- var wrappedParas = [];
- $.each(clustereds, function(idx, paras) {
- wrappedParas = wrappedParas.concat(self.wrapList(paras, listName));
- });
- paras = wrappedParas;
- // list to paragraph or change list style
- } else {
- var diffLists = rng.nodes(dom.isList, {
- includeAncestor: true
- }).filter(function(listNode) {
- return !$.nodeName(listNode, listName);
- });
-
- if (diffLists.length) {
- $.each(diffLists, function(idx, listNode) {
- dom.replace(listNode, listName);
- });
- } else {
- paras = this.releaseList(clustereds, true);
- }
- }
-
- range.createFromParaBookmark(bookmark, paras).select();
- };
-
- /**
- * @method wrapList
- *
- * @param {Node[]} paras
- * @param {String} listName
- * @return {Node[]}
- */
- this.wrapList = function(paras, listName) {
- var head = list.head(paras);
- var last = list.last(paras);
-
- var prevList = dom.isList(head.previousSibling) && head.previousSibling;
- var nextList = dom.isList(last.nextSibling) && last.nextSibling;
-
- var listNode = prevList || dom.insertAfter(dom.create(listName || 'UL'), last);
-
- // P to LI
- paras = $.map(paras, function(para) {
- return dom.isPurePara(para) ? dom.replace(para, 'LI') : para;
- });
-
- // append to list(<ul>, <ol>)
- dom.appendChildNodes(listNode, paras);
-
- if (nextList) {
- dom.appendChildNodes(listNode, list.from(nextList.childNodes));
- dom.remove(nextList);
- }
-
- return paras;
- };
-
- /**
- * @method releaseList
- *
- * @param {Array[]} clustereds
- * @param {Boolean} isEscapseToBody
- * @return {Node[]}
- */
- this.releaseList = function(clustereds, isEscapseToBody) {
- var releasedParas = [];
-
- $.each(clustereds, function(idx, paras) {
- var head = list.head(paras);
- var last = list.last(paras);
-
- var headList = isEscapseToBody ? dom.lastAncestor(head, dom.isList) :
- head.parentNode;
- var lastList = headList.childNodes.length > 1 ? dom.splitTree(headList, {
- node: last.parentNode,
- offset: dom.position(last) + 1
- }, {
- isSkipPaddingBlankHTML: true
- }) : null;
-
- var middleList = dom.splitTree(headList, {
- node: head.parentNode,
- offset: dom.position(head)
- }, {
- isSkipPaddingBlankHTML: true
- });
-
- paras = isEscapseToBody ? dom.listDescendant(middleList, dom.isLi) :
- list.from(middleList.childNodes).filter(dom.isLi);
-
- // LI to P
- if (isEscapseToBody || !dom.isList(headList.parentNode)) {
- paras = $.map(paras, function(para) {
- return dom.replace(para, 'P');
- });
- }
-
- $.each(list.from(paras).reverse(), function(idx, para) {
- dom.insertAfter(para, headList);
- });
-
- // remove empty lists
- var rootLists = list.compact([headList, middleList, lastList]);
- $.each(rootLists, function(idx, rootList) {
- var listNodes = [rootList].concat(dom.listDescendant(rootList, dom.isList));
- $.each(listNodes.reverse(), function(idx, listNode) {
- if (!dom.nodeLength(listNode)) {
- dom.remove(listNode, true);
- }
- });
- });
-
- releasedParas = releasedParas.concat(paras);
- });
-
- return releasedParas;
- };
- };
-
-
- /**
- * @class editing.Typing
- *
- * Typing
- *
- */
- var Typing = function() {
-
- // a Bullet instance to toggle lists off
- var bullet = new Bullet();
-
- /**
- * insert tab
- *
- * @param {jQuery} $editable
- * @param {WrappedRange} rng
- * @param {Number} tabsize
- */
- this.insertTab = function($editable, rng, tabsize) {
- var tab = dom.createText(new Array(tabsize + 1).join(dom.NBSP_CHAR));
- rng = rng.deleteContents();
- rng.insertNode(tab, true);
-
- rng = range.create(tab, tabsize);
- rng.select();
- };
-
- /**
- * insert paragraph
- */
- this.insertParagraph = function() {
- var rng = range.create();
-
- // deleteContents on range.
- rng = rng.deleteContents();
-
- // Wrap range if it needs to be wrapped by paragraph
- rng = rng.wrapBodyInlineWithPara();
-
- // finding paragraph
- var splitRoot = dom.ancestor(rng.sc, dom.isPara);
-
- var nextPara;
- // on paragraph: split paragraph
- if (splitRoot) {
- // if it is an empty line with li
- if (dom.isEmpty(splitRoot) && dom.isLi(splitRoot)) {
- // disable UL/OL and escape!
- bullet.toggleList(splitRoot.parentNode.nodeName);
- return;
- // if new line has content (not a line break)
- } else {
- nextPara = dom.splitTree(splitRoot, rng.getStartPoint());
-
- var emptyAnchors = dom.listDescendant(splitRoot, dom.isEmptyAnchor);
- emptyAnchors = emptyAnchors.concat(dom.listDescendant(nextPara, dom.isEmptyAnchor));
-
- $.each(emptyAnchors, function(idx, anchor) {
- dom.remove(anchor);
- });
- }
- // no paragraph: insert empty paragraph
- } else {
- var next = rng.sc.childNodes[rng.so];
- nextPara = $(dom.emptyPara)[0];
- if (next) {
- rng.sc.insertBefore(nextPara, next);
- } else {
- rng.sc.appendChild(nextPara);
- }
- }
-
- range.create(nextPara, 0).normalize().select();
-
- };
-
- };
-
- /**
- * @class editing.Table
- *
- * Table
- *
- */
- var Table = function() {
- /**
- * handle tab key
- *
- * @param {WrappedRange} rng
- * @param {Boolean} isShift
- */
- this.tab = function(rng, isShift) {
- var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
- var table = dom.ancestor(cell, dom.isTable);
- var cells = dom.listDescendant(table, dom.isCell);
-
- var nextCell = list[isShift ? 'prev' : 'next'](cells, cell);
- if (nextCell) {
- range.create(nextCell, 0).select();
- }
- };
-
- /**
- * create empty table element
- *
- * @param {Number} rowCount
- * @param {Number} colCount
- * @return {Node}
- */
- this.createTable = function(tOptions) {
- var tds = [], tdHTML;
- var theaders = [];
- var colCount = tOptions[0];
- var rowCount = tOptions[1];
- var classes = tOptions.slice(2, tOptions.length);
-
- for (var idxCol = 0; idxCol < colCount; idxCol++) {
- //tds.push('<td>' + dom.blank + '</td>');
- tds.push('<td>(item)</td>');
- theaders.push('<th>header</th>');
- }
- tdHTML = tds.join('');
- theaders = theaders.join('');
-
- var trs = [], trHTML;
- for (var idxRow = 0; idxRow < rowCount; idxRow++) {
- trs.push('<tr>' + tdHTML + '</tr>');
- }
- trHTML = trs.join('');
-
- return $('<table class="' + classes.join(' ') + '"><thead><tr>' + theaders + '</tr></thead><tbody>' + trHTML + '</tbody></table>')[0];
- };
- };
-
-
- var KEY_BOGUS = 'bogus';
-
- /**
- * @class editing.Editor
- *
- * Editor
- *
- */
- var Editor = function(handler) {
-
- var style = new Style();
- var table = new Table();
- var typing = new Typing();
- var bullet = new Bullet();
-
- /**
- * @method createRange
- *
- * create range
- *
- * @param {jQuery} $editable
- * @return {WrappedRange}
- */
- this.createRange = function($editable) {
- this.focus($editable);
- return range.create();
- };
-
- /**
- * @method saveRange
- *
- * save current range
- *
- * @param {jQuery} $editable
- * @param {Boolean} [thenCollapse=false]
- */
- this.saveRange = function($editable, thenCollapse) {
- this.focus($editable);
- $editable.data('range', range.create());
- if (thenCollapse) {
- range.create().collapse().select();
- }
- };
-
- /**
- * @method saveRange
- *
- * save current node list to $editable.data('childNodes')
- *
- * @param {jQuery} $editable
- */
- this.saveNode = function($editable) {
- // copy child node reference
- var copy = [];
- for (var key = 0, len = $editable[0].childNodes.length; key < len; key++) {
- copy.push($editable[0].childNodes[key]);
- }
- $editable.data('childNodes', copy);
- };
-
- /**
- * @method restoreRange
- *
- * restore lately range
- *
- * @param {jQuery} $editable
- */
- this.restoreRange = function($editable) {
- var rng = $editable.data('range');
- if (rng) {
- rng.select();
- this.focus($editable);
- }
- };
-
- /**
- * @method restoreNode
- *
- * restore lately node list
- *
- * @param {jQuery} $editable
- */
- this.restoreNode = function($editable) {
- $editable.html('');
- var child = $editable.data('childNodes');
- for (var index = 0, len = child.length; index < len; index++) {
- $editable[0].appendChild(child[index]);
- }
- };
- /**
- * @method currentStyle
- *
- * current style
- *
- * @param {Node} target
- * @return {Boolean} false if range is no
- */
- this.currentStyle = function(target) {
- var rng = range.create();
- return rng ? rng.isOnEditable() && style.current(rng, target) : false;
- };
-
- var triggerOnBeforeChange = function($editable) {
- var $holder = dom.makeLayoutInfo($editable).holder();
- handler.bindCustomEvent(
- $holder, $editable.data('callbacks'), 'before.command'
- )($editable.html(), $editable);
- };
-
- var triggerOnChange = function($editable) {
- var $holder = dom.makeLayoutInfo($editable).holder();
- handler.bindCustomEvent(
- $holder, $editable.data('callbacks'), 'change'
- )($editable.html(), $editable);
- };
-
- /**
- * @method undo
- * undo
- * @param {jQuery} $editable
- */
- this.undo = function($editable) {
- triggerOnBeforeChange($editable);
- $editable.data('NoteHistory').undo();
- triggerOnChange($editable);
- };
-
- /**
- * @method redo
- * redo
- * @param {jQuery} $editable
- */
- this.redo = function($editable) {
- triggerOnBeforeChange($editable);
- $editable.data('NoteHistory').redo();
- triggerOnChange($editable);
- };
-
- var self = this;
- /**
- * @method beforeCommand
- * before command
- * @param {jQuery} $editable
- */
- var beforeCommand = this.beforeCommand = function($editable) {
- triggerOnBeforeChange($editable);
- // keep focus on editable before command execution
- self.focus($editable);
- };
-
- /**
- * @method afterCommand
- * after command
- * @param {jQuery} $editable
- * @param {Boolean} isPreventTrigger
- */
- var afterCommand = this.afterCommand = function($editable, isPreventTrigger) {
- $editable.data('NoteHistory').recordUndo();
- if (!isPreventTrigger) {
- triggerOnChange($editable);
- }
- };
-
- /**
- * @method bold
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method italic
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method underline
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method strikethrough
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method formatBlock
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method superscript
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method subscript
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method justifyLeft
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method justifyCenter
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method justifyRight
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method justifyFull
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method formatBlock
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method removeFormat
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method backColor
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method foreColor
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method insertHorizontalRule
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method fontName
- *
- * change font name
- *
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /* jshint ignore:start */
- // native commands(with execCommand), generate function for execCommand
- // >>>>>>> CK
- var commands = ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript',
- 'justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull',
- 'formatBlock', 'removeFormat',
- 'backColor', 'foreColor', 'fontName'];
-
- for (var idx = 0, len = commands.length; idx < len; idx ++) {
- this[commands[idx]] = (function(sCmd) {
- return function($editable, value) {
- beforeCommand($editable);
-
- document.execCommand(sCmd, false, value);
-
- afterCommand($editable, true);
- };
- })(commands[idx]);
- }
- /* jshint ignore:end */
-
- this.insertHorizontalRule = function() {
- var hrNode = $('<div />');
- hrNode.addClass('divider');
-
- range.create().insertNode(hrNode[0]);
- };
-
- /**
- * @method tab
- *
- * handle tab key
- *
- * @param {jQuery} $editable
- * @param {Object} options
- */
- this.tab = function($editable, options) {
- var rng = this.createRange($editable);
- if (rng.isCollapsed() && rng.isOnCell()) {
- table.tab(rng);
- } else {
- beforeCommand($editable);
- typing.insertTab($editable, rng, options.tabsize);
- afterCommand($editable);
- }
- };
-
- /**
- * @method untab
- *
- * handle shift+tab key
- *
- */
- this.untab = function($editable) {
- var rng = this.createRange($editable);
- if (rng.isCollapsed() && rng.isOnCell()) {
- table.tab(rng, true);
- }
- };
-
- /**
- * @method insertParagraph
- *
- * insert paragraph
- *
- * @param {Node} $editable
- */
- this.insertParagraph = function($editable) {
- beforeCommand($editable);
- typing.insertParagraph($editable);
- afterCommand($editable);
- };
-
- /**
- * @method insertOrderedList
- *
- * @param {jQuery} $editable
- */
- this.insertOrderedList = function($editable) {
- beforeCommand($editable);
- bullet.insertOrderedList($editable);
- afterCommand($editable);
- };
-
- /**
- * @param {jQuery} $editable
- */
- this.insertUnorderedList = function($editable) {
- beforeCommand($editable);
- bullet.insertUnorderedList($editable);
- afterCommand($editable);
- };
-
- /**
- * @param {jQuery} $editable
- */
- this.indent = function($editable) {
- beforeCommand($editable);
- bullet.indent($editable);
- afterCommand($editable);
- };
-
- /**
- * @param {jQuery} $editable
- */
- this.outdent = function($editable) {
- beforeCommand($editable);
- bullet.outdent($editable);
- afterCommand($editable);
- };
-
- /**
- * insert image
- *
- * @param {jQuery} $editable
- * @param {String} sUrl
- */
- this.insertImage = function($editable, sUrl, filename) {
- async.createImage(sUrl, filename).then(function($image) {
- beforeCommand($editable);
- $image.css({
- display: '',
- width: Math.min($editable.width(), $image.width())
- });
- range.create().insertNode($image[0]);
- range.createFromNodeAfter($image[0]).select();
- afterCommand($editable);
- }).fail(function() {
- var $holder = dom.makeLayoutInfo($editable).holder();
- handler.bindCustomEvent(
- $holder, $editable.data('callbacks'), 'image.upload.error'
- )();
- });
- };
-
- /**
- * @method insertNode
- * insert node
- * @param {Node} $editable
- * @param {Node} node
- */
- this.insertNode = function($editable, node) {
- beforeCommand($editable);
- range.create().insertNode(node);
- range.createFromNodeAfter(node).select();
- afterCommand($editable);
- };
-
- /**
- * insert text
- * @param {Node} $editable
- * @param {String} text
- */
- this.insertText = function($editable, text) {
- beforeCommand($editable);
- var textNode = range.create().insertNode(dom.createText(text));
- range.create(textNode, dom.nodeLength(textNode)).select();
- afterCommand($editable);
- };
-
- /**
- * paste HTML
- * @param {Node} $editable
- * @param {String} markup
- */
- this.pasteHTML = function($editable, markup) {
- beforeCommand($editable);
- var contents = range.create().pasteHTML(markup);
- range.createFromNodeAfter(list.last(contents)).select();
- afterCommand($editable);
- };
-
- /**
- * formatBlock
- *
- * @param {jQuery} $editable
- * @param {String} tagName
- */
- this.formatBlock = function($editable, tagName) {
- beforeCommand($editable);
- // [workaround] for MSIE, IE need `<`
- tagName = agent.isMSIE ? '<' + tagName + '>' : tagName;
- document.execCommand('FormatBlock', false, tagName);
- afterCommand($editable);
- };
-
- this.formatPara = function($editable) {
- beforeCommand($editable);
- this.formatBlock($editable, 'P');
- afterCommand($editable);
- };
-
- /* jshint ignore:start */
- for (var idx = 1; idx <= 6; idx ++) {
- this['formatH' + idx] = function(idx) {
- return function($editable) {
- this.formatBlock($editable, 'H' + idx);
- };
- }(idx);
- };
- /* jshint ignore:end */
-
- /**
- * fontSize
- *
- * @param {jQuery} $editable
- * @param {String} value - px
- */
- this.fontSize = function($editable, value) {
- var rng = range.create();
- var isCollapsed = rng.isCollapsed();
-
- if (isCollapsed) {
- var spans = style.styleNodes(rng);
- var firstSpan = list.head(spans);
-
- $(spans).css({
- 'font-size': value + 'px'
- });
-
- // [workaround] added styled bogus span for style
- // - also bogus character needed for cursor position
- if (firstSpan && !dom.nodeLength(firstSpan)) {
- firstSpan.innerHTML = dom.ZERO_WIDTH_NBSP_CHAR;
- range.createFromNodeAfter(firstSpan.firstChild).select();
- $editable.data(KEY_BOGUS, firstSpan);
- }
- } else {
- beforeCommand($editable);
- $(style.styleNodes(rng)).css({
- 'font-size': value + 'px'
- });
- afterCommand($editable);
- }
- };
-
- /**
- * remove bogus node and character
- */
- this.removeBogus = function($editable) {
- var bogusNode = $editable.data(KEY_BOGUS);
- if (!bogusNode) {
- return;
- }
-
- var textNode = list.find(list.from(bogusNode.childNodes), dom.isText);
-
- var bogusCharIdx = textNode.nodeValue.indexOf(dom.ZERO_WIDTH_NBSP_CHAR);
- if (bogusCharIdx !== -1) {
- textNode.deleteData(bogusCharIdx, 1);
- }
-
- if (dom.isEmpty(bogusNode)) {
- dom.remove(bogusNode);
- }
-
- $editable.removeData(KEY_BOGUS);
- };
-
- /**
- * lineHeight
- * @param {jQuery} $editable
- * @param {String} value
- */
- this.lineHeight = function($editable, value) {
- beforeCommand($editable);
- style.stylePara(range.create(), {
- lineHeight: value
- });
- afterCommand($editable);
- };
-
- /**
- * unlink
- *
- * @type command
- *
- * @param {jQuery} $editable
- */
- this.unlink = function($editable) {
- var rng = this.createRange($editable);
- if (rng.isOnAnchor()) {
- var anchor = dom.ancestor(rng.sc, dom.isAnchor);
- rng = range.createFromNode(anchor);
- rng.select();
-
- beforeCommand($editable);
- document.execCommand('unlink');
- afterCommand($editable);
- }
- };
-
- /**
- * create link (command)
- *
- * @param {jQuery} $editable
- * @param {Object} linkInfo
- * @param {Object} options
- */
- this.createLink = function($editable, linkInfo, options) {
- var linkUrl = linkInfo.url;
- var linkText = linkInfo.text;
- var isNewWindow = linkInfo.newWindow;
- var rng = linkInfo.range;
- var isTextChanged = rng.toString() !== linkText;
-
- beforeCommand($editable);
-
- if (options.onCreateLink) {
- linkUrl = options.onCreateLink(linkUrl);
- }
-
- var anchors = [];
- if (isTextChanged) {
- // Create a new link when text changed.
- var anchor = rng.insertNode($('<A>' + linkText + '</A>')[0]);
- anchors.push(anchor);
- } else {
- anchors = style.styleNodes(rng, {
- nodeName: 'A',
- expandClosestSibling: true,
- onlyPartialContains: true
- });
- }
-
- $.each(anchors, function(idx, anchor) {
- $(anchor).attr('href', linkUrl);
- if (isNewWindow) {
- $(anchor).attr('target', '_blank');
- } else {
- $(anchor).removeAttr('target');
- }
- });
-
- var startRange = range.createFromNodeBefore(list.head(anchors));
- var startPoint = startRange.getStartPoint();
- var endRange = range.createFromNodeAfter(list.last(anchors));
- var endPoint = endRange.getEndPoint();
-
- range.create(
- startPoint.node,
- startPoint.offset,
- endPoint.node,
- endPoint.offset
- ).select();
-
- afterCommand($editable);
- };
-
- /**
- * returns link info
- *
- * @return {Object}
- * @return {WrappedRange} return.range
- * @return {String} return.text
- * @return {Boolean} [return.isNewWindow=true]
- * @return {String} [return.url='']
- */
- this.getLinkInfo = function($editable) {
- this.focus($editable);
-
- var rng = range.create().expand(dom.isAnchor);
-
- // Get the first anchor on range(for edit).
- var $anchor = $(list.head(rng.nodes(dom.isAnchor)));
-
- return {
- range: rng,
- text: rng.toString(),
- isNewWindow: $anchor.length ? $anchor.attr('target') === '_blank' : false,
- url: $anchor.length ? $anchor.attr('href') : ''
- };
- };
-
- /**
- * setting color
- *
- * @param {Node} $editable
- * @param {Object} sObjColor color code
- * @param {String} sObjColor.foreColor foreground color
- * @param {String} sObjColor.backColor background color
- */
- this.color = function($editable, sObjColor) {
- var oColor = JSON.parse(sObjColor);
- var foreColor = oColor.foreColor, backColor = oColor.backColor;
-
- beforeCommand($editable);
-
- if (foreColor) { document.execCommand('foreColor', false, foreColor); }
- if (backColor) { document.execCommand('backColor', false, backColor); }
-
- afterCommand($editable);
- };
-
- /**
- * insert Table
- *
- * @param {Node} $editable
- * @param {String} sDim dimension of table (ex : "5x5")
- */
- this.insertTable = function($editable, sDim) {
- var tOptions = sDim.split('x');
- beforeCommand($editable);
-
- var rng = range.create().deleteContents();
- rng.insertNode(table.createTable(tOptions));
- afterCommand($editable);
- };
-
- /**
- * float me
- *
- * @param {jQuery} $editable
- * @param {String} value
- * @param {jQuery} $target
- */
- this.floatMe = function($editable, value, $target) {
- beforeCommand($editable);
- $target.css('float', value);
- afterCommand($editable);
- };
-
- /**
- * change image shape
- *
- * @param {jQuery} $editable
- * @param {String} value css class
- * @param {Node} $target
- */
- this.imageShape = function($editable, value, $target) {
- beforeCommand($editable);
-
- $target.removeClass('img-rounded img-circle img-thumbnail img-bordered');
-
- if (value) {
- $target.addClass(value);
- }
-
- afterCommand($editable);
- };
-
- /**
- * >>>>>>> CK
- * change image class
- *
- * @param {jQuery} $editable
- * @param {String} value css class
- * @param {Node} $target
- */
- this.imageClass = function($editable, value, $target) {
- beforeCommand($editable);
-
- if (value) {
- if ($target.hasClass(value)) {
- $target.removeClass(value);
- } else {
- $target.addClass(value);
- }
- }
-
- afterCommand($editable);
- };
-
- /**
- * resize overlay element
- * @param {jQuery} $editable
- * @param {String} value
- * @param {jQuery} $target - target element
- */
- this.resize = function($editable, value, $target) {
- beforeCommand($editable);
-
- $target.css({
- width: value * 100 + '%',
- height: ''
- });
-
- afterCommand($editable);
- };
-
- /**
- * @param {Position} pos
- * @param {jQuery} $target - target element
- * @param {Boolean} [bKeepRatio] - keep ratio
- */
- this.resizeTo = function(pos, $target, bKeepRatio) {
- var imageSize;
- if (bKeepRatio) {
- var newRatio = pos.y / pos.x;
- var ratio = $target.data('ratio');
- imageSize = {
- width: ratio > newRatio ? pos.x : pos.y / ratio,
- height: ratio > newRatio ? pos.x * ratio : pos.y
- };
- } else {
- imageSize = {
- width: pos.x,
- height: pos.y
- };
- }
-
- $target.css(imageSize);
- };
-
- /**
- * remove media object
- *
- * @param {jQuery} $editable
- * @param {String} value - dummy argument (for keep interface)
- * @param {jQuery} $target - target element
- */
- this.removeMedia = function($editable, value, $target) {
- beforeCommand($editable);
- $target.detach();
-
- handler.bindCustomEvent(
- $(), $editable.data('callbacks'), 'media.delete'
- )($target, $editable);
-
- afterCommand($editable);
- };
-
- /**
- * set focus
- *
- * @param $editable
- */
- this.focus = function($editable) {
- $editable.focus();
-
- // [workaround] for firefox bug http://goo.gl/lVfAaI
- if (agent.isFF && !range.create().isOnEditable()) {
- range.createFromNode($editable[0])
- .normalize()
- .collapse()
- .select();
- }
- };
-
- /**
- * returns whether contents is empty or not.
- *
- * @param {jQuery} $editable
- * @return {Boolean}
- */
- this.isEmpty = function($editable) {
- return dom.isEmpty($editable[0]) || dom.emptyPara === $editable.html();
- };
- };
-
- /**
- * @class module.Button
- *
- * Button
- */
- var Button = function() {
- /**
- * update button status
- *
- * @param {jQuery} $container
- * @param {Object} styleInfo
- */
- this.update = function($container, styleInfo) {
- /**
- * handle dropdown's check mark (for fontname, fontsize, lineHeight).
- * @param {jQuery} $btn
- * @param {Number} value
- */
- var checkDropdownMenu = function($btn, value) {
- $btn.find('.dropdown-menu li').each(function() {
-
- var div = $(this).children('div');
- var currentValue = div.data('value');
-
- // always compare string to avoid creating another func.
- if ((currentValue + '') === (value + '')) {
- div.children('i').removeClass('transparent');
- } else {
- div.children('i').addClass('transparent');
- }
- });
- };
-
- /**
- * update button state(active or not).
- *
- * @private
- * @param {String} selector
- * @param {Function} pred
- */
- var btnState = function(selector, pred) {
- var $btn = $container.find(selector);
-
- $btn.toggleClass('active', pred());
- };
-
- if (styleInfo.image) {
- var $img = $(styleInfo.image);
-
- btnState('.btn[data-event="imageClass"][data-value="img-rounded"]', function() {
- return $img.hasClass('img-rounded');
- });
- btnState('.btn[data-event="imageClass"][data-value="img-circle"]', function() {
- return $img.hasClass('img-circle');
- });
- btnState('.btn[data-event="imageClass"][data-value="img-thumbnail"]', function() {
- return $img.hasClass('img-thumbnail');
- });
- btnState('.btn[data-event="imageClass"][data-value="img-bordered"]', function() {
- return $img.hasClass('img-bordered');
- });
- btnState('.btn[data-event="imageShape"]:not([data-value])', function() {
- return !$img.is('.img-rounded, .img-circle, .img-thumbnail, .img-bordered');
- });
-
- var imgFloat = $img.css('float');
- btnState('.btn[data-event="floatMe"][data-value="left"]', function() {
- return imgFloat === 'left';
- });
- btnState('.btn[data-event="floatMe"][data-value="right"]', function() {
- return imgFloat === 'right';
- });
- btnState('.btn[data-event="floatMe"][data-value="none"]', function() {
- return imgFloat !== 'left' && imgFloat !== 'right';
- });
-
- var style = $img.attr('style');
- btnState('.btn[data-event="resize"][data-value="1"]', function() {
- return !!/(^|\s)(max-)?width\s*:\s*100%/.test(style);
- });
- btnState('.btn[data-event="resize"][data-value="0.5"]', function() {
- return !!/(^|\s)(max-)?width\s*:\s*50%/.test(style);
- });
- btnState('.btn[data-event="resize"][data-value="0.25"]', function() {
- return !!/(^|\s)(max-)?width\s*:\s*25%/.test(style);
- });
- return;
- }
-
- // fontname
- var $fontname = $container.find('.note-fontname[data-name=fontname]');
- if ($fontname.length) {
- var selectedFont = styleInfo['font-family'];
- if (!!selectedFont) {
-
- var list = selectedFont.split(',');
- for (var i = 0, len = list.length; i < len; i++) {
- selectedFont = list[i].replace(/[\'\"]/g, '').replace(/\s+$/, '').replace(/^\s+/, '');
- if (agent.isFontInstalled(selectedFont)) {
- break;
- }
- }
-
- $fontname.find('.note-current-fontname').text(selectedFont);
- checkDropdownMenu($fontname, selectedFont);
-
- }
- }
-
- // fontsize
- var $fontsize = $container.find('.note-fontsize[data-name=fontsize]');
- $fontsize.find('.note-current-fontsize').text(styleInfo['font-size']);
- checkDropdownMenu($fontsize, parseFloat(styleInfo['font-size']));
-
- // lineheight
- var $lineHeight = $container.find('.note-height[data-name=lineheight]');
- checkDropdownMenu($lineHeight, parseFloat(styleInfo['line-height']));
-
- btnState('.btn[data-event="bold"]', function() {
- return styleInfo['font-bold'] === 'bold';
- });
- btnState('.btn[data-event="italic"]', function() {
- return styleInfo['font-italic'] === 'italic';
- });
- btnState('.btn[data-event="underline"]', function() {
- return styleInfo['font-underline'] === 'underline';
- });
- btnState('.btn[data-event="strikethrough"]', function() {
- return styleInfo['font-strikethrough'] === 'strikethrough';
- });
- btnState('.btn[data-event="superscript"]', function() {
- return styleInfo['font-superscript'] === 'superscript';
- });
- btnState('.btn[data-event="subscript"]', function() {
- return styleInfo['font-subscript'] === 'subscript';
- });
- btnState('.btn[data-event="justifyLeft"]', function() {
- return styleInfo['text-align'] === 'left' || styleInfo['text-align'] === 'start';
- });
- btnState('.btn[data-event="justifyCenter"]', function() {
- return styleInfo['text-align'] === 'center';
- });
- btnState('.btn[data-event="justifyRight"]', function() {
- return styleInfo['text-align'] === 'right';
- });
- btnState('.btn[data-event="justifyFull"]', function() {
- return styleInfo['text-align'] === 'justify';
- });
- btnState('.btn[data-event="insertUnorderedList"]', function() {
- return styleInfo['list-style'] === 'unordered';
- });
- btnState('.btn[data-event="insertOrderedList"]', function() {
- return styleInfo['list-style'] === 'ordered';
- });
- };
-
- /**
- * update recent color
- *
- * @param {Node} button
- * @param {String} eventName
- * @param {Mixed} value
- */
- this.updateRecentColor = function(button, eventName, value) {
- var $color = $(button).closest('.note-color');
- var $recentColor = $color.find('.note-recent-color');
- var colorInfo = JSON.parse($recentColor.attr('data-value'));
- var sKey = eventName === 'backColor' ? 'background-color' : 'color';
-
- colorInfo[eventName] = value;
- $recentColor.attr('data-value', JSON.stringify(colorInfo));
- $recentColor.css(sKey, value);
- };
- };
-
- /**
- * @class module.Toolbar
- *
- * Toolbar
- */
- var Toolbar = function() {
- var button = new Button();
-
- this.update = function($toolbar, styleInfo) {
- button.update($toolbar, styleInfo);
- };
-
- /**
- * @param {Node} button
- * @param {String} eventName
- * @param {String} value
- */
- this.updateRecentColor = function(buttonNode, eventName, value) {
- button.updateRecentColor(buttonNode, eventName, value);
- };
-
- /**
- * activate buttons exclude codeview
- * @param {jQuery} $toolbar
- */
- this.activate = function($toolbar) {
- $toolbar.find('button, .btn')
- .not('.btn[data-event="codeview"]')
- .removeClass('disabled');
- };
-
- /**
- * deactivate buttons exclude codeview
- * @param {jQuery} $toolbar
- */
- this.deactivate = function($toolbar) {
- $toolbar.find('button, .btn')
- .not('.btn[data-event="codeview"]')
- .addClass('disabled');
- };
-
- /**
- * @param {jQuery} $container
- * @param {Boolean} [bFullscreen=false]
- */
- this.updateFullscreen = function($container, bFullscreen) {
- var $btn = $container.find('.btn[data-event="fullscreen"]');
- $btn.toggleClass('active', bFullscreen);
- };
-
- /**
- * @param {jQuery} $container
- * @param {Boolean} [isCodeview=false]
- */
- this.updateCodeview = function($container, isCodeview) {
- var $btn = $container.find('.btn[data-event="codeview"]');
- $btn.toggleClass('active', isCodeview);
-
- if (isCodeview) {
- this.deactivate($container);
- } else {
- this.activate($container);
- }
- };
-
- /**
- * get button in toolbar
- *
- * @param {jQuery} $editable
- * @param {String} name
- * @return {jQuery}
- */
- this.get = function($editable, name) {
- var $toolbar = dom.makeLayoutInfo($editable).toolbar();
-
- return $toolbar.find('[data-name=' + name + ']');
- };
-
- /**
- * set button state
- * @param {jQuery} $editable
- * @param {String} name
- * @param {Boolean} [isActive=true]
- */
- this.setButtonState = function($editable, name, isActive) {
- isActive = (isActive === false) ? false : true;
-
- var $button = this.get($editable, name);
- $button.toggleClass('active', isActive);
- };
- };
-
- var EDITABLE_PADDING = 24;
-
- var Statusbar = function() {
- var $document = $(document);
-
- this.attach = function(layoutInfo, options) {
- if (!options.disableResizeEditor) {
- layoutInfo.statusbar().on('mousedown', hStatusbarMousedown);
- }
- };
-
- /**
- * `mousedown` event handler on statusbar
- *
- * @param {MouseEvent} event
- */
- var hStatusbarMousedown = function(event) {
- event.preventDefault();
- event.stopPropagation();
-
- var $editable = dom.makeLayoutInfo(event.target).editable();
- var editableTop = $editable.offset().top - $document.scrollTop();
-
- var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);
- var options = layoutInfo.editor().data('options');
-
- $document.on('mousemove', function(event) {
- var nHeight = event.clientY - (editableTop + EDITABLE_PADDING);
-
- nHeight = (options.minHeight > 0) ? Math.max(nHeight, options.minHeight) : nHeight;
- nHeight = (options.maxHeight > 0) ? Math.min(nHeight, options.maxHeight) : nHeight;
-
- $editable.height(nHeight);
- }).one('mouseup', function() {
- $document.off('mousemove');
- });
- };
- };
-
- /**
- * @class module.Popover
- *
- * Popover (http://getbootstrap.com/javascript/#popovers)
- *
- */
- var Popover = function() {
- var button = new Button();
-
- /**
- * returns position from placeholder
- *
- * @private
- * @param {Node} placeholder
- * @param {Boolean} isAirMode
- * @return {Object}
- * @return {Number} return.left
- * @return {Number} return.top
- */
- var posFromPlaceholder = function(placeholder, isAirMode) {
- var $placeholder = $(placeholder);
- var pos = isAirMode ? $placeholder.offset() : $placeholder.position();
- var height = $placeholder.outerHeight(true); // include margin
-
- // popover below placeholder.
- return {
- left: pos.left,
- top: pos.top + height
- };
- };
-
- /**
- * show popover
- *
- * @private
- * @param {jQuery} popover
- * @param {Position} pos
- */
- var showPopover = function($popover, pos) {
- $popover.css({
- display: 'block',
- left: pos.left,
- top: pos.top
- });
- };
-
- var PX_POPOVER_ARROW_OFFSET_X = 20;
-
- /**
- * update current state
- * @param {jQuery} $popover - popover container
- * @param {Object} styleInfo - style object
- * @param {Boolean} isAirMode
- */
- this.update = function($popover, styleInfo, isAirMode) {
- button.update($popover, styleInfo);
-
- var $linkPopover = $popover.find('.note-link-popover');
- if (styleInfo.anchor) {
- var $anchor = $linkPopover.find('a');
- var href = $(styleInfo.anchor).attr('href');
- var target = $(styleInfo.anchor).attr('target');
- $anchor.attr('href', href).html(href);
- if (!target) {
- $anchor.removeAttr('target');
- } else {
- $anchor.attr('target', '_blank');
- }
- showPopover($linkPopover, posFromPlaceholder(styleInfo.anchor, isAirMode));
- } else {
- $linkPopover.hide();
- }
-
- var $imagePopover = $popover.find('.note-image-popover');
- if (styleInfo.image) {
- showPopover($imagePopover, posFromPlaceholder(styleInfo.image, isAirMode));
- } else {
- $imagePopover.hide();
- }
-
- var $airPopover = $popover.find('.note-air-popover');
- if (isAirMode && !styleInfo.range.isCollapsed()) {
- var rect = list.last(styleInfo.range.getClientRects());
- if (rect) {
- var bnd = func.rect2bnd(rect);
- showPopover($airPopover, {
- left: Math.max(bnd.left + bnd.width / 2 - PX_POPOVER_ARROW_OFFSET_X, 0),
- top: bnd.top + bnd.height
- });
- }
- } else {
- $airPopover.hide();
- }
- };
-
- /**
- * @param {Node} button
- * @param {String} eventName
- * @param {String} value
- */
- this.updateRecentColor = function(button, eventName, value) {
- button.updateRecentColor(button, eventName, value);
- };
-
- /**
- * hide all popovers
- * @param {jQuery} $popover - popover container
- */
- this.hide = function($popover) {
- $popover.children().hide();
- };
- };
-
- /**
- * @class module.Handle
- *
- * Handle
- */
- var Handle = function(handler) {
- var $document = $(document);
-
- /**
- * `mousedown` event handler on $handle
- * - controlSizing: resize image
- *
- * @param {MouseEvent} event
- */
- var hHandleMousedown = function(event) {
- if (dom.isControlSizing(event.target)) {
- event.preventDefault();
- event.stopPropagation();
-
- var layoutInfo = dom.makeLayoutInfo(event.target),
- $handle = layoutInfo.handle(),
- $popover = layoutInfo.popover(),
- $editable = layoutInfo.editable(),
- $editor = layoutInfo.editor();
-
- var target = $handle.find('.note-control-selection').data('target'),
- $target = $(target), posStart = $target.offset(),
- scrollTop = $document.scrollTop();
-
- var isAirMode = $editor.data('options').airMode;
-
- $document.on('mousemove', function(event) {
- handler.invoke('editor.resizeTo', {
- x: event.clientX - posStart.left,
- y: event.clientY - (posStart.top - scrollTop)
- }, $target, !event.shiftKey);
-
- handler.invoke('handle.update', $handle, {image: target}, isAirMode);
- handler.invoke('popover.update', $popover, {image: target}, isAirMode);
- }).one('mouseup', function() {
- $document.off('mousemove');
- handler.invoke('editor.afterCommand', $editable);
- });
-
- if (!$target.data('ratio')) { // original ratio.
- $target.data('ratio', $target.height() / $target.width());
- }
- }
- };
-
- this.attach = function(layoutInfo) {
- layoutInfo.handle().on('mousedown', hHandleMousedown);
- };
-
- /**
- * update handle
- * @param {jQuery} $handle
- * @param {Object} styleInfo
- * @param {Boolean} isAirMode
- */
- this.update = function($handle, styleInfo, isAirMode) {
- var $selection = $handle.find('.note-control-selection');
- if (styleInfo.image) {
- var $image = $(styleInfo.image);
- var pos = isAirMode ? $image.offset() : $image.position();
-
- // include margin
- var imageSize = {
- w: $image.outerWidth(true),
- h: $image.outerHeight(true)
- };
-
- $selection.css({
- display: 'block',
- left: pos.left,
- top: pos.top,
- width: imageSize.w,
- height: imageSize.h
- }).data('target', styleInfo.image); // save current image element.
- var sizingText = imageSize.w + 'x' + imageSize.h;
- $selection.find('.note-control-selection-info').text(sizingText);
- } else {
- $selection.hide();
- }
- };
-
- /**
- * hide
- *
- * @param {jQuery} $handle
- */
- this.hide = function($handle) {
- $handle.children().hide();
- };
- };
-
- var Fullscreen = function(handler) {
- var $window = $(window);
- var $scrollbar = $('html, body');
-
- /**
- * toggle fullscreen
- *
- * @param {Object} layoutInfo
- */
- this.toggle = function(layoutInfo) {
-
- var $editor = layoutInfo.editor(),
- $toolbar = layoutInfo.toolbar(),
- $editable = layoutInfo.editable(),
- $codable = layoutInfo.codable();
-
- var resize = function(size) {
- $editable.css('height', size.h);
- $codable.css('height', size.h);
- if ($codable.data('cmeditor')) {
- $codable.data('cmeditor').setsize(null, size.h);
- }
- };
-
- $editor.toggleClass('fullscreen');
- var isFullscreen = $editor.hasClass('fullscreen');
- if (isFullscreen) {
-
- $editable.data('orgheight', $editable.css('height'));
-
- $window.on('resize', function() {
- resize({
- h: $window.height() - $toolbar.outerHeight()
- });
- }).trigger('resize');
-
- $scrollbar.css('overflow', 'hidden');
- $toolbar.css('top', 0);
- } else {
- $window.off('resize');
- resize({
- h: $editable.data('orgheight')
- });
- $scrollbar.css('overflow', 'visible');
- }
-
- handler.invoke('toolbar.updateFullscreen', $toolbar, isFullscreen);
- };
- };
-
-
- var CodeMirror;
- if (agent.hasCodeMirror) {
- if (agent.isSupportAmd) {
- require(['CodeMirror'], function(cm) {
- CodeMirror = cm;
- });
- } else {
- CodeMirror = window.CodeMirror;
- }
- }
-
- /**
- * @class Codeview
- */
- var Codeview = function(handler) {
-
- this.sync = function(layoutInfo) {
- var isCodeview = handler.invoke('codeview.isActivated', layoutInfo);
- if (isCodeview && agent.hasCodeMirror) {
- layoutInfo.codable().data('cmEditor').save();
- }
- };
-
- /**
- * @param {Object} layoutInfo
- * @return {Boolean}
- */
- this.isActivated = function(layoutInfo) {
- var $editor = layoutInfo.editor();
- return $editor.hasClass('codeview');
- };
-
- /**
- * toggle codeview
- *
- * @param {Object} layoutInfo
- */
- this.toggle = function(layoutInfo) {
- if (this.isActivated(layoutInfo)) {
- this.deactivate(layoutInfo);
- } else {
- this.activate(layoutInfo);
- }
- };
-
- //var originalValue;
- /**
- * activate code view
- *
- * @param {Object} layoutInfo
- */
- this.activate = function(layoutInfo) {
- var $editor = layoutInfo.editor(),
- $toolbar = layoutInfo.toolbar(),
- $editable = layoutInfo.editable(),
- $codable = layoutInfo.codable(),
- $popover = layoutInfo.popover(),
- $handle = layoutInfo.handle();
-
- var options = $editor.data('options');
- var codeString = dom.html($editable, false);
-
- // >>>>>>> CK indentation function
- function beautifyHTML(code, level, insideLastBlock, dictionary) {
- var openTag = code.indexOf('<');
- var closeTag = code.indexOf('>');
- var chunk;
-
- if (openTag === 0) {
- //first thing is a tag
- chunk = code.substring(0, closeTag + 1);
- code = code.substring(closeTag + 1);
-
- if (chunk.indexOf("</") === 0) {
- level--;
- insideLastBlock = false;
- } else {
- if (insideLastBlock) {
- level++;
- }
-
- //check if current tag is a self closing tag (no indent next line in this case)
- var found = false;
-
- for (var i = 0; i < dictionary.length; i++) {
- if (chunk.indexOf(dictionary[i]) === 0) {
- found = true;
- break;
- }
- }
- if (!found) {
- insideLastBlock = true;
- } else {
- insideLastBlock = false;
- }
- }
- } else {
- //first thing is content
- chunk = code.substring(0, openTag);
- code = code.substring(openTag);
-
- if (insideLastBlock) {
- level++;
- }
- insideLastBlock = false;
- }
-
- if (level < 0) {
- level = 0;
- }
- chunk = new Array(level + 1).join(' ') + chunk.trim();
-
- //console.log(level);
- //console.log(chunk);
- //console.log(code);
-
- if (code.length === 0) {
- return chunk;
- }
- return chunk + "\n" + beautifyHTML(code.trim(), level, insideLastBlock, dictionary);
- }
-
- //originalValue = codeString;
-
- var selfCloseTags = ['<img', '<br', '<hr'];
- codeString = beautifyHTML(codeString, 0, false, selfCloseTags);
- // CK end -----------------------
-
- $codable.val(codeString);
-
- var buttonHeight = $toolbar.find('.btn[data-event=codeview]').height();
- var areaHeight = $(window).height() - buttonHeight;
- $codable.height($editable.height());
-
- handler.invoke('toolbar.updateCodeview', $toolbar, true);
- handler.invoke('popover.hide', $popover);
- handler.invoke('handle.hide', $handle);
-
- $editor.addClass('codeview');
-
- $codable.focus();
-
- // activate CodeMirror as codable
- if (agent.hasCodeMirror) {
- var cmEditor = CodeMirror.fromTextArea($codable[0], options.codemirror);
-
- // CodeMirror TernServer
- if (options.codemirror.tern) {
- var server = new CodeMirror.TernServer(options.codemirror.tern);
- cmEditor.ternServer = server;
- cmEditor.on('cursorActivity', function(cm) {
- server.updateArgHints(cm);
- });
- }
-
- // CodeMirror hasn't Padding.
- if ($editor.hasClass('fullscreen')) {
- cmEditor.setSize(null, areaHeight);
- }
- else {
- cmEditor.setSize(null, $editable.outerHeight());
- }
-
- $codable.data('cmEditor', cmEditor);
- }
- };
-
- /**
- * deactivate code view
- *
- * @param {Object} layoutInfo
- */
- this.deactivate = function(layoutInfo) {
- var $holder = layoutInfo.holder(),
- $editor = layoutInfo.editor(),
- $toolbar = layoutInfo.toolbar(),
- $editable = layoutInfo.editable(),
- $codable = layoutInfo.codable();
-
- var options = $editor.data('options');
-
- // deactivate CodeMirror as codable
- if (agent.hasCodeMirror) {
- var cmEditor = $codable.data('cmEditor');
- $codable.val(cmEditor.getValue());
- cmEditor.toTextArea();
- }
-
- var value = dom.value($codable, options.prettifyHtml) || dom.emptyPara;
- //var value = originalValue;
- var isChange = $editable.html() !== value;
-
- $editable.html(value);
- $editable.height(options.height ? $codable.height() : 'auto');
- $editor.removeClass('codeview');
-
- if (isChange) {
- handler.bindCustomEvent(
- $holder, $editable.data('callbacks'), 'change'
- )($editable.html(), $editable);
- }
-
- $editable.focus();
-
- handler.invoke('toolbar.updateCodeview', $toolbar, false);
- };
- };
-
- var DragAndDrop = function(handler) {
- var $document = $(document);
-
- /**
- * attach Drag and Drop Events
- *
- * @param {Object} layoutInfo - layout Informations
- * @param {Object} options
- */
- this.attach = function(layoutInfo, options) {
- if (options.airMode || options.disableDragAndDrop) {
- // prevent default drop event
- $document.on('drop', function(e) {
- e.preventDefault();
- });
- } else {
- this.attachDragAndDropEvent(layoutInfo, options);
- }
- };
-
- /**
- * attach Drag and Drop Events
- *
- * @param {Object} layoutInfo - layout Informations
- * @param {Object} options
- */
- this.attachDragAndDropEvent = function(layoutInfo, options) {
- var collection = $(),
- $editor = layoutInfo.editor(),
- $dropzone = layoutInfo.dropzone(),
- $dropzoneMessage = $dropzone.find('.note-dropzone-message');
-
- // show dropzone on dragenter when dragging a object to document
- // -but only if the editor is visible, i.e. has a positive width and height
- $document.on('dragenter', function(e) {
- var isCodeview = handler.invoke('codeview.isActivated', layoutInfo);
- var hasEditorSize = $editor.width() > 0 && $editor.height() > 0;
- if (!isCodeview && !collection.length && hasEditorSize) {
- $editor.addClass('dragover');
- $dropzone.width($editor.width());
- $dropzone.height($editor.height());
- $dropzoneMessage.text(options.langInfo.image.dragImageHere);
- }
- collection = collection.add(e.target);
- }).on('dragleave', function(e) {
- collection = collection.not(e.target);
- if (!collection.length) {
- $editor.removeClass('dragover');
- }
- }).on('drop', function() {
- collection = $();
- $editor.removeClass('dragover');
- });
-
- // change dropzone's message on hover.
- $dropzone.on('dragenter', function() {
- $dropzone.addClass('hover');
- $dropzoneMessage.text(options.langInfo.image.dropImage);
- }).on('dragleave', function() {
- $dropzone.removeClass('hover');
- $dropzoneMessage.text(options.langInfo.image.dragImageHere);
- });
-
- // attach dropImage
- $dropzone.on('drop', function(event) {
-
- var dataTransfer = event.originalEvent.dataTransfer;
- var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);
-
- if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {
- event.preventDefault();
- layoutInfo.editable().focus();
- handler.insertImages(layoutInfo, dataTransfer.files);
- } else {
- var insertNodefunc = function() {
- layoutInfo.holder().materialnote('insertNode', this);
- };
-
- for (var i = 0, len = dataTransfer.types.length; i < len; i++) {
- var type = dataTransfer.types[i];
- var content = dataTransfer.getData(type);
-
- if (type.toLowerCase().indexOf('text') > -1) {
- layoutInfo.holder().materialnote('pasteHTML', content);
- } else {
- $(content).each(insertNodefunc);
- }
- }
- }
- }).on('dragover', false); // prevent default dragover event
- };
- };
-
- var Clipboard = function(handler) {
-
- var $paste;
-
- this.attach = function(layoutInfo) {
-
- if (window.clipboardData || agent.isFF) {
- $paste = $('<div />').attr('contenteditable', true).css({
- position : 'absolute',
- left : -100000,
- 'opacity' : 0
- });
- layoutInfo.editable().after($paste);
- $paste.one('paste', hPasteClipboardImage);
-
- layoutInfo.editable().on('keydown', function(e) {
- if (e.ctrlKey && e.keyCode === 86) { // CTRL+V
- handler.invoke('saveRange', layoutInfo.editable());
- if ($paste) {
- $paste.focus();
- }
- }
- });
- }
-
- layoutInfo.editable().on('paste', hPasteClipboardImage);
- };
-
- /**
- * paste clipboard image
- *
- * @param {Event} event
- */
- var hPasteClipboardImage = function(event) {
-
- var clipboardData = event.originalEvent.clipboardData;
- var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);
- var $editable = layoutInfo.editable();
-
- if (!clipboardData || !clipboardData.items || !clipboardData.items.length) {
-
- var callbacks = $editable.data('callbacks');
- // only can run if it has onImageUpload method
- if (!callbacks.onImageUpload) {
- return;
- }
-
- setTimeout(function() {
- if (!$paste) {
- return;
- }
-
- var imgNode = $paste[0].firstChild;
- if (!imgNode) {
- return;
- }
-
- handler.invoke('restoreRange', $editable);
- if (!dom.isImg(imgNode)) {
- handler.invoke('pasteHTML', $editable, $paste.html());
- } else {
- var datauri = imgNode.src;
-
- var data = atob(datauri.split(',')[1]);
- var array = new Uint8Array(data.length);
- for (var i = 0; i < data.length; i++) {
- array[i] = data.charCodeAt(i);
- }
-
- var blob = new Blob([array], { type : 'image/png' });
- blob.name = 'clipboard.png';
- handler.invoke('focus', $editable);
- handler.insertImages(layoutInfo, [blob]);
- }
-
- $paste.remove();
-
- }, 0);
-
- return;
- }
-
- var item = list.head(clipboardData.items);
- var isClipboardImage = item.kind === 'file' && item.type.indexOf('image/') !== -1;
-
- if (isClipboardImage) {
- handler.insertImages(layoutInfo, [item.getAsFile()]);
- }
-
- handler.invoke('editor.afterCommand', $editable);
- };
- };
-
- var LinkDialog = function(handler) {
-
- /**
- * toggle button status
- *
- * @private
- * @param {jQuery} $btn
- * @param {Boolean} isEnable
- */
- var toggleBtn = function($btn, isEnable) {
- $btn.toggleClass('disabled', !isEnable);
- $btn.attr('disabled', !isEnable);
- };
-
- /**
- * bind enter key
- *
- * @private
- * @param {jQuery} $input
- * @param {jQuery} $btn
- */
- var bindEnterKey = function($input, $btn) {
- $input.on('keypress', function(event) {
- if (event.keyCode === key.code.ENTER) {
- $btn.trigger('click');
- }
- });
- };
-
- /**
- * Show link dialog and set event handlers on dialog controls.
- *
- * @param {jQuery} $editable
- * @param {jQuery} $dialog
- * @param {Object} linkInfo
- * @return {Promise}
- */
- this.showLinkDialog = function($editable, $dialog, linkInfo) {
- return $.Deferred(function(deferred) {
- var $linkDialog = $dialog.find('.note-link-dialog');
- var $linkText = $linkDialog.find('.note-link-text'),
- $linkTextLabel = $linkText.next('label'),
- $linkUrl = $linkDialog.find('.note-link-url'),
- $linkBtn = $linkDialog.find('.note-link-btn'),
- $closeBtn = $linkDialog.find('.btnClose');
- var $openInNewWindow = $linkDialog.find('input[type=checkbox]');
-
- $linkDialog.openModal();
- $linkText.val(linkInfo.text);
- if (linkInfo.text.length > 0) $linkTextLabel.addClass('active');
-
- $linkText.on('keyup', function() {
- toggleBtn($linkBtn, $linkText.val() && $linkUrl.val());
- // if linktext was modified by keyup,
- // stop cloning text from linkUrl
- linkInfo.text = $linkText.val();
- });
-
- $closeBtn.click(function(event) {
- event.preventDefault();
-
- $linkDialog.closeModal();
- });
-
- // if no url was given, copy text to url
- if (!linkInfo.url) {
- linkInfo.url = linkInfo.text || 'http://';
- toggleBtn($linkBtn, linkInfo.text);
- }
-
- $linkUrl.on('keyup', function() {
- toggleBtn($linkBtn, $linkText.val() && $linkUrl.val());
- // display same link on `Text to display` input
- // when create a new link
- if (!linkInfo.text) {
- $linkTextLabel.addClass('active');
- $linkText.val($linkUrl.val());
- }
- }).val(linkInfo.url).trigger('focus').trigger('select');
-
- bindEnterKey($linkUrl, $linkBtn);
- bindEnterKey($linkText, $linkBtn);
-
- $openInNewWindow.prop('checked', linkInfo.newWindow);
-
- $linkBtn.one('click', function(event) {
- event.preventDefault();
-
- deferred.resolve({
- range: linkInfo.range,
- url: $linkUrl.val(),
- text: $linkText.val(),
- newWindow: $openInNewWindow.is(':checked')
- });
-
- $('.note-link-text').val('');
- $('.note-link-text').next('label').removeClass('active');
- $('.note-link-url').val('');
- $linkDialog.closeModal();
- });
- }).promise();
- };
-
- /**
- * @param {Object} layoutInfo
- */
- this.show = function(layoutInfo) {
- var $editor = layoutInfo.editor(),
- $dialog = layoutInfo.dialog(),
- $editable = layoutInfo.editable(),
- $popover = layoutInfo.popover(),
- linkInfo = handler.invoke('editor.getLinkInfo', $editable);
-
- var options = $editor.data('options');
-
- handler.invoke('editor.saveRange', $editable);
- this.showLinkDialog($editable, $dialog, linkInfo).then(function(linkInfo) {
- handler.invoke('editor.restoreRange', $editable);
- handler.invoke('editor.createLink', $editable, linkInfo, options);
- // hide popover after creating link
- handler.invoke('popover.hide', $popover);
- }).fail(function() {
- handler.invoke('editor.restoreRange', $editable);
- });
- };
- };
-
- var ImageDialog = function(handler) {
- /**
- * toggle button status
- *
- * @private
- * @param {jQuery} $btn
- * @param {Boolean} isEnable
- */
- var toggleBtn = function($btn, isEnable) {
- $btn.toggleClass('disabled', !isEnable);
- $btn.attr('disabled', !isEnable);
- };
-
- /**
- * bind enter key
- *
- * @private
- * @param {jQuery} $input
- * @param {jQuery} $btn
- */
- var bindEnterKey = function($input, $btn) {
- $input.on('keypress', function(event) {
- if (event.keyCode === key.code.ENTER) {
- $btn.trigger('click');
- }
- });
- };
-
- this.show = function(layoutInfo) {
- var $dialog = layoutInfo.dialog(),
- $editable = layoutInfo.editable();
-
- handler.invoke('editor.saveRange', $editable);
- this.showImageDialog($editable, $dialog).then(function(data) {
- handler.invoke('editor.restoreRange', $editable);
-
- if (typeof data === 'string') {
- // image url
- handler.invoke('editor.insertImage', $editable, data);
- } else {
- // array of files
- handler.insertImages(layoutInfo, data);
- }
- }).fail(function() {
- handler.invoke('editor.restoreRange', $editable);
- });
- };
-
- /**
- * show image dialog
- *
- * @param {jQuery} $editable
- * @param {jQuery} $dialog
- * @return {Promise}
- */
- this.showImageDialog = function($editable, $dialog) {
- return $.Deferred(function(deferred) {
- var $imageDialog = $dialog.find('.note-image-dialog');
- var $imageInput = $dialog.find('.note-image-input'),
- $imageUrl = $dialog.find('.note-image-url'),
- $imageBtn = $dialog.find('.note-image-btn'),
- $closeBtn = $imageDialog.find('.btnClose');
-
- $imageDialog.openModal();
- // Cloning imageInput to clear element.
- $imageInput.replaceWith($imageInput.clone()
- .on('change', function() {
- deferred.resolve(this.files || this.value);
- $imageUrl.val('');
- $imageDialog.closeModal();
- deferred.resolve();
- })
- .val('')
- );
-
- $imageBtn.click(function(event) {
- event.preventDefault();
-
- deferred.resolve($imageUrl.val());
- $imageUrl.val('');
- $imageDialog.closeModal();
- deferred.resolve();
- });
-
- $closeBtn.click(function(event) {
- event.preventDefault();
-
- $imageDialog.closeModal();
- });
-
- $imageUrl.on('keyup paste', function(event) {
- var url;
-
- if (event.type === 'paste') {
- url = event.originalEvent.clipboardData.getData('text');
- } else {
- url = $imageUrl.val();
- }
- toggleBtn($imageBtn, url);
- });
-
- bindEnterKey($imageUrl, $imageBtn);
- });
- };
- };
-
- var HelpDialog = function(handler) {
- /**
- * show help dialog
- *
- * @param {jQuery} $editable
- * @param {jQuery} $dialog
- * @return {Promise}
- */
- this.showHelpDialog = function($editable, $dialog) {
- return $.Deferred(function(deferred) {
- var $helpDialog = $dialog.find('.note-help-dialog');
-
- $helpDialog.openModal();
- deferred.resolve();
- }).promise();
- };
-
- /**
- * @param {Object} layoutInfo
- */
- this.show = function(layoutInfo) {
- var $dialog = layoutInfo.dialog(),
- $editable = layoutInfo.editable();
-
- handler.invoke('editor.saveRange', $editable, true);
- this.showHelpDialog($editable, $dialog).then(function() {
- handler.invoke('editor.restoreRange', $editable);
- });
- };
- };
-
-
- /**
- * @class EventHandler
- *
- * EventHandler
- * - TODO: new instance per a editor
- */
- var EventHandler = function() {
- /**
- * Modules
- */
- var modules = this.modules = {
- editor: new Editor(this),
- toolbar: new Toolbar(this),
- statusbar: new Statusbar(this),
- popover: new Popover(this),
- handle: new Handle(this),
- fullscreen: new Fullscreen(this),
- codeview: new Codeview(this),
- dragAndDrop: new DragAndDrop(this),
- clipboard: new Clipboard(this),
- linkDialog: new LinkDialog(this),
- imageDialog: new ImageDialog(this),
- helpDialog: new HelpDialog(this)
- };
-
- /**
- * invoke module's method
- *
- * @param {String} moduleAndMethod - ex) 'editor.redo'
- * @param {...*} arguments - arguments of method
- * @return {*}
- */
- this.invoke = function() {
- var moduleAndMethod = list.head(list.from(arguments));
- var args = list.tail(list.from(arguments));
-
- var splits = moduleAndMethod.split('.');
- var hasSeparator = splits.length > 1;
- var moduleName = hasSeparator && list.head(splits);
- var methodName = hasSeparator ? list.last(splits) : list.head(splits);
-
- var module = this.getModule(moduleName);
- var method = module[methodName];
-
- return method && method.apply(module, args);
- };
-
- /**
- * returns module
- *
- * @param {String} moduleName - name of module
- * @return {Module} - defaults is editor
- */
- this.getModule = function(moduleName) {
- return this.modules[moduleName] || this.modules.editor;
- };
-
- /**
- * @param {jQuery} $holder
- * @param {Object} callbacks
- * @param {String} eventNamespace
- * @returns {Function}
- */
- var bindCustomEvent = this.bindCustomEvent = function($holder, callbacks, eventNamespace) {
- return function() {
- var callback = callbacks[func.namespaceToCamel(eventNamespace, 'on')];
- if (callback) {
- callback.apply($holder[0], arguments);
- }
- return $holder.trigger('materialnote.' + eventNamespace, arguments);
- };
- };
-
- /**
- * insert Images from file array.
- *
- * @private
- * @param {Object} layoutInfo
- * @param {File[]} files
- */
- this.insertImages = function(layoutInfo, files) {
- var $editor = layoutInfo.editor(),
- $editable = layoutInfo.editable(),
- $holder = layoutInfo.holder();
-
- var callbacks = $editable.data('callbacks');
- var options = $editor.data('options');
-
- // If onImageUpload options setted
- if (callbacks.onImageUpload) {
- bindCustomEvent($holder, callbacks, 'image.upload')(files);
- // else insert Image as dataURL
- } else {
- $.each(files, function(idx, file) {
- var filename = file.name;
- if (options.maximumImageFileSize && options.maximumImageFileSize < file.size) {
- bindCustomEvent($holder, callbacks, 'image.upload.error')(options.langInfo.image.maximumFileSizeError);
- } else {
- async.readFileAsDataURL(file).then(function(sDataURL) {
- modules.editor.insertImage($editable, sDataURL, filename);
- }).fail(function() {
- bindCustomEvent($holder, callbacks, 'image.upload.error')(options.langInfo.image.maximumFileSizeError);
- });
- }
- });
- }
- };
-
- var commands = {
- /**
- * @param {Object} layoutInfo
- */
- showLinkDialog: function(layoutInfo) {
- modules.linkDialog.show(layoutInfo);
- },
-
- /**
- * @param {Object} layoutInfo
- */
- showImageDialog: function(layoutInfo) {
- modules.imageDialog.show(layoutInfo);
- },
-
- /**
- * @param {Object} layoutInfo
- */
- showHelpDialog: function(layoutInfo) {
- modules.helpDialog.show(layoutInfo);
- },
-
- /**
- * @param {Object} layoutInfo
- */
- fullscreen: function(layoutInfo) {
- modules.fullscreen.toggle(layoutInfo);
- },
-
- /**
- * @param {Object} layoutInfo
- */
- codeview: function(layoutInfo) {
- modules.codeview.toggle(layoutInfo);
- }
- };
-
- var hMousedown = function(event) {
- //preventDefault Selection for FF, IE8+
- if (dom.isImg(event.target)) {
- event.preventDefault();
- }
- };
-
- var hKeyupAndMouseup = function(event) {
- var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);
- modules.editor.removeBogus(layoutInfo.editable());
- hToolbarAndPopoverUpdate(event);
- };
-
- var hToolbarAndPopoverUpdate = function(event) {
- // delay for range after mouseup
- setTimeout(function() {
- var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);
- var styleInfo = modules.editor.currentStyle(event.target);
- if (!styleInfo) { return; }
-
- var isAirMode = layoutInfo.editor().data('options').airMode;
- if (!isAirMode) {
- modules.toolbar.update(layoutInfo.toolbar(), styleInfo);
- }
-
- modules.popover.update(layoutInfo.popover(), styleInfo, isAirMode);
- modules.handle.update(layoutInfo.handle(), styleInfo, isAirMode);
- }, 0);
- };
-
- var hScroll = function(event) {
- var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);
- //hide popover and handle when scrolled
- modules.popover.hide(layoutInfo.popover());
- modules.handle.hide(layoutInfo.handle());
- };
-
- var hToolbarAndPopoverMousedown = function(event) {
- // prevent default event when insertTable (FF, Webkit)
- var $btn = $(event.target).closest('[data-event]');
- if ($btn.length) {
- event.preventDefault();
- }
- };
-
- var hToolbarAndPopoverClick = function(event) {
- var $btn = $(event.target).closest('[data-event]');
-
- if ($btn.length) {
- var eventName = $btn.attr('data-event'),
- value = $btn.attr('data-value'),
- hide = $btn.attr('data-hide');
-
- var layoutInfo = dom.makeLayoutInfo(event.target);
-
- // before command: detect control selection element($target)
- var $target;
- if ($.inArray(eventName, ['resize', 'floatMe', 'removeMedia', 'imageShape', 'imageClass']) !== -1) {
- var $selection = layoutInfo.handle().find('.note-control-selection');
- $target = $($selection.data('target'));
- }
-
- // If requested, hide the popover when the button is clicked.
- // Useful for things like showHelpDialog.
- if (hide) {
- $btn.parents('.popover').hide();
- }
-
- if ($.isFunction($.materialnote.pluginEvents[eventName])) {
- $.materialnote.pluginEvents[eventName](event, modules.editor, layoutInfo, value);
- } else if (modules.editor[eventName]) { // on command
- var $editable = layoutInfo.editable();
- $editable.focus();
- modules.editor[eventName]($editable, value, $target);
- event.preventDefault();
- } else if (commands[eventName]) {
- commands[eventName].call(this, layoutInfo);
- event.preventDefault();
- }
-
- // after command
- if ($.inArray(eventName, ['backColor', 'foreColor']) !== -1) {
- var options = layoutInfo.editor().data('options', options);
- var module = options.airMode ? modules.popover : modules.toolbar;
- module.updateRecentColor(list.head($btn), eventName, value);
- }
-
- hToolbarAndPopoverUpdate(event);
- }
- };
-
- var gridUnit = 26;
- var hDimensionPickerMove = function(event, options) {
- var $picker = $(event.target.parentNode); // target is mousecatcher
- var $dropdown = $picker.parent();
- var $dimensionDisplay = $picker.next();
- var $catcher = $picker.find('.note-dimension-picker-mousecatcher');
- var $highlighted = $picker.find('.note-dimension-picker-highlighted');
- var $unhighlighted = $picker.find('.note-dimension-picker-unhighlighted');
- var $hoverableOption = $dropdown.find("[id$='-hoverable']");
- var $borderedOption = $dropdown.find("[id$='-bordered']");
- var $stripedOption = $dropdown.find("[id$='-striped']");
- var $responsiveOption = $dropdown.find("[id$='-responsive']");
-
- var posOffset;
- // HTML5 with jQuery - e.offsetX is undefined in Firefox
- if (event.offsetX === undefined) {
- var posCatcher = $(event.target).offset();
-
- posOffset = {
- x: event.pageX - posCatcher.left,
- y: event.pageY - posCatcher.top
- };
- } else {
- posOffset = {
- x: event.offsetX,
- y: event.offsetY
- };
- }
-
- var dim = {
- c: Math.ceil(posOffset.x / gridUnit) || 1,
- r: Math.ceil(posOffset.y / gridUnit) || 1
- };
- /*console.log(posOffset);
- console.log(dim);
- console.log('------------------');*/
-
- var tableOptions = [];
- if ($hoverableOption.is(':checked')) tableOptions.push('hoverable');
- if ($borderedOption.is(':checked')) tableOptions.push('bordered');
- if ($stripedOption.is(':checked')) tableOptions.push('striped');
- if ($responsiveOption.is(':checked')) tableOptions.push('responsive-table');
-
- $highlighted.css({ width: (dim.c * gridUnit) + 'px', height: (dim.r * gridUnit) + 'px' });
- $catcher.attr('data-value', dim.c + 'x' + dim.r + 'x' + tableOptions.join('x'));
-
- //if (3 < dim.c && dim.c < options.insertTableMaxSize.col) {
- $unhighlighted.css({ width: (options.insertTableMaxSize * gridUnit) + 'px'});
- //}
-
- if (3 < dim.r && dim.r < options.insertTableMaxSize.row) {
- $unhighlighted.css({ height: ((dim.r + 1) * gridUnit) + 'px'});
- }
-
- $dimensionDisplay.html(dim.c + ' x ' + dim.r);
- };
-
- /**
- * bind KeyMap on keydown
- *
- * @param {Object} layoutInfo
- * @param {Object} keyMap
- */
- this.bindKeyMap = function(layoutInfo, keyMap) {
- var $editor = layoutInfo.editor();
- var $editable = layoutInfo.editable();
-
- $editable.on('keydown', function(event) {
- var keys = [];
-
- // modifier
- if (event.metaKey) { keys.push('CMD'); }
- if (event.ctrlKey && !event.altKey) { keys.push('CTRL'); }
- if (event.shiftKey) { keys.push('SHIFT'); }
-
- // keycode
- var keyName = key.nameFromCode[event.keyCode];
- if (keyName) {
- keys.push(keyName);
- }
-
- var pluginEvent;
- var keyString = keys.join('+');
- var eventName = keyMap[keyString];
- if (eventName) {
- // FIXME materialnote doesn't support event pipeline yet.
- // - Plugin -> Base Code
- pluginEvent = $.materialnote.pluginEvents[keyString];
- if ($.isFunction(pluginEvent)) {
- if (pluginEvent(event, modules.editor, layoutInfo)) {
- return false;
- }
- }
-
- pluginEvent = $.materialnote.pluginEvents[eventName];
-
- if ($.isFunction(pluginEvent)) {
- pluginEvent(event, modules.editor, layoutInfo);
- } else if (modules.editor[eventName]) {
- modules.editor[eventName]($editable, $editor.data('options'));
- event.preventDefault();
- } else if (commands[eventName]) {
- commands[eventName].call(this, layoutInfo);
- event.preventDefault();
- }
- } else if (key.isEdit(event.keyCode)) {
- modules.editor.afterCommand($editable);
- }
- });
- };
-
- /**
- * attach eventhandler
- *
- * @param {Object} layoutInfo - layout Informations
- * @param {Object} options - user options include custom event handlers
- */
- this.attach = function(layoutInfo, options) {
- // handlers for editable
- if (options.shortcuts) {
- this.bindKeyMap(layoutInfo, options.keyMap[agent.isMac ? 'mac' : 'pc']);
- }
- layoutInfo.editable().on('mousedown', hMousedown);
- layoutInfo.editable().on('keyup mouseup', hKeyupAndMouseup);
- layoutInfo.editable().on('scroll', hScroll);
-
- // handler for clipboard
- modules.clipboard.attach(layoutInfo, options);
-
- // handler for handle and popover
- modules.handle.attach(layoutInfo, options);
- layoutInfo.popover().on('click', hToolbarAndPopoverClick);
- layoutInfo.popover().on('mousedown', hToolbarAndPopoverMousedown);
-
- // handler for drag and drop
- modules.dragAndDrop.attach(layoutInfo, options);
-
- // handlers for frame mode (toolbar, statusbar)
- if (!options.airMode) {
- // handler for toolbar
- layoutInfo.toolbar().on('click', hToolbarAndPopoverClick);
- layoutInfo.toolbar().on('mousedown', hToolbarAndPopoverMousedown);
-
- // handler for statusbar
- modules.statusbar.attach(layoutInfo, options);
- }
-
- // handler for table dimension
- var $catcherContainer = options.airMode ? layoutInfo.popover() :
- layoutInfo.toolbar();
- var $catcher = $catcherContainer.find('.note-dimension-picker-mousecatcher');
- $catcher.css({
- width: options.insertTableMaxSize.col * gridUnit + 'px',
- height: options.insertTableMaxSize.row * gridUnit + 'px'
- }).on('mousemove', function(event) {
- hDimensionPickerMove(event, options);
- });
-
- // save options on editor
- layoutInfo.editor().data('options', options);
-
- // ret styleWithCSS for backColor / foreColor clearing with 'inherit'.
- if (!agent.isMSIE) {
- // [workaround] for Firefox
- // - protect FF Error: NS_ERROR_FAILURE: Failure
- setTimeout(function() {
- document.execCommand('styleWithCSS', 0, options.styleWithSpan);
- }, 0);
- }
-
- // History
- var history = new History(layoutInfo.editable());
- layoutInfo.editable().data('NoteHistory', history);
-
- // All editor status will be saved on editable with jquery's data
- // for support multiple editor with singleton object.
- layoutInfo.editable().data('callbacks', {
- onInit: options.onInit,
- onFocus: options.onFocus,
- onBlur: options.onBlur,
- onKeydown: options.onKeydown,
- onKeyup: options.onKeyup,
- onMousedown: options.onMousedown,
- onEnter: options.onEnter,
- onPaste: options.onPaste,
- onBeforeCommand: options.onBeforeCommand,
- onChange: options.onChange,
- onImageUpload: options.onImageUpload,
- onImageUploadError: options.onImageUploadError,
- onMediaDelete: options.onMediaDelete,
- onToolbarClick: options.onToolbarClick
- });
-
- // Textarea: auto filling the code before form submit.
- if (dom.isTextarea(list.head(layoutInfo.holder()))) {
- layoutInfo.holder().closest('form').submit(function() {
- layoutInfo.holder().val(layoutInfo.holder().code());
- });
- }
- };
-
- /**
- * attach jquery custom event
- *
- * @param {Object} layoutInfo - layout Informations
- */
- this.attachCustomEvent = function(layoutInfo, options) {
- var $holder = layoutInfo.holder();
- var $editable = layoutInfo.editable();
- var callbacks = $editable.data('callbacks');
-
- $editable.focus(bindCustomEvent($holder, callbacks, 'focus'));
- $editable.blur(bindCustomEvent($holder, callbacks, 'blur'));
-
- $editable.keydown(function(event) {
- if (event.keyCode === key.code.ENTER) {
- bindCustomEvent($holder, callbacks, 'enter').call(this, event);
- }
- bindCustomEvent($holder, callbacks, 'keydown').call(this, event);
- });
- $editable.keyup(bindCustomEvent($holder, callbacks, 'keyup'));
-
- $editable.on('mousedown', bindCustomEvent($holder, callbacks, 'mousedown'));
- $editable.on('mouseup', bindCustomEvent($holder, callbacks, 'mouseup'));
- $editable.on('scroll', bindCustomEvent($holder, callbacks, 'scroll'));
-
- $editable.on('paste', bindCustomEvent($holder, callbacks, 'paste'));
-
- // [workaround] for old IE - IE8 don't have input events
- // - TODO check IE version
- var changeEventName = agent.isMSIE ? 'DOMCharacterDataModified DOMSubtreeModified DOMNodeInserted' : 'input';
- $editable.on(changeEventName, function() {
- bindCustomEvent($holder, callbacks, 'change')($editable.html(), $editable);
- });
-
- if (!options.airMode) {
- layoutInfo.toolbar().click(bindCustomEvent($holder, callbacks, 'toolbar.click'));
- layoutInfo.popover().click(bindCustomEvent($holder, callbacks, 'popover.click'));
- }
-
- // Textarea: auto filling the code before form submit.
- if (dom.isTextarea(list.head($holder))) {
- $holder.closest('form').submit(function(e) {
- bindCustomEvent($holder, callbacks, 'submit').call(this, e, $holder.code());
- });
- }
-
- // fire init event
- bindCustomEvent($holder, callbacks, 'init')(layoutInfo);
-
- // fire plugin init event
- for (var i = 0, len = $.materialnote.plugins.length; i < len; i++) {
- if ($.isFunction($.materialnote.plugins[i].init)) {
- $.materialnote.plugins[i].init(layoutInfo);
- }
- }
- };
-
- this.detach = function(layoutInfo, options) {
- layoutInfo.holder().off();
- layoutInfo.editable().off();
-
- layoutInfo.popover().off();
- layoutInfo.handle().off();
- layoutInfo.dialog().off();
-
- if (!options.airMode) {
- layoutInfo.dropzone().off();
- layoutInfo.toolbar().off();
- layoutInfo.statusbar().off();
- }
- };
- };
-
- /**
- * @class Renderer
- *
- * renderer
- *
- * rendering toolbar and editable
- */
- var Renderer = function() {
-
- /**
- * bootstrap button template
- * @private
- * @param {String} label button name
- * @param {Object} [options] button options
- * @param {String} [options.event] data-event
- * @param {String} [options.className] button's class name
- * @param {String} [options.value] data-value
- * @param {String} [options.title] button's title for popup
- * @param {String} [options.dropdown] dropdown html
- * @param {String} [options.hide] data-hide
- */
-
- // >>>>>>> CK altered
- var tplButton = function(label, options) {
- var event = options.event;
- var value = options.value;
- var title = options.title;
- var style = options.style;
- var btnClassName = options.btnClassName;
- var className = options.className;
- var dropdown = options.dropdown;
- var hide = options.hide;
-
- if (!dropdown) {
- var button = [
- '<div class="waves-effect waves-light btn',
- (className ? " " + className : '') + '"',
- (title ? ' title="' + title + '"' : ''),
- (style ? ' style="' + style + '"' : ''),
- (event ? ' data-event="' + event + '"' : ''),
- (value ? ' data-value=\'' + value + '\'' : ''),
- (hide ? ' data-hide=\'' + hide + '\'' : ''),
- ' tabindex="-1">' + label + '</div>'
- ].join('');
-
- return button;
- } else {
- var list = [
- '<div class="btn-group',
- (className ? " " + className : '') + '">',
- '<button class="waves-effect waves-light btn dropdown ' + (btnClassName ? btnClassName : '') + '"',
- (title ? ' title="' + title + '"' : ''),
- (event ? ' data-event="' + event + '"' : ''),
- (value ? ' data-value=\'' + value + '\'' : ''),
- (hide ? ' data-hide=\'' + hide + '\'' : ''),
- '><i class="material-icons left">arrow_drop_down</i>' + label + '</button>',
- dropdown,
- '</div>'
- ].join('');
-
- return list;
- }
- };
-
- /**
- * bootstrap icon button template
- * @private
- * @param {String} iconClassName
- * @param {Object} [options]
- * @param {String} [options.event]
- * @param {String} [options.value]
- * @param {String} [options.title]
- * @param {String} [options.dropdown]
- */
- // >>>>>>> CK
- var tplIconButton = function(iconClassName, options) {
- var label = '<i class="material-icons">' + iconClassName + '</i>';
- return tplButton(label, options);
- };
-
- /**
- * bootstrap popover template
- * @private
- * @param {String} className
- * @param {String} content
- */
- var tplPopover = function(className, content) {
- var $popover = $('<div class="' + className + ' popover bottom in" style="display: none;">' +
- '<div class="arrow"></div>' +
- '<div class="popover-content">' +
- '</div>' +
- '</div>');
-
- $popover.find('.popover-content').append(content);
- return $popover;
- };
-
- /**
- * bootstrap dialog template
- *
- * @param {String} className
- * @param {String} [title='']
- * @param {String} body
- * @param {String} [footer='']
- */
- // >>>>>>> CK dialog
- var tplDialog = function(className, title, body, footer) {
-
- var modal = [
- '<div class="' + className + ' modal modal-fixed-footer">',
- '<div class="modal-content">',
- (title ? '<h4>' + title + '</h4>' : ''),
- '<p>' + body + '</p>',
- '</div>',
- (footer ? '<div class="modal-footer">' + footer + '</div>' : ''),
- '</div>'
- ].join('');
-
- return modal;
- };
-
- var tplButtonInfo = {
- picture: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.image.image, {
- event: 'showImageDialog',
- title: lang.image.image,
- hide: true
- });
- },
- link: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.link.link, {
- event: 'showLinkDialog',
- title: lang.link.link,
- hide: true
- });
- },
- table: function(lang, options) {
- var dropdown = '<ul class="note-table dropdown-menu">' +
- '<div class="row">' +
- '<div class="col s6 preventDropClose"><input type="checkbox" id="' + materialUniqueId + '-bordered" checked="checked" /><label for="' + materialUniqueId + '-bordered">' + lang.table.bordered + '</label></div>' +
- '<div class="col s6 preventDropClose"><input type="checkbox" id="' + materialUniqueId + '-striped" checked="checked" /><label for="' + materialUniqueId + '-striped">' + lang.table.striped + '</label></div>' +
- '</div>' +
- '<div class="row">' +
- '<div class="col s6 preventDropClose"><input type="checkbox" id="' + materialUniqueId + '-hoverable" checked="checked" /><label for="' + materialUniqueId + '-hoverable">' + lang.table.hoverable + '</label></div>' +
- '<div class="col s6 preventDropClose"><input type="checkbox" id="' + materialUniqueId + '-responsive" checked="checked" /><label for="' + materialUniqueId + '-responsive">' + lang.table.responsive + '</label></div>' +
- '</div>' +
- '<div class="note-dimension-picker">' +
- '<div class="note-dimension-picker-mousecatcher" data-event="insertTable" data-value="1x1"></div>' +
- '<div class="note-dimension-picker-highlighted"></div>' +
- '<div class="note-dimension-picker-unhighlighted"></div>' +
- '</div>' +
- '<div class="note-dimension-display"> 1 x 1 </div>' +
- '</ul>';
- return tplIconButton(options.iconPrefix + options.icons.table.table, {
- title: lang.table.table,
- dropdown: dropdown
- });
- },
- style: function(lang, options) {
- var items = options.styleTags.reduce(function(memo, v) {
- var label = lang.style[v === 'p' ? 'normal' : v];
-
- return memo + '<li><div data-event="formatBlock" data-value="' + v + '">' +
- ((v === 'p' || v === 'pre') ? label : '<' + v + '>' + label + '</' + v + '>') +
- '</div></li>';
- }, '');
-
- return tplIconButton(options.iconPrefix + options.icons.style.style, {
- title: lang.style.style,
- dropdown: '<ul class="dropdown-menu largeDropdown">' + items + '</ul>'
- });
- },
- fontname: function(lang, options) {
- var realFontList = [];
- var items = options.fontNames.reduce(function(memo, v) {
- if (!agent.isFontInstalled(v) && options.fontNamesIgnoreCheck.indexOf(v) === -1) {
- return memo;
- }
- realFontList.push(v);
- return memo + '<li><div data-event="fontName" data-value="' + v + '" style="font-family:\'' + v + '\'">' +
- '<i class="material-icons tiny transparent">' + options.iconPrefix + options.icons.misc.check + '</i> ' + v + '</div></li>';
- }, '');
-
- var hasDefaultFont = agent.isFontInstalled(options.defaultFontName);
- var defaultFontName = (hasDefaultFont) ? options.defaultFontName : realFontList[0];
- var label = '<div class="note-current-fontname">' + defaultFontName + '</div>';
- // console.log('editing right file...')
- return tplButton(label, {
- title: lang.font.name,
- className: 'note-fontname',
- dropdown: '<ul class="dropdown-menu note-check">' + items + '</ul>'
- });
- },
- fontsize: function(lang, options) {
- var items = options.fontSizes.reduce(function(memo, v) {
- return memo + '<li><div data-event="fontSize" data-value="' + v + '">' +
- '<i class="material-icons tiny transparent">' + options.iconPrefix + options.icons.misc.check + '</i> ' + v +
- '</div></li>';
- }, '');
-
- var label = '<span class="note-current-fontsize">15</span>';
- return tplButton(label, {
- title: lang.font.size,
- className: 'note-fontsize',
- dropdown: '<ul class="dropdown-menu note-check">' + items + '</ul>'
- });
- },
- color: function(lang, options) {
- // >>>>>>> CK
- var colorButtonLabel = '<i class="material-icons">' + options.icons.color.recent + '</i>',
- colorButton = tplButton(colorButtonLabel, {
- className: 'note-recent-color',
- title: lang.color.recent,
- style: "color: " + options.defaultTextColor + "; background-color: " + options.defaultBackColor + ";",
- event: 'color',
- value: '{"backColor": "' + options.defaultBackColor + '"}'
- });
-
- var dropdown = '<ul id="colors" class="dropdown-menu">' +
- '<li>' +
- '<div class="col s12">' +
- '<ul class="tabs">' +
- '<li class="tab"><span class="active">' + lang.color.foreground + '</span></li>' +
- '<li class="tab"><span>' + lang.color.background + '</span></li>' +
- '</ul>' +
- '</div>' +
- '<div class="col s12 colorTable">' +
- '<div id="' + materialUniqueId + '-foreColor">' +
- '<div class="note-color-reset waves-effect waves-light btn" data-event="foreColor" data-value="' + options.defaultTextColor + '" title="' + lang.color.reset + '">' +
- lang.color.resetToDefault +
- '</div>' +
- '<div class="colorName"></div>' +
- '<div class="note-color-palette" data-target-event="foreColor"></div>' +
- '</div>' +
- '<div id="' + materialUniqueId + '-backColor">' +
- '<div class="note-color-reset waves-effect waves-light btn" data-event="backColor"' + ' data-value="' + options.defaultBackColor + '" title="' + lang.color.transparent + '">' +
- lang.color.setTransparent +
- '</div>' +
- '<div class="colorName"></div>' +
- '<div class="note-color-palette" data-target-event="backColor"></div>' +
- '</div>' +
- '</div>' +
- '</li>' +
- '</ul>';
-
- var moreButton = tplButton('', {
- title: lang.color.more,
- className: 'closeLeft',
- dropdown: dropdown
- });
-
- return moreButton + colorButton;
- },
- bold: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.font.bold, {
- event: 'bold',
- title: lang.font.bold
- });
- },
- italic: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.font.italic, {
- event: 'italic',
- title: lang.font.italic
- });
- },
- underline: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.font.underline, {
- event: 'underline',
- title: lang.font.underline
- });
- },
- strikethrough: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.font.strikethrough, {
- event: 'strikethrough',
- title: lang.font.strikethrough
- });
- },
- superscript: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.font.superscript, {
- event: 'superscript',
- title: lang.font.superscript
- });
- },
- subscript: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.font.subscript, {
- event: 'subscript',
- title: lang.font.subscript
- });
- },
- clear: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.font.clear, {
- event: 'removeFormat',
- title: lang.font.clear
- });
- },
- ul: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.lists.unordered, {
- event: 'insertUnorderedList',
- title: lang.lists.unordered
- });
- },
- ol: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.lists.ordered, {
- event: 'insertOrderedList',
- title: lang.lists.ordered
- });
- },
- //>>>>>>> CK paragraph single buttons
- leftButton: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.paragraph.left, {
- title: lang.paragraph.left,
- event: 'justifyLeft'
- });
- },
- centerButton: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.paragraph.center, {
- title: lang.paragraph.center,
- event: 'justifyCenter'
- });
- },
- rightButton: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.paragraph.right, {
- title: lang.paragraph.right,
- event: 'justifyRight'
- });
- },
- justifyButton: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.paragraph.justify, {
- title: lang.paragraph.justify,
- event: 'justifyFull'
- });
- },
- outdentButton: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.paragraph.outdent, {
- title: lang.paragraph.outdent,
- event: 'outdent'
- });
- },
- indentButton: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.paragraph.indent, {
- title: lang.paragraph.indent,
- event: 'indent'
- });
- },
-
- paragraph: function(lang, options) {
- var leftButton = tplIconButton(options.iconPrefix + options.icons.paragraph.left, {
- title: lang.paragraph.left,
- event: 'justifyLeft'
- });
- var centerButton = tplIconButton(options.iconPrefix + options.icons.paragraph.center, {
- title: lang.paragraph.center,
- event: 'justifyCenter'
- });
- var rightButton = tplIconButton(options.iconPrefix + options.icons.paragraph.right, {
- title: lang.paragraph.right,
- event: 'justifyRight'
- });
- var justifyButton = tplIconButton(options.iconPrefix + options.icons.paragraph.justify, {
- title: lang.paragraph.justify,
- event: 'justifyFull'
- });
-
- var outdentButton = tplIconButton(options.iconPrefix + options.icons.paragraph.outdent, {
- title: lang.paragraph.outdent,
- event: 'outdent'
- });
- var indentButton = tplIconButton(options.iconPrefix + options.icons.paragraph.indent, {
- title: lang.paragraph.indent,
- event: 'indent'
- });
-
- var dropdown = '<ul class="dropdown-menu">' +
- '<div class="note-align btn-group">' +
- leftButton + centerButton + rightButton + justifyButton +
- '</div>' +
- '<div class="note-list btn-group">' +
- indentButton + outdentButton +
- '</div>' +
- '</ul>';
-
- return tplIconButton(options.iconPrefix + options.icons.paragraph.paragraph, {
- title: lang.paragraph.paragraph,
- dropdown: dropdown
- });
- },
- lineheight: function(lang, options) {
- var items = options.lineHeights.reduce(function(memo, v) {
- return memo + '<li><div data-event="lineHeight" data-value="' + parseFloat(v) + '">' +
- '<i class="material-icons tiny transparent">' + options.iconPrefix + options.icons.misc.check + '</i> ' + v +
- '</div></li>';
- }, '');
-
- return tplIconButton(options.iconPrefix + options.icons.font.height, {
- title: lang.font.height,
- className: 'note-height',
- dropdown: '<ul class="dropdown-menu note-check">' + items + '</ul>'
- });
-
- },
- help: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.options.help, {
- event: 'showHelpDialog',
- title: lang.options.help,
- hide: true
- });
- },
- fullscreen: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.options.fullscreen, {
- event: 'fullscreen',
- title: lang.options.fullscreen
- });
- },
- codeview: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.options.codeview, {
- event: 'codeview',
- title: lang.options.codeview
- });
- },
- undo: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.history.undo, {
- event: 'undo',
- title: lang.history.undo
- });
- },
- redo: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.history.redo, {
- event: 'redo',
- title: lang.history.redo
- });
- },
- hr: function(lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.hr.insert, {
- event: 'insertHorizontalRule',
- title: lang.hr.insert
- });
- }
- };
-
- var tplPopovers = function(lang, options) {
- var tplLinkPopover = function() {
- var linkButton = tplIconButton(options.iconPrefix + options.icons.link.edit, {
- title: lang.link.edit,
- event: 'showLinkDialog',
- hide: true
- });
- var unlinkButton = tplIconButton(options.iconPrefix + options.icons.link.unlink, {
- title: lang.link.unlink,
- event: 'unlink'
- });
- var content = '<a href="https://www.bosssauce.it" target="_blank">www.bosssauce.it</a>&nbsp;&nbsp;' +
- '<div class="note-insert btn-group">' +
- linkButton + unlinkButton +
- '</div>';
- return tplPopover('note-link-popover', content);
- };
-
- var tplImagePopover = function() {
- var fullButton = tplButton('<span class="note-fontsize-10">100%</span>', {
- title: lang.image.resizeFull,
- event: 'resize',
- value: '1'
- });
- var halfButton = tplButton('<span class="note-fontsize-10">50%</span>', {
- title: lang.image.resizeHalf,
- event: 'resize',
- value: '0.5'
- });
- var quarterButton = tplButton('<span class="note-fontsize-10">25%</span>', {
- title: lang.image.resizeQuarter,
- event: 'resize',
- value: '0.25'
- });
-
- var leftButton = tplIconButton(options.iconPrefix + options.icons.image.floatLeft, {
- title: lang.image.floatLeft,
- event: 'floatMe',
- value: 'left'
- });
- var rightButton = tplIconButton(options.iconPrefix + options.icons.image.floatRight, {
- title: lang.image.floatRight,
- event: 'floatMe',
- value: 'right'
- });
- var justifyButton = tplIconButton(options.iconPrefix + options.icons.image.floatNone, {
- title: lang.image.floatNone,
- event: 'floatMe',
- value: 'none'
- });
-
- var roundedButton = tplIconButton(options.iconPrefix + options.icons.image.shapeRounded, {
- title: lang.image.shapeRounded,
- event: 'imageClass',
- value: 'img-rounded'
- });
- var circleButton = tplIconButton(options.iconPrefix + options.icons.image.shapeCircle, {
- title: lang.image.shapeCircle,
- event: 'imageClass',
- value: 'img-circle'
- });
- var thumbnailButton = tplIconButton(options.iconPrefix + options.icons.image.shapeThumbnail, {
- title: lang.image.shapeThumbnail,
- event: 'imageClass',
- value: 'img-thumbnail'
- });
- var borderedButton = tplIconButton(options.iconPrefix + options.icons.image.bordered, {
- title: lang.image.bordered,
- event: 'imageClass',
- value: 'img-bordered'
- });
- var noneButton = tplIconButton(options.iconPrefix + options.icons.image.shapeNone, {
- title: lang.image.shapeNone,
- event: 'imageShape',
- value: ''
- });
-
- var removeButton = tplIconButton(options.iconPrefix + options.icons.image.remove, {
- title: lang.image.remove,
- event: 'removeMedia',
- value: 'none'
- });
-
- var content = //'<div class="btn-group">' + fullButton + halfButton + quarterButton + '</div>' +
- '<div class="btn-group">' + leftButton + rightButton + justifyButton + '</div>' +
- '<div class="btn-group">' + roundedButton + circleButton + thumbnailButton + borderedButton + noneButton + '</div>' +
- '<div class="btn-group">' + removeButton + '</div>';
- return tplPopover('note-image-popover', content);
- };
-
- var tplAirPopover = function() {
- var $content = $('<div />');
- for (var idx = 0, len = options.airPopover.length; idx < len; idx ++) {
- var group = options.airPopover[idx];
-
- var $group = $('<div class="note-' + group[0] + ' btn-group">');
- for (var i = 0, lenGroup = group[1].length; i < lenGroup; i++) {
- var $button = $(tplButtonInfo[group[1][i]](lang, options));
-
- $button.attr('data-name', group[1][i]);
-
- $group.append($button);
- }
- $content.append($group);
- }
-
- return tplPopover('note-air-popover', $content.children());
- };
-
- var $notePopover = $('<div class="note-popover" />');
-
- $notePopover.append(tplLinkPopover());
- $notePopover.append(tplImagePopover());
-
- if (options.airMode) {
- $notePopover.append(tplAirPopover());
- }
-
- return $notePopover;
- };
-
- var tplHandles = function() {
- return '<div class="note-handle">' +
- '<div class="note-control-selection">' +
- '<div class="note-control-selection-bg"></div>' +
- '<div class="note-control-sizing note-control-se"></div>' +
- '<div class="note-control-selection-info"></div>' +
- '</div>' +
- '</div>';
- };
-
- /**
- * shortcut table template
- * @param {String} title
- * @param {String} body
- */
- var tplShortcut = function(title, keys) {
- var keyClass = 'note-shortcut-col col-xs-6 note-shortcut-';
- var body = [];
-
- for (var i in keys) {
- if (keys.hasOwnProperty(i)) {
- body.push(
- '<tr><td>' + keys[i].kbd + '</td><td>' + keys[i].text + '</td></tr>'
- );
- }
- }
-
- return '<thead><tr><th>' + title + '</th><th>' + '(keys)' + '</th></tr></thead>' +
- '<tbody>' + body.join('') + '</tbody>';
- };
-
- var tplShortcutText = function(lang) {
- var keys = [
- { kbd: '⌘ + B', text: lang.font.bold },
- { kbd: '⌘ + I', text: lang.font.italic },
- { kbd: '⌘ + U', text: lang.font.underline },
- { kbd: '⌘ + \\', text: lang.font.clear }
- ];
-
- return tplShortcut(lang.shortcut.textFormatting, keys);
- };
-
- var tplShortcutAction = function(lang) {
- var keys = [
- { kbd: '⌘ + Z', text: lang.history.undo },
- { kbd: '⌘ + ⇧ + Z', text: lang.history.redo },
- { kbd: '⌘ + ]', text: lang.paragraph.indent },
- { kbd: '⌘ + [', text: lang.paragraph.outdent },
- { kbd: '⌘ + ENTER', text: lang.hr.insert }
- ];
-
- return tplShortcut(lang.shortcut.action, keys);
- };
-
- var tplShortcutPara = function(lang) {
- var keys = [
- { kbd: '⌘ + ⇧ + L', text: lang.paragraph.left },
- { kbd: '⌘ + ⇧ + E', text: lang.paragraph.center },
- { kbd: '⌘ + ⇧ + R', text: lang.paragraph.right },
- { kbd: '⌘ + ⇧ + J', text: lang.paragraph.justify },
- { kbd: '⌘ + ⇧ + NUM7', text: lang.lists.ordered },
- { kbd: '⌘ + ⇧ + NUM8', text: lang.lists.unordered }
- ];
-
- return tplShortcut(lang.shortcut.paragraphFormatting, keys);
- };
-
- var tplShortcutStyle = function(lang) {
- var keys = [
- { kbd: '⌘ + NUM0', text: lang.style.normal },
- { kbd: '⌘ + NUM1', text: lang.style.h1 },
- { kbd: '⌘ + NUM2', text: lang.style.h2 },
- { kbd: '⌘ + NUM3', text: lang.style.h3 },
- { kbd: '⌘ + NUM4', text: lang.style.h4 },
- { kbd: '⌘ + NUM5', text: lang.style.h5 },
- { kbd: '⌘ + NUM6', text: lang.style.h6 }
- ];
-
- return tplShortcut(lang.shortcut.documentStyle, keys);
- };
-
- var tplExtraShortcuts = function(lang, options) {
- var extraKeys = options.extraKeys;
- var keys = [];
-
- for (var key in extraKeys) {
- if (extraKeys.hasOwnProperty(key)) {
- keys.push({ kbd: key, text: extraKeys[key] });
- }
- }
-
- return tplShortcut(lang.shortcut.extraKeys, keys);
- };
-
- var tplShortcutTable = function(lang, options) {
- var template = [
- '<table class="striped hoverable">' + tplShortcutAction(lang, options) + '</table>',
- '<table class="striped hoverable">' + tplShortcutStyle(lang, options) + '</table>',
- '<table class="striped hoverable">' + tplShortcutText(lang, options) + '</table>',
- '<table class="striped hoverable">' + tplShortcutPara(lang, options) + '</table>'
- ].join('<br>');
-
- if (options.extraKeys) {
- //template.push('<table class="striped hoverable">' + tplExtraShortcuts(lang, options) + '</table>');
- }
- return template;
- };
-
- var replaceMacKeys = function(sHtml) {
- return sHtml.replace(/⌘/g, 'Ctrl').replace(/⇧/g, 'Shift');
- };
-
- var tplDialogInfo = {
- image: function(lang, options) {
- var imageLimitation = '';
-
- if (options.maximumImageFileSize) {
- var unit = Math.floor(Math.log(options.maximumImageFileSize) / Math.log(1024));
- var readableSize = (options.maximumImageFileSize / Math.pow(1024, unit)).toFixed(2) * 1 + ' ' + ' KMGTP'[unit] + 'B';
-
- imageLimitation = '<small>' + lang.image.maximumFileSize + ' : ' + readableSize + '</small>';
- }
-
- var body = '<div class="row">' +
- '<div class="col s12">' +
- '<div class="file-field input-field">' +
- '<div class="btn">' +
- '<span>' + lang.image.image + '</span>' +
- '<input class="note-image-input" name="files" type="file" />' +
- '</div>' +
- '<div class="file-path-wrapper">' +
- '<input class="file-path" type="text" />' +
- '</div>' +
- '</div>' +
- '</div>' +
- '</div>' +
- '<div class="row">' +
- '<div class="input-field col s12">' +
- '<input class="note-image-url" type="text" />' +
- '<label>' + lang.image.url + '</label>' +
- '</div>' +
- '</div>';
-
- var footer = '<button class="waves-effect waves-light btn note-image-btn disabled" disabled>' + lang.image.insert + '</button>' +
- '<button class="waves-effect waves-light btn btnClose">' + lang.shortcut.close + '</button>';
- return tplDialog('note-image-dialog', lang.image.insert, body, footer);
- },
-
- link: function(lang, options) {
- var body = '<div class="row">' +
- '<div class="input-field col s12">' +
- '<input class="note-link-text" type="text" />' +
- '<label>' + lang.link.textToDisplay + '</label>' +
- '</div>' +
- '</div>' +
- '<div class="row">' +
- '<div class="input-field col s12">' +
- '<input class="note-link-url" type="text" value="http://" />' +
- '<label class="active">' + lang.link.url + '</label>' +
- '</div>' +
- '</div>' +
- (!options.disableLinkTarget ?
- '<div class="row">' +
- '<div class="col s12">' +
- '<input type="checkbox" id="' + materialUniqueId + '-noteInsertLinkNewWindow" checked="checked" />' +
- '<label for="' + materialUniqueId + '-noteInsertLinkNewWindow">' + lang.link.openInNewWindow + '</label>' +
- '</div>' +
- '</div>'
- : ''
- );
-
- var footer = '<button class="waves-effect waves-light btn note-link-btn disabled" disabled>' + lang.link.insert + '</button>' +
- '<button class="waves-effect waves-light btn btnClose">' + lang.shortcut.close + '</button>';
- return tplDialog('note-link-dialog', lang.link.insert, body, footer);
- },
-
- help: function(lang, options) {
- var body = (agent.isMac ? tplShortcutTable(lang, options) : replaceMacKeys(tplShortcutTable(lang, options)));
- var footer = '<button class="waves-effect waves-light btn modal-close">' + lang.shortcut.close + '</button>';
-
- return tplDialog('note-help-dialog', lang.shortcut.shortcuts, body, footer);
- }
- };
-
- var tplDialogs = function(lang, options) {
- var dialogs = '';
-
- $.each(tplDialogInfo, function(idx, tplDialog) {
- dialogs += tplDialog(lang, options);
- });
-
- return '<div class="note-dialog">' + dialogs + '</div>';
- };
-
- var tplStatusbar = function() {
- return '<div class="note-resizebar">' +
- '<div class="note-icon-bar"></div>' +
- '<div class="note-icon-bar"></div>' +
- '<div class="note-icon-bar"></div>' +
- '</div>';
- };
-
- var representShortcut = function(str) {
- if (agent.isMac) {
- str = str.replace('CMD', '⌘').replace('SHIFT', '⇧');
- }
-
- return str.replace('BACKSLASH', '\\')
- .replace('SLASH', '/')
- .replace('LEFTBRACKET', '[')
- .replace('RIGHTBRACKET', ']');
- };
-
- /**
- * createTooltip
- * @param {jQuery} $container
- * @param {Object} keyMap
- * @param {String} [sPlacement]
- */
- // >>>>>>> CK
- var createTooltip = function($container, keyMap, sPlacement) {
- $(document).ready(function() {
- var invertedKeyMap = func.invertObject(keyMap);
- var $buttons = $container.find('.btn');
-
- $buttons.each(function(i, elBtn) {
- var $btn = $(elBtn);
- var sShortcut = invertedKeyMap[$btn.data('event')];
- var text = $btn.attr('title');
-
- if (sShortcut) {
- $btn.attr('data-tooltip', function(i, v) {
- text = text + ' (' + representShortcut(sShortcut) + ')';
-
- $(this).removeAttr('title');
- return text;
- });
- }
- $btn.attr('data-position', 'bottom');
- $btn.attr('data-tooltip', text);
- $btn.removeAttr('title');
- }).ckTooltip({
- container: $container,
- position: 'top',
- delay: 30
- });
- });
- };
-
- // >>>>>>> CK
- // createPalette
- var createPalette = function($container, options) {
- var colorInfo = options.colors;
- var colorTitles = options.colorTitles;
-
- $container.find('.note-color-palette').each(function() {
- var $palette = $(this), eventName = $palette.attr('data-target-event');
- var paletteContents = [];
-
- for (var row = 0, lenRow = colorInfo.length; row < lenRow; row++) {
- var colors = colorInfo[row];
- var titles = colorTitles[row];
- var buttons = [];
-
- for (var col = 0, lenCol = colors.length; col < lenCol; col++) {
- var color = colors[col];
- var title = titles[col];
-
- buttons.push(['<button type="button" class="note-color-btn" style="background-color:', color,
- ';" data-event="', eventName,
- '" data-value="', color,
- '" data-description="', title,
- '" data-toggle="button" tabindex="-1"></button>'].join(''));
- }
- paletteContents.push('<div class="note-color-row">' + buttons.join('') + '</div>');
- }
- $palette.html(paletteContents.join(''));
-
- $palette.find('button').mouseenter(function() {
- $palette.siblings('.colorName').html($(this).data('description'));
- });
- $palette.mouseleave(function() {
- $(this).siblings('.colorName').html('');
- });
- });
- };
-
- /**
- * create materialnote layout (air mode)
- *
- * @param {jQuery} $holder
- * @param {Object} options
- */
- this.createLayoutByAirMode = function($holder, options) {
- var langInfo = options.langInfo;
- var keyMap = options.keyMap[agent.isMac ? 'mac' : 'pc'];
- var id = func.uniqueId();
-
- $holder.addClass('note-air-editor note-editable');
- $holder.attr({
- 'id': 'note-editor-' + id,
- 'contentEditable': true
- });
-
- var body = document.body;
-
- // create Popover
- var $popover = $(tplPopovers(langInfo, options));
- $popover.addClass('note-air-layout');
- $popover.attr('id', 'note-popover-' + id);
- $popover.appendTo(body);
- createTooltip($popover, keyMap);
- createPalette($popover, options);
-
- // create Handle
- var $handle = $(tplHandles());
- $handle.addClass('note-air-layout');
- $handle.attr('id', 'note-handle-' + id);
- $handle.appendTo(body);
-
- // create Dialog
- var $dialog = $(tplDialogs(langInfo, options));
- $dialog.addClass('note-air-layout');
- $dialog.attr('id', 'note-dialog-' + id);
- $dialog.find('button.close, a.modal-close').click(function() {
- $(this).closest('.modal').closeModal();
- });
- $dialog.appendTo(body);
- };
-
- /**
- * create materialnote layout (normal mode)
- *
- * @param {jQuery} $holder
- * @param {Object} options
- */
- this.createLayoutByFrame = function($holder, options) {
- var langInfo = options.langInfo;
-
- //01. create Editor
- var $editor = $('<div class="note-editor"></div>');
- if (options.width) {
- $editor.width(options.width);
- }
-
- //02. statusbar (resizebar)
- if (options.height > 0) {
- $('<div class="note-statusbar">' + (options.disableResizeEditor ? '' : tplStatusbar()) + '</div>').prependTo($editor);
- }
-
- //03. create Editable
- var isContentEditable = !$holder.is(':disabled');
- var $editable = $('<div class="note-editable" contentEditable="' + isContentEditable + '"></div>')
- .prependTo($editor);
- if (options.height) {
- $editable.height(options.height);
- }
- if (options.direction) {
- $editable.attr('dir', options.direction);
- }
- var placeholder = $holder.attr('placeholder') || options.placeholder;
- if (placeholder) {
- $editable.attr('data-placeholder', placeholder);
- }
-
- $editable.html(dom.html($holder));
-
- //031. create codable
- $('<textarea class="note-codable"></textarea>').prependTo($editor);
-
- //04. create Toolbar
- var $toolbar = $('<div class="note-toolbar btn-toolbar" />');
- for (var idx = 0, len = options.toolbar.length; idx < len; idx ++) {
- var groupName = options.toolbar[idx][0];
- var groupButtons = options.toolbar[idx][1];
-
- var $group = $('<div class="note-' + groupName + ' btn-group" />');
- for (var i = 0, btnLength = groupButtons.length; i < btnLength; i++) {
- var buttonInfo = tplButtonInfo[groupButtons[i]];
- // continue creating toolbar even if a button doesn't exist
- if (!$.isFunction(buttonInfo)) { continue; }
-
- var $button = $(buttonInfo(langInfo, options));
- $button.attr('data-name', groupButtons[i]); // set button's alias, because to get button element from $toolbar
- $group.append($button);
- }
- $toolbar.append($group);
- }
-
- $toolbar.prependTo($editor);
- var keyMap = options.keyMap[agent.isMac ? 'mac' : 'pc'];
- createPalette($toolbar, options);
- createTooltip($toolbar, keyMap, 'bottom');
-
-
- // >>>>>>> CK - following toolbar
- // following toolbar
- function followingBar() {
- // $(window).unbind('scroll');
- // console.log($._data( $(window)[0], "events" ));
- $(window).scroll(function() {
- var isFullscreen = $editor.hasClass('fullscreen');
-
- if (isFullscreen) {
- // console.log("fullscreen");
- return false;
- }
-
- var toolbar = $editor.children('.note-toolbar');
- var toolbarHeight = toolbar.outerHeight();
- var editable = $editor.children('.note-editable');
- var editableHeight = editable.outerHeight();
- var editorWidth = $editor.width;
- var toolbarOffset, editorOffsetTop, editorOffsetBottom;
- var activateOffset, deactivateOffsetTop, deactivateOffsetBottom;
- var currentOffset;
- var relativeOffset;
- var otherBarHeight;
-
- // check if the web app is currently using another static bar
- otherBarHeight = $("." + options.otherStaticBarClass).outerHeight();
- if (!otherBarHeight) otherBarHeight = 0;
- //console.log(otherBarHeight);
-
- currentOffset = $(document).scrollTop();
- toolbarOffset = toolbar.offset().top;
- editorOffsetTop = $editor.offset().top;
- editorOffsetBottom = editorOffsetTop + editableHeight;
- activateOffset = toolbarOffset - otherBarHeight;
- deactivateOffsetBottom = editorOffsetBottom - otherBarHeight;
- deactivateOffsetTop = editorOffsetTop - otherBarHeight;
-
- if ((currentOffset > activateOffset) && (currentOffset < deactivateOffsetBottom)) {
- relativeOffset = currentOffset - $editor.offset().top + otherBarHeight;
- toolbar.css({'top': relativeOffset + 'px', 'z-index': 2000});
- } else {
- if ((currentOffset < toolbarOffset) && (currentOffset < deactivateOffsetBottom)) {
- toolbar.css({'top': 0, 'z-index': 1052});
-
- if (currentOffset > deactivateOffsetTop) {
- relativeOffset = currentOffset - $editor.offset().top + otherBarHeight;
- toolbar.css({'top': relativeOffset + 'px', 'z-index': 2000});
- }
- }
- }
- });
- }
- if (options.followingToolbar) {
- followingBar();
- }
-
- //05. create Popover
- var $popover = $(tplPopovers(langInfo, options)).prependTo($editor);
- createPalette($popover, options);
- createTooltip($popover, keyMap);
-
- //06. handle(control selection, ...)
- $(tplHandles()).prependTo($editor);
-
- //07. create Dialog
- var $dialog = $(tplDialogs(langInfo, options)).prependTo($editor);
- $dialog.find('button.close, a.modal-close').click(function() {
- $(this).closest('.modal').closeModal();
- });
-
- //08. create Dropzone
- $('<div class="note-dropzone"><div class="note-dropzone-message"></div></div>').prependTo($editor);
-
- //09. Editor/Holder switch
- $editor.insertAfter($holder);
- $holder.hide();
- };
-
- this.hasNoteEditor = function($holder) {
- return this.noteEditorFromHolder($holder).length > 0;
- };
-
- this.noteEditorFromHolder = function($holder) {
- if ($holder.hasClass('note-air-editor')) {
- return $holder;
- } else if ($holder.next().hasClass('note-editor')) {
- return $holder.next();
- } else {
- return $();
- }
- };
-
- /**
- * create materialnote layout
- *
- * @param {jQuery} $holder
- * @param {Object} options
- */
- this.createLayout = function($holder, options) {
- if (options.airMode) {
- this.createLayoutByAirMode($holder, options);
- } else {
- this.createLayoutByFrame($holder, options);
- }
- };
-
- /**
- * returns layoutInfo from holder
- *
- * @param {jQuery} $holder - placeholder
- * @return {Object}
- */
- this.layoutInfoFromHolder = function($holder) {
- var $editor = this.noteEditorFromHolder($holder);
- if (!$editor.length) {
- return;
- }
-
- // connect $holder to $editor
- $editor.data('holder', $holder);
-
- return dom.buildLayoutInfo($editor);
- };
-
- /**
- * removeLayout
- *
- * @param {jQuery} $holder - placeholder
- * @param {Object} layoutInfo
- * @param {Object} options
- *
- */
- this.removeLayout = function($holder, layoutInfo, options) {
- if (options.airMode) {
- $holder.removeClass('note-air-editor note-editable')
- .removeAttr('id contentEditable');
-
- layoutInfo.popover().remove();
- layoutInfo.handle().remove();
- layoutInfo.dialog().remove();
- } else {
- $holder.html(layoutInfo.editable().html());
-
- layoutInfo.editor().remove();
- $holder.show();
- }
- };
-
- /**
- *
- * @return {Object}
- * @return {function(label, options=):string} return.button {@link #tplButton function to make text button}
- * @return {function(iconClass, options=):string} return.iconButton {@link #tplIconButton function to make icon button}
- * @return {function(className, title=, body=, footer=):string} return.dialog {@link #tplDialog function to make dialog}
- */
- this.getTemplate = function() {
- return {
- button: tplButton,
- iconButton: tplIconButton,
- dialog: tplDialog
- };
- };
-
- /**
- * add button information
- *
- * @param {String} name button name
- * @param {Function} buttonInfo function to make button, reference to {@link #tplButton},{@link #tplIconButton}
- */
- this.addButtonInfo = function(name, buttonInfo) {
- tplButtonInfo[name] = buttonInfo;
- };
-
- /**
- *
- * @param {String} name
- * @param {Function} dialogInfo function to make dialog, reference to {@link #tplDialog}
- */
- this.addDialogInfo = function(name, dialogInfo) {
- tplDialogInfo[name] = dialogInfo;
- };
- };
-
-
- // jQuery namespace for materialnote
- /**
- * @class $.materialnote
- *
- * materialnote attribute
- *
- * @mixin defaults
- * @singleton
- *
- */
- $.materialnote = $.materialnote || {};
-
- // extends default settings
- // - $.materialnote.version
- // - $.materialnote.options
- // - $.materialnote.lang
- $.extend($.materialnote, defaults);
-
- var renderer = new Renderer();
- var eventHandler = new EventHandler();
-
- $.extend($.materialnote, {
- /** @property {Renderer} */
- renderer: renderer,
- /** @property {EventHandler} */
- eventHandler: eventHandler,
- /**
- * @property {Object} core
- * @property {core.agent} core.agent
- * @property {core.dom} core.dom
- * @property {core.range} core.range
- */
- core: {
- agent: agent,
- list : list,
- dom: dom,
- range: range
- },
- /**
- * @property {Object}
- * pluginEvents event list for plugins
- * event has name and callback function.
- *
- * ```
- * $.materialnote.addPlugin({
- * events : {
- * 'hello' : function(layoutInfo, value, $target) {
- * console.log('event name is hello, value is ' + value );
- * }
- * }
- * })
- * ```
- *
- * * event name is data-event property.
- * * layoutInfo is a materialnote layout information.
- * * value is data-value property.
- */
- pluginEvents: {},
-
- plugins : []
- });
-
- /**
- * @method addPlugin
- *
- * add Plugin in materialnote
- *
- * materialnote can make a own plugin.
- *
- * ### Define plugin
- * ```
- * // get template function
- * var tmpl = $.materialnote.renderer.getTemplate();
- *
- * // add a button
- * $.materialnote.addPlugin({
- * buttons : {
- * // "hello" is button's namespace.
- * "hello" : function(lang, options) {
- * // make icon button by template function
- * return tmpl.iconButton(options.iconPrefix + 'header', {
- * // callback function name when button clicked
- * event : 'hello',
- * // set data-value property
- * value : 'hello',
- * hide : true
- * });
- * }
- *
- * },
- *
- * events : {
- * "hello" : function(layoutInfo, value) {
- * // here is event code
- * }
- * }
- * });
- * ```
- * ### Use a plugin in toolbar
- *
- * ```
- * $("#editor").materialnote({
- * ...
- * toolbar : [
- * // display hello plugin in toolbar
- * ['group', [ 'hello' ]]
- * ]
- * ...
- * });
- * ```
- *
- *
- * @param {Object} plugin
- * @param {Object} [plugin.buttons] define plugin button. for detail, see to Renderer.addButtonInfo
- * @param {Object} [plugin.dialogs] define plugin dialog. for detail, see to Renderer.addDialogInfo
- * @param {Object} [plugin.events] add event in $.materialnote.pluginEvents
- * @param {Object} [plugin.langs] update $.materialnote.lang
- * @param {Object} [plugin.options] update $.materialnote.options
- */
- $.materialnote.addPlugin = function(plugin) {
-
- // save plugin list
- $.materialnote.plugins.push(plugin);
-
- if (plugin.buttons) {
- $.each(plugin.buttons, function(name, button) {
- renderer.addButtonInfo(name, button);
- });
- }
-
- if (plugin.dialogs) {
- $.each(plugin.dialogs, function(name, dialog) {
- renderer.addDialogInfo(name, dialog);
- });
- }
-
- if (plugin.events) {
- $.each(plugin.events, function(name, event) {
- $.materialnote.pluginEvents[name] = event;
- });
- }
-
- if (plugin.langs) {
- $.each(plugin.langs, function(locale, lang) {
- if ($.materialnote.lang[locale]) {
- $.extend($.materialnote.lang[locale], lang);
- }
- });
- }
-
- if (plugin.options) {
- $.extend($.materialnote.options, plugin.options);
- }
- };
-
- /*
- * extend $.fn
- */
- $.fn.extend({
- /**
- * @method
- * Initialize materialnote
- * - create editor layout and attach Mouse and keyboard events.
- *
- * ```
- * $("#materialnote").materialnote( { options ..} );
- * ```
- *
- * @member $.fn
- * @param {Object|String} options reference to $.materialnote.options
- * @return {this}
- */
- materialnote: function() {
-
- // check first argument's type
- // - {String}: External API call {{module}}.{{method}}
- // - {Object}: init options
- var type = $.type(list.head(arguments));
- var isExternalAPICalled = type === 'string';
- var hasInitOptions = type === 'object';
-
- // extend default options with custom user options
- var options = hasInitOptions ? list.head(arguments) : {};
-
- options = $.extend({}, $.materialnote.options, options);
- options.icons = $.extend({}, $.materialnote.options.icons, options.icons);
-
- // Include langInfo in options for later use, e.g. for image drag-n-drop
- // Setup language info with en-US as default
- options.langInfo = $.extend(true, {}, $.materialnote.lang['en-US'], $.materialnote.lang[options.lang]);
-
- // override plugin options
- if (!isExternalAPICalled && hasInitOptions) {
- for (var i = 0, len = $.materialnote.plugins.length; i < len; i++) {
- var plugin = $.materialnote.plugins[i];
-
- if (options.plugin[plugin.name]) {
- $.materialnote.plugins[i] = $.extend(true, plugin, options.plugin[plugin.name]);
- }
- }
- }
-
- this.each(function(idx, holder) {
- // >>>>>>> CK set id for this editor
- materialUniqueId = $(holder).attr('id');
-
- var $holder = $(holder);
-
- // if layout isn't created yet, createLayout and attach events
- if (!renderer.hasNoteEditor($holder)) {
- renderer.createLayout($holder, options);
-
- var layoutInfo = renderer.layoutInfoFromHolder($holder);
- $holder.data('layoutInfo', layoutInfo);
-
- eventHandler.attach(layoutInfo, options);
- eventHandler.attachCustomEvent(layoutInfo, options);
-
- }
- });
-
- var $first = this.first();
- if ($first.length) {
- var layoutInfo = renderer.layoutInfoFromHolder($first);
-
- // external API
- if (isExternalAPICalled) {
- var moduleAndMethod = list.head(list.from(arguments));
- var args = list.tail(list.from(arguments));
-
- // TODO now external API only works for editor
- var params = [moduleAndMethod, layoutInfo.editable()].concat(args);
- return eventHandler.invoke.apply(eventHandler, params);
- } else if (options.focus) {
- // focus on first editable element for initialize editor
- layoutInfo.editable().focus();
- }
- }
-
-
-
- // >>>>>>> CK dropdowns - tabs activation
- $(this).each(function(index, editor) {
- var tabs;
- var tabContainer;
- var toolbar;
- var isAir = false;
-
- if ($(editor).hasClass('note-air-editor')) {
- var id = $(this).attr('id');
- if (id) id = id.substring(id.lastIndexOf('-') + 1, id.length);
-
- editor = $('#note-popover-' + id).find('.note-air-popover');
- tabContainer = editor.find('ul.tabs');
- tabs = editor.find('li.tab a');
- toolbar = $(editor).find('.popover-content button.dropdown');
- isAir = true;
- } else {
- editor = $(editor).next('.note-editor');
- tabContainer = editor.find('ul.tabs');
- tabs = editor.find('li.tab a');
- toolbar = $(editor).find('.note-toolbar button.dropdown');
- }
- var go = true;
-
- function handleDropdowns(select, bar) {
- var list = $(select).next('ul.dropdown-menu');
- var container = $(select).parent('.btn-group');
-
- list.slideUp(0);
-
- $('.preventDropClose').click(function(event) {
- event.stopPropagation();
- });
-
- $(select).click(function(event) {
- // calculate dropdown open position to avoid overflow from editor
- var btnOffset = Math.round($(select).parent('.btn-group').offset().left - toolbar.offset().left);
- var listBorderWidth = parseInt(list.css("border-left-width"));
- var editorWidth = editor.outerWidth();
- var listOffset = listBorderWidth;
-
- list.css({'max-width': editorWidth + 'px'});
-
- var listWidth = list.outerWidth();
- var th = listWidth + btnOffset;
-
- if (th >= editorWidth) {
- listOffset = th - editorWidth;
-
- if (!isAir) {
- listOffset = listOffset + listBorderWidth;
- }
- }
-
- list.css({'left': '-' + listOffset + 'px'});
-
- var reopen = true;
-
- if (list.is(':visible')) reopen = false;
-
- bar.find('ul.dropdown-menu').slideUp(200);
-
- if (reopen) {
- list.slideToggle(200);
- }
- event.stopPropagation();
- });
-
- tabs.unbind().click(function(event) {
- go = false;
- });
- }
-
- $(window).click(function(event) {
- if (go) editor.find('ul.dropdown-menu').slideUp(200);
- go = true;
- event.stopPropagation();
- });
-
- // dropdowns
- toolbar.each(function(index, select) {
- handleDropdowns(select, editor);
- });
-
- // activate tabs
- tabContainer.tabs();
- });
-
- return this;
- },
-
- /**
- * @method
- *
- * get the HTML contents of note or set the HTML contents of note.
- *
- * * get contents
- * ```
- * var content = $("#materialnote").code();
- * ```
- * * set contents
- *
- * ```
- * $("#materialnote").code(html);
- * ```
- *
- * @member $.fn
- * @param {String} [html] - HTML contents(optional, set)
- * @return {this|String} - context(set) or HTML contents of note(get).
- */
- code: function(html) {
- // get the HTML contents of note
- if (html === undefined) {
- var $holder = this.first();
- if (!$holder.length) {
- return;
- }
-
- var layoutInfo = renderer.layoutInfoFromHolder($holder);
- var $editable = layoutInfo && layoutInfo.editable();
-
- if ($editable && $editable.length) {
- var isCodeview = eventHandler.invoke('codeview.isActivated', layoutInfo);
- eventHandler.invoke('codeview.sync', layoutInfo);
- return isCodeview ? layoutInfo.codable().val() :
- layoutInfo.editable().html();
- }
- return dom.value($holder);
- }
-
- // set the HTML contents of note
- this.each(function(i, holder) {
- var layoutInfo = renderer.layoutInfoFromHolder($(holder));
- var $editable = layoutInfo && layoutInfo.editable();
- if ($editable) {
- $editable.html(html);
- }
- });
-
- return this;
- },
-
- /**
- * @method
- *
- * destroy Editor Layout and detach Key and Mouse Event
- *
- * @member $.fn
- * @return {this}
- */
- destroy: function() {
- this.each(function(idx, holder) {
- var $holder = $(holder);
-
- if (!renderer.hasNoteEditor($holder)) {
- return;
- }
-
- var info = renderer.layoutInfoFromHolder($holder);
- var options = info.editor().data('options');
-
- eventHandler.detach(info, options);
- renderer.removeLayout($holder, info, options);
- });
-
- return this;
- }
- });
-}));
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/license.txt b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/license.txt
deleted file mode 100644
index d978e1d..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/license.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2015 CK
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE. \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_buttons.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_buttons.scss
deleted file mode 100644
index 7192bec..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_buttons.scss
+++ /dev/null
@@ -1,157 +0,0 @@
-// shared styles
-.btn, .btn-flat {
- border: none;
- border-radius: 2px;
- display: inline-block;
- height: $button-height;
- line-height: $button-line-height;
- // margin-bottom: 15px;
- outline: 0;
- padding: 0 2rem;
- text-transform: uppercase;
- vertical-align: middle;
- // Gets rid of tap active state
- -webkit-tap-highlight-color: transparent;
-}
-// Disabled shared style
-.btn.disabled, .btn-floating.disabled, .btn-large.disabled, .btn:disabled, .btn-large:disabled, .btn-floating:disabled {
- background-color: $button-bg-color-disabled !important;
- box-shadow: none;
- color: $button-color-disabled !important;
- cursor: default;
- * {
- pointer-events: none;
- }
-
- &:hover {
- background-color: $button-bg-color-disabled;
- color: $button-color-disabled;
- }
-}
-// Shared icon styles
-.btn, .btn-floating, .btn-large, .btn-flat {
- i {
- font-size: $button-font-size-shared;
- line-height: inherit;
- }
-}
-
-// Raised Button
-.btn {
- text-decoration:none;
- color: $button-color-raised;
- background-color: $button-color;
- text-align: center;
- letter-spacing: .5px;
- @extend .z-depth-1;
- @include transition(.2s ease-out);
- cursor: pointer;
-
- &:hover {
- background-color: lighten($button-color, 5%);
- @extend .z-depth-1-half;
- }
-}
-
-// Floating button
-.btn-floating {
- display: inline-block;
- color: $button-color-raised;
- position: relative;
- overflow: hidden;
- z-index: 1;
- width: $button-floating-size;
- height: $button-floating-size;
- line-height: $button-floating-size;
- padding: 0;
- background-color: $button-color;
- border-radius: 50%;
- @extend .z-depth-1;
- transition: .3s;
- cursor: pointer;
- vertical-align: middle;
-
- i {
- width: inherit;
- display: inline-block;
- text-align: center;
- color: $button-color-raised;
- font-size: $button-large-icon-font-size;
- line-height: $button-floating-size;
- }
-
- &:hover {
- @extend .z-depth-1-half;
- }
- &:before {
- border-radius: 0;
- }
- &.btn-large {
- width: $button-floating-size * 1.5;
- height: $button-floating-size * 1.5;
- i{
- line-height: $button-floating-size * 1.5;
- }
- }
-
-}
-// button fix
-button.btn-floating {
- border: none;
-}
-
-// Fixed Action Button
-.fixed-action-btn {
- position: fixed;
- right: 23px;
- bottom: 23px;
- padding-top: 15px;
- margin-bottom: 0;
- z-index: 998;
-
- ul {
- left: 0;
- right: 0;
- text-align: center;
- position: absolute;
- bottom: 64px;
- margin: 0;
-
- li {
- margin-bottom: 15px;
- }
-
- a.btn-floating {
- opacity: 0;
- }
- }
-}
-
-// Flat button
-.btn-flat {
- box-shadow: none;
- background-color: transparent;
- color: $button-color-flat;
- cursor: pointer;
-
- &.disabled {
- color: lighten(#999, 10%);
- cursor: default;
- }
-}
-
-// Large button
-.btn-large {
- @extend .btn;
- height: $button-height * 1.5;
- line-height: 56px;
-
- i {
- font-size: $button-large-icon-font-size;
- }
-}
-
-// Block button
-.btn-block {
- display: block;
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_cards.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_cards.scss
deleted file mode 100644
index 524d0cf..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_cards.scss
+++ /dev/null
@@ -1,152 +0,0 @@
-
-
-.card-panel {
- transition: box-shadow .25s;
- padding: $card-padding;
- margin: $element-top-margin 0 $element-bottom-margin 0;
- border-radius: 2px;
- @extend .z-depth-1;
- background-color: $card-bg-color;
-}
-
-.card {
- position: relative;
- overflow: hidden;
- margin: $element-top-margin 0 $element-bottom-margin 0;
- background-color: $card-bg-color;
- transition: box-shadow .25s;
- border-radius: 2px;
- @extend .z-depth-1;
-
-
- .card-title {
- color: $card-bg-color;
- font-size: 24px;
- font-weight: 300;
- &.activator {
- cursor: pointer;
- }
- }
-
- // Card Sizes
- &.small, &.medium, &.large {
- position: relative;
-
- .card-image {
- overflow: hidden;
- }
- .card-content {
- overflow: hidden;
- }
- .card-action {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- }
- }
-
- &.small {
- height: 300px;
-
- .card-image {
- height: 150px;
- }
- .card-content {
- height: 150px;
- }
-
- }
-
- &.medium {
- height: 400px;
-
- .card-image {
- height: 250px;
- }
- .card-content {
- height: 150px;
- }
- }
-
- &.large {
- height: 500px;
-
- .card-image {
- height: 330px;
- }
- .card-content {
- height: 170px;
- }
- }
-
-
- .card-image {
- position: relative;
-
- // Image background for content
- img {
- border-radius: 2px 2px 0 0;
- position: relative;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- width: 100%;
- }
-
- .card-title {
- position: absolute;
- bottom: 0;
- left: 0;
- padding: $card-padding;
- }
-
- }
-
- .card-content {
- padding: $card-padding;
- border-radius: 0 0 2px 2px;
-
-
- p {
- margin: 0;
- color: inherit;
- }
- .card-title {
- line-height: 48px;
- }
- }
-
- .card-action {
- border-top: 1px solid rgba(160,160,160,.2);
- padding: $card-padding;
-
- a {
- color: $card-link-color;
- margin-right: $card-padding;
- @include transition(color .3s ease);
- text-transform: uppercase;
-
- &:hover { color: $card-link-color-light; }
- }
- }
-
- .card-reveal {
- padding: $card-padding;
- position: absolute;
- background-color: $card-bg-color;
- width: 100%;
- overflow-y: auto;
- top: 100%;
- height: 100%;
- z-index: 1;
- display: none;
-
- .card-title {
- cursor: pointer;
- display: block;
- }
-
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_collapsible.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_collapsible.scss
deleted file mode 100644
index 6b45d1e..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_collapsible.scss
+++ /dev/null
@@ -1,85 +0,0 @@
-.collapsible {
- border-top: 1px solid $collapsible-border-color;
- border-right: 1px solid $collapsible-border-color;
- border-left: 1px solid $collapsible-border-color;
- margin: $element-top-margin 0 $element-bottom-margin 0;
- @extend .z-depth-1;
-}
-
-.collapsible-header {
- display: block;
- cursor: pointer;
- height: $collapsible-height;
- line-height: $collapsible-height;
- padding: 0 1rem;
- background-color: $collapsible-header-color;
- border-bottom: 1px solid $collapsible-border-color;
-
- i {
- width: 2rem;
- font-size: 1.6rem;
- line-height: $collapsible-height;
- display: block;
- float: left;
- text-align: center;
- margin-right: 1rem;
- }
-}
-
-.collapsible-body {
- display: none;
- border-bottom: 1px solid $collapsible-border-color;
- @include box-sizing(border-box);
-
- p {
- margin: 0;
- padding: 2rem;
- }
-}
-
-// sideNav collapsible styling
-.side-nav {
-
- .collapsible {
- border: none;
- box-shadow: none;
-
- li { padding: 0; }
- }
-
- .collapsible-header {
- background-color: transparent;
- border: none;
- line-height: inherit;
- height: inherit;
- margin: 0 1rem;
-
- i { line-height: inherit; }
- }
-
- .collapsible-body {
- border: 0;
- background-color: $collapsible-header-color;
-
- li a { margin: 0 1rem 0 2rem; }
- }
-
-}
-
-// Popout Collapsible
-
-.collapsible.popout {
- border: none;
- box-shadow: none;
- > li {
- box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
- // transform: scaleX(.92);
- margin: 0 24px;
- transition: margin .35s cubic-bezier(0.250, 0.460, 0.450, 0.940);
- }
- > li.active {
- box-shadow: 0 5px 11px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15);
- margin: 16px 0;
- // transform: scaleX(1);
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_color.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_color.scss
deleted file mode 100644
index 95d65d5..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_color.scss
+++ /dev/null
@@ -1,412 +0,0 @@
-// Utility Color Classes
-
-//.success {
-//
-//}
-
-// Google Color Palette defined: http://www.google.com/design/spec/style/color.html
-
-
-$materialize-red: (
- "lighten-5": #fdeaeb,
- "lighten-4": #f8c1c3,
- "lighten-3": #f3989b,
- "lighten-2": #ee6e73,
- "lighten-1": #ea454b,
- "base": #e51c23,
- "darken-1": #d0181e,
- "darken-2": #b9151b,
- "darken-3": #a21318,
- "darken-4": #8b1014,
-);
-
-$red: (
- "lighten-5": #FFEBEE,
- "lighten-4": #FFCDD2,
- "lighten-3": #EF9A9A,
- "lighten-2": #E57373,
- "lighten-1": #EF5350,
- "base": #F44336,
- "darken-1": #E53935,
- "darken-2": #D32F2F,
- "darken-3": #C62828,
- "darken-4": #B71C1C,
- "accent-1": #FF8A80,
- "accent-2": #FF5252,
- "accent-3": #FF1744,
- "accent-4": #D50000
-);
-
-$pink: (
- "lighten-5": #fce4ec,
- "lighten-4": #f8bbd0,
- "lighten-3": #f48fb1,
- "lighten-2": #f06292,
- "lighten-1": #ec407a,
- "base": #e91e63,
- "darken-1": #d81b60,
- "darken-2": #c2185b,
- "darken-3": #ad1457,
- "darken-4": #880e4f,
- "accent-1": #ff80ab,
- "accent-2": #ff4081,
- "accent-3": #f50057,
- "accent-4": #c51162
-);
-
-$purple: (
- "lighten-5": #f3e5f5,
- "lighten-4": #e1bee7,
- "lighten-3": #ce93d8,
- "lighten-2": #ba68c8,
- "lighten-1": #ab47bc,
- "base": #9c27b0,
- "darken-1": #8e24aa,
- "darken-2": #7b1fa2,
- "darken-3": #6a1b9a,
- "darken-4": #4a148c,
- "accent-1": #ea80fc,
- "accent-2": #e040fb,
- "accent-3": #d500f9,
- "accent-4": #aa00ff
-);
-
-$deep-purple: (
- "lighten-5": #ede7f6,
- "lighten-4": #d1c4e9,
- "lighten-3": #b39ddb,
- "lighten-2": #9575cd,
- "lighten-1": #7e57c2,
- "base": #673ab7,
- "darken-1": #5e35b1,
- "darken-2": #512da8,
- "darken-3": #4527a0,
- "darken-4": #311b92,
- "accent-1": #b388ff,
- "accent-2": #7c4dff,
- "accent-3": #651fff,
- "accent-4": #6200ea
-);
-
-$indigo: (
- "lighten-5": #e8eaf6,
- "lighten-4": #c5cae9,
- "lighten-3": #9fa8da,
- "lighten-2": #7986cb,
- "lighten-1": #5c6bc0,
- "base": #3f51b5,
- "darken-1": #3949ab,
- "darken-2": #303f9f,
- "darken-3": #283593,
- "darken-4": #1a237e,
- "accent-1": #8c9eff,
- "accent-2": #536dfe,
- "accent-3": #3d5afe,
- "accent-4": #304ffe
-);
-
-$blue: (
- "lighten-5": #E3F2FD,
- "lighten-4": #BBDEFB,
- "lighten-3": #90CAF9,
- "lighten-2": #64B5F6,
- "lighten-1": #42A5F5,
- "base": #2196F3,
- "darken-1": #1E88E5,
- "darken-2": #1976D2,
- "darken-3": #1565C0,
- "darken-4": #0D47A1,
- "accent-1": #82B1FF,
- "accent-2": #448AFF,
- "accent-3": #2979FF,
- "accent-4": #2962FF
-);
-
-$light-blue: (
- "lighten-5": #e1f5fe,
- "lighten-4": #b3e5fc,
- "lighten-3": #81d4fa,
- "lighten-2": #4fc3f7,
- "lighten-1": #29b6f6,
- "base": #03a9f4,
- "darken-1": #039be5,
- "darken-2": #0288d1,
- "darken-3": #0277bd,
- "darken-4": #01579b,
- "accent-1": #80d8ff,
- "accent-2": #40c4ff,
- "accent-3": #00b0ff,
- "accent-4": #0091ea
-);
-
-$cyan: (
- "lighten-5": #e0f7fa,
- "lighten-4": #b2ebf2,
- "lighten-3": #80deea,
- "lighten-2": #4dd0e1,
- "lighten-1": #26c6da,
- "base": #00bcd4,
- "darken-1": #00acc1,
- "darken-2": #0097a7,
- "darken-3": #00838f,
- "darken-4": #006064,
- "accent-1": #84ffff,
- "accent-2": #18ffff,
- "accent-3": #00e5ff,
- "accent-4": #00b8d4
-);
-
-$teal: (
- "lighten-5": #e0f2f1,
- "lighten-4": #b2dfdb,
- "lighten-3": #80cbc4,
- "lighten-2": #4db6ac,
- "lighten-1": #26a69a,
- "base": #009688,
- "darken-1": #00897b,
- "darken-2": #00796b,
- "darken-3": #00695c,
- "darken-4": #004d40,
- "accent-1": #a7ffeb,
- "accent-2": #64ffda,
- "accent-3": #1de9b6,
- "accent-4": #00bfa5
-);
-
-$green: (
- "lighten-5": #E8F5E9,
- "lighten-4": #C8E6C9,
- "lighten-3": #A5D6A7,
- "lighten-2": #81C784,
- "lighten-1": #66BB6A,
- "base": #4CAF50,
- "darken-1": #43A047,
- "darken-2": #388E3C,
- "darken-3": #2E7D32,
- "darken-4": #1B5E20,
- "accent-1": #B9F6CA,
- "accent-2": #69F0AE,
- "accent-3": #00E676,
- "accent-4": #00C853
-);
-
-$light-green: (
- "lighten-5": #f1f8e9,
- "lighten-4": #dcedc8,
- "lighten-3": #c5e1a5,
- "lighten-2": #aed581,
- "lighten-1": #9ccc65,
- "base": #8bc34a,
- "darken-1": #7cb342,
- "darken-2": #689f38,
- "darken-3": #558b2f,
- "darken-4": #33691e,
- "accent-1": #ccff90,
- "accent-2": #b2ff59,
- "accent-3": #76ff03,
- "accent-4": #64dd17
-);
-
-$lime: (
- "lighten-5": #f9fbe7,
- "lighten-4": #f0f4c3,
- "lighten-3": #e6ee9c,
- "lighten-2": #dce775,
- "lighten-1": #d4e157,
- "base": #cddc39,
- "darken-1": #c0ca33,
- "darken-2": #afb42b,
- "darken-3": #9e9d24,
- "darken-4": #827717,
- "accent-1": #f4ff81,
- "accent-2": #eeff41,
- "accent-3": #c6ff00,
- "accent-4": #aeea00
-);
-
-$yellow: (
- "lighten-5": #fffde7,
- "lighten-4": #fff9c4,
- "lighten-3": #fff59d,
- "lighten-2": #fff176,
- "lighten-1": #ffee58,
- "base": #ffeb3b,
- "darken-1": #fdd835,
- "darken-2": #fbc02d,
- "darken-3": #f9a825,
- "darken-4": #f57f17,
- "accent-1": #ffff8d,
- "accent-2": #ffff00,
- "accent-3": #ffea00,
- "accent-4": #ffd600
-);
-
-$amber: (
- "lighten-5": #fff8e1,
- "lighten-4": #ffecb3,
- "lighten-3": #ffe082,
- "lighten-2": #ffd54f,
- "lighten-1": #ffca28,
- "base": #ffc107,
- "darken-1": #ffb300,
- "darken-2": #ffa000,
- "darken-3": #ff8f00,
- "darken-4": #ff6f00,
- "accent-1": #ffe57f,
- "accent-2": #ffd740,
- "accent-3": #ffc400,
- "accent-4": #ffab00
-);
-
-$orange: (
- "lighten-5": #fff3e0,
- "lighten-4": #ffe0b2,
- "lighten-3": #ffcc80,
- "lighten-2": #ffb74d,
- "lighten-1": #ffa726,
- "base": #ff9800,
- "darken-1": #fb8c00,
- "darken-2": #f57c00,
- "darken-3": #ef6c00,
- "darken-4": #e65100,
- "accent-1": #ffd180,
- "accent-2": #ffab40,
- "accent-3": #ff9100,
- "accent-4": #ff6d00
-);
-
-$deep-orange: (
- "lighten-5": #fbe9e7,
- "lighten-4": #ffccbc,
- "lighten-3": #ffab91,
- "lighten-2": #ff8a65,
- "lighten-1": #ff7043,
- "base": #ff5722,
- "darken-1": #f4511e,
- "darken-2": #e64a19,
- "darken-3": #d84315,
- "darken-4": #bf360c,
- "accent-1": #ff9e80,
- "accent-2": #ff6e40,
- "accent-3": #ff3d00,
- "accent-4": #dd2c00
-);
-
-$brown: (
- "lighten-5": #efebe9,
- "lighten-4": #d7ccc8,
- "lighten-3": #bcaaa4,
- "lighten-2": #a1887f,
- "lighten-1": #8d6e63,
- "base": #795548,
- "darken-1": #6d4c41,
- "darken-2": #5d4037,
- "darken-3": #4e342e,
- "darken-4": #3e2723
-);
-
-$blue-grey: (
- "lighten-5": #eceff1,
- "lighten-4": #cfd8dc,
- "lighten-3": #b0bec5,
- "lighten-2": #90a4ae,
- "lighten-1": #78909c,
- "base": #607d8b,
- "darken-1": #546e7a,
- "darken-2": #455a64,
- "darken-3": #37474f,
- "darken-4": #263238
-);
-
-$grey: (
- "lighten-5": #fafafa,
- "lighten-4": #f5f5f5,
- "lighten-3": #eeeeee,
- "lighten-2": #e0e0e0,
- "lighten-1": #bdbdbd,
- "base": #9e9e9e,
- "darken-1": #757575,
- "darken-2": #616161,
- "darken-3": #424242,
- "darken-4": #212121
-);
-
-$shades: (
- "black": #000000,
- "white": #FFFFFF,
- "transparent": transparent
-);
-
-$colors: (
- "materialize-red": $materialize-red,
- "red": $red,
- "pink": $pink,
- "purple": $purple,
- "deep-purple": $deep-purple,
- "indigo": $indigo,
- "blue": $blue,
- "light-blue": $light-blue,
- "cyan": $cyan,
- "teal": $teal,
- "green": $green,
- "light-green": $light-green,
- "lime": $lime,
- "yellow": $yellow,
- "amber": $amber,
- "orange": $orange,
- "deep-orange": $deep-orange,
- "brown": $brown,
- "blue-grey": $blue-grey,
- "grey": $grey,
- "shades": $shades
-);
-
-
-// Color Classes
-
-@each $color_name, $color in $colors {
- @each $color_type, $color_value in $color {
- @if $color_type == "base" {
- .#{$color_name} {
- background-color: $color_value !important;
- }
- .#{$color_name}-text {
- color: $color_value !important;
- }
- }
- @else {
- .#{$color_name}.#{$color_type} {
- background-color: $color_value !important;
- }
- .#{$color_name}-text.text-#{$color_type} {
- color: $color_value !important;
- }
- }
- }
-}
-
-// Shade classes
-@each $color, $color_value in $shades {
- .#{$color} {
- background-color: $color_value !important;
- }
- .#{$color}-text {
- color: $color_value !important;
- }
-}
-
-
-// usage: color("name_of_color", "type_of_color")
-// to avoid to repeating map-get($colors, ...)
-
-@function color($color, $type) {
- @if map-has-key($colors, $color) {
- $curr_color: map-get($colors, $color);
- @if map-has-key($curr_color, $type) {
- @return map-get($curr_color, $type);
- }
- }
- @warn "Unknown `#{name}` in $colors.";
- @return null;
-}
-
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_dropdown.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_dropdown.scss
deleted file mode 100644
index 585fbd6..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_dropdown.scss
+++ /dev/null
@@ -1,40 +0,0 @@
-.dropdown-content {
- @extend .z-depth-1;
- background-color: $dropdown-bg-color;
- margin: 0;
- display: none;
- min-width: 100px;
- max-height: 650px;
- overflow-y: auto;
- opacity: 0;
- position: absolute;
- z-index: 999;
- will-change: width, height;
-
- li {
- clear: both;
- color: $off-black;
- cursor: pointer;
- line-height: 1.5rem;
- width: 100%;
- text-align: left;
- text-transform: none;
-
- &:hover, &.active {
- background-color: $dropdown-hover-bg-color;
- }
-
- & > a, & > span {
- font-size: 1.2rem;
- color: $dropdown-color;
- display: block;
- padding: 1rem 1rem;
- }
-
- // Icon alignment override
- & > a > i {
- height: inherit;
- line-height: inherit;
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_form.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_form.scss
deleted file mode 100644
index ed35233..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_form.scss
+++ /dev/null
@@ -1,886 +0,0 @@
-/* Remove Focus Boxes */
-select:focus {
- outline: 1px solid lighten($secondary-color, 47%);
-}
-button:focus {
- outline: none;
- background-color: lighten($button-color, 4%);
-}
-
-label {
- font-size: $label-font-size;
- color: $input-border-color;
-}
-
-/***************************
- Text Inputs + Textarea
-****************************/
-
-// Style Placeholders
-::-webkit-input-placeholder {
- color: lighten($input-border-color, 20%);
-}
-
-:-moz-placeholder { /* Firefox 18- */
- color: lighten($input-border-color, 20%);
-}
-
-::-moz-placeholder { /* Firefox 19+ */
- color: lighten($input-border-color, 20%);
-}
-
-:-ms-input-placeholder {
- color: lighten($input-border-color, 20%);
-}
-
-// Text inputs
-input[type=text],
-input[type=password],
-input[type=email],
-input[type=url],
-input[type=time],
-input[type=date],
-input[type=datetime-local],
-input[type=tel],
-input[type=number],
-input[type=search],
-textarea.materialize-textarea {
-
- // General Styles
- background-color: transparent;
- border: none;
- border-bottom: 1px solid $input-border-color;
- border-radius: 0;
- outline: none;
- height: 3rem;
- width: 100%;
-
- font-size: 1rem;
- margin: 0 0 15px 0;
- padding: 0;
- box-shadow: none;
- @include box-sizing(content-box);
- transition: all .3s;
-
-
- // Disabled input style
- &:disabled, &[readonly="readonly"] {
- color: $input-disabled-color;
- border-bottom: 1px dotted $input-disabled-color;
- }
- // Disabled label style
- &:disabled+label, &[readonly="readonly"]+label {
- color: $input-disabled-color;
- }
- // Focused input style
- &:focus:not([readonly]) {
- border-bottom: 1px solid $input-focus-color;
- box-shadow: 0 1px 0 0 $input-focus-color;
- }
- // Focused label style
- &:focus:not([readonly])+label {
- color: $input-focus-color;
- }
- // Valid Input Style
- &.valid,
- &:focus.valid {
- border-bottom: 1px solid $input-success-color;
- box-shadow: 0 1px 0 0 $input-success-color;
- }
- // Custom Success Message
- &.valid + label:after,
- &:focus.valid + label:after {
- content: attr(data-success);
- color: $input-success-color;
- opacity: 1;
- }
- // Invalid Input Style
- &.invalid,
- &:focus.invalid {
- border-bottom: 1px solid $input-error-color;
- box-shadow: 0 1px 0 0 $input-error-color;
- }
- // Custom Error message
- &.invalid + label:after,
- &:focus.invalid + label:after {
- content: attr(data-error);
- color: $input-error-color;
- opacity: 1;
- }
-
- // Form Message Shared Styles
- & + label:after {
- display: block;
- content: "";
- position: absolute;
- top: 65px;
- opacity: 0;
- transition: .2s opacity ease-out, .2s color ease-out;
- }
-}
-
-// Styling for input field wrapper
-.input-field {
- position: relative;
- margin-top: 1rem;
-
- label {
- color: $input-border-color;
- position: absolute;
- top: 0.8rem;
- left: $gutter-width / 2;
- font-size: 1rem;
- cursor: text;
- @include transition(.2s ease-out);
- }
- label.active {
- font-size: $label-font-size;
- @include transform(translateY(-140%));
- }
-
- // Prefix Icons
- .prefix {
- position: absolute;
- width: 3rem;
- font-size: 2rem;
- @include transition(color .2s);
-
- &.active { color: $input-focus-color; }
- }
- .prefix ~ input,
- .prefix ~ textarea {
- margin-left: 3rem;
- width: 92%;
- width: calc(100% - 3rem);
- }
- .prefix ~ textarea { padding-top: .8rem; }
- .prefix ~ label { margin-left: 3rem; }
-
- @media #{$medium-and-down} {
- .prefix ~ input {
- width: 86%;
- width: calc(100% - 3rem);
- }
- }
- @media #{$small-and-down} {
- .prefix ~ input {
- width: 80%;
- width: calc(100% - 3rem);
- }
- }
-}
-
-
-// Search Field
-
-
-.input-field input[type=search] {
- display: block;
- line-height: inherit;
- padding-left: 4rem;
- width: calc(100% - 4rem);
-
- &:focus {
- background-color: $input-bg-color;
- border: 0;
- box-shadow: none;
- color: #444;
-
- & + label i,
- & ~ .mdi-navigation-close {
- color: #444;
- }
- }
-
- & + label {
- left: 1rem;
- }
-
- & ~ .mdi-navigation-close {
- position: absolute;
- top: 0;
- right: 1rem;
- color: transparent;
- cursor: pointer;
- font-size: 2rem;
- transition: .3s color;
- }
-}
-
-
-// Default textarea
-textarea {
- width: 100%;
- height: 3rem;
- background-color: transparent;
-
- &.materialize-textarea {
- overflow-y: hidden; /* prevents scroll bar flash */
- padding: 1.6rem 0; /* prevents text jump on Enter keypress */
- resize: none;
- min-height: 3rem;
- }
-}
-
-
-// For textarea autoresize
-.hiddendiv {
- display: none;
- white-space: pre-wrap;
- word-wrap: break-word;
- overflow-wrap: break-word; /* future version of deprecated 'word-wrap' */
- padding-top: 1.2rem; /* prevents text jump on Enter keypress */
-}
-
-
-/***************
- Radio Buttons
-***************/
-
-/* Remove default Radio Buttons */
-[type="radio"]:not(:checked),
-[type="radio"]:checked {
- position: absolute;
- left: -9999px;
- visibility: hidden;
-}
-
-[type="radio"]:not(:checked) + label,
-[type="radio"]:checked + label {
- position: relative;
- padding-left: 35px;
- cursor: pointer;
- display: inline-block;
- height: 25px;
- line-height: 25px;
- font-size: 1rem;
- @include transition(.28s ease);
-
- -webkit-user-select: none; /* webkit (safari, chrome) browsers */
- -moz-user-select: none; /* mozilla browsers */
- -khtml-user-select: none; /* webkit (konqueror) browsers */
- -ms-user-select: none; /* IE10+ */
-}
-
-[type="radio"] + label:before,
-[type="radio"] + label:after {
- content: '';
- position: absolute;
- left: 0;
- top: 0;
- margin: 4px;
- width: 16px;
- height: 16px;
- z-index: 0;
- @include transition(.28s ease);
-}
-
-
-/* Unchecked styles */
-[type="radio"]:not(:checked) + label:before {
- border-radius: 50%;
- border: 2px solid $radio-empty-color;
-}
-[type="radio"]:not(:checked) + label:after {
- border-radius: 50%;
- border: 2px solid $radio-empty-color;
- z-index: -1;
-
- @include transform(scale(0));
-}
-
-/* Checked styles */
-[type="radio"]:checked + label:before {
- border-radius: 50%;
- border: 2px solid transparent;
-}
-[type="radio"]:checked + label:after {
- border-radius: 50%;
- border: 2px solid $radio-fill-color;
- background-color: $radio-fill-color;
- z-index: 0;
- @include transform(scale(1.02));
-}
-
-/* Radio With gap */
-[type="radio"].with-gap:checked + label:before {
- border-radius: 50%;
- border: 2px solid $radio-fill-color;
-}
-[type="radio"].with-gap:checked + label:after {
- border-radius: 50%;
- border: 2px solid $radio-fill-color;
- background-color: $radio-fill-color;
- z-index: 0;
- @include transform(scale(.5));
-}
-
-/* Disabled Radio With gap */
-[type="radio"].with-gap:disabled:checked + label:before {
- border: 2px solid $input-disabled-color;
-}
-[type="radio"].with-gap:disabled:checked + label:after {
- border: none;
- background-color: $input-disabled-color;
-}
-
-/* Disabled style */
-[type="radio"]:disabled:not(:checked) + label:before,
-[type="radio"]:disabled:checked + label:before {
- background-color: transparent;
- border-color: $input-disabled-color;
-}
-[type="radio"]:disabled + label {
- color: $input-disabled-color;
-}
-[type="radio"]:disabled:not(:checked) + label:before {
- border-color: $input-disabled-color;
-}
-[type="radio"]:disabled:checked + label:after {
- background-color: $input-disabled-color;
- border-color: $input-disabled-solid-color;
-}
-
-
-/***************
- Checkboxes
-***************/
-
-/* CUSTOM CSS CHECKBOXES */
-form p {
- margin-bottom: 10px;
- text-align: left;
-}
-form p:last-child {
- margin-bottom: 0;
-}
-
-/* Remove default checkbox */
-[type="checkbox"]:not(:checked),
-[type="checkbox"]:checked {
- position: absolute;
- left: -9999px;
- visibility: hidden;
-}
-
-
-// Checkbox Styles
-[type="checkbox"] {
-
- // Text Label Style
- + label {
- position: relative;
- padding-left: 35px;
- cursor: pointer;
- display: inline-block;
- height: 25px;
- line-height: 25px;
- font-size: 1rem;
-
- -webkit-user-select: none; /* webkit (safari, chrome) browsers */
- -moz-user-select: none; /* mozilla browsers */
- -khtml-user-select: none; /* webkit (konqueror) browsers */
- -ms-user-select: none; /* IE10+ */
- }
-
- /* checkbox aspect */
- + label:before {
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- width: 18px;
- height: 18px;
- z-index: 0;
- border: 2px solid $radio-empty-color;
- border-radius: 1px;
- margin-top: 2px;
- @include transition(.2s);
- }
-
- &:not(:checked):disabled + label:before {
- border: none;
- background-color: $input-disabled-color;
- }
-
-}
-
-[type="checkbox"]:checked {
- + label:before {
- top: -4px;
- left: -3px;
- width: 12px; height: 22px;
- border-top: 2px solid transparent;
- border-left: 2px solid transparent;
- border-right: 2px solid $radio-fill-color;
- border-bottom: 2px solid $radio-fill-color;
- @include transform(rotate(40deg));
- -webkit-backface-visibility: hidden;
- @include transform-origin(100% 100%);
- }
-
- &:disabled + label:before {
- border-right: 2px solid $input-disabled-color;
- border-bottom: 2px solid $input-disabled-color;
- }
-
-}
-
-/* Indeterminate checkbox */
-[type="checkbox"]:indeterminate {
- +label:before {
- left: -10px;
- top: -11px;
- width: 10px; height: 22px;
- border-top: none;
- border-left: none;
- border-right: 2px solid $radio-fill-color;
- border-bottom: none;
- @include transform(rotate(90deg));
- -webkit-backface-visibility: hidden;
- @include transform-origin(100% 100%);
- }
-
- // Disabled indeterminate
- &:disabled + label:before {
- border-right: 2px solid $input-disabled-color;
- background-color: transparent;
- }
-}
-
-
-// Filled in Style
-[type="checkbox"].filled-in {
- // General
- + label:after {
- border-radius: 2px;
- }
- + label:before,
- + label:after {
- content: '';
- left: 0;
- position: absolute;
- /* .1s delay is for check animation */
- transition: border .25s, background-color .25s, width .20s .1s, height .20s .1s, top .20s .1s, left .20s .1s;
- z-index: 1;
- }
- // Unchecked style
- &:not(:checked) + label:before {
- width: 0;
- height: 0;
- border: 3px solid transparent;
- left: 6px;
- top: 10px;
-
- -webkit-transform: rotateZ(37deg);
- transform: rotateZ(37deg);
- -webkit-transform-origin: 20% 40%;
- transform-origin: 100% 100%;
- }
- &:not(:checked) + label:after {
- height: 20px;
- width: 20px;
- background-color: transparent;
- border: 2px solid $radio-empty-color;
- top: 0px;
- z-index: 0;
- }
- // Checked style
- &:checked {
- + label:before {
- top: 0;
- left: 1px;
- width: 8px;
- height: 13px;
- border-top: 2px solid transparent;
- border-left: 2px solid transparent;
- border-right: 2px solid $input-bg-color;
- border-bottom: 2px solid $input-bg-color;
- -webkit-transform: rotateZ(37deg);
- transform: rotateZ(37deg);
-
- -webkit-transform-origin: 100% 100%;
- transform-origin: 100% 100%;
- }
- + label:after {
- top: 0px;
- width: 20px;
- height: 20px;
- border: 2px solid $secondary-color;
- background-color: $secondary-color;
- z-index: 0;
- }
- }
- // Disabled style
- &:disabled:not(:checked) + label:before {
-
- background-color: transparent;
- border: 2px solid transparent;
- }
- &:disabled:not(:checked) + label:after {
- border-color: transparent;
- background-color: $input-disabled-solid-color;
- }
- &:disabled:checked + label:before {
- background-color: transparent;
-
- }
- &:disabled:checked + label:after {
- background-color: $input-disabled-solid-color;
- border-color: $input-disabled-solid-color;
- }
-
-}
-
-/***************
- Switch
-***************/
-.switch,
-.switch * {
- -webkit-user-select: none;
- -moz-user-select: none;
- -khtml-user-select: none;
- -ms-user-select: none;
-}
-.switch label {
- cursor: pointer;
-}
-.switch label input[type=checkbox]{
- opacity: 0;
- width: 0;
- height: 0;
-}
-.switch label input[type=checkbox]:checked + .lever {
- background-color: $switch-checked-lever-bg;
-}
-.switch label input[type=checkbox]:checked + .lever:after {
- background-color: $switch-bg-color;
-}
-.switch label .lever {
- content: "";
- display: inline-block;
- position: relative;
- width: 40px;
- height: 15px;
- background-color: $switch-unchecked-lever-bg;
- border-radius: 15px;
- margin-right: 10px;
- transition: background 0.3s ease;
- vertical-align: middle;
- margin: 0 16px;
-}
-.switch label .lever:after {
- content: "";
- position: absolute;
- display: inline-block;
- width: 21px;
- height: 21px;
- background-color: $switch-unchecked-bg;
- border-radius: 21px;
- box-shadow: 0 1px 3px 1px rgba(0,0,0,.4);
- left: -5px;
- top: -3px;
- transition: left 0.3s ease, background .3s ease, box-shadow 0.1s ease;
-}
-// Switch active style
-input[type=checkbox]:checked:not(:disabled) ~ .lever:active:after {
- box-shadow: 0 1px 3px 1px rgba(0,0,0,.4), 0 0 0 15px transparentize($switch-bg-color, .9);
-}
-input[type=checkbox]:not(:disabled) ~ .lever:active:after {
- box-shadow: 0 1px 3px 1px rgba(0,0,0,.4), 0 0 0 15px rgba(0, 0, 0, .08);
-}
-.switch label input[type=checkbox]:checked + .lever:after {
- left: 24px;
-}
-
-// Disabled Styles
-
-.switch input[type=checkbox][disabled] + .lever{
- cursor: default;
-}
-.switch label input[type=checkbox][disabled] + .lever:after,
-.switch label input[type=checkbox][disabled]:checked + .lever:after {
- background-color: $input-disabled-solid-color;
-}
-
-
-
-
-/***************
- Select Field
-***************/
-
-.select-label {
- position: absolute;
-}
-
-.select-wrapper {
- position: relative;
-
- input.select-dropdown {
- position: relative;
- cursor: pointer;
- // color: #444;
- background-color: transparent;
- border: none;
- border-bottom: 1px solid $input-border-color;
- outline: none;
- height: 3rem;
- line-height: 3rem;
- width: 100%;
- font-size: 1rem;
- margin: 0 0 15px 0;
- padding: 0;
- display: block;
- }
- span.caret {
- color: initial;
- position: absolute;
- right: 0;
- top: 16px;
- font-size: 10px;
- &.disabled {
- color: $input-disabled-color;
- }
- }
- & + label {
- position: absolute;
- top: -14px;
- font-size: $label-font-size;
- }
-}
-
-select { display: none; }
-select.browser-default { display: block; }
-
-
-// Disabled styles
-select:disabled {
- color: rgba(0,0,0,.3);
-}
-.select-wrapper input.select-dropdown:disabled {
- color: rgba(0,0,0,.3);
- cursor: default;
- -webkit-user-select: none; /* webkit (safari, chrome) browsers */
- -moz-user-select: none; /* mozilla browsers */
- -ms-user-select: none; /* IE10+ */
- border-bottom: 1px solid rgba(0,0,0,.3);
-}
-.select-wrapper i {
- color: rgba(0,0,0,.3);
-}
-.select-dropdown li.disabled {
- color: rgba(0,0,0,.3);
- background-color: transparent;
-}
-
-
-/*********************
- File Input
-**********************/
-.file-field {
- position: relative;
-
- .file-path-wrapper {
- overflow: hidden;
- padding-left: 10px;
- }
- input.file-path { width: 100%; }
-
- .btn {
- float: left;
- height: 3rem;
- line-height: 3rem;
- }
-
- span {
- cursor: pointer;
- }
-
- input[type=file] {
- position: absolute;
- top: 0;
- right: 0;
- left: 0;
- bottom: 0;
- width: 100%;
- margin: 0;
- padding: 0;
- font-size: 20px;
- cursor: pointer;
- opacity: 0;
- filter: alpha(opacity=0);
- }
-}
-
-
-
-/***************
- Range
-***************/
-
-.range-field {
- position: relative;
-}
-
-input[type=range], input[type=range] + .thumb {
- @extend .no-select;
- cursor: pointer;
-}
-
-input[type=range] {
- position: relative;
- background-color: transparent;
- border: none;
- outline: none;
- width: 100%;
- margin: 15px 0px;
- padding: 0;
-}
-input[type=range] + .thumb {
- position: absolute;
- border: none;
- height: 0;
- width: 0;
- border-radius: 50%;
- background-color: $radio-fill-color;
- top: 10px;
- margin-left: -6px;
-
- @include transform-origin(50% 50%);
- @include transform(rotate(-45deg));
-
- .value {
- display: block;
- width: 30px;
- text-align: center;
- color: $radio-fill-color;
- font-size: 0;
- @include transform(rotate(45deg));
- }
-
- &.active {
- border-radius: 50% 50% 50% 0;
-
- .value {
- color: $input-bg-color;
- margin-left: -1px;
- margin-top: 8px;
- font-size: 10px;
- }
- }
-}
-
-
-input[type=range]:focus {
- outline: none;
-}
-
-
-
-// WebKit
-input[type=range]{
- -webkit-appearance: none;
-}
-
-input[type=range]::-webkit-slider-runnable-track {
- height: 3px;
- background: #c2c0c2;
- border: none;
-}
-
-input[type=range]::-webkit-slider-thumb {
- -webkit-appearance: none;
- border: none;
- height: 14px;
- width: 14px;
- border-radius: 50%;
- background-color: $radio-fill-color;
- transform-origin: 50% 50%;
- margin: -5px 0 0 0;
- @include transition(.3s);
-}
-
-input[type=range]:focus::-webkit-slider-runnable-track {
- background: #ccc;
-}
-
-// FireFox
-input[type=range]{
- /* fix for FF unable to apply focus style bug */
- border: 1px solid white;
-
- /*required for proper track sizing in FF*/
-}
-
-input[type=range]::-moz-range-track {
- height: 3px;
- background: #ddd;
- border: none;
-}
-
-input[type=range]::-moz-range-thumb {
- border: none;
- height: 14px;
- width: 14px;
- border-radius: 50%;
- background: $radio-fill-color;
- margin-top: -5px;
-}
-
-/*hide the outline behind the border*/
-input[type=range]:-moz-focusring{
- outline: 1px solid white;
- outline-offset: -1px;
-}
-
-input[type=range]:focus::-moz-range-track {
- background: #ccc;
-}
-
-// IE 10+
-input[type=range]::-ms-track {
- height: 3px;
-
- /*remove bg colour from the track, we'll use ms-fill-lower and ms-fill-upper instead */
- background: transparent;
-
- /*leave room for the larger thumb to overflow with a transparent border */
- border-color: transparent;
- border-width: 6px 0;
-
- /*remove default tick marks*/
- color: transparent;
-}
-input[type=range]::-ms-fill-lower {
- background: #777;
-}
-input[type=range]::-ms-fill-upper {
- background: #ddd;
-}
-input[type=range]::-ms-thumb {
- border: none;
- height: 14px;
- width: 14px;
- border-radius: 50%;
- background: $radio-fill-color;
-}
-input[type=range]:focus::-ms-fill-lower {
- background: #888;
-}
-input[type=range]:focus::-ms-fill-upper {
- background: #ccc;
-}
-
-/***************************
- Text Inputs + Textarea
-****************************/
-
-select {
- background-color: rgba(255, 255, 255, 0.90);
- width: 100%;
- padding: 5px;
- border: 1px solid #f2f2f2;
- border-radius: 2px;
- height: 3rem;
- }
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_global.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_global.scss
deleted file mode 100644
index c246270..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_global.scss
+++ /dev/null
@@ -1,718 +0,0 @@
-@charset "UTF-8";
-
-
-//Default styles
-
-html {
- box-sizing: border-box;
-}
-*, *:before, *:after {
- box-sizing: inherit;
-}
-
-body {
- // display: flex;
- // min-height: 100vh;
- // flex-direction: column;
-}
-
-main {
- // flex: 1 0 auto;
-}
-
-ul {
- list-style-type: none;
-}
-
-a {
- color: $link-color;
- text-decoration: none;
-
- // Gets rid of tap active state
- -webkit-tap-highlight-color: transparent;
-}
-
-
-// Positioning
-.valign-wrapper {
- @include flexbox();
- @include align(center);
-
- .valign {
- display: block;
- }
-}
-
-
-ul {
- padding: 0;
- li {
- list-style-type: none;
- }
-}
-
-// classic clearfix
-.clearfix {
- clear: both;
-}
-
-
-// Z-levels
-.z-depth-0 {
- box-shadow: none !important;
-}
-.z-depth-1{
- box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
-}
-.z-depth-1-half{
- box-shadow: 0 5px 11px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15);
-}
-.z-depth-2{
- box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
-}
-.z-depth-3{
- box-shadow: 0 12px 15px 0 rgba(0, 0, 0, 0.24), 0 17px 50px 0 rgba(0, 0, 0, 0.19);
-}
-.z-depth-4{
- box-shadow: 0 16px 28px 0 rgba(0, 0, 0, 0.22), 0 25px 55px 0 rgba(0, 0, 0, 0.21);
-}
-.z-depth-5{
- box-shadow: 0 27px 24px 0 rgba(0, 0, 0, 0.2), 0 40px 77px 0 rgba(0, 0, 0, 0.22);
-}
-
-.hoverable:hover {
- transition: box-shadow .25s;
- box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
-}
-
-// Dividers
-
-.divider {
- height: 1px;
- overflow: hidden;
- background-color: color("grey", "lighten-2");
-}
-
-
-// Blockquote
-
-blockquote {
- margin: 20px 0;
- padding-left: 1.5rem;
- border-left: 5px solid $primary-color;
-}
-
-// Icon Styles
-
-i {
- line-height: inherit;
-
- &.left {
- float: left;
- margin-right: 15px;
- }
- &.right {
- float: right;
- margin-left: 15px;
- }
- &.tiny {
- font-size: 1rem;
- }
- &.small {
- font-size: 2rem;
- }
- &.medium {
- font-size: 4rem;
- }
- &.large {
- font-size: 6rem;
- }
-}
-
-// Images
-img.responsive-img,
-video.responsive-video {
- max-width: 100%;
- height: auto;
-}
-
-
-// Pagination
-
-.pagination {
-
- li {
- float: left;
- font-size: 1.2rem;
- padding: 0 10px;
- line-height: 30px;
- border-radius: 2px;
- text-align: center;
-
- a { color: #444; }
-
- &.active a { color: #fff; }
-
- &.active { background-color: $primary-color; }
-
- &.disabled a {
- cursor: default;
- color: #999;
- }
-
- i {
- font-size: 2rem;
- }
- }
-
-
- li.pages ul li {
- display: inline-block;
- float: none;
- }
-}
-@media #{$medium-and-down} {
- .pagination {
- width: 100%;
-
- li.prev,
- li.next {
- width: 10%;
- }
-
- li.pages {
- width: 80%;
- overflow: hidden;
- white-space: nowrap;
- }
- }
-}
-
-
-// Parallax
-.parallax-container {
- position: relative;
- overflow: hidden;
- height: 500px;
-}
-
-.parallax {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: -1;
-
- img {
- display: none;
- position: absolute;
- left: 50%;
- bottom: 0;
- min-width: 100%;
- min-height: 100%;
- -webkit-transform: translate3d(0,0,0);
- transform: translate3d(0,0,0);
- transform: translateX(-50%);
- }
-}
-
-// Pushpin
-.pin-top, .pin-bottom {
- position: relative;
-}
-.pinned {
- position: fixed !important;
-}
-
-/*********************
- Transition Classes
-**********************/
-
-ul.staggered-list li {
- opacity: 0;
-}
-
-.fade-in {
- opacity: 0;
- transform-origin: 0 50%;
-}
-
-
-/*********************
- Media Query Classes
-**********************/
-.hide-on-small-only, .hide-on-small-and-down {
- @media #{$small-and-down} {
- display: none !important;
- }
-}
-.hide-on-med-and-down {
- @media #{$medium-and-down} {
- display: none !important;
- }
-}
-.hide-on-med-and-up {
- @media #{$medium-and-up} {
- display: none !important;
- }
-}
-.hide-on-med-only {
- @media only screen and (min-width: $small-screen) and (max-width: $medium-screen) {
- display: none !important;
- }
-}
-.hide-on-large-only {
- @media #{$large-and-up} {
- display: none !important;
- }
-}
-.show-on-large {
- @media #{$large-and-up} {
- display: initial !important;
- }
-}
-.show-on-medium {
- @media only screen and (min-width: $small-screen) and (max-width: $medium-screen) {
- display: initial !important;
- }
-}
-.show-on-small {
- @media #{$small-and-down} {
- display: initial !important;
- }
-}
-.show-on-medium-and-up {
- @media #{$medium-and-up} {
- display: initial !important;
- }
-}
-.show-on-medium-and-down {
- @media #{$medium-and-down} {
- display: initial !important;
- }
-}
-
-
-// Center text on mobile
-.center-on-small-only {
- @media #{$small-and-down} {
- text-align: center;
- }
-}
-
-// Footer
-footer.page-footer {
- margin-top: 20px;
- padding-top: 20px;
- background-color: $footer-bg-color;
-
- .footer-copyright {
- overflow: hidden;
- height: 50px;
- line-height: 50px;
- color: rgba(255,255,255,.8);
- background-color: rgba(51,51,51,.08);;
- @extend .light;
- }
-}
-
-// Tables
-table, th, td {
- border: none;
-}
-
-table {
- width:100%;
- display: table;
-
- &.bordered > thead > tr,
- &.bordered > tbody > tr {
- border-bottom: 1px solid $table-border-color;
- }
-
- &.striped > tbody {
- > tr:nth-child(odd) {
- background-color: $table-striped-color;
- }
-
- > tr > td {
- border-radius: 0px;
- }
- }
-
- &.hoverable > tbody > tr {
- @include transition(background-color .25s ease);
- &:hover {
- background-color: $table-striped-color;
- }
- }
-
- &.centered {
- thead tr th, tbody tr td {
- text-align: center;
-
- }
- }
-
-}
-
-thead {
- border-bottom: 1px solid $table-border-color;
-}
-
-td, th{
- padding: 15px 5px;
- display: table-cell;
- text-align: left;
- vertical-align: middle;
- border-radius: 2px;
-}
-
-// Responsive Table
-@media #{$medium-and-down} {
-
- table.responsive-table {
- width: 100%;
- border-collapse: collapse;
- border-spacing: 0;
- display: block;
- position: relative;
-
- th,
- td {
- margin: 0;
- vertical-align: top;
- }
-
- th { text-align: left; }
- thead {
- display: block;
- float: left;
-
- tr {
- display: block;
- padding: 0 10px 0 0;
-
- th::before {
- content: "\00a0";
- }
- }
- }
- tbody {
- display: block;
- width: auto;
- position: relative;
- overflow-x: auto;
- white-space: nowrap;
-
- tr {
- display: inline-block;
- vertical-align: top;
- }
- }
- th {
- display: block;
- text-align: right;
- }
- td {
- display: block;
- min-height: 1.25em;
- text-align: left;
- }
- tr { padding: 0 10px; }
-
- /* sort out borders */
- thead {
- border: 0;
- border-right: 1px solid $table-border-color;
- }
-
- &.bordered {
- th { border-bottom: 0; border-left: 0; }
- td { border-left: 0; border-right: 0; border-bottom: 0; }
- tr { border: 0; }
- tbody tr { border-right: 1px solid $table-border-color; }
- }
-
- }
-
-}
-
-
-// Collections
-.collection {
- margin: $element-top-margin 0 $element-bottom-margin 0;
- border: 1px solid $collection-border-color;
- border-radius: 2px;
- overflow: hidden;
- position: relative;
-
- .collection-item {
- background-color: $collection-bg-color;
- line-height: 1.5rem;
- padding: 10px 20px;
- margin: 0;
- border-bottom: 1px solid $collection-border-color;
-
- // Avatar Collection
- &.avatar {
- min-height: 84px;
- padding-left: 72px;
- position: relative;
-
- .circle {
- position: absolute;
- width: 42px;
- height: 42px;
- overflow: hidden;
- left: 15px;
- display: inline-block;
- vertical-align: middle;
- }
- i.circle {
- font-size: 18px;
- line-height: 42px;
- color: #fff;
- background-color: #999;
- text-align: center;
- }
-
-
- .title {
- font-size: 16px;
- }
-
- p {
- margin: 0;
- }
-
- .secondary-content {
- position: absolute;
- top: 16px;
- right: 16px;
- }
-
- }
-
-
- &:last-child {
- border-bottom: none;
- }
-
- &.active {
- background-color: $collection-active-bg-color;
- color: $collection-active-color;
- }
- }
- a.collection-item{
- display: block;
- @include transition(.25s);
- color: $secondary-color;
- &:not(.active) {
- &:hover {
- background-color: $collection-hover-bg-color;
- }
- }
- }
-
- &.with-header {
- .collection-header {
- background-color: $collection-bg-color;
- border-bottom: 1px solid $collection-border-color;
- padding: 10px 20px;
- }
- .collection-item {
- padding-left: 30px;
- }
- .collection-item.avatar {
- padding-left: 72px;
- }
- }
-
-}
-// Made less specific to allow easier overriding
-.secondary-content {
- float: right;
- color: $secondary-color;
-}
-
-
-// Badges
-span.badge {
- min-width: 3rem;
- padding: 0 6px;
- text-align: center;
- font-size: 1rem;
- line-height: inherit;
- color: color('grey', 'darken-1');
- position: absolute;
- right: 15px;
- @include box-sizing(border-box);
-
- &.new {
- font-weight: 300;
- font-size: 0.8rem;
- color: #fff;
- background-color: $badge-bg-color;
- border-radius: 2px;
- }
- &.new:after {
- content: " new";
- }
-}
-
-// Responsive Videos
-.video-container {
- position: relative;
- padding-bottom: 56.25%;
- padding-top: 30px;
- height: 0;
- overflow: hidden;
- &.no-controls {
- padding-top: 0;
- }
-
- iframe, object, embed {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- }
-}
-
-// Progress Bar
-.progress {
- position: relative;
- height: 4px;
- display: block;
- width: 100%;
- background-color: lighten($progress-bar-color, 40%);
- border-radius: 2px;
- margin: $element-top-margin 0 $element-bottom-margin 0;
- overflow: hidden;
- .determinate {
- position: absolute;
- background-color: inherit;
- top: 0;
- left: 0;
- bottom: 0;
- background-color: $progress-bar-color;
- @include transition(width .3s linear);
- }
- .indeterminate {
- background-color: $progress-bar-color;
- &:before {
- content: '';
- position: absolute;
- background-color: inherit;
- top: 0;
- left:0;
- bottom: 0;
- will-change: left, right;
- // Custom bezier
- @include animation(indeterminate 2.1s cubic-bezier(0.650, 0.815, 0.735, 0.395) infinite);
-
- }
- &:after {
- content: '';
- position: absolute;
- background-color: inherit;
- top: 0;
- left:0;
- bottom: 0;
- will-change: left, right;
- // Custom bezier
- @include animation(indeterminate-short 2.1s cubic-bezier(0.165, 0.840, 0.440, 1.000) infinite);
- @include animation-delay(1.15s);
- }
- }
-}
-@include keyframes(indeterminate) {
- 0% {
- left: -35%;
- right:100%;
- }
- 60% {
- left: 100%;
- right: -90%;
- }
- 100% {
- left: 100%;
- right: -90%;
- }
-}
-
-@include keyframes(indeterminate-short) {
- 0% {
- left: -200%;
- right: 100%;
- }
- 60% {
- left: 107%;
- right: -8%;
- }
- 100% {
- left: 107%;
- right: -8%;
- }
-}
-
-
-/*******************
- Utility Classes
-*******************/
-
-.hide {
- display: none !important;
-}
-
-// Text Align
-.left-align {
- text-align: left;
-}
-.right-align {
- text-align: right
-}
-.center, .center-align {
- text-align: center;
-}
-
-.left {
- float: left !important;
-}
-.right {
- float: right !important;
-}
-
-// No Text Select
-.no-select {
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -khtml-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-
-.circle {
- border-radius: 50%;
-}
-
-.center-block {
- display: block;
- margin-left: auto;
- margin-right: auto;
-}
-
-.truncate {
- display: block;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.no-padding {
- padding: 0 !important;
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_grid.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_grid.scss
deleted file mode 100644
index 68d727d..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_grid.scss
+++ /dev/null
@@ -1,117 +0,0 @@
-.container {
- margin: 0 auto;
- max-width: 1280px;
- width: 90%;
-}
-@media #{$medium-and-up} {
- .container {
- width: 85%;
- }
-}
-@media #{$large-and-up} {
- .container {
- width: 70%;
- }
-}
-.container .row {
- margin-left: (-1 * $gutter-width / 2);
- margin-right: (-1 * $gutter-width / 2);
-}
-
-.section {
- padding-top: 1rem;
- padding-bottom: 1rem;
-
- &.no-pad {
- padding: 0;
- }
- &.no-pad-bot {
- padding-bottom: 0;
- }
- &.no-pad-top {
- padding-top: 0;
- }
-}
-
-
-.row {
- margin-left: auto;
- margin-right: auto;
- margin-bottom: 20px;
-
- // Clear floating children
- &:after {
- content: "";
- display: table;
- clear: both;
- }
-
- .col {
- float: left;
- @include box-sizing(border-box);
- padding: 0 $gutter-width / 2;
-
- $i: 1;
- @while $i <= $num-cols {
- $perc: unquote((100 / ($num-cols / $i)) + "%");
- &.s#{$i} {
- width: $perc;
- margin-left: 0;
- }
- $i: $i + 1;
- }
- $i: 1;
- @while $i <= $num-cols {
- $perc: unquote((100 / ($num-cols / $i)) + "%");
- &.offset-s#{$i} {
- margin-left: $perc;
- }
- $i: $i + 1;
- }
-
- @media #{$medium-and-up} {
-
- $i: 1;
- @while $i <= $num-cols {
- $perc: unquote((100 / ($num-cols / $i)) + "%");
- &.m#{$i} {
- width: $perc;
- margin-left: 0;
- }
- $i: $i + 1;
- }
- $i: 1;
- @while $i <= $num-cols {
- $perc: unquote((100 / ($num-cols / $i)) + "%");
- &.offset-m#{$i} {
- margin-left: $perc;
- }
- $i: $i + 1;
- }
-
- }
-
- @media #{$large-and-up} {
-
- $i: 1;
- @while $i <= $num-cols {
- $perc: unquote((100 / ($num-cols / $i)) + "%");
- &.l#{$i} {
- width: $perc;
- margin-left: 0;
- }
- $i: $i + 1;
- }
- $i: 1;
- @while $i <= $num-cols {
- $perc: unquote((100 / ($num-cols / $i)) + "%");
- &.offset-l#{$i} {
- margin-left: $perc;
- }
- $i: $i + 1;
- }
-
- }
-
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_icons-material-design.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_icons-material-design.scss
deleted file mode 100644
index 3c78470..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_icons-material-design.scss
+++ /dev/null
@@ -1,3257 +0,0 @@
-$font-mdi : 'Material-Design-Icons';
-$mdi-prefix : 'mdi-';
-
-@font-face {
- font-family: "#{$font-mdi}";
- src:url("#{$icons-font-path}#{$font-mdi}.eot?#iefix") format("embedded-opentype"),
- url("#{$icons-font-path}#{$font-mdi}.woff2") format("woff2"),
- url("#{$icons-font-path}#{$font-mdi}.woff") format("woff"),
- url("#{$icons-font-path}#{$font-mdi}.ttf") format("truetype"),
- url("#{$icons-font-path}#{$font-mdi}.svg##{$font-mdi}") format("svg");
- font-weight: normal;
- font-style: normal;
-}
-
-[class^="mdi-"], [class*="mdi-"] {
- speak: none;
- display: inline-block;
- font-family: "Material-Design-Icons";
- font-style: normal;
- font-weight: normal;
- font-variant: normal;
- text-rendering: auto;
- /* Better Font Rendering =========== */
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- transform: translate(0, 0);
- &:before {
- display: inline-block;
- speak: none;
- text-decoration: inherit;
- }
- &.pull-left {
- margin-right: .3em;
- }
- &.pull-right{
- margin-left: .3em;
- }
- &.mdi-lg:before, &.mdi-lg:after {
- font-size: 1.33333333em;
- line-height: 0.75em;
- vertical-align: -15%;
- }
- &.mdi-2x:before, &.mdi-2x:after {
- font-size: 2em;
- }
- &.mdi-3x:before, &.mdi-3x:after {
- font-size: 3em;
- }
- &.mdi-4x:before, &.mdi-4x:after {
- font-size: 4em;
- }
- &.mdi-5x:before, &.mdi-5x:after {
- font-size: 5em;
- }
-}
-
-[class^="mdi-device-signal-cellular-"],
-[class^="mdi-device-battery-"],
-[class^="mdi-device-battery-charging-"],
-[class^="mdi-device-signal-cellular-connected-no-internet-"],
-[class^="mdi-device-signal-wifi-"],
-[class^="mdi-device-signal-wifi-statusbar-not-connected"],
-.mdi-device-network-wifi{
- &:after {
- opacity: .3;
- position: absolute;
- left: 0;
- top: 0;
- z-index: 1;
- display: inline-block;
- speak: none;
- text-decoration: inherit;
- }
-}
-
-[class^="mdi-device-signal-cellular-"]:after {content:"\e758";}
-[class^="mdi-device-battery-"]:after {content:"\e735";}
-[class^="mdi-device-battery-charging-"]:after {content:"\e733";}
-[class^="mdi-device-signal-cellular-connected-no-internet-"]:after {content:"\e75d";}
-[class^="mdi-device-signal-wifi-"]:after, .mdi-device-network-wifi:after {content:"\e765";}
-[class^="mdi-device-signal-wifi-statusbasr-not-connected"]:after {content:"\e8f7";}
-
-.mdi-device-signal-cellular-off, .mdi-device-signal-cellular-null, .mdi-device-signal-cellular-no-sim, .mdi-device-signal-wifi-off, .mdi-device-signal-wifi-4-bar, .mdi-device-signal-cellular-4-bar, .mdi-device-battery-alert, .mdi-device-signal-cellular-connected-no-internet-4-bar, .mdi-device-battery-std, .mdi-device-battery-full .mdi-device-battery-unknown {
- &:after {
- content: "";
- }
-}
-
-.mdi-fw {
- width: 1.28571429em;
- text-align: center;
-}
-.mdi-ul {
- padding-left: 0;
- margin-left: 2.14285714em;
- list-style-type: none;
-}
-.mdi-ul > li {
- position: relative;
-}
-.mdi-li {
- position: absolute;
- left: -2.14285714em;
- width: 2.14285714em;
- top: 0.14285714em;
- text-align: center;
-}
-.mdi-li.mdi-lg {
- left: -1.85714286em;
-}
-.mdi-border {
- padding: .2em .25em .15em;
- border: solid 0.08em #eeeeee;
- border-radius: .1em;
-}
-
-.mdi-spin {
- -webkit-animation: mdi-spin 2s infinite linear;
- animation: mdi-spin 2s infinite linear;
- -webkit-transform-origin: 50% 50%;
- -moz-transform-origin: 50% 50%;
- -o-transform-origin: 50% 50%;
- transform-origin: 50% 50%;
-}
-.mdi-pulse {
- -webkit-animation: mdi-spin 1s steps(8) infinite;
- animation: mdi-spin 1s steps(8) infinite ;
- -webkit-transform-origin: 50% 50%;
- -moz-transform-origin: 50% 50%;
- -o-transform-origin: 50% 50%;
- transform-origin: 50% 50%;
-}
-@-webkit-keyframes mdi-spin {
- 0% {
- -webkit-transform: rotate(0deg);
- transform: rotate(0deg);
- }
- 100% {
- -webkit-transform: rotate(359deg);
- transform: rotate(359deg);
- }
-}
-@keyframes mdi-spin {
- 0% {
- -webkit-transform: rotate(0deg);
- transform: rotate(0deg);
- }
- 100% {
- -webkit-transform: rotate(359deg);
- transform: rotate(359deg);
- }
-}
-.mdi-rotate-90 {
- filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
- -webkit-transform: rotate(90deg);
- -ms-transform: rotate(90deg);
- transform: rotate(90deg);
-}
-.mdi-rotate-180 {
- filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
- -webkit-transform: rotate(180deg);
- -ms-transform: rotate(180deg);
- transform: rotate(180deg);
-}
-.mdi-rotate-270 {
- filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
- -webkit-transform: rotate(270deg);
- -ms-transform: rotate(270deg);
- transform: rotate(270deg);
-}
-.mdi-flip-horizontal {
- filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);
- -webkit-transform: scale(-1, 1);
- -ms-transform: scale(-1, 1);
- transform: scale(-1, 1);
-}
-.mdi-flip-vertical {
- filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);
- -webkit-transform: scale(1, -1);
- -ms-transform: scale(1, -1);
- transform: scale(1, -1);
-}
-:root .mdi-rotate-90,
-:root .mdi-rotate-180,
-:root .mdi-rotate-270,
-:root .mdi-flip-horizontal,
-:root .mdi-flip-vertical {
- filter: none;
-}
-.mdi-stack {
- position: relative;
- display: inline-block;
- width: 2em;
- height: 2em;
- line-height: 2em;
- vertical-align: middle;
-}
-.mdi-stack-1x,
-.mdi-stack-2x {
- position: absolute;
- left: 0;
- width: 100%;
- text-align: center;
-}
-.mdi-stack-1x {
- line-height: inherit;
-}
-.mdi-stack-2x {
- font-size: 2em;
-}
-.mdi-inverse {
- color: #ffffff;
-}
-
-
-/* Start Icons */
-
-
-.mdi-action-3d-rotation:before {
- content: "\e600";
-}
-
-.mdi-action-accessibility:before {
- content: "\e601";
-}
-
-.mdi-action-account-balance-wallet:before {
- content: "\e602";
-}
-
-.mdi-action-account-balance:before {
- content: "\e603";
-}
-
-.mdi-action-account-box:before {
- content: "\e604";
-}
-
-.mdi-action-account-child:before {
- content: "\e605";
-}
-
-.mdi-action-account-circle:before {
- content: "\e606";
-}
-
-.mdi-action-add-shopping-cart:before {
- content: "\e607";
-}
-
-.mdi-action-alarm-add:before {
- content: "\e608";
-}
-
-.mdi-action-alarm-off:before {
- content: "\e609";
-}
-
-.mdi-action-alarm-on:before {
- content: "\e60a";
-}
-
-.mdi-action-alarm:before {
- content: "\e60b";
-}
-
-.mdi-action-android:before {
- content: "\e60c";
-}
-
-.mdi-action-announcement:before {
- content: "\e60d";
-}
-
-.mdi-action-aspect-ratio:before {
- content: "\e60e";
-}
-
-.mdi-action-assessment:before {
- content: "\e60f";
-}
-
-.mdi-action-assignment-ind:before {
- content: "\e610";
-}
-
-.mdi-action-assignment-late:before {
- content: "\e611";
-}
-
-.mdi-action-assignment-return:before {
- content: "\e612";
-}
-
-.mdi-action-assignment-returned:before {
- content: "\e613";
-}
-
-.mdi-action-assignment-turned-in:before {
- content: "\e614";
-}
-
-.mdi-action-assignment:before {
- content: "\e615";
-}
-
-.mdi-action-autorenew:before {
- content: "\e616";
-}
-
-.mdi-action-backup:before {
- content: "\e617";
-}
-
-.mdi-action-book:before {
- content: "\e618";
-}
-
-.mdi-action-bookmark-outline:before {
- content: "\e619";
-}
-
-.mdi-action-bookmark:before {
- content: "\e61a";
-}
-
-.mdi-action-bug-report:before {
- content: "\e61b";
-}
-
-.mdi-action-cached:before {
- content: "\e61c";
-}
-
-.mdi-action-check-circle:before {
- content: "\e61d";
-}
-
-.mdi-action-class:before {
- content: "\e61e";
-}
-
-.mdi-action-credit-card:before {
- content: "\e61f";
-}
-
-.mdi-action-dashboard:before {
- content: "\e620";
-}
-
-.mdi-action-delete:before {
- content: "\e621";
-}
-
-.mdi-action-description:before {
- content: "\e622";
-}
-
-.mdi-action-dns:before {
- content: "\e623";
-}
-
-.mdi-action-done-all:before {
- content: "\e624";
-}
-
-.mdi-action-done:before {
- content: "\e625";
-}
-
-.mdi-action-event:before {
- content: "\e626";
-}
-
-.mdi-action-exit-to-app:before {
- content: "\e627";
-}
-
-.mdi-action-explore:before {
- content: "\e628";
-}
-
-.mdi-action-extension:before {
- content: "\e629";
-}
-
-.mdi-action-face-unlock:before {
- content: "\e62a";
-}
-
-.mdi-action-favorite-outline:before {
- content: "\e62b";
-}
-
-.mdi-action-favorite:before {
- content: "\e62c";
-}
-
-.mdi-action-find-in-page:before {
- content: "\e62d";
-}
-
-.mdi-action-find-replace:before {
- content: "\e62e";
-}
-
-.mdi-action-flip-to-back:before {
- content: "\e62f";
-}
-
-.mdi-action-flip-to-front:before {
- content: "\e630";
-}
-
-.mdi-action-get-app:before {
- content: "\e631";
-}
-
-.mdi-action-grade:before {
- content: "\e632";
-}
-
-.mdi-action-group-work:before {
- content: "\e633";
-}
-
-.mdi-action-help:before {
- content: "\e634";
-}
-
-.mdi-action-highlight-remove:before {
- content: "\e635";
-}
-
-.mdi-action-history:before {
- content: "\e636";
-}
-
-.mdi-action-home:before {
- content: "\e637";
-}
-
-.mdi-action-https:before {
- content: "\e638";
-}
-
-.mdi-action-info-outline:before {
- content: "\e639";
-}
-
-.mdi-action-info:before {
- content: "\e63a";
-}
-
-.mdi-action-input:before {
- content: "\e63b";
-}
-
-.mdi-action-invert-colors:before {
- content: "\e63c";
-}
-
-.mdi-action-label-outline:before {
- content: "\e63d";
-}
-
-.mdi-action-label:before {
- content: "\e63e";
-}
-
-.mdi-action-language:before {
- content: "\e63f";
-}
-
-.mdi-action-launch:before {
- content: "\e640";
-}
-
-.mdi-action-list:before {
- content: "\e641";
-}
-
-.mdi-action-lock-open:before {
- content: "\e642";
-}
-
-.mdi-action-lock-outline:before {
- content: "\e643";
-}
-
-.mdi-action-lock:before {
- content: "\e644";
-}
-
-.mdi-action-loyalty:before {
- content: "\e645";
-}
-
-.mdi-action-markunread-mailbox:before {
- content: "\e646";
-}
-
-.mdi-action-note-add:before {
- content: "\e647";
-}
-
-.mdi-action-open-in-browser:before {
- content: "\e648";
-}
-
-.mdi-action-open-in-new:before {
- content: "\e649";
-}
-
-.mdi-action-open-with:before {
- content: "\e64a";
-}
-
-.mdi-action-pageview:before {
- content: "\e64b";
-}
-
-.mdi-action-payment:before {
- content: "\e64c";
-}
-
-.mdi-action-perm-camera-mic:before {
- content: "\e64d";
-}
-
-.mdi-action-perm-contact-cal:before {
- content: "\e64e";
-}
-
-.mdi-action-perm-data-setting:before {
- content: "\e64f";
-}
-
-.mdi-action-perm-device-info:before {
- content: "\e650";
-}
-
-.mdi-action-perm-identity:before {
- content: "\e651";
-}
-
-.mdi-action-perm-media:before {
- content: "\e652";
-}
-
-.mdi-action-perm-phone-msg:before {
- content: "\e653";
-}
-
-.mdi-action-perm-scan-wifi:before {
- content: "\e654";
-}
-
-.mdi-action-picture-in-picture:before {
- content: "\e655";
-}
-
-.mdi-action-polymer:before {
- content: "\e656";
-}
-
-.mdi-action-print:before {
- content: "\e657";
-}
-
-.mdi-action-query-builder:before {
- content: "\e658";
-}
-
-.mdi-action-question-answer:before {
- content: "\e659";
-}
-
-.mdi-action-receipt:before {
- content: "\e65a";
-}
-
-.mdi-action-redeem:before {
- content: "\e65b";
-}
-
-.mdi-action-reorder:before {
- content: "\e65c";
-}
-
-.mdi-action-report-problem:before {
- content: "\e65d";
-}
-
-.mdi-action-restore:before {
- content: "\e65e";
-}
-
-.mdi-action-room:before {
- content: "\e65f";
-}
-
-.mdi-action-schedule:before {
- content: "\e660";
-}
-
-.mdi-action-search:before {
- content: "\e661";
-}
-
-.mdi-action-settings-applications:before {
- content: "\e662";
-}
-
-.mdi-action-settings-backup-restore:before {
- content: "\e663";
-}
-
-.mdi-action-settings-bluetooth:before {
- content: "\e664";
-}
-
-.mdi-action-settings-cell:before {
- content: "\e665";
-}
-
-.mdi-action-settings-display:before {
- content: "\e666";
-}
-
-.mdi-action-settings-ethernet:before {
- content: "\e667";
-}
-
-.mdi-action-settings-input-antenna:before {
- content: "\e668";
-}
-
-.mdi-action-settings-input-component:before {
- content: "\e669";
-}
-
-.mdi-action-settings-input-composite:before {
- content: "\e66a";
-}
-
-.mdi-action-settings-input-hdmi:before {
- content: "\e66b";
-}
-
-.mdi-action-settings-input-svideo:before {
- content: "\e66c";
-}
-
-.mdi-action-settings-overscan:before {
- content: "\e66d";
-}
-
-.mdi-action-settings-phone:before {
- content: "\e66e";
-}
-
-.mdi-action-settings-power:before {
- content: "\e66f";
-}
-
-.mdi-action-settings-remote:before {
- content: "\e670";
-}
-
-.mdi-action-settings-voice:before {
- content: "\e671";
-}
-
-.mdi-action-settings:before {
- content: "\e672";
-}
-
-.mdi-action-shop-two:before {
- content: "\e673";
-}
-
-.mdi-action-shop:before {
- content: "\e674";
-}
-
-.mdi-action-shopping-basket:before {
- content: "\e675";
-}
-
-.mdi-action-shopping-cart:before {
- content: "\e676";
-}
-
-.mdi-action-speaker-notes:before {
- content: "\e677";
-}
-
-.mdi-action-spellcheck:before {
- content: "\e678";
-}
-
-.mdi-action-star-rate:before {
- content: "\e679";
-}
-
-.mdi-action-stars:before {
- content: "\e67a";
-}
-
-.mdi-action-store:before {
- content: "\e67b";
-}
-
-.mdi-action-subject:before {
- content: "\e67c";
-}
-
-.mdi-action-supervisor-account:before {
- content: "\e67d";
-}
-
-.mdi-action-swap-horiz:before {
- content: "\e67e";
-}
-
-.mdi-action-swap-vert-circle:before {
- content: "\e67f";
-}
-
-.mdi-action-swap-vert:before {
- content: "\e680";
-}
-
-.mdi-action-system-update-tv:before {
- content: "\e681";
-}
-
-.mdi-action-tab-unselected:before {
- content: "\e682";
-}
-
-.mdi-action-tab:before {
- content: "\e683";
-}
-
-.mdi-action-theaters:before {
- content: "\e684";
-}
-
-.mdi-action-thumb-down:before {
- content: "\e685";
-}
-
-.mdi-action-thumb-up:before {
- content: "\e686";
-}
-
-.mdi-action-thumbs-up-down:before {
- content: "\e687";
-}
-
-.mdi-action-toc:before {
- content: "\e688";
-}
-
-.mdi-action-today:before {
- content: "\e689";
-}
-
-.mdi-action-track-changes:before {
- content: "\e68a";
-}
-
-.mdi-action-translate:before {
- content: "\e68b";
-}
-
-.mdi-action-trending-down:before {
- content: "\e68c";
-}
-
-.mdi-action-trending-neutral:before {
- content: "\e68d";
-}
-
-.mdi-action-trending-up:before {
- content: "\e68e";
-}
-
-.mdi-action-turned-in-not:before {
- content: "\e68f";
-}
-
-.mdi-action-turned-in:before {
- content: "\e690";
-}
-
-.mdi-action-verified-user:before {
- content: "\e691";
-}
-
-.mdi-action-view-agenda:before {
- content: "\e692";
-}
-
-.mdi-action-view-array:before {
- content: "\e693";
-}
-
-.mdi-action-view-carousel:before {
- content: "\e694";
-}
-
-.mdi-action-view-column:before {
- content: "\e695";
-}
-
-.mdi-action-view-day:before {
- content: "\e696";
-}
-
-.mdi-action-view-headline:before {
- content: "\e697";
-}
-
-.mdi-action-view-list:before {
- content: "\e698";
-}
-
-.mdi-action-view-module:before {
- content: "\e699";
-}
-
-.mdi-action-view-quilt:before {
- content: "\e69a";
-}
-
-.mdi-action-view-stream:before {
- content: "\e69b";
-}
-
-.mdi-action-view-week:before {
- content: "\e69c";
-}
-
-.mdi-action-visibility-off:before {
- content: "\e69d";
-}
-
-.mdi-action-visibility:before {
- content: "\e69e";
-}
-
-.mdi-action-wallet-giftcard:before {
- content: "\e69f";
-}
-
-.mdi-action-wallet-membership:before {
- content: "\e6a0";
-}
-
-.mdi-action-wallet-travel:before {
- content: "\e6a1";
-}
-
-.mdi-action-work:before {
- content: "\e6a2";
-}
-
-.mdi-alert-error:before {
- content: "\e6a3";
-}
-
-.mdi-alert-warning:before {
- content: "\e6a4";
-}
-
-.mdi-av-album:before {
- content: "\e6a5";
-}
-
-.mdi-av-closed-caption:before {
- content: "\e6a6";
-}
-
-.mdi-av-equalizer:before {
- content: "\e6a7";
-}
-
-.mdi-av-explicit:before {
- content: "\e6a8";
-}
-
-.mdi-av-fast-forward:before {
- content: "\e6a9";
-}
-
-.mdi-av-fast-rewind:before {
- content: "\e6aa";
-}
-
-.mdi-av-games:before {
- content: "\e6ab";
-}
-
-.mdi-av-hearing:before {
- content: "\e6ac";
-}
-
-.mdi-av-high-quality:before {
- content: "\e6ad";
-}
-
-.mdi-av-loop:before {
- content: "\e6ae";
-}
-
-.mdi-av-mic-none:before {
- content: "\e6af";
-}
-
-.mdi-av-mic-off:before {
- content: "\e6b0";
-}
-
-.mdi-av-mic:before {
- content: "\e6b1";
-}
-
-.mdi-av-movie:before {
- content: "\e6b2";
-}
-
-.mdi-av-my-library-add:before {
- content: "\e6b3";
-}
-
-.mdi-av-my-library-books:before {
- content: "\e6b4";
-}
-
-.mdi-av-my-library-music:before {
- content: "\e6b5";
-}
-
-.mdi-av-new-releases:before {
- content: "\e6b6";
-}
-
-.mdi-av-not-interested:before {
- content: "\e6b7";
-}
-
-.mdi-av-pause-circle-fill:before {
- content: "\e6b8";
-}
-
-.mdi-av-pause-circle-outline:before {
- content: "\e6b9";
-}
-
-.mdi-av-pause:before {
- content: "\e6ba";
-}
-
-.mdi-av-play-arrow:before {
- content: "\e6bb";
-}
-
-.mdi-av-play-circle-fill:before {
- content: "\e6bc";
-}
-
-.mdi-av-play-circle-outline:before {
- content: "\e6bd";
-}
-
-.mdi-av-play-shopping-bag:before {
- content: "\e6be";
-}
-
-.mdi-av-playlist-add:before {
- content: "\e6bf";
-}
-
-.mdi-av-queue-music:before {
- content: "\e6c0";
-}
-
-.mdi-av-queue:before {
- content: "\e6c1";
-}
-
-.mdi-av-radio:before {
- content: "\e6c2";
-}
-
-.mdi-av-recent-actors:before {
- content: "\e6c3";
-}
-
-.mdi-av-repeat-one:before {
- content: "\e6c4";
-}
-
-.mdi-av-repeat:before {
- content: "\e6c5";
-}
-
-.mdi-av-replay:before {
- content: "\e6c6";
-}
-
-.mdi-av-shuffle:before {
- content: "\e6c7";
-}
-
-.mdi-av-skip-next:before {
- content: "\e6c8";
-}
-
-.mdi-av-skip-previous:before {
- content: "\e6c9";
-}
-
-.mdi-av-snooze:before {
- content: "\e6ca";
-}
-
-.mdi-av-stop:before {
- content: "\e6cb";
-}
-
-.mdi-av-subtitles:before {
- content: "\e6cc";
-}
-
-.mdi-av-surround-sound:before {
- content: "\e6cd";
-}
-
-.mdi-av-timer:before {
- content: "\e6ce";
-}
-
-.mdi-av-video-collection:before {
- content: "\e6cf";
-}
-
-.mdi-av-videocam-off:before {
- content: "\e6d0";
-}
-
-.mdi-av-videocam:before {
- content: "\e6d1";
-}
-
-.mdi-av-volume-down:before {
- content: "\e6d2";
-}
-
-.mdi-av-volume-mute:before {
- content: "\e6d3";
-}
-
-.mdi-av-volume-off:before {
- content: "\e6d4";
-}
-
-.mdi-av-volume-up:before {
- content: "\e6d5";
-}
-
-.mdi-av-web:before {
- content: "\e6d6";
-}
-
-.mdi-communication-business:before {
- content: "\e6d7";
-}
-
-.mdi-communication-call-end:before {
- content: "\e6d8";
-}
-
-.mdi-communication-call-made:before {
- content: "\e6d9";
-}
-
-.mdi-communication-call-merge:before {
- content: "\e6da";
-}
-
-.mdi-communication-call-missed:before {
- content: "\e6db";
-}
-
-.mdi-communication-call-received:before {
- content: "\e6dc";
-}
-
-.mdi-communication-call-split:before {
- content: "\e6dd";
-}
-
-.mdi-communication-call:before {
- content: "\e6de";
-}
-
-.mdi-communication-chat:before {
- content: "\e6df";
-}
-
-.mdi-communication-clear-all:before {
- content: "\e6e0";
-}
-
-.mdi-communication-comment:before {
- content: "\e6e1";
-}
-
-.mdi-communication-contacts:before {
- content: "\e6e2";
-}
-
-.mdi-communication-dialer-sip:before {
- content: "\e6e3";
-}
-
-.mdi-communication-dialpad:before {
- content: "\e6e4";
-}
-
-.mdi-communication-dnd-on:before {
- content: "\e6e5";
-}
-
-.mdi-communication-email:before {
- content: "\e6e6";
-}
-
-.mdi-communication-forum:before {
- content: "\e6e7";
-}
-
-.mdi-communication-import-export:before {
- content: "\e6e8";
-}
-
-.mdi-communication-invert-colors-off:before {
- content: "\e6e9";
-}
-
-.mdi-communication-invert-colors-on:before {
- content: "\e6ea";
-}
-
-.mdi-communication-live-help:before {
- content: "\e6eb";
-}
-
-.mdi-communication-location-off:before {
- content: "\e6ec";
-}
-
-.mdi-communication-location-on:before {
- content: "\e6ed";
-}
-
-.mdi-communication-message:before {
- content: "\e6ee";
-}
-
-.mdi-communication-messenger:before {
- content: "\e6ef";
-}
-
-.mdi-communication-no-sim:before {
- content: "\e6f0";
-}
-
-.mdi-communication-phone:before {
- content: "\e6f1";
-}
-
-.mdi-communication-portable-wifi-off:before {
- content: "\e6f2";
-}
-
-.mdi-communication-quick-contacts-dialer:before {
- content: "\e6f3";
-}
-
-.mdi-communication-quick-contacts-mail:before {
- content: "\e6f4";
-}
-
-.mdi-communication-ring-volume:before {
- content: "\e6f5";
-}
-
-.mdi-communication-stay-current-landscape:before {
- content: "\e6f6";
-}
-
-.mdi-communication-stay-current-portrait:before {
- content: "\e6f7";
-}
-
-.mdi-communication-stay-primary-landscape:before {
- content: "\e6f8";
-}
-
-.mdi-communication-stay-primary-portrait:before {
- content: "\e6f9";
-}
-
-.mdi-communication-swap-calls:before {
- content: "\e6fa";
-}
-
-.mdi-communication-textsms:before {
- content: "\e6fb";
-}
-
-.mdi-communication-voicemail:before {
- content: "\e6fc";
-}
-
-.mdi-communication-vpn-key:before {
- content: "\e6fd";
-}
-
-.mdi-content-add-box:before {
- content: "\e6fe";
-}
-
-.mdi-content-add-circle-outline:before {
- content: "\e6ff";
-}
-
-.mdi-content-add-circle:before {
- content: "\e700";
-}
-
-.mdi-content-add:before {
- content: "\e701";
-}
-
-.mdi-content-archive:before {
- content: "\e702";
-}
-
-.mdi-content-backspace:before {
- content: "\e703";
-}
-
-.mdi-content-block:before {
- content: "\e704";
-}
-
-.mdi-content-clear:before {
- content: "\e705";
-}
-
-.mdi-content-content-copy:before {
- content: "\e706";
-}
-
-.mdi-content-content-cut:before {
- content: "\e707";
-}
-
-.mdi-content-content-paste:before {
- content: "\e708";
-}
-
-.mdi-content-create:before {
- content: "\e709";
-}
-
-.mdi-content-drafts:before {
- content: "\e70a";
-}
-
-.mdi-content-filter-list:before {
- content: "\e70b";
-}
-
-.mdi-content-flag:before {
- content: "\e70c";
-}
-
-.mdi-content-forward:before {
- content: "\e70d";
-}
-
-.mdi-content-gesture:before {
- content: "\e70e";
-}
-
-.mdi-content-inbox:before {
- content: "\e70f";
-}
-
-.mdi-content-link:before {
- content: "\e710";
-}
-
-.mdi-content-mail:before {
- content: "\e711";
-}
-
-.mdi-content-markunread:before {
- content: "\e712";
-}
-
-.mdi-content-redo:before {
- content: "\e713";
-}
-
-.mdi-content-remove-circle-outline:before {
- content: "\e714";
-}
-
-.mdi-content-remove-circle:before {
- content: "\e715";
-}
-
-.mdi-content-remove:before {
- content: "\e716";
-}
-
-.mdi-content-reply-all:before {
- content: "\e717";
-}
-
-.mdi-content-reply:before {
- content: "\e718";
-}
-
-.mdi-content-report:before {
- content: "\e719";
-}
-
-.mdi-content-save:before {
- content: "\e71a";
-}
-
-.mdi-content-select-all:before {
- content: "\e71b";
-}
-
-.mdi-content-send:before {
- content: "\e71c";
-}
-
-.mdi-content-sort:before {
- content: "\e71d";
-}
-
-.mdi-content-text-format:before {
- content: "\e71e";
-}
-
-.mdi-content-undo:before {
- content: "\e71f";
-}
-
-.mdi-editor-attach-file:before {
- content: "\e776";
-}
-
-.mdi-editor-attach-money:before {
- content: "\e777";
-}
-
-.mdi-editor-border-all:before {
- content: "\e778";
-}
-
-.mdi-editor-border-bottom:before {
- content: "\e779";
-}
-
-.mdi-editor-border-clear:before {
- content: "\e77a";
-}
-
-.mdi-editor-border-color:before {
- content: "\e77b";
-}
-
-.mdi-editor-border-horizontal:before {
- content: "\e77c";
-}
-
-.mdi-editor-border-inner:before {
- content: "\e77d";
-}
-
-.mdi-editor-border-left:before {
- content: "\e77e";
-}
-
-.mdi-editor-border-outer:before {
- content: "\e77f";
-}
-
-.mdi-editor-border-right:before {
- content: "\e780";
-}
-
-.mdi-editor-border-style:before {
- content: "\e781";
-}
-
-.mdi-editor-border-top:before {
- content: "\e782";
-}
-
-.mdi-editor-border-vertical:before {
- content: "\e783";
-}
-
-.mdi-editor-format-align-center:before {
- content: "\e784";
-}
-
-.mdi-editor-format-align-justify:before {
- content: "\e785";
-}
-
-.mdi-editor-format-align-left:before {
- content: "\e786";
-}
-
-.mdi-editor-format-align-right:before {
- content: "\e787";
-}
-
-.mdi-editor-format-bold:before {
- content: "\e788";
-}
-
-.mdi-editor-format-clear:before {
- content: "\e789";
-}
-
-.mdi-editor-format-color-fill:before {
- content: "\e78a";
-}
-
-.mdi-editor-format-color-reset:before {
- content: "\e78b";
-}
-
-.mdi-editor-format-color-text:before {
- content: "\e78c";
-}
-
-.mdi-editor-format-indent-decrease:before {
- content: "\e78d";
-}
-
-.mdi-editor-format-indent-increase:before {
- content: "\e78e";
-}
-
-.mdi-editor-format-italic:before {
- content: "\e78f";
-}
-
-.mdi-editor-format-line-spacing:before {
- content: "\e790";
-}
-
-.mdi-editor-format-list-bulleted:before {
- content: "\e791";
-}
-
-.mdi-editor-format-list-numbered:before {
- content: "\e792";
-}
-
-.mdi-editor-format-paint:before {
- content: "\e793";
-}
-
-.mdi-editor-format-quote:before {
- content: "\e794";
-}
-
-.mdi-editor-format-size:before {
- content: "\e795";
-}
-
-.mdi-editor-format-strikethrough:before {
- content: "\e796";
-}
-
-.mdi-editor-format-textdirection-l-to-r:before {
- content: "\e797";
-}
-
-.mdi-editor-format-textdirection-r-to-l:before {
- content: "\e798";
-}
-
-.mdi-editor-format-underline:before {
- content: "\e799";
-}
-
-.mdi-editor-functions:before {
- content: "\e79a";
-}
-
-.mdi-editor-insert-chart:before {
- content: "\e79b";
-}
-
-.mdi-editor-insert-comment:before {
- content: "\e79c";
-}
-
-.mdi-editor-insert-drive-file:before {
- content: "\e79d";
-}
-
-.mdi-editor-insert-emoticon:before {
- content: "\e79e";
-}
-
-.mdi-editor-insert-invitation:before {
- content: "\e79f";
-}
-
-.mdi-editor-insert-link:before {
- content: "\e7a0";
-}
-
-.mdi-editor-insert-photo:before {
- content: "\e7a1";
-}
-
-.mdi-editor-merge-type:before {
- content: "\e7a2";
-}
-
-.mdi-editor-mode-comment:before {
- content: "\e7a3";
-}
-
-.mdi-editor-mode-edit:before {
- content: "\e7a4";
-}
-
-.mdi-editor-publish:before {
- content: "\e7a5";
-}
-
-.mdi-editor-vertical-align-bottom:before {
- content: "\e7a6";
-}
-
-.mdi-editor-vertical-align-center:before {
- content: "\e7a7";
-}
-
-.mdi-editor-vertical-align-top:before {
- content: "\e7a8";
-}
-
-.mdi-editor-wrap-text:before {
- content: "\e7a9";
-}
-
-.mdi-file-attachment:before {
- content: "\e7aa";
-}
-
-.mdi-file-cloud-circle:before {
- content: "\e7ab";
-}
-
-.mdi-file-cloud-done:before {
- content: "\e7ac";
-}
-
-.mdi-file-cloud-download:before {
- content: "\e7ad";
-}
-
-.mdi-file-cloud-off:before {
- content: "\e7ae";
-}
-
-.mdi-file-cloud-queue:before {
- content: "\e7af";
-}
-
-.mdi-file-cloud-upload:before {
- content: "\e7b0";
-}
-
-.mdi-file-cloud:before {
- content: "\e7b1";
-}
-
-.mdi-file-file-download:before {
- content: "\e7b2";
-}
-
-.mdi-file-file-upload:before {
- content: "\e7b3";
-}
-
-.mdi-file-folder-open:before {
- content: "\e7b4";
-}
-
-.mdi-file-folder-shared:before {
- content: "\e7b5";
-}
-
-.mdi-file-folder:before {
- content: "\e7b6";
-}
-
-.mdi-device-access-alarm:before {
- content: "\e720";
-}
-
-.mdi-device-access-alarms:before {
- content: "\e721";
-}
-
-.mdi-device-access-time:before {
- content: "\e722";
-}
-
-.mdi-device-add-alarm:before {
- content: "\e723";
-}
-
-.mdi-device-airplanemode-off:before {
- content: "\e724";
-}
-
-.mdi-device-airplanemode-on:before {
- content: "\e725";
-}
-
-.mdi-device-battery-20:before {
- content: "\e726";
-}
-
-.mdi-device-battery-30:before {
- content: "\e727";
-}
-
-.mdi-device-battery-50:before {
- content: "\e728";
-}
-
-.mdi-device-battery-60:before {
- content: "\e729";
-}
-
-.mdi-device-battery-80:before {
- content: "\e72a";
-}
-
-.mdi-device-battery-90:before {
- content: "\e72b";
-}
-
-.mdi-device-battery-alert:before {
- content: "\e72c";
-}
-
-.mdi-device-battery-charging-20:before {
- content: "\e72d";
-}
-
-.mdi-device-battery-charging-30:before {
- content: "\e72e";
-}
-
-.mdi-device-battery-charging-50:before {
- content: "\e72f";
-}
-
-.mdi-device-battery-charging-60:before {
- content: "\e730";
-}
-
-.mdi-device-battery-charging-80:before {
- content: "\e731";
-}
-
-.mdi-device-battery-charging-90:before {
- content: "\e732";
-}
-
-.mdi-device-battery-charging-full:before {
- content: "\e733";
-}
-
-.mdi-device-battery-full:before {
- content: "\e734";
-}
-
-.mdi-device-battery-std:before {
- content: "\e735";
-}
-
-.mdi-device-battery-unknown:before {
- content: "\e736";
-}
-
-.mdi-device-bluetooth-connected:before {
- content: "\e737";
-}
-
-.mdi-device-bluetooth-disabled:before {
- content: "\e738";
-}
-
-.mdi-device-bluetooth-searching:before {
- content: "\e739";
-}
-
-.mdi-device-bluetooth:before {
- content: "\e73a";
-}
-
-.mdi-device-brightness-auto:before {
- content: "\e73b";
-}
-
-.mdi-device-brightness-high:before {
- content: "\e73c";
-}
-
-.mdi-device-brightness-low:before {
- content: "\e73d";
-}
-
-.mdi-device-brightness-medium:before {
- content: "\e73e";
-}
-
-.mdi-device-data-usage:before {
- content: "\e73f";
-}
-
-.mdi-device-developer-mode:before {
- content: "\e740";
-}
-
-.mdi-device-devices:before {
- content: "\e741";
-}
-
-.mdi-device-dvr:before {
- content: "\e742";
-}
-
-.mdi-device-gps-fixed:before {
- content: "\e743";
-}
-
-.mdi-device-gps-not-fixed:before {
- content: "\e744";
-}
-
-.mdi-device-gps-off:before {
- content: "\e745";
-}
-
-.mdi-device-location-disabled:before {
- content: "\e746";
-}
-
-.mdi-device-location-searching:before {
- content: "\e747";
-}
-
-.mdi-device-multitrack-audio:before {
- content: "\e748";
-}
-
-.mdi-device-network-cell:before {
- content: "\e749";
-}
-
-.mdi-device-network-wifi:before {
- content: "\e74a";
-}
-
-.mdi-device-nfc:before {
- content: "\e74b";
-}
-
-.mdi-device-now-wallpaper:before {
- content: "\e74c";
-}
-
-.mdi-device-now-widgets:before {
- content: "\e74d";
-}
-
-.mdi-device-screen-lock-landscape:before {
- content: "\e74e";
-}
-
-.mdi-device-screen-lock-portrait:before {
- content: "\e74f";
-}
-
-.mdi-device-screen-lock-rotation:before {
- content: "\e750";
-}
-
-.mdi-device-screen-rotation:before {
- content: "\e751";
-}
-
-.mdi-device-sd-storage:before {
- content: "\e752";
-}
-
-.mdi-device-settings-system-daydream:before {
- content: "\e753";
-}
-
-.mdi-device-signal-cellular-0-bar:before {
- content: "\e754";
-}
-
-.mdi-device-signal-cellular-1-bar:before {
- content: "\e755";
-}
-
-.mdi-device-signal-cellular-2-bar:before {
- content: "\e756";
-}
-
-.mdi-device-signal-cellular-3-bar:before {
- content: "\e757";
-}
-
-.mdi-device-signal-cellular-4-bar:before {
- content: "\e758";
-}
-
-.mdi-signal-wifi-statusbar-connected-no-internet-after:before {
- content: "\e8f6";
-}
-
-.mdi-device-signal-cellular-connected-no-internet-0-bar:before {
- content: "\e759";
-}
-
-.mdi-device-signal-cellular-connected-no-internet-1-bar:before {
- content: "\e75a";
-}
-
-.mdi-device-signal-cellular-connected-no-internet-2-bar:before {
- content: "\e75b";
-}
-
-.mdi-device-signal-cellular-connected-no-internet-3-bar:before {
- content: "\e75c";
-}
-
-.mdi-device-signal-cellular-connected-no-internet-4-bar:before {
- content: "\e75d";
-}
-
-.mdi-device-signal-cellular-no-sim:before {
- content: "\e75e";
-}
-
-.mdi-device-signal-cellular-null:before {
- content: "\e75f";
-}
-
-.mdi-device-signal-cellular-off:before {
- content: "\e760";
-}
-
-.mdi-device-signal-wifi-0-bar:before {
- content: "\e761";
-}
-
-.mdi-device-signal-wifi-1-bar:before {
- content: "\e762";
-}
-
-.mdi-device-signal-wifi-2-bar:before {
- content: "\e763";
-}
-
-.mdi-device-signal-wifi-3-bar:before {
- content: "\e764";
-}
-
-.mdi-device-signal-wifi-4-bar:before {
- content: "\e765";
-}
-
-.mdi-device-signal-wifi-off:before {
- content: "\e766";
-}
-
-.mdi-device-signal-wifi-statusbar-1-bar:before {
- content: "\e767";
-}
-
-.mdi-device-signal-wifi-statusbar-2-bar:before {
- content: "\e768";
-}
-
-.mdi-device-signal-wifi-statusbar-3-bar:before {
- content: "\e769";
-}
-
-.mdi-device-signal-wifi-statusbar-4-bar:before {
- content: "\e76a";
-}
-
-.mdi-device-signal-wifi-statusbar-connected-no-internet-:before {
- content: "\e76b";
-}
-
-.mdi-device-signal-wifi-statusbar-connected-no-internet:before {
- content: "\e76f";
-}
-
-.mdi-device-signal-wifi-statusbar-connected-no-internet-2:before {
- content: "\e76c";
-}
-
-.mdi-device-signal-wifi-statusbar-connected-no-internet-3:before {
- content: "\e76d";
-}
-
-.mdi-device-signal-wifi-statusbar-connected-no-internet-4:before {
- content: "\e76e";
-}
-
-.mdi-signal-wifi-statusbar-not-connected-after:before {
- content: "\e8f7";
-}
-
-.mdi-device-signal-wifi-statusbar-not-connected:before {
- content: "\e770";
-}
-
-.mdi-device-signal-wifi-statusbar-null:before {
- content: "\e771";
-}
-
-.mdi-device-storage:before {
- content: "\e772";
-}
-
-.mdi-device-usb:before {
- content: "\e773";
-}
-
-.mdi-device-wifi-lock:before {
- content: "\e774";
-}
-
-.mdi-device-wifi-tethering:before {
- content: "\e775";
-}
-
-.mdi-hardware-cast-connected:before {
- content: "\e7b7";
-}
-
-.mdi-hardware-cast:before {
- content: "\e7b8";
-}
-
-.mdi-hardware-computer:before {
- content: "\e7b9";
-}
-
-.mdi-hardware-desktop-mac:before {
- content: "\e7ba";
-}
-
-.mdi-hardware-desktop-windows:before {
- content: "\e7bb";
-}
-
-.mdi-hardware-dock:before {
- content: "\e7bc";
-}
-
-.mdi-hardware-gamepad:before {
- content: "\e7bd";
-}
-
-.mdi-hardware-headset-mic:before {
- content: "\e7be";
-}
-
-.mdi-hardware-headset:before {
- content: "\e7bf";
-}
-
-.mdi-hardware-keyboard-alt:before {
- content: "\e7c0";
-}
-
-.mdi-hardware-keyboard-arrow-down:before {
- content: "\e7c1";
-}
-
-.mdi-hardware-keyboard-arrow-left:before {
- content: "\e7c2";
-}
-
-.mdi-hardware-keyboard-arrow-right:before {
- content: "\e7c3";
-}
-
-.mdi-hardware-keyboard-arrow-up:before {
- content: "\e7c4";
-}
-
-.mdi-hardware-keyboard-backspace:before {
- content: "\e7c5";
-}
-
-.mdi-hardware-keyboard-capslock:before {
- content: "\e7c6";
-}
-
-.mdi-hardware-keyboard-control:before {
- content: "\e7c7";
-}
-
-.mdi-hardware-keyboard-hide:before {
- content: "\e7c8";
-}
-
-.mdi-hardware-keyboard-return:before {
- content: "\e7c9";
-}
-
-.mdi-hardware-keyboard-tab:before {
- content: "\e7ca";
-}
-
-.mdi-hardware-keyboard-voice:before {
- content: "\e7cb";
-}
-
-.mdi-hardware-keyboard:before {
- content: "\e7cc";
-}
-
-.mdi-hardware-laptop-chromebook:before {
- content: "\e7cd";
-}
-
-.mdi-hardware-laptop-mac:before {
- content: "\e7ce";
-}
-
-.mdi-hardware-laptop-windows:before {
- content: "\e7cf";
-}
-
-.mdi-hardware-laptop:before {
- content: "\e7d0";
-}
-
-.mdi-hardware-memory:before {
- content: "\e7d1";
-}
-
-.mdi-hardware-mouse:before {
- content: "\e7d2";
-}
-
-.mdi-hardware-phone-android:before {
- content: "\e7d3";
-}
-
-.mdi-hardware-phone-iphone:before {
- content: "\e7d4";
-}
-
-.mdi-hardware-phonelink-off:before {
- content: "\e7d5";
-}
-
-.mdi-hardware-phonelink:before {
- content: "\e7d6";
-}
-
-.mdi-hardware-security:before {
- content: "\e7d7";
-}
-
-.mdi-hardware-sim-card:before {
- content: "\e7d8";
-}
-
-.mdi-hardware-smartphone:before {
- content: "\e7d9";
-}
-
-.mdi-hardware-speaker:before {
- content: "\e7da";
-}
-
-.mdi-hardware-tablet-android:before {
- content: "\e7db";
-}
-
-.mdi-hardware-tablet-mac:before {
- content: "\e7dc";
-}
-
-.mdi-hardware-tablet:before {
- content: "\e7dd";
-}
-
-.mdi-hardware-tv:before {
- content: "\e7de";
-}
-
-.mdi-hardware-watch:before {
- content: "\e7df";
-}
-
-.mdi-image-add-to-photos:before {
- content: "\e7e0";
-}
-
-.mdi-image-adjust:before {
- content: "\e7e1";
-}
-
-.mdi-image-assistant-photo:before {
- content: "\e7e2";
-}
-
-.mdi-image-audiotrack:before {
- content: "\e7e3";
-}
-
-.mdi-image-blur-circular:before {
- content: "\e7e4";
-}
-
-.mdi-image-blur-linear:before {
- content: "\e7e5";
-}
-
-.mdi-image-blur-off:before {
- content: "\e7e6";
-}
-
-.mdi-image-blur-on:before {
- content: "\e7e7";
-}
-
-.mdi-image-brightness-1:before {
- content: "\e7e8";
-}
-
-.mdi-image-brightness-2:before {
- content: "\e7e9";
-}
-
-.mdi-image-brightness-3:before {
- content: "\e7ea";
-}
-
-.mdi-image-brightness-4:before {
- content: "\e7eb";
-}
-
-.mdi-image-brightness-5:before {
- content: "\e7ec";
-}
-
-.mdi-image-brightness-6:before {
- content: "\e7ed";
-}
-
-.mdi-image-brightness-7:before {
- content: "\e7ee";
-}
-
-.mdi-image-brush:before {
- content: "\e7ef";
-}
-
-.mdi-image-camera-alt:before {
- content: "\e7f0";
-}
-
-.mdi-image-camera-front:before {
- content: "\e7f1";
-}
-
-.mdi-image-camera-rear:before {
- content: "\e7f2";
-}
-
-.mdi-image-camera-roll:before {
- content: "\e7f3";
-}
-
-.mdi-image-camera:before {
- content: "\e7f4";
-}
-
-.mdi-image-center-focus-strong:before {
- content: "\e7f5";
-}
-
-.mdi-image-center-focus-weak:before {
- content: "\e7f6";
-}
-
-.mdi-image-collections:before {
- content: "\e7f7";
-}
-
-.mdi-image-color-lens:before {
- content: "\e7f8";
-}
-
-.mdi-image-colorize:before {
- content: "\e7f9";
-}
-
-.mdi-image-compare:before {
- content: "\e7fa";
-}
-
-.mdi-image-control-point-duplicate:before {
- content: "\e7fb";
-}
-
-.mdi-image-control-point:before {
- content: "\e7fc";
-}
-
-.mdi-image-crop-3-2:before {
- content: "\e7fd";
-}
-
-.mdi-image-crop-5-4:before {
- content: "\e7fe";
-}
-
-.mdi-image-crop-7-5:before {
- content: "\e7ff";
-}
-
-.mdi-image-crop-16-9:before {
- content: "\e800";
-}
-
-.mdi-image-crop-din:before {
- content: "\e801";
-}
-
-.mdi-image-crop-free:before {
- content: "\e802";
-}
-
-.mdi-image-crop-landscape:before {
- content: "\e803";
-}
-
-.mdi-image-crop-original:before {
- content: "\e804";
-}
-
-.mdi-image-crop-portrait:before {
- content: "\e805";
-}
-
-.mdi-image-crop-square:before {
- content: "\e806";
-}
-
-.mdi-image-crop:before {
- content: "\e807";
-}
-
-.mdi-image-dehaze:before {
- content: "\e808";
-}
-
-.mdi-image-details:before {
- content: "\e809";
-}
-
-.mdi-image-edit:before {
- content: "\e80a";
-}
-
-.mdi-image-exposure-minus-1:before {
- content: "\e80b";
-}
-
-.mdi-image-exposure-minus-2:before {
- content: "\e80c";
-}
-
-.mdi-image-exposure-plus-1:before {
- content: "\e80d";
-}
-
-.mdi-image-exposure-plus-2:before {
- content: "\e80e";
-}
-
-.mdi-image-exposure-zero:before {
- content: "\e80f";
-}
-
-.mdi-image-exposure:before {
- content: "\e810";
-}
-
-.mdi-image-filter-1:before {
- content: "\e811";
-}
-
-.mdi-image-filter-2:before {
- content: "\e812";
-}
-
-.mdi-image-filter-3:before {
- content: "\e813";
-}
-
-.mdi-image-filter-4:before {
- content: "\e814";
-}
-
-.mdi-image-filter-5:before {
- content: "\e815";
-}
-
-.mdi-image-filter-6:before {
- content: "\e816";
-}
-
-.mdi-image-filter-7:before {
- content: "\e817";
-}
-
-.mdi-image-filter-8:before {
- content: "\e818";
-}
-
-.mdi-image-filter-9-plus:before {
- content: "\e819";
-}
-
-.mdi-image-filter-9:before {
- content: "\e81a";
-}
-
-.mdi-image-filter-b-and-w:before {
- content: "\e81b";
-}
-
-.mdi-image-filter-center-focus:before {
- content: "\e81c";
-}
-
-.mdi-image-filter-drama:before {
- content: "\e81d";
-}
-
-.mdi-image-filter-frames:before {
- content: "\e81e";
-}
-
-.mdi-image-filter-hdr:before {
- content: "\e81f";
-}
-
-.mdi-image-filter-none:before {
- content: "\e820";
-}
-
-.mdi-image-filter-tilt-shift:before {
- content: "\e821";
-}
-
-.mdi-image-filter-vintage:before {
- content: "\e822";
-}
-
-.mdi-image-filter:before {
- content: "\e823";
-}
-
-.mdi-image-flare:before {
- content: "\e824";
-}
-
-.mdi-image-flash-auto:before {
- content: "\e825";
-}
-
-.mdi-image-flash-off:before {
- content: "\e826";
-}
-
-.mdi-image-flash-on:before {
- content: "\e827";
-}
-
-.mdi-image-flip:before {
- content: "\e828";
-}
-
-.mdi-image-gradient:before {
- content: "\e829";
-}
-
-.mdi-image-grain:before {
- content: "\e82a";
-}
-
-.mdi-image-grid-off:before {
- content: "\e82b";
-}
-
-.mdi-image-grid-on:before {
- content: "\e82c";
-}
-
-.mdi-image-hdr-off:before {
- content: "\e82d";
-}
-
-.mdi-image-hdr-on:before {
- content: "\e82e";
-}
-
-.mdi-image-hdr-strong:before {
- content: "\e82f";
-}
-
-.mdi-image-hdr-weak:before {
- content: "\e830";
-}
-
-.mdi-image-healing:before {
- content: "\e831";
-}
-
-.mdi-image-image-aspect-ratio:before {
- content: "\e832";
-}
-
-.mdi-image-image:before {
- content: "\e833";
-}
-
-.mdi-image-iso:before {
- content: "\e834";
-}
-
-.mdi-image-landscape:before {
- content: "\e835";
-}
-
-.mdi-image-leak-add:before {
- content: "\e836";
-}
-
-.mdi-image-leak-remove:before {
- content: "\e837";
-}
-
-.mdi-image-lens:before {
- content: "\e838";
-}
-
-.mdi-image-looks-3:before {
- content: "\e839";
-}
-
-.mdi-image-looks-4:before {
- content: "\e83a";
-}
-
-.mdi-image-looks-5:before {
- content: "\e83b";
-}
-
-.mdi-image-looks-6:before {
- content: "\e83c";
-}
-
-.mdi-image-looks-one:before {
- content: "\e83d";
-}
-
-.mdi-image-looks-two:before {
- content: "\e83e";
-}
-
-.mdi-image-looks:before {
- content: "\e83f";
-}
-
-.mdi-image-loupe:before {
- content: "\e840";
-}
-
-.mdi-image-movie-creation:before {
- content: "\e841";
-}
-
-.mdi-image-nature-people:before {
- content: "\e842";
-}
-
-.mdi-image-nature:before {
- content: "\e843";
-}
-
-.mdi-image-navigate-before:before {
- content: "\e844";
-}
-
-.mdi-image-navigate-next:before {
- content: "\e845";
-}
-
-.mdi-image-palette:before {
- content: "\e846";
-}
-
-.mdi-image-panorama-fisheye:before {
- content: "\e847";
-}
-
-.mdi-image-panorama-horizontal:before {
- content: "\e848";
-}
-
-.mdi-image-panorama-vertical:before {
- content: "\e849";
-}
-
-.mdi-image-panorama-wide-angle:before {
- content: "\e84a";
-}
-
-.mdi-image-panorama:before {
- content: "\e84b";
-}
-
-.mdi-image-photo-album:before {
- content: "\e84c";
-}
-
-.mdi-image-photo-camera:before {
- content: "\e84d";
-}
-
-.mdi-image-photo-library:before {
- content: "\e84e";
-}
-
-.mdi-image-photo:before {
- content: "\e84f";
-}
-
-.mdi-image-portrait:before {
- content: "\e850";
-}
-
-.mdi-image-remove-red-eye:before {
- content: "\e851";
-}
-
-.mdi-image-rotate-left:before {
- content: "\e852";
-}
-
-.mdi-image-rotate-right:before {
- content: "\e853";
-}
-
-.mdi-image-slideshow:before {
- content: "\e854";
-}
-
-.mdi-image-straighten:before {
- content: "\e855";
-}
-
-.mdi-image-style:before {
- content: "\e856";
-}
-
-.mdi-image-switch-camera:before {
- content: "\e857";
-}
-
-.mdi-image-switch-video:before {
- content: "\e858";
-}
-
-.mdi-image-tag-faces:before {
- content: "\e859";
-}
-
-.mdi-image-texture:before {
- content: "\e85a";
-}
-
-.mdi-image-timelapse:before {
- content: "\e85b";
-}
-
-.mdi-image-timer-3:before {
- content: "\e85c";
-}
-
-.mdi-image-timer-10:before {
- content: "\e85d";
-}
-
-.mdi-image-timer-auto:before {
- content: "\e85e";
-}
-
-.mdi-image-timer-off:before {
- content: "\e85f";
-}
-
-.mdi-image-timer:before {
- content: "\e860";
-}
-
-.mdi-image-tonality:before {
- content: "\e861";
-}
-
-.mdi-image-transform:before {
- content: "\e862";
-}
-
-.mdi-image-tune:before {
- content: "\e863";
-}
-
-.mdi-image-wb-auto:before {
- content: "\e864";
-}
-
-.mdi-image-wb-cloudy:before {
- content: "\e865";
-}
-
-.mdi-image-wb-incandescent:before {
- content: "\e866";
-}
-
-.mdi-image-wb-irradescent:before {
- content: "\e867";
-}
-
-.mdi-image-wb-sunny:before {
- content: "\e868";
-}
-
-.mdi-maps-beenhere:before {
- content: "\e869";
-}
-
-.mdi-maps-directions-bike:before {
- content: "\e86a";
-}
-
-.mdi-maps-directions-bus:before {
- content: "\e86b";
-}
-
-.mdi-maps-directions-car:before {
- content: "\e86c";
-}
-
-.mdi-maps-directions-ferry:before {
- content: "\e86d";
-}
-
-.mdi-maps-directions-subway:before {
- content: "\e86e";
-}
-
-.mdi-maps-directions-train:before {
- content: "\e86f";
-}
-
-.mdi-maps-directions-transit:before {
- content: "\e870";
-}
-
-.mdi-maps-directions-walk:before {
- content: "\e871";
-}
-
-.mdi-maps-directions:before {
- content: "\e872";
-}
-
-.mdi-maps-flight:before {
- content: "\e873";
-}
-
-.mdi-maps-hotel:before {
- content: "\e874";
-}
-
-.mdi-maps-layers-clear:before {
- content: "\e875";
-}
-
-.mdi-maps-layers:before {
- content: "\e876";
-}
-
-.mdi-maps-local-airport:before {
- content: "\e877";
-}
-
-.mdi-maps-local-atm:before {
- content: "\e878";
-}
-
-.mdi-maps-local-attraction:before {
- content: "\e879";
-}
-
-.mdi-maps-local-bar:before {
- content: "\e87a";
-}
-
-.mdi-maps-local-cafe:before {
- content: "\e87b";
-}
-
-.mdi-maps-local-car-wash:before {
- content: "\e87c";
-}
-
-.mdi-maps-local-convenience-store:before {
- content: "\e87d";
-}
-
-.mdi-maps-local-drink:before {
- content: "\e87e";
-}
-
-.mdi-maps-local-florist:before {
- content: "\e87f";
-}
-
-.mdi-maps-local-gas-station:before {
- content: "\e880";
-}
-
-.mdi-maps-local-grocery-store:before {
- content: "\e881";
-}
-
-.mdi-maps-local-hospital:before {
- content: "\e882";
-}
-
-.mdi-maps-local-hotel:before {
- content: "\e883";
-}
-
-.mdi-maps-local-laundry-service:before {
- content: "\e884";
-}
-
-.mdi-maps-local-library:before {
- content: "\e885";
-}
-
-.mdi-maps-local-mall:before {
- content: "\e886";
-}
-
-.mdi-maps-local-movies:before {
- content: "\e887";
-}
-
-.mdi-maps-local-offer:before {
- content: "\e888";
-}
-
-.mdi-maps-local-parking:before {
- content: "\e889";
-}
-
-.mdi-maps-local-pharmacy:before {
- content: "\e88a";
-}
-
-.mdi-maps-local-phone:before {
- content: "\e88b";
-}
-
-.mdi-maps-local-pizza:before {
- content: "\e88c";
-}
-
-.mdi-maps-local-play:before {
- content: "\e88d";
-}
-
-.mdi-maps-local-post-office:before {
- content: "\e88e";
-}
-
-.mdi-maps-local-print-shop:before {
- content: "\e88f";
-}
-
-.mdi-maps-local-restaurant:before {
- content: "\e890";
-}
-
-.mdi-maps-local-see:before {
- content: "\e891";
-}
-
-.mdi-maps-local-shipping:before {
- content: "\e892";
-}
-
-.mdi-maps-local-taxi:before {
- content: "\e893";
-}
-
-.mdi-maps-location-history:before {
- content: "\e894";
-}
-
-.mdi-maps-map:before {
- content: "\e895";
-}
-
-.mdi-maps-my-location:before {
- content: "\e896";
-}
-
-.mdi-maps-navigation:before {
- content: "\e897";
-}
-
-.mdi-maps-pin-drop:before {
- content: "\e898";
-}
-
-.mdi-maps-place:before {
- content: "\e899";
-}
-
-.mdi-maps-rate-review:before {
- content: "\e89a";
-}
-
-.mdi-maps-restaurant-menu:before {
- content: "\e89b";
-}
-
-.mdi-maps-satellite:before {
- content: "\e89c";
-}
-
-.mdi-maps-store-mall-directory:before {
- content: "\e89d";
-}
-
-.mdi-maps-terrain:before {
- content: "\e89e";
-}
-
-.mdi-maps-traffic:before {
- content: "\e89f";
-}
-
-.mdi-navigation-apps:before {
- content: "\e8a0";
-}
-
-.mdi-navigation-arrow-back:before {
- content: "\e8a1";
-}
-
-.mdi-navigation-arrow-drop-down-circle:before {
- content: "\e8a2";
-}
-
-.mdi-navigation-arrow-drop-down:before {
- content: "\e8a3";
-}
-
-.mdi-navigation-arrow-drop-up:before {
- content: "\e8a4";
-}
-
-.mdi-navigation-arrow-forward:before {
- content: "\e8a5";
-}
-
-.mdi-navigation-cancel:before {
- content: "\e8a6";
-}
-
-.mdi-navigation-check:before {
- content: "\e8a7";
-}
-
-.mdi-navigation-chevron-left:before {
- content: "\e8a8";
-}
-
-.mdi-navigation-chevron-right:before {
- content: "\e8a9";
-}
-
-.mdi-navigation-close:before {
- content: "\e8aa";
-}
-
-.mdi-navigation-expand-less:before {
- content: "\e8ab";
-}
-
-.mdi-navigation-expand-more:before {
- content: "\e8ac";
-}
-
-.mdi-navigation-fullscreen-exit:before {
- content: "\e8ad";
-}
-
-.mdi-navigation-fullscreen:before {
- content: "\e8ae";
-}
-
-.mdi-navigation-menu:before {
- content: "\e8af";
-}
-
-.mdi-navigation-more-horiz:before {
- content: "\e8b0";
-}
-
-.mdi-navigation-more-vert:before {
- content: "\e8b1";
-}
-
-.mdi-navigation-refresh:before {
- content: "\e8b2";
-}
-
-.mdi-navigation-unfold-less:before {
- content: "\e8b3";
-}
-
-.mdi-navigation-unfold-more:before {
- content: "\e8b4";
-}
-
-.mdi-notification-adb:before {
- content: "\e8b5";
-}
-
-.mdi-notification-bluetooth-audio:before {
- content: "\e8b6";
-}
-
-.mdi-notification-disc-full:before {
- content: "\e8b7";
-}
-
-.mdi-notification-dnd-forwardslash:before {
- content: "\e8b8";
-}
-
-.mdi-notification-do-not-disturb:before {
- content: "\e8b9";
-}
-
-.mdi-notification-drive-eta:before {
- content: "\e8ba";
-}
-
-.mdi-notification-event-available:before {
- content: "\e8bb";
-}
-
-.mdi-notification-event-busy:before {
- content: "\e8bc";
-}
-
-.mdi-notification-event-note:before {
- content: "\e8bd";
-}
-
-.mdi-notification-folder-special:before {
- content: "\e8be";
-}
-
-.mdi-notification-mms:before {
- content: "\e8bf";
-}
-
-.mdi-notification-more:before {
- content: "\e8c0";
-}
-
-.mdi-notification-network-locked:before {
- content: "\e8c1";
-}
-
-.mdi-notification-phone-bluetooth-speaker:before {
- content: "\e8c2";
-}
-
-.mdi-notification-phone-forwarded:before {
- content: "\e8c3";
-}
-
-.mdi-notification-phone-in-talk:before {
- content: "\e8c4";
-}
-
-.mdi-notification-phone-locked:before {
- content: "\e8c5";
-}
-
-.mdi-notification-phone-missed:before {
- content: "\e8c6";
-}
-
-.mdi-notification-phone-paused:before {
- content: "\e8c7";
-}
-
-.mdi-notification-play-download:before {
- content: "\e8c8";
-}
-
-.mdi-notification-play-install:before {
- content: "\e8c9";
-}
-
-.mdi-notification-sd-card:before {
- content: "\e8ca";
-}
-
-.mdi-notification-sim-card-alert:before {
- content: "\e8cb";
-}
-
-.mdi-notification-sms-failed:before {
- content: "\e8cc";
-}
-
-.mdi-notification-sms:before {
- content: "\e8cd";
-}
-
-.mdi-notification-sync-disabled:before {
- content: "\e8ce";
-}
-
-.mdi-notification-sync-problem:before {
- content: "\e8cf";
-}
-
-.mdi-notification-sync:before {
- content: "\e8d0";
-}
-
-.mdi-notification-system-update:before {
- content: "\e8d1";
-}
-
-.mdi-notification-tap-and-play:before {
- content: "\e8d2";
-}
-
-.mdi-notification-time-to-leave:before {
- content: "\e8d3";
-}
-
-.mdi-notification-vibration:before {
- content: "\e8d4";
-}
-
-.mdi-notification-voice-chat:before {
- content: "\e8d5";
-}
-
-.mdi-notification-vpn-lock:before {
- content: "\e8d6";
-}
-
-.mdi-social-cake:before {
- content: "\e8d7";
-}
-
-.mdi-social-domain:before {
- content: "\e8d8";
-}
-
-.mdi-social-group-add:before {
- content: "\e8d9";
-}
-
-.mdi-social-group:before {
- content: "\e8da";
-}
-
-.mdi-social-location-city:before {
- content: "\e8db";
-}
-
-.mdi-social-mood:before {
- content: "\e8dc";
-}
-
-.mdi-social-notifications-none:before {
- content: "\e8dd";
-}
-
-.mdi-social-notifications-off:before {
- content: "\e8de";
-}
-
-.mdi-social-notifications-on:before {
- content: "\e8df";
-}
-
-.mdi-social-notifications-paused:before {
- content: "\e8e0";
-}
-
-.mdi-social-notifications:before {
- content: "\e8e1";
-}
-
-.mdi-social-pages:before {
- content: "\e8e2";
-}
-
-.mdi-social-party-mode:before {
- content: "\e8e3";
-}
-
-.mdi-social-people-outline:before {
- content: "\e8e4";
-}
-
-.mdi-social-people:before {
- content: "\e8e5";
-}
-
-.mdi-social-person-add:before {
- content: "\e8e6";
-}
-
-.mdi-social-person-outline:before {
- content: "\e8e7";
-}
-
-.mdi-social-person:before {
- content: "\e8e8";
-}
-
-.mdi-social-plus-one:before {
- content: "\e8e9";
-}
-
-.mdi-social-poll:before {
- content: "\e8ea";
-}
-
-.mdi-social-public:before {
- content: "\e8eb";
-}
-
-.mdi-social-school:before {
- content: "\e8ec";
-}
-
-.mdi-social-share:before {
- content: "\e8ed";
-}
-
-.mdi-social-whatshot:before {
- content: "\e8ee";
-}
-
-.mdi-toggle-check-box-outline-blank:before {
- content: "\e8ef";
-}
-
-.mdi-toggle-check-box:before {
- content: "\e8f0";
-}
-
-.mdi-toggle-radio-button-off:before {
- content: "\e8f1";
-}
-
-.mdi-toggle-radio-button-on:before {
- content: "\e8f2";
-}
-
-.mdi-toggle-star-half:before {
- content: "\e8f3";
-}
-
-.mdi-toggle-star-outline:before {
- content: "\e8f4";
-}
-
-.mdi-toggle-star:before {
- content: "\e8f5";
-} \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_materialbox.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_materialbox.scss
deleted file mode 100644
index 9c20176..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_materialbox.scss
+++ /dev/null
@@ -1,41 +0,0 @@
-.materialboxed {
- cursor: zoom-in;
- position: relative;
- @include transition(opacity .4s);
-
- &:hover {
- &:not(.active) {
- opacity: .8;
- }
- will-change: left, top, width, height;
- }
-}
-
-.materialboxed.active {
- cursor: zoom-out;
-}
-
-#materialbox-overlay {
- position:fixed;
- top:0;
- left:0;
- right: 0;
- bottom: 0;
- background-color: #292929;
- z-index: 999;
-
- will-change: opacity;
-}
-.materialbox-caption {
- position: fixed;
- display: none;
- color: #fff;
- line-height: 50px;
- bottom: 0;
- width: 100%;
- text-align: center;
- padding: 0% 15%;
- height: 50px;
- z-index: 1000;
- -webkit-font-smoothing: antialiased;
-} \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_mixins.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_mixins.scss
deleted file mode 100644
index 4c3d373..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_mixins.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-@mixin box-shadow-2($args1, $args2) {
- -webkit-box-shadow: $args1, $args2;
- -moz-box-shadow: $args1, $args2;
- box-shadow: $args1, $args2;
-} \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_modal.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_modal.scss
deleted file mode 100644
index 0a6dcfb..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_modal.scss
+++ /dev/null
@@ -1,90 +0,0 @@
-.modal {
- @extend .z-depth-4;
-
- display: none;
- position: fixed;
- left: 0;
- right: 0;
- background-color: #fafafa;
- padding: 0;
- max-height: 70%;
- width: 55%;
- margin: auto;
- overflow-y: auto;
-
- border-radius: 2px;
- will-change: top, opacity;
-
- @media #{$medium-and-down} {
- width: 80%;
- }
-
- h1,h2,h3,h4 {
- margin-top: 0;
- }
-
- .modal-content {
- padding: 24px;
- }
- .modal-close {
- cursor: pointer;
- }
-
- .modal-footer {
- border-radius: 0 0 2px 2px;
- background-color: #fafafa;
- padding: 4px 6px;
- height: 56px;
- width: 100%;
-
- .btn, .btn-flat {
- float: right;
- margin: 6px 0;
- }
- }
-}
-.lean-overlay {
- position: fixed;
- z-index:999;
- top: -100px;
- left: 0;
- bottom: 0;
- right: 0;
- height: 125%;
- width: 100%;
- background: #000;
- display: none;
-
- will-change: opacity;
-}
-
-// Modal with fixed action footer
-.modal.modal-fixed-footer {
- padding: 0;
- height: 70%;
-
- .modal-content {
- position: absolute;
- height: calc(100% - 56px);
- max-height: 100%;
- width: 100%;
- overflow-y: auto;
- }
-
- .modal-footer {
- border-top: 1px solid rgba(0,0,0,.1);
- position: absolute;
- bottom: 0;
- }
-}
-
-// Modal Bottom Sheet Style
-.modal.bottom-sheet {
- top: auto;
- bottom: -100%;
- margin: 0;
- width: 100%;
- max-height: 45%;
- border-radius: 0;
- will-change: bottom, opacity;
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_navbar.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_navbar.scss
deleted file mode 100644
index 65cd277..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_navbar.scss
+++ /dev/null
@@ -1,144 +0,0 @@
-nav {
- color: $navbar-font-color;
- @extend .z-depth-1;
- background-color: $primary-color;
- width: 100%;
- height: $navbar-height-mobile;
- line-height: $navbar-height-mobile;
-
- a { color: $navbar-font-color; }
-
- .nav-wrapper {
- position: relative;
- height: 100%;
-
- i {
- display: block;
- font-size: 2rem;
- }
- }
-
- @media #{$large-and-up} {
- a.button-collapse { display: none; }
- }
-
-
- // Collapse button
- .button-collapse {
- float: left;
- position: relative;
- z-index: 1;
- height: $navbar-height-mobile;
-
- i {
- font-size: 2.7rem;
- height: $navbar-height-mobile;
- line-height: $navbar-height-mobile;
- }
- }
-
-
- // Logo
- .brand-logo {
- position: absolute;
- color: $navbar-font-color;
- display: inline-block;
- font-size: $navbar-brand-font-size;
- padding: 0;
- white-space: nowrap;
-
- &.center {
- left: 50%;
- @include transform(translateX(-50%));
- }
-
- @media #{$medium-and-down} {
- left: 50%;
- @include transform(translateX(-50%));
- }
-
- &.right {
- right: 0.5rem;
- padding: 0;
- }
- }
-
-
- // Navbar Links
- ul {
- margin: 0;
-
- li {
- @include transition(background-color .3s);
- float: left;
- padding: 0;
-
- &:hover, &.active {
- background-color: rgba(0,0,0,.1);
- }
- }
- a {
- font-size: 1rem;
- color: $navbar-font-color;
- display: block;
- padding: 0 15px;
- }
-
- &.left {
- float: left;
- }
- }
-
- // Navbar Search Form
- .input-field {
- margin: 0;
-
- input {
- height: 100%;
- font-size: 1.2rem;
- border: none;
- padding-left: 2rem;
-
- &:focus, &[type=text]:valid, &[type=password]:valid,
- &[type=email]:valid, &[type=url]:valid, &[type=date]:valid {
- border: none;
- box-shadow: none;
- }
- }
- label {
- top: 0;
- left: 0;
-
- i {
- color: rgba(255,255,255,.7);
- @include transition(color .3s);
- }
- &.active i { color: $navbar-font-color; }
- &.active {
- @include transform(translateY(0));
- }
- }
-
- }
-
-}
-
-// Fixed Navbar
-.navbar-fixed {
- position: relative;
- height: $navbar-height-mobile;
- z-index: 998;
-
- nav {
- position: fixed;
- }
-}
-@media #{$medium-and-up} {
- nav, nav .nav-wrapper i, nav a.button-collapse, nav a.button-collapse i {
- height: $navbar-height;
- line-height: $navbar-height;
- }
- .navbar-fixed {
- height: $navbar-height;
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_normalize.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_normalize.scss
deleted file mode 100644
index ab626c4..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_normalize.scss
+++ /dev/null
@@ -1,427 +0,0 @@
-/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
-
-/**
- * 1. Set default font family to sans-serif.
- * 2. Prevent iOS text size adjust after orientation change, without disabling
- * user zoom.
- */
-
-html {
- font-family: sans-serif; /* 1 */
- -ms-text-size-adjust: 100%; /* 2 */
- -webkit-text-size-adjust: 100%; /* 2 */
-}
-
-/**
- * Remove default margin.
- */
-
-body {
- margin: 0;
-}
-
-/* HTML5 display definitions
- ========================================================================== */
-
-/**
- * Correct `block` display not defined for any HTML5 element in IE 8/9.
- * Correct `block` display not defined for `details` or `summary` in IE 10/11
- * and Firefox.
- * Correct `block` display not defined for `main` in IE 11.
- */
-
-article,
-aside,
-details,
-figcaption,
-figure,
-footer,
-header,
-hgroup,
-main,
-menu,
-nav,
-section,
-summary {
- display: block;
-}
-
-/**
- * 1. Correct `inline-block` display not defined in IE 8/9.
- * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
- */
-
-audio,
-canvas,
-progress,
-video {
- display: inline-block; /* 1 */
- vertical-align: baseline; /* 2 */
-}
-
-/**
- * Prevent modern browsers from displaying `audio` without controls.
- * Remove excess height in iOS 5 devices.
- */
-
-audio:not([controls]) {
- display: none;
- height: 0;
-}
-
-/**
- * Address `[hidden]` styling not present in IE 8/9/10.
- * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
- */
-
-[hidden],
-template {
- display: none;
-}
-
-/* Links
- ========================================================================== */
-
-/**
- * Remove the gray background color from active links in IE 10.
- */
-
-a {
- background-color: transparent;
-}
-
-/**
- * Improve readability when focused and also mouse hovered in all browsers.
- */
-
-a:active,
-a:hover {
- outline: 0;
-}
-
-/* Text-level semantics
- ========================================================================== */
-
-/**
- * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
- */
-
-abbr[title] {
- border-bottom: 1px dotted;
-}
-
-/**
- * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
- */
-
-b,
-strong {
- font-weight: bold;
-}
-
-/**
- * Address styling not present in Safari and Chrome.
- */
-
-dfn {
- font-style: italic;
-}
-
-/**
- * Address variable `h1` font-size and margin within `section` and `article`
- * contexts in Firefox 4+, Safari, and Chrome.
- */
-
-h1 {
- font-size: 2em;
- margin: 0.67em 0;
-}
-
-/**
- * Address styling not present in IE 8/9.
- */
-
-mark {
- background: #ff0;
- color: #000;
-}
-
-/**
- * Address inconsistent and variable font size in all browsers.
- */
-
-small {
- font-size: 80%;
-}
-
-/**
- * Prevent `sub` and `sup` affecting `line-height` in all browsers.
- */
-
-sub,
-sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline;
-}
-
-sup {
- top: -0.5em;
-}
-
-sub {
- bottom: -0.25em;
-}
-
-/* Embedded content
- ========================================================================== */
-
-/**
- * Remove border when inside `a` element in IE 8/9/10.
- */
-
-img {
- border: 0;
-}
-
-/**
- * Correct overflow not hidden in IE 9/10/11.
- */
-
-svg:not(:root) {
- overflow: hidden;
-}
-
-/* Grouping content
- ========================================================================== */
-
-/**
- * Address margin not present in IE 8/9 and Safari.
- */
-
-figure {
- margin: 1em 40px;
-}
-
-/**
- * Address differences between Firefox and other browsers.
- */
-
-hr {
- -moz-box-sizing: content-box;
- box-sizing: content-box;
- height: 0;
-}
-
-/**
- * Contain overflow in all browsers.
- */
-
-pre {
- overflow: auto;
-}
-
-/**
- * Address odd `em`-unit font size rendering in all browsers.
- */
-
-code,
-kbd,
-pre,
-samp {
- font-family: monospace, monospace;
- font-size: 1em;
-}
-
-/* Forms
- ========================================================================== */
-
-/**
- * Known limitation: by default, Chrome and Safari on OS X allow very limited
- * styling of `select`, unless a `border` property is set.
- */
-
-/**
- * 1. Correct color not being inherited.
- * Known issue: affects color of disabled elements.
- * 2. Correct font properties not being inherited.
- * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
- */
-
-button,
-input,
-optgroup,
-select,
-textarea {
- color: inherit; /* 1 */
- font: inherit; /* 2 */
- margin: 0; /* 3 */
-}
-
-/**
- * Address `overflow` set to `hidden` in IE 8/9/10/11.
- */
-
-button {
- overflow: visible;
-}
-
-/**
- * Address inconsistent `text-transform` inheritance for `button` and `select`.
- * All other form control elements do not inherit `text-transform` values.
- * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
- * Correct `select` style inheritance in Firefox.
- */
-
-button,
-select {
- text-transform: none;
-}
-
-/**
- * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
- * and `video` controls.
- * 2. Correct inability to style clickable `input` types in iOS.
- * 3. Improve usability and consistency of cursor style between image-type
- * `input` and others.
- */
-
-/* 1 */ html input[type="button"],
-button,
-input[type="reset"],
-input[type="submit"] {
- -webkit-appearance: button; /* 2 */
- cursor: pointer; /* 3 */
-}
-
-/**
- * Re-set default cursor for disabled elements.
- */
-
-button[disabled],
-html input[disabled] {
- cursor: default;
-}
-
-/**
- * Remove inner padding and border in Firefox 4+.
- */
-
-button::-moz-focus-inner,
-input::-moz-focus-inner {
- border: 0;
- padding: 0;
-}
-
-/**
- * Address Firefox 4+ setting `line-height` on `input` using `!important` in
- * the UA stylesheet.
- */
-
-input {
- line-height: normal;
-}
-
-/**
- * It's recommended that you don't attempt to style these elements.
- * Firefox's implementation doesn't respect box-sizing, padding, or width.
- *
- * 1. Address box sizing set to `content-box` in IE 8/9/10.
- * 2. Remove excess padding in IE 8/9/10.
- */
-
-input[type="checkbox"],
-input[type="radio"] {
- box-sizing: border-box; /* 1 */
- padding: 0; /* 2 */
-}
-
-/**
- * Fix the cursor style for Chrome's increment/decrement buttons. For certain
- * `font-size` values of the `input`, it causes the cursor style of the
- * decrement button to change from `default` to `text`.
- */
-
-input[type="number"]::-webkit-inner-spin-button,
-input[type="number"]::-webkit-outer-spin-button {
- height: auto;
-}
-
-/**
- * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
- * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
- * (include `-moz` to future-proof).
- */
-
-input[type="search"] {
- -webkit-appearance: textfield; /* 1 */
- -moz-box-sizing: content-box;
- -webkit-box-sizing: content-box; /* 2 */
- box-sizing: content-box;
-}
-
-/**
- * Remove inner padding and search cancel button in Safari and Chrome on OS X.
- * Safari (but not Chrome) clips the cancel button when the search input has
- * padding (and `textfield` appearance).
- */
-
-input[type="search"]::-webkit-search-cancel-button,
-input[type="search"]::-webkit-search-decoration {
- -webkit-appearance: none;
-}
-
-/**
- * Define consistent border, margin, and padding.
- */
-
-fieldset {
- border: 1px solid #c0c0c0;
- margin: 0 2px;
- padding: 0.35em 0.625em 0.75em;
-}
-
-/**
- * 1. Correct `color` not being inherited in IE 8/9/10/11.
- * 2. Remove padding so people aren't caught out if they zero out fieldsets.
- */
-
-legend {
- border: 0; /* 1 */
- padding: 0; /* 2 */
-}
-
-/**
- * Remove default vertical scrollbar in IE 8/9/10/11.
- */
-
-textarea {
- overflow: auto;
-}
-
-/**
- * Don't inherit the `font-weight` (applied by a rule above).
- * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
- */
-
-optgroup {
- font-weight: bold;
-}
-
-/* Tables
- ========================================================================== */
-
-/**
- * Remove most spacing between table cells.
- */
-
-table {
- border-collapse: collapse;
- border-spacing: 0;
-}
-
-td,
-th {
- padding: 0;
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_prefixer.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_prefixer.scss
deleted file mode 100644
index f483eaf..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_prefixer.scss
+++ /dev/null
@@ -1,376 +0,0 @@
-//---------------------------------------------------
-// Sass Prefixer
-// -------------------------------------------------
-// TABLE OF CONTENTS
-// (*) denotes a syntax-sugar helper
-// -------------------------------------------------
-//
-// animation($args)
-// animation-delay($delay)
-// animation-direction($direction)
-// animation-duration($duration)
-// animation-fill-mode($mode)
-// animation-iteration-count($count)
-// animation-name($name)
-// animation-play-state($state)
-// animation-timing-function($function)
-// background-size($args)
-// inner-shadow($args) *
-// box-sizing($args)
-// border-box() *
-// content-box() *
-// columns($args)
-// column-count($count)
-// column-gap($gap)
-// column-rule($args)
-// column-width($width)
-// flexbox()
-// flex($args)
-// order($args)
-// align($args)
-// justify-content($args)
-// gradient($default,$start,$stop) *
-// linear-gradient-top($default,$color1,$stop1,$color2,$stop2,[$color3,$stop3,$color4,$stop4])*
-// linear-gradient-left($default,$color1,$stop1,$color2,$stop2,[$color3,$stop3,$color4,$stop4])*
-// transform($args)
-// transform-origin($args)
-// transform-style($style)
-// rotate($deg)
-// scale($factor)
-// translate($x,$y)
-// translate3d($x,$y,$z)
-// translateHardware($x,$y) *
-// text-shadow($args)
-// transition($args)
-// transition-delay($delay)
-// transition-duration($duration)
-// transition-property($property)
-// transition-timing-function($function)
-
-
-// Animation
-
-@mixin animation($args) {
- -webkit-animation: $args;
- -moz-animation: $args;
- -ms-animation: $args;
- -o-animation: $args;
- animation: $args;
-}
-@mixin animation-delay($delay) {
- -webkit-animation-delay: $delay;
- -moz-animation-delay: $delay;
- -ms-animation-delay: $delay;
- -o-animation-delay: $delay;
- animation-delay: $delay;
-}
-@mixin animation-direction($direction) {
- -webkit-animation-direction: $direction;
- -moz-animation-direction: $direction;
- -ms-animation-direction: $direction;
- -o-animation-direction: $direction;
-}
-@mixin animation-duration($duration) {
- -webkit-animation-duration: $duration;
- -moz-animation-duration: $duration;
- -ms-animation-duration: $duration;
- -o-animation-duration: $duration;
-}
-@mixin animation-fill-mode($mode) {
- -webkit-animation-fill-mode: $mode;
- -moz-animation-fill-mode: $mode;
- -ms-animation-fill-mode: $mode;
- -o-animation-fill-mode: $mode;
- animation-fill-mode: $mode;
-}
-@mixin animation-iteration-count($count) {
- -webkit-animation-iteration-count: $count;
- -moz-animation-iteration-count: $count;
- -ms-animation-iteration-count: $count;
- -o-animation-iteration-count: $count;
- animation-iteration-count: $count;
-}
-@mixin animation-name($name) {
- -webkit-animation-name: $name;
- -moz-animation-name: $name;
- -ms-animation-name: $name;
- -o-animation-name: $name;
- animation-name: $name;
-}
-@mixin animation-play-state($state) {
- -webkit-animation-play-state: $state;
- -moz-animation-play-state: $state;
- -ms-animation-play-state: $state;
- -o-animation-play-state: $state;
- animation-play-state: $state;
-}
-@mixin animation-timing-function($function) {
- -webkit-animation-timing-function: $function;
- -moz-animation-timing-function: $function;
- -ms-animation-timing-function: $function;
- -o-animation-timing-function: $function;
- animation-timing-function: $function;
-}
-
-// Keyframes
-@mixin keyframes($animation-name) {
- @-webkit-keyframes #{$animation-name} {
- @content;
- }
- @-moz-keyframes #{$animation-name} {
- @content;
- }
- @keyframes #{$animation-name} {
- @content;
- }
-}
-
-// Backface-visibility
-
-@mixin backface-visibility($args) {
- -webkit-backface-visibility: $args;
- -moz-backface-visibility: $args;
- -ms-backface-visibility: $args;
- backface-visibility: $args;
-}
-
-
-// Background Size
-
-@mixin background-size($args) {
- -webkit-background-size: $args;
- background-size: $args;
-}
-
-// Box Sizing
-
-@mixin box-sizing($args) {
- -webkit-box-sizing: $args;
- -moz-box-sizing: $args;
- box-sizing: $args;
-}
-@mixin border-box(){
- @include box-sizing(border-box);
-}
-@mixin content-box(){
- @include box-sizing(content-box);
-}
-
-
-// Columns
-
-@mixin columns($args) {
- -webkit-columns: $args;
- -moz-columns: $args;
- columns: $args;
-}
-@mixin column-count($count) {
- -webkit-column-count: $count;
- -moz-column-count: $count;
- column-count: $count;
-}
-@mixin column-gap($gap) {
- -webkit-column-gap: $gap;
- -moz-column-gap: $gap;
- column-gap: $gap;
-}
-@mixin column-width($width) {
- -webkit-column-width: $width;
- -moz-column-width: $width;
- column-width: $width;
-}
-@mixin column-rule($args) {
- -webkit-column-rule: $args;
- -moz-column-rule: $args;
- column-rule: $args;
-}
-
-// Filter
-@mixin filter($args) {
- -webkit-filter: $args;
- -moz-filter: $args;
- -o-filter: $args;
- -ms-filter: $args;
-}
-
-// Flexbox
-@mixin flexbox() {
- display: -webkit-box;
- display: -moz-box;
- display: -ms-flexbox;
- display: -webkit-flex;
- display: flex;
-}
- @mixin flex($values) {
- -webkit-box-flex: $values;
- -moz-box-flex: $values;
- -webkit-flex: $values;
- -ms-flex: $values;
- flex: $values;
- }
- @mixin order($val) {
- -webkit-box-ordinal-group: $val;
- -moz-box-ordinal-group: $val;
- -ms-flex-order: $val;
- -webkit-order: $val;
- order: $val;
- }
- @mixin align($align) {
- -webkit-flex-align: $align;
- -ms-flex-align: $align;
- -webkit-align-items: $align;
- align-items: $align;
- }
- @mixin justify-content($val) {
- -webkit-justify-content: $val;
- justify-content: $val;
- }
-// Gradients
-
-@mixin gradient($default: #F5F5F5, $start: #EEE, $stop: #FFF) {
- @include linear-gradient-top($default,$start,0%,$stop,100%);
-}
-@mixin linear-gradient-top($default,$color1,$stop1,$color2,$stop2) {
- background-color: $default;
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop($stop1, $color1), color-stop($stop2 $color2));
- background-image: -webkit-linear-gradient(top, $color1 $stop1, $color2 $stop2);
- background-image: -moz-linear-gradient(top, $color1 $stop1, $color2 $stop2);
- background-image: -ms-linear-gradient(top, $color1 $stop1, $color2 $stop2);
- background-image: -o-linear-gradient(top, $color1 $stop1, $color2 $stop2);
- background-image: linear-gradient(top, $color1 $stop1, $color2 $stop2);
-}
-@mixin linear-gradient-top2($default,$color1,$stop1,$color2,$stop2,$color3,$stop3) {
- background-color: $default;
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop($stop1, $color1), color-stop($stop2 $color2), color-stop($stop3 $color3));
- background-image: -webkit-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3);
- background-image: -moz-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3);
- background-image: -ms-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3);
- background-image: -o-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3);
- background-image: linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3);
-}
-@mixin linear-gradient-top3($default,$color1,$stop1,$color2,$stop2,$color3,$stop3,$color4,$stop4) {
- background-color: $default;
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop($stop1, $color1), color-stop($stop2 $color2), color-stop($stop3 $color3), color-stop($stop4 $color4));
- background-image: -webkit-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4);
- background-image: -moz-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4);
- background-image: -ms-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4);
- background-image: -o-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4);
- background-image: linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4);
-}
-@mixin linear-gradient-left($default,$color1,$stop1,$color2,$stop2) {
- background-color: $default;
- background-image: -webkit-gradient(linear, left top, left top, color-stop($stop1, $color1), color-stop($stop2 $color2));
- background-image: -webkit-linear-gradient(left, $color1 $stop1, $color2 $stop2);
- background-image: -moz-linear-gradient(left, $color1 $stop1, $color2 $stop2);
- background-image: -ms-linear-gradient(left, $color1 $stop1, $color2 $stop2);
- background-image: -o-linear-gradient(left, $color1 $stop1, $color2 $stop2);
- background-image: linear-gradient(left, $color1 $stop1, $color2 $stop2);
-}
-@mixin linear-gradient-left2($default,$color1,$stop1,$color2,$stop2,$color3,$stop3) {
- background-color: $default;
- background-image: -webkit-gradient(linear, left top, left top, color-stop($stop1, $color1), color-stop($stop2 $color2), color-stop($stop3 $color3));
- background-image: -webkit-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3);
- background-image: -moz-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3);
- background-image: -ms-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3);
- background-image: -o-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3);
- background-image: linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3);
-}
-@mixin linear-gradient-left3($default,$color1,$stop1,$color2,$stop2,$color3,$stop3,$color4,$stop4) {
- background-color: $default;
- background-image: -webkit-gradient(linear, left top, left top, color-stop($stop1, $color1), color-stop($stop2 $color2), color-stop($stop3 $color3), color-stop($stop4 $color4));
- background-image: -webkit-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4);
- background-image: -moz-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4);
- background-image: -ms-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4);
- background-image: -o-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4);
- background-image: linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4);
-}
-
-// Text Shadow
-
-@mixin text-shadow($args) {
- text-shadow: $args;
-}
-
-
-// Transforms
-
-@mixin transform($args) {
- -webkit-transform: $args;
- -moz-transform: $args;
- -ms-transform: $args;
- -o-transform: $args;
- transform: $args;
-}
-@mixin transform-origin($args) {
- -webkit-transform-origin: $args;
- -moz-transform-origin: $args;
- -ms-transform-origin: $args;
- -o-transform-origin: $args;
- transform-origin: $args;
-}
-@mixin transform-style($style) {
- -webkit-transform-style: $style;
- -moz-transform-style: $style;
- -ms-transform-style: $style;
- -o-transform-style: $style;
- transform-style: $style;
-}
-@mixin rotate($deg:45deg){
- @include transform(rotate($deg));
-}
-@mixin scale($factor:.5){
- @include transform(scale($factor));
-}
-@mixin translate($x,$y){
- @include transform(translate($x,$y));
-}
-@mixin translate3d($x,$y,$z) {
- @include transform(translate3d($x,$y,$z));
-}
-@mixin translateHardware($x,$y) {
- @include translate($x,$y);
- -webkit-transform: translate3d($x,$y,0);
- -moz-transform: translate3d($x,$y,0);
- -o-transform: translate3d($x,$y,0);
- -ms-transform: translate3d($x,$y,0);
- transform: translate3d($x,$y,0);
-}
-
-
-// Transitions
-
-@mixin transition($args:200ms) {
- -webkit-transition: $args;
- -moz-transition: $args;
- -o-transition: $args;
- -ms-transition: $args;
- transition: $args;
-}
-@mixin transition-delay($delay:0) {
- -webkit-transition-delay: $delay;
- -moz-transition-delay: $delay;
- -o-transition-delay: $delay;
- -ms-transition-delay: $delay;
- transition-delay: $delay;
-}
-@mixin transition-duration($duration:200ms) {
- -webkit-transition-duration: $duration;
- -moz-transition-duration: $duration;
- -o-transition-duration: $duration;
- -ms-transition-duration: $duration;
- transition-duration: $duration;
-}
-@mixin transition-property($property:all) {
- -webkit-transition-property: $property;
- -moz-transition-property: $property;
- -o-transition-property: $property;
- -ms-transition-property: $property;
- transition-property: $property;
-}
-@mixin transition-timing-function($function:ease) {
- -webkit-transition-timing-function: $function;
- -moz-transition-timing-function: $function;
- -o-transition-timing-function: $function;
- -ms-transition-timing-function: $function;
- transition-timing-function: $function;
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_preloader.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_preloader.scss
deleted file mode 100644
index ab5c783..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_preloader.scss
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- @license
- Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
- This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
- The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
- The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
- Code distributed by Google as part of the polymer project is also
- subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
- */
-
-/**************************/
-/* STYLES FOR THE SPINNER */
-/**************************/
-
-/*
- * Constants:
- * STROKEWIDTH = 3px
- * ARCSIZE = 270 degrees (amount of circle the arc takes up)
- * ARCTIME = 1333ms (time it takes to expand and contract arc)
- * ARCSTARTROT = 216 degrees (how much the start location of the arc
- * should rotate each time, 216 gives us a
- * 5 pointed star shape (it's 360/5 * 3).
- * For a 7 pointed star, we might do
- * 360/7 * 3 = 154.286)
- * CONTAINERWIDTH = 28px
- * SHRINK_TIME = 400ms
- */
-
-
-.preloader-wrapper {
- display: inline-block;
- position: relative;
- width: 48px;
- height: 48px;
-
- &.small {
- width: 36px;
- height: 36px;
- }
-
- &.big {
- width: 64px;
- height: 64px;
- }
-
- &.active {
- /* duration: 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */
- -webkit-animation: container-rotate 1568ms linear infinite;
- animation: container-rotate 1568ms linear infinite;
- }
-}
-
-@-webkit-keyframes container-rotate {
- to { -webkit-transform: rotate(360deg) }
-}
-
-@keyframes container-rotate {
- to { transform: rotate(360deg) }
-}
-
-.spinner-layer {
- position: absolute;
- width: 100%;
- height: 100%;
- opacity: 0;
-}
-
-.spinner-blue,
-.spinner-blue-only {
- border-color: #4285f4;
-}
-
-.spinner-red,
-.spinner-red-only {
- border-color: #db4437;
-}
-
-.spinner-yellow,
-.spinner-yellow-only {
- border-color: #f4b400;
-}
-
-.spinner-green,
-.spinner-green-only {
- border-color: #0f9d58;
-}
-
-/**
- * IMPORTANT NOTE ABOUT CSS ANIMATION PROPERTIES (keanulee):
- *
- * iOS Safari (tested on iOS 8.1) does not handle animation-delay very well - it doesn't
- * guarantee that the animation will start _exactly_ after that value. So we avoid using
- * animation-delay and instead set custom keyframes for each color (as redundant as it
- * seems).
- *
- * We write out each animation in full (instead of separating animation-name,
- * animation-duration, etc.) because under the polyfill, Safari does not recognize those
- * specific properties properly, treats them as -webkit-animation, and overrides the
- * other animation rules. See https://github.com/Polymer/platform/issues/53.
- */
-.active .spinner-layer.spinner-blue {
- /* durations: 4 * ARCTIME */
- -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
- animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
-}
-
-.active .spinner-layer.spinner-red {
- /* durations: 4 * ARCTIME */
- -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
- animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
-}
-
-.active .spinner-layer.spinner-yellow {
- /* durations: 4 * ARCTIME */
- -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
- animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
-}
-
-.active .spinner-layer.spinner-green {
- /* durations: 4 * ARCTIME */
- -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
- animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
-}
-
-.active .spinner-layer.spinner-blue-only,
-.active .spinner-layer.spinner-red-only,
-.active .spinner-layer.spinner-yellow-only,
-.active .spinner-layer.spinner-green-only {
- /* durations: 4 * ARCTIME */
- opacity: 1;
- -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
- animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
-}
-
-@-webkit-keyframes fill-unfill-rotate {
- 12.5% { -webkit-transform: rotate(135deg); } /* 0.5 * ARCSIZE */
- 25% { -webkit-transform: rotate(270deg); } /* 1 * ARCSIZE */
- 37.5% { -webkit-transform: rotate(405deg); } /* 1.5 * ARCSIZE */
- 50% { -webkit-transform: rotate(540deg); } /* 2 * ARCSIZE */
- 62.5% { -webkit-transform: rotate(675deg); } /* 2.5 * ARCSIZE */
- 75% { -webkit-transform: rotate(810deg); } /* 3 * ARCSIZE */
- 87.5% { -webkit-transform: rotate(945deg); } /* 3.5 * ARCSIZE */
- to { -webkit-transform: rotate(1080deg); } /* 4 * ARCSIZE */
-}
-
-@keyframes fill-unfill-rotate {
- 12.5% { transform: rotate(135deg); } /* 0.5 * ARCSIZE */
- 25% { transform: rotate(270deg); } /* 1 * ARCSIZE */
- 37.5% { transform: rotate(405deg); } /* 1.5 * ARCSIZE */
- 50% { transform: rotate(540deg); } /* 2 * ARCSIZE */
- 62.5% { transform: rotate(675deg); } /* 2.5 * ARCSIZE */
- 75% { transform: rotate(810deg); } /* 3 * ARCSIZE */
- 87.5% { transform: rotate(945deg); } /* 3.5 * ARCSIZE */
- to { transform: rotate(1080deg); } /* 4 * ARCSIZE */
-}
-
-@-webkit-keyframes blue-fade-in-out {
- from { opacity: 1; }
- 25% { opacity: 1; }
- 26% { opacity: 0; }
- 89% { opacity: 0; }
- 90% { opacity: 1; }
- 100% { opacity: 1; }
-}
-
-@keyframes blue-fade-in-out {
- from { opacity: 1; }
- 25% { opacity: 1; }
- 26% { opacity: 0; }
- 89% { opacity: 0; }
- 90% { opacity: 1; }
- 100% { opacity: 1; }
-}
-
-@-webkit-keyframes red-fade-in-out {
- from { opacity: 0; }
- 15% { opacity: 0; }
- 25% { opacity: 1; }
- 50% { opacity: 1; }
- 51% { opacity: 0; }
-}
-
-@keyframes red-fade-in-out {
- from { opacity: 0; }
- 15% { opacity: 0; }
- 25% { opacity: 1; }
- 50% { opacity: 1; }
- 51% { opacity: 0; }
-}
-
-@-webkit-keyframes yellow-fade-in-out {
- from { opacity: 0; }
- 40% { opacity: 0; }
- 50% { opacity: 1; }
- 75% { opacity: 1; }
- 76% { opacity: 0; }
-}
-
-@keyframes yellow-fade-in-out {
- from { opacity: 0; }
- 40% { opacity: 0; }
- 50% { opacity: 1; }
- 75% { opacity: 1; }
- 76% { opacity: 0; }
-}
-
-@-webkit-keyframes green-fade-in-out {
- from { opacity: 0; }
- 65% { opacity: 0; }
- 75% { opacity: 1; }
- 90% { opacity: 1; }
- 100% { opacity: 0; }
-}
-
-@keyframes green-fade-in-out {
- from { opacity: 0; }
- 65% { opacity: 0; }
- 75% { opacity: 1; }
- 90% { opacity: 1; }
- 100% { opacity: 0; }
-}
-
-/**
- * Patch the gap that appear between the two adjacent div.circle-clipper while the
- * spinner is rotating (appears on Chrome 38, Safari 7.1, and IE 11).
- */
-.gap-patch {
- position: absolute;
- top: 0;
- left: 45%;
- width: 10%;
- height: 100%;
- overflow: hidden;
- border-color: inherit;
-}
-
-.gap-patch .circle {
- width: 1000%;
- left: -450%;
-}
-
-.circle-clipper {
- display: inline-block;
- position: relative;
- width: 50%;
- height: 100%;
- overflow: hidden;
- border-color: inherit;
-
- .circle {
- width: 200%;
- height: 100%;
- border-width: 3px; /* STROKEWIDTH */
- border-style: solid;
- border-color: inherit;
- border-bottom-color: transparent !important;
- border-radius: 50%;
- -webkit-animation: none;
- animation: none;
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- }
-
- &.left .circle {
- left: 0;
- border-right-color: transparent !important;
- -webkit-transform: rotate(129deg);
- transform: rotate(129deg);
- }
- &.right .circle {
- left: -100%;
- border-left-color: transparent !important;
- -webkit-transform: rotate(-129deg);
- transform: rotate(-129deg);
- }
-}
-
-
-
-.active .circle-clipper.left .circle {
- /* duration: ARCTIME */
- -webkit-animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
- animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
-}
-
-.active .circle-clipper.right .circle {
- /* duration: ARCTIME */
- -webkit-animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
- animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
-}
-
-@-webkit-keyframes left-spin {
- from { -webkit-transform: rotate(130deg); }
- 50% { -webkit-transform: rotate(-5deg); }
- to { -webkit-transform: rotate(130deg); }
-}
-
-@keyframes left-spin {
- from { transform: rotate(130deg); }
- 50% { transform: rotate(-5deg); }
- to { transform: rotate(130deg); }
-}
-
-@-webkit-keyframes right-spin {
- from { -webkit-transform: rotate(-130deg); }
- 50% { -webkit-transform: rotate(5deg); }
- to { -webkit-transform: rotate(-130deg); }
-}
-
-@keyframes right-spin {
- from { transform: rotate(-130deg); }
- 50% { transform: rotate(5deg); }
- to { transform: rotate(-130deg); }
-}
-
-#spinnerContainer.cooldown {
- /* duration: SHRINK_TIME */
- -webkit-animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
- animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
-}
-
-@-webkit-keyframes fade-out {
- from { opacity: 1; }
- to { opacity: 0; }
-}
-
-@keyframes fade-out {
- from { opacity: 1; }
- to { opacity: 0; }
-} \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_roboto.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_roboto.scss
deleted file mode 100644
index 8bfdbd3..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_roboto.scss
+++ /dev/null
@@ -1,38 +0,0 @@
-@font-face {
- font-family: "Roboto";
- src: url("#{$roboto-font-path}Roboto-Thin.woff2") format("woff2"),
- url("#{$roboto-font-path}Roboto-Thin.woff") format("woff"),
- url("#{$roboto-font-path}Roboto-Thin.ttf") format("truetype");
- font-weight: 200;
-}
-@font-face {
- font-family: "Roboto";
- src: url("#{$roboto-font-path}Roboto-Light.woff2") format("woff2"),
- url("#{$roboto-font-path}Roboto-Light.woff") format("woff"),
- url("#{$roboto-font-path}Roboto-Light.ttf") format("truetype");
- font-weight: 300;
-}
-
-@font-face {
- font-family: "Roboto";
- src: url("#{$roboto-font-path}Roboto-Regular.woff2") format("woff2"),
- url("#{$roboto-font-path}Roboto-Regular.woff") format("woff"),
- url("#{$roboto-font-path}Roboto-Regular.ttf") format("truetype");
- font-weight: 400;
-}
-
-@font-face {
- font-family: "Roboto";
- src: url("#{$roboto-font-path}Roboto-Medium.woff2") format("woff2"),
- url("#{$roboto-font-path}Roboto-Medium.woff") format("woff"),
- url("#{$roboto-font-path}Roboto-Medium.ttf") format("truetype");
- font-weight: 500;
-}
-
-@font-face {
- font-family: "Roboto";
- src: url("#{$roboto-font-path}Roboto-Bold.woff2") format("woff2"),
- url("#{$roboto-font-path}Roboto-Bold.woff") format("woff"),
- url("#{$roboto-font-path}Roboto-Bold.ttf") format("truetype");
- font-weight: 700;
-} \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_sideNav.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_sideNav.scss
deleted file mode 100644
index 98794a1..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_sideNav.scss
+++ /dev/null
@@ -1,111 +0,0 @@
-.side-nav {
- position: fixed;
- width: 240px;
- left: -105%;
- top: 0;
- margin: 0;
- height: 100%;
- height: calc(100% + 60px);
- height: -moz-calc(100%); //Temporary Firefox Fix
- padding-bottom: 60px;
- background-color: $sidenav-bg-color;
- z-index: 999;
- overflow-y: auto;
-
- @extend .z-depth-1;
- will-change: left;
-
- // Right Align
- &.right-aligned {
- will-change: right;
- right: -105%;
- left: auto;
- }
-
- .collapsible{
- margin: 0;
- }
-
-
- li {
- float: none;
- padding: 0 $sidenav-padding-right;
- &:hover, &.active { background-color: #ddd; }
- }
- a {
- color: #444;
- display: block;
- font-size: 1rem;
- height: 64px;
- line-height: 64px;
- padding: 0 $sidenav-padding-right;
- }
-}
-
-
-// Touch interaction
-.drag-target {
- height: 100%;
- width: 10px;
- position: fixed;
- top: 0;
- z-index: 998;
-}
-
-
-// Hidden side-nav for all sizes
-.side-nav.fixed {
- a {
- display: block;
- padding: 0 $sidenav-padding-right;
- color: #444;
- }
-}
-
-
-// Fixed side-nav shown
-.side-nav.fixed {
- left: 0;
- position: fixed;
-
- // Right Align
- &.right-aligned {
- right: 0;
- left: auto;
- }
-}
-
-// Fixed sideNav hide on smaller
-@media #{$medium-and-down} {
- .side-nav.fixed {
- left: -105%;
-
- &.right-aligned {
- right: -105%;
- left: auto;
- }
- }
-}
-
-
-.side-nav .collapsible-body li.active,
-.side-nav.fixed .collapsible-body li.active {
- background-color: $primary-color;
- a {
- color: $sidenav-bg-color;
- }
-}
-
-
-#sidenav-overlay {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
-
- height: 120vh;
- background-color: rgba(0,0,0,.5);
- z-index: 997;
-
- will-change: opacity;
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_slider.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_slider.scss
deleted file mode 100644
index 3d2071a..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_slider.scss
+++ /dev/null
@@ -1,92 +0,0 @@
-.slider {
- position: relative;
- height: 400px;
- width: 100%;
-
- // Fullscreen slider
- &.fullscreen {
- height: 100%;
- width: 100%;
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
-
- ul.slides {
- height: 100%;
- }
-
- ul.indicators {
- z-index: 2;
- bottom: 30px;
- }
- }
-
- .slides {
- background-color: $slider-bg-color;
- margin: 0;
- height: 400px;
-
- li {
- opacity: 0;
- position: absolute;
- top: 0;
- left: 0;
- z-index: 1;
- width: 100%;
- height: inherit;
- overflow: hidden;
-
- img {
- height: 100%;
- width: 100%;
- background-size: cover;
- background-position: center;
- }
-
- .caption {
- color: #fff;
- position: absolute;
- top: 15%;
- left: 15%;
- width: 70%;
- opacity: 0;
-
- p { color: $slider-bg-color-light; }
- }
-
- &.active {
- z-index: 2;
- }
- }
- }
-
-
- .indicators {
- position: absolute;
- text-align: center;
- left: 0;
- right: 0;
- bottom: 0;
- margin: 0;
-
- .indicator-item {
- display: inline-block;
- position: relative;
- cursor: pointer;
- height: 16px;
- width: 16px;
- margin: 0 12px;
- background-color: $slider-bg-color-light;
-
- @include transition(background-color .3s);
- border-radius: 50%;
-
- &.active {
- background-color: $slider-indicator-color;
- }
- }
- }
-
-} \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_table_of_contents.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_table_of_contents.scss
deleted file mode 100644
index 2872bdb..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_table_of_contents.scss
+++ /dev/null
@@ -1,33 +0,0 @@
-/***************
- Nav List
-***************/
-.table-of-contents {
- &.fixed {
- position: fixed;
- }
-
- li {
- padding: 2px 0;
- }
- a {
- display: inline-block;
- font-weight: 300;
- color: #757575;
- padding-left: 20px;
- height: 1.5rem;
- line-height: 1.5rem;
- letter-spacing: .4;
- display: inline-block;
-
- &:hover {
- color: lighten(#757575, 20%);
- padding-left: 19px;
- border-left: 1px solid lighten(color("materialize-red", "base"),10%);
- }
- &.active {
- font-weight: 500;
- padding-left: 18px;
- border-left: 2px solid lighten(color("materialize-red", "base"),10%);
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_tabs.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_tabs.scss
deleted file mode 100644
index dcf29e1..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_tabs.scss
+++ /dev/null
@@ -1,47 +0,0 @@
-.tabs {
- position: relative;
- height: 48px;
- background-color: $tabs-bg-color;
- margin: 0 auto;
- width: 100%;
- white-space: nowrap;
-
- .tab {
- display: block;
- float: left;
- text-align: center;
- line-height: 48px;
- height: 48px;
- padding: 0 20px;
- margin: 0;
- text-transform: uppercase;
- letter-spacing: .8px;
- width: 15%;
-
- a {
- color: $tabs-text-color;
- display: block;
- width: 100%;
- height: 100%;
- @include transition( color .28s ease);
- &:hover {
- color: lighten($tabs-text-color, 20%);
- }
- }
-
- &.disabled a {
- color: lighten($tabs-text-color, 20%);
- cursor: default;
- }
- }
- .indicator {
- position: absolute;
- bottom: 0;
- height: 2px;
- background-color: $tabs-underline-color;
- will-change: left, right;
- }
-}
-
-.tabs .tab { padding: 0; }
-
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_toast.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_toast.scss
deleted file mode 100644
index 87bd7dd..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_toast.scss
+++ /dev/null
@@ -1,63 +0,0 @@
-#toast-container {
- display:block;
- position: fixed;
- z-index: 1001;
-
- @media #{$small-and-down} {
- min-width: 100%;
- bottom: 0%;
- }
- @media #{$medium-only} {
- min-width: 30%;
- left: 5%;
- bottom: 7%;
- }
- @media #{$large-and-up} {
- min-width: 8%;
- top: 10%;
- right: 7%;
- }
-}
-
-.toast {
- @extend .z-depth-1;
- border-radius: 2px;
- top: 0;
- width: auto;
- clear: both;
- margin-top: 10px;
- position: relative;
- max-width:100%;
- height: $toast-height;
- line-height: $toast-height;
- background-color: $toast-color;
- padding: 0 25px;
- font-size: 1.1rem;
- font-weight: 300;
- color: $toast-text-color;
-
- @include flexbox();
- @include align(center);
- @include justify-content(space-between);
-
- .btn, .btn-flat {
- margin: 0;
- margin-left: 3rem;
- }
-
- &.rounded{
- border-radius: 24px;
- }
-
- @media #{$small-and-down} {
- width:100%;
- border-radius: 0;
- }
- @media #{$medium-only} {
- float: left;
- }
- @media #{$large-and-up} {
- float: right;
- }
-
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_tooltip.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_tooltip.scss
deleted file mode 100644
index 374ace9..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_tooltip.scss
+++ /dev/null
@@ -1,34 +0,0 @@
-.material-tooltip {
- padding: 10px 8px;
- font-size: 1rem;
- z-index: 2000;
- background-color: transparent;
- border-radius: 2px;
- color: #fff;
- min-height: 36px;
- line-height: 1rem;
- // max-width: 350px;
- opacity: 0;
- display: none;
- position: absolute;
- text-align: center;
- overflow: hidden;
- left:0;
- top:0;
-
- will-change: top, left;
-}
-
-.backdrop {
- position: absolute;
- opacity: 0;
- display: none;
- height: 7px;
- width: 14px;
- border-radius: 0 0 14px 14px;
- background-color: #323232;
- z-index: -1;
- @include transform-origin( 50% 10%);
-
- will-change: transform, opacity;
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_typography.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_typography.scss
deleted file mode 100644
index 3aec273..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_typography.scss
+++ /dev/null
@@ -1,58 +0,0 @@
-a {
- text-decoration: none;
-}
-
-html{
- line-height: 1.5;
-
- @media only screen and (min-width: 0) {
- font-size: 14px;
- }
-
- @media only screen and (min-width: $medium-screen) {
- font-size: 14.5px;
- }
-
- @media only screen and (min-width: $large-screen) {
- font-size: 15px;
- }
-
- font-family: "Roboto", sans-serif;
- font-weight: normal;
- color: $off-black;
-}
-h1, h2, h3, h4, h5, h6 {
- font-weight: 400;
- line-height: 1.1;
-}
-
-// Header Styles
-h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { font-weight: inherit; }
-h1 { font-size: $h1-fontsize; line-height: 110%; margin: ($h1-fontsize / 2) 0 ($h1-fontsize / 2.5) 0;}
-h2 { font-size: $h2-fontsize; line-height: 110%; margin: ($h2-fontsize / 2) 0 ($h2-fontsize / 2.5) 0;}
-h3 { font-size: $h3-fontsize; line-height: 110%; margin: ($h3-fontsize / 2) 0 ($h3-fontsize / 2.5) 0;}
-h4 { font-size: $h4-fontsize; line-height: 110%; margin: ($h4-fontsize / 2) 0 ($h4-fontsize / 2.5) 0;}
-h5 { font-size: $h5-fontsize; line-height: 110%; margin: ($h5-fontsize / 2) 0 ($h5-fontsize / 2.5) 0;}
-h6 { font-size: $h6-fontsize; line-height: 110%; margin: ($h6-fontsize / 2) 0 ($h6-fontsize / 2.5) 0;}
-
-// Text Styles
-em { font-style: italic; }
-strong { font-weight: 500; }
-small { font-size: 75%; }
-.light { font-weight: 300; }
-.thin { font-weight: 200; }
-
-.flow-text{
- font-weight: 300;
- $i: 0;
- @while $i <= $intervals {
- @media only screen and (min-width : 360 + ($i * $interval-size)) {
- font-size: 1.2rem * (1 + (.02 * $i));
- }
- $i: $i + 1;
- }
- // Handle below 360px screen
- @media only screen and (max-width: 360px) {
- font-size: 1.2rem;
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_variables.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_variables.scss
deleted file mode 100644
index 833d49f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_variables.scss
+++ /dev/null
@@ -1,152 +0,0 @@
-/*** Colors ***/
-$primary-color: color("materialize-red", "lighten-2") !default;
-$primary-color-light: lighten($primary-color, 15%) !default;
-$primary-color-dark: darken($primary-color, 15%) !default;
-
-$secondary-color: color("teal", "lighten-1") !default;
-$success-color: color("green", "base") !default;
-$error-color: color("red", "base") !default;
-$link-color: color("light-blue", "darken-1") !default;
-
-/*** Badges ***/
-$badge-bg-color: $secondary-color !default;
-
-/*** Buttons ***/
-$button-bg-color-disabled: #DFDFDF !default;
-$button-color: $secondary-color !default;
-$button-color-disabled: #9F9F9F !default;
-$button-color-flat: #343434 !default;
-$button-color-raised: #fff !default;
-$button-floating-size: 37px !default;
-$button-height: 36px !default;
-$button-font-size-shared: 1.3rem !default;
-$button-large-icon-font-size: 1.6rem !default;
-$button-line-height: 36px !default;
-
-/*** Cards ***/
-$card-padding: 20px !default;
-$card-bg-color: #fff !default;
-$card-link-color: color("orange", "accent-2") !default;
-$card-link-color-light: lighten($card-link-color, 20%) !default;
-
-/*** Collapsible ***/
-$collapsible-height: 3rem !default;
-$collapsible-header-color: #fff !default;
-$collapsible-border-color: #ddd !default;
-
-/*** Dropdown ***/
-$dropdown-bg-color: #fff !default;
-$dropdown-hover-bg-color: #eee !default;
-$dropdown-color: $secondary-color !default;
-
-/*** Fonts ***/
-$roboto-font-path: "../font/roboto/" !default;
-$icons-font-path: "../font/material-design-icons/" !default;
-
-/*** Forms ***/
-// Text Inputs + Textarea
-$input-border-color: color("grey", "base") !default;
-$input-bg-color: #fff !default;
-$input-error-color: $error-color !default;
-$input-success-color: $success-color !default;
-$input-focus-color: $secondary-color !default;
-$label-font-size: .8rem !default;
-$input-disabled-color: rgba(0,0,0, .26) !default;
-$input-disabled-solid-color: #BDBDBD !default;
-
-// Radio Buttons
-$radio-fill-color: $secondary-color !default;
-$radio-empty-color: #5a5a5a !default;
-
-// Switches
-$switch-bg-color: $secondary-color !default;
-$switch-checked-lever-bg: desaturate(lighten($secondary-color, 25%), 25%) !default;
-$switch-unchecked-bg: #F1F1F1 !default;
-$switch-unchecked-lever-bg: #818181 !default;
-
-// Date Picker
-$datepicker-weekday-bg: darken($secondary_color, 7%) !default;
-$datepicker-date-bg: $secondary_color !default;
-$datepicker-year: rgba(255, 255, 255, .4) !default;
-$datepicker-focus: rgba(0,0,0, .05) !default;
-$datepicker-selected: $secondary-color !default;
-$datepicker-selected-outfocus: desaturate(lighten($secondary-color, 35%), 15%) !default;
-
-
-/*** Global ***/
-// Media Query Ranges
-$small-screen-up: 601px !default;
-$medium-screen-up: 993px !default;
-$large-screen-up: 1201px !default;
-$small-screen: 600px !default;
-$medium-screen: 992px !default;
-$large-screen: 1200px !default;
-
-$medium-and-up: "only screen and (min-width : #{$small-screen-up})" !default;
-$large-and-up: "only screen and (min-width : #{$medium-screen-up})" !default;
-$small-and-down: "only screen and (max-width : #{$small-screen})" !default;
-$medium-and-down: "only screen and (max-width : #{$medium-screen})" !default;
-$medium-only: "only screen and (min-width : #{$small-screen-up}) and (max-width : #{$medium-screen})" !default;
-
-// Grid Variables
-$num-cols: 12 !default;
-$gutter-width: 1.5rem !default;
-$element-top-margin: $gutter-width/3 !default;
-$element-bottom-margin: ($gutter-width*2)/3 !default;
-
-/*** Navbar ***/
-$navbar-height: 64px !default;
-$navbar-height-mobile: 56px !default;
-$navbar-font-color: #fff !default;
-$navbar-brand-font-size: 2.1rem !default;
-
-/*** SideNav ***/
-$sidenav-bg-color: #fff !default;
-$sidenav-padding-right: 15px !default;
-
-/*** Photo Slider ***/
-$slider-bg-color: color('grey', 'base') !default;
-$slider-bg-color-light: color('grey', 'lighten-2') !default;
-$slider-indicator-color: color('green', 'base') !default;
-
-/*** Tabs ***/
-$tabs-underline-color: $primary-color-light !default;
-$tabs-text-color: $primary-color !default;
-$tabs-bg-color: #fff !default;
-
-/*** Tables ***/
-$table-border-color: #d0d0d0 !default;
-$table-striped-color: #f2f2f2 !default;
-
-/*** Toasts ***/
-$toast-height: 48px !default;
-$toast-color: #323232 !default;
-$toast-text-color: #fff !default;
-
-/*** Typography ***/
-$off-black: rgba(0, 0, 0, 0.87) !default;
-// Header Styles
-$h1-fontsize: 4.2rem !default;
-$h2-fontsize: 3.56rem !default;
-$h3-fontsize: 2.92rem !default;
-$h4-fontsize: 2.28rem !default;
-$h5-fontsize: 1.64rem !default;
-$h6-fontsize: 1rem !default;
-
-// Footer
-$footer-bg-color: $primary-color !default;
-
-// Flowtext
-$range : $large-screen - $small-screen !default;
-$intervals: 20 !default;
-$interval-size: $range / $intervals !default;
-
-/*** Collections ***/
-$collection-border-color: #e0e0e0 !default;
-$collection-bg-color: #fff !default;
-$collection-active-bg-color: $secondary-color !default;
-$collection-active-color: lighten($secondary-color, 55%) !default;
-$collection-hover-bg-color: #ddd !default;
-
-/* Progress Bar */
-$progress-bar-color: $secondary-color !default;
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_waves.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_waves.scss
deleted file mode 100644
index 7a8e8c0..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_waves.scss
+++ /dev/null
@@ -1,167 +0,0 @@
-
-/*!
- * Waves v0.6.0
- * http://fian.my.id/Waves
- *
- * Copyright 2014 Alfiana E. Sibuea and other contributors
- * Released under the MIT license
- * https://github.com/fians/Waves/blob/master/LICENSE
- */
-
-
-.waves-effect {
- position: relative;
- cursor: pointer;
- display: inline-block;
- overflow: hidden;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- -webkit-tap-highlight-color: transparent;
- // white-space: nowrap;
- // outline: 0;
-
- vertical-align: middle;
- // cursor: pointer;
- // border: none;
- // outline: none;
- // color: inherit;
- // background-color: rgba(0, 0, 0, 0);
- // font-size: 1em;
- // line-height:1em;
- // text-align: center;
- // text-decoration: none;
- z-index: 1;
- will-change: opacity, transform;
- @include transition(all .3s ease-out);
-
- .waves-ripple {
- position: absolute;
- border-radius: 50%;
- width: 20px;
- height: 20px;
- margin-top:-10px;
- margin-left:-10px;
- opacity: 0;
-
- background: rgba(0,0,0,0.2);
- // $gradient: rgba(0,0,0,0.2) 0,rgba(0,0,0,.3) 40%,rgba(0,0,0,.4) 50%,rgba(0,0,0,.5) 60%,rgba(255,255,255,0) 70%;
- // background: -webkit-radial-gradient($gradient);
- // background: -o-radial-gradient($gradient);
- // background: -moz-radial-gradient($gradient);
- // background: radial-gradient($gradient);
- @include transition(all 0.7s ease-out);
- -webkit-transition-property: -webkit-transform, opacity;
- -moz-transition-property: -moz-transform, opacity;
- -o-transition-property: -o-transform, opacity;
- transition-property: transform, opacity;
- @include transform(scale(0));
- pointer-events: none;
- }
-
- // Waves Colors
- &.waves-light .waves-ripple {
- background-color: rgba(255, 255, 255, 0.45);
- }
-
- &.waves-red .waves-ripple {
- background-color: rgba(244, 67, 54, .70);
- }
- &.waves-yellow .waves-ripple {
- background-color: rgba(255, 235, 59, .70);
- }
- &.waves-orange .waves-ripple {
- background-color: rgba(255, 152, 0, .70);
- }
- &.waves-purple .waves-ripple {
- background-color: rgba(156, 39, 176, 0.70);
- }
- &.waves-green .waves-ripple {
- background-color: rgba(76, 175, 80, 0.70);
- }
- &.waves-teal .waves-ripple {
- background-color: rgba(0, 150, 136, 0.70);
- }
-
-}
-
-.waves-notransition {
- @include transition(none #{"!important"});
-}
-
-.waves-circle {
- @include transform(translateZ(0));
- -webkit-mask-image: -webkit-radial-gradient(circle, white 100%, black 100%);
-}
-
-// .waves-button,
-// .waves-button:hover,
-// .waves-button:visited,
-// .waves-button-input {
-// white-space: nowrap;
-// vertical-align: middle;
-// cursor: pointer;
-// border: none;
-// outline: none;
-// color: inherit;
-// background-color: rgba(0, 0, 0, 0);
-// font-size: 1em;
-// line-height:1em;
-// text-align: center;
-// text-decoration: none;
-// z-index: 1;
-// }
-
-// .waves-button {
-// padding: 0.85em 1.1em;
-// border-radius: 0.2em;
-// }
-
-// .waves-button-input {
-// margin: 0;
-// padding: 0.85em 1.1em;
-// }
-
-.waves-input-wrapper {
- border-radius: 0.2em;
- vertical-align: bottom;
-
- // &.waves-button {
- // padding: 0;
- // }
-
- .waves-button-input {
- position: relative;
- top: 0;
- left: 0;
- z-index: 1;
- }
-}
-
-.waves-circle {
- text-align: center;
- width: 2.5em;
- height: 2.5em;
- line-height: 2.5em;
- border-radius: 50%;
- -webkit-mask-image: none;
-}
-
-// .waves-float {
- // -webkit-mask-image: none;
- // @include box-shadow(0px 1px 1.5px 1px rgba(0, 0, 0, 0.12));
-
- // &:active {
- // @include box-shadow(0px 8px 20px 1px rgba(0, 0, 0, 0.30));
-// }
-// }
-
-.waves-block {
- display: block;
-}
-
-/* Firefox Bug: link not triggered */
-a.waves-effect .waves-ripple {
- z-index: -1;
-} \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/date_picker/_default.date.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/date_picker/_default.date.scss
deleted file mode 100644
index 1cd0f93..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/date_picker/_default.date.scss
+++ /dev/null
@@ -1,435 +0,0 @@
-/* ==========================================================================
- $BASE-DATE-PICKER
- ========================================================================== */
-/**
- * The picker box.
- */
-.picker__box {
- padding: 0 1em;
-}
-/**
- * The header containing the month and year stuff.
- */
-.picker__header {
- text-align: center;
- position: relative;
- margin-top: .75em;
-}
-/**
- * The month and year labels.
- */
-.picker__month,
-.picker__year {
-// font-weight: 500;
- display: inline-block;
- margin-left: .25em;
- margin-right: .25em;
-}
-/**
- * The month and year selectors.
- */
-.picker__select--month,
-.picker__select--year {
-
- height: 2em;
- padding: 0;
- margin-left: .25em;
- margin-right: .25em;
-}
-
-// Modified
-.picker__select--month.browser-default {
- display: inline;
- background-color: #FFFFFF;
- width: 40%;
-}
-.picker__select--year.browser-default {
- display: inline;
- background-color: #FFFFFF;
- width: 25%;
-}
-.picker__select--month:focus,
-.picker__select--year:focus {
- border-color: $datepicker-focus;
-}
-/**
- * The month navigation buttons.
- */
-.picker__nav--prev,
-.picker__nav--next {
- position: absolute;
- padding: .5em 1.25em;
- width: 1em;
- height: 1em;
- box-sizing: content-box;
- top: -0.25em;
-}
-//@media (min-width: 24.5em) {
-// .picker__nav--prev,
-// .picker__nav--next {
-// top: -0.33em;
-// }
-//}
-.picker__nav--prev {
- left: -1em;
- padding-right: 1.25em;
-}
-//@media (min-width: 24.5em) {
-// .picker__nav--prev {
-// padding-right: 1.5em;
-// }
-//}
-.picker__nav--next {
- right: -1em;
- padding-left: 1.25em;
-}
-//@media (min-width: 24.5em) {
-// .picker__nav--next {
-// padding-left: 1.5em;
-// }
-//}
-
-.picker__nav--disabled,
-.picker__nav--disabled:hover,
-.picker__nav--disabled:before,
-.picker__nav--disabled:before:hover {
- cursor: default;
- background: none;
- border-right-color: #f5f5f5;
- border-left-color: #f5f5f5;
-}
-/**
- * The calendar table of dates
- */
-.picker__table {
- text-align: center;
- border-collapse: collapse;
- border-spacing: 0;
- table-layout: fixed;
- font-size: 1rem;
- width: 100%;
- margin-top: .75em;
- margin-bottom: .5em;
-}
-
-
-
-.picker__table th, .picker__table td {
- text-align: center;
-}
-
-
-
-
-
-
-.picker__table td {
- margin: 0;
- padding: 0;
-}
-/**
- * The weekday labels
- */
-.picker__weekday {
- width: 14.285714286%;
- font-size: .75em;
- padding-bottom: .25em;
- color: #999999;
- font-weight: 500;
- /* Increase the spacing a tad */
-}
-@media (min-height: 33.875em) {
- .picker__weekday {
- padding-bottom: .5em;
- }
-}
-/**
- * The days on the calendar
- */
-
-.picker__day--today {
- position: relative;
- color: #595959;
- letter-spacing: -.3;
- padding: .75rem 0;
- font-weight: 400;
- border: 1px solid transparent;
-
-}
-
-//.picker__day--today:before {
-// content: " ";
-// position: absolute;
-// top: 2px;
-// right: 2px;
-// width: 0;
-// height: 0;
-// border-top: 0.5em solid #0059bc;
-// border-left: .5em solid transparent;
-//}
-.picker__day--disabled:before {
- border-top-color: #aaaaaa;
-}
-
-
-.picker__day--infocus:hover{
- cursor: pointer;
- color: #000;
- font-weight: 500;
-}
-
-.picker__day--outfocus {
- display: none;
- padding: .75rem 0;
- color: #fff;
-
-}
-.picker__day--outfocus:hover {
- cursor: pointer;
- color: #dddddd;
-// background: #b1dcfb;
- font-weight: 500;
-}
-
-
-.picker__day--highlighted {
-// border-color: #0089ec;
-}
-.picker__day--highlighted:hover,
-.picker--focused .picker__day--highlighted {
- cursor: pointer;
-// color: #000000;
-// background: #b1dcfb;
-// font-weight: 500;
-}
-.picker__day--selected,
-.picker__day--selected:hover,
-.picker--focused .picker__day--selected {
-
-
-// Circle background
- border-radius: 50%;
- @include transform(scale(.75));
- background: #0089ec;
- color: #ffffff;
-}
-.picker__day--disabled,
-.picker__day--disabled:hover,
-.picker--focused .picker__day--disabled {
- background: #f5f5f5;
- border-color: #f5f5f5;
- color: #dddddd;
- cursor: default;
-}
-.picker__day--highlighted.picker__day--disabled,
-.picker__day--highlighted.picker__day--disabled:hover {
- background: #bbbbbb;
-}
-/**
- * The footer containing the "today", "clear", and "close" buttons.
- */
-.picker__footer {
- text-align: center;
- display: flex;
- align-items: center;
- justify-content: space-between;
-}
-.picker__button--today,
-.picker__button--clear,
-.picker__button--close {
- border: 1px solid #ffffff;
- background: #ffffff;
- font-size: .8em;
- padding: .66em 0;
- font-weight: bold;
- width: 33%;
- display: inline-block;
- vertical-align: bottom;
-}
-.picker__button--today:hover,
-.picker__button--clear:hover,
-.picker__button--close:hover {
- cursor: pointer;
- color: #000000;
- background: #b1dcfb;
- border-bottom-color: #b1dcfb;
-}
-.picker__button--today:focus,
-.picker__button--clear:focus,
-.picker__button--close:focus {
- background: #b1dcfb;
- border-color: $datepicker-focus;
- outline: none;
-}
-.picker__button--today:before,
-.picker__button--clear:before,
-.picker__button--close:before {
- position: relative;
- display: inline-block;
- height: 0;
-}
-.picker__button--today:before,
-.picker__button--clear:before {
- content: " ";
- margin-right: .45em;
-}
-.picker__button--today:before {
- top: -0.05em;
- width: 0;
- border-top: 0.66em solid #0059bc;
- border-left: .66em solid transparent;
-}
-.picker__button--clear:before {
- top: -0.25em;
- width: .66em;
- border-top: 3px solid #ee2200;
-}
-.picker__button--close:before {
- content: "\D7";
- top: -0.1em;
- vertical-align: top;
- font-size: 1.1em;
- margin-right: .35em;
- color: #777777;
-}
-.picker__button--today[disabled],
-.picker__button--today[disabled]:hover {
- background: #f5f5f5;
- border-color: #f5f5f5;
- color: #dddddd;
- cursor: default;
-}
-.picker__button--today[disabled]:before {
- border-top-color: #aaaaaa;
-}
-
-/* ==========================================================================
- CUSTOM MATERIALIZE STYLES
- ========================================================================== */
-.picker__box {
- border-radius: 2px;
- overflow: hidden;
-}
-
-.picker__date-display {
- text-align: center;
- background-color: $datepicker-date-bg;
- color: #fff;
- padding-bottom: 15px;
- font-weight: 300;
-}
-
-.picker__nav--prev:hover,
-.picker__nav--next:hover {
- cursor: pointer;
- color: #000000;
- background: $datepicker-selected-outfocus;
-}
-
-.picker__weekday-display {
- background-color: $datepicker-weekday-bg;
- padding: 10px;
- font-weight: 200;
- letter-spacing: .5;
- font-size: 1rem;
- margin-bottom: 15px;
-}
-
-.picker__month-display {
- text-transform: uppercase;
- font-size: 2rem;
-}
-.picker__day-display {
-
- font-size: 4.5rem;
- font-weight: 400;
-}
-.picker__year-display {
- font-size: 1.8rem;
- color: $datepicker-year;
-}
-
-.picker__box {
- padding: 0;
-}
-.picker__calendar-container {
- padding: 0 1rem;
-
- thead {
- border: none;
- }
-}
-
-// Calendar
-.picker__table {
- margin-top: 0;
- margin-bottom: .5em;
-}
-
-.picker__day--infocus {
- color: #595959;
- letter-spacing: -.3;
- padding: .75rem 0;
- font-weight: 400;
- border: 1px solid transparent;
-}
-
-//Today style
-.picker__day.picker__day--today {
- color: $datepicker-selected;
-}
-
-.picker__day.picker__day--today.picker__day--selected {
- color: #fff;
-}
-
-// Table Header
-.picker__weekday {
- font-size: .9rem;
-}
-
-
-.picker__day--selected,
-.picker__day--selected:hover,
-.picker--focused .picker__day--selected {
- // Circle background
- border-radius: 50%;
- @include transform(scale(.9));
- background-color: $datepicker-selected;
- &.picker__day--outfocus {
- background-color: $datepicker-selected-outfocus;
- }
- color: #ffffff;
-}
-
-.picker__footer {
- text-align: right;
- padding: 5px 10px;
-}
-
-// Materialize modified
-.picker__close, .picker__today {
- font-size: 1.1rem;
- padding: 0 1rem;
- color: $datepicker-selected;
-}
-
-//month nav buttons
-.picker__nav--prev:before,
-.picker__nav--next:before {
- content: " ";
- border-top: .5em solid transparent;
- border-bottom: .5em solid transparent;
- border-right: 0.75em solid #676767;
- width: 0;
- height: 0;
- display: block;
- margin: 0 auto;
-}
-.picker__nav--next:before {
- border-right: 0;
- border-left: 0.75em solid #676767;
-}
-button.picker__today:focus, button.picker__clear:focus, button.picker__close:focus {
- background-color: $datepicker-selected-outfocus;
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/date_picker/_default.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/date_picker/_default.scss
deleted file mode 100644
index d96395f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/date_picker/_default.scss
+++ /dev/null
@@ -1,201 +0,0 @@
-/* ==========================================================================
- $BASE-PICKER
- ========================================================================== */
-/**
- * Note: the root picker element should *NOT* be styled more than what's here.
- */
-.picker {
- font-size: 16px;
- text-align: left;
- line-height: 1.2;
- color: #000000;
- position: absolute;
- z-index: 10000;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-/**
- * The picker input element.
- */
-.picker__input {
- cursor: default;
-}
-/**
- * When the picker is opened, the input element is "activated".
- */
-.picker__input.picker__input--active {
- border-color: #0089ec;
-}
-/**
- * The holder is the only "scrollable" top-level container element.
- */
-.picker__holder {
- width: 100%;
- overflow-y: auto;
- -webkit-overflow-scrolling: touch;
-}
-
-/*!
- * Default mobile-first, responsive styling for pickadate.js
- * Demo: http://amsul.github.io/pickadate.js
- */
-/**
- * Note: the root picker element should *NOT* be styled more than what's here.
- */
-/**
- * Make the holder and frame fullscreen.
- */
-.picker__holder,
-.picker__frame {
- bottom: 0;
- left: 0;
- right: 0;
- top: 100%;
-}
-/**
- * The holder should overlay the entire screen.
- */
-.picker__holder {
- position: fixed;
- -webkit-transition: background 0.15s ease-out, top 0s 0.15s;
- -moz-transition: background 0.15s ease-out, top 0s 0.15s;
- transition: background 0.15s ease-out, top 0s 0.15s;
- -webkit-backface-visibility: hidden;
-}
-/**
- * The frame that bounds the box contents of the picker.
- */
-.picker__frame {
- position: absolute;
- margin: 0 auto;
- min-width: 256px;
-
-// picker width
- width: 300px;
- max-height: 350px;
-
- -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
- filter: alpha(opacity=0);
- -moz-opacity: 0;
- opacity: 0;
- -webkit-transition: all 0.15s ease-out;
- -moz-transition: all 0.15s ease-out;
- transition: all 0.15s ease-out;
-}
-@media (min-height: 28.875em) {
- .picker__frame {
- overflow: visible;
- top: auto;
- bottom: -100%;
- max-height: 80%;
- }
-}
-@media (min-height: 40.125em) {
- .picker__frame {
- margin-bottom: 7.5%;
- }
-}
-/**
- * The wrapper sets the stage to vertically align the box contents.
- */
-.picker__wrap {
- display: table;
- width: 100%;
- height: 100%;
-}
-@media (min-height: 28.875em) {
- .picker__wrap {
- display: block;
- }
-}
-/**
- * The box contains all the picker contents.
- */
-.picker__box {
- background: #ffffff;
- display: table-cell;
- vertical-align: middle;
-}
-//@media (min-height: 26.5em) {
-// .picker__box {
-//// font-size: 1.25em;
-// }
-//}
-@media (min-height: 28.875em) {
- .picker__box {
- display: block;
-
-// picker header font-size
-// font-size: 1rem;
-
- border: 1px solid #777777;
- border-top-color: #898989;
- border-bottom-width: 0;
- -webkit-border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- border-radius: 5px 5px 0 0;
- -webkit-box-shadow: 0 12px 36px 16px rgba(0, 0, 0, 0.24);
- -moz-box-shadow: 0 12px 36px 16px rgba(0, 0, 0, 0.24);
- box-shadow: 0 12px 36px 16px rgba(0, 0, 0, 0.24);
- }
-}
-//@media (min-height: 40.125em) {
-// .picker__box {
-// font-size: 1.1rem;
-// border-bottom-width: 1px;
-// -webkit-border-radius: 5px;
-// -moz-border-radius: 5px;
-// border-radius: 5px;
-// }
-//}
-/**
- * When the picker opens...
- */
-.picker--opened .picker__holder {
- top: 0;
- background: transparent;
- -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E000000,endColorstr=#1E000000)";
- zoom: 1;
- background: rgba(0, 0, 0, 0.32);
- -webkit-transition: background 0.15s ease-out;
- -moz-transition: background 0.15s ease-out;
- transition: background 0.15s ease-out;
-}
-.picker--opened .picker__frame {
- top: 0;
- -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
- filter: alpha(opacity=100);
- -moz-opacity: 1;
- opacity: 1;
-}
-@media (min-height: 35.875em) {
- .picker--opened .picker__frame {
- top: 10%;
- bottom: 20%auto;
- }
-}
-/**
- * For `large` screens, transform into an inline picker.
- */
-
-/* ==========================================================================
- CUSTOM MATERIALIZE STYLES
- ========================================================================== */
-
-.picker__input.picker__input--active {
- border-color: color("blue", "lighten-5");
-}
-
-.picker__frame {
- margin: 0 auto;
- max-width: 325px;
-}
-
-@media (min-height: 38.875em) {
- .picker--opened .picker__frame {
- top: 10%;
- bottom: auto;
- }
-} \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/date_picker/_default.time.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/date_picker/_default.time.scss
deleted file mode 100644
index 0b159c8..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/date_picker/_default.time.scss
+++ /dev/null
@@ -1,125 +0,0 @@
-/* ==========================================================================
- $BASE-TIME-PICKER
- ========================================================================== */
-/**
- * The list of times.
- */
-.picker__list {
- list-style: none;
- padding: 0.75em 0 4.2em;
- margin: 0;
-}
-/**
- * The times on the clock.
- */
-.picker__list-item {
- border-bottom: 1px solid #dddddd;
- border-top: 1px solid #dddddd;
- margin-bottom: -1px;
- position: relative;
- background: #ffffff;
- padding: .75em 1.25em;
-}
-@media (min-height: 46.75em) {
- .picker__list-item {
- padding: .5em 1em;
- }
-}
-/* Hovered time */
-.picker__list-item:hover {
- cursor: pointer;
- color: #000000;
- background: #b1dcfb;
- border-color: #0089ec;
- z-index: 10;
-}
-/* Highlighted and hovered/focused time */
-.picker__list-item--highlighted {
- border-color: #0089ec;
- z-index: 10;
-}
-.picker__list-item--highlighted:hover,
-.picker--focused .picker__list-item--highlighted {
- cursor: pointer;
- color: #000000;
- background: #b1dcfb;
-}
-/* Selected and hovered/focused time */
-.picker__list-item--selected,
-.picker__list-item--selected:hover,
-.picker--focused .picker__list-item--selected {
- background: #0089ec;
- color: #ffffff;
- z-index: 10;
-}
-/* Disabled time */
-.picker__list-item--disabled,
-.picker__list-item--disabled:hover,
-.picker--focused .picker__list-item--disabled {
- background: #f5f5f5;
- border-color: #f5f5f5;
- color: #dddddd;
- cursor: default;
- border-color: #dddddd;
- z-index: auto;
-}
-/**
- * The clear button
- */
-.picker--time .picker__button--clear {
- display: block;
- width: 80%;
- margin: 1em auto 0;
- padding: 1em 1.25em;
- background: none;
- border: 0;
- font-weight: 500;
- font-size: .67em;
- text-align: center;
- text-transform: uppercase;
- color: #666;
-}
-.picker--time .picker__button--clear:hover,
-.picker--time .picker__button--clear:focus {
- color: #000000;
- background: #b1dcfb;
- background: #ee2200;
- border-color: #ee2200;
- cursor: pointer;
- color: #ffffff;
- outline: none;
-}
-.picker--time .picker__button--clear:before {
- top: -0.25em;
- color: #666;
- font-size: 1.25em;
- font-weight: bold;
-}
-.picker--time .picker__button--clear:hover:before,
-.picker--time .picker__button--clear:focus:before {
- color: #ffffff;
-}
-
-/* ==========================================================================
- $DEFAULT-TIME-PICKER
- ========================================================================== */
-/**
- * The frame the bounds the time picker.
- */
-.picker--time .picker__frame {
- min-width: 256px;
- max-width: 320px;
-}
-/**
- * The picker box.
- */
-.picker--time .picker__box {
- font-size: 1em;
- background: #f2f2f2;
- padding: 0;
-}
-@media (min-height: 40.125em) {
- .picker--time .picker__box {
- margin-bottom: 5em;
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/materialNote.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/materialNote.scss
deleted file mode 100644
index 5faca9e..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/materialNote.scss
+++ /dev/null
@@ -1,734 +0,0 @@
-@import "components/color";
-@import "components/variables";
-
-/* variables
-=================================================================================*/
-$toolbarColor: color("grey", "lighten-2") !default;
-$toolbarTextColor: color("grey", "darken-3") !default;
-
-$borderColor: color("grey", "base") !default;
-
-$firstButtonColor: color("grey", "lighten-2") !default;
-$firstButtonHoverColor: color("grey", "base") !default;
-$secondButtonColor: color("blue", "darken-4") !default;
-$secondButtonHoverColor: color("blue", "base") !default;
-$thirdButtonColor: color("red", "darken-4") !default;
-$thirdButtonHoverColor: color("blue", "base") !default;
-
-$firstFocusColor: color("blue", "base") !default;
-$secondFocusColor: color("grey", "base") !default;
-
-$selectionColor: color("grey", "darken-1") !default;
-
-$helpBackgroundColor: color("grey", "lighten-2") !default;
-
-// base unit for table dimension picker
-$gridUnit: 26px;
-
-
-.editorDialogs .modal, .note-editor .modal {
- background-color: lighten($toolbarColor, 100%);
- color: $toolbarTextColor;
- z-index: 1057 !important;
- backface-visibility: hidden;
-
- .input-field input:not([readonly]), .input-field input.datepicker {
- border-color: $toolbarTextColor !important;
- }
- .input-field input:focus:not([readonly]), .input-field input.datepicker:focus, textarea.materialize-textarea:focus:not([readonly]) {
- box-shadow: 0 1px 0 0 $firstFocusColor !important;
- border-color: $firstFocusColor !important;
- }
- label, .input-field input:not([readonly]) + label, .input-field input.datepicker + label, .input-field .prefix, .note-editor + label {
- color: $toolbarTextColor !important;
- }
- .input-field input:focus:not([readonly]) + label, .input-field input.datepicker:focus + label, .input-field .prefix.active, textarea.materialize-textarea:focus:not([readonly]) + label {
- color: $firstFocusColor !important;
- }
-
- .btn {
- background-color: $secondButtonColor;
- color: lighten($toolbarTextColor, 100%) !important;
- }
- .btn:hover {
- background-color: lighten($secondButtonColor, 10%) !important;
- }
-
- .btn.disabled {
- background-color: darken($secondButtonColor, 15%) !important;
- }
-
- .modal-footer {
- background-color: darken($toolbarColor, 10%);
-
- .btnClose {
- margin-right: 15px;
- background-color: $thirdButtonColor;
- }
-
- .btnClose:hover {
- background-color: lighten($thirdButtonColor, 10%) !important;
- }
- }
-
- .canvasContainerEmpty {
- border: solid 5px $firstFocusColor;
- }
-}
-
-//scrollbars
-.note-editor .note-editable, .editorDialogs .modal-content, .note-editor .note-color-palette, .note-editor .note-codable, .modal.modal-fixed-footer .modal-content {
- &::-webkit-scrollbar {
- width: 17px !important;
- }
- &::-webkit-scrollbar-track {
- background-color: $toolbarColor !important;
- }
- &::-webkit-scrollbar-thumb {
- background-color: lighten($toolbarColor, 20%) !important;
- }
- &::-webkit-scrollbar-thumb:hover {
- background-color: lighten($toolbarColor, 30%) !important;
- }
-}
-
-.note-editor {
- position: relative;
- border: {
- left: 1px solid $toolbarColor;
- bottom: 1px solid $toolbarColor;
- right: 1px solid $toolbarColor;
- }
-
- .img-circle {
- border-radius: 50%;
- }
-
- .img-rounded {
- border-radius: 5%;
- }
-
- .img-thumbnail {
- border: solid 2px $toolbarColor;
- height: 200px;
- }
-
- .img-bordered {
- border: solid 5px $toolbarColor;
- }
-
- .btn:hover {
- background-color: lighten($firstButtonColor, 10%) !important;
- }
-
- .btn.active {
- background-color: $firstFocusColor;
- }
-
- .note-editable {
- ul li {
- list-style-type: square !important;
- display: list-item;
- list-style-position: inside;
- }
- }
-
- .note-dialog {
- & > div {
- display: none
- }
- .form-group {
- margin-right: 0;
- margin-left: 0
- }
- .note-modal-form {
- margin: 0
- }
- .note-image-dialog .note-dropzone {
- min-height: 100px;
- margin-bottom: 10px;
- font-size: 30px;
- line-height: 4;
- color: lightgray;
- text-align: center;
- border: 4px dashed lightgray
- }
- }
-
- .transparent {
- opacity: 0;
- }
-
- .note-resizebar {
- background-color: $toolbarColor;
- width: 100%;
- height: 13px;
- cursor: ns-resize;
- padding-top: 1px;
-
- .note-icon-bar {
- width: 20px;
- margin: 2px auto;
- border-top: 2px solid lighten($toolbarColor, 20%);
- }
- }
-
- .note-toolbar {
- position: relative;
- color: $toolbarTextColor;
- background-color: $toolbarColor;
- margin: 0;
- z-index: 1052;
-
- ul {
- padding: 0;
- }
-
- .btn.disabled, button.disabled {
- display: none;
- }
-
- .dropdown {
- cursor: pointer;
- }
-
- .note-current-fontname {
- min-width: 134px;
- display: inline-block;
- text-align: left;
- }
- }
-
- .note-handle {
- .note-control-selection {
- position: absolute;
- display: none;
- border: 2px solid $firstButtonColor;
-
- .note-control-selection-bg {
- width: 100%;
- height: 100%;
- z-index: 3;
- background-color: transparentize($selectionColor, 0.7);
- }
-
- & > div {
- position: absolute
- }
- .note-control-handle {
- width: 7px;
- height: 7px;
- border: 1px solid black;
- }
- .note-control-holder {
- width: 7px;
- height: 7px;
- border: 1px solid black;
- }
- .note-control-sizing {
- width: 15px;
- height: 15px;
- background-color: $firstButtonColor;
- z-index: 5;
- cursor: se-resize;
- }
- .note-control-nw {
- top: -5px;
- left: -5px;
- border-right: 0;
- border-bottom: 0;
- }
- .note-control-ne {
- top: -5px;
- right: -5px;
- border-bottom: 0;
- border-left: none;
- }
- .note-control-sw {
- bottom: -5px;
- left: -5px;
- border-top: 0;
- border-right: 0;
- }
- .note-control-se {
- right: -5px;
- bottom: -5px;
- }
- .note-control-selection-info {
- right: 0;
- bottom: 0;
- padding: 5px;
- margin: 17px;
- font-size: 15px;
- color: $toolbarTextColor;
- background-color: $firstButtonColor;
- z-index: 5;
- }
- }
- }
-}
-
-.note-dialog .note-help-dialog {
- color: $toolbarColor;
-
- h4 {
- color: $toolbarTextColor;
- }
-
- thead {
- background-color: $firstFocusColor;
- }
-
- tbody {
- background-color: $helpBackgroundColor;
- }
-}
-
-.note-editor, .popover {
- .btn-group {
- display: inline-block;
- margin-right: 10px;
- position: relative;
-
- ul {
- padding: 0;
- }
-
- .closeLeft {
- padding-right: 0 !important;
- margin-right: 0 !important;
-
- i {
- margin-right: 0 !important;
- }
- }
-
- i.left {
- margin-right: 5px;
- }
- }
-
- .note-toolbar .btn {
- border-radius: 0 !important;
- box-shadow: none !important;
- padding: 0 9px !important;
- background-color: $firstButtonColor;
- }
-
- .btnSecond {
- background-color: $secondButtonColor !important;
- }
-
- .btnThird {
- background-color: $thirdButtonColor !important;
- }
-
- note-toolbar button, button, .note-toolbar .btn {
- background-color: $firstButtonColor;
- border: none;
- height: 36px;
- text-transform: uppercase;
- color: $toolbarTextColor !important;
- }
-
- [type="checkbox"]:checked + label:before, [type="checkbox"]:checked + label:before {
- border-right-color: $secondButtonColor !important;
- border-bottom-color: $secondButtonColor !important;
- }
-
- .note-palette-title {
- padding: 0 !important;
- }
-
- .colorName {
- display: inline-block;
- color: $toolbarTextColor;
-
- @media #{$small-and-down} {
- display: none;
- }
- }
-
- .note-color-palette {
- line-height: 10px;
- border: solid 3px $toolbarColor;
- padding: 0 !important;
- overflow-x: scroll;
- overflow-y: hidden;
-
- .note-color-row {
- padding: 0 !important;
- min-width: 300px;
- }
-
- button.note-color-btn {
- width: 20px;
- height: 20px;
- padding: 0;
- margin: 0;
- }
-
- .note-color-btn:hover {
- &:after {
- position: absolute;
- width: 30px;
- height: 30px;
- content: "";
- background-color: inherit;
- margin-top: -15px;
- margin-left: -15px;
- }
- }
- }
-
- .note-dimension-picker {
- overflow: hidden;
- }
-
- .largeDropdown {
- width: 290px;
- }
-
- .dropdown-menu {
- z-index: 1033;
-
- &.note-check {
- min-width: 80px;
- }
-
- label {
- color: $toolbarTextColor !important;
- }
- }
-
- ul.dropdown-menu {
- position: absolute;
- top: 20px;
- background-color: lighten($toolbarColor, 10%);
- border: {
- left: 3px solid $toolbarColor;
- bottom: 3px solid $toolbarColor;
- right: 3px solid $toolbarColor;
- }
-
- &#colors {
- width: 342px;
-
- .indicator {
- width: 50%;
- left: 0;
- }
- }
-
- .colorTable {
- padding: 3px 0;
- }
-
- .tabs {
- background-color: $toolbarColor;
-
- &:hover {
- background-color: $toolbarColor;
- }
-
- .tab a, .tab a:hover {
- color: $secondFocusColor;
- }
-
- .indicator {
- background-color: $secondFocusColor;
- }
- }
-
- li {
- list-style-type: none;
- padding: 0 !important;
-
- div {
- padding: 3px 15px;
- cursor: pointer;
- }
- }
- }
-}
-
-.note-popover .popover {
- position: absolute;
- max-width: none;
- color: $toolbarTextColor;
-
- .arrow {
- width: 0;
- height: 0;
- border-style: solid;
- border-width: 0 10px 10px 10px;
- border-color: transparent transparent $firstButtonColor transparent;
- }
-
- .popover-content {
- background-color: $firstButtonColor;
-
- & > a {
- margin-left: 12px;
- }
-
- a {
- display: inline-block;
- max-width: 200px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- vertical-align: middle
- }
-
- .arrow {
- left: 20px
- }
-
- .btn-group {
- display: inline-block;
-
- .btn {
- border-radius: 0 !important;
- box-shadow: none !important;
- padding: 0 9px !important;
- background-color: $firstButtonColor;
- color: $toolbarTextColor !important;
- }
- }
- }
-}
-
-.note-popover .popover .popover-content .note-para .dropdown-menu, .note-toolbar .note-para .dropdown-menu {
- min-width: 172px;
- padding: 5px
-}
-.note-popover .popover .popover-content .note-para .dropdown-menu > div:first-child, .note-toolbar .note-para .dropdown-menu > div:first-child {
- margin-right: 5px
-}
-
-
-
-
-
-
-
-// the following is unchanged from original summernote css
-.note-editor .note-dropzone {
- position: absolute;
- z-index: 100;
- display: none;
- color: #87cefa;
- background-color: white;
- border: 2px dashed #87cefa;
- opacity: .95;
- pointer-event: none
-}
-.note-editor .note-dropzone .note-dropzone-message {
- display: table-cell;
- font-size: 28px;
- font-weight: bold;
- text-align: center;
- vertical-align: middle
-}
-.note-editor .note-dropzone.hover {
- color: #098ddf;
- border: 2px dashed #098ddf
-}
-.note-editor.dragover .note-dropzone {
- display: table
-}
-
-.note-editor.fullscreen {
- position: fixed;
- top: 0;
- left: 0;
- z-index: 2021;
- width: 100%
-}
-.note-editor.fullscreen .note-editable {
- background-color: white
-}
-.note-editor.fullscreen .note-resizebar {
- display: none
-}
-.note-editor.codeview .note-editable {
- display: none
-}
-.note-editor.codeview .note-codable {
- display: block
-}
-.note-editor .note-statusbar {
- background-color: #f5f5f5
-}
-.note-editor .note-editable[contenteditable=true]:empty:not(:focus):before {
- color: #a9a9a9;
- content: attr(data-placeholder)
-}
-.note-editor .note-editable {
- padding: 10px;
- overflow: auto;
- outline: 0
-}
-.note-editor .note-editable[contenteditable="false"] {
- background-color: #e5e5e5
-}
-.note-editor .note-codable {
- display: none;
- width: 100%;
- padding: 10px;
- margin-bottom: 0;
- font-family: Menlo, Monaco, monospace, sans-serif;
- font-size: 14px;
- color: #ccc;
- background-color: #222;
- border: 0;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
- box-shadow: none;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- -ms-box-sizing: border-box;
- box-sizing: border-box;
- resize: none
-}
-.note-air-editor {
- outline: 0
-}
-
-.note-popover .popover .popover-content,
-.note-toolbar {
- padding: 0;
- margin: 0
-}
-.note-popover .popover .popover-content > .btn-group,
-.note-toolbar > .btn-group {
- margin-top: 0;
- margin-right: 5px;
- margin-left: 0
-}
-.note-popover .popover .popover-content .btn-group .note-table,
-.note-toolbar .btn-group .note-table {
- min-width: 0;
- padding: 5px
-}
-.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker,
-.note-toolbar .btn-group .note-table .note-dimension-picker {
- font-size: 18px
-}
-.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker .note-dimension-picker-mousecatcher,
-.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-mousecatcher {
- position: absolute!important;
- z-index: 3;
- width: $gridUnit * 10;
- height:$gridUnit * 10;
- cursor: pointer
-}
-.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker .note-dimension-picker-unhighlighted,
-.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-unhighlighted {
- position: relative !important;
- z-index: 1;
- width: $gridUnit * 12;
- height: $gridUnit * 5;
- background-size: 26px 26px;
- background-image:repeating-linear-gradient(0deg, #3b3b3b, #3b3b3b 4px, transparent 4px, transparent 26px),
- repeating-linear-gradient(-90deg, transparent, transparent 4px, #fff 4px, #fff 26px);
-}
-.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker .note-dimension-picker-highlighted,
-.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-highlighted {
- position: absolute !important;
- z-index: 2;
- width: $gridUnit;
- height: $gridUnit;
- background-size: 26px 26px;
- background-image:repeating-linear-gradient(0deg, #3b3b3b, #3b3b3b 4px, transparent 4px, transparent 26px),
- repeating-linear-gradient(-90deg, transparent, transparent 4px, $firstFocusColor 4px, $firstFocusColor 26px);
-}
-
-.note-popover .popover .popover-content .note-style h1,
-.note-toolbar .note-style h1,
-.note-popover .popover .popover-content .note-style h2,
-.note-toolbar .note-style h2,
-.note-popover .popover .popover-content .note-style h3,
-.note-toolbar .note-style h3,
-.note-popover .popover .popover-content .note-style h4,
-.note-toolbar .note-style h4,
-.note-popover .popover .popover-content .note-style h5,
-.note-toolbar .note-style h5,
-.note-popover .popover .popover-content .note-style h6,
-.note-toolbar .note-style h6,
-.note-popover .popover .popover-content .note-style blockquote,
-.note-toolbar .note-style blockquote {
- margin: 0
-}
-.note-popover .popover .popover-content .note-color .dropdown-toggle,
-.note-toolbar .note-color .dropdown-toggle {
- width: 20px;
- padding-left: 5px
-}
-.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group,
-.note-toolbar .note-color .dropdown-menu .btn-group {
- margin: 0
-}
-.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group:first-child,
-.note-toolbar .note-color .dropdown-menu .btn-group:first-child {
- margin: 0 5px
-}
-.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-palette-title,
-.note-toolbar .note-color .dropdown-menu .btn-group .note-palette-title {
- margin: 2px 7px;
- font-size: 12px;
- text-align: center;
- border-bottom: 1px solid #eee
-}
-.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-reset,
-.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset {
- padding: 0 3px;
- margin: 3px;
- font-size: 11px;
- cursor: pointer;
- -webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px
-}
-.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-row,
-.note-toolbar .note-color .dropdown-menu .btn-group .note-color-row {
- height: 20px
-}
-.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-reset:hover,
-.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset:hover {
- background: #eee
-}
-/*.note-popover .popover .popover-content .dropdown-menu,
-.note-toolbar .dropdown-menu {
- min-width: 90px
-}*/
-.note-popover .popover .popover-content .dropdown-menu.right,
-.note-toolbar .dropdown-menu.right {
- right: 0;
- left: auto
-}
-.note-popover .popover .popover-content .dropdown-menu.right::before,
-.note-toolbar .dropdown-menu.right::before {
- right: 9px;
- left: auto!important
-}
-.note-popover .popover .popover-content .dropdown-menu.right::after,
-.note-toolbar .dropdown-menu.right::after {
- right: 10px;
- left: auto!important
-}
-.note-popover .popover .popover-content .dropdown-menu.note-check li a i,
-.note-toolbar .dropdown-menu.note-check li a i {
- color: deepskyblue;
- visibility: hidden
-}
-.note-popover .popover .popover-content .dropdown-menu.note-check li a.checked i,
-.note-toolbar .dropdown-menu.note-check li a.checked i {
- visibility: visible
-}
-.note-popover .popover .popover-content .note-fontsize-10,
-.note-toolbar .note-fontsize-10 {
- font-size: 10px
-} \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/materialize.scss b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/materialize.scss
deleted file mode 100644
index 4421631..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/materialize.scss
+++ /dev/null
@@ -1,38 +0,0 @@
-@charset "UTF-8";
-
-// Mixins
-@import "components/prefixer";
-@import "components/mixins";
-@import "components/color";
-
-// Variables;
-@import "components/variables";
-
-// Reset
-@import "components/normalize";
-
-// components
-@import "components/global";
-@import "components/icons-material-design";
-@import "components/grid";
-@import "components/navbar";
-@import "components/roboto";
-@import "components/typography";
-@import "components/cards";
-@import "components/toast";
-@import "components/tabs";
-@import "components/tooltip";
-@import "components/buttons";
-@import "components/dropdown";
-@import "components/waves";
-@import "components/modal";
-@import "components/collapsible";
-@import "components/materialbox";
-@import "components/form";
-@import "components/table_of_contents";
-@import "components/sideNav";
-@import "components/preloader";
-@import "components/slider";
-@import "components/date_picker/default.scss";
-@import "components/date_picker/default.date.scss";
-@import "components/date_picker/default.time.scss"; \ No newline at end of file
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/upload/backup.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/upload/backup.go
deleted file mode 100644
index 28b1b8e..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/upload/backup.go
+++ /dev/null
@@ -1,113 +0,0 @@
-package upload
-
-import (
- "archive/tar"
- "compress/gzip"
- "fmt"
- "io"
- "net/http"
- "os"
- "path/filepath"
- "time"
-)
-
-// Backup creates an archive of a project's uploads and writes it
-// to the response as a download
-func Backup(res http.ResponseWriter) error {
- ts := time.Now().Unix()
- filename := fmt.Sprintf("uploads-%d.bak.tar.gz", ts)
- tmp := os.TempDir()
- backup := filepath.Join(tmp, filename)
-
- // create uploads-{stamp}.bak.tar.gz
- f, err := os.Create(backup)
- if err != nil {
- return err
- }
-
- // loop through directory and gzip files
- // add all to uploads.bak.tar.gz tarball
- gz := gzip.NewWriter(f)
- tarball := tar.NewWriter(gz)
-
- err = filepath.Walk("uploads", func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
-
- hdr, err := tar.FileInfoHeader(info, "")
- if err != nil {
- return err
- }
-
- hdr.Name = path
-
- err = tarball.WriteHeader(hdr)
- if err != nil {
- return err
- }
-
- if !info.IsDir() {
- src, err := os.Open(path)
- if err != nil {
- return err
- }
- defer src.Close()
- _, err = io.Copy(tarball, src)
- if err != nil {
- return err
- }
-
- err = tarball.Flush()
- if err != nil {
- return err
- }
-
- err = gz.Flush()
- if err != nil {
- return err
- }
- }
-
- return nil
- })
- if err != nil {
- fmt.Println(err)
- return err
- }
-
- err = gz.Close()
- if err != nil {
- return err
- }
- err = tarball.Close()
- if err != nil {
- return err
- }
- err = f.Close()
- if err != nil {
- return err
- }
-
- // write data to response
- data, err := os.Open(backup)
- if err != nil {
- return err
- }
- defer data.Close()
- defer os.Remove(backup)
-
- disposition := `attachment; filename=%s`
- info, err := data.Stat()
- if err != nil {
- return err
- }
-
- res.Header().Set("Content-Type", "application/octet-stream")
- res.Header().Set("Content-Disposition", fmt.Sprintf(disposition, ts))
- res.Header().Set("Content-Length", fmt.Sprintf("%d", info.Size()))
-
- _, err = io.Copy(res, data)
-
- return err
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/upload/upload.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/upload/upload.go
deleted file mode 100644
index cab3bb7..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/upload/upload.go
+++ /dev/null
@@ -1,96 +0,0 @@
-package upload
-
-import (
- "fmt"
- "io"
- "net/http"
- "os"
- "path/filepath"
- "strconv"
- "time"
-
- "github.com/ponzu-cms/ponzu/system/item"
-)
-
-// StoreFiles stores file uploads at paths like /YYYY/MM/filename.ext
-func StoreFiles(req *http.Request) (map[string]string, error) {
- err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB
- if err != nil {
- return nil, err
- }
-
- ts := req.FormValue("timestamp") // timestamp in milliseconds since unix epoch
-
- if ts == "" {
- ts = fmt.Sprintf("%d", int64(time.Nanosecond)*time.Now().UnixNano()/int64(time.Millisecond)) // Unix() returns seconds since unix epoch
- }
-
- req.Form.Set("timestamp", ts)
-
- // To use for FormValue name:urlPath
- urlPaths := make(map[string]string)
-
- // get or create upload directory to save files from request
- pwd, err := os.Getwd()
- if err != nil {
- err := fmt.Errorf("Failed to locate current directory: %s", err)
- return nil, err
- }
-
- i, err := strconv.ParseInt(ts, 10, 64)
- if err != nil {
- return nil, err
- }
-
- tm := time.Unix(int64(i/1000), int64(i%1000))
-
- urlPathPrefix := "api"
- uploadDirName := "uploads"
-
- uploadDir := filepath.Join(pwd, uploadDirName, fmt.Sprintf("%d", tm.Year()), fmt.Sprintf("%02d", tm.Month()))
- err = os.MkdirAll(uploadDir, os.ModeDir|os.ModePerm)
-
- // loop over all files and save them to disk
- for name, fds := range req.MultipartForm.File {
- filename, err := item.NormalizeString(fds[0].Filename)
- if err != nil {
- return nil, err
- }
-
- src, err := fds[0].Open()
- if err != nil {
- err := fmt.Errorf("Couldn't open uploaded file: %s", err)
- return nil, err
-
- }
- defer src.Close()
-
- // check if file at path exists, if so, add timestamp to file
- absPath := filepath.Join(uploadDir, filename)
-
- if _, err := os.Stat(absPath); !os.IsNotExist(err) {
- filename = fmt.Sprintf("%d-%s", time.Now().Unix(), filename)
- absPath = filepath.Join(uploadDir, filename)
- }
-
- // save to disk (TODO: or check if S3 credentials exist, & save to cloud)
- dst, err := os.Create(absPath)
- if err != nil {
- err := fmt.Errorf("Failed to create destination file for upload: %s", err)
- return nil, err
- }
-
- // copy file from src to dst on disk
- if _, err = io.Copy(dst, src); err != nil {
- err := fmt.Errorf("Failed to copy uploaded file to destination: %s", err)
- return nil, err
- }
-
- // add name:urlPath to req.PostForm to be inserted into db
- urlPath := fmt.Sprintf("/%s/%s/%d/%02d/%s", urlPathPrefix, uploadDirName, tm.Year(), tm.Month(), filename)
-
- urlPaths[name] = urlPath
- }
-
- return urlPaths, nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/user/auth.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/user/auth.go
deleted file mode 100644
index 76c4804..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/user/auth.go
+++ /dev/null
@@ -1,145 +0,0 @@
-package user
-
-import (
- "bytes"
- crand "crypto/rand"
- "encoding/base64"
- "log"
- mrand "math/rand"
- "net/http"
- "time"
-
- "github.com/nilslice/jwt"
- "golang.org/x/crypto/bcrypt"
-)
-
-// User defines a admin user in the system
-type User struct {
- ID int `json:"id"`
- Email string `json:"email"`
- Hash string `json:"hash"`
- Salt string `json:"salt"`
-}
-
-var (
- r = mrand.New(mrand.NewSource(time.Now().Unix()))
-)
-
-// New creates a user
-func New(email, password string) (*User, error) {
- salt, err := randSalt()
- if err != nil {
- return nil, err
- }
-
- hash, err := hashPassword([]byte(password), salt)
- if err != nil {
- return nil, err
- }
-
- user := &User{
- Email: email,
- Hash: string(hash),
- Salt: base64.StdEncoding.EncodeToString(salt),
- }
-
- return user, nil
-}
-
-// Auth is HTTP middleware to ensure the request has proper token credentials
-func Auth(next http.HandlerFunc) http.HandlerFunc {
- return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
- redir := req.URL.Scheme + req.URL.Host + "/admin/login"
-
- if IsValid(req) {
- next.ServeHTTP(res, req)
- } else {
- http.Redirect(res, req, redir, http.StatusFound)
- }
- })
-}
-
-// IsValid checks if the user request is authenticated
-func IsValid(req *http.Request) bool {
- // check if token exists in cookie
- cookie, err := req.Cookie("_token")
- if err != nil {
- return false
- }
- // validate it and allow or redirect request
- token := cookie.Value
- return jwt.Passes(token)
-}
-
-// IsUser checks for consistency in email/pass combination
-func IsUser(usr *User, password string) bool {
- salt, err := base64.StdEncoding.DecodeString(usr.Salt)
- if err != nil {
- return false
- }
-
- err = checkPassword([]byte(usr.Hash), []byte(password), salt)
- if err != nil {
- log.Println("Error checking password:", err)
- return false
- }
-
- return true
-}
-
-// randSalt generates 16 * 8 bits of data for a random salt
-func randSalt() ([]byte, error) {
- buf := make([]byte, 16)
- count := len(buf)
- n, err := crand.Read(buf)
- if err != nil {
- return nil, err
- }
-
- if n != count || err != nil {
- for count > 0 {
- count--
- buf[count] = byte(r.Int31n(256))
- }
- }
-
- return buf, nil
-}
-
-// saltPassword combines the salt and password provided
-func saltPassword(password, salt []byte) ([]byte, error) {
- salted := &bytes.Buffer{}
- _, err := salted.Write(append(salt, password...))
- if err != nil {
- return nil, err
- }
-
- return salted.Bytes(), nil
-}
-
-// hashPassword encrypts the salted password using bcrypt
-func hashPassword(password, salt []byte) ([]byte, error) {
- salted, err := saltPassword(password, salt)
- if err != nil {
- return nil, err
- }
-
- hash, err := bcrypt.GenerateFromPassword(salted, 10)
- if err != nil {
- return nil, err
- }
-
- return hash, nil
-}
-
-// checkPassword compares the hash with the salted password. A nil return means
-// the password is correct, but an error could mean either the password is not
-// correct, or the salt process failed - indicated in logs
-func checkPassword(hash, password, salt []byte) error {
- salted, err := saltPassword(password, salt)
- if err != nil {
- return err
- }
-
- return bcrypt.CompareHashAndPassword(hash, salted)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/analytics/backup.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/analytics/backup.go
deleted file mode 100644
index 07b1a46..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/analytics/backup.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package analytics
-
-import (
- "fmt"
- "net/http"
- "time"
-
- "github.com/boltdb/bolt"
-)
-
-// Backup writes a snapshot of the analytics.db database to an HTTP response
-func Backup(res http.ResponseWriter) error {
- err := store.View(func(tx *bolt.Tx) error {
- ts := time.Now().Unix()
- disposition := `attachment; filename="analytics-%d.db.bak"`
-
- res.Header().Set("Content-Type", "application/octet-stream")
- res.Header().Set("Content-Disposition", fmt.Sprintf(disposition, ts))
- res.Header().Set("Content-Length", fmt.Sprintf("%d", int(tx.Size())))
-
- _, err := tx.WriteTo(res)
- return err
- })
-
- return err
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/analytics/batch.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/analytics/batch.go
deleted file mode 100644
index 68ffd65..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/analytics/batch.go
+++ /dev/null
@@ -1,98 +0,0 @@
-package analytics
-
-import (
- "encoding/json"
- "strconv"
- "time"
-
- "github.com/boltdb/bolt"
-)
-
-// batchInsert is effectively a specialized version of SetContentMulti from the
-// db package, iterating over a []apiRequest instead of []url.Values
-func batchInsert(requests chan apiRequest) error {
- var reqs []apiRequest
- batchSize := len(requestChan)
-
- for i := 0; i < batchSize; i++ {
- reqs = append(reqs, <-requestChan)
- }
-
- err := store.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucketIfNotExists([]byte("__requests"))
- if err != nil {
- return err
- }
-
- for _, apiReq := range reqs {
- // get the next available ID and convert to string
- // also set effectedID to int of ID
- id, err := b.NextSequence()
- if err != nil {
- return err
- }
- cid := strconv.FormatUint(id, 10)
-
- j, err := json.Marshal(apiReq)
- if err != nil {
- return err
- }
-
- err = b.Put([]byte(cid), j)
- if err != nil {
- return err
- }
- }
-
- return nil
-
- })
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// batchPrune takes a duration to evaluate apiRequest dates against. If any of
-// the apiRequest timestamps are before the threshold, they are removed.
-// TODO: add feature to alternatively backup old analytics to cloud
-func batchPrune(threshold time.Duration) error {
- now := time.Now()
- today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
- max := today.Add(threshold)
-
- // iterate through all request data
- err := store.Update(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("__requests"))
-
- err := b.ForEach(func(k, v []byte) error {
- var r apiRequest
- err := json.Unmarshal(v, &r)
- if err != nil {
- return err
- }
-
- // delete if timestamp is below or equal to max
- ts := time.Unix(r.Timestamp/1000, 0)
- if ts.Equal(max) || ts.Before(max) {
- err := b.Delete(k)
- if err != nil {
- return err
- }
- }
-
- return nil
- })
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return err
- }
-
- return nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/analytics/init.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/analytics/init.go
deleted file mode 100644
index caa187a..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/analytics/init.go
+++ /dev/null
@@ -1,349 +0,0 @@
-// Package analytics provides the methods to run an analytics reporting system
-// for API requests which may be useful to users for measuring access and
-// possibly identifying bad actors abusing requests.
-package analytics
-
-import (
- "encoding/json"
- "log"
- "net/http"
- "runtime"
- "strings"
- "time"
-
- "github.com/boltdb/bolt"
-)
-
-type apiRequest struct {
- URL string `json:"url"`
- Method string `json:"http_method"`
- Origin string `json:"origin"`
- Proto string `json:"http_protocol"`
- RemoteAddr string `json:"ip_address"`
- Timestamp int64 `json:"timestamp"`
- External bool `json:"external_content"`
-}
-
-type apiMetric struct {
- Date string `json:"date"`
- Total int `json:"total"`
- Unique int `json:"unique"`
-}
-
-var (
- store *bolt.DB
- requestChan chan apiRequest
-)
-
-// RANGE determines the number of days ponzu request analytics and metrics are
-// stored and displayed within the system
-const RANGE = 14
-
-// Record queues an apiRequest for metrics
-func Record(req *http.Request) {
- external := strings.Contains(req.URL.Path, "/external/")
-
- ts := int64(time.Nanosecond) * time.Now().UnixNano() / int64(time.Millisecond)
-
- r := apiRequest{
- URL: req.URL.String(),
- Method: req.Method,
- Origin: req.Header.Get("Origin"),
- Proto: req.Proto,
- RemoteAddr: req.RemoteAddr,
- Timestamp: ts,
- External: external,
- }
-
- // put r on buffered requestChan to take advantage of batch insertion in DB
- requestChan <- r
-}
-
-// Close exports the abillity to close our db file. Should be called with defer
-// after call to Init() from the same place.
-func Close() {
- err := store.Close()
- if err != nil {
- log.Println(err)
- }
-}
-
-// Init creates a db connection, initializes the db with schema and data and
-// sets up the queue/batching channel
-func Init() {
- var err error
- store, err = bolt.Open("analytics.db", 0666, nil)
- if err != nil {
- log.Fatalln(err)
- }
-
- err = store.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucketIfNotExists([]byte("__requests"))
- if err != nil {
- return err
- }
-
- _, err = tx.CreateBucketIfNotExists([]byte("__metrics"))
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- log.Fatalln("Error idempotently creating requests bucket in analytics.db:", err)
- }
-
- requestChan = make(chan apiRequest, 1024*64*runtime.NumCPU())
-
- go serve()
-
- if err != nil {
- log.Fatalln(err)
- }
-}
-
-func serve() {
- // make timer to notify select to batch request insert from requestChan
- // interval: 30 seconds
- apiRequestTimer := time.NewTicker(time.Second * 30)
-
- // make timer to notify select to remove analytics older than RANGE days
- // interval: RANGE/2 days
- // TODO: enable analytics backup service to cloud
- pruneThreshold := time.Hour * 24 * RANGE
- pruneDBTimer := time.NewTicker(pruneThreshold / 2)
-
- for {
- select {
- case <-apiRequestTimer.C:
- err := batchInsert(requestChan)
- if err != nil {
- log.Println(err)
- }
-
- case <-pruneDBTimer.C:
- err := batchPrune(pruneThreshold)
- if err != nil {
- log.Println(err)
- }
-
- case <-time.After(time.Second * 30):
- continue
- }
- }
-}
-
-// ChartData returns the map containing decoded javascript needed to chart RANGE
-// days of data by day
-func ChartData() (map[string]interface{}, error) {
- // set thresholds for today and the RANGE-1 days preceding
- times := [RANGE]time.Time{}
- dates := [RANGE]string{}
- now := time.Now()
- today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
-
- ips := [RANGE]map[string]struct{}{}
- for i := range ips {
- ips[i] = make(map[string]struct{})
- }
-
- total := [RANGE]int{}
- unique := [RANGE]int{}
-
- for i := range times {
- // subtract 24 * i hours to make days prior
- dur := time.Duration(24 * i * -1)
- day := today.Add(time.Hour * dur)
-
- // day threshold is [...n-1-i, n-1, n]
- times[len(times)-1-i] = day
- dates[len(times)-1-i] = day.Format("01/02")
- }
-
- // get api request analytics and metrics from db
- var requests = []apiRequest{}
- currentMetrics := make(map[string]apiMetric)
-
- err := store.Update(func(tx *bolt.Tx) error {
- m := tx.Bucket([]byte("__metrics"))
- b := tx.Bucket([]byte("__requests"))
-
- err := m.ForEach(func(k, v []byte) error {
- var metric apiMetric
- err := json.Unmarshal(v, &metric)
- if err != nil {
- log.Println("Error decoding api metric json from analytics db:", err)
- return nil
- }
-
- // add metric to currentMetrics map
- currentMetrics[metric.Date] = metric
-
- return nil
- })
- if err != nil {
- return err
- }
-
- err = b.ForEach(func(k, v []byte) error {
- var r apiRequest
- err := json.Unmarshal(v, &r)
- if err != nil {
- log.Println("Error decoding api request json from analytics db:", err)
- return nil
- }
-
- // append request to requests for analysis if its timestamp is today
- // or if its day is not already in cache, otherwise delete it
- d := time.Unix(r.Timestamp/1000, 0)
- _, inCache := currentMetrics[d.Format("01/02")]
- if !d.Before(today) || !inCache {
- requests = append(requests, r)
- } else {
- err := b.Delete(k)
- if err != nil {
- return err
- }
- }
-
- return nil
- })
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return nil, err
- }
-
-CHECK_REQUEST:
- for i := range requests {
- ts := time.Unix(requests[i].Timestamp/1000, 0)
-
- for j := range times {
- // if on today, there will be no next iteration to set values for
- // day prior so all valid requests belong to today
- if j == len(times)-1 {
- if ts.After(times[j]) || ts.Equal(times[j]) {
- // do all record keeping
- total[j]++
-
- if _, ok := ips[j][requests[i].RemoteAddr]; !ok {
- unique[j]++
- ips[j][requests[i].RemoteAddr] = struct{}{}
- }
-
- continue CHECK_REQUEST
- }
- }
-
- if ts.Equal(times[j]) {
- // increment total count for current time threshold (day)
- total[j]++
-
- // if no IP found for current threshold, increment unique and record IP
- if _, ok := ips[j][requests[i].RemoteAddr]; !ok {
- unique[j]++
- ips[j][requests[i].RemoteAddr] = struct{}{}
- }
-
- continue CHECK_REQUEST
- }
-
- if ts.Before(times[j]) {
- // check if older than earliest threshold
- if j == 0 {
- continue CHECK_REQUEST
- }
-
- // increment total count for previous time threshold (day)
- total[j-1]++
-
- // if no IP found for day prior, increment unique and record IP
- if _, ok := ips[j-1][requests[i].RemoteAddr]; !ok {
- unique[j-1]++
- ips[j-1][requests[i].RemoteAddr] = struct{}{}
- }
- }
- }
- }
-
- // add data to currentMetrics from total and unique
- for i := range dates {
- _, ok := currentMetrics[dates[i]]
- if !ok {
- m := apiMetric{
- Date: dates[i],
- Total: total[i],
- Unique: unique[i],
- }
-
- currentMetrics[dates[i]] = m
- }
- }
-
- // loop through total and unique to see which dates are accounted for and
- // insert data from metrics array where dates are not
- err = store.Update(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("__metrics"))
-
- for i := range dates {
- // populate total and unique with cached data if needed
- if total[i] == 0 {
- total[i] = currentMetrics[dates[i]].Total
- }
-
- if unique[i] == 0 {
- unique[i] = currentMetrics[dates[i]].Unique
- }
-
- // check if we need to insert old data into cache - as long as it
- // is not today's data
- if dates[i] != today.Format("01/02") {
- k := []byte(dates[i])
- if b.Get(k) == nil {
- // keep zero counts out of cache in case data is added from
- // other sources
- if currentMetrics[dates[i]].Total != 0 {
- v, err := json.Marshal(currentMetrics[dates[i]])
- if err != nil {
- return err
- }
-
- err = b.Put(k, v)
- if err != nil {
- return err
- }
- }
- }
- }
- }
-
- return nil
- })
- if err != nil {
- return nil, err
- }
-
- // marshal array counts to js arrays for output to chart
- jsUnique, err := json.Marshal(unique)
- if err != nil {
- return nil, err
- }
-
- jsTotal, err := json.Marshal(total)
- if err != nil {
- return nil, err
- }
-
- return map[string]interface{}{
- "dates": dates,
- "unique": string(jsUnique),
- "total": string(jsTotal),
- "from": dates[0],
- "to": dates[len(dates)-1],
- }, nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/cors.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/cors.go
deleted file mode 100644
index 249a378..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/cors.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package api
-
-import (
- "log"
- "net/http"
- "net/url"
-
- "github.com/ponzu-cms/ponzu/system/db"
-)
-
-// sendPreflight is used to respond to a cross-origin "OPTIONS" request
-func sendPreflight(res http.ResponseWriter) {
- res.Header().Set("Access-Control-Allow-Headers", "Accept, Authorization, Content-Type")
- res.Header().Set("Access-Control-Allow-Origin", "*")
- res.WriteHeader(200)
- return
-}
-
-func responseWithCORS(res http.ResponseWriter, req *http.Request) (http.ResponseWriter, bool) {
- if db.ConfigCache("cors_disabled").(bool) == true {
- // check origin matches config domain
- domain := db.ConfigCache("domain").(string)
- origin := req.Header.Get("Origin")
- u, err := url.Parse(origin)
- if err != nil {
- log.Println("Error parsing URL from request Origin header:", origin)
- return res, false
- }
-
- // hack to get dev environments to bypass cors since u.Host (below) will
- // be empty, based on Go's url.Parse function
- if domain == "localhost" {
- domain = ""
- }
- origin = u.Host
-
- // currently, this will check for exact match. will need feedback to
- // determine if subdomains should be allowed or allow multiple domains
- // in config
- if origin == domain {
- // apply limited CORS headers and return
- res.Header().Set("Access-Control-Allow-Headers", "Accept, Authorization, Content-Type")
- res.Header().Set("Access-Control-Allow-Origin", domain)
- return res, true
- }
-
- // disallow request
- res.WriteHeader(http.StatusForbidden)
- return res, false
- }
-
- // apply full CORS headers and return
- res.Header().Set("Access-Control-Allow-Headers", "Accept, Authorization, Content-Type")
- res.Header().Set("Access-Control-Allow-Origin", "*")
-
- return res, true
-}
-
-// CORS wraps a HandlerFunc to respond to OPTIONS requests properly
-func CORS(next http.HandlerFunc) http.HandlerFunc {
- return db.CacheControl(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
- res, cors := responseWithCORS(res, req)
- if !cors {
- return
- }
-
- if req.Method == http.MethodOptions {
- sendPreflight(res)
- return
- }
-
- next.ServeHTTP(res, req)
- }))
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/create.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/create.go
deleted file mode 100644
index 3328bd6..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/create.go
+++ /dev/null
@@ -1,230 +0,0 @@
-package api
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "log"
- "net/http"
- "strings"
- "time"
-
- "github.com/ponzu-cms/ponzu/system/admin/upload"
- "github.com/ponzu-cms/ponzu/system/db"
- "github.com/ponzu-cms/ponzu/system/item"
-)
-
-// Createable accepts or rejects external POST requests to endpoints such as:
-// /api/content/create?type=Review
-type Createable interface {
- // Create enables external clients to submit content of a specific type
- Create(http.ResponseWriter, *http.Request) error
-}
-
-// Trustable allows external content to be auto-approved, meaning content sent
-// as an Createable will be stored in the public content bucket
-type Trustable interface {
- AutoApprove(http.ResponseWriter, *http.Request) error
-}
-
-func createContentHandler(res http.ResponseWriter, req *http.Request) {
- if req.Method != http.MethodPost {
- res.WriteHeader(http.StatusMethodNotAllowed)
- return
- }
-
- err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB
- if err != nil {
- log.Println("[Create] error:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- t := req.URL.Query().Get("type")
- if t == "" {
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- p, found := item.Types[t]
- if !found {
- log.Println("[Create] attempt to submit unknown type:", t, "from:", req.RemoteAddr)
- res.WriteHeader(http.StatusNotFound)
- return
- }
-
- post := p()
-
- ext, ok := post.(Createable)
- if !ok {
- log.Println("[Create] rejected non-createable type:", t, "from:", req.RemoteAddr)
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- ts := fmt.Sprintf("%d", int64(time.Nanosecond)*time.Now().UnixNano()/int64(time.Millisecond))
- req.PostForm.Set("timestamp", ts)
- req.PostForm.Set("updated", ts)
-
- urlPaths, err := upload.StoreFiles(req)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- for name, urlPath := range urlPaths {
- req.PostForm.Set(name, urlPath)
- }
-
- // check for any multi-value fields (ex. checkbox fields)
- // and correctly format for db storage. Essentially, we need
- // fieldX.0: value1, fieldX.1: value2 => fieldX: []string{value1, value2}
- fieldOrderValue := make(map[string]map[string][]string)
- ordVal := make(map[string][]string)
- for k, v := range req.PostForm {
- if strings.Contains(k, ".") {
- fo := strings.Split(k, ".")
-
- // put the order and the field value into map
- field := string(fo[0])
- order := string(fo[1])
- fieldOrderValue[field] = ordVal
-
- // orderValue is 0:[?type=Thing&id=1]
- orderValue := fieldOrderValue[field]
- orderValue[order] = v
- fieldOrderValue[field] = orderValue
-
- // discard the post form value with name.N
- req.PostForm.Del(k)
- }
-
- }
-
- // add/set the key & value to the post form in order
- for f, ov := range fieldOrderValue {
- for i := 0; i < len(ov); i++ {
- position := fmt.Sprintf("%d", i)
- fieldValue := ov[position]
-
- if req.PostForm.Get(f) == "" {
- for i, fv := range fieldValue {
- if i == 0 {
- req.PostForm.Set(f, fv)
- } else {
- req.PostForm.Add(f, fv)
- }
- }
- } else {
- for _, fv := range fieldValue {
- req.PostForm.Add(f, fv)
- }
- }
- }
- }
-
- hook, ok := post.(item.Hookable)
- if !ok {
- log.Println("[Create] error: Type", t, "does not implement item.Hookable or embed item.Item.")
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- err = hook.BeforeAPICreate(res, req)
- if err != nil {
- log.Println("[Create] error calling BeforeAccept:", err)
- return
- }
-
- err = ext.Create(res, req)
- if err != nil {
- log.Println("[Create] error calling Accept:", err)
- return
- }
-
- err = hook.BeforeSave(res, req)
- if err != nil {
- log.Println("[Create] error calling BeforeSave:", err)
- return
- }
-
- // set specifier for db bucket in case content is/isn't Trustable
- var spec string
-
- // check if the content is Trustable should be auto-approved, if so the
- // content is immediately added to the public content API. If not, then it
- // is added to a "pending" list, only visible to Admins in the CMS and only
- // if the type implements editor.Mergable
- trusted, ok := post.(Trustable)
- if ok {
- err := trusted.AutoApprove(res, req)
- if err != nil {
- log.Println("[Create] error calling AutoApprove:", err)
- return
- }
- } else {
- spec = "__pending"
- }
-
- id, err := db.SetContent(t+spec+":-1", req.PostForm)
- if err != nil {
- log.Println("[Create] error calling SetContent:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- // set the target in the context so user can get saved value from db in hook
- ctx := context.WithValue(req.Context(), "target", fmt.Sprintf("%s:%d", t, id))
- req = req.WithContext(ctx)
-
- err = hook.AfterSave(res, req)
- if err != nil {
- log.Println("[Create] error calling AfterSave:", err)
- return
- }
-
- err = hook.AfterAPICreate(res, req)
- if err != nil {
- log.Println("[Create] error calling AfterAccept:", err)
- return
- }
-
- // create JSON response to send data back to client
- var data map[string]interface{}
- if spec != "" {
- spec = strings.TrimPrefix(spec, "__")
- data = map[string]interface{}{
- "status": spec,
- "type": t,
- }
- } else {
- spec = "public"
- data = map[string]interface{}{
- "id": id,
- "status": spec,
- "type": t,
- }
- }
-
- resp := map[string]interface{}{
- "data": []map[string]interface{}{
- data,
- },
- }
-
- j, err := json.Marshal(resp)
- if err != nil {
- log.Println("[Create] error marshalling response to JSON:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- res.Header().Set("Content-Type", "application/json")
- _, err = res.Write(j)
- if err != nil {
- log.Println("[Create] error writing response:", err)
- return
- }
-
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/delete.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/delete.go
deleted file mode 100644
index 36f2b1b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/delete.go
+++ /dev/null
@@ -1,140 +0,0 @@
-package api
-
-import (
- "encoding/json"
- "log"
- "net/http"
-
- "github.com/ponzu-cms/ponzu/system/db"
- "github.com/ponzu-cms/ponzu/system/item"
-)
-
-// Deleteable accepts or rejects update POST requests to endpoints such as:
-// /api/content/delete?type=Review&id=1
-type Deleteable interface {
- // Delete enables external clients to delete content of a specific type
- Delete(http.ResponseWriter, *http.Request) error
-}
-
-func deleteContentHandler(res http.ResponseWriter, req *http.Request) {
- if req.Method != http.MethodPost {
- res.WriteHeader(http.StatusMethodNotAllowed)
- return
- }
-
- err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB
- if err != nil {
- log.Println("[Delete] error:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- t := req.URL.Query().Get("type")
- if t == "" {
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- p, found := item.Types[t]
- if !found {
- log.Println("[Delete] attempt to delete content of unknown type:", t, "from:", req.RemoteAddr)
- res.WriteHeader(http.StatusNotFound)
- return
- }
-
- id := req.URL.Query().Get("id")
- if !db.IsValidID(id) {
- log.Println("[Delete] attempt to delete content with missing or invalid id from:", req.RemoteAddr)
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- post := p()
-
- ext, ok := post.(Deleteable)
- if !ok {
- log.Println("[Delete] rejected non-deleteable type:", t, "from:", req.RemoteAddr)
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- hook, ok := post.(item.Hookable)
- if !ok {
- log.Println("[Delete] error: Type", t, "does not implement item.Hookable or embed item.Item.")
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- err = hook.BeforeAPIDelete(res, req)
- if err != nil {
- log.Println("[Delete] error calling BeforeAPIDelete:", err)
- if err == ErrNoAuth {
- // BeforeAPIDelete can check user.IsValid(req) for auth
- res.WriteHeader(http.StatusUnauthorized)
- }
- return
- }
-
- err = ext.Delete(res, req)
- if err != nil {
- log.Println("[Delete] error calling Delete:", err)
- if err == ErrNoAuth {
- // Delete can check user.IsValid(req) or other forms of validation for auth
- res.WriteHeader(http.StatusUnauthorized)
- }
- return
- }
-
- err = hook.BeforeDelete(res, req)
- if err != nil {
- log.Println("[Delete] error calling BeforeSave:", err)
- return
- }
-
- err = db.DeleteContent(t + ":" + id)
- if err != nil {
- log.Println("[Delete] error calling DeleteContent:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- err = hook.AfterDelete(res, req)
- if err != nil {
- log.Println("[Delete] error calling AfterDelete:", err)
- return
- }
-
- err = hook.AfterAPIDelete(res, req)
- if err != nil {
- log.Println("[Delete] error calling AfterAPIDelete:", err)
- return
- }
-
- // create JSON response to send data back to client
- var data = map[string]interface{}{
- "id": id,
- "status": "deleted",
- "type": t,
- }
-
- resp := map[string]interface{}{
- "data": []map[string]interface{}{
- data,
- },
- }
-
- j, err := json.Marshal(resp)
- if err != nil {
- log.Println("[Delete] error marshalling response to JSON:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- res.Header().Set("Content-Type", "application/json")
- _, err = res.Write(j)
- if err != nil {
- log.Println("[Delete] error writing response:", err)
- return
- }
-
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/gzip.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/gzip.go
deleted file mode 100644
index be5a51b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/gzip.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package api
-
-import (
- "compress/gzip"
- "net/http"
- "strings"
-
- "github.com/ponzu-cms/ponzu/system/db"
-)
-
-// Gzip wraps a HandlerFunc to compress responses when possible
-func Gzip(next http.HandlerFunc) http.HandlerFunc {
- return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
- if db.ConfigCache("gzip_disabled").(bool) == true {
- next.ServeHTTP(res, req)
- return
- }
-
- // check if req header content-encoding supports gzip
- if strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") {
- // gzip response data
- res.Header().Set("Content-Encoding", "gzip")
- var gzres gzipResponseWriter
- if pusher, ok := res.(http.Pusher); ok {
- gzres = gzipResponseWriter{res, pusher, gzip.NewWriter(res)}
- } else {
- gzres = gzipResponseWriter{res, nil, gzip.NewWriter(res)}
- }
-
- next.ServeHTTP(gzres, req)
- return
- }
-
- next.ServeHTTP(res, req)
- })
-}
-
-type gzipResponseWriter struct {
- http.ResponseWriter
- pusher http.Pusher
-
- gw *gzip.Writer
-}
-
-func (gzw gzipResponseWriter) Write(p []byte) (int, error) {
- defer gzw.gw.Close()
- return gzw.gw.Write(p)
-}
-
-func (gzw gzipResponseWriter) Push(target string, opts *http.PushOptions) error {
- if gzw.pusher == nil {
- return nil
- }
-
- if opts == nil {
- opts = &http.PushOptions{
- Header: make(http.Header),
- }
- }
-
- opts.Header.Set("Accept-Encoding", "gzip")
-
- return gzw.pusher.Push(target, opts)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/handlers.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/handlers.go
deleted file mode 100644
index 83bbe43..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/handlers.go
+++ /dev/null
@@ -1,196 +0,0 @@
-package api
-
-import (
- "encoding/json"
- "errors"
- "log"
- "net/http"
- "strconv"
- "strings"
-
- "github.com/ponzu-cms/ponzu/system/db"
- "github.com/ponzu-cms/ponzu/system/item"
-)
-
-// ErrNoAuth should be used to report failed auth requests
-var ErrNoAuth = errors.New("Auth failed for request")
-
-// deprecating from API, but going to provide code here in case someone wants it
-func typesHandler(res http.ResponseWriter, req *http.Request) {
- var types = []string{}
- for t, fn := range item.Types {
- if !hide(fn(), res, req) {
- types = append(types, t)
- }
- }
-
- j, err := toJSON(types)
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- sendData(res, req, j)
-}
-
-func contentsHandler(res http.ResponseWriter, req *http.Request) {
- q := req.URL.Query()
- t := q.Get("type")
- if t == "" {
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- it, ok := item.Types[t]
- if !ok {
- res.WriteHeader(http.StatusNotFound)
- return
- }
-
- if hide(it(), res, req) {
- return
- }
-
- count, err := strconv.Atoi(q.Get("count")) // int: determines number of posts to return (10 default, -1 is all)
- if err != nil {
- if q.Get("count") == "" {
- count = 10
- } else {
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
- }
-
- offset, err := strconv.Atoi(q.Get("offset")) // int: multiplier of count for pagination (0 default)
- if err != nil {
- if q.Get("offset") == "" {
- offset = 0
- } else {
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
- }
-
- order := strings.ToLower(q.Get("order")) // string: sort order of posts by timestamp ASC / DESC (DESC default)
- if order != "asc" {
- order = "desc"
- }
-
- opts := db.QueryOptions{
- Count: count,
- Offset: offset,
- Order: order,
- }
-
- _, bb := db.Query(t+"__sorted", opts)
- var result = []json.RawMessage{}
- for i := range bb {
- result = append(result, bb[i])
- }
-
- j, err := fmtJSON(result...)
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- j, err = omit(it(), j)
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- sendData(res, req, j)
-}
-
-func contentHandler(res http.ResponseWriter, req *http.Request) {
- q := req.URL.Query()
- id := q.Get("id")
- t := q.Get("type")
- slug := q.Get("slug")
-
- if slug != "" {
- contentHandlerBySlug(res, req)
- return
- }
-
- if t == "" || id == "" {
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- pt, ok := item.Types[t]
- if !ok {
- res.WriteHeader(http.StatusNotFound)
- return
- }
-
- if hide(pt(), res, req) {
- return
- }
-
- post, err := db.Content(t + ":" + id)
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- push(res, req, pt, post)
-
- j, err := fmtJSON(json.RawMessage(post))
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- j, err = omit(pt(), j)
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- sendData(res, req, j)
-}
-
-func contentHandlerBySlug(res http.ResponseWriter, req *http.Request) {
- slug := req.URL.Query().Get("slug")
-
- if slug == "" {
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- // lookup type:id by slug key in __contentIndex
- t, post, err := db.ContentBySlug(slug)
- if err != nil {
- log.Println("Error finding content by slug:", slug, err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- it, ok := item.Types[t]
- if !ok {
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- if hide(it(), res, req) {
- return
- }
-
- push(res, req, it, post)
-
- j, err := fmtJSON(json.RawMessage(post))
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- j, err = omit(it(), j)
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- sendData(res, req, j)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/hide.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/hide.go
deleted file mode 100644
index eed2c8b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/hide.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package api
-
-import (
- "net/http"
-
- "github.com/ponzu-cms/ponzu/system/item"
-)
-
-func hide(it interface{}, res http.ResponseWriter, req *http.Request) bool {
- // check if should be hidden
- if h, ok := it.(item.Hideable); ok {
- err := h.Hide(res, req)
- if err == item.ErrAllowHiddenItem {
- return false
- }
-
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- return true
- }
-
- res.WriteHeader(http.StatusNotFound)
- return true
- }
-
- return false
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/json.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/json.go
deleted file mode 100644
index e9d448e..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/json.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package api
-
-import (
- "bytes"
- "encoding/json"
- "log"
- "net/http"
-)
-
-func fmtJSON(data ...json.RawMessage) ([]byte, error) {
- var msg = []json.RawMessage{}
- for _, d := range data {
- msg = append(msg, d)
- }
-
- resp := map[string][]json.RawMessage{
- "data": msg,
- }
-
- var buf = &bytes.Buffer{}
- enc := json.NewEncoder(buf)
- err := enc.Encode(resp)
- if err != nil {
- log.Println("Failed to encode data to JSON:", err)
- return nil, err
- }
-
- return buf.Bytes(), nil
-}
-
-func toJSON(data []string) ([]byte, error) {
- var buf = &bytes.Buffer{}
- enc := json.NewEncoder(buf)
- resp := map[string][]string{
- "data": data,
- }
-
- err := enc.Encode(resp)
- if err != nil {
- log.Println("Failed to encode data to JSON:", err)
- return nil, err
- }
-
- return buf.Bytes(), nil
-}
-
-// sendData should be used any time you want to communicate
-// data back to a foreign client
-func sendData(res http.ResponseWriter, req *http.Request, data []byte) {
- res.Header().Set("Content-Type", "application/json")
- res.Header().Set("Vary", "Accept-Encoding")
-
- _, err := res.Write(data)
- if err != nil {
- log.Println("Error writing to response in sendData")
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/omit.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/omit.go
deleted file mode 100644
index 909e3ad..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/omit.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package api
-
-import (
- "fmt"
- "log"
-
- "github.com/ponzu-cms/ponzu/system/item"
-
- "github.com/tidwall/gjson"
- "github.com/tidwall/sjson"
-)
-
-func omit(it interface{}, data []byte) ([]byte, error) {
- // is it Omittable
- om, ok := it.(item.Omittable)
- if !ok {
- return data, nil
- }
-
- return omitFields(om, data, "data")
-}
-
-func omitFields(om item.Omittable, data []byte, pathPrefix string) ([]byte, error) {
- // get fields to omit from json data
- fields := om.Omit()
-
- // remove each field from json, all responses contain json object(s) in top-level "data" array
- n := int(gjson.GetBytes(data, pathPrefix+".#").Int())
- for i := 0; i < n; i++ {
- for k := range fields {
- var err error
- data, err = sjson.DeleteBytes(data, fmt.Sprintf("%s.%d.%s", pathPrefix, i, fields[k]))
- if err != nil {
- log.Println("Erorr omitting field:", fields[k], "from item.Omittable:", om)
- return nil, err
- }
- }
- }
-
- return data, nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/push.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/push.go
deleted file mode 100644
index 2b68d5b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/push.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package api
-
-import (
- "log"
- "net/http"
-
- "github.com/ponzu-cms/ponzu/system/item"
-
- "github.com/tidwall/gjson"
- "golang.org/x/net/http2"
-)
-
-func push(res http.ResponseWriter, req *http.Request, pt func() interface{}, data []byte) {
- // Push(target string, opts *PushOptions) error
- if pusher, ok := res.(http.Pusher); ok {
- if p, ok := pt().(item.Pushable); ok {
- // get fields to pull values from data
- fields := p.Push()
-
- // parse values from data to push
- values := gjson.GetManyBytes(data, fields...)
-
- // push all values from Pushable items' fields
- for i := range values {
- val := values[i]
- val.ForEach(func(k, v gjson.Result) bool {
- if v.String() == "null" {
- return true
- }
-
- // check that the push is not to its parent URL
- if v.String() == (req.URL.Path + "?" + req.URL.RawQuery) {
- return true
- }
-
- err := pusher.Push(v.String(), nil)
- // check for error, "http2: recursive push not allowed"
- // and return, suppressing a log message
- if err != nil && err.Error() == http2.ErrRecursivePush.Error() {
- return true
- }
- if err != nil {
- log.Println("Error during Push of value:", v.String(), err)
- }
-
- return true
- })
- }
- }
- }
-
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/record.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/record.go
deleted file mode 100644
index 93d4aaf..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/record.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package api
-
-import (
- "net/http"
-
- "github.com/ponzu-cms/ponzu/system/api/analytics"
-)
-
-// Record wraps a HandlerFunc to record API requests for analytical purposes
-func Record(next http.HandlerFunc) http.HandlerFunc {
- return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
- go analytics.Record(req)
-
- next.ServeHTTP(res, req)
- })
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/search.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/search.go
deleted file mode 100644
index ae6ac1c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/search.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package api
-
-import (
- "encoding/json"
- "log"
- "net/http"
- "net/url"
-
- "github.com/ponzu-cms/ponzu/system/db"
- "github.com/ponzu-cms/ponzu/system/item"
-)
-
-func searchContentHandler(res http.ResponseWriter, req *http.Request) {
- qs := req.URL.Query()
- t := qs.Get("type")
- // type must be set, future version may compile multi-type result set
- if t == "" {
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- it, ok := item.Types[t]
- if !ok {
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- if hide(it(), res, req) {
- return
- }
-
- q, err := url.QueryUnescape(qs.Get("q"))
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- // q must be set
- if q == "" {
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- // execute search for query provided, if no index for type send 404
- matches, err := db.SearchType(t, q)
- if err == db.ErrNoSearchIndex {
- res.WriteHeader(http.StatusBadRequest)
- return
- }
- if err != nil {
- log.Println("[search] Error:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- // respond with json formatted results
- bb, err := db.ContentMulti(matches)
- if err != nil {
- log.Println("[search] Error:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- var result = []json.RawMessage{}
- for i := range bb {
- result = append(result, bb[i])
- }
-
- j, err := fmtJSON(result...)
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- j, err = omit(it(), j)
- if err != nil {
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- sendData(res, req, j)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/server.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/server.go
deleted file mode 100644
index 209ddaa..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/server.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package api
-
-import "net/http"
-
-// Run adds Handlers to default http listener for API
-func Run() {
- http.HandleFunc("/api/contents", Record(CORS(Gzip(contentsHandler))))
-
- http.HandleFunc("/api/content", Record(CORS(Gzip(contentHandler))))
-
- http.HandleFunc("/api/content/create", Record(CORS(createContentHandler)))
-
- http.HandleFunc("/api/content/update", Record(CORS(updateContentHandler)))
-
- http.HandleFunc("/api/content/delete", Record(CORS(deleteContentHandler)))
-
- http.HandleFunc("/api/search", Record(CORS(searchContentHandler)))
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/update.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/update.go
deleted file mode 100644
index 9414ab4..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/update.go
+++ /dev/null
@@ -1,224 +0,0 @@
-package api
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "log"
- "net/http"
- "strings"
- "time"
-
- "github.com/ponzu-cms/ponzu/system/admin/upload"
- "github.com/ponzu-cms/ponzu/system/db"
- "github.com/ponzu-cms/ponzu/system/item"
-)
-
-// Updateable accepts or rejects update POST requests to endpoints such as:
-// /api/content/update?type=Review&id=1
-type Updateable interface {
- // Update enabled external clients to update content of a specific type
- Update(http.ResponseWriter, *http.Request) error
-}
-
-func updateContentHandler(res http.ResponseWriter, req *http.Request) {
- if req.Method != http.MethodPost {
- res.WriteHeader(http.StatusMethodNotAllowed)
- return
- }
-
- err := req.ParseMultipartForm(1024 * 1024 * 4) // maxMemory 4MB
- if err != nil {
- log.Println("[Update] error:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- t := req.URL.Query().Get("type")
- if t == "" {
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- p, found := item.Types[t]
- if !found {
- log.Println("[Update] attempt to update content unknown type:", t, "from:", req.RemoteAddr)
- res.WriteHeader(http.StatusNotFound)
- return
- }
-
- id := req.URL.Query().Get("id")
- if !db.IsValidID(id) {
- log.Println("[Update] attempt to update content with missing or invalid id from:", req.RemoteAddr)
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- post := p()
-
- ext, ok := post.(Updateable)
- if !ok {
- log.Println("[Update] rejected non-updateable type:", t, "from:", req.RemoteAddr)
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- ts := fmt.Sprintf("%d", int64(time.Nanosecond)*time.Now().UnixNano()/int64(time.Millisecond))
- req.PostForm.Set("timestamp", ts)
- req.PostForm.Set("updated", ts)
-
- urlPaths, err := upload.StoreFiles(req)
- if err != nil {
- log.Println(err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- for name, urlPath := range urlPaths {
- req.PostForm.Set(name, urlPath)
- }
-
- // check for any multi-value fields (ex. checkbox fields)
- // and correctly format for db storage. Essentially, we need
- // fieldX.0: value1, fieldX.1: value2 => fieldX: []string{value1, value2}
- fieldOrderValue := make(map[string]map[string][]string)
- ordVal := make(map[string][]string)
- for k, v := range req.PostForm {
- if strings.Contains(k, ".") {
- fo := strings.Split(k, ".")
-
- // put the order and the field value into map
- field := string(fo[0])
- order := string(fo[1])
- fieldOrderValue[field] = ordVal
-
- // orderValue is 0:[?type=Thing&id=1]
- orderValue := fieldOrderValue[field]
- orderValue[order] = v
- fieldOrderValue[field] = orderValue
-
- // discard the post form value with name.N
- req.PostForm.Del(k)
- }
-
- }
-
- // add/set the key & value to the post form in order
- for f, ov := range fieldOrderValue {
- for i := 0; i < len(ov); i++ {
- position := fmt.Sprintf("%d", i)
- fieldValue := ov[position]
-
- if req.PostForm.Get(f) == "" {
- for i, fv := range fieldValue {
- if i == 0 {
- req.PostForm.Set(f, fv)
- } else {
- req.PostForm.Add(f, fv)
- }
- }
- } else {
- for _, fv := range fieldValue {
- req.PostForm.Add(f, fv)
- }
- }
- }
- }
-
- hook, ok := post.(item.Hookable)
- if !ok {
- log.Println("[Update] error: Type", t, "does not implement item.Hookable or embed item.Item.")
- res.WriteHeader(http.StatusBadRequest)
- return
- }
-
- err = hook.BeforeAPIUpdate(res, req)
- if err != nil {
- log.Println("[Update] error calling BeforeAPIUpdate:", err)
- if err == ErrNoAuth {
- // BeforeAPIUpdate can check user.IsValid(req) for auth
- res.WriteHeader(http.StatusUnauthorized)
- }
- return
- }
-
- err = ext.Update(res, req)
- if err != nil {
- log.Println("[Update] error calling Update:", err)
- if err == ErrNoAuth {
- // Update can check user.IsValid(req) or other forms of validation for auth
- res.WriteHeader(http.StatusUnauthorized)
- }
- return
- }
-
- err = hook.BeforeSave(res, req)
- if err != nil {
- log.Println("[Update] error calling BeforeSave:", err)
- return
- }
-
- // set specifier for db bucket in case content is/isn't Trustable
- var spec string
-
- _, err = db.UpdateContent(t+spec+":"+id, req.PostForm)
- if err != nil {
- log.Println("[Update] error calling UpdateContent:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- // set the target in the context so user can get saved value from db in hook
- ctx := context.WithValue(req.Context(), "target", fmt.Sprintf("%s:%s", t, id))
- req = req.WithContext(ctx)
-
- err = hook.AfterSave(res, req)
- if err != nil {
- log.Println("[Update] error calling AfterSave:", err)
- return
- }
-
- err = hook.AfterAPIUpdate(res, req)
- if err != nil {
- log.Println("[Update] error calling AfterAPIUpdate:", err)
- return
- }
-
- // create JSON response to send data back to client
- var data map[string]interface{}
- if spec != "" {
- spec = strings.TrimPrefix(spec, "__")
- data = map[string]interface{}{
- "status": spec,
- "type": t,
- }
- } else {
- spec = "public"
- data = map[string]interface{}{
- "id": id,
- "status": spec,
- "type": t,
- }
- }
-
- resp := map[string]interface{}{
- "data": []map[string]interface{}{
- data,
- },
- }
-
- j, err := json.Marshal(resp)
- if err != nil {
- log.Println("[Update] error marshalling response to JSON:", err)
- res.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- res.Header().Set("Content-Type", "application/json")
- _, err = res.Write(j)
- if err != nil {
- log.Println("[Update] error writing response:", err)
- return
- }
-
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/auth.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/auth.go
deleted file mode 100644
index cf1adf2..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/auth.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package system
-
-import (
- "net/http"
-
- "github.com/ponzu-cms/ponzu/system/db"
-)
-
-// BasicAuth adds HTTP Basic Auth check for requests that should implement it
-func BasicAuth(next http.HandlerFunc) http.HandlerFunc {
- return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
- u := db.ConfigCache("backup_basic_auth_user").(string)
- p := db.ConfigCache("backup_basic_auth_password").(string)
-
- if u == "" || p == "" {
- res.WriteHeader(http.StatusForbidden)
- return
- }
-
- user, password, ok := req.BasicAuth()
-
- if !ok {
- res.WriteHeader(http.StatusForbidden)
- return
- }
-
- if u != user || p != password {
- res.WriteHeader(http.StatusUnauthorized)
- return
- }
-
- next.ServeHTTP(res, req)
- })
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/addon.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/addon.go
deleted file mode 100644
index 0f63405..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/addon.go
+++ /dev/null
@@ -1,165 +0,0 @@
-package db
-
-import (
- "bytes"
- "encoding/json"
- "errors"
- "fmt"
- "log"
- "net/url"
-
- "github.com/boltdb/bolt"
- "github.com/gorilla/schema"
-)
-
-var (
- // ErrNoAddonExists indicates that there was not addon found in the db
- ErrNoAddonExists = errors.New("No addon exists.")
-)
-
-// Addon looks for an addon by its addon_reverse_dns as the key and returns
-// the []byte as json representation of an addon
-func Addon(key string) ([]byte, error) {
- buf := &bytes.Buffer{}
-
- err := store.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("__addons"))
- if b == nil {
- return bolt.ErrBucketNotFound
- }
-
- val := b.Get([]byte(key))
-
- if val == nil {
- return ErrNoAddonExists
- }
-
- _, err := buf.Write(val)
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return nil, err
- }
-
- return buf.Bytes(), nil
-}
-
-// SetAddon stores the values of an addon into the __addons bucket with a the
-// `addon_reverse_dns` field used as the key. `kind` is the interface{} type for
-// the provided addon (as in the result of calling addon.Types[id])
-func SetAddon(data url.Values, kind interface{}) error {
- dec := schema.NewDecoder()
- dec.IgnoreUnknownKeys(true)
- dec.SetAliasTag("json")
- err := dec.Decode(kind, data)
-
- v, err := json.Marshal(kind)
-
- k := data.Get("addon_reverse_dns")
- if k == "" {
- name := data.Get("addon_name")
- return fmt.Errorf(`Addon "%s" has no identifier to use as key.`, name)
- }
-
- err = store.Update(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("__addons"))
- if b == nil {
- return bolt.ErrBucketNotFound
- }
-
- err := b.Put([]byte(k), v)
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// AddonAll returns all registered addons as a [][]byte
-func AddonAll() [][]byte {
- var all [][]byte
-
- err := store.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("__addons"))
- if b == nil {
- return bolt.ErrBucketNotFound
- }
-
- err := b.ForEach(func(k, v []byte) error {
- all = append(all, v)
-
- return nil
- })
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- log.Println("Error finding addons in db with db.AddonAll:", err)
- return nil
- }
-
- return all
-}
-
-// DeleteAddon removes an addon from the db by its key, the addon_reverse_dns
-func DeleteAddon(key string) error {
- err := store.Update(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("__addons"))
- if b == nil {
- return bolt.ErrBucketNotFound
- }
-
- if err := b.Delete([]byte(key)); err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// AddonExists checks if there is an existing addon stored. The key is an the
-// value at addon_reverse_dns
-func AddonExists(key string) bool {
- var exists bool
-
- if store == nil {
- Init()
- }
-
- err := store.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucketIfNotExists([]byte("__addons"))
- if err != nil {
- return err
- }
- if b.Get([]byte(key)) == nil {
- return nil
- }
-
- exists = true
- return nil
- })
- if err != nil {
- log.Println("Error checking existence of addon with key:", key, "-", err)
- return false
- }
-
- return exists
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/backup.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/backup.go
deleted file mode 100644
index 735abe4..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/backup.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package db
-
-import (
- "fmt"
- "net/http"
- "time"
-
- "github.com/boltdb/bolt"
-)
-
-// Backup writes a snapshot of the system.db database to an HTTP response
-func Backup(res http.ResponseWriter) error {
- err := store.View(func(tx *bolt.Tx) error {
- ts := time.Now().Unix()
- disposition := `attachment; filename="system-%d.db.bak"`
-
- res.Header().Set("Content-Type", "application/octet-stream")
- res.Header().Set("Content-Disposition", fmt.Sprintf(disposition, ts))
- res.Header().Set("Content-Length", fmt.Sprintf("%d", int(tx.Size())))
-
- _, err := tx.WriteTo(res)
- return err
- })
-
- return err
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/cache.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/cache.go
deleted file mode 100644
index fbb0fd5..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/cache.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package db
-
-import (
- "encoding/base64"
- "fmt"
- "net/http"
- "strings"
- "time"
-)
-
-// CacheControl sets the default cache policy on static asset responses
-func CacheControl(next http.Handler) http.HandlerFunc {
- return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
- cacheDisabled := ConfigCache("cache_disabled").(bool)
- if cacheDisabled {
- res.Header().Add("Cache-Control", "no-cache")
- next.ServeHTTP(res, req)
- } else {
- age := int64(ConfigCache("cache_max_age").(float64))
- etag := ConfigCache("etag").(string)
- if age == 0 {
- age = DefaultMaxAge
- }
- policy := fmt.Sprintf("max-age=%d, public", age)
- res.Header().Add("ETag", etag)
- res.Header().Add("Cache-Control", policy)
-
- if match := req.Header.Get("If-None-Match"); match != "" {
- if strings.Contains(match, etag) {
- res.WriteHeader(http.StatusNotModified)
- return
- }
- }
-
- next.ServeHTTP(res, req)
- }
- })
-}
-
-// NewEtag generates a new Etag for response caching
-func NewEtag() string {
- now := fmt.Sprintf("%d", time.Now().Unix())
- etag := base64.StdEncoding.EncodeToString([]byte(now))
-
- return etag
-}
-
-// InvalidateCache sets a new Etag for http responses
-func InvalidateCache() error {
- err := PutConfig("etag", NewEtag())
- if err != nil {
- return err
- }
-
- return nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/config.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/config.go
deleted file mode 100644
index 6a409c2..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/config.go
+++ /dev/null
@@ -1,256 +0,0 @@
-package db
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "net/url"
- "strings"
-
- "github.com/ponzu-cms/ponzu/system/admin/config"
-
- "github.com/boltdb/bolt"
- "github.com/gorilla/schema"
-)
-
-const (
- // DefaultMaxAge provides a 2592000 second (30-day) cache max-age setting
- DefaultMaxAge = int64(60 * 60 * 24 * 30)
-)
-
-var configCache map[string]interface{}
-
-func init() {
- configCache = make(map[string]interface{})
-}
-
-// SetConfig sets key:value pairs in the db for configuration settings
-func SetConfig(data url.Values) error {
- var j []byte
- err := store.Update(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("__config"))
-
- // check for any multi-value fields (ex. checkbox fields)
- // and correctly format for db storage. Essentially, we need
- // fieldX.0: value1, fieldX.1: value2 => fieldX: []string{value1, value2}
- fieldOrderValue := make(map[string]map[string][]string)
- ordVal := make(map[string][]string)
- for k, v := range data {
- if strings.Contains(k, ".") {
- fo := strings.Split(k, ".")
-
- // put the order and the field value into map
- field := string(fo[0])
- order := string(fo[1])
- fieldOrderValue[field] = ordVal
-
- // orderValue is 0:[?type=Thing&id=1]
- orderValue := fieldOrderValue[field]
- orderValue[order] = v
- fieldOrderValue[field] = orderValue
-
- // discard the post form value with name.N
- data.Del(k)
- }
-
- }
-
- // add/set the key & value to the post form in order
- for f, ov := range fieldOrderValue {
- for i := 0; i < len(ov); i++ {
- position := fmt.Sprintf("%d", i)
- fieldValue := ov[position]
-
- if data.Get(f) == "" {
- for i, fv := range fieldValue {
- if i == 0 {
- data.Set(f, fv)
- } else {
- data.Add(f, fv)
- }
- }
- } else {
- for _, fv := range fieldValue {
- data.Add(f, fv)
- }
- }
- }
- }
-
- cfg := &config.Config{}
- dec := schema.NewDecoder()
- dec.SetAliasTag("json") // allows simpler struct tagging when creating a content type
- dec.IgnoreUnknownKeys(true) // will skip over form values submitted, but not in struct
- err := dec.Decode(cfg, data)
- if err != nil {
- return err
- }
-
- // check for "invalidate" value to reset the Etag
- if len(cfg.CacheInvalidate) > 0 && cfg.CacheInvalidate[0] == "invalidate" {
- cfg.Etag = NewEtag()
- cfg.CacheInvalidate = []string{}
- }
-
- j, err = json.Marshal(cfg)
- if err != nil {
- return err
- }
-
- err = b.Put([]byte("settings"), j)
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return err
- }
-
- // convert json => map[string]interface{}
- var kv map[string]interface{}
- err = json.Unmarshal(j, &kv)
- if err != nil {
- return err
- }
-
- configCache = kv
-
- return nil
-}
-
-// Config gets the value of a key in the configuration from the db
-func Config(key string) ([]byte, error) {
- kv := make(map[string]interface{})
-
- cfg, err := ConfigAll()
- if err != nil {
- return nil, err
- }
-
- if len(cfg) < 1 {
- return nil, nil
- }
-
- err = json.Unmarshal(cfg, &kv)
- if err != nil {
- return nil, err
- }
-
- return []byte(kv[key].(string)), nil
-}
-
-// ConfigAll gets the configuration from the db
-func ConfigAll() ([]byte, error) {
- val := &bytes.Buffer{}
- err := store.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("__config"))
- if b == nil {
- return fmt.Errorf("Error finding bucket: %s", "__config")
- }
- _, err := val.Write(b.Get([]byte("settings")))
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return nil, err
- }
-
- return val.Bytes(), nil
-}
-
-// PutConfig updates a single k/v in the config
-func PutConfig(key string, value interface{}) error {
- kv := make(map[string]interface{})
-
- c, err := ConfigAll()
- if err != nil {
- return err
- }
-
- if c == nil {
- c, err = emptyConfig()
- if err != nil {
- return err
- }
- }
-
- err = json.Unmarshal(c, &kv)
- if err != nil {
- return err
- }
-
- // set k/v from params to decoded map
- kv[key] = value
-
- data := make(url.Values)
- for k, v := range kv {
- switch v.(type) {
- case string:
- data.Set(k, v.(string))
-
- case []string:
- vv := v.([]string)
- for i := range vv {
- data.Add(k, vv[i])
- }
-
- default:
- data.Set(k, fmt.Sprintf("%v", v))
- }
- }
-
- err = SetConfig(data)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// ConfigCache is a in-memory cache of the Configs for quicker lookups
-// 'key' is the JSON tag associated with the config field
-func ConfigCache(key string) interface{} {
- return configCache[key]
-}
-
-// LoadCacheConfig loads the config into a cache to be accessed by ConfigCache()
-func LoadCacheConfig() error {
- c, err := ConfigAll()
- if err != nil {
- return err
- }
-
- if c == nil {
- c, err = emptyConfig()
- if err != nil {
- return err
- }
- }
-
- // convert json => map[string]interface{}
- var kv map[string]interface{}
- err = json.Unmarshal(c, &kv)
- if err != nil {
- return err
- }
-
- configCache = kv
-
- return nil
-}
-
-func emptyConfig() ([]byte, error) {
- cfg := &config.Config{}
-
- data, err := json.Marshal(cfg)
- if err != nil {
- return nil, err
- }
-
- return data, nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/content.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/content.go
deleted file mode 100644
index 49cba87..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/content.go
+++ /dev/null
@@ -1,722 +0,0 @@
-package db
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "log"
- "net/url"
- "sort"
- "strconv"
- "strings"
-
- "github.com/ponzu-cms/ponzu/system/item"
-
- "github.com/boltdb/bolt"
- "github.com/gorilla/schema"
- uuid "github.com/satori/go.uuid"
-)
-
-// IsValidID checks that an ID from a DB target is valid.
-// ID should be an integer greater than 0.
-// ID of -1 is special for new posts, not updates.
-// IDs start at 1 for auto-incrementing
-func IsValidID(id string) bool {
- if i, err := strconv.Atoi(id); err != nil || i < 1 {
- return false
- }
- return true
-}
-
-// SetContent inserts/replaces values in the database.
-// The `target` argument is a string made up of namespace:id (string:int)
-func SetContent(target string, data url.Values) (int, error) {
- t := strings.Split(target, ":")
- ns, id := t[0], t[1]
-
- // check if content id == -1 (indicating new post).
- // if so, run an insert which will assign the next auto incremented int.
- // this is done because boltdb begins its bucket auto increment value at 0,
- // which is the zero-value of an int in the Item struct field for ID.
- // this is a problem when the original first post (with auto ID = 0) gets
- // overwritten by any new post, originally having no ID, defauting to 0.
- if id == "-1" {
- return insert(ns, data)
- }
-
- return update(ns, id, data, nil)
-}
-
-// UpdateContent updates/merges values in the database.
-// The `target` argument is a string made up of namespace:id (string:int)
-func UpdateContent(target string, data url.Values) (int, error) {
- t := strings.Split(target, ":")
- ns, id := t[0], t[1]
-
- if !IsValidID(id) {
- return 0, fmt.Errorf("Invalid ID in target for UpdateContent: %s", target)
- }
-
- // retrieve existing content from the database
- existingContent, err := Content(target)
- if err != nil {
- return 0, err
- }
- return update(ns, id, data, &existingContent)
-}
-
-// update can support merge or replace behavior depending on existingContent.
-// if existingContent is non-nil, we merge field values. empty/missing fields are ignored.
-// if existingContent is nil, we replace field values. empty/missing fields are reset.
-func update(ns, id string, data url.Values, existingContent *[]byte) (int, error) {
- var specifier string // i.e. __pending, __sorted, etc.
- if strings.Contains(ns, "__") {
- spec := strings.Split(ns, "__")
- ns = spec[0]
- specifier = "__" + spec[1]
- }
-
- cid, err := strconv.Atoi(id)
- if err != nil {
- return 0, err
- }
-
- var j []byte
- if existingContent == nil {
- j, err = postToJSON(ns, data)
- if err != nil {
- return 0, err
- }
- } else {
- j, err = mergeData(ns, data, *existingContent)
- if err != nil {
- return 0, err
- }
- }
-
- err = store.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucketIfNotExists([]byte(ns + specifier))
- if err != nil {
- return err
- }
-
- err = b.Put([]byte(fmt.Sprintf("%d", cid)), j)
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return 0, nil
- }
-
- if specifier == "" {
- go SortContent(ns)
- }
-
- // update changes data, so invalidate client caching
- err = InvalidateCache()
- if err != nil {
- return 0, err
- }
-
- go func() {
- // update data in search index
- target := fmt.Sprintf("%s:%s", ns, id)
- err = UpdateSearchIndex(target, string(j))
- if err != nil {
- log.Println("[search] UpdateSearchIndex Error:", err)
- }
- }()
-
- return cid, nil
-}
-
-func mergeData(ns string, data url.Values, existingContent []byte) ([]byte, error) {
- var j []byte
- t, ok := item.Types[ns]
- if !ok {
- return nil, fmt.Errorf("Namespace type not found: %s", ns)
- }
-
- // Unmarsal the existing values
- s := t()
- err := json.Unmarshal(existingContent, &s)
- if err != nil {
- log.Println("Error decoding json while updating", ns, ":", err)
- return j, err
- }
-
- // Don't allow the Item fields to be updated from form values
- data.Del("id")
- data.Del("uuid")
- data.Del("slug")
-
- dec := schema.NewDecoder()
- dec.SetAliasTag("json") // allows simpler struct tagging when creating a content type
- dec.IgnoreUnknownKeys(true) // will skip over form values submitted, but not in struct
- err = dec.Decode(s, data)
- if err != nil {
- return j, err
- }
-
- j, err = json.Marshal(s)
- if err != nil {
- return j, err
- }
-
- return j, nil
-}
-
-func insert(ns string, data url.Values) (int, error) {
- var effectedID int
- var specifier string // i.e. __pending, __sorted, etc.
- if strings.Contains(ns, "__") {
- spec := strings.Split(ns, "__")
- ns = spec[0]
- specifier = "__" + spec[1]
- }
-
- var j []byte
- var cid string
- err := store.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucketIfNotExists([]byte(ns + specifier))
- if err != nil {
- return err
- }
-
- // get the next available ID and convert to string
- // also set effectedID to int of ID
- id, err := b.NextSequence()
- if err != nil {
- return err
- }
- cid = strconv.FormatUint(id, 10)
- effectedID, err = strconv.Atoi(cid)
- if err != nil {
- return err
- }
- data.Set("id", cid)
-
- // add UUID to data for use in embedded Item
- uid := uuid.NewV4()
- data.Set("uuid", uid.String())
-
- // if type has a specifier, add it to data for downstream processing
- if specifier != "" {
- data.Set("__specifier", specifier)
- }
-
- j, err = postToJSON(ns, data)
- if err != nil {
- return err
- }
-
- err = b.Put([]byte(cid), j)
- if err != nil {
- return err
- }
-
- // store the slug,type:id in contentIndex if public content
- if specifier == "" {
- ci := tx.Bucket([]byte("__contentIndex"))
- if ci == nil {
- return bolt.ErrBucketNotFound
- }
-
- k := []byte(data.Get("slug"))
- v := []byte(fmt.Sprintf("%s:%d", ns, effectedID))
- err := ci.Put(k, v)
- if err != nil {
- return err
- }
- }
-
- return nil
- })
- if err != nil {
- return 0, err
- }
-
- if specifier == "" {
- go SortContent(ns)
- }
-
- // insert changes data, so invalidate client caching
- err = InvalidateCache()
- if err != nil {
- return 0, err
- }
-
- go func() {
- // add data to seach index
- target := fmt.Sprintf("%s:%s", ns, cid)
- err = UpdateSearchIndex(target, string(j))
- if err != nil {
- log.Println("[search] UpdateSearchIndex Error:", err)
- }
- }()
-
- return effectedID, nil
-}
-
-// DeleteContent removes an item from the database. Deleting a non-existent item
-// will return a nil error.
-func DeleteContent(target string) error {
- t := strings.Split(target, ":")
- ns, id := t[0], t[1]
-
- b, err := Content(target)
- if err != nil {
- return err
- }
-
- // get content slug to delete from __contentIndex if it exists
- // this way content added later can use slugs even if previously
- // deleted content had used one
- var itm item.Item
- err = json.Unmarshal(b, &itm)
- if err != nil {
- return err
- }
-
- err = store.Update(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte(ns))
- if b == nil {
- return bolt.ErrBucketNotFound
- }
-
- err := b.Delete([]byte(id))
- if err != nil {
- return err
- }
-
- // if content has a slug, also delete it from __contentIndex
- if itm.Slug != "" {
- ci := tx.Bucket([]byte("__contentIndex"))
- if ci == nil {
- return bolt.ErrBucketNotFound
- }
-
- err := ci.Delete([]byte(itm.Slug))
- if err != nil {
- return err
- }
- }
-
- return nil
- })
- if err != nil {
- return err
- }
-
- // delete changes data, so invalidate client caching
- err = InvalidateCache()
- if err != nil {
- return err
- }
-
- go func() {
- // delete indexed data from search index
- if !strings.Contains(ns, "__") {
- target = fmt.Sprintf("%s:%s", ns, id)
- err = DeleteSearchIndex(target)
- if err != nil {
- log.Println("[search] DeleteSearchIndex Error:", err)
- }
- }
- }()
-
- // exception to typical "run in goroutine" pattern:
- // we want to have an updated admin view as soon as this is deleted, so
- // in some cases, the delete and redirect is faster than the sort,
- // thus still showing a deleted post in the admin view.
- SortContent(ns)
-
- return nil
-}
-
-// Content retrives one item from the database. Non-existent values will return an empty []byte
-// The `target` argument is a string made up of namespace:id (string:int)
-func Content(target string) ([]byte, error) {
- t := strings.Split(target, ":")
- ns, id := t[0], t[1]
-
- val := &bytes.Buffer{}
- err := store.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte(ns))
- if b == nil {
- return bolt.ErrBucketNotFound
- }
-
- _, err := val.Write(b.Get([]byte(id)))
- if err != nil {
- log.Println(err)
- return err
- }
-
- return nil
- })
- if err != nil {
- return nil, err
- }
-
- return val.Bytes(), nil
-}
-
-// ContentMulti returns a set of content based on the the targets / identifiers
-// provided in Ponzu target string format: Type:ID
-// NOTE: All targets should be of the same type
-func ContentMulti(targets []string) ([][]byte, error) {
- var contents [][]byte
- for i := range targets {
- b, err := Content(targets[i])
- if err != nil {
- return nil, err
- }
-
- contents = append(contents, b)
- }
-
- return contents, nil
-}
-
-// ContentBySlug does a lookup in the content index to find the type and id of
-// the requested content. Subsequently, issues the lookup in the type bucket and
-// returns the the type and data at that ID or nil if nothing exists.
-func ContentBySlug(slug string) (string, []byte, error) {
- val := &bytes.Buffer{}
- var t, id string
- err := store.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("__contentIndex"))
- if b == nil {
- return bolt.ErrBucketNotFound
- }
- idx := b.Get([]byte(slug))
-
- if idx != nil {
- tid := strings.Split(string(idx), ":")
-
- if len(tid) < 2 {
- return fmt.Errorf("Bad data in content index for slug: %s", slug)
- }
-
- t, id = tid[0], tid[1]
- }
-
- c := tx.Bucket([]byte(t))
- if c == nil {
- return bolt.ErrBucketNotFound
- }
- _, err := val.Write(c.Get([]byte(id)))
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return t, nil, err
- }
-
- return t, val.Bytes(), nil
-}
-
-// ContentAll retrives all items from the database within the provided namespace
-func ContentAll(namespace string) [][]byte {
- var posts [][]byte
- store.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte(namespace))
- if b == nil {
- return bolt.ErrBucketNotFound
- }
-
- numKeys := b.Stats().KeyN
- posts = make([][]byte, 0, numKeys)
-
- b.ForEach(func(k, v []byte) error {
- posts = append(posts, v)
-
- return nil
- })
-
- return nil
- })
-
- return posts
-}
-
-// QueryOptions holds options for a query
-type QueryOptions struct {
- Count int
- Offset int
- Order string
-}
-
-// Query retrieves a set of content from the db based on options
-// and returns the total number of content in the namespace and the content
-func Query(namespace string, opts QueryOptions) (int, [][]byte) {
- var posts [][]byte
- var total int
-
- // correct bad input rather than return nil or error
- // similar to default case for opts.Order switch below
- if opts.Count < 0 {
- opts.Count = -1
- }
-
- if opts.Offset < 0 {
- opts.Offset = 0
- }
-
- store.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte(namespace))
- if b == nil {
- return bolt.ErrBucketNotFound
- }
-
- c := b.Cursor()
- n := b.Stats().KeyN
- total = n
-
- // return nil if no content
- if n == 0 {
- return nil
- }
-
- var start, end int
- switch opts.Count {
- case -1:
- start = 0
- end = n
-
- default:
- start = opts.Count * opts.Offset
- end = start + opts.Count
- }
-
- // bounds check on posts given the start & end count
- if start > n {
- start = n - opts.Count
- }
- if end > n {
- end = n
- }
-
- i := 0 // count of num posts added
- cur := 0 // count of num cursor moves
- switch opts.Order {
- case "desc", "":
- for k, v := c.Last(); k != nil; k, v = c.Prev() {
- if cur < start {
- cur++
- continue
- }
-
- if cur >= end {
- break
- }
-
- posts = append(posts, v)
- i++
- cur++
- }
-
- case "asc":
- for k, v := c.First(); k != nil; k, v = c.Next() {
- if cur < start {
- cur++
- continue
- }
-
- if cur >= end {
- break
- }
-
- posts = append(posts, v)
- i++
- cur++
- }
-
- default:
- // results for DESC order
- for k, v := c.Last(); k != nil; k, v = c.Prev() {
- if cur < start {
- cur++
- continue
- }
-
- if cur >= end {
- break
- }
-
- posts = append(posts, v)
- i++
- cur++
- }
- }
-
- return nil
- })
-
- return total, posts
-}
-
-// SortContent sorts all content of the type supplied as the namespace by time,
-// in descending order, from most recent to least recent
-// Should be called from a goroutine after SetContent is successful
-func SortContent(namespace string) {
- // only sort main content types i.e. Post
- if strings.Contains(namespace, "__") {
- return
- }
-
- all := ContentAll(namespace)
-
- var posts sortableContent
- // decode each (json) into type to then sort
- for i := range all {
- j := all[i]
- post := item.Types[namespace]()
-
- err := json.Unmarshal(j, &post)
- if err != nil {
- log.Println("Error decoding json while sorting", namespace, ":", err)
- return
- }
-
- posts = append(posts, post.(item.Sortable))
- }
-
- // sort posts
- sort.Sort(posts)
-
- // marshal posts to json
- var bb [][]byte
- for i := range posts {
- j, err := json.Marshal(posts[i])
- if err != nil {
- // log error and kill sort so __sorted is not in invalid state
- log.Println("Error marshal post to json in SortContent:", err)
- return
- }
-
- bb = append(bb, j)
- }
-
- // store in <namespace>_sorted bucket, first delete existing
- err := store.Update(func(tx *bolt.Tx) error {
- bname := []byte(namespace + "__sorted")
- err := tx.DeleteBucket(bname)
- if err != nil && err != bolt.ErrBucketNotFound {
- return err
- }
-
- b, err := tx.CreateBucketIfNotExists(bname)
- if err != nil {
- return err
- }
-
- // encode to json and store as 'post.Time():i':post
- for i := range bb {
- cid := fmt.Sprintf("%d:%d", posts[i].Time(), i)
- err = b.Put([]byte(cid), bb[i])
- if err != nil {
- return err
- }
- }
-
- return nil
- })
- if err != nil {
- log.Println("Error while updating db with sorted", namespace, err)
- }
-
-}
-
-type sortableContent []item.Sortable
-
-func (s sortableContent) Len() int {
- return len(s)
-}
-
-func (s sortableContent) Less(i, j int) bool {
- return s[i].Time() > s[j].Time()
-}
-
-func (s sortableContent) Swap(i, j int) {
- s[i], s[j] = s[j], s[i]
-}
-
-func postToJSON(ns string, data url.Values) ([]byte, error) {
- // find the content type and decode values into it
- t, ok := item.Types[ns]
- if !ok {
- return nil, fmt.Errorf(item.ErrTypeNotRegistered.Error(), ns)
- }
- post := t()
-
- dec := schema.NewDecoder()
- dec.SetAliasTag("json") // allows simpler struct tagging when creating a content type
- dec.IgnoreUnknownKeys(true) // will skip over form values submitted, but not in struct
- err := dec.Decode(post, data)
- if err != nil {
- return nil, err
- }
-
- // if the content has no slug, and has no specifier, create a slug, check it
- // for duplicates, and add it to our values
- if data.Get("slug") == "" && data.Get("__specifier") == "" {
- slug, err := item.Slug(post.(item.Identifiable))
- if err != nil {
- return nil, err
- }
-
- slug, err = checkSlugForDuplicate(slug)
- if err != nil {
- return nil, err
- }
-
- post.(item.Sluggable).SetSlug(slug)
- data.Set("slug", slug)
- }
-
- // marshall content struct to json for db storage
- j, err := json.Marshal(post)
- if err != nil {
- return nil, err
- }
-
- return j, nil
-}
-
-func checkSlugForDuplicate(slug string) (string, error) {
- // check for existing slug in __contentIndex
- err := store.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("__contentIndex"))
- if b == nil {
- return bolt.ErrBucketNotFound
- }
- original := slug
- exists := true
- i := 0
- for exists {
- s := b.Get([]byte(slug))
- if s == nil {
- exists = false
- return nil
- }
-
- i++
- slug = fmt.Sprintf("%s-%d", original, i)
- }
-
- return nil
- })
- if err != nil {
- return "", err
- }
-
- return slug, nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/index.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/index.go
deleted file mode 100644
index 6a2727a..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/index.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package db
-
-import (
- "bytes"
- "encoding/json"
-
- "github.com/boltdb/bolt"
-)
-
-// Index gets the value from the namespace at the key provided
-func Index(namespace, key string) ([]byte, error) {
- val := &bytes.Buffer{}
- err := store.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte(index(namespace)))
- if b == nil {
- return nil
- }
-
- v := b.Get([]byte(key))
-
- _, err := val.Write(v)
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return nil, err
- }
-
- return val.Bytes(), nil
-}
-
-// SetIndex sets a key/value pair within the namespace provided and will return
-// an error if it fails
-func SetIndex(namespace, key string, value interface{}) error {
- return store.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucketIfNotExists([]byte(index(namespace)))
- if err != nil {
- return err
- }
-
- val, err := json.Marshal(value)
- if err != nil {
- return err
- }
-
- return b.Put([]byte(key), val)
- })
-}
-
-// DeleteIndex removes the key and value from the namespace provided and will
-// return an error if it fails. It will return nil if there was no key/value in
-// the index to delete.
-func DeleteIndex(namespace, key string) error {
- return store.Update(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte(index(namespace)))
- if b == nil {
- return nil
- }
-
- return b.Delete([]byte(key))
- })
-}
-
-// DropIndex removes the index and all key/value pairs in the namespace index
-func DropIndex(namespace string) error {
- return store.Update(func(tx *bolt.Tx) error {
- err := tx.DeleteBucket([]byte(index(namespace)))
- if err == bolt.ErrBucketNotFound {
- return nil
- }
-
- if err != nil {
- return err
- }
-
- return nil
- })
-}
-
-func index(namespace string) string {
- return "__index_" + namespace
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/init.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/init.go
deleted file mode 100644
index 4e9c3cf..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/init.go
+++ /dev/null
@@ -1,121 +0,0 @@
-package db
-
-import (
- "log"
-
- "github.com/ponzu-cms/ponzu/system/item"
-
- "github.com/boltdb/bolt"
- "github.com/nilslice/jwt"
-)
-
-var store *bolt.DB
-
-// Close exports the abillity to close our db file. Should be called with defer
-// after call to Init() from the same place.
-func Close() {
- err := store.Close()
- if err != nil {
- log.Println(err)
- }
-}
-
-// Init creates a db connection, initializes db with required info, sets secrets
-func Init() {
- if store != nil {
- return
- }
-
- var err error
- store, err = bolt.Open("system.db", 0666, nil)
- if err != nil {
- log.Fatalln(err)
- }
-
- err = store.Update(func(tx *bolt.Tx) error {
- // initialize db with all content type buckets & sorted bucket for type
- for t := range item.Types {
- _, err := tx.CreateBucketIfNotExists([]byte(t))
- if err != nil {
- return err
- }
-
- _, err = tx.CreateBucketIfNotExists([]byte(t + "__sorted"))
- if err != nil {
- return err
- }
- }
-
- // init db with other buckets as needed
- buckets := []string{"__config", "__users", "__contentIndex", "__addons"}
- for _, name := range buckets {
- _, err := tx.CreateBucketIfNotExists([]byte(name))
- if err != nil {
- return err
- }
- }
-
- return nil
- })
- if err != nil {
- log.Fatalln("Coudn't initialize db with buckets.", err)
- }
-
- err = LoadCacheConfig()
- if err != nil {
- log.Fatalln("Failed to load config cache.", err)
- }
-
- clientSecret := ConfigCache("client_secret").(string)
-
- if clientSecret != "" {
- jwt.Secret([]byte(clientSecret))
- }
-
- // invalidate cache on system start
- err = InvalidateCache()
- if err != nil {
- log.Fatalln("Failed to invalidate cache.", err)
- }
-
- go func() {
- for t := range item.Types {
- err := MapSearchIndex(t)
- if err != nil {
- log.Fatalln(err)
- return
- }
-
- SortContent(t)
- }
- }()
-}
-
-// SystemInitComplete checks if there is at least 1 admin user in the db which
-// would indicate that the system has been configured to the minimum required.
-func SystemInitComplete() bool {
- complete := false
-
- err := store.View(func(tx *bolt.Tx) error {
- users := tx.Bucket([]byte("__users"))
- if users == nil {
- return bolt.ErrBucketNotFound
- }
-
- err := users.ForEach(func(k, v []byte) error {
- complete = true
- return nil
- })
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- complete = false
- log.Fatalln(err)
- }
-
- return complete
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/search.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/search.go
deleted file mode 100644
index 3e7a9d6..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/search.go
+++ /dev/null
@@ -1,145 +0,0 @@
-package db
-
-import (
- "errors"
- "fmt"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/ponzu-cms/ponzu/system/item"
-
- "github.com/blevesearch/bleve"
- "github.com/blevesearch/bleve/mapping"
-)
-
-var (
- // Search tracks all search indices to use throughout system
- Search map[string]bleve.Index
-
- // ErrNoSearchIndex is for failed checks for an index in Search map
- ErrNoSearchIndex = errors.New("No search index found for type provided")
-)
-
-// Searchable ...
-type Searchable interface {
- SearchMapping() (*mapping.IndexMappingImpl, error)
-}
-
-func init() {
- Search = make(map[string]bleve.Index)
-}
-
-// MapSearchIndex creates the mapping for a type and tracks the index to be used within
-// the system for adding/deleting/checking data
-func MapSearchIndex(typeName string) error {
- // type assert for Searchable, get configuration (which can be overridden)
- // by Ponzu user if defines own SearchMapping()
- it, ok := item.Types[typeName]
- if !ok {
- return fmt.Errorf("[search] MapSearchIndex Error: Failed to MapIndex for %s, type doesn't exist", typeName)
- }
- s, ok := it().(Searchable)
- if !ok {
- return fmt.Errorf("[search] MapSearchIndex Error: Item type %s doesn't implement db.Searchable", typeName)
- }
-
- mapping, err := s.SearchMapping()
- if err == item.ErrNoSearchMapping {
- return nil
- }
- if err != nil {
- return err
- }
-
- idxName := typeName + ".index"
- var idx bleve.Index
-
- // check if index exists, use it or create new one
- pwd, err := os.Getwd()
- if err != nil {
- return err
- }
-
- searchPath := filepath.Join(pwd, "search")
-
- err = os.MkdirAll(searchPath, os.ModeDir|os.ModePerm)
- if err != nil {
- return err
- }
-
- idxPath := filepath.Join(searchPath, idxName)
- if _, err = os.Stat(idxPath); os.IsNotExist(err) {
- idx, err = bleve.New(idxPath, mapping)
- if err != nil {
- return err
- }
- idx.SetName(idxName)
- } else {
- idx, err = bleve.Open(idxPath)
- if err != nil {
- return err
- }
- }
-
- // add the type name to the index and track the index
- Search[typeName] = idx
-
- return nil
-}
-
-// UpdateSearchIndex sets data into a content type's search index at the given
-// identifier
-func UpdateSearchIndex(id string, data interface{}) error {
- // check if there is a search index to work with
- target := strings.Split(id, ":")
- ns := target[0]
-
- idx, ok := Search[ns]
- if ok {
- // add data to search index
- return idx.Index(id, data)
- }
-
- return nil
-}
-
-// DeleteSearchIndex removes data from a content type's search index at the
-// given identifier
-func DeleteSearchIndex(id string) error {
- // check if there is a search index to work with
- target := strings.Split(id, ":")
- ns := target[0]
-
- idx, ok := Search[ns]
- if ok {
- // add data to search index
- return idx.Delete(id)
- }
-
- return nil
-}
-
-// SearchType conducts a search and returns a set of Ponzu "targets", Type:ID pairs,
-// and an error. If there is no search index for the typeName (Type) provided,
-// db.ErrNoSearchIndex will be returned as the error
-func SearchType(typeName, query string) ([]string, error) {
- idx, ok := Search[typeName]
- if !ok {
- return nil, ErrNoSearchIndex
- }
-
- q := bleve.NewQueryStringQuery(query)
- req := bleve.NewSearchRequest(q)
- res, err := idx.Search(req)
- if err != nil {
- return nil, err
- }
-
- var results []string
- for _, hit := range res.Hits {
- results = append(results, hit.ID)
- }
-
- return results, nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/user.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/user.go
deleted file mode 100644
index 164ae7b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/user.go
+++ /dev/null
@@ -1,266 +0,0 @@
-package db
-
-import (
- "bytes"
- "encoding/json"
- "errors"
- "fmt"
- "math/rand"
- "net/http"
- "time"
-
- "github.com/ponzu-cms/ponzu/system/admin/user"
-
- "github.com/boltdb/bolt"
- "github.com/nilslice/jwt"
-)
-
-// ErrUserExists is used for the db to report to admin user of existing user
-var ErrUserExists = errors.New("Error. User exists.")
-
-// ErrNoUserExists is used for the db to report to admin user of non-existing user
-var ErrNoUserExists = errors.New("Error. No user exists.")
-
-// SetUser sets key:value pairs in the db for user settings
-func SetUser(usr *user.User) (int, error) {
- err := store.Update(func(tx *bolt.Tx) error {
- email := []byte(usr.Email)
- users := tx.Bucket([]byte("__users"))
- if users == nil {
- return bolt.ErrBucketNotFound
- }
-
- // check if user is found by email, fail if nil
- exists := users.Get(email)
- if exists != nil {
- return ErrUserExists
- }
-
- // get NextSequence int64 and set it as the User.ID
- id, err := users.NextSequence()
- if err != nil {
- return err
- }
- usr.ID = int(id)
-
- // marshal User to json and put into bucket
- j, err := json.Marshal(usr)
- if err != nil {
- return err
- }
-
- err = users.Put(email, j)
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return 0, err
- }
-
- return usr.ID, nil
-}
-
-// UpdateUser sets key:value pairs in the db for existing user settings
-func UpdateUser(usr, updatedUsr *user.User) error {
- // ensure user ID remains the same
- if updatedUsr.ID != usr.ID {
- updatedUsr.ID = usr.ID
- }
-
- err := store.Update(func(tx *bolt.Tx) error {
- users := tx.Bucket([]byte("__users"))
- if users == nil {
- return bolt.ErrBucketNotFound
- }
-
- // check if user is found by email, fail if nil
- exists := users.Get([]byte(usr.Email))
- if exists == nil {
- return ErrNoUserExists
- }
-
- // marshal User to json and put into bucket
- j, err := json.Marshal(updatedUsr)
- if err != nil {
- return err
- }
-
- err = users.Put([]byte(updatedUsr.Email), j)
- if err != nil {
- return err
- }
-
- // if email address was changed, delete the old record of former
- // user with original email address
- if usr.Email != updatedUsr.Email {
- err = users.Delete([]byte(usr.Email))
- if err != nil {
- return err
- }
-
- }
-
- return nil
- })
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// DeleteUser deletes a user from the db by email
-func DeleteUser(email string) error {
- err := store.Update(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("__users"))
- if b == nil {
- return bolt.ErrBucketNotFound
- }
-
- err := b.Delete([]byte(email))
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// User gets the user by email from the db
-func User(email string) ([]byte, error) {
- val := &bytes.Buffer{}
- err := store.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("__users"))
- if b == nil {
- return bolt.ErrBucketNotFound
- }
-
- usr := b.Get([]byte(email))
-
- _, err := val.Write(usr)
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return nil, err
- }
-
- if val.Bytes() == nil {
- return nil, ErrNoUserExists
- }
-
- return val.Bytes(), nil
-}
-
-// UserAll returns all users from the db
-func UserAll() ([][]byte, error) {
- var users [][]byte
- err := store.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("__users"))
- if b == nil {
- return bolt.ErrBucketNotFound
- }
-
- err := b.ForEach(func(k, v []byte) error {
- users = append(users, v)
- return nil
- })
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return nil, err
- }
-
- return users, nil
-}
-
-// CurrentUser extracts the user from the request data and returns the current user from the db
-func CurrentUser(req *http.Request) ([]byte, error) {
- if !user.IsValid(req) {
- return nil, fmt.Errorf("Error. Invalid User.")
- }
-
- token, err := req.Cookie("_token")
- if err != nil {
- return nil, err
- }
-
- claims := jwt.GetClaims(token.Value)
- email, ok := claims["user"]
- if !ok {
- return nil, fmt.Errorf("Error. No user data found in request token.")
- }
-
- usr, err := User(email.(string))
- if err != nil {
- return nil, err
- }
-
- return usr, nil
-}
-
-// SetRecoveryKey generates and saves a random secret key to verify an email
-// address submitted in order to recover/reset an account password
-func SetRecoveryKey(email string) (string, error) {
- r := rand.New(rand.NewSource(time.Now().Unix()))
- key := fmt.Sprintf("%d", r.Int63())
-
- err := store.Update(func(tx *bolt.Tx) error {
- b, err := tx.CreateBucketIfNotExists([]byte("__recoveryKeys"))
- if err != nil {
- return err
- }
-
- err = b.Put([]byte(email), []byte(key))
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return "", err
- }
-
- return key, nil
-}
-
-// RecoveryKey gets a previously set recovery key to verify an email address
-// submitted in order to recover/reset an account password
-func RecoveryKey(email string) (string, error) {
- key := &bytes.Buffer{}
-
- err := store.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte("__recoveryKeys"))
- if b == nil {
- return bolt.ErrBucketNotFound
- }
-
- _, err := key.Write(b.Get([]byte(email)))
- if err != nil {
- return err
- }
-
- return nil
- })
- if err != nil {
- return "", err
- }
-
- return key.String(), nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/item/item.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/item/item.go
deleted file mode 100644
index 4750ef5..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/item/item.go
+++ /dev/null
@@ -1,287 +0,0 @@
-package item
-
-import (
- "fmt"
- "net/http"
- "regexp"
- "strings"
- "unicode"
-
- "github.com/blevesearch/bleve"
- "github.com/blevesearch/bleve/mapping"
- uuid "github.com/satori/go.uuid"
- "golang.org/x/text/transform"
- "golang.org/x/text/unicode/norm"
-)
-
-// Sluggable makes a struct locatable by URL with it's own path.
-// As an Item implementing Sluggable, slugs may overlap. If this is an issue,
-// make your content struct (or one which embeds Item) implement Sluggable
-// and it will override the slug created by Item's SetSlug with your own
-type Sluggable interface {
- SetSlug(string)
- ItemSlug() string
-}
-
-// Identifiable enables a struct to have its ID set/get. Typically this is done
-// to set an ID to -1 indicating it is new for DB inserts, since by default
-// a newly initialized struct would have an ID of 0, the int zero-value, and
-// BoltDB's starting key per bucket is 0, thus overwriting the first record.
-type Identifiable interface {
- ItemID() int
- SetItemID(int)
- UniqueID() uuid.UUID
- String() string
-}
-
-// Sortable ensures data is sortable by time
-type Sortable interface {
- Time() int64
- Touch() int64
-}
-
-// Hookable provides our user with an easy way to intercept or add functionality
-// to the different lifecycles/events a struct may encounter. Item implements
-// Hookable with no-ops so our user can override only whichever ones necessary.
-type Hookable interface {
- BeforeAPICreate(http.ResponseWriter, *http.Request) error
- AfterAPICreate(http.ResponseWriter, *http.Request) error
-
- BeforeAPIUpdate(http.ResponseWriter, *http.Request) error
- AfterAPIUpdate(http.ResponseWriter, *http.Request) error
-
- BeforeAPIDelete(http.ResponseWriter, *http.Request) error
- AfterAPIDelete(http.ResponseWriter, *http.Request) error
-
- BeforeSave(http.ResponseWriter, *http.Request) error
- AfterSave(http.ResponseWriter, *http.Request) error
-
- BeforeDelete(http.ResponseWriter, *http.Request) error
- AfterDelete(http.ResponseWriter, *http.Request) error
-
- BeforeApprove(http.ResponseWriter, *http.Request) error
- AfterApprove(http.ResponseWriter, *http.Request) error
-
- BeforeReject(http.ResponseWriter, *http.Request) error
- AfterReject(http.ResponseWriter, *http.Request) error
-}
-
-// Hideable lets a user keep items hidden
-type Hideable interface {
- Hide(http.ResponseWriter, *http.Request) error
-}
-
-// Pushable lets a user define which values of certain struct fields are
-// 'pushed' down to a client via HTTP/2 Server Push. All items in the slice
-// should be the json tag names of the struct fields to which they correspond.
-type Pushable interface {
- // the values contained by fields returned by Push must strictly be URL paths
- Push() []string
-}
-
-// Omittable lets a user define certin fields within a content struct to remove
-// from an API response. Helpful when you want data in the CMS, but not entirely
-// shown or available from the content API. All items in the slice should be the
-// json tag names of the struct fields to which they correspond.
-type Omittable interface {
- Omit() []string
-}
-
-// Item should only be embedded into content type structs.
-type Item struct {
- UUID uuid.UUID `json:"uuid"`
- ID int `json:"id"`
- Slug string `json:"slug"`
- Timestamp int64 `json:"timestamp"`
- Updated int64 `json:"updated"`
-}
-
-// Time partially implements the Sortable interface
-func (i Item) Time() int64 {
- return i.Timestamp
-}
-
-// Touch partially implements the Sortable interface
-func (i Item) Touch() int64 {
- return i.Updated
-}
-
-// SetSlug sets the item's slug for its URL
-func (i *Item) SetSlug(slug string) {
- i.Slug = slug
-}
-
-// ItemSlug sets the item's slug for its URL
-func (i *Item) ItemSlug() string {
- return i.Slug
-}
-
-// ItemID gets the Item's ID field
-// partially implements the Identifiable interface
-func (i Item) ItemID() int {
- return i.ID
-}
-
-// SetItemID sets the Item's ID field
-// partially implements the Identifiable interface
-func (i *Item) SetItemID(id int) {
- i.ID = id
-}
-
-// UniqueID gets the Item's UUID field
-// partially implements the Identifiable interface
-func (i Item) UniqueID() uuid.UUID {
- return i.UUID
-}
-
-// String formats an Item into a printable value
-// partially implements the Identifiable interface
-func (i Item) String() string {
- return fmt.Sprintf("Item ID: %s", i.UniqueID())
-}
-
-// BeforeAPICreate is a no-op to ensure structs which embed Item implement Hookable
-func (i Item) BeforeAPICreate(res http.ResponseWriter, req *http.Request) error {
- return nil
-}
-
-// AfterAPICreate is a no-op to ensure structs which embed Item implement Hookable
-func (i Item) AfterAPICreate(res http.ResponseWriter, req *http.Request) error {
- return nil
-}
-
-// BeforeAPIUpdate is a no-op to ensure structs which embed Item implement Hookable
-func (i Item) BeforeAPIUpdate(res http.ResponseWriter, req *http.Request) error {
- return nil
-}
-
-// AfterAPIUpdate is a no-op to ensure structs which embed Item implement Hookable
-func (i Item) AfterAPIUpdate(res http.ResponseWriter, req *http.Request) error {
- return nil
-}
-
-// BeforeAPIDelete is a no-op to ensure structs which embed Item implement Hookable
-func (i Item) BeforeAPIDelete(res http.ResponseWriter, req *http.Request) error {
- return nil
-}
-
-// AfterAPIDelete is a no-op to ensure structs which embed Item implement Hookable
-func (i Item) AfterAPIDelete(res http.ResponseWriter, req *http.Request) error {
- return nil
-}
-
-// BeforeSave is a no-op to ensure structs which embed Item implement Hookable
-func (i Item) BeforeSave(res http.ResponseWriter, req *http.Request) error {
- return nil
-}
-
-// AfterSave is a no-op to ensure structs which embed Item implement Hookable
-func (i Item) AfterSave(res http.ResponseWriter, req *http.Request) error {
- return nil
-}
-
-// BeforeDelete is a no-op to ensure structs which embed Item implement Hookable
-func (i Item) BeforeDelete(res http.ResponseWriter, req *http.Request) error {
- return nil
-}
-
-// AfterDelete is a no-op to ensure structs which embed Item implement Hookable
-func (i Item) AfterDelete(res http.ResponseWriter, req *http.Request) error {
- return nil
-}
-
-// BeforeApprove is a no-op to ensure structs which embed Item implement Hookable
-func (i Item) BeforeApprove(res http.ResponseWriter, req *http.Request) error {
- return nil
-}
-
-// AfterApprove is a no-op to ensure structs which embed Item implement Hookable
-func (i Item) AfterApprove(res http.ResponseWriter, req *http.Request) error {
- return nil
-}
-
-// BeforeReject is a no-op to ensure structs which embed Item implement Hookable
-func (i Item) BeforeReject(res http.ResponseWriter, req *http.Request) error {
- return nil
-}
-
-// AfterReject is a no-op to ensure structs which embed Item implement Hookable
-func (i Item) AfterReject(res http.ResponseWriter, req *http.Request) error {
- return nil
-}
-
-// SearchMapping returns a default implementation of a Bleve IndexMappingImpl
-// partially implements db.Searchable
-func (i Item) SearchMapping() (*mapping.IndexMappingImpl, error) {
- mapping := bleve.NewIndexMapping()
- mapping.StoreDynamic = false
-
- return mapping, nil
-}
-
-// Slug returns a URL friendly string from the title of a post item
-func Slug(i Identifiable) (string, error) {
- // get the name of the post item
- name := strings.TrimSpace(i.String())
-
- // filter out non-alphanumeric character or non-whitespace
- slug, err := stringToSlug(name)
- if err != nil {
- return "", err
- }
-
- return slug, nil
-}
-
-func isMn(r rune) bool {
- return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks
-}
-
-// modified version of: https://www.socketloop.com/tutorials/golang-format-strings-to-seo-friendly-url-example
-func stringToSlug(s string) (string, error) {
- src := []byte(strings.ToLower(s))
-
- // convert all spaces to dash
- rx := regexp.MustCompile("[[:space:]]")
- src = rx.ReplaceAll(src, []byte("-"))
-
- // remove all blanks such as tab
- rx = regexp.MustCompile("[[:blank:]]")
- src = rx.ReplaceAll(src, []byte(""))
-
- rx = regexp.MustCompile("[!/:-@[-`{-~]")
- src = rx.ReplaceAll(src, []byte(""))
-
- rx = regexp.MustCompile("/[^\x20-\x7F]/")
- src = rx.ReplaceAll(src, []byte(""))
-
- rx = regexp.MustCompile("`&(amp;)?#?[a-z0-9]+;`i")
- src = rx.ReplaceAll(src, []byte("-"))
-
- rx = regexp.MustCompile("`&([a-z])(acute|uml|circ|grave|ring|cedil|slash|tilde|caron|lig|quot|rsquo);`i")
- src = rx.ReplaceAll(src, []byte("\\1"))
-
- rx = regexp.MustCompile("`[^a-z0-9]`i")
- src = rx.ReplaceAll(src, []byte("-"))
-
- rx = regexp.MustCompile("`[-]+`")
- src = rx.ReplaceAll(src, []byte("-"))
-
- str := strings.Replace(string(src), "'", "", -1)
- str = strings.Replace(str, `"`, "", -1)
- str = strings.Replace(str, "&", "-", -1)
-
- t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
- slug, _, err := transform.String(t, str)
- if err != nil {
- return "", err
- }
-
- return strings.TrimSpace(slug), nil
-}
-
-// NormalizeString removes and replaces illegal characters for URLs and other
-// path entities. Useful for taking user input and converting it for keys or URLs.
-func NormalizeString(s string) (string, error) {
- return stringToSlug(s)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/item/types.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/item/types.go
deleted file mode 100644
index dbf13af..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/item/types.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package item
-
-import "errors"
-
-const (
- typeNotRegistered = `Error:
-There is no type registered for %[1]s
-
-Add this to the file which defines %[1]s{} in the 'content' package:
-
-
- func init() {
- item.Types["%[1]s"] = func() interface{} { return new(%[1]s) }
- }
-
-
-`
-)
-
-var (
- // ErrTypeNotRegistered means content type isn't registered (not found in Types map)
- ErrTypeNotRegistered = errors.New(typeNotRegistered)
-
- // ErrAllowHiddenItem should be used as an error to tell a caller of Hideable#Hide
- // that this type is hidden, but should be shown in a particular case, i.e.
- // if requested by a valid admin or user
- ErrAllowHiddenItem = errors.New(`Allow hidden item`)
-
- // ErrNoSearchMapping can be used to tell the system not to create an index mapping
- ErrNoSearchMapping = errors.New(`No search mapping for item`)
-
- // Types is a map used to reference a type name to its actual Editable type
- // mainly for lookups in /admin route based utilities
- Types map[string]func() interface{}
-)
-
-func init() {
- Types = make(map[string]func() interface{})
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/tls/devcerts.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/tls/devcerts.go
deleted file mode 100644
index 0554aa4..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/tls/devcerts.go
+++ /dev/null
@@ -1,148 +0,0 @@
-// 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.
-
-// Modified 2016 by Steve Manuel, Boss Sauce Creative, LLC
-// All modifications are relicensed under the same BSD license
-// found in the LICENSE file.
-
-// Generate a self-signed X.509 certificate for a TLS server. Outputs to
-// 'devcerts/cert.pem' and 'devcerts/key.pem' and will overwrite existing files.
-
-package tls
-
-import (
- "crypto/ecdsa"
- "crypto/rand"
- "crypto/rsa"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/pem"
- "fmt"
- "log"
- "math/big"
- "net"
- "os"
- "path/filepath"
- "time"
-
- "github.com/ponzu-cms/ponzu/system/db"
-)
-
-func publicKey(priv interface{}) interface{} {
- switch k := priv.(type) {
- case *rsa.PrivateKey:
- return &k.PublicKey
- case *ecdsa.PrivateKey:
- return &k.PublicKey
- default:
- return nil
- }
-}
-
-func pemBlockForKey(priv interface{}) *pem.Block {
- switch k := priv.(type) {
- case *rsa.PrivateKey:
- return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
- case *ecdsa.PrivateKey:
- b, err := x509.MarshalECPrivateKey(k)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err)
- os.Exit(2)
- }
- return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
- default:
- return nil
- }
-}
-
-func setupDev() {
- var priv interface{}
- var err error
-
- priv, err = rsa.GenerateKey(rand.Reader, 2048)
-
- if err != nil {
- log.Fatalf("failed to generate private key: %s", err)
- }
-
- notBefore := time.Now()
- notAfter := notBefore.Add(time.Hour * 24 * 30) // valid for 30 days
-
- serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
- serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
- if err != nil {
- log.Fatalf("failed to generate serial number: %s", err)
- }
-
- template := x509.Certificate{
- SerialNumber: serialNumber,
- Subject: pkix.Name{
- Organization: []string{"Ponzu Dev Server"},
- },
- NotBefore: notBefore,
- NotAfter: notAfter,
-
- KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
- ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
- BasicConstraintsValid: true,
- }
-
- hosts := []string{"localhost", "0.0.0.0"}
- domain := db.ConfigCache("domain").(string)
- if domain != "" {
- hosts = append(hosts, domain)
- }
-
- for _, h := range hosts {
- if ip := net.ParseIP(h); ip != nil {
- template.IPAddresses = append(template.IPAddresses, ip)
- } else {
- template.DNSNames = append(template.DNSNames, h)
- }
- }
-
- // make all certs CA
- template.IsCA = true
- template.KeyUsage |= x509.KeyUsageCertSign
-
- derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
- if err != nil {
- log.Fatalln("Failed to create certificate:", err)
- }
-
- // overwrite/create directory for devcerts
- pwd, err := os.Getwd()
- if err != nil {
- log.Fatalln("Couldn't find working directory to locate or save dev certificates:", err)
- }
-
- vendorTLSPath := filepath.Join(pwd, "cmd", "ponzu", "vendor", "github.com", "ponzu-cms", "ponzu", "system", "tls")
- devcertsPath := filepath.Join(vendorTLSPath, "devcerts")
-
- // clear all old certs if found
- err = os.RemoveAll(devcertsPath)
- if err != nil {
- log.Fatalln("Failed to remove old files from dev certificate directory:", err)
- }
-
- err = os.Mkdir(devcertsPath, os.ModeDir|os.ModePerm)
- if err != nil {
- log.Fatalln("Failed to create directory to locate or save dev certificates:", err)
- }
-
- certOut, err := os.Create(filepath.Join(devcertsPath, "cert.pem"))
- if err != nil {
- log.Fatalln("Failed to open devcerts/cert.pem for writing:", err)
- }
- pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
- certOut.Close()
-
- keyOut, err := os.OpenFile(filepath.Join(devcertsPath, "key.pem"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
- if err != nil {
- log.Fatalln("Failed to open devcerts/key.pem for writing:", err)
- return
- }
- pem.Encode(keyOut, pemBlockForKey(priv))
- keyOut.Close()
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/tls/enable.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/tls/enable.go
deleted file mode 100644
index f2c65d5..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/tls/enable.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package tls
-
-import (
- "crypto/tls"
- "fmt"
- "log"
- "net/http"
- "os"
- "path/filepath"
- "time"
-
- "github.com/ponzu-cms/ponzu/system/db"
- "golang.org/x/crypto/acme/autocert"
-)
-
-var m autocert.Manager
-
-// setup attempts to locate or create the cert cache directory and the certs for TLS encryption
-func setup() {
- pwd, err := os.Getwd()
- if err != nil {
- log.Fatalln("Couldn't find working directory to locate or save certificates.")
- }
-
- cache := autocert.DirCache(filepath.Join(pwd, "system", "tls", "certs"))
- if _, err := os.Stat(string(cache)); os.IsNotExist(err) {
- err := os.MkdirAll(string(cache), os.ModePerm|os.ModeDir)
- if err != nil {
- log.Fatalln("Couldn't create cert directory at", cache)
- }
- }
-
- // get host/domain and email from Config to use for TLS request to Let's encryption.
- // we will fail fatally if either are not found since Let's Encrypt will rate-limit
- // and sending incomplete requests is wasteful and guaranteed to fail its check
- host, err := db.Config("domain")
- if err != nil {
- log.Fatalln("Error identifying host/domain during TLS set-up.", err)
- }
-
- if host == nil {
- log.Fatalln("No 'domain' field set in Configuration. Please add a domain before attempting to make certificates.")
- }
- fmt.Println("Using", string(host), "as host/domain for certificate...")
- fmt.Println("NOTE: if the host/domain is not configured properly or is unreachable, HTTPS set-up will fail.")
-
- email, err := db.Config("admin_email")
- if err != nil {
- log.Fatalln("Error identifying admin email during TLS set-up.", err)
- }
-
- if email == nil {
- log.Fatalln("No 'admin_email' field set in Configuration. Please add an admin email before attempting to make certificates.")
- }
- fmt.Println("Using", string(email), "as contact email for certificate...")
-
- m = autocert.Manager{
- Prompt: autocert.AcceptTOS,
- Cache: cache,
- HostPolicy: autocert.HostWhitelist(string(host)),
- RenewBefore: time.Hour * 24 * 30,
- Email: string(email),
- }
-
-}
-
-// Enable runs the setup for creating or locating production certificates and
-// starts the TLS server
-func Enable() {
- setup()
-
- server := &http.Server{
- Addr: fmt.Sprintf(":%s", db.ConfigCache("https_port").(string)),
- TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
- }
-
- log.Fatalln(server.ListenAndServeTLS("", ""))
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/tls/enabledev.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/tls/enabledev.go
deleted file mode 100644
index 3550fc0..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/tls/enabledev.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package tls
-
-import (
- "log"
- "net/http"
- "os"
- "path/filepath"
-)
-
-// EnableDev generates self-signed SSL certificates to use HTTPS & HTTP/2 while
-// working in a development environment. The certs are saved in a different
-// directory than the production certs (from Let's Encrypt), so that the
-// acme/autocert package doesn't mistake them for it's own.
-// Additionally, a TLS server is started using the default http mux.
-func EnableDev() {
- setupDev()
-
- pwd, err := os.Getwd()
- if err != nil {
- log.Fatalln("Couldn't find working directory to activate dev certificates:", err)
- }
-
- vendorPath := filepath.Join(pwd, "cmd", "ponzu", "vendor", "github.com", "ponzu-cms", "ponzu", "system", "tls")
-
- cert := filepath.Join(vendorPath, "devcerts", "cert.pem")
- key := filepath.Join(vendorPath, "devcerts", "key.pem")
-
- log.Fatalln(http.ListenAndServeTLS(":10443", cert, key, nil))
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/.travis.yml b/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/.travis.yml
deleted file mode 100644
index bf90ad5..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/.travis.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-language: go
-sudo: false
-go:
- - 1.2
- - 1.3
- - 1.4
- - 1.5
- - 1.6
- - 1.7
- - tip
-matrix:
- allow_failures:
- - go: tip
- fast_finish: true
-before_install:
- - go get github.com/mattn/goveralls
- - go get golang.org/x/tools/cmd/cover
-script:
- - $HOME/gopath/bin/goveralls -service=travis-ci
-notifications:
- email: false
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/LICENSE b/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/LICENSE
deleted file mode 100644
index 488357b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright (C) 2013-2016 by Maxim Bublis <b@codemonkey.ru>
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/README.md b/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/README.md
deleted file mode 100644
index b6aad1c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/README.md
+++ /dev/null
@@ -1,65 +0,0 @@
-# UUID package for Go language
-
-[![Build Status](https://travis-ci.org/satori/go.uuid.png?branch=master)](https://travis-ci.org/satori/go.uuid)
-[![Coverage Status](https://coveralls.io/repos/github/satori/go.uuid/badge.svg?branch=master)](https://coveralls.io/github/satori/go.uuid)
-[![GoDoc](http://godoc.org/github.com/satori/go.uuid?status.png)](http://godoc.org/github.com/satori/go.uuid)
-
-This package provides pure Go implementation of Universally Unique Identifier (UUID). Supported both creation and parsing of UUIDs.
-
-With 100% test coverage and benchmarks out of box.
-
-Supported versions:
-* Version 1, based on timestamp and MAC address (RFC 4122)
-* Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1)
-* Version 3, based on MD5 hashing (RFC 4122)
-* Version 4, based on random numbers (RFC 4122)
-* Version 5, based on SHA-1 hashing (RFC 4122)
-
-## Installation
-
-Use the `go` command:
-
- $ go get github.com/satori/go.uuid
-
-## Requirements
-
-UUID package requires Go >= 1.2.
-
-## Example
-
-```go
-package main
-
-import (
- "fmt"
- "github.com/satori/go.uuid"
-)
-
-func main() {
- // Creating UUID Version 4
- u1 := uuid.NewV4()
- fmt.Printf("UUIDv4: %s\n", u1)
-
- // Parsing UUID from string input
- u2, err := uuid.FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
- if err != nil {
- fmt.Printf("Something gone wrong: %s", err)
- }
- fmt.Printf("Successfully parsed: %s", u2)
-}
-```
-
-## Documentation
-
-[Documentation](http://godoc.org/github.com/satori/go.uuid) is hosted at GoDoc project.
-
-## Links
-* [RFC 4122](http://tools.ietf.org/html/rfc4122)
-* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01)
-
-## Copyright
-
-Copyright (C) 2013-2016 by Maxim Bublis <b@codemonkey.ru>.
-
-UUID package released under MIT License.
-See [LICENSE](https://github.com/satori/go.uuid/blob/master/LICENSE) for details.
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/benchmarks_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/benchmarks_test.go
deleted file mode 100644
index c3baeab..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/benchmarks_test.go
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright (C) 2013-2015 by Maxim Bublis <b@codemonkey.ru>
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-package uuid
-
-import (
- "testing"
-)
-
-func BenchmarkFromBytes(b *testing.B) {
- bytes := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
- for i := 0; i < b.N; i++ {
- FromBytes(bytes)
- }
-}
-
-func BenchmarkFromString(b *testing.B) {
- s := "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
- for i := 0; i < b.N; i++ {
- FromString(s)
- }
-}
-
-func BenchmarkFromStringUrn(b *testing.B) {
- s := "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
- for i := 0; i < b.N; i++ {
- FromString(s)
- }
-}
-
-func BenchmarkFromStringWithBrackets(b *testing.B) {
- s := "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}"
- for i := 0; i < b.N; i++ {
- FromString(s)
- }
-}
-
-func BenchmarkNewV1(b *testing.B) {
- for i := 0; i < b.N; i++ {
- NewV1()
- }
-}
-
-func BenchmarkNewV2(b *testing.B) {
- for i := 0; i < b.N; i++ {
- NewV2(DomainPerson)
- }
-}
-
-func BenchmarkNewV3(b *testing.B) {
- for i := 0; i < b.N; i++ {
- NewV3(NamespaceDNS, "www.example.com")
- }
-}
-
-func BenchmarkNewV4(b *testing.B) {
- for i := 0; i < b.N; i++ {
- NewV4()
- }
-}
-
-func BenchmarkNewV5(b *testing.B) {
- for i := 0; i < b.N; i++ {
- NewV5(NamespaceDNS, "www.example.com")
- }
-}
-
-func BenchmarkMarshalBinary(b *testing.B) {
- u := NewV4()
- for i := 0; i < b.N; i++ {
- u.MarshalBinary()
- }
-}
-
-func BenchmarkMarshalText(b *testing.B) {
- u := NewV4()
- for i := 0; i < b.N; i++ {
- u.MarshalText()
- }
-}
-
-func BenchmarkUnmarshalBinary(b *testing.B) {
- bytes := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
- u := UUID{}
- for i := 0; i < b.N; i++ {
- u.UnmarshalBinary(bytes)
- }
-}
-
-func BenchmarkUnmarshalText(b *testing.B) {
- bytes := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
- u := UUID{}
- for i := 0; i < b.N; i++ {
- u.UnmarshalText(bytes)
- }
-}
-
-var sink string
-
-func BenchmarkMarshalToString(b *testing.B) {
- u := NewV4()
- for i := 0; i < b.N; i++ {
- sink = u.String()
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/uuid.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/uuid.go
deleted file mode 100644
index 295f3fc..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/uuid.go
+++ /dev/null
@@ -1,481 +0,0 @@
-// Copyright (C) 2013-2015 by Maxim Bublis <b@codemonkey.ru>
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// Package uuid provides implementation of Universally Unique Identifier (UUID).
-// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and
-// version 2 (as specified in DCE 1.1).
-package uuid
-
-import (
- "bytes"
- "crypto/md5"
- "crypto/rand"
- "crypto/sha1"
- "database/sql/driver"
- "encoding/binary"
- "encoding/hex"
- "fmt"
- "hash"
- "net"
- "os"
- "sync"
- "time"
-)
-
-// UUID layout variants.
-const (
- VariantNCS = iota
- VariantRFC4122
- VariantMicrosoft
- VariantFuture
-)
-
-// UUID DCE domains.
-const (
- DomainPerson = iota
- DomainGroup
- DomainOrg
-)
-
-// Difference in 100-nanosecond intervals between
-// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
-const epochStart = 122192928000000000
-
-// Used in string method conversion
-const dash byte = '-'
-
-// UUID v1/v2 storage.
-var (
- storageMutex sync.Mutex
- storageOnce sync.Once
- epochFunc = unixTimeFunc
- clockSequence uint16
- lastTime uint64
- hardwareAddr [6]byte
- posixUID = uint32(os.Getuid())
- posixGID = uint32(os.Getgid())
-)
-
-// String parse helpers.
-var (
- urnPrefix = []byte("urn:uuid:")
- byteGroups = []int{8, 4, 4, 4, 12}
-)
-
-func initClockSequence() {
- buf := make([]byte, 2)
- safeRandom(buf)
- clockSequence = binary.BigEndian.Uint16(buf)
-}
-
-func initHardwareAddr() {
- interfaces, err := net.Interfaces()
- if err == nil {
- for _, iface := range interfaces {
- if len(iface.HardwareAddr) >= 6 {
- copy(hardwareAddr[:], iface.HardwareAddr)
- return
- }
- }
- }
-
- // Initialize hardwareAddr randomly in case
- // of real network interfaces absence
- safeRandom(hardwareAddr[:])
-
- // Set multicast bit as recommended in RFC 4122
- hardwareAddr[0] |= 0x01
-}
-
-func initStorage() {
- initClockSequence()
- initHardwareAddr()
-}
-
-func safeRandom(dest []byte) {
- if _, err := rand.Read(dest); err != nil {
- panic(err)
- }
-}
-
-// Returns difference in 100-nanosecond intervals between
-// UUID epoch (October 15, 1582) and current time.
-// This is default epoch calculation function.
-func unixTimeFunc() uint64 {
- return epochStart + uint64(time.Now().UnixNano()/100)
-}
-
-// UUID representation compliant with specification
-// described in RFC 4122.
-type UUID [16]byte
-
-// NullUUID can be used with the standard sql package to represent a
-// UUID value that can be NULL in the database
-type NullUUID struct {
- UUID UUID
- Valid bool
-}
-
-// The nil UUID is special form of UUID that is specified to have all
-// 128 bits set to zero.
-var Nil = UUID{}
-
-// Predefined namespace UUIDs.
-var (
- NamespaceDNS, _ = FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
- NamespaceURL, _ = FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
- NamespaceOID, _ = FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
- NamespaceX500, _ = FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
-)
-
-// And returns result of binary AND of two UUIDs.
-func And(u1 UUID, u2 UUID) UUID {
- u := UUID{}
- for i := 0; i < 16; i++ {
- u[i] = u1[i] & u2[i]
- }
- return u
-}
-
-// Or returns result of binary OR of two UUIDs.
-func Or(u1 UUID, u2 UUID) UUID {
- u := UUID{}
- for i := 0; i < 16; i++ {
- u[i] = u1[i] | u2[i]
- }
- return u
-}
-
-// Equal returns true if u1 and u2 equals, otherwise returns false.
-func Equal(u1 UUID, u2 UUID) bool {
- return bytes.Equal(u1[:], u2[:])
-}
-
-// Version returns algorithm version used to generate UUID.
-func (u UUID) Version() uint {
- return uint(u[6] >> 4)
-}
-
-// Variant returns UUID layout variant.
-func (u UUID) Variant() uint {
- switch {
- case (u[8] & 0x80) == 0x00:
- return VariantNCS
- case (u[8]&0xc0)|0x80 == 0x80:
- return VariantRFC4122
- case (u[8]&0xe0)|0xc0 == 0xc0:
- return VariantMicrosoft
- }
- return VariantFuture
-}
-
-// Bytes returns bytes slice representation of UUID.
-func (u UUID) Bytes() []byte {
- return u[:]
-}
-
-// Returns canonical string representation of UUID:
-// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
-func (u UUID) String() string {
- buf := make([]byte, 36)
-
- hex.Encode(buf[0:8], u[0:4])
- buf[8] = dash
- hex.Encode(buf[9:13], u[4:6])
- buf[13] = dash
- hex.Encode(buf[14:18], u[6:8])
- buf[18] = dash
- hex.Encode(buf[19:23], u[8:10])
- buf[23] = dash
- hex.Encode(buf[24:], u[10:])
-
- return string(buf)
-}
-
-// SetVersion sets version bits.
-func (u *UUID) SetVersion(v byte) {
- u[6] = (u[6] & 0x0f) | (v << 4)
-}
-
-// SetVariant sets variant bits as described in RFC 4122.
-func (u *UUID) SetVariant() {
- u[8] = (u[8] & 0xbf) | 0x80
-}
-
-// MarshalText implements the encoding.TextMarshaler interface.
-// The encoding is the same as returned by String.
-func (u UUID) MarshalText() (text []byte, err error) {
- text = []byte(u.String())
- return
-}
-
-// UnmarshalText implements the encoding.TextUnmarshaler interface.
-// Following formats are supported:
-// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
-// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
-// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
-func (u *UUID) UnmarshalText(text []byte) (err error) {
- if len(text) < 32 {
- err = fmt.Errorf("uuid: UUID string too short: %s", text)
- return
- }
-
- t := text[:]
- braced := false
-
- if bytes.Equal(t[:9], urnPrefix) {
- t = t[9:]
- } else if t[0] == '{' {
- braced = true
- t = t[1:]
- }
-
- b := u[:]
-
- for i, byteGroup := range byteGroups {
- if i > 0 {
- if t[0] != '-' {
- err = fmt.Errorf("uuid: invalid string format")
- return
- }
- t = t[1:]
- }
-
- if len(t) < byteGroup {
- err = fmt.Errorf("uuid: UUID string too short: %s", text)
- return
- }
-
- if i == 4 && len(t) > byteGroup &&
- ((braced && t[byteGroup] != '}') || len(t[byteGroup:]) > 1 || !braced) {
- err = fmt.Errorf("uuid: UUID string too long: %s", text)
- return
- }
-
- _, err = hex.Decode(b[:byteGroup/2], t[:byteGroup])
- if err != nil {
- return
- }
-
- t = t[byteGroup:]
- b = b[byteGroup/2:]
- }
-
- return
-}
-
-// MarshalBinary implements the encoding.BinaryMarshaler interface.
-func (u UUID) MarshalBinary() (data []byte, err error) {
- data = u.Bytes()
- return
-}
-
-// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
-// It will return error if the slice isn't 16 bytes long.
-func (u *UUID) UnmarshalBinary(data []byte) (err error) {
- if len(data) != 16 {
- err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data))
- return
- }
- copy(u[:], data)
-
- return
-}
-
-// Value implements the driver.Valuer interface.
-func (u UUID) Value() (driver.Value, error) {
- return u.String(), nil
-}
-
-// Scan implements the sql.Scanner interface.
-// A 16-byte slice is handled by UnmarshalBinary, while
-// a longer byte slice or a string is handled by UnmarshalText.
-func (u *UUID) Scan(src interface{}) error {
- switch src := src.(type) {
- case []byte:
- if len(src) == 16 {
- return u.UnmarshalBinary(src)
- }
- return u.UnmarshalText(src)
-
- case string:
- return u.UnmarshalText([]byte(src))
- }
-
- return fmt.Errorf("uuid: cannot convert %T to UUID", src)
-}
-
-// Value implements the driver.Valuer interface.
-func (u NullUUID) Value() (driver.Value, error) {
- if !u.Valid {
- return nil, nil
- }
- // Delegate to UUID Value function
- return u.UUID.Value()
-}
-
-// Scan implements the sql.Scanner interface.
-func (u *NullUUID) Scan(src interface{}) error {
- if src == nil {
- u.UUID, u.Valid = Nil, false
- return nil
- }
-
- // Delegate to UUID Scan function
- u.Valid = true
- return u.UUID.Scan(src)
-}
-
-// FromBytes returns UUID converted from raw byte slice input.
-// It will return error if the slice isn't 16 bytes long.
-func FromBytes(input []byte) (u UUID, err error) {
- err = u.UnmarshalBinary(input)
- return
-}
-
-// FromBytesOrNil returns UUID converted from raw byte slice input.
-// Same behavior as FromBytes, but returns a Nil UUID on error.
-func FromBytesOrNil(input []byte) UUID {
- uuid, err := FromBytes(input)
- if err != nil {
- return Nil
- }
- return uuid
-}
-
-// FromString returns UUID parsed from string input.
-// Input is expected in a form accepted by UnmarshalText.
-func FromString(input string) (u UUID, err error) {
- err = u.UnmarshalText([]byte(input))
- return
-}
-
-// FromStringOrNil returns UUID parsed from string input.
-// Same behavior as FromString, but returns a Nil UUID on error.
-func FromStringOrNil(input string) UUID {
- uuid, err := FromString(input)
- if err != nil {
- return Nil
- }
- return uuid
-}
-
-// Returns UUID v1/v2 storage state.
-// Returns epoch timestamp, clock sequence, and hardware address.
-func getStorage() (uint64, uint16, []byte) {
- storageOnce.Do(initStorage)
-
- storageMutex.Lock()
- defer storageMutex.Unlock()
-
- timeNow := epochFunc()
- // Clock changed backwards since last UUID generation.
- // Should increase clock sequence.
- if timeNow <= lastTime {
- clockSequence++
- }
- lastTime = timeNow
-
- return timeNow, clockSequence, hardwareAddr[:]
-}
-
-// NewV1 returns UUID based on current timestamp and MAC address.
-func NewV1() UUID {
- u := UUID{}
-
- timeNow, clockSeq, hardwareAddr := getStorage()
-
- binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
- binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
- binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
- binary.BigEndian.PutUint16(u[8:], clockSeq)
-
- copy(u[10:], hardwareAddr)
-
- u.SetVersion(1)
- u.SetVariant()
-
- return u
-}
-
-// NewV2 returns DCE Security UUID based on POSIX UID/GID.
-func NewV2(domain byte) UUID {
- u := UUID{}
-
- timeNow, clockSeq, hardwareAddr := getStorage()
-
- switch domain {
- case DomainPerson:
- binary.BigEndian.PutUint32(u[0:], posixUID)
- case DomainGroup:
- binary.BigEndian.PutUint32(u[0:], posixGID)
- }
-
- binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
- binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
- binary.BigEndian.PutUint16(u[8:], clockSeq)
- u[9] = domain
-
- copy(u[10:], hardwareAddr)
-
- u.SetVersion(2)
- u.SetVariant()
-
- return u
-}
-
-// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
-func NewV3(ns UUID, name string) UUID {
- u := newFromHash(md5.New(), ns, name)
- u.SetVersion(3)
- u.SetVariant()
-
- return u
-}
-
-// NewV4 returns random generated UUID.
-func NewV4() UUID {
- u := UUID{}
- safeRandom(u[:])
- u.SetVersion(4)
- u.SetVariant()
-
- return u
-}
-
-// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
-func NewV5(ns UUID, name string) UUID {
- u := newFromHash(sha1.New(), ns, name)
- u.SetVersion(5)
- u.SetVariant()
-
- return u
-}
-
-// Returns UUID based on hashing of namespace UUID and name.
-func newFromHash(h hash.Hash, ns UUID, name string) UUID {
- u := UUID{}
- h.Write(ns[:])
- h.Write([]byte(name))
- copy(u[:], h.Sum(nil))
-
- return u
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/uuid_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/uuid_test.go
deleted file mode 100644
index 5650480..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/uuid_test.go
+++ /dev/null
@@ -1,633 +0,0 @@
-// Copyright (C) 2013, 2015 by Maxim Bublis <b@codemonkey.ru>
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-package uuid
-
-import (
- "bytes"
- "testing"
-)
-
-func TestBytes(t *testing.T) {
- u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
-
- bytes1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
-
- if !bytes.Equal(u.Bytes(), bytes1) {
- t.Errorf("Incorrect bytes representation for UUID: %s", u)
- }
-}
-
-func TestString(t *testing.T) {
- if NamespaceDNS.String() != "6ba7b810-9dad-11d1-80b4-00c04fd430c8" {
- t.Errorf("Incorrect string representation for UUID: %s", NamespaceDNS.String())
- }
-}
-
-func TestEqual(t *testing.T) {
- if !Equal(NamespaceDNS, NamespaceDNS) {
- t.Errorf("Incorrect comparison of %s and %s", NamespaceDNS, NamespaceDNS)
- }
-
- if Equal(NamespaceDNS, NamespaceURL) {
- t.Errorf("Incorrect comparison of %s and %s", NamespaceDNS, NamespaceURL)
- }
-}
-
-func TestOr(t *testing.T) {
- u1 := UUID{0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff}
- u2 := UUID{0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00}
-
- u := UUID{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
-
- if !Equal(u, Or(u1, u2)) {
- t.Errorf("Incorrect bitwise OR result %s", Or(u1, u2))
- }
-}
-
-func TestAnd(t *testing.T) {
- u1 := UUID{0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff}
- u2 := UUID{0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00}
-
- u := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
-
- if !Equal(u, And(u1, u2)) {
- t.Errorf("Incorrect bitwise AND result %s", And(u1, u2))
- }
-}
-
-func TestVersion(t *testing.T) {
- u := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
-
- if u.Version() != 1 {
- t.Errorf("Incorrect version for UUID: %d", u.Version())
- }
-}
-
-func TestSetVersion(t *testing.T) {
- u := UUID{}
- u.SetVersion(4)
-
- if u.Version() != 4 {
- t.Errorf("Incorrect version for UUID after u.setVersion(4): %d", u.Version())
- }
-}
-
-func TestVariant(t *testing.T) {
- u1 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
-
- if u1.Variant() != VariantNCS {
- t.Errorf("Incorrect variant for UUID variant %d: %d", VariantNCS, u1.Variant())
- }
-
- u2 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
-
- if u2.Variant() != VariantRFC4122 {
- t.Errorf("Incorrect variant for UUID variant %d: %d", VariantRFC4122, u2.Variant())
- }
-
- u3 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
-
- if u3.Variant() != VariantMicrosoft {
- t.Errorf("Incorrect variant for UUID variant %d: %d", VariantMicrosoft, u3.Variant())
- }
-
- u4 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
-
- if u4.Variant() != VariantFuture {
- t.Errorf("Incorrect variant for UUID variant %d: %d", VariantFuture, u4.Variant())
- }
-}
-
-func TestSetVariant(t *testing.T) {
- u := new(UUID)
- u.SetVariant()
-
- if u.Variant() != VariantRFC4122 {
- t.Errorf("Incorrect variant for UUID after u.setVariant(): %d", u.Variant())
- }
-}
-
-func TestFromBytes(t *testing.T) {
- u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
- b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
-
- u1, err := FromBytes(b1)
- if err != nil {
- t.Errorf("Error parsing UUID from bytes: %s", err)
- }
-
- if !Equal(u, u1) {
- t.Errorf("UUIDs should be equal: %s and %s", u, u1)
- }
-
- b2 := []byte{}
-
- _, err = FromBytes(b2)
- if err == nil {
- t.Errorf("Should return error parsing from empty byte slice, got %s", err)
- }
-}
-
-func TestMarshalBinary(t *testing.T) {
- u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
- b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
-
- b2, err := u.MarshalBinary()
- if err != nil {
- t.Errorf("Error marshaling UUID: %s", err)
- }
-
- if !bytes.Equal(b1, b2) {
- t.Errorf("Marshaled UUID should be %s, got %s", b1, b2)
- }
-}
-
-func TestUnmarshalBinary(t *testing.T) {
- u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
- b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
-
- u1 := UUID{}
- err := u1.UnmarshalBinary(b1)
- if err != nil {
- t.Errorf("Error unmarshaling UUID: %s", err)
- }
-
- if !Equal(u, u1) {
- t.Errorf("UUIDs should be equal: %s and %s", u, u1)
- }
-
- b2 := []byte{}
- u2 := UUID{}
-
- err = u2.UnmarshalBinary(b2)
- if err == nil {
- t.Errorf("Should return error unmarshalling from empty byte slice, got %s", err)
- }
-}
-
-func TestFromString(t *testing.T) {
- u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
-
- s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
- s2 := "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}"
- s3 := "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
-
- _, err := FromString("")
- if err == nil {
- t.Errorf("Should return error trying to parse empty string, got %s", err)
- }
-
- u1, err := FromString(s1)
- if err != nil {
- t.Errorf("Error parsing UUID from string: %s", err)
- }
-
- if !Equal(u, u1) {
- t.Errorf("UUIDs should be equal: %s and %s", u, u1)
- }
-
- u2, err := FromString(s2)
- if err != nil {
- t.Errorf("Error parsing UUID from string: %s", err)
- }
-
- if !Equal(u, u2) {
- t.Errorf("UUIDs should be equal: %s and %s", u, u2)
- }
-
- u3, err := FromString(s3)
- if err != nil {
- t.Errorf("Error parsing UUID from string: %s", err)
- }
-
- if !Equal(u, u3) {
- t.Errorf("UUIDs should be equal: %s and %s", u, u3)
- }
-}
-
-func TestFromStringShort(t *testing.T) {
- // Invalid 35-character UUID string
- s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c"
-
- for i := len(s1); i >= 0; i-- {
- _, err := FromString(s1[:i])
- if err == nil {
- t.Errorf("Should return error trying to parse too short string, got %s", err)
- }
- }
-}
-
-func TestFromStringLong(t *testing.T) {
- // Invalid 37+ character UUID string
- s := []string{
- "6ba7b810-9dad-11d1-80b4-00c04fd430c8=",
- "6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
- "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}f",
- "6ba7b810-9dad-11d1-80b4-00c04fd430c800c04fd430c8",
- }
-
- for _, str := range s {
- _, err := FromString(str)
- if err == nil {
- t.Errorf("Should return error trying to parse too long string, passed %s", str)
- }
- }
-}
-
-func TestFromStringInvalid(t *testing.T) {
- // Invalid UUID string formats
- s := []string{
- "6ba7b8109dad11d180b400c04fd430c8",
- "6ba7b8109dad11d180b400c04fd430c86ba7b8109dad11d180b400c04fd430c8",
- "urn:uuid:{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
- "6ba7b8109-dad-11d1-80b4-00c04fd430c8",
- "6ba7b810-9dad1-1d1-80b4-00c04fd430c8",
- "6ba7b810-9dad-11d18-0b4-00c04fd430c8",
- "6ba7b810-9dad-11d1-80b40-0c04fd430c8",
- "6ba7b810+9dad+11d1+80b4+00c04fd430c8",
- "6ba7b810-9dad11d180b400c04fd430c8",
- "6ba7b8109dad-11d180b400c04fd430c8",
- "6ba7b8109dad11d1-80b400c04fd430c8",
- "6ba7b8109dad11d180b4-00c04fd430c8",
- }
-
- for _, str := range s {
- _, err := FromString(str)
- if err == nil {
- t.Errorf("Should return error trying to parse invalid string, passed %s", str)
- }
- }
-}
-
-func TestFromStringOrNil(t *testing.T) {
- u := FromStringOrNil("")
- if u != Nil {
- t.Errorf("Should return Nil UUID on parse failure, got %s", u)
- }
-}
-
-func TestFromBytesOrNil(t *testing.T) {
- b := []byte{}
- u := FromBytesOrNil(b)
- if u != Nil {
- t.Errorf("Should return Nil UUID on parse failure, got %s", u)
- }
-}
-
-func TestMarshalText(t *testing.T) {
- u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
- b1 := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
-
- b2, err := u.MarshalText()
- if err != nil {
- t.Errorf("Error marshaling UUID: %s", err)
- }
-
- if !bytes.Equal(b1, b2) {
- t.Errorf("Marshaled UUID should be %s, got %s", b1, b2)
- }
-}
-
-func TestUnmarshalText(t *testing.T) {
- u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
- b1 := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
-
- u1 := UUID{}
- err := u1.UnmarshalText(b1)
- if err != nil {
- t.Errorf("Error unmarshaling UUID: %s", err)
- }
-
- if !Equal(u, u1) {
- t.Errorf("UUIDs should be equal: %s and %s", u, u1)
- }
-
- b2 := []byte("")
- u2 := UUID{}
-
- err = u2.UnmarshalText(b2)
- if err == nil {
- t.Errorf("Should return error trying to unmarshal from empty string")
- }
-}
-
-func TestValue(t *testing.T) {
- u, err := FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
- if err != nil {
- t.Errorf("Error parsing UUID from string: %s", err)
- }
-
- val, err := u.Value()
- if err != nil {
- t.Errorf("Error getting UUID value: %s", err)
- }
-
- if val != u.String() {
- t.Errorf("Wrong value returned, should be equal: %s and %s", val, u)
- }
-}
-
-func TestValueNil(t *testing.T) {
- u := UUID{}
-
- val, err := u.Value()
- if err != nil {
- t.Errorf("Error getting UUID value: %s", err)
- }
-
- if val != Nil.String() {
- t.Errorf("Wrong value returned, should be equal to UUID.Nil: %s", val)
- }
-}
-
-func TestNullUUIDValueNil(t *testing.T) {
- u := NullUUID{}
-
- val, err := u.Value()
- if err != nil {
- t.Errorf("Error getting UUID value: %s", err)
- }
-
- if val != nil {
- t.Errorf("Wrong value returned, should be nil: %s", val)
- }
-}
-
-func TestScanBinary(t *testing.T) {
- u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
- b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
-
- u1 := UUID{}
- err := u1.Scan(b1)
- if err != nil {
- t.Errorf("Error unmarshaling UUID: %s", err)
- }
-
- if !Equal(u, u1) {
- t.Errorf("UUIDs should be equal: %s and %s", u, u1)
- }
-
- b2 := []byte{}
- u2 := UUID{}
-
- err = u2.Scan(b2)
- if err == nil {
- t.Errorf("Should return error unmarshalling from empty byte slice, got %s", err)
- }
-}
-
-func TestScanString(t *testing.T) {
- u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
- s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
-
- u1 := UUID{}
- err := u1.Scan(s1)
- if err != nil {
- t.Errorf("Error unmarshaling UUID: %s", err)
- }
-
- if !Equal(u, u1) {
- t.Errorf("UUIDs should be equal: %s and %s", u, u1)
- }
-
- s2 := ""
- u2 := UUID{}
-
- err = u2.Scan(s2)
- if err == nil {
- t.Errorf("Should return error trying to unmarshal from empty string")
- }
-}
-
-func TestScanText(t *testing.T) {
- u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
- b1 := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
-
- u1 := UUID{}
- err := u1.Scan(b1)
- if err != nil {
- t.Errorf("Error unmarshaling UUID: %s", err)
- }
-
- if !Equal(u, u1) {
- t.Errorf("UUIDs should be equal: %s and %s", u, u1)
- }
-
- b2 := []byte("")
- u2 := UUID{}
-
- err = u2.Scan(b2)
- if err == nil {
- t.Errorf("Should return error trying to unmarshal from empty string")
- }
-}
-
-func TestScanUnsupported(t *testing.T) {
- u := UUID{}
-
- err := u.Scan(true)
- if err == nil {
- t.Errorf("Should return error trying to unmarshal from bool")
- }
-}
-
-func TestScanNil(t *testing.T) {
- u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
-
- err := u.Scan(nil)
- if err == nil {
- t.Errorf("Error UUID shouldn't allow unmarshalling from nil")
- }
-}
-
-func TestNullUUIDScanValid(t *testing.T) {
- u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
- s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
-
- u1 := NullUUID{}
- err := u1.Scan(s1)
- if err != nil {
- t.Errorf("Error unmarshaling NullUUID: %s", err)
- }
-
- if !u1.Valid {
- t.Errorf("NullUUID should be valid")
- }
-
- if !Equal(u, u1.UUID) {
- t.Errorf("UUIDs should be equal: %s and %s", u, u1.UUID)
- }
-}
-
-func TestNullUUIDScanNil(t *testing.T) {
- u := NullUUID{UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}, true}
-
- err := u.Scan(nil)
- if err != nil {
- t.Errorf("Error unmarshaling NullUUID: %s", err)
- }
-
- if u.Valid {
- t.Errorf("NullUUID should not be valid")
- }
-
- if !Equal(u.UUID, Nil) {
- t.Errorf("NullUUID value should be equal to Nil: %v", u)
- }
-}
-
-func TestNewV1(t *testing.T) {
- u := NewV1()
-
- if u.Version() != 1 {
- t.Errorf("UUIDv1 generated with incorrect version: %d", u.Version())
- }
-
- if u.Variant() != VariantRFC4122 {
- t.Errorf("UUIDv1 generated with incorrect variant: %d", u.Variant())
- }
-
- u1 := NewV1()
- u2 := NewV1()
-
- if Equal(u1, u2) {
- t.Errorf("UUIDv1 generated two equal UUIDs: %s and %s", u1, u2)
- }
-
- oldFunc := epochFunc
- epochFunc = func() uint64 { return 0 }
-
- u3 := NewV1()
- u4 := NewV1()
-
- if Equal(u3, u4) {
- t.Errorf("UUIDv1 generated two equal UUIDs: %s and %s", u3, u4)
- }
-
- epochFunc = oldFunc
-}
-
-func TestNewV2(t *testing.T) {
- u1 := NewV2(DomainPerson)
-
- if u1.Version() != 2 {
- t.Errorf("UUIDv2 generated with incorrect version: %d", u1.Version())
- }
-
- if u1.Variant() != VariantRFC4122 {
- t.Errorf("UUIDv2 generated with incorrect variant: %d", u1.Variant())
- }
-
- u2 := NewV2(DomainGroup)
-
- if u2.Version() != 2 {
- t.Errorf("UUIDv2 generated with incorrect version: %d", u2.Version())
- }
-
- if u2.Variant() != VariantRFC4122 {
- t.Errorf("UUIDv2 generated with incorrect variant: %d", u2.Variant())
- }
-}
-
-func TestNewV3(t *testing.T) {
- u := NewV3(NamespaceDNS, "www.example.com")
-
- if u.Version() != 3 {
- t.Errorf("UUIDv3 generated with incorrect version: %d", u.Version())
- }
-
- if u.Variant() != VariantRFC4122 {
- t.Errorf("UUIDv3 generated with incorrect variant: %d", u.Variant())
- }
-
- if u.String() != "5df41881-3aed-3515-88a7-2f4a814cf09e" {
- t.Errorf("UUIDv3 generated incorrectly: %s", u.String())
- }
-
- u = NewV3(NamespaceDNS, "python.org")
-
- if u.String() != "6fa459ea-ee8a-3ca4-894e-db77e160355e" {
- t.Errorf("UUIDv3 generated incorrectly: %s", u.String())
- }
-
- u1 := NewV3(NamespaceDNS, "golang.org")
- u2 := NewV3(NamespaceDNS, "golang.org")
- if !Equal(u1, u2) {
- t.Errorf("UUIDv3 generated different UUIDs for same namespace and name: %s and %s", u1, u2)
- }
-
- u3 := NewV3(NamespaceDNS, "example.com")
- if Equal(u1, u3) {
- t.Errorf("UUIDv3 generated same UUIDs for different names in same namespace: %s and %s", u1, u2)
- }
-
- u4 := NewV3(NamespaceURL, "golang.org")
- if Equal(u1, u4) {
- t.Errorf("UUIDv3 generated same UUIDs for sane names in different namespaces: %s and %s", u1, u4)
- }
-}
-
-func TestNewV4(t *testing.T) {
- u := NewV4()
-
- if u.Version() != 4 {
- t.Errorf("UUIDv4 generated with incorrect version: %d", u.Version())
- }
-
- if u.Variant() != VariantRFC4122 {
- t.Errorf("UUIDv4 generated with incorrect variant: %d", u.Variant())
- }
-}
-
-func TestNewV5(t *testing.T) {
- u := NewV5(NamespaceDNS, "www.example.com")
-
- if u.Version() != 5 {
- t.Errorf("UUIDv5 generated with incorrect version: %d", u.Version())
- }
-
- if u.Variant() != VariantRFC4122 {
- t.Errorf("UUIDv5 generated with incorrect variant: %d", u.Variant())
- }
-
- u = NewV5(NamespaceDNS, "python.org")
-
- if u.String() != "886313e1-3b8a-5372-9b90-0c9aee199e5d" {
- t.Errorf("UUIDv5 generated incorrectly: %s", u.String())
- }
-
- u1 := NewV5(NamespaceDNS, "golang.org")
- u2 := NewV5(NamespaceDNS, "golang.org")
- if !Equal(u1, u2) {
- t.Errorf("UUIDv5 generated different UUIDs for same namespace and name: %s and %s", u1, u2)
- }
-
- u3 := NewV5(NamespaceDNS, "example.com")
- if Equal(u1, u3) {
- t.Errorf("UUIDv5 generated same UUIDs for different names in same namespace: %s and %s", u1, u2)
- }
-
- u4 := NewV5(NamespaceURL, "golang.org")
- if Equal(u1, u4) {
- t.Errorf("UUIDv3 generated same UUIDs for sane names in different namespaces: %s and %s", u1, u4)
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/LICENSE b/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/LICENSE
deleted file mode 100644
index 58f5819..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2016 Josh Baker
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/README.md b/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/README.md
deleted file mode 100644
index bc26c3c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/README.md
+++ /dev/null
@@ -1,371 +0,0 @@
-<p align="center">
-<img
- src="logo.png"
- width="240" height="78" border="0" alt="GJSON">
-<br>
-<a href="https://travis-ci.org/tidwall/gjson"><img src="https://img.shields.io/travis/tidwall/gjson.svg?style=flat-square" alt="Build Status"></a><!--
-<a href="http://gocover.io/github.com/tidwall/gjson"><img src="https://img.shields.io/badge/coverage-97%25-brightgreen.svg?style=flat-square" alt="Code Coverage"></a>
--->
-<a href="https://godoc.org/github.com/tidwall/gjson"><img src="https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt="GoDoc"></a>
-</p>
-
-<p align="center">get a json value quickly</a></p>
-
-GJSON is a Go package that provides a [very fast](#performance) and simple way to get a value from a json document. The purpose for this library it to give efficient json indexing for the [BuntDB](https://github.com/tidwall/buntdb) project.
-
-For a command line interface check out [JSONed](https://github.com/tidwall/jsoned).
-
-Getting Started
-===============
-
-## Installing
-
-To start using GJSON, install Go and run `go get`:
-
-```sh
-$ go get -u github.com/tidwall/gjson
-```
-
-This will retrieve the library.
-
-## Get a value
-Get searches json for the specified path. A path is in dot syntax, such as "name.last" or "age". This function expects that the json is well-formed and validates. Invalid json will not panic, but it may return back unexpected results. When the value is found it's returned immediately.
-
-```go
-package main
-
-import "github.com/tidwall/gjson"
-
-const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`
-
-func main() {
- value := gjson.Get(json, "name.last")
- println(value.String())
-}
-```
-
-This will print:
-
-```
-Prichard
-```
-*There's also the [GetMany](#get-multiple-values-at-once) function to get multiple values at once, and [GetBytes](#working-with-bytes) for working with JSON byte slices.*
-
-## Path Syntax
-
-A path is a series of keys separated by a dot.
-A key may contain special wildcard characters '\*' and '?'.
-To access an array value use the index as the key.
-To get the number of elements in an array or to access a child path, use the '#' character.
-The dot and wildcard characters can be escaped with '\'.
-
-```json
-{
- "name": {"first": "Tom", "last": "Anderson"},
- "age":37,
- "children": ["Sara","Alex","Jack"],
- "fav.movie": "Deer Hunter",
- "friends": [
- {"first": "Dale", "last": "Murphy", "age": 44},
- {"first": "Roger", "last": "Craig", "age": 68},
- {"first": "Jane", "last": "Murphy", "age": 47}
- ]
-}
-```
-```
-"name.last" >> "Anderson"
-"age" >> 37
-"children" >> ["Sara","Alex","Jack"]
-"children.#" >> 3
-"children.1" >> "Alex"
-"child*.2" >> "Jack"
-"c?ildren.0" >> "Sara"
-"fav\.movie" >> "Deer Hunter"
-"friends.#.first" >> ["Dale","Roger","Jane"]
-"friends.1.last" >> "Craig"
-```
-
-You can also query an array for the first match by using `#[...]`, or find all matches with `#[...]#`.
-Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=` comparison operators and the simple pattern matching `%` operator.
-
-```
-friends.#[last=="Murphy"].first >> "Dale"
-friends.#[last=="Murphy"]#.first >> ["Dale","Jane"]
-friends.#[age>45]#.last >> ["Craig","Murphy"]
-friends.#[first%"D*"].last >> "Murphy"
-```
-
-## Result Type
-
-GJSON supports the json types `string`, `number`, `bool`, and `null`.
-Arrays and Objects are returned as their raw json types.
-
-The `Result` type holds one of these:
-
-```
-bool, for JSON booleans
-float64, for JSON numbers
-string, for JSON string literals
-nil, for JSON null
-```
-
-To directly access the value:
-
-```go
-result.Type // can be String, Number, True, False, Null, or JSON
-result.Str // holds the string
-result.Num // holds the float64 number
-result.Raw // holds the raw json
-result.Index // index of raw value in original json, zero means index unknown
-```
-
-There are a variety of handy functions that work on a result:
-
-```go
-result.Value() interface{}
-result.Int() int64
-result.Uint() uint64
-result.Float() float64
-result.String() string
-result.Bool() bool
-result.Array() []gjson.Result
-result.Map() map[string]gjson.Result
-result.Get(path string) Result
-result.ForEach(iterator func(key, value Result) bool)
-result.Less(token Result, caseSensitive bool) bool
-```
-
-The `result.Value()` function returns an `interface{}` which requires type assertion and is one of the following Go types:
-
-
-
-The `result.Array()` function returns back an array of values.
-If the result represents a non-existent value, then an empty array will be returned.
-If the result is not a JSON array, the return value will be an array containing one result.
-
-```go
-boolean >> bool
-number >> float64
-string >> string
-null >> nil
-array >> []interface{}
-object >> map[string]interface{}
-```
-
-## Get nested array values
-
-Suppose you want all the last names from the following json:
-
-```json
-{
- "programmers": [
- {
- "firstName": "Janet",
- "lastName": "McLaughlin",
- }, {
- "firstName": "Elliotte",
- "lastName": "Hunter",
- }, {
- "firstName": "Jason",
- "lastName": "Harold",
- }
- ]
-}`
-```
-
-You would use the path "programmers.#.lastName" like such:
-
-```go
-result := gjson.Get(json, "programmers.#.lastName")
-for _,name := range result.Array() {
- println(name.String())
-}
-```
-
-You can also query an object inside an array:
-
-```go
-name := gjson.Get(json, `programmers.#[lastName="Hunter"].firstName`)
-println(name.String()) // prints "Elliotte"
-```
-
-## Iterate through an object or array
-
-The `ForEach` function allows for quickly iterating through an object or array.
-The key and value are passed to the iterator function for objects.
-Only the value is passed for arrays.
-Returning `false` from an iterator will stop iteration.
-
-```go
-result := gjson.Get(json, "programmers")
-result.ForEach(func(key, value gjson.Result) bool{
- println(value.String())
- return true // keep iterating
-})
-```
-
-## Simple Parse and Get
-
-There's a `Parse(json)` function that will do a simple parse, and `result.Get(path)` that will search a result.
-
-For example, all of these will return the same result:
-
-```go
-gjson.Parse(json).Get("name").Get("last")
-gjson.Get(json, "name").Get("last")
-gjson.Get(json, "name.last")
-```
-
-## Check for the existence of a value
-
-Sometimes you just want to know if a value exists.
-
-```go
-value := gjson.Get(json, "name.last")
-if !value.Exists() {
- println("no last name")
-} else {
- println(value.String())
-}
-
-// Or as one step
-if gjson.Get(json, "name.last").Exists(){
- println("has a last name")
-}
-```
-
-## Unmarshal to a map
-
-To unmarshal to a `map[string]interface{}`:
-
-```go
-m, ok := gjson.Parse(json).Value().(map[string]interface{})
-if !ok{
- // not a map
-}
-```
-
-## Working with Bytes
-
-If your JSON is contained in a `[]byte` slice, there's the [GetBytes](https://godoc.org/github.com/tidwall/gjson#GetBytes) function. This is preferred over `Get(string(data), path)`.
-
-```go
-var json []byte = ...
-result := gjson.GetBytes(json, path)
-```
-
-If you are using the `gjson.GetBytes(json, path)` function and you want to avoid converting `result.Raw` to a `[]byte`, then you can use this pattern:
-
-```go
-var json []byte = ...
-result := gjson.GetBytes(json, path)
-var raw []byte
-if result.Index > 0 {
- raw = json[result.Index:result.Index+len(result.Raw)]
-} else {
- raw = []byte(result.Raw)
-}
-```
-
-This is a best-effort no allocation sub slice of the original json. This method utilizes the `result.Index` field, which is the position of the raw data in the original json. It's possible that the value of `result.Index` equals zero, in which case the `result.Raw` is converted to a `[]byte`.
-
-## Get multiple values at once
-
-The `GetMany` function can be used to get multiple values at the same time, and is optimized to scan over a JSON payload once.
-
-```go
-results := gjson.GetMany(json, "name.first", "name.last", "age")
-```
-
-The return value is a `[]Result`, which will always contain exactly the same number of items as the input paths.
-
-## Performance
-
-Benchmarks of GJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/),
-[ffjson](https://github.com/pquerna/ffjson),
-[EasyJSON](https://github.com/mailru/easyjson),
-and [jsonparser](https://github.com/buger/jsonparser)
-
-```
-BenchmarkGJSONGet-8 15000000 333 ns/op 0 B/op 0 allocs/op
-BenchmarkGJSONUnmarshalMap-8 900000 4188 ns/op 1920 B/op 26 allocs/op
-BenchmarkJSONUnmarshalMap-8 600000 8908 ns/op 3048 B/op 69 allocs/op
-BenchmarkJSONUnmarshalStruct-8 600000 9026 ns/op 1832 B/op 69 allocs/op
-BenchmarkJSONDecoder-8 300000 14339 ns/op 4224 B/op 184 allocs/op
-BenchmarkFFJSONLexer-8 1500000 3156 ns/op 896 B/op 8 allocs/op
-BenchmarkEasyJSONLexer-8 3000000 938 ns/op 613 B/op 6 allocs/op
-BenchmarkJSONParserGet-8 3000000 442 ns/op 21 B/op 0 allocs/op
-```
-
-Benchmarks for the `GetMany` function:
-
-```
-BenchmarkGJSONGetMany4Paths-8 4000000 319 ns/op 112 B/op 0 allocs/op
-BenchmarkGJSONGetMany8Paths-8 8000000 218 ns/op 56 B/op 0 allocs/op
-BenchmarkGJSONGetMany16Paths-8 16000000 160 ns/op 56 B/op 0 allocs/op
-BenchmarkGJSONGetMany32Paths-8 32000000 130 ns/op 64 B/op 0 allocs/op
-BenchmarkGJSONGetMany64Paths-8 64000000 117 ns/op 64 B/op 0 allocs/op
-BenchmarkGJSONGetMany128Paths-8 128000000 109 ns/op 64 B/op 0 allocs/op
-```
-
-JSON document used:
-
-```json
-{
- "widget": {
- "debug": "on",
- "window": {
- "title": "Sample Konfabulator Widget",
- "name": "main_window",
- "width": 500,
- "height": 500
- },
- "image": {
- "src": "Images/Sun.png",
- "hOffset": 250,
- "vOffset": 250,
- "alignment": "center"
- },
- "text": {
- "data": "Click Here",
- "size": 36,
- "style": "bold",
- "vOffset": 100,
- "alignment": "center",
- "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
- }
- }
-}
-```
-
-Each operation was rotated though one of the following search paths:
-
-```
-widget.window.name
-widget.image.hOffset
-widget.text.onMouseUp
-```
-
-For the `GetMany` benchmarks these paths are used:
-
-```
-widget.window.name
-widget.image.hOffset
-widget.text.onMouseUp
-widget.window.title
-widget.image.alignment
-widget.text.style
-widget.window.height
-widget.image.src
-widget.text.data
-widget.text.size
-```
-
-*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.7.*
-
-## Contact
-Josh Baker [@tidwall](http://twitter.com/tidwall)
-
-## License
-
-GJSON source code is available under the MIT [License](/LICENSE).
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/gjson.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/gjson.go
deleted file mode 100644
index 1ee26c9..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/gjson.go
+++ /dev/null
@@ -1,1942 +0,0 @@
-// Package gjson provides searching for json strings.
-package gjson
-
-import (
- "reflect"
- "strconv"
- "unsafe"
-
- "github.com/tidwall/match"
-)
-
-// Type is Result type
-type Type int
-
-const (
- // Null is a null json value
- Null Type = iota
- // False is a json false boolean
- False
- // Number is json number
- Number
- // String is a json string
- String
- // True is a json true boolean
- True
- // JSON is a raw block of JSON
- JSON
-)
-
-// String returns a string representation of the type.
-func (t Type) String() string {
- switch t {
- default:
- return ""
- case Null:
- return "Null"
- case False:
- return "False"
- case Number:
- return "Number"
- case String:
- return "String"
- case True:
- return "True"
- case JSON:
- return "JSON"
- }
-}
-
-// Result represents a json value that is returned from Get().
-type Result struct {
- // Type is the json type
- Type Type
- // Raw is the raw json
- Raw string
- // Str is the json string
- Str string
- // Num is the json number
- Num float64
- // Index of raw value in original json, zero means index unknown
- Index int
-}
-
-// String returns a string representation of the value.
-func (t Result) String() string {
- switch t.Type {
- default:
- return "null"
- case False:
- return "false"
- case Number:
- return strconv.FormatFloat(t.Num, 'f', -1, 64)
- case String:
- return t.Str
- case JSON:
- return t.Raw
- case True:
- return "true"
- }
-}
-
-// Bool returns an boolean representation.
-func (t Result) Bool() bool {
- switch t.Type {
- default:
- return false
- case True:
- return true
- case String:
- return t.Str != "" && t.Str != "0"
- case Number:
- return t.Num != 0
- }
-}
-
-// Int returns an integer representation.
-func (t Result) Int() int64 {
- switch t.Type {
- default:
- return 0
- case True:
- return 1
- case String:
- n, _ := strconv.ParseInt(t.Str, 10, 64)
- return n
- case Number:
- return int64(t.Num)
- }
-}
-
-// Uint returns an unsigned integer representation.
-func (t Result) Uint() uint64 {
- switch t.Type {
- default:
- return 0
- case True:
- return 1
- case String:
- n, _ := strconv.ParseUint(t.Str, 10, 64)
- return n
- case Number:
- return uint64(t.Num)
- }
-}
-
-// Float returns an float64 representation.
-func (t Result) Float() float64 {
- switch t.Type {
- default:
- return 0
- case True:
- return 1
- case String:
- n, _ := strconv.ParseFloat(t.Str, 64)
- return n
- case Number:
- return t.Num
- }
-}
-
-// Array returns back an array of values.
-// If the result represents a non-existent value, then an empty array will be returned.
-// If the result is not a JSON array, the return value will be an array containing one result.
-func (t Result) Array() []Result {
- if !t.Exists() {
- return nil
- }
- if t.Type != JSON {
- return []Result{t}
- }
- r := t.arrayOrMap('[', false)
- return r.a
-}
-
-// ForEach iterates through values.
-// If the result represents a non-existent value, then no values will be iterated.
-// If the result is an Object, the iterator will pass the key and value of each item.
-// If the result is an Array, the iterator will only pass the value of each item.
-// If the result is not a JSON array or object, the iterator will pass back one value equal to the result.
-func (t Result) ForEach(iterator func(key, value Result) bool) {
- if !t.Exists() {
- return
- }
- if t.Type != JSON {
- iterator(Result{}, t)
- return
- }
- json := t.Raw
- var keys bool
- var i int
- var key, value Result
- for ; i < len(json); i++ {
- if json[i] == '{' {
- i++
- key.Type = String
- keys = true
- break
- } else if json[i] == '[' {
- i++
- break
- }
- if json[i] > ' ' {
- return
- }
- }
- var str string
- var vesc bool
- var ok bool
- for ; i < len(json); i++ {
- if keys {
- if json[i] != '"' {
- continue
- }
- s := i
- i, str, vesc, ok = parseString(json, i+1)
- if !ok {
- return
- }
- if vesc {
- key.Str = unescape(str[1 : len(str)-1])
- } else {
- key.Str = str[1 : len(str)-1]
- }
- key.Raw = str
- key.Index = s
- }
- for ; i < len(json); i++ {
- if json[i] <= ' ' || json[i] == ',' || json[i] == ':' {
- continue
- }
- break
- }
- s := i
- i, value, ok = parseAny(json, i, true)
- if !ok {
- return
- }
- value.Index = s
- if !iterator(key, value) {
- return
- }
- }
-}
-
-// Map returns back an map of values. The result should be a JSON array.
-func (t Result) Map() map[string]Result {
- if t.Type != JSON {
- return map[string]Result{}
- }
- r := t.arrayOrMap('{', false)
- return r.o
-}
-
-// Get searches result for the specified path.
-// The result should be a JSON array or object.
-func (t Result) Get(path string) Result {
- return Get(t.Raw, path)
-}
-
-type arrayOrMapResult struct {
- a []Result
- ai []interface{}
- o map[string]Result
- oi map[string]interface{}
- vc byte
-}
-
-func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) {
- var json = t.Raw
- var i int
- var value Result
- var count int
- var key Result
- if vc == 0 {
- for ; i < len(json); i++ {
- if json[i] == '{' || json[i] == '[' {
- r.vc = json[i]
- i++
- break
- }
- if json[i] > ' ' {
- goto end
- }
- }
- } else {
- for ; i < len(json); i++ {
- if json[i] == vc {
- i++
- break
- }
- if json[i] > ' ' {
- goto end
- }
- }
- r.vc = vc
- }
- if r.vc == '{' {
- if valueize {
- r.oi = make(map[string]interface{})
- } else {
- r.o = make(map[string]Result)
- }
- } else {
- if valueize {
- r.ai = make([]interface{}, 0)
- } else {
- r.a = make([]Result, 0)
- }
- }
- for ; i < len(json); i++ {
- if json[i] <= ' ' {
- continue
- }
- // get next value
- if json[i] == ']' || json[i] == '}' {
- break
- }
- switch json[i] {
- default:
- if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' {
- value.Type = Number
- value.Raw, value.Num = tonum(json[i:])
- } else {
- continue
- }
- case '{', '[':
- value.Type = JSON
- value.Raw = squash(json[i:])
- case 'n':
- value.Type = Null
- value.Raw = tolit(json[i:])
- case 't':
- value.Type = True
- value.Raw = tolit(json[i:])
- case 'f':
- value.Type = False
- value.Raw = tolit(json[i:])
- case '"':
- value.Type = String
- value.Raw, value.Str = tostr(json[i:])
- }
- i += len(value.Raw) - 1
-
- if r.vc == '{' {
- if count%2 == 0 {
- key = value
- } else {
- if valueize {
- r.oi[key.Str] = value.Value()
- } else {
- r.o[key.Str] = value
- }
- }
- count++
- } else {
- if valueize {
- r.ai = append(r.ai, value.Value())
- } else {
- r.a = append(r.a, value)
- }
- }
- }
-end:
- return
-}
-
-// Parse parses the json and returns a result.
-func Parse(json string) Result {
- var value Result
- for i := 0; i < len(json); i++ {
- if json[i] == '{' || json[i] == '[' {
- value.Type = JSON
- value.Raw = json[i:] // just take the entire raw
- break
- }
- if json[i] <= ' ' {
- continue
- }
- switch json[i] {
- default:
- if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' {
- value.Type = Number
- value.Raw, value.Num = tonum(json[i:])
- } else {
- return Result{}
- }
- case 'n':
- value.Type = Null
- value.Raw = tolit(json[i:])
- case 't':
- value.Type = True
- value.Raw = tolit(json[i:])
- case 'f':
- value.Type = False
- value.Raw = tolit(json[i:])
- case '"':
- value.Type = String
- value.Raw, value.Str = tostr(json[i:])
- }
- break
- }
- return value
-}
-
-// ParseBytes parses the json and returns a result.
-// If working with bytes, this method preferred over Parse(string(data))
-func ParseBytes(json []byte) Result {
- return Parse(string(json))
-}
-
-func squash(json string) string {
- // expects that the lead character is a '[' or '{'
- // squash the value, ignoring all nested arrays and objects.
- // the first '[' or '{' has already been read
- depth := 1
- for i := 1; i < len(json); i++ {
- if json[i] >= '"' && json[i] <= '}' {
- switch json[i] {
- case '"':
- i++
- s2 := i
- for ; i < len(json); i++ {
- if json[i] > '\\' {
- continue
- }
- if json[i] == '"' {
- // look for an escaped slash
- if json[i-1] == '\\' {
- n := 0
- for j := i - 2; j > s2-1; j-- {
- if json[j] != '\\' {
- break
- }
- n++
- }
- if n%2 == 0 {
- continue
- }
- }
- break
- }
- }
- case '{', '[':
- depth++
- case '}', ']':
- depth--
- if depth == 0 {
- return json[:i+1]
- }
- }
- }
- }
- return json
-}
-
-func tonum(json string) (raw string, num float64) {
- for i := 1; i < len(json); i++ {
- // less than dash might have valid characters
- if json[i] <= '-' {
- if json[i] <= ' ' || json[i] == ',' {
- // break on whitespace and comma
- raw = json[:i]
- num, _ = strconv.ParseFloat(raw, 64)
- return
- }
- // could be a '+' or '-'. let's assume so.
- continue
- }
- if json[i] < ']' {
- // probably a valid number
- continue
- }
- if json[i] == 'e' || json[i] == 'E' {
- // allow for exponential numbers
- continue
- }
- // likely a ']' or '}'
- raw = json[:i]
- num, _ = strconv.ParseFloat(raw, 64)
- return
- }
- raw = json
- num, _ = strconv.ParseFloat(raw, 64)
- return
-}
-
-func tolit(json string) (raw string) {
- for i := 1; i < len(json); i++ {
- if json[i] <= 'a' || json[i] >= 'z' {
- return json[:i]
- }
- }
- return json
-}
-
-func tostr(json string) (raw string, str string) {
- // expects that the lead character is a '"'
- for i := 1; i < len(json); i++ {
- if json[i] > '\\' {
- continue
- }
- if json[i] == '"' {
- return json[:i+1], json[1:i]
- }
- if json[i] == '\\' {
- i++
- for ; i < len(json); i++ {
- if json[i] > '\\' {
- continue
- }
- if json[i] == '"' {
- // look for an escaped slash
- if json[i-1] == '\\' {
- n := 0
- for j := i - 2; j > 0; j-- {
- if json[j] != '\\' {
- break
- }
- n++
- }
- if n%2 == 0 {
- continue
- }
- }
- break
- }
- }
- var ret string
- if i+1 < len(json) {
- ret = json[:i+1]
- } else {
- ret = json[:i]
- }
- return ret, unescape(json[1:i])
- }
- }
- return json, json[1:]
-}
-
-// Exists returns true if value exists.
-//
-// if gjson.Get(json, "name.last").Exists(){
-// println("value exists")
-// }
-func (t Result) Exists() bool {
- return t.Type != Null || len(t.Raw) != 0
-}
-
-// Value returns one of these types:
-//
-// bool, for JSON booleans
-// float64, for JSON numbers
-// Number, for JSON numbers
-// string, for JSON string literals
-// nil, for JSON null
-//
-func (t Result) Value() interface{} {
- if t.Type == String {
- return t.Str
- }
- switch t.Type {
- default:
- return nil
- case False:
- return false
- case Number:
- return t.Num
- case JSON:
- r := t.arrayOrMap(0, true)
- if r.vc == '{' {
- return r.oi
- } else if r.vc == '[' {
- return r.ai
- }
- return nil
- case True:
- return true
- }
-}
-
-func parseString(json string, i int) (int, string, bool, bool) {
- var s = i
- for ; i < len(json); i++ {
- if json[i] > '\\' {
- continue
- }
- if json[i] == '"' {
- return i + 1, json[s-1 : i+1], false, true
- }
- if json[i] == '\\' {
- i++
- for ; i < len(json); i++ {
- if json[i] > '\\' {
- continue
- }
- if json[i] == '"' {
- // look for an escaped slash
- if json[i-1] == '\\' {
- n := 0
- for j := i - 2; j > 0; j-- {
- if json[j] != '\\' {
- break
- }
- n++
- }
- if n%2 == 0 {
- continue
- }
- }
- return i + 1, json[s-1 : i+1], true, true
- }
- }
- break
- }
- }
- return i, json[s-1:], false, false
-}
-
-func parseNumber(json string, i int) (int, string) {
- var s = i
- i++
- for ; i < len(json); i++ {
- if json[i] <= ' ' || json[i] == ',' || json[i] == ']' || json[i] == '}' {
- return i, json[s:i]
- }
- }
- return i, json[s:]
-}
-
-func parseLiteral(json string, i int) (int, string) {
- var s = i
- i++
- for ; i < len(json); i++ {
- if json[i] < 'a' || json[i] > 'z' {
- return i, json[s:i]
- }
- }
- return i, json[s:]
-}
-
-type arrayPathResult struct {
- part string
- path string
- more bool
- alogok bool
- arrch bool
- alogkey string
- query struct {
- on bool
- path string
- op string
- value string
- all bool
- }
-}
-
-func parseArrayPath(path string) (r arrayPathResult) {
- for i := 0; i < len(path); i++ {
- if path[i] == '.' {
- r.part = path[:i]
- r.path = path[i+1:]
- r.more = true
- return
- }
- if path[i] == '#' {
- r.arrch = true
- if i == 0 && len(path) > 1 {
- if path[1] == '.' {
- r.alogok = true
- r.alogkey = path[2:]
- r.path = path[:1]
- } else if path[1] == '[' {
- r.query.on = true
- // query
- i += 2
- // whitespace
- for ; i < len(path); i++ {
- if path[i] > ' ' {
- break
- }
- }
- s := i
- for ; i < len(path); i++ {
- if path[i] <= ' ' ||
- path[i] == '!' ||
- path[i] == '=' ||
- path[i] == '<' ||
- path[i] == '>' ||
- path[i] == '%' ||
- path[i] == ']' {
- break
- }
- }
- r.query.path = path[s:i]
- // whitespace
- for ; i < len(path); i++ {
- if path[i] > ' ' {
- break
- }
- }
- if i < len(path) {
- s = i
- if path[i] == '!' {
- if i < len(path)-1 && path[i+1] == '=' {
- i++
- }
- } else if path[i] == '<' || path[i] == '>' {
- if i < len(path)-1 && path[i+1] == '=' {
- i++
- }
- } else if path[i] == '=' {
- if i < len(path)-1 && path[i+1] == '=' {
- s++
- i++
- }
- }
- i++
- r.query.op = path[s:i]
- // whitespace
- for ; i < len(path); i++ {
- if path[i] > ' ' {
- break
- }
- }
- s = i
- for ; i < len(path); i++ {
- if path[i] == '"' {
- i++
- s2 := i
- for ; i < len(path); i++ {
- if path[i] > '\\' {
- continue
- }
- if path[i] == '"' {
- // look for an escaped slash
- if path[i-1] == '\\' {
- n := 0
- for j := i - 2; j > s2-1; j-- {
- if path[j] != '\\' {
- break
- }
- n++
- }
- if n%2 == 0 {
- continue
- }
- }
- break
- }
- }
- } else if path[i] == ']' {
- if i+1 < len(path) && path[i+1] == '#' {
- r.query.all = true
- }
- break
- }
- }
- if i > len(path) {
- i = len(path)
- }
- v := path[s:i]
- for len(v) > 0 && v[len(v)-1] <= ' ' {
- v = v[:len(v)-1]
- }
- r.query.value = v
- }
- }
- }
- continue
- }
- }
- r.part = path
- r.path = ""
- return
-}
-
-type objectPathResult struct {
- part string
- path string
- wild bool
- more bool
-}
-
-func parseObjectPath(path string) (r objectPathResult) {
- for i := 0; i < len(path); i++ {
- if path[i] == '.' {
- r.part = path[:i]
- r.path = path[i+1:]
- r.more = true
- return
- }
- if path[i] == '*' || path[i] == '?' {
- r.wild = true
- continue
- }
- if path[i] == '\\' {
- // go into escape mode. this is a slower path that
- // strips off the escape character from the part.
- epart := []byte(path[:i])
- i++
- if i < len(path) {
- epart = append(epart, path[i])
- i++
- for ; i < len(path); i++ {
- if path[i] == '\\' {
- i++
- if i < len(path) {
- epart = append(epart, path[i])
- }
- continue
- } else if path[i] == '.' {
- r.part = string(epart)
- r.path = path[i+1:]
- r.more = true
- return
- } else if path[i] == '*' || path[i] == '?' {
- r.wild = true
- }
- epart = append(epart, path[i])
- }
- }
- // append the last part
- r.part = string(epart)
- return
- }
- }
- r.part = path
- return
-}
-
-func parseSquash(json string, i int) (int, string) {
- // expects that the lead character is a '[' or '{'
- // squash the value, ignoring all nested arrays and objects.
- // the first '[' or '{' has already been read
- s := i
- i++
- depth := 1
- for ; i < len(json); i++ {
- if json[i] >= '"' && json[i] <= '}' {
- switch json[i] {
- case '"':
- i++
- s2 := i
- for ; i < len(json); i++ {
- if json[i] > '\\' {
- continue
- }
- if json[i] == '"' {
- // look for an escaped slash
- if json[i-1] == '\\' {
- n := 0
- for j := i - 2; j > s2-1; j-- {
- if json[j] != '\\' {
- break
- }
- n++
- }
- if n%2 == 0 {
- continue
- }
- }
- break
- }
- }
- case '{', '[':
- depth++
- case '}', ']':
- depth--
- if depth == 0 {
- i++
- return i, json[s:i]
- }
- }
- }
- }
- return i, json[s:]
-}
-
-func parseObject(c *parseContext, i int, path string) (int, bool) {
- var pmatch, kesc, vesc, ok, hit bool
- var key, val string
- rp := parseObjectPath(path)
- for i < len(c.json) {
- for ; i < len(c.json); i++ {
- if c.json[i] == '"' {
- // parse_key_string
- // this is slightly different from getting s string value
- // because we don't need the outer quotes.
- i++
- var s = i
- for ; i < len(c.json); i++ {
- if c.json[i] > '\\' {
- continue
- }
- if c.json[i] == '"' {
- i, key, kesc, ok = i+1, c.json[s:i], false, true
- goto parse_key_string_done
- }
- if c.json[i] == '\\' {
- i++
- for ; i < len(c.json); i++ {
- if c.json[i] > '\\' {
- continue
- }
- if c.json[i] == '"' {
- // look for an escaped slash
- if c.json[i-1] == '\\' {
- n := 0
- for j := i - 2; j > 0; j-- {
- if c.json[j] != '\\' {
- break
- }
- n++
- }
- if n%2 == 0 {
- continue
- }
- }
- i, key, kesc, ok = i+1, c.json[s:i], true, true
- goto parse_key_string_done
- }
- }
- break
- }
- }
- i, key, kesc, ok = i, c.json[s:], false, false
- parse_key_string_done:
- break
- }
- if c.json[i] == '}' {
- return i + 1, false
- }
- }
- if !ok {
- return i, false
- }
- if rp.wild {
- if kesc {
- pmatch = match.Match(unescape(key), rp.part)
- } else {
- pmatch = match.Match(key, rp.part)
- }
- } else {
- if kesc {
- pmatch = rp.part == unescape(key)
- } else {
- pmatch = rp.part == key
- }
- }
- hit = pmatch && !rp.more
- for ; i < len(c.json); i++ {
- switch c.json[i] {
- default:
- continue
- case '"':
- i++
- i, val, vesc, ok = parseString(c.json, i)
- if !ok {
- return i, false
- }
- if hit {
- if vesc {
- c.value.Str = unescape(val[1 : len(val)-1])
- } else {
- c.value.Str = val[1 : len(val)-1]
- }
- c.value.Raw = val
- c.value.Type = String
- return i, true
- }
- case '{':
- if pmatch && !hit {
- i, hit = parseObject(c, i+1, rp.path)
- if hit {
- return i, true
- }
- } else {
- i, val = parseSquash(c.json, i)
- if hit {
- c.value.Raw = val
- c.value.Type = JSON
- return i, true
- }
- }
- case '[':
- if pmatch && !hit {
- i, hit = parseArray(c, i+1, rp.path)
- if hit {
- return i, true
- }
- } else {
- i, val = parseSquash(c.json, i)
- if hit {
- c.value.Raw = val
- c.value.Type = JSON
- return i, true
- }
- }
- case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- i, val = parseNumber(c.json, i)
- if hit {
- c.value.Raw = val
- c.value.Type = Number
- c.value.Num, _ = strconv.ParseFloat(val, 64)
- return i, true
- }
- case 't', 'f', 'n':
- vc := c.json[i]
- i, val = parseLiteral(c.json, i)
- if hit {
- c.value.Raw = val
- switch vc {
- case 't':
- c.value.Type = True
- case 'f':
- c.value.Type = False
- }
- return i, true
- }
- }
- break
- }
- }
- return i, false
-}
-func queryMatches(rp *arrayPathResult, value Result) bool {
- rpv := rp.query.value
- if len(rpv) > 2 && rpv[0] == '"' && rpv[len(rpv)-1] == '"' {
- rpv = rpv[1 : len(rpv)-1]
- }
- switch value.Type {
- case String:
- switch rp.query.op {
- case "=":
- return value.Str == rpv
- case "!=":
- return value.Str != rpv
- case "<":
- return value.Str < rpv
- case "<=":
- return value.Str <= rpv
- case ">":
- return value.Str > rpv
- case ">=":
- return value.Str >= rpv
- case "%":
- return match.Match(value.Str, rpv)
- }
- case Number:
- rpvn, _ := strconv.ParseFloat(rpv, 64)
- switch rp.query.op {
- case "=":
- return value.Num == rpvn
- case "!=":
- return value.Num == rpvn
- case "<":
- return value.Num < rpvn
- case "<=":
- return value.Num <= rpvn
- case ">":
- return value.Num > rpvn
- case ">=":
- return value.Num >= rpvn
- }
- case True:
- switch rp.query.op {
- case "=":
- return rpv == "true"
- case "!=":
- return rpv != "true"
- case ">":
- return rpv == "false"
- case ">=":
- return true
- }
- case False:
- switch rp.query.op {
- case "=":
- return rpv == "false"
- case "!=":
- return rpv != "false"
- case "<":
- return rpv == "true"
- case "<=":
- return true
- }
- }
- return false
-}
-func parseArray(c *parseContext, i int, path string) (int, bool) {
- var pmatch, vesc, ok, hit bool
- var val string
- var h int
- var alog []int
- var partidx int
- var multires []byte
- rp := parseArrayPath(path)
- if !rp.arrch {
- n, err := strconv.ParseUint(rp.part, 10, 64)
- if err != nil {
- partidx = -1
- } else {
- partidx = int(n)
- }
- }
- for i < len(c.json) {
- if !rp.arrch {
- pmatch = partidx == h
- hit = pmatch && !rp.more
- }
- h++
- if rp.alogok {
- alog = append(alog, i)
- }
- for ; i < len(c.json); i++ {
- switch c.json[i] {
- default:
- continue
- case '"':
- i++
- i, val, vesc, ok = parseString(c.json, i)
- if !ok {
- return i, false
- }
- if hit {
- if rp.alogok {
- break
- }
- if vesc {
- c.value.Str = unescape(val[1 : len(val)-1])
- } else {
- c.value.Str = val[1 : len(val)-1]
- }
- c.value.Raw = val
- c.value.Type = String
- return i, true
- }
- case '{':
- if pmatch && !hit {
- i, hit = parseObject(c, i+1, rp.path)
- if hit {
- if rp.alogok {
- break
- }
- return i, true
- }
- } else {
- i, val = parseSquash(c.json, i)
- if rp.query.on {
- res := Get(val, rp.query.path)
- if queryMatches(&rp, res) {
- if rp.more {
- res = Get(val, rp.path)
- } else {
- res = Result{Raw: val, Type: JSON}
- }
- if rp.query.all {
- if len(multires) == 0 {
- multires = append(multires, '[')
- } else {
- multires = append(multires, ',')
- }
- multires = append(multires, res.Raw...)
- } else {
- c.value = res
- return i, true
- }
- }
- } else if hit {
- if rp.alogok {
- break
- }
- c.value.Raw = val
- c.value.Type = JSON
- return i, true
- }
- }
- case '[':
- if pmatch && !hit {
- i, hit = parseArray(c, i+1, rp.path)
- if hit {
- if rp.alogok {
- break
- }
- return i, true
- }
- } else {
- i, val = parseSquash(c.json, i)
- if hit {
- if rp.alogok {
- break
- }
- c.value.Raw = val
- c.value.Type = JSON
- return i, true
- }
- }
- case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- i, val = parseNumber(c.json, i)
- if hit {
- if rp.alogok {
- break
- }
- c.value.Raw = val
- c.value.Type = Number
- c.value.Num, _ = strconv.ParseFloat(val, 64)
- return i, true
- }
- case 't', 'f', 'n':
- vc := c.json[i]
- i, val = parseLiteral(c.json, i)
- if hit {
- if rp.alogok {
- break
- }
- c.value.Raw = val
- switch vc {
- case 't':
- c.value.Type = True
- case 'f':
- c.value.Type = False
- }
- return i, true
- }
- case ']':
- if rp.arrch && rp.part == "#" {
- if rp.alogok {
- var jsons = make([]byte, 0, 64)
- jsons = append(jsons, '[')
- for j, k := 0, 0; j < len(alog); j++ {
- res := Get(c.json[alog[j]:], rp.alogkey)
- if res.Exists() {
- if k > 0 {
- jsons = append(jsons, ',')
- }
- jsons = append(jsons, []byte(res.Raw)...)
- k++
- }
- }
- jsons = append(jsons, ']')
- c.value.Type = JSON
- c.value.Raw = string(jsons)
- return i + 1, true
- } else {
- if rp.alogok {
- break
- }
- c.value.Raw = val
- c.value.Type = Number
- c.value.Num = float64(h - 1)
- c.calcd = true
- return i + 1, true
- }
- }
- if len(multires) > 0 && !c.value.Exists() {
- c.value = Result{
- Raw: string(append(multires, ']')),
- Type: JSON,
- }
- }
- return i + 1, false
- }
- break
- }
- }
- return i, false
-}
-
-type parseContext struct {
- json string
- value Result
- calcd bool
-}
-
-// Get searches json for the specified path.
-// A path is in dot syntax, such as "name.last" or "age".
-// This function expects that the json is well-formed, and does not validate.
-// Invalid json will not panic, but it may return back unexpected results.
-// When the value is found it's returned immediately.
-//
-// A path is a series of keys searated by a dot.
-// A key may contain special wildcard characters '*' and '?'.
-// To access an array value use the index as the key.
-// To get the number of elements in an array or to access a child path, use the '#' character.
-// The dot and wildcard character can be escaped with '\'.
-//
-// {
-// "name": {"first": "Tom", "last": "Anderson"},
-// "age":37,
-// "children": ["Sara","Alex","Jack"],
-// "friends": [
-// {"first": "James", "last": "Murphy"},
-// {"first": "Roger", "last": "Craig"}
-// ]
-// }
-// "name.last" >> "Anderson"
-// "age" >> 37
-// "children" >> ["Sara","Alex","Jack"]
-// "children.#" >> 3
-// "children.1" >> "Alex"
-// "child*.2" >> "Jack"
-// "c?ildren.0" >> "Sara"
-// "friends.#.first" >> ["James","Roger"]
-//
-func Get(json, path string) Result {
- var i int
- var c = &parseContext{json: json}
- for ; i < len(c.json); i++ {
- if c.json[i] == '{' {
- i++
- parseObject(c, i, path)
- break
- }
- if c.json[i] == '[' {
- i++
- parseArray(c, i, path)
- break
- }
- }
- if len(c.value.Raw) > 0 && !c.calcd {
- jhdr := *(*reflect.StringHeader)(unsafe.Pointer(&json))
- rhdr := *(*reflect.StringHeader)(unsafe.Pointer(&(c.value.Raw)))
- c.value.Index = int(rhdr.Data - jhdr.Data)
- if c.value.Index < 0 || c.value.Index >= len(json) {
- c.value.Index = 0
- }
- }
- return c.value
-}
-func fromBytesGet(result Result) Result {
- // safely get the string headers
- rawhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Raw))
- strhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Str))
- // create byte slice headers
- rawh := reflect.SliceHeader{Data: rawhi.Data, Len: rawhi.Len}
- strh := reflect.SliceHeader{Data: strhi.Data, Len: strhi.Len}
- if strh.Data == 0 {
- // str is nil
- if rawh.Data == 0 {
- // raw is nil
- result.Raw = ""
- } else {
- // raw has data, safely copy the slice header to a string
- result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
- }
- result.Str = ""
- } else if rawh.Data == 0 {
- // raw is nil
- result.Raw = ""
- // str has data, safely copy the slice header to a string
- result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
- } else if strh.Data >= rawh.Data &&
- int(strh.Data)+strh.Len <= int(rawh.Data)+rawh.Len {
- // Str is a substring of Raw.
- start := int(strh.Data - rawh.Data)
- // safely copy the raw slice header
- result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
- // substring the raw
- result.Str = result.Raw[start : start+strh.Len]
- } else {
- // safely copy both the raw and str slice headers to strings
- result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
- result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
- }
- return result
-}
-
-// GetBytes searches json for the specified path.
-// If working with bytes, this method preferred over Get(string(data), path)
-func GetBytes(json []byte, path string) Result {
- var result Result
- if json != nil {
- // unsafe cast to string
- result = Get(*(*string)(unsafe.Pointer(&json)), path)
- result = fromBytesGet(result)
- }
- return result
-}
-
-// unescape unescapes a string
-func unescape(json string) string { //, error) {
- var str = make([]byte, 0, len(json))
- for i := 0; i < len(json); i++ {
- switch {
- default:
- str = append(str, json[i])
- case json[i] < ' ':
- return "" //, errors.New("invalid character in string")
- case json[i] == '\\':
- i++
- if i >= len(json) {
- return "" //, errors.New("invalid escape sequence")
- }
- switch json[i] {
- default:
- return "" //, errors.New("invalid escape sequence")
- case '\\':
- str = append(str, '\\')
- case '/':
- str = append(str, '/')
- case 'b':
- str = append(str, '\b')
- case 'f':
- str = append(str, '\f')
- case 'n':
- str = append(str, '\n')
- case 'r':
- str = append(str, '\r')
- case 't':
- str = append(str, '\t')
- case '"':
- str = append(str, '"')
- case 'u':
- if i+5 > len(json) {
- return "" //, errors.New("invalid escape sequence")
- }
- i++
- // extract the codepoint
- var code int
- for j := i; j < i+4; j++ {
- switch {
- default:
- return "" //, errors.New("invalid escape sequence")
- case json[j] >= '0' && json[j] <= '9':
- code += (int(json[j]) - '0') << uint(12-(j-i)*4)
- case json[j] >= 'a' && json[j] <= 'f':
- code += (int(json[j]) - 'a' + 10) << uint(12-(j-i)*4)
- case json[j] >= 'a' && json[j] <= 'f':
- code += (int(json[j]) - 'a' + 10) << uint(12-(j-i)*4)
- }
- }
- str = append(str, []byte(string(code))...)
- i += 3 // only 3 because we will increment on the for-loop
- }
- }
- }
- return string(str) //, nil
-}
-
-// Less return true if a token is less than another token.
-// The caseSensitive paramater is used when the tokens are Strings.
-// The order when comparing two different type is:
-//
-// Null < False < Number < String < True < JSON
-//
-func (t Result) Less(token Result, caseSensitive bool) bool {
- if t.Type < token.Type {
- return true
- }
- if t.Type > token.Type {
- return false
- }
- if t.Type == String {
- if caseSensitive {
- return t.Str < token.Str
- }
- return stringLessInsensitive(t.Str, token.Str)
- }
- if t.Type == Number {
- return t.Num < token.Num
- }
- return t.Raw < token.Raw
-}
-
-func stringLessInsensitive(a, b string) bool {
- for i := 0; i < len(a) && i < len(b); i++ {
- if a[i] >= 'A' && a[i] <= 'Z' {
- if b[i] >= 'A' && b[i] <= 'Z' {
- // both are uppercase, do nothing
- if a[i] < b[i] {
- return true
- } else if a[i] > b[i] {
- return false
- }
- } else {
- // a is uppercase, convert a to lowercase
- if a[i]+32 < b[i] {
- return true
- } else if a[i]+32 > b[i] {
- return false
- }
- }
- } else if b[i] >= 'A' && b[i] <= 'Z' {
- // b is uppercase, convert b to lowercase
- if a[i] < b[i]+32 {
- return true
- } else if a[i] > b[i]+32 {
- return false
- }
- } else {
- // neither are uppercase
- if a[i] < b[i] {
- return true
- } else if a[i] > b[i] {
- return false
- }
- }
- }
- return len(a) < len(b)
-}
-
-// parseAny parses the next value from a json string.
-// A Result is returned when the hit param is set.
-// The return values are (i int, res Result, ok bool)
-func parseAny(json string, i int, hit bool) (int, Result, bool) {
- var res Result
- var val string
- for ; i < len(json); i++ {
- if json[i] == '{' || json[i] == '[' {
- i, val = parseSquash(json, i)
- if hit {
- res.Raw = val
- res.Type = JSON
- }
- return i, res, true
- }
- if json[i] <= ' ' {
- continue
- }
- switch json[i] {
- case '"':
- i++
- var vesc bool
- var ok bool
- i, val, vesc, ok = parseString(json, i)
- if !ok {
- return i, res, false
- }
- if hit {
- res.Type = String
- res.Raw = val
- if vesc {
- res.Str = unescape(val[1 : len(val)-1])
- } else {
- res.Str = val[1 : len(val)-1]
- }
- }
- return i, res, true
- case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- i, val = parseNumber(json, i)
- if hit {
- res.Raw = val
- res.Type = Number
- res.Num, _ = strconv.ParseFloat(val, 64)
- }
- return i, res, true
- case 't', 'f', 'n':
- vc := json[i]
- i, val = parseLiteral(json, i)
- if hit {
- res.Raw = val
- switch vc {
- case 't':
- res.Type = True
- case 'f':
- res.Type = False
- }
- return i, res, true
- }
- }
- }
- return i, res, false
-}
-
-var ( // used for testing
- testWatchForFallback bool
- testLastWasFallback bool
-)
-
-// areSimplePaths returns true if all the paths are simple enough
-// to parse quickly for GetMany(). Allows alpha-numeric, dots,
-// underscores, and the dollar sign. It does not allow non-alnum,
-// escape characters, or keys which start with a numbers.
-// For example:
-// "name.last" == OK
-// "user.id0" == OK
-// "user.ID" == OK
-// "user.first_name" == OK
-// "user.firstName" == OK
-// "user.0item" == BAD
-// "user.#id" == BAD
-// "user\.name" == BAD
-func areSimplePaths(paths []string) bool {
- for _, path := range paths {
- var fi int // first key index, for keys with numeric prefix
- for i := 0; i < len(path); i++ {
- if path[i] >= 'a' && path[i] <= 'z' {
- // a-z is likely to be the highest frequency charater.
- continue
- }
- if path[i] == '.' {
- fi = i + 1
- continue
- }
- if path[i] >= 'A' && path[i] <= 'Z' {
- continue
- }
- if path[i] == '_' || path[i] == '$' {
- continue
- }
- if i > fi && path[i] >= '0' && path[i] <= '9' {
- continue
- }
- return false
- }
- }
- return true
-}
-
-// GetMany searches json for the multiple paths.
-// The return value is a Result array where the number of items
-// will be equal to the number of input paths.
-func GetMany(json string, paths ...string) []Result {
- if len(paths) < 4 {
- if testWatchForFallback {
- testLastWasFallback = false
- }
- switch len(paths) {
- case 0:
- // return nil when no paths are specified.
- return nil
- case 1:
- return []Result{Get(json, paths[0])}
- case 2:
- return []Result{Get(json, paths[0]), Get(json, paths[1])}
- case 3:
- return []Result{Get(json, paths[0]), Get(json, paths[1]), Get(json, paths[2])}
- }
- }
- var results []Result
- var ok bool
- var i int
- if len(paths) > 512 {
- // we can only support up to 512 paths. Is that too many?
- goto fallback
- }
- if !areSimplePaths(paths) {
- // If there is even one path that is not considered "simple" then
- // we need to use the fallback method.
- goto fallback
- }
- // locate the object token.
- for ; i < len(json); i++ {
- if json[i] == '{' {
- i++
- break
- }
- if json[i] <= ' ' {
- continue
- }
- goto fallback
- }
- // use the call function table.
- if len(paths) <= 8 {
- results, ok = getMany8(json, i, paths)
- } else if len(paths) <= 16 {
- results, ok = getMany16(json, i, paths)
- } else if len(paths) <= 32 {
- results, ok = getMany32(json, i, paths)
- } else if len(paths) <= 64 {
- results, ok = getMany64(json, i, paths)
- } else if len(paths) <= 128 {
- results, ok = getMany128(json, i, paths)
- } else if len(paths) <= 256 {
- results, ok = getMany256(json, i, paths)
- } else if len(paths) <= 512 {
- results, ok = getMany512(json, i, paths)
- }
- if !ok {
- // there was some fault while parsing. we should try the
- // fallback method. This could result in performance
- // degregation in some cases.
- goto fallback
- }
- if testWatchForFallback {
- testLastWasFallback = false
- }
- return results
-fallback:
- results = results[:0]
- for i := 0; i < len(paths); i++ {
- results = append(results, Get(json, paths[i]))
- }
- if testWatchForFallback {
- testLastWasFallback = true
- }
- return results
-}
-
-// GetManyBytes searches json for the specified path.
-// If working with bytes, this method preferred over
-// GetMany(string(data), paths...)
-func GetManyBytes(json []byte, paths ...string) []Result {
- if json == nil {
- return GetMany("", paths...)
- }
- results := GetMany(*(*string)(unsafe.Pointer(&json)), paths...)
- for i := range results {
- results[i] = fromBytesGet(results[i])
- }
- return results
-}
-
-// parseGetMany parses a json object for keys that match against the callers
-// paths. It's a best-effort attempt and quickly locating and assigning the
-// values to the []Result array. If there are failures such as bad json, or
-// invalid input paths, or too much recursion, the function will exit with a
-// return value of 'false'.
-func parseGetMany(
- json string, i int,
- level uint, kplen int,
- paths []string, completed []bool, matches []uint64, results []Result,
-) (int, bool) {
- if level > 62 {
- // The recursion level is limited because the matches []uint64
- // array cannot handle more the 64-bits.
- return i, false
- }
- // At this point the last character read was a '{'.
- // Read all object keys and try to match against the paths.
- var key string
- var val string
- var vesc, ok bool
-next_key:
- for ; i < len(json); i++ {
- if json[i] == '"' {
- // read the key
- i, val, vesc, ok = parseString(json, i+1)
- if !ok {
- return i, false
- }
- if vesc {
- // the value is escaped
- key = unescape(val[1 : len(val)-1])
- } else {
- // just a plain old ascii key
- key = val[1 : len(val)-1]
- }
- var hasMatch bool
- var parsedVal bool
- var valOrgIndex int
- var valPathIndex int
- for j := 0; j < len(key); j++ {
- if key[j] == '.' {
- // we need to look for keys with dot and ignore them.
- if i, _, ok = parseAny(json, i, false); !ok {
- return i, false
- }
- continue next_key
- }
- }
- var usedPaths int
- // loop through paths and look for matches
- for j := 0; j < len(paths); j++ {
- if completed[j] {
- usedPaths++
- // ignore completed paths
- continue
- }
- if level > 0 && (matches[j]>>(level-1))&1 == 0 {
- // ignore unmatched paths
- usedPaths++
- continue
- }
-
- // try to match the key to the path
- // this is spaghetti code but the idea is to minimize
- // calls and variable assignments when comparing the
- // key to paths
- if len(paths[j])-kplen >= len(key) {
- i, k := kplen, 0
- for ; k < len(key); k, i = k+1, i+1 {
- if key[k] != paths[j][i] {
- // no match
- goto nomatch
- }
- }
- if i < len(paths[j]) {
- if paths[j][i] == '.' {
- // matched, but there still more keys in the path
- goto match_not_atend
- }
- }
- // matched and at the end of the path
- goto match_atend
- }
- // no match, jump to the nomatch label
- goto nomatch
- match_atend:
- // found a match
- // at the end of the path. we must take the value.
- usedPaths++
- if !parsedVal {
- // the value has not been parsed yet. let's do so.
- valOrgIndex = i // keep track of the current position.
- i, results[j], ok = parseAny(json, i, true)
- if !ok {
- return i, false
- }
- parsedVal = true
- valPathIndex = j
- } else {
- results[j] = results[valPathIndex]
- }
- // mark as complete
- completed[j] = true
- // jump over the match_not_atend label
- goto nomatch
- match_not_atend:
- // found a match
- // still in the middle of the path.
- usedPaths++
- // mark the path as matched
- matches[j] |= 1 << level
- if !hasMatch {
- hasMatch = true
- }
- nomatch: // noop label
- }
-
- if !parsedVal {
- if hasMatch {
- // we found a match and the value has not been parsed yet.
- // let's find out if the next value type is an object.
- for ; i < len(json); i++ {
- if json[i] <= ' ' || json[i] == ':' {
- continue
- }
- break
- }
- if i < len(json) {
- if json[i] == '{' {
- // it's an object. let's go deeper
- i, ok = parseGetMany(json, i+1, level+1, kplen+len(key)+1, paths, completed, matches, results)
- if !ok {
- return i, false
- }
- } else {
- // not an object. just parse and ignore.
- if i, _, ok = parseAny(json, i, false); !ok {
- return i, false
- }
- }
- }
- } else {
- // Since there was no matches we can just parse the value and
- // ignore the result.
- if i, _, ok = parseAny(json, i, false); !ok {
- return i, false
- }
- }
- } else if hasMatch && len(results[valPathIndex].Raw) > 0 && results[valPathIndex].Raw[0] == '{' {
- // The value was already parsed and the value type is an object.
- // Rewind the json index and let's parse deeper.
- i = valOrgIndex
- for ; i < len(json); i++ {
- if json[i] == '{' {
- break
- }
- }
- i, ok = parseGetMany(json, i+1, level+1, kplen+len(key)+1, paths, completed, matches, results)
- if !ok {
- return i, false
- }
- }
- if usedPaths == len(paths) {
- // all paths have been used, either completed or matched.
- // we should stop parsing this object to save CPU cycles.
- if level > 0 && i < len(json) {
- i, _ = parseSquash(json, i)
- }
- return i, true
- }
- } else if json[i] == '}' {
- // reached the end of the object. end it here.
- return i + 1, true
- }
- }
- return i, true
-}
-
-// Call table for GetMany. Using an isolated function allows for allocating
-// arrays with know capacities on the stack, as opposed to dynamically
-// allocating on the heap. This can provide a tremendous performance boost
-// by avoiding the GC.
-func getMany8(json string, i int, paths []string) ([]Result, bool) {
- const max = 8
- var completed = make([]bool, 0, max)
- var matches = make([]uint64, 0, max)
- var results = make([]Result, 0, max)
- completed = completed[0:len(paths):max]
- matches = matches[0:len(paths):max]
- results = results[0:len(paths):max]
- _, ok := parseGetMany(json, i, 0, 0, paths, completed, matches, results)
- return results, ok
-}
-func getMany16(json string, i int, paths []string) ([]Result, bool) {
- const max = 16
- var completed = make([]bool, 0, max)
- var matches = make([]uint64, 0, max)
- var results = make([]Result, 0, max)
- completed = completed[0:len(paths):max]
- matches = matches[0:len(paths):max]
- results = results[0:len(paths):max]
- _, ok := parseGetMany(json, i, 0, 0, paths, completed, matches, results)
- return results, ok
-}
-func getMany32(json string, i int, paths []string) ([]Result, bool) {
- const max = 32
- var completed = make([]bool, 0, max)
- var matches = make([]uint64, 0, max)
- var results = make([]Result, 0, max)
- completed = completed[0:len(paths):max]
- matches = matches[0:len(paths):max]
- results = results[0:len(paths):max]
- _, ok := parseGetMany(json, i, 0, 0, paths, completed, matches, results)
- return results, ok
-}
-func getMany64(json string, i int, paths []string) ([]Result, bool) {
- const max = 64
- var completed = make([]bool, 0, max)
- var matches = make([]uint64, 0, max)
- var results = make([]Result, 0, max)
- completed = completed[0:len(paths):max]
- matches = matches[0:len(paths):max]
- results = results[0:len(paths):max]
- _, ok := parseGetMany(json, i, 0, 0, paths, completed, matches, results)
- return results, ok
-}
-func getMany128(json string, i int, paths []string) ([]Result, bool) {
- const max = 128
- var completed = make([]bool, 0, max)
- var matches = make([]uint64, 0, max)
- var results = make([]Result, 0, max)
- completed = completed[0:len(paths):max]
- matches = matches[0:len(paths):max]
- results = results[0:len(paths):max]
- _, ok := parseGetMany(json, i, 0, 0, paths, completed, matches, results)
- return results, ok
-}
-func getMany256(json string, i int, paths []string) ([]Result, bool) {
- const max = 256
- var completed = make([]bool, 0, max)
- var matches = make([]uint64, 0, max)
- var results = make([]Result, 0, max)
- completed = completed[0:len(paths):max]
- matches = matches[0:len(paths):max]
- results = results[0:len(paths):max]
- _, ok := parseGetMany(json, i, 0, 0, paths, completed, matches, results)
- return results, ok
-}
-func getMany512(json string, i int, paths []string) ([]Result, bool) {
- const max = 512
- var completed = make([]bool, 0, max)
- var matches = make([]uint64, 0, max)
- var results = make([]Result, 0, max)
- completed = completed[0:len(paths):max]
- matches = matches[0:len(paths):max]
- results = results[0:len(paths):max]
- _, ok := parseGetMany(json, i, 0, 0, paths, completed, matches, results)
- return results, ok
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/logo.png b/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/logo.png
deleted file mode 100644
index 17a8bbe..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/logo.png
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/.travis.yml b/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/.travis.yml
deleted file mode 100644
index 4f2ee4d..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/.travis.yml
+++ /dev/null
@@ -1 +0,0 @@
-language: go
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/LICENSE b/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/LICENSE
deleted file mode 100644
index 89593c7..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2016 Josh Baker
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/README.md b/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/README.md
deleted file mode 100644
index 1a7c5c4..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/README.md
+++ /dev/null
@@ -1,278 +0,0 @@
-<p align="center">
-<img
- src="logo.png"
- width="240" height="78" border="0" alt="SJSON">
-<br>
-<a href="https://travis-ci.org/tidwall/sjson"><img src="https://img.shields.io/travis/tidwall/sjson.svg?style=flat-square" alt="Build Status"></a>
-<a href="https://godoc.org/github.com/tidwall/sjson"><img src="https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt="GoDoc"></a>
-</p>
-
-<p align="center">set a json value quickly</a></p>
-
-SJSON is a Go package that provides a [very fast](#performance) and simple way to set a value in a json document. The purpose for this library is to provide efficient json updating for the [SummitDB](https://github.com/tidwall/summitdb) project.
-For quickly retrieving json values check out [GJSON](https://github.com/tidwall/gjson).
-
-For a command line interface check out [JSONed](https://github.com/tidwall/jsoned).
-
-Getting Started
-===============
-
-Installing
-----------
-
-To start using SJSON, install Go and run `go get`:
-
-```sh
-$ go get -u github.com/tidwall/sjson
-```
-
-This will retrieve the library.
-
-Set a value
------------
-Set sets the value for the specified path.
-A path is in dot syntax, such as "name.last" or "age".
-This function expects that the json is well-formed and validated.
-Invalid json will not panic, but it may return back unexpected results.
-Invalid paths may return an error.
-
-```go
-package main
-
-import "github.com/tidwall/sjson"
-
-const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`
-
-func main() {
- value, _ := sjson.Set(json, "name.last", "Anderson")
- println(value)
-}
-```
-
-This will print:
-
-```json
-{"name":{"first":"Janet","last":"Anderson"},"age":47}
-```
-
-Path syntax
------------
-
-A path is a series of keys separated by a dot.
-The dot and colon characters can be escaped with '\'.
-
-```json
-{
- "name": {"first": "Tom", "last": "Anderson"},
- "age":37,
- "children": ["Sara","Alex","Jack"],
- "fav.movie": "Deer Hunter",
- "friends": [
- {"first": "James", "last": "Murphy"},
- {"first": "Roger", "last": "Craig"}
- ]
-}
-```
-```
-"name.last" >> "Anderson"
-"age" >> 37
-"children.1" >> "Alex"
-"friends.1.last" >> "Craig"
-```
-
-The `-1` key can be used to append a value to an existing array:
-
-```
-"children.-1" >> appends a new value to the end of the children array
-```
-
-Normally number keys are used to modify arrays, but it's possible to force a numeric object key by using the colon character:
-
-```json
-{
- "users":{
- "2313":{"name":"Sara"},
- "7839":{"name":"Andy"}
- }
-}
-```
-
-A colon path would look like:
-
-```
-"users.:2313.name" >> "Sara"
-```
-
-Supported types
----------------
-
-Pretty much any type is supported:
-
-```go
-sjson.Set(`{"key":true}`, "key", nil)
-sjson.Set(`{"key":true}`, "key", false)
-sjson.Set(`{"key":true}`, "key", 1)
-sjson.Set(`{"key":true}`, "key", 10.5)
-sjson.Set(`{"key":true}`, "key", "hello")
-sjson.Set(`{"key":true}`, "key", map[string]interface{}{"hello":"world"})
-```
-
-When a type is not recognized, SJSON will fallback to the `encoding/json` Marshaller.
-
-
-Examples
---------
-
-Set a value from empty document:
-```go
-value, _ := sjson.Set("", "name", "Tom")
-println(value)
-
-// Output:
-// {"name":"Tom"}
-```
-
-Set a nested value from empty document:
-```go
-value, _ := sjson.Set("", "name.last", "Anderson")
-println(value)
-
-// Output:
-// {"name":{"last":"Anderson"}}
-```
-
-Set a new value:
-```go
-value, _ := sjson.Set(`{"name":{"last":"Anderson"}}`, "name.first", "Sara")
-println(value)
-
-// Output:
-// {"name":{"first":"Sara","last":"Anderson"}}
-```
-
-Update an existing value:
-```go
-value, _ := sjson.Set(`{"name":{"last":"Anderson"}}`, "name.last", "Smith")
-println(value)
-
-// Output:
-// {"name":{"last":"Smith"}}
-```
-
-Set a new array value:
-```go
-value, _ := sjson.Set(`{"friends":["Andy","Carol"]}`, "friends.2", "Sara")
-println(value)
-
-// Output:
-// {"friends":["Andy","Carol","Sara"]
-```
-
-Append an array value by using the `-1` key in a path:
-```go
-value, _ := sjson.Set(`{"friends":["Andy","Carol"]}`, "friends.-1", "Sara")
-println(value)
-
-// Output:
-// {"friends":["Andy","Carol","Sara"]
-```
-
-Append an array value that is past the end:
-```go
-value, _ := sjson.Set(`{"friends":["Andy","Carol"]}`, "friends.4", "Sara")
-println(value)
-
-// Output:
-// {"friends":["Andy","Carol",null,null,"Sara"]
-```
-
-Delete a value:
-```go
-value, _ := sjson.Delete(`{"name":{"first":"Sara","last":"Anderson"}}`, "name.first")
-println(value)
-
-// Output:
-// {"name":{"last":"Anderson"}}
-```
-
-Delete an array value:
-```go
-value, _ := sjson.Delete(`{"friends":["Andy","Carol"]}`, "friends.1")
-println(value)
-
-// Output:
-// {"friends":["Andy"]}
-```
-
-Delete the last array value:
-```go
-value, _ := sjson.Delete(`{"friends":["Andy","Carol"]}`, "friends.-1")
-println(value)
-
-// Output:
-// {"friends":["Andy"]}
-```
-
-## Performance
-
-Benchmarks of SJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/),
-[ffjson](https://github.com/pquerna/ffjson),
-[EasyJSON](https://github.com/mailru/easyjson),
-and [Gabs](https://github.com/Jeffail/gabs)
-
-```
-Benchmark_SJSON-8 3000000 805 ns/op 1077 B/op 3 allocs/op
-Benchmark_SJSON_ReplaceInPlace-8 3000000 449 ns/op 0 B/op 0 allocs/op
-Benchmark_JSON_Map-8 300000 21236 ns/op 6392 B/op 150 allocs/op
-Benchmark_JSON_Struct-8 300000 14691 ns/op 1789 B/op 24 allocs/op
-Benchmark_Gabs-8 300000 21311 ns/op 6752 B/op 150 allocs/op
-Benchmark_FFJSON-8 300000 17673 ns/op 3589 B/op 47 allocs/op
-Benchmark_EasyJSON-8 1500000 3119 ns/op 1061 B/op 13 allocs/op
-```
-
-JSON document used:
-
-```json
-{
- "widget": {
- "debug": "on",
- "window": {
- "title": "Sample Konfabulator Widget",
- "name": "main_window",
- "width": 500,
- "height": 500
- },
- "image": {
- "src": "Images/Sun.png",
- "hOffset": 250,
- "vOffset": 250,
- "alignment": "center"
- },
- "text": {
- "data": "Click Here",
- "size": 36,
- "style": "bold",
- "vOffset": 100,
- "alignment": "center",
- "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
- }
- }
-}
-```
-
-Each operation was rotated though one of the following search paths:
-
-```
-widget.window.name
-widget.image.hOffset
-widget.text.onMouseUp
-```
-
-*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.7.*
-
-## Contact
-Josh Baker [@tidwall](http://twitter.com/tidwall)
-
-## License
-
-SJSON source code is available under the MIT [License](/LICENSE).
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/logo.png b/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/logo.png
deleted file mode 100644
index b5aa257..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/logo.png
+++ /dev/null
Binary files differ
diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/sjson.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/sjson.go
deleted file mode 100644
index 7f1d358..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/sjson.go
+++ /dev/null
@@ -1,653 +0,0 @@
-// Package sjson provides setting json values.
-package sjson
-
-import (
- jsongo "encoding/json"
- "reflect"
- "strconv"
- "unsafe"
-
- "github.com/tidwall/gjson"
-)
-
-type errorType struct {
- msg string
-}
-
-func (err *errorType) Error() string {
- return err.msg
-}
-
-// Options represents additional options for the Set and Delete functions.
-type Options struct {
- // Optimistic is a hint that the value likely exists which
- // allows for the sjson to perform a fast-track search and replace.
- Optimistic bool
- // ReplaceInPlace is a hint to replace the input json rather than
- // allocate a new json byte slice. When this field is specified
- // the input json will not longer be valid and it should not be used
- // In the case when the destination slice doesn't have enough free
- // bytes to replace the data in place, a new bytes slice will be
- // created under the hood.
- // The Optimistic flag must be set to true and the input must be a
- // byte slice in order to use this field.
- ReplaceInPlace bool
-}
-
-type pathResult struct {
- part string // current key part
- path string // remaining path
- force bool // force a string key
- more bool // there is more path to parse
-}
-
-func parsePath(path string) (pathResult, error) {
- var r pathResult
- if len(path) > 0 && path[0] == ':' {
- r.force = true
- path = path[1:]
- }
- for i := 0; i < len(path); i++ {
- if path[i] == '.' {
- r.part = path[:i]
- r.path = path[i+1:]
- r.more = true
- return r, nil
- }
- if path[i] == '*' || path[i] == '?' {
- return r, &errorType{"wildcard characters not allowed in path"}
- } else if path[i] == '#' {
- return r, &errorType{"array access character not allowed in path"}
- }
- if path[i] == '\\' {
- // go into escape mode. this is a slower path that
- // strips off the escape character from the part.
- epart := []byte(path[:i])
- i++
- if i < len(path) {
- epart = append(epart, path[i])
- i++
- for ; i < len(path); i++ {
- if path[i] == '\\' {
- i++
- if i < len(path) {
- epart = append(epart, path[i])
- }
- continue
- } else if path[i] == '.' {
- r.part = string(epart)
- r.path = path[i+1:]
- r.more = true
- return r, nil
- } else if path[i] == '*' || path[i] == '?' {
- return r, &errorType{
- "wildcard characters not allowed in path"}
- } else if path[i] == '#' {
- return r, &errorType{
- "array access character not allowed in path"}
- }
- epart = append(epart, path[i])
- }
- }
- // append the last part
- r.part = string(epart)
- return r, nil
- }
- }
- r.part = path
- return r, nil
-}
-
-func mustMarshalString(s string) bool {
- for i := 0; i < len(s); i++ {
- if s[i] < ' ' || s[i] > 0x7f || s[i] == '"' {
- return true
- }
- }
- return false
-}
-
-// appendStringify makes a json string and appends to buf.
-func appendStringify(buf []byte, s string) []byte {
- if mustMarshalString(s) {
- b, _ := jsongo.Marshal(s)
- return append(buf, b...)
- }
- buf = append(buf, '"')
- buf = append(buf, s...)
- buf = append(buf, '"')
- return buf
-}
-
-// appendBuild builds a json block from a json path.
-func appendBuild(buf []byte, array bool, paths []pathResult, raw string,
- stringify bool) []byte {
- if !array {
- buf = appendStringify(buf, paths[0].part)
- buf = append(buf, ':')
- }
- if len(paths) > 1 {
- n, numeric := atoui(paths[1])
- if numeric || (!paths[1].force && paths[1].part == "-1") {
- buf = append(buf, '[')
- buf = appendRepeat(buf, "null,", n)
- buf = appendBuild(buf, true, paths[1:], raw, stringify)
- buf = append(buf, ']')
- } else {
- buf = append(buf, '{')
- buf = appendBuild(buf, false, paths[1:], raw, stringify)
- buf = append(buf, '}')
- }
- } else {
- if stringify {
- buf = appendStringify(buf, raw)
- } else {
- buf = append(buf, raw...)
- }
- }
- return buf
-}
-
-// atoui does a rip conversion of string -> unigned int.
-func atoui(r pathResult) (n int, ok bool) {
- if r.force {
- return 0, false
- }
- for i := 0; i < len(r.part); i++ {
- if r.part[i] < '0' || r.part[i] > '9' {
- return 0, false
- }
- n = n*10 + int(r.part[i]-'0')
- }
- return n, true
-}
-
-// appendRepeat repeats string "n" times and appends to buf.
-func appendRepeat(buf []byte, s string, n int) []byte {
- for i := 0; i < n; i++ {
- buf = append(buf, s...)
- }
- return buf
-}
-
-// trim does a rip trim
-func trim(s string) string {
- for len(s) > 0 {
- if s[0] <= ' ' {
- s = s[1:]
- continue
- }
- break
- }
- for len(s) > 0 {
- if s[len(s)-1] <= ' ' {
- s = s[:len(s)-1]
- continue
- }
- break
- }
- return s
-}
-
-// deleteTailItem deletes the previous key or comma.
-func deleteTailItem(buf []byte) ([]byte, bool) {
-loop:
- for i := len(buf) - 1; i >= 0; i-- {
- // look for either a ',',':','['
- switch buf[i] {
- case '[':
- return buf, true
- case ',':
- return buf[:i], false
- case ':':
- // delete tail string
- i--
- for ; i >= 0; i-- {
- if buf[i] == '"' {
- i--
- for ; i >= 0; i-- {
- if buf[i] == '"' {
- i--
- if i >= 0 && i == '\\' {
- i--
- continue
- }
- for ; i >= 0; i-- {
- // look for either a ',','{'
- switch buf[i] {
- case '{':
- return buf[:i+1], true
- case ',':
- return buf[:i], false
- }
- }
- }
- }
- break
- }
- }
- break loop
- }
- }
- return buf, false
-}
-
-var errNoChange = &errorType{"no change"}
-
-func appendRawPaths(buf []byte, jstr string, paths []pathResult, raw string,
- stringify, del bool) ([]byte, error) {
- var err error
- var res gjson.Result
- var found bool
- if del {
- if paths[0].part == "-1" && !paths[0].force {
- res = gjson.Get(jstr, "#")
- if res.Int() > 0 {
- res = gjson.Get(jstr, strconv.FormatInt(int64(res.Int()-1), 10))
- found = true
- }
- }
- }
- if !found {
- res = gjson.Get(jstr, paths[0].part)
- }
- if res.Index > 0 {
- if len(paths) > 1 {
- buf = append(buf, jstr[:res.Index]...)
- buf, err = appendRawPaths(buf, res.Raw, paths[1:], raw,
- stringify, del)
- if err != nil {
- return nil, err
- }
- buf = append(buf, jstr[res.Index+len(res.Raw):]...)
- return buf, nil
- }
- buf = append(buf, jstr[:res.Index]...)
- var exidx int // additional forward stripping
- if del {
- var delNextComma bool
- buf, delNextComma = deleteTailItem(buf)
- if delNextComma {
- i, j := res.Index+len(res.Raw), 0
- for ; i < len(jstr); i, j = i+1, j+1 {
- if jstr[i] <= ' ' {
- continue
- }
- if jstr[i] == ',' {
- exidx = j + 1
- }
- break
- }
- }
- } else {
- if stringify {
- buf = appendStringify(buf, raw)
- } else {
- buf = append(buf, raw...)
- }
- }
- buf = append(buf, jstr[res.Index+len(res.Raw)+exidx:]...)
- return buf, nil
- }
- if del {
- return nil, errNoChange
- }
- n, numeric := atoui(paths[0])
- isempty := true
- for i := 0; i < len(jstr); i++ {
- if jstr[i] > ' ' {
- isempty = false
- break
- }
- }
- if isempty {
- if numeric {
- jstr = "[]"
- } else {
- jstr = "{}"
- }
- }
- jsres := gjson.Parse(jstr)
- if jsres.Type != gjson.JSON {
- if numeric {
- jstr = "[]"
- } else {
- jstr = "{}"
- }
- jsres = gjson.Parse(jstr)
- }
- var comma bool
- for i := 1; i < len(jsres.Raw); i++ {
- if jsres.Raw[i] <= ' ' {
- continue
- }
- if jsres.Raw[i] == '}' || jsres.Raw[i] == ']' {
- break
- }
- comma = true
- break
- }
- switch jsres.Raw[0] {
- default:
- return nil, &errorType{"json must be an object or array"}
- case '{':
- buf = append(buf, '{')
- buf = appendBuild(buf, false, paths, raw, stringify)
- if comma {
- buf = append(buf, ',')
- }
- buf = append(buf, jsres.Raw[1:]...)
- return buf, nil
- case '[':
- var appendit bool
- if !numeric {
- if paths[0].part == "-1" && !paths[0].force {
- appendit = true
- } else {
- return nil, &errorType{
- "cannot set array element for non-numeric key '" +
- paths[0].part + "'"}
- }
- }
- if appendit {
- njson := trim(jsres.Raw)
- if njson[len(njson)-1] == ']' {
- njson = njson[:len(njson)-1]
- }
- buf = append(buf, njson...)
- if comma {
- buf = append(buf, ',')
- }
-
- buf = appendBuild(buf, true, paths, raw, stringify)
- buf = append(buf, ']')
- return buf, nil
- }
- buf = append(buf, '[')
- ress := jsres.Array()
- for i := 0; i < len(ress); i++ {
- if i > 0 {
- buf = append(buf, ',')
- }
- buf = append(buf, ress[i].Raw...)
- }
- if len(ress) == 0 {
- buf = appendRepeat(buf, "null,", n-len(ress))
- } else {
- buf = appendRepeat(buf, ",null", n-len(ress))
- if comma {
- buf = append(buf, ',')
- }
- }
- buf = appendBuild(buf, true, paths, raw, stringify)
- buf = append(buf, ']')
- return buf, nil
- }
-}
-
-func isOptimisticPath(path string) bool {
- for i := 0; i < len(path); i++ {
- if path[i] < '.' || path[i] > 'z' {
- return false
- }
- if path[i] > '9' && path[i] < 'A' {
- return false
- }
- if path[i] > 'z' {
- return false
- }
- }
- return true
-}
-
-func set(jstr, path, raw string,
- stringify, del, optimistic, inplace bool) ([]byte, error) {
- if path == "" {
- return nil, &errorType{"path cannot be empty"}
- }
- if !del && optimistic && isOptimisticPath(path) {
- res := gjson.Get(jstr, path)
- if res.Exists() && res.Index > 0 {
- sz := len(jstr) - len(res.Raw) + len(raw)
- if stringify {
- sz += 2
- }
- if inplace && sz <= len(jstr) {
- if !stringify || !mustMarshalString(raw) {
- jsonh := *(*reflect.StringHeader)(unsafe.Pointer(&jstr))
- jsonbh := reflect.SliceHeader{
- Data: jsonh.Data, Len: jsonh.Len, Cap: jsonh.Len}
- jbytes := *(*[]byte)(unsafe.Pointer(&jsonbh))
- if stringify {
- jbytes[res.Index] = '"'
- copy(jbytes[res.Index+1:], []byte(raw))
- jbytes[res.Index+1+len(raw)] = '"'
- copy(jbytes[res.Index+1+len(raw)+1:],
- jbytes[res.Index+len(res.Raw):])
- } else {
- copy(jbytes[res.Index:], []byte(raw))
- copy(jbytes[res.Index+len(raw):],
- jbytes[res.Index+len(res.Raw):])
- }
- return jbytes[:sz], nil
- }
- return nil, nil
- }
- buf := make([]byte, 0, sz)
- buf = append(buf, jstr[:res.Index]...)
- if stringify {
- buf = appendStringify(buf, raw)
- } else {
- buf = append(buf, raw...)
- }
- buf = append(buf, jstr[res.Index+len(res.Raw):]...)
- return buf, nil
- }
- }
- // parse the path, make sure that it does not contain invalid characters
- // such as '#', '?', '*'
- paths := make([]pathResult, 0, 4)
- r, err := parsePath(path)
- if err != nil {
- return nil, err
- }
- paths = append(paths, r)
- for r.more {
- if r, err = parsePath(r.path); err != nil {
- return nil, err
- }
- paths = append(paths, r)
- }
-
- njson, err := appendRawPaths(nil, jstr, paths, raw, stringify, del)
- if err != nil {
- return nil, err
- }
- return njson, nil
-}
-
-// Set sets a json value for the specified path.
-// A path is in dot syntax, such as "name.last" or "age".
-// This function expects that the json is well-formed, and does not validate.
-// Invalid json will not panic, but it may return back unexpected results.
-// An error is returned if the path is not valid.
-//
-// A path is a series of keys separated by a dot.
-//
-// {
-// "name": {"first": "Tom", "last": "Anderson"},
-// "age":37,
-// "children": ["Sara","Alex","Jack"],
-// "friends": [
-// {"first": "James", "last": "Murphy"},
-// {"first": "Roger", "last": "Craig"}
-// ]
-// }
-// "name.last" >> "Anderson"
-// "age" >> 37
-// "children.1" >> "Alex"
-//
-func Set(json, path string, value interface{}) (string, error) {
- return SetOptions(json, path, value, nil)
-}
-
-// SetOptions sets a json value for the specified path with options.
-// A path is in dot syntax, such as "name.last" or "age".
-// This function expects that the json is well-formed, and does not validate.
-// Invalid json will not panic, but it may return back unexpected results.
-// An error is returned if the path is not valid.
-func SetOptions(json, path string, value interface{},
- opts *Options) (string, error) {
- if opts != nil {
- if opts.ReplaceInPlace {
- // it's not safe to replace bytes in-place for strings
- // copy the Options and set options.ReplaceInPlace to false.
- nopts := *opts
- opts = &nopts
- opts.ReplaceInPlace = false
- }
- }
- jsonh := *(*reflect.StringHeader)(unsafe.Pointer(&json))
- jsonbh := reflect.SliceHeader{Data: jsonh.Data, Len: jsonh.Len}
- jsonb := *(*[]byte)(unsafe.Pointer(&jsonbh))
- res, err := SetBytesOptions(jsonb, path, value, opts)
- return string(res), err
-}
-
-// SetBytes sets a json value for the specified path.
-// If working with bytes, this method preferred over
-// Set(string(data), path, value)
-func SetBytes(json []byte, path string, value interface{}) ([]byte, error) {
- return SetBytesOptions(json, path, value, nil)
-}
-
-// SetBytesOptions sets a json value for the specified path with options.
-// If working with bytes, this method preferred over
-// SetOptions(string(data), path, value)
-func SetBytesOptions(json []byte, path string, value interface{},
- opts *Options) ([]byte, error) {
- var optimistic, inplace bool
- if opts != nil {
- optimistic = opts.Optimistic
- inplace = opts.ReplaceInPlace
- }
- jstr := *(*string)(unsafe.Pointer(&json))
- var res []byte
- var err error
- switch v := value.(type) {
- default:
- b, err := jsongo.Marshal(value)
- if err != nil {
- return nil, err
- }
- raw := *(*string)(unsafe.Pointer(&b))
- res, err = set(jstr, path, raw, false, false, optimistic, inplace)
- case dtype:
- res, err = set(jstr, path, "", false, true, optimistic, inplace)
- case string:
- res, err = set(jstr, path, v, true, false, optimistic, inplace)
- case []byte:
- raw := *(*string)(unsafe.Pointer(&v))
- res, err = set(jstr, path, raw, true, false, optimistic, inplace)
- case bool:
- if v {
- res, err = set(jstr, path, "true", false, false, optimistic, inplace)
- } else {
- res, err = set(jstr, path, "false", false, false, optimistic, inplace)
- }
- case int8:
- res, err = set(jstr, path, strconv.FormatInt(int64(v), 10),
- false, false, optimistic, inplace)
- case int16:
- res, err = set(jstr, path, strconv.FormatInt(int64(v), 10),
- false, false, optimistic, inplace)
- case int32:
- res, err = set(jstr, path, strconv.FormatInt(int64(v), 10),
- false, false, optimistic, inplace)
- case int64:
- res, err = set(jstr, path, strconv.FormatInt(int64(v), 10),
- false, false, optimistic, inplace)
- case uint8:
- res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10),
- false, false, optimistic, inplace)
- case uint16:
- res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10),
- false, false, optimistic, inplace)
- case uint32:
- res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10),
- false, false, optimistic, inplace)
- case uint64:
- res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10),
- false, false, optimistic, inplace)
- case float32:
- res, err = set(jstr, path, strconv.FormatFloat(float64(v), 'f', -1, 64),
- false, false, optimistic, inplace)
- case float64:
- res, err = set(jstr, path, strconv.FormatFloat(float64(v), 'f', -1, 64),
- false, false, optimistic, inplace)
- }
- if err == errNoChange {
- return json, nil
- }
- return res, err
-}
-
-// SetRaw sets a raw json value for the specified path.
-// This function works the same as Set except that the value is set as a
-// raw block of json. This allows for setting premarshalled json objects.
-func SetRaw(json, path, value string) (string, error) {
- return SetRawOptions(json, path, value, nil)
-}
-
-// SetRawOptions sets a raw json value for the specified path with options.
-// This furnction works the same as SetOptions except that the value is set
-// as a raw block of json. This allows for setting premarshalled json objects.
-func SetRawOptions(json, path, value string, opts *Options) (string, error) {
- var optimistic bool
- if opts != nil {
- optimistic = opts.Optimistic
- }
- res, err := set(json, path, value, false, false, optimistic, false)
- if err == errNoChange {
- return json, nil
- }
- return string(res), err
-}
-
-// SetRawBytes sets a raw json value for the specified path.
-// If working with bytes, this method preferred over
-// SetRaw(string(data), path, value)
-func SetRawBytes(json []byte, path string, value []byte) ([]byte, error) {
- return SetRawBytesOptions(json, path, value, nil)
-}
-
-// SetRawBytesOptions sets a raw json value for the specified path with options.
-// If working with bytes, this method preferred over
-// SetRawOptions(string(data), path, value, opts)
-func SetRawBytesOptions(json []byte, path string, value []byte,
- opts *Options) ([]byte, error) {
- jstr := *(*string)(unsafe.Pointer(&json))
- vstr := *(*string)(unsafe.Pointer(&value))
- var optimistic, inplace bool
- if opts != nil {
- optimistic = opts.Optimistic
- inplace = opts.ReplaceInPlace
- }
- res, err := set(jstr, path, vstr, false, false, optimistic, inplace)
- if err == errNoChange {
- return json, nil
- }
- return res, err
-}
-
-type dtype struct{}
-
-// Delete deletes a value from json for the specified path.
-func Delete(json, path string) (string, error) {
- return Set(json, path, dtype{})
-}
-
-// DeleteBytes deletes a value from json for the specified path.
-func DeleteBytes(json []byte, path string) ([]byte, error) {
- return SetBytes(json, path, dtype{})
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert.go
deleted file mode 100644
index 12c9010..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert.go
+++ /dev/null
@@ -1,776 +0,0 @@
-// 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 autocert provides automatic access to certificates from Let's Encrypt
-// and any other ACME-based CA.
-//
-// This package is a work in progress and makes no API stability promises.
-package autocert
-
-import (
- "bytes"
- "crypto"
- "crypto/ecdsa"
- "crypto/elliptic"
- "crypto/rand"
- "crypto/rsa"
- "crypto/tls"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/pem"
- "errors"
- "fmt"
- "io"
- mathrand "math/rand"
- "net/http"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "golang.org/x/crypto/acme"
- "golang.org/x/net/context"
-)
-
-// pseudoRand is safe for concurrent use.
-var pseudoRand *lockedMathRand
-
-func init() {
- src := mathrand.NewSource(timeNow().UnixNano())
- pseudoRand = &lockedMathRand{rnd: mathrand.New(src)}
-}
-
-// AcceptTOS always returns true to indicate the acceptance of a CA Terms of Service
-// during account registration.
-func AcceptTOS(tosURL string) bool { return true }
-
-// HostPolicy specifies which host names the Manager is allowed to respond to.
-// It returns a non-nil error if the host should be rejected.
-// The returned error is accessible via tls.Conn.Handshake and its callers.
-// See Manager's HostPolicy field and GetCertificate method docs for more details.
-type HostPolicy func(ctx context.Context, host string) error
-
-// HostWhitelist returns a policy where only the specified host names are allowed.
-// Only exact matches are currently supported. Subdomains, regexp or wildcard
-// will not match.
-func HostWhitelist(hosts ...string) HostPolicy {
- whitelist := make(map[string]bool, len(hosts))
- for _, h := range hosts {
- whitelist[h] = true
- }
- return func(_ context.Context, host string) error {
- if !whitelist[host] {
- return errors.New("acme/autocert: host not configured")
- }
- return nil
- }
-}
-
-// defaultHostPolicy is used when Manager.HostPolicy is not set.
-func defaultHostPolicy(context.Context, string) error {
- return nil
-}
-
-// Manager is a stateful certificate manager built on top of acme.Client.
-// It obtains and refreshes certificates automatically,
-// as well as providing them to a TLS server via tls.Config.
-//
-// A simple usage example:
-//
-// m := autocert.Manager{
-// Prompt: autocert.AcceptTOS,
-// HostPolicy: autocert.HostWhitelist("example.org"),
-// }
-// s := &http.Server{
-// Addr: ":https",
-// TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
-// }
-// s.ListenAndServeTLS("", "")
-//
-// To preserve issued certificates and improve overall performance,
-// use a cache implementation of Cache. For instance, DirCache.
-type Manager struct {
- // Prompt specifies a callback function to conditionally accept a CA's Terms of Service (TOS).
- // The registration may require the caller to agree to the CA's TOS.
- // If so, Manager calls Prompt with a TOS URL provided by the CA. Prompt should report
- // whether the caller agrees to the terms.
- //
- // To always accept the terms, the callers can use AcceptTOS.
- Prompt func(tosURL string) bool
-
- // Cache optionally stores and retrieves previously-obtained certificates.
- // If nil, certs will only be cached for the lifetime of the Manager.
- //
- // Manager passes the Cache certificates data encoded in PEM, with private/public
- // parts combined in a single Cache.Put call, private key first.
- Cache Cache
-
- // HostPolicy controls which domains the Manager will attempt
- // to retrieve new certificates for. It does not affect cached certs.
- //
- // If non-nil, HostPolicy is called before requesting a new cert.
- // If nil, all hosts are currently allowed. This is not recommended,
- // as it opens a potential attack where clients connect to a server
- // by IP address and pretend to be asking for an incorrect host name.
- // Manager will attempt to obtain a certificate for that host, incorrectly,
- // eventually reaching the CA's rate limit for certificate requests
- // and making it impossible to obtain actual certificates.
- //
- // See GetCertificate for more details.
- HostPolicy HostPolicy
-
- // RenewBefore optionally specifies how early certificates should
- // be renewed before they expire.
- //
- // If zero, they're renewed 1 week before expiration.
- RenewBefore time.Duration
-
- // Client is used to perform low-level operations, such as account registration
- // and requesting new certificates.
- // If Client is nil, a zero-value acme.Client is used with acme.LetsEncryptURL
- // directory endpoint and a newly-generated ECDSA P-256 key.
- //
- // Mutating the field after the first call of GetCertificate method will have no effect.
- Client *acme.Client
-
- // Email optionally specifies a contact email address.
- // This is used by CAs, such as Let's Encrypt, to notify about problems
- // with issued certificates.
- //
- // If the Client's account key is already registered, Email is not used.
- Email string
-
- clientMu sync.Mutex
- client *acme.Client // initialized by acmeClient method
-
- stateMu sync.Mutex
- state map[string]*certState // keyed by domain name
-
- // tokenCert is keyed by token domain name, which matches server name
- // of ClientHello. Keys always have ".acme.invalid" suffix.
- tokenCertMu sync.RWMutex
- tokenCert map[string]*tls.Certificate
-
- // renewal tracks the set of domains currently running renewal timers.
- // It is keyed by domain name.
- renewalMu sync.Mutex
- renewal map[string]*domainRenewal
-}
-
-// GetCertificate implements the tls.Config.GetCertificate hook.
-// It provides a TLS certificate for hello.ServerName host, including answering
-// *.acme.invalid (TLS-SNI) challenges. All other fields of hello are ignored.
-//
-// If m.HostPolicy is non-nil, GetCertificate calls the policy before requesting
-// a new cert. A non-nil error returned from m.HostPolicy halts TLS negotiation.
-// The error is propagated back to the caller of GetCertificate and is user-visible.
-// This does not affect cached certs. See HostPolicy field description for more details.
-func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
- name := hello.ServerName
- if name == "" {
- return nil, errors.New("acme/autocert: missing server name")
- }
-
- // check whether this is a token cert requested for TLS-SNI challenge
- if strings.HasSuffix(name, ".acme.invalid") {
- m.tokenCertMu.RLock()
- defer m.tokenCertMu.RUnlock()
- if cert := m.tokenCert[name]; cert != nil {
- return cert, nil
- }
- if cert, err := m.cacheGet(name); err == nil {
- return cert, nil
- }
- // TODO: cache error results?
- return nil, fmt.Errorf("acme/autocert: no token cert for %q", name)
- }
-
- // regular domain
- cert, err := m.cert(name)
- if err == nil {
- return cert, nil
- }
- if err != ErrCacheMiss {
- return nil, err
- }
-
- // first-time
- ctx := context.Background() // TODO: use a deadline?
- if err := m.hostPolicy()(ctx, name); err != nil {
- return nil, err
- }
- cert, err = m.createCert(ctx, name)
- if err != nil {
- return nil, err
- }
- m.cachePut(name, cert)
- return cert, nil
-}
-
-// cert returns an existing certificate either from m.state or cache.
-// If a certificate is found in cache but not in m.state, the latter will be filled
-// with the cached value.
-func (m *Manager) cert(name string) (*tls.Certificate, error) {
- m.stateMu.Lock()
- if s, ok := m.state[name]; ok {
- m.stateMu.Unlock()
- s.RLock()
- defer s.RUnlock()
- return s.tlscert()
- }
- defer m.stateMu.Unlock()
- cert, err := m.cacheGet(name)
- if err != nil {
- return nil, err
- }
- signer, ok := cert.PrivateKey.(crypto.Signer)
- if !ok {
- return nil, errors.New("acme/autocert: private key cannot sign")
- }
- if m.state == nil {
- m.state = make(map[string]*certState)
- }
- s := &certState{
- key: signer,
- cert: cert.Certificate,
- leaf: cert.Leaf,
- }
- m.state[name] = s
- go m.renew(name, s.key, s.leaf.NotAfter)
- return cert, nil
-}
-
-// cacheGet always returns a valid certificate, or an error otherwise.
-func (m *Manager) cacheGet(domain string) (*tls.Certificate, error) {
- if m.Cache == nil {
- return nil, ErrCacheMiss
- }
- // TODO: might want to define a cache timeout on m
- ctx := context.Background()
- data, err := m.Cache.Get(ctx, domain)
- if err != nil {
- return nil, err
- }
-
- // private
- priv, pub := pem.Decode(data)
- if priv == nil || !strings.Contains(priv.Type, "PRIVATE") {
- return nil, errors.New("acme/autocert: no private key found in cache")
- }
- privKey, err := parsePrivateKey(priv.Bytes)
- if err != nil {
- return nil, err
- }
-
- // public
- var pubDER [][]byte
- for len(pub) > 0 {
- var b *pem.Block
- b, pub = pem.Decode(pub)
- if b == nil {
- break
- }
- pubDER = append(pubDER, b.Bytes)
- }
- if len(pub) > 0 {
- return nil, errors.New("acme/autocert: invalid public key")
- }
-
- // verify and create TLS cert
- leaf, err := validCert(domain, pubDER, privKey)
- if err != nil {
- return nil, err
- }
- tlscert := &tls.Certificate{
- Certificate: pubDER,
- PrivateKey: privKey,
- Leaf: leaf,
- }
- return tlscert, nil
-}
-
-func (m *Manager) cachePut(domain string, tlscert *tls.Certificate) error {
- if m.Cache == nil {
- return nil
- }
-
- // contains PEM-encoded data
- var buf bytes.Buffer
-
- // private
- switch key := tlscert.PrivateKey.(type) {
- case *ecdsa.PrivateKey:
- if err := encodeECDSAKey(&buf, key); err != nil {
- return err
- }
- case *rsa.PrivateKey:
- b := x509.MarshalPKCS1PrivateKey(key)
- pb := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: b}
- if err := pem.Encode(&buf, pb); err != nil {
- return err
- }
- default:
- return errors.New("acme/autocert: unknown private key type")
- }
-
- // public
- for _, b := range tlscert.Certificate {
- pb := &pem.Block{Type: "CERTIFICATE", Bytes: b}
- if err := pem.Encode(&buf, pb); err != nil {
- return err
- }
- }
-
- // TODO: might want to define a cache timeout on m
- ctx := context.Background()
- return m.Cache.Put(ctx, domain, buf.Bytes())
-}
-
-func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error {
- b, err := x509.MarshalECPrivateKey(key)
- if err != nil {
- return err
- }
- pb := &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
- return pem.Encode(w, pb)
-}
-
-// createCert starts the domain ownership verification and returns a certificate
-// for that domain upon success.
-//
-// If the domain is already being verified, it waits for the existing verification to complete.
-// Either way, createCert blocks for the duration of the whole process.
-func (m *Manager) createCert(ctx context.Context, domain string) (*tls.Certificate, error) {
- // TODO: maybe rewrite this whole piece using sync.Once
- state, err := m.certState(domain)
- if err != nil {
- return nil, err
- }
- // state may exist if another goroutine is already working on it
- // in which case just wait for it to finish
- if !state.locked {
- state.RLock()
- defer state.RUnlock()
- return state.tlscert()
- }
-
- // We are the first; state is locked.
- // Unblock the readers when domain ownership is verified
- // and the we got the cert or the process failed.
- defer state.Unlock()
- state.locked = false
-
- der, leaf, err := m.authorizedCert(ctx, state.key, domain)
- if err != nil {
- return nil, err
- }
- state.cert = der
- state.leaf = leaf
- go m.renew(domain, state.key, state.leaf.NotAfter)
- return state.tlscert()
-}
-
-// certState returns a new or existing certState.
-// If a new certState is returned, state.exist is false and the state is locked.
-// The returned error is non-nil only in the case where a new state could not be created.
-func (m *Manager) certState(domain string) (*certState, error) {
- m.stateMu.Lock()
- defer m.stateMu.Unlock()
- if m.state == nil {
- m.state = make(map[string]*certState)
- }
- // existing state
- if state, ok := m.state[domain]; ok {
- return state, nil
- }
- // new locked state
- key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- return nil, err
- }
- state := &certState{
- key: key,
- locked: true,
- }
- state.Lock() // will be unlocked by m.certState caller
- m.state[domain] = state
- return state, nil
-}
-
-// authorizedCert starts domain ownership verification process and requests a new cert upon success.
-// The key argument is the certificate private key.
-func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain string) (der [][]byte, leaf *x509.Certificate, err error) {
- // TODO: make m.verify retry or retry m.verify calls here
- if err := m.verify(ctx, domain); err != nil {
- return nil, nil, err
- }
- client, err := m.acmeClient(ctx)
- if err != nil {
- return nil, nil, err
- }
- csr, err := certRequest(key, domain)
- if err != nil {
- return nil, nil, err
- }
- der, _, err = client.CreateCert(ctx, csr, 0, true)
- if err != nil {
- return nil, nil, err
- }
- leaf, err = validCert(domain, der, key)
- if err != nil {
- return nil, nil, err
- }
- return der, leaf, nil
-}
-
-// verify starts a new identifier (domain) authorization flow.
-// It prepares a challenge response and then blocks until the authorization
-// is marked as "completed" by the CA (either succeeded or failed).
-//
-// verify returns nil iff the verification was successful.
-func (m *Manager) verify(ctx context.Context, domain string) error {
- client, err := m.acmeClient(ctx)
- if err != nil {
- return err
- }
-
- // start domain authorization and get the challenge
- authz, err := client.Authorize(ctx, domain)
- if err != nil {
- return err
- }
- // maybe don't need to at all
- if authz.Status == acme.StatusValid {
- return nil
- }
-
- // pick a challenge: prefer tls-sni-02 over tls-sni-01
- // TODO: consider authz.Combinations
- var chal *acme.Challenge
- for _, c := range authz.Challenges {
- if c.Type == "tls-sni-02" {
- chal = c
- break
- }
- if c.Type == "tls-sni-01" {
- chal = c
- }
- }
- if chal == nil {
- return errors.New("acme/autocert: no supported challenge type found")
- }
-
- // create a token cert for the challenge response
- var (
- cert tls.Certificate
- name string
- )
- switch chal.Type {
- case "tls-sni-01":
- cert, name, err = client.TLSSNI01ChallengeCert(chal.Token)
- case "tls-sni-02":
- cert, name, err = client.TLSSNI02ChallengeCert(chal.Token)
- default:
- err = fmt.Errorf("acme/autocert: unknown challenge type %q", chal.Type)
- }
- if err != nil {
- return err
- }
- m.putTokenCert(name, &cert)
- defer func() {
- // verification has ended at this point
- // don't need token cert anymore
- go m.deleteTokenCert(name)
- }()
-
- // ready to fulfill the challenge
- if _, err := client.Accept(ctx, chal); err != nil {
- return err
- }
- // wait for the CA to validate
- _, err = client.WaitAuthorization(ctx, authz.URI)
- return err
-}
-
-// putTokenCert stores the cert under the named key in both m.tokenCert map
-// and m.Cache.
-func (m *Manager) putTokenCert(name string, cert *tls.Certificate) {
- m.tokenCertMu.Lock()
- defer m.tokenCertMu.Unlock()
- if m.tokenCert == nil {
- m.tokenCert = make(map[string]*tls.Certificate)
- }
- m.tokenCert[name] = cert
- m.cachePut(name, cert)
-}
-
-// deleteTokenCert removes the token certificate for the specified domain name
-// from both m.tokenCert map and m.Cache.
-func (m *Manager) deleteTokenCert(name string) {
- m.tokenCertMu.Lock()
- defer m.tokenCertMu.Unlock()
- delete(m.tokenCert, name)
- if m.Cache != nil {
- m.Cache.Delete(context.Background(), name)
- }
-}
-
-// renew starts a cert renewal timer loop, one per domain.
-//
-// The loop is scheduled in two cases:
-// - a cert was fetched from cache for the first time (wasn't in m.state)
-// - a new cert was created by m.createCert
-//
-// The key argument is a certificate private key.
-// The exp argument is the cert expiration time (NotAfter).
-func (m *Manager) renew(domain string, key crypto.Signer, exp time.Time) {
- m.renewalMu.Lock()
- defer m.renewalMu.Unlock()
- if m.renewal[domain] != nil {
- // another goroutine is already on it
- return
- }
- if m.renewal == nil {
- m.renewal = make(map[string]*domainRenewal)
- }
- dr := &domainRenewal{m: m, domain: domain, key: key}
- m.renewal[domain] = dr
- dr.start(exp)
-}
-
-// stopRenew stops all currently running cert renewal timers.
-// The timers are not restarted during the lifetime of the Manager.
-func (m *Manager) stopRenew() {
- m.renewalMu.Lock()
- defer m.renewalMu.Unlock()
- for name, dr := range m.renewal {
- delete(m.renewal, name)
- dr.stop()
- }
-}
-
-func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) {
- const keyName = "acme_account.key"
-
- genKey := func() (*ecdsa.PrivateKey, error) {
- return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- }
-
- if m.Cache == nil {
- return genKey()
- }
-
- data, err := m.Cache.Get(ctx, keyName)
- if err == ErrCacheMiss {
- key, err := genKey()
- if err != nil {
- return nil, err
- }
- var buf bytes.Buffer
- if err := encodeECDSAKey(&buf, key); err != nil {
- return nil, err
- }
- if err := m.Cache.Put(ctx, keyName, buf.Bytes()); err != nil {
- return nil, err
- }
- return key, nil
- }
- if err != nil {
- return nil, err
- }
-
- priv, _ := pem.Decode(data)
- if priv == nil || !strings.Contains(priv.Type, "PRIVATE") {
- return nil, errors.New("acme/autocert: invalid account key found in cache")
- }
- return parsePrivateKey(priv.Bytes)
-}
-
-func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) {
- m.clientMu.Lock()
- defer m.clientMu.Unlock()
- if m.client != nil {
- return m.client, nil
- }
-
- client := m.Client
- if client == nil {
- client = &acme.Client{DirectoryURL: acme.LetsEncryptURL}
- }
- if client.Key == nil {
- var err error
- client.Key, err = m.accountKey(ctx)
- if err != nil {
- return nil, err
- }
- }
- var contact []string
- if m.Email != "" {
- contact = []string{"mailto:" + m.Email}
- }
- a := &acme.Account{Contact: contact}
- _, err := client.Register(ctx, a, m.Prompt)
- if ae, ok := err.(*acme.Error); err == nil || ok && ae.StatusCode == http.StatusConflict {
- // conflict indicates the key is already registered
- m.client = client
- err = nil
- }
- return m.client, err
-}
-
-func (m *Manager) hostPolicy() HostPolicy {
- if m.HostPolicy != nil {
- return m.HostPolicy
- }
- return defaultHostPolicy
-}
-
-func (m *Manager) renewBefore() time.Duration {
- if m.RenewBefore > maxRandRenew {
- return m.RenewBefore
- }
- return 7 * 24 * time.Hour // 1 week
-}
-
-// certState is ready when its mutex is unlocked for reading.
-type certState struct {
- sync.RWMutex
- locked bool // locked for read/write
- key crypto.Signer // private key for cert
- cert [][]byte // DER encoding
- leaf *x509.Certificate // parsed cert[0]; always non-nil if cert != nil
-}
-
-// tlscert creates a tls.Certificate from s.key and s.cert.
-// Callers should wrap it in s.RLock() and s.RUnlock().
-func (s *certState) tlscert() (*tls.Certificate, error) {
- if s.key == nil {
- return nil, errors.New("acme/autocert: missing signer")
- }
- if len(s.cert) == 0 {
- return nil, errors.New("acme/autocert: missing certificate")
- }
- return &tls.Certificate{
- PrivateKey: s.key,
- Certificate: s.cert,
- Leaf: s.leaf,
- }, nil
-}
-
-// certRequest creates a certificate request for the given common name cn
-// and optional SANs.
-func certRequest(key crypto.Signer, cn string, san ...string) ([]byte, error) {
- req := &x509.CertificateRequest{
- Subject: pkix.Name{CommonName: cn},
- DNSNames: san,
- }
- return x509.CreateCertificateRequest(rand.Reader, req, key)
-}
-
-// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
-// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys.
-// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
-//
-// Inspired by parsePrivateKey in crypto/tls/tls.go.
-func parsePrivateKey(der []byte) (crypto.Signer, error) {
- if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
- return key, nil
- }
- if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
- switch key := key.(type) {
- case *rsa.PrivateKey:
- return key, nil
- case *ecdsa.PrivateKey:
- return key, nil
- default:
- return nil, errors.New("acme/autocert: unknown private key type in PKCS#8 wrapping")
- }
- }
- if key, err := x509.ParseECPrivateKey(der); err == nil {
- return key, nil
- }
-
- return nil, errors.New("acme/autocert: failed to parse private key")
-}
-
-// validCert parses a cert chain provided as der argument and verifies the leaf, der[0],
-// corresponds to the private key, as well as the domain match and expiration dates.
-// It doesn't do any revocation checking.
-//
-// The returned value is the verified leaf cert.
-func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certificate, err error) {
- // parse public part(s)
- var n int
- for _, b := range der {
- n += len(b)
- }
- pub := make([]byte, n)
- n = 0
- for _, b := range der {
- n += copy(pub[n:], b)
- }
- x509Cert, err := x509.ParseCertificates(pub)
- if len(x509Cert) == 0 {
- return nil, errors.New("acme/autocert: no public key found")
- }
- // verify the leaf is not expired and matches the domain name
- leaf = x509Cert[0]
- now := timeNow()
- if now.Before(leaf.NotBefore) {
- return nil, errors.New("acme/autocert: certificate is not valid yet")
- }
- if now.After(leaf.NotAfter) {
- return nil, errors.New("acme/autocert: expired certificate")
- }
- if err := leaf.VerifyHostname(domain); err != nil {
- return nil, err
- }
- // ensure the leaf corresponds to the private key
- switch pub := leaf.PublicKey.(type) {
- case *rsa.PublicKey:
- prv, ok := key.(*rsa.PrivateKey)
- if !ok {
- return nil, errors.New("acme/autocert: private key type does not match public key type")
- }
- if pub.N.Cmp(prv.N) != 0 {
- return nil, errors.New("acme/autocert: private key does not match public key")
- }
- case *ecdsa.PublicKey:
- prv, ok := key.(*ecdsa.PrivateKey)
- if !ok {
- return nil, errors.New("acme/autocert: private key type does not match public key type")
- }
- if pub.X.Cmp(prv.X) != 0 || pub.Y.Cmp(prv.Y) != 0 {
- return nil, errors.New("acme/autocert: private key does not match public key")
- }
- default:
- return nil, errors.New("acme/autocert: unknown public key algorithm")
- }
- return leaf, nil
-}
-
-func retryAfter(v string) time.Duration {
- if i, err := strconv.Atoi(v); err == nil {
- return time.Duration(i) * time.Second
- }
- if t, err := http.ParseTime(v); err == nil {
- return t.Sub(timeNow())
- }
- return time.Second
-}
-
-type lockedMathRand struct {
- sync.Mutex
- rnd *mathrand.Rand
-}
-
-func (r *lockedMathRand) int63n(max int64) int64 {
- r.Lock()
- n := r.rnd.Int63n(max)
- r.Unlock()
- return n
-}
-
-// for easier testing
-var timeNow = time.Now
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert_test.go
deleted file mode 100644
index 3a9daa1..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert_test.go
+++ /dev/null
@@ -1,390 +0,0 @@
-// 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 autocert
-
-import (
- "crypto"
- "crypto/ecdsa"
- "crypto/elliptic"
- "crypto/rand"
- "crypto/rsa"
- "crypto/tls"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/base64"
- "encoding/json"
- "fmt"
- "html/template"
- "io"
- "math/big"
- "net/http"
- "net/http/httptest"
- "reflect"
- "testing"
- "time"
-
- "golang.org/x/crypto/acme"
- "golang.org/x/net/context"
-)
-
-var discoTmpl = template.Must(template.New("disco").Parse(`{
- "new-reg": "{{.}}/new-reg",
- "new-authz": "{{.}}/new-authz",
- "new-cert": "{{.}}/new-cert"
-}`))
-
-var authzTmpl = template.Must(template.New("authz").Parse(`{
- "status": "pending",
- "challenges": [
- {
- "uri": "{{.}}/challenge/1",
- "type": "tls-sni-01",
- "token": "token-01"
- },
- {
- "uri": "{{.}}/challenge/2",
- "type": "tls-sni-02",
- "token": "token-02"
- }
- ]
-}`))
-
-type memCache map[string][]byte
-
-func (m memCache) Get(ctx context.Context, key string) ([]byte, error) {
- v, ok := m[key]
- if !ok {
- return nil, ErrCacheMiss
- }
- return v, nil
-}
-
-func (m memCache) Put(ctx context.Context, key string, data []byte) error {
- m[key] = data
- return nil
-}
-
-func (m memCache) Delete(ctx context.Context, key string) error {
- delete(m, key)
- return nil
-}
-
-func dummyCert(pub interface{}, san ...string) ([]byte, error) {
- return dateDummyCert(pub, time.Now(), time.Now().Add(90*24*time.Hour), san...)
-}
-
-func dateDummyCert(pub interface{}, start, end time.Time, san ...string) ([]byte, error) {
- // use EC key to run faster on 386
- key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- return nil, err
- }
- t := &x509.Certificate{
- SerialNumber: big.NewInt(1),
- NotBefore: start,
- NotAfter: end,
- BasicConstraintsValid: true,
- KeyUsage: x509.KeyUsageKeyEncipherment,
- DNSNames: san,
- }
- if pub == nil {
- pub = &key.PublicKey
- }
- return x509.CreateCertificate(rand.Reader, t, t, pub, key)
-}
-
-func decodePayload(v interface{}, r io.Reader) error {
- var req struct{ Payload string }
- if err := json.NewDecoder(r).Decode(&req); err != nil {
- return err
- }
- payload, err := base64.RawURLEncoding.DecodeString(req.Payload)
- if err != nil {
- return err
- }
- return json.Unmarshal(payload, v)
-}
-
-func TestGetCertificate(t *testing.T) {
- const domain = "example.org"
- man := &Manager{Prompt: AcceptTOS}
- defer man.stopRenew()
-
- // echo token-02 | shasum -a 256
- // then divide result in 2 parts separated by dot
- tokenCertName := "4e8eb87631187e9ff2153b56b13a4dec.13a35d002e485d60ff37354b32f665d9.token.acme.invalid"
- verifyTokenCert := func() {
- hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
- _, err := man.GetCertificate(hello)
- if err != nil {
- t.Errorf("verifyTokenCert: GetCertificate(%q): %v", tokenCertName, err)
- return
- }
- }
-
- // ACME CA server stub
- var ca *httptest.Server
- ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("replay-nonce", "nonce")
- if r.Method == "HEAD" {
- // a nonce request
- return
- }
-
- switch r.URL.Path {
- // discovery
- case "/":
- if err := discoTmpl.Execute(w, ca.URL); err != nil {
- t.Fatalf("discoTmpl: %v", err)
- }
- // client key registration
- case "/new-reg":
- w.Write([]byte("{}"))
- // domain authorization
- case "/new-authz":
- w.Header().Set("location", ca.URL+"/authz/1")
- w.WriteHeader(http.StatusCreated)
- if err := authzTmpl.Execute(w, ca.URL); err != nil {
- t.Fatalf("authzTmpl: %v", err)
- }
- // accept tls-sni-02 challenge
- case "/challenge/2":
- verifyTokenCert()
- w.Write([]byte("{}"))
- // authorization status
- case "/authz/1":
- w.Write([]byte(`{"status": "valid"}`))
- // cert request
- case "/new-cert":
- var req struct {
- CSR string `json:"csr"`
- }
- decodePayload(&req, r.Body)
- b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
- csr, err := x509.ParseCertificateRequest(b)
- if err != nil {
- t.Fatalf("new-cert: CSR: %v", err)
- }
- der, err := dummyCert(csr.PublicKey, domain)
- if err != nil {
- t.Fatalf("new-cert: dummyCert: %v", err)
- }
- chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL)
- w.Header().Set("link", chainUp)
- w.WriteHeader(http.StatusCreated)
- w.Write(der)
- // CA chain cert
- case "/ca-cert":
- der, err := dummyCert(nil, "ca")
- if err != nil {
- t.Fatalf("ca-cert: dummyCert: %v", err)
- }
- w.Write(der)
- default:
- t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
- }
- }))
- defer ca.Close()
-
- // use EC key to run faster on 386
- key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- t.Fatal(err)
- }
- man.Client = &acme.Client{
- Key: key,
- DirectoryURL: ca.URL,
- }
-
- // simulate tls.Config.GetCertificate
- var tlscert *tls.Certificate
- done := make(chan struct{})
- go func() {
- hello := &tls.ClientHelloInfo{ServerName: domain}
- tlscert, err = man.GetCertificate(hello)
- close(done)
- }()
- select {
- case <-time.After(time.Minute):
- t.Fatal("man.GetCertificate took too long to return")
- case <-done:
- }
- if err != nil {
- t.Fatalf("man.GetCertificate: %v", err)
- }
-
- // verify the tlscert is the same we responded with from the CA stub
- if len(tlscert.Certificate) == 0 {
- t.Fatal("len(tlscert.Certificate) is 0")
- }
- cert, err := x509.ParseCertificate(tlscert.Certificate[0])
- if err != nil {
- t.Fatalf("x509.ParseCertificate: %v", err)
- }
- if len(cert.DNSNames) == 0 || cert.DNSNames[0] != domain {
- t.Errorf("cert.DNSNames = %v; want %q", cert.DNSNames, domain)
- }
-
- // make sure token cert was removed
- done = make(chan struct{})
- go func() {
- for {
- hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
- if _, err := man.GetCertificate(hello); err != nil {
- break
- }
- time.Sleep(100 * time.Millisecond)
- }
- close(done)
- }()
- select {
- case <-time.After(5 * time.Second):
- t.Error("token cert was not removed")
- case <-done:
- }
-}
-
-func TestAccountKeyCache(t *testing.T) {
- cache := make(memCache)
- m := Manager{Cache: cache}
- ctx := context.Background()
- k1, err := m.accountKey(ctx)
- if err != nil {
- t.Fatal(err)
- }
- k2, err := m.accountKey(ctx)
- if err != nil {
- t.Fatal(err)
- }
- if !reflect.DeepEqual(k1, k2) {
- t.Errorf("account keys don't match: k1 = %#v; k2 = %#v", k1, k2)
- }
-}
-
-func TestCache(t *testing.T) {
- privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- t.Fatal(err)
- }
- tmpl := &x509.Certificate{
- SerialNumber: big.NewInt(1),
- Subject: pkix.Name{CommonName: "example.org"},
- NotAfter: time.Now().Add(time.Hour),
- }
- pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &privKey.PublicKey, privKey)
- if err != nil {
- t.Fatal(err)
- }
- tlscert := &tls.Certificate{
- Certificate: [][]byte{pub},
- PrivateKey: privKey,
- }
-
- cache := make(memCache)
- man := &Manager{Cache: cache}
- defer man.stopRenew()
- if err := man.cachePut("example.org", tlscert); err != nil {
- t.Fatalf("man.cachePut: %v", err)
- }
- res, err := man.cacheGet("example.org")
- if err != nil {
- t.Fatalf("man.cacheGet: %v", err)
- }
- if res == nil {
- t.Fatal("res is nil")
- }
-}
-
-func TestHostWhitelist(t *testing.T) {
- policy := HostWhitelist("example.com", "example.org", "*.example.net")
- tt := []struct {
- host string
- allow bool
- }{
- {"example.com", true},
- {"example.org", true},
- {"one.example.com", false},
- {"two.example.org", false},
- {"three.example.net", false},
- {"dummy", false},
- }
- for i, test := range tt {
- err := policy(nil, test.host)
- if err != nil && test.allow {
- t.Errorf("%d: policy(%q): %v; want nil", i, test.host, err)
- }
- if err == nil && !test.allow {
- t.Errorf("%d: policy(%q): nil; want an error", i, test.host)
- }
- }
-}
-
-func TestValidCert(t *testing.T) {
- key1, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- t.Fatal(err)
- }
- key2, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- t.Fatal(err)
- }
- key3, err := rsa.GenerateKey(rand.Reader, 512)
- if err != nil {
- t.Fatal(err)
- }
- cert1, err := dummyCert(key1.Public(), "example.org")
- if err != nil {
- t.Fatal(err)
- }
- cert2, err := dummyCert(key2.Public(), "example.org")
- if err != nil {
- t.Fatal(err)
- }
- cert3, err := dummyCert(key3.Public(), "example.org")
- if err != nil {
- t.Fatal(err)
- }
- now := time.Now()
- early, err := dateDummyCert(key1.Public(), now.Add(time.Hour), now.Add(2*time.Hour), "example.org")
- if err != nil {
- t.Fatal(err)
- }
- expired, err := dateDummyCert(key1.Public(), now.Add(-2*time.Hour), now.Add(-time.Hour), "example.org")
- if err != nil {
- t.Fatal(err)
- }
-
- tt := []struct {
- domain string
- key crypto.Signer
- cert [][]byte
- ok bool
- }{
- {"example.org", key1, [][]byte{cert1}, true},
- {"example.org", key3, [][]byte{cert3}, true},
- {"example.org", key1, [][]byte{cert1, cert2, cert3}, true},
- {"example.org", key1, [][]byte{cert1, {1}}, false},
- {"example.org", key1, [][]byte{{1}}, false},
- {"example.org", key1, [][]byte{cert2}, false},
- {"example.org", key2, [][]byte{cert1}, false},
- {"example.org", key1, [][]byte{cert3}, false},
- {"example.org", key3, [][]byte{cert1}, false},
- {"example.net", key1, [][]byte{cert1}, false},
- {"example.org", key1, [][]byte{early}, false},
- {"example.org", key1, [][]byte{expired}, false},
- }
- for i, test := range tt {
- leaf, err := validCert(test.domain, test.cert, test.key)
- if err != nil && test.ok {
- t.Errorf("%d: err = %v", i, err)
- }
- if err == nil && !test.ok {
- t.Errorf("%d: err is nil", i)
- }
- if err == nil && test.ok && leaf == nil {
- t.Errorf("%d: leaf is nil", i)
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache.go
deleted file mode 100644
index 1c67f6c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache.go
+++ /dev/null
@@ -1,130 +0,0 @@
-// 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 autocert
-
-import (
- "errors"
- "io/ioutil"
- "os"
- "path/filepath"
-
- "golang.org/x/net/context"
-)
-
-// ErrCacheMiss is returned when a certificate is not found in cache.
-var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss")
-
-// Cache is used by Manager to store and retrieve previously obtained certificates
-// as opaque data.
-//
-// The key argument of the methods refers to a domain name but need not be an FQDN.
-// Cache implementations should not rely on the key naming pattern.
-type Cache interface {
- // Get returns a certificate data for the specified key.
- // If there's no such key, Get returns ErrCacheMiss.
- Get(ctx context.Context, key string) ([]byte, error)
-
- // Put stores the data in the cache under the specified key.
- // Inderlying implementations may use any data storage format,
- // as long as the reverse operation, Get, results in the original data.
- Put(ctx context.Context, key string, data []byte) error
-
- // Delete removes a certificate data from the cache under the specified key.
- // If there's no such key in the cache, Delete returns nil.
- Delete(ctx context.Context, key string) error
-}
-
-// DirCache implements Cache using a directory on the local filesystem.
-// If the directory does not exist, it will be created with 0700 permissions.
-type DirCache string
-
-// Get reads a certificate data from the specified file name.
-func (d DirCache) Get(ctx context.Context, name string) ([]byte, error) {
- name = filepath.Join(string(d), name)
- var (
- data []byte
- err error
- done = make(chan struct{})
- )
- go func() {
- data, err = ioutil.ReadFile(name)
- close(done)
- }()
- select {
- case <-ctx.Done():
- return nil, ctx.Err()
- case <-done:
- }
- if os.IsNotExist(err) {
- return nil, ErrCacheMiss
- }
- return data, err
-}
-
-// Put writes the certificate data to the specified file name.
-// The file will be created with 0600 permissions.
-func (d DirCache) Put(ctx context.Context, name string, data []byte) error {
- if err := os.MkdirAll(string(d), 0700); err != nil {
- return err
- }
-
- done := make(chan struct{})
- var err error
- go func() {
- defer close(done)
- var tmp string
- if tmp, err = d.writeTempFile(name, data); err != nil {
- return
- }
- // prevent overwriting the file if the context was cancelled
- if ctx.Err() != nil {
- return // no need to set err
- }
- name = filepath.Join(string(d), name)
- err = os.Rename(tmp, name)
- }()
- select {
- case <-ctx.Done():
- return ctx.Err()
- case <-done:
- }
- return err
-}
-
-// Delete removes the specified file name.
-func (d DirCache) Delete(ctx context.Context, name string) error {
- name = filepath.Join(string(d), name)
- var (
- err error
- done = make(chan struct{})
- )
- go func() {
- err = os.Remove(name)
- close(done)
- }()
- select {
- case <-ctx.Done():
- return ctx.Err()
- case <-done:
- }
- if err != nil && !os.IsNotExist(err) {
- return err
- }
- return nil
-}
-
-// writeTempFile writes b to a temporary file, closes the file and returns its path.
-func (d DirCache) writeTempFile(prefix string, b []byte) (string, error) {
- // TempFile uses 0600 permissions
- f, err := ioutil.TempFile(string(d), prefix)
- if err != nil {
- return "", err
- }
- if _, err := f.Write(b); err != nil {
- f.Close()
- return "", err
- }
- return f.Name(), f.Close()
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache_test.go
deleted file mode 100644
index ad6d4a4..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// 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 autocert
-
-import (
- "io/ioutil"
- "os"
- "path/filepath"
- "reflect"
- "testing"
-
- "golang.org/x/net/context"
-)
-
-// make sure DirCache satisfies Cache interface
-var _ Cache = DirCache("/")
-
-func TestDirCache(t *testing.T) {
- dir, err := ioutil.TempDir("", "autocert")
- if err != nil {
- t.Fatal(err)
- }
- dir = filepath.Join(dir, "certs") // a nonexistent dir
- cache := DirCache(dir)
- ctx := context.Background()
-
- // test cache miss
- if _, err := cache.Get(ctx, "nonexistent"); err != ErrCacheMiss {
- t.Errorf("get: %v; want ErrCacheMiss", err)
- }
-
- // test put/get
- b1 := []byte{1}
- if err := cache.Put(ctx, "dummy", b1); err != nil {
- t.Fatalf("put: %v", err)
- }
- b2, err := cache.Get(ctx, "dummy")
- if err != nil {
- t.Fatalf("get: %v", err)
- }
- if !reflect.DeepEqual(b1, b2) {
- t.Errorf("b1 = %v; want %v", b1, b2)
- }
- name := filepath.Join(dir, "dummy")
- if _, err := os.Stat(name); err != nil {
- t.Error(err)
- }
-
- // test delete
- if err := cache.Delete(ctx, "dummy"); err != nil {
- t.Fatalf("delete: %v", err)
- }
- if _, err := cache.Get(ctx, "dummy"); err != ErrCacheMiss {
- t.Errorf("get: %v; want ErrCacheMiss", err)
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal.go
deleted file mode 100644
index 1a5018c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal.go
+++ /dev/null
@@ -1,125 +0,0 @@
-// 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 autocert
-
-import (
- "crypto"
- "sync"
- "time"
-
- "golang.org/x/net/context"
-)
-
-// maxRandRenew is a maximum deviation from Manager.RenewBefore.
-const maxRandRenew = time.Hour
-
-// domainRenewal tracks the state used by the periodic timers
-// renewing a single domain's cert.
-type domainRenewal struct {
- m *Manager
- domain string
- key crypto.Signer
-
- timerMu sync.Mutex
- timer *time.Timer
-}
-
-// start starts a cert renewal timer at the time
-// defined by the certificate expiration time exp.
-//
-// If the timer is already started, calling start is a noop.
-func (dr *domainRenewal) start(exp time.Time) {
- dr.timerMu.Lock()
- defer dr.timerMu.Unlock()
- if dr.timer != nil {
- return
- }
- dr.timer = time.AfterFunc(dr.next(exp), dr.renew)
-}
-
-// stop stops the cert renewal timer.
-// If the timer is already stopped, calling stop is a noop.
-func (dr *domainRenewal) stop() {
- dr.timerMu.Lock()
- defer dr.timerMu.Unlock()
- if dr.timer == nil {
- return
- }
- dr.timer.Stop()
- dr.timer = nil
-}
-
-// renew is called periodically by a timer.
-// The first renew call is kicked off by dr.start.
-func (dr *domainRenewal) renew() {
- dr.timerMu.Lock()
- defer dr.timerMu.Unlock()
- if dr.timer == nil {
- return
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
- defer cancel()
- // TODO: rotate dr.key at some point?
- next, err := dr.do(ctx)
- if err != nil {
- next = maxRandRenew / 2
- next += time.Duration(pseudoRand.int63n(int64(next)))
- }
- dr.timer = time.AfterFunc(next, dr.renew)
- testDidRenewLoop(next, err)
-}
-
-// do is similar to Manager.createCert but it doesn't lock a Manager.state item.
-// Instead, it requests a new certificate independently and, upon success,
-// replaces dr.m.state item with a new one and updates cache for the given domain.
-//
-// It may return immediately if the expiration date of the currently cached cert
-// is far enough in the future.
-//
-// The returned value is a time interval after which the renewal should occur again.
-func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
- // a race is likely unavoidable in a distributed environment
- // but we try nonetheless
- if tlscert, err := dr.m.cacheGet(dr.domain); err == nil {
- next := dr.next(tlscert.Leaf.NotAfter)
- if next > dr.m.renewBefore()+maxRandRenew {
- return next, nil
- }
- }
-
- der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.domain)
- if err != nil {
- return 0, err
- }
- state := &certState{
- key: dr.key,
- cert: der,
- leaf: leaf,
- }
- tlscert, err := state.tlscert()
- if err != nil {
- return 0, err
- }
- dr.m.cachePut(dr.domain, tlscert)
- dr.m.stateMu.Lock()
- defer dr.m.stateMu.Unlock()
- // m.state is guaranteed to be non-nil at this point
- dr.m.state[dr.domain] = state
- return dr.next(leaf.NotAfter), nil
-}
-
-func (dr *domainRenewal) next(expiry time.Time) time.Duration {
- d := expiry.Sub(timeNow()) - dr.m.renewBefore()
- // add a bit of randomness to renew deadline
- n := pseudoRand.int63n(int64(maxRandRenew))
- d -= time.Duration(n)
- if d < 0 {
- return 0
- }
- return d
-}
-
-var testDidRenewLoop = func(next time.Duration, err error) {}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal_test.go
deleted file mode 100644
index d1ec52f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal_test.go
+++ /dev/null
@@ -1,190 +0,0 @@
-// 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 autocert
-
-import (
- "crypto/ecdsa"
- "crypto/elliptic"
- "crypto/rand"
- "crypto/tls"
- "crypto/x509"
- "encoding/base64"
- "fmt"
- "net/http"
- "net/http/httptest"
- "testing"
- "time"
-
- "golang.org/x/crypto/acme"
-)
-
-func TestRenewalNext(t *testing.T) {
- now := time.Now()
- timeNow = func() time.Time { return now }
- defer func() { timeNow = time.Now }()
-
- man := &Manager{RenewBefore: 7 * 24 * time.Hour}
- defer man.stopRenew()
- tt := []struct {
- expiry time.Time
- min, max time.Duration
- }{
- {now.Add(90 * 24 * time.Hour), 83*24*time.Hour - maxRandRenew, 83 * 24 * time.Hour},
- {now.Add(time.Hour), 0, 1},
- {now, 0, 1},
- {now.Add(-time.Hour), 0, 1},
- }
-
- dr := &domainRenewal{m: man}
- for i, test := range tt {
- next := dr.next(test.expiry)
- if next < test.min || test.max < next {
- t.Errorf("%d: next = %v; want between %v and %v", i, next, test.min, test.max)
- }
- }
-}
-
-func TestRenewFromCache(t *testing.T) {
- const domain = "example.org"
-
- // ACME CA server stub
- var ca *httptest.Server
- ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("replay-nonce", "nonce")
- if r.Method == "HEAD" {
- // a nonce request
- return
- }
-
- switch r.URL.Path {
- // discovery
- case "/":
- if err := discoTmpl.Execute(w, ca.URL); err != nil {
- t.Fatalf("discoTmpl: %v", err)
- }
- // client key registration
- case "/new-reg":
- w.Write([]byte("{}"))
- // domain authorization
- case "/new-authz":
- w.Header().Set("location", ca.URL+"/authz/1")
- w.WriteHeader(http.StatusCreated)
- w.Write([]byte(`{"status": "valid"}`))
- // cert request
- case "/new-cert":
- var req struct {
- CSR string `json:"csr"`
- }
- decodePayload(&req, r.Body)
- b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
- csr, err := x509.ParseCertificateRequest(b)
- if err != nil {
- t.Fatalf("new-cert: CSR: %v", err)
- }
- der, err := dummyCert(csr.PublicKey, domain)
- if err != nil {
- t.Fatalf("new-cert: dummyCert: %v", err)
- }
- chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL)
- w.Header().Set("link", chainUp)
- w.WriteHeader(http.StatusCreated)
- w.Write(der)
- // CA chain cert
- case "/ca-cert":
- der, err := dummyCert(nil, "ca")
- if err != nil {
- t.Fatalf("ca-cert: dummyCert: %v", err)
- }
- w.Write(der)
- default:
- t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
- }
- }))
- defer ca.Close()
-
- // use EC key to run faster on 386
- key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- if err != nil {
- t.Fatal(err)
- }
- man := &Manager{
- Prompt: AcceptTOS,
- Cache: make(memCache),
- RenewBefore: 24 * time.Hour,
- Client: &acme.Client{
- Key: key,
- DirectoryURL: ca.URL,
- },
- }
- defer man.stopRenew()
-
- // cache an almost expired cert
- now := time.Now()
- cert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), domain)
- if err != nil {
- t.Fatal(err)
- }
- tlscert := &tls.Certificate{PrivateKey: key, Certificate: [][]byte{cert}}
- if err := man.cachePut(domain, tlscert); err != nil {
- t.Fatal(err)
- }
-
- // veriy the renewal happened
- defer func() {
- testDidRenewLoop = func(next time.Duration, err error) {}
- }()
- done := make(chan struct{})
- testDidRenewLoop = func(next time.Duration, err error) {
- defer close(done)
- if err != nil {
- t.Errorf("testDidRenewLoop: %v", err)
- }
- // Next should be about 90 days:
- // dummyCert creates 90days expiry + account for man.RenewBefore.
- // Previous expiration was within 1 min.
- future := 88 * 24 * time.Hour
- if next < future {
- t.Errorf("testDidRenewLoop: next = %v; want >= %v", next, future)
- }
-
- // ensure the new cert is cached
- after := time.Now().Add(future)
- tlscert, err := man.cacheGet(domain)
- if err != nil {
- t.Fatalf("man.cacheGet: %v", err)
- }
- if !tlscert.Leaf.NotAfter.After(after) {
- t.Errorf("cache leaf.NotAfter = %v; want > %v", tlscert.Leaf.NotAfter, after)
- }
-
- // verify the old cert is also replaced in memory
- man.stateMu.Lock()
- defer man.stateMu.Unlock()
- s := man.state[domain]
- if s == nil {
- t.Fatalf("m.state[%q] is nil", domain)
- }
- tlscert, err = s.tlscert()
- if err != nil {
- t.Fatalf("s.tlscert: %v", err)
- }
- if !tlscert.Leaf.NotAfter.After(after) {
- t.Errorf("state leaf.NotAfter = %v; want > %v", tlscert.Leaf.NotAfter, after)
- }
- }
-
- // trigger renew
- hello := &tls.ClientHelloInfo{ServerName: domain}
- if _, err := man.GetCertificate(hello); err != nil {
- t.Fatal(err)
- }
-
- // wait for renew loop
- select {
- case <-time.After(10 * time.Second):
- t.Fatal("renew took too long to occur")
- case <-done:
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/bcrypt/base64.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/bcrypt/base64.go
deleted file mode 100644
index fc31160..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/bcrypt/base64.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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 bcrypt
-
-import "encoding/base64"
-
-const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
-
-var bcEncoding = base64.NewEncoding(alphabet)
-
-func base64Encode(src []byte) []byte {
- n := bcEncoding.EncodedLen(len(src))
- dst := make([]byte, n)
- bcEncoding.Encode(dst, src)
- for dst[n-1] == '=' {
- n--
- }
- return dst[:n]
-}
-
-func base64Decode(src []byte) ([]byte, error) {
- numOfEquals := 4 - (len(src) % 4)
- for i := 0; i < numOfEquals; i++ {
- src = append(src, '=')
- }
-
- dst := make([]byte, bcEncoding.DecodedLen(len(src)))
- n, err := bcEncoding.Decode(dst, src)
- if err != nil {
- return nil, err
- }
- return dst[:n], nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/bcrypt/bcrypt.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/bcrypt/bcrypt.go
deleted file mode 100644
index f8b807f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/bcrypt/bcrypt.go
+++ /dev/null
@@ -1,294 +0,0 @@
-// 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 bcrypt implements Provos and Mazières's bcrypt adaptive hashing
-// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf
-package bcrypt // import "golang.org/x/crypto/bcrypt"
-
-// The code is a port of Provos and Mazières's C implementation.
-import (
- "crypto/rand"
- "crypto/subtle"
- "errors"
- "fmt"
- "golang.org/x/crypto/blowfish"
- "io"
- "strconv"
-)
-
-const (
- MinCost int = 4 // the minimum allowable cost as passed in to GenerateFromPassword
- MaxCost int = 31 // the maximum allowable cost as passed in to GenerateFromPassword
- DefaultCost int = 10 // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword
-)
-
-// The error returned from CompareHashAndPassword when a password and hash do
-// not match.
-var ErrMismatchedHashAndPassword = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password")
-
-// The error returned from CompareHashAndPassword when a hash is too short to
-// be a bcrypt hash.
-var ErrHashTooShort = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password")
-
-// The error returned from CompareHashAndPassword when a hash was created with
-// a bcrypt algorithm newer than this implementation.
-type HashVersionTooNewError byte
-
-func (hv HashVersionTooNewError) Error() string {
- return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion)
-}
-
-// The error returned from CompareHashAndPassword when a hash starts with something other than '$'
-type InvalidHashPrefixError byte
-
-func (ih InvalidHashPrefixError) Error() string {
- return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih))
-}
-
-type InvalidCostError int
-
-func (ic InvalidCostError) Error() string {
- return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), int(MinCost), int(MaxCost))
-}
-
-const (
- majorVersion = '2'
- minorVersion = 'a'
- maxSaltSize = 16
- maxCryptedHashSize = 23
- encodedSaltSize = 22
- encodedHashSize = 31
- minHashSize = 59
-)
-
-// magicCipherData is an IV for the 64 Blowfish encryption calls in
-// bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes.
-var magicCipherData = []byte{
- 0x4f, 0x72, 0x70, 0x68,
- 0x65, 0x61, 0x6e, 0x42,
- 0x65, 0x68, 0x6f, 0x6c,
- 0x64, 0x65, 0x72, 0x53,
- 0x63, 0x72, 0x79, 0x44,
- 0x6f, 0x75, 0x62, 0x74,
-}
-
-type hashed struct {
- hash []byte
- salt []byte
- cost int // allowed range is MinCost to MaxCost
- major byte
- minor byte
-}
-
-// GenerateFromPassword returns the bcrypt hash of the password at the given
-// cost. If the cost given is less than MinCost, the cost will be set to
-// DefaultCost, instead. Use CompareHashAndPassword, as defined in this package,
-// to compare the returned hashed password with its cleartext version.
-func GenerateFromPassword(password []byte, cost int) ([]byte, error) {
- p, err := newFromPassword(password, cost)
- if err != nil {
- return nil, err
- }
- return p.Hash(), nil
-}
-
-// CompareHashAndPassword compares a bcrypt hashed password with its possible
-// plaintext equivalent. Returns nil on success, or an error on failure.
-func CompareHashAndPassword(hashedPassword, password []byte) error {
- p, err := newFromHash(hashedPassword)
- if err != nil {
- return err
- }
-
- otherHash, err := bcrypt(password, p.cost, p.salt)
- if err != nil {
- return err
- }
-
- otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor}
- if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 {
- return nil
- }
-
- return ErrMismatchedHashAndPassword
-}
-
-// Cost returns the hashing cost used to create the given hashed
-// password. When, in the future, the hashing cost of a password system needs
-// to be increased in order to adjust for greater computational power, this
-// function allows one to establish which passwords need to be updated.
-func Cost(hashedPassword []byte) (int, error) {
- p, err := newFromHash(hashedPassword)
- if err != nil {
- return 0, err
- }
- return p.cost, nil
-}
-
-func newFromPassword(password []byte, cost int) (*hashed, error) {
- if cost < MinCost {
- cost = DefaultCost
- }
- p := new(hashed)
- p.major = majorVersion
- p.minor = minorVersion
-
- err := checkCost(cost)
- if err != nil {
- return nil, err
- }
- p.cost = cost
-
- unencodedSalt := make([]byte, maxSaltSize)
- _, err = io.ReadFull(rand.Reader, unencodedSalt)
- if err != nil {
- return nil, err
- }
-
- p.salt = base64Encode(unencodedSalt)
- hash, err := bcrypt(password, p.cost, p.salt)
- if err != nil {
- return nil, err
- }
- p.hash = hash
- return p, err
-}
-
-func newFromHash(hashedSecret []byte) (*hashed, error) {
- if len(hashedSecret) < minHashSize {
- return nil, ErrHashTooShort
- }
- p := new(hashed)
- n, err := p.decodeVersion(hashedSecret)
- if err != nil {
- return nil, err
- }
- hashedSecret = hashedSecret[n:]
- n, err = p.decodeCost(hashedSecret)
- if err != nil {
- return nil, err
- }
- hashedSecret = hashedSecret[n:]
-
- // The "+2" is here because we'll have to append at most 2 '=' to the salt
- // when base64 decoding it in expensiveBlowfishSetup().
- p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2)
- copy(p.salt, hashedSecret[:encodedSaltSize])
-
- hashedSecret = hashedSecret[encodedSaltSize:]
- p.hash = make([]byte, len(hashedSecret))
- copy(p.hash, hashedSecret)
-
- return p, nil
-}
-
-func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) {
- cipherData := make([]byte, len(magicCipherData))
- copy(cipherData, magicCipherData)
-
- c, err := expensiveBlowfishSetup(password, uint32(cost), salt)
- if err != nil {
- return nil, err
- }
-
- for i := 0; i < 24; i += 8 {
- for j := 0; j < 64; j++ {
- c.Encrypt(cipherData[i:i+8], cipherData[i:i+8])
- }
- }
-
- // Bug compatibility with C bcrypt implementations. We only encode 23 of
- // the 24 bytes encrypted.
- hsh := base64Encode(cipherData[:maxCryptedHashSize])
- return hsh, nil
-}
-
-func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) {
-
- csalt, err := base64Decode(salt)
- if err != nil {
- return nil, err
- }
-
- // Bug compatibility with C bcrypt implementations. They use the trailing
- // NULL in the key string during expansion.
- ckey := append(key, 0)
-
- c, err := blowfish.NewSaltedCipher(ckey, csalt)
- if err != nil {
- return nil, err
- }
-
- var i, rounds uint64
- rounds = 1 << cost
- for i = 0; i < rounds; i++ {
- blowfish.ExpandKey(ckey, c)
- blowfish.ExpandKey(csalt, c)
- }
-
- return c, nil
-}
-
-func (p *hashed) Hash() []byte {
- arr := make([]byte, 60)
- arr[0] = '$'
- arr[1] = p.major
- n := 2
- if p.minor != 0 {
- arr[2] = p.minor
- n = 3
- }
- arr[n] = '$'
- n += 1
- copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost)))
- n += 2
- arr[n] = '$'
- n += 1
- copy(arr[n:], p.salt)
- n += encodedSaltSize
- copy(arr[n:], p.hash)
- n += encodedHashSize
- return arr[:n]
-}
-
-func (p *hashed) decodeVersion(sbytes []byte) (int, error) {
- if sbytes[0] != '$' {
- return -1, InvalidHashPrefixError(sbytes[0])
- }
- if sbytes[1] > majorVersion {
- return -1, HashVersionTooNewError(sbytes[1])
- }
- p.major = sbytes[1]
- n := 3
- if sbytes[2] != '$' {
- p.minor = sbytes[2]
- n++
- }
- return n, nil
-}
-
-// sbytes should begin where decodeVersion left off.
-func (p *hashed) decodeCost(sbytes []byte) (int, error) {
- cost, err := strconv.Atoi(string(sbytes[0:2]))
- if err != nil {
- return -1, err
- }
- err = checkCost(cost)
- if err != nil {
- return -1, err
- }
- p.cost = cost
- return 3, nil
-}
-
-func (p *hashed) String() string {
- return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor)
-}
-
-func checkCost(cost int) error {
- if cost < MinCost || cost > MaxCost {
- return InvalidCostError(cost)
- }
- return nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go
deleted file mode 100644
index f08a6f5..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go
+++ /dev/null
@@ -1,226 +0,0 @@
-// 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 bcrypt
-
-import (
- "bytes"
- "fmt"
- "testing"
-)
-
-func TestBcryptingIsEasy(t *testing.T) {
- pass := []byte("mypassword")
- hp, err := GenerateFromPassword(pass, 0)
- if err != nil {
- t.Fatalf("GenerateFromPassword error: %s", err)
- }
-
- if CompareHashAndPassword(hp, pass) != nil {
- t.Errorf("%v should hash %s correctly", hp, pass)
- }
-
- notPass := "notthepass"
- err = CompareHashAndPassword(hp, []byte(notPass))
- if err != ErrMismatchedHashAndPassword {
- t.Errorf("%v and %s should be mismatched", hp, notPass)
- }
-}
-
-func TestBcryptingIsCorrect(t *testing.T) {
- pass := []byte("allmine")
- salt := []byte("XajjQvNhvvRt5GSeFk1xFe")
- expectedHash := []byte("$2a$10$XajjQvNhvvRt5GSeFk1xFeyqRrsxkhBkUiQeg0dt.wU1qD4aFDcga")
-
- hash, err := bcrypt(pass, 10, salt)
- if err != nil {
- t.Fatalf("bcrypt blew up: %v", err)
- }
- if !bytes.HasSuffix(expectedHash, hash) {
- t.Errorf("%v should be the suffix of %v", hash, expectedHash)
- }
-
- h, err := newFromHash(expectedHash)
- if err != nil {
- t.Errorf("Unable to parse %s: %v", string(expectedHash), err)
- }
-
- // This is not the safe way to compare these hashes. We do this only for
- // testing clarity. Use bcrypt.CompareHashAndPassword()
- if err == nil && !bytes.Equal(expectedHash, h.Hash()) {
- t.Errorf("Parsed hash %v should equal %v", h.Hash(), expectedHash)
- }
-}
-
-func TestVeryShortPasswords(t *testing.T) {
- key := []byte("k")
- salt := []byte("XajjQvNhvvRt5GSeFk1xFe")
- _, err := bcrypt(key, 10, salt)
- if err != nil {
- t.Errorf("One byte key resulted in error: %s", err)
- }
-}
-
-func TestTooLongPasswordsWork(t *testing.T) {
- salt := []byte("XajjQvNhvvRt5GSeFk1xFe")
- // One byte over the usual 56 byte limit that blowfish has
- tooLongPass := []byte("012345678901234567890123456789012345678901234567890123456")
- tooLongExpected := []byte("$2a$10$XajjQvNhvvRt5GSeFk1xFe5l47dONXg781AmZtd869sO8zfsHuw7C")
- hash, err := bcrypt(tooLongPass, 10, salt)
- if err != nil {
- t.Fatalf("bcrypt blew up on long password: %v", err)
- }
- if !bytes.HasSuffix(tooLongExpected, hash) {
- t.Errorf("%v should be the suffix of %v", hash, tooLongExpected)
- }
-}
-
-type InvalidHashTest struct {
- err error
- hash []byte
-}
-
-var invalidTests = []InvalidHashTest{
- {ErrHashTooShort, []byte("$2a$10$fooo")},
- {ErrHashTooShort, []byte("$2a")},
- {HashVersionTooNewError('3'), []byte("$3a$10$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")},
- {InvalidHashPrefixError('%'), []byte("%2a$10$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")},
- {InvalidCostError(32), []byte("$2a$32$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")},
-}
-
-func TestInvalidHashErrors(t *testing.T) {
- check := func(name string, expected, err error) {
- if err == nil {
- t.Errorf("%s: Should have returned an error", name)
- }
- if err != nil && err != expected {
- t.Errorf("%s gave err %v but should have given %v", name, err, expected)
- }
- }
- for _, iht := range invalidTests {
- _, err := newFromHash(iht.hash)
- check("newFromHash", iht.err, err)
- err = CompareHashAndPassword(iht.hash, []byte("anything"))
- check("CompareHashAndPassword", iht.err, err)
- }
-}
-
-func TestUnpaddedBase64Encoding(t *testing.T) {
- original := []byte{101, 201, 101, 75, 19, 227, 199, 20, 239, 236, 133, 32, 30, 109, 243, 30}
- encodedOriginal := []byte("XajjQvNhvvRt5GSeFk1xFe")
-
- encoded := base64Encode(original)
-
- if !bytes.Equal(encodedOriginal, encoded) {
- t.Errorf("Encoded %v should have equaled %v", encoded, encodedOriginal)
- }
-
- decoded, err := base64Decode(encodedOriginal)
- if err != nil {
- t.Fatalf("base64Decode blew up: %s", err)
- }
-
- if !bytes.Equal(decoded, original) {
- t.Errorf("Decoded %v should have equaled %v", decoded, original)
- }
-}
-
-func TestCost(t *testing.T) {
- suffix := "XajjQvNhvvRt5GSeFk1xFe5l47dONXg781AmZtd869sO8zfsHuw7C"
- for _, vers := range []string{"2a", "2"} {
- for _, cost := range []int{4, 10} {
- s := fmt.Sprintf("$%s$%02d$%s", vers, cost, suffix)
- h := []byte(s)
- actual, err := Cost(h)
- if err != nil {
- t.Errorf("Cost, error: %s", err)
- continue
- }
- if actual != cost {
- t.Errorf("Cost, expected: %d, actual: %d", cost, actual)
- }
- }
- }
- _, err := Cost([]byte("$a$a$" + suffix))
- if err == nil {
- t.Errorf("Cost, malformed but no error returned")
- }
-}
-
-func TestCostValidationInHash(t *testing.T) {
- if testing.Short() {
- return
- }
-
- pass := []byte("mypassword")
-
- for c := 0; c < MinCost; c++ {
- p, _ := newFromPassword(pass, c)
- if p.cost != DefaultCost {
- t.Errorf("newFromPassword should default costs below %d to %d, but was %d", MinCost, DefaultCost, p.cost)
- }
- }
-
- p, _ := newFromPassword(pass, 14)
- if p.cost != 14 {
- t.Errorf("newFromPassword should default cost to 14, but was %d", p.cost)
- }
-
- hp, _ := newFromHash(p.Hash())
- if p.cost != hp.cost {
- t.Errorf("newFromHash should maintain the cost at %d, but was %d", p.cost, hp.cost)
- }
-
- _, err := newFromPassword(pass, 32)
- if err == nil {
- t.Fatalf("newFromPassword: should return a cost error")
- }
- if err != InvalidCostError(32) {
- t.Errorf("newFromPassword: should return cost error, got %#v", err)
- }
-}
-
-func TestCostReturnsWithLeadingZeroes(t *testing.T) {
- hp, _ := newFromPassword([]byte("abcdefgh"), 7)
- cost := hp.Hash()[4:7]
- expected := []byte("07$")
-
- if !bytes.Equal(expected, cost) {
- t.Errorf("single digit costs in hash should have leading zeros: was %v instead of %v", cost, expected)
- }
-}
-
-func TestMinorNotRequired(t *testing.T) {
- noMinorHash := []byte("$2$10$XajjQvNhvvRt5GSeFk1xFeyqRrsxkhBkUiQeg0dt.wU1qD4aFDcga")
- h, err := newFromHash(noMinorHash)
- if err != nil {
- t.Fatalf("No minor hash blew up: %s", err)
- }
- if h.minor != 0 {
- t.Errorf("Should leave minor version at 0, but was %d", h.minor)
- }
-
- if !bytes.Equal(noMinorHash, h.Hash()) {
- t.Errorf("Should generate hash %v, but created %v", noMinorHash, h.Hash())
- }
-}
-
-func BenchmarkEqual(b *testing.B) {
- b.StopTimer()
- passwd := []byte("somepasswordyoulike")
- hash, _ := GenerateFromPassword(passwd, 10)
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- CompareHashAndPassword(hash, passwd)
- }
-}
-
-func BenchmarkGeneration(b *testing.B) {
- b.StopTimer()
- passwd := []byte("mylongpassword1234")
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- GenerateFromPassword(passwd, 10)
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/context.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/context.go
deleted file mode 100644
index 134654c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/context.go
+++ /dev/null
@@ -1,156 +0,0 @@
-// 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.
-//
-// 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"
-
-import "time"
-
-// A Context carries a deadline, a cancelation signal, and other values across
-// API boundaries.
-//
-// Context's methods may be called by multiple goroutines simultaneously.
-type Context interface {
- // Deadline returns the time when work done on behalf of this context
- // should be canceled. Deadline returns ok==false when no deadline is
- // set. Successive calls to Deadline return the same results.
- Deadline() (deadline time.Time, ok bool)
-
- // Done returns a channel that's closed when work done on behalf of this
- // context should be canceled. Done may return nil if this context can
- // never be canceled. Successive calls to Done return the same value.
- //
- // WithCancel arranges for Done to be closed when cancel is called;
- // WithDeadline arranges for Done to be closed when the deadline
- // expires; WithTimeout arranges for Done to be closed when the timeout
- // elapses.
- //
- // Done is provided for use in select statements:
- //
- // // Stream generates values with DoSomething and sends them to out
- // // until DoSomething returns an error or ctx.Done is closed.
- // func Stream(ctx context.Context, out chan<- Value) error {
- // for {
- // v, err := DoSomething(ctx)
- // if err != nil {
- // return err
- // }
- // select {
- // case <-ctx.Done():
- // return ctx.Err()
- // case out <- v:
- // }
- // }
- // }
- //
- // See http://blog.golang.org/pipelines for more examples of how to use
- // a Done channel for cancelation.
- Done() <-chan struct{}
-
- // Err returns a non-nil error value after Done is closed. Err returns
- // Canceled if the context was canceled or DeadlineExceeded if the
- // context's deadline passed. No other values for Err are defined.
- // After Done is closed, successive calls to Err return the same value.
- Err() error
-
- // Value returns the value associated with this context for key, or nil
- // if no value is associated with key. Successive calls to Value with
- // the same key returns the same result.
- //
- // Use context values only for request-scoped data that transits
- // processes and API boundaries, not for passing optional parameters to
- // functions.
- //
- // A key identifies a specific value in a Context. Functions that wish
- // to store values in Context typically allocate a key in a global
- // variable then use that key as the argument to context.WithValue and
- // Context.Value. A key can be any type that supports equality;
- // packages should define keys as an unexported type to avoid
- // collisions.
- //
- // Packages that define a Context key should provide type-safe accessors
- // for the values stores using that key:
- //
- // // Package user defines a User type that's stored in Contexts.
- // package user
- //
- // import "golang.org/x/net/context"
- //
- // // User is the type of value stored in the Contexts.
- // type User struct {...}
- //
- // // key is an unexported type for keys defined in this package.
- // // This prevents collisions with keys defined in other packages.
- // type key int
- //
- // // userKey is the key for user.User values in Contexts. It is
- // // unexported; clients use user.NewContext and user.FromContext
- // // instead of using this key directly.
- // var userKey key = 0
- //
- // // NewContext returns a new Context that carries value u.
- // func NewContext(ctx context.Context, u *User) context.Context {
- // return context.WithValue(ctx, userKey, u)
- // }
- //
- // // FromContext returns the User value stored in ctx, if any.
- // func FromContext(ctx context.Context) (*User, bool) {
- // u, ok := ctx.Value(userKey).(*User)
- // return u, ok
- // }
- Value(key interface{}) interface{}
-}
-
-// Background returns a non-nil, empty Context. It is never canceled, has no
-// values, and has no deadline. It is typically used by the main function,
-// 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
-}
-
-// A CancelFunc tells an operation to abandon its work.
-// A CancelFunc does not wait for the work to stop.
-// After the first call, subsequent calls to a CancelFunc do nothing.
-type CancelFunc func()
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/context_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/context_test.go
deleted file mode 100644
index 6284413..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/context_test.go
+++ /dev/null
@@ -1,583 +0,0 @@
-// 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 (
- "fmt"
- "math/rand"
- "runtime"
- "strings"
- "sync"
- "testing"
- "time"
-)
-
-// otherContext is a Context that's not one of the types defined in context.go.
-// This lets us test code paths that differ based on the underlying type of the
-// Context.
-type otherContext struct {
- Context
-}
-
-func TestBackground(t *testing.T) {
- c := Background()
- if c == nil {
- t.Fatalf("Background returned nil")
- }
- select {
- case x := <-c.Done():
- t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
- default:
- }
- if got, want := fmt.Sprint(c), "context.Background"; got != want {
- t.Errorf("Background().String() = %q want %q", got, want)
- }
-}
-
-func TestTODO(t *testing.T) {
- c := TODO()
- if c == nil {
- t.Fatalf("TODO returned nil")
- }
- select {
- case x := <-c.Done():
- t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
- default:
- }
- if got, want := fmt.Sprint(c), "context.TODO"; got != want {
- t.Errorf("TODO().String() = %q want %q", got, want)
- }
-}
-
-func TestWithCancel(t *testing.T) {
- c1, cancel := WithCancel(Background())
-
- if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want {
- t.Errorf("c1.String() = %q want %q", got, want)
- }
-
- o := otherContext{c1}
- c2, _ := WithCancel(o)
- contexts := []Context{c1, o, c2}
-
- for i, c := range contexts {
- if d := c.Done(); d == nil {
- t.Errorf("c[%d].Done() == %v want non-nil", i, d)
- }
- if e := c.Err(); e != nil {
- t.Errorf("c[%d].Err() == %v want nil", i, e)
- }
-
- select {
- case x := <-c.Done():
- t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
- default:
- }
- }
-
- cancel()
- time.Sleep(100 * time.Millisecond) // let cancelation propagate
-
- for i, c := range contexts {
- select {
- case <-c.Done():
- default:
- t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i)
- }
- if e := c.Err(); e != Canceled {
- t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled)
- }
- }
-}
-
-func TestParentFinishesChild(t *testing.T) {
- // Context tree:
- // parent -> cancelChild
- // parent -> valueChild -> timerChild
- parent, cancel := WithCancel(Background())
- cancelChild, stop := WithCancel(parent)
- defer stop()
- valueChild := WithValue(parent, "key", "value")
- timerChild, stop := WithTimeout(valueChild, 10000*time.Hour)
- defer stop()
-
- select {
- case x := <-parent.Done():
- t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
- case x := <-cancelChild.Done():
- t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x)
- case x := <-timerChild.Done():
- t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x)
- case x := <-valueChild.Done():
- t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x)
- default:
- }
-
- // The parent's children should contain the two cancelable children.
- pc := parent.(*cancelCtx)
- cc := cancelChild.(*cancelCtx)
- tc := timerChild.(*timerCtx)
- pc.mu.Lock()
- if len(pc.children) != 2 || !pc.children[cc] || !pc.children[tc] {
- t.Errorf("bad linkage: pc.children = %v, want %v and %v",
- pc.children, cc, tc)
- }
- pc.mu.Unlock()
-
- if p, ok := parentCancelCtx(cc.Context); !ok || p != pc {
- t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc)
- }
- if p, ok := parentCancelCtx(tc.Context); !ok || p != pc {
- t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc)
- }
-
- cancel()
-
- pc.mu.Lock()
- if len(pc.children) != 0 {
- t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children)
- }
- pc.mu.Unlock()
-
- // parent and children should all be finished.
- check := func(ctx Context, name string) {
- select {
- case <-ctx.Done():
- default:
- t.Errorf("<-%s.Done() blocked, but shouldn't have", name)
- }
- if e := ctx.Err(); e != Canceled {
- t.Errorf("%s.Err() == %v want %v", name, e, Canceled)
- }
- }
- check(parent, "parent")
- check(cancelChild, "cancelChild")
- check(valueChild, "valueChild")
- check(timerChild, "timerChild")
-
- // WithCancel should return a canceled context on a canceled parent.
- precanceledChild := WithValue(parent, "key", "value")
- select {
- case <-precanceledChild.Done():
- default:
- t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have")
- }
- if e := precanceledChild.Err(); e != Canceled {
- t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled)
- }
-}
-
-func TestChildFinishesFirst(t *testing.T) {
- cancelable, stop := WithCancel(Background())
- defer stop()
- for _, parent := range []Context{Background(), cancelable} {
- child, cancel := WithCancel(parent)
-
- select {
- case x := <-parent.Done():
- t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
- case x := <-child.Done():
- t.Errorf("<-child.Done() == %v want nothing (it should block)", x)
- default:
- }
-
- cc := child.(*cancelCtx)
- pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background()
- if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) {
- t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok)
- }
-
- if pcok {
- pc.mu.Lock()
- if len(pc.children) != 1 || !pc.children[cc] {
- t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc)
- }
- pc.mu.Unlock()
- }
-
- cancel()
-
- if pcok {
- pc.mu.Lock()
- if len(pc.children) != 0 {
- t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children)
- }
- pc.mu.Unlock()
- }
-
- // child should be finished.
- select {
- case <-child.Done():
- default:
- t.Errorf("<-child.Done() blocked, but shouldn't have")
- }
- if e := child.Err(); e != Canceled {
- t.Errorf("child.Err() == %v want %v", e, Canceled)
- }
-
- // parent should not be finished.
- select {
- case x := <-parent.Done():
- t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
- default:
- }
- if e := parent.Err(); e != nil {
- t.Errorf("parent.Err() == %v want nil", e)
- }
- }
-}
-
-func testDeadline(c Context, wait time.Duration, t *testing.T) {
- select {
- case <-time.After(wait):
- t.Fatalf("context should have timed out")
- case <-c.Done():
- }
- if e := c.Err(); e != DeadlineExceeded {
- t.Errorf("c.Err() == %v want %v", e, DeadlineExceeded)
- }
-}
-
-func TestDeadline(t *testing.T) {
- t.Parallel()
- const timeUnit = 500 * time.Millisecond
- c, _ := WithDeadline(Background(), time.Now().Add(1*timeUnit))
- if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
- t.Errorf("c.String() = %q want prefix %q", got, prefix)
- }
- testDeadline(c, 2*timeUnit, t)
-
- c, _ = WithDeadline(Background(), time.Now().Add(1*timeUnit))
- o := otherContext{c}
- testDeadline(o, 2*timeUnit, t)
-
- c, _ = WithDeadline(Background(), time.Now().Add(1*timeUnit))
- o = otherContext{c}
- c, _ = WithDeadline(o, time.Now().Add(3*timeUnit))
- testDeadline(c, 2*timeUnit, t)
-}
-
-func TestTimeout(t *testing.T) {
- t.Parallel()
- const timeUnit = 500 * time.Millisecond
- c, _ := WithTimeout(Background(), 1*timeUnit)
- if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
- t.Errorf("c.String() = %q want prefix %q", got, prefix)
- }
- testDeadline(c, 2*timeUnit, t)
-
- c, _ = WithTimeout(Background(), 1*timeUnit)
- o := otherContext{c}
- testDeadline(o, 2*timeUnit, t)
-
- c, _ = WithTimeout(Background(), 1*timeUnit)
- o = otherContext{c}
- c, _ = WithTimeout(o, 3*timeUnit)
- testDeadline(c, 2*timeUnit, t)
-}
-
-func TestCanceledTimeout(t *testing.T) {
- t.Parallel()
- const timeUnit = 500 * time.Millisecond
- c, _ := WithTimeout(Background(), 2*timeUnit)
- o := otherContext{c}
- c, cancel := WithTimeout(o, 4*timeUnit)
- cancel()
- time.Sleep(1 * timeUnit) // let cancelation propagate
- select {
- case <-c.Done():
- default:
- t.Errorf("<-c.Done() blocked, but shouldn't have")
- }
- if e := c.Err(); e != Canceled {
- t.Errorf("c.Err() == %v want %v", e, Canceled)
- }
-}
-
-type key1 int
-type key2 int
-
-var k1 = key1(1)
-var k2 = key2(1) // same int as k1, different type
-var k3 = key2(3) // same type as k2, different int
-
-func TestValues(t *testing.T) {
- check := func(c Context, nm, v1, v2, v3 string) {
- if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 {
- t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0)
- }
- if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 {
- t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0)
- }
- if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 {
- t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0)
- }
- }
-
- c0 := Background()
- check(c0, "c0", "", "", "")
-
- c1 := WithValue(Background(), k1, "c1k1")
- check(c1, "c1", "c1k1", "", "")
-
- if got, want := fmt.Sprint(c1), `context.Background.WithValue(1, "c1k1")`; got != want {
- t.Errorf("c.String() = %q want %q", got, want)
- }
-
- c2 := WithValue(c1, k2, "c2k2")
- check(c2, "c2", "c1k1", "c2k2", "")
-
- c3 := WithValue(c2, k3, "c3k3")
- check(c3, "c2", "c1k1", "c2k2", "c3k3")
-
- c4 := WithValue(c3, k1, nil)
- check(c4, "c4", "", "c2k2", "c3k3")
-
- o0 := otherContext{Background()}
- check(o0, "o0", "", "", "")
-
- o1 := otherContext{WithValue(Background(), k1, "c1k1")}
- check(o1, "o1", "c1k1", "", "")
-
- o2 := WithValue(o1, k2, "o2k2")
- check(o2, "o2", "c1k1", "o2k2", "")
-
- o3 := otherContext{c4}
- check(o3, "o3", "", "c2k2", "c3k3")
-
- o4 := WithValue(o3, k3, nil)
- check(o4, "o4", "", "c2k2", "")
-}
-
-func TestAllocs(t *testing.T) {
- bg := Background()
- for _, test := range []struct {
- desc string
- f func()
- limit float64
- gccgoLimit float64
- }{
- {
- desc: "Background()",
- f: func() { Background() },
- limit: 0,
- gccgoLimit: 0,
- },
- {
- desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1),
- f: func() {
- c := WithValue(bg, k1, nil)
- c.Value(k1)
- },
- limit: 3,
- gccgoLimit: 3,
- },
- {
- desc: "WithTimeout(bg, 15*time.Millisecond)",
- f: func() {
- c, _ := WithTimeout(bg, 15*time.Millisecond)
- <-c.Done()
- },
- limit: 8,
- gccgoLimit: 16,
- },
- {
- desc: "WithCancel(bg)",
- f: func() {
- c, cancel := WithCancel(bg)
- cancel()
- <-c.Done()
- },
- limit: 5,
- gccgoLimit: 8,
- },
- {
- desc: "WithTimeout(bg, 100*time.Millisecond)",
- f: func() {
- c, cancel := WithTimeout(bg, 100*time.Millisecond)
- cancel()
- <-c.Done()
- },
- limit: 8,
- gccgoLimit: 25,
- },
- } {
- limit := test.limit
- if runtime.Compiler == "gccgo" {
- // gccgo does not yet do escape analysis.
- // TODO(iant): Remove this when gccgo does do escape analysis.
- limit = test.gccgoLimit
- }
- if n := testing.AllocsPerRun(100, test.f); n > limit {
- t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit))
- }
- }
-}
-
-func TestSimultaneousCancels(t *testing.T) {
- root, cancel := WithCancel(Background())
- m := map[Context]CancelFunc{root: cancel}
- q := []Context{root}
- // Create a tree of contexts.
- for len(q) != 0 && len(m) < 100 {
- parent := q[0]
- q = q[1:]
- for i := 0; i < 4; i++ {
- ctx, cancel := WithCancel(parent)
- m[ctx] = cancel
- q = append(q, ctx)
- }
- }
- // Start all the cancels in a random order.
- var wg sync.WaitGroup
- wg.Add(len(m))
- for _, cancel := range m {
- go func(cancel CancelFunc) {
- cancel()
- wg.Done()
- }(cancel)
- }
- // Wait on all the contexts in a random order.
- for ctx := range m {
- select {
- case <-ctx.Done():
- case <-time.After(1 * time.Second):
- buf := make([]byte, 10<<10)
- n := runtime.Stack(buf, true)
- t.Fatalf("timed out waiting for <-ctx.Done(); stacks:\n%s", buf[:n])
- }
- }
- // Wait for all the cancel functions to return.
- done := make(chan struct{})
- go func() {
- wg.Wait()
- close(done)
- }()
- select {
- case <-done:
- case <-time.After(1 * time.Second):
- buf := make([]byte, 10<<10)
- n := runtime.Stack(buf, true)
- t.Fatalf("timed out waiting for cancel functions; stacks:\n%s", buf[:n])
- }
-}
-
-func TestInterlockedCancels(t *testing.T) {
- parent, cancelParent := WithCancel(Background())
- child, cancelChild := WithCancel(parent)
- go func() {
- parent.Done()
- cancelChild()
- }()
- cancelParent()
- select {
- case <-child.Done():
- case <-time.After(1 * time.Second):
- buf := make([]byte, 10<<10)
- n := runtime.Stack(buf, true)
- t.Fatalf("timed out waiting for child.Done(); stacks:\n%s", buf[:n])
- }
-}
-
-func TestLayersCancel(t *testing.T) {
- testLayers(t, time.Now().UnixNano(), false)
-}
-
-func TestLayersTimeout(t *testing.T) {
- testLayers(t, time.Now().UnixNano(), true)
-}
-
-func testLayers(t *testing.T, seed int64, testTimeout bool) {
- rand.Seed(seed)
- errorf := func(format string, a ...interface{}) {
- t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
- }
- const (
- timeout = 200 * time.Millisecond
- minLayers = 30
- )
- type value int
- var (
- vals []*value
- cancels []CancelFunc
- numTimers int
- ctx = Background()
- )
- for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ {
- switch rand.Intn(3) {
- case 0:
- v := new(value)
- ctx = WithValue(ctx, v, v)
- vals = append(vals, v)
- case 1:
- var cancel CancelFunc
- ctx, cancel = WithCancel(ctx)
- cancels = append(cancels, cancel)
- case 2:
- var cancel CancelFunc
- ctx, cancel = WithTimeout(ctx, timeout)
- cancels = append(cancels, cancel)
- numTimers++
- }
- }
- checkValues := func(when string) {
- for _, key := range vals {
- if val := ctx.Value(key).(*value); key != val {
- errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key)
- }
- }
- }
- select {
- case <-ctx.Done():
- errorf("ctx should not be canceled yet")
- default:
- }
- if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) {
- t.Errorf("ctx.String() = %q want prefix %q", s, prefix)
- }
- t.Log(ctx)
- checkValues("before cancel")
- if testTimeout {
- select {
- case <-ctx.Done():
- case <-time.After(timeout + 100*time.Millisecond):
- errorf("ctx should have timed out")
- }
- checkValues("after timeout")
- } else {
- cancel := cancels[rand.Intn(len(cancels))]
- cancel()
- select {
- case <-ctx.Done():
- default:
- errorf("ctx should be canceled")
- }
- checkValues("after cancel")
- }
-}
-
-func TestCancelRemoves(t *testing.T) {
- checkChildren := func(when string, ctx Context, want int) {
- if got := len(ctx.(*cancelCtx).children); got != want {
- t.Errorf("%s: context has %d children, want %d", when, got, want)
- }
- }
-
- ctx, _ := WithCancel(Background())
- checkChildren("after creation", ctx, 0)
- _, cancel := WithCancel(ctx)
- checkChildren("with WithCancel child ", ctx, 1)
- cancel()
- checkChildren("after cancelling WithCancel child", ctx, 0)
-
- ctx, _ = WithCancel(Background())
- checkChildren("after creation", ctx, 0)
- _, cancel = WithTimeout(ctx, 60*time.Minute)
- checkChildren("with WithTimeout child ", ctx, 1)
- cancel()
- checkChildren("after cancelling WithTimeout child", ctx, 0)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
deleted file mode 100644
index 606cf1f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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 ctxhttp provides helper functions for performing context-aware HTTP requests.
-package ctxhttp // import "golang.org/x/net/context/ctxhttp"
-
-import (
- "io"
- "net/http"
- "net/url"
- "strings"
-
- "golang.org/x/net/context"
-)
-
-// Do sends an HTTP request with the provided http.Client and returns
-// an HTTP response.
-//
-// If the client is nil, http.DefaultClient is used.
-//
-// The provided ctx must be non-nil. If it is canceled or times out,
-// ctx.Err() will be returned.
-func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
- if client == nil {
- client = http.DefaultClient
- }
- resp, err := client.Do(req.WithContext(ctx))
- // If we got an error, and the context has been canceled,
- // the context's error is probably more useful.
- if err != nil {
- select {
- case <-ctx.Done():
- err = ctx.Err()
- default:
- }
- }
- return resp, err
-}
-
-// Get issues a GET request via the Do function.
-func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
- req, err := http.NewRequest("GET", url, nil)
- if err != nil {
- return nil, err
- }
- return Do(ctx, client, req)
-}
-
-// Head issues a HEAD request via the Do function.
-func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
- req, err := http.NewRequest("HEAD", url, nil)
- if err != nil {
- return nil, err
- }
- return Do(ctx, client, req)
-}
-
-// Post issues a POST request via the Do function.
-func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
- req, err := http.NewRequest("POST", url, body)
- if err != nil {
- return nil, err
- }
- req.Header.Set("Content-Type", bodyType)
- return Do(ctx, client, req)
-}
-
-// PostForm issues a POST request via the Do function.
-func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
- return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go
deleted file mode 100644
index 9f0f90f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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.
-
-// +build !plan9,go1.7
-
-package ctxhttp
-
-import (
- "io"
- "net/http"
- "net/http/httptest"
- "testing"
-
- "context"
-)
-
-func TestGo17Context(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- io.WriteString(w, "ok")
- }))
- ctx := context.Background()
- resp, err := Get(ctx, http.DefaultClient, ts.URL)
- if resp == nil || err != nil {
- t.Fatalf("error received from client: %v %v", err, resp)
- }
- resp.Body.Close()
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
deleted file mode 100644
index 926870c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
+++ /dev/null
@@ -1,147 +0,0 @@
-// 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.
-
-// +build !go1.7
-
-package ctxhttp // import "golang.org/x/net/context/ctxhttp"
-
-import (
- "io"
- "net/http"
- "net/url"
- "strings"
-
- "golang.org/x/net/context"
-)
-
-func nop() {}
-
-var (
- testHookContextDoneBeforeHeaders = nop
- testHookDoReturned = nop
- testHookDidBodyClose = nop
-)
-
-// Do sends an HTTP request with the provided http.Client and returns an HTTP response.
-// If the client is nil, http.DefaultClient is used.
-// If the context is canceled or times out, ctx.Err() will be returned.
-func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
- if client == nil {
- client = http.DefaultClient
- }
-
- // TODO(djd): Respect any existing value of req.Cancel.
- cancel := make(chan struct{})
- req.Cancel = cancel
-
- type responseAndError struct {
- resp *http.Response
- err error
- }
- result := make(chan responseAndError, 1)
-
- // Make local copies of test hooks closed over by goroutines below.
- // Prevents data races in tests.
- testHookDoReturned := testHookDoReturned
- testHookDidBodyClose := testHookDidBodyClose
-
- go func() {
- resp, err := client.Do(req)
- testHookDoReturned()
- result <- responseAndError{resp, err}
- }()
-
- var resp *http.Response
-
- select {
- case <-ctx.Done():
- testHookContextDoneBeforeHeaders()
- close(cancel)
- // Clean up after the goroutine calling client.Do:
- go func() {
- if r := <-result; r.resp != nil {
- testHookDidBodyClose()
- r.resp.Body.Close()
- }
- }()
- return nil, ctx.Err()
- case r := <-result:
- var err error
- resp, err = r.resp, r.err
- if err != nil {
- return resp, err
- }
- }
-
- c := make(chan struct{})
- go func() {
- select {
- case <-ctx.Done():
- close(cancel)
- case <-c:
- // The response's Body is closed.
- }
- }()
- resp.Body = &notifyingReader{resp.Body, c}
-
- return resp, nil
-}
-
-// Get issues a GET request via the Do function.
-func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
- req, err := http.NewRequest("GET", url, nil)
- if err != nil {
- return nil, err
- }
- return Do(ctx, client, req)
-}
-
-// Head issues a HEAD request via the Do function.
-func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
- req, err := http.NewRequest("HEAD", url, nil)
- if err != nil {
- return nil, err
- }
- return Do(ctx, client, req)
-}
-
-// Post issues a POST request via the Do function.
-func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
- req, err := http.NewRequest("POST", url, body)
- if err != nil {
- return nil, err
- }
- req.Header.Set("Content-Type", bodyType)
- return Do(ctx, client, req)
-}
-
-// PostForm issues a POST request via the Do function.
-func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
- return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
-}
-
-// notifyingReader is an io.ReadCloser that closes the notify channel after
-// Close is called or a Read fails on the underlying ReadCloser.
-type notifyingReader struct {
- io.ReadCloser
- notify chan<- struct{}
-}
-
-func (r *notifyingReader) Read(p []byte) (int, error) {
- n, err := r.ReadCloser.Read(p)
- if err != nil && r.notify != nil {
- close(r.notify)
- r.notify = nil
- }
- return n, err
-}
-
-func (r *notifyingReader) Close() error {
- err := r.ReadCloser.Close()
- if r.notify != nil {
- close(r.notify)
- r.notify = nil
- }
- return err
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go
deleted file mode 100644
index 9159cf0..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go
+++ /dev/null
@@ -1,79 +0,0 @@
-// 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.
-
-// +build !plan9,!go1.7
-
-package ctxhttp
-
-import (
- "net"
- "net/http"
- "net/http/httptest"
- "sync"
- "testing"
- "time"
-
- "golang.org/x/net/context"
-)
-
-// golang.org/issue/14065
-func TestClosesResponseBodyOnCancel(t *testing.T) {
- defer func() { testHookContextDoneBeforeHeaders = nop }()
- defer func() { testHookDoReturned = nop }()
- defer func() { testHookDidBodyClose = nop }()
-
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
- defer ts.Close()
-
- ctx, cancel := context.WithCancel(context.Background())
-
- // closed when Do enters select case <-ctx.Done()
- enteredDonePath := make(chan struct{})
-
- testHookContextDoneBeforeHeaders = func() {
- close(enteredDonePath)
- }
-
- testHookDoReturned = func() {
- // We now have the result (the Flush'd headers) at least,
- // so we can cancel the request.
- cancel()
-
- // But block the client.Do goroutine from sending
- // until Do enters into the <-ctx.Done() path, since
- // otherwise if both channels are readable, select
- // picks a random one.
- <-enteredDonePath
- }
-
- sawBodyClose := make(chan struct{})
- testHookDidBodyClose = func() { close(sawBodyClose) }
-
- tr := &http.Transport{}
- defer tr.CloseIdleConnections()
- c := &http.Client{Transport: tr}
- req, _ := http.NewRequest("GET", ts.URL, nil)
- _, doErr := Do(ctx, c, req)
-
- select {
- case <-sawBodyClose:
- case <-time.After(5 * time.Second):
- t.Fatal("timeout waiting for body to close")
- }
-
- if doErr != ctx.Err() {
- t.Errorf("Do error = %v; want %v", doErr, ctx.Err())
- }
-}
-
-type noteCloseConn struct {
- net.Conn
- onceClose sync.Once
- closefn func()
-}
-
-func (c *noteCloseConn) Close() error {
- c.onceClose.Do(c.closefn)
- return c.Conn.Close()
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go
deleted file mode 100644
index 1e41551..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// 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.
-
-// +build !plan9
-
-package ctxhttp
-
-import (
- "io"
- "io/ioutil"
- "net/http"
- "net/http/httptest"
- "testing"
- "time"
-
- "golang.org/x/net/context"
-)
-
-const (
- requestDuration = 100 * time.Millisecond
- requestBody = "ok"
-)
-
-func okHandler(w http.ResponseWriter, r *http.Request) {
- time.Sleep(requestDuration)
- io.WriteString(w, requestBody)
-}
-
-func TestNoTimeout(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(okHandler))
- defer ts.Close()
-
- ctx := context.Background()
- res, err := Get(ctx, nil, ts.URL)
- if err != nil {
- t.Fatal(err)
- }
- defer res.Body.Close()
- slurp, err := ioutil.ReadAll(res.Body)
- if err != nil {
- t.Fatal(err)
- }
- if string(slurp) != requestBody {
- t.Errorf("body = %q; want %q", slurp, requestBody)
- }
-}
-
-func TestCancelBeforeHeaders(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
-
- blockServer := make(chan struct{})
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- cancel()
- <-blockServer
- io.WriteString(w, requestBody)
- }))
- defer ts.Close()
- defer close(blockServer)
-
- res, err := Get(ctx, nil, ts.URL)
- if err == nil {
- res.Body.Close()
- t.Fatal("Get returned unexpected nil error")
- }
- if err != context.Canceled {
- t.Errorf("err = %v; want %v", err, context.Canceled)
- }
-}
-
-func TestCancelAfterHangingRequest(t *testing.T) {
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(http.StatusOK)
- w.(http.Flusher).Flush()
- <-w.(http.CloseNotifier).CloseNotify()
- }))
- defer ts.Close()
-
- ctx, cancel := context.WithCancel(context.Background())
- resp, err := Get(ctx, nil, ts.URL)
- if err != nil {
- t.Fatalf("unexpected error in Get: %v", err)
- }
-
- // Cancel befer reading the body.
- // Reading Request.Body should fail, since the request was
- // canceled before anything was written.
- cancel()
-
- done := make(chan struct{})
-
- go func() {
- b, err := ioutil.ReadAll(resp.Body)
- if len(b) != 0 || err == nil {
- t.Errorf(`Read got (%q, %v); want ("", error)`, b, err)
- }
- close(done)
- }()
-
- select {
- case <-time.After(1 * time.Second):
- t.Errorf("Test timed out")
- case <-done:
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/go17.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/go17.go
deleted file mode 100644
index f8cda19..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/go17.go
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/pre_go17.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/pre_go17.go
deleted file mode 100644
index 5a30aca..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/pre_go17.go
+++ /dev/null
@@ -1,300 +0,0 @@
-// 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)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/withtimeout_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/withtimeout_test.go
deleted file mode 100644
index a6754dc..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/withtimeout_test.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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_test
-
-import (
- "fmt"
- "time"
-
- "golang.org/x/net/context"
-)
-
-func ExampleWithTimeout() {
- // Pass a context with a timeout to tell a blocking function that it
- // should abandon its work after the timeout elapses.
- ctx, _ := context.WithTimeout(context.Background(), 100*time.Millisecond)
- select {
- case <-time.After(200 * time.Millisecond):
- fmt.Println("overslept")
- case <-ctx.Done():
- fmt.Println(ctx.Err()) // prints "context deadline exceeded"
- }
- // Output:
- // context deadline exceeded
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/.gitignore b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/.gitignore
deleted file mode 100644
index 190f122..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*~
-h2i/h2i
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/Dockerfile b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/Dockerfile
deleted file mode 100644
index 53fc525..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/Dockerfile
+++ /dev/null
@@ -1,51 +0,0 @@
-#
-# This Dockerfile builds a recent curl with HTTP/2 client support, using
-# a recent nghttp2 build.
-#
-# See the Makefile for how to tag it. If Docker and that image is found, the
-# Go tests use this curl binary for integration tests.
-#
-
-FROM ubuntu:trusty
-
-RUN apt-get update && \
- apt-get upgrade -y && \
- apt-get install -y git-core build-essential wget
-
-RUN apt-get install -y --no-install-recommends \
- autotools-dev libtool pkg-config zlib1g-dev \
- libcunit1-dev libssl-dev libxml2-dev libevent-dev \
- automake autoconf
-
-# The list of packages nghttp2 recommends for h2load:
-RUN apt-get install -y --no-install-recommends make binutils \
- autoconf automake autotools-dev \
- libtool pkg-config zlib1g-dev libcunit1-dev libssl-dev libxml2-dev \
- libev-dev libevent-dev libjansson-dev libjemalloc-dev \
- cython python3.4-dev python-setuptools
-
-# Note: setting NGHTTP2_VER before the git clone, so an old git clone isn't cached:
-ENV NGHTTP2_VER 895da9a
-RUN cd /root && git clone https://github.com/tatsuhiro-t/nghttp2.git
-
-WORKDIR /root/nghttp2
-RUN git reset --hard $NGHTTP2_VER
-RUN autoreconf -i
-RUN automake
-RUN autoconf
-RUN ./configure
-RUN make
-RUN make install
-
-WORKDIR /root
-RUN wget http://curl.haxx.se/download/curl-7.45.0.tar.gz
-RUN tar -zxvf curl-7.45.0.tar.gz
-WORKDIR /root/curl-7.45.0
-RUN ./configure --with-ssl --with-nghttp2=/usr/local
-RUN make
-RUN make install
-RUN ldconfig
-
-CMD ["-h"]
-ENTRYPOINT ["/usr/local/bin/curl"]
-
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/Makefile b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/Makefile
deleted file mode 100644
index 55fd826..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-curlimage:
- docker build -t gohttp2/curl .
-
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/README b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/README
deleted file mode 100644
index 360d5aa..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/README
+++ /dev/null
@@ -1,20 +0,0 @@
-This is a work-in-progress HTTP/2 implementation for Go.
-
-It will eventually live in the Go standard library and won't require
-any changes to your code to use. It will just be automatic.
-
-Status:
-
-* The server support is pretty good. A few things are missing
- but are being worked on.
-* The client work has just started but shares a lot of code
- is coming along much quicker.
-
-Docs are at https://godoc.org/golang.org/x/net/http2
-
-Demo test server at https://http2.golang.org/
-
-Help & bug reports welcome!
-
-Contributing: https://golang.org/doc/contribute.html
-Bugs: https://golang.org/issue/new?title=x/net/http2:+
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/client_conn_pool.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/client_conn_pool.go
deleted file mode 100644
index bdf5652..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/client_conn_pool.go
+++ /dev/null
@@ -1,256 +0,0 @@
-// 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.
-
-// Transport code's client connection pooling.
-
-package http2
-
-import (
- "crypto/tls"
- "net/http"
- "sync"
-)
-
-// ClientConnPool manages a pool of HTTP/2 client connections.
-type ClientConnPool interface {
- GetClientConn(req *http.Request, addr string) (*ClientConn, error)
- MarkDead(*ClientConn)
-}
-
-// clientConnPoolIdleCloser is the interface implemented by ClientConnPool
-// implementations which can close their idle connections.
-type clientConnPoolIdleCloser interface {
- ClientConnPool
- closeIdleConnections()
-}
-
-var (
- _ clientConnPoolIdleCloser = (*clientConnPool)(nil)
- _ clientConnPoolIdleCloser = noDialClientConnPool{}
-)
-
-// TODO: use singleflight for dialing and addConnCalls?
-type clientConnPool struct {
- t *Transport
-
- mu sync.Mutex // TODO: maybe switch to RWMutex
- // TODO: add support for sharing conns based on cert names
- // (e.g. share conn for googleapis.com and appspot.com)
- conns map[string][]*ClientConn // key is host:port
- dialing map[string]*dialCall // currently in-flight dials
- keys map[*ClientConn][]string
- addConnCalls map[string]*addConnCall // in-flight addConnIfNeede calls
-}
-
-func (p *clientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
- return p.getClientConn(req, addr, dialOnMiss)
-}
-
-const (
- dialOnMiss = true
- noDialOnMiss = false
-)
-
-func (p *clientConnPool) getClientConn(req *http.Request, addr string, dialOnMiss bool) (*ClientConn, error) {
- if isConnectionCloseRequest(req) && dialOnMiss {
- // It gets its own connection.
- const singleUse = true
- cc, err := p.t.dialClientConn(addr, singleUse)
- if err != nil {
- return nil, err
- }
- return cc, nil
- }
- p.mu.Lock()
- for _, cc := range p.conns[addr] {
- if cc.CanTakeNewRequest() {
- p.mu.Unlock()
- return cc, nil
- }
- }
- if !dialOnMiss {
- p.mu.Unlock()
- return nil, ErrNoCachedConn
- }
- call := p.getStartDialLocked(addr)
- p.mu.Unlock()
- <-call.done
- return call.res, call.err
-}
-
-// dialCall is an in-flight Transport dial call to a host.
-type dialCall struct {
- p *clientConnPool
- done chan struct{} // closed when done
- res *ClientConn // valid after done is closed
- err error // valid after done is closed
-}
-
-// requires p.mu is held.
-func (p *clientConnPool) getStartDialLocked(addr string) *dialCall {
- if call, ok := p.dialing[addr]; ok {
- // A dial is already in-flight. Don't start another.
- return call
- }
- call := &dialCall{p: p, done: make(chan struct{})}
- if p.dialing == nil {
- p.dialing = make(map[string]*dialCall)
- }
- p.dialing[addr] = call
- go call.dial(addr)
- return call
-}
-
-// run in its own goroutine.
-func (c *dialCall) dial(addr string) {
- const singleUse = false // shared conn
- c.res, c.err = c.p.t.dialClientConn(addr, singleUse)
- close(c.done)
-
- c.p.mu.Lock()
- delete(c.p.dialing, addr)
- if c.err == nil {
- c.p.addConnLocked(addr, c.res)
- }
- c.p.mu.Unlock()
-}
-
-// addConnIfNeeded makes a NewClientConn out of c if a connection for key doesn't
-// already exist. It coalesces concurrent calls with the same key.
-// This is used by the http1 Transport code when it creates a new connection. Because
-// the http1 Transport doesn't de-dup TCP dials to outbound hosts (because it doesn't know
-// the protocol), it can get into a situation where it has multiple TLS connections.
-// This code decides which ones live or die.
-// The return value used is whether c was used.
-// c is never closed.
-func (p *clientConnPool) addConnIfNeeded(key string, t *Transport, c *tls.Conn) (used bool, err error) {
- p.mu.Lock()
- for _, cc := range p.conns[key] {
- if cc.CanTakeNewRequest() {
- p.mu.Unlock()
- return false, nil
- }
- }
- call, dup := p.addConnCalls[key]
- if !dup {
- if p.addConnCalls == nil {
- p.addConnCalls = make(map[string]*addConnCall)
- }
- call = &addConnCall{
- p: p,
- done: make(chan struct{}),
- }
- p.addConnCalls[key] = call
- go call.run(t, key, c)
- }
- p.mu.Unlock()
-
- <-call.done
- if call.err != nil {
- return false, call.err
- }
- return !dup, nil
-}
-
-type addConnCall struct {
- p *clientConnPool
- done chan struct{} // closed when done
- err error
-}
-
-func (c *addConnCall) run(t *Transport, key string, tc *tls.Conn) {
- cc, err := t.NewClientConn(tc)
-
- p := c.p
- p.mu.Lock()
- if err != nil {
- c.err = err
- } else {
- p.addConnLocked(key, cc)
- }
- delete(p.addConnCalls, key)
- p.mu.Unlock()
- close(c.done)
-}
-
-func (p *clientConnPool) addConn(key string, cc *ClientConn) {
- p.mu.Lock()
- p.addConnLocked(key, cc)
- p.mu.Unlock()
-}
-
-// p.mu must be held
-func (p *clientConnPool) addConnLocked(key string, cc *ClientConn) {
- for _, v := range p.conns[key] {
- if v == cc {
- return
- }
- }
- if p.conns == nil {
- p.conns = make(map[string][]*ClientConn)
- }
- if p.keys == nil {
- p.keys = make(map[*ClientConn][]string)
- }
- p.conns[key] = append(p.conns[key], cc)
- p.keys[cc] = append(p.keys[cc], key)
-}
-
-func (p *clientConnPool) MarkDead(cc *ClientConn) {
- p.mu.Lock()
- defer p.mu.Unlock()
- for _, key := range p.keys[cc] {
- vv, ok := p.conns[key]
- if !ok {
- continue
- }
- newList := filterOutClientConn(vv, cc)
- if len(newList) > 0 {
- p.conns[key] = newList
- } else {
- delete(p.conns, key)
- }
- }
- delete(p.keys, cc)
-}
-
-func (p *clientConnPool) closeIdleConnections() {
- p.mu.Lock()
- defer p.mu.Unlock()
- // TODO: don't close a cc if it was just added to the pool
- // milliseconds ago and has never been used. There's currently
- // a small race window with the HTTP/1 Transport's integration
- // where it can add an idle conn just before using it, and
- // somebody else can concurrently call CloseIdleConns and
- // break some caller's RoundTrip.
- for _, vv := range p.conns {
- for _, cc := range vv {
- cc.closeIfIdle()
- }
- }
-}
-
-func filterOutClientConn(in []*ClientConn, exclude *ClientConn) []*ClientConn {
- out := in[:0]
- for _, v := range in {
- if v != exclude {
- out = append(out, v)
- }
- }
- // If we filtered it out, zero out the last item to prevent
- // the GC from seeing it.
- if len(in) != len(out) {
- in[len(in)-1] = nil
- }
- return out
-}
-
-// noDialClientConnPool is an implementation of http2.ClientConnPool
-// which never dials. We let the HTTP/1.1 client dial and use its TLS
-// connection instead.
-type noDialClientConnPool struct{ *clientConnPool }
-
-func (p noDialClientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
- return p.getClientConn(req, addr, noDialOnMiss)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/configure_transport.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/configure_transport.go
deleted file mode 100644
index 4f720f5..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/configure_transport.go
+++ /dev/null
@@ -1,80 +0,0 @@
-// 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.
-
-// +build go1.6
-
-package http2
-
-import (
- "crypto/tls"
- "fmt"
- "net/http"
-)
-
-func configureTransport(t1 *http.Transport) (*Transport, error) {
- connPool := new(clientConnPool)
- t2 := &Transport{
- ConnPool: noDialClientConnPool{connPool},
- t1: t1,
- }
- connPool.t = t2
- if err := registerHTTPSProtocol(t1, noDialH2RoundTripper{t2}); err != nil {
- return nil, err
- }
- if t1.TLSClientConfig == nil {
- t1.TLSClientConfig = new(tls.Config)
- }
- if !strSliceContains(t1.TLSClientConfig.NextProtos, "h2") {
- t1.TLSClientConfig.NextProtos = append([]string{"h2"}, t1.TLSClientConfig.NextProtos...)
- }
- if !strSliceContains(t1.TLSClientConfig.NextProtos, "http/1.1") {
- t1.TLSClientConfig.NextProtos = append(t1.TLSClientConfig.NextProtos, "http/1.1")
- }
- upgradeFn := func(authority string, c *tls.Conn) http.RoundTripper {
- addr := authorityAddr("https", authority)
- if used, err := connPool.addConnIfNeeded(addr, t2, c); err != nil {
- go c.Close()
- return erringRoundTripper{err}
- } else if !used {
- // Turns out we don't need this c.
- // For example, two goroutines made requests to the same host
- // at the same time, both kicking off TCP dials. (since protocol
- // was unknown)
- go c.Close()
- }
- return t2
- }
- if m := t1.TLSNextProto; len(m) == 0 {
- t1.TLSNextProto = map[string]func(string, *tls.Conn) http.RoundTripper{
- "h2": upgradeFn,
- }
- } else {
- m["h2"] = upgradeFn
- }
- return t2, nil
-}
-
-// registerHTTPSProtocol calls Transport.RegisterProtocol but
-// convering panics into errors.
-func registerHTTPSProtocol(t *http.Transport, rt http.RoundTripper) (err error) {
- defer func() {
- if e := recover(); e != nil {
- err = fmt.Errorf("%v", e)
- }
- }()
- t.RegisterProtocol("https", rt)
- return nil
-}
-
-// noDialH2RoundTripper is a RoundTripper which only tries to complete the request
-// if there's already has a cached connection to the host.
-type noDialH2RoundTripper struct{ t *Transport }
-
-func (rt noDialH2RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
- res, err := rt.t.RoundTrip(req)
- if err == ErrNoCachedConn {
- return nil, http.ErrSkipAltProtocol
- }
- return res, err
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/errors.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/errors.go
deleted file mode 100644
index 20fd762..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/errors.go
+++ /dev/null
@@ -1,130 +0,0 @@
-// 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 http2
-
-import (
- "errors"
- "fmt"
-)
-
-// An ErrCode is an unsigned 32-bit error code as defined in the HTTP/2 spec.
-type ErrCode uint32
-
-const (
- ErrCodeNo ErrCode = 0x0
- ErrCodeProtocol ErrCode = 0x1
- ErrCodeInternal ErrCode = 0x2
- ErrCodeFlowControl ErrCode = 0x3
- ErrCodeSettingsTimeout ErrCode = 0x4
- ErrCodeStreamClosed ErrCode = 0x5
- ErrCodeFrameSize ErrCode = 0x6
- ErrCodeRefusedStream ErrCode = 0x7
- ErrCodeCancel ErrCode = 0x8
- ErrCodeCompression ErrCode = 0x9
- ErrCodeConnect ErrCode = 0xa
- ErrCodeEnhanceYourCalm ErrCode = 0xb
- ErrCodeInadequateSecurity ErrCode = 0xc
- ErrCodeHTTP11Required ErrCode = 0xd
-)
-
-var errCodeName = map[ErrCode]string{
- ErrCodeNo: "NO_ERROR",
- ErrCodeProtocol: "PROTOCOL_ERROR",
- ErrCodeInternal: "INTERNAL_ERROR",
- ErrCodeFlowControl: "FLOW_CONTROL_ERROR",
- ErrCodeSettingsTimeout: "SETTINGS_TIMEOUT",
- ErrCodeStreamClosed: "STREAM_CLOSED",
- ErrCodeFrameSize: "FRAME_SIZE_ERROR",
- ErrCodeRefusedStream: "REFUSED_STREAM",
- ErrCodeCancel: "CANCEL",
- ErrCodeCompression: "COMPRESSION_ERROR",
- ErrCodeConnect: "CONNECT_ERROR",
- ErrCodeEnhanceYourCalm: "ENHANCE_YOUR_CALM",
- ErrCodeInadequateSecurity: "INADEQUATE_SECURITY",
- ErrCodeHTTP11Required: "HTTP_1_1_REQUIRED",
-}
-
-func (e ErrCode) String() string {
- if s, ok := errCodeName[e]; ok {
- return s
- }
- return fmt.Sprintf("unknown error code 0x%x", uint32(e))
-}
-
-// ConnectionError is an error that results in the termination of the
-// entire connection.
-type ConnectionError ErrCode
-
-func (e ConnectionError) Error() string { return fmt.Sprintf("connection error: %s", ErrCode(e)) }
-
-// StreamError is an error that only affects one stream within an
-// HTTP/2 connection.
-type StreamError struct {
- StreamID uint32
- Code ErrCode
- Cause error // optional additional detail
-}
-
-func streamError(id uint32, code ErrCode) StreamError {
- return StreamError{StreamID: id, Code: code}
-}
-
-func (e StreamError) Error() string {
- if e.Cause != nil {
- return fmt.Sprintf("stream error: stream ID %d; %v; %v", e.StreamID, e.Code, e.Cause)
- }
- return fmt.Sprintf("stream error: stream ID %d; %v", e.StreamID, e.Code)
-}
-
-// 6.9.1 The Flow Control Window
-// "If a sender receives a WINDOW_UPDATE that causes a flow control
-// window to exceed this maximum it MUST terminate either the stream
-// or the connection, as appropriate. For streams, [...]; for the
-// connection, a GOAWAY frame with a FLOW_CONTROL_ERROR code."
-type goAwayFlowError struct{}
-
-func (goAwayFlowError) Error() string { return "connection exceeded flow control window size" }
-
-// connErrorReason wraps a ConnectionError with an informative error about why it occurs.
-
-// Errors of this type are only returned by the frame parser functions
-// and converted into ConnectionError(ErrCodeProtocol).
-type connError struct {
- Code ErrCode
- Reason string
-}
-
-func (e connError) Error() string {
- return fmt.Sprintf("http2: connection error: %v: %v", e.Code, e.Reason)
-}
-
-type pseudoHeaderError string
-
-func (e pseudoHeaderError) Error() string {
- return fmt.Sprintf("invalid pseudo-header %q", string(e))
-}
-
-type duplicatePseudoHeaderError string
-
-func (e duplicatePseudoHeaderError) Error() string {
- return fmt.Sprintf("duplicate pseudo-header %q", string(e))
-}
-
-type headerFieldNameError string
-
-func (e headerFieldNameError) Error() string {
- return fmt.Sprintf("invalid header field name %q", string(e))
-}
-
-type headerFieldValueError string
-
-func (e headerFieldValueError) Error() string {
- return fmt.Sprintf("invalid header field value %q", string(e))
-}
-
-var (
- errMixPseudoHeaderTypes = errors.New("mix of request and response pseudo headers")
- errPseudoAfterRegular = errors.New("pseudo header field after regular")
-)
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/errors_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/errors_test.go
deleted file mode 100644
index da5c58c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/errors_test.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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 http2
-
-import "testing"
-
-func TestErrCodeString(t *testing.T) {
- tests := []struct {
- err ErrCode
- want string
- }{
- {ErrCodeProtocol, "PROTOCOL_ERROR"},
- {0xd, "HTTP_1_1_REQUIRED"},
- {0xf, "unknown error code 0xf"},
- }
- for i, tt := range tests {
- got := tt.err.String()
- if got != tt.want {
- t.Errorf("%d. Error = %q; want %q", i, got, tt.want)
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/fixed_buffer.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/fixed_buffer.go
deleted file mode 100644
index 47da0f0..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/fixed_buffer.go
+++ /dev/null
@@ -1,60 +0,0 @@
-// 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 http2
-
-import (
- "errors"
-)
-
-// fixedBuffer is an io.ReadWriter backed by a fixed size buffer.
-// It never allocates, but moves old data as new data is written.
-type fixedBuffer struct {
- buf []byte
- r, w int
-}
-
-var (
- errReadEmpty = errors.New("read from empty fixedBuffer")
- errWriteFull = errors.New("write on full fixedBuffer")
-)
-
-// Read copies bytes from the buffer into p.
-// It is an error to read when no data is available.
-func (b *fixedBuffer) Read(p []byte) (n int, err error) {
- if b.r == b.w {
- return 0, errReadEmpty
- }
- n = copy(p, b.buf[b.r:b.w])
- b.r += n
- if b.r == b.w {
- b.r = 0
- b.w = 0
- }
- return n, nil
-}
-
-// Len returns the number of bytes of the unread portion of the buffer.
-func (b *fixedBuffer) Len() int {
- return b.w - b.r
-}
-
-// Write copies bytes from p into the buffer.
-// It is an error to write more data than the buffer can hold.
-func (b *fixedBuffer) Write(p []byte) (n int, err error) {
- // Slide existing data to beginning.
- if b.r > 0 && len(p) > len(b.buf)-b.w {
- copy(b.buf, b.buf[b.r:b.w])
- b.w -= b.r
- b.r = 0
- }
-
- // Write new data.
- n = copy(b.buf[b.w:], p)
- b.w += n
- if n < len(p) {
- err = errWriteFull
- }
- return n, err
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/fixed_buffer_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/fixed_buffer_test.go
deleted file mode 100644
index f5432f8..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/fixed_buffer_test.go
+++ /dev/null
@@ -1,128 +0,0 @@
-// 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 http2
-
-import (
- "reflect"
- "testing"
-)
-
-var bufferReadTests = []struct {
- buf fixedBuffer
- read, wn int
- werr error
- wp []byte
- wbuf fixedBuffer
-}{
- {
- fixedBuffer{[]byte{'a', 0}, 0, 1},
- 5, 1, nil, []byte{'a'},
- fixedBuffer{[]byte{'a', 0}, 0, 0},
- },
- {
- fixedBuffer{[]byte{0, 'a'}, 1, 2},
- 5, 1, nil, []byte{'a'},
- fixedBuffer{[]byte{0, 'a'}, 0, 0},
- },
- {
- fixedBuffer{[]byte{'a', 'b'}, 0, 2},
- 1, 1, nil, []byte{'a'},
- fixedBuffer{[]byte{'a', 'b'}, 1, 2},
- },
- {
- fixedBuffer{[]byte{}, 0, 0},
- 5, 0, errReadEmpty, []byte{},
- fixedBuffer{[]byte{}, 0, 0},
- },
-}
-
-func TestBufferRead(t *testing.T) {
- for i, tt := range bufferReadTests {
- read := make([]byte, tt.read)
- n, err := tt.buf.Read(read)
- if n != tt.wn {
- t.Errorf("#%d: wn = %d want %d", i, n, tt.wn)
- continue
- }
- if err != tt.werr {
- t.Errorf("#%d: werr = %v want %v", i, err, tt.werr)
- continue
- }
- read = read[:n]
- if !reflect.DeepEqual(read, tt.wp) {
- t.Errorf("#%d: read = %+v want %+v", i, read, tt.wp)
- }
- if !reflect.DeepEqual(tt.buf, tt.wbuf) {
- t.Errorf("#%d: buf = %+v want %+v", i, tt.buf, tt.wbuf)
- }
- }
-}
-
-var bufferWriteTests = []struct {
- buf fixedBuffer
- write, wn int
- werr error
- wbuf fixedBuffer
-}{
- {
- buf: fixedBuffer{
- buf: []byte{},
- },
- wbuf: fixedBuffer{
- buf: []byte{},
- },
- },
- {
- buf: fixedBuffer{
- buf: []byte{1, 'a'},
- },
- write: 1,
- wn: 1,
- wbuf: fixedBuffer{
- buf: []byte{0, 'a'},
- w: 1,
- },
- },
- {
- buf: fixedBuffer{
- buf: []byte{'a', 1},
- r: 1,
- w: 1,
- },
- write: 2,
- wn: 2,
- wbuf: fixedBuffer{
- buf: []byte{0, 0},
- w: 2,
- },
- },
- {
- buf: fixedBuffer{
- buf: []byte{},
- },
- write: 5,
- werr: errWriteFull,
- wbuf: fixedBuffer{
- buf: []byte{},
- },
- },
-}
-
-func TestBufferWrite(t *testing.T) {
- for i, tt := range bufferWriteTests {
- n, err := tt.buf.Write(make([]byte, tt.write))
- if n != tt.wn {
- t.Errorf("#%d: wrote %d bytes; want %d", i, n, tt.wn)
- continue
- }
- if err != tt.werr {
- t.Errorf("#%d: error = %v; want %v", i, err, tt.werr)
- continue
- }
- if !reflect.DeepEqual(tt.buf, tt.wbuf) {
- t.Errorf("#%d: buf = %+v; want %+v", i, tt.buf, tt.wbuf)
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/flow.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/flow.go
deleted file mode 100644
index 957de25..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/flow.go
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.
-
-// Flow control
-
-package http2
-
-// flow is the flow control window's size.
-type flow struct {
- // n is the number of DATA bytes we're allowed to send.
- // A flow is kept both on a conn and a per-stream.
- n int32
-
- // conn points to the shared connection-level flow that is
- // shared by all streams on that conn. It is nil for the flow
- // that's on the conn directly.
- conn *flow
-}
-
-func (f *flow) setConnFlow(cf *flow) { f.conn = cf }
-
-func (f *flow) available() int32 {
- n := f.n
- if f.conn != nil && f.conn.n < n {
- n = f.conn.n
- }
- return n
-}
-
-func (f *flow) take(n int32) {
- if n > f.available() {
- panic("internal error: took too much")
- }
- f.n -= n
- if f.conn != nil {
- f.conn.n -= n
- }
-}
-
-// add adds n bytes (positive or negative) to the flow control window.
-// It returns false if the sum would exceed 2^31-1.
-func (f *flow) add(n int32) bool {
- remain := (1<<31 - 1) - f.n
- if n > remain {
- return false
- }
- f.n += n
- return true
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/flow_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/flow_test.go
deleted file mode 100644
index 859adf5..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/flow_test.go
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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 http2
-
-import "testing"
-
-func TestFlow(t *testing.T) {
- var st flow
- var conn flow
- st.add(3)
- conn.add(2)
-
- if got, want := st.available(), int32(3); got != want {
- t.Errorf("available = %d; want %d", got, want)
- }
- st.setConnFlow(&conn)
- if got, want := st.available(), int32(2); got != want {
- t.Errorf("after parent setup, available = %d; want %d", got, want)
- }
-
- st.take(2)
- if got, want := conn.available(), int32(0); got != want {
- t.Errorf("after taking 2, conn = %d; want %d", got, want)
- }
- if got, want := st.available(), int32(0); got != want {
- t.Errorf("after taking 2, stream = %d; want %d", got, want)
- }
-}
-
-func TestFlowAdd(t *testing.T) {
- var f flow
- if !f.add(1) {
- t.Fatal("failed to add 1")
- }
- if !f.add(-1) {
- t.Fatal("failed to add -1")
- }
- if got, want := f.available(), int32(0); got != want {
- t.Fatalf("size = %d; want %d", got, want)
- }
- if !f.add(1<<31 - 1) {
- t.Fatal("failed to add 2^31-1")
- }
- if got, want := f.available(), int32(1<<31-1); got != want {
- t.Fatalf("size = %d; want %d", got, want)
- }
- if f.add(1) {
- t.Fatal("adding 1 to max shouldn't be allowed")
- }
-
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/frame.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/frame.go
deleted file mode 100644
index 9573588..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/frame.go
+++ /dev/null
@@ -1,1556 +0,0 @@
-// 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 http2
-
-import (
- "bytes"
- "encoding/binary"
- "errors"
- "fmt"
- "io"
- "log"
- "strings"
- "sync"
-
- "golang.org/x/net/http2/hpack"
- "golang.org/x/net/lex/httplex"
-)
-
-const frameHeaderLen = 9
-
-var padZeros = make([]byte, 255) // zeros for padding
-
-// A FrameType is a registered frame type as defined in
-// http://http2.github.io/http2-spec/#rfc.section.11.2
-type FrameType uint8
-
-const (
- FrameData FrameType = 0x0
- FrameHeaders FrameType = 0x1
- FramePriority FrameType = 0x2
- FrameRSTStream FrameType = 0x3
- FrameSettings FrameType = 0x4
- FramePushPromise FrameType = 0x5
- FramePing FrameType = 0x6
- FrameGoAway FrameType = 0x7
- FrameWindowUpdate FrameType = 0x8
- FrameContinuation FrameType = 0x9
-)
-
-var frameName = map[FrameType]string{
- FrameData: "DATA",
- FrameHeaders: "HEADERS",
- FramePriority: "PRIORITY",
- FrameRSTStream: "RST_STREAM",
- FrameSettings: "SETTINGS",
- FramePushPromise: "PUSH_PROMISE",
- FramePing: "PING",
- FrameGoAway: "GOAWAY",
- FrameWindowUpdate: "WINDOW_UPDATE",
- FrameContinuation: "CONTINUATION",
-}
-
-func (t FrameType) String() string {
- if s, ok := frameName[t]; ok {
- return s
- }
- return fmt.Sprintf("UNKNOWN_FRAME_TYPE_%d", uint8(t))
-}
-
-// Flags is a bitmask of HTTP/2 flags.
-// The meaning of flags varies depending on the frame type.
-type Flags uint8
-
-// Has reports whether f contains all (0 or more) flags in v.
-func (f Flags) Has(v Flags) bool {
- return (f & v) == v
-}
-
-// Frame-specific FrameHeader flag bits.
-const (
- // Data Frame
- FlagDataEndStream Flags = 0x1
- FlagDataPadded Flags = 0x8
-
- // Headers Frame
- FlagHeadersEndStream Flags = 0x1
- FlagHeadersEndHeaders Flags = 0x4
- FlagHeadersPadded Flags = 0x8
- FlagHeadersPriority Flags = 0x20
-
- // Settings Frame
- FlagSettingsAck Flags = 0x1
-
- // Ping Frame
- FlagPingAck Flags = 0x1
-
- // Continuation Frame
- FlagContinuationEndHeaders Flags = 0x4
-
- FlagPushPromiseEndHeaders Flags = 0x4
- FlagPushPromisePadded Flags = 0x8
-)
-
-var flagName = map[FrameType]map[Flags]string{
- FrameData: {
- FlagDataEndStream: "END_STREAM",
- FlagDataPadded: "PADDED",
- },
- FrameHeaders: {
- FlagHeadersEndStream: "END_STREAM",
- FlagHeadersEndHeaders: "END_HEADERS",
- FlagHeadersPadded: "PADDED",
- FlagHeadersPriority: "PRIORITY",
- },
- FrameSettings: {
- FlagSettingsAck: "ACK",
- },
- FramePing: {
- FlagPingAck: "ACK",
- },
- FrameContinuation: {
- FlagContinuationEndHeaders: "END_HEADERS",
- },
- FramePushPromise: {
- FlagPushPromiseEndHeaders: "END_HEADERS",
- FlagPushPromisePadded: "PADDED",
- },
-}
-
-// a frameParser parses a frame given its FrameHeader and payload
-// bytes. The length of payload will always equal fh.Length (which
-// might be 0).
-type frameParser func(fh FrameHeader, payload []byte) (Frame, error)
-
-var frameParsers = map[FrameType]frameParser{
- FrameData: parseDataFrame,
- FrameHeaders: parseHeadersFrame,
- FramePriority: parsePriorityFrame,
- FrameRSTStream: parseRSTStreamFrame,
- FrameSettings: parseSettingsFrame,
- FramePushPromise: parsePushPromise,
- FramePing: parsePingFrame,
- FrameGoAway: parseGoAwayFrame,
- FrameWindowUpdate: parseWindowUpdateFrame,
- FrameContinuation: parseContinuationFrame,
-}
-
-func typeFrameParser(t FrameType) frameParser {
- if f := frameParsers[t]; f != nil {
- return f
- }
- return parseUnknownFrame
-}
-
-// A FrameHeader is the 9 byte header of all HTTP/2 frames.
-//
-// See http://http2.github.io/http2-spec/#FrameHeader
-type FrameHeader struct {
- valid bool // caller can access []byte fields in the Frame
-
- // Type is the 1 byte frame type. There are ten standard frame
- // types, but extension frame types may be written by WriteRawFrame
- // and will be returned by ReadFrame (as UnknownFrame).
- Type FrameType
-
- // Flags are the 1 byte of 8 potential bit flags per frame.
- // They are specific to the frame type.
- Flags Flags
-
- // Length is the length of the frame, not including the 9 byte header.
- // The maximum size is one byte less than 16MB (uint24), but only
- // frames up to 16KB are allowed without peer agreement.
- Length uint32
-
- // StreamID is which stream this frame is for. Certain frames
- // are not stream-specific, in which case this field is 0.
- StreamID uint32
-}
-
-// Header returns h. It exists so FrameHeaders can be embedded in other
-// specific frame types and implement the Frame interface.
-func (h FrameHeader) Header() FrameHeader { return h }
-
-func (h FrameHeader) String() string {
- var buf bytes.Buffer
- buf.WriteString("[FrameHeader ")
- h.writeDebug(&buf)
- buf.WriteByte(']')
- return buf.String()
-}
-
-func (h FrameHeader) writeDebug(buf *bytes.Buffer) {
- buf.WriteString(h.Type.String())
- if h.Flags != 0 {
- buf.WriteString(" flags=")
- set := 0
- for i := uint8(0); i < 8; i++ {
- if h.Flags&(1<<i) == 0 {
- continue
- }
- set++
- if set > 1 {
- buf.WriteByte('|')
- }
- name := flagName[h.Type][Flags(1<<i)]
- if name != "" {
- buf.WriteString(name)
- } else {
- fmt.Fprintf(buf, "0x%x", 1<<i)
- }
- }
- }
- if h.StreamID != 0 {
- fmt.Fprintf(buf, " stream=%d", h.StreamID)
- }
- fmt.Fprintf(buf, " len=%d", h.Length)
-}
-
-func (h *FrameHeader) checkValid() {
- if !h.valid {
- panic("Frame accessor called on non-owned Frame")
- }
-}
-
-func (h *FrameHeader) invalidate() { h.valid = false }
-
-// frame header bytes.
-// Used only by ReadFrameHeader.
-var fhBytes = sync.Pool{
- New: func() interface{} {
- buf := make([]byte, frameHeaderLen)
- return &buf
- },
-}
-
-// ReadFrameHeader reads 9 bytes from r and returns a FrameHeader.
-// Most users should use Framer.ReadFrame instead.
-func ReadFrameHeader(r io.Reader) (FrameHeader, error) {
- bufp := fhBytes.Get().(*[]byte)
- defer fhBytes.Put(bufp)
- return readFrameHeader(*bufp, r)
-}
-
-func readFrameHeader(buf []byte, r io.Reader) (FrameHeader, error) {
- _, err := io.ReadFull(r, buf[:frameHeaderLen])
- if err != nil {
- return FrameHeader{}, err
- }
- return FrameHeader{
- Length: (uint32(buf[0])<<16 | uint32(buf[1])<<8 | uint32(buf[2])),
- Type: FrameType(buf[3]),
- Flags: Flags(buf[4]),
- StreamID: binary.BigEndian.Uint32(buf[5:]) & (1<<31 - 1),
- valid: true,
- }, nil
-}
-
-// A Frame is the base interface implemented by all frame types.
-// Callers will generally type-assert the specific frame type:
-// *HeadersFrame, *SettingsFrame, *WindowUpdateFrame, etc.
-//
-// Frames are only valid until the next call to Framer.ReadFrame.
-type Frame interface {
- Header() FrameHeader
-
- // invalidate is called by Framer.ReadFrame to make this
- // frame's buffers as being invalid, since the subsequent
- // frame will reuse them.
- invalidate()
-}
-
-// A Framer reads and writes Frames.
-type Framer struct {
- r io.Reader
- lastFrame Frame
- errDetail error
-
- // lastHeaderStream is non-zero if the last frame was an
- // unfinished HEADERS/CONTINUATION.
- lastHeaderStream uint32
-
- maxReadSize uint32
- headerBuf [frameHeaderLen]byte
-
- // TODO: let getReadBuf be configurable, and use a less memory-pinning
- // allocator in server.go to minimize memory pinned for many idle conns.
- // Will probably also need to make frame invalidation have a hook too.
- getReadBuf func(size uint32) []byte
- readBuf []byte // cache for default getReadBuf
-
- maxWriteSize uint32 // zero means unlimited; TODO: implement
-
- w io.Writer
- wbuf []byte
-
- // AllowIllegalWrites permits the Framer's Write methods to
- // write frames that do not conform to the HTTP/2 spec. This
- // permits using the Framer to test other HTTP/2
- // implementations' conformance to the spec.
- // If false, the Write methods will prefer to return an error
- // rather than comply.
- AllowIllegalWrites bool
-
- // AllowIllegalReads permits the Framer's ReadFrame method
- // to return non-compliant frames or frame orders.
- // This is for testing and permits using the Framer to test
- // other HTTP/2 implementations' conformance to the spec.
- // It is not compatible with ReadMetaHeaders.
- AllowIllegalReads bool
-
- // ReadMetaHeaders if non-nil causes ReadFrame to merge
- // HEADERS and CONTINUATION frames together and return
- // MetaHeadersFrame instead.
- ReadMetaHeaders *hpack.Decoder
-
- // MaxHeaderListSize is the http2 MAX_HEADER_LIST_SIZE.
- // It's used only if ReadMetaHeaders is set; 0 means a sane default
- // (currently 16MB)
- // If the limit is hit, MetaHeadersFrame.Truncated is set true.
- MaxHeaderListSize uint32
-
- // TODO: track which type of frame & with which flags was sent
- // last. Then return an error (unless AllowIllegalWrites) if
- // we're in the middle of a header block and a
- // non-Continuation or Continuation on a different stream is
- // attempted to be written.
-
- logReads, logWrites bool
-
- debugFramer *Framer // only use for logging written writes
- debugFramerBuf *bytes.Buffer
- debugReadLoggerf func(string, ...interface{})
- debugWriteLoggerf func(string, ...interface{})
-}
-
-func (fr *Framer) maxHeaderListSize() uint32 {
- if fr.MaxHeaderListSize == 0 {
- return 16 << 20 // sane default, per docs
- }
- return fr.MaxHeaderListSize
-}
-
-func (f *Framer) startWrite(ftype FrameType, flags Flags, streamID uint32) {
- // Write the FrameHeader.
- f.wbuf = append(f.wbuf[:0],
- 0, // 3 bytes of length, filled in in endWrite
- 0,
- 0,
- byte(ftype),
- byte(flags),
- byte(streamID>>24),
- byte(streamID>>16),
- byte(streamID>>8),
- byte(streamID))
-}
-
-func (f *Framer) endWrite() error {
- // Now that we know the final size, fill in the FrameHeader in
- // the space previously reserved for it. Abuse append.
- length := len(f.wbuf) - frameHeaderLen
- if length >= (1 << 24) {
- return ErrFrameTooLarge
- }
- _ = append(f.wbuf[:0],
- byte(length>>16),
- byte(length>>8),
- byte(length))
- if f.logWrites {
- f.logWrite()
- }
-
- n, err := f.w.Write(f.wbuf)
- if err == nil && n != len(f.wbuf) {
- err = io.ErrShortWrite
- }
- return err
-}
-
-func (f *Framer) logWrite() {
- if f.debugFramer == nil {
- f.debugFramerBuf = new(bytes.Buffer)
- f.debugFramer = NewFramer(nil, f.debugFramerBuf)
- f.debugFramer.logReads = false // we log it ourselves, saying "wrote" below
- // Let us read anything, even if we accidentally wrote it
- // in the wrong order:
- f.debugFramer.AllowIllegalReads = true
- }
- f.debugFramerBuf.Write(f.wbuf)
- fr, err := f.debugFramer.ReadFrame()
- if err != nil {
- f.debugWriteLoggerf("http2: Framer %p: failed to decode just-written frame", f)
- return
- }
- f.debugWriteLoggerf("http2: Framer %p: wrote %v", f, summarizeFrame(fr))
-}
-
-func (f *Framer) writeByte(v byte) { f.wbuf = append(f.wbuf, v) }
-func (f *Framer) writeBytes(v []byte) { f.wbuf = append(f.wbuf, v...) }
-func (f *Framer) writeUint16(v uint16) { f.wbuf = append(f.wbuf, byte(v>>8), byte(v)) }
-func (f *Framer) writeUint32(v uint32) {
- f.wbuf = append(f.wbuf, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
-}
-
-const (
- minMaxFrameSize = 1 << 14
- maxFrameSize = 1<<24 - 1
-)
-
-// NewFramer returns a Framer that writes frames to w and reads them from r.
-func NewFramer(w io.Writer, r io.Reader) *Framer {
- fr := &Framer{
- w: w,
- r: r,
- logReads: logFrameReads,
- logWrites: logFrameWrites,
- debugReadLoggerf: log.Printf,
- debugWriteLoggerf: log.Printf,
- }
- fr.getReadBuf = func(size uint32) []byte {
- if cap(fr.readBuf) >= int(size) {
- return fr.readBuf[:size]
- }
- fr.readBuf = make([]byte, size)
- return fr.readBuf
- }
- fr.SetMaxReadFrameSize(maxFrameSize)
- return fr
-}
-
-// SetMaxReadFrameSize sets the maximum size of a frame
-// that will be read by a subsequent call to ReadFrame.
-// It is the caller's responsibility to advertise this
-// limit with a SETTINGS frame.
-func (fr *Framer) SetMaxReadFrameSize(v uint32) {
- if v > maxFrameSize {
- v = maxFrameSize
- }
- fr.maxReadSize = v
-}
-
-// ErrorDetail returns a more detailed error of the last error
-// returned by Framer.ReadFrame. For instance, if ReadFrame
-// returns a StreamError with code PROTOCOL_ERROR, ErrorDetail
-// will say exactly what was invalid. ErrorDetail is not guaranteed
-// to return a non-nil value and like the rest of the http2 package,
-// its return value is not protected by an API compatibility promise.
-// ErrorDetail is reset after the next call to ReadFrame.
-func (fr *Framer) ErrorDetail() error {
- return fr.errDetail
-}
-
-// ErrFrameTooLarge is returned from Framer.ReadFrame when the peer
-// sends a frame that is larger than declared with SetMaxReadFrameSize.
-var ErrFrameTooLarge = errors.New("http2: frame too large")
-
-// terminalReadFrameError reports whether err is an unrecoverable
-// error from ReadFrame and no other frames should be read.
-func terminalReadFrameError(err error) bool {
- if _, ok := err.(StreamError); ok {
- return false
- }
- return err != nil
-}
-
-// ReadFrame reads a single frame. The returned Frame is only valid
-// until the next call to ReadFrame.
-//
-// If the frame is larger than previously set with SetMaxReadFrameSize, the
-// returned error is ErrFrameTooLarge. Other errors may be of type
-// ConnectionError, StreamError, or anything else from the underlying
-// reader.
-func (fr *Framer) ReadFrame() (Frame, error) {
- fr.errDetail = nil
- if fr.lastFrame != nil {
- fr.lastFrame.invalidate()
- }
- fh, err := readFrameHeader(fr.headerBuf[:], fr.r)
- if err != nil {
- return nil, err
- }
- if fh.Length > fr.maxReadSize {
- return nil, ErrFrameTooLarge
- }
- payload := fr.getReadBuf(fh.Length)
- if _, err := io.ReadFull(fr.r, payload); err != nil {
- return nil, err
- }
- f, err := typeFrameParser(fh.Type)(fh, payload)
- if err != nil {
- if ce, ok := err.(connError); ok {
- return nil, fr.connError(ce.Code, ce.Reason)
- }
- return nil, err
- }
- if err := fr.checkFrameOrder(f); err != nil {
- return nil, err
- }
- if fr.logReads {
- fr.debugReadLoggerf("http2: Framer %p: read %v", fr, summarizeFrame(f))
- }
- if fh.Type == FrameHeaders && fr.ReadMetaHeaders != nil {
- return fr.readMetaFrame(f.(*HeadersFrame))
- }
- return f, nil
-}
-
-// connError returns ConnectionError(code) but first
-// stashes away a public reason to the caller can optionally relay it
-// to the peer before hanging up on them. This might help others debug
-// their implementations.
-func (fr *Framer) connError(code ErrCode, reason string) error {
- fr.errDetail = errors.New(reason)
- return ConnectionError(code)
-}
-
-// checkFrameOrder reports an error if f is an invalid frame to return
-// next from ReadFrame. Mostly it checks whether HEADERS and
-// CONTINUATION frames are contiguous.
-func (fr *Framer) checkFrameOrder(f Frame) error {
- last := fr.lastFrame
- fr.lastFrame = f
- if fr.AllowIllegalReads {
- return nil
- }
-
- fh := f.Header()
- if fr.lastHeaderStream != 0 {
- if fh.Type != FrameContinuation {
- return fr.connError(ErrCodeProtocol,
- fmt.Sprintf("got %s for stream %d; expected CONTINUATION following %s for stream %d",
- fh.Type, fh.StreamID,
- last.Header().Type, fr.lastHeaderStream))
- }
- if fh.StreamID != fr.lastHeaderStream {
- return fr.connError(ErrCodeProtocol,
- fmt.Sprintf("got CONTINUATION for stream %d; expected stream %d",
- fh.StreamID, fr.lastHeaderStream))
- }
- } else if fh.Type == FrameContinuation {
- return fr.connError(ErrCodeProtocol, fmt.Sprintf("unexpected CONTINUATION for stream %d", fh.StreamID))
- }
-
- switch fh.Type {
- case FrameHeaders, FrameContinuation:
- if fh.Flags.Has(FlagHeadersEndHeaders) {
- fr.lastHeaderStream = 0
- } else {
- fr.lastHeaderStream = fh.StreamID
- }
- }
-
- return nil
-}
-
-// A DataFrame conveys arbitrary, variable-length sequences of octets
-// associated with a stream.
-// See http://http2.github.io/http2-spec/#rfc.section.6.1
-type DataFrame struct {
- FrameHeader
- data []byte
-}
-
-func (f *DataFrame) StreamEnded() bool {
- return f.FrameHeader.Flags.Has(FlagDataEndStream)
-}
-
-// Data returns the frame's data octets, not including any padding
-// size byte or padding suffix bytes.
-// The caller must not retain the returned memory past the next
-// call to ReadFrame.
-func (f *DataFrame) Data() []byte {
- f.checkValid()
- return f.data
-}
-
-func parseDataFrame(fh FrameHeader, payload []byte) (Frame, error) {
- if fh.StreamID == 0 {
- // DATA frames MUST be associated with a stream. If a
- // DATA frame is received whose stream identifier
- // field is 0x0, the recipient MUST respond with a
- // connection error (Section 5.4.1) of type
- // PROTOCOL_ERROR.
- return nil, connError{ErrCodeProtocol, "DATA frame with stream ID 0"}
- }
- f := &DataFrame{
- FrameHeader: fh,
- }
- var padSize byte
- if fh.Flags.Has(FlagDataPadded) {
- var err error
- payload, padSize, err = readByte(payload)
- if err != nil {
- return nil, err
- }
- }
- if int(padSize) > len(payload) {
- // If the length of the padding is greater than the
- // length of the frame payload, the recipient MUST
- // treat this as a connection error.
- // Filed: https://github.com/http2/http2-spec/issues/610
- return nil, connError{ErrCodeProtocol, "pad size larger than data payload"}
- }
- f.data = payload[:len(payload)-int(padSize)]
- return f, nil
-}
-
-var (
- errStreamID = errors.New("invalid stream ID")
- errDepStreamID = errors.New("invalid dependent stream ID")
- errPadLength = errors.New("pad length too large")
- errPadBytes = errors.New("padding bytes must all be zeros unless AllowIllegalWrites is enabled")
-)
-
-func validStreamIDOrZero(streamID uint32) bool {
- return streamID&(1<<31) == 0
-}
-
-func validStreamID(streamID uint32) bool {
- return streamID != 0 && streamID&(1<<31) == 0
-}
-
-// WriteData writes a DATA frame.
-//
-// It will perform exactly one Write to the underlying Writer.
-// It is the caller's responsibility not to violate the maximum frame size
-// and to not call other Write methods concurrently.
-func (f *Framer) WriteData(streamID uint32, endStream bool, data []byte) error {
- return f.WriteDataPadded(streamID, endStream, data, nil)
-}
-
-// WriteData writes a DATA frame with optional padding.
-//
-// If pad is nil, the padding bit is not sent.
-// The length of pad must not exceed 255 bytes.
-// The bytes of pad must all be zero, unless f.AllowIllegalWrites is set.
-//
-// It will perform exactly one Write to the underlying Writer.
-// It is the caller's responsibility not to violate the maximum frame size
-// and to not call other Write methods concurrently.
-func (f *Framer) WriteDataPadded(streamID uint32, endStream bool, data, pad []byte) error {
- if !validStreamID(streamID) && !f.AllowIllegalWrites {
- return errStreamID
- }
- if len(pad) > 0 {
- if len(pad) > 255 {
- return errPadLength
- }
- if !f.AllowIllegalWrites {
- for _, b := range pad {
- if b != 0 {
- // "Padding octets MUST be set to zero when sending."
- return errPadBytes
- }
- }
- }
- }
- var flags Flags
- if endStream {
- flags |= FlagDataEndStream
- }
- if pad != nil {
- flags |= FlagDataPadded
- }
- f.startWrite(FrameData, flags, streamID)
- if pad != nil {
- f.wbuf = append(f.wbuf, byte(len(pad)))
- }
- f.wbuf = append(f.wbuf, data...)
- f.wbuf = append(f.wbuf, pad...)
- return f.endWrite()
-}
-
-// A SettingsFrame conveys configuration parameters that affect how
-// endpoints communicate, such as preferences and constraints on peer
-// behavior.
-//
-// See http://http2.github.io/http2-spec/#SETTINGS
-type SettingsFrame struct {
- FrameHeader
- p []byte
-}
-
-func parseSettingsFrame(fh FrameHeader, p []byte) (Frame, error) {
- if fh.Flags.Has(FlagSettingsAck) && fh.Length > 0 {
- // When this (ACK 0x1) bit is set, the payload of the
- // SETTINGS frame MUST be empty. Receipt of a
- // SETTINGS frame with the ACK flag set and a length
- // field value other than 0 MUST be treated as a
- // connection error (Section 5.4.1) of type
- // FRAME_SIZE_ERROR.
- return nil, ConnectionError(ErrCodeFrameSize)
- }
- if fh.StreamID != 0 {
- // SETTINGS frames always apply to a connection,
- // never a single stream. The stream identifier for a
- // SETTINGS frame MUST be zero (0x0). If an endpoint
- // receives a SETTINGS frame whose stream identifier
- // field is anything other than 0x0, the endpoint MUST
- // respond with a connection error (Section 5.4.1) of
- // type PROTOCOL_ERROR.
- return nil, ConnectionError(ErrCodeProtocol)
- }
- if len(p)%6 != 0 {
- // Expecting even number of 6 byte settings.
- return nil, ConnectionError(ErrCodeFrameSize)
- }
- f := &SettingsFrame{FrameHeader: fh, p: p}
- if v, ok := f.Value(SettingInitialWindowSize); ok && v > (1<<31)-1 {
- // Values above the maximum flow control window size of 2^31 - 1 MUST
- // be treated as a connection error (Section 5.4.1) of type
- // FLOW_CONTROL_ERROR.
- return nil, ConnectionError(ErrCodeFlowControl)
- }
- return f, nil
-}
-
-func (f *SettingsFrame) IsAck() bool {
- return f.FrameHeader.Flags.Has(FlagSettingsAck)
-}
-
-func (f *SettingsFrame) Value(s SettingID) (v uint32, ok bool) {
- f.checkValid()
- buf := f.p
- for len(buf) > 0 {
- settingID := SettingID(binary.BigEndian.Uint16(buf[:2]))
- if settingID == s {
- return binary.BigEndian.Uint32(buf[2:6]), true
- }
- buf = buf[6:]
- }
- return 0, false
-}
-
-// ForeachSetting runs fn for each setting.
-// It stops and returns the first error.
-func (f *SettingsFrame) ForeachSetting(fn func(Setting) error) error {
- f.checkValid()
- buf := f.p
- for len(buf) > 0 {
- if err := fn(Setting{
- SettingID(binary.BigEndian.Uint16(buf[:2])),
- binary.BigEndian.Uint32(buf[2:6]),
- }); err != nil {
- return err
- }
- buf = buf[6:]
- }
- return nil
-}
-
-// WriteSettings writes a SETTINGS frame with zero or more settings
-// specified and the ACK bit not set.
-//
-// It will perform exactly one Write to the underlying Writer.
-// It is the caller's responsibility to not call other Write methods concurrently.
-func (f *Framer) WriteSettings(settings ...Setting) error {
- f.startWrite(FrameSettings, 0, 0)
- for _, s := range settings {
- f.writeUint16(uint16(s.ID))
- f.writeUint32(s.Val)
- }
- return f.endWrite()
-}
-
-// WriteSettingsAck writes an empty SETTINGS frame with the ACK bit set.
-//
-// It will perform exactly one Write to the underlying Writer.
-// It is the caller's responsibility to not call other Write methods concurrently.
-func (f *Framer) WriteSettingsAck() error {
- f.startWrite(FrameSettings, FlagSettingsAck, 0)
- return f.endWrite()
-}
-
-// A PingFrame is a mechanism for measuring a minimal round trip time
-// from the sender, as well as determining whether an idle connection
-// is still functional.
-// See http://http2.github.io/http2-spec/#rfc.section.6.7
-type PingFrame struct {
- FrameHeader
- Data [8]byte
-}
-
-func (f *PingFrame) IsAck() bool { return f.Flags.Has(FlagPingAck) }
-
-func parsePingFrame(fh FrameHeader, payload []byte) (Frame, error) {
- if len(payload) != 8 {
- return nil, ConnectionError(ErrCodeFrameSize)
- }
- if fh.StreamID != 0 {
- return nil, ConnectionError(ErrCodeProtocol)
- }
- f := &PingFrame{FrameHeader: fh}
- copy(f.Data[:], payload)
- return f, nil
-}
-
-func (f *Framer) WritePing(ack bool, data [8]byte) error {
- var flags Flags
- if ack {
- flags = FlagPingAck
- }
- f.startWrite(FramePing, flags, 0)
- f.writeBytes(data[:])
- return f.endWrite()
-}
-
-// A GoAwayFrame informs the remote peer to stop creating streams on this connection.
-// See http://http2.github.io/http2-spec/#rfc.section.6.8
-type GoAwayFrame struct {
- FrameHeader
- LastStreamID uint32
- ErrCode ErrCode
- debugData []byte
-}
-
-// DebugData returns any debug data in the GOAWAY frame. Its contents
-// are not defined.
-// The caller must not retain the returned memory past the next
-// call to ReadFrame.
-func (f *GoAwayFrame) DebugData() []byte {
- f.checkValid()
- return f.debugData
-}
-
-func parseGoAwayFrame(fh FrameHeader, p []byte) (Frame, error) {
- if fh.StreamID != 0 {
- return nil, ConnectionError(ErrCodeProtocol)
- }
- if len(p) < 8 {
- return nil, ConnectionError(ErrCodeFrameSize)
- }
- return &GoAwayFrame{
- FrameHeader: fh,
- LastStreamID: binary.BigEndian.Uint32(p[:4]) & (1<<31 - 1),
- ErrCode: ErrCode(binary.BigEndian.Uint32(p[4:8])),
- debugData: p[8:],
- }, nil
-}
-
-func (f *Framer) WriteGoAway(maxStreamID uint32, code ErrCode, debugData []byte) error {
- f.startWrite(FrameGoAway, 0, 0)
- f.writeUint32(maxStreamID & (1<<31 - 1))
- f.writeUint32(uint32(code))
- f.writeBytes(debugData)
- return f.endWrite()
-}
-
-// An UnknownFrame is the frame type returned when the frame type is unknown
-// or no specific frame type parser exists.
-type UnknownFrame struct {
- FrameHeader
- p []byte
-}
-
-// Payload returns the frame's payload (after the header). It is not
-// valid to call this method after a subsequent call to
-// Framer.ReadFrame, nor is it valid to retain the returned slice.
-// The memory is owned by the Framer and is invalidated when the next
-// frame is read.
-func (f *UnknownFrame) Payload() []byte {
- f.checkValid()
- return f.p
-}
-
-func parseUnknownFrame(fh FrameHeader, p []byte) (Frame, error) {
- return &UnknownFrame{fh, p}, nil
-}
-
-// A WindowUpdateFrame is used to implement flow control.
-// See http://http2.github.io/http2-spec/#rfc.section.6.9
-type WindowUpdateFrame struct {
- FrameHeader
- Increment uint32 // never read with high bit set
-}
-
-func parseWindowUpdateFrame(fh FrameHeader, p []byte) (Frame, error) {
- if len(p) != 4 {
- return nil, ConnectionError(ErrCodeFrameSize)
- }
- inc := binary.BigEndian.Uint32(p[:4]) & 0x7fffffff // mask off high reserved bit
- if inc == 0 {
- // A receiver MUST treat the receipt of a
- // WINDOW_UPDATE frame with an flow control window
- // increment of 0 as a stream error (Section 5.4.2) of
- // type PROTOCOL_ERROR; errors on the connection flow
- // control window MUST be treated as a connection
- // error (Section 5.4.1).
- if fh.StreamID == 0 {
- return nil, ConnectionError(ErrCodeProtocol)
- }
- return nil, streamError(fh.StreamID, ErrCodeProtocol)
- }
- return &WindowUpdateFrame{
- FrameHeader: fh,
- Increment: inc,
- }, nil
-}
-
-// WriteWindowUpdate writes a WINDOW_UPDATE frame.
-// The increment value must be between 1 and 2,147,483,647, inclusive.
-// If the Stream ID is zero, the window update applies to the
-// connection as a whole.
-func (f *Framer) WriteWindowUpdate(streamID, incr uint32) error {
- // "The legal range for the increment to the flow control window is 1 to 2^31-1 (2,147,483,647) octets."
- if (incr < 1 || incr > 2147483647) && !f.AllowIllegalWrites {
- return errors.New("illegal window increment value")
- }
- f.startWrite(FrameWindowUpdate, 0, streamID)
- f.writeUint32(incr)
- return f.endWrite()
-}
-
-// A HeadersFrame is used to open a stream and additionally carries a
-// header block fragment.
-type HeadersFrame struct {
- FrameHeader
-
- // Priority is set if FlagHeadersPriority is set in the FrameHeader.
- Priority PriorityParam
-
- headerFragBuf []byte // not owned
-}
-
-func (f *HeadersFrame) HeaderBlockFragment() []byte {
- f.checkValid()
- return f.headerFragBuf
-}
-
-func (f *HeadersFrame) HeadersEnded() bool {
- return f.FrameHeader.Flags.Has(FlagHeadersEndHeaders)
-}
-
-func (f *HeadersFrame) StreamEnded() bool {
- return f.FrameHeader.Flags.Has(FlagHeadersEndStream)
-}
-
-func (f *HeadersFrame) HasPriority() bool {
- return f.FrameHeader.Flags.Has(FlagHeadersPriority)
-}
-
-func parseHeadersFrame(fh FrameHeader, p []byte) (_ Frame, err error) {
- hf := &HeadersFrame{
- FrameHeader: fh,
- }
- if fh.StreamID == 0 {
- // HEADERS frames MUST be associated with a stream. If a HEADERS frame
- // is received whose stream identifier field is 0x0, the recipient MUST
- // respond with a connection error (Section 5.4.1) of type
- // PROTOCOL_ERROR.
- return nil, connError{ErrCodeProtocol, "HEADERS frame with stream ID 0"}
- }
- var padLength uint8
- if fh.Flags.Has(FlagHeadersPadded) {
- if p, padLength, err = readByte(p); err != nil {
- return
- }
- }
- if fh.Flags.Has(FlagHeadersPriority) {
- var v uint32
- p, v, err = readUint32(p)
- if err != nil {
- return nil, err
- }
- hf.Priority.StreamDep = v & 0x7fffffff
- hf.Priority.Exclusive = (v != hf.Priority.StreamDep) // high bit was set
- p, hf.Priority.Weight, err = readByte(p)
- if err != nil {
- return nil, err
- }
- }
- if len(p)-int(padLength) <= 0 {
- return nil, streamError(fh.StreamID, ErrCodeProtocol)
- }
- hf.headerFragBuf = p[:len(p)-int(padLength)]
- return hf, nil
-}
-
-// HeadersFrameParam are the parameters for writing a HEADERS frame.
-type HeadersFrameParam struct {
- // StreamID is the required Stream ID to initiate.
- StreamID uint32
- // BlockFragment is part (or all) of a Header Block.
- BlockFragment []byte
-
- // EndStream indicates that the header block is the last that
- // the endpoint will send for the identified stream. Setting
- // this flag causes the stream to enter one of "half closed"
- // states.
- EndStream bool
-
- // EndHeaders indicates that this frame contains an entire
- // header block and is not followed by any
- // CONTINUATION frames.
- EndHeaders bool
-
- // PadLength is the optional number of bytes of zeros to add
- // to this frame.
- PadLength uint8
-
- // Priority, if non-zero, includes stream priority information
- // in the HEADER frame.
- Priority PriorityParam
-}
-
-// WriteHeaders writes a single HEADERS frame.
-//
-// This is a low-level header writing method. Encoding headers and
-// splitting them into any necessary CONTINUATION frames is handled
-// elsewhere.
-//
-// It will perform exactly one Write to the underlying Writer.
-// It is the caller's responsibility to not call other Write methods concurrently.
-func (f *Framer) WriteHeaders(p HeadersFrameParam) error {
- if !validStreamID(p.StreamID) && !f.AllowIllegalWrites {
- return errStreamID
- }
- var flags Flags
- if p.PadLength != 0 {
- flags |= FlagHeadersPadded
- }
- if p.EndStream {
- flags |= FlagHeadersEndStream
- }
- if p.EndHeaders {
- flags |= FlagHeadersEndHeaders
- }
- if !p.Priority.IsZero() {
- flags |= FlagHeadersPriority
- }
- f.startWrite(FrameHeaders, flags, p.StreamID)
- if p.PadLength != 0 {
- f.writeByte(p.PadLength)
- }
- if !p.Priority.IsZero() {
- v := p.Priority.StreamDep
- if !validStreamIDOrZero(v) && !f.AllowIllegalWrites {
- return errDepStreamID
- }
- if p.Priority.Exclusive {
- v |= 1 << 31
- }
- f.writeUint32(v)
- f.writeByte(p.Priority.Weight)
- }
- f.wbuf = append(f.wbuf, p.BlockFragment...)
- f.wbuf = append(f.wbuf, padZeros[:p.PadLength]...)
- return f.endWrite()
-}
-
-// A PriorityFrame specifies the sender-advised priority of a stream.
-// See http://http2.github.io/http2-spec/#rfc.section.6.3
-type PriorityFrame struct {
- FrameHeader
- PriorityParam
-}
-
-// PriorityParam are the stream prioritzation parameters.
-type PriorityParam struct {
- // StreamDep is a 31-bit stream identifier for the
- // stream that this stream depends on. Zero means no
- // dependency.
- StreamDep uint32
-
- // Exclusive is whether the dependency is exclusive.
- Exclusive bool
-
- // Weight is the stream's zero-indexed weight. It should be
- // set together with StreamDep, or neither should be set. Per
- // the spec, "Add one to the value to obtain a weight between
- // 1 and 256."
- Weight uint8
-}
-
-func (p PriorityParam) IsZero() bool {
- return p == PriorityParam{}
-}
-
-func parsePriorityFrame(fh FrameHeader, payload []byte) (Frame, error) {
- if fh.StreamID == 0 {
- return nil, connError{ErrCodeProtocol, "PRIORITY frame with stream ID 0"}
- }
- if len(payload) != 5 {
- return nil, connError{ErrCodeFrameSize, fmt.Sprintf("PRIORITY frame payload size was %d; want 5", len(payload))}
- }
- v := binary.BigEndian.Uint32(payload[:4])
- streamID := v & 0x7fffffff // mask off high bit
- return &PriorityFrame{
- FrameHeader: fh,
- PriorityParam: PriorityParam{
- Weight: payload[4],
- StreamDep: streamID,
- Exclusive: streamID != v, // was high bit set?
- },
- }, nil
-}
-
-// WritePriority writes a PRIORITY frame.
-//
-// It will perform exactly one Write to the underlying Writer.
-// It is the caller's responsibility to not call other Write methods concurrently.
-func (f *Framer) WritePriority(streamID uint32, p PriorityParam) error {
- if !validStreamID(streamID) && !f.AllowIllegalWrites {
- return errStreamID
- }
- if !validStreamIDOrZero(p.StreamDep) {
- return errDepStreamID
- }
- f.startWrite(FramePriority, 0, streamID)
- v := p.StreamDep
- if p.Exclusive {
- v |= 1 << 31
- }
- f.writeUint32(v)
- f.writeByte(p.Weight)
- return f.endWrite()
-}
-
-// A RSTStreamFrame allows for abnormal termination of a stream.
-// See http://http2.github.io/http2-spec/#rfc.section.6.4
-type RSTStreamFrame struct {
- FrameHeader
- ErrCode ErrCode
-}
-
-func parseRSTStreamFrame(fh FrameHeader, p []byte) (Frame, error) {
- if len(p) != 4 {
- return nil, ConnectionError(ErrCodeFrameSize)
- }
- if fh.StreamID == 0 {
- return nil, ConnectionError(ErrCodeProtocol)
- }
- return &RSTStreamFrame{fh, ErrCode(binary.BigEndian.Uint32(p[:4]))}, nil
-}
-
-// WriteRSTStream writes a RST_STREAM frame.
-//
-// It will perform exactly one Write to the underlying Writer.
-// It is the caller's responsibility to not call other Write methods concurrently.
-func (f *Framer) WriteRSTStream(streamID uint32, code ErrCode) error {
- if !validStreamID(streamID) && !f.AllowIllegalWrites {
- return errStreamID
- }
- f.startWrite(FrameRSTStream, 0, streamID)
- f.writeUint32(uint32(code))
- return f.endWrite()
-}
-
-// A ContinuationFrame is used to continue a sequence of header block fragments.
-// See http://http2.github.io/http2-spec/#rfc.section.6.10
-type ContinuationFrame struct {
- FrameHeader
- headerFragBuf []byte
-}
-
-func parseContinuationFrame(fh FrameHeader, p []byte) (Frame, error) {
- if fh.StreamID == 0 {
- return nil, connError{ErrCodeProtocol, "CONTINUATION frame with stream ID 0"}
- }
- return &ContinuationFrame{fh, p}, nil
-}
-
-func (f *ContinuationFrame) HeaderBlockFragment() []byte {
- f.checkValid()
- return f.headerFragBuf
-}
-
-func (f *ContinuationFrame) HeadersEnded() bool {
- return f.FrameHeader.Flags.Has(FlagContinuationEndHeaders)
-}
-
-// WriteContinuation writes a CONTINUATION frame.
-//
-// It will perform exactly one Write to the underlying Writer.
-// It is the caller's responsibility to not call other Write methods concurrently.
-func (f *Framer) WriteContinuation(streamID uint32, endHeaders bool, headerBlockFragment []byte) error {
- if !validStreamID(streamID) && !f.AllowIllegalWrites {
- return errStreamID
- }
- var flags Flags
- if endHeaders {
- flags |= FlagContinuationEndHeaders
- }
- f.startWrite(FrameContinuation, flags, streamID)
- f.wbuf = append(f.wbuf, headerBlockFragment...)
- return f.endWrite()
-}
-
-// A PushPromiseFrame is used to initiate a server stream.
-// See http://http2.github.io/http2-spec/#rfc.section.6.6
-type PushPromiseFrame struct {
- FrameHeader
- PromiseID uint32
- headerFragBuf []byte // not owned
-}
-
-func (f *PushPromiseFrame) HeaderBlockFragment() []byte {
- f.checkValid()
- return f.headerFragBuf
-}
-
-func (f *PushPromiseFrame) HeadersEnded() bool {
- return f.FrameHeader.Flags.Has(FlagPushPromiseEndHeaders)
-}
-
-func parsePushPromise(fh FrameHeader, p []byte) (_ Frame, err error) {
- pp := &PushPromiseFrame{
- FrameHeader: fh,
- }
- if pp.StreamID == 0 {
- // PUSH_PROMISE frames MUST be associated with an existing,
- // peer-initiated stream. The stream identifier of a
- // PUSH_PROMISE frame indicates the stream it is associated
- // with. If the stream identifier field specifies the value
- // 0x0, a recipient MUST respond with a connection error
- // (Section 5.4.1) of type PROTOCOL_ERROR.
- return nil, ConnectionError(ErrCodeProtocol)
- }
- // The PUSH_PROMISE frame includes optional padding.
- // Padding fields and flags are identical to those defined for DATA frames
- var padLength uint8
- if fh.Flags.Has(FlagPushPromisePadded) {
- if p, padLength, err = readByte(p); err != nil {
- return
- }
- }
-
- p, pp.PromiseID, err = readUint32(p)
- if err != nil {
- return
- }
- pp.PromiseID = pp.PromiseID & (1<<31 - 1)
-
- if int(padLength) > len(p) {
- // like the DATA frame, error out if padding is longer than the body.
- return nil, ConnectionError(ErrCodeProtocol)
- }
- pp.headerFragBuf = p[:len(p)-int(padLength)]
- return pp, nil
-}
-
-// PushPromiseParam are the parameters for writing a PUSH_PROMISE frame.
-type PushPromiseParam struct {
- // StreamID is the required Stream ID to initiate.
- StreamID uint32
-
- // PromiseID is the required Stream ID which this
- // Push Promises
- PromiseID uint32
-
- // BlockFragment is part (or all) of a Header Block.
- BlockFragment []byte
-
- // EndHeaders indicates that this frame contains an entire
- // header block and is not followed by any
- // CONTINUATION frames.
- EndHeaders bool
-
- // PadLength is the optional number of bytes of zeros to add
- // to this frame.
- PadLength uint8
-}
-
-// WritePushPromise writes a single PushPromise Frame.
-//
-// As with Header Frames, This is the low level call for writing
-// individual frames. Continuation frames are handled elsewhere.
-//
-// It will perform exactly one Write to the underlying Writer.
-// It is the caller's responsibility to not call other Write methods concurrently.
-func (f *Framer) WritePushPromise(p PushPromiseParam) error {
- if !validStreamID(p.StreamID) && !f.AllowIllegalWrites {
- return errStreamID
- }
- var flags Flags
- if p.PadLength != 0 {
- flags |= FlagPushPromisePadded
- }
- if p.EndHeaders {
- flags |= FlagPushPromiseEndHeaders
- }
- f.startWrite(FramePushPromise, flags, p.StreamID)
- if p.PadLength != 0 {
- f.writeByte(p.PadLength)
- }
- if !validStreamID(p.PromiseID) && !f.AllowIllegalWrites {
- return errStreamID
- }
- f.writeUint32(p.PromiseID)
- f.wbuf = append(f.wbuf, p.BlockFragment...)
- f.wbuf = append(f.wbuf, padZeros[:p.PadLength]...)
- return f.endWrite()
-}
-
-// WriteRawFrame writes a raw frame. This can be used to write
-// extension frames unknown to this package.
-func (f *Framer) WriteRawFrame(t FrameType, flags Flags, streamID uint32, payload []byte) error {
- f.startWrite(t, flags, streamID)
- f.writeBytes(payload)
- return f.endWrite()
-}
-
-func readByte(p []byte) (remain []byte, b byte, err error) {
- if len(p) == 0 {
- return nil, 0, io.ErrUnexpectedEOF
- }
- return p[1:], p[0], nil
-}
-
-func readUint32(p []byte) (remain []byte, v uint32, err error) {
- if len(p) < 4 {
- return nil, 0, io.ErrUnexpectedEOF
- }
- return p[4:], binary.BigEndian.Uint32(p[:4]), nil
-}
-
-type streamEnder interface {
- StreamEnded() bool
-}
-
-type headersEnder interface {
- HeadersEnded() bool
-}
-
-type headersOrContinuation interface {
- headersEnder
- HeaderBlockFragment() []byte
-}
-
-// A MetaHeadersFrame is the representation of one HEADERS frame and
-// zero or more contiguous CONTINUATION frames and the decoding of
-// their HPACK-encoded contents.
-//
-// This type of frame does not appear on the wire and is only returned
-// by the Framer when Framer.ReadMetaHeaders is set.
-type MetaHeadersFrame struct {
- *HeadersFrame
-
- // Fields are the fields contained in the HEADERS and
- // CONTINUATION frames. The underlying slice is owned by the
- // Framer and must not be retained after the next call to
- // ReadFrame.
- //
- // Fields are guaranteed to be in the correct http2 order and
- // not have unknown pseudo header fields or invalid header
- // field names or values. Required pseudo header fields may be
- // missing, however. Use the MetaHeadersFrame.Pseudo accessor
- // method access pseudo headers.
- Fields []hpack.HeaderField
-
- // Truncated is whether the max header list size limit was hit
- // and Fields is incomplete. The hpack decoder state is still
- // valid, however.
- Truncated bool
-}
-
-// PseudoValue returns the given pseudo header field's value.
-// The provided pseudo field should not contain the leading colon.
-func (mh *MetaHeadersFrame) PseudoValue(pseudo string) string {
- for _, hf := range mh.Fields {
- if !hf.IsPseudo() {
- return ""
- }
- if hf.Name[1:] == pseudo {
- return hf.Value
- }
- }
- return ""
-}
-
-// RegularFields returns the regular (non-pseudo) header fields of mh.
-// The caller does not own the returned slice.
-func (mh *MetaHeadersFrame) RegularFields() []hpack.HeaderField {
- for i, hf := range mh.Fields {
- if !hf.IsPseudo() {
- return mh.Fields[i:]
- }
- }
- return nil
-}
-
-// PseudoFields returns the pseudo header fields of mh.
-// The caller does not own the returned slice.
-func (mh *MetaHeadersFrame) PseudoFields() []hpack.HeaderField {
- for i, hf := range mh.Fields {
- if !hf.IsPseudo() {
- return mh.Fields[:i]
- }
- }
- return mh.Fields
-}
-
-func (mh *MetaHeadersFrame) checkPseudos() error {
- var isRequest, isResponse bool
- pf := mh.PseudoFields()
- for i, hf := range pf {
- switch hf.Name {
- case ":method", ":path", ":scheme", ":authority":
- isRequest = true
- case ":status":
- isResponse = true
- default:
- return pseudoHeaderError(hf.Name)
- }
- // Check for duplicates.
- // This would be a bad algorithm, but N is 4.
- // And this doesn't allocate.
- for _, hf2 := range pf[:i] {
- if hf.Name == hf2.Name {
- return duplicatePseudoHeaderError(hf.Name)
- }
- }
- }
- if isRequest && isResponse {
- return errMixPseudoHeaderTypes
- }
- return nil
-}
-
-func (fr *Framer) maxHeaderStringLen() int {
- v := fr.maxHeaderListSize()
- if uint32(int(v)) == v {
- return int(v)
- }
- // They had a crazy big number for MaxHeaderBytes anyway,
- // so give them unlimited header lengths:
- return 0
-}
-
-// readMetaFrame returns 0 or more CONTINUATION frames from fr and
-// merge them into into the provided hf and returns a MetaHeadersFrame
-// with the decoded hpack values.
-func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) {
- if fr.AllowIllegalReads {
- return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders")
- }
- mh := &MetaHeadersFrame{
- HeadersFrame: hf,
- }
- var remainSize = fr.maxHeaderListSize()
- var sawRegular bool
-
- var invalid error // pseudo header field errors
- hdec := fr.ReadMetaHeaders
- hdec.SetEmitEnabled(true)
- hdec.SetMaxStringLength(fr.maxHeaderStringLen())
- hdec.SetEmitFunc(func(hf hpack.HeaderField) {
- if VerboseLogs && fr.logReads {
- fr.debugReadLoggerf("http2: decoded hpack field %+v", hf)
- }
- if !httplex.ValidHeaderFieldValue(hf.Value) {
- invalid = headerFieldValueError(hf.Value)
- }
- isPseudo := strings.HasPrefix(hf.Name, ":")
- if isPseudo {
- if sawRegular {
- invalid = errPseudoAfterRegular
- }
- } else {
- sawRegular = true
- if !validWireHeaderFieldName(hf.Name) {
- invalid = headerFieldNameError(hf.Name)
- }
- }
-
- if invalid != nil {
- hdec.SetEmitEnabled(false)
- return
- }
-
- size := hf.Size()
- if size > remainSize {
- hdec.SetEmitEnabled(false)
- mh.Truncated = true
- return
- }
- remainSize -= size
-
- mh.Fields = append(mh.Fields, hf)
- })
- // Lose reference to MetaHeadersFrame:
- defer hdec.SetEmitFunc(func(hf hpack.HeaderField) {})
-
- var hc headersOrContinuation = hf
- for {
- frag := hc.HeaderBlockFragment()
- if _, err := hdec.Write(frag); err != nil {
- return nil, ConnectionError(ErrCodeCompression)
- }
-
- if hc.HeadersEnded() {
- break
- }
- if f, err := fr.ReadFrame(); err != nil {
- return nil, err
- } else {
- hc = f.(*ContinuationFrame) // guaranteed by checkFrameOrder
- }
- }
-
- mh.HeadersFrame.headerFragBuf = nil
- mh.HeadersFrame.invalidate()
-
- if err := hdec.Close(); err != nil {
- return nil, ConnectionError(ErrCodeCompression)
- }
- if invalid != nil {
- fr.errDetail = invalid
- if VerboseLogs {
- log.Printf("http2: invalid header: %v", invalid)
- }
- return nil, StreamError{mh.StreamID, ErrCodeProtocol, invalid}
- }
- if err := mh.checkPseudos(); err != nil {
- fr.errDetail = err
- if VerboseLogs {
- log.Printf("http2: invalid pseudo headers: %v", err)
- }
- return nil, StreamError{mh.StreamID, ErrCodeProtocol, err}
- }
- return mh, nil
-}
-
-func summarizeFrame(f Frame) string {
- var buf bytes.Buffer
- f.Header().writeDebug(&buf)
- switch f := f.(type) {
- case *SettingsFrame:
- n := 0
- f.ForeachSetting(func(s Setting) error {
- n++
- if n == 1 {
- buf.WriteString(", settings:")
- }
- fmt.Fprintf(&buf, " %v=%v,", s.ID, s.Val)
- return nil
- })
- if n > 0 {
- buf.Truncate(buf.Len() - 1) // remove trailing comma
- }
- case *DataFrame:
- data := f.Data()
- const max = 256
- if len(data) > max {
- data = data[:max]
- }
- fmt.Fprintf(&buf, " data=%q", data)
- if len(f.Data()) > max {
- fmt.Fprintf(&buf, " (%d bytes omitted)", len(f.Data())-max)
- }
- case *WindowUpdateFrame:
- if f.StreamID == 0 {
- buf.WriteString(" (conn)")
- }
- fmt.Fprintf(&buf, " incr=%v", f.Increment)
- case *PingFrame:
- fmt.Fprintf(&buf, " ping=%q", f.Data[:])
- case *GoAwayFrame:
- fmt.Fprintf(&buf, " LastStreamID=%v ErrCode=%v Debug=%q",
- f.LastStreamID, f.ErrCode, f.debugData)
- case *RSTStreamFrame:
- fmt.Fprintf(&buf, " ErrCode=%v", f.ErrCode)
- }
- return buf.String()
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/frame_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/frame_test.go
deleted file mode 100644
index 311f86f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/frame_test.go
+++ /dev/null
@@ -1,1102 +0,0 @@
-// 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 http2
-
-import (
- "bytes"
- "fmt"
- "io"
- "reflect"
- "strings"
- "testing"
- "unsafe"
-
- "golang.org/x/net/http2/hpack"
-)
-
-func testFramer() (*Framer, *bytes.Buffer) {
- buf := new(bytes.Buffer)
- return NewFramer(buf, buf), buf
-}
-
-func TestFrameSizes(t *testing.T) {
- // Catch people rearranging the FrameHeader fields.
- if got, want := int(unsafe.Sizeof(FrameHeader{})), 12; got != want {
- t.Errorf("FrameHeader size = %d; want %d", got, want)
- }
-}
-
-func TestFrameTypeString(t *testing.T) {
- tests := []struct {
- ft FrameType
- want string
- }{
- {FrameData, "DATA"},
- {FramePing, "PING"},
- {FrameGoAway, "GOAWAY"},
- {0xf, "UNKNOWN_FRAME_TYPE_15"},
- }
-
- for i, tt := range tests {
- got := tt.ft.String()
- if got != tt.want {
- t.Errorf("%d. String(FrameType %d) = %q; want %q", i, int(tt.ft), got, tt.want)
- }
- }
-}
-
-func TestWriteRST(t *testing.T) {
- fr, buf := testFramer()
- var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
- var errCode uint32 = 7<<24 + 6<<16 + 5<<8 + 4
- fr.WriteRSTStream(streamID, ErrCode(errCode))
- const wantEnc = "\x00\x00\x04\x03\x00\x01\x02\x03\x04\x07\x06\x05\x04"
- if buf.String() != wantEnc {
- t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
- }
- f, err := fr.ReadFrame()
- if err != nil {
- t.Fatal(err)
- }
- want := &RSTStreamFrame{
- FrameHeader: FrameHeader{
- valid: true,
- Type: 0x3,
- Flags: 0x0,
- Length: 0x4,
- StreamID: 0x1020304,
- },
- ErrCode: 0x7060504,
- }
- if !reflect.DeepEqual(f, want) {
- t.Errorf("parsed back %#v; want %#v", f, want)
- }
-}
-
-func TestWriteData(t *testing.T) {
- fr, buf := testFramer()
- var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
- data := []byte("ABC")
- fr.WriteData(streamID, true, data)
- const wantEnc = "\x00\x00\x03\x00\x01\x01\x02\x03\x04ABC"
- if buf.String() != wantEnc {
- t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
- }
- f, err := fr.ReadFrame()
- if err != nil {
- t.Fatal(err)
- }
- df, ok := f.(*DataFrame)
- if !ok {
- t.Fatalf("got %T; want *DataFrame", f)
- }
- if !bytes.Equal(df.Data(), data) {
- t.Errorf("got %q; want %q", df.Data(), data)
- }
- if f.Header().Flags&1 == 0 {
- t.Errorf("didn't see END_STREAM flag")
- }
-}
-
-func TestWriteDataPadded(t *testing.T) {
- tests := [...]struct {
- streamID uint32
- endStream bool
- data []byte
- pad []byte
- wantHeader FrameHeader
- }{
- // Unpadded:
- 0: {
- streamID: 1,
- endStream: true,
- data: []byte("foo"),
- pad: nil,
- wantHeader: FrameHeader{
- Type: FrameData,
- Flags: FlagDataEndStream,
- Length: 3,
- StreamID: 1,
- },
- },
-
- // Padded bit set, but no padding:
- 1: {
- streamID: 1,
- endStream: true,
- data: []byte("foo"),
- pad: []byte{},
- wantHeader: FrameHeader{
- Type: FrameData,
- Flags: FlagDataEndStream | FlagDataPadded,
- Length: 4,
- StreamID: 1,
- },
- },
-
- // Padded bit set, with padding:
- 2: {
- streamID: 1,
- endStream: false,
- data: []byte("foo"),
- pad: []byte{0, 0, 0},
- wantHeader: FrameHeader{
- Type: FrameData,
- Flags: FlagDataPadded,
- Length: 7,
- StreamID: 1,
- },
- },
- }
- for i, tt := range tests {
- fr, _ := testFramer()
- fr.WriteDataPadded(tt.streamID, tt.endStream, tt.data, tt.pad)
- f, err := fr.ReadFrame()
- if err != nil {
- t.Errorf("%d. ReadFrame: %v", i, err)
- continue
- }
- got := f.Header()
- tt.wantHeader.valid = true
- if got != tt.wantHeader {
- t.Errorf("%d. read %+v; want %+v", i, got, tt.wantHeader)
- continue
- }
- df := f.(*DataFrame)
- if !bytes.Equal(df.Data(), tt.data) {
- t.Errorf("%d. got %q; want %q", i, df.Data(), tt.data)
- }
- }
-}
-
-func TestWriteHeaders(t *testing.T) {
- tests := []struct {
- name string
- p HeadersFrameParam
- wantEnc string
- wantFrame *HeadersFrame
- }{
- {
- "basic",
- HeadersFrameParam{
- StreamID: 42,
- BlockFragment: []byte("abc"),
- Priority: PriorityParam{},
- },
- "\x00\x00\x03\x01\x00\x00\x00\x00*abc",
- &HeadersFrame{
- FrameHeader: FrameHeader{
- valid: true,
- StreamID: 42,
- Type: FrameHeaders,
- Length: uint32(len("abc")),
- },
- Priority: PriorityParam{},
- headerFragBuf: []byte("abc"),
- },
- },
- {
- "basic + end flags",
- HeadersFrameParam{
- StreamID: 42,
- BlockFragment: []byte("abc"),
- EndStream: true,
- EndHeaders: true,
- Priority: PriorityParam{},
- },
- "\x00\x00\x03\x01\x05\x00\x00\x00*abc",
- &HeadersFrame{
- FrameHeader: FrameHeader{
- valid: true,
- StreamID: 42,
- Type: FrameHeaders,
- Flags: FlagHeadersEndStream | FlagHeadersEndHeaders,
- Length: uint32(len("abc")),
- },
- Priority: PriorityParam{},
- headerFragBuf: []byte("abc"),
- },
- },
- {
- "with padding",
- HeadersFrameParam{
- StreamID: 42,
- BlockFragment: []byte("abc"),
- EndStream: true,
- EndHeaders: true,
- PadLength: 5,
- Priority: PriorityParam{},
- },
- "\x00\x00\t\x01\r\x00\x00\x00*\x05abc\x00\x00\x00\x00\x00",
- &HeadersFrame{
- FrameHeader: FrameHeader{
- valid: true,
- StreamID: 42,
- Type: FrameHeaders,
- Flags: FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded,
- Length: uint32(1 + len("abc") + 5), // pad length + contents + padding
- },
- Priority: PriorityParam{},
- headerFragBuf: []byte("abc"),
- },
- },
- {
- "with priority",
- HeadersFrameParam{
- StreamID: 42,
- BlockFragment: []byte("abc"),
- EndStream: true,
- EndHeaders: true,
- PadLength: 2,
- Priority: PriorityParam{
- StreamDep: 15,
- Exclusive: true,
- Weight: 127,
- },
- },
- "\x00\x00\v\x01-\x00\x00\x00*\x02\x80\x00\x00\x0f\u007fabc\x00\x00",
- &HeadersFrame{
- FrameHeader: FrameHeader{
- valid: true,
- StreamID: 42,
- Type: FrameHeaders,
- Flags: FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded | FlagHeadersPriority,
- Length: uint32(1 + 5 + len("abc") + 2), // pad length + priority + contents + padding
- },
- Priority: PriorityParam{
- StreamDep: 15,
- Exclusive: true,
- Weight: 127,
- },
- headerFragBuf: []byte("abc"),
- },
- },
- {
- "with priority stream dep zero", // golang.org/issue/15444
- HeadersFrameParam{
- StreamID: 42,
- BlockFragment: []byte("abc"),
- EndStream: true,
- EndHeaders: true,
- PadLength: 2,
- Priority: PriorityParam{
- StreamDep: 0,
- Exclusive: true,
- Weight: 127,
- },
- },
- "\x00\x00\v\x01-\x00\x00\x00*\x02\x80\x00\x00\x00\u007fabc\x00\x00",
- &HeadersFrame{
- FrameHeader: FrameHeader{
- valid: true,
- StreamID: 42,
- Type: FrameHeaders,
- Flags: FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded | FlagHeadersPriority,
- Length: uint32(1 + 5 + len("abc") + 2), // pad length + priority + contents + padding
- },
- Priority: PriorityParam{
- StreamDep: 0,
- Exclusive: true,
- Weight: 127,
- },
- headerFragBuf: []byte("abc"),
- },
- },
- }
- for _, tt := range tests {
- fr, buf := testFramer()
- if err := fr.WriteHeaders(tt.p); err != nil {
- t.Errorf("test %q: %v", tt.name, err)
- continue
- }
- if buf.String() != tt.wantEnc {
- t.Errorf("test %q: encoded %q; want %q", tt.name, buf.Bytes(), tt.wantEnc)
- }
- f, err := fr.ReadFrame()
- if err != nil {
- t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
- continue
- }
- if !reflect.DeepEqual(f, tt.wantFrame) {
- t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
- }
- }
-}
-
-func TestWriteInvalidStreamDep(t *testing.T) {
- fr, _ := testFramer()
- err := fr.WriteHeaders(HeadersFrameParam{
- StreamID: 42,
- Priority: PriorityParam{
- StreamDep: 1 << 31,
- },
- })
- if err != errDepStreamID {
- t.Errorf("header error = %v; want %q", err, errDepStreamID)
- }
-
- err = fr.WritePriority(2, PriorityParam{StreamDep: 1 << 31})
- if err != errDepStreamID {
- t.Errorf("priority error = %v; want %q", err, errDepStreamID)
- }
-}
-
-func TestWriteContinuation(t *testing.T) {
- const streamID = 42
- tests := []struct {
- name string
- end bool
- frag []byte
-
- wantFrame *ContinuationFrame
- }{
- {
- "not end",
- false,
- []byte("abc"),
- &ContinuationFrame{
- FrameHeader: FrameHeader{
- valid: true,
- StreamID: streamID,
- Type: FrameContinuation,
- Length: uint32(len("abc")),
- },
- headerFragBuf: []byte("abc"),
- },
- },
- {
- "end",
- true,
- []byte("def"),
- &ContinuationFrame{
- FrameHeader: FrameHeader{
- valid: true,
- StreamID: streamID,
- Type: FrameContinuation,
- Flags: FlagContinuationEndHeaders,
- Length: uint32(len("def")),
- },
- headerFragBuf: []byte("def"),
- },
- },
- }
- for _, tt := range tests {
- fr, _ := testFramer()
- if err := fr.WriteContinuation(streamID, tt.end, tt.frag); err != nil {
- t.Errorf("test %q: %v", tt.name, err)
- continue
- }
- fr.AllowIllegalReads = true
- f, err := fr.ReadFrame()
- if err != nil {
- t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
- continue
- }
- if !reflect.DeepEqual(f, tt.wantFrame) {
- t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
- }
- }
-}
-
-func TestWritePriority(t *testing.T) {
- const streamID = 42
- tests := []struct {
- name string
- priority PriorityParam
- wantFrame *PriorityFrame
- }{
- {
- "not exclusive",
- PriorityParam{
- StreamDep: 2,
- Exclusive: false,
- Weight: 127,
- },
- &PriorityFrame{
- FrameHeader{
- valid: true,
- StreamID: streamID,
- Type: FramePriority,
- Length: 5,
- },
- PriorityParam{
- StreamDep: 2,
- Exclusive: false,
- Weight: 127,
- },
- },
- },
-
- {
- "exclusive",
- PriorityParam{
- StreamDep: 3,
- Exclusive: true,
- Weight: 77,
- },
- &PriorityFrame{
- FrameHeader{
- valid: true,
- StreamID: streamID,
- Type: FramePriority,
- Length: 5,
- },
- PriorityParam{
- StreamDep: 3,
- Exclusive: true,
- Weight: 77,
- },
- },
- },
- }
- for _, tt := range tests {
- fr, _ := testFramer()
- if err := fr.WritePriority(streamID, tt.priority); err != nil {
- t.Errorf("test %q: %v", tt.name, err)
- continue
- }
- f, err := fr.ReadFrame()
- if err != nil {
- t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
- continue
- }
- if !reflect.DeepEqual(f, tt.wantFrame) {
- t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
- }
- }
-}
-
-func TestWriteSettings(t *testing.T) {
- fr, buf := testFramer()
- settings := []Setting{{1, 2}, {3, 4}}
- fr.WriteSettings(settings...)
- const wantEnc = "\x00\x00\f\x04\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00\x00\x04"
- if buf.String() != wantEnc {
- t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
- }
- f, err := fr.ReadFrame()
- if err != nil {
- t.Fatal(err)
- }
- sf, ok := f.(*SettingsFrame)
- if !ok {
- t.Fatalf("Got a %T; want a SettingsFrame", f)
- }
- var got []Setting
- sf.ForeachSetting(func(s Setting) error {
- got = append(got, s)
- valBack, ok := sf.Value(s.ID)
- if !ok || valBack != s.Val {
- t.Errorf("Value(%d) = %v, %v; want %v, true", s.ID, valBack, ok, s.Val)
- }
- return nil
- })
- if !reflect.DeepEqual(settings, got) {
- t.Errorf("Read settings %+v != written settings %+v", got, settings)
- }
-}
-
-func TestWriteSettingsAck(t *testing.T) {
- fr, buf := testFramer()
- fr.WriteSettingsAck()
- const wantEnc = "\x00\x00\x00\x04\x01\x00\x00\x00\x00"
- if buf.String() != wantEnc {
- t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
- }
-}
-
-func TestWriteWindowUpdate(t *testing.T) {
- fr, buf := testFramer()
- const streamID = 1<<24 + 2<<16 + 3<<8 + 4
- const incr = 7<<24 + 6<<16 + 5<<8 + 4
- if err := fr.WriteWindowUpdate(streamID, incr); err != nil {
- t.Fatal(err)
- }
- const wantEnc = "\x00\x00\x04\x08\x00\x01\x02\x03\x04\x07\x06\x05\x04"
- if buf.String() != wantEnc {
- t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
- }
- f, err := fr.ReadFrame()
- if err != nil {
- t.Fatal(err)
- }
- want := &WindowUpdateFrame{
- FrameHeader: FrameHeader{
- valid: true,
- Type: 0x8,
- Flags: 0x0,
- Length: 0x4,
- StreamID: 0x1020304,
- },
- Increment: 0x7060504,
- }
- if !reflect.DeepEqual(f, want) {
- t.Errorf("parsed back %#v; want %#v", f, want)
- }
-}
-
-func TestWritePing(t *testing.T) { testWritePing(t, false) }
-func TestWritePingAck(t *testing.T) { testWritePing(t, true) }
-
-func testWritePing(t *testing.T, ack bool) {
- fr, buf := testFramer()
- if err := fr.WritePing(ack, [8]byte{1, 2, 3, 4, 5, 6, 7, 8}); err != nil {
- t.Fatal(err)
- }
- var wantFlags Flags
- if ack {
- wantFlags = FlagPingAck
- }
- var wantEnc = "\x00\x00\x08\x06" + string(wantFlags) + "\x00\x00\x00\x00" + "\x01\x02\x03\x04\x05\x06\x07\x08"
- if buf.String() != wantEnc {
- t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
- }
-
- f, err := fr.ReadFrame()
- if err != nil {
- t.Fatal(err)
- }
- want := &PingFrame{
- FrameHeader: FrameHeader{
- valid: true,
- Type: 0x6,
- Flags: wantFlags,
- Length: 0x8,
- StreamID: 0,
- },
- Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
- }
- if !reflect.DeepEqual(f, want) {
- t.Errorf("parsed back %#v; want %#v", f, want)
- }
-}
-
-func TestReadFrameHeader(t *testing.T) {
- tests := []struct {
- in string
- want FrameHeader
- }{
- {in: "\x00\x00\x00" + "\x00" + "\x00" + "\x00\x00\x00\x00", want: FrameHeader{}},
- {in: "\x01\x02\x03" + "\x04" + "\x05" + "\x06\x07\x08\x09", want: FrameHeader{
- Length: 66051, Type: 4, Flags: 5, StreamID: 101124105,
- }},
- // Ignore high bit:
- {in: "\xff\xff\xff" + "\xff" + "\xff" + "\xff\xff\xff\xff", want: FrameHeader{
- Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}},
- {in: "\xff\xff\xff" + "\xff" + "\xff" + "\x7f\xff\xff\xff", want: FrameHeader{
- Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}},
- }
- for i, tt := range tests {
- got, err := readFrameHeader(make([]byte, 9), strings.NewReader(tt.in))
- if err != nil {
- t.Errorf("%d. readFrameHeader(%q) = %v", i, tt.in, err)
- continue
- }
- tt.want.valid = true
- if got != tt.want {
- t.Errorf("%d. readFrameHeader(%q) = %+v; want %+v", i, tt.in, got, tt.want)
- }
- }
-}
-
-func TestReadWriteFrameHeader(t *testing.T) {
- tests := []struct {
- len uint32
- typ FrameType
- flags Flags
- streamID uint32
- }{
- {len: 0, typ: 255, flags: 1, streamID: 0},
- {len: 0, typ: 255, flags: 1, streamID: 1},
- {len: 0, typ: 255, flags: 1, streamID: 255},
- {len: 0, typ: 255, flags: 1, streamID: 256},
- {len: 0, typ: 255, flags: 1, streamID: 65535},
- {len: 0, typ: 255, flags: 1, streamID: 65536},
-
- {len: 0, typ: 1, flags: 255, streamID: 1},
- {len: 255, typ: 1, flags: 255, streamID: 1},
- {len: 256, typ: 1, flags: 255, streamID: 1},
- {len: 65535, typ: 1, flags: 255, streamID: 1},
- {len: 65536, typ: 1, flags: 255, streamID: 1},
- {len: 16777215, typ: 1, flags: 255, streamID: 1},
- }
- for _, tt := range tests {
- fr, buf := testFramer()
- fr.startWrite(tt.typ, tt.flags, tt.streamID)
- fr.writeBytes(make([]byte, tt.len))
- fr.endWrite()
- fh, err := ReadFrameHeader(buf)
- if err != nil {
- t.Errorf("ReadFrameHeader(%+v) = %v", tt, err)
- continue
- }
- if fh.Type != tt.typ || fh.Flags != tt.flags || fh.Length != tt.len || fh.StreamID != tt.streamID {
- t.Errorf("ReadFrameHeader(%+v) = %+v; mismatch", tt, fh)
- }
- }
-
-}
-
-func TestWriteTooLargeFrame(t *testing.T) {
- fr, _ := testFramer()
- fr.startWrite(0, 1, 1)
- fr.writeBytes(make([]byte, 1<<24))
- err := fr.endWrite()
- if err != ErrFrameTooLarge {
- t.Errorf("endWrite = %v; want errFrameTooLarge", err)
- }
-}
-
-func TestWriteGoAway(t *testing.T) {
- const debug = "foo"
- fr, buf := testFramer()
- if err := fr.WriteGoAway(0x01020304, 0x05060708, []byte(debug)); err != nil {
- t.Fatal(err)
- }
- const wantEnc = "\x00\x00\v\a\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" + debug
- if buf.String() != wantEnc {
- t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
- }
- f, err := fr.ReadFrame()
- if err != nil {
- t.Fatal(err)
- }
- want := &GoAwayFrame{
- FrameHeader: FrameHeader{
- valid: true,
- Type: 0x7,
- Flags: 0,
- Length: uint32(4 + 4 + len(debug)),
- StreamID: 0,
- },
- LastStreamID: 0x01020304,
- ErrCode: 0x05060708,
- debugData: []byte(debug),
- }
- if !reflect.DeepEqual(f, want) {
- t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want)
- }
- if got := string(f.(*GoAwayFrame).DebugData()); got != debug {
- t.Errorf("debug data = %q; want %q", got, debug)
- }
-}
-
-func TestWritePushPromise(t *testing.T) {
- pp := PushPromiseParam{
- StreamID: 42,
- PromiseID: 42,
- BlockFragment: []byte("abc"),
- }
- fr, buf := testFramer()
- if err := fr.WritePushPromise(pp); err != nil {
- t.Fatal(err)
- }
- const wantEnc = "\x00\x00\x07\x05\x00\x00\x00\x00*\x00\x00\x00*abc"
- if buf.String() != wantEnc {
- t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
- }
- f, err := fr.ReadFrame()
- if err != nil {
- t.Fatal(err)
- }
- _, ok := f.(*PushPromiseFrame)
- if !ok {
- t.Fatalf("got %T; want *PushPromiseFrame", f)
- }
- want := &PushPromiseFrame{
- FrameHeader: FrameHeader{
- valid: true,
- Type: 0x5,
- Flags: 0x0,
- Length: 0x7,
- StreamID: 42,
- },
- PromiseID: 42,
- headerFragBuf: []byte("abc"),
- }
- if !reflect.DeepEqual(f, want) {
- t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want)
- }
-}
-
-// test checkFrameOrder and that HEADERS and CONTINUATION frames can't be intermingled.
-func TestReadFrameOrder(t *testing.T) {
- head := func(f *Framer, id uint32, end bool) {
- f.WriteHeaders(HeadersFrameParam{
- StreamID: id,
- BlockFragment: []byte("foo"), // unused, but non-empty
- EndHeaders: end,
- })
- }
- cont := func(f *Framer, id uint32, end bool) {
- f.WriteContinuation(id, end, []byte("foo"))
- }
-
- tests := [...]struct {
- name string
- w func(*Framer)
- atLeast int
- wantErr string
- }{
- 0: {
- w: func(f *Framer) {
- head(f, 1, true)
- },
- },
- 1: {
- w: func(f *Framer) {
- head(f, 1, true)
- head(f, 2, true)
- },
- },
- 2: {
- wantErr: "got HEADERS for stream 2; expected CONTINUATION following HEADERS for stream 1",
- w: func(f *Framer) {
- head(f, 1, false)
- head(f, 2, true)
- },
- },
- 3: {
- wantErr: "got DATA for stream 1; expected CONTINUATION following HEADERS for stream 1",
- w: func(f *Framer) {
- head(f, 1, false)
- },
- },
- 4: {
- w: func(f *Framer) {
- head(f, 1, false)
- cont(f, 1, true)
- head(f, 2, true)
- },
- },
- 5: {
- wantErr: "got CONTINUATION for stream 2; expected stream 1",
- w: func(f *Framer) {
- head(f, 1, false)
- cont(f, 2, true)
- head(f, 2, true)
- },
- },
- 6: {
- wantErr: "unexpected CONTINUATION for stream 1",
- w: func(f *Framer) {
- cont(f, 1, true)
- },
- },
- 7: {
- wantErr: "unexpected CONTINUATION for stream 1",
- w: func(f *Framer) {
- cont(f, 1, false)
- },
- },
- 8: {
- wantErr: "HEADERS frame with stream ID 0",
- w: func(f *Framer) {
- head(f, 0, true)
- },
- },
- 9: {
- wantErr: "CONTINUATION frame with stream ID 0",
- w: func(f *Framer) {
- cont(f, 0, true)
- },
- },
- 10: {
- wantErr: "unexpected CONTINUATION for stream 1",
- atLeast: 5,
- w: func(f *Framer) {
- head(f, 1, false)
- cont(f, 1, false)
- cont(f, 1, false)
- cont(f, 1, false)
- cont(f, 1, true)
- cont(f, 1, false)
- },
- },
- }
- for i, tt := range tests {
- buf := new(bytes.Buffer)
- f := NewFramer(buf, buf)
- f.AllowIllegalWrites = true
- tt.w(f)
- f.WriteData(1, true, nil) // to test transition away from last step
-
- var err error
- n := 0
- var log bytes.Buffer
- for {
- var got Frame
- got, err = f.ReadFrame()
- fmt.Fprintf(&log, " read %v, %v\n", got, err)
- if err != nil {
- break
- }
- n++
- }
- if err == io.EOF {
- err = nil
- }
- ok := tt.wantErr == ""
- if ok && err != nil {
- t.Errorf("%d. after %d good frames, ReadFrame = %v; want success\n%s", i, n, err, log.Bytes())
- continue
- }
- if !ok && err != ConnectionError(ErrCodeProtocol) {
- t.Errorf("%d. after %d good frames, ReadFrame = %v; want ConnectionError(ErrCodeProtocol)\n%s", i, n, err, log.Bytes())
- continue
- }
- if !((f.errDetail == nil && tt.wantErr == "") || (fmt.Sprint(f.errDetail) == tt.wantErr)) {
- t.Errorf("%d. framer eror = %q; want %q\n%s", i, f.errDetail, tt.wantErr, log.Bytes())
- }
- if n < tt.atLeast {
- t.Errorf("%d. framer only read %d frames; want at least %d\n%s", i, n, tt.atLeast, log.Bytes())
- }
- }
-}
-
-func TestMetaFrameHeader(t *testing.T) {
- write := func(f *Framer, frags ...[]byte) {
- for i, frag := range frags {
- end := (i == len(frags)-1)
- if i == 0 {
- f.WriteHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: frag,
- EndHeaders: end,
- })
- } else {
- f.WriteContinuation(1, end, frag)
- }
- }
- }
-
- want := func(flags Flags, length uint32, pairs ...string) *MetaHeadersFrame {
- mh := &MetaHeadersFrame{
- HeadersFrame: &HeadersFrame{
- FrameHeader: FrameHeader{
- Type: FrameHeaders,
- Flags: flags,
- Length: length,
- StreamID: 1,
- },
- },
- Fields: []hpack.HeaderField(nil),
- }
- for len(pairs) > 0 {
- mh.Fields = append(mh.Fields, hpack.HeaderField{
- Name: pairs[0],
- Value: pairs[1],
- })
- pairs = pairs[2:]
- }
- return mh
- }
- truncated := func(mh *MetaHeadersFrame) *MetaHeadersFrame {
- mh.Truncated = true
- return mh
- }
-
- const noFlags Flags = 0
-
- oneKBString := strings.Repeat("a", 1<<10)
-
- tests := [...]struct {
- name string
- w func(*Framer)
- want interface{} // *MetaHeaderFrame or error
- wantErrReason string
- maxHeaderListSize uint32
- }{
- 0: {
- name: "single_headers",
- w: func(f *Framer) {
- var he hpackEncoder
- all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/")
- write(f, all)
- },
- want: want(FlagHeadersEndHeaders, 2, ":method", "GET", ":path", "/"),
- },
- 1: {
- name: "with_continuation",
- w: func(f *Framer) {
- var he hpackEncoder
- all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", "bar")
- write(f, all[:1], all[1:])
- },
- want: want(noFlags, 1, ":method", "GET", ":path", "/", "foo", "bar"),
- },
- 2: {
- name: "with_two_continuation",
- w: func(f *Framer) {
- var he hpackEncoder
- all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", "bar")
- write(f, all[:2], all[2:4], all[4:])
- },
- want: want(noFlags, 2, ":method", "GET", ":path", "/", "foo", "bar"),
- },
- 3: {
- name: "big_string_okay",
- w: func(f *Framer) {
- var he hpackEncoder
- all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", oneKBString)
- write(f, all[:2], all[2:])
- },
- want: want(noFlags, 2, ":method", "GET", ":path", "/", "foo", oneKBString),
- },
- 4: {
- name: "big_string_error",
- w: func(f *Framer) {
- var he hpackEncoder
- all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", oneKBString)
- write(f, all[:2], all[2:])
- },
- maxHeaderListSize: (1 << 10) / 2,
- want: ConnectionError(ErrCodeCompression),
- },
- 5: {
- name: "max_header_list_truncated",
- w: func(f *Framer) {
- var he hpackEncoder
- var pairs = []string{":method", "GET", ":path", "/"}
- for i := 0; i < 100; i++ {
- pairs = append(pairs, "foo", "bar")
- }
- all := he.encodeHeaderRaw(t, pairs...)
- write(f, all[:2], all[2:])
- },
- maxHeaderListSize: (1 << 10) / 2,
- want: truncated(want(noFlags, 2,
- ":method", "GET",
- ":path", "/",
- "foo", "bar",
- "foo", "bar",
- "foo", "bar",
- "foo", "bar",
- "foo", "bar",
- "foo", "bar",
- "foo", "bar",
- "foo", "bar",
- "foo", "bar",
- "foo", "bar",
- "foo", "bar", // 11
- )),
- },
- 6: {
- name: "pseudo_order",
- w: func(f *Framer) {
- write(f, encodeHeaderRaw(t,
- ":method", "GET",
- "foo", "bar",
- ":path", "/", // bogus
- ))
- },
- want: streamError(1, ErrCodeProtocol),
- wantErrReason: "pseudo header field after regular",
- },
- 7: {
- name: "pseudo_unknown",
- w: func(f *Framer) {
- write(f, encodeHeaderRaw(t,
- ":unknown", "foo", // bogus
- "foo", "bar",
- ))
- },
- want: streamError(1, ErrCodeProtocol),
- wantErrReason: "invalid pseudo-header \":unknown\"",
- },
- 8: {
- name: "pseudo_mix_request_response",
- w: func(f *Framer) {
- write(f, encodeHeaderRaw(t,
- ":method", "GET",
- ":status", "100",
- ))
- },
- want: streamError(1, ErrCodeProtocol),
- wantErrReason: "mix of request and response pseudo headers",
- },
- 9: {
- name: "pseudo_dup",
- w: func(f *Framer) {
- write(f, encodeHeaderRaw(t,
- ":method", "GET",
- ":method", "POST",
- ))
- },
- want: streamError(1, ErrCodeProtocol),
- wantErrReason: "duplicate pseudo-header \":method\"",
- },
- 10: {
- name: "trailer_okay_no_pseudo",
- w: func(f *Framer) { write(f, encodeHeaderRaw(t, "foo", "bar")) },
- want: want(FlagHeadersEndHeaders, 8, "foo", "bar"),
- },
- 11: {
- name: "invalid_field_name",
- w: func(f *Framer) { write(f, encodeHeaderRaw(t, "CapitalBad", "x")) },
- want: streamError(1, ErrCodeProtocol),
- wantErrReason: "invalid header field name \"CapitalBad\"",
- },
- 12: {
- name: "invalid_field_value",
- w: func(f *Framer) { write(f, encodeHeaderRaw(t, "key", "bad_null\x00")) },
- want: streamError(1, ErrCodeProtocol),
- wantErrReason: "invalid header field value \"bad_null\\x00\"",
- },
- }
- for i, tt := range tests {
- buf := new(bytes.Buffer)
- f := NewFramer(buf, buf)
- f.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil)
- f.MaxHeaderListSize = tt.maxHeaderListSize
- tt.w(f)
-
- name := tt.name
- if name == "" {
- name = fmt.Sprintf("test index %d", i)
- }
-
- var got interface{}
- var err error
- got, err = f.ReadFrame()
- if err != nil {
- got = err
-
- // Ignore the StreamError.Cause field, if it matches the wantErrReason.
- // The test table above predates the Cause field.
- if se, ok := err.(StreamError); ok && se.Cause != nil && se.Cause.Error() == tt.wantErrReason {
- se.Cause = nil
- got = se
- }
- }
- if !reflect.DeepEqual(got, tt.want) {
- if mhg, ok := got.(*MetaHeadersFrame); ok {
- if mhw, ok := tt.want.(*MetaHeadersFrame); ok {
- hg := mhg.HeadersFrame
- hw := mhw.HeadersFrame
- if hg != nil && hw != nil && !reflect.DeepEqual(*hg, *hw) {
- t.Errorf("%s: headers differ:\n got: %+v\nwant: %+v\n", name, *hg, *hw)
- }
- }
- }
- str := func(v interface{}) string {
- if _, ok := v.(error); ok {
- return fmt.Sprintf("error %v", v)
- } else {
- return fmt.Sprintf("value %#v", v)
- }
- }
- t.Errorf("%s:\n got: %v\nwant: %s", name, str(got), str(tt.want))
- }
- if tt.wantErrReason != "" && tt.wantErrReason != fmt.Sprint(f.errDetail) {
- t.Errorf("%s: got error reason %q; want %q", name, f.errDetail, tt.wantErrReason)
- }
- }
-}
-
-func encodeHeaderRaw(t *testing.T, pairs ...string) []byte {
- var he hpackEncoder
- return he.encodeHeaderRaw(t, pairs...)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go16.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go16.go
deleted file mode 100644
index 2b72855..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go16.go
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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.6
-
-package http2
-
-import (
- "crypto/tls"
- "net/http"
- "time"
-)
-
-func transportExpectContinueTimeout(t1 *http.Transport) time.Duration {
- return t1.ExpectContinueTimeout
-}
-
-// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
-func isBadCipher(cipher uint16) bool {
- switch cipher {
- case tls.TLS_RSA_WITH_RC4_128_SHA,
- tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
- tls.TLS_RSA_WITH_AES_128_CBC_SHA,
- tls.TLS_RSA_WITH_AES_256_CBC_SHA,
- tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
- tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
- tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
- tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
- tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
- tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
- tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
- tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- // Reject cipher suites from Appendix A.
- // "This list includes those cipher suites that do not
- // offer an ephemeral key exchange and those that are
- // based on the TLS null, stream or block cipher type"
- return true
- default:
- return false
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go17.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go17.go
deleted file mode 100644
index 47b7fae..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go17.go
+++ /dev/null
@@ -1,106 +0,0 @@
-// 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 http2
-
-import (
- "context"
- "net"
- "net/http"
- "net/http/httptrace"
- "time"
-)
-
-type contextContext interface {
- context.Context
-}
-
-func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx contextContext, cancel func()) {
- ctx, cancel = context.WithCancel(context.Background())
- ctx = context.WithValue(ctx, http.LocalAddrContextKey, c.LocalAddr())
- if hs := opts.baseConfig(); hs != nil {
- ctx = context.WithValue(ctx, http.ServerContextKey, hs)
- }
- return
-}
-
-func contextWithCancel(ctx contextContext) (_ contextContext, cancel func()) {
- return context.WithCancel(ctx)
-}
-
-func requestWithContext(req *http.Request, ctx contextContext) *http.Request {
- return req.WithContext(ctx)
-}
-
-type clientTrace httptrace.ClientTrace
-
-func reqContext(r *http.Request) context.Context { return r.Context() }
-
-func (t *Transport) idleConnTimeout() time.Duration {
- if t.t1 != nil {
- return t.t1.IdleConnTimeout
- }
- return 0
-}
-
-func setResponseUncompressed(res *http.Response) { res.Uncompressed = true }
-
-func traceGotConn(req *http.Request, cc *ClientConn) {
- trace := httptrace.ContextClientTrace(req.Context())
- if trace == nil || trace.GotConn == nil {
- return
- }
- ci := httptrace.GotConnInfo{Conn: cc.tconn}
- cc.mu.Lock()
- ci.Reused = cc.nextStreamID > 1
- ci.WasIdle = len(cc.streams) == 0 && ci.Reused
- if ci.WasIdle && !cc.lastActive.IsZero() {
- ci.IdleTime = time.Now().Sub(cc.lastActive)
- }
- cc.mu.Unlock()
-
- trace.GotConn(ci)
-}
-
-func traceWroteHeaders(trace *clientTrace) {
- if trace != nil && trace.WroteHeaders != nil {
- trace.WroteHeaders()
- }
-}
-
-func traceGot100Continue(trace *clientTrace) {
- if trace != nil && trace.Got100Continue != nil {
- trace.Got100Continue()
- }
-}
-
-func traceWait100Continue(trace *clientTrace) {
- if trace != nil && trace.Wait100Continue != nil {
- trace.Wait100Continue()
- }
-}
-
-func traceWroteRequest(trace *clientTrace, err error) {
- if trace != nil && trace.WroteRequest != nil {
- trace.WroteRequest(httptrace.WroteRequestInfo{Err: err})
- }
-}
-
-func traceFirstResponseByte(trace *clientTrace) {
- if trace != nil && trace.GotFirstResponseByte != nil {
- trace.GotFirstResponseByte()
- }
-}
-
-func requestTrace(req *http.Request) *clientTrace {
- trace := httptrace.ContextClientTrace(req.Context())
- return (*clientTrace)(trace)
-}
-
-// Ping sends a PING frame to the server and waits for the ack.
-func (cc *ClientConn) Ping(ctx context.Context) error {
- return cc.ping(ctx)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go17_not18.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go17_not18.go
deleted file mode 100644
index b4c52ec..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go17_not18.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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,!go1.8
-
-package http2
-
-import "crypto/tls"
-
-// temporary copy of Go 1.7's private tls.Config.clone:
-func cloneTLSConfig(c *tls.Config) *tls.Config {
- return &tls.Config{
- Rand: c.Rand,
- Time: c.Time,
- Certificates: c.Certificates,
- NameToCertificate: c.NameToCertificate,
- GetCertificate: c.GetCertificate,
- RootCAs: c.RootCAs,
- NextProtos: c.NextProtos,
- ServerName: c.ServerName,
- ClientAuth: c.ClientAuth,
- ClientCAs: c.ClientCAs,
- InsecureSkipVerify: c.InsecureSkipVerify,
- CipherSuites: c.CipherSuites,
- PreferServerCipherSuites: c.PreferServerCipherSuites,
- SessionTicketsDisabled: c.SessionTicketsDisabled,
- SessionTicketKey: c.SessionTicketKey,
- ClientSessionCache: c.ClientSessionCache,
- MinVersion: c.MinVersion,
- MaxVersion: c.MaxVersion,
- CurvePreferences: c.CurvePreferences,
- DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
- Renegotiation: c.Renegotiation,
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go18.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go18.go
deleted file mode 100644
index 633202c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go18.go
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.
-
-// +build go1.8
-
-package http2
-
-import (
- "crypto/tls"
- "io"
- "net/http"
-)
-
-func cloneTLSConfig(c *tls.Config) *tls.Config { return c.Clone() }
-
-var _ http.Pusher = (*responseWriter)(nil)
-
-// Push implements http.Pusher.
-func (w *responseWriter) Push(target string, opts *http.PushOptions) error {
- internalOpts := pushOptions{}
- if opts != nil {
- internalOpts.Method = opts.Method
- internalOpts.Header = opts.Header
- }
- return w.push(target, internalOpts)
-}
-
-func configureServer18(h1 *http.Server, h2 *Server) error {
- if h2.IdleTimeout == 0 {
- if h1.IdleTimeout != 0 {
- h2.IdleTimeout = h1.IdleTimeout
- } else {
- h2.IdleTimeout = h1.ReadTimeout
- }
- }
- return nil
-}
-
-func shouldLogPanic(panicValue interface{}) bool {
- return panicValue != nil && panicValue != http.ErrAbortHandler
-}
-
-func reqGetBody(req *http.Request) func() (io.ReadCloser, error) {
- return req.GetBody
-}
-
-func reqBodyIsNoBody(body io.ReadCloser) bool {
- return body == http.NoBody
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go18_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go18_test.go
deleted file mode 100644
index 8365505..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go18_test.go
+++ /dev/null
@@ -1,66 +0,0 @@
-// 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.8
-
-package http2
-
-import (
- "net/http"
- "testing"
- "time"
-)
-
-// Tests that http2.Server.IdleTimeout is initialized from
-// http.Server.{Idle,Read}Timeout. http.Server.IdleTimeout was
-// added in Go 1.8.
-func TestConfigureServerIdleTimeout_Go18(t *testing.T) {
- const timeout = 5 * time.Second
- const notThisOne = 1 * time.Second
-
- // With a zero http2.Server, verify that it copies IdleTimeout:
- {
- s1 := &http.Server{
- IdleTimeout: timeout,
- ReadTimeout: notThisOne,
- }
- s2 := &Server{}
- if err := ConfigureServer(s1, s2); err != nil {
- t.Fatal(err)
- }
- if s2.IdleTimeout != timeout {
- t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
- }
- }
-
- // And that it falls back to ReadTimeout:
- {
- s1 := &http.Server{
- ReadTimeout: timeout,
- }
- s2 := &Server{}
- if err := ConfigureServer(s1, s2); err != nil {
- t.Fatal(err)
- }
- if s2.IdleTimeout != timeout {
- t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
- }
- }
-
- // Verify that s1's IdleTimeout doesn't overwrite an existing setting:
- {
- s1 := &http.Server{
- IdleTimeout: notThisOne,
- }
- s2 := &Server{
- IdleTimeout: timeout,
- }
- if err := ConfigureServer(s1, s2); err != nil {
- t.Fatal(err)
- }
- if s2.IdleTimeout != timeout {
- t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/gotrack.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/gotrack.go
deleted file mode 100644
index 9933c9f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/gotrack.go
+++ /dev/null
@@ -1,170 +0,0 @@
-// 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.
-
-// Defensive debug-only utility to track that functions run on the
-// goroutine that they're supposed to.
-
-package http2
-
-import (
- "bytes"
- "errors"
- "fmt"
- "os"
- "runtime"
- "strconv"
- "sync"
-)
-
-var DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
-
-type goroutineLock uint64
-
-func newGoroutineLock() goroutineLock {
- if !DebugGoroutines {
- return 0
- }
- return goroutineLock(curGoroutineID())
-}
-
-func (g goroutineLock) check() {
- if !DebugGoroutines {
- return
- }
- if curGoroutineID() != uint64(g) {
- panic("running on the wrong goroutine")
- }
-}
-
-func (g goroutineLock) checkNotOn() {
- if !DebugGoroutines {
- return
- }
- if curGoroutineID() == uint64(g) {
- panic("running on the wrong goroutine")
- }
-}
-
-var goroutineSpace = []byte("goroutine ")
-
-func curGoroutineID() uint64 {
- bp := littleBuf.Get().(*[]byte)
- defer littleBuf.Put(bp)
- b := *bp
- b = b[:runtime.Stack(b, false)]
- // Parse the 4707 out of "goroutine 4707 ["
- b = bytes.TrimPrefix(b, goroutineSpace)
- i := bytes.IndexByte(b, ' ')
- if i < 0 {
- panic(fmt.Sprintf("No space found in %q", b))
- }
- b = b[:i]
- n, err := parseUintBytes(b, 10, 64)
- if err != nil {
- panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err))
- }
- return n
-}
-
-var littleBuf = sync.Pool{
- New: func() interface{} {
- buf := make([]byte, 64)
- return &buf
- },
-}
-
-// parseUintBytes is like strconv.ParseUint, but using a []byte.
-func parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {
- var cutoff, maxVal uint64
-
- if bitSize == 0 {
- bitSize = int(strconv.IntSize)
- }
-
- s0 := s
- switch {
- case len(s) < 1:
- err = strconv.ErrSyntax
- goto Error
-
- case 2 <= base && base <= 36:
- // valid base; nothing to do
-
- case base == 0:
- // Look for octal, hex prefix.
- switch {
- case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
- base = 16
- s = s[2:]
- if len(s) < 1 {
- err = strconv.ErrSyntax
- goto Error
- }
- case s[0] == '0':
- base = 8
- default:
- base = 10
- }
-
- default:
- err = errors.New("invalid base " + strconv.Itoa(base))
- goto Error
- }
-
- n = 0
- cutoff = cutoff64(base)
- maxVal = 1<<uint(bitSize) - 1
-
- for i := 0; i < len(s); i++ {
- var v byte
- d := s[i]
- switch {
- case '0' <= d && d <= '9':
- v = d - '0'
- case 'a' <= d && d <= 'z':
- v = d - 'a' + 10
- case 'A' <= d && d <= 'Z':
- v = d - 'A' + 10
- default:
- n = 0
- err = strconv.ErrSyntax
- goto Error
- }
- if int(v) >= base {
- n = 0
- err = strconv.ErrSyntax
- goto Error
- }
-
- if n >= cutoff {
- // n*base overflows
- n = 1<<64 - 1
- err = strconv.ErrRange
- goto Error
- }
- n *= uint64(base)
-
- n1 := n + uint64(v)
- if n1 < n || n1 > maxVal {
- // n+v overflows
- n = 1<<64 - 1
- err = strconv.ErrRange
- goto Error
- }
- n = n1
- }
-
- return n, nil
-
-Error:
- return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err}
-}
-
-// Return the first number n such that n*base >= 1<<64.
-func cutoff64(base int) uint64 {
- if base < 2 {
- return 0
- }
- return (1<<64-1)/uint64(base) + 1
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/gotrack_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/gotrack_test.go
deleted file mode 100644
index 06db612..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/gotrack_test.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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 http2
-
-import (
- "fmt"
- "strings"
- "testing"
-)
-
-func TestGoroutineLock(t *testing.T) {
- oldDebug := DebugGoroutines
- DebugGoroutines = true
- defer func() { DebugGoroutines = oldDebug }()
-
- g := newGoroutineLock()
- g.check()
-
- sawPanic := make(chan interface{})
- go func() {
- defer func() { sawPanic <- recover() }()
- g.check() // should panic
- }()
- e := <-sawPanic
- if e == nil {
- t.Fatal("did not see panic from check in other goroutine")
- }
- if !strings.Contains(fmt.Sprint(e), "wrong goroutine") {
- t.Errorf("expected on see panic about running on the wrong goroutine; got %v", e)
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/.gitignore b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/.gitignore
deleted file mode 100644
index 0de86dd..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-h2demo
-h2demo.linux
-client-id.dat
-client-secret.dat
-token.dat
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/Makefile b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/Makefile
deleted file mode 100644
index f5c31ef..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-h2demo.linux: h2demo.go
- GOOS=linux go build --tags=h2demo -o h2demo.linux .
-
-FORCE:
-
-upload: FORCE
- go install golang.org/x/build/cmd/upload
- upload --verbose --osarch=linux-amd64 --tags=h2demo --file=go:golang.org/x/net/http2/h2demo --public http2-demo-server-tls/h2demo
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/README b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/README
deleted file mode 100644
index 212a96f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/README
+++ /dev/null
@@ -1,16 +0,0 @@
-
-Client:
- -- Firefox nightly with about:config network.http.spdy.enabled.http2draft set true
- -- Chrome: go to chrome://flags/#enable-spdy4, save and restart (button at bottom)
-
-Make CA:
-$ openssl genrsa -out rootCA.key 2048
-$ openssl req -x509 -new -nodes -key rootCA.key -days 1024 -out rootCA.pem
-... install that to Firefox
-
-Make cert:
-$ openssl genrsa -out server.key 2048
-$ openssl req -new -key server.key -out server.csr
-$ openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 500
-
-
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/h2demo.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/h2demo.go
deleted file mode 100644
index 980b6d6..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/h2demo.go
+++ /dev/null
@@ -1,486 +0,0 @@
-// 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 h2demo
-
-package main
-
-import (
- "bytes"
- "crypto/tls"
- "flag"
- "fmt"
- "hash/crc32"
- "image"
- "image/jpeg"
- "io"
- "io/ioutil"
- "log"
- "net"
- "net/http"
- "os"
- "path"
- "regexp"
- "runtime"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "go4.org/syncutil/singleflight"
- "golang.org/x/crypto/acme/autocert"
- "golang.org/x/net/http2"
-)
-
-var (
- prod = flag.Bool("prod", false, "Whether to configure itself to be the production http2.golang.org server.")
-
- httpsAddr = flag.String("https_addr", "localhost:4430", "TLS address to listen on ('host:port' or ':port'). Required.")
- httpAddr = flag.String("http_addr", "", "Plain HTTP address to listen on ('host:port', or ':port'). Empty means no HTTP.")
-
- hostHTTP = flag.String("http_host", "", "Optional host or host:port to use for http:// links to this service. By default, this is implied from -http_addr.")
- hostHTTPS = flag.String("https_host", "", "Optional host or host:port to use for http:// links to this service. By default, this is implied from -https_addr.")
-)
-
-func homeOldHTTP(w http.ResponseWriter, r *http.Request) {
- io.WriteString(w, `<html>
-<body>
-<h1>Go + HTTP/2</h1>
-<p>Welcome to <a href="https://golang.org/">the Go language</a>'s <a href="https://http2.github.io/">HTTP/2</a> demo & interop server.</p>
-<p>Unfortunately, you're <b>not</b> using HTTP/2 right now. To do so:</p>
-<ul>
- <li>Use Firefox Nightly or go to <b>about:config</b> and enable "network.http.spdy.enabled.http2draft"</li>
- <li>Use Google Chrome Canary and/or go to <b>chrome://flags/#enable-spdy4</b> to <i>Enable SPDY/4</i> (Chrome's name for HTTP/2)</li>
-</ul>
-<p>See code & instructions for connecting at <a href="https://github.com/golang/net/tree/master/http2">https://github.com/golang/net/tree/master/http2</a>.</p>
-
-</body></html>`)
-}
-
-func home(w http.ResponseWriter, r *http.Request) {
- if r.URL.Path != "/" {
- http.NotFound(w, r)
- return
- }
- io.WriteString(w, `<html>
-<body>
-<h1>Go + HTTP/2</h1>
-
-<p>Welcome to <a href="https://golang.org/">the Go language</a>'s <a
-href="https://http2.github.io/">HTTP/2</a> demo & interop server.</p>
-
-<p>Congratulations, <b>you're using HTTP/2 right now</b>.</p>
-
-<p>This server exists for others in the HTTP/2 community to test their HTTP/2 client implementations and point out flaws in our server.</p>
-
-<p>
-The code is at <a href="https://golang.org/x/net/http2">golang.org/x/net/http2</a> and
-is used transparently by the Go standard library from Go 1.6 and later.
-</p>
-
-<p>Contact info: <i>bradfitz@golang.org</i>, or <a
-href="https://golang.org/s/http2bug">file a bug</a>.</p>
-
-<h2>Handlers for testing</h2>
-<ul>
- <li>GET <a href="/reqinfo">/reqinfo</a> to dump the request + headers received</li>
- <li>GET <a href="/clockstream">/clockstream</a> streams the current time every second</li>
- <li>GET <a href="/gophertiles">/gophertiles</a> to see a page with a bunch of images</li>
- <li>GET <a href="/file/gopher.png">/file/gopher.png</a> for a small file (does If-Modified-Since, Content-Range, etc)</li>
- <li>GET <a href="/file/go.src.tar.gz">/file/go.src.tar.gz</a> for a larger file (~10 MB)</li>
- <li>GET <a href="/redirect">/redirect</a> to redirect back to / (this page)</li>
- <li>GET <a href="/goroutines">/goroutines</a> to see all active goroutines in this server</li>
- <li>PUT something to <a href="/crc32">/crc32</a> to get a count of number of bytes and its CRC-32</li>
- <li>PUT something to <a href="/ECHO">/ECHO</a> and it will be streamed back to you capitalized</li>
-</ul>
-
-</body></html>`)
-}
-
-func reqInfoHandler(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "text/plain")
- fmt.Fprintf(w, "Method: %s\n", r.Method)
- fmt.Fprintf(w, "Protocol: %s\n", r.Proto)
- fmt.Fprintf(w, "Host: %s\n", r.Host)
- fmt.Fprintf(w, "RemoteAddr: %s\n", r.RemoteAddr)
- fmt.Fprintf(w, "RequestURI: %q\n", r.RequestURI)
- fmt.Fprintf(w, "URL: %#v\n", r.URL)
- fmt.Fprintf(w, "Body.ContentLength: %d (-1 means unknown)\n", r.ContentLength)
- fmt.Fprintf(w, "Close: %v (relevant for HTTP/1 only)\n", r.Close)
- fmt.Fprintf(w, "TLS: %#v\n", r.TLS)
- fmt.Fprintf(w, "\nHeaders:\n")
- r.Header.Write(w)
-}
-
-func crcHandler(w http.ResponseWriter, r *http.Request) {
- if r.Method != "PUT" {
- http.Error(w, "PUT required.", 400)
- return
- }
- crc := crc32.NewIEEE()
- n, err := io.Copy(crc, r.Body)
- if err == nil {
- w.Header().Set("Content-Type", "text/plain")
- fmt.Fprintf(w, "bytes=%d, CRC32=%x", n, crc.Sum(nil))
- }
-}
-
-type capitalizeReader struct {
- r io.Reader
-}
-
-func (cr capitalizeReader) Read(p []byte) (n int, err error) {
- n, err = cr.r.Read(p)
- for i, b := range p[:n] {
- if b >= 'a' && b <= 'z' {
- p[i] = b - ('a' - 'A')
- }
- }
- return
-}
-
-type flushWriter struct {
- w io.Writer
-}
-
-func (fw flushWriter) Write(p []byte) (n int, err error) {
- n, err = fw.w.Write(p)
- if f, ok := fw.w.(http.Flusher); ok {
- f.Flush()
- }
- return
-}
-
-func echoCapitalHandler(w http.ResponseWriter, r *http.Request) {
- if r.Method != "PUT" {
- http.Error(w, "PUT required.", 400)
- return
- }
- io.Copy(flushWriter{w}, capitalizeReader{r.Body})
-}
-
-var (
- fsGrp singleflight.Group
- fsMu sync.Mutex // guards fsCache
- fsCache = map[string]http.Handler{}
-)
-
-// fileServer returns a file-serving handler that proxies URL.
-// It lazily fetches URL on the first access and caches its contents forever.
-func fileServer(url string) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- hi, err := fsGrp.Do(url, func() (interface{}, error) {
- fsMu.Lock()
- if h, ok := fsCache[url]; ok {
- fsMu.Unlock()
- return h, nil
- }
- fsMu.Unlock()
-
- res, err := http.Get(url)
- if err != nil {
- return nil, err
- }
- defer res.Body.Close()
- slurp, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return nil, err
- }
-
- modTime := time.Now()
- var h http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- http.ServeContent(w, r, path.Base(url), modTime, bytes.NewReader(slurp))
- })
- fsMu.Lock()
- fsCache[url] = h
- fsMu.Unlock()
- return h, nil
- })
- if err != nil {
- http.Error(w, err.Error(), 500)
- return
- }
- hi.(http.Handler).ServeHTTP(w, r)
- })
-}
-
-func clockStreamHandler(w http.ResponseWriter, r *http.Request) {
- clientGone := w.(http.CloseNotifier).CloseNotify()
- w.Header().Set("Content-Type", "text/plain")
- ticker := time.NewTicker(1 * time.Second)
- defer ticker.Stop()
- fmt.Fprintf(w, "# ~1KB of junk to force browsers to start rendering immediately: \n")
- io.WriteString(w, strings.Repeat("# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n", 13))
-
- for {
- fmt.Fprintf(w, "%v\n", time.Now())
- w.(http.Flusher).Flush()
- select {
- case <-ticker.C:
- case <-clientGone:
- log.Printf("Client %v disconnected from the clock", r.RemoteAddr)
- return
- }
- }
-}
-
-func registerHandlers() {
- tiles := newGopherTilesHandler()
-
- mux2 := http.NewServeMux()
- http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
- if r.TLS == nil {
- if r.URL.Path == "/gophertiles" {
- tiles.ServeHTTP(w, r)
- return
- }
- http.Redirect(w, r, "https://"+httpsHost()+"/", http.StatusFound)
- return
- }
- if r.ProtoMajor == 1 {
- if r.URL.Path == "/reqinfo" {
- reqInfoHandler(w, r)
- return
- }
- homeOldHTTP(w, r)
- return
- }
- mux2.ServeHTTP(w, r)
- })
- mux2.HandleFunc("/", home)
- mux2.Handle("/file/gopher.png", fileServer("https://golang.org/doc/gopher/frontpage.png"))
- mux2.Handle("/file/go.src.tar.gz", fileServer("https://storage.googleapis.com/golang/go1.4.1.src.tar.gz"))
- mux2.HandleFunc("/reqinfo", reqInfoHandler)
- mux2.HandleFunc("/crc32", crcHandler)
- mux2.HandleFunc("/ECHO", echoCapitalHandler)
- mux2.HandleFunc("/clockstream", clockStreamHandler)
- mux2.Handle("/gophertiles", tiles)
- mux2.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) {
- http.Redirect(w, r, "/", http.StatusFound)
- })
- stripHomedir := regexp.MustCompile(`/(Users|home)/\w+`)
- mux2.HandleFunc("/goroutines", func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- buf := make([]byte, 2<<20)
- w.Write(stripHomedir.ReplaceAll(buf[:runtime.Stack(buf, true)], nil))
- })
-}
-
-func newGopherTilesHandler() http.Handler {
- const gopherURL = "https://blog.golang.org/go-programming-language-turns-two_gophers.jpg"
- res, err := http.Get(gopherURL)
- if err != nil {
- log.Fatal(err)
- }
- if res.StatusCode != 200 {
- log.Fatalf("Error fetching %s: %v", gopherURL, res.Status)
- }
- slurp, err := ioutil.ReadAll(res.Body)
- res.Body.Close()
- if err != nil {
- log.Fatal(err)
- }
- im, err := jpeg.Decode(bytes.NewReader(slurp))
- if err != nil {
- if len(slurp) > 1024 {
- slurp = slurp[:1024]
- }
- log.Fatalf("Failed to decode gopher image: %v (got %q)", err, slurp)
- }
-
- type subImager interface {
- SubImage(image.Rectangle) image.Image
- }
- const tileSize = 32
- xt := im.Bounds().Max.X / tileSize
- yt := im.Bounds().Max.Y / tileSize
- var tile [][][]byte // y -> x -> jpeg bytes
- for yi := 0; yi < yt; yi++ {
- var row [][]byte
- for xi := 0; xi < xt; xi++ {
- si := im.(subImager).SubImage(image.Rectangle{
- Min: image.Point{xi * tileSize, yi * tileSize},
- Max: image.Point{(xi + 1) * tileSize, (yi + 1) * tileSize},
- })
- buf := new(bytes.Buffer)
- if err := jpeg.Encode(buf, si, &jpeg.Options{Quality: 90}); err != nil {
- log.Fatal(err)
- }
- row = append(row, buf.Bytes())
- }
- tile = append(tile, row)
- }
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- ms, _ := strconv.Atoi(r.FormValue("latency"))
- const nanosPerMilli = 1e6
- if r.FormValue("x") != "" {
- x, _ := strconv.Atoi(r.FormValue("x"))
- y, _ := strconv.Atoi(r.FormValue("y"))
- if ms <= 1000 {
- time.Sleep(time.Duration(ms) * nanosPerMilli)
- }
- if x >= 0 && x < xt && y >= 0 && y < yt {
- http.ServeContent(w, r, "", time.Time{}, bytes.NewReader(tile[y][x]))
- return
- }
- }
- io.WriteString(w, "<html><body onload='showtimes()'>")
- fmt.Fprintf(w, "A grid of %d tiled images is below. Compare:<p>", xt*yt)
- for _, ms := range []int{0, 30, 200, 1000} {
- d := time.Duration(ms) * nanosPerMilli
- fmt.Fprintf(w, "[<a href='https://%s/gophertiles?latency=%d'>HTTP/2, %v latency</a>] [<a href='http://%s/gophertiles?latency=%d'>HTTP/1, %v latency</a>]<br>\n",
- httpsHost(), ms, d,
- httpHost(), ms, d,
- )
- }
- io.WriteString(w, "<p>\n")
- cacheBust := time.Now().UnixNano()
- for y := 0; y < yt; y++ {
- for x := 0; x < xt; x++ {
- fmt.Fprintf(w, "<img width=%d height=%d src='/gophertiles?x=%d&y=%d&cachebust=%d&latency=%d'>",
- tileSize, tileSize, x, y, cacheBust, ms)
- }
- io.WriteString(w, "<br/>\n")
- }
- io.WriteString(w, `<p><div id='loadtimes'></div></p>
-<script>
-function showtimes() {
- var times = 'Times from connection start:<br>'
- times += 'DOM loaded: ' + (window.performance.timing.domContentLoadedEventEnd - window.performance.timing.connectStart) + 'ms<br>'
- times += 'DOM complete (images loaded): ' + (window.performance.timing.domComplete - window.performance.timing.connectStart) + 'ms<br>'
- document.getElementById('loadtimes').innerHTML = times
-}
-</script>
-<hr><a href='/'>&lt;&lt Back to Go HTTP/2 demo server</a></body></html>`)
- })
-}
-
-func httpsHost() string {
- if *hostHTTPS != "" {
- return *hostHTTPS
- }
- if v := *httpsAddr; strings.HasPrefix(v, ":") {
- return "localhost" + v
- } else {
- return v
- }
-}
-
-func httpHost() string {
- if *hostHTTP != "" {
- return *hostHTTP
- }
- if v := *httpAddr; strings.HasPrefix(v, ":") {
- return "localhost" + v
- } else {
- return v
- }
-}
-
-func serveProdTLS() error {
- const cacheDir = "/var/cache/autocert"
- if err := os.MkdirAll(cacheDir, 0700); err != nil {
- return err
- }
- m := autocert.Manager{
- Cache: autocert.DirCache(cacheDir),
- Prompt: autocert.AcceptTOS,
- HostPolicy: autocert.HostWhitelist("http2.golang.org"),
- }
- srv := &http.Server{
- TLSConfig: &tls.Config{
- GetCertificate: m.GetCertificate,
- },
- }
- http2.ConfigureServer(srv, &http2.Server{})
- ln, err := net.Listen("tcp", ":443")
- if err != nil {
- return err
- }
- return srv.Serve(tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, srv.TLSConfig))
-}
-
-type tcpKeepAliveListener struct {
- *net.TCPListener
-}
-
-func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
- tc, err := ln.AcceptTCP()
- if err != nil {
- return
- }
- tc.SetKeepAlive(true)
- tc.SetKeepAlivePeriod(3 * time.Minute)
- return tc, nil
-}
-
-func serveProd() error {
- errc := make(chan error, 2)
- go func() { errc <- http.ListenAndServe(":80", nil) }()
- go func() { errc <- serveProdTLS() }()
- return <-errc
-}
-
-const idleTimeout = 5 * time.Minute
-const activeTimeout = 10 * time.Minute
-
-// TODO: put this into the standard library and actually send
-// PING frames and GOAWAY, etc: golang.org/issue/14204
-func idleTimeoutHook() func(net.Conn, http.ConnState) {
- var mu sync.Mutex
- m := map[net.Conn]*time.Timer{}
- return func(c net.Conn, cs http.ConnState) {
- mu.Lock()
- defer mu.Unlock()
- if t, ok := m[c]; ok {
- delete(m, c)
- t.Stop()
- }
- var d time.Duration
- switch cs {
- case http.StateNew, http.StateIdle:
- d = idleTimeout
- case http.StateActive:
- d = activeTimeout
- default:
- return
- }
- m[c] = time.AfterFunc(d, func() {
- log.Printf("closing idle conn %v after %v", c.RemoteAddr(), d)
- go c.Close()
- })
- }
-}
-
-func main() {
- var srv http.Server
- flag.BoolVar(&http2.VerboseLogs, "verbose", false, "Verbose HTTP/2 debugging.")
- flag.Parse()
- srv.Addr = *httpsAddr
- srv.ConnState = idleTimeoutHook()
-
- registerHandlers()
-
- if *prod {
- *hostHTTP = "http2.golang.org"
- *hostHTTPS = "http2.golang.org"
- log.Fatal(serveProd())
- }
-
- url := "https://" + httpsHost() + "/"
- log.Printf("Listening on " + url)
- http2.ConfigureServer(&srv, &http2.Server{})
-
- if *httpAddr != "" {
- go func() {
- log.Printf("Listening on http://" + httpHost() + "/ (for unencrypted HTTP/1)")
- log.Fatal(http.ListenAndServe(*httpAddr, nil))
- }()
- }
-
- go func() {
- log.Fatal(srv.ListenAndServeTLS("server.crt", "server.key"))
- }()
- select {}
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/launch.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/launch.go
deleted file mode 100644
index df0866a..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/launch.go
+++ /dev/null
@@ -1,302 +0,0 @@
-// 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 ignore
-
-package main
-
-import (
- "bufio"
- "bytes"
- "encoding/json"
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "net/http"
- "os"
- "strings"
- "time"
-
- "golang.org/x/oauth2"
- "golang.org/x/oauth2/google"
- compute "google.golang.org/api/compute/v1"
-)
-
-var (
- proj = flag.String("project", "symbolic-datum-552", "name of Project")
- zone = flag.String("zone", "us-central1-a", "GCE zone")
- mach = flag.String("machinetype", "n1-standard-1", "Machine type")
- instName = flag.String("instance_name", "http2-demo", "Name of VM instance.")
- sshPub = flag.String("ssh_public_key", "", "ssh public key file to authorize. Can modify later in Google's web UI anyway.")
- staticIP = flag.String("static_ip", "130.211.116.44", "Static IP to use. If empty, automatic.")
-
- writeObject = flag.String("write_object", "", "If non-empty, a VM isn't created and the flag value is Google Cloud Storage bucket/object to write. The contents from stdin.")
- publicObject = flag.Bool("write_object_is_public", false, "Whether the object created by --write_object should be public.")
-)
-
-func readFile(v string) string {
- slurp, err := ioutil.ReadFile(v)
- if err != nil {
- log.Fatalf("Error reading %s: %v", v, err)
- }
- return strings.TrimSpace(string(slurp))
-}
-
-var config = &oauth2.Config{
- // The client-id and secret should be for an "Installed Application" when using
- // the CLI. Later we'll use a web application with a callback.
- ClientID: readFile("client-id.dat"),
- ClientSecret: readFile("client-secret.dat"),
- Endpoint: google.Endpoint,
- Scopes: []string{
- compute.DevstorageFullControlScope,
- compute.ComputeScope,
- "https://www.googleapis.com/auth/sqlservice",
- "https://www.googleapis.com/auth/sqlservice.admin",
- },
- RedirectURL: "urn:ietf:wg:oauth:2.0:oob",
-}
-
-const baseConfig = `#cloud-config
-coreos:
- units:
- - name: h2demo.service
- command: start
- content: |
- [Unit]
- Description=HTTP2 Demo
-
- [Service]
- ExecStartPre=/bin/bash -c 'mkdir -p /opt/bin && curl -s -o /opt/bin/h2demo http://storage.googleapis.com/http2-demo-server-tls/h2demo && chmod +x /opt/bin/h2demo'
- ExecStart=/opt/bin/h2demo --prod
- RestartSec=5s
- Restart=always
- Type=simple
-
- [Install]
- WantedBy=multi-user.target
-`
-
-func main() {
- flag.Parse()
- if *proj == "" {
- log.Fatalf("Missing --project flag")
- }
- prefix := "https://www.googleapis.com/compute/v1/projects/" + *proj
- machType := prefix + "/zones/" + *zone + "/machineTypes/" + *mach
-
- const tokenFileName = "token.dat"
- tokenFile := tokenCacheFile(tokenFileName)
- tokenSource := oauth2.ReuseTokenSource(nil, tokenFile)
- token, err := tokenSource.Token()
- if err != nil {
- if *writeObject != "" {
- log.Fatalf("Can't use --write_object without a valid token.dat file already cached.")
- }
- log.Printf("Error getting token from %s: %v", tokenFileName, err)
- log.Printf("Get auth code from %v", config.AuthCodeURL("my-state"))
- fmt.Print("\nEnter auth code: ")
- sc := bufio.NewScanner(os.Stdin)
- sc.Scan()
- authCode := strings.TrimSpace(sc.Text())
- token, err = config.Exchange(oauth2.NoContext, authCode)
- if err != nil {
- log.Fatalf("Error exchanging auth code for a token: %v", err)
- }
- if err := tokenFile.WriteToken(token); err != nil {
- log.Fatalf("Error writing to %s: %v", tokenFileName, err)
- }
- tokenSource = oauth2.ReuseTokenSource(token, nil)
- }
-
- oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource)
-
- if *writeObject != "" {
- writeCloudStorageObject(oauthClient)
- return
- }
-
- computeService, _ := compute.New(oauthClient)
-
- natIP := *staticIP
- if natIP == "" {
- // Try to find it by name.
- aggAddrList, err := computeService.Addresses.AggregatedList(*proj).Do()
- if err != nil {
- log.Fatal(err)
- }
- // http://godoc.org/code.google.com/p/google-api-go-client/compute/v1#AddressAggregatedList
- IPLoop:
- for _, asl := range aggAddrList.Items {
- for _, addr := range asl.Addresses {
- if addr.Name == *instName+"-ip" && addr.Status == "RESERVED" {
- natIP = addr.Address
- break IPLoop
- }
- }
- }
- }
-
- cloudConfig := baseConfig
- if *sshPub != "" {
- key := strings.TrimSpace(readFile(*sshPub))
- cloudConfig += fmt.Sprintf("\nssh_authorized_keys:\n - %s\n", key)
- }
- if os.Getenv("USER") == "bradfitz" {
- cloudConfig += fmt.Sprintf("\nssh_authorized_keys:\n - %s\n", "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAwks9dwWKlRC+73gRbvYtVg0vdCwDSuIlyt4z6xa/YU/jTDynM4R4W10hm2tPjy8iR1k8XhDv4/qdxe6m07NjG/By1tkmGpm1mGwho4Pr5kbAAy/Qg+NLCSdAYnnE00FQEcFOC15GFVMOW2AzDGKisReohwH9eIzHPzdYQNPRWXE= bradfitz@papag.bradfitz.com")
- }
- const maxCloudConfig = 32 << 10 // per compute API docs
- if len(cloudConfig) > maxCloudConfig {
- log.Fatalf("cloud config length of %d bytes is over %d byte limit", len(cloudConfig), maxCloudConfig)
- }
-
- instance := &compute.Instance{
- Name: *instName,
- Description: "Go Builder",
- MachineType: machType,
- Disks: []*compute.AttachedDisk{instanceDisk(computeService)},
- Tags: &compute.Tags{
- Items: []string{"http-server", "https-server"},
- },
- Metadata: &compute.Metadata{
- Items: []*compute.MetadataItems{
- {
- Key: "user-data",
- Value: &cloudConfig,
- },
- },
- },
- NetworkInterfaces: []*compute.NetworkInterface{
- {
- AccessConfigs: []*compute.AccessConfig{
- {
- Type: "ONE_TO_ONE_NAT",
- Name: "External NAT",
- NatIP: natIP,
- },
- },
- Network: prefix + "/global/networks/default",
- },
- },
- ServiceAccounts: []*compute.ServiceAccount{
- {
- Email: "default",
- Scopes: []string{
- compute.DevstorageFullControlScope,
- compute.ComputeScope,
- },
- },
- },
- }
-
- log.Printf("Creating instance...")
- op, err := computeService.Instances.Insert(*proj, *zone, instance).Do()
- if err != nil {
- log.Fatalf("Failed to create instance: %v", err)
- }
- opName := op.Name
- log.Printf("Created. Waiting on operation %v", opName)
-OpLoop:
- for {
- time.Sleep(2 * time.Second)
- op, err := computeService.ZoneOperations.Get(*proj, *zone, opName).Do()
- if err != nil {
- log.Fatalf("Failed to get op %s: %v", opName, err)
- }
- switch op.Status {
- case "PENDING", "RUNNING":
- log.Printf("Waiting on operation %v", opName)
- continue
- case "DONE":
- if op.Error != nil {
- for _, operr := range op.Error.Errors {
- log.Printf("Error: %+v", operr)
- }
- log.Fatalf("Failed to start.")
- }
- log.Printf("Success. %+v", op)
- break OpLoop
- default:
- log.Fatalf("Unknown status %q: %+v", op.Status, op)
- }
- }
-
- inst, err := computeService.Instances.Get(*proj, *zone, *instName).Do()
- if err != nil {
- log.Fatalf("Error getting instance after creation: %v", err)
- }
- ij, _ := json.MarshalIndent(inst, "", " ")
- log.Printf("Instance: %s", ij)
-}
-
-func instanceDisk(svc *compute.Service) *compute.AttachedDisk {
- const imageURL = "https://www.googleapis.com/compute/v1/projects/coreos-cloud/global/images/coreos-stable-444-5-0-v20141016"
- diskName := *instName + "-disk"
-
- return &compute.AttachedDisk{
- AutoDelete: true,
- Boot: true,
- Type: "PERSISTENT",
- InitializeParams: &compute.AttachedDiskInitializeParams{
- DiskName: diskName,
- SourceImage: imageURL,
- DiskSizeGb: 50,
- },
- }
-}
-
-func writeCloudStorageObject(httpClient *http.Client) {
- content := os.Stdin
- const maxSlurp = 1 << 20
- var buf bytes.Buffer
- n, err := io.CopyN(&buf, content, maxSlurp)
- if err != nil && err != io.EOF {
- log.Fatalf("Error reading from stdin: %v, %v", n, err)
- }
- contentType := http.DetectContentType(buf.Bytes())
-
- req, err := http.NewRequest("PUT", "https://storage.googleapis.com/"+*writeObject, io.MultiReader(&buf, content))
- if err != nil {
- log.Fatal(err)
- }
- req.Header.Set("x-goog-api-version", "2")
- if *publicObject {
- req.Header.Set("x-goog-acl", "public-read")
- }
- req.Header.Set("Content-Type", contentType)
- res, err := httpClient.Do(req)
- if err != nil {
- log.Fatal(err)
- }
- if res.StatusCode != 200 {
- res.Write(os.Stderr)
- log.Fatalf("Failed.")
- }
- log.Printf("Success.")
- os.Exit(0)
-}
-
-type tokenCacheFile string
-
-func (f tokenCacheFile) Token() (*oauth2.Token, error) {
- slurp, err := ioutil.ReadFile(string(f))
- if err != nil {
- return nil, err
- }
- t := new(oauth2.Token)
- if err := json.Unmarshal(slurp, t); err != nil {
- return nil, err
- }
- return t, nil
-}
-
-func (f tokenCacheFile) WriteToken(t *oauth2.Token) error {
- jt, err := json.Marshal(t)
- if err != nil {
- return err
- }
- return ioutil.WriteFile(string(f), jt, 0600)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/rootCA.key b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/rootCA.key
deleted file mode 100644
index a15a6ab..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/rootCA.key
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEowIBAAKCAQEAt5fAjp4fTcekWUTfzsp0kyih1OYbsGL0KX1eRbSSR8Od0+9Q
-62Hyny+GFwMTb4A/KU8mssoHvcceSAAbwfbxFK/+s51TobqUnORZrOoTZjkUygby
-XDSK99YBbcR1Pip8vwMTm4XKuLtCigeBBdjjAQdgUO28LENGlsMnmeYkJfODVGnV
-mr5Ltb9ANA8IKyTfsnHJ4iOCS/PlPbUj2q7YnoVLposUBMlgUb/CykX3mOoLb4yJ
-JQyA/iST6ZxiIEj36D4yWZ5lg7YJl+UiiBQHGCnPdGyipqV06ex0heYWcaiW8LWZ
-SUQ93jQ+WVCH8hT7DQO1dmsvUmXlq/JeAlwQ/QIDAQABAoIBAFFHV7JMAqPWnMYA
-nezY6J81v9+XN+7xABNWM2Q8uv4WdksbigGLTXR3/680Z2hXqJ7LMeC5XJACFT/e
-/Gr0vmpgOCygnCPfjGehGKpavtfksXV3edikUlnCXsOP1C//c1bFL+sMYmFCVgTx
-qYdDK8yKzXNGrKYT6q5YG7IglyRNV1rsQa8lM/5taFYiD1Ck/3tQi3YIq8Lcuser
-hrxsMABcQ6mi+EIvG6Xr4mfJug0dGJMHG4RG1UGFQn6RXrQq2+q53fC8ZbVUSi0j
-NQ918aKFzktwv+DouKU0ME4I9toks03gM860bAL7zCbKGmwR3hfgX/TqzVCWpG9E
-LDVfvekCgYEA8fk9N53jbBRmULUGEf4qWypcLGiZnNU0OeXWpbPV9aa3H0VDytA7
-8fCN2dPAVDPqlthMDdVe983NCNwp2Yo8ZimDgowyIAKhdC25s1kejuaiH9OAPj3c
-0f8KbriYX4n8zNHxFwK6Ae3pQ6EqOLJVCUsziUaZX9nyKY5aZlyX6xcCgYEAwjws
-K62PjC64U5wYddNLp+kNdJ4edx+a7qBb3mEgPvSFT2RO3/xafJyG8kQB30Mfstjd
-bRxyUV6N0vtX1zA7VQtRUAvfGCecpMo+VQZzcHXKzoRTnQ7eZg4Lmj5fQ9tOAKAo
-QCVBoSW/DI4PZL26CAMDcAba4Pa22ooLapoRIQsCgYA6pIfkkbxLNkpxpt2YwLtt
-Kr/590O7UaR9n6k8sW/aQBRDXNsILR1KDl2ifAIxpf9lnXgZJiwE7HiTfCAcW7c1
-nzwDCI0hWuHcMTS/NYsFYPnLsstyyjVZI3FY0h4DkYKV9Q9z3zJLQ2hz/nwoD3gy
-b2pHC7giFcTts1VPV4Nt8wKBgHeFn4ihHJweg76vZz3Z78w7VNRWGFklUalVdDK7
-gaQ7w2y/ROn/146mo0OhJaXFIFRlrpvdzVrU3GDf2YXJYDlM5ZRkObwbZADjksev
-WInzcgDy3KDg7WnPasRXbTfMU4t/AkW2p1QKbi3DnSVYuokDkbH2Beo45vxDxhKr
-C69RAoGBAIyo3+OJenoZmoNzNJl2WPW5MeBUzSh8T/bgyjFTdqFHF5WiYRD/lfHj
-x9Glyw2nutuT4hlOqHvKhgTYdDMsF2oQ72fe3v8Q5FU7FuKndNPEAyvKNXZaShVA
-hnlhv5DjXKb0wFWnt5PCCiQLtzG0yyHaITrrEme7FikkIcTxaX/Y
------END RSA PRIVATE KEY-----
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/rootCA.pem b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/rootCA.pem
deleted file mode 100644
index 3a323e7..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/rootCA.pem
+++ /dev/null
@@ -1,26 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIEWjCCA0KgAwIBAgIJALfRlWsI8YQHMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNV
-BAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEUMBIG
-A1UEChMLQnJhZGZpdHppbmMxEjAQBgNVBAMTCWxvY2FsaG9zdDEdMBsGCSqGSIb3
-DQEJARYOYnJhZEBkYW5nYS5jb20wHhcNMTQwNzE1MjA0NjA1WhcNMTcwNTA0MjA0
-NjA1WjB7MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBG
-cmFuY2lzY28xFDASBgNVBAoTC0JyYWRmaXR6aW5jMRIwEAYDVQQDEwlsb2NhbGhv
-c3QxHTAbBgkqhkiG9w0BCQEWDmJyYWRAZGFuZ2EuY29tMIIBIjANBgkqhkiG9w0B
-AQEFAAOCAQ8AMIIBCgKCAQEAt5fAjp4fTcekWUTfzsp0kyih1OYbsGL0KX1eRbSS
-R8Od0+9Q62Hyny+GFwMTb4A/KU8mssoHvcceSAAbwfbxFK/+s51TobqUnORZrOoT
-ZjkUygbyXDSK99YBbcR1Pip8vwMTm4XKuLtCigeBBdjjAQdgUO28LENGlsMnmeYk
-JfODVGnVmr5Ltb9ANA8IKyTfsnHJ4iOCS/PlPbUj2q7YnoVLposUBMlgUb/CykX3
-mOoLb4yJJQyA/iST6ZxiIEj36D4yWZ5lg7YJl+UiiBQHGCnPdGyipqV06ex0heYW
-caiW8LWZSUQ93jQ+WVCH8hT7DQO1dmsvUmXlq/JeAlwQ/QIDAQABo4HgMIHdMB0G
-A1UdDgQWBBRcAROthS4P4U7vTfjByC569R7E6DCBrQYDVR0jBIGlMIGigBRcAROt
-hS4P4U7vTfjByC569R7E6KF/pH0wezELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNB
-MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRQwEgYDVQQKEwtCcmFkZml0emluYzES
-MBAGA1UEAxMJbG9jYWxob3N0MR0wGwYJKoZIhvcNAQkBFg5icmFkQGRhbmdhLmNv
-bYIJALfRlWsI8YQHMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAG6h
-U9f9sNH0/6oBbGGy2EVU0UgITUQIrFWo9rFkrW5k/XkDjQm+3lzjT0iGR4IxE/Ao
-eU6sQhua7wrWeFEn47GL98lnCsJdD7oZNhFmQ95Tb/LnDUjs5Yj9brP0NWzXfYU4
-UK2ZnINJRcJpB8iRCaCxE8DdcUF0XqIEq6pA272snoLmiXLMvNl3kYEdm+je6voD
-58SNVEUsztzQyXmJEhCpwVI0A6QCjzXj+qvpmw3ZZHi8JwXei8ZZBLTSFBki8Z7n
-sH9BBH38/SzUmAN4QHSPy1gjqm00OAE8NaYDkh/bzE4d7mLGGMWp/WE3KPSu82HF
-kPe6XoSbiLm/kxk32T0=
------END CERTIFICATE-----
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/rootCA.srl b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/rootCA.srl
deleted file mode 100644
index 6db3891..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/rootCA.srl
+++ /dev/null
@@ -1 +0,0 @@
-E2CE26BF3285059C
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/server.crt b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/server.crt
deleted file mode 100644
index c59059b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/server.crt
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDPjCCAiYCCQDizia/MoUFnDANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJV
-UzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xFDASBgNVBAoT
-C0JyYWRmaXR6aW5jMRIwEAYDVQQDEwlsb2NhbGhvc3QxHTAbBgkqhkiG9w0BCQEW
-DmJyYWRAZGFuZ2EuY29tMB4XDTE0MDcxNTIwNTAyN1oXDTE1MTEyNzIwNTAyN1ow
-RzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMQswCQYDVQQHEwJTRjEeMBwGA1UE
-ChMVYnJhZGZpdHogaHR0cDIgc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEAs1Y9CyLFrdL8VQWN1WaifDqaZFnoqjHhCMlc1TfG2zA+InDifx2l
-gZD3o8FeNnAcfM2sPlk3+ZleOYw9P/CklFVDlvqmpCv9ss/BEp/dDaWvy1LmJ4c2
-dbQJfmTxn7CV1H3TsVJvKdwFmdoABb41NoBp6+NNO7OtDyhbIMiCI0pL3Nefb3HL
-A7hIMo3DYbORTtJLTIH9W8YKrEWL0lwHLrYFx/UdutZnv+HjdmO6vCN4na55mjws
-/vjKQUmc7xeY7Xe20xDEG2oDKVkL2eD7FfyrYMS3rO1ExP2KSqlXYG/1S9I/fz88
-F0GK7HX55b5WjZCl2J3ERVdnv/0MQv+sYQIDAQABMA0GCSqGSIb3DQEBBQUAA4IB
-AQC0zL+n/YpRZOdulSu9tS8FxrstXqGWoxfe+vIUgqfMZ5+0MkjJ/vW0FqlLDl2R
-rn4XaR3e7FmWkwdDVbq/UB6lPmoAaFkCgh9/5oapMaclNVNnfF3fjCJfRr+qj/iD
-EmJStTIN0ZuUjAlpiACmfnpEU55PafT5Zx+i1yE4FGjw8bJpFoyD4Hnm54nGjX19
-KeCuvcYFUPnBm3lcL0FalF2AjqV02WTHYNQk7YF/oeO7NKBoEgvGvKG3x+xaOeBI
-dwvdq175ZsGul30h+QjrRlXhH/twcuaT3GSdoysDl9cCYE8f1Mk8PD6gan3uBCJU
-90p6/CbU71bGbfpM2PHot2fm
------END CERTIFICATE-----
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/server.key b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/server.key
deleted file mode 100644
index f329c14..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/server.key
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEowIBAAKCAQEAs1Y9CyLFrdL8VQWN1WaifDqaZFnoqjHhCMlc1TfG2zA+InDi
-fx2lgZD3o8FeNnAcfM2sPlk3+ZleOYw9P/CklFVDlvqmpCv9ss/BEp/dDaWvy1Lm
-J4c2dbQJfmTxn7CV1H3TsVJvKdwFmdoABb41NoBp6+NNO7OtDyhbIMiCI0pL3Nef
-b3HLA7hIMo3DYbORTtJLTIH9W8YKrEWL0lwHLrYFx/UdutZnv+HjdmO6vCN4na55
-mjws/vjKQUmc7xeY7Xe20xDEG2oDKVkL2eD7FfyrYMS3rO1ExP2KSqlXYG/1S9I/
-fz88F0GK7HX55b5WjZCl2J3ERVdnv/0MQv+sYQIDAQABAoIBADQ2spUwbY+bcz4p
-3M66ECrNQTBggP40gYl2XyHxGGOu2xhZ94f9ELf1hjRWU2DUKWco1rJcdZClV6q3
-qwmXvcM2Q/SMS8JW0ImkNVl/0/NqPxGatEnj8zY30d/L8hGFb0orzFu/XYA5gCP4
-NbN2WrXgk3ZLeqwcNxHHtSiJWGJ/fPyeDWAu/apy75u9Xf2GlzBZmV6HYD9EfK80
-LTlI60f5FO487CrJnboL7ovPJrIHn+k05xRQqwma4orpz932rTXnTjs9Lg6KtbQN
-a7PrqfAntIISgr11a66Mng3IYH1lYqJsWJJwX/xHT4WLEy0EH4/0+PfYemJekz2+
-Co62drECgYEA6O9zVJZXrLSDsIi54cfxA7nEZWm5CAtkYWeAHa4EJ+IlZ7gIf9sL
-W8oFcEfFGpvwVqWZ+AsQ70dsjXAv3zXaG0tmg9FtqWp7pzRSMPidifZcQwWkKeTO
-gJnFmnVyed8h6GfjTEu4gxo1/S5U0V+mYSha01z5NTnN6ltKx1Or3b0CgYEAxRgm
-S30nZxnyg/V7ys61AZhst1DG2tkZXEMcA7dYhabMoXPJAP/EfhlWwpWYYUs/u0gS
-Wwmf5IivX5TlYScgmkvb/NYz0u4ZmOXkLTnLPtdKKFXhjXJcHjUP67jYmOxNlJLp
-V4vLRnFxTpffAV+OszzRxsXX6fvruwZBANYJeXUCgYBVouLFsFgfWGYp2rpr9XP4
-KK25kvrBqF6JKOIDB1zjxNJ3pUMKrl8oqccCFoCyXa4oTM2kUX0yWxHfleUjrMq4
-yimwQKiOZmV7fVLSSjSw6e/VfBd0h3gb82ygcplZkN0IclkwTY5SNKqwn/3y07V5
-drqdhkrgdJXtmQ6O5YYECQKBgATERcDToQ1USlI4sKrB/wyv1AlG8dg/IebiVJ4e
-ZAyvcQmClFzq0qS+FiQUnB/WQw9TeeYrwGs1hxBHuJh16srwhLyDrbMvQP06qh8R
-48F8UXXSRec22dV9MQphaROhu2qZdv1AC0WD3tqov6L33aqmEOi+xi8JgbT/PLk5
-c/c1AoGBAI1A/02ryksW6/wc7/6SP2M2rTy4m1sD/GnrTc67EHnRcVBdKO6qH2RY
-nqC8YcveC2ZghgPTDsA3VGuzuBXpwY6wTyV99q6jxQJ6/xcrD9/NUG6Uwv/xfCxl
-IJLeBYEqQundSSny3VtaAUK8Ul1nxpTvVRNwtcyWTo8RHAAyNPWd
------END RSA PRIVATE KEY-----
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2i/README.md b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2i/README.md
deleted file mode 100644
index fb5c5ef..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2i/README.md
+++ /dev/null
@@ -1,97 +0,0 @@
-# h2i
-
-**h2i** is an interactive HTTP/2 ("h2") console debugger. Miss the good ol'
-days of telnetting to your HTTP/1.n servers? We're bringing you
-back.
-
-Features:
-- send raw HTTP/2 frames
- - PING
- - SETTINGS
- - HEADERS
- - etc
-- type in HTTP/1.n and have it auto-HPACK/frame-ify it for HTTP/2
-- pretty print all received HTTP/2 frames from the peer (including HPACK decoding)
-- tab completion of commands, options
-
-Not yet features, but soon:
-- unnecessary CONTINUATION frames on short boundaries, to test peer implementations
-- request bodies (DATA frames)
-- send invalid frames for testing server implementations (supported by underlying Framer)
-
-Later:
-- act like a server
-
-## Installation
-
-```
-$ go get golang.org/x/net/http2/h2i
-$ h2i <host>
-```
-
-## Demo
-
-```
-$ h2i
-Usage: h2i <hostname>
-
- -insecure
- Whether to skip TLS cert validation
- -nextproto string
- Comma-separated list of NPN/ALPN protocol names to negotiate. (default "h2,h2-14")
-
-$ h2i google.com
-Connecting to google.com:443 ...
-Connected to 74.125.224.41:443
-Negotiated protocol "h2-14"
-[FrameHeader SETTINGS len=18]
- [MAX_CONCURRENT_STREAMS = 100]
- [INITIAL_WINDOW_SIZE = 1048576]
- [MAX_FRAME_SIZE = 16384]
-[FrameHeader WINDOW_UPDATE len=4]
- Window-Increment = 983041
-
-h2i> PING h2iSayHI
-[FrameHeader PING flags=ACK len=8]
- Data = "h2iSayHI"
-h2i> headers
-(as HTTP/1.1)> GET / HTTP/1.1
-(as HTTP/1.1)> Host: ip.appspot.com
-(as HTTP/1.1)> User-Agent: h2i/brad-n-blake
-(as HTTP/1.1)>
-Opening Stream-ID 1:
- :authority = ip.appspot.com
- :method = GET
- :path = /
- :scheme = https
- user-agent = h2i/brad-n-blake
-[FrameHeader HEADERS flags=END_HEADERS stream=1 len=77]
- :status = "200"
- alternate-protocol = "443:quic,p=1"
- content-length = "15"
- content-type = "text/html"
- date = "Fri, 01 May 2015 23:06:56 GMT"
- server = "Google Frontend"
-[FrameHeader DATA flags=END_STREAM stream=1 len=15]
- "173.164.155.78\n"
-[FrameHeader PING len=8]
- Data = "\x00\x00\x00\x00\x00\x00\x00\x00"
-h2i> ping
-[FrameHeader PING flags=ACK len=8]
- Data = "h2i_ping"
-h2i> ping
-[FrameHeader PING flags=ACK len=8]
- Data = "h2i_ping"
-h2i> ping
-[FrameHeader GOAWAY len=22]
- Last-Stream-ID = 1; Error-Code = PROTOCOL_ERROR (1)
-
-ReadFrame: EOF
-```
-
-## Status
-
-Quick few hour hack. So much yet to do. Feel free to file issues for
-bugs or wishlist items, but [@bmizerany](https://github.com/bmizerany/)
-and I aren't yet accepting pull requests until things settle down.
-
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2i/h2i.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2i/h2i.go
deleted file mode 100644
index 76c7787..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2i/h2i.go
+++ /dev/null
@@ -1,509 +0,0 @@
-// 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.
-
-// +build !plan9,!solaris
-
-/*
-The h2i command is an interactive HTTP/2 console.
-
-Usage:
- $ h2i [flags] <hostname>
-
-Interactive commands in the console: (all parts case-insensitive)
-
- ping [data]
- settings ack
- settings FOO=n BAR=z
- headers (open a new stream by typing HTTP/1.1)
-*/
-package main
-
-import (
- "bufio"
- "bytes"
- "crypto/tls"
- "errors"
- "flag"
- "fmt"
- "io"
- "log"
- "net"
- "net/http"
- "os"
- "regexp"
- "strconv"
- "strings"
-
- "golang.org/x/crypto/ssh/terminal"
- "golang.org/x/net/http2"
- "golang.org/x/net/http2/hpack"
-)
-
-// Flags
-var (
- flagNextProto = flag.String("nextproto", "h2,h2-14", "Comma-separated list of NPN/ALPN protocol names to negotiate.")
- flagInsecure = flag.Bool("insecure", false, "Whether to skip TLS cert validation")
- flagSettings = flag.String("settings", "empty", "comma-separated list of KEY=value settings for the initial SETTINGS frame. The magic value 'empty' sends an empty initial settings frame, and the magic value 'omit' causes no initial settings frame to be sent.")
-)
-
-type command struct {
- run func(*h2i, []string) error // required
-
- // complete optionally specifies tokens (case-insensitive) which are
- // valid for this subcommand.
- complete func() []string
-}
-
-var commands = map[string]command{
- "ping": {run: (*h2i).cmdPing},
- "settings": {
- run: (*h2i).cmdSettings,
- complete: func() []string {
- return []string{
- "ACK",
- http2.SettingHeaderTableSize.String(),
- http2.SettingEnablePush.String(),
- http2.SettingMaxConcurrentStreams.String(),
- http2.SettingInitialWindowSize.String(),
- http2.SettingMaxFrameSize.String(),
- http2.SettingMaxHeaderListSize.String(),
- }
- },
- },
- "quit": {run: (*h2i).cmdQuit},
- "headers": {run: (*h2i).cmdHeaders},
-}
-
-func usage() {
- fmt.Fprintf(os.Stderr, "Usage: h2i <hostname>\n\n")
- flag.PrintDefaults()
-}
-
-// withPort adds ":443" if another port isn't already present.
-func withPort(host string) string {
- if _, _, err := net.SplitHostPort(host); err != nil {
- return net.JoinHostPort(host, "443")
- }
- return host
-}
-
-// withoutPort strips the port from addr if present.
-func withoutPort(addr string) string {
- if h, _, err := net.SplitHostPort(addr); err == nil {
- return h
- }
- return addr
-}
-
-// h2i is the app's state.
-type h2i struct {
- host string
- tc *tls.Conn
- framer *http2.Framer
- term *terminal.Terminal
-
- // owned by the command loop:
- streamID uint32
- hbuf bytes.Buffer
- henc *hpack.Encoder
-
- // owned by the readFrames loop:
- peerSetting map[http2.SettingID]uint32
- hdec *hpack.Decoder
-}
-
-func main() {
- flag.Usage = usage
- flag.Parse()
- if flag.NArg() != 1 {
- usage()
- os.Exit(2)
- }
- log.SetFlags(0)
-
- host := flag.Arg(0)
- app := &h2i{
- host: host,
- peerSetting: make(map[http2.SettingID]uint32),
- }
- app.henc = hpack.NewEncoder(&app.hbuf)
-
- if err := app.Main(); err != nil {
- if app.term != nil {
- app.logf("%v\n", err)
- } else {
- fmt.Fprintf(os.Stderr, "%v\n", err)
- }
- os.Exit(1)
- }
- fmt.Fprintf(os.Stdout, "\n")
-}
-
-func (app *h2i) Main() error {
- cfg := &tls.Config{
- ServerName: withoutPort(app.host),
- NextProtos: strings.Split(*flagNextProto, ","),
- InsecureSkipVerify: *flagInsecure,
- }
-
- hostAndPort := withPort(app.host)
- log.Printf("Connecting to %s ...", hostAndPort)
- tc, err := tls.Dial("tcp", hostAndPort, cfg)
- if err != nil {
- return fmt.Errorf("Error dialing %s: %v", withPort(app.host), err)
- }
- log.Printf("Connected to %v", tc.RemoteAddr())
- defer tc.Close()
-
- if err := tc.Handshake(); err != nil {
- return fmt.Errorf("TLS handshake: %v", err)
- }
- if !*flagInsecure {
- if err := tc.VerifyHostname(app.host); err != nil {
- return fmt.Errorf("VerifyHostname: %v", err)
- }
- }
- state := tc.ConnectionState()
- log.Printf("Negotiated protocol %q", state.NegotiatedProtocol)
- if !state.NegotiatedProtocolIsMutual || state.NegotiatedProtocol == "" {
- return fmt.Errorf("Could not negotiate protocol mutually")
- }
-
- if _, err := io.WriteString(tc, http2.ClientPreface); err != nil {
- return err
- }
-
- app.framer = http2.NewFramer(tc, tc)
-
- oldState, err := terminal.MakeRaw(int(os.Stdin.Fd()))
- if err != nil {
- return err
- }
- defer terminal.Restore(0, oldState)
-
- var screen = struct {
- io.Reader
- io.Writer
- }{os.Stdin, os.Stdout}
-
- app.term = terminal.NewTerminal(screen, "h2i> ")
- lastWord := regexp.MustCompile(`.+\W(\w+)$`)
- app.term.AutoCompleteCallback = func(line string, pos int, key rune) (newLine string, newPos int, ok bool) {
- if key != '\t' {
- return
- }
- if pos != len(line) {
- // TODO: we're being lazy for now, only supporting tab completion at the end.
- return
- }
- // Auto-complete for the command itself.
- if !strings.Contains(line, " ") {
- var name string
- name, _, ok = lookupCommand(line)
- if !ok {
- return
- }
- return name, len(name), true
- }
- _, c, ok := lookupCommand(line[:strings.IndexByte(line, ' ')])
- if !ok || c.complete == nil {
- return
- }
- if strings.HasSuffix(line, " ") {
- app.logf("%s", strings.Join(c.complete(), " "))
- return line, pos, true
- }
- m := lastWord.FindStringSubmatch(line)
- if m == nil {
- return line, len(line), true
- }
- soFar := m[1]
- var match []string
- for _, cand := range c.complete() {
- if len(soFar) > len(cand) || !strings.EqualFold(cand[:len(soFar)], soFar) {
- continue
- }
- match = append(match, cand)
- }
- if len(match) == 0 {
- return
- }
- if len(match) > 1 {
- // TODO: auto-complete any common prefix
- app.logf("%s", strings.Join(match, " "))
- return line, pos, true
- }
- newLine = line[:len(line)-len(soFar)] + match[0]
- return newLine, len(newLine), true
-
- }
-
- errc := make(chan error, 2)
- go func() { errc <- app.readFrames() }()
- go func() { errc <- app.readConsole() }()
- return <-errc
-}
-
-func (app *h2i) logf(format string, args ...interface{}) {
- fmt.Fprintf(app.term, format+"\r\n", args...)
-}
-
-func (app *h2i) readConsole() error {
- if s := *flagSettings; s != "omit" {
- var args []string
- if s != "empty" {
- args = strings.Split(s, ",")
- }
- _, c, ok := lookupCommand("settings")
- if !ok {
- panic("settings command not found")
- }
- c.run(app, args)
- }
-
- for {
- line, err := app.term.ReadLine()
- if err == io.EOF {
- return nil
- }
- if err != nil {
- return fmt.Errorf("terminal.ReadLine: %v", err)
- }
- f := strings.Fields(line)
- if len(f) == 0 {
- continue
- }
- cmd, args := f[0], f[1:]
- if _, c, ok := lookupCommand(cmd); ok {
- err = c.run(app, args)
- } else {
- app.logf("Unknown command %q", line)
- }
- if err == errExitApp {
- return nil
- }
- if err != nil {
- return err
- }
- }
-}
-
-func lookupCommand(prefix string) (name string, c command, ok bool) {
- prefix = strings.ToLower(prefix)
- if c, ok = commands[prefix]; ok {
- return prefix, c, ok
- }
-
- for full, candidate := range commands {
- if strings.HasPrefix(full, prefix) {
- if c.run != nil {
- return "", command{}, false // ambiguous
- }
- c = candidate
- name = full
- }
- }
- return name, c, c.run != nil
-}
-
-var errExitApp = errors.New("internal sentinel error value to quit the console reading loop")
-
-func (a *h2i) cmdQuit(args []string) error {
- if len(args) > 0 {
- a.logf("the QUIT command takes no argument")
- return nil
- }
- return errExitApp
-}
-
-func (a *h2i) cmdSettings(args []string) error {
- if len(args) == 1 && strings.EqualFold(args[0], "ACK") {
- return a.framer.WriteSettingsAck()
- }
- var settings []http2.Setting
- for _, arg := range args {
- if strings.EqualFold(arg, "ACK") {
- a.logf("Error: ACK must be only argument with the SETTINGS command")
- return nil
- }
- eq := strings.Index(arg, "=")
- if eq == -1 {
- a.logf("Error: invalid argument %q (expected SETTING_NAME=nnnn)", arg)
- return nil
- }
- sid, ok := settingByName(arg[:eq])
- if !ok {
- a.logf("Error: unknown setting name %q", arg[:eq])
- return nil
- }
- val, err := strconv.ParseUint(arg[eq+1:], 10, 32)
- if err != nil {
- a.logf("Error: invalid argument %q (expected SETTING_NAME=nnnn)", arg)
- return nil
- }
- settings = append(settings, http2.Setting{
- ID: sid,
- Val: uint32(val),
- })
- }
- a.logf("Sending: %v", settings)
- return a.framer.WriteSettings(settings...)
-}
-
-func settingByName(name string) (http2.SettingID, bool) {
- for _, sid := range [...]http2.SettingID{
- http2.SettingHeaderTableSize,
- http2.SettingEnablePush,
- http2.SettingMaxConcurrentStreams,
- http2.SettingInitialWindowSize,
- http2.SettingMaxFrameSize,
- http2.SettingMaxHeaderListSize,
- } {
- if strings.EqualFold(sid.String(), name) {
- return sid, true
- }
- }
- return 0, false
-}
-
-func (app *h2i) cmdPing(args []string) error {
- if len(args) > 1 {
- app.logf("invalid PING usage: only accepts 0 or 1 args")
- return nil // nil means don't end the program
- }
- var data [8]byte
- if len(args) == 1 {
- copy(data[:], args[0])
- } else {
- copy(data[:], "h2i_ping")
- }
- return app.framer.WritePing(false, data)
-}
-
-func (app *h2i) cmdHeaders(args []string) error {
- if len(args) > 0 {
- app.logf("Error: HEADERS doesn't yet take arguments.")
- // TODO: flags for restricting window size, to force CONTINUATION
- // frames.
- return nil
- }
- var h1req bytes.Buffer
- app.term.SetPrompt("(as HTTP/1.1)> ")
- defer app.term.SetPrompt("h2i> ")
- for {
- line, err := app.term.ReadLine()
- if err != nil {
- return err
- }
- h1req.WriteString(line)
- h1req.WriteString("\r\n")
- if line == "" {
- break
- }
- }
- req, err := http.ReadRequest(bufio.NewReader(&h1req))
- if err != nil {
- app.logf("Invalid HTTP/1.1 request: %v", err)
- return nil
- }
- if app.streamID == 0 {
- app.streamID = 1
- } else {
- app.streamID += 2
- }
- app.logf("Opening Stream-ID %d:", app.streamID)
- hbf := app.encodeHeaders(req)
- if len(hbf) > 16<<10 {
- app.logf("TODO: h2i doesn't yet write CONTINUATION frames. Copy it from transport.go")
- return nil
- }
- return app.framer.WriteHeaders(http2.HeadersFrameParam{
- StreamID: app.streamID,
- BlockFragment: hbf,
- EndStream: req.Method == "GET" || req.Method == "HEAD", // good enough for now
- EndHeaders: true, // for now
- })
-}
-
-func (app *h2i) readFrames() error {
- for {
- f, err := app.framer.ReadFrame()
- if err != nil {
- return fmt.Errorf("ReadFrame: %v", err)
- }
- app.logf("%v", f)
- switch f := f.(type) {
- case *http2.PingFrame:
- app.logf(" Data = %q", f.Data)
- case *http2.SettingsFrame:
- f.ForeachSetting(func(s http2.Setting) error {
- app.logf(" %v", s)
- app.peerSetting[s.ID] = s.Val
- return nil
- })
- case *http2.WindowUpdateFrame:
- app.logf(" Window-Increment = %v", f.Increment)
- case *http2.GoAwayFrame:
- app.logf(" Last-Stream-ID = %d; Error-Code = %v (%d)", f.LastStreamID, f.ErrCode, f.ErrCode)
- case *http2.DataFrame:
- app.logf(" %q", f.Data())
- case *http2.HeadersFrame:
- if f.HasPriority() {
- app.logf(" PRIORITY = %v", f.Priority)
- }
- if app.hdec == nil {
- // TODO: if the user uses h2i to send a SETTINGS frame advertising
- // something larger, we'll need to respect SETTINGS_HEADER_TABLE_SIZE
- // and stuff here instead of using the 4k default. But for now:
- tableSize := uint32(4 << 10)
- app.hdec = hpack.NewDecoder(tableSize, app.onNewHeaderField)
- }
- app.hdec.Write(f.HeaderBlockFragment())
- }
- }
-}
-
-// called from readLoop
-func (app *h2i) onNewHeaderField(f hpack.HeaderField) {
- if f.Sensitive {
- app.logf(" %s = %q (SENSITIVE)", f.Name, f.Value)
- }
- app.logf(" %s = %q", f.Name, f.Value)
-}
-
-func (app *h2i) encodeHeaders(req *http.Request) []byte {
- app.hbuf.Reset()
-
- // TODO(bradfitz): figure out :authority-vs-Host stuff between http2 and Go
- host := req.Host
- if host == "" {
- host = req.URL.Host
- }
-
- path := req.RequestURI
- if path == "" {
- path = "/"
- }
-
- app.writeHeader(":authority", host) // probably not right for all sites
- app.writeHeader(":method", req.Method)
- app.writeHeader(":path", path)
- app.writeHeader(":scheme", "https")
-
- for k, vv := range req.Header {
- lowKey := strings.ToLower(k)
- if lowKey == "host" {
- continue
- }
- for _, v := range vv {
- app.writeHeader(lowKey, v)
- }
- }
- return app.hbuf.Bytes()
-}
-
-func (app *h2i) writeHeader(name, value string) {
- app.henc.WriteField(hpack.HeaderField{Name: name, Value: value})
- app.logf(" %s = %s", name, value)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/headermap.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/headermap.go
deleted file mode 100644
index c2805f6..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/headermap.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// 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 http2
-
-import (
- "net/http"
- "strings"
-)
-
-var (
- commonLowerHeader = map[string]string{} // Go-Canonical-Case -> lower-case
- commonCanonHeader = map[string]string{} // lower-case -> Go-Canonical-Case
-)
-
-func init() {
- for _, v := range []string{
- "accept",
- "accept-charset",
- "accept-encoding",
- "accept-language",
- "accept-ranges",
- "age",
- "access-control-allow-origin",
- "allow",
- "authorization",
- "cache-control",
- "content-disposition",
- "content-encoding",
- "content-language",
- "content-length",
- "content-location",
- "content-range",
- "content-type",
- "cookie",
- "date",
- "etag",
- "expect",
- "expires",
- "from",
- "host",
- "if-match",
- "if-modified-since",
- "if-none-match",
- "if-unmodified-since",
- "last-modified",
- "link",
- "location",
- "max-forwards",
- "proxy-authenticate",
- "proxy-authorization",
- "range",
- "referer",
- "refresh",
- "retry-after",
- "server",
- "set-cookie",
- "strict-transport-security",
- "trailer",
- "transfer-encoding",
- "user-agent",
- "vary",
- "via",
- "www-authenticate",
- } {
- chk := http.CanonicalHeaderKey(v)
- commonLowerHeader[chk] = v
- commonCanonHeader[v] = chk
- }
-}
-
-func lowerHeader(v string) string {
- if s, ok := commonLowerHeader[v]; ok {
- return s
- }
- return strings.ToLower(v)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/encode.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/encode.go
deleted file mode 100644
index 6b3b9f8..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/encode.go
+++ /dev/null
@@ -1,251 +0,0 @@
-// 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 hpack
-
-import (
- "io"
-)
-
-const (
- uint32Max = ^uint32(0)
- initialHeaderTableSize = 4096
-)
-
-type Encoder struct {
- dynTab dynamicTable
- // minSize is the minimum table size set by
- // SetMaxDynamicTableSize after the previous Header Table Size
- // Update.
- minSize uint32
- // maxSizeLimit is the maximum table size this encoder
- // supports. This will protect the encoder from too large
- // size.
- maxSizeLimit uint32
- // tableSizeUpdate indicates whether "Header Table Size
- // Update" is required.
- tableSizeUpdate bool
- w io.Writer
- buf []byte
-}
-
-// NewEncoder returns a new Encoder which performs HPACK encoding. An
-// encoded data is written to w.
-func NewEncoder(w io.Writer) *Encoder {
- e := &Encoder{
- minSize: uint32Max,
- maxSizeLimit: initialHeaderTableSize,
- tableSizeUpdate: false,
- w: w,
- }
- e.dynTab.setMaxSize(initialHeaderTableSize)
- return e
-}
-
-// WriteField encodes f into a single Write to e's underlying Writer.
-// This function may also produce bytes for "Header Table Size Update"
-// if necessary. If produced, it is done before encoding f.
-func (e *Encoder) WriteField(f HeaderField) error {
- e.buf = e.buf[:0]
-
- if e.tableSizeUpdate {
- e.tableSizeUpdate = false
- if e.minSize < e.dynTab.maxSize {
- e.buf = appendTableSize(e.buf, e.minSize)
- }
- e.minSize = uint32Max
- e.buf = appendTableSize(e.buf, e.dynTab.maxSize)
- }
-
- idx, nameValueMatch := e.searchTable(f)
- if nameValueMatch {
- e.buf = appendIndexed(e.buf, idx)
- } else {
- indexing := e.shouldIndex(f)
- if indexing {
- e.dynTab.add(f)
- }
-
- if idx == 0 {
- e.buf = appendNewName(e.buf, f, indexing)
- } else {
- e.buf = appendIndexedName(e.buf, f, idx, indexing)
- }
- }
- n, err := e.w.Write(e.buf)
- if err == nil && n != len(e.buf) {
- err = io.ErrShortWrite
- }
- return err
-}
-
-// searchTable searches f in both stable and dynamic header tables.
-// The static header table is searched first. Only when there is no
-// exact match for both name and value, the dynamic header table is
-// then searched. If there is no match, i is 0. If both name and value
-// match, i is the matched index and nameValueMatch becomes true. If
-// only name matches, i points to that index and nameValueMatch
-// becomes false.
-func (e *Encoder) searchTable(f HeaderField) (i uint64, nameValueMatch bool) {
- for idx, hf := range staticTable {
- if !constantTimeStringCompare(hf.Name, f.Name) {
- continue
- }
- if i == 0 {
- i = uint64(idx + 1)
- }
- if f.Sensitive {
- continue
- }
- if !constantTimeStringCompare(hf.Value, f.Value) {
- continue
- }
- i = uint64(idx + 1)
- nameValueMatch = true
- return
- }
-
- j, nameValueMatch := e.dynTab.search(f)
- if nameValueMatch || (i == 0 && j != 0) {
- i = j + uint64(len(staticTable))
- }
- return
-}
-
-// SetMaxDynamicTableSize changes the dynamic header table size to v.
-// The actual size is bounded by the value passed to
-// SetMaxDynamicTableSizeLimit.
-func (e *Encoder) SetMaxDynamicTableSize(v uint32) {
- if v > e.maxSizeLimit {
- v = e.maxSizeLimit
- }
- if v < e.minSize {
- e.minSize = v
- }
- e.tableSizeUpdate = true
- e.dynTab.setMaxSize(v)
-}
-
-// SetMaxDynamicTableSizeLimit changes the maximum value that can be
-// specified in SetMaxDynamicTableSize to v. By default, it is set to
-// 4096, which is the same size of the default dynamic header table
-// size described in HPACK specification. If the current maximum
-// dynamic header table size is strictly greater than v, "Header Table
-// Size Update" will be done in the next WriteField call and the
-// maximum dynamic header table size is truncated to v.
-func (e *Encoder) SetMaxDynamicTableSizeLimit(v uint32) {
- e.maxSizeLimit = v
- if e.dynTab.maxSize > v {
- e.tableSizeUpdate = true
- e.dynTab.setMaxSize(v)
- }
-}
-
-// shouldIndex reports whether f should be indexed.
-func (e *Encoder) shouldIndex(f HeaderField) bool {
- return !f.Sensitive && f.Size() <= e.dynTab.maxSize
-}
-
-// appendIndexed appends index i, as encoded in "Indexed Header Field"
-// representation, to dst and returns the extended buffer.
-func appendIndexed(dst []byte, i uint64) []byte {
- first := len(dst)
- dst = appendVarInt(dst, 7, i)
- dst[first] |= 0x80
- return dst
-}
-
-// appendNewName appends f, as encoded in one of "Literal Header field
-// - New Name" representation variants, to dst and returns the
-// extended buffer.
-//
-// If f.Sensitive is true, "Never Indexed" representation is used. If
-// f.Sensitive is false and indexing is true, "Inremental Indexing"
-// representation is used.
-func appendNewName(dst []byte, f HeaderField, indexing bool) []byte {
- dst = append(dst, encodeTypeByte(indexing, f.Sensitive))
- dst = appendHpackString(dst, f.Name)
- return appendHpackString(dst, f.Value)
-}
-
-// appendIndexedName appends f and index i referring indexed name
-// entry, as encoded in one of "Literal Header field - Indexed Name"
-// representation variants, to dst and returns the extended buffer.
-//
-// If f.Sensitive is true, "Never Indexed" representation is used. If
-// f.Sensitive is false and indexing is true, "Incremental Indexing"
-// representation is used.
-func appendIndexedName(dst []byte, f HeaderField, i uint64, indexing bool) []byte {
- first := len(dst)
- var n byte
- if indexing {
- n = 6
- } else {
- n = 4
- }
- dst = appendVarInt(dst, n, i)
- dst[first] |= encodeTypeByte(indexing, f.Sensitive)
- return appendHpackString(dst, f.Value)
-}
-
-// appendTableSize appends v, as encoded in "Header Table Size Update"
-// representation, to dst and returns the extended buffer.
-func appendTableSize(dst []byte, v uint32) []byte {
- first := len(dst)
- dst = appendVarInt(dst, 5, uint64(v))
- dst[first] |= 0x20
- return dst
-}
-
-// appendVarInt appends i, as encoded in variable integer form using n
-// bit prefix, to dst and returns the extended buffer.
-//
-// See
-// http://http2.github.io/http2-spec/compression.html#integer.representation
-func appendVarInt(dst []byte, n byte, i uint64) []byte {
- k := uint64((1 << n) - 1)
- if i < k {
- return append(dst, byte(i))
- }
- dst = append(dst, byte(k))
- i -= k
- for ; i >= 128; i >>= 7 {
- dst = append(dst, byte(0x80|(i&0x7f)))
- }
- return append(dst, byte(i))
-}
-
-// appendHpackString appends s, as encoded in "String Literal"
-// representation, to dst and returns the the extended buffer.
-//
-// s will be encoded in Huffman codes only when it produces strictly
-// shorter byte string.
-func appendHpackString(dst []byte, s string) []byte {
- huffmanLength := HuffmanEncodeLength(s)
- if huffmanLength < uint64(len(s)) {
- first := len(dst)
- dst = appendVarInt(dst, 7, huffmanLength)
- dst = AppendHuffmanString(dst, s)
- dst[first] |= 0x80
- } else {
- dst = appendVarInt(dst, 7, uint64(len(s)))
- dst = append(dst, s...)
- }
- return dst
-}
-
-// encodeTypeByte returns type byte. If sensitive is true, type byte
-// for "Never Indexed" representation is returned. If sensitive is
-// false and indexing is true, type byte for "Incremental Indexing"
-// representation is returned. Otherwise, type byte for "Without
-// Indexing" is returned.
-func encodeTypeByte(indexing, sensitive bool) byte {
- if sensitive {
- return 0x10
- }
- if indexing {
- return 0x40
- }
- return 0
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/encode_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/encode_test.go
deleted file mode 100644
index 92286f3..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/encode_test.go
+++ /dev/null
@@ -1,330 +0,0 @@
-// 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 hpack
-
-import (
- "bytes"
- "encoding/hex"
- "reflect"
- "strings"
- "testing"
-)
-
-func TestEncoderTableSizeUpdate(t *testing.T) {
- tests := []struct {
- size1, size2 uint32
- wantHex string
- }{
- // Should emit 2 table size updates (2048 and 4096)
- {2048, 4096, "3fe10f 3fe11f 82"},
-
- // Should emit 1 table size update (2048)
- {16384, 2048, "3fe10f 82"},
- }
- for _, tt := range tests {
- var buf bytes.Buffer
- e := NewEncoder(&buf)
- e.SetMaxDynamicTableSize(tt.size1)
- e.SetMaxDynamicTableSize(tt.size2)
- if err := e.WriteField(pair(":method", "GET")); err != nil {
- t.Fatal(err)
- }
- want := removeSpace(tt.wantHex)
- if got := hex.EncodeToString(buf.Bytes()); got != want {
- t.Errorf("e.SetDynamicTableSize %v, %v = %q; want %q", tt.size1, tt.size2, got, want)
- }
- }
-}
-
-func TestEncoderWriteField(t *testing.T) {
- var buf bytes.Buffer
- e := NewEncoder(&buf)
- var got []HeaderField
- d := NewDecoder(4<<10, func(f HeaderField) {
- got = append(got, f)
- })
-
- tests := []struct {
- hdrs []HeaderField
- }{
- {[]HeaderField{
- pair(":method", "GET"),
- pair(":scheme", "http"),
- pair(":path", "/"),
- pair(":authority", "www.example.com"),
- }},
- {[]HeaderField{
- pair(":method", "GET"),
- pair(":scheme", "http"),
- pair(":path", "/"),
- pair(":authority", "www.example.com"),
- pair("cache-control", "no-cache"),
- }},
- {[]HeaderField{
- pair(":method", "GET"),
- pair(":scheme", "https"),
- pair(":path", "/index.html"),
- pair(":authority", "www.example.com"),
- pair("custom-key", "custom-value"),
- }},
- }
- for i, tt := range tests {
- buf.Reset()
- got = got[:0]
- for _, hf := range tt.hdrs {
- if err := e.WriteField(hf); err != nil {
- t.Fatal(err)
- }
- }
- _, err := d.Write(buf.Bytes())
- if err != nil {
- t.Errorf("%d. Decoder Write = %v", i, err)
- }
- if !reflect.DeepEqual(got, tt.hdrs) {
- t.Errorf("%d. Decoded %+v; want %+v", i, got, tt.hdrs)
- }
- }
-}
-
-func TestEncoderSearchTable(t *testing.T) {
- e := NewEncoder(nil)
-
- e.dynTab.add(pair("foo", "bar"))
- e.dynTab.add(pair("blake", "miz"))
- e.dynTab.add(pair(":method", "GET"))
-
- tests := []struct {
- hf HeaderField
- wantI uint64
- wantMatch bool
- }{
- // Name and Value match
- {pair("foo", "bar"), uint64(len(staticTable) + 3), true},
- {pair("blake", "miz"), uint64(len(staticTable) + 2), true},
- {pair(":method", "GET"), 2, true},
-
- // Only name match because Sensitive == true
- {HeaderField{":method", "GET", true}, 2, false},
-
- // Only Name matches
- {pair("foo", "..."), uint64(len(staticTable) + 3), false},
- {pair("blake", "..."), uint64(len(staticTable) + 2), false},
- {pair(":method", "..."), 2, false},
-
- // None match
- {pair("foo-", "bar"), 0, false},
- }
- for _, tt := range tests {
- if gotI, gotMatch := e.searchTable(tt.hf); gotI != tt.wantI || gotMatch != tt.wantMatch {
- t.Errorf("d.search(%+v) = %v, %v; want %v, %v", tt.hf, gotI, gotMatch, tt.wantI, tt.wantMatch)
- }
- }
-}
-
-func TestAppendVarInt(t *testing.T) {
- tests := []struct {
- n byte
- i uint64
- want []byte
- }{
- // Fits in a byte:
- {1, 0, []byte{0}},
- {2, 2, []byte{2}},
- {3, 6, []byte{6}},
- {4, 14, []byte{14}},
- {5, 30, []byte{30}},
- {6, 62, []byte{62}},
- {7, 126, []byte{126}},
- {8, 254, []byte{254}},
-
- // Multiple bytes:
- {5, 1337, []byte{31, 154, 10}},
- }
- for _, tt := range tests {
- got := appendVarInt(nil, tt.n, tt.i)
- if !bytes.Equal(got, tt.want) {
- t.Errorf("appendVarInt(nil, %v, %v) = %v; want %v", tt.n, tt.i, got, tt.want)
- }
- }
-}
-
-func TestAppendHpackString(t *testing.T) {
- tests := []struct {
- s, wantHex string
- }{
- // Huffman encoded
- {"www.example.com", "8c f1e3 c2e5 f23a 6ba0 ab90 f4ff"},
-
- // Not Huffman encoded
- {"a", "01 61"},
-
- // zero length
- {"", "00"},
- }
- for _, tt := range tests {
- want := removeSpace(tt.wantHex)
- buf := appendHpackString(nil, tt.s)
- if got := hex.EncodeToString(buf); want != got {
- t.Errorf("appendHpackString(nil, %q) = %q; want %q", tt.s, got, want)
- }
- }
-}
-
-func TestAppendIndexed(t *testing.T) {
- tests := []struct {
- i uint64
- wantHex string
- }{
- // 1 byte
- {1, "81"},
- {126, "fe"},
-
- // 2 bytes
- {127, "ff00"},
- {128, "ff01"},
- }
- for _, tt := range tests {
- want := removeSpace(tt.wantHex)
- buf := appendIndexed(nil, tt.i)
- if got := hex.EncodeToString(buf); want != got {
- t.Errorf("appendIndex(nil, %v) = %q; want %q", tt.i, got, want)
- }
- }
-}
-
-func TestAppendNewName(t *testing.T) {
- tests := []struct {
- f HeaderField
- indexing bool
- wantHex string
- }{
- // Incremental indexing
- {HeaderField{"custom-key", "custom-value", false}, true, "40 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
-
- // Without indexing
- {HeaderField{"custom-key", "custom-value", false}, false, "00 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
-
- // Never indexed
- {HeaderField{"custom-key", "custom-value", true}, true, "10 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
- {HeaderField{"custom-key", "custom-value", true}, false, "10 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
- }
- for _, tt := range tests {
- want := removeSpace(tt.wantHex)
- buf := appendNewName(nil, tt.f, tt.indexing)
- if got := hex.EncodeToString(buf); want != got {
- t.Errorf("appendNewName(nil, %+v, %v) = %q; want %q", tt.f, tt.indexing, got, want)
- }
- }
-}
-
-func TestAppendIndexedName(t *testing.T) {
- tests := []struct {
- f HeaderField
- i uint64
- indexing bool
- wantHex string
- }{
- // Incremental indexing
- {HeaderField{":status", "302", false}, 8, true, "48 82 6402"},
-
- // Without indexing
- {HeaderField{":status", "302", false}, 8, false, "08 82 6402"},
-
- // Never indexed
- {HeaderField{":status", "302", true}, 8, true, "18 82 6402"},
- {HeaderField{":status", "302", true}, 8, false, "18 82 6402"},
- }
- for _, tt := range tests {
- want := removeSpace(tt.wantHex)
- buf := appendIndexedName(nil, tt.f, tt.i, tt.indexing)
- if got := hex.EncodeToString(buf); want != got {
- t.Errorf("appendIndexedName(nil, %+v, %v) = %q; want %q", tt.f, tt.indexing, got, want)
- }
- }
-}
-
-func TestAppendTableSize(t *testing.T) {
- tests := []struct {
- i uint32
- wantHex string
- }{
- // Fits into 1 byte
- {30, "3e"},
-
- // Extra byte
- {31, "3f00"},
- {32, "3f01"},
- }
- for _, tt := range tests {
- want := removeSpace(tt.wantHex)
- buf := appendTableSize(nil, tt.i)
- if got := hex.EncodeToString(buf); want != got {
- t.Errorf("appendTableSize(nil, %v) = %q; want %q", tt.i, got, want)
- }
- }
-}
-
-func TestEncoderSetMaxDynamicTableSize(t *testing.T) {
- var buf bytes.Buffer
- e := NewEncoder(&buf)
- tests := []struct {
- v uint32
- wantUpdate bool
- wantMinSize uint32
- wantMaxSize uint32
- }{
- // Set new table size to 2048
- {2048, true, 2048, 2048},
-
- // Set new table size to 16384, but still limited to
- // 4096
- {16384, true, 2048, 4096},
- }
- for _, tt := range tests {
- e.SetMaxDynamicTableSize(tt.v)
- if got := e.tableSizeUpdate; tt.wantUpdate != got {
- t.Errorf("e.tableSizeUpdate = %v; want %v", got, tt.wantUpdate)
- }
- if got := e.minSize; tt.wantMinSize != got {
- t.Errorf("e.minSize = %v; want %v", got, tt.wantMinSize)
- }
- if got := e.dynTab.maxSize; tt.wantMaxSize != got {
- t.Errorf("e.maxSize = %v; want %v", got, tt.wantMaxSize)
- }
- }
-}
-
-func TestEncoderSetMaxDynamicTableSizeLimit(t *testing.T) {
- e := NewEncoder(nil)
- // 4095 < initialHeaderTableSize means maxSize is truncated to
- // 4095.
- e.SetMaxDynamicTableSizeLimit(4095)
- if got, want := e.dynTab.maxSize, uint32(4095); got != want {
- t.Errorf("e.dynTab.maxSize = %v; want %v", got, want)
- }
- if got, want := e.maxSizeLimit, uint32(4095); got != want {
- t.Errorf("e.maxSizeLimit = %v; want %v", got, want)
- }
- if got, want := e.tableSizeUpdate, true; got != want {
- t.Errorf("e.tableSizeUpdate = %v; want %v", got, want)
- }
- // maxSize will be truncated to maxSizeLimit
- e.SetMaxDynamicTableSize(16384)
- if got, want := e.dynTab.maxSize, uint32(4095); got != want {
- t.Errorf("e.dynTab.maxSize = %v; want %v", got, want)
- }
- // 8192 > current maxSizeLimit, so maxSize does not change.
- e.SetMaxDynamicTableSizeLimit(8192)
- if got, want := e.dynTab.maxSize, uint32(4095); got != want {
- t.Errorf("e.dynTab.maxSize = %v; want %v", got, want)
- }
- if got, want := e.maxSizeLimit, uint32(8192); got != want {
- t.Errorf("e.maxSizeLimit = %v; want %v", got, want)
- }
-}
-
-func removeSpace(s string) string {
- return strings.Replace(s, " ", "", -1)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/hpack.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/hpack.go
deleted file mode 100644
index 007bc7f..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/hpack.go
+++ /dev/null
@@ -1,542 +0,0 @@
-// 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 hpack implements HPACK, a compression format for
-// efficiently representing HTTP header fields in the context of HTTP/2.
-//
-// See http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09
-package hpack
-
-import (
- "bytes"
- "errors"
- "fmt"
-)
-
-// A DecodingError is something the spec defines as a decoding error.
-type DecodingError struct {
- Err error
-}
-
-func (de DecodingError) Error() string {
- return fmt.Sprintf("decoding error: %v", de.Err)
-}
-
-// An InvalidIndexError is returned when an encoder references a table
-// entry before the static table or after the end of the dynamic table.
-type InvalidIndexError int
-
-func (e InvalidIndexError) Error() string {
- return fmt.Sprintf("invalid indexed representation index %d", int(e))
-}
-
-// A HeaderField is a name-value pair. Both the name and value are
-// treated as opaque sequences of octets.
-type HeaderField struct {
- Name, Value string
-
- // Sensitive means that this header field should never be
- // indexed.
- Sensitive bool
-}
-
-// IsPseudo reports whether the header field is an http2 pseudo header.
-// That is, it reports whether it starts with a colon.
-// It is not otherwise guaranteed to be a valid pseudo header field,
-// though.
-func (hf HeaderField) IsPseudo() bool {
- return len(hf.Name) != 0 && hf.Name[0] == ':'
-}
-
-func (hf HeaderField) String() string {
- var suffix string
- if hf.Sensitive {
- suffix = " (sensitive)"
- }
- return fmt.Sprintf("header field %q = %q%s", hf.Name, hf.Value, suffix)
-}
-
-// Size returns the size of an entry per RFC 7541 section 4.1.
-func (hf HeaderField) Size() uint32 {
- // http://http2.github.io/http2-spec/compression.html#rfc.section.4.1
- // "The size of the dynamic table is the sum of the size of
- // its entries. The size of an entry is the sum of its name's
- // length in octets (as defined in Section 5.2), its value's
- // length in octets (see Section 5.2), plus 32. The size of
- // an entry is calculated using the length of the name and
- // value without any Huffman encoding applied."
-
- // This can overflow if somebody makes a large HeaderField
- // Name and/or Value by hand, but we don't care, because that
- // won't happen on the wire because the encoding doesn't allow
- // it.
- return uint32(len(hf.Name) + len(hf.Value) + 32)
-}
-
-// A Decoder is the decoding context for incremental processing of
-// header blocks.
-type Decoder struct {
- dynTab dynamicTable
- emit func(f HeaderField)
-
- emitEnabled bool // whether calls to emit are enabled
- maxStrLen int // 0 means unlimited
-
- // buf is the unparsed buffer. It's only written to
- // saveBuf if it was truncated in the middle of a header
- // block. Because it's usually not owned, we can only
- // process it under Write.
- buf []byte // not owned; only valid during Write
-
- // saveBuf is previous data passed to Write which we weren't able
- // to fully parse before. Unlike buf, we own this data.
- saveBuf bytes.Buffer
-}
-
-// NewDecoder returns a new decoder with the provided maximum dynamic
-// table size. The emitFunc will be called for each valid field
-// parsed, in the same goroutine as calls to Write, before Write returns.
-func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decoder {
- d := &Decoder{
- emit: emitFunc,
- emitEnabled: true,
- }
- d.dynTab.allowedMaxSize = maxDynamicTableSize
- d.dynTab.setMaxSize(maxDynamicTableSize)
- return d
-}
-
-// ErrStringLength is returned by Decoder.Write when the max string length
-// (as configured by Decoder.SetMaxStringLength) would be violated.
-var ErrStringLength = errors.New("hpack: string too long")
-
-// SetMaxStringLength sets the maximum size of a HeaderField name or
-// value string. If a string exceeds this length (even after any
-// decompression), Write will return ErrStringLength.
-// A value of 0 means unlimited and is the default from NewDecoder.
-func (d *Decoder) SetMaxStringLength(n int) {
- d.maxStrLen = n
-}
-
-// SetEmitFunc changes the callback used when new header fields
-// are decoded.
-// It must be non-nil. It does not affect EmitEnabled.
-func (d *Decoder) SetEmitFunc(emitFunc func(f HeaderField)) {
- d.emit = emitFunc
-}
-
-// SetEmitEnabled controls whether the emitFunc provided to NewDecoder
-// should be called. The default is true.
-//
-// This facility exists to let servers enforce MAX_HEADER_LIST_SIZE
-// while still decoding and keeping in-sync with decoder state, but
-// without doing unnecessary decompression or generating unnecessary
-// garbage for header fields past the limit.
-func (d *Decoder) SetEmitEnabled(v bool) { d.emitEnabled = v }
-
-// EmitEnabled reports whether calls to the emitFunc provided to NewDecoder
-// are currently enabled. The default is true.
-func (d *Decoder) EmitEnabled() bool { return d.emitEnabled }
-
-// TODO: add method *Decoder.Reset(maxSize, emitFunc) to let callers re-use Decoders and their
-// underlying buffers for garbage reasons.
-
-func (d *Decoder) SetMaxDynamicTableSize(v uint32) {
- d.dynTab.setMaxSize(v)
-}
-
-// SetAllowedMaxDynamicTableSize sets the upper bound that the encoded
-// stream (via dynamic table size updates) may set the maximum size
-// to.
-func (d *Decoder) SetAllowedMaxDynamicTableSize(v uint32) {
- d.dynTab.allowedMaxSize = v
-}
-
-type dynamicTable struct {
- // ents is the FIFO described at
- // http://http2.github.io/http2-spec/compression.html#rfc.section.2.3.2
- // The newest (low index) is append at the end, and items are
- // evicted from the front.
- ents []HeaderField
- size uint32
- maxSize uint32 // current maxSize
- allowedMaxSize uint32 // maxSize may go up to this, inclusive
-}
-
-func (dt *dynamicTable) setMaxSize(v uint32) {
- dt.maxSize = v
- dt.evict()
-}
-
-// TODO: change dynamicTable to be a struct with a slice and a size int field,
-// per http://http2.github.io/http2-spec/compression.html#rfc.section.4.1:
-//
-//
-// Then make add increment the size. maybe the max size should move from Decoder to
-// dynamicTable and add should return an ok bool if there was enough space.
-//
-// Later we'll need a remove operation on dynamicTable.
-
-func (dt *dynamicTable) add(f HeaderField) {
- dt.ents = append(dt.ents, f)
- dt.size += f.Size()
- dt.evict()
-}
-
-// If we're too big, evict old stuff (front of the slice)
-func (dt *dynamicTable) evict() {
- base := dt.ents // keep base pointer of slice
- for dt.size > dt.maxSize {
- dt.size -= dt.ents[0].Size()
- dt.ents = dt.ents[1:]
- }
-
- // Shift slice contents down if we evicted things.
- if len(dt.ents) != len(base) {
- copy(base, dt.ents)
- dt.ents = base[:len(dt.ents)]
- }
-}
-
-// constantTimeStringCompare compares string a and b in a constant
-// time manner.
-func constantTimeStringCompare(a, b string) bool {
- if len(a) != len(b) {
- return false
- }
-
- c := byte(0)
-
- for i := 0; i < len(a); i++ {
- c |= a[i] ^ b[i]
- }
-
- return c == 0
-}
-
-// Search searches f in the table. The return value i is 0 if there is
-// no name match. If there is name match or name/value match, i is the
-// index of that entry (1-based). If both name and value match,
-// nameValueMatch becomes true.
-func (dt *dynamicTable) search(f HeaderField) (i uint64, nameValueMatch bool) {
- l := len(dt.ents)
- for j := l - 1; j >= 0; j-- {
- ent := dt.ents[j]
- if !constantTimeStringCompare(ent.Name, f.Name) {
- continue
- }
- if i == 0 {
- i = uint64(l - j)
- }
- if f.Sensitive {
- continue
- }
- if !constantTimeStringCompare(ent.Value, f.Value) {
- continue
- }
- i = uint64(l - j)
- nameValueMatch = true
- return
- }
- return
-}
-
-func (d *Decoder) maxTableIndex() int {
- return len(d.dynTab.ents) + len(staticTable)
-}
-
-func (d *Decoder) at(i uint64) (hf HeaderField, ok bool) {
- if i < 1 {
- return
- }
- if i > uint64(d.maxTableIndex()) {
- return
- }
- if i <= uint64(len(staticTable)) {
- return staticTable[i-1], true
- }
- dents := d.dynTab.ents
- return dents[len(dents)-(int(i)-len(staticTable))], true
-}
-
-// Decode decodes an entire block.
-//
-// TODO: remove this method and make it incremental later? This is
-// easier for debugging now.
-func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error) {
- var hf []HeaderField
- saveFunc := d.emit
- defer func() { d.emit = saveFunc }()
- d.emit = func(f HeaderField) { hf = append(hf, f) }
- if _, err := d.Write(p); err != nil {
- return nil, err
- }
- if err := d.Close(); err != nil {
- return nil, err
- }
- return hf, nil
-}
-
-func (d *Decoder) Close() error {
- if d.saveBuf.Len() > 0 {
- d.saveBuf.Reset()
- return DecodingError{errors.New("truncated headers")}
- }
- return nil
-}
-
-func (d *Decoder) Write(p []byte) (n int, err error) {
- if len(p) == 0 {
- // Prevent state machine CPU attacks (making us redo
- // work up to the point of finding out we don't have
- // enough data)
- return
- }
- // Only copy the data if we have to. Optimistically assume
- // that p will contain a complete header block.
- if d.saveBuf.Len() == 0 {
- d.buf = p
- } else {
- d.saveBuf.Write(p)
- d.buf = d.saveBuf.Bytes()
- d.saveBuf.Reset()
- }
-
- for len(d.buf) > 0 {
- err = d.parseHeaderFieldRepr()
- if err == errNeedMore {
- // Extra paranoia, making sure saveBuf won't
- // get too large. All the varint and string
- // reading code earlier should already catch
- // overlong things and return ErrStringLength,
- // but keep this as a last resort.
- const varIntOverhead = 8 // conservative
- if d.maxStrLen != 0 && int64(len(d.buf)) > 2*(int64(d.maxStrLen)+varIntOverhead) {
- return 0, ErrStringLength
- }
- d.saveBuf.Write(d.buf)
- return len(p), nil
- }
- if err != nil {
- break
- }
- }
- return len(p), err
-}
-
-// errNeedMore is an internal sentinel error value that means the
-// buffer is truncated and we need to read more data before we can
-// continue parsing.
-var errNeedMore = errors.New("need more data")
-
-type indexType int
-
-const (
- indexedTrue indexType = iota
- indexedFalse
- indexedNever
-)
-
-func (v indexType) indexed() bool { return v == indexedTrue }
-func (v indexType) sensitive() bool { return v == indexedNever }
-
-// returns errNeedMore if there isn't enough data available.
-// any other error is fatal.
-// consumes d.buf iff it returns nil.
-// precondition: must be called with len(d.buf) > 0
-func (d *Decoder) parseHeaderFieldRepr() error {
- b := d.buf[0]
- switch {
- case b&128 != 0:
- // Indexed representation.
- // High bit set?
- // http://http2.github.io/http2-spec/compression.html#rfc.section.6.1
- return d.parseFieldIndexed()
- case b&192 == 64:
- // 6.2.1 Literal Header Field with Incremental Indexing
- // 0b10xxxxxx: top two bits are 10
- // http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.1
- return d.parseFieldLiteral(6, indexedTrue)
- case b&240 == 0:
- // 6.2.2 Literal Header Field without Indexing
- // 0b0000xxxx: top four bits are 0000
- // http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.2
- return d.parseFieldLiteral(4, indexedFalse)
- case b&240 == 16:
- // 6.2.3 Literal Header Field never Indexed
- // 0b0001xxxx: top four bits are 0001
- // http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.3
- return d.parseFieldLiteral(4, indexedNever)
- case b&224 == 32:
- // 6.3 Dynamic Table Size Update
- // Top three bits are '001'.
- // http://http2.github.io/http2-spec/compression.html#rfc.section.6.3
- return d.parseDynamicTableSizeUpdate()
- }
-
- return DecodingError{errors.New("invalid encoding")}
-}
-
-// (same invariants and behavior as parseHeaderFieldRepr)
-func (d *Decoder) parseFieldIndexed() error {
- buf := d.buf
- idx, buf, err := readVarInt(7, buf)
- if err != nil {
- return err
- }
- hf, ok := d.at(idx)
- if !ok {
- return DecodingError{InvalidIndexError(idx)}
- }
- d.buf = buf
- return d.callEmit(HeaderField{Name: hf.Name, Value: hf.Value})
-}
-
-// (same invariants and behavior as parseHeaderFieldRepr)
-func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
- buf := d.buf
- nameIdx, buf, err := readVarInt(n, buf)
- if err != nil {
- return err
- }
-
- var hf HeaderField
- wantStr := d.emitEnabled || it.indexed()
- if nameIdx > 0 {
- ihf, ok := d.at(nameIdx)
- if !ok {
- return DecodingError{InvalidIndexError(nameIdx)}
- }
- hf.Name = ihf.Name
- } else {
- hf.Name, buf, err = d.readString(buf, wantStr)
- if err != nil {
- return err
- }
- }
- hf.Value, buf, err = d.readString(buf, wantStr)
- if err != nil {
- return err
- }
- d.buf = buf
- if it.indexed() {
- d.dynTab.add(hf)
- }
- hf.Sensitive = it.sensitive()
- return d.callEmit(hf)
-}
-
-func (d *Decoder) callEmit(hf HeaderField) error {
- if d.maxStrLen != 0 {
- if len(hf.Name) > d.maxStrLen || len(hf.Value) > d.maxStrLen {
- return ErrStringLength
- }
- }
- if d.emitEnabled {
- d.emit(hf)
- }
- return nil
-}
-
-// (same invariants and behavior as parseHeaderFieldRepr)
-func (d *Decoder) parseDynamicTableSizeUpdate() error {
- buf := d.buf
- size, buf, err := readVarInt(5, buf)
- if err != nil {
- return err
- }
- if size > uint64(d.dynTab.allowedMaxSize) {
- return DecodingError{errors.New("dynamic table size update too large")}
- }
- d.dynTab.setMaxSize(uint32(size))
- d.buf = buf
- return nil
-}
-
-var errVarintOverflow = DecodingError{errors.New("varint integer overflow")}
-
-// readVarInt reads an unsigned variable length integer off the
-// beginning of p. n is the parameter as described in
-// http://http2.github.io/http2-spec/compression.html#rfc.section.5.1.
-//
-// n must always be between 1 and 8.
-//
-// The returned remain buffer is either a smaller suffix of p, or err != nil.
-// The error is errNeedMore if p doesn't contain a complete integer.
-func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
- if n < 1 || n > 8 {
- panic("bad n")
- }
- if len(p) == 0 {
- return 0, p, errNeedMore
- }
- i = uint64(p[0])
- if n < 8 {
- i &= (1 << uint64(n)) - 1
- }
- if i < (1<<uint64(n))-1 {
- return i, p[1:], nil
- }
-
- origP := p
- p = p[1:]
- var m uint64
- for len(p) > 0 {
- b := p[0]
- p = p[1:]
- i += uint64(b&127) << m
- if b&128 == 0 {
- return i, p, nil
- }
- m += 7
- if m >= 63 { // TODO: proper overflow check. making this up.
- return 0, origP, errVarintOverflow
- }
- }
- return 0, origP, errNeedMore
-}
-
-// readString decodes an hpack string from p.
-//
-// wantStr is whether s will be used. If false, decompression and
-// []byte->string garbage are skipped if s will be ignored
-// anyway. This does mean that huffman decoding errors for non-indexed
-// strings past the MAX_HEADER_LIST_SIZE are ignored, but the server
-// is returning an error anyway, and because they're not indexed, the error
-// won't affect the decoding state.
-func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) {
- if len(p) == 0 {
- return "", p, errNeedMore
- }
- isHuff := p[0]&128 != 0
- strLen, p, err := readVarInt(7, p)
- if err != nil {
- return "", p, err
- }
- if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) {
- return "", nil, ErrStringLength
- }
- if uint64(len(p)) < strLen {
- return "", p, errNeedMore
- }
- if !isHuff {
- if wantStr {
- s = string(p[:strLen])
- }
- return s, p[strLen:], nil
- }
-
- if wantStr {
- buf := bufPool.Get().(*bytes.Buffer)
- buf.Reset() // don't trust others
- defer bufPool.Put(buf)
- if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil {
- buf.Reset()
- return "", nil, err
- }
- s = buf.String()
- buf.Reset() // be nice to GC
- }
- return s, p[strLen:], nil
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/hpack_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/hpack_test.go
deleted file mode 100644
index 4c7b17b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/hpack_test.go
+++ /dev/null
@@ -1,854 +0,0 @@
-// 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 hpack
-
-import (
- "bufio"
- "bytes"
- "encoding/hex"
- "fmt"
- "math/rand"
- "reflect"
- "regexp"
- "strconv"
- "strings"
- "testing"
- "time"
-)
-
-func TestStaticTable(t *testing.T) {
- fromSpec := `
- +-------+-----------------------------+---------------+
- | 1 | :authority | |
- | 2 | :method | GET |
- | 3 | :method | POST |
- | 4 | :path | / |
- | 5 | :path | /index.html |
- | 6 | :scheme | http |
- | 7 | :scheme | https |
- | 8 | :status | 200 |
- | 9 | :status | 204 |
- | 10 | :status | 206 |
- | 11 | :status | 304 |
- | 12 | :status | 400 |
- | 13 | :status | 404 |
- | 14 | :status | 500 |
- | 15 | accept-charset | |
- | 16 | accept-encoding | gzip, deflate |
- | 17 | accept-language | |
- | 18 | accept-ranges | |
- | 19 | accept | |
- | 20 | access-control-allow-origin | |
- | 21 | age | |
- | 22 | allow | |
- | 23 | authorization | |
- | 24 | cache-control | |
- | 25 | content-disposition | |
- | 26 | content-encoding | |
- | 27 | content-language | |
- | 28 | content-length | |
- | 29 | content-location | |
- | 30 | content-range | |
- | 31 | content-type | |
- | 32 | cookie | |
- | 33 | date | |
- | 34 | etag | |
- | 35 | expect | |
- | 36 | expires | |
- | 37 | from | |
- | 38 | host | |
- | 39 | if-match | |
- | 40 | if-modified-since | |
- | 41 | if-none-match | |
- | 42 | if-range | |
- | 43 | if-unmodified-since | |
- | 44 | last-modified | |
- | 45 | link | |
- | 46 | location | |
- | 47 | max-forwards | |
- | 48 | proxy-authenticate | |
- | 49 | proxy-authorization | |
- | 50 | range | |
- | 51 | referer | |
- | 52 | refresh | |
- | 53 | retry-after | |
- | 54 | server | |
- | 55 | set-cookie | |
- | 56 | strict-transport-security | |
- | 57 | transfer-encoding | |
- | 58 | user-agent | |
- | 59 | vary | |
- | 60 | via | |
- | 61 | www-authenticate | |
- +-------+-----------------------------+---------------+
-`
- bs := bufio.NewScanner(strings.NewReader(fromSpec))
- re := regexp.MustCompile(`\| (\d+)\s+\| (\S+)\s*\| (\S(.*\S)?)?\s+\|`)
- for bs.Scan() {
- l := bs.Text()
- if !strings.Contains(l, "|") {
- continue
- }
- m := re.FindStringSubmatch(l)
- if m == nil {
- continue
- }
- i, err := strconv.Atoi(m[1])
- if err != nil {
- t.Errorf("Bogus integer on line %q", l)
- continue
- }
- if i < 1 || i > len(staticTable) {
- t.Errorf("Bogus index %d on line %q", i, l)
- continue
- }
- if got, want := staticTable[i-1].Name, m[2]; got != want {
- t.Errorf("header index %d name = %q; want %q", i, got, want)
- }
- if got, want := staticTable[i-1].Value, m[3]; got != want {
- t.Errorf("header index %d value = %q; want %q", i, got, want)
- }
- }
- if err := bs.Err(); err != nil {
- t.Error(err)
- }
-}
-
-func (d *Decoder) mustAt(idx int) HeaderField {
- if hf, ok := d.at(uint64(idx)); !ok {
- panic(fmt.Sprintf("bogus index %d", idx))
- } else {
- return hf
- }
-}
-
-func TestDynamicTableAt(t *testing.T) {
- d := NewDecoder(4096, nil)
- at := d.mustAt
- if got, want := at(2), (pair(":method", "GET")); got != want {
- t.Errorf("at(2) = %v; want %v", got, want)
- }
- d.dynTab.add(pair("foo", "bar"))
- d.dynTab.add(pair("blake", "miz"))
- if got, want := at(len(staticTable)+1), (pair("blake", "miz")); got != want {
- t.Errorf("at(dyn 1) = %v; want %v", got, want)
- }
- if got, want := at(len(staticTable)+2), (pair("foo", "bar")); got != want {
- t.Errorf("at(dyn 2) = %v; want %v", got, want)
- }
- if got, want := at(3), (pair(":method", "POST")); got != want {
- t.Errorf("at(3) = %v; want %v", got, want)
- }
-}
-
-func TestDynamicTableSearch(t *testing.T) {
- dt := dynamicTable{}
- dt.setMaxSize(4096)
-
- dt.add(pair("foo", "bar"))
- dt.add(pair("blake", "miz"))
- dt.add(pair(":method", "GET"))
-
- tests := []struct {
- hf HeaderField
- wantI uint64
- wantMatch bool
- }{
- // Name and Value match
- {pair("foo", "bar"), 3, true},
- {pair(":method", "GET"), 1, true},
-
- // Only name match because of Sensitive == true
- {HeaderField{"blake", "miz", true}, 2, false},
-
- // Only Name matches
- {pair("foo", "..."), 3, false},
- {pair("blake", "..."), 2, false},
- {pair(":method", "..."), 1, false},
-
- // None match
- {pair("foo-", "bar"), 0, false},
- }
- for _, tt := range tests {
- if gotI, gotMatch := dt.search(tt.hf); gotI != tt.wantI || gotMatch != tt.wantMatch {
- t.Errorf("d.search(%+v) = %v, %v; want %v, %v", tt.hf, gotI, gotMatch, tt.wantI, tt.wantMatch)
- }
- }
-}
-
-func TestDynamicTableSizeEvict(t *testing.T) {
- d := NewDecoder(4096, nil)
- if want := uint32(0); d.dynTab.size != want {
- t.Fatalf("size = %d; want %d", d.dynTab.size, want)
- }
- add := d.dynTab.add
- add(pair("blake", "eats pizza"))
- if want := uint32(15 + 32); d.dynTab.size != want {
- t.Fatalf("after pizza, size = %d; want %d", d.dynTab.size, want)
- }
- add(pair("foo", "bar"))
- if want := uint32(15 + 32 + 6 + 32); d.dynTab.size != want {
- t.Fatalf("after foo bar, size = %d; want %d", d.dynTab.size, want)
- }
- d.dynTab.setMaxSize(15 + 32 + 1 /* slop */)
- if want := uint32(6 + 32); d.dynTab.size != want {
- t.Fatalf("after setMaxSize, size = %d; want %d", d.dynTab.size, want)
- }
- if got, want := d.mustAt(len(staticTable)+1), (pair("foo", "bar")); got != want {
- t.Errorf("at(dyn 1) = %v; want %v", got, want)
- }
- add(pair("long", strings.Repeat("x", 500)))
- if want := uint32(0); d.dynTab.size != want {
- t.Fatalf("after big one, size = %d; want %d", d.dynTab.size, want)
- }
-}
-
-func TestDecoderDecode(t *testing.T) {
- tests := []struct {
- name string
- in []byte
- want []HeaderField
- wantDynTab []HeaderField // newest entry first
- }{
- // C.2.1 Literal Header Field with Indexing
- // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.1
- {"C.2.1", dehex("400a 6375 7374 6f6d 2d6b 6579 0d63 7573 746f 6d2d 6865 6164 6572"),
- []HeaderField{pair("custom-key", "custom-header")},
- []HeaderField{pair("custom-key", "custom-header")},
- },
-
- // C.2.2 Literal Header Field without Indexing
- // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.2
- {"C.2.2", dehex("040c 2f73 616d 706c 652f 7061 7468"),
- []HeaderField{pair(":path", "/sample/path")},
- []HeaderField{}},
-
- // C.2.3 Literal Header Field never Indexed
- // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.3
- {"C.2.3", dehex("1008 7061 7373 776f 7264 0673 6563 7265 74"),
- []HeaderField{{"password", "secret", true}},
- []HeaderField{}},
-
- // C.2.4 Indexed Header Field
- // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.4
- {"C.2.4", []byte("\x82"),
- []HeaderField{pair(":method", "GET")},
- []HeaderField{}},
- }
- for _, tt := range tests {
- d := NewDecoder(4096, nil)
- hf, err := d.DecodeFull(tt.in)
- if err != nil {
- t.Errorf("%s: %v", tt.name, err)
- continue
- }
- if !reflect.DeepEqual(hf, tt.want) {
- t.Errorf("%s: Got %v; want %v", tt.name, hf, tt.want)
- }
- gotDynTab := d.dynTab.reverseCopy()
- if !reflect.DeepEqual(gotDynTab, tt.wantDynTab) {
- t.Errorf("%s: dynamic table after = %v; want %v", tt.name, gotDynTab, tt.wantDynTab)
- }
- }
-}
-
-func (dt *dynamicTable) reverseCopy() (hf []HeaderField) {
- hf = make([]HeaderField, len(dt.ents))
- for i := range hf {
- hf[i] = dt.ents[len(dt.ents)-1-i]
- }
- return
-}
-
-type encAndWant struct {
- enc []byte
- want []HeaderField
- wantDynTab []HeaderField
- wantDynSize uint32
-}
-
-// C.3 Request Examples without Huffman Coding
-// http://http2.github.io/http2-spec/compression.html#rfc.section.C.3
-func TestDecodeC3_NoHuffman(t *testing.T) {
- testDecodeSeries(t, 4096, []encAndWant{
- {dehex("8286 8441 0f77 7777 2e65 7861 6d70 6c65 2e63 6f6d"),
- []HeaderField{
- pair(":method", "GET"),
- pair(":scheme", "http"),
- pair(":path", "/"),
- pair(":authority", "www.example.com"),
- },
- []HeaderField{
- pair(":authority", "www.example.com"),
- },
- 57,
- },
- {dehex("8286 84be 5808 6e6f 2d63 6163 6865"),
- []HeaderField{
- pair(":method", "GET"),
- pair(":scheme", "http"),
- pair(":path", "/"),
- pair(":authority", "www.example.com"),
- pair("cache-control", "no-cache"),
- },
- []HeaderField{
- pair("cache-control", "no-cache"),
- pair(":authority", "www.example.com"),
- },
- 110,
- },
- {dehex("8287 85bf 400a 6375 7374 6f6d 2d6b 6579 0c63 7573 746f 6d2d 7661 6c75 65"),
- []HeaderField{
- pair(":method", "GET"),
- pair(":scheme", "https"),
- pair(":path", "/index.html"),
- pair(":authority", "www.example.com"),
- pair("custom-key", "custom-value"),
- },
- []HeaderField{
- pair("custom-key", "custom-value"),
- pair("cache-control", "no-cache"),
- pair(":authority", "www.example.com"),
- },
- 164,
- },
- })
-}
-
-// C.4 Request Examples with Huffman Coding
-// http://http2.github.io/http2-spec/compression.html#rfc.section.C.4
-func TestDecodeC4_Huffman(t *testing.T) {
- testDecodeSeries(t, 4096, []encAndWant{
- {dehex("8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 ff"),
- []HeaderField{
- pair(":method", "GET"),
- pair(":scheme", "http"),
- pair(":path", "/"),
- pair(":authority", "www.example.com"),
- },
- []HeaderField{
- pair(":authority", "www.example.com"),
- },
- 57,
- },
- {dehex("8286 84be 5886 a8eb 1064 9cbf"),
- []HeaderField{
- pair(":method", "GET"),
- pair(":scheme", "http"),
- pair(":path", "/"),
- pair(":authority", "www.example.com"),
- pair("cache-control", "no-cache"),
- },
- []HeaderField{
- pair("cache-control", "no-cache"),
- pair(":authority", "www.example.com"),
- },
- 110,
- },
- {dehex("8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925 a849 e95b b8e8 b4bf"),
- []HeaderField{
- pair(":method", "GET"),
- pair(":scheme", "https"),
- pair(":path", "/index.html"),
- pair(":authority", "www.example.com"),
- pair("custom-key", "custom-value"),
- },
- []HeaderField{
- pair("custom-key", "custom-value"),
- pair("cache-control", "no-cache"),
- pair(":authority", "www.example.com"),
- },
- 164,
- },
- })
-}
-
-// http://http2.github.io/http2-spec/compression.html#rfc.section.C.5
-// "This section shows several consecutive header lists, corresponding
-// to HTTP responses, on the same connection. The HTTP/2 setting
-// parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256
-// octets, causing some evictions to occur."
-func TestDecodeC5_ResponsesNoHuff(t *testing.T) {
- testDecodeSeries(t, 256, []encAndWant{
- {dehex(`
-4803 3330 3258 0770 7269 7661 7465 611d
-4d6f 6e2c 2032 3120 4f63 7420 3230 3133
-2032 303a 3133 3a32 3120 474d 546e 1768
-7474 7073 3a2f 2f77 7777 2e65 7861 6d70
-6c65 2e63 6f6d
-`),
- []HeaderField{
- pair(":status", "302"),
- pair("cache-control", "private"),
- pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
- pair("location", "https://www.example.com"),
- },
- []HeaderField{
- pair("location", "https://www.example.com"),
- pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
- pair("cache-control", "private"),
- pair(":status", "302"),
- },
- 222,
- },
- {dehex("4803 3330 37c1 c0bf"),
- []HeaderField{
- pair(":status", "307"),
- pair("cache-control", "private"),
- pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
- pair("location", "https://www.example.com"),
- },
- []HeaderField{
- pair(":status", "307"),
- pair("location", "https://www.example.com"),
- pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
- pair("cache-control", "private"),
- },
- 222,
- },
- {dehex(`
-88c1 611d 4d6f 6e2c 2032 3120 4f63 7420
-3230 3133 2032 303a 3133 3a32 3220 474d
-54c0 5a04 677a 6970 7738 666f 6f3d 4153
-444a 4b48 514b 425a 584f 5157 454f 5049
-5541 5851 5745 4f49 553b 206d 6178 2d61
-6765 3d33 3630 303b 2076 6572 7369 6f6e
-3d31
-`),
- []HeaderField{
- pair(":status", "200"),
- pair("cache-control", "private"),
- pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
- pair("location", "https://www.example.com"),
- pair("content-encoding", "gzip"),
- pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
- },
- []HeaderField{
- pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
- pair("content-encoding", "gzip"),
- pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
- },
- 215,
- },
- })
-}
-
-// http://http2.github.io/http2-spec/compression.html#rfc.section.C.6
-// "This section shows the same examples as the previous section, but
-// using Huffman encoding for the literal values. The HTTP/2 setting
-// parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256
-// octets, causing some evictions to occur. The eviction mechanism
-// uses the length of the decoded literal values, so the same
-// evictions occurs as in the previous section."
-func TestDecodeC6_ResponsesHuffman(t *testing.T) {
- testDecodeSeries(t, 256, []encAndWant{
- {dehex(`
-4882 6402 5885 aec3 771a 4b61 96d0 7abe
-9410 54d4 44a8 2005 9504 0b81 66e0 82a6
-2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8
-e9ae 82ae 43d3
-`),
- []HeaderField{
- pair(":status", "302"),
- pair("cache-control", "private"),
- pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
- pair("location", "https://www.example.com"),
- },
- []HeaderField{
- pair("location", "https://www.example.com"),
- pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
- pair("cache-control", "private"),
- pair(":status", "302"),
- },
- 222,
- },
- {dehex("4883 640e ffc1 c0bf"),
- []HeaderField{
- pair(":status", "307"),
- pair("cache-control", "private"),
- pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
- pair("location", "https://www.example.com"),
- },
- []HeaderField{
- pair(":status", "307"),
- pair("location", "https://www.example.com"),
- pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
- pair("cache-control", "private"),
- },
- 222,
- },
- {dehex(`
-88c1 6196 d07a be94 1054 d444 a820 0595
-040b 8166 e084 a62d 1bff c05a 839b d9ab
-77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b
-3960 d5af 2708 7f36 72c1 ab27 0fb5 291f
-9587 3160 65c0 03ed 4ee5 b106 3d50 07
-`),
- []HeaderField{
- pair(":status", "200"),
- pair("cache-control", "private"),
- pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
- pair("location", "https://www.example.com"),
- pair("content-encoding", "gzip"),
- pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
- },
- []HeaderField{
- pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
- pair("content-encoding", "gzip"),
- pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
- },
- 215,
- },
- })
-}
-
-func testDecodeSeries(t *testing.T, size uint32, steps []encAndWant) {
- d := NewDecoder(size, nil)
- for i, step := range steps {
- hf, err := d.DecodeFull(step.enc)
- if err != nil {
- t.Fatalf("Error at step index %d: %v", i, err)
- }
- if !reflect.DeepEqual(hf, step.want) {
- t.Fatalf("At step index %d: Got headers %v; want %v", i, hf, step.want)
- }
- gotDynTab := d.dynTab.reverseCopy()
- if !reflect.DeepEqual(gotDynTab, step.wantDynTab) {
- t.Errorf("After step index %d, dynamic table = %v; want %v", i, gotDynTab, step.wantDynTab)
- }
- if d.dynTab.size != step.wantDynSize {
- t.Errorf("After step index %d, dynamic table size = %v; want %v", i, d.dynTab.size, step.wantDynSize)
- }
- }
-}
-
-func TestHuffmanDecodeExcessPadding(t *testing.T) {
- tests := [][]byte{
- {0xff}, // Padding Exceeds 7 bits
- {0x1f, 0xff}, // {"a", 1 byte excess padding}
- {0x1f, 0xff, 0xff}, // {"a", 2 byte excess padding}
- {0x1f, 0xff, 0xff, 0xff}, // {"a", 3 byte excess padding}
- {0xff, 0x9f, 0xff, 0xff, 0xff}, // {"a", 29 bit excess padding}
- {'R', 0xbc, '0', 0xff, 0xff, 0xff, 0xff}, // Padding ends on partial symbol.
- }
- for i, in := range tests {
- var buf bytes.Buffer
- if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman {
- t.Errorf("test-%d: decode(%q) = %v; want ErrInvalidHuffman", i, in, err)
- }
- }
-}
-
-func TestHuffmanDecodeEOS(t *testing.T) {
- in := []byte{0xff, 0xff, 0xff, 0xff, 0xfc} // {EOS, "?"}
- var buf bytes.Buffer
- if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman {
- t.Errorf("error = %v; want ErrInvalidHuffman", err)
- }
-}
-
-func TestHuffmanDecodeMaxLengthOnTrailingByte(t *testing.T) {
- in := []byte{0x00, 0x01} // {"0", "0", "0"}
- var buf bytes.Buffer
- if err := huffmanDecode(&buf, 2, in); err != ErrStringLength {
- t.Errorf("error = %v; want ErrStringLength", err)
- }
-}
-
-func TestHuffmanDecodeCorruptPadding(t *testing.T) {
- in := []byte{0x00}
- var buf bytes.Buffer
- if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman {
- t.Errorf("error = %v; want ErrInvalidHuffman", err)
- }
-}
-
-func TestHuffmanDecode(t *testing.T) {
- tests := []struct {
- inHex, want string
- }{
- {"f1e3 c2e5 f23a 6ba0 ab90 f4ff", "www.example.com"},
- {"a8eb 1064 9cbf", "no-cache"},
- {"25a8 49e9 5ba9 7d7f", "custom-key"},
- {"25a8 49e9 5bb8 e8b4 bf", "custom-value"},
- {"6402", "302"},
- {"aec3 771a 4b", "private"},
- {"d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff", "Mon, 21 Oct 2013 20:13:21 GMT"},
- {"9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3", "https://www.example.com"},
- {"9bd9 ab", "gzip"},
- {"94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07",
- "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
- }
- for i, tt := range tests {
- var buf bytes.Buffer
- in, err := hex.DecodeString(strings.Replace(tt.inHex, " ", "", -1))
- if err != nil {
- t.Errorf("%d. hex input error: %v", i, err)
- continue
- }
- if _, err := HuffmanDecode(&buf, in); err != nil {
- t.Errorf("%d. decode error: %v", i, err)
- continue
- }
- if got := buf.String(); tt.want != got {
- t.Errorf("%d. decode = %q; want %q", i, got, tt.want)
- }
- }
-}
-
-func TestAppendHuffmanString(t *testing.T) {
- tests := []struct {
- in, want string
- }{
- {"www.example.com", "f1e3 c2e5 f23a 6ba0 ab90 f4ff"},
- {"no-cache", "a8eb 1064 9cbf"},
- {"custom-key", "25a8 49e9 5ba9 7d7f"},
- {"custom-value", "25a8 49e9 5bb8 e8b4 bf"},
- {"302", "6402"},
- {"private", "aec3 771a 4b"},
- {"Mon, 21 Oct 2013 20:13:21 GMT", "d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff"},
- {"https://www.example.com", "9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3"},
- {"gzip", "9bd9 ab"},
- {"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
- "94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07"},
- }
- for i, tt := range tests {
- buf := []byte{}
- want := strings.Replace(tt.want, " ", "", -1)
- buf = AppendHuffmanString(buf, tt.in)
- if got := hex.EncodeToString(buf); want != got {
- t.Errorf("%d. encode = %q; want %q", i, got, want)
- }
- }
-}
-
-func TestHuffmanMaxStrLen(t *testing.T) {
- const msg = "Some string"
- huff := AppendHuffmanString(nil, msg)
-
- testGood := func(max int) {
- var out bytes.Buffer
- if err := huffmanDecode(&out, max, huff); err != nil {
- t.Errorf("For maxLen=%d, unexpected error: %v", max, err)
- }
- if out.String() != msg {
- t.Errorf("For maxLen=%d, out = %q; want %q", max, out.String(), msg)
- }
- }
- testGood(0)
- testGood(len(msg))
- testGood(len(msg) + 1)
-
- var out bytes.Buffer
- if err := huffmanDecode(&out, len(msg)-1, huff); err != ErrStringLength {
- t.Errorf("err = %v; want ErrStringLength", err)
- }
-}
-
-func TestHuffmanRoundtripStress(t *testing.T) {
- const Len = 50 // of uncompressed string
- input := make([]byte, Len)
- var output bytes.Buffer
- var huff []byte
-
- n := 5000
- if testing.Short() {
- n = 100
- }
- seed := time.Now().UnixNano()
- t.Logf("Seed = %v", seed)
- src := rand.New(rand.NewSource(seed))
- var encSize int64
- for i := 0; i < n; i++ {
- for l := range input {
- input[l] = byte(src.Intn(256))
- }
- huff = AppendHuffmanString(huff[:0], string(input))
- encSize += int64(len(huff))
- output.Reset()
- if err := huffmanDecode(&output, 0, huff); err != nil {
- t.Errorf("Failed to decode %q -> %q -> error %v", input, huff, err)
- continue
- }
- if !bytes.Equal(output.Bytes(), input) {
- t.Errorf("Roundtrip failure on %q -> %q -> %q", input, huff, output.Bytes())
- }
- }
- t.Logf("Compressed size of original: %0.02f%% (%v -> %v)", 100*(float64(encSize)/(Len*float64(n))), Len*n, encSize)
-}
-
-func TestHuffmanDecodeFuzz(t *testing.T) {
- const Len = 50 // of compressed
- var buf, zbuf bytes.Buffer
-
- n := 5000
- if testing.Short() {
- n = 100
- }
- seed := time.Now().UnixNano()
- t.Logf("Seed = %v", seed)
- src := rand.New(rand.NewSource(seed))
- numFail := 0
- for i := 0; i < n; i++ {
- zbuf.Reset()
- if i == 0 {
- // Start with at least one invalid one.
- zbuf.WriteString("00\x91\xff\xff\xff\xff\xc8")
- } else {
- for l := 0; l < Len; l++ {
- zbuf.WriteByte(byte(src.Intn(256)))
- }
- }
-
- buf.Reset()
- if err := huffmanDecode(&buf, 0, zbuf.Bytes()); err != nil {
- if err == ErrInvalidHuffman {
- numFail++
- continue
- }
- t.Errorf("Failed to decode %q: %v", zbuf.Bytes(), err)
- continue
- }
- }
- t.Logf("%0.02f%% are invalid (%d / %d)", 100*float64(numFail)/float64(n), numFail, n)
- if numFail < 1 {
- t.Error("expected at least one invalid huffman encoding (test starts with one)")
- }
-}
-
-func TestReadVarInt(t *testing.T) {
- type res struct {
- i uint64
- consumed int
- err error
- }
- tests := []struct {
- n byte
- p []byte
- want res
- }{
- // Fits in a byte:
- {1, []byte{0}, res{0, 1, nil}},
- {2, []byte{2}, res{2, 1, nil}},
- {3, []byte{6}, res{6, 1, nil}},
- {4, []byte{14}, res{14, 1, nil}},
- {5, []byte{30}, res{30, 1, nil}},
- {6, []byte{62}, res{62, 1, nil}},
- {7, []byte{126}, res{126, 1, nil}},
- {8, []byte{254}, res{254, 1, nil}},
-
- // Doesn't fit in a byte:
- {1, []byte{1}, res{0, 0, errNeedMore}},
- {2, []byte{3}, res{0, 0, errNeedMore}},
- {3, []byte{7}, res{0, 0, errNeedMore}},
- {4, []byte{15}, res{0, 0, errNeedMore}},
- {5, []byte{31}, res{0, 0, errNeedMore}},
- {6, []byte{63}, res{0, 0, errNeedMore}},
- {7, []byte{127}, res{0, 0, errNeedMore}},
- {8, []byte{255}, res{0, 0, errNeedMore}},
-
- // Ignoring top bits:
- {5, []byte{255, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 111
- {5, []byte{159, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 100
- {5, []byte{191, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 101
-
- // Extra byte:
- {5, []byte{191, 154, 10, 2}, res{1337, 3, nil}}, // extra byte
-
- // Short a byte:
- {5, []byte{191, 154}, res{0, 0, errNeedMore}},
-
- // integer overflow:
- {1, []byte{255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, res{0, 0, errVarintOverflow}},
- }
- for _, tt := range tests {
- i, remain, err := readVarInt(tt.n, tt.p)
- consumed := len(tt.p) - len(remain)
- got := res{i, consumed, err}
- if got != tt.want {
- t.Errorf("readVarInt(%d, %v ~ %x) = %+v; want %+v", tt.n, tt.p, tt.p, got, tt.want)
- }
- }
-}
-
-// Fuzz crash, originally reported at https://github.com/bradfitz/http2/issues/56
-func TestHuffmanFuzzCrash(t *testing.T) {
- got, err := HuffmanDecodeToString([]byte("00\x91\xff\xff\xff\xff\xc8"))
- if got != "" {
- t.Errorf("Got %q; want empty string", got)
- }
- if err != ErrInvalidHuffman {
- t.Errorf("Err = %v; want ErrInvalidHuffman", err)
- }
-}
-
-func dehex(s string) []byte {
- s = strings.Replace(s, " ", "", -1)
- s = strings.Replace(s, "\n", "", -1)
- b, err := hex.DecodeString(s)
- if err != nil {
- panic(err)
- }
- return b
-}
-
-func TestEmitEnabled(t *testing.T) {
- var buf bytes.Buffer
- enc := NewEncoder(&buf)
- enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
- enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
-
- numCallback := 0
- var dec *Decoder
- dec = NewDecoder(8<<20, func(HeaderField) {
- numCallback++
- dec.SetEmitEnabled(false)
- })
- if !dec.EmitEnabled() {
- t.Errorf("initial emit enabled = false; want true")
- }
- if _, err := dec.Write(buf.Bytes()); err != nil {
- t.Error(err)
- }
- if numCallback != 1 {
- t.Errorf("num callbacks = %d; want 1", numCallback)
- }
- if dec.EmitEnabled() {
- t.Errorf("emit enabled = true; want false")
- }
-}
-
-func TestSaveBufLimit(t *testing.T) {
- const maxStr = 1 << 10
- var got []HeaderField
- dec := NewDecoder(initialHeaderTableSize, func(hf HeaderField) {
- got = append(got, hf)
- })
- dec.SetMaxStringLength(maxStr)
- var frag []byte
- frag = append(frag[:0], encodeTypeByte(false, false))
- frag = appendVarInt(frag, 7, 3)
- frag = append(frag, "foo"...)
- frag = appendVarInt(frag, 7, 3)
- frag = append(frag, "bar"...)
-
- if _, err := dec.Write(frag); err != nil {
- t.Fatal(err)
- }
-
- want := []HeaderField{{Name: "foo", Value: "bar"}}
- if !reflect.DeepEqual(got, want) {
- t.Errorf("After small writes, got %v; want %v", got, want)
- }
-
- frag = append(frag[:0], encodeTypeByte(false, false))
- frag = appendVarInt(frag, 7, maxStr*3)
- frag = append(frag, make([]byte, maxStr*3)...)
-
- _, err := dec.Write(frag)
- if err != ErrStringLength {
- t.Fatalf("Write error = %v; want ErrStringLength", err)
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/huffman.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/huffman.go
deleted file mode 100644
index 8850e39..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/huffman.go
+++ /dev/null
@@ -1,212 +0,0 @@
-// 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 hpack
-
-import (
- "bytes"
- "errors"
- "io"
- "sync"
-)
-
-var bufPool = sync.Pool{
- New: func() interface{} { return new(bytes.Buffer) },
-}
-
-// HuffmanDecode decodes the string in v and writes the expanded
-// result to w, returning the number of bytes written to w and the
-// Write call's return value. At most one Write call is made.
-func HuffmanDecode(w io.Writer, v []byte) (int, error) {
- buf := bufPool.Get().(*bytes.Buffer)
- buf.Reset()
- defer bufPool.Put(buf)
- if err := huffmanDecode(buf, 0, v); err != nil {
- return 0, err
- }
- return w.Write(buf.Bytes())
-}
-
-// HuffmanDecodeToString decodes the string in v.
-func HuffmanDecodeToString(v []byte) (string, error) {
- buf := bufPool.Get().(*bytes.Buffer)
- buf.Reset()
- defer bufPool.Put(buf)
- if err := huffmanDecode(buf, 0, v); err != nil {
- return "", err
- }
- return buf.String(), nil
-}
-
-// ErrInvalidHuffman is returned for errors found decoding
-// Huffman-encoded strings.
-var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data")
-
-// huffmanDecode decodes v to buf.
-// If maxLen is greater than 0, attempts to write more to buf than
-// maxLen bytes will return ErrStringLength.
-func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
- n := rootHuffmanNode
- // cur is the bit buffer that has not been fed into n.
- // cbits is the number of low order bits in cur that are valid.
- // sbits is the number of bits of the symbol prefix being decoded.
- cur, cbits, sbits := uint(0), uint8(0), uint8(0)
- for _, b := range v {
- cur = cur<<8 | uint(b)
- cbits += 8
- sbits += 8
- for cbits >= 8 {
- idx := byte(cur >> (cbits - 8))
- n = n.children[idx]
- if n == nil {
- return ErrInvalidHuffman
- }
- if n.children == nil {
- if maxLen != 0 && buf.Len() == maxLen {
- return ErrStringLength
- }
- buf.WriteByte(n.sym)
- cbits -= n.codeLen
- n = rootHuffmanNode
- sbits = cbits
- } else {
- cbits -= 8
- }
- }
- }
- for cbits > 0 {
- n = n.children[byte(cur<<(8-cbits))]
- if n == nil {
- return ErrInvalidHuffman
- }
- if n.children != nil || n.codeLen > cbits {
- break
- }
- if maxLen != 0 && buf.Len() == maxLen {
- return ErrStringLength
- }
- buf.WriteByte(n.sym)
- cbits -= n.codeLen
- n = rootHuffmanNode
- sbits = cbits
- }
- if sbits > 7 {
- // Either there was an incomplete symbol, or overlong padding.
- // Both are decoding errors per RFC 7541 section 5.2.
- return ErrInvalidHuffman
- }
- if mask := uint(1<<cbits - 1); cur&mask != mask {
- // Trailing bits must be a prefix of EOS per RFC 7541 section 5.2.
- return ErrInvalidHuffman
- }
-
- return nil
-}
-
-type node struct {
- // children is non-nil for internal nodes
- children []*node
-
- // The following are only valid if children is nil:
- codeLen uint8 // number of bits that led to the output of sym
- sym byte // output symbol
-}
-
-func newInternalNode() *node {
- return &node{children: make([]*node, 256)}
-}
-
-var rootHuffmanNode = newInternalNode()
-
-func init() {
- if len(huffmanCodes) != 256 {
- panic("unexpected size")
- }
- for i, code := range huffmanCodes {
- addDecoderNode(byte(i), code, huffmanCodeLen[i])
- }
-}
-
-func addDecoderNode(sym byte, code uint32, codeLen uint8) {
- cur := rootHuffmanNode
- for codeLen > 8 {
- codeLen -= 8
- i := uint8(code >> codeLen)
- if cur.children[i] == nil {
- cur.children[i] = newInternalNode()
- }
- cur = cur.children[i]
- }
- shift := 8 - codeLen
- start, end := int(uint8(code<<shift)), int(1<<shift)
- for i := start; i < start+end; i++ {
- cur.children[i] = &node{sym: sym, codeLen: codeLen}
- }
-}
-
-// AppendHuffmanString appends s, as encoded in Huffman codes, to dst
-// and returns the extended buffer.
-func AppendHuffmanString(dst []byte, s string) []byte {
- rembits := uint8(8)
-
- for i := 0; i < len(s); i++ {
- if rembits == 8 {
- dst = append(dst, 0)
- }
- dst, rembits = appendByteToHuffmanCode(dst, rembits, s[i])
- }
-
- if rembits < 8 {
- // special EOS symbol
- code := uint32(0x3fffffff)
- nbits := uint8(30)
-
- t := uint8(code >> (nbits - rembits))
- dst[len(dst)-1] |= t
- }
-
- return dst
-}
-
-// HuffmanEncodeLength returns the number of bytes required to encode
-// s in Huffman codes. The result is round up to byte boundary.
-func HuffmanEncodeLength(s string) uint64 {
- n := uint64(0)
- for i := 0; i < len(s); i++ {
- n += uint64(huffmanCodeLen[s[i]])
- }
- return (n + 7) / 8
-}
-
-// appendByteToHuffmanCode appends Huffman code for c to dst and
-// returns the extended buffer and the remaining bits in the last
-// element. The appending is not byte aligned and the remaining bits
-// in the last element of dst is given in rembits.
-func appendByteToHuffmanCode(dst []byte, rembits uint8, c byte) ([]byte, uint8) {
- code := huffmanCodes[c]
- nbits := huffmanCodeLen[c]
-
- for {
- if rembits > nbits {
- t := uint8(code << (rembits - nbits))
- dst[len(dst)-1] |= t
- rembits -= nbits
- break
- }
-
- t := uint8(code >> (nbits - rembits))
- dst[len(dst)-1] |= t
-
- nbits -= rembits
- rembits = 8
-
- if nbits == 0 {
- break
- }
-
- dst = append(dst, 0)
- }
-
- return dst, rembits
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/tables.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/tables.go
deleted file mode 100644
index b9283a0..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/tables.go
+++ /dev/null
@@ -1,352 +0,0 @@
-// 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 hpack
-
-func pair(name, value string) HeaderField {
- return HeaderField{Name: name, Value: value}
-}
-
-// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B
-var staticTable = [...]HeaderField{
- pair(":authority", ""), // index 1 (1-based)
- pair(":method", "GET"),
- pair(":method", "POST"),
- pair(":path", "/"),
- pair(":path", "/index.html"),
- pair(":scheme", "http"),
- pair(":scheme", "https"),
- pair(":status", "200"),
- pair(":status", "204"),
- pair(":status", "206"),
- pair(":status", "304"),
- pair(":status", "400"),
- pair(":status", "404"),
- pair(":status", "500"),
- pair("accept-charset", ""),
- pair("accept-encoding", "gzip, deflate"),
- pair("accept-language", ""),
- pair("accept-ranges", ""),
- pair("accept", ""),
- pair("access-control-allow-origin", ""),
- pair("age", ""),
- pair("allow", ""),
- pair("authorization", ""),
- pair("cache-control", ""),
- pair("content-disposition", ""),
- pair("content-encoding", ""),
- pair("content-language", ""),
- pair("content-length", ""),
- pair("content-location", ""),
- pair("content-range", ""),
- pair("content-type", ""),
- pair("cookie", ""),
- pair("date", ""),
- pair("etag", ""),
- pair("expect", ""),
- pair("expires", ""),
- pair("from", ""),
- pair("host", ""),
- pair("if-match", ""),
- pair("if-modified-since", ""),
- pair("if-none-match", ""),
- pair("if-range", ""),
- pair("if-unmodified-since", ""),
- pair("last-modified", ""),
- pair("link", ""),
- pair("location", ""),
- pair("max-forwards", ""),
- pair("proxy-authenticate", ""),
- pair("proxy-authorization", ""),
- pair("range", ""),
- pair("referer", ""),
- pair("refresh", ""),
- pair("retry-after", ""),
- pair("server", ""),
- pair("set-cookie", ""),
- pair("strict-transport-security", ""),
- pair("transfer-encoding", ""),
- pair("user-agent", ""),
- pair("vary", ""),
- pair("via", ""),
- pair("www-authenticate", ""),
-}
-
-var huffmanCodes = [256]uint32{
- 0x1ff8,
- 0x7fffd8,
- 0xfffffe2,
- 0xfffffe3,
- 0xfffffe4,
- 0xfffffe5,
- 0xfffffe6,
- 0xfffffe7,
- 0xfffffe8,
- 0xffffea,
- 0x3ffffffc,
- 0xfffffe9,
- 0xfffffea,
- 0x3ffffffd,
- 0xfffffeb,
- 0xfffffec,
- 0xfffffed,
- 0xfffffee,
- 0xfffffef,
- 0xffffff0,
- 0xffffff1,
- 0xffffff2,
- 0x3ffffffe,
- 0xffffff3,
- 0xffffff4,
- 0xffffff5,
- 0xffffff6,
- 0xffffff7,
- 0xffffff8,
- 0xffffff9,
- 0xffffffa,
- 0xffffffb,
- 0x14,
- 0x3f8,
- 0x3f9,
- 0xffa,
- 0x1ff9,
- 0x15,
- 0xf8,
- 0x7fa,
- 0x3fa,
- 0x3fb,
- 0xf9,
- 0x7fb,
- 0xfa,
- 0x16,
- 0x17,
- 0x18,
- 0x0,
- 0x1,
- 0x2,
- 0x19,
- 0x1a,
- 0x1b,
- 0x1c,
- 0x1d,
- 0x1e,
- 0x1f,
- 0x5c,
- 0xfb,
- 0x7ffc,
- 0x20,
- 0xffb,
- 0x3fc,
- 0x1ffa,
- 0x21,
- 0x5d,
- 0x5e,
- 0x5f,
- 0x60,
- 0x61,
- 0x62,
- 0x63,
- 0x64,
- 0x65,
- 0x66,
- 0x67,
- 0x68,
- 0x69,
- 0x6a,
- 0x6b,
- 0x6c,
- 0x6d,
- 0x6e,
- 0x6f,
- 0x70,
- 0x71,
- 0x72,
- 0xfc,
- 0x73,
- 0xfd,
- 0x1ffb,
- 0x7fff0,
- 0x1ffc,
- 0x3ffc,
- 0x22,
- 0x7ffd,
- 0x3,
- 0x23,
- 0x4,
- 0x24,
- 0x5,
- 0x25,
- 0x26,
- 0x27,
- 0x6,
- 0x74,
- 0x75,
- 0x28,
- 0x29,
- 0x2a,
- 0x7,
- 0x2b,
- 0x76,
- 0x2c,
- 0x8,
- 0x9,
- 0x2d,
- 0x77,
- 0x78,
- 0x79,
- 0x7a,
- 0x7b,
- 0x7ffe,
- 0x7fc,
- 0x3ffd,
- 0x1ffd,
- 0xffffffc,
- 0xfffe6,
- 0x3fffd2,
- 0xfffe7,
- 0xfffe8,
- 0x3fffd3,
- 0x3fffd4,
- 0x3fffd5,
- 0x7fffd9,
- 0x3fffd6,
- 0x7fffda,
- 0x7fffdb,
- 0x7fffdc,
- 0x7fffdd,
- 0x7fffde,
- 0xffffeb,
- 0x7fffdf,
- 0xffffec,
- 0xffffed,
- 0x3fffd7,
- 0x7fffe0,
- 0xffffee,
- 0x7fffe1,
- 0x7fffe2,
- 0x7fffe3,
- 0x7fffe4,
- 0x1fffdc,
- 0x3fffd8,
- 0x7fffe5,
- 0x3fffd9,
- 0x7fffe6,
- 0x7fffe7,
- 0xffffef,
- 0x3fffda,
- 0x1fffdd,
- 0xfffe9,
- 0x3fffdb,
- 0x3fffdc,
- 0x7fffe8,
- 0x7fffe9,
- 0x1fffde,
- 0x7fffea,
- 0x3fffdd,
- 0x3fffde,
- 0xfffff0,
- 0x1fffdf,
- 0x3fffdf,
- 0x7fffeb,
- 0x7fffec,
- 0x1fffe0,
- 0x1fffe1,
- 0x3fffe0,
- 0x1fffe2,
- 0x7fffed,
- 0x3fffe1,
- 0x7fffee,
- 0x7fffef,
- 0xfffea,
- 0x3fffe2,
- 0x3fffe3,
- 0x3fffe4,
- 0x7ffff0,
- 0x3fffe5,
- 0x3fffe6,
- 0x7ffff1,
- 0x3ffffe0,
- 0x3ffffe1,
- 0xfffeb,
- 0x7fff1,
- 0x3fffe7,
- 0x7ffff2,
- 0x3fffe8,
- 0x1ffffec,
- 0x3ffffe2,
- 0x3ffffe3,
- 0x3ffffe4,
- 0x7ffffde,
- 0x7ffffdf,
- 0x3ffffe5,
- 0xfffff1,
- 0x1ffffed,
- 0x7fff2,
- 0x1fffe3,
- 0x3ffffe6,
- 0x7ffffe0,
- 0x7ffffe1,
- 0x3ffffe7,
- 0x7ffffe2,
- 0xfffff2,
- 0x1fffe4,
- 0x1fffe5,
- 0x3ffffe8,
- 0x3ffffe9,
- 0xffffffd,
- 0x7ffffe3,
- 0x7ffffe4,
- 0x7ffffe5,
- 0xfffec,
- 0xfffff3,
- 0xfffed,
- 0x1fffe6,
- 0x3fffe9,
- 0x1fffe7,
- 0x1fffe8,
- 0x7ffff3,
- 0x3fffea,
- 0x3fffeb,
- 0x1ffffee,
- 0x1ffffef,
- 0xfffff4,
- 0xfffff5,
- 0x3ffffea,
- 0x7ffff4,
- 0x3ffffeb,
- 0x7ffffe6,
- 0x3ffffec,
- 0x3ffffed,
- 0x7ffffe7,
- 0x7ffffe8,
- 0x7ffffe9,
- 0x7ffffea,
- 0x7ffffeb,
- 0xffffffe,
- 0x7ffffec,
- 0x7ffffed,
- 0x7ffffee,
- 0x7ffffef,
- 0x7fffff0,
- 0x3ffffee,
-}
-
-var huffmanCodeLen = [256]uint8{
- 13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28,
- 28, 28, 28, 28, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28,
- 6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6,
- 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10,
- 13, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6,
- 15, 5, 6, 5, 6, 5, 6, 6, 6, 5, 7, 7, 6, 6, 6, 5,
- 6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, 28,
- 20, 22, 20, 20, 22, 22, 22, 23, 22, 23, 23, 23, 23, 23, 24, 23,
- 24, 24, 22, 23, 24, 23, 23, 23, 23, 21, 22, 23, 22, 23, 23, 24,
- 22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, 24, 21, 22, 23, 23,
- 21, 21, 22, 21, 23, 22, 23, 23, 20, 22, 22, 22, 23, 22, 22, 23,
- 26, 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27, 26, 24, 25,
- 19, 21, 26, 27, 27, 26, 27, 24, 21, 21, 26, 26, 28, 27, 27, 27,
- 20, 24, 20, 21, 22, 21, 21, 23, 22, 22, 25, 25, 24, 24, 26, 23,
- 26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27, 27, 27, 27, 27, 26,
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/http2.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/http2.go
deleted file mode 100644
index b6b0f9a..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/http2.go
+++ /dev/null
@@ -1,387 +0,0 @@
-// 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 http2 implements the HTTP/2 protocol.
-//
-// This package is low-level and intended to be used directly by very
-// few people. Most users will use it indirectly through the automatic
-// use by the net/http package (from Go 1.6 and later).
-// For use in earlier Go versions see ConfigureServer. (Transport support
-// requires Go 1.6 or later)
-//
-// See https://http2.github.io/ for more information on HTTP/2.
-//
-// See https://http2.golang.org/ for a test server running this code.
-//
-package http2 // import "golang.org/x/net/http2"
-
-import (
- "bufio"
- "crypto/tls"
- "errors"
- "fmt"
- "io"
- "net/http"
- "os"
- "sort"
- "strconv"
- "strings"
- "sync"
-
- "golang.org/x/net/lex/httplex"
-)
-
-var (
- VerboseLogs bool
- logFrameWrites bool
- logFrameReads bool
- inTests bool
-)
-
-func init() {
- e := os.Getenv("GODEBUG")
- if strings.Contains(e, "http2debug=1") {
- VerboseLogs = true
- }
- if strings.Contains(e, "http2debug=2") {
- VerboseLogs = true
- logFrameWrites = true
- logFrameReads = true
- }
-}
-
-const (
- // ClientPreface is the string that must be sent by new
- // connections from clients.
- ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
-
- // SETTINGS_MAX_FRAME_SIZE default
- // http://http2.github.io/http2-spec/#rfc.section.6.5.2
- initialMaxFrameSize = 16384
-
- // NextProtoTLS is the NPN/ALPN protocol negotiated during
- // HTTP/2's TLS setup.
- NextProtoTLS = "h2"
-
- // http://http2.github.io/http2-spec/#SettingValues
- initialHeaderTableSize = 4096
-
- initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size
-
- defaultMaxReadFrameSize = 1 << 20
-)
-
-var (
- clientPreface = []byte(ClientPreface)
-)
-
-type streamState int
-
-// HTTP/2 stream states.
-//
-// See http://tools.ietf.org/html/rfc7540#section-5.1.
-//
-// For simplicity, the server code merges "reserved (local)" into
-// "half-closed (remote)". This is one less state transition to track.
-// The only downside is that we send PUSH_PROMISEs slightly less
-// liberally than allowable. More discussion here:
-// https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0599.html
-//
-// "reserved (remote)" is omitted since the client code does not
-// support server push.
-const (
- stateIdle streamState = iota
- stateOpen
- stateHalfClosedLocal
- stateHalfClosedRemote
- stateClosed
-)
-
-var stateName = [...]string{
- stateIdle: "Idle",
- stateOpen: "Open",
- stateHalfClosedLocal: "HalfClosedLocal",
- stateHalfClosedRemote: "HalfClosedRemote",
- stateClosed: "Closed",
-}
-
-func (st streamState) String() string {
- return stateName[st]
-}
-
-// Setting is a setting parameter: which setting it is, and its value.
-type Setting struct {
- // ID is which setting is being set.
- // See http://http2.github.io/http2-spec/#SettingValues
- ID SettingID
-
- // Val is the value.
- Val uint32
-}
-
-func (s Setting) String() string {
- return fmt.Sprintf("[%v = %d]", s.ID, s.Val)
-}
-
-// Valid reports whether the setting is valid.
-func (s Setting) Valid() error {
- // Limits and error codes from 6.5.2 Defined SETTINGS Parameters
- switch s.ID {
- case SettingEnablePush:
- if s.Val != 1 && s.Val != 0 {
- return ConnectionError(ErrCodeProtocol)
- }
- case SettingInitialWindowSize:
- if s.Val > 1<<31-1 {
- return ConnectionError(ErrCodeFlowControl)
- }
- case SettingMaxFrameSize:
- if s.Val < 16384 || s.Val > 1<<24-1 {
- return ConnectionError(ErrCodeProtocol)
- }
- }
- return nil
-}
-
-// A SettingID is an HTTP/2 setting as defined in
-// http://http2.github.io/http2-spec/#iana-settings
-type SettingID uint16
-
-const (
- SettingHeaderTableSize SettingID = 0x1
- SettingEnablePush SettingID = 0x2
- SettingMaxConcurrentStreams SettingID = 0x3
- SettingInitialWindowSize SettingID = 0x4
- SettingMaxFrameSize SettingID = 0x5
- SettingMaxHeaderListSize SettingID = 0x6
-)
-
-var settingName = map[SettingID]string{
- SettingHeaderTableSize: "HEADER_TABLE_SIZE",
- SettingEnablePush: "ENABLE_PUSH",
- SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS",
- SettingInitialWindowSize: "INITIAL_WINDOW_SIZE",
- SettingMaxFrameSize: "MAX_FRAME_SIZE",
- SettingMaxHeaderListSize: "MAX_HEADER_LIST_SIZE",
-}
-
-func (s SettingID) String() string {
- if v, ok := settingName[s]; ok {
- return v
- }
- return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s))
-}
-
-var (
- errInvalidHeaderFieldName = errors.New("http2: invalid header field name")
- errInvalidHeaderFieldValue = errors.New("http2: invalid header field value")
-)
-
-// validWireHeaderFieldName reports whether v is a valid header field
-// name (key). See httplex.ValidHeaderName for the base rules.
-//
-// Further, http2 says:
-// "Just as in HTTP/1.x, header field names are strings of ASCII
-// characters that are compared in a case-insensitive
-// fashion. However, header field names MUST be converted to
-// lowercase prior to their encoding in HTTP/2. "
-func validWireHeaderFieldName(v string) bool {
- if len(v) == 0 {
- return false
- }
- for _, r := range v {
- if !httplex.IsTokenRune(r) {
- return false
- }
- if 'A' <= r && r <= 'Z' {
- return false
- }
- }
- return true
-}
-
-var httpCodeStringCommon = map[int]string{} // n -> strconv.Itoa(n)
-
-func init() {
- for i := 100; i <= 999; i++ {
- if v := http.StatusText(i); v != "" {
- httpCodeStringCommon[i] = strconv.Itoa(i)
- }
- }
-}
-
-func httpCodeString(code int) string {
- if s, ok := httpCodeStringCommon[code]; ok {
- return s
- }
- return strconv.Itoa(code)
-}
-
-// from pkg io
-type stringWriter interface {
- WriteString(s string) (n int, err error)
-}
-
-// A gate lets two goroutines coordinate their activities.
-type gate chan struct{}
-
-func (g gate) Done() { g <- struct{}{} }
-func (g gate) Wait() { <-g }
-
-// A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed).
-type closeWaiter chan struct{}
-
-// Init makes a closeWaiter usable.
-// It exists because so a closeWaiter value can be placed inside a
-// larger struct and have the Mutex and Cond's memory in the same
-// allocation.
-func (cw *closeWaiter) Init() {
- *cw = make(chan struct{})
-}
-
-// Close marks the closeWaiter as closed and unblocks any waiters.
-func (cw closeWaiter) Close() {
- close(cw)
-}
-
-// Wait waits for the closeWaiter to become closed.
-func (cw closeWaiter) Wait() {
- <-cw
-}
-
-// bufferedWriter is a buffered writer that writes to w.
-// Its buffered writer is lazily allocated as needed, to minimize
-// idle memory usage with many connections.
-type bufferedWriter struct {
- w io.Writer // immutable
- bw *bufio.Writer // non-nil when data is buffered
-}
-
-func newBufferedWriter(w io.Writer) *bufferedWriter {
- return &bufferedWriter{w: w}
-}
-
-// bufWriterPoolBufferSize is the size of bufio.Writer's
-// buffers created using bufWriterPool.
-//
-// TODO: pick a less arbitrary value? this is a bit under
-// (3 x typical 1500 byte MTU) at least. Other than that,
-// not much thought went into it.
-const bufWriterPoolBufferSize = 4 << 10
-
-var bufWriterPool = sync.Pool{
- New: func() interface{} {
- return bufio.NewWriterSize(nil, bufWriterPoolBufferSize)
- },
-}
-
-func (w *bufferedWriter) Available() int {
- if w.bw == nil {
- return bufWriterPoolBufferSize
- }
- return w.bw.Available()
-}
-
-func (w *bufferedWriter) Write(p []byte) (n int, err error) {
- if w.bw == nil {
- bw := bufWriterPool.Get().(*bufio.Writer)
- bw.Reset(w.w)
- w.bw = bw
- }
- return w.bw.Write(p)
-}
-
-func (w *bufferedWriter) Flush() error {
- bw := w.bw
- if bw == nil {
- return nil
- }
- err := bw.Flush()
- bw.Reset(nil)
- bufWriterPool.Put(bw)
- w.bw = nil
- return err
-}
-
-func mustUint31(v int32) uint32 {
- if v < 0 || v > 2147483647 {
- panic("out of range")
- }
- return uint32(v)
-}
-
-// bodyAllowedForStatus reports whether a given response status code
-// permits a body. See RFC 2616, section 4.4.
-func bodyAllowedForStatus(status int) bool {
- switch {
- case status >= 100 && status <= 199:
- return false
- case status == 204:
- return false
- case status == 304:
- return false
- }
- return true
-}
-
-type httpError struct {
- msg string
- timeout bool
-}
-
-func (e *httpError) Error() string { return e.msg }
-func (e *httpError) Timeout() bool { return e.timeout }
-func (e *httpError) Temporary() bool { return true }
-
-var errTimeout error = &httpError{msg: "http2: timeout awaiting response headers", timeout: true}
-
-type connectionStater interface {
- ConnectionState() tls.ConnectionState
-}
-
-var sorterPool = sync.Pool{New: func() interface{} { return new(sorter) }}
-
-type sorter struct {
- v []string // owned by sorter
-}
-
-func (s *sorter) Len() int { return len(s.v) }
-func (s *sorter) Swap(i, j int) { s.v[i], s.v[j] = s.v[j], s.v[i] }
-func (s *sorter) Less(i, j int) bool { return s.v[i] < s.v[j] }
-
-// Keys returns the sorted keys of h.
-//
-// The returned slice is only valid until s used again or returned to
-// its pool.
-func (s *sorter) Keys(h http.Header) []string {
- keys := s.v[:0]
- for k := range h {
- keys = append(keys, k)
- }
- s.v = keys
- sort.Sort(s)
- return keys
-}
-
-func (s *sorter) SortStrings(ss []string) {
- // Our sorter works on s.v, which sorter owns, so
- // stash it away while we sort the user's buffer.
- save := s.v
- s.v = ss
- sort.Sort(s)
- s.v = save
-}
-
-// validPseudoPath reports whether v is a valid :path pseudo-header
-// value. It must be either:
-//
-// *) a non-empty string starting with '/', but not with with "//",
-// *) the string '*', for OPTIONS requests.
-//
-// For now this is only used a quick check for deciding when to clean
-// up Opaque URLs before sending requests from the Transport.
-// See golang.org/issue/16847
-func validPseudoPath(v string) bool {
- return (len(v) > 0 && v[0] == '/' && (len(v) == 1 || v[1] != '/')) || v == "*"
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/http2_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/http2_test.go
deleted file mode 100644
index 5248776..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/http2_test.go
+++ /dev/null
@@ -1,199 +0,0 @@
-// 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 http2
-
-import (
- "bytes"
- "errors"
- "flag"
- "fmt"
- "net/http"
- "os/exec"
- "strconv"
- "strings"
- "testing"
-
- "golang.org/x/net/http2/hpack"
-)
-
-var knownFailing = flag.Bool("known_failing", false, "Run known-failing tests.")
-
-func condSkipFailingTest(t *testing.T) {
- if !*knownFailing {
- t.Skip("Skipping known-failing test without --known_failing")
- }
-}
-
-func init() {
- inTests = true
- DebugGoroutines = true
- flag.BoolVar(&VerboseLogs, "verboseh2", VerboseLogs, "Verbose HTTP/2 debug logging")
-}
-
-func TestSettingString(t *testing.T) {
- tests := []struct {
- s Setting
- want string
- }{
- {Setting{SettingMaxFrameSize, 123}, "[MAX_FRAME_SIZE = 123]"},
- {Setting{1<<16 - 1, 123}, "[UNKNOWN_SETTING_65535 = 123]"},
- }
- for i, tt := range tests {
- got := fmt.Sprint(tt.s)
- if got != tt.want {
- t.Errorf("%d. for %#v, string = %q; want %q", i, tt.s, got, tt.want)
- }
- }
-}
-
-type twriter struct {
- t testing.TB
- st *serverTester // optional
-}
-
-func (w twriter) Write(p []byte) (n int, err error) {
- if w.st != nil {
- ps := string(p)
- for _, phrase := range w.st.logFilter {
- if strings.Contains(ps, phrase) {
- return len(p), nil // no logging
- }
- }
- }
- w.t.Logf("%s", p)
- return len(p), nil
-}
-
-// like encodeHeader, but don't add implicit pseudo headers.
-func encodeHeaderNoImplicit(t *testing.T, headers ...string) []byte {
- var buf bytes.Buffer
- enc := hpack.NewEncoder(&buf)
- for len(headers) > 0 {
- k, v := headers[0], headers[1]
- headers = headers[2:]
- if err := enc.WriteField(hpack.HeaderField{Name: k, Value: v}); err != nil {
- t.Fatalf("HPACK encoding error for %q/%q: %v", k, v, err)
- }
- }
- return buf.Bytes()
-}
-
-// Verify that curl has http2.
-func requireCurl(t *testing.T) {
- out, err := dockerLogs(curl(t, "--version"))
- if err != nil {
- t.Skipf("failed to determine curl features; skipping test")
- }
- if !strings.Contains(string(out), "HTTP2") {
- t.Skip("curl doesn't support HTTP2; skipping test")
- }
-}
-
-func curl(t *testing.T, args ...string) (container string) {
- out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "gohttp2/curl"}, args...)...).Output()
- if err != nil {
- t.Skipf("Failed to run curl in docker: %v, %s", err, out)
- }
- return strings.TrimSpace(string(out))
-}
-
-// Verify that h2load exists.
-func requireH2load(t *testing.T) {
- out, err := dockerLogs(h2load(t, "--version"))
- if err != nil {
- t.Skipf("failed to probe h2load; skipping test: %s", out)
- }
- if !strings.Contains(string(out), "h2load nghttp2/") {
- t.Skipf("h2load not present; skipping test. (Output=%q)", out)
- }
-}
-
-func h2load(t *testing.T, args ...string) (container string) {
- out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "--entrypoint=/usr/local/bin/h2load", "gohttp2/curl"}, args...)...).Output()
- if err != nil {
- t.Skipf("Failed to run h2load in docker: %v, %s", err, out)
- }
- return strings.TrimSpace(string(out))
-}
-
-type puppetCommand struct {
- fn func(w http.ResponseWriter, r *http.Request)
- done chan<- bool
-}
-
-type handlerPuppet struct {
- ch chan puppetCommand
-}
-
-func newHandlerPuppet() *handlerPuppet {
- return &handlerPuppet{
- ch: make(chan puppetCommand),
- }
-}
-
-func (p *handlerPuppet) act(w http.ResponseWriter, r *http.Request) {
- for cmd := range p.ch {
- cmd.fn(w, r)
- cmd.done <- true
- }
-}
-
-func (p *handlerPuppet) done() { close(p.ch) }
-func (p *handlerPuppet) do(fn func(http.ResponseWriter, *http.Request)) {
- done := make(chan bool)
- p.ch <- puppetCommand{fn, done}
- <-done
-}
-func dockerLogs(container string) ([]byte, error) {
- out, err := exec.Command("docker", "wait", container).CombinedOutput()
- if err != nil {
- return out, err
- }
- exitStatus, err := strconv.Atoi(strings.TrimSpace(string(out)))
- if err != nil {
- return out, errors.New("unexpected exit status from docker wait")
- }
- out, err = exec.Command("docker", "logs", container).CombinedOutput()
- exec.Command("docker", "rm", container).Run()
- if err == nil && exitStatus != 0 {
- err = fmt.Errorf("exit status %d: %s", exitStatus, out)
- }
- return out, err
-}
-
-func kill(container string) {
- exec.Command("docker", "kill", container).Run()
- exec.Command("docker", "rm", container).Run()
-}
-
-func cleanDate(res *http.Response) {
- if d := res.Header["Date"]; len(d) == 1 {
- d[0] = "XXX"
- }
-}
-
-func TestSorterPoolAllocs(t *testing.T) {
- ss := []string{"a", "b", "c"}
- h := http.Header{
- "a": nil,
- "b": nil,
- "c": nil,
- }
- sorter := new(sorter)
-
- if allocs := testing.AllocsPerRun(100, func() {
- sorter.SortStrings(ss)
- }); allocs >= 1 {
- t.Logf("SortStrings allocs = %v; want <1", allocs)
- }
-
- if allocs := testing.AllocsPerRun(5, func() {
- if len(sorter.Keys(h)) != 3 {
- t.Fatal("wrong result")
- }
- }); allocs > 0 {
- t.Logf("Keys allocs = %v; want <1", allocs)
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/not_go16.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/not_go16.go
deleted file mode 100644
index efd2e12..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/not_go16.go
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-
-// +build !go1.6
-
-package http2
-
-import (
- "crypto/tls"
- "net/http"
- "time"
-)
-
-func configureTransport(t1 *http.Transport) (*Transport, error) {
- return nil, errTransportVersion
-}
-
-func transportExpectContinueTimeout(t1 *http.Transport) time.Duration {
- return 0
-
-}
-
-// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
-func isBadCipher(cipher uint16) bool {
- switch cipher {
- case tls.TLS_RSA_WITH_RC4_128_SHA,
- tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
- tls.TLS_RSA_WITH_AES_128_CBC_SHA,
- tls.TLS_RSA_WITH_AES_256_CBC_SHA,
- tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
- tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
- tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
- tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
- tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
- tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- // Reject cipher suites from Appendix A.
- // "This list includes those cipher suites that do not
- // offer an ephemeral key exchange and those that are
- // based on the TLS null, stream or block cipher type"
- return true
- default:
- return false
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/not_go17.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/not_go17.go
deleted file mode 100644
index 140434a..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/not_go17.go
+++ /dev/null
@@ -1,87 +0,0 @@
-// 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 http2
-
-import (
- "crypto/tls"
- "net"
- "net/http"
- "time"
-)
-
-type contextContext interface {
- Done() <-chan struct{}
- Err() error
-}
-
-type fakeContext struct{}
-
-func (fakeContext) Done() <-chan struct{} { return nil }
-func (fakeContext) Err() error { panic("should not be called") }
-
-func reqContext(r *http.Request) fakeContext {
- return fakeContext{}
-}
-
-func setResponseUncompressed(res *http.Response) {
- // Nothing.
-}
-
-type clientTrace struct{}
-
-func requestTrace(*http.Request) *clientTrace { return nil }
-func traceGotConn(*http.Request, *ClientConn) {}
-func traceFirstResponseByte(*clientTrace) {}
-func traceWroteHeaders(*clientTrace) {}
-func traceWroteRequest(*clientTrace, error) {}
-func traceGot100Continue(trace *clientTrace) {}
-func traceWait100Continue(trace *clientTrace) {}
-
-func nop() {}
-
-func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx contextContext, cancel func()) {
- return nil, nop
-}
-
-func contextWithCancel(ctx contextContext) (_ contextContext, cancel func()) {
- return ctx, nop
-}
-
-func requestWithContext(req *http.Request, ctx contextContext) *http.Request {
- return req
-}
-
-// temporary copy of Go 1.6's private tls.Config.clone:
-func cloneTLSConfig(c *tls.Config) *tls.Config {
- return &tls.Config{
- Rand: c.Rand,
- Time: c.Time,
- Certificates: c.Certificates,
- NameToCertificate: c.NameToCertificate,
- GetCertificate: c.GetCertificate,
- RootCAs: c.RootCAs,
- NextProtos: c.NextProtos,
- ServerName: c.ServerName,
- ClientAuth: c.ClientAuth,
- ClientCAs: c.ClientCAs,
- InsecureSkipVerify: c.InsecureSkipVerify,
- CipherSuites: c.CipherSuites,
- PreferServerCipherSuites: c.PreferServerCipherSuites,
- SessionTicketsDisabled: c.SessionTicketsDisabled,
- SessionTicketKey: c.SessionTicketKey,
- ClientSessionCache: c.ClientSessionCache,
- MinVersion: c.MinVersion,
- MaxVersion: c.MaxVersion,
- CurvePreferences: c.CurvePreferences,
- }
-}
-
-func (cc *ClientConn) Ping(ctx contextContext) error {
- return cc.ping(ctx)
-}
-
-func (t *Transport) idleConnTimeout() time.Duration { return 0 }
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/not_go18.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/not_go18.go
deleted file mode 100644
index efbf83c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/not_go18.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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.8
-
-package http2
-
-import (
- "io"
- "net/http"
-)
-
-func configureServer18(h1 *http.Server, h2 *Server) error {
- // No IdleTimeout to sync prior to Go 1.8.
- return nil
-}
-
-func shouldLogPanic(panicValue interface{}) bool {
- return panicValue != nil
-}
-
-func reqGetBody(req *http.Request) func() (io.ReadCloser, error) {
- return nil
-}
-
-func reqBodyIsNoBody(io.ReadCloser) bool { return false }
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/pipe.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/pipe.go
deleted file mode 100644
index 914aaf8..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/pipe.go
+++ /dev/null
@@ -1,153 +0,0 @@
-// 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 http2
-
-import (
- "errors"
- "io"
- "sync"
-)
-
-// pipe is a goroutine-safe io.Reader/io.Writer pair. It's like
-// io.Pipe except there are no PipeReader/PipeWriter halves, and the
-// underlying buffer is an interface. (io.Pipe is always unbuffered)
-type pipe struct {
- mu sync.Mutex
- c sync.Cond // c.L lazily initialized to &p.mu
- b pipeBuffer
- err error // read error once empty. non-nil means closed.
- breakErr error // immediate read error (caller doesn't see rest of b)
- donec chan struct{} // closed on error
- readFn func() // optional code to run in Read before error
-}
-
-type pipeBuffer interface {
- Len() int
- io.Writer
- io.Reader
-}
-
-func (p *pipe) Len() int {
- p.mu.Lock()
- defer p.mu.Unlock()
- return p.b.Len()
-}
-
-// Read waits until data is available and copies bytes
-// from the buffer into p.
-func (p *pipe) Read(d []byte) (n int, err error) {
- p.mu.Lock()
- defer p.mu.Unlock()
- if p.c.L == nil {
- p.c.L = &p.mu
- }
- for {
- if p.breakErr != nil {
- return 0, p.breakErr
- }
- if p.b.Len() > 0 {
- return p.b.Read(d)
- }
- if p.err != nil {
- if p.readFn != nil {
- p.readFn() // e.g. copy trailers
- p.readFn = nil // not sticky like p.err
- }
- return 0, p.err
- }
- p.c.Wait()
- }
-}
-
-var errClosedPipeWrite = errors.New("write on closed buffer")
-
-// Write copies bytes from p into the buffer and wakes a reader.
-// It is an error to write more data than the buffer can hold.
-func (p *pipe) Write(d []byte) (n int, err error) {
- p.mu.Lock()
- defer p.mu.Unlock()
- if p.c.L == nil {
- p.c.L = &p.mu
- }
- defer p.c.Signal()
- if p.err != nil {
- return 0, errClosedPipeWrite
- }
- return p.b.Write(d)
-}
-
-// CloseWithError causes the next Read (waking up a current blocked
-// Read if needed) to return the provided err after all data has been
-// read.
-//
-// The error must be non-nil.
-func (p *pipe) CloseWithError(err error) { p.closeWithError(&p.err, err, nil) }
-
-// BreakWithError causes the next Read (waking up a current blocked
-// Read if needed) to return the provided err immediately, without
-// waiting for unread data.
-func (p *pipe) BreakWithError(err error) { p.closeWithError(&p.breakErr, err, nil) }
-
-// closeWithErrorAndCode is like CloseWithError but also sets some code to run
-// in the caller's goroutine before returning the error.
-func (p *pipe) closeWithErrorAndCode(err error, fn func()) { p.closeWithError(&p.err, err, fn) }
-
-func (p *pipe) closeWithError(dst *error, err error, fn func()) {
- if err == nil {
- panic("err must be non-nil")
- }
- p.mu.Lock()
- defer p.mu.Unlock()
- if p.c.L == nil {
- p.c.L = &p.mu
- }
- defer p.c.Signal()
- if *dst != nil {
- // Already been done.
- return
- }
- p.readFn = fn
- *dst = err
- p.closeDoneLocked()
-}
-
-// requires p.mu be held.
-func (p *pipe) closeDoneLocked() {
- if p.donec == nil {
- return
- }
- // Close if unclosed. This isn't racy since we always
- // hold p.mu while closing.
- select {
- case <-p.donec:
- default:
- close(p.donec)
- }
-}
-
-// Err returns the error (if any) first set by BreakWithError or CloseWithError.
-func (p *pipe) Err() error {
- p.mu.Lock()
- defer p.mu.Unlock()
- if p.breakErr != nil {
- return p.breakErr
- }
- return p.err
-}
-
-// Done returns a channel which is closed if and when this pipe is closed
-// with CloseWithError.
-func (p *pipe) Done() <-chan struct{} {
- p.mu.Lock()
- defer p.mu.Unlock()
- if p.donec == nil {
- p.donec = make(chan struct{})
- if p.err != nil || p.breakErr != nil {
- // Already hit an error.
- p.closeDoneLocked()
- }
- }
- return p.donec
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/pipe_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/pipe_test.go
deleted file mode 100644
index 7632299..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/pipe_test.go
+++ /dev/null
@@ -1,109 +0,0 @@
-// 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 http2
-
-import (
- "bytes"
- "errors"
- "io"
- "io/ioutil"
- "testing"
-)
-
-func TestPipeClose(t *testing.T) {
- var p pipe
- p.b = new(bytes.Buffer)
- a := errors.New("a")
- b := errors.New("b")
- p.CloseWithError(a)
- p.CloseWithError(b)
- _, err := p.Read(make([]byte, 1))
- if err != a {
- t.Errorf("err = %v want %v", err, a)
- }
-}
-
-func TestPipeDoneChan(t *testing.T) {
- var p pipe
- done := p.Done()
- select {
- case <-done:
- t.Fatal("done too soon")
- default:
- }
- p.CloseWithError(io.EOF)
- select {
- case <-done:
- default:
- t.Fatal("should be done")
- }
-}
-
-func TestPipeDoneChan_ErrFirst(t *testing.T) {
- var p pipe
- p.CloseWithError(io.EOF)
- done := p.Done()
- select {
- case <-done:
- default:
- t.Fatal("should be done")
- }
-}
-
-func TestPipeDoneChan_Break(t *testing.T) {
- var p pipe
- done := p.Done()
- select {
- case <-done:
- t.Fatal("done too soon")
- default:
- }
- p.BreakWithError(io.EOF)
- select {
- case <-done:
- default:
- t.Fatal("should be done")
- }
-}
-
-func TestPipeDoneChan_Break_ErrFirst(t *testing.T) {
- var p pipe
- p.BreakWithError(io.EOF)
- done := p.Done()
- select {
- case <-done:
- default:
- t.Fatal("should be done")
- }
-}
-
-func TestPipeCloseWithError(t *testing.T) {
- p := &pipe{b: new(bytes.Buffer)}
- const body = "foo"
- io.WriteString(p, body)
- a := errors.New("test error")
- p.CloseWithError(a)
- all, err := ioutil.ReadAll(p)
- if string(all) != body {
- t.Errorf("read bytes = %q; want %q", all, body)
- }
- if err != a {
- t.Logf("read error = %v, %v", err, a)
- }
-}
-
-func TestPipeBreakWithError(t *testing.T) {
- p := &pipe{b: new(bytes.Buffer)}
- io.WriteString(p, "foo")
- a := errors.New("test err")
- p.BreakWithError(a)
- all, err := ioutil.ReadAll(p)
- if string(all) != "" {
- t.Errorf("read bytes = %q; want empty string", all)
- }
- if err != a {
- t.Logf("read error = %v, %v", err, a)
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/server.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/server.go
deleted file mode 100644
index 3c641a8..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/server.go
+++ /dev/null
@@ -1,2753 +0,0 @@
-// 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.
-
-// TODO: turn off the serve goroutine when idle, so
-// an idle conn only has the readFrames goroutine active. (which could
-// also be optimized probably to pin less memory in crypto/tls). This
-// would involve tracking when the serve goroutine is active (atomic
-// int32 read/CAS probably?) and starting it up when frames arrive,
-// and shutting it down when all handlers exit. the occasional PING
-// packets could use time.AfterFunc to call sc.wakeStartServeLoop()
-// (which is a no-op if already running) and then queue the PING write
-// as normal. The serve loop would then exit in most cases (if no
-// Handlers running) and not be woken up again until the PING packet
-// returns.
-
-// TODO (maybe): add a mechanism for Handlers to going into
-// half-closed-local mode (rw.(io.Closer) test?) but not exit their
-// handler, and continue to be able to read from the
-// Request.Body. This would be a somewhat semantic change from HTTP/1
-// (or at least what we expose in net/http), so I'd probably want to
-// add it there too. For now, this package says that returning from
-// the Handler ServeHTTP function means you're both done reading and
-// done writing, without a way to stop just one or the other.
-
-package http2
-
-import (
- "bufio"
- "bytes"
- "crypto/tls"
- "errors"
- "fmt"
- "io"
- "log"
- "math"
- "net"
- "net/http"
- "net/textproto"
- "net/url"
- "os"
- "reflect"
- "runtime"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "golang.org/x/net/http2/hpack"
-)
-
-const (
- prefaceTimeout = 10 * time.Second
- firstSettingsTimeout = 2 * time.Second // should be in-flight with preface anyway
- handlerChunkWriteSize = 4 << 10
- defaultMaxStreams = 250 // TODO: make this 100 as the GFE seems to?
-)
-
-var (
- errClientDisconnected = errors.New("client disconnected")
- errClosedBody = errors.New("body closed by handler")
- errHandlerComplete = errors.New("http2: request body closed due to handler exiting")
- errStreamClosed = errors.New("http2: stream closed")
-)
-
-var responseWriterStatePool = sync.Pool{
- New: func() interface{} {
- rws := &responseWriterState{}
- rws.bw = bufio.NewWriterSize(chunkWriter{rws}, handlerChunkWriteSize)
- return rws
- },
-}
-
-// Test hooks.
-var (
- testHookOnConn func()
- testHookGetServerConn func(*serverConn)
- testHookOnPanicMu *sync.Mutex // nil except in tests
- testHookOnPanic func(sc *serverConn, panicVal interface{}) (rePanic bool)
-)
-
-// Server is an HTTP/2 server.
-type Server struct {
- // MaxHandlers limits the number of http.Handler ServeHTTP goroutines
- // which may run at a time over all connections.
- // Negative or zero no limit.
- // TODO: implement
- MaxHandlers int
-
- // MaxConcurrentStreams optionally specifies the number of
- // concurrent streams that each client may have open at a
- // time. This is unrelated to the number of http.Handler goroutines
- // which may be active globally, which is MaxHandlers.
- // If zero, MaxConcurrentStreams defaults to at least 100, per
- // the HTTP/2 spec's recommendations.
- MaxConcurrentStreams uint32
-
- // MaxReadFrameSize optionally specifies the largest frame
- // this server is willing to read. A valid value is between
- // 16k and 16M, inclusive. If zero or otherwise invalid, a
- // default value is used.
- MaxReadFrameSize uint32
-
- // PermitProhibitedCipherSuites, if true, permits the use of
- // cipher suites prohibited by the HTTP/2 spec.
- PermitProhibitedCipherSuites bool
-
- // IdleTimeout specifies how long until idle clients should be
- // closed with a GOAWAY frame. PING frames are not considered
- // activity for the purposes of IdleTimeout.
- IdleTimeout time.Duration
-
- // NewWriteScheduler constructs a write scheduler for a connection.
- // If nil, a default scheduler is chosen.
- NewWriteScheduler func() WriteScheduler
-}
-
-func (s *Server) maxReadFrameSize() uint32 {
- if v := s.MaxReadFrameSize; v >= minMaxFrameSize && v <= maxFrameSize {
- return v
- }
- return defaultMaxReadFrameSize
-}
-
-func (s *Server) maxConcurrentStreams() uint32 {
- if v := s.MaxConcurrentStreams; v > 0 {
- return v
- }
- return defaultMaxStreams
-}
-
-// ConfigureServer adds HTTP/2 support to a net/http Server.
-//
-// The configuration conf may be nil.
-//
-// ConfigureServer must be called before s begins serving.
-func ConfigureServer(s *http.Server, conf *Server) error {
- if s == nil {
- panic("nil *http.Server")
- }
- if conf == nil {
- conf = new(Server)
- }
- if err := configureServer18(s, conf); err != nil {
- return err
- }
-
- if s.TLSConfig == nil {
- s.TLSConfig = new(tls.Config)
- } else if s.TLSConfig.CipherSuites != nil {
- // If they already provided a CipherSuite list, return
- // an error if it has a bad order or is missing
- // ECDHE_RSA_WITH_AES_128_GCM_SHA256.
- const requiredCipher = tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- haveRequired := false
- sawBad := false
- for i, cs := range s.TLSConfig.CipherSuites {
- if cs == requiredCipher {
- haveRequired = true
- }
- if isBadCipher(cs) {
- sawBad = true
- } else if sawBad {
- return fmt.Errorf("http2: TLSConfig.CipherSuites index %d contains an HTTP/2-approved cipher suite (%#04x), but it comes after unapproved cipher suites. With this configuration, clients that don't support previous, approved cipher suites may be given an unapproved one and reject the connection.", i, cs)
- }
- }
- if !haveRequired {
- return fmt.Errorf("http2: TLSConfig.CipherSuites is missing HTTP/2-required TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")
- }
- }
-
- // Note: not setting MinVersion to tls.VersionTLS12,
- // as we don't want to interfere with HTTP/1.1 traffic
- // on the user's server. We enforce TLS 1.2 later once
- // we accept a connection. Ideally this should be done
- // during next-proto selection, but using TLS <1.2 with
- // HTTP/2 is still the client's bug.
-
- s.TLSConfig.PreferServerCipherSuites = true
-
- haveNPN := false
- for _, p := range s.TLSConfig.NextProtos {
- if p == NextProtoTLS {
- haveNPN = true
- break
- }
- }
- if !haveNPN {
- s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, NextProtoTLS)
- }
-
- if s.TLSNextProto == nil {
- s.TLSNextProto = map[string]func(*http.Server, *tls.Conn, http.Handler){}
- }
- protoHandler := func(hs *http.Server, c *tls.Conn, h http.Handler) {
- if testHookOnConn != nil {
- testHookOnConn()
- }
- conf.ServeConn(c, &ServeConnOpts{
- Handler: h,
- BaseConfig: hs,
- })
- }
- s.TLSNextProto[NextProtoTLS] = protoHandler
- return nil
-}
-
-// ServeConnOpts are options for the Server.ServeConn method.
-type ServeConnOpts struct {
- // BaseConfig optionally sets the base configuration
- // for values. If nil, defaults are used.
- BaseConfig *http.Server
-
- // Handler specifies which handler to use for processing
- // requests. If nil, BaseConfig.Handler is used. If BaseConfig
- // or BaseConfig.Handler is nil, http.DefaultServeMux is used.
- Handler http.Handler
-}
-
-func (o *ServeConnOpts) baseConfig() *http.Server {
- if o != nil && o.BaseConfig != nil {
- return o.BaseConfig
- }
- return new(http.Server)
-}
-
-func (o *ServeConnOpts) handler() http.Handler {
- if o != nil {
- if o.Handler != nil {
- return o.Handler
- }
- if o.BaseConfig != nil && o.BaseConfig.Handler != nil {
- return o.BaseConfig.Handler
- }
- }
- return http.DefaultServeMux
-}
-
-// ServeConn serves HTTP/2 requests on the provided connection and
-// blocks until the connection is no longer readable.
-//
-// ServeConn starts speaking HTTP/2 assuming that c has not had any
-// reads or writes. It writes its initial settings frame and expects
-// to be able to read the preface and settings frame from the
-// client. If c has a ConnectionState method like a *tls.Conn, the
-// ConnectionState is used to verify the TLS ciphersuite and to set
-// the Request.TLS field in Handlers.
-//
-// ServeConn does not support h2c by itself. Any h2c support must be
-// implemented in terms of providing a suitably-behaving net.Conn.
-//
-// The opts parameter is optional. If nil, default values are used.
-func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
- baseCtx, cancel := serverConnBaseContext(c, opts)
- defer cancel()
-
- sc := &serverConn{
- srv: s,
- hs: opts.baseConfig(),
- conn: c,
- baseCtx: baseCtx,
- remoteAddrStr: c.RemoteAddr().String(),
- bw: newBufferedWriter(c),
- handler: opts.handler(),
- streams: make(map[uint32]*stream),
- readFrameCh: make(chan readFrameResult),
- wantWriteFrameCh: make(chan FrameWriteRequest, 8),
- wantStartPushCh: make(chan startPushRequest, 8),
- wroteFrameCh: make(chan frameWriteResult, 1), // buffered; one send in writeFrameAsync
- bodyReadCh: make(chan bodyReadMsg), // buffering doesn't matter either way
- doneServing: make(chan struct{}),
- clientMaxStreams: math.MaxUint32, // Section 6.5.2: "Initially, there is no limit to this value"
- advMaxStreams: s.maxConcurrentStreams(),
- initialWindowSize: initialWindowSize,
- maxFrameSize: initialMaxFrameSize,
- headerTableSize: initialHeaderTableSize,
- serveG: newGoroutineLock(),
- pushEnabled: true,
- }
-
- // The net/http package sets the write deadline from the
- // http.Server.WriteTimeout during the TLS handshake, but then
- // passes the connection off to us with the deadline already
- // set. Disarm it here so that it is not applied to additional
- // streams opened on this connection.
- // TODO: implement WriteTimeout fully. See Issue 18437.
- if sc.hs.WriteTimeout != 0 {
- sc.conn.SetWriteDeadline(time.Time{})
- }
-
- if s.NewWriteScheduler != nil {
- sc.writeSched = s.NewWriteScheduler()
- } else {
- sc.writeSched = NewRandomWriteScheduler()
- }
-
- sc.flow.add(initialWindowSize)
- sc.inflow.add(initialWindowSize)
- sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
-
- fr := NewFramer(sc.bw, c)
- fr.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil)
- fr.MaxHeaderListSize = sc.maxHeaderListSize()
- fr.SetMaxReadFrameSize(s.maxReadFrameSize())
- sc.framer = fr
-
- if tc, ok := c.(connectionStater); ok {
- sc.tlsState = new(tls.ConnectionState)
- *sc.tlsState = tc.ConnectionState()
- // 9.2 Use of TLS Features
- // An implementation of HTTP/2 over TLS MUST use TLS
- // 1.2 or higher with the restrictions on feature set
- // and cipher suite described in this section. Due to
- // implementation limitations, it might not be
- // possible to fail TLS negotiation. An endpoint MUST
- // immediately terminate an HTTP/2 connection that
- // does not meet the TLS requirements described in
- // this section with a connection error (Section
- // 5.4.1) of type INADEQUATE_SECURITY.
- if sc.tlsState.Version < tls.VersionTLS12 {
- sc.rejectConn(ErrCodeInadequateSecurity, "TLS version too low")
- return
- }
-
- if sc.tlsState.ServerName == "" {
- // Client must use SNI, but we don't enforce that anymore,
- // since it was causing problems when connecting to bare IP
- // addresses during development.
- //
- // TODO: optionally enforce? Or enforce at the time we receive
- // a new request, and verify the the ServerName matches the :authority?
- // But that precludes proxy situations, perhaps.
- //
- // So for now, do nothing here again.
- }
-
- if !s.PermitProhibitedCipherSuites && isBadCipher(sc.tlsState.CipherSuite) {
- // "Endpoints MAY choose to generate a connection error
- // (Section 5.4.1) of type INADEQUATE_SECURITY if one of
- // the prohibited cipher suites are negotiated."
- //
- // We choose that. In my opinion, the spec is weak
- // here. It also says both parties must support at least
- // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 so there's no
- // excuses here. If we really must, we could allow an
- // "AllowInsecureWeakCiphers" option on the server later.
- // Let's see how it plays out first.
- sc.rejectConn(ErrCodeInadequateSecurity, fmt.Sprintf("Prohibited TLS 1.2 Cipher Suite: %x", sc.tlsState.CipherSuite))
- return
- }
- }
-
- if hook := testHookGetServerConn; hook != nil {
- hook(sc)
- }
- sc.serve()
-}
-
-func (sc *serverConn) rejectConn(err ErrCode, debug string) {
- sc.vlogf("http2: server rejecting conn: %v, %s", err, debug)
- // ignoring errors. hanging up anyway.
- sc.framer.WriteGoAway(0, err, []byte(debug))
- sc.bw.Flush()
- sc.conn.Close()
-}
-
-type serverConn struct {
- // Immutable:
- srv *Server
- hs *http.Server
- conn net.Conn
- bw *bufferedWriter // writing to conn
- handler http.Handler
- baseCtx contextContext
- framer *Framer
- doneServing chan struct{} // closed when serverConn.serve ends
- readFrameCh chan readFrameResult // written by serverConn.readFrames
- wantWriteFrameCh chan FrameWriteRequest // from handlers -> serve
- wantStartPushCh chan startPushRequest // from handlers -> serve
- wroteFrameCh chan frameWriteResult // from writeFrameAsync -> serve, tickles more frame writes
- bodyReadCh chan bodyReadMsg // from handlers -> serve
- testHookCh chan func(int) // code to run on the serve loop
- flow flow // conn-wide (not stream-specific) outbound flow control
- inflow flow // conn-wide inbound flow control
- tlsState *tls.ConnectionState // shared by all handlers, like net/http
- remoteAddrStr string
- writeSched WriteScheduler
-
- // Everything following is owned by the serve loop; use serveG.check():
- serveG goroutineLock // used to verify funcs are on serve()
- pushEnabled bool
- sawFirstSettings bool // got the initial SETTINGS frame after the preface
- needToSendSettingsAck bool
- unackedSettings int // how many SETTINGS have we sent without ACKs?
- clientMaxStreams uint32 // SETTINGS_MAX_CONCURRENT_STREAMS from client (our PUSH_PROMISE limit)
- advMaxStreams uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client
- curClientStreams uint32 // number of open streams initiated by the client
- curPushedStreams uint32 // number of open streams initiated by server push
- maxClientStreamID uint32 // max ever seen from client (odd), or 0 if there have been no client requests
- maxPushPromiseID uint32 // ID of the last push promise (even), or 0 if there have been no pushes
- streams map[uint32]*stream
- initialWindowSize int32
- maxFrameSize int32
- headerTableSize uint32
- peerMaxHeaderListSize uint32 // zero means unknown (default)
- canonHeader map[string]string // http2-lower-case -> Go-Canonical-Case
- writingFrame bool // started writing a frame (on serve goroutine or separate)
- writingFrameAsync bool // started a frame on its own goroutine but haven't heard back on wroteFrameCh
- needsFrameFlush bool // last frame write wasn't a flush
- inGoAway bool // we've started to or sent GOAWAY
- inFrameScheduleLoop bool // whether we're in the scheduleFrameWrite loop
- needToSendGoAway bool // we need to schedule a GOAWAY frame write
- goAwayCode ErrCode
- shutdownTimerCh <-chan time.Time // nil until used
- shutdownTimer *time.Timer // nil until used
- idleTimer *time.Timer // nil if unused
- idleTimerCh <-chan time.Time // nil if unused
-
- // Owned by the writeFrameAsync goroutine:
- headerWriteBuf bytes.Buffer
- hpackEncoder *hpack.Encoder
-}
-
-func (sc *serverConn) maxHeaderListSize() uint32 {
- n := sc.hs.MaxHeaderBytes
- if n <= 0 {
- n = http.DefaultMaxHeaderBytes
- }
- // http2's count is in a slightly different unit and includes 32 bytes per pair.
- // So, take the net/http.Server value and pad it up a bit, assuming 10 headers.
- const perFieldOverhead = 32 // per http2 spec
- const typicalHeaders = 10 // conservative
- return uint32(n + typicalHeaders*perFieldOverhead)
-}
-
-func (sc *serverConn) curOpenStreams() uint32 {
- sc.serveG.check()
- return sc.curClientStreams + sc.curPushedStreams
-}
-
-// stream represents a stream. This is the minimal metadata needed by
-// the serve goroutine. Most of the actual stream state is owned by
-// the http.Handler's goroutine in the responseWriter. Because the
-// responseWriter's responseWriterState is recycled at the end of a
-// handler, this struct intentionally has no pointer to the
-// *responseWriter{,State} itself, as the Handler ending nils out the
-// responseWriter's state field.
-type stream struct {
- // immutable:
- sc *serverConn
- id uint32
- body *pipe // non-nil if expecting DATA frames
- cw closeWaiter // closed wait stream transitions to closed state
- ctx contextContext
- cancelCtx func()
-
- // owned by serverConn's serve loop:
- bodyBytes int64 // body bytes seen so far
- declBodyBytes int64 // or -1 if undeclared
- flow flow // limits writing from Handler to client
- inflow flow // what the client is allowed to POST/etc to us
- parent *stream // or nil
- numTrailerValues int64
- weight uint8
- state streamState
- resetQueued bool // RST_STREAM queued for write; set by sc.resetStream
- gotTrailerHeader bool // HEADER frame for trailers was seen
- wroteHeaders bool // whether we wrote headers (not status 100)
- reqBuf []byte // if non-nil, body pipe buffer to return later at EOF
-
- trailer http.Header // accumulated trailers
- reqTrailer http.Header // handler's Request.Trailer
-}
-
-func (sc *serverConn) Framer() *Framer { return sc.framer }
-func (sc *serverConn) CloseConn() error { return sc.conn.Close() }
-func (sc *serverConn) Flush() error { return sc.bw.Flush() }
-func (sc *serverConn) HeaderEncoder() (*hpack.Encoder, *bytes.Buffer) {
- return sc.hpackEncoder, &sc.headerWriteBuf
-}
-
-func (sc *serverConn) state(streamID uint32) (streamState, *stream) {
- sc.serveG.check()
- // http://tools.ietf.org/html/rfc7540#section-5.1
- if st, ok := sc.streams[streamID]; ok {
- return st.state, st
- }
- // "The first use of a new stream identifier implicitly closes all
- // streams in the "idle" state that might have been initiated by
- // that peer with a lower-valued stream identifier. For example, if
- // a client sends a HEADERS frame on stream 7 without ever sending a
- // frame on stream 5, then stream 5 transitions to the "closed"
- // state when the first frame for stream 7 is sent or received."
- if streamID%2 == 1 {
- if streamID <= sc.maxClientStreamID {
- return stateClosed, nil
- }
- } else {
- if streamID <= sc.maxPushPromiseID {
- return stateClosed, nil
- }
- }
- return stateIdle, nil
-}
-
-// setConnState calls the net/http ConnState hook for this connection, if configured.
-// Note that the net/http package does StateNew and StateClosed for us.
-// There is currently no plan for StateHijacked or hijacking HTTP/2 connections.
-func (sc *serverConn) setConnState(state http.ConnState) {
- if sc.hs.ConnState != nil {
- sc.hs.ConnState(sc.conn, state)
- }
-}
-
-func (sc *serverConn) vlogf(format string, args ...interface{}) {
- if VerboseLogs {
- sc.logf(format, args...)
- }
-}
-
-func (sc *serverConn) logf(format string, args ...interface{}) {
- if lg := sc.hs.ErrorLog; lg != nil {
- lg.Printf(format, args...)
- } else {
- log.Printf(format, args...)
- }
-}
-
-// errno returns v's underlying uintptr, else 0.
-//
-// TODO: remove this helper function once http2 can use build
-// tags. See comment in isClosedConnError.
-func errno(v error) uintptr {
- if rv := reflect.ValueOf(v); rv.Kind() == reflect.Uintptr {
- return uintptr(rv.Uint())
- }
- return 0
-}
-
-// isClosedConnError reports whether err is an error from use of a closed
-// network connection.
-func isClosedConnError(err error) bool {
- if err == nil {
- return false
- }
-
- // TODO: remove this string search and be more like the Windows
- // case below. That might involve modifying the standard library
- // to return better error types.
- str := err.Error()
- if strings.Contains(str, "use of closed network connection") {
- return true
- }
-
- // TODO(bradfitz): x/tools/cmd/bundle doesn't really support
- // build tags, so I can't make an http2_windows.go file with
- // Windows-specific stuff. Fix that and move this, once we
- // have a way to bundle this into std's net/http somehow.
- if runtime.GOOS == "windows" {
- if oe, ok := err.(*net.OpError); ok && oe.Op == "read" {
- if se, ok := oe.Err.(*os.SyscallError); ok && se.Syscall == "wsarecv" {
- const WSAECONNABORTED = 10053
- const WSAECONNRESET = 10054
- if n := errno(se.Err); n == WSAECONNRESET || n == WSAECONNABORTED {
- return true
- }
- }
- }
- }
- return false
-}
-
-func (sc *serverConn) condlogf(err error, format string, args ...interface{}) {
- if err == nil {
- return
- }
- if err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err) {
- // Boring, expected errors.
- sc.vlogf(format, args...)
- } else {
- sc.logf(format, args...)
- }
-}
-
-func (sc *serverConn) canonicalHeader(v string) string {
- sc.serveG.check()
- cv, ok := commonCanonHeader[v]
- if ok {
- return cv
- }
- cv, ok = sc.canonHeader[v]
- if ok {
- return cv
- }
- if sc.canonHeader == nil {
- sc.canonHeader = make(map[string]string)
- }
- cv = http.CanonicalHeaderKey(v)
- sc.canonHeader[v] = cv
- return cv
-}
-
-type readFrameResult struct {
- f Frame // valid until readMore is called
- err error
-
- // readMore should be called once the consumer no longer needs or
- // retains f. After readMore, f is invalid and more frames can be
- // read.
- readMore func()
-}
-
-// readFrames is the loop that reads incoming frames.
-// It takes care to only read one frame at a time, blocking until the
-// consumer is done with the frame.
-// It's run on its own goroutine.
-func (sc *serverConn) readFrames() {
- gate := make(gate)
- gateDone := gate.Done
- for {
- f, err := sc.framer.ReadFrame()
- select {
- case sc.readFrameCh <- readFrameResult{f, err, gateDone}:
- case <-sc.doneServing:
- return
- }
- select {
- case <-gate:
- case <-sc.doneServing:
- return
- }
- if terminalReadFrameError(err) {
- return
- }
- }
-}
-
-// frameWriteResult is the message passed from writeFrameAsync to the serve goroutine.
-type frameWriteResult struct {
- wr FrameWriteRequest // what was written (or attempted)
- err error // result of the writeFrame call
-}
-
-// writeFrameAsync runs in its own goroutine and writes a single frame
-// and then reports when it's done.
-// At most one goroutine can be running writeFrameAsync at a time per
-// serverConn.
-func (sc *serverConn) writeFrameAsync(wr FrameWriteRequest) {
- err := wr.write.writeFrame(sc)
- sc.wroteFrameCh <- frameWriteResult{wr, err}
-}
-
-func (sc *serverConn) closeAllStreamsOnConnClose() {
- sc.serveG.check()
- for _, st := range sc.streams {
- sc.closeStream(st, errClientDisconnected)
- }
-}
-
-func (sc *serverConn) stopShutdownTimer() {
- sc.serveG.check()
- if t := sc.shutdownTimer; t != nil {
- t.Stop()
- }
-}
-
-func (sc *serverConn) notePanic() {
- // Note: this is for serverConn.serve panicking, not http.Handler code.
- if testHookOnPanicMu != nil {
- testHookOnPanicMu.Lock()
- defer testHookOnPanicMu.Unlock()
- }
- if testHookOnPanic != nil {
- if e := recover(); e != nil {
- if testHookOnPanic(sc, e) {
- panic(e)
- }
- }
- }
-}
-
-func (sc *serverConn) serve() {
- sc.serveG.check()
- defer sc.notePanic()
- defer sc.conn.Close()
- defer sc.closeAllStreamsOnConnClose()
- defer sc.stopShutdownTimer()
- defer close(sc.doneServing) // unblocks handlers trying to send
-
- if VerboseLogs {
- sc.vlogf("http2: server connection from %v on %p", sc.conn.RemoteAddr(), sc.hs)
- }
-
- sc.writeFrame(FrameWriteRequest{
- write: writeSettings{
- {SettingMaxFrameSize, sc.srv.maxReadFrameSize()},
- {SettingMaxConcurrentStreams, sc.advMaxStreams},
- {SettingMaxHeaderListSize, sc.maxHeaderListSize()},
-
- // TODO: more actual settings, notably
- // SettingInitialWindowSize, but then we also
- // want to bump up the conn window size the
- // same amount here right after the settings
- },
- })
- sc.unackedSettings++
-
- if err := sc.readPreface(); err != nil {
- sc.condlogf(err, "http2: server: error reading preface from client %v: %v", sc.conn.RemoteAddr(), err)
- return
- }
- // Now that we've got the preface, get us out of the
- // "StateNew" state. We can't go directly to idle, though.
- // Active means we read some data and anticipate a request. We'll
- // do another Active when we get a HEADERS frame.
- sc.setConnState(http.StateActive)
- sc.setConnState(http.StateIdle)
-
- if sc.srv.IdleTimeout != 0 {
- sc.idleTimer = time.NewTimer(sc.srv.IdleTimeout)
- defer sc.idleTimer.Stop()
- sc.idleTimerCh = sc.idleTimer.C
- }
-
- var gracefulShutdownCh <-chan struct{}
- if sc.hs != nil {
- gracefulShutdownCh = h1ServerShutdownChan(sc.hs)
- }
-
- go sc.readFrames() // closed by defer sc.conn.Close above
-
- settingsTimer := time.NewTimer(firstSettingsTimeout)
- loopNum := 0
- for {
- loopNum++
- select {
- case wr := <-sc.wantWriteFrameCh:
- sc.writeFrame(wr)
- case spr := <-sc.wantStartPushCh:
- sc.startPush(spr)
- case res := <-sc.wroteFrameCh:
- sc.wroteFrame(res)
- case res := <-sc.readFrameCh:
- if !sc.processFrameFromReader(res) {
- return
- }
- res.readMore()
- if settingsTimer.C != nil {
- settingsTimer.Stop()
- settingsTimer.C = nil
- }
- case m := <-sc.bodyReadCh:
- sc.noteBodyRead(m.st, m.n)
- case <-settingsTimer.C:
- sc.logf("timeout waiting for SETTINGS frames from %v", sc.conn.RemoteAddr())
- return
- case <-gracefulShutdownCh:
- gracefulShutdownCh = nil
- sc.startGracefulShutdown()
- case <-sc.shutdownTimerCh:
- sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr())
- return
- case <-sc.idleTimerCh:
- sc.vlogf("connection is idle")
- sc.goAway(ErrCodeNo)
- case fn := <-sc.testHookCh:
- fn(loopNum)
- }
-
- if sc.inGoAway && sc.curOpenStreams() == 0 && !sc.needToSendGoAway && !sc.writingFrame {
- return
- }
- }
-}
-
-// readPreface reads the ClientPreface greeting from the peer
-// or returns an error on timeout or an invalid greeting.
-func (sc *serverConn) readPreface() error {
- errc := make(chan error, 1)
- go func() {
- // Read the client preface
- buf := make([]byte, len(ClientPreface))
- if _, err := io.ReadFull(sc.conn, buf); err != nil {
- errc <- err
- } else if !bytes.Equal(buf, clientPreface) {
- errc <- fmt.Errorf("bogus greeting %q", buf)
- } else {
- errc <- nil
- }
- }()
- timer := time.NewTimer(prefaceTimeout) // TODO: configurable on *Server?
- defer timer.Stop()
- select {
- case <-timer.C:
- return errors.New("timeout waiting for client preface")
- case err := <-errc:
- if err == nil {
- if VerboseLogs {
- sc.vlogf("http2: server: client %v said hello", sc.conn.RemoteAddr())
- }
- }
- return err
- }
-}
-
-var errChanPool = sync.Pool{
- New: func() interface{} { return make(chan error, 1) },
-}
-
-var writeDataPool = sync.Pool{
- New: func() interface{} { return new(writeData) },
-}
-
-// writeDataFromHandler writes DATA response frames from a handler on
-// the given stream.
-func (sc *serverConn) writeDataFromHandler(stream *stream, data []byte, endStream bool) error {
- ch := errChanPool.Get().(chan error)
- writeArg := writeDataPool.Get().(*writeData)
- *writeArg = writeData{stream.id, data, endStream}
- err := sc.writeFrameFromHandler(FrameWriteRequest{
- write: writeArg,
- stream: stream,
- done: ch,
- })
- if err != nil {
- return err
- }
- var frameWriteDone bool // the frame write is done (successfully or not)
- select {
- case err = <-ch:
- frameWriteDone = true
- case <-sc.doneServing:
- return errClientDisconnected
- case <-stream.cw:
- // If both ch and stream.cw were ready (as might
- // happen on the final Write after an http.Handler
- // ends), prefer the write result. Otherwise this
- // might just be us successfully closing the stream.
- // The writeFrameAsync and serve goroutines guarantee
- // that the ch send will happen before the stream.cw
- // close.
- select {
- case err = <-ch:
- frameWriteDone = true
- default:
- return errStreamClosed
- }
- }
- errChanPool.Put(ch)
- if frameWriteDone {
- writeDataPool.Put(writeArg)
- }
- return err
-}
-
-// writeFrameFromHandler sends wr to sc.wantWriteFrameCh, but aborts
-// if the connection has gone away.
-//
-// This must not be run from the serve goroutine itself, else it might
-// deadlock writing to sc.wantWriteFrameCh (which is only mildly
-// buffered and is read by serve itself). If you're on the serve
-// goroutine, call writeFrame instead.
-func (sc *serverConn) writeFrameFromHandler(wr FrameWriteRequest) error {
- sc.serveG.checkNotOn() // NOT
- select {
- case sc.wantWriteFrameCh <- wr:
- return nil
- case <-sc.doneServing:
- // Serve loop is gone.
- // Client has closed their connection to the server.
- return errClientDisconnected
- }
-}
-
-// writeFrame schedules a frame to write and sends it if there's nothing
-// already being written.
-//
-// There is no pushback here (the serve goroutine never blocks). It's
-// the http.Handlers that block, waiting for their previous frames to
-// make it onto the wire
-//
-// If you're not on the serve goroutine, use writeFrameFromHandler instead.
-func (sc *serverConn) writeFrame(wr FrameWriteRequest) {
- sc.serveG.check()
-
- // If true, wr will not be written and wr.done will not be signaled.
- var ignoreWrite bool
-
- // We are not allowed to write frames on closed streams. RFC 7540 Section
- // 5.1.1 says: "An endpoint MUST NOT send frames other than PRIORITY on
- // a closed stream." Our server never sends PRIORITY, so that exception
- // does not apply.
- //
- // The serverConn might close an open stream while the stream's handler
- // is still running. For example, the server might close a stream when it
- // receives bad data from the client. If this happens, the handler might
- // attempt to write a frame after the stream has been closed (since the
- // handler hasn't yet been notified of the close). In this case, we simply
- // ignore the frame. The handler will notice that the stream is closed when
- // it waits for the frame to be written.
- //
- // As an exception to this rule, we allow sending RST_STREAM after close.
- // This allows us to immediately reject new streams without tracking any
- // state for those streams (except for the queued RST_STREAM frame). This
- // may result in duplicate RST_STREAMs in some cases, but the client should
- // ignore those.
- if wr.StreamID() != 0 {
- _, isReset := wr.write.(StreamError)
- if state, _ := sc.state(wr.StreamID()); state == stateClosed && !isReset {
- ignoreWrite = true
- }
- }
-
- // Don't send a 100-continue response if we've already sent headers.
- // See golang.org/issue/14030.
- switch wr.write.(type) {
- case *writeResHeaders:
- wr.stream.wroteHeaders = true
- case write100ContinueHeadersFrame:
- if wr.stream.wroteHeaders {
- // We do not need to notify wr.done because this frame is
- // never written with wr.done != nil.
- if wr.done != nil {
- panic("wr.done != nil for write100ContinueHeadersFrame")
- }
- ignoreWrite = true
- }
- }
-
- if !ignoreWrite {
- sc.writeSched.Push(wr)
- }
- sc.scheduleFrameWrite()
-}
-
-// startFrameWrite starts a goroutine to write wr (in a separate
-// goroutine since that might block on the network), and updates the
-// serve goroutine's state about the world, updated from info in wr.
-func (sc *serverConn) startFrameWrite(wr FrameWriteRequest) {
- sc.serveG.check()
- if sc.writingFrame {
- panic("internal error: can only be writing one frame at a time")
- }
-
- st := wr.stream
- if st != nil {
- switch st.state {
- case stateHalfClosedLocal:
- switch wr.write.(type) {
- case StreamError, handlerPanicRST, writeWindowUpdate:
- // RFC 7540 Section 5.1 allows sending RST_STREAM, PRIORITY, and WINDOW_UPDATE
- // in this state. (We never send PRIORITY from the server, so that is not checked.)
- default:
- panic(fmt.Sprintf("internal error: attempt to send frame on a half-closed-local stream: %v", wr))
- }
- case stateClosed:
- panic(fmt.Sprintf("internal error: attempt to send frame on a closed stream: %v", wr))
- }
- }
- if wpp, ok := wr.write.(*writePushPromise); ok {
- var err error
- wpp.promisedID, err = wpp.allocatePromisedID()
- if err != nil {
- sc.writingFrameAsync = false
- wr.replyToWriter(err)
- return
- }
- }
-
- sc.writingFrame = true
- sc.needsFrameFlush = true
- if wr.write.staysWithinBuffer(sc.bw.Available()) {
- sc.writingFrameAsync = false
- err := wr.write.writeFrame(sc)
- sc.wroteFrame(frameWriteResult{wr, err})
- } else {
- sc.writingFrameAsync = true
- go sc.writeFrameAsync(wr)
- }
-}
-
-// errHandlerPanicked is the error given to any callers blocked in a read from
-// Request.Body when the main goroutine panics. Since most handlers read in the
-// the main ServeHTTP goroutine, this will show up rarely.
-var errHandlerPanicked = errors.New("http2: handler panicked")
-
-// wroteFrame is called on the serve goroutine with the result of
-// whatever happened on writeFrameAsync.
-func (sc *serverConn) wroteFrame(res frameWriteResult) {
- sc.serveG.check()
- if !sc.writingFrame {
- panic("internal error: expected to be already writing a frame")
- }
- sc.writingFrame = false
- sc.writingFrameAsync = false
-
- wr := res.wr
-
- if writeEndsStream(wr.write) {
- st := wr.stream
- if st == nil {
- panic("internal error: expecting non-nil stream")
- }
- switch st.state {
- case stateOpen:
- // Here we would go to stateHalfClosedLocal in
- // theory, but since our handler is done and
- // the net/http package provides no mechanism
- // for closing a ResponseWriter while still
- // reading data (see possible TODO at top of
- // this file), we go into closed state here
- // anyway, after telling the peer we're
- // hanging up on them. We'll transition to
- // stateClosed after the RST_STREAM frame is
- // written.
- st.state = stateHalfClosedLocal
- sc.resetStream(streamError(st.id, ErrCodeCancel))
- case stateHalfClosedRemote:
- sc.closeStream(st, errHandlerComplete)
- }
- } else {
- switch v := wr.write.(type) {
- case StreamError:
- // st may be unknown if the RST_STREAM was generated to reject bad input.
- if st, ok := sc.streams[v.StreamID]; ok {
- sc.closeStream(st, v)
- }
- case handlerPanicRST:
- sc.closeStream(wr.stream, errHandlerPanicked)
- }
- }
-
- // Reply (if requested) to unblock the ServeHTTP goroutine.
- wr.replyToWriter(res.err)
-
- sc.scheduleFrameWrite()
-}
-
-// scheduleFrameWrite tickles the frame writing scheduler.
-//
-// If a frame is already being written, nothing happens. This will be called again
-// when the frame is done being written.
-//
-// If a frame isn't being written we need to send one, the best frame
-// to send is selected, preferring first things that aren't
-// stream-specific (e.g. ACKing settings), and then finding the
-// highest priority stream.
-//
-// If a frame isn't being written and there's nothing else to send, we
-// flush the write buffer.
-func (sc *serverConn) scheduleFrameWrite() {
- sc.serveG.check()
- if sc.writingFrame || sc.inFrameScheduleLoop {
- return
- }
- sc.inFrameScheduleLoop = true
- for !sc.writingFrameAsync {
- if sc.needToSendGoAway {
- sc.needToSendGoAway = false
- sc.startFrameWrite(FrameWriteRequest{
- write: &writeGoAway{
- maxStreamID: sc.maxClientStreamID,
- code: sc.goAwayCode,
- },
- })
- continue
- }
- if sc.needToSendSettingsAck {
- sc.needToSendSettingsAck = false
- sc.startFrameWrite(FrameWriteRequest{write: writeSettingsAck{}})
- continue
- }
- if !sc.inGoAway || sc.goAwayCode == ErrCodeNo {
- if wr, ok := sc.writeSched.Pop(); ok {
- sc.startFrameWrite(wr)
- continue
- }
- }
- if sc.needsFrameFlush {
- sc.startFrameWrite(FrameWriteRequest{write: flushFrameWriter{}})
- sc.needsFrameFlush = false // after startFrameWrite, since it sets this true
- continue
- }
- break
- }
- sc.inFrameScheduleLoop = false
-}
-
-// startGracefulShutdown sends a GOAWAY with ErrCodeNo to tell the
-// client we're gracefully shutting down. The connection isn't closed
-// until all current streams are done.
-func (sc *serverConn) startGracefulShutdown() {
- sc.goAwayIn(ErrCodeNo, 0)
-}
-
-func (sc *serverConn) goAway(code ErrCode) {
- sc.serveG.check()
- var forceCloseIn time.Duration
- if code != ErrCodeNo {
- forceCloseIn = 250 * time.Millisecond
- } else {
- // TODO: configurable
- forceCloseIn = 1 * time.Second
- }
- sc.goAwayIn(code, forceCloseIn)
-}
-
-func (sc *serverConn) goAwayIn(code ErrCode, forceCloseIn time.Duration) {
- sc.serveG.check()
- if sc.inGoAway {
- return
- }
- if forceCloseIn != 0 {
- sc.shutDownIn(forceCloseIn)
- }
- sc.inGoAway = true
- sc.needToSendGoAway = true
- sc.goAwayCode = code
- sc.scheduleFrameWrite()
-}
-
-func (sc *serverConn) shutDownIn(d time.Duration) {
- sc.serveG.check()
- sc.shutdownTimer = time.NewTimer(d)
- sc.shutdownTimerCh = sc.shutdownTimer.C
-}
-
-func (sc *serverConn) resetStream(se StreamError) {
- sc.serveG.check()
- sc.writeFrame(FrameWriteRequest{write: se})
- if st, ok := sc.streams[se.StreamID]; ok {
- st.resetQueued = true
- }
-}
-
-// processFrameFromReader processes the serve loop's read from readFrameCh from the
-// frame-reading goroutine.
-// processFrameFromReader returns whether the connection should be kept open.
-func (sc *serverConn) processFrameFromReader(res readFrameResult) bool {
- sc.serveG.check()
- err := res.err
- if err != nil {
- if err == ErrFrameTooLarge {
- sc.goAway(ErrCodeFrameSize)
- return true // goAway will close the loop
- }
- clientGone := err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err)
- if clientGone {
- // TODO: could we also get into this state if
- // the peer does a half close
- // (e.g. CloseWrite) because they're done
- // sending frames but they're still wanting
- // our open replies? Investigate.
- // TODO: add CloseWrite to crypto/tls.Conn first
- // so we have a way to test this? I suppose
- // just for testing we could have a non-TLS mode.
- return false
- }
- } else {
- f := res.f
- if VerboseLogs {
- sc.vlogf("http2: server read frame %v", summarizeFrame(f))
- }
- err = sc.processFrame(f)
- if err == nil {
- return true
- }
- }
-
- switch ev := err.(type) {
- case StreamError:
- sc.resetStream(ev)
- return true
- case goAwayFlowError:
- sc.goAway(ErrCodeFlowControl)
- return true
- case ConnectionError:
- sc.logf("http2: server connection error from %v: %v", sc.conn.RemoteAddr(), ev)
- sc.goAway(ErrCode(ev))
- return true // goAway will handle shutdown
- default:
- if res.err != nil {
- sc.vlogf("http2: server closing client connection; error reading frame from client %s: %v", sc.conn.RemoteAddr(), err)
- } else {
- sc.logf("http2: server closing client connection: %v", err)
- }
- return false
- }
-}
-
-func (sc *serverConn) processFrame(f Frame) error {
- sc.serveG.check()
-
- // First frame received must be SETTINGS.
- if !sc.sawFirstSettings {
- if _, ok := f.(*SettingsFrame); !ok {
- return ConnectionError(ErrCodeProtocol)
- }
- sc.sawFirstSettings = true
- }
-
- switch f := f.(type) {
- case *SettingsFrame:
- return sc.processSettings(f)
- case *MetaHeadersFrame:
- return sc.processHeaders(f)
- case *WindowUpdateFrame:
- return sc.processWindowUpdate(f)
- case *PingFrame:
- return sc.processPing(f)
- case *DataFrame:
- return sc.processData(f)
- case *RSTStreamFrame:
- return sc.processResetStream(f)
- case *PriorityFrame:
- return sc.processPriority(f)
- case *GoAwayFrame:
- return sc.processGoAway(f)
- case *PushPromiseFrame:
- // A client cannot push. Thus, servers MUST treat the receipt of a PUSH_PROMISE
- // frame as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
- return ConnectionError(ErrCodeProtocol)
- default:
- sc.vlogf("http2: server ignoring frame: %v", f.Header())
- return nil
- }
-}
-
-func (sc *serverConn) processPing(f *PingFrame) error {
- sc.serveG.check()
- if f.IsAck() {
- // 6.7 PING: " An endpoint MUST NOT respond to PING frames
- // containing this flag."
- return nil
- }
- if f.StreamID != 0 {
- // "PING frames are not associated with any individual
- // stream. If a PING frame is received with a stream
- // identifier field value other than 0x0, the recipient MUST
- // respond with a connection error (Section 5.4.1) of type
- // PROTOCOL_ERROR."
- return ConnectionError(ErrCodeProtocol)
- }
- if sc.inGoAway && sc.goAwayCode != ErrCodeNo {
- return nil
- }
- sc.writeFrame(FrameWriteRequest{write: writePingAck{f}})
- return nil
-}
-
-func (sc *serverConn) processWindowUpdate(f *WindowUpdateFrame) error {
- sc.serveG.check()
- switch {
- case f.StreamID != 0: // stream-level flow control
- state, st := sc.state(f.StreamID)
- if state == stateIdle {
- // Section 5.1: "Receiving any frame other than HEADERS
- // or PRIORITY on a stream in this state MUST be
- // treated as a connection error (Section 5.4.1) of
- // type PROTOCOL_ERROR."
- return ConnectionError(ErrCodeProtocol)
- }
- if st == nil {
- // "WINDOW_UPDATE can be sent by a peer that has sent a
- // frame bearing the END_STREAM flag. This means that a
- // receiver could receive a WINDOW_UPDATE frame on a "half
- // closed (remote)" or "closed" stream. A receiver MUST
- // NOT treat this as an error, see Section 5.1."
- return nil
- }
- if !st.flow.add(int32(f.Increment)) {
- return streamError(f.StreamID, ErrCodeFlowControl)
- }
- default: // connection-level flow control
- if !sc.flow.add(int32(f.Increment)) {
- return goAwayFlowError{}
- }
- }
- sc.scheduleFrameWrite()
- return nil
-}
-
-func (sc *serverConn) processResetStream(f *RSTStreamFrame) error {
- sc.serveG.check()
-
- state, st := sc.state(f.StreamID)
- if state == stateIdle {
- // 6.4 "RST_STREAM frames MUST NOT be sent for a
- // stream in the "idle" state. If a RST_STREAM frame
- // identifying an idle stream is received, the
- // recipient MUST treat this as a connection error
- // (Section 5.4.1) of type PROTOCOL_ERROR.
- return ConnectionError(ErrCodeProtocol)
- }
- if st != nil {
- st.cancelCtx()
- sc.closeStream(st, streamError(f.StreamID, f.ErrCode))
- }
- return nil
-}
-
-func (sc *serverConn) closeStream(st *stream, err error) {
- sc.serveG.check()
- if st.state == stateIdle || st.state == stateClosed {
- panic(fmt.Sprintf("invariant; can't close stream in state %v", st.state))
- }
- st.state = stateClosed
- if st.isPushed() {
- sc.curPushedStreams--
- } else {
- sc.curClientStreams--
- }
- delete(sc.streams, st.id)
- if len(sc.streams) == 0 {
- sc.setConnState(http.StateIdle)
- if sc.srv.IdleTimeout != 0 {
- sc.idleTimer.Reset(sc.srv.IdleTimeout)
- }
- if h1ServerKeepAlivesDisabled(sc.hs) {
- sc.startGracefulShutdown()
- }
- }
- if p := st.body; p != nil {
- // Return any buffered unread bytes worth of conn-level flow control.
- // See golang.org/issue/16481
- sc.sendWindowUpdate(nil, p.Len())
-
- p.CloseWithError(err)
- }
- st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc
- sc.writeSched.CloseStream(st.id)
-}
-
-func (sc *serverConn) processSettings(f *SettingsFrame) error {
- sc.serveG.check()
- if f.IsAck() {
- sc.unackedSettings--
- if sc.unackedSettings < 0 {
- // Why is the peer ACKing settings we never sent?
- // The spec doesn't mention this case, but
- // hang up on them anyway.
- return ConnectionError(ErrCodeProtocol)
- }
- return nil
- }
- if err := f.ForeachSetting(sc.processSetting); err != nil {
- return err
- }
- sc.needToSendSettingsAck = true
- sc.scheduleFrameWrite()
- return nil
-}
-
-func (sc *serverConn) processSetting(s Setting) error {
- sc.serveG.check()
- if err := s.Valid(); err != nil {
- return err
- }
- if VerboseLogs {
- sc.vlogf("http2: server processing setting %v", s)
- }
- switch s.ID {
- case SettingHeaderTableSize:
- sc.headerTableSize = s.Val
- sc.hpackEncoder.SetMaxDynamicTableSize(s.Val)
- case SettingEnablePush:
- sc.pushEnabled = s.Val != 0
- case SettingMaxConcurrentStreams:
- sc.clientMaxStreams = s.Val
- case SettingInitialWindowSize:
- return sc.processSettingInitialWindowSize(s.Val)
- case SettingMaxFrameSize:
- sc.maxFrameSize = int32(s.Val) // the maximum valid s.Val is < 2^31
- case SettingMaxHeaderListSize:
- sc.peerMaxHeaderListSize = s.Val
- default:
- // Unknown setting: "An endpoint that receives a SETTINGS
- // frame with any unknown or unsupported identifier MUST
- // ignore that setting."
- if VerboseLogs {
- sc.vlogf("http2: server ignoring unknown setting %v", s)
- }
- }
- return nil
-}
-
-func (sc *serverConn) processSettingInitialWindowSize(val uint32) error {
- sc.serveG.check()
- // Note: val already validated to be within range by
- // processSetting's Valid call.
-
- // "A SETTINGS frame can alter the initial flow control window
- // size for all current streams. When the value of
- // SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver MUST
- // adjust the size of all stream flow control windows that it
- // maintains by the difference between the new value and the
- // old value."
- old := sc.initialWindowSize
- sc.initialWindowSize = int32(val)
- growth := sc.initialWindowSize - old // may be negative
- for _, st := range sc.streams {
- if !st.flow.add(growth) {
- // 6.9.2 Initial Flow Control Window Size
- // "An endpoint MUST treat a change to
- // SETTINGS_INITIAL_WINDOW_SIZE that causes any flow
- // control window to exceed the maximum size as a
- // connection error (Section 5.4.1) of type
- // FLOW_CONTROL_ERROR."
- return ConnectionError(ErrCodeFlowControl)
- }
- }
- return nil
-}
-
-func (sc *serverConn) processData(f *DataFrame) error {
- sc.serveG.check()
- if sc.inGoAway && sc.goAwayCode != ErrCodeNo {
- return nil
- }
- data := f.Data()
-
- // "If a DATA frame is received whose stream is not in "open"
- // or "half closed (local)" state, the recipient MUST respond
- // with a stream error (Section 5.4.2) of type STREAM_CLOSED."
- id := f.Header().StreamID
- state, st := sc.state(id)
- if id == 0 || state == stateIdle {
- // Section 5.1: "Receiving any frame other than HEADERS
- // or PRIORITY on a stream in this state MUST be
- // treated as a connection error (Section 5.4.1) of
- // type PROTOCOL_ERROR."
- return ConnectionError(ErrCodeProtocol)
- }
- if st == nil || state != stateOpen || st.gotTrailerHeader || st.resetQueued {
- // This includes sending a RST_STREAM if the stream is
- // in stateHalfClosedLocal (which currently means that
- // the http.Handler returned, so it's done reading &
- // done writing). Try to stop the client from sending
- // more DATA.
-
- // But still enforce their connection-level flow control,
- // and return any flow control bytes since we're not going
- // to consume them.
- if sc.inflow.available() < int32(f.Length) {
- return streamError(id, ErrCodeFlowControl)
- }
- // Deduct the flow control from inflow, since we're
- // going to immediately add it back in
- // sendWindowUpdate, which also schedules sending the
- // frames.
- sc.inflow.take(int32(f.Length))
- sc.sendWindowUpdate(nil, int(f.Length)) // conn-level
-
- if st != nil && st.resetQueued {
- // Already have a stream error in flight. Don't send another.
- return nil
- }
- return streamError(id, ErrCodeStreamClosed)
- }
- if st.body == nil {
- panic("internal error: should have a body in this state")
- }
-
- // Sender sending more than they'd declared?
- if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
- st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
- return streamError(id, ErrCodeStreamClosed)
- }
- if f.Length > 0 {
- // Check whether the client has flow control quota.
- if st.inflow.available() < int32(f.Length) {
- return streamError(id, ErrCodeFlowControl)
- }
- st.inflow.take(int32(f.Length))
-
- if len(data) > 0 {
- wrote, err := st.body.Write(data)
- if err != nil {
- return streamError(id, ErrCodeStreamClosed)
- }
- if wrote != len(data) {
- panic("internal error: bad Writer")
- }
- st.bodyBytes += int64(len(data))
- }
-
- // Return any padded flow control now, since we won't
- // refund it later on body reads.
- if pad := int32(f.Length) - int32(len(data)); pad > 0 {
- sc.sendWindowUpdate32(nil, pad)
- sc.sendWindowUpdate32(st, pad)
- }
- }
- if f.StreamEnded() {
- st.endStream()
- }
- return nil
-}
-
-func (sc *serverConn) processGoAway(f *GoAwayFrame) error {
- sc.serveG.check()
- if f.ErrCode != ErrCodeNo {
- sc.logf("http2: received GOAWAY %+v, starting graceful shutdown", f)
- } else {
- sc.vlogf("http2: received GOAWAY %+v, starting graceful shutdown", f)
- }
- sc.startGracefulShutdown()
- // http://tools.ietf.org/html/rfc7540#section-6.8
- // We should not create any new streams, which means we should disable push.
- sc.pushEnabled = false
- return nil
-}
-
-// isPushed reports whether the stream is server-initiated.
-func (st *stream) isPushed() bool {
- return st.id%2 == 0
-}
-
-// endStream closes a Request.Body's pipe. It is called when a DATA
-// frame says a request body is over (or after trailers).
-func (st *stream) endStream() {
- sc := st.sc
- sc.serveG.check()
-
- if st.declBodyBytes != -1 && st.declBodyBytes != st.bodyBytes {
- st.body.CloseWithError(fmt.Errorf("request declared a Content-Length of %d but only wrote %d bytes",
- st.declBodyBytes, st.bodyBytes))
- } else {
- st.body.closeWithErrorAndCode(io.EOF, st.copyTrailersToHandlerRequest)
- st.body.CloseWithError(io.EOF)
- }
- st.state = stateHalfClosedRemote
-}
-
-// copyTrailersToHandlerRequest is run in the Handler's goroutine in
-// its Request.Body.Read just before it gets io.EOF.
-func (st *stream) copyTrailersToHandlerRequest() {
- for k, vv := range st.trailer {
- if _, ok := st.reqTrailer[k]; ok {
- // Only copy it over it was pre-declared.
- st.reqTrailer[k] = vv
- }
- }
-}
-
-func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
- sc.serveG.check()
- id := f.StreamID
- if sc.inGoAway {
- // Ignore.
- return nil
- }
- // http://tools.ietf.org/html/rfc7540#section-5.1.1
- // Streams initiated by a client MUST use odd-numbered stream
- // identifiers. [...] An endpoint that receives an unexpected
- // stream identifier MUST respond with a connection error
- // (Section 5.4.1) of type PROTOCOL_ERROR.
- if id%2 != 1 {
- return ConnectionError(ErrCodeProtocol)
- }
- // A HEADERS frame can be used to create a new stream or
- // send a trailer for an open one. If we already have a stream
- // open, let it process its own HEADERS frame (trailers at this
- // point, if it's valid).
- if st := sc.streams[f.StreamID]; st != nil {
- if st.resetQueued {
- // We're sending RST_STREAM to close the stream, so don't bother
- // processing this frame.
- return nil
- }
- return st.processTrailerHeaders(f)
- }
-
- // [...] The identifier of a newly established stream MUST be
- // numerically greater than all streams that the initiating
- // endpoint has opened or reserved. [...] An endpoint that
- // receives an unexpected stream identifier MUST respond with
- // a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
- if id <= sc.maxClientStreamID {
- return ConnectionError(ErrCodeProtocol)
- }
- sc.maxClientStreamID = id
-
- if sc.idleTimer != nil {
- sc.idleTimer.Stop()
- }
-
- // http://tools.ietf.org/html/rfc7540#section-5.1.2
- // [...] Endpoints MUST NOT exceed the limit set by their peer. An
- // endpoint that receives a HEADERS frame that causes their
- // advertised concurrent stream limit to be exceeded MUST treat
- // this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR
- // or REFUSED_STREAM.
- if sc.curClientStreams+1 > sc.advMaxStreams {
- if sc.unackedSettings == 0 {
- // They should know better.
- return streamError(id, ErrCodeProtocol)
- }
- // Assume it's a network race, where they just haven't
- // received our last SETTINGS update. But actually
- // this can't happen yet, because we don't yet provide
- // a way for users to adjust server parameters at
- // runtime.
- return streamError(id, ErrCodeRefusedStream)
- }
-
- initialState := stateOpen
- if f.StreamEnded() {
- initialState = stateHalfClosedRemote
- }
- st := sc.newStream(id, 0, initialState)
-
- if f.HasPriority() {
- if err := checkPriority(f.StreamID, f.Priority); err != nil {
- return err
- }
- sc.writeSched.AdjustStream(st.id, f.Priority)
- }
-
- rw, req, err := sc.newWriterAndRequest(st, f)
- if err != nil {
- return err
- }
- st.reqTrailer = req.Trailer
- if st.reqTrailer != nil {
- st.trailer = make(http.Header)
- }
- st.body = req.Body.(*requestBody).pipe // may be nil
- st.declBodyBytes = req.ContentLength
-
- handler := sc.handler.ServeHTTP
- if f.Truncated {
- // Their header list was too long. Send a 431 error.
- handler = handleHeaderListTooLong
- } else if err := checkValidHTTP2RequestHeaders(req.Header); err != nil {
- handler = new400Handler(err)
- }
-
- // The net/http package sets the read deadline from the
- // http.Server.ReadTimeout during the TLS handshake, but then
- // passes the connection off to us with the deadline already
- // set. Disarm it here after the request headers are read,
- // similar to how the http1 server works. Here it's
- // technically more like the http1 Server's ReadHeaderTimeout
- // (in Go 1.8), though. That's a more sane option anyway.
- if sc.hs.ReadTimeout != 0 {
- sc.conn.SetReadDeadline(time.Time{})
- }
-
- go sc.runHandler(rw, req, handler)
- return nil
-}
-
-func (st *stream) processTrailerHeaders(f *MetaHeadersFrame) error {
- sc := st.sc
- sc.serveG.check()
- if st.gotTrailerHeader {
- return ConnectionError(ErrCodeProtocol)
- }
- st.gotTrailerHeader = true
- if !f.StreamEnded() {
- return streamError(st.id, ErrCodeProtocol)
- }
-
- if len(f.PseudoFields()) > 0 {
- return streamError(st.id, ErrCodeProtocol)
- }
- if st.trailer != nil {
- for _, hf := range f.RegularFields() {
- key := sc.canonicalHeader(hf.Name)
- if !ValidTrailerHeader(key) {
- // TODO: send more details to the peer somehow. But http2 has
- // no way to send debug data at a stream level. Discuss with
- // HTTP folk.
- return streamError(st.id, ErrCodeProtocol)
- }
- st.trailer[key] = append(st.trailer[key], hf.Value)
- }
- }
- st.endStream()
- return nil
-}
-
-func checkPriority(streamID uint32, p PriorityParam) error {
- if streamID == p.StreamDep {
- // Section 5.3.1: "A stream cannot depend on itself. An endpoint MUST treat
- // this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR."
- // Section 5.3.3 says that a stream can depend on one of its dependencies,
- // so it's only self-dependencies that are forbidden.
- return streamError(streamID, ErrCodeProtocol)
- }
- return nil
-}
-
-func (sc *serverConn) processPriority(f *PriorityFrame) error {
- if sc.inGoAway {
- return nil
- }
- if err := checkPriority(f.StreamID, f.PriorityParam); err != nil {
- return err
- }
- sc.writeSched.AdjustStream(f.StreamID, f.PriorityParam)
- return nil
-}
-
-func (sc *serverConn) newStream(id, pusherID uint32, state streamState) *stream {
- sc.serveG.check()
- if id == 0 {
- panic("internal error: cannot create stream with id 0")
- }
-
- ctx, cancelCtx := contextWithCancel(sc.baseCtx)
- st := &stream{
- sc: sc,
- id: id,
- state: state,
- ctx: ctx,
- cancelCtx: cancelCtx,
- }
- st.cw.Init()
- st.flow.conn = &sc.flow // link to conn-level counter
- st.flow.add(sc.initialWindowSize)
- st.inflow.conn = &sc.inflow // link to conn-level counter
- st.inflow.add(initialWindowSize) // TODO: update this when we send a higher initial window size in the initial settings
-
- sc.streams[id] = st
- sc.writeSched.OpenStream(st.id, OpenStreamOptions{PusherID: pusherID})
- if st.isPushed() {
- sc.curPushedStreams++
- } else {
- sc.curClientStreams++
- }
- if sc.curOpenStreams() == 1 {
- sc.setConnState(http.StateActive)
- }
-
- return st
-}
-
-func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*responseWriter, *http.Request, error) {
- sc.serveG.check()
-
- rp := requestParam{
- method: f.PseudoValue("method"),
- scheme: f.PseudoValue("scheme"),
- authority: f.PseudoValue("authority"),
- path: f.PseudoValue("path"),
- }
-
- isConnect := rp.method == "CONNECT"
- if isConnect {
- if rp.path != "" || rp.scheme != "" || rp.authority == "" {
- return nil, nil, streamError(f.StreamID, ErrCodeProtocol)
- }
- } else if rp.method == "" || rp.path == "" || (rp.scheme != "https" && rp.scheme != "http") {
- // See 8.1.2.6 Malformed Requests and Responses:
- //
- // Malformed requests or responses that are detected
- // MUST be treated as a stream error (Section 5.4.2)
- // of type PROTOCOL_ERROR."
- //
- // 8.1.2.3 Request Pseudo-Header Fields
- // "All HTTP/2 requests MUST include exactly one valid
- // value for the :method, :scheme, and :path
- // pseudo-header fields"
- return nil, nil, streamError(f.StreamID, ErrCodeProtocol)
- }
-
- bodyOpen := !f.StreamEnded()
- if rp.method == "HEAD" && bodyOpen {
- // HEAD requests can't have bodies
- return nil, nil, streamError(f.StreamID, ErrCodeProtocol)
- }
-
- rp.header = make(http.Header)
- for _, hf := range f.RegularFields() {
- rp.header.Add(sc.canonicalHeader(hf.Name), hf.Value)
- }
- if rp.authority == "" {
- rp.authority = rp.header.Get("Host")
- }
-
- rw, req, err := sc.newWriterAndRequestNoBody(st, rp)
- if err != nil {
- return nil, nil, err
- }
- if bodyOpen {
- st.reqBuf = getRequestBodyBuf()
- req.Body.(*requestBody).pipe = &pipe{
- b: &fixedBuffer{buf: st.reqBuf},
- }
-
- if vv, ok := rp.header["Content-Length"]; ok {
- req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64)
- } else {
- req.ContentLength = -1
- }
- }
- return rw, req, nil
-}
-
-type requestParam struct {
- method string
- scheme, authority, path string
- header http.Header
-}
-
-func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp requestParam) (*responseWriter, *http.Request, error) {
- sc.serveG.check()
-
- var tlsState *tls.ConnectionState // nil if not scheme https
- if rp.scheme == "https" {
- tlsState = sc.tlsState
- }
-
- needsContinue := rp.header.Get("Expect") == "100-continue"
- if needsContinue {
- rp.header.Del("Expect")
- }
- // Merge Cookie headers into one "; "-delimited value.
- if cookies := rp.header["Cookie"]; len(cookies) > 1 {
- rp.header.Set("Cookie", strings.Join(cookies, "; "))
- }
-
- // Setup Trailers
- var trailer http.Header
- for _, v := range rp.header["Trailer"] {
- for _, key := range strings.Split(v, ",") {
- key = http.CanonicalHeaderKey(strings.TrimSpace(key))
- switch key {
- case "Transfer-Encoding", "Trailer", "Content-Length":
- // Bogus. (copy of http1 rules)
- // Ignore.
- default:
- if trailer == nil {
- trailer = make(http.Header)
- }
- trailer[key] = nil
- }
- }
- }
- delete(rp.header, "Trailer")
-
- var url_ *url.URL
- var requestURI string
- if rp.method == "CONNECT" {
- url_ = &url.URL{Host: rp.authority}
- requestURI = rp.authority // mimic HTTP/1 server behavior
- } else {
- var err error
- url_, err = url.ParseRequestURI(rp.path)
- if err != nil {
- return nil, nil, streamError(st.id, ErrCodeProtocol)
- }
- requestURI = rp.path
- }
-
- body := &requestBody{
- conn: sc,
- stream: st,
- needsContinue: needsContinue,
- }
- req := &http.Request{
- Method: rp.method,
- URL: url_,
- RemoteAddr: sc.remoteAddrStr,
- Header: rp.header,
- RequestURI: requestURI,
- Proto: "HTTP/2.0",
- ProtoMajor: 2,
- ProtoMinor: 0,
- TLS: tlsState,
- Host: rp.authority,
- Body: body,
- Trailer: trailer,
- }
- req = requestWithContext(req, st.ctx)
-
- rws := responseWriterStatePool.Get().(*responseWriterState)
- bwSave := rws.bw
- *rws = responseWriterState{} // zero all the fields
- rws.conn = sc
- rws.bw = bwSave
- rws.bw.Reset(chunkWriter{rws})
- rws.stream = st
- rws.req = req
- rws.body = body
-
- rw := &responseWriter{rws: rws}
- return rw, req, nil
-}
-
-var reqBodyCache = make(chan []byte, 8)
-
-func getRequestBodyBuf() []byte {
- select {
- case b := <-reqBodyCache:
- return b
- default:
- return make([]byte, initialWindowSize)
- }
-}
-
-func putRequestBodyBuf(b []byte) {
- select {
- case reqBodyCache <- b:
- default:
- }
-}
-
-// Run on its own goroutine.
-func (sc *serverConn) runHandler(rw *responseWriter, req *http.Request, handler func(http.ResponseWriter, *http.Request)) {
- didPanic := true
- defer func() {
- rw.rws.stream.cancelCtx()
- if didPanic {
- e := recover()
- sc.writeFrameFromHandler(FrameWriteRequest{
- write: handlerPanicRST{rw.rws.stream.id},
- stream: rw.rws.stream,
- })
- // Same as net/http:
- if shouldLogPanic(e) {
- const size = 64 << 10
- buf := make([]byte, size)
- buf = buf[:runtime.Stack(buf, false)]
- sc.logf("http2: panic serving %v: %v\n%s", sc.conn.RemoteAddr(), e, buf)
- }
- return
- }
- rw.handlerDone()
- }()
- handler(rw, req)
- didPanic = false
-}
-
-func handleHeaderListTooLong(w http.ResponseWriter, r *http.Request) {
- // 10.5.1 Limits on Header Block Size:
- // .. "A server that receives a larger header block than it is
- // willing to handle can send an HTTP 431 (Request Header Fields Too
- // Large) status code"
- const statusRequestHeaderFieldsTooLarge = 431 // only in Go 1.6+
- w.WriteHeader(statusRequestHeaderFieldsTooLarge)
- io.WriteString(w, "<h1>HTTP Error 431</h1><p>Request Header Field(s) Too Large</p>")
-}
-
-// called from handler goroutines.
-// h may be nil.
-func (sc *serverConn) writeHeaders(st *stream, headerData *writeResHeaders) error {
- sc.serveG.checkNotOn() // NOT on
- var errc chan error
- if headerData.h != nil {
- // If there's a header map (which we don't own), so we have to block on
- // waiting for this frame to be written, so an http.Flush mid-handler
- // writes out the correct value of keys, before a handler later potentially
- // mutates it.
- errc = errChanPool.Get().(chan error)
- }
- if err := sc.writeFrameFromHandler(FrameWriteRequest{
- write: headerData,
- stream: st,
- done: errc,
- }); err != nil {
- return err
- }
- if errc != nil {
- select {
- case err := <-errc:
- errChanPool.Put(errc)
- return err
- case <-sc.doneServing:
- return errClientDisconnected
- case <-st.cw:
- return errStreamClosed
- }
- }
- return nil
-}
-
-// called from handler goroutines.
-func (sc *serverConn) write100ContinueHeaders(st *stream) {
- sc.writeFrameFromHandler(FrameWriteRequest{
- write: write100ContinueHeadersFrame{st.id},
- stream: st,
- })
-}
-
-// A bodyReadMsg tells the server loop that the http.Handler read n
-// bytes of the DATA from the client on the given stream.
-type bodyReadMsg struct {
- st *stream
- n int
-}
-
-// called from handler goroutines.
-// Notes that the handler for the given stream ID read n bytes of its body
-// and schedules flow control tokens to be sent.
-func (sc *serverConn) noteBodyReadFromHandler(st *stream, n int, err error) {
- sc.serveG.checkNotOn() // NOT on
- if n > 0 {
- select {
- case sc.bodyReadCh <- bodyReadMsg{st, n}:
- case <-sc.doneServing:
- }
- }
- if err == io.EOF {
- if buf := st.reqBuf; buf != nil {
- st.reqBuf = nil // shouldn't matter; field unused by other
- putRequestBodyBuf(buf)
- }
- }
-}
-
-func (sc *serverConn) noteBodyRead(st *stream, n int) {
- sc.serveG.check()
- sc.sendWindowUpdate(nil, n) // conn-level
- if st.state != stateHalfClosedRemote && st.state != stateClosed {
- // Don't send this WINDOW_UPDATE if the stream is closed
- // remotely.
- sc.sendWindowUpdate(st, n)
- }
-}
-
-// st may be nil for conn-level
-func (sc *serverConn) sendWindowUpdate(st *stream, n int) {
- sc.serveG.check()
- // "The legal range for the increment to the flow control
- // window is 1 to 2^31-1 (2,147,483,647) octets."
- // A Go Read call on 64-bit machines could in theory read
- // a larger Read than this. Very unlikely, but we handle it here
- // rather than elsewhere for now.
- const maxUint31 = 1<<31 - 1
- for n >= maxUint31 {
- sc.sendWindowUpdate32(st, maxUint31)
- n -= maxUint31
- }
- sc.sendWindowUpdate32(st, int32(n))
-}
-
-// st may be nil for conn-level
-func (sc *serverConn) sendWindowUpdate32(st *stream, n int32) {
- sc.serveG.check()
- if n == 0 {
- return
- }
- if n < 0 {
- panic("negative update")
- }
- var streamID uint32
- if st != nil {
- streamID = st.id
- }
- sc.writeFrame(FrameWriteRequest{
- write: writeWindowUpdate{streamID: streamID, n: uint32(n)},
- stream: st,
- })
- var ok bool
- if st == nil {
- ok = sc.inflow.add(n)
- } else {
- ok = st.inflow.add(n)
- }
- if !ok {
- panic("internal error; sent too many window updates without decrements?")
- }
-}
-
-// requestBody is the Handler's Request.Body type.
-// Read and Close may be called concurrently.
-type requestBody struct {
- stream *stream
- conn *serverConn
- closed bool // for use by Close only
- sawEOF bool // for use by Read only
- pipe *pipe // non-nil if we have a HTTP entity message body
- needsContinue bool // need to send a 100-continue
-}
-
-func (b *requestBody) Close() error {
- if b.pipe != nil && !b.closed {
- b.pipe.BreakWithError(errClosedBody)
- }
- b.closed = true
- return nil
-}
-
-func (b *requestBody) Read(p []byte) (n int, err error) {
- if b.needsContinue {
- b.needsContinue = false
- b.conn.write100ContinueHeaders(b.stream)
- }
- if b.pipe == nil || b.sawEOF {
- return 0, io.EOF
- }
- n, err = b.pipe.Read(p)
- if err == io.EOF {
- b.sawEOF = true
- }
- if b.conn == nil && inTests {
- return
- }
- b.conn.noteBodyReadFromHandler(b.stream, n, err)
- return
-}
-
-// responseWriter is the http.ResponseWriter implementation. It's
-// intentionally small (1 pointer wide) to minimize garbage. The
-// responseWriterState pointer inside is zeroed at the end of a
-// request (in handlerDone) and calls on the responseWriter thereafter
-// simply crash (caller's mistake), but the much larger responseWriterState
-// and buffers are reused between multiple requests.
-type responseWriter struct {
- rws *responseWriterState
-}
-
-// Optional http.ResponseWriter interfaces implemented.
-var (
- _ http.CloseNotifier = (*responseWriter)(nil)
- _ http.Flusher = (*responseWriter)(nil)
- _ stringWriter = (*responseWriter)(nil)
-)
-
-type responseWriterState struct {
- // immutable within a request:
- stream *stream
- req *http.Request
- body *requestBody // to close at end of request, if DATA frames didn't
- conn *serverConn
-
- // TODO: adjust buffer writing sizes based on server config, frame size updates from peer, etc
- bw *bufio.Writer // writing to a chunkWriter{this *responseWriterState}
-
- // mutated by http.Handler goroutine:
- handlerHeader http.Header // nil until called
- snapHeader http.Header // snapshot of handlerHeader at WriteHeader time
- trailers []string // set in writeChunk
- status int // status code passed to WriteHeader
- wroteHeader bool // WriteHeader called (explicitly or implicitly). Not necessarily sent to user yet.
- sentHeader bool // have we sent the header frame?
- handlerDone bool // handler has finished
-
- sentContentLen int64 // non-zero if handler set a Content-Length header
- wroteBytes int64
-
- closeNotifierMu sync.Mutex // guards closeNotifierCh
- closeNotifierCh chan bool // nil until first used
-}
-
-type chunkWriter struct{ rws *responseWriterState }
-
-func (cw chunkWriter) Write(p []byte) (n int, err error) { return cw.rws.writeChunk(p) }
-
-func (rws *responseWriterState) hasTrailers() bool { return len(rws.trailers) != 0 }
-
-// declareTrailer is called for each Trailer header when the
-// response header is written. It notes that a header will need to be
-// written in the trailers at the end of the response.
-func (rws *responseWriterState) declareTrailer(k string) {
- k = http.CanonicalHeaderKey(k)
- if !ValidTrailerHeader(k) {
- // Forbidden by RFC 2616 14.40.
- rws.conn.logf("ignoring invalid trailer %q", k)
- return
- }
- if !strSliceContains(rws.trailers, k) {
- rws.trailers = append(rws.trailers, k)
- }
-}
-
-// writeChunk writes chunks from the bufio.Writer. But because
-// bufio.Writer may bypass its chunking, sometimes p may be
-// arbitrarily large.
-//
-// writeChunk is also responsible (on the first chunk) for sending the
-// HEADER response.
-func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
- if !rws.wroteHeader {
- rws.writeHeader(200)
- }
-
- isHeadResp := rws.req.Method == "HEAD"
- if !rws.sentHeader {
- rws.sentHeader = true
- var ctype, clen string
- if clen = rws.snapHeader.Get("Content-Length"); clen != "" {
- rws.snapHeader.Del("Content-Length")
- clen64, err := strconv.ParseInt(clen, 10, 64)
- if err == nil && clen64 >= 0 {
- rws.sentContentLen = clen64
- } else {
- clen = ""
- }
- }
- if clen == "" && rws.handlerDone && bodyAllowedForStatus(rws.status) && (len(p) > 0 || !isHeadResp) {
- clen = strconv.Itoa(len(p))
- }
- _, hasContentType := rws.snapHeader["Content-Type"]
- if !hasContentType && bodyAllowedForStatus(rws.status) {
- ctype = http.DetectContentType(p)
- }
- var date string
- if _, ok := rws.snapHeader["Date"]; !ok {
- // TODO(bradfitz): be faster here, like net/http? measure.
- date = time.Now().UTC().Format(http.TimeFormat)
- }
-
- for _, v := range rws.snapHeader["Trailer"] {
- foreachHeaderElement(v, rws.declareTrailer)
- }
-
- endStream := (rws.handlerDone && !rws.hasTrailers() && len(p) == 0) || isHeadResp
- err = rws.conn.writeHeaders(rws.stream, &writeResHeaders{
- streamID: rws.stream.id,
- httpResCode: rws.status,
- h: rws.snapHeader,
- endStream: endStream,
- contentType: ctype,
- contentLength: clen,
- date: date,
- })
- if err != nil {
- return 0, err
- }
- if endStream {
- return 0, nil
- }
- }
- if isHeadResp {
- return len(p), nil
- }
- if len(p) == 0 && !rws.handlerDone {
- return 0, nil
- }
-
- if rws.handlerDone {
- rws.promoteUndeclaredTrailers()
- }
-
- endStream := rws.handlerDone && !rws.hasTrailers()
- if len(p) > 0 || endStream {
- // only send a 0 byte DATA frame if we're ending the stream.
- if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil {
- return 0, err
- }
- }
-
- if rws.handlerDone && rws.hasTrailers() {
- err = rws.conn.writeHeaders(rws.stream, &writeResHeaders{
- streamID: rws.stream.id,
- h: rws.handlerHeader,
- trailers: rws.trailers,
- endStream: true,
- })
- return len(p), err
- }
- return len(p), nil
-}
-
-// TrailerPrefix is a magic prefix for ResponseWriter.Header map keys
-// that, if present, signals that the map entry is actually for
-// the response trailers, and not the response headers. The prefix
-// is stripped after the ServeHTTP call finishes and the values are
-// sent in the trailers.
-//
-// This mechanism is intended only for trailers that are not known
-// prior to the headers being written. If the set of trailers is fixed
-// or known before the header is written, the normal Go trailers mechanism
-// is preferred:
-// https://golang.org/pkg/net/http/#ResponseWriter
-// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
-const TrailerPrefix = "Trailer:"
-
-// promoteUndeclaredTrailers permits http.Handlers to set trailers
-// after the header has already been flushed. Because the Go
-// ResponseWriter interface has no way to set Trailers (only the
-// Header), and because we didn't want to expand the ResponseWriter
-// interface, and because nobody used trailers, and because RFC 2616
-// says you SHOULD (but not must) predeclare any trailers in the
-// header, the official ResponseWriter rules said trailers in Go must
-// be predeclared, and then we reuse the same ResponseWriter.Header()
-// map to mean both Headers and Trailers. When it's time to write the
-// Trailers, we pick out the fields of Headers that were declared as
-// trailers. That worked for a while, until we found the first major
-// user of Trailers in the wild: gRPC (using them only over http2),
-// and gRPC libraries permit setting trailers mid-stream without
-// predeclarnig them. So: change of plans. We still permit the old
-// way, but we also permit this hack: if a Header() key begins with
-// "Trailer:", the suffix of that key is a Trailer. Because ':' is an
-// invalid token byte anyway, there is no ambiguity. (And it's already
-// filtered out) It's mildly hacky, but not terrible.
-//
-// This method runs after the Handler is done and promotes any Header
-// fields to be trailers.
-func (rws *responseWriterState) promoteUndeclaredTrailers() {
- for k, vv := range rws.handlerHeader {
- if !strings.HasPrefix(k, TrailerPrefix) {
- continue
- }
- trailerKey := strings.TrimPrefix(k, TrailerPrefix)
- rws.declareTrailer(trailerKey)
- rws.handlerHeader[http.CanonicalHeaderKey(trailerKey)] = vv
- }
-
- if len(rws.trailers) > 1 {
- sorter := sorterPool.Get().(*sorter)
- sorter.SortStrings(rws.trailers)
- sorterPool.Put(sorter)
- }
-}
-
-func (w *responseWriter) Flush() {
- rws := w.rws
- if rws == nil {
- panic("Header called after Handler finished")
- }
- if rws.bw.Buffered() > 0 {
- if err := rws.bw.Flush(); err != nil {
- // Ignore the error. The frame writer already knows.
- return
- }
- } else {
- // The bufio.Writer won't call chunkWriter.Write
- // (writeChunk with zero bytes, so we have to do it
- // ourselves to force the HTTP response header and/or
- // final DATA frame (with END_STREAM) to be sent.
- rws.writeChunk(nil)
- }
-}
-
-func (w *responseWriter) CloseNotify() <-chan bool {
- rws := w.rws
- if rws == nil {
- panic("CloseNotify called after Handler finished")
- }
- rws.closeNotifierMu.Lock()
- ch := rws.closeNotifierCh
- if ch == nil {
- ch = make(chan bool, 1)
- rws.closeNotifierCh = ch
- cw := rws.stream.cw
- go func() {
- cw.Wait() // wait for close
- ch <- true
- }()
- }
- rws.closeNotifierMu.Unlock()
- return ch
-}
-
-func (w *responseWriter) Header() http.Header {
- rws := w.rws
- if rws == nil {
- panic("Header called after Handler finished")
- }
- if rws.handlerHeader == nil {
- rws.handlerHeader = make(http.Header)
- }
- return rws.handlerHeader
-}
-
-func (w *responseWriter) WriteHeader(code int) {
- rws := w.rws
- if rws == nil {
- panic("WriteHeader called after Handler finished")
- }
- rws.writeHeader(code)
-}
-
-func (rws *responseWriterState) writeHeader(code int) {
- if !rws.wroteHeader {
- rws.wroteHeader = true
- rws.status = code
- if len(rws.handlerHeader) > 0 {
- rws.snapHeader = cloneHeader(rws.handlerHeader)
- }
- }
-}
-
-func cloneHeader(h http.Header) http.Header {
- h2 := make(http.Header, len(h))
- for k, vv := range h {
- vv2 := make([]string, len(vv))
- copy(vv2, vv)
- h2[k] = vv2
- }
- return h2
-}
-
-// The Life Of A Write is like this:
-//
-// * Handler calls w.Write or w.WriteString ->
-// * -> rws.bw (*bufio.Writer) ->
-// * (Handler migth call Flush)
-// * -> chunkWriter{rws}
-// * -> responseWriterState.writeChunk(p []byte)
-// * -> responseWriterState.writeChunk (most of the magic; see comment there)
-func (w *responseWriter) Write(p []byte) (n int, err error) {
- return w.write(len(p), p, "")
-}
-
-func (w *responseWriter) WriteString(s string) (n int, err error) {
- return w.write(len(s), nil, s)
-}
-
-// either dataB or dataS is non-zero.
-func (w *responseWriter) write(lenData int, dataB []byte, dataS string) (n int, err error) {
- rws := w.rws
- if rws == nil {
- panic("Write called after Handler finished")
- }
- if !rws.wroteHeader {
- w.WriteHeader(200)
- }
- if !bodyAllowedForStatus(rws.status) {
- return 0, http.ErrBodyNotAllowed
- }
- rws.wroteBytes += int64(len(dataB)) + int64(len(dataS)) // only one can be set
- if rws.sentContentLen != 0 && rws.wroteBytes > rws.sentContentLen {
- // TODO: send a RST_STREAM
- return 0, errors.New("http2: handler wrote more than declared Content-Length")
- }
-
- if dataB != nil {
- return rws.bw.Write(dataB)
- } else {
- return rws.bw.WriteString(dataS)
- }
-}
-
-func (w *responseWriter) handlerDone() {
- rws := w.rws
- rws.handlerDone = true
- w.Flush()
- w.rws = nil
- responseWriterStatePool.Put(rws)
-}
-
-// Push errors.
-var (
- ErrRecursivePush = errors.New("http2: recursive push not allowed")
- ErrPushLimitReached = errors.New("http2: push would exceed peer's SETTINGS_MAX_CONCURRENT_STREAMS")
-)
-
-// pushOptions is the internal version of http.PushOptions, which we
-// cannot include here because it's only defined in Go 1.8 and later.
-type pushOptions struct {
- Method string
- Header http.Header
-}
-
-func (w *responseWriter) push(target string, opts pushOptions) error {
- st := w.rws.stream
- sc := st.sc
- sc.serveG.checkNotOn()
-
- // No recursive pushes: "PUSH_PROMISE frames MUST only be sent on a peer-initiated stream."
- // http://tools.ietf.org/html/rfc7540#section-6.6
- if st.isPushed() {
- return ErrRecursivePush
- }
-
- // Default options.
- if opts.Method == "" {
- opts.Method = "GET"
- }
- if opts.Header == nil {
- opts.Header = http.Header{}
- }
- wantScheme := "http"
- if w.rws.req.TLS != nil {
- wantScheme = "https"
- }
-
- // Validate the request.
- u, err := url.Parse(target)
- if err != nil {
- return err
- }
- if u.Scheme == "" {
- if !strings.HasPrefix(target, "/") {
- return fmt.Errorf("target must be an absolute URL or an absolute path: %q", target)
- }
- u.Scheme = wantScheme
- u.Host = w.rws.req.Host
- } else {
- if u.Scheme != wantScheme {
- return fmt.Errorf("cannot push URL with scheme %q from request with scheme %q", u.Scheme, wantScheme)
- }
- if u.Host == "" {
- return errors.New("URL must have a host")
- }
- }
- for k := range opts.Header {
- if strings.HasPrefix(k, ":") {
- return fmt.Errorf("promised request headers cannot include pseudo header %q", k)
- }
- // These headers are meaningful only if the request has a body,
- // but PUSH_PROMISE requests cannot have a body.
- // http://tools.ietf.org/html/rfc7540#section-8.2
- // Also disallow Host, since the promised URL must be absolute.
- switch strings.ToLower(k) {
- case "content-length", "content-encoding", "trailer", "te", "expect", "host":
- return fmt.Errorf("promised request headers cannot include %q", k)
- }
- }
- if err := checkValidHTTP2RequestHeaders(opts.Header); err != nil {
- return err
- }
-
- // The RFC effectively limits promised requests to GET and HEAD:
- // "Promised requests MUST be cacheable [GET, HEAD, or POST], and MUST be safe [GET or HEAD]"
- // http://tools.ietf.org/html/rfc7540#section-8.2
- if opts.Method != "GET" && opts.Method != "HEAD" {
- return fmt.Errorf("method %q must be GET or HEAD", opts.Method)
- }
-
- msg := startPushRequest{
- parent: st,
- method: opts.Method,
- url: u,
- header: cloneHeader(opts.Header),
- done: errChanPool.Get().(chan error),
- }
-
- select {
- case <-sc.doneServing:
- return errClientDisconnected
- case <-st.cw:
- return errStreamClosed
- case sc.wantStartPushCh <- msg:
- }
-
- select {
- case <-sc.doneServing:
- return errClientDisconnected
- case <-st.cw:
- return errStreamClosed
- case err := <-msg.done:
- errChanPool.Put(msg.done)
- return err
- }
-}
-
-type startPushRequest struct {
- parent *stream
- method string
- url *url.URL
- header http.Header
- done chan error
-}
-
-func (sc *serverConn) startPush(msg startPushRequest) {
- sc.serveG.check()
-
- // http://tools.ietf.org/html/rfc7540#section-6.6.
- // PUSH_PROMISE frames MUST only be sent on a peer-initiated stream that
- // is in either the "open" or "half-closed (remote)" state.
- if msg.parent.state != stateOpen && msg.parent.state != stateHalfClosedRemote {
- // responseWriter.Push checks that the stream is peer-initiaed.
- msg.done <- errStreamClosed
- return
- }
-
- // http://tools.ietf.org/html/rfc7540#section-6.6.
- if !sc.pushEnabled {
- msg.done <- http.ErrNotSupported
- return
- }
-
- // PUSH_PROMISE frames must be sent in increasing order by stream ID, so
- // we allocate an ID for the promised stream lazily, when the PUSH_PROMISE
- // is written. Once the ID is allocated, we start the request handler.
- allocatePromisedID := func() (uint32, error) {
- sc.serveG.check()
-
- // Check this again, just in case. Technically, we might have received
- // an updated SETTINGS by the time we got around to writing this frame.
- if !sc.pushEnabled {
- return 0, http.ErrNotSupported
- }
- // http://tools.ietf.org/html/rfc7540#section-6.5.2.
- if sc.curPushedStreams+1 > sc.clientMaxStreams {
- return 0, ErrPushLimitReached
- }
-
- // http://tools.ietf.org/html/rfc7540#section-5.1.1.
- // Streams initiated by the server MUST use even-numbered identifiers.
- // A server that is unable to establish a new stream identifier can send a GOAWAY
- // frame so that the client is forced to open a new connection for new streams.
- if sc.maxPushPromiseID+2 >= 1<<31 {
- sc.startGracefulShutdown()
- return 0, ErrPushLimitReached
- }
- sc.maxPushPromiseID += 2
- promisedID := sc.maxPushPromiseID
-
- // http://tools.ietf.org/html/rfc7540#section-8.2.
- // Strictly speaking, the new stream should start in "reserved (local)", then
- // transition to "half closed (remote)" after sending the initial HEADERS, but
- // we start in "half closed (remote)" for simplicity.
- // See further comments at the definition of stateHalfClosedRemote.
- promised := sc.newStream(promisedID, msg.parent.id, stateHalfClosedRemote)
- rw, req, err := sc.newWriterAndRequestNoBody(promised, requestParam{
- method: msg.method,
- scheme: msg.url.Scheme,
- authority: msg.url.Host,
- path: msg.url.RequestURI(),
- header: cloneHeader(msg.header), // clone since handler runs concurrently with writing the PUSH_PROMISE
- })
- if err != nil {
- // Should not happen, since we've already validated msg.url.
- panic(fmt.Sprintf("newWriterAndRequestNoBody(%+v): %v", msg.url, err))
- }
-
- go sc.runHandler(rw, req, sc.handler.ServeHTTP)
- return promisedID, nil
- }
-
- sc.writeFrame(FrameWriteRequest{
- write: &writePushPromise{
- streamID: msg.parent.id,
- method: msg.method,
- url: msg.url,
- h: msg.header,
- allocatePromisedID: allocatePromisedID,
- },
- stream: msg.parent,
- done: msg.done,
- })
-}
-
-// foreachHeaderElement splits v according to the "#rule" construction
-// in RFC 2616 section 2.1 and calls fn for each non-empty element.
-func foreachHeaderElement(v string, fn func(string)) {
- v = textproto.TrimString(v)
- if v == "" {
- return
- }
- if !strings.Contains(v, ",") {
- fn(v)
- return
- }
- for _, f := range strings.Split(v, ",") {
- if f = textproto.TrimString(f); f != "" {
- fn(f)
- }
- }
-}
-
-// From http://httpwg.org/specs/rfc7540.html#rfc.section.8.1.2.2
-var connHeaders = []string{
- "Connection",
- "Keep-Alive",
- "Proxy-Connection",
- "Transfer-Encoding",
- "Upgrade",
-}
-
-// checkValidHTTP2RequestHeaders checks whether h is a valid HTTP/2 request,
-// per RFC 7540 Section 8.1.2.2.
-// The returned error is reported to users.
-func checkValidHTTP2RequestHeaders(h http.Header) error {
- for _, k := range connHeaders {
- if _, ok := h[k]; ok {
- return fmt.Errorf("request header %q is not valid in HTTP/2", k)
- }
- }
- te := h["Te"]
- if len(te) > 0 && (len(te) > 1 || (te[0] != "trailers" && te[0] != "")) {
- return errors.New(`request header "TE" may only be "trailers" in HTTP/2`)
- }
- return nil
-}
-
-func new400Handler(err error) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- http.Error(w, err.Error(), http.StatusBadRequest)
- }
-}
-
-// ValidTrailerHeader reports whether name is a valid header field name to appear
-// in trailers.
-// See: http://tools.ietf.org/html/rfc7230#section-4.1.2
-func ValidTrailerHeader(name string) bool {
- name = http.CanonicalHeaderKey(name)
- if strings.HasPrefix(name, "If-") || badTrailer[name] {
- return false
- }
- return true
-}
-
-var badTrailer = map[string]bool{
- "Authorization": true,
- "Cache-Control": true,
- "Connection": true,
- "Content-Encoding": true,
- "Content-Length": true,
- "Content-Range": true,
- "Content-Type": true,
- "Expect": true,
- "Host": true,
- "Keep-Alive": true,
- "Max-Forwards": true,
- "Pragma": true,
- "Proxy-Authenticate": true,
- "Proxy-Authorization": true,
- "Proxy-Connection": true,
- "Range": true,
- "Realm": true,
- "Te": true,
- "Trailer": true,
- "Transfer-Encoding": true,
- "Www-Authenticate": true,
-}
-
-// h1ServerShutdownChan returns a channel that will be closed when the
-// provided *http.Server wants to shut down.
-//
-// This is a somewhat hacky way to get at http1 innards. It works
-// when the http2 code is bundled into the net/http package in the
-// standard library. The alternatives ended up making the cmd/go tool
-// depend on http Servers. This is the lightest option for now.
-// This is tested via the TestServeShutdown* tests in net/http.
-func h1ServerShutdownChan(hs *http.Server) <-chan struct{} {
- if fn := testh1ServerShutdownChan; fn != nil {
- return fn(hs)
- }
- var x interface{} = hs
- type I interface {
- getDoneChan() <-chan struct{}
- }
- if hs, ok := x.(I); ok {
- return hs.getDoneChan()
- }
- return nil
-}
-
-// optional test hook for h1ServerShutdownChan.
-var testh1ServerShutdownChan func(hs *http.Server) <-chan struct{}
-
-// h1ServerKeepAlivesDisabled reports whether hs has its keep-alives
-// disabled. See comments on h1ServerShutdownChan above for why
-// the code is written this way.
-func h1ServerKeepAlivesDisabled(hs *http.Server) bool {
- var x interface{} = hs
- type I interface {
- doKeepAlives() bool
- }
- if hs, ok := x.(I); ok {
- return !hs.doKeepAlives()
- }
- return false
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/server_push_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/server_push_test.go
deleted file mode 100644
index f70edd3..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/server_push_test.go
+++ /dev/null
@@ -1,521 +0,0 @@
-// 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.8
-
-package http2
-
-import (
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "reflect"
- "strconv"
- "sync"
- "testing"
- "time"
-)
-
-func TestServer_Push_Success(t *testing.T) {
- const (
- mainBody = "<html>index page</html>"
- pushedBody = "<html>pushed page</html>"
- userAgent = "testagent"
- cookie = "testcookie"
- )
-
- var stURL string
- checkPromisedReq := func(r *http.Request, wantMethod string, wantH http.Header) error {
- if got, want := r.Method, wantMethod; got != want {
- return fmt.Errorf("promised Req.Method=%q, want %q", got, want)
- }
- if got, want := r.Header, wantH; !reflect.DeepEqual(got, want) {
- return fmt.Errorf("promised Req.Header=%q, want %q", got, want)
- }
- if got, want := "https://"+r.Host, stURL; got != want {
- return fmt.Errorf("promised Req.Host=%q, want %q", got, want)
- }
- if r.Body == nil {
- return fmt.Errorf("nil Body")
- }
- if buf, err := ioutil.ReadAll(r.Body); err != nil || len(buf) != 0 {
- return fmt.Errorf("ReadAll(Body)=%q,%v, want '',nil", buf, err)
- }
- return nil
- }
-
- errc := make(chan error, 3)
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- switch r.URL.RequestURI() {
- case "/":
- // Push "/pushed?get" as a GET request, using an absolute URL.
- opt := &http.PushOptions{
- Header: http.Header{
- "User-Agent": {userAgent},
- },
- }
- if err := w.(http.Pusher).Push(stURL+"/pushed?get", opt); err != nil {
- errc <- fmt.Errorf("error pushing /pushed?get: %v", err)
- return
- }
- // Push "/pushed?head" as a HEAD request, using a path.
- opt = &http.PushOptions{
- Method: "HEAD",
- Header: http.Header{
- "User-Agent": {userAgent},
- "Cookie": {cookie},
- },
- }
- if err := w.(http.Pusher).Push("/pushed?head", opt); err != nil {
- errc <- fmt.Errorf("error pushing /pushed?head: %v", err)
- return
- }
- w.Header().Set("Content-Type", "text/html")
- w.Header().Set("Content-Length", strconv.Itoa(len(mainBody)))
- w.WriteHeader(200)
- io.WriteString(w, mainBody)
- errc <- nil
-
- case "/pushed?get":
- wantH := http.Header{}
- wantH.Set("User-Agent", userAgent)
- if err := checkPromisedReq(r, "GET", wantH); err != nil {
- errc <- fmt.Errorf("/pushed?get: %v", err)
- return
- }
- w.Header().Set("Content-Type", "text/html")
- w.Header().Set("Content-Length", strconv.Itoa(len(pushedBody)))
- w.WriteHeader(200)
- io.WriteString(w, pushedBody)
- errc <- nil
-
- case "/pushed?head":
- wantH := http.Header{}
- wantH.Set("User-Agent", userAgent)
- wantH.Set("Cookie", cookie)
- if err := checkPromisedReq(r, "HEAD", wantH); err != nil {
- errc <- fmt.Errorf("/pushed?head: %v", err)
- return
- }
- w.WriteHeader(204)
- errc <- nil
-
- default:
- errc <- fmt.Errorf("unknown RequestURL %q", r.URL.RequestURI())
- }
- })
- stURL = st.ts.URL
-
- // Send one request, which should push two responses.
- st.greet()
- getSlash(st)
- for k := 0; k < 3; k++ {
- select {
- case <-time.After(2 * time.Second):
- t.Errorf("timeout waiting for handler %d to finish", k)
- case err := <-errc:
- if err != nil {
- t.Fatal(err)
- }
- }
- }
-
- checkPushPromise := func(f Frame, promiseID uint32, wantH [][2]string) error {
- pp, ok := f.(*PushPromiseFrame)
- if !ok {
- return fmt.Errorf("got a %T; want *PushPromiseFrame", f)
- }
- if !pp.HeadersEnded() {
- return fmt.Errorf("want END_HEADERS flag in PushPromiseFrame")
- }
- if got, want := pp.PromiseID, promiseID; got != want {
- return fmt.Errorf("got PromiseID %v; want %v", got, want)
- }
- gotH := st.decodeHeader(pp.HeaderBlockFragment())
- if !reflect.DeepEqual(gotH, wantH) {
- return fmt.Errorf("got promised headers %v; want %v", gotH, wantH)
- }
- return nil
- }
- checkHeaders := func(f Frame, wantH [][2]string) error {
- hf, ok := f.(*HeadersFrame)
- if !ok {
- return fmt.Errorf("got a %T; want *HeadersFrame", f)
- }
- gotH := st.decodeHeader(hf.HeaderBlockFragment())
- if !reflect.DeepEqual(gotH, wantH) {
- return fmt.Errorf("got response headers %v; want %v", gotH, wantH)
- }
- return nil
- }
- checkData := func(f Frame, wantData string) error {
- df, ok := f.(*DataFrame)
- if !ok {
- return fmt.Errorf("got a %T; want *DataFrame", f)
- }
- if gotData := string(df.Data()); gotData != wantData {
- return fmt.Errorf("got response data %q; want %q", gotData, wantData)
- }
- return nil
- }
-
- // Stream 1 has 2 PUSH_PROMISE + HEADERS + DATA
- // Stream 2 has HEADERS + DATA
- // Stream 4 has HEADERS
- expected := map[uint32][]func(Frame) error{
- 1: {
- func(f Frame) error {
- return checkPushPromise(f, 2, [][2]string{
- {":method", "GET"},
- {":scheme", "https"},
- {":authority", st.ts.Listener.Addr().String()},
- {":path", "/pushed?get"},
- {"user-agent", userAgent},
- })
- },
- func(f Frame) error {
- return checkPushPromise(f, 4, [][2]string{
- {":method", "HEAD"},
- {":scheme", "https"},
- {":authority", st.ts.Listener.Addr().String()},
- {":path", "/pushed?head"},
- {"cookie", cookie},
- {"user-agent", userAgent},
- })
- },
- func(f Frame) error {
- return checkHeaders(f, [][2]string{
- {":status", "200"},
- {"content-type", "text/html"},
- {"content-length", strconv.Itoa(len(mainBody))},
- })
- },
- func(f Frame) error {
- return checkData(f, mainBody)
- },
- },
- 2: {
- func(f Frame) error {
- return checkHeaders(f, [][2]string{
- {":status", "200"},
- {"content-type", "text/html"},
- {"content-length", strconv.Itoa(len(pushedBody))},
- })
- },
- func(f Frame) error {
- return checkData(f, pushedBody)
- },
- },
- 4: {
- func(f Frame) error {
- return checkHeaders(f, [][2]string{
- {":status", "204"},
- })
- },
- },
- }
-
- consumed := map[uint32]int{}
- for k := 0; len(expected) > 0; k++ {
- f, err := st.readFrame()
- if err != nil {
- for id, left := range expected {
- t.Errorf("stream %d: missing %d frames", id, len(left))
- }
- t.Fatalf("readFrame %d: %v", k, err)
- }
- id := f.Header().StreamID
- label := fmt.Sprintf("stream %d, frame %d", id, consumed[id])
- if len(expected[id]) == 0 {
- t.Fatalf("%s: unexpected frame %#+v", label, f)
- }
- check := expected[id][0]
- expected[id] = expected[id][1:]
- if len(expected[id]) == 0 {
- delete(expected, id)
- }
- if err := check(f); err != nil {
- t.Fatalf("%s: %v", label, err)
- }
- consumed[id]++
- }
-}
-
-func TestServer_Push_SuccessNoRace(t *testing.T) {
- // Regression test for issue #18326. Ensure the request handler can mutate
- // pushed request headers without racing with the PUSH_PROMISE write.
- errc := make(chan error, 2)
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- switch r.URL.RequestURI() {
- case "/":
- opt := &http.PushOptions{
- Header: http.Header{"User-Agent": {"testagent"}},
- }
- if err := w.(http.Pusher).Push("/pushed", opt); err != nil {
- errc <- fmt.Errorf("error pushing: %v", err)
- return
- }
- w.WriteHeader(200)
- errc <- nil
-
- case "/pushed":
- // Update request header, ensure there is no race.
- r.Header.Set("User-Agent", "newagent")
- r.Header.Set("Cookie", "cookie")
- w.WriteHeader(200)
- errc <- nil
-
- default:
- errc <- fmt.Errorf("unknown RequestURL %q", r.URL.RequestURI())
- }
- })
-
- // Send one request, which should push one response.
- st.greet()
- getSlash(st)
- for k := 0; k < 2; k++ {
- select {
- case <-time.After(2 * time.Second):
- t.Errorf("timeout waiting for handler %d to finish", k)
- case err := <-errc:
- if err != nil {
- t.Fatal(err)
- }
- }
- }
-}
-
-func TestServer_Push_RejectRecursivePush(t *testing.T) {
- // Expect two requests, but might get three if there's a bug and the second push succeeds.
- errc := make(chan error, 3)
- handler := func(w http.ResponseWriter, r *http.Request) error {
- baseURL := "https://" + r.Host
- switch r.URL.Path {
- case "/":
- if err := w.(http.Pusher).Push(baseURL+"/push1", nil); err != nil {
- return fmt.Errorf("first Push()=%v, want nil", err)
- }
- return nil
-
- case "/push1":
- if got, want := w.(http.Pusher).Push(baseURL+"/push2", nil), ErrRecursivePush; got != want {
- return fmt.Errorf("Push()=%v, want %v", got, want)
- }
- return nil
-
- default:
- return fmt.Errorf("unexpected path: %q", r.URL.Path)
- }
- }
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- errc <- handler(w, r)
- })
- defer st.Close()
- st.greet()
- getSlash(st)
- if err := <-errc; err != nil {
- t.Errorf("First request failed: %v", err)
- }
- if err := <-errc; err != nil {
- t.Errorf("Second request failed: %v", err)
- }
-}
-
-func testServer_Push_RejectSingleRequest(t *testing.T, doPush func(http.Pusher, *http.Request) error, settings ...Setting) {
- // Expect one request, but might get two if there's a bug and the push succeeds.
- errc := make(chan error, 2)
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- errc <- doPush(w.(http.Pusher), r)
- })
- defer st.Close()
- st.greet()
- if err := st.fr.WriteSettings(settings...); err != nil {
- st.t.Fatalf("WriteSettings: %v", err)
- }
- st.wantSettingsAck()
- getSlash(st)
- if err := <-errc; err != nil {
- t.Error(err)
- }
- // Should not get a PUSH_PROMISE frame.
- hf := st.wantHeaders()
- if !hf.StreamEnded() {
- t.Error("stream should end after headers")
- }
-}
-
-func TestServer_Push_RejectIfDisabled(t *testing.T) {
- testServer_Push_RejectSingleRequest(t,
- func(p http.Pusher, r *http.Request) error {
- if got, want := p.Push("https://"+r.Host+"/pushed", nil), http.ErrNotSupported; got != want {
- return fmt.Errorf("Push()=%v, want %v", got, want)
- }
- return nil
- },
- Setting{SettingEnablePush, 0})
-}
-
-func TestServer_Push_RejectWhenNoConcurrentStreams(t *testing.T) {
- testServer_Push_RejectSingleRequest(t,
- func(p http.Pusher, r *http.Request) error {
- if got, want := p.Push("https://"+r.Host+"/pushed", nil), ErrPushLimitReached; got != want {
- return fmt.Errorf("Push()=%v, want %v", got, want)
- }
- return nil
- },
- Setting{SettingMaxConcurrentStreams, 0})
-}
-
-func TestServer_Push_RejectWrongScheme(t *testing.T) {
- testServer_Push_RejectSingleRequest(t,
- func(p http.Pusher, r *http.Request) error {
- if err := p.Push("http://"+r.Host+"/pushed", nil); err == nil {
- return errors.New("Push() should have failed (push target URL is http)")
- }
- return nil
- })
-}
-
-func TestServer_Push_RejectMissingHost(t *testing.T) {
- testServer_Push_RejectSingleRequest(t,
- func(p http.Pusher, r *http.Request) error {
- if err := p.Push("https:pushed", nil); err == nil {
- return errors.New("Push() should have failed (push target URL missing host)")
- }
- return nil
- })
-}
-
-func TestServer_Push_RejectRelativePath(t *testing.T) {
- testServer_Push_RejectSingleRequest(t,
- func(p http.Pusher, r *http.Request) error {
- if err := p.Push("../test", nil); err == nil {
- return errors.New("Push() should have failed (push target is a relative path)")
- }
- return nil
- })
-}
-
-func TestServer_Push_RejectForbiddenMethod(t *testing.T) {
- testServer_Push_RejectSingleRequest(t,
- func(p http.Pusher, r *http.Request) error {
- if err := p.Push("https://"+r.Host+"/pushed", &http.PushOptions{Method: "POST"}); err == nil {
- return errors.New("Push() should have failed (cannot promise a POST)")
- }
- return nil
- })
-}
-
-func TestServer_Push_RejectForbiddenHeader(t *testing.T) {
- testServer_Push_RejectSingleRequest(t,
- func(p http.Pusher, r *http.Request) error {
- header := http.Header{
- "Content-Length": {"10"},
- "Content-Encoding": {"gzip"},
- "Trailer": {"Foo"},
- "Te": {"trailers"},
- "Host": {"test.com"},
- ":authority": {"test.com"},
- }
- if err := p.Push("https://"+r.Host+"/pushed", &http.PushOptions{Header: header}); err == nil {
- return errors.New("Push() should have failed (forbidden headers)")
- }
- return nil
- })
-}
-
-func TestServer_Push_StateTransitions(t *testing.T) {
- const body = "foo"
-
- gotPromise := make(chan bool)
- finishedPush := make(chan bool)
-
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- switch r.URL.RequestURI() {
- case "/":
- if err := w.(http.Pusher).Push("/pushed", nil); err != nil {
- t.Errorf("Push error: %v", err)
- }
- // Don't finish this request until the push finishes so we don't
- // nondeterministically interleave output frames with the push.
- <-finishedPush
- case "/pushed":
- <-gotPromise
- }
- w.Header().Set("Content-Type", "text/html")
- w.Header().Set("Content-Length", strconv.Itoa(len(body)))
- w.WriteHeader(200)
- io.WriteString(w, body)
- })
- defer st.Close()
-
- st.greet()
- if st.stream(2) != nil {
- t.Fatal("stream 2 should be empty")
- }
- if got, want := st.streamState(2), stateIdle; got != want {
- t.Fatalf("streamState(2)=%v, want %v", got, want)
- }
- getSlash(st)
- // After the PUSH_PROMISE is sent, the stream should be stateHalfClosedRemote.
- st.wantPushPromise()
- if got, want := st.streamState(2), stateHalfClosedRemote; got != want {
- t.Fatalf("streamState(2)=%v, want %v", got, want)
- }
- // We stall the HTTP handler for "/pushed" until the above check. If we don't
- // stall the handler, then the handler might write HEADERS and DATA and finish
- // the stream before we check st.streamState(2) -- should that happen, we'll
- // see stateClosed and fail the above check.
- close(gotPromise)
- st.wantHeaders()
- if df := st.wantData(); !df.StreamEnded() {
- t.Fatal("expected END_STREAM flag on DATA")
- }
- if got, want := st.streamState(2), stateClosed; got != want {
- t.Fatalf("streamState(2)=%v, want %v", got, want)
- }
- close(finishedPush)
-}
-
-func TestServer_Push_RejectAfterGoAway(t *testing.T) {
- var readyOnce sync.Once
- ready := make(chan struct{})
- errc := make(chan error, 2)
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- select {
- case <-ready:
- case <-time.After(5 * time.Second):
- errc <- fmt.Errorf("timeout waiting for GOAWAY to be processed")
- }
- if got, want := w.(http.Pusher).Push("https://"+r.Host+"/pushed", nil), http.ErrNotSupported; got != want {
- errc <- fmt.Errorf("Push()=%v, want %v", got, want)
- }
- errc <- nil
- })
- defer st.Close()
- st.greet()
- getSlash(st)
-
- // Send GOAWAY and wait for it to be processed.
- st.fr.WriteGoAway(1, ErrCodeNo, nil)
- go func() {
- for {
- select {
- case <-ready:
- return
- default:
- }
- st.sc.testHookCh <- func(loopNum int) {
- if !st.sc.pushEnabled {
- readyOnce.Do(func() { close(ready) })
- }
- }
- }
- }()
- if err := <-errc; err != nil {
- t.Error(err)
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/server_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/server_test.go
deleted file mode 100644
index c2e51e6..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/server_test.go
+++ /dev/null
@@ -1,3610 +0,0 @@
-// 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 http2
-
-import (
- "bytes"
- "crypto/tls"
- "errors"
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "net"
- "net/http"
- "net/http/httptest"
- "os"
- "os/exec"
- "reflect"
- "runtime"
- "strconv"
- "strings"
- "sync"
- "sync/atomic"
- "testing"
- "time"
-
- "golang.org/x/net/http2/hpack"
-)
-
-var stderrVerbose = flag.Bool("stderr_verbose", false, "Mirror verbosity to stderr, unbuffered")
-
-func stderrv() io.Writer {
- if *stderrVerbose {
- return os.Stderr
- }
-
- return ioutil.Discard
-}
-
-type serverTester struct {
- cc net.Conn // client conn
- t testing.TB
- ts *httptest.Server
- fr *Framer
- serverLogBuf bytes.Buffer // logger for httptest.Server
- logFilter []string // substrings to filter out
- scMu sync.Mutex // guards sc
- sc *serverConn
- hpackDec *hpack.Decoder
- decodedHeaders [][2]string
-
- // If http2debug!=2, then we capture Frame debug logs that will be written
- // to t.Log after a test fails. The read and write logs use separate locks
- // and buffers so we don't accidentally introduce synchronization between
- // the read and write goroutines, which may hide data races.
- frameReadLogMu sync.Mutex
- frameReadLogBuf bytes.Buffer
- frameWriteLogMu sync.Mutex
- frameWriteLogBuf bytes.Buffer
-
- // writing headers:
- headerBuf bytes.Buffer
- hpackEnc *hpack.Encoder
-}
-
-func init() {
- testHookOnPanicMu = new(sync.Mutex)
-}
-
-func resetHooks() {
- testHookOnPanicMu.Lock()
- testHookOnPanic = nil
- testHookOnPanicMu.Unlock()
-}
-
-type serverTesterOpt string
-
-var optOnlyServer = serverTesterOpt("only_server")
-var optQuiet = serverTesterOpt("quiet_logging")
-
-func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}) *serverTester {
- resetHooks()
-
- ts := httptest.NewUnstartedServer(handler)
-
- tlsConfig := &tls.Config{
- InsecureSkipVerify: true,
- NextProtos: []string{NextProtoTLS},
- }
-
- var onlyServer, quiet bool
- h2server := new(Server)
- for _, opt := range opts {
- switch v := opt.(type) {
- case func(*tls.Config):
- v(tlsConfig)
- case func(*httptest.Server):
- v(ts)
- case func(*Server):
- v(h2server)
- case serverTesterOpt:
- switch v {
- case optOnlyServer:
- onlyServer = true
- case optQuiet:
- quiet = true
- }
- case func(net.Conn, http.ConnState):
- ts.Config.ConnState = v
- default:
- t.Fatalf("unknown newServerTester option type %T", v)
- }
- }
-
- ConfigureServer(ts.Config, h2server)
-
- st := &serverTester{
- t: t,
- ts: ts,
- }
- st.hpackEnc = hpack.NewEncoder(&st.headerBuf)
- st.hpackDec = hpack.NewDecoder(initialHeaderTableSize, st.onHeaderField)
-
- ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config
- if quiet {
- ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
- } else {
- ts.Config.ErrorLog = log.New(io.MultiWriter(stderrv(), twriter{t: t, st: st}, &st.serverLogBuf), "", log.LstdFlags)
- }
- ts.StartTLS()
-
- if VerboseLogs {
- t.Logf("Running test server at: %s", ts.URL)
- }
- testHookGetServerConn = func(v *serverConn) {
- st.scMu.Lock()
- defer st.scMu.Unlock()
- st.sc = v
- st.sc.testHookCh = make(chan func(int))
- }
- log.SetOutput(io.MultiWriter(stderrv(), twriter{t: t, st: st}))
- if !onlyServer {
- cc, err := tls.Dial("tcp", ts.Listener.Addr().String(), tlsConfig)
- if err != nil {
- t.Fatal(err)
- }
- st.cc = cc
- st.fr = NewFramer(cc, cc)
- if !logFrameReads && !logFrameWrites {
- st.fr.debugReadLoggerf = func(m string, v ...interface{}) {
- m = time.Now().Format("2006-01-02 15:04:05.999999999 ") + strings.TrimPrefix(m, "http2: ") + "\n"
- st.frameReadLogMu.Lock()
- fmt.Fprintf(&st.frameReadLogBuf, m, v...)
- st.frameReadLogMu.Unlock()
- }
- st.fr.debugWriteLoggerf = func(m string, v ...interface{}) {
- m = time.Now().Format("2006-01-02 15:04:05.999999999 ") + strings.TrimPrefix(m, "http2: ") + "\n"
- st.frameWriteLogMu.Lock()
- fmt.Fprintf(&st.frameWriteLogBuf, m, v...)
- st.frameWriteLogMu.Unlock()
- }
- st.fr.logReads = true
- st.fr.logWrites = true
- }
- }
- return st
-}
-
-func (st *serverTester) closeConn() {
- st.scMu.Lock()
- defer st.scMu.Unlock()
- st.sc.conn.Close()
-}
-
-func (st *serverTester) addLogFilter(phrase string) {
- st.logFilter = append(st.logFilter, phrase)
-}
-
-func (st *serverTester) stream(id uint32) *stream {
- ch := make(chan *stream, 1)
- st.sc.testHookCh <- func(int) {
- ch <- st.sc.streams[id]
- }
- return <-ch
-}
-
-func (st *serverTester) streamState(id uint32) streamState {
- ch := make(chan streamState, 1)
- st.sc.testHookCh <- func(int) {
- state, _ := st.sc.state(id)
- ch <- state
- }
- return <-ch
-}
-
-// loopNum reports how many times this conn's select loop has gone around.
-func (st *serverTester) loopNum() int {
- lastc := make(chan int, 1)
- st.sc.testHookCh <- func(loopNum int) {
- lastc <- loopNum
- }
- return <-lastc
-}
-
-// awaitIdle heuristically awaits for the server conn's select loop to be idle.
-// The heuristic is that the server connection's serve loop must schedule
-// 50 times in a row without any channel sends or receives occurring.
-func (st *serverTester) awaitIdle() {
- remain := 50
- last := st.loopNum()
- for remain > 0 {
- n := st.loopNum()
- if n == last+1 {
- remain--
- } else {
- remain = 50
- }
- last = n
- }
-}
-
-func (st *serverTester) Close() {
- if st.t.Failed() {
- st.frameReadLogMu.Lock()
- if st.frameReadLogBuf.Len() > 0 {
- st.t.Logf("Framer read log:\n%s", st.frameReadLogBuf.String())
- }
- st.frameReadLogMu.Unlock()
-
- st.frameWriteLogMu.Lock()
- if st.frameWriteLogBuf.Len() > 0 {
- st.t.Logf("Framer write log:\n%s", st.frameWriteLogBuf.String())
- }
- st.frameWriteLogMu.Unlock()
-
- // If we failed already (and are likely in a Fatal,
- // unwindowing), force close the connection, so the
- // httptest.Server doesn't wait forever for the conn
- // to close.
- if st.cc != nil {
- st.cc.Close()
- }
- }
- st.ts.Close()
- if st.cc != nil {
- st.cc.Close()
- }
- log.SetOutput(os.Stderr)
-}
-
-// greet initiates the client's HTTP/2 connection into a state where
-// frames may be sent.
-func (st *serverTester) greet() {
- st.writePreface()
- st.writeInitialSettings()
- st.wantSettings()
- st.writeSettingsAck()
- st.wantSettingsAck()
-}
-
-func (st *serverTester) writePreface() {
- n, err := st.cc.Write(clientPreface)
- if err != nil {
- st.t.Fatalf("Error writing client preface: %v", err)
- }
- if n != len(clientPreface) {
- st.t.Fatalf("Writing client preface, wrote %d bytes; want %d", n, len(clientPreface))
- }
-}
-
-func (st *serverTester) writeInitialSettings() {
- if err := st.fr.WriteSettings(); err != nil {
- st.t.Fatalf("Error writing initial SETTINGS frame from client to server: %v", err)
- }
-}
-
-func (st *serverTester) writeSettingsAck() {
- if err := st.fr.WriteSettingsAck(); err != nil {
- st.t.Fatalf("Error writing ACK of server's SETTINGS: %v", err)
- }
-}
-
-func (st *serverTester) writeHeaders(p HeadersFrameParam) {
- if err := st.fr.WriteHeaders(p); err != nil {
- st.t.Fatalf("Error writing HEADERS: %v", err)
- }
-}
-
-func (st *serverTester) writePriority(id uint32, p PriorityParam) {
- if err := st.fr.WritePriority(id, p); err != nil {
- st.t.Fatalf("Error writing PRIORITY: %v", err)
- }
-}
-
-func (st *serverTester) encodeHeaderField(k, v string) {
- err := st.hpackEnc.WriteField(hpack.HeaderField{Name: k, Value: v})
- if err != nil {
- st.t.Fatalf("HPACK encoding error for %q/%q: %v", k, v, err)
- }
-}
-
-// encodeHeaderRaw is the magic-free version of encodeHeader.
-// It takes 0 or more (k, v) pairs and encodes them.
-func (st *serverTester) encodeHeaderRaw(headers ...string) []byte {
- if len(headers)%2 == 1 {
- panic("odd number of kv args")
- }
- st.headerBuf.Reset()
- for len(headers) > 0 {
- k, v := headers[0], headers[1]
- st.encodeHeaderField(k, v)
- headers = headers[2:]
- }
- return st.headerBuf.Bytes()
-}
-
-// encodeHeader encodes headers and returns their HPACK bytes. headers
-// must contain an even number of key/value pairs. There may be
-// multiple pairs for keys (e.g. "cookie"). The :method, :path, and
-// :scheme headers default to GET, / and https. The :authority header
-// defaults to st.ts.Listener.Addr().
-func (st *serverTester) encodeHeader(headers ...string) []byte {
- if len(headers)%2 == 1 {
- panic("odd number of kv args")
- }
-
- st.headerBuf.Reset()
- defaultAuthority := st.ts.Listener.Addr().String()
-
- if len(headers) == 0 {
- // Fast path, mostly for benchmarks, so test code doesn't pollute
- // profiles when we're looking to improve server allocations.
- st.encodeHeaderField(":method", "GET")
- st.encodeHeaderField(":scheme", "https")
- st.encodeHeaderField(":authority", defaultAuthority)
- st.encodeHeaderField(":path", "/")
- return st.headerBuf.Bytes()
- }
-
- if len(headers) == 2 && headers[0] == ":method" {
- // Another fast path for benchmarks.
- st.encodeHeaderField(":method", headers[1])
- st.encodeHeaderField(":scheme", "https")
- st.encodeHeaderField(":authority", defaultAuthority)
- st.encodeHeaderField(":path", "/")
- return st.headerBuf.Bytes()
- }
-
- pseudoCount := map[string]int{}
- keys := []string{":method", ":scheme", ":authority", ":path"}
- vals := map[string][]string{
- ":method": {"GET"},
- ":scheme": {"https"},
- ":authority": {defaultAuthority},
- ":path": {"/"},
- }
- for len(headers) > 0 {
- k, v := headers[0], headers[1]
- headers = headers[2:]
- if _, ok := vals[k]; !ok {
- keys = append(keys, k)
- }
- if strings.HasPrefix(k, ":") {
- pseudoCount[k]++
- if pseudoCount[k] == 1 {
- vals[k] = []string{v}
- } else {
- // Allows testing of invalid headers w/ dup pseudo fields.
- vals[k] = append(vals[k], v)
- }
- } else {
- vals[k] = append(vals[k], v)
- }
- }
- for _, k := range keys {
- for _, v := range vals[k] {
- st.encodeHeaderField(k, v)
- }
- }
- return st.headerBuf.Bytes()
-}
-
-// bodylessReq1 writes a HEADERS frames with StreamID 1 and EndStream and EndHeaders set.
-func (st *serverTester) bodylessReq1(headers ...string) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(headers...),
- EndStream: true,
- EndHeaders: true,
- })
-}
-
-func (st *serverTester) writeData(streamID uint32, endStream bool, data []byte) {
- if err := st.fr.WriteData(streamID, endStream, data); err != nil {
- st.t.Fatalf("Error writing DATA: %v", err)
- }
-}
-
-func (st *serverTester) writeDataPadded(streamID uint32, endStream bool, data, pad []byte) {
- if err := st.fr.WriteDataPadded(streamID, endStream, data, pad); err != nil {
- st.t.Fatalf("Error writing DATA: %v", err)
- }
-}
-
-func readFrameTimeout(fr *Framer, wait time.Duration) (Frame, error) {
- ch := make(chan interface{}, 1)
- go func() {
- fr, err := fr.ReadFrame()
- if err != nil {
- ch <- err
- } else {
- ch <- fr
- }
- }()
- t := time.NewTimer(wait)
- select {
- case v := <-ch:
- t.Stop()
- if fr, ok := v.(Frame); ok {
- return fr, nil
- }
- return nil, v.(error)
- case <-t.C:
- return nil, errors.New("timeout waiting for frame")
- }
-}
-
-func (st *serverTester) readFrame() (Frame, error) {
- return readFrameTimeout(st.fr, 2*time.Second)
-}
-
-func (st *serverTester) wantHeaders() *HeadersFrame {
- f, err := st.readFrame()
- if err != nil {
- st.t.Fatalf("Error while expecting a HEADERS frame: %v", err)
- }
- hf, ok := f.(*HeadersFrame)
- if !ok {
- st.t.Fatalf("got a %T; want *HeadersFrame", f)
- }
- return hf
-}
-
-func (st *serverTester) wantContinuation() *ContinuationFrame {
- f, err := st.readFrame()
- if err != nil {
- st.t.Fatalf("Error while expecting a CONTINUATION frame: %v", err)
- }
- cf, ok := f.(*ContinuationFrame)
- if !ok {
- st.t.Fatalf("got a %T; want *ContinuationFrame", f)
- }
- return cf
-}
-
-func (st *serverTester) wantData() *DataFrame {
- f, err := st.readFrame()
- if err != nil {
- st.t.Fatalf("Error while expecting a DATA frame: %v", err)
- }
- df, ok := f.(*DataFrame)
- if !ok {
- st.t.Fatalf("got a %T; want *DataFrame", f)
- }
- return df
-}
-
-func (st *serverTester) wantSettings() *SettingsFrame {
- f, err := st.readFrame()
- if err != nil {
- st.t.Fatalf("Error while expecting a SETTINGS frame: %v", err)
- }
- sf, ok := f.(*SettingsFrame)
- if !ok {
- st.t.Fatalf("got a %T; want *SettingsFrame", f)
- }
- return sf
-}
-
-func (st *serverTester) wantPing() *PingFrame {
- f, err := st.readFrame()
- if err != nil {
- st.t.Fatalf("Error while expecting a PING frame: %v", err)
- }
- pf, ok := f.(*PingFrame)
- if !ok {
- st.t.Fatalf("got a %T; want *PingFrame", f)
- }
- return pf
-}
-
-func (st *serverTester) wantGoAway() *GoAwayFrame {
- f, err := st.readFrame()
- if err != nil {
- st.t.Fatalf("Error while expecting a GOAWAY frame: %v", err)
- }
- gf, ok := f.(*GoAwayFrame)
- if !ok {
- st.t.Fatalf("got a %T; want *GoAwayFrame", f)
- }
- return gf
-}
-
-func (st *serverTester) wantRSTStream(streamID uint32, errCode ErrCode) {
- f, err := st.readFrame()
- if err != nil {
- st.t.Fatalf("Error while expecting an RSTStream frame: %v", err)
- }
- rs, ok := f.(*RSTStreamFrame)
- if !ok {
- st.t.Fatalf("got a %T; want *RSTStreamFrame", f)
- }
- if rs.FrameHeader.StreamID != streamID {
- st.t.Fatalf("RSTStream StreamID = %d; want %d", rs.FrameHeader.StreamID, streamID)
- }
- if rs.ErrCode != errCode {
- st.t.Fatalf("RSTStream ErrCode = %d (%s); want %d (%s)", rs.ErrCode, rs.ErrCode, errCode, errCode)
- }
-}
-
-func (st *serverTester) wantWindowUpdate(streamID, incr uint32) {
- f, err := st.readFrame()
- if err != nil {
- st.t.Fatalf("Error while expecting a WINDOW_UPDATE frame: %v", err)
- }
- wu, ok := f.(*WindowUpdateFrame)
- if !ok {
- st.t.Fatalf("got a %T; want *WindowUpdateFrame", f)
- }
- if wu.FrameHeader.StreamID != streamID {
- st.t.Fatalf("WindowUpdate StreamID = %d; want %d", wu.FrameHeader.StreamID, streamID)
- }
- if wu.Increment != incr {
- st.t.Fatalf("WindowUpdate increment = %d; want %d", wu.Increment, incr)
- }
-}
-
-func (st *serverTester) wantSettingsAck() {
- f, err := st.readFrame()
- if err != nil {
- st.t.Fatal(err)
- }
- sf, ok := f.(*SettingsFrame)
- if !ok {
- st.t.Fatalf("Wanting a settings ACK, received a %T", f)
- }
- if !sf.Header().Flags.Has(FlagSettingsAck) {
- st.t.Fatal("Settings Frame didn't have ACK set")
- }
-}
-
-func (st *serverTester) wantPushPromise() *PushPromiseFrame {
- f, err := st.readFrame()
- if err != nil {
- st.t.Fatal(err)
- }
- ppf, ok := f.(*PushPromiseFrame)
- if !ok {
- st.t.Fatalf("Wanted PushPromise, received %T", ppf)
- }
- return ppf
-}
-
-func TestServer(t *testing.T) {
- gotReq := make(chan bool, 1)
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Foo", "Bar")
- gotReq <- true
- })
- defer st.Close()
-
- covers("3.5", `
- The server connection preface consists of a potentially empty
- SETTINGS frame ([SETTINGS]) that MUST be the first frame the
- server sends in the HTTP/2 connection.
- `)
-
- st.writePreface()
- st.writeInitialSettings()
- st.wantSettings()
- st.writeSettingsAck()
- st.wantSettingsAck()
-
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(),
- EndStream: true, // no DATA frames
- EndHeaders: true,
- })
-
- select {
- case <-gotReq:
- case <-time.After(2 * time.Second):
- t.Error("timeout waiting for request")
- }
-}
-
-func TestServer_Request_Get(t *testing.T) {
- testServerRequest(t, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader("foo-bar", "some-value"),
- EndStream: true, // no DATA frames
- EndHeaders: true,
- })
- }, func(r *http.Request) {
- if r.Method != "GET" {
- t.Errorf("Method = %q; want GET", r.Method)
- }
- if r.URL.Path != "/" {
- t.Errorf("URL.Path = %q; want /", r.URL.Path)
- }
- if r.ContentLength != 0 {
- t.Errorf("ContentLength = %v; want 0", r.ContentLength)
- }
- if r.Close {
- t.Error("Close = true; want false")
- }
- if !strings.Contains(r.RemoteAddr, ":") {
- t.Errorf("RemoteAddr = %q; want something with a colon", r.RemoteAddr)
- }
- if r.Proto != "HTTP/2.0" || r.ProtoMajor != 2 || r.ProtoMinor != 0 {
- t.Errorf("Proto = %q Major=%v,Minor=%v; want HTTP/2.0", r.Proto, r.ProtoMajor, r.ProtoMinor)
- }
- wantHeader := http.Header{
- "Foo-Bar": []string{"some-value"},
- }
- if !reflect.DeepEqual(r.Header, wantHeader) {
- t.Errorf("Header = %#v; want %#v", r.Header, wantHeader)
- }
- if n, err := r.Body.Read([]byte(" ")); err != io.EOF || n != 0 {
- t.Errorf("Read = %d, %v; want 0, EOF", n, err)
- }
- })
-}
-
-func TestServer_Request_Get_PathSlashes(t *testing.T) {
- testServerRequest(t, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(":path", "/%2f/"),
- EndStream: true, // no DATA frames
- EndHeaders: true,
- })
- }, func(r *http.Request) {
- if r.RequestURI != "/%2f/" {
- t.Errorf("RequestURI = %q; want /%%2f/", r.RequestURI)
- }
- if r.URL.Path != "///" {
- t.Errorf("URL.Path = %q; want ///", r.URL.Path)
- }
- })
-}
-
-// TODO: add a test with EndStream=true on the HEADERS but setting a
-// Content-Length anyway. Should we just omit it and force it to
-// zero?
-
-func TestServer_Request_Post_NoContentLength_EndStream(t *testing.T) {
- testServerRequest(t, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(":method", "POST"),
- EndStream: true,
- EndHeaders: true,
- })
- }, func(r *http.Request) {
- if r.Method != "POST" {
- t.Errorf("Method = %q; want POST", r.Method)
- }
- if r.ContentLength != 0 {
- t.Errorf("ContentLength = %v; want 0", r.ContentLength)
- }
- if n, err := r.Body.Read([]byte(" ")); err != io.EOF || n != 0 {
- t.Errorf("Read = %d, %v; want 0, EOF", n, err)
- }
- })
-}
-
-func TestServer_Request_Post_Body_ImmediateEOF(t *testing.T) {
- testBodyContents(t, -1, "", func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(":method", "POST"),
- EndStream: false, // to say DATA frames are coming
- EndHeaders: true,
- })
- st.writeData(1, true, nil) // just kidding. empty body.
- })
-}
-
-func TestServer_Request_Post_Body_OneData(t *testing.T) {
- const content = "Some content"
- testBodyContents(t, -1, content, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(":method", "POST"),
- EndStream: false, // to say DATA frames are coming
- EndHeaders: true,
- })
- st.writeData(1, true, []byte(content))
- })
-}
-
-func TestServer_Request_Post_Body_TwoData(t *testing.T) {
- const content = "Some content"
- testBodyContents(t, -1, content, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(":method", "POST"),
- EndStream: false, // to say DATA frames are coming
- EndHeaders: true,
- })
- st.writeData(1, false, []byte(content[:5]))
- st.writeData(1, true, []byte(content[5:]))
- })
-}
-
-func TestServer_Request_Post_Body_ContentLength_Correct(t *testing.T) {
- const content = "Some content"
- testBodyContents(t, int64(len(content)), content, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(
- ":method", "POST",
- "content-length", strconv.Itoa(len(content)),
- ),
- EndStream: false, // to say DATA frames are coming
- EndHeaders: true,
- })
- st.writeData(1, true, []byte(content))
- })
-}
-
-func TestServer_Request_Post_Body_ContentLength_TooLarge(t *testing.T) {
- testBodyContentsFail(t, 3, "request declared a Content-Length of 3 but only wrote 2 bytes",
- func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(
- ":method", "POST",
- "content-length", "3",
- ),
- EndStream: false, // to say DATA frames are coming
- EndHeaders: true,
- })
- st.writeData(1, true, []byte("12"))
- })
-}
-
-func TestServer_Request_Post_Body_ContentLength_TooSmall(t *testing.T) {
- testBodyContentsFail(t, 4, "sender tried to send more than declared Content-Length of 4 bytes",
- func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(
- ":method", "POST",
- "content-length", "4",
- ),
- EndStream: false, // to say DATA frames are coming
- EndHeaders: true,
- })
- st.writeData(1, true, []byte("12345"))
- })
-}
-
-func testBodyContents(t *testing.T, wantContentLength int64, wantBody string, write func(st *serverTester)) {
- testServerRequest(t, write, func(r *http.Request) {
- if r.Method != "POST" {
- t.Errorf("Method = %q; want POST", r.Method)
- }
- if r.ContentLength != wantContentLength {
- t.Errorf("ContentLength = %v; want %d", r.ContentLength, wantContentLength)
- }
- all, err := ioutil.ReadAll(r.Body)
- if err != nil {
- t.Fatal(err)
- }
- if string(all) != wantBody {
- t.Errorf("Read = %q; want %q", all, wantBody)
- }
- if err := r.Body.Close(); err != nil {
- t.Fatalf("Close: %v", err)
- }
- })
-}
-
-func testBodyContentsFail(t *testing.T, wantContentLength int64, wantReadError string, write func(st *serverTester)) {
- testServerRequest(t, write, func(r *http.Request) {
- if r.Method != "POST" {
- t.Errorf("Method = %q; want POST", r.Method)
- }
- if r.ContentLength != wantContentLength {
- t.Errorf("ContentLength = %v; want %d", r.ContentLength, wantContentLength)
- }
- all, err := ioutil.ReadAll(r.Body)
- if err == nil {
- t.Fatalf("expected an error (%q) reading from the body. Successfully read %q instead.",
- wantReadError, all)
- }
- if !strings.Contains(err.Error(), wantReadError) {
- t.Fatalf("Body.Read = %v; want substring %q", err, wantReadError)
- }
- if err := r.Body.Close(); err != nil {
- t.Fatalf("Close: %v", err)
- }
- })
-}
-
-// Using a Host header, instead of :authority
-func TestServer_Request_Get_Host(t *testing.T) {
- const host = "example.com"
- testServerRequest(t, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(":authority", "", "host", host),
- EndStream: true,
- EndHeaders: true,
- })
- }, func(r *http.Request) {
- if r.Host != host {
- t.Errorf("Host = %q; want %q", r.Host, host)
- }
- })
-}
-
-// Using an :authority pseudo-header, instead of Host
-func TestServer_Request_Get_Authority(t *testing.T) {
- const host = "example.com"
- testServerRequest(t, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(":authority", host),
- EndStream: true,
- EndHeaders: true,
- })
- }, func(r *http.Request) {
- if r.Host != host {
- t.Errorf("Host = %q; want %q", r.Host, host)
- }
- })
-}
-
-func TestServer_Request_WithContinuation(t *testing.T) {
- wantHeader := http.Header{
- "Foo-One": []string{"value-one"},
- "Foo-Two": []string{"value-two"},
- "Foo-Three": []string{"value-three"},
- }
- testServerRequest(t, func(st *serverTester) {
- fullHeaders := st.encodeHeader(
- "foo-one", "value-one",
- "foo-two", "value-two",
- "foo-three", "value-three",
- )
- remain := fullHeaders
- chunks := 0
- for len(remain) > 0 {
- const maxChunkSize = 5
- chunk := remain
- if len(chunk) > maxChunkSize {
- chunk = chunk[:maxChunkSize]
- }
- remain = remain[len(chunk):]
-
- if chunks == 0 {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: chunk,
- EndStream: true, // no DATA frames
- EndHeaders: false, // we'll have continuation frames
- })
- } else {
- err := st.fr.WriteContinuation(1, len(remain) == 0, chunk)
- if err != nil {
- t.Fatal(err)
- }
- }
- chunks++
- }
- if chunks < 2 {
- t.Fatal("too few chunks")
- }
- }, func(r *http.Request) {
- if !reflect.DeepEqual(r.Header, wantHeader) {
- t.Errorf("Header = %#v; want %#v", r.Header, wantHeader)
- }
- })
-}
-
-// Concatenated cookie headers. ("8.1.2.5 Compressing the Cookie Header Field")
-func TestServer_Request_CookieConcat(t *testing.T) {
- const host = "example.com"
- testServerRequest(t, func(st *serverTester) {
- st.bodylessReq1(
- ":authority", host,
- "cookie", "a=b",
- "cookie", "c=d",
- "cookie", "e=f",
- )
- }, func(r *http.Request) {
- const want = "a=b; c=d; e=f"
- if got := r.Header.Get("Cookie"); got != want {
- t.Errorf("Cookie = %q; want %q", got, want)
- }
- })
-}
-
-func TestServer_Request_Reject_CapitalHeader(t *testing.T) {
- testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("UPPER", "v") })
-}
-
-func TestServer_Request_Reject_HeaderFieldNameColon(t *testing.T) {
- testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("has:colon", "v") })
-}
-
-func TestServer_Request_Reject_HeaderFieldNameNULL(t *testing.T) {
- testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("has\x00null", "v") })
-}
-
-func TestServer_Request_Reject_HeaderFieldNameEmpty(t *testing.T) {
- testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("", "v") })
-}
-
-func TestServer_Request_Reject_HeaderFieldValueNewline(t *testing.T) {
- testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("foo", "has\nnewline") })
-}
-
-func TestServer_Request_Reject_HeaderFieldValueCR(t *testing.T) {
- testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("foo", "has\rcarriage") })
-}
-
-func TestServer_Request_Reject_HeaderFieldValueDEL(t *testing.T) {
- testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("foo", "has\x7fdel") })
-}
-
-func TestServer_Request_Reject_Pseudo_Missing_method(t *testing.T) {
- testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":method", "") })
-}
-
-func TestServer_Request_Reject_Pseudo_ExactlyOne(t *testing.T) {
- // 8.1.2.3 Request Pseudo-Header Fields
- // "All HTTP/2 requests MUST include exactly one valid value" ...
- testRejectRequest(t, func(st *serverTester) {
- st.addLogFilter("duplicate pseudo-header")
- st.bodylessReq1(":method", "GET", ":method", "POST")
- })
-}
-
-func TestServer_Request_Reject_Pseudo_AfterRegular(t *testing.T) {
- // 8.1.2.3 Request Pseudo-Header Fields
- // "All pseudo-header fields MUST appear in the header block
- // before regular header fields. Any request or response that
- // contains a pseudo-header field that appears in a header
- // block after a regular header field MUST be treated as
- // malformed (Section 8.1.2.6)."
- testRejectRequest(t, func(st *serverTester) {
- st.addLogFilter("pseudo-header after regular header")
- var buf bytes.Buffer
- enc := hpack.NewEncoder(&buf)
- enc.WriteField(hpack.HeaderField{Name: ":method", Value: "GET"})
- enc.WriteField(hpack.HeaderField{Name: "regular", Value: "foobar"})
- enc.WriteField(hpack.HeaderField{Name: ":path", Value: "/"})
- enc.WriteField(hpack.HeaderField{Name: ":scheme", Value: "https"})
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: buf.Bytes(),
- EndStream: true,
- EndHeaders: true,
- })
- })
-}
-
-func TestServer_Request_Reject_Pseudo_Missing_path(t *testing.T) {
- testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":path", "") })
-}
-
-func TestServer_Request_Reject_Pseudo_Missing_scheme(t *testing.T) {
- testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":scheme", "") })
-}
-
-func TestServer_Request_Reject_Pseudo_scheme_invalid(t *testing.T) {
- testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":scheme", "bogus") })
-}
-
-func TestServer_Request_Reject_Pseudo_Unknown(t *testing.T) {
- testRejectRequest(t, func(st *serverTester) {
- st.addLogFilter(`invalid pseudo-header ":unknown_thing"`)
- st.bodylessReq1(":unknown_thing", "")
- })
-}
-
-func testRejectRequest(t *testing.T, send func(*serverTester)) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- t.Error("server request made it to handler; should've been rejected")
- })
- defer st.Close()
-
- st.greet()
- send(st)
- st.wantRSTStream(1, ErrCodeProtocol)
-}
-
-func testRejectRequestWithProtocolError(t *testing.T, send func(*serverTester)) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- t.Error("server request made it to handler; should've been rejected")
- }, optQuiet)
- defer st.Close()
-
- st.greet()
- send(st)
- gf := st.wantGoAway()
- if gf.ErrCode != ErrCodeProtocol {
- t.Errorf("err code = %v; want %v", gf.ErrCode, ErrCodeProtocol)
- }
-}
-
-// Section 5.1, on idle connections: "Receiving any frame other than
-// HEADERS or PRIORITY on a stream in this state MUST be treated as a
-// connection error (Section 5.4.1) of type PROTOCOL_ERROR."
-func TestRejectFrameOnIdle_WindowUpdate(t *testing.T) {
- testRejectRequestWithProtocolError(t, func(st *serverTester) {
- st.fr.WriteWindowUpdate(123, 456)
- })
-}
-func TestRejectFrameOnIdle_Data(t *testing.T) {
- testRejectRequestWithProtocolError(t, func(st *serverTester) {
- st.fr.WriteData(123, true, nil)
- })
-}
-func TestRejectFrameOnIdle_RSTStream(t *testing.T) {
- testRejectRequestWithProtocolError(t, func(st *serverTester) {
- st.fr.WriteRSTStream(123, ErrCodeCancel)
- })
-}
-
-func TestServer_Request_Connect(t *testing.T) {
- testServerRequest(t, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeaderRaw(
- ":method", "CONNECT",
- ":authority", "example.com:123",
- ),
- EndStream: true,
- EndHeaders: true,
- })
- }, func(r *http.Request) {
- if g, w := r.Method, "CONNECT"; g != w {
- t.Errorf("Method = %q; want %q", g, w)
- }
- if g, w := r.RequestURI, "example.com:123"; g != w {
- t.Errorf("RequestURI = %q; want %q", g, w)
- }
- if g, w := r.URL.Host, "example.com:123"; g != w {
- t.Errorf("URL.Host = %q; want %q", g, w)
- }
- })
-}
-
-func TestServer_Request_Connect_InvalidPath(t *testing.T) {
- testServerRejectsStream(t, ErrCodeProtocol, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeaderRaw(
- ":method", "CONNECT",
- ":authority", "example.com:123",
- ":path", "/bogus",
- ),
- EndStream: true,
- EndHeaders: true,
- })
- })
-}
-
-func TestServer_Request_Connect_InvalidScheme(t *testing.T) {
- testServerRejectsStream(t, ErrCodeProtocol, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeaderRaw(
- ":method", "CONNECT",
- ":authority", "example.com:123",
- ":scheme", "https",
- ),
- EndStream: true,
- EndHeaders: true,
- })
- })
-}
-
-func TestServer_Ping(t *testing.T) {
- st := newServerTester(t, nil)
- defer st.Close()
- st.greet()
-
- // Server should ignore this one, since it has ACK set.
- ackPingData := [8]byte{1, 2, 4, 8, 16, 32, 64, 128}
- if err := st.fr.WritePing(true, ackPingData); err != nil {
- t.Fatal(err)
- }
-
- // But the server should reply to this one, since ACK is false.
- pingData := [8]byte{1, 2, 3, 4, 5, 6, 7, 8}
- if err := st.fr.WritePing(false, pingData); err != nil {
- t.Fatal(err)
- }
-
- pf := st.wantPing()
- if !pf.Flags.Has(FlagPingAck) {
- t.Error("response ping doesn't have ACK set")
- }
- if pf.Data != pingData {
- t.Errorf("response ping has data %q; want %q", pf.Data, pingData)
- }
-}
-
-func TestServer_RejectsLargeFrames(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Skip("see golang.org/issue/13434")
- }
-
- st := newServerTester(t, nil)
- defer st.Close()
- st.greet()
-
- // Write too large of a frame (too large by one byte)
- // We ignore the return value because it's expected that the server
- // will only read the first 9 bytes (the headre) and then disconnect.
- st.fr.WriteRawFrame(0xff, 0, 0, make([]byte, defaultMaxReadFrameSize+1))
-
- gf := st.wantGoAway()
- if gf.ErrCode != ErrCodeFrameSize {
- t.Errorf("GOAWAY err = %v; want %v", gf.ErrCode, ErrCodeFrameSize)
- }
- if st.serverLogBuf.Len() != 0 {
- // Previously we spun here for a bit until the GOAWAY disconnect
- // timer fired, logging while we fired.
- t.Errorf("unexpected server output: %.500s\n", st.serverLogBuf.Bytes())
- }
-}
-
-func TestServer_Handler_Sends_WindowUpdate(t *testing.T) {
- puppet := newHandlerPuppet()
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- puppet.act(w, r)
- })
- defer st.Close()
- defer puppet.done()
-
- st.greet()
-
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(":method", "POST"),
- EndStream: false, // data coming
- EndHeaders: true,
- })
- st.writeData(1, false, []byte("abcdef"))
- puppet.do(readBodyHandler(t, "abc"))
- st.wantWindowUpdate(0, 3)
- st.wantWindowUpdate(1, 3)
-
- puppet.do(readBodyHandler(t, "def"))
- st.wantWindowUpdate(0, 3)
- st.wantWindowUpdate(1, 3)
-
- st.writeData(1, true, []byte("ghijkl")) // END_STREAM here
- puppet.do(readBodyHandler(t, "ghi"))
- puppet.do(readBodyHandler(t, "jkl"))
- st.wantWindowUpdate(0, 3)
- st.wantWindowUpdate(0, 3) // no more stream-level, since END_STREAM
-}
-
-// the version of the TestServer_Handler_Sends_WindowUpdate with padding.
-// See golang.org/issue/16556
-func TestServer_Handler_Sends_WindowUpdate_Padding(t *testing.T) {
- puppet := newHandlerPuppet()
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- puppet.act(w, r)
- })
- defer st.Close()
- defer puppet.done()
-
- st.greet()
-
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeader(":method", "POST"),
- EndStream: false,
- EndHeaders: true,
- })
- st.writeDataPadded(1, false, []byte("abcdef"), []byte{0, 0, 0, 0})
-
- // Expect to immediately get our 5 bytes of padding back for
- // both the connection and stream (4 bytes of padding + 1 byte of length)
- st.wantWindowUpdate(0, 5)
- st.wantWindowUpdate(1, 5)
-
- puppet.do(readBodyHandler(t, "abc"))
- st.wantWindowUpdate(0, 3)
- st.wantWindowUpdate(1, 3)
-
- puppet.do(readBodyHandler(t, "def"))
- st.wantWindowUpdate(0, 3)
- st.wantWindowUpdate(1, 3)
-}
-
-func TestServer_Send_GoAway_After_Bogus_WindowUpdate(t *testing.T) {
- st := newServerTester(t, nil)
- defer st.Close()
- st.greet()
- if err := st.fr.WriteWindowUpdate(0, 1<<31-1); err != nil {
- t.Fatal(err)
- }
- gf := st.wantGoAway()
- if gf.ErrCode != ErrCodeFlowControl {
- t.Errorf("GOAWAY err = %v; want %v", gf.ErrCode, ErrCodeFlowControl)
- }
- if gf.LastStreamID != 0 {
- t.Errorf("GOAWAY last stream ID = %v; want %v", gf.LastStreamID, 0)
- }
-}
-
-func TestServer_Send_RstStream_After_Bogus_WindowUpdate(t *testing.T) {
- inHandler := make(chan bool)
- blockHandler := make(chan bool)
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- inHandler <- true
- <-blockHandler
- })
- defer st.Close()
- defer close(blockHandler)
- st.greet()
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeader(":method", "POST"),
- EndStream: false, // keep it open
- EndHeaders: true,
- })
- <-inHandler
- // Send a bogus window update:
- if err := st.fr.WriteWindowUpdate(1, 1<<31-1); err != nil {
- t.Fatal(err)
- }
- st.wantRSTStream(1, ErrCodeFlowControl)
-}
-
-// testServerPostUnblock sends a hanging POST with unsent data to handler,
-// then runs fn once in the handler, and verifies that the error returned from
-// handler is acceptable. It fails if takes over 5 seconds for handler to exit.
-func testServerPostUnblock(t *testing.T,
- handler func(http.ResponseWriter, *http.Request) error,
- fn func(*serverTester),
- checkErr func(error),
- otherHeaders ...string) {
- inHandler := make(chan bool)
- errc := make(chan error, 1)
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- inHandler <- true
- errc <- handler(w, r)
- })
- defer st.Close()
- st.greet()
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeader(append([]string{":method", "POST"}, otherHeaders...)...),
- EndStream: false, // keep it open
- EndHeaders: true,
- })
- <-inHandler
- fn(st)
- select {
- case err := <-errc:
- if checkErr != nil {
- checkErr(err)
- }
- case <-time.After(5 * time.Second):
- t.Fatal("timeout waiting for Handler to return")
- }
-}
-
-func TestServer_RSTStream_Unblocks_Read(t *testing.T) {
- testServerPostUnblock(t,
- func(w http.ResponseWriter, r *http.Request) (err error) {
- _, err = r.Body.Read(make([]byte, 1))
- return
- },
- func(st *serverTester) {
- if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil {
- t.Fatal(err)
- }
- },
- func(err error) {
- want := StreamError{StreamID: 0x1, Code: 0x8}
- if !reflect.DeepEqual(err, want) {
- t.Errorf("Read error = %v; want %v", err, want)
- }
- },
- )
-}
-
-func TestServer_RSTStream_Unblocks_Header_Write(t *testing.T) {
- // Run this test a bunch, because it doesn't always
- // deadlock. But with a bunch, it did.
- n := 50
- if testing.Short() {
- n = 5
- }
- for i := 0; i < n; i++ {
- testServer_RSTStream_Unblocks_Header_Write(t)
- }
-}
-
-func testServer_RSTStream_Unblocks_Header_Write(t *testing.T) {
- inHandler := make(chan bool, 1)
- unblockHandler := make(chan bool, 1)
- headerWritten := make(chan bool, 1)
- wroteRST := make(chan bool, 1)
-
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- inHandler <- true
- <-wroteRST
- w.Header().Set("foo", "bar")
- w.WriteHeader(200)
- w.(http.Flusher).Flush()
- headerWritten <- true
- <-unblockHandler
- })
- defer st.Close()
-
- st.greet()
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeader(":method", "POST"),
- EndStream: false, // keep it open
- EndHeaders: true,
- })
- <-inHandler
- if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil {
- t.Fatal(err)
- }
- wroteRST <- true
- st.awaitIdle()
- select {
- case <-headerWritten:
- case <-time.After(2 * time.Second):
- t.Error("timeout waiting for header write")
- }
- unblockHandler <- true
-}
-
-func TestServer_DeadConn_Unblocks_Read(t *testing.T) {
- testServerPostUnblock(t,
- func(w http.ResponseWriter, r *http.Request) (err error) {
- _, err = r.Body.Read(make([]byte, 1))
- return
- },
- func(st *serverTester) { st.cc.Close() },
- func(err error) {
- if err == nil {
- t.Error("unexpected nil error from Request.Body.Read")
- }
- },
- )
-}
-
-var blockUntilClosed = func(w http.ResponseWriter, r *http.Request) error {
- <-w.(http.CloseNotifier).CloseNotify()
- return nil
-}
-
-func TestServer_CloseNotify_After_RSTStream(t *testing.T) {
- testServerPostUnblock(t, blockUntilClosed, func(st *serverTester) {
- if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil {
- t.Fatal(err)
- }
- }, nil)
-}
-
-func TestServer_CloseNotify_After_ConnClose(t *testing.T) {
- testServerPostUnblock(t, blockUntilClosed, func(st *serverTester) { st.cc.Close() }, nil)
-}
-
-// that CloseNotify unblocks after a stream error due to the client's
-// problem that's unrelated to them explicitly canceling it (which is
-// TestServer_CloseNotify_After_RSTStream above)
-func TestServer_CloseNotify_After_StreamError(t *testing.T) {
- testServerPostUnblock(t, blockUntilClosed, func(st *serverTester) {
- // data longer than declared Content-Length => stream error
- st.writeData(1, true, []byte("1234"))
- }, nil, "content-length", "3")
-}
-
-func TestServer_StateTransitions(t *testing.T) {
- var st *serverTester
- inHandler := make(chan bool)
- writeData := make(chan bool)
- leaveHandler := make(chan bool)
- st = newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- inHandler <- true
- if st.stream(1) == nil {
- t.Errorf("nil stream 1 in handler")
- }
- if got, want := st.streamState(1), stateOpen; got != want {
- t.Errorf("in handler, state is %v; want %v", got, want)
- }
- writeData <- true
- if n, err := r.Body.Read(make([]byte, 1)); n != 0 || err != io.EOF {
- t.Errorf("body read = %d, %v; want 0, EOF", n, err)
- }
- if got, want := st.streamState(1), stateHalfClosedRemote; got != want {
- t.Errorf("in handler, state is %v; want %v", got, want)
- }
-
- <-leaveHandler
- })
- st.greet()
- if st.stream(1) != nil {
- t.Fatal("stream 1 should be empty")
- }
- if got := st.streamState(1); got != stateIdle {
- t.Fatalf("stream 1 should be idle; got %v", got)
- }
-
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeader(":method", "POST"),
- EndStream: false, // keep it open
- EndHeaders: true,
- })
- <-inHandler
- <-writeData
- st.writeData(1, true, nil)
-
- leaveHandler <- true
- hf := st.wantHeaders()
- if !hf.StreamEnded() {
- t.Fatal("expected END_STREAM flag")
- }
-
- if got, want := st.streamState(1), stateClosed; got != want {
- t.Errorf("at end, state is %v; want %v", got, want)
- }
- if st.stream(1) != nil {
- t.Fatal("at end, stream 1 should be gone")
- }
-}
-
-// test HEADERS w/o EndHeaders + another HEADERS (should get rejected)
-func TestServer_Rejects_HeadersNoEnd_Then_Headers(t *testing.T) {
- testServerRejectsConn(t, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeader(),
- EndStream: true,
- EndHeaders: false,
- })
- st.writeHeaders(HeadersFrameParam{ // Not a continuation.
- StreamID: 3, // different stream.
- BlockFragment: st.encodeHeader(),
- EndStream: true,
- EndHeaders: true,
- })
- })
-}
-
-// test HEADERS w/o EndHeaders + PING (should get rejected)
-func TestServer_Rejects_HeadersNoEnd_Then_Ping(t *testing.T) {
- testServerRejectsConn(t, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeader(),
- EndStream: true,
- EndHeaders: false,
- })
- if err := st.fr.WritePing(false, [8]byte{}); err != nil {
- t.Fatal(err)
- }
- })
-}
-
-// test HEADERS w/ EndHeaders + a continuation HEADERS (should get rejected)
-func TestServer_Rejects_HeadersEnd_Then_Continuation(t *testing.T) {
- testServerRejectsConn(t, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeader(),
- EndStream: true,
- EndHeaders: true,
- })
- st.wantHeaders()
- if err := st.fr.WriteContinuation(1, true, encodeHeaderNoImplicit(t, "foo", "bar")); err != nil {
- t.Fatal(err)
- }
- })
-}
-
-// test HEADERS w/o EndHeaders + a continuation HEADERS on wrong stream ID
-func TestServer_Rejects_HeadersNoEnd_Then_ContinuationWrongStream(t *testing.T) {
- testServerRejectsConn(t, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeader(),
- EndStream: true,
- EndHeaders: false,
- })
- if err := st.fr.WriteContinuation(3, true, encodeHeaderNoImplicit(t, "foo", "bar")); err != nil {
- t.Fatal(err)
- }
- })
-}
-
-// No HEADERS on stream 0.
-func TestServer_Rejects_Headers0(t *testing.T) {
- testServerRejectsConn(t, func(st *serverTester) {
- st.fr.AllowIllegalWrites = true
- st.writeHeaders(HeadersFrameParam{
- StreamID: 0,
- BlockFragment: st.encodeHeader(),
- EndStream: true,
- EndHeaders: true,
- })
- })
-}
-
-// No CONTINUATION on stream 0.
-func TestServer_Rejects_Continuation0(t *testing.T) {
- testServerRejectsConn(t, func(st *serverTester) {
- st.fr.AllowIllegalWrites = true
- if err := st.fr.WriteContinuation(0, true, st.encodeHeader()); err != nil {
- t.Fatal(err)
- }
- })
-}
-
-// No PRIORITY on stream 0.
-func TestServer_Rejects_Priority0(t *testing.T) {
- testServerRejectsConn(t, func(st *serverTester) {
- st.fr.AllowIllegalWrites = true
- st.writePriority(0, PriorityParam{StreamDep: 1})
- })
-}
-
-// No HEADERS frame with a self-dependence.
-func TestServer_Rejects_HeadersSelfDependence(t *testing.T) {
- testServerRejectsStream(t, ErrCodeProtocol, func(st *serverTester) {
- st.fr.AllowIllegalWrites = true
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeader(),
- EndStream: true,
- EndHeaders: true,
- Priority: PriorityParam{StreamDep: 1},
- })
- })
-}
-
-// No PRIORTY frame with a self-dependence.
-func TestServer_Rejects_PrioritySelfDependence(t *testing.T) {
- testServerRejectsStream(t, ErrCodeProtocol, func(st *serverTester) {
- st.fr.AllowIllegalWrites = true
- st.writePriority(1, PriorityParam{StreamDep: 1})
- })
-}
-
-func TestServer_Rejects_PushPromise(t *testing.T) {
- testServerRejectsConn(t, func(st *serverTester) {
- pp := PushPromiseParam{
- StreamID: 1,
- PromiseID: 3,
- }
- if err := st.fr.WritePushPromise(pp); err != nil {
- t.Fatal(err)
- }
- })
-}
-
-// testServerRejectsConn tests that the server hangs up with a GOAWAY
-// frame and a server close after the client does something
-// deserving a CONNECTION_ERROR.
-func testServerRejectsConn(t *testing.T, writeReq func(*serverTester)) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {})
- st.addLogFilter("connection error: PROTOCOL_ERROR")
- defer st.Close()
- st.greet()
- writeReq(st)
-
- st.wantGoAway()
- errc := make(chan error, 1)
- go func() {
- fr, err := st.fr.ReadFrame()
- if err == nil {
- err = fmt.Errorf("got frame of type %T", fr)
- }
- errc <- err
- }()
- select {
- case err := <-errc:
- if err != io.EOF {
- t.Errorf("ReadFrame = %v; want io.EOF", err)
- }
- case <-time.After(2 * time.Second):
- t.Error("timeout waiting for disconnect")
- }
-}
-
-// testServerRejectsStream tests that the server sends a RST_STREAM with the provided
-// error code after a client sends a bogus request.
-func testServerRejectsStream(t *testing.T, code ErrCode, writeReq func(*serverTester)) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {})
- defer st.Close()
- st.greet()
- writeReq(st)
- st.wantRSTStream(1, code)
-}
-
-// testServerRequest sets up an idle HTTP/2 connection and lets you
-// write a single request with writeReq, and then verify that the
-// *http.Request is built correctly in checkReq.
-func testServerRequest(t *testing.T, writeReq func(*serverTester), checkReq func(*http.Request)) {
- gotReq := make(chan bool, 1)
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- if r.Body == nil {
- t.Fatal("nil Body")
- }
- checkReq(r)
- gotReq <- true
- })
- defer st.Close()
-
- st.greet()
- writeReq(st)
-
- select {
- case <-gotReq:
- case <-time.After(2 * time.Second):
- t.Error("timeout waiting for request")
- }
-}
-
-func getSlash(st *serverTester) { st.bodylessReq1() }
-
-func TestServer_Response_NoData(t *testing.T) {
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- // Nothing.
- return nil
- }, func(st *serverTester) {
- getSlash(st)
- hf := st.wantHeaders()
- if !hf.StreamEnded() {
- t.Fatal("want END_STREAM flag")
- }
- if !hf.HeadersEnded() {
- t.Fatal("want END_HEADERS flag")
- }
- })
-}
-
-func TestServer_Response_NoData_Header_FooBar(t *testing.T) {
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- w.Header().Set("Foo-Bar", "some-value")
- return nil
- }, func(st *serverTester) {
- getSlash(st)
- hf := st.wantHeaders()
- if !hf.StreamEnded() {
- t.Fatal("want END_STREAM flag")
- }
- if !hf.HeadersEnded() {
- t.Fatal("want END_HEADERS flag")
- }
- goth := st.decodeHeader(hf.HeaderBlockFragment())
- wanth := [][2]string{
- {":status", "200"},
- {"foo-bar", "some-value"},
- {"content-type", "text/plain; charset=utf-8"},
- {"content-length", "0"},
- }
- if !reflect.DeepEqual(goth, wanth) {
- t.Errorf("Got headers %v; want %v", goth, wanth)
- }
- })
-}
-
-func TestServer_Response_Data_Sniff_DoesntOverride(t *testing.T) {
- const msg = "<html>this is HTML."
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- w.Header().Set("Content-Type", "foo/bar")
- io.WriteString(w, msg)
- return nil
- }, func(st *serverTester) {
- getSlash(st)
- hf := st.wantHeaders()
- if hf.StreamEnded() {
- t.Fatal("don't want END_STREAM, expecting data")
- }
- if !hf.HeadersEnded() {
- t.Fatal("want END_HEADERS flag")
- }
- goth := st.decodeHeader(hf.HeaderBlockFragment())
- wanth := [][2]string{
- {":status", "200"},
- {"content-type", "foo/bar"},
- {"content-length", strconv.Itoa(len(msg))},
- }
- if !reflect.DeepEqual(goth, wanth) {
- t.Errorf("Got headers %v; want %v", goth, wanth)
- }
- df := st.wantData()
- if !df.StreamEnded() {
- t.Error("expected DATA to have END_STREAM flag")
- }
- if got := string(df.Data()); got != msg {
- t.Errorf("got DATA %q; want %q", got, msg)
- }
- })
-}
-
-func TestServer_Response_TransferEncoding_chunked(t *testing.T) {
- const msg = "hi"
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- w.Header().Set("Transfer-Encoding", "chunked") // should be stripped
- io.WriteString(w, msg)
- return nil
- }, func(st *serverTester) {
- getSlash(st)
- hf := st.wantHeaders()
- goth := st.decodeHeader(hf.HeaderBlockFragment())
- wanth := [][2]string{
- {":status", "200"},
- {"content-type", "text/plain; charset=utf-8"},
- {"content-length", strconv.Itoa(len(msg))},
- }
- if !reflect.DeepEqual(goth, wanth) {
- t.Errorf("Got headers %v; want %v", goth, wanth)
- }
- })
-}
-
-// Header accessed only after the initial write.
-func TestServer_Response_Data_IgnoreHeaderAfterWrite_After(t *testing.T) {
- const msg = "<html>this is HTML."
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- io.WriteString(w, msg)
- w.Header().Set("foo", "should be ignored")
- return nil
- }, func(st *serverTester) {
- getSlash(st)
- hf := st.wantHeaders()
- if hf.StreamEnded() {
- t.Fatal("unexpected END_STREAM")
- }
- if !hf.HeadersEnded() {
- t.Fatal("want END_HEADERS flag")
- }
- goth := st.decodeHeader(hf.HeaderBlockFragment())
- wanth := [][2]string{
- {":status", "200"},
- {"content-type", "text/html; charset=utf-8"},
- {"content-length", strconv.Itoa(len(msg))},
- }
- if !reflect.DeepEqual(goth, wanth) {
- t.Errorf("Got headers %v; want %v", goth, wanth)
- }
- })
-}
-
-// Header accessed before the initial write and later mutated.
-func TestServer_Response_Data_IgnoreHeaderAfterWrite_Overwrite(t *testing.T) {
- const msg = "<html>this is HTML."
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- w.Header().Set("foo", "proper value")
- io.WriteString(w, msg)
- w.Header().Set("foo", "should be ignored")
- return nil
- }, func(st *serverTester) {
- getSlash(st)
- hf := st.wantHeaders()
- if hf.StreamEnded() {
- t.Fatal("unexpected END_STREAM")
- }
- if !hf.HeadersEnded() {
- t.Fatal("want END_HEADERS flag")
- }
- goth := st.decodeHeader(hf.HeaderBlockFragment())
- wanth := [][2]string{
- {":status", "200"},
- {"foo", "proper value"},
- {"content-type", "text/html; charset=utf-8"},
- {"content-length", strconv.Itoa(len(msg))},
- }
- if !reflect.DeepEqual(goth, wanth) {
- t.Errorf("Got headers %v; want %v", goth, wanth)
- }
- })
-}
-
-func TestServer_Response_Data_SniffLenType(t *testing.T) {
- const msg = "<html>this is HTML."
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- io.WriteString(w, msg)
- return nil
- }, func(st *serverTester) {
- getSlash(st)
- hf := st.wantHeaders()
- if hf.StreamEnded() {
- t.Fatal("don't want END_STREAM, expecting data")
- }
- if !hf.HeadersEnded() {
- t.Fatal("want END_HEADERS flag")
- }
- goth := st.decodeHeader(hf.HeaderBlockFragment())
- wanth := [][2]string{
- {":status", "200"},
- {"content-type", "text/html; charset=utf-8"},
- {"content-length", strconv.Itoa(len(msg))},
- }
- if !reflect.DeepEqual(goth, wanth) {
- t.Errorf("Got headers %v; want %v", goth, wanth)
- }
- df := st.wantData()
- if !df.StreamEnded() {
- t.Error("expected DATA to have END_STREAM flag")
- }
- if got := string(df.Data()); got != msg {
- t.Errorf("got DATA %q; want %q", got, msg)
- }
- })
-}
-
-func TestServer_Response_Header_Flush_MidWrite(t *testing.T) {
- const msg = "<html>this is HTML"
- const msg2 = ", and this is the next chunk"
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- io.WriteString(w, msg)
- w.(http.Flusher).Flush()
- io.WriteString(w, msg2)
- return nil
- }, func(st *serverTester) {
- getSlash(st)
- hf := st.wantHeaders()
- if hf.StreamEnded() {
- t.Fatal("unexpected END_STREAM flag")
- }
- if !hf.HeadersEnded() {
- t.Fatal("want END_HEADERS flag")
- }
- goth := st.decodeHeader(hf.HeaderBlockFragment())
- wanth := [][2]string{
- {":status", "200"},
- {"content-type", "text/html; charset=utf-8"}, // sniffed
- // and no content-length
- }
- if !reflect.DeepEqual(goth, wanth) {
- t.Errorf("Got headers %v; want %v", goth, wanth)
- }
- {
- df := st.wantData()
- if df.StreamEnded() {
- t.Error("unexpected END_STREAM flag")
- }
- if got := string(df.Data()); got != msg {
- t.Errorf("got DATA %q; want %q", got, msg)
- }
- }
- {
- df := st.wantData()
- if !df.StreamEnded() {
- t.Error("wanted END_STREAM flag on last data chunk")
- }
- if got := string(df.Data()); got != msg2 {
- t.Errorf("got DATA %q; want %q", got, msg2)
- }
- }
- })
-}
-
-func TestServer_Response_LargeWrite(t *testing.T) {
- const size = 1 << 20
- const maxFrameSize = 16 << 10
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- n, err := w.Write(bytes.Repeat([]byte("a"), size))
- if err != nil {
- return fmt.Errorf("Write error: %v", err)
- }
- if n != size {
- return fmt.Errorf("wrong size %d from Write", n)
- }
- return nil
- }, func(st *serverTester) {
- if err := st.fr.WriteSettings(
- Setting{SettingInitialWindowSize, 0},
- Setting{SettingMaxFrameSize, maxFrameSize},
- ); err != nil {
- t.Fatal(err)
- }
- st.wantSettingsAck()
-
- getSlash(st) // make the single request
-
- // Give the handler quota to write:
- if err := st.fr.WriteWindowUpdate(1, size); err != nil {
- t.Fatal(err)
- }
- // Give the handler quota to write to connection-level
- // window as well
- if err := st.fr.WriteWindowUpdate(0, size); err != nil {
- t.Fatal(err)
- }
- hf := st.wantHeaders()
- if hf.StreamEnded() {
- t.Fatal("unexpected END_STREAM flag")
- }
- if !hf.HeadersEnded() {
- t.Fatal("want END_HEADERS flag")
- }
- goth := st.decodeHeader(hf.HeaderBlockFragment())
- wanth := [][2]string{
- {":status", "200"},
- {"content-type", "text/plain; charset=utf-8"}, // sniffed
- // and no content-length
- }
- if !reflect.DeepEqual(goth, wanth) {
- t.Errorf("Got headers %v; want %v", goth, wanth)
- }
- var bytes, frames int
- for {
- df := st.wantData()
- bytes += len(df.Data())
- frames++
- for _, b := range df.Data() {
- if b != 'a' {
- t.Fatal("non-'a' byte seen in DATA")
- }
- }
- if df.StreamEnded() {
- break
- }
- }
- if bytes != size {
- t.Errorf("Got %d bytes; want %d", bytes, size)
- }
- if want := int(size / maxFrameSize); frames < want || frames > want*2 {
- t.Errorf("Got %d frames; want %d", frames, size)
- }
- })
-}
-
-// Test that the handler can't write more than the client allows
-func TestServer_Response_LargeWrite_FlowControlled(t *testing.T) {
- // Make these reads. Before each read, the client adds exactly enough
- // flow-control to satisfy the read. Numbers chosen arbitrarily.
- reads := []int{123, 1, 13, 127}
- size := 0
- for _, n := range reads {
- size += n
- }
-
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- w.(http.Flusher).Flush()
- n, err := w.Write(bytes.Repeat([]byte("a"), size))
- if err != nil {
- return fmt.Errorf("Write error: %v", err)
- }
- if n != size {
- return fmt.Errorf("wrong size %d from Write", n)
- }
- return nil
- }, func(st *serverTester) {
- // Set the window size to something explicit for this test.
- // It's also how much initial data we expect.
- if err := st.fr.WriteSettings(Setting{SettingInitialWindowSize, uint32(reads[0])}); err != nil {
- t.Fatal(err)
- }
- st.wantSettingsAck()
-
- getSlash(st) // make the single request
-
- hf := st.wantHeaders()
- if hf.StreamEnded() {
- t.Fatal("unexpected END_STREAM flag")
- }
- if !hf.HeadersEnded() {
- t.Fatal("want END_HEADERS flag")
- }
-
- df := st.wantData()
- if got := len(df.Data()); got != reads[0] {
- t.Fatalf("Initial window size = %d but got DATA with %d bytes", reads[0], got)
- }
-
- for _, quota := range reads[1:] {
- if err := st.fr.WriteWindowUpdate(1, uint32(quota)); err != nil {
- t.Fatal(err)
- }
- df := st.wantData()
- if int(quota) != len(df.Data()) {
- t.Fatalf("read %d bytes after giving %d quota", len(df.Data()), quota)
- }
- }
- })
-}
-
-// Test that the handler blocked in a Write is unblocked if the server sends a RST_STREAM.
-func TestServer_Response_RST_Unblocks_LargeWrite(t *testing.T) {
- const size = 1 << 20
- const maxFrameSize = 16 << 10
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- w.(http.Flusher).Flush()
- errc := make(chan error, 1)
- go func() {
- _, err := w.Write(bytes.Repeat([]byte("a"), size))
- errc <- err
- }()
- select {
- case err := <-errc:
- if err == nil {
- return errors.New("unexpected nil error from Write in handler")
- }
- return nil
- case <-time.After(2 * time.Second):
- return errors.New("timeout waiting for Write in handler")
- }
- }, func(st *serverTester) {
- if err := st.fr.WriteSettings(
- Setting{SettingInitialWindowSize, 0},
- Setting{SettingMaxFrameSize, maxFrameSize},
- ); err != nil {
- t.Fatal(err)
- }
- st.wantSettingsAck()
-
- getSlash(st) // make the single request
-
- hf := st.wantHeaders()
- if hf.StreamEnded() {
- t.Fatal("unexpected END_STREAM flag")
- }
- if !hf.HeadersEnded() {
- t.Fatal("want END_HEADERS flag")
- }
-
- if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil {
- t.Fatal(err)
- }
- })
-}
-
-func TestServer_Response_Empty_Data_Not_FlowControlled(t *testing.T) {
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- w.(http.Flusher).Flush()
- // Nothing; send empty DATA
- return nil
- }, func(st *serverTester) {
- // Handler gets no data quota:
- if err := st.fr.WriteSettings(Setting{SettingInitialWindowSize, 0}); err != nil {
- t.Fatal(err)
- }
- st.wantSettingsAck()
-
- getSlash(st) // make the single request
-
- hf := st.wantHeaders()
- if hf.StreamEnded() {
- t.Fatal("unexpected END_STREAM flag")
- }
- if !hf.HeadersEnded() {
- t.Fatal("want END_HEADERS flag")
- }
-
- df := st.wantData()
- if got := len(df.Data()); got != 0 {
- t.Fatalf("unexpected %d DATA bytes; want 0", got)
- }
- if !df.StreamEnded() {
- t.Fatal("DATA didn't have END_STREAM")
- }
- })
-}
-
-func TestServer_Response_Automatic100Continue(t *testing.T) {
- const msg = "foo"
- const reply = "bar"
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- if v := r.Header.Get("Expect"); v != "" {
- t.Errorf("Expect header = %q; want empty", v)
- }
- buf := make([]byte, len(msg))
- // This read should trigger the 100-continue being sent.
- if n, err := io.ReadFull(r.Body, buf); err != nil || n != len(msg) || string(buf) != msg {
- return fmt.Errorf("ReadFull = %q, %v; want %q, nil", buf[:n], err, msg)
- }
- _, err := io.WriteString(w, reply)
- return err
- }, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(":method", "POST", "expect", "100-continue"),
- EndStream: false,
- EndHeaders: true,
- })
- hf := st.wantHeaders()
- if hf.StreamEnded() {
- t.Fatal("unexpected END_STREAM flag")
- }
- if !hf.HeadersEnded() {
- t.Fatal("want END_HEADERS flag")
- }
- goth := st.decodeHeader(hf.HeaderBlockFragment())
- wanth := [][2]string{
- {":status", "100"},
- }
- if !reflect.DeepEqual(goth, wanth) {
- t.Fatalf("Got headers %v; want %v", goth, wanth)
- }
-
- // Okay, they sent status 100, so we can send our
- // gigantic and/or sensitive "foo" payload now.
- st.writeData(1, true, []byte(msg))
-
- st.wantWindowUpdate(0, uint32(len(msg)))
-
- hf = st.wantHeaders()
- if hf.StreamEnded() {
- t.Fatal("expected data to follow")
- }
- if !hf.HeadersEnded() {
- t.Fatal("want END_HEADERS flag")
- }
- goth = st.decodeHeader(hf.HeaderBlockFragment())
- wanth = [][2]string{
- {":status", "200"},
- {"content-type", "text/plain; charset=utf-8"},
- {"content-length", strconv.Itoa(len(reply))},
- }
- if !reflect.DeepEqual(goth, wanth) {
- t.Errorf("Got headers %v; want %v", goth, wanth)
- }
-
- df := st.wantData()
- if string(df.Data()) != reply {
- t.Errorf("Client read %q; want %q", df.Data(), reply)
- }
- if !df.StreamEnded() {
- t.Errorf("expect data stream end")
- }
- })
-}
-
-func TestServer_HandlerWriteErrorOnDisconnect(t *testing.T) {
- errc := make(chan error, 1)
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- p := []byte("some data.\n")
- for {
- _, err := w.Write(p)
- if err != nil {
- errc <- err
- return nil
- }
- }
- }, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeader(),
- EndStream: false,
- EndHeaders: true,
- })
- hf := st.wantHeaders()
- if hf.StreamEnded() {
- t.Fatal("unexpected END_STREAM flag")
- }
- if !hf.HeadersEnded() {
- t.Fatal("want END_HEADERS flag")
- }
- // Close the connection and wait for the handler to (hopefully) notice.
- st.cc.Close()
- select {
- case <-errc:
- case <-time.After(5 * time.Second):
- t.Error("timeout")
- }
- })
-}
-
-func TestServer_Rejects_Too_Many_Streams(t *testing.T) {
- const testPath = "/some/path"
-
- inHandler := make(chan uint32)
- leaveHandler := make(chan bool)
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- id := w.(*responseWriter).rws.stream.id
- inHandler <- id
- if id == 1+(defaultMaxStreams+1)*2 && r.URL.Path != testPath {
- t.Errorf("decoded final path as %q; want %q", r.URL.Path, testPath)
- }
- <-leaveHandler
- })
- defer st.Close()
- st.greet()
- nextStreamID := uint32(1)
- streamID := func() uint32 {
- defer func() { nextStreamID += 2 }()
- return nextStreamID
- }
- sendReq := func(id uint32, headers ...string) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: id,
- BlockFragment: st.encodeHeader(headers...),
- EndStream: true,
- EndHeaders: true,
- })
- }
- for i := 0; i < defaultMaxStreams; i++ {
- sendReq(streamID())
- <-inHandler
- }
- defer func() {
- for i := 0; i < defaultMaxStreams; i++ {
- leaveHandler <- true
- }
- }()
-
- // And this one should cross the limit:
- // (It's also sent as a CONTINUATION, to verify we still track the decoder context,
- // even if we're rejecting it)
- rejectID := streamID()
- headerBlock := st.encodeHeader(":path", testPath)
- frag1, frag2 := headerBlock[:3], headerBlock[3:]
- st.writeHeaders(HeadersFrameParam{
- StreamID: rejectID,
- BlockFragment: frag1,
- EndStream: true,
- EndHeaders: false, // CONTINUATION coming
- })
- if err := st.fr.WriteContinuation(rejectID, true, frag2); err != nil {
- t.Fatal(err)
- }
- st.wantRSTStream(rejectID, ErrCodeProtocol)
-
- // But let a handler finish:
- leaveHandler <- true
- st.wantHeaders()
-
- // And now another stream should be able to start:
- goodID := streamID()
- sendReq(goodID, ":path", testPath)
- select {
- case got := <-inHandler:
- if got != goodID {
- t.Errorf("Got stream %d; want %d", got, goodID)
- }
- case <-time.After(3 * time.Second):
- t.Error("timeout waiting for handler")
- }
-}
-
-// So many response headers that the server needs to use CONTINUATION frames:
-func TestServer_Response_ManyHeaders_With_Continuation(t *testing.T) {
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- h := w.Header()
- for i := 0; i < 5000; i++ {
- h.Set(fmt.Sprintf("x-header-%d", i), fmt.Sprintf("x-value-%d", i))
- }
- return nil
- }, func(st *serverTester) {
- getSlash(st)
- hf := st.wantHeaders()
- if hf.HeadersEnded() {
- t.Fatal("got unwanted END_HEADERS flag")
- }
- n := 0
- for {
- n++
- cf := st.wantContinuation()
- if cf.HeadersEnded() {
- break
- }
- }
- if n < 5 {
- t.Errorf("Only got %d CONTINUATION frames; expected 5+ (currently 6)", n)
- }
- })
-}
-
-// This previously crashed (reported by Mathieu Lonjaret as observed
-// while using Camlistore) because we got a DATA frame from the client
-// after the handler exited and our logic at the time was wrong,
-// keeping a stream in the map in stateClosed, which tickled an
-// invariant check later when we tried to remove that stream (via
-// defer sc.closeAllStreamsOnConnClose) when the serverConn serve loop
-// ended.
-func TestServer_NoCrash_HandlerClose_Then_ClientClose(t *testing.T) {
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- // nothing
- return nil
- }, func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeader(),
- EndStream: false, // DATA is coming
- EndHeaders: true,
- })
- hf := st.wantHeaders()
- if !hf.HeadersEnded() || !hf.StreamEnded() {
- t.Fatalf("want END_HEADERS+END_STREAM, got %v", hf)
- }
-
- // Sent when the a Handler closes while a client has
- // indicated it's still sending DATA:
- st.wantRSTStream(1, ErrCodeCancel)
-
- // Now the handler has ended, so it's ended its
- // stream, but the client hasn't closed its side
- // (stateClosedLocal). So send more data and verify
- // it doesn't crash with an internal invariant panic, like
- // it did before.
- st.writeData(1, true, []byte("foo"))
-
- // Get our flow control bytes back, since the handler didn't get them.
- st.wantWindowUpdate(0, uint32(len("foo")))
-
- // Sent after a peer sends data anyway (admittedly the
- // previous RST_STREAM might've still been in-flight),
- // but they'll get the more friendly 'cancel' code
- // first.
- st.wantRSTStream(1, ErrCodeStreamClosed)
-
- // Set up a bunch of machinery to record the panic we saw
- // previously.
- var (
- panMu sync.Mutex
- panicVal interface{}
- )
-
- testHookOnPanicMu.Lock()
- testHookOnPanic = func(sc *serverConn, pv interface{}) bool {
- panMu.Lock()
- panicVal = pv
- panMu.Unlock()
- return true
- }
- testHookOnPanicMu.Unlock()
-
- // Now force the serve loop to end, via closing the connection.
- st.cc.Close()
- select {
- case <-st.sc.doneServing:
- // Loop has exited.
- panMu.Lock()
- got := panicVal
- panMu.Unlock()
- if got != nil {
- t.Errorf("Got panic: %v", got)
- }
- case <-time.After(5 * time.Second):
- t.Error("timeout")
- }
- })
-}
-
-func TestServer_Rejects_TLS10(t *testing.T) { testRejectTLS(t, tls.VersionTLS10) }
-func TestServer_Rejects_TLS11(t *testing.T) { testRejectTLS(t, tls.VersionTLS11) }
-
-func testRejectTLS(t *testing.T, max uint16) {
- st := newServerTester(t, nil, func(c *tls.Config) {
- c.MaxVersion = max
- })
- defer st.Close()
- gf := st.wantGoAway()
- if got, want := gf.ErrCode, ErrCodeInadequateSecurity; got != want {
- t.Errorf("Got error code %v; want %v", got, want)
- }
-}
-
-func TestServer_Rejects_TLSBadCipher(t *testing.T) {
- st := newServerTester(t, nil, func(c *tls.Config) {
- // Only list bad ones:
- c.CipherSuites = []uint16{
- tls.TLS_RSA_WITH_RC4_128_SHA,
- tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
- tls.TLS_RSA_WITH_AES_128_CBC_SHA,
- tls.TLS_RSA_WITH_AES_256_CBC_SHA,
- tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
- tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
- tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
- tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
- tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
- tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
- }
- })
- defer st.Close()
- gf := st.wantGoAway()
- if got, want := gf.ErrCode, ErrCodeInadequateSecurity; got != want {
- t.Errorf("Got error code %v; want %v", got, want)
- }
-}
-
-func TestServer_Advertises_Common_Cipher(t *testing.T) {
- const requiredSuite = tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- st := newServerTester(t, nil, func(c *tls.Config) {
- // Have the client only support the one required by the spec.
- c.CipherSuites = []uint16{requiredSuite}
- }, func(ts *httptest.Server) {
- var srv *http.Server = ts.Config
- // Have the server configured with no specific cipher suites.
- // This tests that Go's defaults include the required one.
- srv.TLSConfig = nil
- })
- defer st.Close()
- st.greet()
-}
-
-func (st *serverTester) onHeaderField(f hpack.HeaderField) {
- if f.Name == "date" {
- return
- }
- st.decodedHeaders = append(st.decodedHeaders, [2]string{f.Name, f.Value})
-}
-
-func (st *serverTester) decodeHeader(headerBlock []byte) (pairs [][2]string) {
- st.decodedHeaders = nil
- if _, err := st.hpackDec.Write(headerBlock); err != nil {
- st.t.Fatalf("hpack decoding error: %v", err)
- }
- if err := st.hpackDec.Close(); err != nil {
- st.t.Fatalf("hpack decoding error: %v", err)
- }
- return st.decodedHeaders
-}
-
-// testServerResponse sets up an idle HTTP/2 connection. The client function should
-// write a single request that must be handled by the handler. This waits up to 5s
-// for client to return, then up to an additional 2s for the handler to return.
-func testServerResponse(t testing.TB,
- handler func(http.ResponseWriter, *http.Request) error,
- client func(*serverTester),
-) {
- errc := make(chan error, 1)
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- if r.Body == nil {
- t.Fatal("nil Body")
- }
- errc <- handler(w, r)
- })
- defer st.Close()
-
- donec := make(chan bool)
- go func() {
- defer close(donec)
- st.greet()
- client(st)
- }()
-
- select {
- case <-donec:
- case <-time.After(5 * time.Second):
- t.Fatal("timeout in client")
- }
-
- select {
- case err := <-errc:
- if err != nil {
- t.Fatalf("Error in handler: %v", err)
- }
- case <-time.After(2 * time.Second):
- t.Fatal("timeout in handler")
- }
-}
-
-// readBodyHandler returns an http Handler func that reads len(want)
-// bytes from r.Body and fails t if the contents read were not
-// the value of want.
-func readBodyHandler(t *testing.T, want string) func(w http.ResponseWriter, r *http.Request) {
- return func(w http.ResponseWriter, r *http.Request) {
- buf := make([]byte, len(want))
- _, err := io.ReadFull(r.Body, buf)
- if err != nil {
- t.Error(err)
- return
- }
- if string(buf) != want {
- t.Errorf("read %q; want %q", buf, want)
- }
- }
-}
-
-// TestServerWithCurl currently fails, hence the LenientCipherSuites test. See:
-// https://github.com/tatsuhiro-t/nghttp2/issues/140 &
-// http://sourceforge.net/p/curl/bugs/1472/
-func TestServerWithCurl(t *testing.T) { testServerWithCurl(t, false) }
-func TestServerWithCurl_LenientCipherSuites(t *testing.T) { testServerWithCurl(t, true) }
-
-func testServerWithCurl(t *testing.T, permitProhibitedCipherSuites bool) {
- if runtime.GOOS != "linux" {
- t.Skip("skipping Docker test when not on Linux; requires --net which won't work with boot2docker anyway")
- }
- if testing.Short() {
- t.Skip("skipping curl test in short mode")
- }
- requireCurl(t)
- var gotConn int32
- testHookOnConn = func() { atomic.StoreInt32(&gotConn, 1) }
-
- const msg = "Hello from curl!\n"
- ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Foo", "Bar")
- w.Header().Set("Client-Proto", r.Proto)
- io.WriteString(w, msg)
- }))
- ConfigureServer(ts.Config, &Server{
- PermitProhibitedCipherSuites: permitProhibitedCipherSuites,
- })
- ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config
- ts.StartTLS()
- defer ts.Close()
-
- t.Logf("Running test server for curl to hit at: %s", ts.URL)
- container := curl(t, "--silent", "--http2", "--insecure", "-v", ts.URL)
- defer kill(container)
- resc := make(chan interface{}, 1)
- go func() {
- res, err := dockerLogs(container)
- if err != nil {
- resc <- err
- } else {
- resc <- res
- }
- }()
- select {
- case res := <-resc:
- if err, ok := res.(error); ok {
- t.Fatal(err)
- }
- body := string(res.([]byte))
- // Search for both "key: value" and "key:value", since curl changed their format
- // Our Dockerfile contains the latest version (no space), but just in case people
- // didn't rebuild, check both.
- if !strings.Contains(body, "foo: Bar") && !strings.Contains(body, "foo:Bar") {
- t.Errorf("didn't see foo: Bar header")
- t.Logf("Got: %s", body)
- }
- if !strings.Contains(body, "client-proto: HTTP/2") && !strings.Contains(body, "client-proto:HTTP/2") {
- t.Errorf("didn't see client-proto: HTTP/2 header")
- t.Logf("Got: %s", res)
- }
- if !strings.Contains(string(res.([]byte)), msg) {
- t.Errorf("didn't see %q content", msg)
- t.Logf("Got: %s", res)
- }
- case <-time.After(3 * time.Second):
- t.Errorf("timeout waiting for curl")
- }
-
- if atomic.LoadInt32(&gotConn) == 0 {
- t.Error("never saw an http2 connection")
- }
-}
-
-var doh2load = flag.Bool("h2load", false, "Run h2load test")
-
-func TestServerWithH2Load(t *testing.T) {
- if !*doh2load {
- t.Skip("Skipping without --h2load flag.")
- }
- if runtime.GOOS != "linux" {
- t.Skip("skipping Docker test when not on Linux; requires --net which won't work with boot2docker anyway")
- }
- requireH2load(t)
-
- msg := strings.Repeat("Hello, h2load!\n", 5000)
- ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- io.WriteString(w, msg)
- w.(http.Flusher).Flush()
- io.WriteString(w, msg)
- }))
- ts.StartTLS()
- defer ts.Close()
-
- cmd := exec.Command("docker", "run", "--net=host", "--entrypoint=/usr/local/bin/h2load", "gohttp2/curl",
- "-n100000", "-c100", "-m100", ts.URL)
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- if err := cmd.Run(); err != nil {
- t.Fatal(err)
- }
-}
-
-// Issue 12843
-func TestServerDoS_MaxHeaderListSize(t *testing.T) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {})
- defer st.Close()
-
- // shake hands
- st.writePreface()
- st.writeInitialSettings()
- frameSize := defaultMaxReadFrameSize
- var advHeaderListSize *uint32
- st.wantSettings().ForeachSetting(func(s Setting) error {
- switch s.ID {
- case SettingMaxFrameSize:
- if s.Val < minMaxFrameSize {
- frameSize = minMaxFrameSize
- } else if s.Val > maxFrameSize {
- frameSize = maxFrameSize
- } else {
- frameSize = int(s.Val)
- }
- case SettingMaxHeaderListSize:
- advHeaderListSize = &s.Val
- }
- return nil
- })
- st.writeSettingsAck()
- st.wantSettingsAck()
-
- if advHeaderListSize == nil {
- t.Errorf("server didn't advertise a max header list size")
- } else if *advHeaderListSize == 0 {
- t.Errorf("server advertised a max header list size of 0")
- }
-
- st.encodeHeaderField(":method", "GET")
- st.encodeHeaderField(":path", "/")
- st.encodeHeaderField(":scheme", "https")
- cookie := strings.Repeat("*", 4058)
- st.encodeHeaderField("cookie", cookie)
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.headerBuf.Bytes(),
- EndStream: true,
- EndHeaders: false,
- })
-
- // Capture the short encoding of a duplicate ~4K cookie, now
- // that we've already sent it once.
- st.headerBuf.Reset()
- st.encodeHeaderField("cookie", cookie)
-
- // Now send 1MB of it.
- const size = 1 << 20
- b := bytes.Repeat(st.headerBuf.Bytes(), size/st.headerBuf.Len())
- for len(b) > 0 {
- chunk := b
- if len(chunk) > frameSize {
- chunk = chunk[:frameSize]
- }
- b = b[len(chunk):]
- st.fr.WriteContinuation(1, len(b) == 0, chunk)
- }
-
- h := st.wantHeaders()
- if !h.HeadersEnded() {
- t.Fatalf("Got HEADERS without END_HEADERS set: %v", h)
- }
- headers := st.decodeHeader(h.HeaderBlockFragment())
- want := [][2]string{
- {":status", "431"},
- {"content-type", "text/html; charset=utf-8"},
- {"content-length", "63"},
- }
- if !reflect.DeepEqual(headers, want) {
- t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want)
- }
-}
-
-func TestCompressionErrorOnWrite(t *testing.T) {
- const maxStrLen = 8 << 10
- var serverConfig *http.Server
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- // No response body.
- }, func(ts *httptest.Server) {
- serverConfig = ts.Config
- serverConfig.MaxHeaderBytes = maxStrLen
- })
- st.addLogFilter("connection error: COMPRESSION_ERROR")
- defer st.Close()
- st.greet()
-
- maxAllowed := st.sc.framer.maxHeaderStringLen()
-
- // Crank this up, now that we have a conn connected with the
- // hpack.Decoder's max string length set has been initialized
- // from the earlier low ~8K value. We want this higher so don't
- // hit the max header list size. We only want to test hitting
- // the max string size.
- serverConfig.MaxHeaderBytes = 1 << 20
-
- // First a request with a header that's exactly the max allowed size
- // for the hpack compression. It's still too long for the header list
- // size, so we'll get the 431 error, but that keeps the compression
- // context still valid.
- hbf := st.encodeHeader("foo", strings.Repeat("a", maxAllowed))
-
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: hbf,
- EndStream: true,
- EndHeaders: true,
- })
- h := st.wantHeaders()
- if !h.HeadersEnded() {
- t.Fatalf("Got HEADERS without END_HEADERS set: %v", h)
- }
- headers := st.decodeHeader(h.HeaderBlockFragment())
- want := [][2]string{
- {":status", "431"},
- {"content-type", "text/html; charset=utf-8"},
- {"content-length", "63"},
- }
- if !reflect.DeepEqual(headers, want) {
- t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want)
- }
- df := st.wantData()
- if !strings.Contains(string(df.Data()), "HTTP Error 431") {
- t.Errorf("Unexpected data body: %q", df.Data())
- }
- if !df.StreamEnded() {
- t.Fatalf("expect data stream end")
- }
-
- // And now send one that's just one byte too big.
- hbf = st.encodeHeader("bar", strings.Repeat("b", maxAllowed+1))
- st.writeHeaders(HeadersFrameParam{
- StreamID: 3,
- BlockFragment: hbf,
- EndStream: true,
- EndHeaders: true,
- })
- ga := st.wantGoAway()
- if ga.ErrCode != ErrCodeCompression {
- t.Errorf("GOAWAY err = %v; want ErrCodeCompression", ga.ErrCode)
- }
-}
-
-func TestCompressionErrorOnClose(t *testing.T) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- // No response body.
- })
- st.addLogFilter("connection error: COMPRESSION_ERROR")
- defer st.Close()
- st.greet()
-
- hbf := st.encodeHeader("foo", "bar")
- hbf = hbf[:len(hbf)-1] // truncate one byte from the end, so hpack.Decoder.Close fails.
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: hbf,
- EndStream: true,
- EndHeaders: true,
- })
- ga := st.wantGoAway()
- if ga.ErrCode != ErrCodeCompression {
- t.Errorf("GOAWAY err = %v; want ErrCodeCompression", ga.ErrCode)
- }
-}
-
-// test that a server handler can read trailers from a client
-func TestServerReadsTrailers(t *testing.T) {
- const testBody = "some test body"
- writeReq := func(st *serverTester) {
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader("trailer", "Foo, Bar", "trailer", "Baz"),
- EndStream: false,
- EndHeaders: true,
- })
- st.writeData(1, false, []byte(testBody))
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeaderRaw(
- "foo", "foov",
- "bar", "barv",
- "baz", "bazv",
- "surprise", "wasn't declared; shouldn't show up",
- ),
- EndStream: true,
- EndHeaders: true,
- })
- }
- checkReq := func(r *http.Request) {
- wantTrailer := http.Header{
- "Foo": nil,
- "Bar": nil,
- "Baz": nil,
- }
- if !reflect.DeepEqual(r.Trailer, wantTrailer) {
- t.Errorf("initial Trailer = %v; want %v", r.Trailer, wantTrailer)
- }
- slurp, err := ioutil.ReadAll(r.Body)
- if string(slurp) != testBody {
- t.Errorf("read body %q; want %q", slurp, testBody)
- }
- if err != nil {
- t.Fatalf("Body slurp: %v", err)
- }
- wantTrailerAfter := http.Header{
- "Foo": {"foov"},
- "Bar": {"barv"},
- "Baz": {"bazv"},
- }
- if !reflect.DeepEqual(r.Trailer, wantTrailerAfter) {
- t.Errorf("final Trailer = %v; want %v", r.Trailer, wantTrailerAfter)
- }
- }
- testServerRequest(t, writeReq, checkReq)
-}
-
-// test that a server handler can send trailers
-func TestServerWritesTrailers_WithFlush(t *testing.T) { testServerWritesTrailers(t, true) }
-func TestServerWritesTrailers_WithoutFlush(t *testing.T) { testServerWritesTrailers(t, false) }
-
-func testServerWritesTrailers(t *testing.T, withFlush bool) {
- // See https://httpwg.github.io/specs/rfc7540.html#rfc.section.8.1.3
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- w.Header().Set("Trailer", "Server-Trailer-A, Server-Trailer-B")
- w.Header().Add("Trailer", "Server-Trailer-C")
- w.Header().Add("Trailer", "Transfer-Encoding, Content-Length, Trailer") // filtered
-
- // Regular headers:
- w.Header().Set("Foo", "Bar")
- w.Header().Set("Content-Length", "5") // len("Hello")
-
- io.WriteString(w, "Hello")
- if withFlush {
- w.(http.Flusher).Flush()
- }
- w.Header().Set("Server-Trailer-A", "valuea")
- w.Header().Set("Server-Trailer-C", "valuec") // skipping B
- // After a flush, random keys like Server-Surprise shouldn't show up:
- w.Header().Set("Server-Surpise", "surprise! this isn't predeclared!")
- // But we do permit promoting keys to trailers after a
- // flush if they start with the magic
- // otherwise-invalid "Trailer:" prefix:
- w.Header().Set("Trailer:Post-Header-Trailer", "hi1")
- w.Header().Set("Trailer:post-header-trailer2", "hi2")
- w.Header().Set("Trailer:Range", "invalid")
- w.Header().Set("Trailer:Foo\x01Bogus", "invalid")
- w.Header().Set("Transfer-Encoding", "should not be included; Forbidden by RFC 2616 14.40")
- w.Header().Set("Content-Length", "should not be included; Forbidden by RFC 2616 14.40")
- w.Header().Set("Trailer", "should not be included; Forbidden by RFC 2616 14.40")
- return nil
- }, func(st *serverTester) {
- getSlash(st)
- hf := st.wantHeaders()
- if hf.StreamEnded() {
- t.Fatal("response HEADERS had END_STREAM")
- }
- if !hf.HeadersEnded() {
- t.Fatal("response HEADERS didn't have END_HEADERS")
- }
- goth := st.decodeHeader(hf.HeaderBlockFragment())
- wanth := [][2]string{
- {":status", "200"},
- {"foo", "Bar"},
- {"trailer", "Server-Trailer-A, Server-Trailer-B"},
- {"trailer", "Server-Trailer-C"},
- {"trailer", "Transfer-Encoding, Content-Length, Trailer"},
- {"content-type", "text/plain; charset=utf-8"},
- {"content-length", "5"},
- }
- if !reflect.DeepEqual(goth, wanth) {
- t.Errorf("Header mismatch.\n got: %v\nwant: %v", goth, wanth)
- }
- df := st.wantData()
- if string(df.Data()) != "Hello" {
- t.Fatalf("Client read %q; want Hello", df.Data())
- }
- if df.StreamEnded() {
- t.Fatalf("data frame had STREAM_ENDED")
- }
- tf := st.wantHeaders() // for the trailers
- if !tf.StreamEnded() {
- t.Fatalf("trailers HEADERS lacked END_STREAM")
- }
- if !tf.HeadersEnded() {
- t.Fatalf("trailers HEADERS lacked END_HEADERS")
- }
- wanth = [][2]string{
- {"post-header-trailer", "hi1"},
- {"post-header-trailer2", "hi2"},
- {"server-trailer-a", "valuea"},
- {"server-trailer-c", "valuec"},
- }
- goth = st.decodeHeader(tf.HeaderBlockFragment())
- if !reflect.DeepEqual(goth, wanth) {
- t.Errorf("Header mismatch.\n got: %v\nwant: %v", goth, wanth)
- }
- })
-}
-
-// validate transmitted header field names & values
-// golang.org/issue/14048
-func TestServerDoesntWriteInvalidHeaders(t *testing.T) {
- testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
- w.Header().Add("OK1", "x")
- w.Header().Add("Bad:Colon", "x") // colon (non-token byte) in key
- w.Header().Add("Bad1\x00", "x") // null in key
- w.Header().Add("Bad2", "x\x00y") // null in value
- return nil
- }, func(st *serverTester) {
- getSlash(st)
- hf := st.wantHeaders()
- if !hf.StreamEnded() {
- t.Error("response HEADERS lacked END_STREAM")
- }
- if !hf.HeadersEnded() {
- t.Fatal("response HEADERS didn't have END_HEADERS")
- }
- goth := st.decodeHeader(hf.HeaderBlockFragment())
- wanth := [][2]string{
- {":status", "200"},
- {"ok1", "x"},
- {"content-type", "text/plain; charset=utf-8"},
- {"content-length", "0"},
- }
- if !reflect.DeepEqual(goth, wanth) {
- t.Errorf("Header mismatch.\n got: %v\nwant: %v", goth, wanth)
- }
- })
-}
-
-func BenchmarkServerGets(b *testing.B) {
- defer disableGoroutineTracking()()
- b.ReportAllocs()
-
- const msg = "Hello, world"
- st := newServerTester(b, func(w http.ResponseWriter, r *http.Request) {
- io.WriteString(w, msg)
- })
- defer st.Close()
- st.greet()
-
- // Give the server quota to reply. (plus it has the the 64KB)
- if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil {
- b.Fatal(err)
- }
-
- for i := 0; i < b.N; i++ {
- id := 1 + uint32(i)*2
- st.writeHeaders(HeadersFrameParam{
- StreamID: id,
- BlockFragment: st.encodeHeader(),
- EndStream: true,
- EndHeaders: true,
- })
- st.wantHeaders()
- df := st.wantData()
- if !df.StreamEnded() {
- b.Fatalf("DATA didn't have END_STREAM; got %v", df)
- }
- }
-}
-
-func BenchmarkServerPosts(b *testing.B) {
- defer disableGoroutineTracking()()
- b.ReportAllocs()
-
- const msg = "Hello, world"
- st := newServerTester(b, func(w http.ResponseWriter, r *http.Request) {
- // Consume the (empty) body from th peer before replying, otherwise
- // the server will sometimes (depending on scheduling) send the peer a
- // a RST_STREAM with the CANCEL error code.
- if n, err := io.Copy(ioutil.Discard, r.Body); n != 0 || err != nil {
- b.Errorf("Copy error; got %v, %v; want 0, nil", n, err)
- }
- io.WriteString(w, msg)
- })
- defer st.Close()
- st.greet()
-
- // Give the server quota to reply. (plus it has the the 64KB)
- if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil {
- b.Fatal(err)
- }
-
- for i := 0; i < b.N; i++ {
- id := 1 + uint32(i)*2
- st.writeHeaders(HeadersFrameParam{
- StreamID: id,
- BlockFragment: st.encodeHeader(":method", "POST"),
- EndStream: false,
- EndHeaders: true,
- })
- st.writeData(id, true, nil)
- st.wantHeaders()
- df := st.wantData()
- if !df.StreamEnded() {
- b.Fatalf("DATA didn't have END_STREAM; got %v", df)
- }
- }
-}
-
-// go-fuzz bug, originally reported at https://github.com/bradfitz/http2/issues/53
-// Verify we don't hang.
-func TestIssue53(t *testing.T) {
- const data = "PRI * HTTP/2.0\r\n\r\nSM" +
- "\r\n\r\n\x00\x00\x00\x01\ainfinfin\ad"
- s := &http.Server{
- ErrorLog: log.New(io.MultiWriter(stderrv(), twriter{t: t}), "", log.LstdFlags),
- Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
- w.Write([]byte("hello"))
- }),
- }
- s2 := &Server{
- MaxReadFrameSize: 1 << 16,
- PermitProhibitedCipherSuites: true,
- }
- c := &issue53Conn{[]byte(data), false, false}
- s2.ServeConn(c, &ServeConnOpts{BaseConfig: s})
- if !c.closed {
- t.Fatal("connection is not closed")
- }
-}
-
-type issue53Conn struct {
- data []byte
- closed bool
- written bool
-}
-
-func (c *issue53Conn) Read(b []byte) (n int, err error) {
- if len(c.data) == 0 {
- return 0, io.EOF
- }
- n = copy(b, c.data)
- c.data = c.data[n:]
- return
-}
-
-func (c *issue53Conn) Write(b []byte) (n int, err error) {
- c.written = true
- return len(b), nil
-}
-
-func (c *issue53Conn) Close() error {
- c.closed = true
- return nil
-}
-
-func (c *issue53Conn) LocalAddr() net.Addr {
- return &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 49706}
-}
-func (c *issue53Conn) RemoteAddr() net.Addr {
- return &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 49706}
-}
-func (c *issue53Conn) SetDeadline(t time.Time) error { return nil }
-func (c *issue53Conn) SetReadDeadline(t time.Time) error { return nil }
-func (c *issue53Conn) SetWriteDeadline(t time.Time) error { return nil }
-
-// golang.org/issue/12895
-func TestConfigureServer(t *testing.T) {
- tests := []struct {
- name string
- tlsConfig *tls.Config
- wantErr string
- }{
- {
- name: "empty server",
- },
- {
- name: "just the required cipher suite",
- tlsConfig: &tls.Config{
- CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- },
- },
- {
- name: "missing required cipher suite",
- tlsConfig: &tls.Config{
- CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
- },
- wantErr: "is missing HTTP/2-required TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
- },
- {
- name: "required after bad",
- tlsConfig: &tls.Config{
- CipherSuites: []uint16{tls.TLS_RSA_WITH_RC4_128_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- },
- wantErr: "contains an HTTP/2-approved cipher suite (0xc02f), but it comes after",
- },
- {
- name: "bad after required",
- tlsConfig: &tls.Config{
- CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_RSA_WITH_RC4_128_SHA},
- },
- },
- }
- for _, tt := range tests {
- srv := &http.Server{TLSConfig: tt.tlsConfig}
- err := ConfigureServer(srv, nil)
- if (err != nil) != (tt.wantErr != "") {
- if tt.wantErr != "" {
- t.Errorf("%s: success, but want error", tt.name)
- } else {
- t.Errorf("%s: unexpected error: %v", tt.name, err)
- }
- }
- if err != nil && tt.wantErr != "" && !strings.Contains(err.Error(), tt.wantErr) {
- t.Errorf("%s: err = %v; want substring %q", tt.name, err, tt.wantErr)
- }
- if err == nil && !srv.TLSConfig.PreferServerCipherSuites {
- t.Errorf("%s: PreferServerCipherSuite is false; want true", tt.name)
- }
- }
-}
-
-func TestServerRejectHeadWithBody(t *testing.T) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- // No response body.
- })
- defer st.Close()
- st.greet()
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(":method", "HEAD"),
- EndStream: false, // what we're testing, a bogus HEAD request with body
- EndHeaders: true,
- })
- st.wantRSTStream(1, ErrCodeProtocol)
-}
-
-func TestServerNoAutoContentLengthOnHead(t *testing.T) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- // No response body. (or smaller than one frame)
- })
- defer st.Close()
- st.greet()
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1, // clients send odd numbers
- BlockFragment: st.encodeHeader(":method", "HEAD"),
- EndStream: true,
- EndHeaders: true,
- })
- h := st.wantHeaders()
- headers := st.decodeHeader(h.HeaderBlockFragment())
- want := [][2]string{
- {":status", "200"},
- {"content-type", "text/plain; charset=utf-8"},
- }
- if !reflect.DeepEqual(headers, want) {
- t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want)
- }
-}
-
-// golang.org/issue/13495
-func TestServerNoDuplicateContentType(t *testing.T) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- w.Header()["Content-Type"] = []string{""}
- fmt.Fprintf(w, "<html><head></head><body>hi</body></html>")
- })
- defer st.Close()
- st.greet()
- st.writeHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: st.encodeHeader(),
- EndStream: true,
- EndHeaders: true,
- })
- h := st.wantHeaders()
- headers := st.decodeHeader(h.HeaderBlockFragment())
- want := [][2]string{
- {":status", "200"},
- {"content-type", ""},
- {"content-length", "41"},
- }
- if !reflect.DeepEqual(headers, want) {
- t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want)
- }
-}
-
-func disableGoroutineTracking() (restore func()) {
- old := DebugGoroutines
- DebugGoroutines = false
- return func() { DebugGoroutines = old }
-}
-
-func BenchmarkServer_GetRequest(b *testing.B) {
- defer disableGoroutineTracking()()
- b.ReportAllocs()
- const msg = "Hello, world."
- st := newServerTester(b, func(w http.ResponseWriter, r *http.Request) {
- n, err := io.Copy(ioutil.Discard, r.Body)
- if err != nil || n > 0 {
- b.Errorf("Read %d bytes, error %v; want 0 bytes.", n, err)
- }
- io.WriteString(w, msg)
- })
- defer st.Close()
-
- st.greet()
- // Give the server quota to reply. (plus it has the the 64KB)
- if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil {
- b.Fatal(err)
- }
- hbf := st.encodeHeader(":method", "GET")
- for i := 0; i < b.N; i++ {
- streamID := uint32(1 + 2*i)
- st.writeHeaders(HeadersFrameParam{
- StreamID: streamID,
- BlockFragment: hbf,
- EndStream: true,
- EndHeaders: true,
- })
- st.wantHeaders()
- st.wantData()
- }
-}
-
-func BenchmarkServer_PostRequest(b *testing.B) {
- defer disableGoroutineTracking()()
- b.ReportAllocs()
- const msg = "Hello, world."
- st := newServerTester(b, func(w http.ResponseWriter, r *http.Request) {
- n, err := io.Copy(ioutil.Discard, r.Body)
- if err != nil || n > 0 {
- b.Errorf("Read %d bytes, error %v; want 0 bytes.", n, err)
- }
- io.WriteString(w, msg)
- })
- defer st.Close()
- st.greet()
- // Give the server quota to reply. (plus it has the the 64KB)
- if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil {
- b.Fatal(err)
- }
- hbf := st.encodeHeader(":method", "POST")
- for i := 0; i < b.N; i++ {
- streamID := uint32(1 + 2*i)
- st.writeHeaders(HeadersFrameParam{
- StreamID: streamID,
- BlockFragment: hbf,
- EndStream: false,
- EndHeaders: true,
- })
- st.writeData(streamID, true, nil)
- st.wantHeaders()
- st.wantData()
- }
-}
-
-type connStateConn struct {
- net.Conn
- cs tls.ConnectionState
-}
-
-func (c connStateConn) ConnectionState() tls.ConnectionState { return c.cs }
-
-// golang.org/issue/12737 -- handle any net.Conn, not just
-// *tls.Conn.
-func TestServerHandleCustomConn(t *testing.T) {
- var s Server
- c1, c2 := net.Pipe()
- clientDone := make(chan struct{})
- handlerDone := make(chan struct{})
- var req *http.Request
- go func() {
- defer close(clientDone)
- defer c2.Close()
- fr := NewFramer(c2, c2)
- io.WriteString(c2, ClientPreface)
- fr.WriteSettings()
- fr.WriteSettingsAck()
- f, err := fr.ReadFrame()
- if err != nil {
- t.Error(err)
- return
- }
- if sf, ok := f.(*SettingsFrame); !ok || sf.IsAck() {
- t.Errorf("Got %v; want non-ACK SettingsFrame", summarizeFrame(f))
- return
- }
- f, err = fr.ReadFrame()
- if err != nil {
- t.Error(err)
- return
- }
- if sf, ok := f.(*SettingsFrame); !ok || !sf.IsAck() {
- t.Errorf("Got %v; want ACK SettingsFrame", summarizeFrame(f))
- return
- }
- var henc hpackEncoder
- fr.WriteHeaders(HeadersFrameParam{
- StreamID: 1,
- BlockFragment: henc.encodeHeaderRaw(t, ":method", "GET", ":path", "/", ":scheme", "https", ":authority", "foo.com"),
- EndStream: true,
- EndHeaders: true,
- })
- go io.Copy(ioutil.Discard, c2)
- <-handlerDone
- }()
- const testString = "my custom ConnectionState"
- fakeConnState := tls.ConnectionState{
- ServerName: testString,
- Version: tls.VersionTLS12,
- }
- go s.ServeConn(connStateConn{c1, fakeConnState}, &ServeConnOpts{
- BaseConfig: &http.Server{
- Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- defer close(handlerDone)
- req = r
- }),
- }})
- select {
- case <-clientDone:
- case <-time.After(5 * time.Second):
- t.Fatal("timeout waiting for handler")
- }
- if req.TLS == nil {
- t.Fatalf("Request.TLS is nil. Got: %#v", req)
- }
- if req.TLS.ServerName != testString {
- t.Fatalf("Request.TLS = %+v; want ServerName of %q", req.TLS, testString)
- }
-}
-
-// golang.org/issue/14214
-func TestServer_Rejects_ConnHeaders(t *testing.T) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- t.Error("should not get to Handler")
- })
- defer st.Close()
- st.greet()
- st.bodylessReq1("connection", "foo")
- hf := st.wantHeaders()
- goth := st.decodeHeader(hf.HeaderBlockFragment())
- wanth := [][2]string{
- {":status", "400"},
- {"content-type", "text/plain; charset=utf-8"},
- {"x-content-type-options", "nosniff"},
- {"content-length", "51"},
- }
- if !reflect.DeepEqual(goth, wanth) {
- t.Errorf("Got headers %v; want %v", goth, wanth)
- }
-}
-
-type hpackEncoder struct {
- enc *hpack.Encoder
- buf bytes.Buffer
-}
-
-func (he *hpackEncoder) encodeHeaderRaw(t *testing.T, headers ...string) []byte {
- if len(headers)%2 == 1 {
- panic("odd number of kv args")
- }
- he.buf.Reset()
- if he.enc == nil {
- he.enc = hpack.NewEncoder(&he.buf)
- }
- for len(headers) > 0 {
- k, v := headers[0], headers[1]
- err := he.enc.WriteField(hpack.HeaderField{Name: k, Value: v})
- if err != nil {
- t.Fatalf("HPACK encoding error for %q/%q: %v", k, v, err)
- }
- headers = headers[2:]
- }
- return he.buf.Bytes()
-}
-
-func TestCheckValidHTTP2Request(t *testing.T) {
- tests := []struct {
- h http.Header
- want error
- }{
- {
- h: http.Header{"Te": {"trailers"}},
- want: nil,
- },
- {
- h: http.Header{"Te": {"trailers", "bogus"}},
- want: errors.New(`request header "TE" may only be "trailers" in HTTP/2`),
- },
- {
- h: http.Header{"Foo": {""}},
- want: nil,
- },
- {
- h: http.Header{"Connection": {""}},
- want: errors.New(`request header "Connection" is not valid in HTTP/2`),
- },
- {
- h: http.Header{"Proxy-Connection": {""}},
- want: errors.New(`request header "Proxy-Connection" is not valid in HTTP/2`),
- },
- {
- h: http.Header{"Keep-Alive": {""}},
- want: errors.New(`request header "Keep-Alive" is not valid in HTTP/2`),
- },
- {
- h: http.Header{"Upgrade": {""}},
- want: errors.New(`request header "Upgrade" is not valid in HTTP/2`),
- },
- }
- for i, tt := range tests {
- got := checkValidHTTP2RequestHeaders(tt.h)
- if !reflect.DeepEqual(got, tt.want) {
- t.Errorf("%d. checkValidHTTP2Request = %v; want %v", i, got, tt.want)
- }
- }
-}
-
-// golang.org/issue/14030
-func TestExpect100ContinueAfterHandlerWrites(t *testing.T) {
- const msg = "Hello"
- const msg2 = "World"
-
- doRead := make(chan bool, 1)
- defer close(doRead) // fallback cleanup
-
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- io.WriteString(w, msg)
- w.(http.Flusher).Flush()
-
- // Do a read, which might force a 100-continue status to be sent.
- <-doRead
- r.Body.Read(make([]byte, 10))
-
- io.WriteString(w, msg2)
-
- }, optOnlyServer)
- defer st.Close()
-
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
-
- req, _ := http.NewRequest("POST", st.ts.URL, io.LimitReader(neverEnding('A'), 2<<20))
- req.Header.Set("Expect", "100-continue")
-
- res, err := tr.RoundTrip(req)
- if err != nil {
- t.Fatal(err)
- }
- defer res.Body.Close()
-
- buf := make([]byte, len(msg))
- if _, err := io.ReadFull(res.Body, buf); err != nil {
- t.Fatal(err)
- }
- if string(buf) != msg {
- t.Fatalf("msg = %q; want %q", buf, msg)
- }
-
- doRead <- true
-
- if _, err := io.ReadFull(res.Body, buf); err != nil {
- t.Fatal(err)
- }
- if string(buf) != msg2 {
- t.Fatalf("second msg = %q; want %q", buf, msg2)
- }
-}
-
-type funcReader func([]byte) (n int, err error)
-
-func (f funcReader) Read(p []byte) (n int, err error) { return f(p) }
-
-// golang.org/issue/16481 -- return flow control when streams close with unread data.
-// (The Server version of the bug. See also TestUnreadFlowControlReturned_Transport)
-func TestUnreadFlowControlReturned_Server(t *testing.T) {
- unblock := make(chan bool, 1)
- defer close(unblock)
-
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- // Don't read the 16KB request body. Wait until the client's
- // done sending it and then return. This should cause the Server
- // to then return those 16KB of flow control to the client.
- <-unblock
- }, optOnlyServer)
- defer st.Close()
-
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
-
- // This previously hung on the 4th iteration.
- for i := 0; i < 6; i++ {
- body := io.MultiReader(
- io.LimitReader(neverEnding('A'), 16<<10),
- funcReader(func([]byte) (n int, err error) {
- unblock <- true
- return 0, io.EOF
- }),
- )
- req, _ := http.NewRequest("POST", st.ts.URL, body)
- res, err := tr.RoundTrip(req)
- if err != nil {
- t.Fatal(err)
- }
- res.Body.Close()
- }
-
-}
-
-func TestServerIdleTimeout(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping in short mode")
- }
-
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- }, func(h2s *Server) {
- h2s.IdleTimeout = 500 * time.Millisecond
- })
- defer st.Close()
-
- st.greet()
- ga := st.wantGoAway()
- if ga.ErrCode != ErrCodeNo {
- t.Errorf("GOAWAY error = %v; want ErrCodeNo", ga.ErrCode)
- }
-}
-
-func TestServerIdleTimeout_AfterRequest(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping in short mode")
- }
- const timeout = 250 * time.Millisecond
-
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- time.Sleep(timeout * 2)
- }, func(h2s *Server) {
- h2s.IdleTimeout = timeout
- })
- defer st.Close()
-
- st.greet()
-
- // Send a request which takes twice the timeout. Verifies the
- // idle timeout doesn't fire while we're in a request:
- st.bodylessReq1()
- st.wantHeaders()
-
- // But the idle timeout should be rearmed after the request
- // is done:
- ga := st.wantGoAway()
- if ga.ErrCode != ErrCodeNo {
- t.Errorf("GOAWAY error = %v; want ErrCodeNo", ga.ErrCode)
- }
-}
-
-// grpc-go closes the Request.Body currently with a Read.
-// Verify that it doesn't race.
-// See https://github.com/grpc/grpc-go/pull/938
-func TestRequestBodyReadCloseRace(t *testing.T) {
- for i := 0; i < 100; i++ {
- body := &requestBody{
- pipe: &pipe{
- b: new(bytes.Buffer),
- },
- }
- body.pipe.CloseWithError(io.EOF)
-
- done := make(chan bool, 1)
- buf := make([]byte, 10)
- go func() {
- time.Sleep(1 * time.Millisecond)
- body.Close()
- done <- true
- }()
- body.Read(buf)
- <-done
- }
-}
-
-func TestServerGracefulShutdown(t *testing.T) {
- shutdownCh := make(chan struct{})
- defer func() { testh1ServerShutdownChan = nil }()
- testh1ServerShutdownChan = func(*http.Server) <-chan struct{} { return shutdownCh }
-
- var st *serverTester
- handlerDone := make(chan struct{})
- st = newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- defer close(handlerDone)
- close(shutdownCh)
-
- ga := st.wantGoAway()
- if ga.ErrCode != ErrCodeNo {
- t.Errorf("GOAWAY error = %v; want ErrCodeNo", ga.ErrCode)
- }
- if ga.LastStreamID != 1 {
- t.Errorf("GOAWAY LastStreamID = %v; want 1", ga.LastStreamID)
- }
-
- w.Header().Set("x-foo", "bar")
- })
- defer st.Close()
-
- st.greet()
- st.bodylessReq1()
-
- <-handlerDone
- hf := st.wantHeaders()
- goth := st.decodeHeader(hf.HeaderBlockFragment())
- wanth := [][2]string{
- {":status", "200"},
- {"x-foo", "bar"},
- {"content-type", "text/plain; charset=utf-8"},
- {"content-length", "0"},
- }
- if !reflect.DeepEqual(goth, wanth) {
- t.Errorf("Got headers %v; want %v", goth, wanth)
- }
-
- n, err := st.cc.Read([]byte{0})
- if n != 0 || err == nil {
- t.Errorf("Read = %v, %v; want 0, non-nil", n, err)
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/testdata/draft-ietf-httpbis-http2.xml b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/testdata/draft-ietf-httpbis-http2.xml
deleted file mode 100644
index 31a84be..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/testdata/draft-ietf-httpbis-http2.xml
+++ /dev/null
@@ -1,5021 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/xsl" href="lib/rfc2629.xslt"?>
-<?rfc toc="yes" ?>
-<?rfc symrefs="yes" ?>
-<?rfc sortrefs="yes" ?>
-<?rfc compact="yes"?>
-<?rfc subcompact="no" ?>
-<?rfc linkmailto="no" ?>
-<?rfc editing="no" ?>
-<?rfc comments="yes" ?>
-<?rfc inline="yes"?>
-<?rfc rfcedstyle="yes"?>
-<?rfc-ext allow-markup-in-artwork="yes" ?>
-<?rfc-ext include-index="no" ?>
-
-<rfc ipr="trust200902"
- category="std"
- docName="draft-ietf-httpbis-http2-latest"
- x:maturity-level="proposed"
- xmlns:x="http://purl.org/net/xml2rfc/ext">
- <x:feedback template="mailto:ietf-http-wg@w3.org?subject={docname},%20%22{section}%22&amp;body=&lt;{ref}&gt;:"/>
- <front>
- <title abbrev="HTTP/2">Hypertext Transfer Protocol version 2</title>
-
- <author initials="M." surname="Belshe" fullname="Mike Belshe">
- <organization>Twist</organization>
- <address>
- <email>mbelshe@chromium.org</email>
- </address>
- </author>
-
- <author initials="R." surname="Peon" fullname="Roberto Peon">
- <organization>Google, Inc</organization>
- <address>
- <email>fenix@google.com</email>
- </address>
- </author>
-
- <author initials="M." surname="Thomson" fullname="Martin Thomson" role="editor">
- <organization>Mozilla</organization>
- <address>
- <postal>
- <street>331 E Evelyn Street</street>
- <city>Mountain View</city>
- <region>CA</region>
- <code>94041</code>
- <country>US</country>
- </postal>
- <email>martin.thomson@gmail.com</email>
- </address>
- </author>
-
- <date year="2014" />
- <area>Applications</area>
- <workgroup>HTTPbis</workgroup>
- <keyword>HTTP</keyword>
- <keyword>SPDY</keyword>
- <keyword>Web</keyword>
-
- <abstract>
- <t>
- This specification describes an optimized expression of the semantics of the Hypertext
- Transfer Protocol (HTTP). HTTP/2 enables a more efficient use of network resources and a
- reduced perception of latency by introducing header field compression and allowing multiple
- concurrent messages on the same connection. It also introduces unsolicited push of
- representations from servers to clients.
- </t>
- <t>
- This specification is an alternative to, but does not obsolete, the HTTP/1.1 message syntax.
- HTTP's existing semantics remain unchanged.
- </t>
- </abstract>
-
- <note title="Editorial Note (To be removed by RFC Editor)">
- <t>
- Discussion of this draft takes place on the HTTPBIS working group mailing list
- (ietf-http-wg@w3.org), which is archived at <eref
- target="https://lists.w3.org/Archives/Public/ietf-http-wg/"/>.
- </t>
- <t>
- Working Group information can be found at <eref
- target="https://tools.ietf.org/wg/httpbis/"/>; that specific to HTTP/2 are at <eref
- target="https://http2.github.io/"/>.
- </t>
- <t>
- The changes in this draft are summarized in <xref
- target="change.log"/>.
- </t>
- </note>
-
- </front>
-
- <middle>
- <section anchor="intro" title="Introduction">
-
- <t>
- The Hypertext Transfer Protocol (HTTP) is a wildly successful protocol. However, the
- HTTP/1.1 message format (<xref target="RFC7230" x:fmt="," x:rel="#http.message"/>) has
- several characteristics that have a negative overall effect on application performance
- today.
- </t>
- <t>
- In particular, HTTP/1.0 allowed only one request to be outstanding at a time on a given
- TCP connection. HTTP/1.1 added request pipelining, but this only partially addressed
- request concurrency and still suffers from head-of-line blocking. Therefore, HTTP/1.1
- clients that need to make many requests typically use multiple connections to a server in
- order to achieve concurrency and thereby reduce latency.
- </t>
- <t>
- Furthermore, HTTP header fields are often repetitive and verbose, causing unnecessary
- network traffic, as well as causing the initial <xref target="TCP">TCP</xref> congestion
- window to quickly fill. This can result in excessive latency when multiple requests are
- made on a new TCP connection.
- </t>
- <t>
- HTTP/2 addresses these issues by defining an optimized mapping of HTTP's semantics to an
- underlying connection. Specifically, it allows interleaving of request and response
- messages on the same connection and uses an efficient coding for HTTP header fields. It
- also allows prioritization of requests, letting more important requests complete more
- quickly, further improving performance.
- </t>
- <t>
- The resulting protocol is more friendly to the network, because fewer TCP connections can
- be used in comparison to HTTP/1.x. This means less competition with other flows, and
- longer-lived connections, which in turn leads to better utilization of available network
- capacity.
- </t>
- <t>
- Finally, HTTP/2 also enables more efficient processing of messages through use of binary
- message framing.
- </t>
- </section>
-
- <section anchor="Overview" title="HTTP/2 Protocol Overview">
- <t>
- HTTP/2 provides an optimized transport for HTTP semantics. HTTP/2 supports all of the core
- features of HTTP/1.1, but aims to be more efficient in several ways.
- </t>
- <t>
- The basic protocol unit in HTTP/2 is a <xref target="FrameHeader">frame</xref>. Each frame
- type serves a different purpose. For example, <x:ref>HEADERS</x:ref> and
- <x:ref>DATA</x:ref> frames form the basis of <xref target="HttpSequence">HTTP requests and
- responses</xref>; other frame types like <x:ref>SETTINGS</x:ref>,
- <x:ref>WINDOW_UPDATE</x:ref>, and <x:ref>PUSH_PROMISE</x:ref> are used in support of other
- HTTP/2 features.
- </t>
- <t>
- Multiplexing of requests is achieved by having each HTTP request-response exchange
- associated with its own <xref target="StreamsLayer">stream</xref>. Streams are largely
- independent of each other, so a blocked or stalled request or response does not prevent
- progress on other streams.
- </t>
- <t>
- Flow control and prioritization ensure that it is possible to efficiently use multiplexed
- streams. <xref target="FlowControl">Flow control</xref> helps to ensure that only data that
- can be used by a receiver is transmitted. <xref
- target="StreamPriority">Prioritization</xref> ensures that limited resources can be directed
- to the most important streams first.
- </t>
- <t>
- HTTP/2 adds a new interaction mode, whereby a server can <xref target="PushResources">push
- responses to a client</xref>. Server push allows a server to speculatively send a client
- data that the server anticipates the client will need, trading off some network usage
- against a potential latency gain. The server does this by synthesizing a request, which it
- sends as a <x:ref>PUSH_PROMISE</x:ref> frame. The server is then able to send a response to
- the synthetic request on a separate stream.
- </t>
- <t>
- Frames that contain HTTP header fields are <xref target="HeaderBlock">compressed</xref>.
- HTTP requests can be highly redundant, so compression can reduce the size of requests and
- responses significantly.
- </t>
-
- <section title="Document Organization">
- <t>
- The HTTP/2 specification is split into four parts:
- <list style="symbols">
- <t>
- <xref target="starting">Starting HTTP/2</xref> covers how an HTTP/2 connection is
- initiated.
- </t>
- <t>
- The <xref target="FramingLayer">framing</xref> and <xref
- target="StreamsLayer">streams</xref> layers describe the way HTTP/2 frames are
- structured and formed into multiplexed streams.
- </t>
- <t>
- <xref target="FrameTypes">Frame</xref> and <xref target="ErrorCodes">error</xref>
- definitions include details of the frame and error types used in HTTP/2.
- </t>
- <t>
- <xref target="HTTPLayer">HTTP mappings</xref> and <xref target="HttpExtra">additional
- requirements</xref> describe how HTTP semantics are expressed using frames and
- streams.
- </t>
- </list>
- </t>
- <t>
- While some of the frame and stream layer concepts are isolated from HTTP, this
- specification does not define a completely generic framing layer. The framing and streams
- layers are tailored to the needs of the HTTP protocol and server push.
- </t>
- </section>
-
- <section title="Conventions and Terminology">
- <t>
- The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD
- NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as
- described in <xref target="RFC2119">RFC 2119</xref>.
- </t>
- <t>
- All numeric values are in network byte order. Values are unsigned unless otherwise
- indicated. Literal values are provided in decimal or hexadecimal as appropriate.
- Hexadecimal literals are prefixed with <spanx style="verb">0x</spanx> to distinguish them
- from decimal literals.
- </t>
- <t>
- The following terms are used:
- <list style="hanging">
- <t hangText="client:">
- The endpoint initiating the HTTP/2 connection.
- </t>
- <t hangText="connection:">
- A transport-layer connection between two endpoints.
- </t>
- <t hangText="connection error:">
- An error that affects the entire HTTP/2 connection.
- </t>
- <t hangText="endpoint:">
- Either the client or server of the connection.
- </t>
- <t hangText="frame:">
- The smallest unit of communication within an HTTP/2 connection, consisting of a header
- and a variable-length sequence of octets structured according to the frame type.
- </t>
- <t hangText="peer:">
- An endpoint. When discussing a particular endpoint, "peer" refers to the endpoint
- that is remote to the primary subject of discussion.
- </t>
- <t hangText="receiver:">
- An endpoint that is receiving frames.
- </t>
- <t hangText="sender:">
- An endpoint that is transmitting frames.
- </t>
- <t hangText="server:">
- The endpoint which did not initiate the HTTP/2 connection.
- </t>
- <t hangText="stream:">
- A bi-directional flow of frames across a virtual channel within the HTTP/2 connection.
- </t>
- <t hangText="stream error:">
- An error on the individual HTTP/2 stream.
- </t>
- </list>
- </t>
- <t>
- Finally, the terms "gateway", "intermediary", "proxy", and "tunnel" are defined
- in <xref target="RFC7230" x:fmt="of" x:rel="#intermediaries"/>.
- </t>
- </section>
- </section>
-
- <section anchor="starting" title="Starting HTTP/2">
- <t>
- An HTTP/2 connection is an application layer protocol running on top of a TCP connection
- (<xref target="TCP"/>). The client is the TCP connection initiator.
- </t>
- <t>
- HTTP/2 uses the same "http" and "https" URI schemes used by HTTP/1.1. HTTP/2 shares the same
- default port numbers: 80 for "http" URIs and 443 for "https" URIs. As a result,
- implementations processing requests for target resource URIs like <spanx
- style="verb">http://example.org/foo</spanx> or <spanx
- style="verb">https://example.com/bar</spanx> are required to first discover whether the
- upstream server (the immediate peer to which the client wishes to establish a connection)
- supports HTTP/2.
- </t>
-
- <t>
- The means by which support for HTTP/2 is determined is different for "http" and "https"
- URIs. Discovery for "http" URIs is described in <xref target="discover-http"/>. Discovery
- for "https" URIs is described in <xref target="discover-https"/>.
- </t>
-
- <section anchor="versioning" title="HTTP/2 Version Identification">
- <t>
- The protocol defined in this document has two identifiers.
- <list style="symbols">
- <x:lt>
- <t>
- The string "h2" identifies the protocol where HTTP/2 uses <xref
- target="TLS12">TLS</xref>. This identifier is used in the <xref
- target="TLS-ALPN">TLS application layer protocol negotiation extension (ALPN)</xref>
- field and any place that HTTP/2 over TLS is identified.
- </t>
- <t>
- The "h2" string is serialized into an ALPN protocol identifier as the two octet
- sequence: 0x68, 0x32.
- </t>
- </x:lt>
- <x:lt>
- <t>
- The string "h2c" identifies the protocol where HTTP/2 is run over cleartext TCP.
- This identifier is used in the HTTP/1.1 Upgrade header field and any place that
- HTTP/2 over TCP is identified.
- </t>
- </x:lt>
- </list>
- </t>
- <t>
- Negotiating "h2" or "h2c" implies the use of the transport, security, framing and message
- semantics described in this document.
- </t>
- <t>
- <cref>RFC Editor's Note: please remove the remainder of this section prior to the
- publication of a final version of this document.</cref>
- </t>
- <t>
- Only implementations of the final, published RFC can identify themselves as "h2" or "h2c".
- Until such an RFC exists, implementations MUST NOT identify themselves using these
- strings.
- </t>
- <t>
- Examples and text throughout the rest of this document use "h2" as a matter of
- editorial convenience only. Implementations of draft versions MUST NOT identify using
- this string.
- </t>
- <t>
- Implementations of draft versions of the protocol MUST add the string "-" and the
- corresponding draft number to the identifier. For example, draft-ietf-httpbis-http2-11
- over TLS is identified using the string "h2-11".
- </t>
- <t>
- Non-compatible experiments that are based on these draft versions MUST append the string
- "-" and an experiment name to the identifier. For example, an experimental implementation
- of packet mood-based encoding based on draft-ietf-httpbis-http2-09 might identify itself
- as "h2-09-emo". Note that any label MUST conform to the "token" syntax defined in
- <xref target="RFC7230" x:fmt="of" x:rel="#field.components"/>. Experimenters are
- encouraged to coordinate their experiments on the ietf-http-wg@w3.org mailing list.
- </t>
- </section>
-
- <section anchor="discover-http" title="Starting HTTP/2 for &quot;http&quot; URIs">
- <t>
- A client that makes a request for an "http" URI without prior knowledge about support for
- HTTP/2 uses the HTTP Upgrade mechanism (<xref target="RFC7230" x:fmt="of"
- x:rel="#header.upgrade"/>). The client makes an HTTP/1.1 request that includes an Upgrade
- header field identifying HTTP/2 with the "h2c" token. The HTTP/1.1 request MUST include
- exactly one <xref target="Http2SettingsHeader">HTTP2-Settings</xref> header field.
- </t>
- <figure>
- <preamble>For example:</preamble>
- <artwork type="message/http; msgtype=&#34;request&#34;" x:indent-with=" "><![CDATA[
-GET / HTTP/1.1
-Host: server.example.com
-Connection: Upgrade, HTTP2-Settings
-Upgrade: h2c
-HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>
-
-]]></artwork>
- </figure>
- <t>
- Requests that contain an entity body MUST be sent in their entirety before the client can
- send HTTP/2 frames. This means that a large request entity can block the use of the
- connection until it is completely sent.
- </t>
- <t>
- If concurrency of an initial request with subsequent requests is important, an OPTIONS
- request can be used to perform the upgrade to HTTP/2, at the cost of an additional
- round-trip.
- </t>
- <t>
- A server that does not support HTTP/2 can respond to the request as though the Upgrade
- header field were absent:
- </t>
- <figure>
- <artwork type="message/http; msgtype=&#34;response&#34;" x:indent-with=" ">
-HTTP/1.1 200 OK
-Content-Length: 243
-Content-Type: text/html
-
-...
-</artwork>
- </figure>
- <t>
- A server MUST ignore a "h2" token in an Upgrade header field. Presence of a token with
- "h2" implies HTTP/2 over TLS, which is instead negotiated as described in <xref
- target="discover-https"/>.
- </t>
- <t>
- A server that supports HTTP/2 can accept the upgrade with a 101 (Switching Protocols)
- response. After the empty line that terminates the 101 response, the server can begin
- sending HTTP/2 frames. These frames MUST include a response to the request that initiated
- the Upgrade.
- </t>
-
- <figure>
- <preamble>
- For example:
- </preamble>
- <artwork type="message/http; msgtype=&#34;response&#34;" x:indent-with=" ">
-HTTP/1.1 101 Switching Protocols
-Connection: Upgrade
-Upgrade: h2c
-
-[ HTTP/2 connection ...
-</artwork>
- </figure>
- <t>
- The first HTTP/2 frame sent by the server is a <x:ref>SETTINGS</x:ref> frame (<xref
- target="SETTINGS"/>) as the server connection preface (<xref
- target="ConnectionHeader"/>). Upon receiving the 101 response, the client sends a <xref
- target="ConnectionHeader">connection preface</xref>, which includes a
- <x:ref>SETTINGS</x:ref> frame.
- </t>
- <t>
- The HTTP/1.1 request that is sent prior to upgrade is assigned stream identifier 1 and is
- assigned <xref target="pri-default">default priority values</xref>. Stream 1 is
- implicitly half closed from the client toward the server, since the request is completed
- as an HTTP/1.1 request. After commencing the HTTP/2 connection, stream 1 is used for the
- response.
- </t>
-
- <section anchor="Http2SettingsHeader" title="HTTP2-Settings Header Field">
- <t>
- A request that upgrades from HTTP/1.1 to HTTP/2 MUST include exactly one <spanx
- style="verb">HTTP2-Settings</spanx> header field. The <spanx
- style="verb">HTTP2-Settings</spanx> header field is a connection-specific header field
- that includes parameters that govern the HTTP/2 connection, provided in anticipation of
- the server accepting the request to upgrade.
- </t>
- <figure>
- <artwork type="abnf" x:indent-with=" "><![CDATA[
-HTTP2-Settings = token68
-]]></artwork>
- </figure>
- <t>
- A server MUST NOT upgrade the connection to HTTP/2 if this header field is not present,
- or if more than one is present. A server MUST NOT send this header field.
- </t>
-
- <t>
- The content of the <spanx style="verb">HTTP2-Settings</spanx> header field is the
- payload of a <x:ref>SETTINGS</x:ref> frame (<xref target="SETTINGS"/>), encoded as a
- base64url string (that is, the URL- and filename-safe Base64 encoding described in <xref
- target="RFC4648" x:fmt="of" x:sec="5"/>, with any trailing '=' characters omitted). The
- <xref target="RFC5234">ABNF</xref> production for <spanx style="verb">token68</spanx> is
- defined in <xref target="RFC7235" x:fmt="of" x:rel="#challenge.and.response"/>.
- </t>
- <t>
- Since the upgrade is only intended to apply to the immediate connection, a client
- sending <spanx style="verb">HTTP2-Settings</spanx> MUST also send <spanx
- style="verb">HTTP2-Settings</spanx> as a connection option in the <spanx
- style="verb">Connection</spanx> header field to prevent it from being forwarded
- downstream.
- </t>
- <t>
- A server decodes and interprets these values as it would any other
- <x:ref>SETTINGS</x:ref> frame. <xref target="SettingsSync">Acknowledgement of the
- SETTINGS parameters</xref> is not necessary, since a 101 response serves as implicit
- acknowledgment. Providing these values in the Upgrade request gives a client an
- opportunity to provide parameters prior to receiving any frames from the server.
- </t>
- </section>
- </section>
-
- <section anchor="discover-https" title="Starting HTTP/2 for &quot;https&quot; URIs">
- <t>
- A client that makes a request to an "https" URI uses <xref target="TLS12">TLS</xref>
- with the <xref target="TLS-ALPN">application layer protocol negotiation extension</xref>.
- </t>
- <t>
- HTTP/2 over TLS uses the "h2" application token. The "h2c" token MUST NOT be sent by a
- client or selected by a server.
- </t>
- <t>
- Once TLS negotiation is complete, both the client and the server send a <xref
- target="ConnectionHeader">connection preface</xref>.
- </t>
- </section>
-
- <section anchor="known-http" title="Starting HTTP/2 with Prior Knowledge">
- <t>
- A client can learn that a particular server supports HTTP/2 by other means. For example,
- <xref target="ALT-SVC"/> describes a mechanism for advertising this capability.
- </t>
- <t>
- A client MAY immediately send HTTP/2 frames to a server that is known to support HTTP/2,
- after the <xref target="ConnectionHeader">connection preface</xref>; a server can
- identify such a connection by the presence of the connection preface. This only affects
- the establishment of HTTP/2 connections over cleartext TCP; implementations that support
- HTTP/2 over TLS MUST use <xref target="TLS-ALPN">protocol negotiation in TLS</xref>.
- </t>
- <t>
- Without additional information, prior support for HTTP/2 is not a strong signal that a
- given server will support HTTP/2 for future connections. For example, it is possible for
- server configurations to change, for configurations to differ between instances in
- clustered servers, or for network conditions to change.
- </t>
- </section>
-
- <section anchor="ConnectionHeader" title="HTTP/2 Connection Preface">
- <t>
- Upon establishment of a TCP connection and determination that HTTP/2 will be used by both
- peers, each endpoint MUST send a connection preface as a final confirmation and to
- establish the initial SETTINGS parameters for the HTTP/2 connection. The client and
- server each send a different connection preface.
- </t>
- <t>
- The client connection preface starts with a sequence of 24 octets, which in hex notation
- are:
- </t>
- <figure>
- <artwork type="inline" x:indent-with=" "><![CDATA[
-0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
-]]></artwork>
- </figure>
- <t>
- (the string <spanx style="verb">PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n</spanx>). This sequence
- is followed by a <x:ref>SETTINGS</x:ref> frame (<xref target="SETTINGS"/>). The
- <x:ref>SETTINGS</x:ref> frame MAY be empty. The client sends the client connection
- preface immediately upon receipt of a 101 Switching Protocols response (indicating a
- successful upgrade), or as the first application data octets of a TLS connection. If
- starting an HTTP/2 connection with prior knowledge of server support for the protocol, the
- client connection preface is sent upon connection establishment.
- </t>
- <t>
- <list>
- <t>
- The client connection preface is selected so that a large proportion of HTTP/1.1 or
- HTTP/1.0 servers and intermediaries do not attempt to process further frames. Note
- that this does not address the concerns raised in <xref target="TALKING"/>.
- </t>
- </list>
- </t>
- <t>
- The server connection preface consists of a potentially empty <x:ref>SETTINGS</x:ref>
- frame (<xref target="SETTINGS"/>) that MUST be the first frame the server sends in the
- HTTP/2 connection.
- </t>
- <t>
- The <x:ref>SETTINGS</x:ref> frames received from a peer as part of the connection preface
- MUST be acknowledged (see <xref target="SettingsSync"/>) after sending the connection
- preface.
- </t>
- <t>
- To avoid unnecessary latency, clients are permitted to send additional frames to the
- server immediately after sending the client connection preface, without waiting to receive
- the server connection preface. It is important to note, however, that the server
- connection preface <x:ref>SETTINGS</x:ref> frame might include parameters that necessarily
- alter how a client is expected to communicate with the server. Upon receiving the
- <x:ref>SETTINGS</x:ref> frame, the client is expected to honor any parameters established.
- In some configurations, it is possible for the server to transmit <x:ref>SETTINGS</x:ref>
- before the client sends additional frames, providing an opportunity to avoid this issue.
- </t>
- <t>
- Clients and servers MUST treat an invalid connection preface as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>. A <x:ref>GOAWAY</x:ref> frame (<xref target="GOAWAY"/>)
- MAY be omitted in this case, since an invalid preface indicates that the peer is not using
- HTTP/2.
- </t>
- </section>
- </section>
-
- <section anchor="FramingLayer" title="HTTP Frames">
- <t>
- Once the HTTP/2 connection is established, endpoints can begin exchanging frames.
- </t>
-
- <section anchor="FrameHeader" title="Frame Format">
- <t>
- All frames begin with a fixed 9-octet header followed by a variable-length payload.
- </t>
- <figure title="Frame Layout">
- <artwork type="inline"><![CDATA[
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Length (24) |
- +---------------+---------------+---------------+
- | Type (8) | Flags (8) |
- +-+-+-----------+---------------+-------------------------------+
- |R| Stream Identifier (31) |
- +=+=============================================================+
- | Frame Payload (0...) ...
- +---------------------------------------------------------------+
-]]></artwork>
- </figure>
- <t>
- The fields of the frame header are defined as:
- <list style="hanging">
- <x:lt hangText="Length:">
- <t>
- The length of the frame payload expressed as an unsigned 24-bit integer. Values
- greater than 2<x:sup>14</x:sup> (16,384) MUST NOT be sent unless the receiver has
- set a larger value for <x:ref>SETTINGS_MAX_FRAME_SIZE</x:ref>.
- </t>
- <t>
- The 9 octets of the frame header are not included in this value.
- </t>
- </x:lt>
- <x:lt hangText="Type:">
- <t>
- The 8-bit type of the frame. The frame type determines the format and semantics of
- the frame. Implementations MUST ignore and discard any frame that has a type that
- is unknown.
- </t>
- </x:lt>
- <x:lt hangText="Flags:">
- <t>
- An 8-bit field reserved for frame-type specific boolean flags.
- </t>
- <t>
- Flags are assigned semantics specific to the indicated frame type. Flags that have
- no defined semantics for a particular frame type MUST be ignored, and MUST be left
- unset (0) when sending.
- </t>
- </x:lt>
- <x:lt hangText="R:">
- <t>
- A reserved 1-bit field. The semantics of this bit are undefined and the bit MUST
- remain unset (0) when sending and MUST be ignored when receiving.
- </t>
- </x:lt>
- <x:lt hangText="Stream Identifier:">
- <t>
- A 31-bit stream identifier (see <xref target="StreamIdentifiers"/>). The value 0 is
- reserved for frames that are associated with the connection as a whole as opposed to
- an individual stream.
- </t>
- </x:lt>
- </list>
- </t>
- <t>
- The structure and content of the frame payload is dependent entirely on the frame type.
- </t>
- </section>
-
- <section anchor="FrameSize" title="Frame Size">
- <t>
- The size of a frame payload is limited by the maximum size that a receiver advertises in
- the <x:ref>SETTINGS_MAX_FRAME_SIZE</x:ref> setting. This setting can have any value
- between 2<x:sup>14</x:sup> (16,384) and 2<x:sup>24</x:sup>-1 (16,777,215) octets,
- inclusive.
- </t>
- <t>
- All implementations MUST be capable of receiving and minimally processing frames up to
- 2<x:sup>14</x:sup> octets in length, plus the 9 octet <xref target="FrameHeader">frame
- header</xref>. The size of the frame header is not included when describing frame sizes.
- <list style="hanging">
- <t hangText="Note:">
- Certain frame types, such as <xref target="PING">PING</xref>, impose additional limits
- on the amount of payload data allowed.
- </t>
- </list>
- </t>
- <t>
- If a frame size exceeds any defined limit, or is too small to contain mandatory frame
- data, the endpoint MUST send a <x:ref>FRAME_SIZE_ERROR</x:ref> error. A frame size error
- in a frame that could alter the state of the entire connection MUST be treated as a <xref
- target="ConnectionErrorHandler">connection error</xref>; this includes any frame carrying
- a <xref target="HeaderBlock">header block</xref> (that is, <x:ref>HEADERS</x:ref>,
- <x:ref>PUSH_PROMISE</x:ref>, and <x:ref>CONTINUATION</x:ref>), <x:ref>SETTINGS</x:ref>,
- and any <x:ref>WINDOW_UPDATE</x:ref> frame with a stream identifier of 0.
- </t>
- <t>
- Endpoints are not obligated to use all available space in a frame. Responsiveness can be
- improved by using frames that are smaller than the permitted maximum size. Sending large
- frames can result in delays in sending time-sensitive frames (such
- <x:ref>RST_STREAM</x:ref>, <x:ref>WINDOW_UPDATE</x:ref>, or <x:ref>PRIORITY</x:ref>)
- which if blocked by the transmission of a large frame, could affect performance.
- </t>
- </section>
-
- <section anchor="HeaderBlock" title="Header Compression and Decompression">
- <t>
- Just as in HTTP/1, a header field in HTTP/2 is a name with one or more associated values.
- They are used within HTTP request and response messages as well as server push operations
- (see <xref target="PushResources" />).
- </t>
- <t>
- Header lists are collections of zero or more header fields. When transmitted over a
- connection, a header list is serialized into a header block using <xref
- target="COMPRESSION">HTTP Header Compression</xref>. The serialized header block is then
- divided into one or more octet sequences, called header block fragments, and transmitted
- within the payload of <xref target="HEADERS">HEADERS</xref>, <xref
- target="PUSH_PROMISE">PUSH_PROMISE</xref> or <xref
- target="CONTINUATION">CONTINUATION</xref> frames.
- </t>
- <t>
- The <xref target="COOKIE">Cookie header field</xref> is treated specially by the HTTP
- mapping (see <xref target="CompressCookie"/>).
- </t>
- <t>
- A receiving endpoint reassembles the header block by concatenating its fragments, then
- decompresses the block to reconstruct the header list.
- </t>
- <t>
- A complete header block consists of either:
- <list style="symbols">
- <t>
- a single <x:ref>HEADERS</x:ref> or <x:ref>PUSH_PROMISE</x:ref> frame,
- with the END_HEADERS flag set, or
- </t>
- <t>
- a <x:ref>HEADERS</x:ref> or <x:ref>PUSH_PROMISE</x:ref> frame with the END_HEADERS
- flag cleared and one or more <x:ref>CONTINUATION</x:ref> frames,
- where the last <x:ref>CONTINUATION</x:ref> frame has the END_HEADERS flag set.
- </t>
- </list>
- </t>
- <t>
- Header compression is stateful. One compression context and one decompression context is
- used for the entire connection. Each header block is processed as a discrete unit.
- Header blocks MUST be transmitted as a contiguous sequence of frames, with no interleaved
- frames of any other type or from any other stream. The last frame in a sequence of
- <x:ref>HEADERS</x:ref> or <x:ref>CONTINUATION</x:ref> frames MUST have the END_HEADERS
- flag set. The last frame in a sequence of <x:ref>PUSH_PROMISE</x:ref> or
- <x:ref>CONTINUATION</x:ref> frames MUST have the END_HEADERS flag set. This allows a
- header block to be logically equivalent to a single frame.
- </t>
- <t>
- Header block fragments can only be sent as the payload of <x:ref>HEADERS</x:ref>,
- <x:ref>PUSH_PROMISE</x:ref> or <x:ref>CONTINUATION</x:ref> frames, because these frames
- carry data that can modify the compression context maintained by a receiver. An endpoint
- receiving <x:ref>HEADERS</x:ref>, <x:ref>PUSH_PROMISE</x:ref> or
- <x:ref>CONTINUATION</x:ref> frames MUST reassemble header blocks and perform decompression
- even if the frames are to be discarded. A receiver MUST terminate the connection with a
- <xref target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>COMPRESSION_ERROR</x:ref> if it does not decompress a header block.
- </t>
- </section>
- </section>
-
- <section anchor="StreamsLayer" title="Streams and Multiplexing">
- <t>
- A "stream" is an independent, bi-directional sequence of frames exchanged between the client
- and server within an HTTP/2 connection. Streams have several important characteristics:
- <list style="symbols">
- <t>
- A single HTTP/2 connection can contain multiple concurrently open streams, with either
- endpoint interleaving frames from multiple streams.
- </t>
- <t>
- Streams can be established and used unilaterally or shared by either the client or
- server.
- </t>
- <t>
- Streams can be closed by either endpoint.
- </t>
- <t>
- The order in which frames are sent on a stream is significant. Recipients process frames
- in the order they are received. In particular, the order of <x:ref>HEADERS</x:ref>,
- and <x:ref>DATA</x:ref> frames is semantically significant.
- </t>
- <t>
- Streams are identified by an integer. Stream identifiers are assigned to streams by the
- endpoint initiating the stream.
- </t>
- </list>
- </t>
-
- <section anchor="StreamStates" title="Stream States">
- <t>
- The lifecycle of a stream is shown in <xref target="StreamStatesFigure"/>.
- </t>
-
- <figure anchor="StreamStatesFigure" title="Stream States">
- <artwork type="drawing">
- <![CDATA[
- +--------+
- PP | | PP
- ,--------| idle |--------.
- / | | \
- v +--------+ v
- +----------+ | +----------+
- | | | H | |
- ,---| reserved | | | reserved |---.
- | | (local) | v | (remote) | |
- | +----------+ +--------+ +----------+ |
- | | ES | | ES | |
- | | H ,-------| open |-------. | H |
- | | / | | \ | |
- | v v +--------+ v v |
- | +----------+ | +----------+ |
- | | half | | | half | |
- | | closed | | R | closed | |
- | | (remote) | | | (local) | |
- | +----------+ | +----------+ |
- | | v | |
- | | ES / R +--------+ ES / R | |
- | `----------->| |<-----------' |
- | R | closed | R |
- `-------------------->| |<--------------------'
- +--------+
-
- H: HEADERS frame (with implied CONTINUATIONs)
- PP: PUSH_PROMISE frame (with implied CONTINUATIONs)
- ES: END_STREAM flag
- R: RST_STREAM frame
-]]>
- </artwork>
- </figure>
-
- <t>
- Note that this diagram shows stream state transitions and the frames and flags that affect
- those transitions only. In this regard, <x:ref>CONTINUATION</x:ref> frames do not result
- in state transitions; they are effectively part of the <x:ref>HEADERS</x:ref> or
- <x:ref>PUSH_PROMISE</x:ref> that they follow. For this purpose, the END_STREAM flag is
- processed as a separate event to the frame that bears it; a <x:ref>HEADERS</x:ref> frame
- with the END_STREAM flag set can cause two state transitions.
- </t>
- <t>
- Both endpoints have a subjective view of the state of a stream that could be different
- when frames are in transit. Endpoints do not coordinate the creation of streams; they are
- created unilaterally by either endpoint. The negative consequences of a mismatch in
- states are limited to the "closed" state after sending <x:ref>RST_STREAM</x:ref>, where
- frames might be received for some time after closing.
- </t>
- <t>
- Streams have the following states:
- <list style="hanging">
-
- <x:lt hangText="idle:">
- <t>
- <vspace blankLines="0"/>
- All streams start in the "idle" state. In this state, no frames have been
- exchanged.
- </t>
- <t>
- The following transitions are valid from this state:
- <list style="symbols">
- <t>
- Sending or receiving a <x:ref>HEADERS</x:ref> frame causes the stream to become
- "open". The stream identifier is selected as described in <xref
- target="StreamIdentifiers"/>. The same <x:ref>HEADERS</x:ref> frame can also
- cause a stream to immediately become "half closed".
- </t>
- <t>
- Sending a <x:ref>PUSH_PROMISE</x:ref> frame marks the associated stream for
- later use. The stream state for the reserved stream transitions to "reserved
- (local)".
- </t>
- <t>
- Receiving a <x:ref>PUSH_PROMISE</x:ref> frame marks the associated stream as
- reserved by the remote peer. The state of the stream becomes "reserved
- (remote)".
- </t>
- </list>
- </t>
- <t>
- Receiving any frames other than <x:ref>HEADERS</x:ref> or
- <x:ref>PUSH_PROMISE</x:ref> on a stream in this state MUST be treated as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- </x:lt>
-
- <x:lt hangText="reserved (local):">
- <t>
- <vspace blankLines="0"/>
- A stream in the "reserved (local)" state is one that has been promised by sending a
- <x:ref>PUSH_PROMISE</x:ref> frame. A <x:ref>PUSH_PROMISE</x:ref> frame reserves an
- idle stream by associating the stream with an open stream that was initiated by the
- remote peer (see <xref target="PushResources"/>).
- </t>
- <t>
- In this state, only the following transitions are possible:
- <list style="symbols">
- <t>
- The endpoint can send a <x:ref>HEADERS</x:ref> frame. This causes the stream to
- open in a "half closed (remote)" state.
- </t>
- <t>
- Either endpoint can send a <x:ref>RST_STREAM</x:ref> frame to cause the stream
- to become "closed". This releases the stream reservation.
- </t>
- </list>
- </t>
- <t>
- An endpoint MUST NOT send any type of frame other than <x:ref>HEADERS</x:ref> or
- <x:ref>RST_STREAM</x:ref> in this state.
- </t>
- <t>
- A <x:ref>PRIORITY</x:ref> frame MAY be received in this state. Receiving any type
- of frame other than <x:ref>RST_STREAM</x:ref> or <x:ref>PRIORITY</x:ref> on a stream
- in this state MUST be treated as a <xref target="ConnectionErrorHandler">connection
- error</xref> of type <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- </x:lt>
-
- <x:lt hangText="reserved (remote):">
- <t>
- <vspace blankLines="0"/>
- A stream in the "reserved (remote)" state has been reserved by a remote peer.
- </t>
- <t>
- In this state, only the following transitions are possible:
- <list style="symbols">
- <t>
- Receiving a <x:ref>HEADERS</x:ref> frame causes the stream to transition to
- "half closed (local)".
- </t>
- <t>
- Either endpoint can send a <x:ref>RST_STREAM</x:ref> frame to cause the stream
- to become "closed". This releases the stream reservation.
- </t>
- </list>
- </t>
- <t>
- An endpoint MAY send a <x:ref>PRIORITY</x:ref> frame in this state to reprioritize
- the reserved stream. An endpoint MUST NOT send any type of frame other than
- <x:ref>RST_STREAM</x:ref>, <x:ref>WINDOW_UPDATE</x:ref>, or <x:ref>PRIORITY</x:ref>
- in this state.
- </t>
- <t>
- Receiving any type of frame other than <x:ref>HEADERS</x:ref> or
- <x:ref>RST_STREAM</x:ref> on a stream in this state MUST be treated as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- </x:lt>
-
- <x:lt hangText="open:">
- <t>
- <vspace blankLines="0"/>
- A stream in the "open" state may be used by both peers to send frames of any type.
- In this state, sending peers observe advertised <xref target="FlowControl">stream
- level flow control limits</xref>.
- </t>
- <t>
- From this state either endpoint can send a frame with an END_STREAM flag set, which
- causes the stream to transition into one of the "half closed" states: an endpoint
- sending an END_STREAM flag causes the stream state to become "half closed (local)";
- an endpoint receiving an END_STREAM flag causes the stream state to become "half
- closed (remote)".
- </t>
- <t>
- Either endpoint can send a <x:ref>RST_STREAM</x:ref> frame from this state, causing
- it to transition immediately to "closed".
- </t>
- </x:lt>
-
- <x:lt hangText="half closed (local):">
- <t>
- <vspace blankLines="0"/>
- A stream that is in the "half closed (local)" state cannot be used for sending
- frames. Only <x:ref>WINDOW_UPDATE</x:ref>, <x:ref>PRIORITY</x:ref> and
- <x:ref>RST_STREAM</x:ref> frames can be sent in this state.
- </t>
- <t>
- A stream transitions from this state to "closed" when a frame that contains an
- END_STREAM flag is received, or when either peer sends a <x:ref>RST_STREAM</x:ref>
- frame.
- </t>
- <t>
- A receiver can ignore <x:ref>WINDOW_UPDATE</x:ref> frames in this state, which might
- arrive for a short period after a frame bearing the END_STREAM flag is sent.
- </t>
- <t>
- <x:ref>PRIORITY</x:ref> frames received in this state are used to reprioritize
- streams that depend on the current stream.
- </t>
- </x:lt>
-
- <x:lt hangText="half closed (remote):">
- <t>
- <vspace blankLines="0"/>
- A stream that is "half closed (remote)" is no longer being used by the peer to send
- frames. In this state, an endpoint is no longer obligated to maintain a receiver
- flow control window if it performs flow control.
- </t>
- <t>
- If an endpoint receives additional frames for a stream that is in this state, other
- than <x:ref>WINDOW_UPDATE</x:ref>, <x:ref>PRIORITY</x:ref> or
- <x:ref>RST_STREAM</x:ref>, it MUST respond with a <xref
- target="StreamErrorHandler">stream error</xref> of type
- <x:ref>STREAM_CLOSED</x:ref>.
- </t>
- <t>
- A stream that is "half closed (remote)" can be used by the endpoint to send frames
- of any type. In this state, the endpoint continues to observe advertised <xref
- target="FlowControl">stream level flow control limits</xref>.
- </t>
- <t>
- A stream can transition from this state to "closed" by sending a frame that contains
- an END_STREAM flag, or when either peer sends a <x:ref>RST_STREAM</x:ref> frame.
- </t>
- </x:lt>
-
- <x:lt hangText="closed:">
- <t>
- <vspace blankLines="0"/>
- The "closed" state is the terminal state.
- </t>
- <t>
- An endpoint MUST NOT send frames other than <x:ref>PRIORITY</x:ref> on a closed
- stream. An endpoint that receives any frame other than <x:ref>PRIORITY</x:ref>
- after receiving a <x:ref>RST_STREAM</x:ref> MUST treat that as a <xref
- target="StreamErrorHandler">stream error</xref> of type
- <x:ref>STREAM_CLOSED</x:ref>. Similarly, an endpoint that receives any frames after
- receiving a frame with the END_STREAM flag set MUST treat that as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>STREAM_CLOSED</x:ref>, unless the frame is permitted as described below.
- </t>
- <t>
- <x:ref>WINDOW_UPDATE</x:ref> or <x:ref>RST_STREAM</x:ref> frames can be received in
- this state for a short period after a <x:ref>DATA</x:ref> or <x:ref>HEADERS</x:ref>
- frame containing an END_STREAM flag is sent. Until the remote peer receives and
- processes <x:ref>RST_STREAM</x:ref> or the frame bearing the END_STREAM flag, it
- might send frames of these types. Endpoints MUST ignore
- <x:ref>WINDOW_UPDATE</x:ref> or <x:ref>RST_STREAM</x:ref> frames received in this
- state, though endpoints MAY choose to treat frames that arrive a significant time
- after sending END_STREAM as a <xref target="ConnectionErrorHandler">connection
- error</xref> of type <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- <t>
- <x:ref>PRIORITY</x:ref> frames can be sent on closed streams to prioritize streams
- that are dependent on the closed stream. Endpoints SHOULD process
- <x:ref>PRIORITY</x:ref> frame, though they can be ignored if the stream has been
- removed from the dependency tree (see <xref target="priority-gc"/>).
- </t>
- <t>
- If this state is reached as a result of sending a <x:ref>RST_STREAM</x:ref> frame,
- the peer that receives the <x:ref>RST_STREAM</x:ref> might have already sent - or
- enqueued for sending - frames on the stream that cannot be withdrawn. An endpoint
- MUST ignore frames that it receives on closed streams after it has sent a
- <x:ref>RST_STREAM</x:ref> frame. An endpoint MAY choose to limit the period over
- which it ignores frames and treat frames that arrive after this time as being in
- error.
- </t>
- <t>
- Flow controlled frames (i.e., <x:ref>DATA</x:ref>) received after sending
- <x:ref>RST_STREAM</x:ref> are counted toward the connection flow control window.
- Even though these frames might be ignored, because they are sent before the sender
- receives the <x:ref>RST_STREAM</x:ref>, the sender will consider the frames to count
- against the flow control window.
- </t>
- <t>
- An endpoint might receive a <x:ref>PUSH_PROMISE</x:ref> frame after it sends
- <x:ref>RST_STREAM</x:ref>. <x:ref>PUSH_PROMISE</x:ref> causes a stream to become
- "reserved" even if the associated stream has been reset. Therefore, a
- <x:ref>RST_STREAM</x:ref> is needed to close an unwanted promised stream.
- </t>
- </x:lt>
- </list>
- </t>
- <t>
- In the absence of more specific guidance elsewhere in this document, implementations
- SHOULD treat the receipt of a frame that is not expressly permitted in the description of
- a state as a <xref target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>. Frame of unknown types are ignored.
- </t>
- <t>
- An example of the state transitions for an HTTP request/response exchange can be found in
- <xref target="HttpSequence"/>. An example of the state transitions for server push can be
- found in <xref target="PushRequests"/> and <xref target="PushResponses"/>.
- </t>
-
- <section anchor="StreamIdentifiers" title="Stream Identifiers">
- <t>
- Streams are identified with an unsigned 31-bit integer. Streams initiated by a client
- MUST use odd-numbered stream identifiers; those initiated by the server MUST use
- even-numbered stream identifiers. A stream identifier of zero (0x0) is used for
- connection control messages; the stream identifier zero cannot be used to establish a
- new stream.
- </t>
- <t>
- HTTP/1.1 requests that are upgraded to HTTP/2 (see <xref target="discover-http"/>) are
- responded to with a stream identifier of one (0x1). After the upgrade
- completes, stream 0x1 is "half closed (local)" to the client. Therefore, stream 0x1
- cannot be selected as a new stream identifier by a client that upgrades from HTTP/1.1.
- </t>
- <t>
- The identifier of a newly established stream MUST be numerically greater than all
- streams that the initiating endpoint has opened or reserved. This governs streams that
- are opened using a <x:ref>HEADERS</x:ref> frame and streams that are reserved using
- <x:ref>PUSH_PROMISE</x:ref>. An endpoint that receives an unexpected stream identifier
- MUST respond with a <xref target="ConnectionErrorHandler">connection error</xref> of
- type <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- <t>
- The first use of a new stream identifier implicitly closes all streams in the "idle"
- state that might have been initiated by that peer with a lower-valued stream identifier.
- For example, if a client sends a <x:ref>HEADERS</x:ref> frame on stream 7 without ever
- sending a frame on stream 5, then stream 5 transitions to the "closed" state when the
- first frame for stream 7 is sent or received.
- </t>
- <t>
- Stream identifiers cannot be reused. Long-lived connections can result in an endpoint
- exhausting the available range of stream identifiers. A client that is unable to
- establish a new stream identifier can establish a new connection for new streams. A
- server that is unable to establish a new stream identifier can send a
- <x:ref>GOAWAY</x:ref> frame so that the client is forced to open a new connection for
- new streams.
- </t>
- </section>
-
- <section title="Stream Concurrency">
- <t>
- A peer can limit the number of concurrently active streams using the
- <x:ref>SETTINGS_MAX_CONCURRENT_STREAMS</x:ref> parameter (see <xref
- target="SettingValues"/>) within a <x:ref>SETTINGS</x:ref> frame. The maximum concurrent
- streams setting is specific to each endpoint and applies only to the peer that receives
- the setting. That is, clients specify the maximum number of concurrent streams the
- server can initiate, and servers specify the maximum number of concurrent streams the
- client can initiate.
- </t>
- <t>
- Streams that are in the "open" state, or either of the "half closed" states count toward
- the maximum number of streams that an endpoint is permitted to open. Streams in any of
- these three states count toward the limit advertised in the
- <x:ref>SETTINGS_MAX_CONCURRENT_STREAMS</x:ref> setting. Streams in either of the
- "reserved" states do not count toward the stream limit.
- </t>
- <t>
- Endpoints MUST NOT exceed the limit set by their peer. An endpoint that receives a
- <x:ref>HEADERS</x:ref> frame that causes their advertised concurrent stream limit to be
- exceeded MUST treat this as a <xref target="StreamErrorHandler">stream error</xref>. An
- endpoint that wishes to reduce the value of
- <x:ref>SETTINGS_MAX_CONCURRENT_STREAMS</x:ref> to a value that is below the current
- number of open streams can either close streams that exceed the new value or allow
- streams to complete.
- </t>
- </section>
- </section>
-
- <section anchor="FlowControl" title="Flow Control">
- <t>
- Using streams for multiplexing introduces contention over use of the TCP connection,
- resulting in blocked streams. A flow control scheme ensures that streams on the same
- connection do not destructively interfere with each other. Flow control is used for both
- individual streams and for the connection as a whole.
- </t>
- <t>
- HTTP/2 provides for flow control through use of the <xref
- target="WINDOW_UPDATE">WINDOW_UPDATE frame</xref>.
- </t>
-
- <section anchor="fc-principles" title="Flow Control Principles">
- <t>
- HTTP/2 stream flow control aims to allow a variety of flow control algorithms to be
- used without requiring protocol changes. Flow control in HTTP/2 has the following
- characteristics:
- <list style="numbers">
- <t>
- Flow control is specific to a connection; i.e., it is "hop-by-hop", not
- "end-to-end".
- </t>
- <t>
- Flow control is based on window update frames. Receivers advertise how many octets
- they are prepared to receive on a stream and for the entire connection. This is a
- credit-based scheme.
- </t>
- <t>
- Flow control is directional with overall control provided by the receiver. A
- receiver MAY choose to set any window size that it desires for each stream and for
- the entire connection. A sender MUST respect flow control limits imposed by a
- receiver. Clients, servers and intermediaries all independently advertise their
- flow control window as a receiver and abide by the flow control limits set by
- their peer when sending.
- </t>
- <t>
- The initial value for the flow control window is 65,535 octets for both new streams
- and the overall connection.
- </t>
- <t>
- The frame type determines whether flow control applies to a frame. Of the frames
- specified in this document, only <x:ref>DATA</x:ref> frames are subject to flow
- control; all other frame types do not consume space in the advertised flow control
- window. This ensures that important control frames are not blocked by flow control.
- </t>
- <t>
- Flow control cannot be disabled.
- </t>
- <t>
- HTTP/2 defines only the format and semantics of the <x:ref>WINDOW_UPDATE</x:ref>
- frame (<xref target="WINDOW_UPDATE"/>). This document does not stipulate how a
- receiver decides when to send this frame or the value that it sends, nor does it
- specify how a sender chooses to send packets. Implementations are able to select
- any algorithm that suits their needs.
- </t>
- </list>
- </t>
- <t>
- Implementations are also responsible for managing how requests and responses are sent
- based on priority; choosing how to avoid head of line blocking for requests; and
- managing the creation of new streams. Algorithm choices for these could interact with
- any flow control algorithm.
- </t>
- </section>
-
- <section anchor="DisableFlowControl" title="Appropriate Use of Flow Control">
- <t>
- Flow control is defined to protect endpoints that are operating under resource
- constraints. For example, a proxy needs to share memory between many connections, and
- also might have a slow upstream connection and a fast downstream one. Flow control
- addresses cases where the receiver is unable process data on one stream, yet wants to
- continue to process other streams in the same connection.
- </t>
- <t>
- Deployments that do not require this capability can advertise a flow control window of
- the maximum size, incrementing the available space when new data is received. This
- effectively disables flow control for that receiver. Conversely, a sender is always
- subject to the flow control window advertised by the receiver.
- </t>
- <t>
- Deployments with constrained resources (for example, memory) can employ flow control to
- limit the amount of memory a peer can consume. Note, however, that this can lead to
- suboptimal use of available network resources if flow control is enabled without
- knowledge of the bandwidth-delay product (see <xref target="RFC1323"/>).
- </t>
- <t>
- Even with full awareness of the current bandwidth-delay product, implementation of flow
- control can be difficult. When using flow control, the receiver MUST read from the TCP
- receive buffer in a timely fashion. Failure to do so could lead to a deadlock when
- critical frames, such as <x:ref>WINDOW_UPDATE</x:ref>, are not read and acted upon.
- </t>
- </section>
- </section>
-
- <section anchor="StreamPriority" title="Stream priority">
- <t>
- A client can assign a priority for a new stream by including prioritization information in
- the <xref target="HEADERS">HEADERS frame</xref> that opens the stream. For an existing
- stream, the <xref target="PRIORITY">PRIORITY frame</xref> can be used to change the
- priority.
- </t>
- <t>
- The purpose of prioritization is to allow an endpoint to express how it would prefer its
- peer allocate resources when managing concurrent streams. Most importantly, priority can
- be used to select streams for transmitting frames when there is limited capacity for
- sending.
- </t>
- <t>
- Streams can be prioritized by marking them as dependent on the completion of other streams
- (<xref target="pri-depend"/>). Each dependency is assigned a relative weight, a number
- that is used to determine the relative proportion of available resources that are assigned
- to streams dependent on the same stream.
- </t>
- <!--
- Note that stream dependencies have not yet been validated in practice. The theory
- might be fairly sound, but there are no implementations currently sending these. If it
- turns out that they are not useful, or actively harmful, implementations will be requested
- to avoid creating stream dependencies.
- -->
- <t>
- Explicitly setting the priority for a stream is input to a prioritization process. It
- does not guarantee any particular processing or transmission order for the stream relative
- to any other stream. An endpoint cannot force a peer to process concurrent streams in a
- particular order using priority. Expressing priority is therefore only ever a suggestion.
- </t>
- <t>
- Providing prioritization information is optional, so default values are used if no
- explicit indicator is provided (<xref target="pri-default"/>).
- </t>
-
- <section title="Stream Dependencies" anchor="pri-depend">
- <t>
- Each stream can be given an explicit dependency on another stream. Including a
- dependency expresses a preference to allocate resources to the identified stream rather
- than to the dependent stream.
- </t>
- <t>
- A stream that is not dependent on any other stream is given a stream dependency of 0x0.
- In other words, the non-existent stream 0 forms the root of the tree.
- </t>
- <t>
- A stream that depends on another stream is a dependent stream. The stream upon which a
- stream is dependent is a parent stream. A dependency on a stream that is not currently
- in the tree - such as a stream in the "idle" state - results in that stream being given
- a <xref target="pri-default">default priority</xref>.
- </t>
- <t>
- When assigning a dependency on another stream, the stream is added as a new dependency
- of the parent stream. Dependent streams that share the same parent are not ordered with
- respect to each other. For example, if streams B and C are dependent on stream A, and
- if stream D is created with a dependency on stream A, this results in a dependency order
- of A followed by B, C, and D in any order.
- </t>
- <figure title="Example of Default Dependency Creation">
- <artwork type="inline"><![CDATA[
- A A
- / \ ==> /|\
- B C B D C
-]]></artwork>
- </figure>
- <t>
- An exclusive flag allows for the insertion of a new level of dependencies. The
- exclusive flag causes the stream to become the sole dependency of its parent stream,
- causing other dependencies to become dependent on the exclusive stream. In the
- previous example, if stream D is created with an exclusive dependency on stream A, this
- results in D becoming the dependency parent of B and C.
- </t>
- <figure title="Example of Exclusive Dependency Creation">
- <artwork type="inline"><![CDATA[
- A
- A |
- / \ ==> D
- B C / \
- B C
-]]></artwork>
- </figure>
- <t>
- Inside the dependency tree, a dependent stream SHOULD only be allocated resources if all
- of the streams that it depends on (the chain of parent streams up to 0x0) are either
- closed, or it is not possible to make progress on them.
- </t>
- <t>
- A stream cannot depend on itself. An endpoint MUST treat this as a <xref
- target="StreamErrorHandler">stream error</xref> of type <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- </section>
-
- <section title="Dependency Weighting">
- <t>
- All dependent streams are allocated an integer weight between 1 and 256 (inclusive).
- </t>
- <t>
- Streams with the same parent SHOULD be allocated resources proportionally based on their
- weight. Thus, if stream B depends on stream A with weight 4, and C depends on stream A
- with weight 12, and if no progress can be made on A, stream B ideally receives one third
- of the resources allocated to stream C.
- </t>
- </section>
-
- <section anchor="reprioritize" title="Reprioritization">
- <t>
- Stream priorities are changed using the <x:ref>PRIORITY</x:ref> frame. Setting a
- dependency causes a stream to become dependent on the identified parent stream.
- </t>
- <t>
- Dependent streams move with their parent stream if the parent is reprioritized. Setting
- a dependency with the exclusive flag for a reprioritized stream moves all the
- dependencies of the new parent stream to become dependent on the reprioritized stream.
- </t>
- <t>
- If a stream is made dependent on one of its own dependencies, the formerly dependent
- stream is first moved to be dependent on the reprioritized stream's previous parent.
- The moved dependency retains its weight.
- </t>
- <figure title="Example of Dependency Reordering">
- <preamble>
- For example, consider an original dependency tree where B and C depend on A, D and E
- depend on C, and F depends on D. If A is made dependent on D, then D takes the place
- of A. All other dependency relationships stay the same, except for F, which becomes
- dependent on A if the reprioritization is exclusive.
- </preamble>
- <artwork type="inline"><![CDATA[
- ? ? ? ?
- | / \ | |
- A D A D D
- / \ / / \ / \ |
- B C ==> F B C ==> F A OR A
- / \ | / \ /|\
- D E E B C B C F
- | | |
- F E E
- (intermediate) (non-exclusive) (exclusive)
-]]></artwork>
- </figure>
- </section>
-
- <section anchor="priority-gc" title="Prioritization State Management">
- <t>
- When a stream is removed from the dependency tree, its dependencies can be moved to
- become dependent on the parent of the closed stream. The weights of new dependencies
- are recalculated by distributing the weight of the dependency of the closed stream
- proportionally based on the weights of its dependencies.
- </t>
- <t>
- Streams that are removed from the dependency tree cause some prioritization information
- to be lost. Resources are shared between streams with the same parent stream, which
- means that if a stream in that set closes or becomes blocked, any spare capacity
- allocated to a stream is distributed to the immediate neighbors of the stream. However,
- if the common dependency is removed from the tree, those streams share resources with
- streams at the next highest level.
- </t>
- <t>
- For example, assume streams A and B share a parent, and streams C and D both depend on
- stream A. Prior to the removal of stream A, if streams A and D are unable to proceed,
- then stream C receives all the resources dedicated to stream A. If stream A is removed
- from the tree, the weight of stream A is divided between streams C and D. If stream D
- is still unable to proceed, this results in stream C receiving a reduced proportion of
- resources. For equal starting weights, C receives one third, rather than one half, of
- available resources.
- </t>
- <t>
- It is possible for a stream to become closed while prioritization information that
- creates a dependency on that stream is in transit. If a stream identified in a
- dependency has no associated priority information, then the dependent stream is instead
- assigned a <xref target="pri-default">default priority</xref>. This potentially creates
- suboptimal prioritization, since the stream could be given a priority that is different
- to what is intended.
- </t>
- <t>
- To avoid these problems, an endpoint SHOULD retain stream prioritization state for a
- period after streams become closed. The longer state is retained, the lower the chance
- that streams are assigned incorrect or default priority values.
- </t>
- <t>
- This could create a large state burden for an endpoint, so this state MAY be limited.
- An endpoint MAY apply a fixed upper limit on the number of closed streams for which
- prioritization state is tracked to limit state exposure. The amount of additional state
- an endpoint maintains could be dependent on load; under high load, prioritization state
- can be discarded to limit resource commitments. In extreme cases, an endpoint could
- even discard prioritization state for active or reserved streams. If a fixed limit is
- applied, endpoints SHOULD maintain state for at least as many streams as allowed by
- their setting for <x:ref>SETTINGS_MAX_CONCURRENT_STREAMS</x:ref>.
- </t>
- <t>
- An endpoint receiving a <x:ref>PRIORITY</x:ref> frame that changes the priority of a
- closed stream SHOULD alter the dependencies of the streams that depend on it, if it has
- retained enough state to do so.
- </t>
- </section>
-
- <section title="Default Priorities" anchor="pri-default">
- <t>
- Providing priority information is optional. Streams are assigned a non-exclusive
- dependency on stream 0x0 by default. <xref target="PushResources">Pushed streams</xref>
- initially depend on their associated stream. In both cases, streams are assigned a
- default weight of 16.
- </t>
- </section>
- </section>
-
- <section title="Error Handling">
- <t>
- HTTP/2 framing permits two classes of error:
- <list style="symbols">
- <t>
- An error condition that renders the entire connection unusable is a connection error.
- </t>
- <t>
- An error in an individual stream is a stream error.
- </t>
- </list>
- </t>
- <t>
- A list of error codes is included in <xref target="ErrorCodes"/>.
- </t>
-
- <section anchor="ConnectionErrorHandler" title="Connection Error Handling">
- <t>
- A connection error is any error which prevents further processing of the framing layer,
- or which corrupts any connection state.
- </t>
- <t>
- An endpoint that encounters a connection error SHOULD first send a <x:ref>GOAWAY</x:ref>
- frame (<xref target="GOAWAY"/>) with the stream identifier of the last stream that it
- successfully received from its peer. The <x:ref>GOAWAY</x:ref> frame includes an error
- code that indicates why the connection is terminating. After sending the
- <x:ref>GOAWAY</x:ref> frame, the endpoint MUST close the TCP connection.
- </t>
- <t>
- It is possible that the <x:ref>GOAWAY</x:ref> will not be reliably received by the
- receiving endpoint (see <xref target="RFC7230" x:fmt=","
- x:rel="#persistent.tear-down"/>). In the event of a connection error,
- <x:ref>GOAWAY</x:ref> only provides a best effort attempt to communicate with the peer
- about why the connection is being terminated.
- </t>
- <t>
- An endpoint can end a connection at any time. In particular, an endpoint MAY choose to
- treat a stream error as a connection error. Endpoints SHOULD send a
- <x:ref>GOAWAY</x:ref> frame when ending a connection, providing that circumstances
- permit it.
- </t>
- </section>
-
- <section anchor="StreamErrorHandler" title="Stream Error Handling">
- <t>
- A stream error is an error related to a specific stream that does not affect processing
- of other streams.
- </t>
- <t>
- An endpoint that detects a stream error sends a <x:ref>RST_STREAM</x:ref> frame (<xref
- target="RST_STREAM"/>) that contains the stream identifier of the stream where the error
- occurred. The <x:ref>RST_STREAM</x:ref> frame includes an error code that indicates the
- type of error.
- </t>
- <t>
- A <x:ref>RST_STREAM</x:ref> is the last frame that an endpoint can send on a stream.
- The peer that sends the <x:ref>RST_STREAM</x:ref> frame MUST be prepared to receive any
- frames that were sent or enqueued for sending by the remote peer. These frames can be
- ignored, except where they modify connection state (such as the state maintained for
- <xref target="HeaderBlock">header compression</xref>, or flow control).
- </t>
- <t>
- Normally, an endpoint SHOULD NOT send more than one <x:ref>RST_STREAM</x:ref> frame for
- any stream. However, an endpoint MAY send additional <x:ref>RST_STREAM</x:ref> frames if
- it receives frames on a closed stream after more than a round-trip time. This behavior
- is permitted to deal with misbehaving implementations.
- </t>
- <t>
- An endpoint MUST NOT send a <x:ref>RST_STREAM</x:ref> in response to an
- <x:ref>RST_STREAM</x:ref> frame, to avoid looping.
- </t>
- </section>
-
- <section title="Connection Termination">
- <t>
- If the TCP connection is closed or reset while streams remain in open or half closed
- states, then the endpoint MUST assume that those streams were abnormally interrupted and
- could be incomplete.
- </t>
- </section>
- </section>
-
- <section anchor="extensibility" title="Extending HTTP/2">
- <t>
- HTTP/2 permits extension of the protocol. Protocol extensions can be used to provide
- additional services or alter any aspect of the protocol, within the limitations described
- in this section. Extensions are effective only within the scope of a single HTTP/2
- connection.
- </t>
- <t>
- Extensions are permitted to use new <xref target="FrameHeader">frame types</xref>, new
- <xref target="SettingValues">settings</xref>, or new <xref target="ErrorCodes">error
- codes</xref>. Registries are established for managing these extension points: <xref
- target="iana-frames">frame types</xref>, <xref target="iana-settings">settings</xref> and
- <xref target="iana-errors">error codes</xref>.
- </t>
- <t>
- Implementations MUST ignore unknown or unsupported values in all extensible protocol
- elements. Implementations MUST discard frames that have unknown or unsupported types.
- This means that any of these extension points can be safely used by extensions without
- prior arrangement or negotiation. However, extension frames that appear in the middle of
- a <xref target="HeaderBlock">header block</xref> are not permitted; these MUST be treated
- as a <xref target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- <t>
- However, extensions that could change the semantics of existing protocol components MUST
- be negotiated before being used. For example, an extension that changes the layout of the
- <x:ref>HEADERS</x:ref> frame cannot be used until the peer has given a positive signal
- that this is acceptable. In this case, it could also be necessary to coordinate when the
- revised layout comes into effect. Note that treating any frame other than
- <x:ref>DATA</x:ref> frames as flow controlled is such a change in semantics, and can only
- be done through negotiation.
- </t>
- <t>
- This document doesn't mandate a specific method for negotiating the use of an extension,
- but notes that a <xref target="SettingValues">setting</xref> could be used for that
- purpose. If both peers set a value that indicates willingness to use the extension, then
- the extension can be used. If a setting is used for extension negotiation, the initial
- value MUST be defined so that the extension is initially disabled.
- </t>
- </section>
- </section>
-
- <section anchor="FrameTypes" title="Frame Definitions">
- <t>
- This specification defines a number of frame types, each identified by a unique 8-bit type
- code. Each frame type serves a distinct purpose either in the establishment and management
- of the connection as a whole, or of individual streams.
- </t>
- <t>
- The transmission of specific frame types can alter the state of a connection. If endpoints
- fail to maintain a synchronized view of the connection state, successful communication
- within the connection will no longer be possible. Therefore, it is important that endpoints
- have a shared comprehension of how the state is affected by the use any given frame.
- </t>
-
- <section anchor="DATA" title="DATA">
- <t>
- DATA frames (type=0x0) convey arbitrary, variable-length sequences of octets associated
- with a stream. One or more DATA frames are used, for instance, to carry HTTP request or
- response payloads.
- </t>
- <t>
- DATA frames MAY also contain arbitrary padding. Padding can be added to DATA frames to
- obscure the size of messages.
- </t>
- <figure title="DATA Frame Payload">
- <artwork type="inline"><![CDATA[
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |Pad Length? (8)|
- +---------------+-----------------------------------------------+
- | Data (*) ...
- +---------------------------------------------------------------+
- | Padding (*) ...
- +---------------------------------------------------------------+
-]]></artwork>
- </figure>
- <t>
- The DATA frame contains the following fields:
- <list style="hanging">
- <t hangText="Pad Length:">
- An 8-bit field containing the length of the frame padding in units of octets. This
- field is optional and is only present if the PADDED flag is set.
- </t>
- <t hangText="Data:">
- Application data. The amount of data is the remainder of the frame payload after
- subtracting the length of the other fields that are present.
- </t>
- <t hangText="Padding:">
- Padding octets that contain no application semantic value. Padding octets MUST be set
- to zero when sending and ignored when receiving.
- </t>
- </list>
- </t>
-
- <t>
- The DATA frame defines the following flags:
- <list style="hanging">
- <t hangText="END_STREAM (0x1):">
- Bit 1 being set indicates that this frame is the last that the endpoint will send for
- the identified stream. Setting this flag causes the stream to enter one of <xref
- target="StreamStates">the "half closed" states or the "closed" state</xref>.
- </t>
- <t hangText="PADDED (0x8):">
- Bit 4 being set indicates that the Pad Length field and any padding that it describes
- is present.
- </t>
- </list>
- </t>
- <t>
- DATA frames MUST be associated with a stream. If a DATA frame is received whose stream
- identifier field is 0x0, the recipient MUST respond with a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- <t>
- DATA frames are subject to flow control and can only be sent when a stream is in the
- "open" or "half closed (remote)" states. The entire DATA frame payload is included in flow
- control, including Pad Length and Padding fields if present. If a DATA frame is received
- whose stream is not in "open" or "half closed (local)" state, the recipient MUST respond
- with a <xref target="StreamErrorHandler">stream error</xref> of type
- <x:ref>STREAM_CLOSED</x:ref>.
- </t>
- <t>
- The total number of padding octets is determined by the value of the Pad Length field. If
- the length of the padding is greater than the length of the frame payload, the recipient
- MUST treat this as a <xref target="ConnectionErrorHandler">connection error</xref> of
- type <x:ref>PROTOCOL_ERROR</x:ref>.
- <list style="hanging">
- <t hangText="Note:">
- A frame can be increased in size by one octet by including a Pad Length field with a
- value of zero.
- </t>
- </list>
- </t>
- <t>
- Padding is a security feature; see <xref target="padding"/>.
- </t>
- </section>
-
- <section anchor="HEADERS" title="HEADERS">
- <t>
- The HEADERS frame (type=0x1) is used to <xref target="StreamStates">open a stream</xref>,
- and additionally carries a header block fragment. HEADERS frames can be sent on a stream
- in the "open" or "half closed (remote)" states.
- </t>
- <figure title="HEADERS Frame Payload">
- <artwork type="inline"><![CDATA[
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |Pad Length? (8)|
- +-+-------------+-----------------------------------------------+
- |E| Stream Dependency? (31) |
- +-+-------------+-----------------------------------------------+
- | Weight? (8) |
- +-+-------------+-----------------------------------------------+
- | Header Block Fragment (*) ...
- +---------------------------------------------------------------+
- | Padding (*) ...
- +---------------------------------------------------------------+
-]]></artwork>
- </figure>
- <t>
- The HEADERS frame payload has the following fields:
- <list style="hanging">
- <t hangText="Pad Length:">
- An 8-bit field containing the length of the frame padding in units of octets. This
- field is only present if the PADDED flag is set.
- </t>
- <t hangText="E:">
- A single bit flag indicates that the stream dependency is exclusive, see <xref
- target="StreamPriority"/>. This field is only present if the PRIORITY flag is set.
- </t>
- <t hangText="Stream Dependency:">
- A 31-bit stream identifier for the stream that this stream depends on, see <xref
- target="StreamPriority"/>. This field is only present if the PRIORITY flag is set.
- </t>
- <t hangText="Weight:">
- An 8-bit weight for the stream, see <xref target="StreamPriority"/>. Add one to the
- value to obtain a weight between 1 and 256. This field is only present if the
- PRIORITY flag is set.
- </t>
- <t hangText="Header Block Fragment:">
- A <xref target="HeaderBlock">header block fragment</xref>.
- </t>
- <t hangText="Padding:">
- Padding octets that contain no application semantic value. Padding octets MUST be set
- to zero when sending and ignored when receiving.
- </t>
- </list>
- </t>
-
- <t>
- The HEADERS frame defines the following flags:
- <list style="hanging">
- <x:lt hangText="END_STREAM (0x1):">
- <t>
- Bit 1 being set indicates that the <xref target="HeaderBlock">header block</xref> is
- the last that the endpoint will send for the identified stream. Setting this flag
- causes the stream to enter one of <xref target="StreamStates">"half closed"
- states</xref>.
- </t>
- <t>
- A HEADERS frame carries the END_STREAM flag that signals the end of a stream.
- However, a HEADERS frame with the END_STREAM flag set can be followed by
- <x:ref>CONTINUATION</x:ref> frames on the same stream. Logically, the
- <x:ref>CONTINUATION</x:ref> frames are part of the HEADERS frame.
- </t>
- </x:lt>
- <x:lt hangText="END_HEADERS (0x4):">
- <t>
- Bit 3 being set indicates that this frame contains an entire <xref
- target="HeaderBlock">header block</xref> and is not followed by any
- <x:ref>CONTINUATION</x:ref> frames.
- </t>
- <t>
- A HEADERS frame without the END_HEADERS flag set MUST be followed by a
- <x:ref>CONTINUATION</x:ref> frame for the same stream. A receiver MUST treat the
- receipt of any other type of frame or a frame on a different stream as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- </x:lt>
- <x:lt hangText="PADDED (0x8):">
- <t>
- Bit 4 being set indicates that the Pad Length field and any padding that it
- describes is present.
- </t>
- </x:lt>
- <x:lt hangText="PRIORITY (0x20):">
- <t>
- Bit 6 being set indicates that the Exclusive Flag (E), Stream Dependency, and Weight
- fields are present; see <xref target="StreamPriority"/>.
- </t>
- </x:lt>
- </list>
- </t>
-
- <t>
- The payload of a HEADERS frame contains a <xref target="HeaderBlock">header block
- fragment</xref>. A header block that does not fit within a HEADERS frame is continued in
- a <xref target="CONTINUATION">CONTINUATION frame</xref>.
- </t>
-
- <t>
- HEADERS frames MUST be associated with a stream. If a HEADERS frame is received whose
- stream identifier field is 0x0, the recipient MUST respond with a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
-
- <t>
- The HEADERS frame changes the connection state as described in <xref
- target="HeaderBlock"/>.
- </t>
-
- <t>
- The HEADERS frame includes optional padding. Padding fields and flags are identical to
- those defined for <xref target="DATA">DATA frames</xref>.
- </t>
- <t>
- Prioritization information in a HEADERS frame is logically equivalent to a separate
- <x:ref>PRIORITY</x:ref> frame, but inclusion in HEADERS avoids the potential for churn in
- stream prioritization when new streams are created. Priorization fields in HEADERS frames
- subsequent to the first on a stream <xref target="reprioritize">reprioritize the
- stream</xref>.
- </t>
- </section>
-
- <section anchor="PRIORITY" title="PRIORITY">
- <t>
- The PRIORITY frame (type=0x2) specifies the <xref target="StreamPriority">sender-advised
- priority of a stream</xref>. It can be sent at any time for an existing stream, including
- closed streams. This enables reprioritization of existing streams.
- </t>
- <figure title="PRIORITY Frame Payload">
- <artwork type="inline"><![CDATA[
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |E| Stream Dependency (31) |
- +-+-------------+-----------------------------------------------+
- | Weight (8) |
- +-+-------------+
-]]></artwork>
- </figure>
- <t>
- The payload of a PRIORITY frame contains the following fields:
- <list style="hanging">
- <t hangText="E:">
- A single bit flag indicates that the stream dependency is exclusive, see <xref
- target="StreamPriority"/>.
- </t>
- <t hangText="Stream Dependency:">
- A 31-bit stream identifier for the stream that this stream depends on, see <xref
- target="StreamPriority"/>.
- </t>
- <t hangText="Weight:">
- An 8-bit weight for the identified stream dependency, see <xref
- target="StreamPriority"/>. Add one to the value to obtain a weight between 1 and 256.
- </t>
- </list>
- </t>
-
- <t>
- The PRIORITY frame does not define any flags.
- </t>
-
- <t>
- The PRIORITY frame is associated with an existing stream. If a PRIORITY frame is received
- with a stream identifier of 0x0, the recipient MUST respond with a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- <t>
- The PRIORITY frame can be sent on a stream in any of the "reserved (remote)", "open",
- "half closed (local)", "half closed (remote)", or "closed" states, though it cannot be
- sent between consecutive frames that comprise a single <xref target="HeaderBlock">header
- block</xref>. Note that this frame could arrive after processing or frame sending has
- completed, which would cause it to have no effect on the current stream. For a stream
- that is in the "half closed (remote)" or "closed" - state, this frame can only affect
- processing of the current stream and not frame transmission.
- </t>
- <t>
- The PRIORITY frame is the only frame that can be sent for a stream in the "closed" state.
- This allows for the reprioritization of a group of dependent streams by altering the
- priority of a parent stream, which might be closed. However, a PRIORITY frame sent on a
- closed stream risks being ignored due to the peer having discarded priority state
- information for that stream.
- </t>
- </section>
-
- <section anchor="RST_STREAM" title="RST_STREAM">
- <t>
- The RST_STREAM frame (type=0x3) allows for abnormal termination of a stream. When sent by
- the initiator of a stream, it indicates that they wish to cancel the stream or that an
- error condition has occurred. When sent by the receiver of a stream, it indicates that
- either the receiver is rejecting the stream, requesting that the stream be cancelled, or
- that an error condition has occurred.
- </t>
- <figure title="RST_STREAM Frame Payload">
- <artwork type="inline"><![CDATA[
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Error Code (32) |
- +---------------------------------------------------------------+
-]]></artwork>
- </figure>
-
- <t>
- The RST_STREAM frame contains a single unsigned, 32-bit integer identifying the <xref
- target="ErrorCodes">error code</xref>. The error code indicates why the stream is being
- terminated.
- </t>
-
- <t>
- The RST_STREAM frame does not define any flags.
- </t>
-
- <t>
- The RST_STREAM frame fully terminates the referenced stream and causes it to enter the
- closed state. After receiving a RST_STREAM on a stream, the receiver MUST NOT send
- additional frames for that stream, with the exception of <x:ref>PRIORITY</x:ref>. However,
- after sending the RST_STREAM, the sending endpoint MUST be prepared to receive and process
- additional frames sent on the stream that might have been sent by the peer prior to the
- arrival of the RST_STREAM.
- </t>
-
- <t>
- RST_STREAM frames MUST be associated with a stream. If a RST_STREAM frame is received
- with a stream identifier of 0x0, the recipient MUST treat this as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
-
- <t>
- RST_STREAM frames MUST NOT be sent for a stream in the "idle" state. If a RST_STREAM
- frame identifying an idle stream is received, the recipient MUST treat this as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
-
- </section>
-
- <section anchor="SETTINGS" title="SETTINGS">
- <t>
- The SETTINGS frame (type=0x4) conveys configuration parameters that affect how endpoints
- communicate, such as preferences and constraints on peer behavior. The SETTINGS frame is
- also used to acknowledge the receipt of those parameters. Individually, a SETTINGS
- parameter can also be referred to as a "setting".
- </t>
- <t>
- SETTINGS parameters are not negotiated; they describe characteristics of the sending peer,
- which are used by the receiving peer. Different values for the same parameter can be
- advertised by each peer. For example, a client might set a high initial flow control
- window, whereas a server might set a lower value to conserve resources.
- </t>
-
- <t>
- A SETTINGS frame MUST be sent by both endpoints at the start of a connection, and MAY be
- sent at any other time by either endpoint over the lifetime of the connection.
- Implementations MUST support all of the parameters defined by this specification.
- </t>
-
- <t>
- Each parameter in a SETTINGS frame replaces any existing value for that parameter.
- Parameters are processed in the order in which they appear, and a receiver of a SETTINGS
- frame does not need to maintain any state other than the current value of its
- parameters. Therefore, the value of a SETTINGS parameter is the last value that is seen by
- a receiver.
- </t>
- <t>
- SETTINGS parameters are acknowledged by the receiving peer. To enable this, the SETTINGS
- frame defines the following flag:
- <list style="hanging">
- <t hangText="ACK (0x1):">
- Bit 1 being set indicates that this frame acknowledges receipt and application of the
- peer's SETTINGS frame. When this bit is set, the payload of the SETTINGS frame MUST
- be empty. Receipt of a SETTINGS frame with the ACK flag set and a length field value
- other than 0 MUST be treated as a <xref target="ConnectionErrorHandler">connection
- error</xref> of type <x:ref>FRAME_SIZE_ERROR</x:ref>. For more info, see <xref
- target="SettingsSync">Settings Synchronization</xref>.
- </t>
- </list>
- </t>
- <t>
- SETTINGS frames always apply to a connection, never a single stream. The stream
- identifier for a SETTINGS frame MUST be zero (0x0). If an endpoint receives a SETTINGS
- frame whose stream identifier field is anything other than 0x0, the endpoint MUST respond
- with a <xref target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- <t>
- The SETTINGS frame affects connection state. A badly formed or incomplete SETTINGS frame
- MUST be treated as a <xref target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
-
- <section title="SETTINGS Format" anchor="SettingFormat">
- <t>
- The payload of a SETTINGS frame consists of zero or more parameters, each consisting of
- an unsigned 16-bit setting identifier and an unsigned 32-bit value.
- </t>
-
- <figure title="Setting Format">
- <artwork type="inline"><![CDATA[
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Identifier (16) |
- +-------------------------------+-------------------------------+
- | Value (32) |
- +---------------------------------------------------------------+
-]]></artwork>
- </figure>
- </section>
-
- <section anchor="SettingValues" title="Defined SETTINGS Parameters">
- <t>
- The following parameters are defined:
- <list style="hanging">
- <x:lt hangText="SETTINGS_HEADER_TABLE_SIZE (0x1):"
- anchor="SETTINGS_HEADER_TABLE_SIZE">
- <t>
- Allows the sender to inform the remote endpoint of the maximum size of the header
- compression table used to decode header blocks, in octets. The encoder can select
- any size equal to or less than this value by using signaling specific to the
- header compression format inside a header block. The initial value is 4,096
- octets.
- </t>
- </x:lt>
- <x:lt hangText="SETTINGS_ENABLE_PUSH (0x2):"
- anchor="SETTINGS_ENABLE_PUSH">
- <t>
- This setting can be use to disable <xref target="PushResources">server
- push</xref>. An endpoint MUST NOT send a <x:ref>PUSH_PROMISE</x:ref> frame if it
- receives this parameter set to a value of 0. An endpoint that has both set this
- parameter to 0 and had it acknowledged MUST treat the receipt of a
- <x:ref>PUSH_PROMISE</x:ref> frame as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- <t>
- The initial value is 1, which indicates that server push is permitted. Any value
- other than 0 or 1 MUST be treated as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- </x:lt>
- <x:lt hangText="SETTINGS_MAX_CONCURRENT_STREAMS (0x3):"
- anchor="SETTINGS_MAX_CONCURRENT_STREAMS">
- <t>
- Indicates the maximum number of concurrent streams that the sender will allow.
- This limit is directional: it applies to the number of streams that the sender
- permits the receiver to create. Initially there is no limit to this value. It is
- recommended that this value be no smaller than 100, so as to not unnecessarily
- limit parallelism.
- </t>
- <t>
- A value of 0 for SETTINGS_MAX_CONCURRENT_STREAMS SHOULD NOT be treated as special
- by endpoints. A zero value does prevent the creation of new streams, however this
- can also happen for any limit that is exhausted with active streams. Servers
- SHOULD only set a zero value for short durations; if a server does not wish to
- accept requests, closing the connection could be preferable.
- </t>
- </x:lt>
- <x:lt hangText="SETTINGS_INITIAL_WINDOW_SIZE (0x4):"
- anchor="SETTINGS_INITIAL_WINDOW_SIZE">
- <t>
- Indicates the sender's initial window size (in octets) for stream level flow
- control. The initial value is 2<x:sup>16</x:sup>-1 (65,535) octets.
- </t>
- <t>
- This setting affects the window size of all streams, including existing streams,
- see <xref target="InitialWindowSize"/>.
- </t>
- <t>
- Values above the maximum flow control window size of 2<x:sup>31</x:sup>-1 MUST
- be treated as a <xref target="ConnectionErrorHandler">connection error</xref> of
- type <x:ref>FLOW_CONTROL_ERROR</x:ref>.
- </t>
- </x:lt>
- <x:lt hangText="SETTINGS_MAX_FRAME_SIZE (0x5):"
- anchor="SETTINGS_MAX_FRAME_SIZE">
- <t>
- Indicates the size of the largest frame payload that the sender is willing to
- receive, in octets.
- </t>
- <t>
- The initial value is 2<x:sup>14</x:sup> (16,384) octets. The value advertised by
- an endpoint MUST be between this initial value and the maximum allowed frame size
- (2<x:sup>24</x:sup>-1 or 16,777,215 octets), inclusive. Values outside this range
- MUST be treated as a <xref target="ConnectionErrorHandler">connection error</xref>
- of type <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- </x:lt>
- <x:lt hangText="SETTINGS_MAX_HEADER_LIST_SIZE (0x6):"
- anchor="SETTINGS_MAX_HEADER_LIST_SIZE">
- <t>
- This advisory setting informs a peer of the maximum size of header list that the
- sender is prepared to accept, in octets. The value is based on the uncompressed
- size of header fields, including the length of the name and value in octets plus
- an overhead of 32 octets for each header field.
- </t>
- <t>
- For any given request, a lower limit than what is advertised MAY be enforced. The
- initial value of this setting is unlimited.
- </t>
- </x:lt>
- </list>
- </t>
- <t>
- An endpoint that receives a SETTINGS frame with any unknown or unsupported identifier
- MUST ignore that setting.
- </t>
- </section>
-
- <section anchor="SettingsSync" title="Settings Synchronization">
- <t>
- Most values in SETTINGS benefit from or require an understanding of when the peer has
- received and applied the changed parameter values. In order to provide
- such synchronization timepoints, the recipient of a SETTINGS frame in which the ACK flag
- is not set MUST apply the updated parameters as soon as possible upon receipt.
- </t>
- <t>
- The values in the SETTINGS frame MUST be processed in the order they appear, with no
- other frame processing between values. Unsupported parameters MUST be ignored. Once
- all values have been processed, the recipient MUST immediately emit a SETTINGS frame
- with the ACK flag set. Upon receiving a SETTINGS frame with the ACK flag set, the sender
- of the altered parameters can rely on the setting having been applied.
- </t>
- <t>
- If the sender of a SETTINGS frame does not receive an acknowledgement within a
- reasonable amount of time, it MAY issue a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>SETTINGS_TIMEOUT</x:ref>.
- </t>
- </section>
- </section>
-
- <section anchor="PUSH_PROMISE" title="PUSH_PROMISE">
- <t>
- The PUSH_PROMISE frame (type=0x5) is used to notify the peer endpoint in advance of
- streams the sender intends to initiate. The PUSH_PROMISE frame includes the unsigned
- 31-bit identifier of the stream the endpoint plans to create along with a set of headers
- that provide additional context for the stream. <xref target="PushResources"/> contains a
- thorough description of the use of PUSH_PROMISE frames.
- </t>
-
- <figure title="PUSH_PROMISE Payload Format">
- <artwork type="inline"><![CDATA[
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |Pad Length? (8)|
- +-+-------------+-----------------------------------------------+
- |R| Promised Stream ID (31) |
- +-+-----------------------------+-------------------------------+
- | Header Block Fragment (*) ...
- +---------------------------------------------------------------+
- | Padding (*) ...
- +---------------------------------------------------------------+
-]]></artwork>
- </figure>
- <t>
- The PUSH_PROMISE frame payload has the following fields:
- <list style="hanging">
- <t hangText="Pad Length:">
- An 8-bit field containing the length of the frame padding in units of octets. This
- field is only present if the PADDED flag is set.
- </t>
- <t hangText="R:">
- A single reserved bit.
- </t>
- <t hangText="Promised Stream ID:">
- An unsigned 31-bit integer that identifies the stream that is reserved by the
- PUSH_PROMISE. The promised stream identifier MUST be a valid choice for the next
- stream sent by the sender (see <xref target="StreamIdentifiers">new stream
- identifier</xref>).
- </t>
- <t hangText="Header Block Fragment:">
- A <xref target="HeaderBlock">header block fragment</xref> containing request header
- fields.
- </t>
- <t hangText="Padding:">
- Padding octets.
- </t>
- </list>
- </t>
-
- <t>
- The PUSH_PROMISE frame defines the following flags:
- <list style="hanging">
- <x:lt hangText="END_HEADERS (0x4):">
- <t>
- Bit 3 being set indicates that this frame contains an entire <xref
- target="HeaderBlock">header block</xref> and is not followed by any
- <x:ref>CONTINUATION</x:ref> frames.
- </t>
- <t>
- A PUSH_PROMISE frame without the END_HEADERS flag set MUST be followed by a
- CONTINUATION frame for the same stream. A receiver MUST treat the receipt of any
- other type of frame or a frame on a different stream as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- </x:lt>
- <x:lt hangText="PADDED (0x8):">
- <t>
- Bit 4 being set indicates that the Pad Length field and any padding that it
- describes is present.
- </t>
- </x:lt>
- </list>
- </t>
-
- <t>
- PUSH_PROMISE frames MUST be associated with an existing, peer-initiated stream. The stream
- identifier of a PUSH_PROMISE frame indicates the stream it is associated with. If the
- stream identifier field specifies the value 0x0, a recipient MUST respond with a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
-
- <t>
- Promised streams are not required to be used in the order they are promised. The
- PUSH_PROMISE only reserves stream identifiers for later use.
- </t>
-
- <t>
- PUSH_PROMISE MUST NOT be sent if the <x:ref>SETTINGS_ENABLE_PUSH</x:ref> setting of the
- peer endpoint is set to 0. An endpoint that has set this setting and has received
- acknowledgement MUST treat the receipt of a PUSH_PROMISE frame as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- <t>
- Recipients of PUSH_PROMISE frames can choose to reject promised streams by returning a
- <x:ref>RST_STREAM</x:ref> referencing the promised stream identifier back to the sender of
- the PUSH_PROMISE.
- </t>
-
- <t>
- A PUSH_PROMISE frame modifies the connection state in two ways. The inclusion of a <xref
- target="HeaderBlock">header block</xref> potentially modifies the state maintained for
- header compression. PUSH_PROMISE also reserves a stream for later use, causing the
- promised stream to enter the "reserved" state. A sender MUST NOT send a PUSH_PROMISE on a
- stream unless that stream is either "open" or "half closed (remote)"; the sender MUST
- ensure that the promised stream is a valid choice for a <xref
- target="StreamIdentifiers">new stream identifier</xref> (that is, the promised stream MUST
- be in the "idle" state).
- </t>
- <t>
- Since PUSH_PROMISE reserves a stream, ignoring a PUSH_PROMISE frame causes the stream
- state to become indeterminate. A receiver MUST treat the receipt of a PUSH_PROMISE on a
- stream that is neither "open" nor "half closed (local)" as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>. However, an endpoint that has sent
- <x:ref>RST_STREAM</x:ref> on the associated stream MUST handle PUSH_PROMISE frames that
- might have been created before the <x:ref>RST_STREAM</x:ref> frame is received and
- processed.
- </t>
- <t>
- A receiver MUST treat the receipt of a PUSH_PROMISE that promises an <xref
- target="StreamIdentifiers">illegal stream identifier</xref> (that is, an identifier for a
- stream that is not currently in the "idle" state) as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
-
- <t>
- The PUSH_PROMISE frame includes optional padding. Padding fields and flags are identical
- to those defined for <xref target="DATA">DATA frames</xref>.
- </t>
- </section>
-
- <section anchor="PING" title="PING">
- <t>
- The PING frame (type=0x6) is a mechanism for measuring a minimal round trip time from the
- sender, as well as determining whether an idle connection is still functional. PING
- frames can be sent from any endpoint.
- </t>
- <figure title="PING Payload Format">
- <artwork type="inline"><![CDATA[
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | |
- | Opaque Data (64) |
- | |
- +---------------------------------------------------------------+
-]]></artwork>
- </figure>
-
- <t>
- In addition to the frame header, PING frames MUST contain 8 octets of data in the payload.
- A sender can include any value it chooses and use those bytes in any fashion.
- </t>
- <t>
- Receivers of a PING frame that does not include an ACK flag MUST send a PING frame with
- the ACK flag set in response, with an identical payload. PING responses SHOULD be given
- higher priority than any other frame.
- </t>
-
- <t>
- The PING frame defines the following flags:
- <list style="hanging">
- <t hangText="ACK (0x1):">
- Bit 1 being set indicates that this PING frame is a PING response. An endpoint MUST
- set this flag in PING responses. An endpoint MUST NOT respond to PING frames
- containing this flag.
- </t>
- </list>
- </t>
- <t>
- PING frames are not associated with any individual stream. If a PING frame is received
- with a stream identifier field value other than 0x0, the recipient MUST respond with a
- <xref target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- <t>
- Receipt of a PING frame with a length field value other than 8 MUST be treated as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>FRAME_SIZE_ERROR</x:ref>.
- </t>
-
- </section>
-
- <section anchor="GOAWAY" title="GOAWAY">
- <t>
- The GOAWAY frame (type=0x7) informs the remote peer to stop creating streams on this
- connection. GOAWAY can be sent by either the client or the server. Once sent, the sender
- will ignore frames sent on any new streams with identifiers higher than the included last
- stream identifier. Receivers of a GOAWAY frame MUST NOT open additional streams on the
- connection, although a new connection can be established for new streams.
- </t>
- <t>
- The purpose of this frame is to allow an endpoint to gracefully stop accepting new
- streams, while still finishing processing of previously established streams. This enables
- administrative actions, like server maintainance.
- </t>
- <t>
- There is an inherent race condition between an endpoint starting new streams and the
- remote sending a GOAWAY frame. To deal with this case, the GOAWAY contains the stream
- identifier of the last peer-initiated stream which was or might be processed on the
- sending endpoint in this connection. For instance, if the server sends a GOAWAY frame,
- the identified stream is the highest numbered stream initiated by the client.
- </t>
- <t>
- If the receiver of the GOAWAY has sent data on streams with a higher stream identifier
- than what is indicated in the GOAWAY frame, those streams are not or will not be
- processed. The receiver of the GOAWAY frame can treat the streams as though they had
- never been created at all, thereby allowing those streams to be retried later on a new
- connection.
- </t>
- <t>
- Endpoints SHOULD always send a GOAWAY frame before closing a connection so that the remote
- can know whether a stream has been partially processed or not. For example, if an HTTP
- client sends a POST at the same time that a server closes a connection, the client cannot
- know if the server started to process that POST request if the server does not send a
- GOAWAY frame to indicate what streams it might have acted on.
- </t>
- <t>
- An endpoint might choose to close a connection without sending GOAWAY for misbehaving
- peers.
- </t>
-
- <figure title="GOAWAY Payload Format">
- <artwork type="inline"><![CDATA[
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |R| Last-Stream-ID (31) |
- +-+-------------------------------------------------------------+
- | Error Code (32) |
- +---------------------------------------------------------------+
- | Additional Debug Data (*) |
- +---------------------------------------------------------------+
-]]></artwork>
- </figure>
- <t>
- The GOAWAY frame does not define any flags.
- </t>
- <t>
- The GOAWAY frame applies to the connection, not a specific stream. An endpoint MUST treat
- a <x:ref>GOAWAY</x:ref> frame with a stream identifier other than 0x0 as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- <t>
- The last stream identifier in the GOAWAY frame contains the highest numbered stream
- identifier for which the sender of the GOAWAY frame might have taken some action on, or
- might yet take action on. All streams up to and including the identified stream might
- have been processed in some way. The last stream identifier can be set to 0 if no streams
- were processed.
- <list style="hanging">
- <t hangText="Note:">
- In this context, "processed" means that some data from the stream was passed to some
- higher layer of software that might have taken some action as a result.
- </t>
- </list>
- If a connection terminates without a GOAWAY frame, the last stream identifier is
- effectively the highest possible stream identifier.
- </t>
- <t>
- On streams with lower or equal numbered identifiers that were not closed completely prior
- to the connection being closed, re-attempting requests, transactions, or any protocol
- activity is not possible, with the exception of idempotent actions like HTTP GET, PUT, or
- DELETE. Any protocol activity that uses higher numbered streams can be safely retried
- using a new connection.
- </t>
- <t>
- Activity on streams numbered lower or equal to the last stream identifier might still
- complete successfully. The sender of a GOAWAY frame might gracefully shut down a
- connection by sending a GOAWAY frame, maintaining the connection in an open state until
- all in-progress streams complete.
- </t>
- <t>
- An endpoint MAY send multiple GOAWAY frames if circumstances change. For instance, an
- endpoint that sends GOAWAY with <x:ref>NO_ERROR</x:ref> during graceful shutdown could
- subsequently encounter an condition that requires immediate termination of the connection.
- The last stream identifier from the last GOAWAY frame received indicates which streams
- could have been acted upon. Endpoints MUST NOT increase the value they send in the last
- stream identifier, since the peers might already have retried unprocessed requests on
- another connection.
- </t>
- <t>
- A client that is unable to retry requests loses all requests that are in flight when the
- server closes the connection. This is especially true for intermediaries that might
- not be serving clients using HTTP/2. A server that is attempting to gracefully shut down
- a connection SHOULD send an initial GOAWAY frame with the last stream identifier set to
- 2<x:sup>31</x:sup>-1 and a <x:ref>NO_ERROR</x:ref> code. This signals to the client that
- a shutdown is imminent and that no further requests can be initiated. After waiting at
- least one round trip time, the server can send another GOAWAY frame with an updated last
- stream identifier. This ensures that a connection can be cleanly shut down without losing
- requests.
- </t>
-
- <t>
- After sending a GOAWAY frame, the sender can discard frames for streams with identifiers
- higher than the identified last stream. However, any frames that alter connection state
- cannot be completely ignored. For instance, <x:ref>HEADERS</x:ref>,
- <x:ref>PUSH_PROMISE</x:ref> and <x:ref>CONTINUATION</x:ref> frames MUST be minimally
- processed to ensure the state maintained for header compression is consistent (see <xref
- target="HeaderBlock"/>); similarly DATA frames MUST be counted toward the connection flow
- control window. Failure to process these frames can cause flow control or header
- compression state to become unsynchronized.
- </t>
-
- <t>
- The GOAWAY frame also contains a 32-bit <xref target="ErrorCodes">error code</xref> that
- contains the reason for closing the connection.
- </t>
- <t>
- Endpoints MAY append opaque data to the payload of any GOAWAY frame. Additional debug
- data is intended for diagnostic purposes only and carries no semantic value. Debug
- information could contain security- or privacy-sensitive data. Logged or otherwise
- persistently stored debug data MUST have adequate safeguards to prevent unauthorized
- access.
- </t>
- </section>
-
- <section anchor="WINDOW_UPDATE" title="WINDOW_UPDATE">
- <t>
- The WINDOW_UPDATE frame (type=0x8) is used to implement flow control; see <xref
- target="FlowControl"/> for an overview.
- </t>
- <t>
- Flow control operates at two levels: on each individual stream and on the entire
- connection.
- </t>
- <t>
- Both types of flow control are hop-by-hop; that is, only between the two endpoints.
- Intermediaries do not forward WINDOW_UPDATE frames between dependent connections.
- However, throttling of data transfer by any receiver can indirectly cause the propagation
- of flow control information toward the original sender.
- </t>
- <t>
- Flow control only applies to frames that are identified as being subject to flow control.
- Of the frame types defined in this document, this includes only <x:ref>DATA</x:ref> frames.
- Frames that are exempt from flow control MUST be accepted and processed, unless the
- receiver is unable to assign resources to handling the frame. A receiver MAY respond with
- a <xref target="StreamErrorHandler">stream error</xref> or <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>FLOW_CONTROL_ERROR</x:ref> if it is unable to accept a frame.
- </t>
- <figure title="WINDOW_UPDATE Payload Format">
- <artwork type="inline"><![CDATA[
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |R| Window Size Increment (31) |
- +-+-------------------------------------------------------------+
-]]></artwork>
- </figure>
- <t>
- The payload of a WINDOW_UPDATE frame is one reserved bit, plus an unsigned 31-bit integer
- indicating the number of octets that the sender can transmit in addition to the existing
- flow control window. The legal range for the increment to the flow control window is 1 to
- 2<x:sup>31</x:sup>-1 (0x7fffffff) octets.
- </t>
- <t>
- The WINDOW_UPDATE frame does not define any flags.
- </t>
- <t>
- The WINDOW_UPDATE frame can be specific to a stream or to the entire connection. In the
- former case, the frame's stream identifier indicates the affected stream; in the latter,
- the value "0" indicates that the entire connection is the subject of the frame.
- </t>
- <t>
- A receiver MUST treat the receipt of a WINDOW_UPDATE frame with an flow control window
- increment of 0 as a <xref target="StreamErrorHandler">stream error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>; errors on the connection flow control window MUST be
- treated as a <xref target="ConnectionErrorHandler">connection error</xref>.
- </t>
- <t>
- WINDOW_UPDATE can be sent by a peer that has sent a frame bearing the END_STREAM flag.
- This means that a receiver could receive a WINDOW_UPDATE frame on a "half closed (remote)"
- or "closed" stream. A receiver MUST NOT treat this as an error, see <xref
- target="StreamStates"/>.
- </t>
- <t>
- A receiver that receives a flow controlled frame MUST always account for its contribution
- against the connection flow control window, unless the receiver treats this as a <xref
- target="ConnectionErrorHandler">connection error</xref>. This is necessary even if the
- frame is in error. Since the sender counts the frame toward the flow control window, if
- the receiver does not, the flow control window at sender and receiver can become
- different.
- </t>
-
- <section title="The Flow Control Window">
- <t>
- Flow control in HTTP/2 is implemented using a window kept by each sender on every
- stream. The flow control window is a simple integer value that indicates how many octets
- of data the sender is permitted to transmit; as such, its size is a measure of the
- buffering capacity of the receiver.
- </t>
- <t>
- Two flow control windows are applicable: the stream flow control window and the
- connection flow control window. The sender MUST NOT send a flow controlled frame with a
- length that exceeds the space available in either of the flow control windows advertised
- by the receiver. Frames with zero length with the END_STREAM flag set (that is, an
- empty <x:ref>DATA</x:ref> frame) MAY be sent if there is no available space in either
- flow control window.
- </t>
- <t>
- For flow control calculations, the 9 octet frame header is not counted.
- </t>
- <t>
- After sending a flow controlled frame, the sender reduces the space available in both
- windows by the length of the transmitted frame.
- </t>
- <t>
- The receiver of a frame sends a WINDOW_UPDATE frame as it consumes data and frees up
- space in flow control windows. Separate WINDOW_UPDATE frames are sent for the stream
- and connection level flow control windows.
- </t>
- <t>
- A sender that receives a WINDOW_UPDATE frame updates the corresponding window by the
- amount specified in the frame.
- </t>
- <t>
- A sender MUST NOT allow a flow control window to exceed 2<x:sup>31</x:sup>-1 octets.
- If a sender receives a WINDOW_UPDATE that causes a flow control window to exceed this
- maximum it MUST terminate either the stream or the connection, as appropriate. For
- streams, the sender sends a <x:ref>RST_STREAM</x:ref> with the error code of
- <x:ref>FLOW_CONTROL_ERROR</x:ref> code; for the connection, a <x:ref>GOAWAY</x:ref>
- frame with a <x:ref>FLOW_CONTROL_ERROR</x:ref> code.
- </t>
- <t>
- Flow controlled frames from the sender and WINDOW_UPDATE frames from the receiver are
- completely asynchronous with respect to each other. This property allows a receiver to
- aggressively update the window size kept by the sender to prevent streams from stalling.
- </t>
- </section>
-
- <section anchor="InitialWindowSize" title="Initial Flow Control Window Size">
- <t>
- When an HTTP/2 connection is first established, new streams are created with an initial
- flow control window size of 65,535 octets. The connection flow control window is 65,535
- octets. Both endpoints can adjust the initial window size for new streams by including
- a value for <x:ref>SETTINGS_INITIAL_WINDOW_SIZE</x:ref> in the <x:ref>SETTINGS</x:ref>
- frame that forms part of the connection preface. The connection flow control window can
- only be changed using WINDOW_UPDATE frames.
- </t>
- <t>
- Prior to receiving a <x:ref>SETTINGS</x:ref> frame that sets a value for
- <x:ref>SETTINGS_INITIAL_WINDOW_SIZE</x:ref>, an endpoint can only use the default
- initial window size when sending flow controlled frames. Similarly, the connection flow
- control window is set to the default initial window size until a WINDOW_UPDATE frame is
- received.
- </t>
- <t>
- A <x:ref>SETTINGS</x:ref> frame can alter the initial flow control window size for all
- current streams. When the value of <x:ref>SETTINGS_INITIAL_WINDOW_SIZE</x:ref> changes,
- a receiver MUST adjust the size of all stream flow control windows that it maintains by
- the difference between the new value and the old value.
- </t>
- <t>
- A change to <x:ref>SETTINGS_INITIAL_WINDOW_SIZE</x:ref> can cause the available space in
- a flow control window to become negative. A sender MUST track the negative flow control
- window, and MUST NOT send new flow controlled frames until it receives WINDOW_UPDATE
- frames that cause the flow control window to become positive.
- </t>
- <t>
- For example, if the client sends 60KB immediately on connection establishment, and the
- server sets the initial window size to be 16KB, the client will recalculate the
- available flow control window to be -44KB on receipt of the <x:ref>SETTINGS</x:ref>
- frame. The client retains a negative flow control window until WINDOW_UPDATE frames
- restore the window to being positive, after which the client can resume sending.
- </t>
- <t>
- A <x:ref>SETTINGS</x:ref> frame cannot alter the connection flow control window.
- </t>
- <t>
- An endpoint MUST treat a change to <x:ref>SETTINGS_INITIAL_WINDOW_SIZE</x:ref> that
- causes any flow control window to exceed the maximum size as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>FLOW_CONTROL_ERROR</x:ref>.
- </t>
- </section>
-
- <section title="Reducing the Stream Window Size">
- <t>
- A receiver that wishes to use a smaller flow control window than the current size can
- send a new <x:ref>SETTINGS</x:ref> frame. However, the receiver MUST be prepared to
- receive data that exceeds this window size, since the sender might send data that
- exceeds the lower limit prior to processing the <x:ref>SETTINGS</x:ref> frame.
- </t>
- <t>
- After sending a SETTINGS frame that reduces the initial flow control window size, a
- receiver has two options for handling streams that exceed flow control limits:
- <list style="numbers">
- <t>
- The receiver can immediately send <x:ref>RST_STREAM</x:ref> with
- <x:ref>FLOW_CONTROL_ERROR</x:ref> error code for the affected streams.
- </t>
- <t>
- The receiver can accept the streams and tolerate the resulting head of line
- blocking, sending WINDOW_UPDATE frames as it consumes data.
- </t>
- </list>
- </t>
- </section>
- </section>
-
- <section anchor="CONTINUATION" title="CONTINUATION">
- <t>
- The CONTINUATION frame (type=0x9) is used to continue a sequence of <xref
- target="HeaderBlock">header block fragments</xref>. Any number of CONTINUATION frames can
- be sent on an existing stream, as long as the preceding frame is on the same stream and is
- a <x:ref>HEADERS</x:ref>, <x:ref>PUSH_PROMISE</x:ref> or CONTINUATION frame without the
- END_HEADERS flag set.
- </t>
-
- <figure title="CONTINUATION Frame Payload">
- <artwork type="inline"><![CDATA[
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Header Block Fragment (*) ...
- +---------------------------------------------------------------+
-]]></artwork>
- </figure>
- <t>
- The CONTINUATION frame payload contains a <xref target="HeaderBlock">header block
- fragment</xref>.
- </t>
-
- <t>
- The CONTINUATION frame defines the following flag:
- <list style="hanging">
- <x:lt hangText="END_HEADERS (0x4):">
- <t>
- Bit 3 being set indicates that this frame ends a <xref target="HeaderBlock">header
- block</xref>.
- </t>
- <t>
- If the END_HEADERS bit is not set, this frame MUST be followed by another
- CONTINUATION frame. A receiver MUST treat the receipt of any other type of frame or
- a frame on a different stream as a <xref target="ConnectionErrorHandler">connection
- error</xref> of type <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- </x:lt>
- </list>
- </t>
-
- <t>
- The CONTINUATION frame changes the connection state as defined in <xref
- target="HeaderBlock" />.
- </t>
-
- <t>
- CONTINUATION frames MUST be associated with a stream. If a CONTINUATION frame is received
- whose stream identifier field is 0x0, the recipient MUST respond with a <xref
- target="ConnectionErrorHandler">connection error</xref> of type PROTOCOL_ERROR.
- </t>
-
- <t>
- A CONTINUATION frame MUST be preceded by a <x:ref>HEADERS</x:ref>,
- <x:ref>PUSH_PROMISE</x:ref> or CONTINUATION frame without the END_HEADERS flag set. A
- recipient that observes violation of this rule MUST respond with a <xref
- target="ConnectionErrorHandler"> connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- </section>
- </section>
-
- <section anchor="ErrorCodes" title="Error Codes">
- <t>
- Error codes are 32-bit fields that are used in <x:ref>RST_STREAM</x:ref> and
- <x:ref>GOAWAY</x:ref> frames to convey the reasons for the stream or connection error.
- </t>
-
- <t>
- Error codes share a common code space. Some error codes apply only to either streams or the
- entire connection and have no defined semantics in the other context.
- </t>
-
- <t>
- The following error codes are defined:
- <list style="hanging">
- <t hangText="NO_ERROR (0x0):" anchor="NO_ERROR">
- The associated condition is not as a result of an error. For example, a
- <x:ref>GOAWAY</x:ref> might include this code to indicate graceful shutdown of a
- connection.
- </t>
- <t hangText="PROTOCOL_ERROR (0x1):" anchor="PROTOCOL_ERROR">
- The endpoint detected an unspecific protocol error. This error is for use when a more
- specific error code is not available.
- </t>
- <t hangText="INTERNAL_ERROR (0x2):" anchor="INTERNAL_ERROR">
- The endpoint encountered an unexpected internal error.
- </t>
- <t hangText="FLOW_CONTROL_ERROR (0x3):" anchor="FLOW_CONTROL_ERROR">
- The endpoint detected that its peer violated the flow control protocol.
- </t>
- <t hangText="SETTINGS_TIMEOUT (0x4):" anchor="SETTINGS_TIMEOUT">
- The endpoint sent a <x:ref>SETTINGS</x:ref> frame, but did not receive a response in a
- timely manner. See <xref target="SettingsSync">Settings Synchronization</xref>.
- </t>
- <t hangText="STREAM_CLOSED (0x5):" anchor="STREAM_CLOSED">
- The endpoint received a frame after a stream was half closed.
- </t>
- <t hangText="FRAME_SIZE_ERROR (0x6):" anchor="FRAME_SIZE_ERROR">
- The endpoint received a frame with an invalid size.
- </t>
- <t hangText="REFUSED_STREAM (0x7):" anchor="REFUSED_STREAM">
- The endpoint refuses the stream prior to performing any application processing, see
- <xref target="Reliability"/> for details.
- </t>
- <t hangText="CANCEL (0x8):" anchor="CANCEL">
- Used by the endpoint to indicate that the stream is no longer needed.
- </t>
- <t hangText="COMPRESSION_ERROR (0x9):" anchor="COMPRESSION_ERROR">
- The endpoint is unable to maintain the header compression context for the connection.
- </t>
- <t hangText="CONNECT_ERROR (0xa):" anchor="CONNECT_ERROR">
- The connection established in response to a <xref target="CONNECT">CONNECT
- request</xref> was reset or abnormally closed.
- </t>
- <t hangText="ENHANCE_YOUR_CALM (0xb):" anchor="ENHANCE_YOUR_CALM">
- The endpoint detected that its peer is exhibiting a behavior that might be generating
- excessive load.
- </t>
- <t hangText="INADEQUATE_SECURITY (0xc):" anchor="INADEQUATE_SECURITY">
- The underlying transport has properties that do not meet minimum security
- requirements (see <xref target="TLSUsage"/>).
- </t>
- </list>
- </t>
- <t>
- Unknown or unsupported error codes MUST NOT trigger any special behavior. These MAY be
- treated by an implementation as being equivalent to <x:ref>INTERNAL_ERROR</x:ref>.
- </t>
- </section>
-
- <section anchor="HTTPLayer" title="HTTP Message Exchanges">
- <t>
- HTTP/2 is intended to be as compatible as possible with current uses of HTTP. This means
- that, from the application perspective, the features of the protocol are largely
- unchanged. To achieve this, all request and response semantics are preserved, although the
- syntax of conveying those semantics has changed.
- </t>
- <t>
- Thus, the specification and requirements of HTTP/1.1 Semantics and Content <xref
- target="RFC7231"/>, Conditional Requests <xref target="RFC7232"/>, Range Requests <xref
- target="RFC7233"/>, Caching <xref target="RFC7234"/> and Authentication <xref
- target="RFC7235"/> are applicable to HTTP/2. Selected portions of HTTP/1.1 Message Syntax
- and Routing <xref target="RFC7230"/>, such as the HTTP and HTTPS URI schemes, are also
- applicable in HTTP/2, but the expression of those semantics for this protocol are defined
- in the sections below.
- </t>
-
- <section anchor="HttpSequence" title="HTTP Request/Response Exchange">
- <t>
- A client sends an HTTP request on a new stream, using a previously unused <xref
- target="StreamIdentifiers">stream identifier</xref>. A server sends an HTTP response on
- the same stream as the request.
- </t>
- <t>
- An HTTP message (request or response) consists of:
- <list style="numbers">
- <t>
- for a response only, zero or more <x:ref>HEADERS</x:ref> frames (each followed by zero
- or more <x:ref>CONTINUATION</x:ref> frames) containing the message headers of
- informational (1xx) HTTP responses (see <xref target="RFC7230" x:fmt=","
- x:rel="#header.fields"/> and <xref target="RFC7231" x:fmt="," x:rel="#status.1xx"/>),
- and
- </t>
- <t>
- one <x:ref>HEADERS</x:ref> frame (followed by zero or more <x:ref>CONTINUATION</x:ref>
- frames) containing the message headers (see <xref target="RFC7230" x:fmt=","
- x:rel="#header.fields"/>), and
- </t>
- <t>
- zero or more <x:ref>DATA</x:ref> frames containing the message payload (see <xref
- target="RFC7230" x:fmt="," x:rel="#message.body"/>), and
- </t>
- <t>
- optionally, one <x:ref>HEADERS</x:ref> frame, followed by zero or more
- <x:ref>CONTINUATION</x:ref> frames containing the trailer-part, if present (see <xref
- target="RFC7230" x:fmt="," x:rel="#chunked.trailer.part"/>).
- </t>
- </list>
- The last frame in the sequence bears an END_STREAM flag, noting that a
- <x:ref>HEADERS</x:ref> frame bearing the END_STREAM flag can be followed by
- <x:ref>CONTINUATION</x:ref> frames that carry any remaining portions of the header block.
- </t>
- <t>
- Other frames (from any stream) MUST NOT occur between either <x:ref>HEADERS</x:ref> frame
- and any <x:ref>CONTINUATION</x:ref> frames that might follow.
- </t>
-
- <t>
- Trailing header fields are carried in a header block that also terminates the stream.
- That is, a sequence starting with a <x:ref>HEADERS</x:ref> frame, followed by zero or more
- <x:ref>CONTINUATION</x:ref> frames, where the <x:ref>HEADERS</x:ref> frame bears an
- END_STREAM flag. Header blocks after the first that do not terminate the stream are not
- part of an HTTP request or response.
- </t>
- <t>
- A <x:ref>HEADERS</x:ref> frame (and associated <x:ref>CONTINUATION</x:ref> frames) can
- only appear at the start or end of a stream. An endpoint that receives a
- <x:ref>HEADERS</x:ref> frame without the END_STREAM flag set after receiving a final
- (non-informational) status code MUST treat the corresponding request or response as <xref
- target="malformed">malformed</xref>.
- </t>
-
- <t>
- An HTTP request/response exchange fully consumes a single stream. A request starts with
- the <x:ref>HEADERS</x:ref> frame that puts the stream into an "open" state. The request
- ends with a frame bearing END_STREAM, which causes the stream to become "half closed
- (local)" for the client and "half closed (remote)" for the server. A response starts with
- a <x:ref>HEADERS</x:ref> frame and ends with a frame bearing END_STREAM, which places the
- stream in the "closed" state.
- <!-- Yes, the response might be completed before the request does, but that's not a detail
- we need to expand upon. It's complicated enough explaining this as it is. -->
- </t>
-
- <section anchor="informational-responses" title="Upgrading From HTTP/2">
- <t>
- HTTP/2 removes support for the 101 (Switching Protocols) informational status code
- (<xref target="RFC7231" x:fmt="," x:rel="#status.101"/>).
- </t>
- <t>
- The semantics of 101 (Switching Protocols) aren't applicable to a multiplexed protocol.
- Alternative protocols are able to use the same mechanisms that HTTP/2 uses to negotiate
- their use (see <xref target="starting"/>).
- </t>
- </section>
-
- <section anchor="HttpHeaders" title="HTTP Header Fields">
- <t>
- HTTP header fields carry information as a series of key-value pairs. For a listing of
- registered HTTP headers, see the Message Header Field Registry maintained at <eref
- target="https://www.iana.org/assignments/message-headers"/>.
- </t>
-
- <section anchor="PseudoHeaderFields" title="Pseudo-Header Fields">
- <t>
- While HTTP/1.x used the message start-line (see <xref target="RFC7230" x:fmt=","
- x:rel="#start.line"/>) to convey the target URI and method of the request, and the
- status code for the response, HTTP/2 uses special pseudo-header fields beginning with
- ':' character (ASCII 0x3a) for this purpose.
- </t>
- <t>
- Pseudo-header fields are not HTTP header fields. Endpoints MUST NOT generate
- pseudo-header fields other than those defined in this document.
- </t>
- <t>
- Pseudo-header fields are only valid in the context in which they are defined.
- Pseudo-header fields defined for requests MUST NOT appear in responses; pseudo-header
- fields defined for responses MUST NOT appear in requests. Pseudo-header fields MUST
- NOT appear in trailers. Endpoints MUST treat a request or response that contains
- undefined or invalid pseudo-header fields as <xref
- target="malformed">malformed</xref>.
- </t>
- <t>
- Just as in HTTP/1.x, header field names are strings of ASCII characters that are
- compared in a case-insensitive fashion. However, header field names MUST be converted
- to lowercase prior to their encoding in HTTP/2. A request or response containing
- uppercase header field names MUST be treated as <xref
- target="malformed">malformed</xref>.
- </t>
- <t>
- All pseudo-header fields MUST appear in the header block before regular header fields.
- Any request or response that contains a pseudo-header field that appears in a header
- block after a regular header field MUST be treated as <xref
- target="malformed">malformed</xref>.
- </t>
- </section>
-
- <section title="Connection-Specific Header Fields">
- <t>
- HTTP/2 does not use the <spanx style="verb">Connection</spanx> header field to
- indicate connection-specific header fields; in this protocol, connection-specific
- metadata is conveyed by other means. An endpoint MUST NOT generate a HTTP/2 message
- containing connection-specific header fields; any message containing
- connection-specific header fields MUST be treated as <xref
- target="malformed">malformed</xref>.
- </t>
- <t>
- This means that an intermediary transforming an HTTP/1.x message to HTTP/2 will need
- to remove any header fields nominated by the Connection header field, along with the
- Connection header field itself. Such intermediaries SHOULD also remove other
- connection-specific header fields, such as Keep-Alive, Proxy-Connection,
- Transfer-Encoding and Upgrade, even if they are not nominated by Connection.
- </t>
- <t>
- One exception to this is the TE header field, which MAY be present in an HTTP/2
- request, but when it is MUST NOT contain any value other than "trailers".
- </t>
- <t>
- <list style="hanging">
- <t hangText="Note:">
- HTTP/2 purposefully does not support upgrade to another protocol. The handshake
- methods described in <xref target="starting"/> are believed sufficient to
- negotiate the use of alternative protocols.
- </t>
- </list>
- </t>
- </section>
-
- <section anchor="HttpRequest" title="Request Pseudo-Header Fields">
- <t>
- The following pseudo-header fields are defined for HTTP/2 requests:
- <list style="symbols">
- <x:lt>
- <t>
- The <spanx style="verb">:method</spanx> pseudo-header field includes the HTTP
- method (<xref target="RFC7231" x:fmt="," x:rel="#methods"/>).
- </t>
- </x:lt>
- <x:lt>
- <t>
- The <spanx style="verb">:scheme</spanx> pseudo-header field includes the scheme
- portion of the target URI (<xref target="RFC3986" x:fmt="," x:sec="3.1"/>).
- </t>
- <t>
- <spanx style="verb">:scheme</spanx> is not restricted to <spanx
- style="verb">http</spanx> and <spanx style="verb">https</spanx> schemed URIs. A
- proxy or gateway can translate requests for non-HTTP schemes, enabling the use
- of HTTP to interact with non-HTTP services.
- </t>
- </x:lt>
- <x:lt>
- <t>
- The <spanx style="verb">:authority</spanx> pseudo-header field includes the
- authority portion of the target URI (<xref target="RFC3986" x:fmt=","
- x:sec="3.2"/>). The authority MUST NOT include the deprecated <spanx
- style="verb">userinfo</spanx> subcomponent for <spanx style="verb">http</spanx>
- or <spanx style="verb">https</spanx> schemed URIs.
- </t>
- <t>
- To ensure that the HTTP/1.1 request line can be reproduced accurately, this
- pseudo-header field MUST be omitted when translating from an HTTP/1.1 request
- that has a request target in origin or asterisk form (see <xref
- target="RFC7230" x:fmt="," x:rel="#request-target"/>). Clients that generate
- HTTP/2 requests directly SHOULD use the <spanx>:authority</spanx> pseudo-header
- field instead of the <spanx style="verb">Host</spanx> header field. An
- intermediary that converts an HTTP/2 request to HTTP/1.1 MUST create a <spanx
- style="verb">Host</spanx> header field if one is not present in a request by
- copying the value of the <spanx style="verb">:authority</spanx> pseudo-header
- field.
- </t>
- </x:lt>
- <x:lt>
- <t>
- The <spanx style="verb">:path</spanx> pseudo-header field includes the path and
- query parts of the target URI (the <spanx style="verb">path-absolute</spanx>
- production from <xref target="RFC3986"/> and optionally a '?' character
- followed by the <spanx style="verb">query</spanx> production, see <xref
- target="RFC3986" x:fmt="," x:sec="3.3"/> and <xref target="RFC3986" x:fmt=","
- x:sec="3.4"/>). A request in asterisk form includes the value '*' for the
- <spanx style="verb">:path</spanx> pseudo-header field.
- </t>
- <t>
- This pseudo-header field MUST NOT be empty for <spanx style="verb">http</spanx>
- or <spanx style="verb">https</spanx> URIs; <spanx style="verb">http</spanx> or
- <spanx style="verb">https</spanx> URIs that do not contain a path component
- MUST include a value of '/'. The exception to this rule is an OPTIONS request
- for an <spanx style="verb">http</spanx> or <spanx style="verb">https</spanx>
- URI that does not include a path component; these MUST include a <spanx
- style="verb">:path</spanx> pseudo-header field with a value of '*' (see <xref
- target="RFC7230" x:fmt="," x:rel="#asterisk-form"/>).
- </t>
- </x:lt>
- </list>
- </t>
- <t>
- All HTTP/2 requests MUST include exactly one valid value for the <spanx
- style="verb">:method</spanx>, <spanx style="verb">:scheme</spanx>, and <spanx
- style="verb">:path</spanx> pseudo-header fields, unless it is a <xref
- target="CONNECT">CONNECT request</xref>. An HTTP request that omits mandatory
- pseudo-header fields is <xref target="malformed">malformed</xref>.
- </t>
- <t>
- HTTP/2 does not define a way to carry the version identifier that is included in the
- HTTP/1.1 request line.
- </t>
- </section>
-
- <section anchor="HttpResponse" title="Response Pseudo-Header Fields">
- <t>
- For HTTP/2 responses, a single <spanx style="verb">:status</spanx> pseudo-header
- field is defined that carries the HTTP status code field (see <xref target="RFC7231"
- x:fmt="," x:rel="#status.codes"/>). This pseudo-header field MUST be included in all
- responses, otherwise the response is <xref target="malformed">malformed</xref>.
- </t>
- <t>
- HTTP/2 does not define a way to carry the version or reason phrase that is included in
- an HTTP/1.1 status line.
- </t>
- </section>
-
- <section anchor="CompressCookie" title="Compressing the Cookie Header Field">
- <t>
- The <xref target="COOKIE">Cookie header field</xref> can carry a significant amount of
- redundant data.
- </t>
- <t>
- The Cookie header field uses a semi-colon (";") to delimit cookie-pairs (or "crumbs").
- This header field doesn't follow the list construction rules in HTTP (see <xref
- target="RFC7230" x:fmt="," x:rel="#field.order"/>), which prevents cookie-pairs from
- being separated into different name-value pairs. This can significantly reduce
- compression efficiency as individual cookie-pairs are updated.
- </t>
- <t>
- To allow for better compression efficiency, the Cookie header field MAY be split into
- separate header fields, each with one or more cookie-pairs. If there are multiple
- Cookie header fields after decompression, these MUST be concatenated into a single
- octet string using the two octet delimiter of 0x3B, 0x20 (the ASCII string "; ")
- before being passed into a non-HTTP/2 context, such as an HTTP/1.1 connection, or a
- generic HTTP server application.
- </t>
- <figure>
- <preamble>
- Therefore, the following two lists of Cookie header fields are semantically
- equivalent.
- </preamble>
- <artwork type="inline"><![CDATA[
- cookie: a=b; c=d; e=f
-
- cookie: a=b
- cookie: c=d
- cookie: e=f
-]]></artwork>
- </figure>
- </section>
-
- <section anchor="malformed" title="Malformed Requests and Responses">
- <t>
- A malformed request or response is one that is an otherwise valid sequence of HTTP/2
- frames, but is otherwise invalid due to the presence of extraneous frames, prohibited
- header fields, the absence of mandatory header fields, or the inclusion of uppercase
- header field names.
- </t>
- <t>
- A request or response that includes an entity body can include a <spanx
- style="verb">content-length</spanx> header field. A request or response is also
- malformed if the value of a <spanx style="verb">content-length</spanx> header field
- does not equal the sum of the <x:ref>DATA</x:ref> frame payload lengths that form the
- body. A response that is defined to have no payload, as described in <xref
- target="RFC7230" x:fmt="," x:rel="#header.content-length"/>, can have a non-zero
- <spanx style="verb">content-length</spanx> header field, even though no content is
- included in <x:ref>DATA</x:ref> frames.
- </t>
- <t>
- Intermediaries that process HTTP requests or responses (i.e., any intermediary not
- acting as a tunnel) MUST NOT forward a malformed request or response. Malformed
- requests or responses that are detected MUST be treated as a <xref
- target="StreamErrorHandler">stream error</xref> of type <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- <t>
- For malformed requests, a server MAY send an HTTP response prior to closing or
- resetting the stream. Clients MUST NOT accept a malformed response. Note that these
- requirements are intended to protect against several types of common attacks against
- HTTP; they are deliberately strict, because being permissive can expose
- implementations to these vulnerabilities.
- </t>
- </section>
- </section>
-
- <section title="Examples">
- <t>
- This section shows HTTP/1.1 requests and responses, with illustrations of equivalent
- HTTP/2 requests and responses.
- </t>
- <t>
- An HTTP GET request includes request header fields and no body and is therefore
- transmitted as a single <x:ref>HEADERS</x:ref> frame, followed by zero or more
- <x:ref>CONTINUATION</x:ref> frames containing the serialized block of request header
- fields. The <x:ref>HEADERS</x:ref> frame in the following has both the END_HEADERS and
- END_STREAM flags set; no <x:ref>CONTINUATION</x:ref> frames are sent:
- </t>
-
- <figure>
- <artwork type="inline"><![CDATA[
- GET /resource HTTP/1.1 HEADERS
- Host: example.org ==> + END_STREAM
- Accept: image/jpeg + END_HEADERS
- :method = GET
- :scheme = https
- :path = /resource
- host = example.org
- accept = image/jpeg
-]]></artwork>
- </figure>
-
- <t>
- Similarly, a response that includes only response header fields is transmitted as a
- <x:ref>HEADERS</x:ref> frame (again, followed by zero or more
- <x:ref>CONTINUATION</x:ref> frames) containing the serialized block of response header
- fields.
- </t>
-
- <figure>
- <artwork type="inline"><![CDATA[
- HTTP/1.1 304 Not Modified HEADERS
- ETag: "xyzzy" ==> + END_STREAM
- Expires: Thu, 23 Jan ... + END_HEADERS
- :status = 304
- etag = "xyzzy"
- expires = Thu, 23 Jan ...
-]]></artwork>
- </figure>
-
- <t>
- An HTTP POST request that includes request header fields and payload data is transmitted
- as one <x:ref>HEADERS</x:ref> frame, followed by zero or more
- <x:ref>CONTINUATION</x:ref> frames containing the request header fields, followed by one
- or more <x:ref>DATA</x:ref> frames, with the last <x:ref>CONTINUATION</x:ref> (or
- <x:ref>HEADERS</x:ref>) frame having the END_HEADERS flag set and the final
- <x:ref>DATA</x:ref> frame having the END_STREAM flag set:
- </t>
-
- <figure>
- <artwork type="inline"><![CDATA[
- POST /resource HTTP/1.1 HEADERS
- Host: example.org ==> - END_STREAM
- Content-Type: image/jpeg - END_HEADERS
- Content-Length: 123 :method = POST
- :path = /resource
- {binary data} :scheme = https
-
- CONTINUATION
- + END_HEADERS
- content-type = image/jpeg
- host = example.org
- content-length = 123
-
- DATA
- + END_STREAM
- {binary data}
-]]></artwork>
- <postamble>
- Note that data contributing to any given header field could be spread between header
- block fragments. The allocation of header fields to frames in this example is
- illustrative only.
- </postamble>
- </figure>
-
- <t>
- A response that includes header fields and payload data is transmitted as a
- <x:ref>HEADERS</x:ref> frame, followed by zero or more <x:ref>CONTINUATION</x:ref>
- frames, followed by one or more <x:ref>DATA</x:ref> frames, with the last
- <x:ref>DATA</x:ref> frame in the sequence having the END_STREAM flag set:
- </t>
-
- <figure>
- <artwork type="inline"><![CDATA[
- HTTP/1.1 200 OK HEADERS
- Content-Type: image/jpeg ==> - END_STREAM
- Content-Length: 123 + END_HEADERS
- :status = 200
- {binary data} content-type = image/jpeg
- content-length = 123
-
- DATA
- + END_STREAM
- {binary data}
-]]></artwork>
- </figure>
-
- <t>
- Trailing header fields are sent as a header block after both the request or response
- header block and all the <x:ref>DATA</x:ref> frames have been sent. The
- <x:ref>HEADERS</x:ref> frame starting the trailers header block has the END_STREAM flag
- set.
- </t>
-
- <figure>
- <artwork type="inline"><![CDATA[
- HTTP/1.1 200 OK HEADERS
- Content-Type: image/jpeg ==> - END_STREAM
- Transfer-Encoding: chunked + END_HEADERS
- Trailer: Foo :status = 200
- content-length = 123
- 123 content-type = image/jpeg
- {binary data} trailer = Foo
- 0
- Foo: bar DATA
- - END_STREAM
- {binary data}
-
- HEADERS
- + END_STREAM
- + END_HEADERS
- foo = bar
-]]></artwork>
- </figure>
-
-
- <figure>
- <preamble>
- An informational response using a 1xx status code other than 101 is transmitted as a
- <x:ref>HEADERS</x:ref> frame, followed by zero or more <x:ref>CONTINUATION</x:ref>
- frames:
- </preamble>
- <artwork type="inline"><![CDATA[
- HTTP/1.1 103 BAR HEADERS
- Extension-Field: bar ==> - END_STREAM
- + END_HEADERS
- :status = 103
- extension-field = bar
-]]></artwork>
- </figure>
- </section>
-
- <section anchor="Reliability" title="Request Reliability Mechanisms in HTTP/2">
- <t>
- In HTTP/1.1, an HTTP client is unable to retry a non-idempotent request when an error
- occurs, because there is no means to determine the nature of the error. It is possible
- that some server processing occurred prior to the error, which could result in
- undesirable effects if the request were reattempted.
- </t>
- <t>
- HTTP/2 provides two mechanisms for providing a guarantee to a client that a request has
- not been processed:
- <list style="symbols">
- <t>
- The <x:ref>GOAWAY</x:ref> frame indicates the highest stream number that might have
- been processed. Requests on streams with higher numbers are therefore guaranteed to
- be safe to retry.
- </t>
- <t>
- The <x:ref>REFUSED_STREAM</x:ref> error code can be included in a
- <x:ref>RST_STREAM</x:ref> frame to indicate that the stream is being closed prior to
- any processing having occurred. Any request that was sent on the reset stream can
- be safely retried.
- </t>
- </list>
- </t>
- <t>
- Requests that have not been processed have not failed; clients MAY automatically retry
- them, even those with non-idempotent methods.
- </t>
- <t>
- A server MUST NOT indicate that a stream has not been processed unless it can guarantee
- that fact. If frames that are on a stream are passed to the application layer for any
- stream, then <x:ref>REFUSED_STREAM</x:ref> MUST NOT be used for that stream, and a
- <x:ref>GOAWAY</x:ref> frame MUST include a stream identifier that is greater than or
- equal to the given stream identifier.
- </t>
- <t>
- In addition to these mechanisms, the <x:ref>PING</x:ref> frame provides a way for a
- client to easily test a connection. Connections that remain idle can become broken as
- some middleboxes (for instance, network address translators, or load balancers) silently
- discard connection bindings. The <x:ref>PING</x:ref> frame allows a client to safely
- test whether a connection is still active without sending a request.
- </t>
- </section>
- </section>
-
- <section anchor="PushResources" title="Server Push">
- <t>
- HTTP/2 allows a server to pre-emptively send (or "push") responses (along with
- corresponding "promised" requests) to a client in association with a previous
- client-initiated request. This can be useful when the server knows the client will need
- to have those responses available in order to fully process the response to the original
- request.
- </t>
-
- <t>
- Pushing additional message exchanges in this fashion is optional, and is negotiated
- between individual endpoints. The <x:ref>SETTINGS_ENABLE_PUSH</x:ref> setting can be set
- to 0 to indicate that server push is disabled.
- </t>
- <t>
- Promised requests MUST be cacheable (see <xref target="RFC7231" x:fmt=","
- x:rel="#cacheable.methods"/>), MUST be safe (see <xref target="RFC7231" x:fmt=","
- x:rel="#safe.methods"/>) and MUST NOT include a request body. Clients that receive a
- promised request that is not cacheable, unsafe or that includes a request body MUST
- reset the stream with a <xref target="StreamErrorHandler">stream error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
- <t>
- Pushed responses that are cacheable (see <xref target="RFC7234" x:fmt=","
- x:rel="#response.cacheability"/>) can be stored by the client, if it implements a HTTP
- cache. Pushed responses are considered successfully validated on the origin server (e.g.,
- if the "no-cache" cache response directive <xref target="RFC7234" x:fmt=","
- x:rel="#cache-response-directive"/> is present) while the stream identified by the
- promised stream ID is still open.
- </t>
- <t>
- Pushed responses that are not cacheable MUST NOT be stored by any HTTP cache. They MAY
- be made available to the application separately.
- </t>
- <t>
- An intermediary can receive pushes from the server and choose not to forward them on to
- the client. In other words, how to make use of the pushed information is up to that
- intermediary. Equally, the intermediary might choose to make additional pushes to the
- client, without any action taken by the server.
- </t>
- <t>
- A client cannot push. Thus, servers MUST treat the receipt of a
- <x:ref>PUSH_PROMISE</x:ref> frame as a <xref target="ConnectionErrorHandler">connection
- error</xref> of type <x:ref>PROTOCOL_ERROR</x:ref>. Clients MUST reject any attempt to
- change the <x:ref>SETTINGS_ENABLE_PUSH</x:ref> setting to a value other than 0 by treating
- the message as a <xref target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
-
- <section anchor="PushRequests" title="Push Requests">
- <t>
- Server push is semantically equivalent to a server responding to a request; however, in
- this case that request is also sent by the server, as a <x:ref>PUSH_PROMISE</x:ref>
- frame.
- </t>
- <t>
- The <x:ref>PUSH_PROMISE</x:ref> frame includes a header block that contains a complete
- set of request header fields that the server attributes to the request. It is not
- possible to push a response to a request that includes a request body.
- </t>
-
- <t>
- Pushed responses are always associated with an explicit request from the client. The
- <x:ref>PUSH_PROMISE</x:ref> frames sent by the server are sent on that explicit
- request's stream. The <x:ref>PUSH_PROMISE</x:ref> frame also includes a promised stream
- identifier, chosen from the stream identifiers available to the server (see <xref
- target="StreamIdentifiers"/>).
- </t>
-
- <t>
- The header fields in <x:ref>PUSH_PROMISE</x:ref> and any subsequent
- <x:ref>CONTINUATION</x:ref> frames MUST be a valid and complete set of <xref
- target="HttpRequest">request header fields</xref>. The server MUST include a method in
- the <spanx style="verb">:method</spanx> header field that is safe and cacheable. If a
- client receives a <x:ref>PUSH_PROMISE</x:ref> that does not include a complete and valid
- set of header fields, or the <spanx style="verb">:method</spanx> header field identifies
- a method that is not safe, it MUST respond with a <xref
- target="StreamErrorHandler">stream error</xref> of type <x:ref>PROTOCOL_ERROR</x:ref>.
- </t>
-
- <t>
- The server SHOULD send <x:ref>PUSH_PROMISE</x:ref> (<xref target="PUSH_PROMISE"/>)
- frames prior to sending any frames that reference the promised responses. This avoids a
- race where clients issue requests prior to receiving any <x:ref>PUSH_PROMISE</x:ref>
- frames.
- </t>
- <t>
- For example, if the server receives a request for a document containing embedded links
- to multiple image files, and the server chooses to push those additional images to the
- client, sending push promises before the <x:ref>DATA</x:ref> frames that contain the
- image links ensures that the client is able to see the promises before discovering
- embedded links. Similarly, if the server pushes responses referenced by the header block
- (for instance, in Link header fields), sending the push promises before sending the
- header block ensures that clients do not request them.
- </t>
-
- <t>
- <x:ref>PUSH_PROMISE</x:ref> frames MUST NOT be sent by the client.
- </t>
- <t>
- <x:ref>PUSH_PROMISE</x:ref> frames can be sent by the server in response to any
- client-initiated stream, but the stream MUST be in either the "open" or "half closed
- (remote)" state with respect to the server. <x:ref>PUSH_PROMISE</x:ref> frames are
- interspersed with the frames that comprise a response, though they cannot be
- interspersed with <x:ref>HEADERS</x:ref> and <x:ref>CONTINUATION</x:ref> frames that
- comprise a single header block.
- </t>
- <t>
- Sending a <x:ref>PUSH_PROMISE</x:ref> frame creates a new stream and puts the stream
- into the “reserved (local)” state for the server and the “reserved (remote)” state for
- the client.
- </t>
- </section>
-
- <section anchor="PushResponses" title="Push Responses">
- <t>
- After sending the <x:ref>PUSH_PROMISE</x:ref> frame, the server can begin delivering the
- pushed response as a <xref target="HttpResponse">response</xref> on a server-initiated
- stream that uses the promised stream identifier. The server uses this stream to
- transmit an HTTP response, using the same sequence of frames as defined in <xref
- target="HttpSequence"/>. This stream becomes <xref target="StreamStates">"half closed"
- to the client</xref> after the initial <x:ref>HEADERS</x:ref> frame is sent.
- </t>
-
- <t>
- Once a client receives a <x:ref>PUSH_PROMISE</x:ref> frame and chooses to accept the
- pushed response, the client SHOULD NOT issue any requests for the promised response
- until after the promised stream has closed.
- </t>
-
- <t>
- If the client determines, for any reason, that it does not wish to receive the pushed
- response from the server, or if the server takes too long to begin sending the promised
- response, the client can send an <x:ref>RST_STREAM</x:ref> frame, using either the
- <x:ref>CANCEL</x:ref> or <x:ref>REFUSED_STREAM</x:ref> codes, and referencing the pushed
- stream's identifier.
- </t>
- <t>
- A client can use the <x:ref>SETTINGS_MAX_CONCURRENT_STREAMS</x:ref> setting to limit the
- number of responses that can be concurrently pushed by a server. Advertising a
- <x:ref>SETTINGS_MAX_CONCURRENT_STREAMS</x:ref> value of zero disables server push by
- preventing the server from creating the necessary streams. This does not prohibit a
- server from sending <x:ref>PUSH_PROMISE</x:ref> frames; clients need to reset any
- promised streams that are not wanted.
- </t>
-
- <t>
- Clients receiving a pushed response MUST validate that either the server is
- authoritative (see <xref target="authority"/>), or the proxy that provided the pushed
- response is configured for the corresponding request. For example, a server that offers
- a certificate for only the <spanx style="verb">example.com</spanx> DNS-ID or Common Name
- is not permitted to push a response for <spanx
- style="verb">https://www.example.org/doc</spanx>.
- </t>
- <t>
- The response for a <x:ref>PUSH_PROMISE</x:ref> stream begins with a
- <x:ref>HEADERS</x:ref> frame, which immediately puts the stream into the “half closed
- (remote)” state for the server and “half closed (local)” state for the client, and ends
- with a frame bearing END_STREAM, which places the stream in the "closed" state.
- <list style="hanging">
- <t hangText="Note:">
- The client never sends a frame with the END_STREAM flag for a server push.
- </t>
- </list>
- </t>
- </section>
-
- </section>
-
- <section anchor="CONNECT" title="The CONNECT Method">
- <t>
- In HTTP/1.x, the pseudo-method CONNECT (<xref target="RFC7231" x:fmt=","
- x:rel="#CONNECT"/>) is used to convert an HTTP connection into a tunnel to a remote host.
- CONNECT is primarily used with HTTP proxies to establish a TLS session with an origin
- server for the purposes of interacting with <spanx style="verb">https</spanx> resources.
- </t>
- <t>
- In HTTP/2, the CONNECT method is used to establish a tunnel over a single HTTP/2 stream to
- a remote host, for similar purposes. The HTTP header field mapping works as defined in
- <xref target="HttpRequest">Request Header Fields</xref>, with a few
- differences. Specifically:
- <list style="symbols">
- <t>
- The <spanx style="verb">:method</spanx> header field is set to <spanx
- style="verb">CONNECT</spanx>.
- </t>
- <t>
- The <spanx style="verb">:scheme</spanx> and <spanx style="verb">:path</spanx> header
- fields MUST be omitted.
- </t>
- <t>
- The <spanx style="verb">:authority</spanx> header field contains the host and port to
- connect to (equivalent to the authority-form of the request-target of CONNECT
- requests, see <xref target="RFC7230" x:fmt="," x:rel="#request-target"/>).
- </t>
- </list>
- </t>
- <t>
- A proxy that supports CONNECT establishes a <xref target="TCP">TCP connection</xref> to
- the server identified in the <spanx style="verb">:authority</spanx> header field. Once
- this connection is successfully established, the proxy sends a <x:ref>HEADERS</x:ref>
- frame containing a 2xx series status code to the client, as defined in <xref
- target="RFC7231" x:fmt="," x:rel="#CONNECT"/>.
- </t>
- <t>
- After the initial <x:ref>HEADERS</x:ref> frame sent by each peer, all subsequent
- <x:ref>DATA</x:ref> frames correspond to data sent on the TCP connection. The payload of
- any <x:ref>DATA</x:ref> frames sent by the client is transmitted by the proxy to the TCP
- server; data received from the TCP server is assembled into <x:ref>DATA</x:ref> frames by
- the proxy. Frame types other than <x:ref>DATA</x:ref> or stream management frames
- (<x:ref>RST_STREAM</x:ref>, <x:ref>WINDOW_UPDATE</x:ref>, and <x:ref>PRIORITY</x:ref>)
- MUST NOT be sent on a connected stream, and MUST be treated as a <xref
- target="StreamErrorHandler">stream error</xref> if received.
- </t>
- <t>
- The TCP connection can be closed by either peer. The END_STREAM flag on a
- <x:ref>DATA</x:ref> frame is treated as being equivalent to the TCP FIN bit. A client is
- expected to send a <x:ref>DATA</x:ref> frame with the END_STREAM flag set after receiving
- a frame bearing the END_STREAM flag. A proxy that receives a <x:ref>DATA</x:ref> frame
- with the END_STREAM flag set sends the attached data with the FIN bit set on the last TCP
- segment. A proxy that receives a TCP segment with the FIN bit set sends a
- <x:ref>DATA</x:ref> frame with the END_STREAM flag set. Note that the final TCP segment
- or <x:ref>DATA</x:ref> frame could be empty.
- </t>
- <t>
- A TCP connection error is signaled with <x:ref>RST_STREAM</x:ref>. A proxy treats any
- error in the TCP connection, which includes receiving a TCP segment with the RST bit set,
- as a <xref target="StreamErrorHandler">stream error</xref> of type
- <x:ref>CONNECT_ERROR</x:ref>. Correspondingly, a proxy MUST send a TCP segment with the
- RST bit set if it detects an error with the stream or the HTTP/2 connection.
- </t>
- </section>
- </section>
-
- <section anchor="HttpExtra" title="Additional HTTP Requirements/Considerations">
- <t>
- This section outlines attributes of the HTTP protocol that improve interoperability, reduce
- exposure to known security vulnerabilities, or reduce the potential for implementation
- variation.
- </t>
-
- <section title="Connection Management">
- <t>
- HTTP/2 connections are persistent. For best performance, it is expected clients will not
- close connections until it is determined that no further communication with a server is
- necessary (for example, when a user navigates away from a particular web page), or until
- the server closes the connection.
- </t>
- <t>
- Clients SHOULD NOT open more than one HTTP/2 connection to a given host and port pair,
- where host is derived from a URI, a selected <xref target="ALT-SVC">alternative
- service</xref>, or a configured proxy.
- </t>
- <t>
- A client can create additional connections as replacements, either to replace connections
- that are near to exhausting the available <xref target="StreamIdentifiers">stream
- identifier space</xref>, to refresh the keying material for a TLS connection, or to
- replace connections that have encountered <xref
- target="ConnectionErrorHandler">errors</xref>.
- </t>
- <t>
- A client MAY open multiple connections to the same IP address and TCP port using different
- <xref target="TLS-EXT">Server Name Indication</xref> values or to provide different TLS
- client certificates, but SHOULD avoid creating multiple connections with the same
- configuration.
- </t>
- <t>
- Servers are encouraged to maintain open connections for as long as possible, but are
- permitted to terminate idle connections if necessary. When either endpoint chooses to
- close the transport-layer TCP connection, the terminating endpoint SHOULD first send a
- <x:ref>GOAWAY</x:ref> (<xref target="GOAWAY"/>) frame so that both endpoints can reliably
- determine whether previously sent frames have been processed and gracefully complete or
- terminate any necessary remaining tasks.
- </t>
-
- <section anchor="reuse" title="Connection Reuse">
- <t>
- Connections that are made to an origin servers, either directly or through a tunnel
- created using the <xref target="CONNECT">CONNECT method</xref> MAY be reused for
- requests with multiple different URI authority components. A connection can be reused
- as long as the origin server is <xref target="authority">authoritative</xref>. For
- <spanx style="verb">http</spanx> resources, this depends on the host having resolved to
- the same IP address.
- </t>
- <t>
- For <spanx style="verb">https</spanx> resources, connection reuse additionally depends
- on having a certificate that is valid for the host in the URI. An origin server might
- offer a certificate with multiple <spanx style="verb">subjectAltName</spanx> attributes,
- or names with wildcards, one of which is valid for the authority in the URI. For
- example, a certificate with a <spanx style="verb">subjectAltName</spanx> of <spanx
- style="verb">*.example.com</spanx> might permit the use of the same connection for
- requests to URIs starting with <spanx style="verb">https://a.example.com/</spanx> and
- <spanx style="verb">https://b.example.com/</spanx>.
- </t>
- <t>
- In some deployments, reusing a connection for multiple origins can result in requests
- being directed to the wrong origin server. For example, TLS termination might be
- performed by a middlebox that uses the TLS <xref target="TLS-EXT">Server Name Indication
- (SNI)</xref> extension to select an origin server. This means that it is possible
- for clients to send confidential information to servers that might not be the intended
- target for the request, even though the server is otherwise authoritative.
- </t>
- <t>
- A server that does not wish clients to reuse connections can indicate that it is not
- authoritative for a request by sending a 421 (Misdirected Request) status code in response
- to the request (see <xref target="MisdirectedRequest"/>).
- </t>
- <t>
- A client that is configured to use a proxy over HTTP/2 directs requests to that proxy
- through a single connection. That is, all requests sent via a proxy reuse the
- connection to the proxy.
- </t>
- </section>
-
- <section anchor="MisdirectedRequest" title="The 421 (Misdirected Request) Status Code">
- <t>
- The 421 (Misdirected Request) status code indicates that the request was directed at a
- server that is not able to produce a response. This can be sent by a server that is not
- configured to produce responses for the combination of scheme and authority that are
- included in the request URI.
- </t>
- <t>
- Clients receiving a 421 (Misdirected Request) response from a server MAY retry the
- request - whether the request method is idempotent or not - over a different connection.
- This is possible if a connection is reused (<xref target="reuse"/>) or if an alternative
- service is selected (<xref target="ALT-SVC"/>).
- </t>
- <t>
- This status code MUST NOT be generated by proxies.
- </t>
- <t>
- A 421 response is cacheable by default; i.e., unless otherwise indicated by the method
- definition or explicit cache controls (see <xref target="RFC7234"
- x:rel="#heuristic.freshness" x:fmt="of"/>).
- </t>
- </section>
- </section>
-
- <section title="Use of TLS Features" anchor="TLSUsage">
- <t>
- Implementations of HTTP/2 MUST support <xref target="TLS12">TLS 1.2</xref> for HTTP/2 over
- TLS. The general TLS usage guidance in <xref target="TLSBCP"/> SHOULD be followed, with
- some additional restrictions that are specific to HTTP/2.
- </t>
-
- <t>
- An implementation of HTTP/2 over TLS MUST use TLS 1.2 or higher with the restrictions on
- feature set and cipher suite described in this section. Due to implementation
- limitations, it might not be possible to fail TLS negotiation. An endpoint MUST
- immediately terminate an HTTP/2 connection that does not meet these minimum requirements
- with a <xref target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>INADEQUATE_SECURITY</x:ref>.
- </t>
-
- <section anchor="TLSFeatures" title="TLS Features">
- <t>
- The TLS implementation MUST support the <xref target="TLS-EXT">Server Name Indication
- (SNI)</xref> extension to TLS. HTTP/2 clients MUST indicate the target domain name when
- negotiating TLS.
- </t>
- <t>
- The TLS implementation MUST disable compression. TLS compression can lead to the
- exposure of information that would not otherwise be revealed <xref target="RFC3749"/>.
- Generic compression is unnecessary since HTTP/2 provides compression features that are
- more aware of context and therefore likely to be more appropriate for use for
- performance, security or other reasons.
- </t>
- <t>
- The TLS implementation MUST disable renegotiation. An endpoint MUST treat a TLS
- renegotiation as a <xref target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>PROTOCOL_ERROR</x:ref>. Note that disabling renegotiation can result in
- long-lived connections becoming unusable due to limits on the number of messages the
- underlying cipher suite can encipher.
- </t>
- <t>
- A client MAY use renegotiation to provide confidentiality protection for client
- credentials offered in the handshake, but any renegotiation MUST occur prior to sending
- the connection preface. A server SHOULD request a client certificate if it sees a
- renegotiation request immediately after establishing a connection.
- </t>
- <t>
- This effectively prevents the use of renegotiation in response to a request for a
- specific protected resource. A future specification might provide a way to support this
- use case. <!-- <cref> We are tracking this in a non-blocking fashion in issue #496 and
- with a new draft. -->
- </t>
- </section>
-
- <section title="TLS Cipher Suites">
- <t>
- The set of TLS cipher suites that are permitted in HTTP/2 is restricted. HTTP/2 MUST
- only be used with cipher suites that have ephemeral key exchange, such as the <xref
- target="TLS12">ephemeral Diffie-Hellman (DHE)</xref> or the <xref
- target="RFC4492">elliptic curve variant (ECDHE)</xref>. Ephemeral key exchange MUST
- have a minimum size of 2048 bits for DHE or security level of 128 bits for ECDHE.
- Clients MUST accept DHE sizes of up to 4096 bits. HTTP MUST NOT be used with cipher
- suites that use stream or block ciphers. Authenticated Encryption with Additional Data
- (AEAD) modes, such as the <xref target="RFC5288">Galois Counter Model (GCM) mode for
- AES</xref> are acceptable.
- </t>
- <t>
- The effect of these restrictions is that TLS 1.2 implementations could have
- non-intersecting sets of available cipher suites, since these prevent the use of the
- cipher suite that TLS 1.2 makes mandatory. To avoid this problem, implementations of
- HTTP/2 that use TLS 1.2 MUST support TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 <xref
- target="TLS-ECDHE"/> with P256 <xref target="FIPS186"/>.
- </t>
- <t>
- Clients MAY advertise support of cipher suites that are prohibited by the above
- restrictions in order to allow for connection to servers that do not support HTTP/2.
- This enables a fallback to protocols without these constraints without the additional
- latency imposed by using a separate connection for fallback.
- </t>
- </section>
- </section>
- </section>
-
- <section anchor="security" title="Security Considerations">
- <section title="Server Authority" anchor="authority">
- <t>
- HTTP/2 relies on the HTTP/1.1 definition of authority for determining whether a server is
- authoritative in providing a given response, see <xref target="RFC7230" x:fmt=","
- x:rel="#establishing.authority"/>. This relies on local name resolution for the "http"
- URI scheme, and the authenticated server identity for the "https" scheme (see <xref
- target="RFC2818" x:fmt="," x:sec="3"/>).
- </t>
- </section>
-
- <section title="Cross-Protocol Attacks">
- <t>
- In a cross-protocol attack, an attacker causes a client to initiate a transaction in one
- protocol toward a server that understands a different protocol. An attacker might be able
- to cause the transaction to appear as valid transaction in the second protocol. In
- combination with the capabilities of the web context, this can be used to interact with
- poorly protected servers in private networks.
- </t>
- <t>
- Completing a TLS handshake with an ALPN identifier for HTTP/2 can be considered sufficient
- protection against cross protocol attacks. ALPN provides a positive indication that a
- server is willing to proceed with HTTP/2, which prevents attacks on other TLS-based
- protocols.
- </t>
- <t>
- The encryption in TLS makes it difficult for attackers to control the data which could be
- used in a cross-protocol attack on a cleartext protocol.
- </t>
- <t>
- The cleartext version of HTTP/2 has minimal protection against cross-protocol attacks.
- The <xref target="ConnectionHeader">connection preface</xref> contains a string that is
- designed to confuse HTTP/1.1 servers, but no special protection is offered for other
- protocols. A server that is willing to ignore parts of an HTTP/1.1 request containing an
- Upgrade header field in addition to the client connection preface could be exposed to a
- cross-protocol attack.
- </t>
- </section>
-
- <section title="Intermediary Encapsulation Attacks">
- <t>
- HTTP/2 header field names and values are encoded as sequences of octets with a length
- prefix. This enables HTTP/2 to carry any string of octets as the name or value of a
- header field. An intermediary that translates HTTP/2 requests or responses into HTTP/1.1
- directly could permit the creation of corrupted HTTP/1.1 messages. An attacker might
- exploit this behavior to cause the intermediary to create HTTP/1.1 messages with illegal
- header fields, extra header fields, or even new messages that are entirely falsified.
- </t>
- <t>
- Header field names or values that contain characters not permitted by HTTP/1.1, including
- carriage return (ASCII 0xd) or line feed (ASCII 0xa) MUST NOT be translated verbatim by an
- intermediary, as stipulated in <xref target="RFC7230" x:rel="#field.parsing" x:fmt=","/>.
- </t>
- <t>
- Translation from HTTP/1.x to HTTP/2 does not produce the same opportunity to an attacker.
- Intermediaries that perform translation to HTTP/2 MUST remove any instances of the <spanx
- style="verb">obs-fold</spanx> production from header field values.
- </t>
- </section>
-
- <section title="Cacheability of Pushed Responses">
- <t>
- Pushed responses do not have an explicit request from the client; the request
- is provided by the server in the <x:ref>PUSH_PROMISE</x:ref> frame.
- </t>
- <t>
- Caching responses that are pushed is possible based on the guidance provided by the origin
- server in the Cache-Control header field. However, this can cause issues if a single
- server hosts more than one tenant. For example, a server might offer multiple users each
- a small portion of its URI space.
- </t>
- <t>
- Where multiple tenants share space on the same server, that server MUST ensure that
- tenants are not able to push representations of resources that they do not have authority
- over. Failure to enforce this would allow a tenant to provide a representation that would
- be served out of cache, overriding the actual representation that the authoritative tenant
- provides.
- </t>
- <t>
- Pushed responses for which an origin server is not authoritative (see
- <xref target="authority"/>) are never cached or used.
- </t>
- </section>
-
- <section anchor="dos" title="Denial of Service Considerations">
- <t>
- An HTTP/2 connection can demand a greater commitment of resources to operate than a
- HTTP/1.1 connection. The use of header compression and flow control depend on a
- commitment of resources for storing a greater amount of state. Settings for these
- features ensure that memory commitments for these features are strictly bounded.
- </t>
- <t>
- The number of <x:ref>PUSH_PROMISE</x:ref> frames is not constrained in the same fashion.
- A client that accepts server push SHOULD limit the number of streams it allows to be in
- the "reserved (remote)" state. Excessive number of server push streams can be treated as
- a <xref target="StreamErrorHandler">stream error</xref> of type
- <x:ref>ENHANCE_YOUR_CALM</x:ref>.
- </t>
- <t>
- Processing capacity cannot be guarded as effectively as state capacity.
- </t>
- <t>
- The <x:ref>SETTINGS</x:ref> frame can be abused to cause a peer to expend additional
- processing time. This might be done by pointlessly changing SETTINGS parameters, setting
- multiple undefined parameters, or changing the same setting multiple times in the same
- frame. <x:ref>WINDOW_UPDATE</x:ref> or <x:ref>PRIORITY</x:ref> frames can be abused to
- cause an unnecessary waste of resources.
- </t>
- <t>
- Large numbers of small or empty frames can be abused to cause a peer to expend time
- processing frame headers. Note however that some uses are entirely legitimate, such as
- the sending of an empty <x:ref>DATA</x:ref> frame to end a stream.
- </t>
- <t>
- Header compression also offers some opportunities to waste processing resources; see <xref
- target="COMPRESSION" x:fmt="of" x:rel="#Security"/> for more details on potential abuses.
- </t>
- <t>
- Limits in <x:ref>SETTINGS</x:ref> parameters cannot be reduced instantaneously, which
- leaves an endpoint exposed to behavior from a peer that could exceed the new limits. In
- particular, immediately after establishing a connection, limits set by a server are not
- known to clients and could be exceeded without being an obvious protocol violation.
- </t>
- <t>
- All these features - i.e., <x:ref>SETTINGS</x:ref> changes, small frames, header
- compression - have legitimate uses. These features become a burden only when they are
- used unnecessarily or to excess.
- </t>
- <t>
- An endpoint that doesn't monitor this behavior exposes itself to a risk of denial of
- service attack. Implementations SHOULD track the use of these features and set limits on
- their use. An endpoint MAY treat activity that is suspicious as a <xref
- target="ConnectionErrorHandler">connection error</xref> of type
- <x:ref>ENHANCE_YOUR_CALM</x:ref>.
- </t>
-
- <section anchor="MaxHeaderBlock" title="Limits on Header Block Size">
- <t>
- A large <xref target="HeaderBlock">header block</xref> can cause an implementation to
- commit a large amount of state. Header fields that are critical for routing can appear
- toward the end of a header block, which prevents streaming of header fields to their
- ultimate destination. For this an other reasons, such as ensuring cache correctness,
- means that an endpoint might need to buffer the entire header block. Since there is no
- hard limit to the size of a header block, some endpoints could be forced commit a large
- amount of available memory for header fields.
- </t>
- <t>
- An endpoint can use the <x:ref>SETTINGS_MAX_HEADER_LIST_SIZE</x:ref> to advise peers of
- limits that might apply on the size of header blocks. This setting is only advisory, so
- endpoints MAY choose to send header blocks that exceed this limit and risk having the
- request or response being treated as malformed. This setting specific to a connection,
- so any request or response could encounter a hop with a lower, unknown limit. An
- intermediary can attempt to avoid this problem by passing on values presented by
- different peers, but they are not obligated to do so.
- </t>
- <t>
- A server that receives a larger header block than it is willing to handle can send an
- HTTP 431 (Request Header Fields Too Large) status code <xref target="RFC6585"/>. A
- client can discard responses that it cannot process. The header block MUST be processed
- to ensure a consistent connection state, unless the connection is closed.
- </t>
- </section>
- </section>
-
- <section title="Use of Compression">
- <t>
- HTTP/2 enables greater use of compression for both header fields (<xref
- target="HeaderBlock"/>) and entity bodies. Compression can allow an attacker to recover
- secret data when it is compressed in the same context as data under attacker control.
- </t>
- <t>
- There are demonstrable attacks on compression that exploit the characteristics of the web
- (e.g., <xref target="BREACH"/>). The attacker induces multiple requests containing
- varying plaintext, observing the length of the resulting ciphertext in each, which
- reveals a shorter length when a guess about the secret is correct.
- </t>
- <t>
- Implementations communicating on a secure channel MUST NOT compress content that includes
- both confidential and attacker-controlled data unless separate compression dictionaries
- are used for each source of data. Compression MUST NOT be used if the source of data
- cannot be reliably determined. Generic stream compression, such as that provided by TLS
- MUST NOT be used with HTTP/2 (<xref target="TLSFeatures"/>).
- </t>
- <t>
- Further considerations regarding the compression of header fields are described in <xref
- target="COMPRESSION"/>.
- </t>
- </section>
-
- <section title="Use of Padding" anchor="padding">
- <t>
- Padding within HTTP/2 is not intended as a replacement for general purpose padding, such
- as might be provided by <xref target="TLS12">TLS</xref>. Redundant padding could even be
- counterproductive. Correct application can depend on having specific knowledge of the
- data that is being padded.
- </t>
- <t>
- To mitigate attacks that rely on compression, disabling or limiting compression might be
- preferable to padding as a countermeasure.
- </t>
- <t>
- Padding can be used to obscure the exact size of frame content, and is provided to
- mitigate specific attacks within HTTP. For example, attacks where compressed content
- includes both attacker-controlled plaintext and secret data (see for example, <xref
- target="BREACH"/>).
- </t>
- <t>
- Use of padding can result in less protection than might seem immediately obvious. At
- best, padding only makes it more difficult for an attacker to infer length information by
- increasing the number of frames an attacker has to observe. Incorrectly implemented
- padding schemes can be easily defeated. In particular, randomized padding with a
- predictable distribution provides very little protection; similarly, padding payloads to a
- fixed size exposes information as payload sizes cross the fixed size boundary, which could
- be possible if an attacker can control plaintext.
- </t>
- <t>
- Intermediaries SHOULD retain padding for <x:ref>DATA</x:ref> frames, but MAY drop padding
- for <x:ref>HEADERS</x:ref> and <x:ref>PUSH_PROMISE</x:ref> frames. A valid reason for an
- intermediary to change the amount of padding of frames is to improve the protections that
- padding provides.
- </t>
- </section>
-
- <section title="Privacy Considerations">
- <t>
- Several characteristics of HTTP/2 provide an observer an opportunity to correlate actions
- of a single client or server over time. This includes the value of settings, the manner
- in which flow control windows are managed, the way priorities are allocated to streams,
- timing of reactions to stimulus, and handling of any optional features.
- </t>
- <t>
- As far as this creates observable differences in behavior, they could be used as a basis
- for fingerprinting a specific client, as defined in <xref target="HTML5" x:fmt="of"
- x:sec="1.8" x:rel="introduction.html#fingerprint"/>.
- </t>
- </section>
- </section>
-
- <section anchor="iana" title="IANA Considerations">
- <t>
- A string for identifying HTTP/2 is entered into the "Application Layer Protocol Negotiation
- (ALPN) Protocol IDs" registry established in <xref target="TLS-ALPN"/>.
- </t>
- <t>
- This document establishes a registry for frame types, settings, and error codes. These new
- registries are entered into a new "Hypertext Transfer Protocol (HTTP) 2 Parameters" section.
- </t>
- <t>
- This document registers the <spanx style="verb">HTTP2-Settings</spanx> header field for
- use in HTTP; and the 421 (Misdirected Request) status code.
- </t>
- <t>
- This document registers the <spanx style="verb">PRI</spanx> method for use in HTTP, to avoid
- collisions with the <xref target="ConnectionHeader">connection preface</xref>.
- </t>
-
- <section anchor="iana-alpn" title="Registration of HTTP/2 Identification Strings">
- <t>
- This document creates two registrations for the identification of HTTP/2 in the
- "Application Layer Protocol Negotiation (ALPN) Protocol IDs" registry established in <xref
- target="TLS-ALPN"/>.
- </t>
- <t>
- The "h2" string identifies HTTP/2 when used over TLS:
- <list style="hanging">
- <t hangText="Protocol:">HTTP/2 over TLS</t>
- <t hangText="Identification Sequence:">0x68 0x32 ("h2")</t>
- <t hangText="Specification:">This document</t>
- </list>
- </t>
- <t>
- The "h2c" string identifies HTTP/2 when used over cleartext TCP:
- <list style="hanging">
- <t hangText="Protocol:">HTTP/2 over TCP</t>
- <t hangText="Identification Sequence:">0x68 0x32 0x63 ("h2c")</t>
- <t hangText="Specification:">This document</t>
- </list>
- </t>
- </section>
-
- <section anchor="iana-frames" title="Frame Type Registry">
- <t>
- This document establishes a registry for HTTP/2 frame type codes. The "HTTP/2 Frame
- Type" registry manages an 8-bit space. The "HTTP/2 Frame Type" registry operates under
- either of the <xref target="RFC5226">"IETF Review" or "IESG Approval" policies</xref> for
- values between 0x00 and 0xef, with values between 0xf0 and 0xff being reserved for
- experimental use.
- </t>
- <t>
- New entries in this registry require the following information:
- <list style="hanging">
- <t hangText="Frame Type:">
- A name or label for the frame type.
- </t>
- <t hangText="Code:">
- The 8-bit code assigned to the frame type.
- </t>
- <t hangText="Specification:">
- A reference to a specification that includes a description of the frame layout,
- it's semantics and flags that the frame type uses, including any parts of the frame
- that are conditionally present based on the value of flags.
- </t>
- </list>
- </t>
- <t>
- The entries in the following table are registered by this document.
- </t>
- <texttable align="left" suppress-title="true">
- <ttcol>Frame Type</ttcol>
- <ttcol>Code</ttcol>
- <ttcol>Section</ttcol>
- <c>DATA</c><c>0x0</c><c><xref target="DATA"/></c>
- <c>HEADERS</c><c>0x1</c><c><xref target="HEADERS"/></c>
- <c>PRIORITY</c><c>0x2</c><c><xref target="PRIORITY"/></c>
- <c>RST_STREAM</c><c>0x3</c><c><xref target="RST_STREAM"/></c>
- <c>SETTINGS</c><c>0x4</c><c><xref target="SETTINGS"/></c>
- <c>PUSH_PROMISE</c><c>0x5</c><c><xref target="PUSH_PROMISE"/></c>
- <c>PING</c><c>0x6</c><c><xref target="PING"/></c>
- <c>GOAWAY</c><c>0x7</c><c><xref target="GOAWAY"/></c>
- <c>WINDOW_UPDATE</c><c>0x8</c><c><xref target="WINDOW_UPDATE"/></c>
- <c>CONTINUATION</c><c>0x9</c><c><xref target="CONTINUATION"/></c>
- </texttable>
- </section>
-
- <section anchor="iana-settings" title="Settings Registry">
- <t>
- This document establishes a registry for HTTP/2 settings. The "HTTP/2 Settings" registry
- manages a 16-bit space. The "HTTP/2 Settings" registry operates under the <xref
- target="RFC5226">"Expert Review" policy</xref> for values in the range from 0x0000 to
- 0xefff, with values between and 0xf000 and 0xffff being reserved for experimental use.
- </t>
- <t>
- New registrations are advised to provide the following information:
- <list style="hanging">
- <t hangText="Name:">
- A symbolic name for the setting. Specifying a setting name is optional.
- </t>
- <t hangText="Code:">
- The 16-bit code assigned to the setting.
- </t>
- <t hangText="Initial Value:">
- An initial value for the setting.
- </t>
- <t hangText="Specification:">
- An optional reference to a specification that describes the use of the setting.
- </t>
- </list>
- </t>
- <t>
- An initial set of setting registrations can be found in <xref target="SettingValues"/>.
- </t>
- <texttable align="left" suppress-title="true">
- <ttcol>Name</ttcol>
- <ttcol>Code</ttcol>
- <ttcol>Initial Value</ttcol>
- <ttcol>Specification</ttcol>
- <c>HEADER_TABLE_SIZE</c>
- <c>0x1</c><c>4096</c><c><xref target="SettingValues"/></c>
- <c>ENABLE_PUSH</c>
- <c>0x2</c><c>1</c><c><xref target="SettingValues"/></c>
- <c>MAX_CONCURRENT_STREAMS</c>
- <c>0x3</c><c>(infinite)</c><c><xref target="SettingValues"/></c>
- <c>INITIAL_WINDOW_SIZE</c>
- <c>0x4</c><c>65535</c><c><xref target="SettingValues"/></c>
- <c>MAX_FRAME_SIZE</c>
- <c>0x5</c><c>16384</c><c><xref target="SettingValues"/></c>
- <c>MAX_HEADER_LIST_SIZE</c>
- <c>0x6</c><c>(infinite)</c><c><xref target="SettingValues"/></c>
- </texttable>
-
- </section>
-
- <section anchor="iana-errors" title="Error Code Registry">
- <t>
- This document establishes a registry for HTTP/2 error codes. The "HTTP/2 Error Code"
- registry manages a 32-bit space. The "HTTP/2 Error Code" registry operates under the
- <xref target="RFC5226">"Expert Review" policy</xref>.
- </t>
- <t>
- Registrations for error codes are required to include a description of the error code. An
- expert reviewer is advised to examine new registrations for possible duplication with
- existing error codes. Use of existing registrations is to be encouraged, but not
- mandated.
- </t>
- <t>
- New registrations are advised to provide the following information:
- <list style="hanging">
- <t hangText="Name:">
- A name for the error code. Specifying an error code name is optional.
- </t>
- <t hangText="Code:">
- The 32-bit error code value.
- </t>
- <t hangText="Description:">
- A brief description of the error code semantics, longer if no detailed specification
- is provided.
- </t>
- <t hangText="Specification:">
- An optional reference for a specification that defines the error code.
- </t>
- </list>
- </t>
- <t>
- The entries in the following table are registered by this document.
- </t>
- <texttable align="left" suppress-title="true">
- <ttcol>Name</ttcol>
- <ttcol>Code</ttcol>
- <ttcol>Description</ttcol>
- <ttcol>Specification</ttcol>
- <c>NO_ERROR</c><c>0x0</c>
- <c>Graceful shutdown</c>
- <c><xref target="ErrorCodes"/></c>
- <c>PROTOCOL_ERROR</c><c>0x1</c>
- <c>Protocol error detected</c>
- <c><xref target="ErrorCodes"/></c>
- <c>INTERNAL_ERROR</c><c>0x2</c>
- <c>Implementation fault</c>
- <c><xref target="ErrorCodes"/></c>
- <c>FLOW_CONTROL_ERROR</c><c>0x3</c>
- <c>Flow control limits exceeded</c>
- <c><xref target="ErrorCodes"/></c>
- <c>SETTINGS_TIMEOUT</c><c>0x4</c>
- <c>Settings not acknowledged</c>
- <c><xref target="ErrorCodes"/></c>
- <c>STREAM_CLOSED</c><c>0x5</c>
- <c>Frame received for closed stream</c>
- <c><xref target="ErrorCodes"/></c>
- <c>FRAME_SIZE_ERROR</c><c>0x6</c>
- <c>Frame size incorrect</c>
- <c><xref target="ErrorCodes"/></c>
- <c>REFUSED_STREAM</c><c>0x7</c>
- <c>Stream not processed</c>
- <c><xref target="ErrorCodes"/></c>
- <c>CANCEL</c><c>0x8</c>
- <c>Stream cancelled</c>
- <c><xref target="ErrorCodes"/></c>
- <c>COMPRESSION_ERROR</c><c>0x9</c>
- <c>Compression state not updated</c>
- <c><xref target="ErrorCodes"/></c>
- <c>CONNECT_ERROR</c><c>0xa</c>
- <c>TCP connection error for CONNECT method</c>
- <c><xref target="ErrorCodes"/></c>
- <c>ENHANCE_YOUR_CALM</c><c>0xb</c>
- <c>Processing capacity exceeded</c>
- <c><xref target="ErrorCodes"/></c>
- <c>INADEQUATE_SECURITY</c><c>0xc</c>
- <c>Negotiated TLS parameters not acceptable</c>
- <c><xref target="ErrorCodes"/></c>
- </texttable>
-
- </section>
-
- <section title="HTTP2-Settings Header Field Registration">
- <t>
- This section registers the <spanx style="verb">HTTP2-Settings</spanx> header field in the
- <xref target="BCP90">Permanent Message Header Field Registry</xref>.
- <list style="hanging">
- <t hangText="Header field name:">
- HTTP2-Settings
- </t>
- <t hangText="Applicable protocol:">
- http
- </t>
- <t hangText="Status:">
- standard
- </t>
- <t hangText="Author/Change controller:">
- IETF
- </t>
- <t hangText="Specification document(s):">
- <xref target="Http2SettingsHeader"/> of this document
- </t>
- <t hangText="Related information:">
- This header field is only used by an HTTP/2 client for Upgrade-based negotiation.
- </t>
- </list>
- </t>
- </section>
-
- <section title="PRI Method Registration">
- <t>
- This section registers the <spanx style="verb">PRI</spanx> method in the HTTP Method
- Registry (<xref target="RFC7231" x:fmt="," x:rel="#method.registry"/>).
- <list style="hanging">
- <t hangText="Method Name:">
- PRI
- </t>
- <t hangText="Safe">
- No
- </t>
- <t hangText="Idempotent">
- No
- </t>
- <t hangText="Specification document(s)">
- <xref target="ConnectionHeader"/> of this document
- </t>
- <t hangText="Related information:">
- This method is never used by an actual client. This method will appear to be used
- when an HTTP/1.1 server or intermediary attempts to parse an HTTP/2 connection
- preface.
- </t>
- </list>
- </t>
- </section>
-
- <section title="The 421 (Misdirected Request) HTTP Status Code"
- anchor="iana-MisdirectedRequest">
- <t>
- This document registers the 421 (Misdirected Request) HTTP Status code in the Hypertext
- Transfer Protocol (HTTP) Status Code Registry (<xref target="RFC7231" x:fmt=","
- x:rel="#status.code.registry"/>).
- </t>
- <t>
- <list style="hanging">
- <t hangText="Status Code:">
- 421
- </t>
- <t hangText="Short Description:">
- Misdirected Request
- </t>
- <t hangText="Specification:">
- <xref target="MisdirectedRequest"/> of this document
- </t>
- </list>
- </t>
- </section>
-
- </section>
-
- <section title="Acknowledgements">
- <t>
- This document includes substantial input from the following individuals:
- <list style="symbols">
- <t>
- Adam Langley, Wan-Teh Chang, Jim Morrison, Mark Nottingham, Alyssa Wilk, Costin
- Manolache, William Chan, Vitaliy Lvin, Joe Chan, Adam Barth, Ryan Hamilton, Gavin
- Peters, Kent Alstad, Kevin Lindsay, Paul Amer, Fan Yang, Jonathan Leighton (SPDY
- contributors).
- </t>
- <t>
- Gabriel Montenegro and Willy Tarreau (Upgrade mechanism).
- </t>
- <t>
- William Chan, Salvatore Loreto, Osama Mazahir, Gabriel Montenegro, Jitu Padhye, Roberto
- Peon, Rob Trace (Flow control).
- </t>
- <t>
- Mike Bishop (Extensibility).
- </t>
- <t>
- Mark Nottingham, Julian Reschke, James Snell, Jeff Pinner, Mike Bishop, Herve Ruellan
- (Substantial editorial contributions).
- </t>
- <t>
- Kari Hurtta, Tatsuhiro Tsujikawa, Greg Wilkins, Poul-Henning Kamp.
- </t>
- <t>
- Alexey Melnikov was an editor of this document during 2013.
- </t>
- <t>
- A substantial proportion of Martin's contribution was supported by Microsoft during his
- employment there.
- </t>
- </list>
- </t>
- </section>
- </middle>
-
- <back>
- <references title="Normative References">
- <reference anchor="COMPRESSION">
- <front>
- <title>HPACK - Header Compression for HTTP/2</title>
- <author initials="H." surname="Ruellan" fullname="Herve Ruellan"/>
- <author initials="R." surname="Peon" fullname="Roberto Peon"/>
- <date month="July" year="2014" />
- </front>
- <seriesInfo name="Internet-Draft" value="draft-ietf-httpbis-header-compression-09" />
- <x:source href="refs/draft-ietf-httpbis-header-compression-09.xml"/>
- </reference>
-
- <reference anchor="TCP">
- <front>
- <title abbrev="Transmission Control Protocol">
- Transmission Control Protocol
- </title>
- <author initials="J." surname="Postel" fullname="Jon Postel">
- <organization>University of Southern California (USC)/Information Sciences
- Institute</organization>
- </author>
- <date year="1981" month="September" />
- </front>
- <seriesInfo name="STD" value="7" />
- <seriesInfo name="RFC" value="793" />
- </reference>
-
- <reference anchor="RFC2119">
- <front>
- <title>
- Key words for use in RFCs to Indicate Requirement Levels
- </title>
- <author initials="S." surname="Bradner" fullname="Scott Bradner">
- <organization>Harvard University</organization>
- <address><email>sob@harvard.edu</email></address>
- </author>
- <date month="March" year="1997"/>
- </front>
- <seriesInfo name="BCP" value="14"/>
- <seriesInfo name="RFC" value="2119"/>
- </reference>
-
- <reference anchor="RFC2818">
- <front>
- <title>
- HTTP Over TLS
- </title>
- <author initials="E." surname="Rescorla" fullname="Eric Rescorla"/>
- <date month="May" year="2000"/>
- </front>
- <seriesInfo name="RFC" value="2818"/>
- </reference>
-
- <reference anchor="RFC3986">
- <front>
- <title abbrev="URI Generic Syntax">Uniform Resource Identifier (URI): Generic
- Syntax</title>
- <author initials="T." surname="Berners-Lee" fullname="Tim Berners-Lee"></author>
- <author initials="R." surname="Fielding" fullname="Roy T. Fielding"></author>
- <author initials="L." surname="Masinter" fullname="Larry Masinter"></author>
- <date year="2005" month="January" />
- </front>
- <seriesInfo name="STD" value="66" />
- <seriesInfo name="RFC" value="3986" />
- </reference>
-
- <reference anchor="RFC4648">
- <front>
- <title>The Base16, Base32, and Base64 Data Encodings</title>
- <author fullname="S. Josefsson" initials="S." surname="Josefsson"/>
- <date year="2006" month="October"/>
- </front>
- <seriesInfo value="4648" name="RFC"/>
- </reference>
-
- <reference anchor="RFC5226">
- <front>
- <title>Guidelines for Writing an IANA Considerations Section in RFCs</title>
- <author initials="T." surname="Narten" fullname="T. Narten"/>
- <author initials="H." surname="Alvestrand" fullname="H. Alvestrand"/>
- <date year="2008" month="May" />
- </front>
- <seriesInfo name="BCP" value="26" />
- <seriesInfo name="RFC" value="5226" />
- </reference>
-
- <reference anchor="RFC5234">
- <front>
- <title>Augmented BNF for Syntax Specifications: ABNF</title>
- <author initials="D." surname="Crocker" fullname="D. Crocker"/>
- <author initials="P." surname="Overell" fullname="P. Overell"/>
- <date year="2008" month="January" />
- </front>
- <seriesInfo name="STD" value="68" />
- <seriesInfo name="RFC" value="5234" />
- </reference>
-
- <reference anchor="TLS12">
- <front>
- <title>The Transport Layer Security (TLS) Protocol Version 1.2</title>
- <author initials="T." surname="Dierks" fullname="Tim Dierks"/>
- <author initials="E." surname="Rescorla" fullname="Eric Rescorla"/>
- <date year="2008" month="August" />
- </front>
- <seriesInfo name="RFC" value="5246" />
- </reference>
-
- <reference anchor="TLS-EXT">
- <front>
- <title>
- Transport Layer Security (TLS) Extensions: Extension Definitions
- </title>
- <author initials="D." surname="Eastlake" fullname="D. Eastlake"/>
- <date year="2011" month="January"/>
- </front>
- <seriesInfo name="RFC" value="6066"/>
- </reference>
-
- <reference anchor="TLS-ALPN">
- <front>
- <title>Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension</title>
- <author initials="S." surname="Friedl" fullname="Stephan Friedl"></author>
- <author initials="A." surname="Popov" fullname="Andrei Popov"></author>
- <author initials="A." surname="Langley" fullname="Adam Langley"></author>
- <author initials="E." surname="Stephan" fullname="Emile Stephan"></author>
- <date month="July" year="2014" />
- </front>
- <seriesInfo name="RFC" value="7301" />
- </reference>
-
- <reference anchor="TLS-ECDHE">
- <front>
- <title>
- TLS Elliptic Curve Cipher Suites with SHA-256/384 and AES Galois
- Counter Mode (GCM)
- </title>
- <author initials="E." surname="Rescorla" fullname="E. Rescorla"/>
- <date year="2008" month="August" />
- </front>
- <seriesInfo name="RFC" value="5289" />
- </reference>
-
- <reference anchor="FIPS186">
- <front>
- <title>
- Digital Signature Standard (DSS)
- </title>
- <author><organization>NIST</organization></author>
- <date year="2013" month="July" />
- </front>
- <seriesInfo name="FIPS" value="PUB 186-4" />
- </reference>
-
- <reference anchor="RFC7230">
- <front>
- <title>
- Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing</title>
- <author fullname="Roy T. Fielding" initials="R." role="editor" surname="Fielding">
- <organization abbrev="Adobe">Adobe Systems Incorporated</organization>
- <address><email>fielding@gbiv.com</email></address>
- </author>
- <author fullname="Julian F. Reschke" initials="J. F." role="editor" surname="Reschke">
- <organization abbrev="greenbytes">greenbytes GmbH</organization>
- <address><email>julian.reschke@greenbytes.de</email></address>
- </author>
- <date month="June" year="2014" />
- </front>
- <seriesInfo name="RFC" value="7230" />
- <x:source href="refs/rfc7230.xml"
- basename="https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230"/>
- </reference>
- <reference anchor="RFC7231">
- <front>
- <title>
- Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content</title>
- <author fullname="Roy T. Fielding" initials="R." role="editor" surname="Fielding">
- <organization abbrev="Adobe">Adobe Systems Incorporated</organization>
- <address><email>fielding@gbiv.com</email></address>
- </author>
- <author fullname="Julian F. Reschke" initials="J. F." role="editor" surname="Reschke">
- <organization abbrev="greenbytes">greenbytes GmbH</organization>
- <address><email>julian.reschke@greenbytes.de</email></address>
- </author>
- <date month="June" year="2014" />
- </front>
- <seriesInfo name="RFC" value="7231" />
- <x:source href="refs/rfc7231.xml"
- basename="https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7231"/>
- </reference>
- <reference anchor="RFC7232">
- <front>
- <title>Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests</title>
- <author fullname="Roy T. Fielding" initials="R." role="editor" surname="Fielding">
- <organization abbrev="Adobe">Adobe Systems Incorporated</organization>
- <address><email>fielding@gbiv.com</email></address>
- </author>
- <author fullname="Julian F. Reschke" initials="J. F." role="editor" surname="Reschke">
- <organization abbrev="greenbytes">greenbytes GmbH</organization>
- <address><email>julian.reschke@greenbytes.de</email></address>
- </author>
- <date month="June" year="2014" />
- </front>
- <seriesInfo name="RFC" value="7232" />
- </reference>
- <reference anchor="RFC7233">
- <front>
- <title>Hypertext Transfer Protocol (HTTP/1.1): Range Requests</title>
- <author initials="R." surname="Fielding" fullname="Roy T. Fielding" role="editor">
- <organization abbrev="Adobe">Adobe Systems Incorporated</organization>
- <address><email>fielding@gbiv.com</email></address>
- </author>
- <author initials="Y." surname="Lafon" fullname="Yves Lafon" role="editor">
- <organization abbrev="W3C">World Wide Web Consortium</organization>
- <address><email>ylafon@w3.org</email></address>
- </author>
- <author initials="J. F." surname="Reschke" fullname="Julian F. Reschke" role="editor">
- <organization abbrev="greenbytes">greenbytes GmbH</organization>
- <address><email>julian.reschke@greenbytes.de</email></address>
- </author>
- <date month="June" year="2014" />
- </front>
- <seriesInfo name="RFC" value="7233" />
- </reference>
- <reference anchor="RFC7234">
- <front>
- <title>Hypertext Transfer Protocol (HTTP/1.1): Caching</title>
- <author initials="R." surname="Fielding" fullname="Roy T. Fielding" role="editor">
- <organization abbrev="Adobe">Adobe Systems Incorporated</organization>
- <address><email>fielding@gbiv.com</email></address>
- </author>
- <author fullname="Mark Nottingham" initials="M." role="editor" surname="Nottingham">
- <organization>Akamai</organization>
- <address><email>mnot@mnot.net</email></address>
- </author>
- <author initials="J. F." surname="Reschke" fullname="Julian F. Reschke" role="editor">
- <organization abbrev="greenbytes">greenbytes GmbH</organization>
- <address><email>julian.reschke@greenbytes.de</email></address>
- </author>
- <date month="June" year="2014" />
- </front>
- <seriesInfo name="RFC" value="7234"/>
- <x:source href="refs/rfc7234.xml"
- basename="https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7234"/>
- </reference>
- <reference anchor="RFC7235">
- <front>
- <title>Hypertext Transfer Protocol (HTTP/1.1): Authentication</title>
- <author initials="R." surname="Fielding" fullname="Roy T. Fielding" role="editor">
- <organization abbrev="Adobe">Adobe Systems Incorporated</organization>
- <address><email>fielding@gbiv.com</email></address>
- </author>
- <author initials="J. F." surname="Reschke" fullname="Julian F. Reschke" role="editor">
- <organization abbrev="greenbytes">greenbytes GmbH</organization>
- <address><email>julian.reschke@greenbytes.de</email></address>
- </author>
- <date month="June" year="2014" />
- </front>
- <seriesInfo name="RFC" value="7235"/>
- <x:source href="refs/rfc7235.xml"
- basename="https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7235"/>
- </reference>
-
- <reference anchor="COOKIE">
- <front>
- <title>HTTP State Management Mechanism</title>
- <author initials="A." surname="Barth" fullname="A. Barth"/>
- <date year="2011" month="April" />
- </front>
- <seriesInfo name="RFC" value="6265" />
- </reference>
- </references>
-
- <references title="Informative References">
- <reference anchor="RFC1323">
- <front>
- <title>
- TCP Extensions for High Performance
- </title>
- <author initials="V." surname="Jacobson" fullname="Van Jacobson"></author>
- <author initials="B." surname="Braden" fullname="Bob Braden"></author>
- <author initials="D." surname="Borman" fullname="Dave Borman"></author>
- <date year="1992" month="May" />
- </front>
- <seriesInfo name="RFC" value="1323" />
- </reference>
-
- <reference anchor="RFC3749">
- <front>
- <title>Transport Layer Security Protocol Compression Methods</title>
- <author initials="S." surname="Hollenbeck" fullname="S. Hollenbeck"/>
- <date year="2004" month="May" />
- </front>
- <seriesInfo name="RFC" value="3749" />
- </reference>
-
- <reference anchor="RFC6585">
- <front>
- <title>Additional HTTP Status Codes</title>
- <author initials="M." surname="Nottingham" fullname="Mark Nottingham"/>
- <author initials="R." surname="Fielding" fullname="Roy Fielding"/>
- <date year="2012" month="April" />
- </front>
- <seriesInfo name="RFC" value="6585" />
- </reference>
-
- <reference anchor="RFC4492">
- <front>
- <title>
- Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS)
- </title>
- <author initials="S." surname="Blake-Wilson" fullname="S. Blake-Wilson"/>
- <author initials="N." surname="Bolyard" fullname="N. Bolyard"/>
- <author initials="V." surname="Gupta" fullname="V. Gupta"/>
- <author initials="C." surname="Hawk" fullname="C. Hawk"/>
- <author initials="B." surname="Moeller" fullname="B. Moeller"/>
- <date year="2006" month="May" />
- </front>
- <seriesInfo name="RFC" value="4492" />
- </reference>
-
- <reference anchor="RFC5288">
- <front>
- <title>
- AES Galois Counter Mode (GCM) Cipher Suites for TLS
- </title>
- <author initials="J." surname="Salowey" fullname="J. Salowey"/>
- <author initials="A." surname="Choudhury" fullname="A. Choudhury"/>
- <author initials="D." surname="McGrew" fullname="D. McGrew"/>
- <date year="2008" month="August" />
- </front>
- <seriesInfo name="RFC" value="5288" />
- </reference>
-
- <reference anchor='HTML5'
- target='http://www.w3.org/TR/2014/CR-html5-20140731/'>
- <front>
- <title>HTML5</title>
- <author fullname='Robin Berjon' surname='Berjon' initials='R.'/>
- <author fullname='Steve Faulkner' surname='Faulkner' initials='S.'/>
- <author fullname='Travis Leithead' surname='Leithead' initials='T.'/>
- <author fullname='Erika Doyle Navara' surname='Doyle Navara' initials='E.'/>
- <author fullname='Edward O&apos;Connor' surname='O&apos;Connor' initials='E.'/>
- <author fullname='Silvia Pfeiffer' surname='Pfeiffer' initials='S.'/>
- <date year='2014' month='July' day='31'/>
- </front>
- <seriesInfo name='W3C Candidate Recommendation' value='CR-html5-20140731'/>
- <annotation>
- Latest version available at
- <eref target='http://www.w3.org/TR/html5/'/>.
- </annotation>
- </reference>
-
- <reference anchor="TALKING" target="http://w2spconf.com/2011/papers/websocket.pdf">
- <front>
- <title>
- Talking to Yourself for Fun and Profit
- </title>
- <author initials="L-S." surname="Huang"/>
- <author initials="E." surname="Chen"/>
- <author initials="A." surname="Barth"/>
- <author initials="E." surname="Rescorla"/>
- <author initials="C." surname="Jackson"/>
- <date year="2011" />
- </front>
- </reference>
-
- <reference anchor="BREACH"
- target="http://breachattack.com/resources/BREACH%20-%20SSL,%20gone%20in%2030%20seconds.pdf">
- <front>
- <title>
- BREACH: Reviving the CRIME Attack
- </title>
- <author initials="Y." surname="Gluck"/>
- <author initials="N." surname="Harris"/>
- <author initials="A." surname="Prado"/>
- <date year="2013" month="July" day="12"/>
- </front>
- </reference>
-
- <reference anchor="BCP90">
- <front>
- <title>Registration Procedures for Message Header Fields</title>
- <author initials="G." surname="Klyne" fullname="G. Klyne">
- <organization>Nine by Nine</organization>
- <address><email>GK-IETF@ninebynine.org</email></address>
- </author>
- <author initials="M." surname="Nottingham" fullname="M. Nottingham">
- <organization>BEA Systems</organization>
- <address><email>mnot@pobox.com</email></address>
- </author>
- <author initials="J." surname="Mogul" fullname="J. Mogul">
- <organization>HP Labs</organization>
- <address><email>JeffMogul@acm.org</email></address>
- </author>
- <date year="2004" month="September" />
- </front>
- <seriesInfo name="BCP" value="90" />
- <seriesInfo name="RFC" value="3864" />
- </reference>
-
- <reference anchor="TLSBCP">
- <front>
- <title>Recommendations for Secure Use of TLS and DTLS</title>
- <author initials="Y" surname="Sheffer" fullname="Yaron Sheffer">
- <organization />
- </author>
- <author initials="R" surname="Holz" fullname="Ralph Holz">
- <organization />
- </author>
- <author initials="P" surname="Saint-Andre" fullname="Peter Saint-Andre">
- <organization />
- </author>
- <date month="June" day="23" year="2014" />
- </front>
- <seriesInfo name="Internet-Draft" value="draft-ietf-uta-tls-bcp-01" />
- </reference>
-
- <reference anchor="ALT-SVC">
- <front>
- <title>
- HTTP Alternative Services
- </title>
- <author initials="M." surname="Nottingham" fullname="Mark Nottingham">
- <organization>Akamai</organization>
- </author>
- <author initials="P." surname="McManus" fullname="Patrick McManus">
- <organization>Mozilla</organization>
- </author>
- <author initials="J." surname="Reschke" fullname="Julian Reschke">
- <organization>greenbytes</organization>
- </author>
- <date year="2014" month="April"/>
- </front>
- <seriesInfo name="Internet-Draft" value="draft-ietf-httpbis-alt-svc-02"/>
- <x:source href="refs/draft-ietf-httpbis-alt-svc-02.xml"/>
- </reference>
- </references>
-
- <section title="Change Log" anchor="change.log">
- <t>
- This section is to be removed by RFC Editor before publication.
- </t>
-
- <section title="Since draft-ietf-httpbis-http2-14" anchor="changes.since.draft-ietf-httpbis-http2-14">
- <t>
- Renamed Not Authoritative status code to Misdirected Request.
- </t>
- </section>
-
- <section title="Since draft-ietf-httpbis-http2-13" anchor="changes.since.draft-ietf-httpbis-http2-13">
- <t>
- Pseudo-header fields are now required to appear strictly before regular ones.
- </t>
- <t>
- Restored 1xx series status codes, except 101.
- </t>
- <t>
- Changed frame length field 24-bits. Expanded frame header to 9 octets. Added a setting
- to limit the damage.
- </t>
- <t>
- Added a setting to advise peers of header set size limits.
- </t>
- <t>
- Removed segments.
- </t>
- <t>
- Made non-semantic-bearing <x:ref>HEADERS</x:ref> frames illegal in the HTTP mapping.
- </t>
- </section>
-
- <section title="Since draft-ietf-httpbis-http2-12" anchor="changes.since.draft-ietf-httpbis-http2-12">
- <t>
- Restored extensibility options.
- </t>
- <t>
- Restricting TLS cipher suites to AEAD only.
- </t>
- <t>
- Removing Content-Encoding requirements.
- </t>
- <t>
- Permitting the use of <x:ref>PRIORITY</x:ref> after stream close.
- </t>
- <t>
- Removed ALTSVC frame.
- </t>
- <t>
- Removed BLOCKED frame.
- </t>
- <t>
- Reducing the maximum padding size to 256 octets; removing padding from
- <x:ref>CONTINUATION</x:ref> frames.
- </t>
- <t>
- Removed per-frame GZIP compression.
- </t>
- </section>
-
- <section title="Since draft-ietf-httpbis-http2-11" anchor="changes.since.draft-ietf-httpbis-http2-11">
- <t>
- Added BLOCKED frame (at risk).
- </t>
- <t>
- Simplified priority scheme.
- </t>
- <t>
- Added <x:ref>DATA</x:ref> per-frame GZIP compression.
- </t>
- </section>
-
- <section title="Since draft-ietf-httpbis-http2-10" anchor="changes.since.draft-ietf-httpbis-http2-10">
- <t>
- Changed "connection header" to "connection preface" to avoid confusion.
- </t>
- <t>
- Added dependency-based stream prioritization.
- </t>
- <t>
- Added "h2c" identifier to distinguish between cleartext and secured HTTP/2.
- </t>
- <t>
- Adding missing padding to <x:ref>PUSH_PROMISE</x:ref>.
- </t>
- <t>
- Integrate ALTSVC frame and supporting text.
- </t>
- <t>
- Dropping requirement on "deflate" Content-Encoding.
- </t>
- <t>
- Improving security considerations around use of compression.
- </t>
- </section>
-
- <section title="Since draft-ietf-httpbis-http2-09" anchor="changes.since.draft-ietf-httpbis-http2-09">
- <t>
- Adding padding for data frames.
- </t>
- <t>
- Renumbering frame types, error codes, and settings.
- </t>
- <t>
- Adding INADEQUATE_SECURITY error code.
- </t>
- <t>
- Updating TLS usage requirements to 1.2; forbidding TLS compression.
- </t>
- <t>
- Removing extensibility for frames and settings.
- </t>
- <t>
- Changing setting identifier size.
- </t>
- <t>
- Removing the ability to disable flow control.
- </t>
- <t>
- Changing the protocol identification token to "h2".
- </t>
- <t>
- Changing the use of :authority to make it optional and to allow userinfo in non-HTTP
- cases.
- </t>
- <t>
- Allowing split on 0x0 for Cookie.
- </t>
- <t>
- Reserved PRI method in HTTP/1.1 to avoid possible future collisions.
- </t>
- </section>
-
- <section title="Since draft-ietf-httpbis-http2-08" anchor="changes.since.draft-ietf-httpbis-http2-08">
- <t>
- Added cookie crumbling for more efficient header compression.
- </t>
- <t>
- Added header field ordering with the value-concatenation mechanism.
- </t>
- </section>
-
- <section title="Since draft-ietf-httpbis-http2-07" anchor="changes.since.draft-ietf-httpbis-http2-07">
- <t>
- Marked draft for implementation.
- </t>
- </section>
-
- <section title="Since draft-ietf-httpbis-http2-06" anchor="changes.since.draft-ietf-httpbis-http2-06">
- <t>
- Adding definition for CONNECT method.
- </t>
- <t>
- Constraining the use of push to safe, cacheable methods with no request body.
- </t>
- <t>
- Changing from :host to :authority to remove any potential confusion.
- </t>
- <t>
- Adding setting for header compression table size.
- </t>
- <t>
- Adding settings acknowledgement.
- </t>
- <t>
- Removing unnecessary and potentially problematic flags from CONTINUATION.
- </t>
- <t>
- Added denial of service considerations.
- </t>
- </section>
- <section title="Since draft-ietf-httpbis-http2-05" anchor="changes.since.draft-ietf-httpbis-http2-05">
- <t>
- Marking the draft ready for implementation.
- </t>
- <t>
- Renumbering END_PUSH_PROMISE flag.
- </t>
- <t>
- Editorial clarifications and changes.
- </t>
- </section>
-
- <section title="Since draft-ietf-httpbis-http2-04" anchor="changes.since.draft-ietf-httpbis-http2-04">
- <t>
- Added CONTINUATION frame for HEADERS and PUSH_PROMISE.
- </t>
- <t>
- PUSH_PROMISE is no longer implicitly prohibited if SETTINGS_MAX_CONCURRENT_STREAMS is
- zero.
- </t>
- <t>
- Push expanded to allow all safe methods without a request body.
- </t>
- <t>
- Clarified the use of HTTP header fields in requests and responses. Prohibited HTTP/1.1
- hop-by-hop header fields.
- </t>
- <t>
- Requiring that intermediaries not forward requests with missing or illegal routing
- :-headers.
- </t>
- <t>
- Clarified requirements around handling different frames after stream close, stream reset
- and <x:ref>GOAWAY</x:ref>.
- </t>
- <t>
- Added more specific prohibitions for sending of different frame types in various stream
- states.
- </t>
- <t>
- Making the last received setting value the effective value.
- </t>
- <t>
- Clarified requirements on TLS version, extension and ciphers.
- </t>
- </section>
-
- <section title="Since draft-ietf-httpbis-http2-03" anchor="changes.since.draft-ietf-httpbis-http2-03">
- <t>
- Committed major restructuring atrocities.
- </t>
- <t>
- Added reference to first header compression draft.
- </t>
- <t>
- Added more formal description of frame lifecycle.
- </t>
- <t>
- Moved END_STREAM (renamed from FINAL) back to <x:ref>HEADERS</x:ref>/<x:ref>DATA</x:ref>.
- </t>
- <t>
- Removed HEADERS+PRIORITY, added optional priority to <x:ref>HEADERS</x:ref> frame.
- </t>
- <t>
- Added <x:ref>PRIORITY</x:ref> frame.
- </t>
- </section>
-
- <section title="Since draft-ietf-httpbis-http2-02" anchor="changes.since.draft-ietf-httpbis-http2-02">
- <t>
- Added continuations to frames carrying header blocks.
- </t>
- <t>
- Replaced use of "session" with "connection" to avoid confusion with other HTTP stateful
- concepts, like cookies.
- </t>
- <t>
- Removed "message".
- </t>
- <t>
- Switched to TLS ALPN from NPN.
- </t>
- <t>
- Editorial changes.
- </t>
- </section>
-
- <section title="Since draft-ietf-httpbis-http2-01" anchor="changes.since.draft-ietf-httpbis-http2-01">
- <t>
- Added IANA considerations section for frame types, error codes and settings.
- </t>
- <t>
- Removed data frame compression.
- </t>
- <t>
- Added <x:ref>PUSH_PROMISE</x:ref>.
- </t>
- <t>
- Added globally applicable flags to framing.
- </t>
- <t>
- Removed zlib-based header compression mechanism.
- </t>
- <t>
- Updated references.
- </t>
- <t>
- Clarified stream identifier reuse.
- </t>
- <t>
- Removed CREDENTIALS frame and associated mechanisms.
- </t>
- <t>
- Added advice against naive implementation of flow control.
- </t>
- <t>
- Added session header section.
- </t>
- <t>
- Restructured frame header. Removed distinction between data and control frames.
- </t>
- <t>
- Altered flow control properties to include session-level limits.
- </t>
- <t>
- Added note on cacheability of pushed resources and multiple tenant servers.
- </t>
- <t>
- Changed protocol label form based on discussions.
- </t>
- </section>
-
- <section title="Since draft-ietf-httpbis-http2-00" anchor="changes.since.draft-ietf-httpbis-http2-00">
- <t>
- Changed title throughout.
- </t>
- <t>
- Removed section on Incompatibilities with SPDY draft#2.
- </t>
- <t>
- Changed <x:ref>INTERNAL_ERROR</x:ref> on <x:ref>GOAWAY</x:ref> to have a value of 2 <eref
- target="https://groups.google.com/forum/?fromgroups#!topic/spdy-dev/cfUef2gL3iU"/>.
- </t>
- <t>
- Replaced abstract and introduction.
- </t>
- <t>
- Added section on starting HTTP/2.0, including upgrade mechanism.
- </t>
- <t>
- Removed unused references.
- </t>
- <t>
- Added <xref target="fc-principles">flow control principles</xref> based on <eref
- target="https://tools.ietf.org/html/draft-montenegro-httpbis-http2-fc-principles-01"/>.
- </t>
- </section>
-
- <section title="Since draft-mbelshe-httpbis-spdy-00" anchor="changes.since.draft-mbelshe-httpbis-spdy-00">
- <t>
- Adopted as base for draft-ietf-httpbis-http2.
- </t>
- <t>
- Updated authors/editors list.
- </t>
- <t>
- Added status note.
- </t>
- </section>
- </section>
-
- </back>
-</rfc>
-<!--
- vim:et:tw=100:sw=2:
- -->
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/transport.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/transport.go
deleted file mode 100644
index fef8396..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/transport.go
+++ /dev/null
@@ -1,2129 +0,0 @@
-// 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.
-
-// Transport code.
-
-package http2
-
-import (
- "bufio"
- "bytes"
- "compress/gzip"
- "crypto/rand"
- "crypto/tls"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "math"
- "net"
- "net/http"
- "sort"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "golang.org/x/net/http2/hpack"
- "golang.org/x/net/idna"
- "golang.org/x/net/lex/httplex"
-)
-
-const (
- // transportDefaultConnFlow is how many connection-level flow control
- // tokens we give the server at start-up, past the default 64k.
- transportDefaultConnFlow = 1 << 30
-
- // transportDefaultStreamFlow is how many stream-level flow
- // control tokens we announce to the peer, and how many bytes
- // we buffer per stream.
- transportDefaultStreamFlow = 4 << 20
-
- // transportDefaultStreamMinRefresh is the minimum number of bytes we'll send
- // a stream-level WINDOW_UPDATE for at a time.
- transportDefaultStreamMinRefresh = 4 << 10
-
- defaultUserAgent = "Go-http-client/2.0"
-)
-
-// Transport is an HTTP/2 Transport.
-//
-// A Transport internally caches connections to servers. It is safe
-// for concurrent use by multiple goroutines.
-type Transport struct {
- // DialTLS specifies an optional dial function for creating
- // TLS connections for requests.
- //
- // If DialTLS is nil, tls.Dial is used.
- //
- // If the returned net.Conn has a ConnectionState method like tls.Conn,
- // it will be used to set http.Response.TLS.
- DialTLS func(network, addr string, cfg *tls.Config) (net.Conn, error)
-
- // TLSClientConfig specifies the TLS configuration to use with
- // tls.Client. If nil, the default configuration is used.
- TLSClientConfig *tls.Config
-
- // ConnPool optionally specifies an alternate connection pool to use.
- // If nil, the default is used.
- ConnPool ClientConnPool
-
- // DisableCompression, if true, prevents the Transport from
- // requesting compression with an "Accept-Encoding: gzip"
- // request header when the Request contains no existing
- // Accept-Encoding value. If the Transport requests gzip on
- // its own and gets a gzipped response, it's transparently
- // decoded in the Response.Body. However, if the user
- // explicitly requested gzip it is not automatically
- // uncompressed.
- DisableCompression bool
-
- // AllowHTTP, if true, permits HTTP/2 requests using the insecure,
- // plain-text "http" scheme. Note that this does not enable h2c support.
- AllowHTTP bool
-
- // MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to
- // send in the initial settings frame. It is how many bytes
- // of response headers are allow. Unlike the http2 spec, zero here
- // means to use a default limit (currently 10MB). If you actually
- // want to advertise an ulimited value to the peer, Transport
- // interprets the highest possible value here (0xffffffff or 1<<32-1)
- // to mean no limit.
- MaxHeaderListSize uint32
-
- // t1, if non-nil, is the standard library Transport using
- // this transport. Its settings are used (but not its
- // RoundTrip method, etc).
- t1 *http.Transport
-
- connPoolOnce sync.Once
- connPoolOrDef ClientConnPool // non-nil version of ConnPool
-}
-
-func (t *Transport) maxHeaderListSize() uint32 {
- if t.MaxHeaderListSize == 0 {
- return 10 << 20
- }
- if t.MaxHeaderListSize == 0xffffffff {
- return 0
- }
- return t.MaxHeaderListSize
-}
-
-func (t *Transport) disableCompression() bool {
- return t.DisableCompression || (t.t1 != nil && t.t1.DisableCompression)
-}
-
-var errTransportVersion = errors.New("http2: ConfigureTransport is only supported starting at Go 1.6")
-
-// ConfigureTransport configures a net/http HTTP/1 Transport to use HTTP/2.
-// It requires Go 1.6 or later and returns an error if the net/http package is too old
-// or if t1 has already been HTTP/2-enabled.
-func ConfigureTransport(t1 *http.Transport) error {
- _, err := configureTransport(t1) // in configure_transport.go (go1.6) or not_go16.go
- return err
-}
-
-func (t *Transport) connPool() ClientConnPool {
- t.connPoolOnce.Do(t.initConnPool)
- return t.connPoolOrDef
-}
-
-func (t *Transport) initConnPool() {
- if t.ConnPool != nil {
- t.connPoolOrDef = t.ConnPool
- } else {
- t.connPoolOrDef = &clientConnPool{t: t}
- }
-}
-
-// ClientConn is the state of a single HTTP/2 client connection to an
-// HTTP/2 server.
-type ClientConn struct {
- t *Transport
- tconn net.Conn // usually *tls.Conn, except specialized impls
- tlsState *tls.ConnectionState // nil only for specialized impls
- singleUse bool // whether being used for a single http.Request
-
- // readLoop goroutine fields:
- readerDone chan struct{} // closed on error
- readerErr error // set before readerDone is closed
-
- idleTimeout time.Duration // or 0 for never
- idleTimer *time.Timer
-
- mu sync.Mutex // guards following
- cond *sync.Cond // hold mu; broadcast on flow/closed changes
- flow flow // our conn-level flow control quota (cs.flow is per stream)
- inflow flow // peer's conn-level flow control
- closed bool
- wantSettingsAck bool // we sent a SETTINGS frame and haven't heard back
- goAway *GoAwayFrame // if non-nil, the GoAwayFrame we received
- goAwayDebug string // goAway frame's debug data, retained as a string
- streams map[uint32]*clientStream // client-initiated
- nextStreamID uint32
- pings map[[8]byte]chan struct{} // in flight ping data to notification channel
- bw *bufio.Writer
- br *bufio.Reader
- fr *Framer
- lastActive time.Time
- // Settings from peer: (also guarded by mu)
- maxFrameSize uint32
- maxConcurrentStreams uint32
- initialWindowSize uint32
-
- hbuf bytes.Buffer // HPACK encoder writes into this
- henc *hpack.Encoder
- freeBuf [][]byte
-
- wmu sync.Mutex // held while writing; acquire AFTER mu if holding both
- werr error // first write error that has occurred
-}
-
-// clientStream is the state for a single HTTP/2 stream. One of these
-// is created for each Transport.RoundTrip call.
-type clientStream struct {
- cc *ClientConn
- req *http.Request
- trace *clientTrace // or nil
- ID uint32
- resc chan resAndError
- bufPipe pipe // buffered pipe with the flow-controlled response payload
- startedWrite bool // started request body write; guarded by cc.mu
- requestedGzip bool
- on100 func() // optional code to run if get a 100 continue response
-
- flow flow // guarded by cc.mu
- inflow flow // guarded by cc.mu
- bytesRemain int64 // -1 means unknown; owned by transportResponseBody.Read
- readErr error // sticky read error; owned by transportResponseBody.Read
- stopReqBody error // if non-nil, stop writing req body; guarded by cc.mu
- didReset bool // whether we sent a RST_STREAM to the server; guarded by cc.mu
-
- peerReset chan struct{} // closed on peer reset
- resetErr error // populated before peerReset is closed
-
- done chan struct{} // closed when stream remove from cc.streams map; close calls guarded by cc.mu
-
- // owned by clientConnReadLoop:
- firstByte bool // got the first response byte
- pastHeaders bool // got first MetaHeadersFrame (actual headers)
- pastTrailers bool // got optional second MetaHeadersFrame (trailers)
-
- trailer http.Header // accumulated trailers
- resTrailer *http.Header // client's Response.Trailer
-}
-
-// awaitRequestCancel runs in its own goroutine and waits for the user
-// to cancel a RoundTrip request, its context to expire, or for the
-// request to be done (any way it might be removed from the cc.streams
-// map: peer reset, successful completion, TCP connection breakage,
-// etc)
-func (cs *clientStream) awaitRequestCancel(req *http.Request) {
- ctx := reqContext(req)
- if req.Cancel == nil && ctx.Done() == nil {
- return
- }
- select {
- case <-req.Cancel:
- cs.cancelStream()
- cs.bufPipe.CloseWithError(errRequestCanceled)
- case <-ctx.Done():
- cs.cancelStream()
- cs.bufPipe.CloseWithError(ctx.Err())
- case <-cs.done:
- }
-}
-
-func (cs *clientStream) cancelStream() {
- cs.cc.mu.Lock()
- didReset := cs.didReset
- cs.didReset = true
- cs.cc.mu.Unlock()
-
- if !didReset {
- cs.cc.writeStreamReset(cs.ID, ErrCodeCancel, nil)
- }
-}
-
-// checkResetOrDone reports any error sent in a RST_STREAM frame by the
-// server, or errStreamClosed if the stream is complete.
-func (cs *clientStream) checkResetOrDone() error {
- select {
- case <-cs.peerReset:
- return cs.resetErr
- case <-cs.done:
- return errStreamClosed
- default:
- return nil
- }
-}
-
-func (cs *clientStream) abortRequestBodyWrite(err error) {
- if err == nil {
- panic("nil error")
- }
- cc := cs.cc
- cc.mu.Lock()
- cs.stopReqBody = err
- cc.cond.Broadcast()
- cc.mu.Unlock()
-}
-
-type stickyErrWriter struct {
- w io.Writer
- err *error
-}
-
-func (sew stickyErrWriter) Write(p []byte) (n int, err error) {
- if *sew.err != nil {
- return 0, *sew.err
- }
- n, err = sew.w.Write(p)
- *sew.err = err
- return
-}
-
-var ErrNoCachedConn = errors.New("http2: no cached connection was available")
-
-// RoundTripOpt are options for the Transport.RoundTripOpt method.
-type RoundTripOpt struct {
- // OnlyCachedConn controls whether RoundTripOpt may
- // create a new TCP connection. If set true and
- // no cached connection is available, RoundTripOpt
- // will return ErrNoCachedConn.
- OnlyCachedConn bool
-}
-
-func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
- return t.RoundTripOpt(req, RoundTripOpt{})
-}
-
-// authorityAddr returns a given authority (a host/IP, or host:port / ip:port)
-// and returns a host:port. The port 443 is added if needed.
-func authorityAddr(scheme string, authority string) (addr string) {
- host, port, err := net.SplitHostPort(authority)
- if err != nil { // authority didn't have a port
- port = "443"
- if scheme == "http" {
- port = "80"
- }
- host = authority
- }
- if a, err := idna.ToASCII(host); err == nil {
- host = a
- }
- // IPv6 address literal, without a port:
- if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
- return host + ":" + port
- }
- return net.JoinHostPort(host, port)
-}
-
-// RoundTripOpt is like RoundTrip, but takes options.
-func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Response, error) {
- if !(req.URL.Scheme == "https" || (req.URL.Scheme == "http" && t.AllowHTTP)) {
- return nil, errors.New("http2: unsupported scheme")
- }
-
- addr := authorityAddr(req.URL.Scheme, req.URL.Host)
- for {
- cc, err := t.connPool().GetClientConn(req, addr)
- if err != nil {
- t.vlogf("http2: Transport failed to get client conn for %s: %v", addr, err)
- return nil, err
- }
- traceGotConn(req, cc)
- res, err := cc.RoundTrip(req)
- if err != nil {
- if req, err = shouldRetryRequest(req, err); err == nil {
- continue
- }
- }
- if err != nil {
- t.vlogf("RoundTrip failure: %v", err)
- return nil, err
- }
- return res, nil
- }
-}
-
-// CloseIdleConnections closes any connections which were previously
-// connected from previous requests but are now sitting idle.
-// It does not interrupt any connections currently in use.
-func (t *Transport) CloseIdleConnections() {
- if cp, ok := t.connPool().(clientConnPoolIdleCloser); ok {
- cp.closeIdleConnections()
- }
-}
-
-var (
- errClientConnClosed = errors.New("http2: client conn is closed")
- errClientConnUnusable = errors.New("http2: client conn not usable")
-
- errClientConnGotGoAway = errors.New("http2: Transport received Server's graceful shutdown GOAWAY")
- errClientConnGotGoAwayAfterSomeReqBody = errors.New("http2: Transport received Server's graceful shutdown GOAWAY; some request body already written")
-)
-
-// shouldRetryRequest is called by RoundTrip when a request fails to get
-// response headers. It is always called with a non-nil error.
-// It returns either a request to retry (either the same request, or a
-// modified clone), or an error if the request can't be replayed.
-func shouldRetryRequest(req *http.Request, err error) (*http.Request, error) {
- switch err {
- default:
- return nil, err
- case errClientConnUnusable, errClientConnGotGoAway:
- return req, nil
- case errClientConnGotGoAwayAfterSomeReqBody:
- // If the Body is nil (or http.NoBody), it's safe to reuse
- // this request and its Body.
- if req.Body == nil || reqBodyIsNoBody(req.Body) {
- return req, nil
- }
- // Otherwise we depend on the Request having its GetBody
- // func defined.
- getBody := reqGetBody(req) // Go 1.8: getBody = req.GetBody
- if getBody == nil {
- return nil, errors.New("http2: Transport: peer server initiated graceful shutdown after some of Request.Body was written; define Request.GetBody to avoid this error")
- }
- body, err := getBody()
- if err != nil {
- return nil, err
- }
- newReq := *req
- newReq.Body = body
- return &newReq, nil
- }
-}
-
-func (t *Transport) dialClientConn(addr string, singleUse bool) (*ClientConn, error) {
- host, _, err := net.SplitHostPort(addr)
- if err != nil {
- return nil, err
- }
- tconn, err := t.dialTLS()("tcp", addr, t.newTLSConfig(host))
- if err != nil {
- return nil, err
- }
- return t.newClientConn(tconn, singleUse)
-}
-
-func (t *Transport) newTLSConfig(host string) *tls.Config {
- cfg := new(tls.Config)
- if t.TLSClientConfig != nil {
- *cfg = *cloneTLSConfig(t.TLSClientConfig)
- }
- if !strSliceContains(cfg.NextProtos, NextProtoTLS) {
- cfg.NextProtos = append([]string{NextProtoTLS}, cfg.NextProtos...)
- }
- if cfg.ServerName == "" {
- cfg.ServerName = host
- }
- return cfg
-}
-
-func (t *Transport) dialTLS() func(string, string, *tls.Config) (net.Conn, error) {
- if t.DialTLS != nil {
- return t.DialTLS
- }
- return t.dialTLSDefault
-}
-
-func (t *Transport) dialTLSDefault(network, addr string, cfg *tls.Config) (net.Conn, error) {
- cn, err := tls.Dial(network, addr, cfg)
- if err != nil {
- return nil, err
- }
- if err := cn.Handshake(); err != nil {
- return nil, err
- }
- if !cfg.InsecureSkipVerify {
- if err := cn.VerifyHostname(cfg.ServerName); err != nil {
- return nil, err
- }
- }
- state := cn.ConnectionState()
- if p := state.NegotiatedProtocol; p != NextProtoTLS {
- return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", p, NextProtoTLS)
- }
- if !state.NegotiatedProtocolIsMutual {
- return nil, errors.New("http2: could not negotiate protocol mutually")
- }
- return cn, nil
-}
-
-// disableKeepAlives reports whether connections should be closed as
-// soon as possible after handling the first request.
-func (t *Transport) disableKeepAlives() bool {
- return t.t1 != nil && t.t1.DisableKeepAlives
-}
-
-func (t *Transport) expectContinueTimeout() time.Duration {
- if t.t1 == nil {
- return 0
- }
- return transportExpectContinueTimeout(t.t1)
-}
-
-func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
- return t.newClientConn(c, false)
-}
-
-func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, error) {
- cc := &ClientConn{
- t: t,
- tconn: c,
- readerDone: make(chan struct{}),
- nextStreamID: 1,
- maxFrameSize: 16 << 10, // spec default
- initialWindowSize: 65535, // spec default
- maxConcurrentStreams: 1000, // "infinite", per spec. 1000 seems good enough.
- streams: make(map[uint32]*clientStream),
- singleUse: singleUse,
- wantSettingsAck: true,
- pings: make(map[[8]byte]chan struct{}),
- }
- if d := t.idleConnTimeout(); d != 0 {
- cc.idleTimeout = d
- cc.idleTimer = time.AfterFunc(d, cc.onIdleTimeout)
- }
- if VerboseLogs {
- t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr())
- }
-
- cc.cond = sync.NewCond(&cc.mu)
- cc.flow.add(int32(initialWindowSize))
-
- // TODO: adjust this writer size to account for frame size +
- // MTU + crypto/tls record padding.
- cc.bw = bufio.NewWriter(stickyErrWriter{c, &cc.werr})
- cc.br = bufio.NewReader(c)
- cc.fr = NewFramer(cc.bw, cc.br)
- cc.fr.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil)
- cc.fr.MaxHeaderListSize = t.maxHeaderListSize()
-
- // TODO: SetMaxDynamicTableSize, SetMaxDynamicTableSizeLimit on
- // henc in response to SETTINGS frames?
- cc.henc = hpack.NewEncoder(&cc.hbuf)
-
- if cs, ok := c.(connectionStater); ok {
- state := cs.ConnectionState()
- cc.tlsState = &state
- }
-
- initialSettings := []Setting{
- {ID: SettingEnablePush, Val: 0},
- {ID: SettingInitialWindowSize, Val: transportDefaultStreamFlow},
- }
- if max := t.maxHeaderListSize(); max != 0 {
- initialSettings = append(initialSettings, Setting{ID: SettingMaxHeaderListSize, Val: max})
- }
-
- cc.bw.Write(clientPreface)
- cc.fr.WriteSettings(initialSettings...)
- cc.fr.WriteWindowUpdate(0, transportDefaultConnFlow)
- cc.inflow.add(transportDefaultConnFlow + initialWindowSize)
- cc.bw.Flush()
- if cc.werr != nil {
- return nil, cc.werr
- }
-
- go cc.readLoop()
- return cc, nil
-}
-
-func (cc *ClientConn) setGoAway(f *GoAwayFrame) {
- cc.mu.Lock()
- defer cc.mu.Unlock()
-
- old := cc.goAway
- cc.goAway = f
-
- // Merge the previous and current GoAway error frames.
- if cc.goAwayDebug == "" {
- cc.goAwayDebug = string(f.DebugData())
- }
- if old != nil && old.ErrCode != ErrCodeNo {
- cc.goAway.ErrCode = old.ErrCode
- }
- last := f.LastStreamID
- for streamID, cs := range cc.streams {
- if streamID > last {
- select {
- case cs.resc <- resAndError{err: errClientConnGotGoAway}:
- default:
- }
- }
- }
-}
-
-func (cc *ClientConn) CanTakeNewRequest() bool {
- cc.mu.Lock()
- defer cc.mu.Unlock()
- return cc.canTakeNewRequestLocked()
-}
-
-func (cc *ClientConn) canTakeNewRequestLocked() bool {
- if cc.singleUse && cc.nextStreamID > 1 {
- return false
- }
- return cc.goAway == nil && !cc.closed &&
- int64(len(cc.streams)+1) < int64(cc.maxConcurrentStreams) &&
- cc.nextStreamID < math.MaxInt32
-}
-
-// onIdleTimeout is called from a time.AfterFunc goroutine. It will
-// only be called when we're idle, but because we're coming from a new
-// goroutine, there could be a new request coming in at the same time,
-// so this simply calls the synchronized closeIfIdle to shut down this
-// connection. The timer could just call closeIfIdle, but this is more
-// clear.
-func (cc *ClientConn) onIdleTimeout() {
- cc.closeIfIdle()
-}
-
-func (cc *ClientConn) closeIfIdle() {
- cc.mu.Lock()
- if len(cc.streams) > 0 {
- cc.mu.Unlock()
- return
- }
- cc.closed = true
- nextID := cc.nextStreamID
- // TODO: do clients send GOAWAY too? maybe? Just Close:
- cc.mu.Unlock()
-
- if VerboseLogs {
- cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, nextID-2)
- }
- cc.tconn.Close()
-}
-
-const maxAllocFrameSize = 512 << 10
-
-// frameBuffer returns a scratch buffer suitable for writing DATA frames.
-// They're capped at the min of the peer's max frame size or 512KB
-// (kinda arbitrarily), but definitely capped so we don't allocate 4GB
-// bufers.
-func (cc *ClientConn) frameScratchBuffer() []byte {
- cc.mu.Lock()
- size := cc.maxFrameSize
- if size > maxAllocFrameSize {
- size = maxAllocFrameSize
- }
- for i, buf := range cc.freeBuf {
- if len(buf) >= int(size) {
- cc.freeBuf[i] = nil
- cc.mu.Unlock()
- return buf[:size]
- }
- }
- cc.mu.Unlock()
- return make([]byte, size)
-}
-
-func (cc *ClientConn) putFrameScratchBuffer(buf []byte) {
- cc.mu.Lock()
- defer cc.mu.Unlock()
- const maxBufs = 4 // arbitrary; 4 concurrent requests per conn? investigate.
- if len(cc.freeBuf) < maxBufs {
- cc.freeBuf = append(cc.freeBuf, buf)
- return
- }
- for i, old := range cc.freeBuf {
- if old == nil {
- cc.freeBuf[i] = buf
- return
- }
- }
- // forget about it.
-}
-
-// errRequestCanceled is a copy of net/http's errRequestCanceled because it's not
-// exported. At least they'll be DeepEqual for h1-vs-h2 comparisons tests.
-var errRequestCanceled = errors.New("net/http: request canceled")
-
-func commaSeparatedTrailers(req *http.Request) (string, error) {
- keys := make([]string, 0, len(req.Trailer))
- for k := range req.Trailer {
- k = http.CanonicalHeaderKey(k)
- switch k {
- case "Transfer-Encoding", "Trailer", "Content-Length":
- return "", &badStringError{"invalid Trailer key", k}
- }
- keys = append(keys, k)
- }
- if len(keys) > 0 {
- sort.Strings(keys)
- return strings.Join(keys, ","), nil
- }
- return "", nil
-}
-
-func (cc *ClientConn) responseHeaderTimeout() time.Duration {
- if cc.t.t1 != nil {
- return cc.t.t1.ResponseHeaderTimeout
- }
- // No way to do this (yet?) with just an http2.Transport. Probably
- // no need. Request.Cancel this is the new way. We only need to support
- // this for compatibility with the old http.Transport fields when
- // we're doing transparent http2.
- return 0
-}
-
-// checkConnHeaders checks whether req has any invalid connection-level headers.
-// per RFC 7540 section 8.1.2.2: Connection-Specific Header Fields.
-// Certain headers are special-cased as okay but not transmitted later.
-func checkConnHeaders(req *http.Request) error {
- if v := req.Header.Get("Upgrade"); v != "" {
- return fmt.Errorf("http2: invalid Upgrade request header: %q", req.Header["Upgrade"])
- }
- if vv := req.Header["Transfer-Encoding"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "chunked") {
- return fmt.Errorf("http2: invalid Transfer-Encoding request header: %q", vv)
- }
- if vv := req.Header["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "close" && vv[0] != "keep-alive") {
- return fmt.Errorf("http2: invalid Connection request header: %q", vv)
- }
- return nil
-}
-
-// actualContentLength returns a sanitized version of
-// req.ContentLength, where 0 actually means zero (not unknown) and -1
-// means unknown.
-func actualContentLength(req *http.Request) int64 {
- if req.Body == nil {
- return 0
- }
- if req.ContentLength != 0 {
- return req.ContentLength
- }
- return -1
-}
-
-func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
- if err := checkConnHeaders(req); err != nil {
- return nil, err
- }
- if cc.idleTimer != nil {
- cc.idleTimer.Stop()
- }
-
- trailers, err := commaSeparatedTrailers(req)
- if err != nil {
- return nil, err
- }
- hasTrailers := trailers != ""
-
- cc.mu.Lock()
- cc.lastActive = time.Now()
- if cc.closed || !cc.canTakeNewRequestLocked() {
- cc.mu.Unlock()
- return nil, errClientConnUnusable
- }
-
- body := req.Body
- hasBody := body != nil
- contentLen := actualContentLength(req)
-
- // TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
- var requestedGzip bool
- if !cc.t.disableCompression() &&
- req.Header.Get("Accept-Encoding") == "" &&
- req.Header.Get("Range") == "" &&
- req.Method != "HEAD" {
- // Request gzip only, not deflate. Deflate is ambiguous and
- // not as universally supported anyway.
- // See: http://www.gzip.org/zlib/zlib_faq.html#faq38
- //
- // Note that we don't request this for HEAD requests,
- // due to a bug in nginx:
- // http://trac.nginx.org/nginx/ticket/358
- // https://golang.org/issue/5522
- //
- // We don't request gzip if the request is for a range, since
- // auto-decoding a portion of a gzipped document will just fail
- // anyway. See https://golang.org/issue/8923
- requestedGzip = true
- }
-
- // we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is
- // sent by writeRequestBody below, along with any Trailers,
- // again in form HEADERS{1}, CONTINUATION{0,})
- hdrs, err := cc.encodeHeaders(req, requestedGzip, trailers, contentLen)
- if err != nil {
- cc.mu.Unlock()
- return nil, err
- }
-
- cs := cc.newStream()
- cs.req = req
- cs.trace = requestTrace(req)
- cs.requestedGzip = requestedGzip
- bodyWriter := cc.t.getBodyWriterState(cs, body)
- cs.on100 = bodyWriter.on100
-
- cc.wmu.Lock()
- endStream := !hasBody && !hasTrailers
- werr := cc.writeHeaders(cs.ID, endStream, hdrs)
- cc.wmu.Unlock()
- traceWroteHeaders(cs.trace)
- cc.mu.Unlock()
-
- if werr != nil {
- if hasBody {
- req.Body.Close() // per RoundTripper contract
- bodyWriter.cancel()
- }
- cc.forgetStreamID(cs.ID)
- // Don't bother sending a RST_STREAM (our write already failed;
- // no need to keep writing)
- traceWroteRequest(cs.trace, werr)
- return nil, werr
- }
-
- var respHeaderTimer <-chan time.Time
- if hasBody {
- bodyWriter.scheduleBodyWrite()
- } else {
- traceWroteRequest(cs.trace, nil)
- if d := cc.responseHeaderTimeout(); d != 0 {
- timer := time.NewTimer(d)
- defer timer.Stop()
- respHeaderTimer = timer.C
- }
- }
-
- readLoopResCh := cs.resc
- bodyWritten := false
- ctx := reqContext(req)
-
- handleReadLoopResponse := func(re resAndError) (*http.Response, error) {
- res := re.res
- if re.err != nil || res.StatusCode > 299 {
- // On error or status code 3xx, 4xx, 5xx, etc abort any
- // ongoing write, assuming that the server doesn't care
- // about our request body. If the server replied with 1xx or
- // 2xx, however, then assume the server DOES potentially
- // want our body (e.g. full-duplex streaming:
- // golang.org/issue/13444). If it turns out the server
- // doesn't, they'll RST_STREAM us soon enough. This is a
- // heuristic to avoid adding knobs to Transport. Hopefully
- // we can keep it.
- bodyWriter.cancel()
- cs.abortRequestBodyWrite(errStopReqBodyWrite)
- }
- if re.err != nil {
- if re.err == errClientConnGotGoAway {
- cc.mu.Lock()
- if cs.startedWrite {
- re.err = errClientConnGotGoAwayAfterSomeReqBody
- }
- cc.mu.Unlock()
- }
- cc.forgetStreamID(cs.ID)
- return nil, re.err
- }
- res.Request = req
- res.TLS = cc.tlsState
- return res, nil
- }
-
- for {
- select {
- case re := <-readLoopResCh:
- return handleReadLoopResponse(re)
- case <-respHeaderTimer:
- cc.forgetStreamID(cs.ID)
- if !hasBody || bodyWritten {
- cc.writeStreamReset(cs.ID, ErrCodeCancel, nil)
- } else {
- bodyWriter.cancel()
- cs.abortRequestBodyWrite(errStopReqBodyWriteAndCancel)
- }
- return nil, errTimeout
- case <-ctx.Done():
- cc.forgetStreamID(cs.ID)
- if !hasBody || bodyWritten {
- cc.writeStreamReset(cs.ID, ErrCodeCancel, nil)
- } else {
- bodyWriter.cancel()
- cs.abortRequestBodyWrite(errStopReqBodyWriteAndCancel)
- }
- return nil, ctx.Err()
- case <-req.Cancel:
- cc.forgetStreamID(cs.ID)
- if !hasBody || bodyWritten {
- cc.writeStreamReset(cs.ID, ErrCodeCancel, nil)
- } else {
- bodyWriter.cancel()
- cs.abortRequestBodyWrite(errStopReqBodyWriteAndCancel)
- }
- return nil, errRequestCanceled
- case <-cs.peerReset:
- // processResetStream already removed the
- // stream from the streams map; no need for
- // forgetStreamID.
- return nil, cs.resetErr
- case err := <-bodyWriter.resc:
- // Prefer the read loop's response, if available. Issue 16102.
- select {
- case re := <-readLoopResCh:
- return handleReadLoopResponse(re)
- default:
- }
- if err != nil {
- return nil, err
- }
- bodyWritten = true
- if d := cc.responseHeaderTimeout(); d != 0 {
- timer := time.NewTimer(d)
- defer timer.Stop()
- respHeaderTimer = timer.C
- }
- }
- }
-}
-
-// requires cc.wmu be held
-func (cc *ClientConn) writeHeaders(streamID uint32, endStream bool, hdrs []byte) error {
- first := true // first frame written (HEADERS is first, then CONTINUATION)
- frameSize := int(cc.maxFrameSize)
- for len(hdrs) > 0 && cc.werr == nil {
- chunk := hdrs
- if len(chunk) > frameSize {
- chunk = chunk[:frameSize]
- }
- hdrs = hdrs[len(chunk):]
- endHeaders := len(hdrs) == 0
- if first {
- cc.fr.WriteHeaders(HeadersFrameParam{
- StreamID: streamID,
- BlockFragment: chunk,
- EndStream: endStream,
- EndHeaders: endHeaders,
- })
- first = false
- } else {
- cc.fr.WriteContinuation(streamID, endHeaders, chunk)
- }
- }
- // TODO(bradfitz): this Flush could potentially block (as
- // could the WriteHeaders call(s) above), which means they
- // wouldn't respond to Request.Cancel being readable. That's
- // rare, but this should probably be in a goroutine.
- cc.bw.Flush()
- return cc.werr
-}
-
-// internal error values; they don't escape to callers
-var (
- // abort request body write; don't send cancel
- errStopReqBodyWrite = errors.New("http2: aborting request body write")
-
- // abort request body write, but send stream reset of cancel.
- errStopReqBodyWriteAndCancel = errors.New("http2: canceling request")
-)
-
-func (cs *clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) (err error) {
- cc := cs.cc
- sentEnd := false // whether we sent the final DATA frame w/ END_STREAM
- buf := cc.frameScratchBuffer()
- defer cc.putFrameScratchBuffer(buf)
-
- defer func() {
- traceWroteRequest(cs.trace, err)
- // TODO: write h12Compare test showing whether
- // Request.Body is closed by the Transport,
- // and in multiple cases: server replies <=299 and >299
- // while still writing request body
- cerr := bodyCloser.Close()
- if err == nil {
- err = cerr
- }
- }()
-
- req := cs.req
- hasTrailers := req.Trailer != nil
-
- var sawEOF bool
- for !sawEOF {
- n, err := body.Read(buf)
- if err == io.EOF {
- sawEOF = true
- err = nil
- } else if err != nil {
- return err
- }
-
- remain := buf[:n]
- for len(remain) > 0 && err == nil {
- var allowed int32
- allowed, err = cs.awaitFlowControl(len(remain))
- switch {
- case err == errStopReqBodyWrite:
- return err
- case err == errStopReqBodyWriteAndCancel:
- cc.writeStreamReset(cs.ID, ErrCodeCancel, nil)
- return err
- case err != nil:
- return err
- }
- cc.wmu.Lock()
- data := remain[:allowed]
- remain = remain[allowed:]
- sentEnd = sawEOF && len(remain) == 0 && !hasTrailers
- err = cc.fr.WriteData(cs.ID, sentEnd, data)
- if err == nil {
- // TODO(bradfitz): this flush is for latency, not bandwidth.
- // Most requests won't need this. Make this opt-in or
- // opt-out? Use some heuristic on the body type? Nagel-like
- // timers? Based on 'n'? Only last chunk of this for loop,
- // unless flow control tokens are low? For now, always.
- // If we change this, see comment below.
- err = cc.bw.Flush()
- }
- cc.wmu.Unlock()
- }
- if err != nil {
- return err
- }
- }
-
- if sentEnd {
- // Already sent END_STREAM (which implies we have no
- // trailers) and flushed, because currently all
- // WriteData frames above get a flush. So we're done.
- return nil
- }
-
- var trls []byte
- if hasTrailers {
- cc.mu.Lock()
- defer cc.mu.Unlock()
- trls = cc.encodeTrailers(req)
- }
-
- cc.wmu.Lock()
- defer cc.wmu.Unlock()
-
- // Two ways to send END_STREAM: either with trailers, or
- // with an empty DATA frame.
- if len(trls) > 0 {
- err = cc.writeHeaders(cs.ID, true, trls)
- } else {
- err = cc.fr.WriteData(cs.ID, true, nil)
- }
- if ferr := cc.bw.Flush(); ferr != nil && err == nil {
- err = ferr
- }
- return err
-}
-
-// awaitFlowControl waits for [1, min(maxBytes, cc.cs.maxFrameSize)] flow
-// control tokens from the server.
-// It returns either the non-zero number of tokens taken or an error
-// if the stream is dead.
-func (cs *clientStream) awaitFlowControl(maxBytes int) (taken int32, err error) {
- cc := cs.cc
- cc.mu.Lock()
- defer cc.mu.Unlock()
- for {
- if cc.closed {
- return 0, errClientConnClosed
- }
- if cs.stopReqBody != nil {
- return 0, cs.stopReqBody
- }
- if err := cs.checkResetOrDone(); err != nil {
- return 0, err
- }
- if a := cs.flow.available(); a > 0 {
- take := a
- if int(take) > maxBytes {
-
- take = int32(maxBytes) // can't truncate int; take is int32
- }
- if take > int32(cc.maxFrameSize) {
- take = int32(cc.maxFrameSize)
- }
- cs.flow.take(take)
- return take, nil
- }
- cc.cond.Wait()
- }
-}
-
-type badStringError struct {
- what string
- str string
-}
-
-func (e *badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) }
-
-// requires cc.mu be held.
-func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trailers string, contentLength int64) ([]byte, error) {
- cc.hbuf.Reset()
-
- host := req.Host
- if host == "" {
- host = req.URL.Host
- }
- host, err := httplex.PunycodeHostPort(host)
- if err != nil {
- return nil, err
- }
-
- var path string
- if req.Method != "CONNECT" {
- path = req.URL.RequestURI()
- if !validPseudoPath(path) {
- orig := path
- path = strings.TrimPrefix(path, req.URL.Scheme+"://"+host)
- if !validPseudoPath(path) {
- if req.URL.Opaque != "" {
- return nil, fmt.Errorf("invalid request :path %q from URL.Opaque = %q", orig, req.URL.Opaque)
- } else {
- return nil, fmt.Errorf("invalid request :path %q", orig)
- }
- }
- }
- }
-
- // Check for any invalid headers and return an error before we
- // potentially pollute our hpack state. (We want to be able to
- // continue to reuse the hpack encoder for future requests)
- for k, vv := range req.Header {
- if !httplex.ValidHeaderFieldName(k) {
- return nil, fmt.Errorf("invalid HTTP header name %q", k)
- }
- for _, v := range vv {
- if !httplex.ValidHeaderFieldValue(v) {
- return nil, fmt.Errorf("invalid HTTP header value %q for header %q", v, k)
- }
- }
- }
-
- // 8.1.2.3 Request Pseudo-Header Fields
- // The :path pseudo-header field includes the path and query parts of the
- // target URI (the path-absolute production and optionally a '?' character
- // followed by the query production (see Sections 3.3 and 3.4 of
- // [RFC3986]).
- cc.writeHeader(":authority", host)
- cc.writeHeader(":method", req.Method)
- if req.Method != "CONNECT" {
- cc.writeHeader(":path", path)
- cc.writeHeader(":scheme", req.URL.Scheme)
- }
- if trailers != "" {
- cc.writeHeader("trailer", trailers)
- }
-
- var didUA bool
- for k, vv := range req.Header {
- lowKey := strings.ToLower(k)
- switch lowKey {
- case "host", "content-length":
- // Host is :authority, already sent.
- // Content-Length is automatic, set below.
- continue
- case "connection", "proxy-connection", "transfer-encoding", "upgrade", "keep-alive":
- // Per 8.1.2.2 Connection-Specific Header
- // Fields, don't send connection-specific
- // fields. We have already checked if any
- // are error-worthy so just ignore the rest.
- continue
- case "user-agent":
- // Match Go's http1 behavior: at most one
- // User-Agent. If set to nil or empty string,
- // then omit it. Otherwise if not mentioned,
- // include the default (below).
- didUA = true
- if len(vv) < 1 {
- continue
- }
- vv = vv[:1]
- if vv[0] == "" {
- continue
- }
- }
- for _, v := range vv {
- cc.writeHeader(lowKey, v)
- }
- }
- if shouldSendReqContentLength(req.Method, contentLength) {
- cc.writeHeader("content-length", strconv.FormatInt(contentLength, 10))
- }
- if addGzipHeader {
- cc.writeHeader("accept-encoding", "gzip")
- }
- if !didUA {
- cc.writeHeader("user-agent", defaultUserAgent)
- }
- return cc.hbuf.Bytes(), nil
-}
-
-// shouldSendReqContentLength reports whether the http2.Transport should send
-// a "content-length" request header. This logic is basically a copy of the net/http
-// transferWriter.shouldSendContentLength.
-// The contentLength is the corrected contentLength (so 0 means actually 0, not unknown).
-// -1 means unknown.
-func shouldSendReqContentLength(method string, contentLength int64) bool {
- if contentLength > 0 {
- return true
- }
- if contentLength < 0 {
- return false
- }
- // For zero bodies, whether we send a content-length depends on the method.
- // It also kinda doesn't matter for http2 either way, with END_STREAM.
- switch method {
- case "POST", "PUT", "PATCH":
- return true
- default:
- return false
- }
-}
-
-// requires cc.mu be held.
-func (cc *ClientConn) encodeTrailers(req *http.Request) []byte {
- cc.hbuf.Reset()
- for k, vv := range req.Trailer {
- // Transfer-Encoding, etc.. have already been filter at the
- // start of RoundTrip
- lowKey := strings.ToLower(k)
- for _, v := range vv {
- cc.writeHeader(lowKey, v)
- }
- }
- return cc.hbuf.Bytes()
-}
-
-func (cc *ClientConn) writeHeader(name, value string) {
- if VerboseLogs {
- log.Printf("http2: Transport encoding header %q = %q", name, value)
- }
- cc.henc.WriteField(hpack.HeaderField{Name: name, Value: value})
-}
-
-type resAndError struct {
- res *http.Response
- err error
-}
-
-// requires cc.mu be held.
-func (cc *ClientConn) newStream() *clientStream {
- cs := &clientStream{
- cc: cc,
- ID: cc.nextStreamID,
- resc: make(chan resAndError, 1),
- peerReset: make(chan struct{}),
- done: make(chan struct{}),
- }
- cs.flow.add(int32(cc.initialWindowSize))
- cs.flow.setConnFlow(&cc.flow)
- cs.inflow.add(transportDefaultStreamFlow)
- cs.inflow.setConnFlow(&cc.inflow)
- cc.nextStreamID += 2
- cc.streams[cs.ID] = cs
- return cs
-}
-
-func (cc *ClientConn) forgetStreamID(id uint32) {
- cc.streamByID(id, true)
-}
-
-func (cc *ClientConn) streamByID(id uint32, andRemove bool) *clientStream {
- cc.mu.Lock()
- defer cc.mu.Unlock()
- cs := cc.streams[id]
- if andRemove && cs != nil && !cc.closed {
- cc.lastActive = time.Now()
- delete(cc.streams, id)
- if len(cc.streams) == 0 && cc.idleTimer != nil {
- cc.idleTimer.Reset(cc.idleTimeout)
- }
- close(cs.done)
- cc.cond.Broadcast() // wake up checkResetOrDone via clientStream.awaitFlowControl
- }
- return cs
-}
-
-// clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop.
-type clientConnReadLoop struct {
- cc *ClientConn
- activeRes map[uint32]*clientStream // keyed by streamID
- closeWhenIdle bool
-}
-
-// readLoop runs in its own goroutine and reads and dispatches frames.
-func (cc *ClientConn) readLoop() {
- rl := &clientConnReadLoop{
- cc: cc,
- activeRes: make(map[uint32]*clientStream),
- }
-
- defer rl.cleanup()
- cc.readerErr = rl.run()
- if ce, ok := cc.readerErr.(ConnectionError); ok {
- cc.wmu.Lock()
- cc.fr.WriteGoAway(0, ErrCode(ce), nil)
- cc.wmu.Unlock()
- }
-}
-
-// GoAwayError is returned by the Transport when the server closes the
-// TCP connection after sending a GOAWAY frame.
-type GoAwayError struct {
- LastStreamID uint32
- ErrCode ErrCode
- DebugData string
-}
-
-func (e GoAwayError) Error() string {
- return fmt.Sprintf("http2: server sent GOAWAY and closed the connection; LastStreamID=%v, ErrCode=%v, debug=%q",
- e.LastStreamID, e.ErrCode, e.DebugData)
-}
-
-func isEOFOrNetReadError(err error) bool {
- if err == io.EOF {
- return true
- }
- ne, ok := err.(*net.OpError)
- return ok && ne.Op == "read"
-}
-
-func (rl *clientConnReadLoop) cleanup() {
- cc := rl.cc
- defer cc.tconn.Close()
- defer cc.t.connPool().MarkDead(cc)
- defer close(cc.readerDone)
-
- if cc.idleTimer != nil {
- cc.idleTimer.Stop()
- }
-
- // Close any response bodies if the server closes prematurely.
- // TODO: also do this if we've written the headers but not
- // gotten a response yet.
- err := cc.readerErr
- cc.mu.Lock()
- if cc.goAway != nil && isEOFOrNetReadError(err) {
- err = GoAwayError{
- LastStreamID: cc.goAway.LastStreamID,
- ErrCode: cc.goAway.ErrCode,
- DebugData: cc.goAwayDebug,
- }
- } else if err == io.EOF {
- err = io.ErrUnexpectedEOF
- }
- for _, cs := range rl.activeRes {
- cs.bufPipe.CloseWithError(err)
- }
- for _, cs := range cc.streams {
- select {
- case cs.resc <- resAndError{err: err}:
- default:
- }
- close(cs.done)
- }
- cc.closed = true
- cc.cond.Broadcast()
- cc.mu.Unlock()
-}
-
-func (rl *clientConnReadLoop) run() error {
- cc := rl.cc
- rl.closeWhenIdle = cc.t.disableKeepAlives() || cc.singleUse
- gotReply := false // ever saw a HEADERS reply
- gotSettings := false
- for {
- f, err := cc.fr.ReadFrame()
- if err != nil {
- cc.vlogf("http2: Transport readFrame error on conn %p: (%T) %v", cc, err, err)
- }
- if se, ok := err.(StreamError); ok {
- if cs := cc.streamByID(se.StreamID, true /*ended; remove it*/); cs != nil {
- cs.cc.writeStreamReset(cs.ID, se.Code, err)
- if se.Cause == nil {
- se.Cause = cc.fr.errDetail
- }
- rl.endStreamError(cs, se)
- }
- continue
- } else if err != nil {
- return err
- }
- if VerboseLogs {
- cc.vlogf("http2: Transport received %s", summarizeFrame(f))
- }
- if !gotSettings {
- if _, ok := f.(*SettingsFrame); !ok {
- cc.logf("protocol error: received %T before a SETTINGS frame", f)
- return ConnectionError(ErrCodeProtocol)
- }
- gotSettings = true
- }
- maybeIdle := false // whether frame might transition us to idle
-
- switch f := f.(type) {
- case *MetaHeadersFrame:
- err = rl.processHeaders(f)
- maybeIdle = true
- gotReply = true
- case *DataFrame:
- err = rl.processData(f)
- maybeIdle = true
- case *GoAwayFrame:
- err = rl.processGoAway(f)
- maybeIdle = true
- case *RSTStreamFrame:
- err = rl.processResetStream(f)
- maybeIdle = true
- case *SettingsFrame:
- err = rl.processSettings(f)
- case *PushPromiseFrame:
- err = rl.processPushPromise(f)
- case *WindowUpdateFrame:
- err = rl.processWindowUpdate(f)
- case *PingFrame:
- err = rl.processPing(f)
- default:
- cc.logf("Transport: unhandled response frame type %T", f)
- }
- if err != nil {
- if VerboseLogs {
- cc.vlogf("http2: Transport conn %p received error from processing frame %v: %v", cc, summarizeFrame(f), err)
- }
- return err
- }
- if rl.closeWhenIdle && gotReply && maybeIdle && len(rl.activeRes) == 0 {
- cc.closeIfIdle()
- }
- }
-}
-
-func (rl *clientConnReadLoop) processHeaders(f *MetaHeadersFrame) error {
- cc := rl.cc
- cs := cc.streamByID(f.StreamID, f.StreamEnded())
- if cs == nil {
- // We'd get here if we canceled a request while the
- // server had its response still in flight. So if this
- // was just something we canceled, ignore it.
- return nil
- }
- if !cs.firstByte {
- if cs.trace != nil {
- // TODO(bradfitz): move first response byte earlier,
- // when we first read the 9 byte header, not waiting
- // until all the HEADERS+CONTINUATION frames have been
- // merged. This works for now.
- traceFirstResponseByte(cs.trace)
- }
- cs.firstByte = true
- }
- if !cs.pastHeaders {
- cs.pastHeaders = true
- } else {
- return rl.processTrailers(cs, f)
- }
-
- res, err := rl.handleResponse(cs, f)
- if err != nil {
- if _, ok := err.(ConnectionError); ok {
- return err
- }
- // Any other error type is a stream error.
- cs.cc.writeStreamReset(f.StreamID, ErrCodeProtocol, err)
- cs.resc <- resAndError{err: err}
- return nil // return nil from process* funcs to keep conn alive
- }
- if res == nil {
- // (nil, nil) special case. See handleResponse docs.
- return nil
- }
- if res.Body != noBody {
- rl.activeRes[cs.ID] = cs
- }
- cs.resTrailer = &res.Trailer
- cs.resc <- resAndError{res: res}
- return nil
-}
-
-// may return error types nil, or ConnectionError. Any other error value
-// is a StreamError of type ErrCodeProtocol. The returned error in that case
-// is the detail.
-//
-// As a special case, handleResponse may return (nil, nil) to skip the
-// frame (currently only used for 100 expect continue). This special
-// case is going away after Issue 13851 is fixed.
-func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFrame) (*http.Response, error) {
- if f.Truncated {
- return nil, errResponseHeaderListSize
- }
-
- status := f.PseudoValue("status")
- if status == "" {
- return nil, errors.New("missing status pseudo header")
- }
- statusCode, err := strconv.Atoi(status)
- if err != nil {
- return nil, errors.New("malformed non-numeric status pseudo header")
- }
-
- if statusCode == 100 {
- traceGot100Continue(cs.trace)
- if cs.on100 != nil {
- cs.on100() // forces any write delay timer to fire
- }
- cs.pastHeaders = false // do it all again
- return nil, nil
- }
-
- header := make(http.Header)
- res := &http.Response{
- Proto: "HTTP/2.0",
- ProtoMajor: 2,
- Header: header,
- StatusCode: statusCode,
- Status: status + " " + http.StatusText(statusCode),
- }
- for _, hf := range f.RegularFields() {
- key := http.CanonicalHeaderKey(hf.Name)
- if key == "Trailer" {
- t := res.Trailer
- if t == nil {
- t = make(http.Header)
- res.Trailer = t
- }
- foreachHeaderElement(hf.Value, func(v string) {
- t[http.CanonicalHeaderKey(v)] = nil
- })
- } else {
- header[key] = append(header[key], hf.Value)
- }
- }
-
- streamEnded := f.StreamEnded()
- isHead := cs.req.Method == "HEAD"
- if !streamEnded || isHead {
- res.ContentLength = -1
- if clens := res.Header["Content-Length"]; len(clens) == 1 {
- if clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil {
- res.ContentLength = clen64
- } else {
- // TODO: care? unlike http/1, it won't mess up our framing, so it's
- // more safe smuggling-wise to ignore.
- }
- } else if len(clens) > 1 {
- // TODO: care? unlike http/1, it won't mess up our framing, so it's
- // more safe smuggling-wise to ignore.
- }
- }
-
- if streamEnded || isHead {
- res.Body = noBody
- return res, nil
- }
-
- buf := new(bytes.Buffer) // TODO(bradfitz): recycle this garbage
- cs.bufPipe = pipe{b: buf}
- cs.bytesRemain = res.ContentLength
- res.Body = transportResponseBody{cs}
- go cs.awaitRequestCancel(cs.req)
-
- if cs.requestedGzip && res.Header.Get("Content-Encoding") == "gzip" {
- res.Header.Del("Content-Encoding")
- res.Header.Del("Content-Length")
- res.ContentLength = -1
- res.Body = &gzipReader{body: res.Body}
- setResponseUncompressed(res)
- }
- return res, nil
-}
-
-func (rl *clientConnReadLoop) processTrailers(cs *clientStream, f *MetaHeadersFrame) error {
- if cs.pastTrailers {
- // Too many HEADERS frames for this stream.
- return ConnectionError(ErrCodeProtocol)
- }
- cs.pastTrailers = true
- if !f.StreamEnded() {
- // We expect that any headers for trailers also
- // has END_STREAM.
- return ConnectionError(ErrCodeProtocol)
- }
- if len(f.PseudoFields()) > 0 {
- // No pseudo header fields are defined for trailers.
- // TODO: ConnectionError might be overly harsh? Check.
- return ConnectionError(ErrCodeProtocol)
- }
-
- trailer := make(http.Header)
- for _, hf := range f.RegularFields() {
- key := http.CanonicalHeaderKey(hf.Name)
- trailer[key] = append(trailer[key], hf.Value)
- }
- cs.trailer = trailer
-
- rl.endStream(cs)
- return nil
-}
-
-// transportResponseBody is the concrete type of Transport.RoundTrip's
-// Response.Body. It is an io.ReadCloser. On Read, it reads from cs.body.
-// On Close it sends RST_STREAM if EOF wasn't already seen.
-type transportResponseBody struct {
- cs *clientStream
-}
-
-func (b transportResponseBody) Read(p []byte) (n int, err error) {
- cs := b.cs
- cc := cs.cc
-
- if cs.readErr != nil {
- return 0, cs.readErr
- }
- n, err = b.cs.bufPipe.Read(p)
- if cs.bytesRemain != -1 {
- if int64(n) > cs.bytesRemain {
- n = int(cs.bytesRemain)
- if err == nil {
- err = errors.New("net/http: server replied with more than declared Content-Length; truncated")
- cc.writeStreamReset(cs.ID, ErrCodeProtocol, err)
- }
- cs.readErr = err
- return int(cs.bytesRemain), err
- }
- cs.bytesRemain -= int64(n)
- if err == io.EOF && cs.bytesRemain > 0 {
- err = io.ErrUnexpectedEOF
- cs.readErr = err
- return n, err
- }
- }
- if n == 0 {
- // No flow control tokens to send back.
- return
- }
-
- cc.mu.Lock()
- defer cc.mu.Unlock()
-
- var connAdd, streamAdd int32
- // Check the conn-level first, before the stream-level.
- if v := cc.inflow.available(); v < transportDefaultConnFlow/2 {
- connAdd = transportDefaultConnFlow - v
- cc.inflow.add(connAdd)
- }
- if err == nil { // No need to refresh if the stream is over or failed.
- // Consider any buffered body data (read from the conn but not
- // consumed by the client) when computing flow control for this
- // stream.
- v := int(cs.inflow.available()) + cs.bufPipe.Len()
- if v < transportDefaultStreamFlow-transportDefaultStreamMinRefresh {
- streamAdd = int32(transportDefaultStreamFlow - v)
- cs.inflow.add(streamAdd)
- }
- }
- if connAdd != 0 || streamAdd != 0 {
- cc.wmu.Lock()
- defer cc.wmu.Unlock()
- if connAdd != 0 {
- cc.fr.WriteWindowUpdate(0, mustUint31(connAdd))
- }
- if streamAdd != 0 {
- cc.fr.WriteWindowUpdate(cs.ID, mustUint31(streamAdd))
- }
- cc.bw.Flush()
- }
- return
-}
-
-var errClosedResponseBody = errors.New("http2: response body closed")
-
-func (b transportResponseBody) Close() error {
- cs := b.cs
- cc := cs.cc
-
- serverSentStreamEnd := cs.bufPipe.Err() == io.EOF
- unread := cs.bufPipe.Len()
-
- if unread > 0 || !serverSentStreamEnd {
- cc.mu.Lock()
- cc.wmu.Lock()
- if !serverSentStreamEnd {
- cc.fr.WriteRSTStream(cs.ID, ErrCodeCancel)
- }
- // Return connection-level flow control.
- if unread > 0 {
- cc.inflow.add(int32(unread))
- cc.fr.WriteWindowUpdate(0, uint32(unread))
- }
- cc.bw.Flush()
- cc.wmu.Unlock()
- cc.mu.Unlock()
- }
-
- cs.bufPipe.BreakWithError(errClosedResponseBody)
- return nil
-}
-
-func (rl *clientConnReadLoop) processData(f *DataFrame) error {
- cc := rl.cc
- cs := cc.streamByID(f.StreamID, f.StreamEnded())
- data := f.Data()
- if cs == nil {
- cc.mu.Lock()
- neverSent := cc.nextStreamID
- cc.mu.Unlock()
- if f.StreamID >= neverSent {
- // We never asked for this.
- cc.logf("http2: Transport received unsolicited DATA frame; closing connection")
- return ConnectionError(ErrCodeProtocol)
- }
- // We probably did ask for this, but canceled. Just ignore it.
- // TODO: be stricter here? only silently ignore things which
- // we canceled, but not things which were closed normally
- // by the peer? Tough without accumulating too much state.
-
- // But at least return their flow control:
- if f.Length > 0 {
- cc.mu.Lock()
- cc.inflow.add(int32(f.Length))
- cc.mu.Unlock()
-
- cc.wmu.Lock()
- cc.fr.WriteWindowUpdate(0, uint32(f.Length))
- cc.bw.Flush()
- cc.wmu.Unlock()
- }
- return nil
- }
- if f.Length > 0 {
- if len(data) > 0 && cs.bufPipe.b == nil {
- // Data frame after it's already closed?
- cc.logf("http2: Transport received DATA frame for closed stream; closing connection")
- return ConnectionError(ErrCodeProtocol)
- }
-
- // Check connection-level flow control.
- cc.mu.Lock()
- if cs.inflow.available() >= int32(f.Length) {
- cs.inflow.take(int32(f.Length))
- } else {
- cc.mu.Unlock()
- return ConnectionError(ErrCodeFlowControl)
- }
- // Return any padded flow control now, since we won't
- // refund it later on body reads.
- if pad := int32(f.Length) - int32(len(data)); pad > 0 {
- cs.inflow.add(pad)
- cc.inflow.add(pad)
- cc.wmu.Lock()
- cc.fr.WriteWindowUpdate(0, uint32(pad))
- cc.fr.WriteWindowUpdate(cs.ID, uint32(pad))
- cc.bw.Flush()
- cc.wmu.Unlock()
- }
- didReset := cs.didReset
- cc.mu.Unlock()
-
- if len(data) > 0 && !didReset {
- if _, err := cs.bufPipe.Write(data); err != nil {
- rl.endStreamError(cs, err)
- return err
- }
- }
- }
-
- if f.StreamEnded() {
- rl.endStream(cs)
- }
- return nil
-}
-
-var errInvalidTrailers = errors.New("http2: invalid trailers")
-
-func (rl *clientConnReadLoop) endStream(cs *clientStream) {
- // TODO: check that any declared content-length matches, like
- // server.go's (*stream).endStream method.
- rl.endStreamError(cs, nil)
-}
-
-func (rl *clientConnReadLoop) endStreamError(cs *clientStream, err error) {
- var code func()
- if err == nil {
- err = io.EOF
- code = cs.copyTrailers
- }
- cs.bufPipe.closeWithErrorAndCode(err, code)
- delete(rl.activeRes, cs.ID)
- if isConnectionCloseRequest(cs.req) {
- rl.closeWhenIdle = true
- }
-
- select {
- case cs.resc <- resAndError{err: err}:
- default:
- }
-}
-
-func (cs *clientStream) copyTrailers() {
- for k, vv := range cs.trailer {
- t := cs.resTrailer
- if *t == nil {
- *t = make(http.Header)
- }
- (*t)[k] = vv
- }
-}
-
-func (rl *clientConnReadLoop) processGoAway(f *GoAwayFrame) error {
- cc := rl.cc
- cc.t.connPool().MarkDead(cc)
- if f.ErrCode != 0 {
- // TODO: deal with GOAWAY more. particularly the error code
- cc.vlogf("transport got GOAWAY with error code = %v", f.ErrCode)
- }
- cc.setGoAway(f)
- return nil
-}
-
-func (rl *clientConnReadLoop) processSettings(f *SettingsFrame) error {
- cc := rl.cc
- cc.mu.Lock()
- defer cc.mu.Unlock()
-
- if f.IsAck() {
- if cc.wantSettingsAck {
- cc.wantSettingsAck = false
- return nil
- }
- return ConnectionError(ErrCodeProtocol)
- }
-
- err := f.ForeachSetting(func(s Setting) error {
- switch s.ID {
- case SettingMaxFrameSize:
- cc.maxFrameSize = s.Val
- case SettingMaxConcurrentStreams:
- cc.maxConcurrentStreams = s.Val
- case SettingInitialWindowSize:
- // Values above the maximum flow-control
- // window size of 2^31-1 MUST be treated as a
- // connection error (Section 5.4.1) of type
- // FLOW_CONTROL_ERROR.
- if s.Val > math.MaxInt32 {
- return ConnectionError(ErrCodeFlowControl)
- }
-
- // Adjust flow control of currently-open
- // frames by the difference of the old initial
- // window size and this one.
- delta := int32(s.Val) - int32(cc.initialWindowSize)
- for _, cs := range cc.streams {
- cs.flow.add(delta)
- }
- cc.cond.Broadcast()
-
- cc.initialWindowSize = s.Val
- default:
- // TODO(bradfitz): handle more settings? SETTINGS_HEADER_TABLE_SIZE probably.
- cc.vlogf("Unhandled Setting: %v", s)
- }
- return nil
- })
- if err != nil {
- return err
- }
-
- cc.wmu.Lock()
- defer cc.wmu.Unlock()
-
- cc.fr.WriteSettingsAck()
- cc.bw.Flush()
- return cc.werr
-}
-
-func (rl *clientConnReadLoop) processWindowUpdate(f *WindowUpdateFrame) error {
- cc := rl.cc
- cs := cc.streamByID(f.StreamID, false)
- if f.StreamID != 0 && cs == nil {
- return nil
- }
-
- cc.mu.Lock()
- defer cc.mu.Unlock()
-
- fl := &cc.flow
- if cs != nil {
- fl = &cs.flow
- }
- if !fl.add(int32(f.Increment)) {
- return ConnectionError(ErrCodeFlowControl)
- }
- cc.cond.Broadcast()
- return nil
-}
-
-func (rl *clientConnReadLoop) processResetStream(f *RSTStreamFrame) error {
- cs := rl.cc.streamByID(f.StreamID, true)
- if cs == nil {
- // TODO: return error if server tries to RST_STEAM an idle stream
- return nil
- }
- select {
- case <-cs.peerReset:
- // Already reset.
- // This is the only goroutine
- // which closes this, so there
- // isn't a race.
- default:
- err := streamError(cs.ID, f.ErrCode)
- cs.resetErr = err
- close(cs.peerReset)
- cs.bufPipe.CloseWithError(err)
- cs.cc.cond.Broadcast() // wake up checkResetOrDone via clientStream.awaitFlowControl
- }
- delete(rl.activeRes, cs.ID)
- return nil
-}
-
-// Ping sends a PING frame to the server and waits for the ack.
-// Public implementation is in go17.go and not_go17.go
-func (cc *ClientConn) ping(ctx contextContext) error {
- c := make(chan struct{})
- // Generate a random payload
- var p [8]byte
- for {
- if _, err := rand.Read(p[:]); err != nil {
- return err
- }
- cc.mu.Lock()
- // check for dup before insert
- if _, found := cc.pings[p]; !found {
- cc.pings[p] = c
- cc.mu.Unlock()
- break
- }
- cc.mu.Unlock()
- }
- cc.wmu.Lock()
- if err := cc.fr.WritePing(false, p); err != nil {
- cc.wmu.Unlock()
- return err
- }
- if err := cc.bw.Flush(); err != nil {
- cc.wmu.Unlock()
- return err
- }
- cc.wmu.Unlock()
- select {
- case <-c:
- return nil
- case <-ctx.Done():
- return ctx.Err()
- case <-cc.readerDone:
- // connection closed
- return cc.readerErr
- }
-}
-
-func (rl *clientConnReadLoop) processPing(f *PingFrame) error {
- if f.IsAck() {
- cc := rl.cc
- cc.mu.Lock()
- defer cc.mu.Unlock()
- // If ack, notify listener if any
- if c, ok := cc.pings[f.Data]; ok {
- close(c)
- delete(cc.pings, f.Data)
- }
- return nil
- }
- cc := rl.cc
- cc.wmu.Lock()
- defer cc.wmu.Unlock()
- if err := cc.fr.WritePing(true, f.Data); err != nil {
- return err
- }
- return cc.bw.Flush()
-}
-
-func (rl *clientConnReadLoop) processPushPromise(f *PushPromiseFrame) error {
- // We told the peer we don't want them.
- // Spec says:
- // "PUSH_PROMISE MUST NOT be sent if the SETTINGS_ENABLE_PUSH
- // setting of the peer endpoint is set to 0. An endpoint that
- // has set this setting and has received acknowledgement MUST
- // treat the receipt of a PUSH_PROMISE frame as a connection
- // error (Section 5.4.1) of type PROTOCOL_ERROR."
- return ConnectionError(ErrCodeProtocol)
-}
-
-func (cc *ClientConn) writeStreamReset(streamID uint32, code ErrCode, err error) {
- // TODO: map err to more interesting error codes, once the
- // HTTP community comes up with some. But currently for
- // RST_STREAM there's no equivalent to GOAWAY frame's debug
- // data, and the error codes are all pretty vague ("cancel").
- cc.wmu.Lock()
- cc.fr.WriteRSTStream(streamID, code)
- cc.bw.Flush()
- cc.wmu.Unlock()
-}
-
-var (
- errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit")
- errPseudoTrailers = errors.New("http2: invalid pseudo header in trailers")
-)
-
-func (cc *ClientConn) logf(format string, args ...interface{}) {
- cc.t.logf(format, args...)
-}
-
-func (cc *ClientConn) vlogf(format string, args ...interface{}) {
- cc.t.vlogf(format, args...)
-}
-
-func (t *Transport) vlogf(format string, args ...interface{}) {
- if VerboseLogs {
- t.logf(format, args...)
- }
-}
-
-func (t *Transport) logf(format string, args ...interface{}) {
- log.Printf(format, args...)
-}
-
-var noBody io.ReadCloser = ioutil.NopCloser(bytes.NewReader(nil))
-
-func strSliceContains(ss []string, s string) bool {
- for _, v := range ss {
- if v == s {
- return true
- }
- }
- return false
-}
-
-type erringRoundTripper struct{ err error }
-
-func (rt erringRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { return nil, rt.err }
-
-// gzipReader wraps a response body so it can lazily
-// call gzip.NewReader on the first call to Read
-type gzipReader struct {
- body io.ReadCloser // underlying Response.Body
- zr *gzip.Reader // lazily-initialized gzip reader
- zerr error // sticky error
-}
-
-func (gz *gzipReader) Read(p []byte) (n int, err error) {
- if gz.zerr != nil {
- return 0, gz.zerr
- }
- if gz.zr == nil {
- gz.zr, err = gzip.NewReader(gz.body)
- if err != nil {
- gz.zerr = err
- return 0, err
- }
- }
- return gz.zr.Read(p)
-}
-
-func (gz *gzipReader) Close() error {
- return gz.body.Close()
-}
-
-type errorReader struct{ err error }
-
-func (r errorReader) Read(p []byte) (int, error) { return 0, r.err }
-
-// bodyWriterState encapsulates various state around the Transport's writing
-// of the request body, particularly regarding doing delayed writes of the body
-// when the request contains "Expect: 100-continue".
-type bodyWriterState struct {
- cs *clientStream
- timer *time.Timer // if non-nil, we're doing a delayed write
- fnonce *sync.Once // to call fn with
- fn func() // the code to run in the goroutine, writing the body
- resc chan error // result of fn's execution
- delay time.Duration // how long we should delay a delayed write for
-}
-
-func (t *Transport) getBodyWriterState(cs *clientStream, body io.Reader) (s bodyWriterState) {
- s.cs = cs
- if body == nil {
- return
- }
- resc := make(chan error, 1)
- s.resc = resc
- s.fn = func() {
- cs.cc.mu.Lock()
- cs.startedWrite = true
- cs.cc.mu.Unlock()
- resc <- cs.writeRequestBody(body, cs.req.Body)
- }
- s.delay = t.expectContinueTimeout()
- if s.delay == 0 ||
- !httplex.HeaderValuesContainsToken(
- cs.req.Header["Expect"],
- "100-continue") {
- return
- }
- s.fnonce = new(sync.Once)
-
- // Arm the timer with a very large duration, which we'll
- // intentionally lower later. It has to be large now because
- // we need a handle to it before writing the headers, but the
- // s.delay value is defined to not start until after the
- // request headers were written.
- const hugeDuration = 365 * 24 * time.Hour
- s.timer = time.AfterFunc(hugeDuration, func() {
- s.fnonce.Do(s.fn)
- })
- return
-}
-
-func (s bodyWriterState) cancel() {
- if s.timer != nil {
- s.timer.Stop()
- }
-}
-
-func (s bodyWriterState) on100() {
- if s.timer == nil {
- // If we didn't do a delayed write, ignore the server's
- // bogus 100 continue response.
- return
- }
- s.timer.Stop()
- go func() { s.fnonce.Do(s.fn) }()
-}
-
-// scheduleBodyWrite starts writing the body, either immediately (in
-// the common case) or after the delay timeout. It should not be
-// called until after the headers have been written.
-func (s bodyWriterState) scheduleBodyWrite() {
- if s.timer == nil {
- // We're not doing a delayed write (see
- // getBodyWriterState), so just start the writing
- // goroutine immediately.
- go s.fn()
- return
- }
- traceWait100Continue(s.cs.trace)
- if s.timer.Stop() {
- s.timer.Reset(s.delay)
- }
-}
-
-// isConnectionCloseRequest reports whether req should use its own
-// connection for a single request and then close the connection.
-func isConnectionCloseRequest(req *http.Request) bool {
- return req.Close || httplex.HeaderValuesContainsToken(req.Header["Connection"], "close")
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/transport_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/transport_test.go
deleted file mode 100644
index 7ae8ff7..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/transport_test.go
+++ /dev/null
@@ -1,2916 +0,0 @@
-// 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 http2
-
-import (
- "bufio"
- "bytes"
- "crypto/tls"
- "errors"
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "math/rand"
- "net"
- "net/http"
- "net/url"
- "os"
- "reflect"
- "runtime"
- "sort"
- "strconv"
- "strings"
- "sync"
- "sync/atomic"
- "testing"
- "time"
-
- "golang.org/x/net/http2/hpack"
-)
-
-var (
- extNet = flag.Bool("extnet", false, "do external network tests")
- transportHost = flag.String("transporthost", "http2.golang.org", "hostname to use for TestTransport")
- insecure = flag.Bool("insecure", false, "insecure TLS dials") // TODO: dead code. remove?
-)
-
-var tlsConfigInsecure = &tls.Config{InsecureSkipVerify: true}
-
-type testContext struct{}
-
-func (testContext) Done() <-chan struct{} { return make(chan struct{}) }
-func (testContext) Err() error { panic("should not be called") }
-func (testContext) Deadline() (deadline time.Time, ok bool) { return time.Time{}, false }
-func (testContext) Value(key interface{}) interface{} { return nil }
-
-func TestTransportExternal(t *testing.T) {
- if !*extNet {
- t.Skip("skipping external network test")
- }
- req, _ := http.NewRequest("GET", "https://"+*transportHost+"/", nil)
- rt := &Transport{TLSClientConfig: tlsConfigInsecure}
- res, err := rt.RoundTrip(req)
- if err != nil {
- t.Fatalf("%v", err)
- }
- res.Write(os.Stdout)
-}
-
-type fakeTLSConn struct {
- net.Conn
-}
-
-func (c *fakeTLSConn) ConnectionState() tls.ConnectionState {
- return tls.ConnectionState{
- Version: tls.VersionTLS12,
- }
-}
-
-func startH2cServer(t *testing.T) net.Listener {
- h2Server := &Server{}
- l := newLocalListener(t)
- go func() {
- conn, err := l.Accept()
- if err != nil {
- t.Error(err)
- return
- }
- h2Server.ServeConn(&fakeTLSConn{conn}, &ServeConnOpts{Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintf(w, "Hello, %v, http: %v", r.URL.Path, r.TLS == nil)
- })})
- }()
- return l
-}
-
-func TestTransportH2c(t *testing.T) {
- l := startH2cServer(t)
- defer l.Close()
- req, err := http.NewRequest("GET", "http://"+l.Addr().String()+"/foobar", nil)
- if err != nil {
- t.Fatal(err)
- }
- tr := &Transport{
- AllowHTTP: true,
- DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
- return net.Dial(network, addr)
- },
- }
- res, err := tr.RoundTrip(req)
- if err != nil {
- t.Fatal(err)
- }
- if res.ProtoMajor != 2 {
- t.Fatal("proto not h2c")
- }
- body, err := ioutil.ReadAll(res.Body)
- if err != nil {
- t.Fatal(err)
- }
- if got, want := string(body), "Hello, /foobar, http: true"; got != want {
- t.Fatalf("response got %v, want %v", got, want)
- }
-}
-
-func TestTransport(t *testing.T) {
- const body = "sup"
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- io.WriteString(w, body)
- }, optOnlyServer)
- defer st.Close()
-
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
-
- req, err := http.NewRequest("GET", st.ts.URL, nil)
- if err != nil {
- t.Fatal(err)
- }
- res, err := tr.RoundTrip(req)
- if err != nil {
- t.Fatal(err)
- }
- defer res.Body.Close()
-
- t.Logf("Got res: %+v", res)
- if g, w := res.StatusCode, 200; g != w {
- t.Errorf("StatusCode = %v; want %v", g, w)
- }
- if g, w := res.Status, "200 OK"; g != w {
- t.Errorf("Status = %q; want %q", g, w)
- }
- wantHeader := http.Header{
- "Content-Length": []string{"3"},
- "Content-Type": []string{"text/plain; charset=utf-8"},
- "Date": []string{"XXX"}, // see cleanDate
- }
- cleanDate(res)
- if !reflect.DeepEqual(res.Header, wantHeader) {
- t.Errorf("res Header = %v; want %v", res.Header, wantHeader)
- }
- if res.Request != req {
- t.Errorf("Response.Request = %p; want %p", res.Request, req)
- }
- if res.TLS == nil {
- t.Error("Response.TLS = nil; want non-nil")
- }
- slurp, err := ioutil.ReadAll(res.Body)
- if err != nil {
- t.Errorf("Body read: %v", err)
- } else if string(slurp) != body {
- t.Errorf("Body = %q; want %q", slurp, body)
- }
-}
-
-func onSameConn(t *testing.T, modReq func(*http.Request)) bool {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- io.WriteString(w, r.RemoteAddr)
- }, optOnlyServer, func(c net.Conn, st http.ConnState) {
- t.Logf("conn %v is now state %v", c.RemoteAddr(), st)
- })
- defer st.Close()
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
- get := func() string {
- req, err := http.NewRequest("GET", st.ts.URL, nil)
- if err != nil {
- t.Fatal(err)
- }
- modReq(req)
- res, err := tr.RoundTrip(req)
- if err != nil {
- t.Fatal(err)
- }
- defer res.Body.Close()
- slurp, err := ioutil.ReadAll(res.Body)
- if err != nil {
- t.Fatalf("Body read: %v", err)
- }
- addr := strings.TrimSpace(string(slurp))
- if addr == "" {
- t.Fatalf("didn't get an addr in response")
- }
- return addr
- }
- first := get()
- second := get()
- return first == second
-}
-
-func TestTransportReusesConns(t *testing.T) {
- if !onSameConn(t, func(*http.Request) {}) {
- t.Errorf("first and second responses were on different connections")
- }
-}
-
-func TestTransportReusesConn_RequestClose(t *testing.T) {
- if onSameConn(t, func(r *http.Request) { r.Close = true }) {
- t.Errorf("first and second responses were not on different connections")
- }
-}
-
-func TestTransportReusesConn_ConnClose(t *testing.T) {
- if onSameConn(t, func(r *http.Request) { r.Header.Set("Connection", "close") }) {
- t.Errorf("first and second responses were not on different connections")
- }
-}
-
-// Tests that the Transport only keeps one pending dial open per destination address.
-// https://golang.org/issue/13397
-func TestTransportGroupsPendingDials(t *testing.T) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- io.WriteString(w, r.RemoteAddr)
- }, optOnlyServer)
- defer st.Close()
- tr := &Transport{
- TLSClientConfig: tlsConfigInsecure,
- }
- defer tr.CloseIdleConnections()
- var (
- mu sync.Mutex
- dials = map[string]int{}
- )
- var wg sync.WaitGroup
- for i := 0; i < 10; i++ {
- wg.Add(1)
- go func() {
- defer wg.Done()
- req, err := http.NewRequest("GET", st.ts.URL, nil)
- if err != nil {
- t.Error(err)
- return
- }
- res, err := tr.RoundTrip(req)
- if err != nil {
- t.Error(err)
- return
- }
- defer res.Body.Close()
- slurp, err := ioutil.ReadAll(res.Body)
- if err != nil {
- t.Errorf("Body read: %v", err)
- }
- addr := strings.TrimSpace(string(slurp))
- if addr == "" {
- t.Errorf("didn't get an addr in response")
- }
- mu.Lock()
- dials[addr]++
- mu.Unlock()
- }()
- }
- wg.Wait()
- if len(dials) != 1 {
- t.Errorf("saw %d dials; want 1: %v", len(dials), dials)
- }
- tr.CloseIdleConnections()
- if err := retry(50, 10*time.Millisecond, func() error {
- cp, ok := tr.connPool().(*clientConnPool)
- if !ok {
- return fmt.Errorf("Conn pool is %T; want *clientConnPool", tr.connPool())
- }
- cp.mu.Lock()
- defer cp.mu.Unlock()
- if len(cp.dialing) != 0 {
- return fmt.Errorf("dialing map = %v; want empty", cp.dialing)
- }
- if len(cp.conns) != 0 {
- return fmt.Errorf("conns = %v; want empty", cp.conns)
- }
- if len(cp.keys) != 0 {
- return fmt.Errorf("keys = %v; want empty", cp.keys)
- }
- return nil
- }); err != nil {
- t.Errorf("State of pool after CloseIdleConnections: %v", err)
- }
-}
-
-func retry(tries int, delay time.Duration, fn func() error) error {
- var err error
- for i := 0; i < tries; i++ {
- err = fn()
- if err == nil {
- return nil
- }
- time.Sleep(delay)
- }
- return err
-}
-
-func TestTransportAbortClosesPipes(t *testing.T) {
- shutdown := make(chan struct{})
- st := newServerTester(t,
- func(w http.ResponseWriter, r *http.Request) {
- w.(http.Flusher).Flush()
- <-shutdown
- },
- optOnlyServer,
- )
- defer st.Close()
- defer close(shutdown) // we must shutdown before st.Close() to avoid hanging
-
- done := make(chan struct{})
- requestMade := make(chan struct{})
- go func() {
- defer close(done)
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- req, err := http.NewRequest("GET", st.ts.URL, nil)
- if err != nil {
- t.Fatal(err)
- }
- res, err := tr.RoundTrip(req)
- if err != nil {
- t.Fatal(err)
- }
- defer res.Body.Close()
- close(requestMade)
- _, err = ioutil.ReadAll(res.Body)
- if err == nil {
- t.Error("expected error from res.Body.Read")
- }
- }()
-
- <-requestMade
- // Now force the serve loop to end, via closing the connection.
- st.closeConn()
- // deadlock? that's a bug.
- select {
- case <-done:
- case <-time.After(3 * time.Second):
- t.Fatal("timeout")
- }
-}
-
-// TODO: merge this with TestTransportBody to make TestTransportRequest? This
-// could be a table-driven test with extra goodies.
-func TestTransportPath(t *testing.T) {
- gotc := make(chan *url.URL, 1)
- st := newServerTester(t,
- func(w http.ResponseWriter, r *http.Request) {
- gotc <- r.URL
- },
- optOnlyServer,
- )
- defer st.Close()
-
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
- const (
- path = "/testpath"
- query = "q=1"
- )
- surl := st.ts.URL + path + "?" + query
- req, err := http.NewRequest("POST", surl, nil)
- if err != nil {
- t.Fatal(err)
- }
- c := &http.Client{Transport: tr}
- res, err := c.Do(req)
- if err != nil {
- t.Fatal(err)
- }
- defer res.Body.Close()
- got := <-gotc
- if got.Path != path {
- t.Errorf("Read Path = %q; want %q", got.Path, path)
- }
- if got.RawQuery != query {
- t.Errorf("Read RawQuery = %q; want %q", got.RawQuery, query)
- }
-}
-
-func randString(n int) string {
- rnd := rand.New(rand.NewSource(int64(n)))
- b := make([]byte, n)
- for i := range b {
- b[i] = byte(rnd.Intn(256))
- }
- return string(b)
-}
-
-type panicReader struct{}
-
-func (panicReader) Read([]byte) (int, error) { panic("unexpected Read") }
-func (panicReader) Close() error { panic("unexpected Close") }
-
-func TestActualContentLength(t *testing.T) {
- tests := []struct {
- req *http.Request
- want int64
- }{
- // Verify we don't read from Body:
- 0: {
- req: &http.Request{Body: panicReader{}},
- want: -1,
- },
- // nil Body means 0, regardless of ContentLength:
- 1: {
- req: &http.Request{Body: nil, ContentLength: 5},
- want: 0,
- },
- // ContentLength is used if set.
- 2: {
- req: &http.Request{Body: panicReader{}, ContentLength: 5},
- want: 5,
- },
- }
- for i, tt := range tests {
- got := actualContentLength(tt.req)
- if got != tt.want {
- t.Errorf("test[%d]: got %d; want %d", i, got, tt.want)
- }
- }
-}
-
-func TestTransportBody(t *testing.T) {
- bodyTests := []struct {
- body string
- noContentLen bool
- }{
- {body: "some message"},
- {body: "some message", noContentLen: true},
- {body: strings.Repeat("a", 1<<20), noContentLen: true},
- {body: strings.Repeat("a", 1<<20)},
- {body: randString(16<<10 - 1)},
- {body: randString(16 << 10)},
- {body: randString(16<<10 + 1)},
- {body: randString(512<<10 - 1)},
- {body: randString(512 << 10)},
- {body: randString(512<<10 + 1)},
- {body: randString(1<<20 - 1)},
- {body: randString(1 << 20)},
- {body: randString(1<<20 + 2)},
- }
-
- type reqInfo struct {
- req *http.Request
- slurp []byte
- err error
- }
- gotc := make(chan reqInfo, 1)
- st := newServerTester(t,
- func(w http.ResponseWriter, r *http.Request) {
- slurp, err := ioutil.ReadAll(r.Body)
- if err != nil {
- gotc <- reqInfo{err: err}
- } else {
- gotc <- reqInfo{req: r, slurp: slurp}
- }
- },
- optOnlyServer,
- )
- defer st.Close()
-
- for i, tt := range bodyTests {
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
-
- var body io.Reader = strings.NewReader(tt.body)
- if tt.noContentLen {
- body = struct{ io.Reader }{body} // just a Reader, hiding concrete type and other methods
- }
- req, err := http.NewRequest("POST", st.ts.URL, body)
- if err != nil {
- t.Fatalf("#%d: %v", i, err)
- }
- c := &http.Client{Transport: tr}
- res, err := c.Do(req)
- if err != nil {
- t.Fatalf("#%d: %v", i, err)
- }
- defer res.Body.Close()
- ri := <-gotc
- if ri.err != nil {
- t.Errorf("#%d: read error: %v", i, ri.err)
- continue
- }
- if got := string(ri.slurp); got != tt.body {
- t.Errorf("#%d: Read body mismatch.\n got: %q (len %d)\nwant: %q (len %d)", i, shortString(got), len(got), shortString(tt.body), len(tt.body))
- }
- wantLen := int64(len(tt.body))
- if tt.noContentLen && tt.body != "" {
- wantLen = -1
- }
- if ri.req.ContentLength != wantLen {
- t.Errorf("#%d. handler got ContentLength = %v; want %v", i, ri.req.ContentLength, wantLen)
- }
- }
-}
-
-func shortString(v string) string {
- const maxLen = 100
- if len(v) <= maxLen {
- return v
- }
- return fmt.Sprintf("%v[...%d bytes omitted...]%v", v[:maxLen/2], len(v)-maxLen, v[len(v)-maxLen/2:])
-}
-
-func TestTransportDialTLS(t *testing.T) {
- var mu sync.Mutex // guards following
- var gotReq, didDial bool
-
- ts := newServerTester(t,
- func(w http.ResponseWriter, r *http.Request) {
- mu.Lock()
- gotReq = true
- mu.Unlock()
- },
- optOnlyServer,
- )
- defer ts.Close()
- tr := &Transport{
- DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) {
- mu.Lock()
- didDial = true
- mu.Unlock()
- cfg.InsecureSkipVerify = true
- c, err := tls.Dial(netw, addr, cfg)
- if err != nil {
- return nil, err
- }
- return c, c.Handshake()
- },
- }
- defer tr.CloseIdleConnections()
- client := &http.Client{Transport: tr}
- res, err := client.Get(ts.ts.URL)
- if err != nil {
- t.Fatal(err)
- }
- res.Body.Close()
- mu.Lock()
- if !gotReq {
- t.Error("didn't get request")
- }
- if !didDial {
- t.Error("didn't use dial hook")
- }
-}
-
-func TestConfigureTransport(t *testing.T) {
- t1 := &http.Transport{}
- err := ConfigureTransport(t1)
- if err == errTransportVersion {
- t.Skip(err)
- }
- if err != nil {
- t.Fatal(err)
- }
- if got := fmt.Sprintf("%#v", t1); !strings.Contains(got, `"h2"`) {
- // Laziness, to avoid buildtags.
- t.Errorf("stringification of HTTP/1 transport didn't contain \"h2\": %v", got)
- }
- wantNextProtos := []string{"h2", "http/1.1"}
- if t1.TLSClientConfig == nil {
- t.Errorf("nil t1.TLSClientConfig")
- } else if !reflect.DeepEqual(t1.TLSClientConfig.NextProtos, wantNextProtos) {
- t.Errorf("TLSClientConfig.NextProtos = %q; want %q", t1.TLSClientConfig.NextProtos, wantNextProtos)
- }
- if err := ConfigureTransport(t1); err == nil {
- t.Error("unexpected success on second call to ConfigureTransport")
- }
-
- // And does it work?
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- io.WriteString(w, r.Proto)
- }, optOnlyServer)
- defer st.Close()
-
- t1.TLSClientConfig.InsecureSkipVerify = true
- c := &http.Client{Transport: t1}
- res, err := c.Get(st.ts.URL)
- if err != nil {
- t.Fatal(err)
- }
- slurp, err := ioutil.ReadAll(res.Body)
- if err != nil {
- t.Fatal(err)
- }
- if got, want := string(slurp), "HTTP/2.0"; got != want {
- t.Errorf("body = %q; want %q", got, want)
- }
-}
-
-type capitalizeReader struct {
- r io.Reader
-}
-
-func (cr capitalizeReader) Read(p []byte) (n int, err error) {
- n, err = cr.r.Read(p)
- for i, b := range p[:n] {
- if b >= 'a' && b <= 'z' {
- p[i] = b - ('a' - 'A')
- }
- }
- return
-}
-
-type flushWriter struct {
- w io.Writer
-}
-
-func (fw flushWriter) Write(p []byte) (n int, err error) {
- n, err = fw.w.Write(p)
- if f, ok := fw.w.(http.Flusher); ok {
- f.Flush()
- }
- return
-}
-
-type clientTester struct {
- t *testing.T
- tr *Transport
- sc, cc net.Conn // server and client conn
- fr *Framer // server's framer
- client func() error
- server func() error
-}
-
-func newClientTester(t *testing.T) *clientTester {
- var dialOnce struct {
- sync.Mutex
- dialed bool
- }
- ct := &clientTester{
- t: t,
- }
- ct.tr = &Transport{
- TLSClientConfig: tlsConfigInsecure,
- DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
- dialOnce.Lock()
- defer dialOnce.Unlock()
- if dialOnce.dialed {
- return nil, errors.New("only one dial allowed in test mode")
- }
- dialOnce.dialed = true
- return ct.cc, nil
- },
- }
-
- ln := newLocalListener(t)
- cc, err := net.Dial("tcp", ln.Addr().String())
- if err != nil {
- t.Fatal(err)
-
- }
- sc, err := ln.Accept()
- if err != nil {
- t.Fatal(err)
- }
- ln.Close()
- ct.cc = cc
- ct.sc = sc
- ct.fr = NewFramer(sc, sc)
- return ct
-}
-
-func newLocalListener(t *testing.T) net.Listener {
- ln, err := net.Listen("tcp4", "127.0.0.1:0")
- if err == nil {
- return ln
- }
- ln, err = net.Listen("tcp6", "[::1]:0")
- if err != nil {
- t.Fatal(err)
- }
- return ln
-}
-
-func (ct *clientTester) greet() {
- buf := make([]byte, len(ClientPreface))
- _, err := io.ReadFull(ct.sc, buf)
- if err != nil {
- ct.t.Fatalf("reading client preface: %v", err)
- }
- f, err := ct.fr.ReadFrame()
- if err != nil {
- ct.t.Fatalf("Reading client settings frame: %v", err)
- }
- if sf, ok := f.(*SettingsFrame); !ok {
- ct.t.Fatalf("Wanted client settings frame; got %v", f)
- _ = sf // stash it away?
- }
- if err := ct.fr.WriteSettings(); err != nil {
- ct.t.Fatal(err)
- }
- if err := ct.fr.WriteSettingsAck(); err != nil {
- ct.t.Fatal(err)
- }
-}
-
-func (ct *clientTester) readNonSettingsFrame() (Frame, error) {
- for {
- f, err := ct.fr.ReadFrame()
- if err != nil {
- return nil, err
- }
- if _, ok := f.(*SettingsFrame); ok {
- continue
- }
- return f, nil
- }
-}
-
-func (ct *clientTester) cleanup() {
- ct.tr.CloseIdleConnections()
-}
-
-func (ct *clientTester) run() {
- errc := make(chan error, 2)
- ct.start("client", errc, ct.client)
- ct.start("server", errc, ct.server)
- defer ct.cleanup()
- for i := 0; i < 2; i++ {
- if err := <-errc; err != nil {
- ct.t.Error(err)
- return
- }
- }
-}
-
-func (ct *clientTester) start(which string, errc chan<- error, fn func() error) {
- go func() {
- finished := false
- var err error
- defer func() {
- if !finished {
- err = fmt.Errorf("%s goroutine didn't finish.", which)
- } else if err != nil {
- err = fmt.Errorf("%s: %v", which, err)
- }
- errc <- err
- }()
- err = fn()
- finished = true
- }()
-}
-
-func (ct *clientTester) readFrame() (Frame, error) {
- return readFrameTimeout(ct.fr, 2*time.Second)
-}
-
-func (ct *clientTester) firstHeaders() (*HeadersFrame, error) {
- for {
- f, err := ct.readFrame()
- if err != nil {
- return nil, fmt.Errorf("ReadFrame while waiting for Headers: %v", err)
- }
- switch f.(type) {
- case *WindowUpdateFrame, *SettingsFrame:
- continue
- }
- hf, ok := f.(*HeadersFrame)
- if !ok {
- return nil, fmt.Errorf("Got %T; want HeadersFrame", f)
- }
- return hf, nil
- }
-}
-
-type countingReader struct {
- n *int64
-}
-
-func (r countingReader) Read(p []byte) (n int, err error) {
- for i := range p {
- p[i] = byte(i)
- }
- atomic.AddInt64(r.n, int64(len(p)))
- return len(p), err
-}
-
-func TestTransportReqBodyAfterResponse_200(t *testing.T) { testTransportReqBodyAfterResponse(t, 200) }
-func TestTransportReqBodyAfterResponse_403(t *testing.T) { testTransportReqBodyAfterResponse(t, 403) }
-
-func testTransportReqBodyAfterResponse(t *testing.T, status int) {
- const bodySize = 10 << 20
- clientDone := make(chan struct{})
- ct := newClientTester(t)
- ct.client = func() error {
- defer ct.cc.(*net.TCPConn).CloseWrite()
- defer close(clientDone)
-
- var n int64 // atomic
- req, err := http.NewRequest("PUT", "https://dummy.tld/", io.LimitReader(countingReader{&n}, bodySize))
- if err != nil {
- return err
- }
- res, err := ct.tr.RoundTrip(req)
- if err != nil {
- return fmt.Errorf("RoundTrip: %v", err)
- }
- defer res.Body.Close()
- if res.StatusCode != status {
- return fmt.Errorf("status code = %v; want %v", res.StatusCode, status)
- }
- slurp, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return fmt.Errorf("Slurp: %v", err)
- }
- if len(slurp) > 0 {
- return fmt.Errorf("unexpected body: %q", slurp)
- }
- if status == 200 {
- if got := atomic.LoadInt64(&n); got != bodySize {
- return fmt.Errorf("For 200 response, Transport wrote %d bytes; want %d", got, bodySize)
- }
- } else {
- if got := atomic.LoadInt64(&n); got == 0 || got >= bodySize {
- return fmt.Errorf("For %d response, Transport wrote %d bytes; want (0,%d) exclusive", status, got, bodySize)
- }
- }
- return nil
- }
- ct.server = func() error {
- ct.greet()
- var buf bytes.Buffer
- enc := hpack.NewEncoder(&buf)
- var dataRecv int64
- var closed bool
- for {
- f, err := ct.fr.ReadFrame()
- if err != nil {
- select {
- case <-clientDone:
- // If the client's done, it
- // will have reported any
- // errors on its side.
- return nil
- default:
- return err
- }
- }
- //println(fmt.Sprintf("server got frame: %v", f))
- switch f := f.(type) {
- case *WindowUpdateFrame, *SettingsFrame:
- case *HeadersFrame:
- if !f.HeadersEnded() {
- return fmt.Errorf("headers should have END_HEADERS be ended: %v", f)
- }
- if f.StreamEnded() {
- return fmt.Errorf("headers contains END_STREAM unexpectedly: %v", f)
- }
- case *DataFrame:
- dataLen := len(f.Data())
- if dataLen > 0 {
- if dataRecv == 0 {
- enc.WriteField(hpack.HeaderField{Name: ":status", Value: strconv.Itoa(status)})
- ct.fr.WriteHeaders(HeadersFrameParam{
- StreamID: f.StreamID,
- EndHeaders: true,
- EndStream: false,
- BlockFragment: buf.Bytes(),
- })
- }
- if err := ct.fr.WriteWindowUpdate(0, uint32(dataLen)); err != nil {
- return err
- }
- if err := ct.fr.WriteWindowUpdate(f.StreamID, uint32(dataLen)); err != nil {
- return err
- }
- }
- dataRecv += int64(dataLen)
-
- if !closed && ((status != 200 && dataRecv > 0) ||
- (status == 200 && dataRecv == bodySize)) {
- closed = true
- if err := ct.fr.WriteData(f.StreamID, true, nil); err != nil {
- return err
- }
- }
- default:
- return fmt.Errorf("Unexpected client frame %v", f)
- }
- }
- }
- ct.run()
-}
-
-// See golang.org/issue/13444
-func TestTransportFullDuplex(t *testing.T) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(200) // redundant but for clarity
- w.(http.Flusher).Flush()
- io.Copy(flushWriter{w}, capitalizeReader{r.Body})
- fmt.Fprintf(w, "bye.\n")
- }, optOnlyServer)
- defer st.Close()
-
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
- c := &http.Client{Transport: tr}
-
- pr, pw := io.Pipe()
- req, err := http.NewRequest("PUT", st.ts.URL, ioutil.NopCloser(pr))
- if err != nil {
- t.Fatal(err)
- }
- req.ContentLength = -1
- res, err := c.Do(req)
- if err != nil {
- t.Fatal(err)
- }
- defer res.Body.Close()
- if res.StatusCode != 200 {
- t.Fatalf("StatusCode = %v; want %v", res.StatusCode, 200)
- }
- bs := bufio.NewScanner(res.Body)
- want := func(v string) {
- if !bs.Scan() {
- t.Fatalf("wanted to read %q but Scan() = false, err = %v", v, bs.Err())
- }
- }
- write := func(v string) {
- _, err := io.WriteString(pw, v)
- if err != nil {
- t.Fatalf("pipe write: %v", err)
- }
- }
- write("foo\n")
- want("FOO")
- write("bar\n")
- want("BAR")
- pw.Close()
- want("bye.")
- if err := bs.Err(); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestTransportConnectRequest(t *testing.T) {
- gotc := make(chan *http.Request, 1)
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- gotc <- r
- }, optOnlyServer)
- defer st.Close()
-
- u, err := url.Parse(st.ts.URL)
- if err != nil {
- t.Fatal(err)
- }
-
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
- c := &http.Client{Transport: tr}
-
- tests := []struct {
- req *http.Request
- want string
- }{
- {
- req: &http.Request{
- Method: "CONNECT",
- Header: http.Header{},
- URL: u,
- },
- want: u.Host,
- },
- {
- req: &http.Request{
- Method: "CONNECT",
- Header: http.Header{},
- URL: u,
- Host: "example.com:123",
- },
- want: "example.com:123",
- },
- }
-
- for i, tt := range tests {
- res, err := c.Do(tt.req)
- if err != nil {
- t.Errorf("%d. RoundTrip = %v", i, err)
- continue
- }
- res.Body.Close()
- req := <-gotc
- if req.Method != "CONNECT" {
- t.Errorf("method = %q; want CONNECT", req.Method)
- }
- if req.Host != tt.want {
- t.Errorf("Host = %q; want %q", req.Host, tt.want)
- }
- if req.URL.Host != tt.want {
- t.Errorf("URL.Host = %q; want %q", req.URL.Host, tt.want)
- }
- }
-}
-
-type headerType int
-
-const (
- noHeader headerType = iota // omitted
- oneHeader
- splitHeader // broken into continuation on purpose
-)
-
-const (
- f0 = noHeader
- f1 = oneHeader
- f2 = splitHeader
- d0 = false
- d1 = true
-)
-
-// Test all 36 combinations of response frame orders:
-// (3 ways of 100-continue) * (2 ways of headers) * (2 ways of data) * (3 ways of trailers):func TestTransportResponsePattern_00f0(t *testing.T) { testTransportResponsePattern(h0, h1, false, h0) }
-// Generated by http://play.golang.org/p/SScqYKJYXd
-func TestTransportResPattern_c0h1d0t0(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f0) }
-func TestTransportResPattern_c0h1d0t1(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f1) }
-func TestTransportResPattern_c0h1d0t2(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f2) }
-func TestTransportResPattern_c0h1d1t0(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f0) }
-func TestTransportResPattern_c0h1d1t1(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f1) }
-func TestTransportResPattern_c0h1d1t2(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f2) }
-func TestTransportResPattern_c0h2d0t0(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f0) }
-func TestTransportResPattern_c0h2d0t1(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f1) }
-func TestTransportResPattern_c0h2d0t2(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f2) }
-func TestTransportResPattern_c0h2d1t0(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f0) }
-func TestTransportResPattern_c0h2d1t1(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f1) }
-func TestTransportResPattern_c0h2d1t2(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f2) }
-func TestTransportResPattern_c1h1d0t0(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f0) }
-func TestTransportResPattern_c1h1d0t1(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f1) }
-func TestTransportResPattern_c1h1d0t2(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f2) }
-func TestTransportResPattern_c1h1d1t0(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f0) }
-func TestTransportResPattern_c1h1d1t1(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f1) }
-func TestTransportResPattern_c1h1d1t2(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f2) }
-func TestTransportResPattern_c1h2d0t0(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f0) }
-func TestTransportResPattern_c1h2d0t1(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f1) }
-func TestTransportResPattern_c1h2d0t2(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f2) }
-func TestTransportResPattern_c1h2d1t0(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f0) }
-func TestTransportResPattern_c1h2d1t1(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f1) }
-func TestTransportResPattern_c1h2d1t2(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f2) }
-func TestTransportResPattern_c2h1d0t0(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f0) }
-func TestTransportResPattern_c2h1d0t1(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f1) }
-func TestTransportResPattern_c2h1d0t2(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f2) }
-func TestTransportResPattern_c2h1d1t0(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f0) }
-func TestTransportResPattern_c2h1d1t1(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f1) }
-func TestTransportResPattern_c2h1d1t2(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f2) }
-func TestTransportResPattern_c2h2d0t0(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f0) }
-func TestTransportResPattern_c2h2d0t1(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f1) }
-func TestTransportResPattern_c2h2d0t2(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f2) }
-func TestTransportResPattern_c2h2d1t0(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f0) }
-func TestTransportResPattern_c2h2d1t1(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f1) }
-func TestTransportResPattern_c2h2d1t2(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f2) }
-
-func testTransportResPattern(t *testing.T, expect100Continue, resHeader headerType, withData bool, trailers headerType) {
- const reqBody = "some request body"
- const resBody = "some response body"
-
- if resHeader == noHeader {
- // TODO: test 100-continue followed by immediate
- // server stream reset, without headers in the middle?
- panic("invalid combination")
- }
-
- ct := newClientTester(t)
- ct.client = func() error {
- req, _ := http.NewRequest("POST", "https://dummy.tld/", strings.NewReader(reqBody))
- if expect100Continue != noHeader {
- req.Header.Set("Expect", "100-continue")
- }
- res, err := ct.tr.RoundTrip(req)
- if err != nil {
- return fmt.Errorf("RoundTrip: %v", err)
- }
- defer res.Body.Close()
- if res.StatusCode != 200 {
- return fmt.Errorf("status code = %v; want 200", res.StatusCode)
- }
- slurp, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return fmt.Errorf("Slurp: %v", err)
- }
- wantBody := resBody
- if !withData {
- wantBody = ""
- }
- if string(slurp) != wantBody {
- return fmt.Errorf("body = %q; want %q", slurp, wantBody)
- }
- if trailers == noHeader {
- if len(res.Trailer) > 0 {
- t.Errorf("Trailer = %v; want none", res.Trailer)
- }
- } else {
- want := http.Header{"Some-Trailer": {"some-value"}}
- if !reflect.DeepEqual(res.Trailer, want) {
- t.Errorf("Trailer = %v; want %v", res.Trailer, want)
- }
- }
- return nil
- }
- ct.server = func() error {
- ct.greet()
- var buf bytes.Buffer
- enc := hpack.NewEncoder(&buf)
-
- for {
- f, err := ct.fr.ReadFrame()
- if err != nil {
- return err
- }
- endStream := false
- send := func(mode headerType) {
- hbf := buf.Bytes()
- switch mode {
- case oneHeader:
- ct.fr.WriteHeaders(HeadersFrameParam{
- StreamID: f.Header().StreamID,
- EndHeaders: true,
- EndStream: endStream,
- BlockFragment: hbf,
- })
- case splitHeader:
- if len(hbf) < 2 {
- panic("too small")
- }
- ct.fr.WriteHeaders(HeadersFrameParam{
- StreamID: f.Header().StreamID,
- EndHeaders: false,
- EndStream: endStream,
- BlockFragment: hbf[:1],
- })
- ct.fr.WriteContinuation(f.Header().StreamID, true, hbf[1:])
- default:
- panic("bogus mode")
- }
- }
- switch f := f.(type) {
- case *WindowUpdateFrame, *SettingsFrame:
- case *DataFrame:
- if !f.StreamEnded() {
- // No need to send flow control tokens. The test request body is tiny.
- continue
- }
- // Response headers (1+ frames; 1 or 2 in this test, but never 0)
- {
- buf.Reset()
- enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
- enc.WriteField(hpack.HeaderField{Name: "x-foo", Value: "blah"})
- enc.WriteField(hpack.HeaderField{Name: "x-bar", Value: "more"})
- if trailers != noHeader {
- enc.WriteField(hpack.HeaderField{Name: "trailer", Value: "some-trailer"})
- }
- endStream = withData == false && trailers == noHeader
- send(resHeader)
- }
- if withData {
- endStream = trailers == noHeader
- ct.fr.WriteData(f.StreamID, endStream, []byte(resBody))
- }
- if trailers != noHeader {
- endStream = true
- buf.Reset()
- enc.WriteField(hpack.HeaderField{Name: "some-trailer", Value: "some-value"})
- send(trailers)
- }
- if endStream {
- return nil
- }
- case *HeadersFrame:
- if expect100Continue != noHeader {
- buf.Reset()
- enc.WriteField(hpack.HeaderField{Name: ":status", Value: "100"})
- send(expect100Continue)
- }
- }
- }
- }
- ct.run()
-}
-
-func TestTransportReceiveUndeclaredTrailer(t *testing.T) {
- ct := newClientTester(t)
- ct.client = func() error {
- req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
- res, err := ct.tr.RoundTrip(req)
- if err != nil {
- return fmt.Errorf("RoundTrip: %v", err)
- }
- defer res.Body.Close()
- if res.StatusCode != 200 {
- return fmt.Errorf("status code = %v; want 200", res.StatusCode)
- }
- slurp, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return fmt.Errorf("res.Body ReadAll error = %q, %v; want %v", slurp, err, nil)
- }
- if len(slurp) > 0 {
- return fmt.Errorf("body = %q; want nothing", slurp)
- }
- if _, ok := res.Trailer["Some-Trailer"]; !ok {
- return fmt.Errorf("expected Some-Trailer")
- }
- return nil
- }
- ct.server = func() error {
- ct.greet()
-
- var n int
- var hf *HeadersFrame
- for hf == nil && n < 10 {
- f, err := ct.fr.ReadFrame()
- if err != nil {
- return err
- }
- hf, _ = f.(*HeadersFrame)
- n++
- }
-
- var buf bytes.Buffer
- enc := hpack.NewEncoder(&buf)
-
- // send headers without Trailer header
- enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
- ct.fr.WriteHeaders(HeadersFrameParam{
- StreamID: hf.StreamID,
- EndHeaders: true,
- EndStream: false,
- BlockFragment: buf.Bytes(),
- })
-
- // send trailers
- buf.Reset()
- enc.WriteField(hpack.HeaderField{Name: "some-trailer", Value: "I'm an undeclared Trailer!"})
- ct.fr.WriteHeaders(HeadersFrameParam{
- StreamID: hf.StreamID,
- EndHeaders: true,
- EndStream: true,
- BlockFragment: buf.Bytes(),
- })
- return nil
- }
- ct.run()
-}
-
-func TestTransportInvalidTrailer_Pseudo1(t *testing.T) {
- testTransportInvalidTrailer_Pseudo(t, oneHeader)
-}
-func TestTransportInvalidTrailer_Pseudo2(t *testing.T) {
- testTransportInvalidTrailer_Pseudo(t, splitHeader)
-}
-func testTransportInvalidTrailer_Pseudo(t *testing.T, trailers headerType) {
- testInvalidTrailer(t, trailers, pseudoHeaderError(":colon"), func(enc *hpack.Encoder) {
- enc.WriteField(hpack.HeaderField{Name: ":colon", Value: "foo"})
- enc.WriteField(hpack.HeaderField{Name: "foo", Value: "bar"})
- })
-}
-
-func TestTransportInvalidTrailer_Capital1(t *testing.T) {
- testTransportInvalidTrailer_Capital(t, oneHeader)
-}
-func TestTransportInvalidTrailer_Capital2(t *testing.T) {
- testTransportInvalidTrailer_Capital(t, splitHeader)
-}
-func testTransportInvalidTrailer_Capital(t *testing.T, trailers headerType) {
- testInvalidTrailer(t, trailers, headerFieldNameError("Capital"), func(enc *hpack.Encoder) {
- enc.WriteField(hpack.HeaderField{Name: "foo", Value: "bar"})
- enc.WriteField(hpack.HeaderField{Name: "Capital", Value: "bad"})
- })
-}
-func TestTransportInvalidTrailer_EmptyFieldName(t *testing.T) {
- testInvalidTrailer(t, oneHeader, headerFieldNameError(""), func(enc *hpack.Encoder) {
- enc.WriteField(hpack.HeaderField{Name: "", Value: "bad"})
- })
-}
-func TestTransportInvalidTrailer_BinaryFieldValue(t *testing.T) {
- testInvalidTrailer(t, oneHeader, headerFieldValueError("has\nnewline"), func(enc *hpack.Encoder) {
- enc.WriteField(hpack.HeaderField{Name: "x", Value: "has\nnewline"})
- })
-}
-
-func testInvalidTrailer(t *testing.T, trailers headerType, wantErr error, writeTrailer func(*hpack.Encoder)) {
- ct := newClientTester(t)
- ct.client = func() error {
- req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
- res, err := ct.tr.RoundTrip(req)
- if err != nil {
- return fmt.Errorf("RoundTrip: %v", err)
- }
- defer res.Body.Close()
- if res.StatusCode != 200 {
- return fmt.Errorf("status code = %v; want 200", res.StatusCode)
- }
- slurp, err := ioutil.ReadAll(res.Body)
- se, ok := err.(StreamError)
- if !ok || se.Cause != wantErr {
- return fmt.Errorf("res.Body ReadAll error = %q, %#v; want StreamError with cause %T, %#v", slurp, err, wantErr, wantErr)
- }
- if len(slurp) > 0 {
- return fmt.Errorf("body = %q; want nothing", slurp)
- }
- return nil
- }
- ct.server = func() error {
- ct.greet()
- var buf bytes.Buffer
- enc := hpack.NewEncoder(&buf)
-
- for {
- f, err := ct.fr.ReadFrame()
- if err != nil {
- return err
- }
- switch f := f.(type) {
- case *HeadersFrame:
- var endStream bool
- send := func(mode headerType) {
- hbf := buf.Bytes()
- switch mode {
- case oneHeader:
- ct.fr.WriteHeaders(HeadersFrameParam{
- StreamID: f.StreamID,
- EndHeaders: true,
- EndStream: endStream,
- BlockFragment: hbf,
- })
- case splitHeader:
- if len(hbf) < 2 {
- panic("too small")
- }
- ct.fr.WriteHeaders(HeadersFrameParam{
- StreamID: f.StreamID,
- EndHeaders: false,
- EndStream: endStream,
- BlockFragment: hbf[:1],
- })
- ct.fr.WriteContinuation(f.StreamID, true, hbf[1:])
- default:
- panic("bogus mode")
- }
- }
- // Response headers (1+ frames; 1 or 2 in this test, but never 0)
- {
- buf.Reset()
- enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
- enc.WriteField(hpack.HeaderField{Name: "trailer", Value: "declared"})
- endStream = false
- send(oneHeader)
- }
- // Trailers:
- {
- endStream = true
- buf.Reset()
- writeTrailer(enc)
- send(trailers)
- }
- return nil
- }
- }
- }
- ct.run()
-}
-
-func TestTransportChecksResponseHeaderListSize(t *testing.T) {
- ct := newClientTester(t)
- ct.client = func() error {
- req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
- res, err := ct.tr.RoundTrip(req)
- if err != errResponseHeaderListSize {
- if res != nil {
- res.Body.Close()
- }
- size := int64(0)
- for k, vv := range res.Header {
- for _, v := range vv {
- size += int64(len(k)) + int64(len(v)) + 32
- }
- }
- return fmt.Errorf("RoundTrip Error = %v (and %d bytes of response headers); want errResponseHeaderListSize", err, size)
- }
- return nil
- }
- ct.server = func() error {
- ct.greet()
- var buf bytes.Buffer
- enc := hpack.NewEncoder(&buf)
-
- for {
- f, err := ct.fr.ReadFrame()
- if err != nil {
- return err
- }
- switch f := f.(type) {
- case *HeadersFrame:
- enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
- large := strings.Repeat("a", 1<<10)
- for i := 0; i < 5042; i++ {
- enc.WriteField(hpack.HeaderField{Name: large, Value: large})
- }
- if size, want := buf.Len(), 6329; size != want {
- // Note: this number might change if
- // our hpack implementation
- // changes. That's fine. This is
- // just a sanity check that our
- // response can fit in a single
- // header block fragment frame.
- return fmt.Errorf("encoding over 10MB of duplicate keypairs took %d bytes; expected %d", size, want)
- }
- ct.fr.WriteHeaders(HeadersFrameParam{
- StreamID: f.StreamID,
- EndHeaders: true,
- EndStream: true,
- BlockFragment: buf.Bytes(),
- })
- return nil
- }
- }
- }
- ct.run()
-}
-
-// Test that the the Transport returns a typed error from Response.Body.Read calls
-// when the server sends an error. (here we use a panic, since that should generate
-// a stream error, but others like cancel should be similar)
-func TestTransportBodyReadErrorType(t *testing.T) {
- doPanic := make(chan bool, 1)
- st := newServerTester(t,
- func(w http.ResponseWriter, r *http.Request) {
- w.(http.Flusher).Flush() // force headers out
- <-doPanic
- panic("boom")
- },
- optOnlyServer,
- optQuiet,
- )
- defer st.Close()
-
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
- c := &http.Client{Transport: tr}
-
- res, err := c.Get(st.ts.URL)
- if err != nil {
- t.Fatal(err)
- }
- defer res.Body.Close()
- doPanic <- true
- buf := make([]byte, 100)
- n, err := res.Body.Read(buf)
- want := StreamError{StreamID: 0x1, Code: 0x2}
- if !reflect.DeepEqual(want, err) {
- t.Errorf("Read = %v, %#v; want error %#v", n, err, want)
- }
-}
-
-// golang.org/issue/13924
-// This used to fail after many iterations, especially with -race:
-// go test -v -run=TestTransportDoubleCloseOnWriteError -count=500 -race
-func TestTransportDoubleCloseOnWriteError(t *testing.T) {
- var (
- mu sync.Mutex
- conn net.Conn // to close if set
- )
-
- st := newServerTester(t,
- func(w http.ResponseWriter, r *http.Request) {
- mu.Lock()
- defer mu.Unlock()
- if conn != nil {
- conn.Close()
- }
- },
- optOnlyServer,
- )
- defer st.Close()
-
- tr := &Transport{
- TLSClientConfig: tlsConfigInsecure,
- DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
- tc, err := tls.Dial(network, addr, cfg)
- if err != nil {
- return nil, err
- }
- mu.Lock()
- defer mu.Unlock()
- conn = tc
- return tc, nil
- },
- }
- defer tr.CloseIdleConnections()
- c := &http.Client{Transport: tr}
- c.Get(st.ts.URL)
-}
-
-// Test that the http1 Transport.DisableKeepAlives option is respected
-// and connections are closed as soon as idle.
-// See golang.org/issue/14008
-func TestTransportDisableKeepAlives(t *testing.T) {
- st := newServerTester(t,
- func(w http.ResponseWriter, r *http.Request) {
- io.WriteString(w, "hi")
- },
- optOnlyServer,
- )
- defer st.Close()
-
- connClosed := make(chan struct{}) // closed on tls.Conn.Close
- tr := &Transport{
- t1: &http.Transport{
- DisableKeepAlives: true,
- },
- TLSClientConfig: tlsConfigInsecure,
- DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
- tc, err := tls.Dial(network, addr, cfg)
- if err != nil {
- return nil, err
- }
- return &noteCloseConn{Conn: tc, closefn: func() { close(connClosed) }}, nil
- },
- }
- c := &http.Client{Transport: tr}
- res, err := c.Get(st.ts.URL)
- if err != nil {
- t.Fatal(err)
- }
- if _, err := ioutil.ReadAll(res.Body); err != nil {
- t.Fatal(err)
- }
- defer res.Body.Close()
-
- select {
- case <-connClosed:
- case <-time.After(1 * time.Second):
- t.Errorf("timeout")
- }
-
-}
-
-// Test concurrent requests with Transport.DisableKeepAlives. We can share connections,
-// but when things are totally idle, it still needs to close.
-func TestTransportDisableKeepAlives_Concurrency(t *testing.T) {
- const D = 25 * time.Millisecond
- st := newServerTester(t,
- func(w http.ResponseWriter, r *http.Request) {
- time.Sleep(D)
- io.WriteString(w, "hi")
- },
- optOnlyServer,
- )
- defer st.Close()
-
- var dials int32
- var conns sync.WaitGroup
- tr := &Transport{
- t1: &http.Transport{
- DisableKeepAlives: true,
- },
- TLSClientConfig: tlsConfigInsecure,
- DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
- tc, err := tls.Dial(network, addr, cfg)
- if err != nil {
- return nil, err
- }
- atomic.AddInt32(&dials, 1)
- conns.Add(1)
- return &noteCloseConn{Conn: tc, closefn: func() { conns.Done() }}, nil
- },
- }
- c := &http.Client{Transport: tr}
- var reqs sync.WaitGroup
- const N = 20
- for i := 0; i < N; i++ {
- reqs.Add(1)
- if i == N-1 {
- // For the final request, try to make all the
- // others close. This isn't verified in the
- // count, other than the Log statement, since
- // it's so timing dependent. This test is
- // really to make sure we don't interrupt a
- // valid request.
- time.Sleep(D * 2)
- }
- go func() {
- defer reqs.Done()
- res, err := c.Get(st.ts.URL)
- if err != nil {
- t.Error(err)
- return
- }
- if _, err := ioutil.ReadAll(res.Body); err != nil {
- t.Error(err)
- return
- }
- res.Body.Close()
- }()
- }
- reqs.Wait()
- conns.Wait()
- t.Logf("did %d dials, %d requests", atomic.LoadInt32(&dials), N)
-}
-
-type noteCloseConn struct {
- net.Conn
- onceClose sync.Once
- closefn func()
-}
-
-func (c *noteCloseConn) Close() error {
- c.onceClose.Do(c.closefn)
- return c.Conn.Close()
-}
-
-func isTimeout(err error) bool {
- switch err := err.(type) {
- case nil:
- return false
- case *url.Error:
- return isTimeout(err.Err)
- case net.Error:
- return err.Timeout()
- }
- return false
-}
-
-// Test that the http1 Transport.ResponseHeaderTimeout option and cancel is sent.
-func TestTransportResponseHeaderTimeout_NoBody(t *testing.T) {
- testTransportResponseHeaderTimeout(t, false)
-}
-func TestTransportResponseHeaderTimeout_Body(t *testing.T) {
- testTransportResponseHeaderTimeout(t, true)
-}
-
-func testTransportResponseHeaderTimeout(t *testing.T, body bool) {
- ct := newClientTester(t)
- ct.tr.t1 = &http.Transport{
- ResponseHeaderTimeout: 5 * time.Millisecond,
- }
- ct.client = func() error {
- c := &http.Client{Transport: ct.tr}
- var err error
- var n int64
- const bodySize = 4 << 20
- if body {
- _, err = c.Post("https://dummy.tld/", "text/foo", io.LimitReader(countingReader{&n}, bodySize))
- } else {
- _, err = c.Get("https://dummy.tld/")
- }
- if !isTimeout(err) {
- t.Errorf("client expected timeout error; got %#v", err)
- }
- if body && n != bodySize {
- t.Errorf("only read %d bytes of body; want %d", n, bodySize)
- }
- return nil
- }
- ct.server = func() error {
- ct.greet()
- for {
- f, err := ct.fr.ReadFrame()
- if err != nil {
- t.Logf("ReadFrame: %v", err)
- return nil
- }
- switch f := f.(type) {
- case *DataFrame:
- dataLen := len(f.Data())
- if dataLen > 0 {
- if err := ct.fr.WriteWindowUpdate(0, uint32(dataLen)); err != nil {
- return err
- }
- if err := ct.fr.WriteWindowUpdate(f.StreamID, uint32(dataLen)); err != nil {
- return err
- }
- }
- case *RSTStreamFrame:
- if f.StreamID == 1 && f.ErrCode == ErrCodeCancel {
- return nil
- }
- }
- }
- }
- ct.run()
-}
-
-func TestTransportDisableCompression(t *testing.T) {
- const body = "sup"
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- want := http.Header{
- "User-Agent": []string{"Go-http-client/2.0"},
- }
- if !reflect.DeepEqual(r.Header, want) {
- t.Errorf("request headers = %v; want %v", r.Header, want)
- }
- }, optOnlyServer)
- defer st.Close()
-
- tr := &Transport{
- TLSClientConfig: tlsConfigInsecure,
- t1: &http.Transport{
- DisableCompression: true,
- },
- }
- defer tr.CloseIdleConnections()
-
- req, err := http.NewRequest("GET", st.ts.URL, nil)
- if err != nil {
- t.Fatal(err)
- }
- res, err := tr.RoundTrip(req)
- if err != nil {
- t.Fatal(err)
- }
- defer res.Body.Close()
-}
-
-// RFC 7540 section 8.1.2.2
-func TestTransportRejectsConnHeaders(t *testing.T) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- var got []string
- for k := range r.Header {
- got = append(got, k)
- }
- sort.Strings(got)
- w.Header().Set("Got-Header", strings.Join(got, ","))
- }, optOnlyServer)
- defer st.Close()
-
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
-
- tests := []struct {
- key string
- value []string
- want string
- }{
- {
- key: "Upgrade",
- value: []string{"anything"},
- want: "ERROR: http2: invalid Upgrade request header: [\"anything\"]",
- },
- {
- key: "Connection",
- value: []string{"foo"},
- want: "ERROR: http2: invalid Connection request header: [\"foo\"]",
- },
- {
- key: "Connection",
- value: []string{"close"},
- want: "Accept-Encoding,User-Agent",
- },
- {
- key: "Connection",
- value: []string{"close", "something-else"},
- want: "ERROR: http2: invalid Connection request header: [\"close\" \"something-else\"]",
- },
- {
- key: "Connection",
- value: []string{"keep-alive"},
- want: "Accept-Encoding,User-Agent",
- },
- {
- key: "Proxy-Connection", // just deleted and ignored
- value: []string{"keep-alive"},
- want: "Accept-Encoding,User-Agent",
- },
- {
- key: "Transfer-Encoding",
- value: []string{""},
- want: "Accept-Encoding,User-Agent",
- },
- {
- key: "Transfer-Encoding",
- value: []string{"foo"},
- want: "ERROR: http2: invalid Transfer-Encoding request header: [\"foo\"]",
- },
- {
- key: "Transfer-Encoding",
- value: []string{"chunked"},
- want: "Accept-Encoding,User-Agent",
- },
- {
- key: "Transfer-Encoding",
- value: []string{"chunked", "other"},
- want: "ERROR: http2: invalid Transfer-Encoding request header: [\"chunked\" \"other\"]",
- },
- {
- key: "Content-Length",
- value: []string{"123"},
- want: "Accept-Encoding,User-Agent",
- },
- {
- key: "Keep-Alive",
- value: []string{"doop"},
- want: "Accept-Encoding,User-Agent",
- },
- }
-
- for _, tt := range tests {
- req, _ := http.NewRequest("GET", st.ts.URL, nil)
- req.Header[tt.key] = tt.value
- res, err := tr.RoundTrip(req)
- var got string
- if err != nil {
- got = fmt.Sprintf("ERROR: %v", err)
- } else {
- got = res.Header.Get("Got-Header")
- res.Body.Close()
- }
- if got != tt.want {
- t.Errorf("For key %q, value %q, got = %q; want %q", tt.key, tt.value, got, tt.want)
- }
- }
-}
-
-// golang.org/issue/14048
-func TestTransportFailsOnInvalidHeaders(t *testing.T) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- var got []string
- for k := range r.Header {
- got = append(got, k)
- }
- sort.Strings(got)
- w.Header().Set("Got-Header", strings.Join(got, ","))
- }, optOnlyServer)
- defer st.Close()
-
- tests := [...]struct {
- h http.Header
- wantErr string
- }{
- 0: {
- h: http.Header{"with space": {"foo"}},
- wantErr: `invalid HTTP header name "with space"`,
- },
- 1: {
- h: http.Header{"name": {"Брэд"}},
- wantErr: "", // okay
- },
- 2: {
- h: http.Header{"имя": {"Brad"}},
- wantErr: `invalid HTTP header name "имя"`,
- },
- 3: {
- h: http.Header{"foo": {"foo\x01bar"}},
- wantErr: `invalid HTTP header value "foo\x01bar" for header "foo"`,
- },
- }
-
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
-
- for i, tt := range tests {
- req, _ := http.NewRequest("GET", st.ts.URL, nil)
- req.Header = tt.h
- res, err := tr.RoundTrip(req)
- var bad bool
- if tt.wantErr == "" {
- if err != nil {
- bad = true
- t.Errorf("case %d: error = %v; want no error", i, err)
- }
- } else {
- if !strings.Contains(fmt.Sprint(err), tt.wantErr) {
- bad = true
- t.Errorf("case %d: error = %v; want error %q", i, err, tt.wantErr)
- }
- }
- if err == nil {
- if bad {
- t.Logf("case %d: server got headers %q", i, res.Header.Get("Got-Header"))
- }
- res.Body.Close()
- }
- }
-}
-
-// Tests that gzipReader doesn't crash on a second Read call following
-// the first Read call's gzip.NewReader returning an error.
-func TestGzipReader_DoubleReadCrash(t *testing.T) {
- gz := &gzipReader{
- body: ioutil.NopCloser(strings.NewReader("0123456789")),
- }
- var buf [1]byte
- n, err1 := gz.Read(buf[:])
- if n != 0 || !strings.Contains(fmt.Sprint(err1), "invalid header") {
- t.Fatalf("Read = %v, %v; want 0, invalid header", n, err1)
- }
- n, err2 := gz.Read(buf[:])
- if n != 0 || err2 != err1 {
- t.Fatalf("second Read = %v, %v; want 0, %v", n, err2, err1)
- }
-}
-
-func TestTransportNewTLSConfig(t *testing.T) {
- tests := [...]struct {
- conf *tls.Config
- host string
- want *tls.Config
- }{
- // Normal case.
- 0: {
- conf: nil,
- host: "foo.com",
- want: &tls.Config{
- ServerName: "foo.com",
- NextProtos: []string{NextProtoTLS},
- },
- },
-
- // User-provided name (bar.com) takes precedence:
- 1: {
- conf: &tls.Config{
- ServerName: "bar.com",
- },
- host: "foo.com",
- want: &tls.Config{
- ServerName: "bar.com",
- NextProtos: []string{NextProtoTLS},
- },
- },
-
- // NextProto is prepended:
- 2: {
- conf: &tls.Config{
- NextProtos: []string{"foo", "bar"},
- },
- host: "example.com",
- want: &tls.Config{
- ServerName: "example.com",
- NextProtos: []string{NextProtoTLS, "foo", "bar"},
- },
- },
-
- // NextProto is not duplicated:
- 3: {
- conf: &tls.Config{
- NextProtos: []string{"foo", "bar", NextProtoTLS},
- },
- host: "example.com",
- want: &tls.Config{
- ServerName: "example.com",
- NextProtos: []string{"foo", "bar", NextProtoTLS},
- },
- },
- }
- for i, tt := range tests {
- // Ignore the session ticket keys part, which ends up populating
- // unexported fields in the Config:
- if tt.conf != nil {
- tt.conf.SessionTicketsDisabled = true
- }
-
- tr := &Transport{TLSClientConfig: tt.conf}
- got := tr.newTLSConfig(tt.host)
-
- got.SessionTicketsDisabled = false
-
- if !reflect.DeepEqual(got, tt.want) {
- t.Errorf("%d. got %#v; want %#v", i, got, tt.want)
- }
- }
-}
-
-// The Google GFE responds to HEAD requests with a HEADERS frame
-// without END_STREAM, followed by a 0-length DATA frame with
-// END_STREAM. Make sure we don't get confused by that. (We did.)
-func TestTransportReadHeadResponse(t *testing.T) {
- ct := newClientTester(t)
- clientDone := make(chan struct{})
- ct.client = func() error {
- defer close(clientDone)
- req, _ := http.NewRequest("HEAD", "https://dummy.tld/", nil)
- res, err := ct.tr.RoundTrip(req)
- if err != nil {
- return err
- }
- if res.ContentLength != 123 {
- return fmt.Errorf("Content-Length = %d; want 123", res.ContentLength)
- }
- slurp, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return fmt.Errorf("ReadAll: %v", err)
- }
- if len(slurp) > 0 {
- return fmt.Errorf("Unexpected non-empty ReadAll body: %q", slurp)
- }
- return nil
- }
- ct.server = func() error {
- ct.greet()
- for {
- f, err := ct.fr.ReadFrame()
- if err != nil {
- t.Logf("ReadFrame: %v", err)
- return nil
- }
- hf, ok := f.(*HeadersFrame)
- if !ok {
- continue
- }
- var buf bytes.Buffer
- enc := hpack.NewEncoder(&buf)
- enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
- enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "123"})
- ct.fr.WriteHeaders(HeadersFrameParam{
- StreamID: hf.StreamID,
- EndHeaders: true,
- EndStream: false, // as the GFE does
- BlockFragment: buf.Bytes(),
- })
- ct.fr.WriteData(hf.StreamID, true, nil)
-
- <-clientDone
- return nil
- }
- }
- ct.run()
-}
-
-type neverEnding byte
-
-func (b neverEnding) Read(p []byte) (int, error) {
- for i := range p {
- p[i] = byte(b)
- }
- return len(p), nil
-}
-
-// golang.org/issue/15425: test that a handler closing the request
-// body doesn't terminate the stream to the peer. (It just stops
-// readability from the handler's side, and eventually the client
-// runs out of flow control tokens)
-func TestTransportHandlerBodyClose(t *testing.T) {
- const bodySize = 10 << 20
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- r.Body.Close()
- io.Copy(w, io.LimitReader(neverEnding('A'), bodySize))
- }, optOnlyServer)
- defer st.Close()
-
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
-
- g0 := runtime.NumGoroutine()
-
- const numReq = 10
- for i := 0; i < numReq; i++ {
- req, err := http.NewRequest("POST", st.ts.URL, struct{ io.Reader }{io.LimitReader(neverEnding('A'), bodySize)})
- if err != nil {
- t.Fatal(err)
- }
- res, err := tr.RoundTrip(req)
- if err != nil {
- t.Fatal(err)
- }
- n, err := io.Copy(ioutil.Discard, res.Body)
- res.Body.Close()
- if n != bodySize || err != nil {
- t.Fatalf("req#%d: Copy = %d, %v; want %d, nil", i, n, err, bodySize)
- }
- }
- tr.CloseIdleConnections()
-
- gd := runtime.NumGoroutine() - g0
- if gd > numReq/2 {
- t.Errorf("appeared to leak goroutines")
- }
-
-}
-
-// https://golang.org/issue/15930
-func TestTransportFlowControl(t *testing.T) {
- const bufLen = 64 << 10
- var total int64 = 100 << 20 // 100MB
- if testing.Short() {
- total = 10 << 20
- }
-
- var wrote int64 // updated atomically
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- b := make([]byte, bufLen)
- for wrote < total {
- n, err := w.Write(b)
- atomic.AddInt64(&wrote, int64(n))
- if err != nil {
- t.Errorf("ResponseWriter.Write error: %v", err)
- break
- }
- w.(http.Flusher).Flush()
- }
- }, optOnlyServer)
-
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
- req, err := http.NewRequest("GET", st.ts.URL, nil)
- if err != nil {
- t.Fatal("NewRequest error:", err)
- }
- resp, err := tr.RoundTrip(req)
- if err != nil {
- t.Fatal("RoundTrip error:", err)
- }
- defer resp.Body.Close()
-
- var read int64
- b := make([]byte, bufLen)
- for {
- n, err := resp.Body.Read(b)
- if err == io.EOF {
- break
- }
- if err != nil {
- t.Fatal("Read error:", err)
- }
- read += int64(n)
-
- const max = transportDefaultStreamFlow
- if w := atomic.LoadInt64(&wrote); -max > read-w || read-w > max {
- t.Fatalf("Too much data inflight: server wrote %v bytes but client only received %v", w, read)
- }
-
- // Let the server get ahead of the client.
- time.Sleep(1 * time.Millisecond)
- }
-}
-
-// golang.org/issue/14627 -- if the server sends a GOAWAY frame, make
-// the Transport remember it and return it back to users (via
-// RoundTrip or request body reads) if needed (e.g. if the server
-// proceeds to close the TCP connection before the client gets its
-// response)
-func TestTransportUsesGoAwayDebugError_RoundTrip(t *testing.T) {
- testTransportUsesGoAwayDebugError(t, false)
-}
-
-func TestTransportUsesGoAwayDebugError_Body(t *testing.T) {
- testTransportUsesGoAwayDebugError(t, true)
-}
-
-func testTransportUsesGoAwayDebugError(t *testing.T, failMidBody bool) {
- ct := newClientTester(t)
- clientDone := make(chan struct{})
-
- const goAwayErrCode = ErrCodeHTTP11Required // arbitrary
- const goAwayDebugData = "some debug data"
-
- ct.client = func() error {
- defer close(clientDone)
- req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
- res, err := ct.tr.RoundTrip(req)
- if failMidBody {
- if err != nil {
- return fmt.Errorf("unexpected client RoundTrip error: %v", err)
- }
- _, err = io.Copy(ioutil.Discard, res.Body)
- res.Body.Close()
- }
- want := GoAwayError{
- LastStreamID: 5,
- ErrCode: goAwayErrCode,
- DebugData: goAwayDebugData,
- }
- if !reflect.DeepEqual(err, want) {
- t.Errorf("RoundTrip error = %T: %#v, want %T (%#v)", err, err, want, want)
- }
- return nil
- }
- ct.server = func() error {
- ct.greet()
- for {
- f, err := ct.fr.ReadFrame()
- if err != nil {
- t.Logf("ReadFrame: %v", err)
- return nil
- }
- hf, ok := f.(*HeadersFrame)
- if !ok {
- continue
- }
- if failMidBody {
- var buf bytes.Buffer
- enc := hpack.NewEncoder(&buf)
- enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
- enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "123"})
- ct.fr.WriteHeaders(HeadersFrameParam{
- StreamID: hf.StreamID,
- EndHeaders: true,
- EndStream: false,
- BlockFragment: buf.Bytes(),
- })
- }
- // Write two GOAWAY frames, to test that the Transport takes
- // the interesting parts of both.
- ct.fr.WriteGoAway(5, ErrCodeNo, []byte(goAwayDebugData))
- ct.fr.WriteGoAway(5, goAwayErrCode, nil)
- ct.sc.(*net.TCPConn).CloseWrite()
- <-clientDone
- return nil
- }
- }
- ct.run()
-}
-
-// See golang.org/issue/16481
-func TestTransportReturnsUnusedFlowControl(t *testing.T) {
- ct := newClientTester(t)
-
- clientClosed := make(chan bool, 1)
- serverWroteBody := make(chan bool, 1)
-
- ct.client = func() error {
- req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
- res, err := ct.tr.RoundTrip(req)
- if err != nil {
- return err
- }
- <-serverWroteBody
-
- if n, err := res.Body.Read(make([]byte, 1)); err != nil || n != 1 {
- return fmt.Errorf("body read = %v, %v; want 1, nil", n, err)
- }
- res.Body.Close() // leaving 4999 bytes unread
- clientClosed <- true
-
- return nil
- }
- ct.server = func() error {
- ct.greet()
-
- var hf *HeadersFrame
- for {
- f, err := ct.fr.ReadFrame()
- if err != nil {
- return fmt.Errorf("ReadFrame while waiting for Headers: %v", err)
- }
- switch f.(type) {
- case *WindowUpdateFrame, *SettingsFrame:
- continue
- }
- var ok bool
- hf, ok = f.(*HeadersFrame)
- if !ok {
- return fmt.Errorf("Got %T; want HeadersFrame", f)
- }
- break
- }
-
- var buf bytes.Buffer
- enc := hpack.NewEncoder(&buf)
- enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
- enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "5000"})
- ct.fr.WriteHeaders(HeadersFrameParam{
- StreamID: hf.StreamID,
- EndHeaders: true,
- EndStream: false,
- BlockFragment: buf.Bytes(),
- })
- ct.fr.WriteData(hf.StreamID, false, make([]byte, 5000)) // without ending stream
- serverWroteBody <- true
-
- <-clientClosed
-
- waitingFor := "RSTStreamFrame"
- for {
- f, err := ct.fr.ReadFrame()
- if err != nil {
- return fmt.Errorf("ReadFrame while waiting for %s: %v", waitingFor, err)
- }
- if _, ok := f.(*SettingsFrame); ok {
- continue
- }
- switch waitingFor {
- case "RSTStreamFrame":
- if rf, ok := f.(*RSTStreamFrame); !ok || rf.ErrCode != ErrCodeCancel {
- return fmt.Errorf("Expected a WindowUpdateFrame with code cancel; got %v", summarizeFrame(f))
- }
- waitingFor = "WindowUpdateFrame"
- case "WindowUpdateFrame":
- if wuf, ok := f.(*WindowUpdateFrame); !ok || wuf.Increment != 4999 {
- return fmt.Errorf("Expected WindowUpdateFrame for 4999 bytes; got %v", summarizeFrame(f))
- }
- return nil
- }
- }
- }
- ct.run()
-}
-
-// Issue 16612: adjust flow control on open streams when transport
-// receives SETTINGS with INITIAL_WINDOW_SIZE from server.
-func TestTransportAdjustsFlowControl(t *testing.T) {
- ct := newClientTester(t)
- clientDone := make(chan struct{})
-
- const bodySize = 1 << 20
-
- ct.client = func() error {
- defer ct.cc.(*net.TCPConn).CloseWrite()
- defer close(clientDone)
-
- req, _ := http.NewRequest("POST", "https://dummy.tld/", struct{ io.Reader }{io.LimitReader(neverEnding('A'), bodySize)})
- res, err := ct.tr.RoundTrip(req)
- if err != nil {
- return err
- }
- res.Body.Close()
- return nil
- }
- ct.server = func() error {
- _, err := io.ReadFull(ct.sc, make([]byte, len(ClientPreface)))
- if err != nil {
- return fmt.Errorf("reading client preface: %v", err)
- }
-
- var gotBytes int64
- var sentSettings bool
- for {
- f, err := ct.fr.ReadFrame()
- if err != nil {
- select {
- case <-clientDone:
- return nil
- default:
- return fmt.Errorf("ReadFrame while waiting for Headers: %v", err)
- }
- }
- switch f := f.(type) {
- case *DataFrame:
- gotBytes += int64(len(f.Data()))
- // After we've got half the client's
- // initial flow control window's worth
- // of request body data, give it just
- // enough flow control to finish.
- if gotBytes >= initialWindowSize/2 && !sentSettings {
- sentSettings = true
-
- ct.fr.WriteSettings(Setting{ID: SettingInitialWindowSize, Val: bodySize})
- ct.fr.WriteWindowUpdate(0, bodySize)
- ct.fr.WriteSettingsAck()
- }
-
- if f.StreamEnded() {
- var buf bytes.Buffer
- enc := hpack.NewEncoder(&buf)
- enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
- ct.fr.WriteHeaders(HeadersFrameParam{
- StreamID: f.StreamID,
- EndHeaders: true,
- EndStream: true,
- BlockFragment: buf.Bytes(),
- })
- }
- }
- }
- }
- ct.run()
-}
-
-// See golang.org/issue/16556
-func TestTransportReturnsDataPaddingFlowControl(t *testing.T) {
- ct := newClientTester(t)
-
- unblockClient := make(chan bool, 1)
-
- ct.client = func() error {
- req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
- res, err := ct.tr.RoundTrip(req)
- if err != nil {
- return err
- }
- defer res.Body.Close()
- <-unblockClient
- return nil
- }
- ct.server = func() error {
- ct.greet()
-
- var hf *HeadersFrame
- for {
- f, err := ct.fr.ReadFrame()
- if err != nil {
- return fmt.Errorf("ReadFrame while waiting for Headers: %v", err)
- }
- switch f.(type) {
- case *WindowUpdateFrame, *SettingsFrame:
- continue
- }
- var ok bool
- hf, ok = f.(*HeadersFrame)
- if !ok {
- return fmt.Errorf("Got %T; want HeadersFrame", f)
- }
- break
- }
-
- var buf bytes.Buffer
- enc := hpack.NewEncoder(&buf)
- enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
- enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "5000"})
- ct.fr.WriteHeaders(HeadersFrameParam{
- StreamID: hf.StreamID,
- EndHeaders: true,
- EndStream: false,
- BlockFragment: buf.Bytes(),
- })
- pad := make([]byte, 5)
- ct.fr.WriteDataPadded(hf.StreamID, false, make([]byte, 5000), pad) // without ending stream
-
- f, err := ct.readNonSettingsFrame()
- if err != nil {
- return fmt.Errorf("ReadFrame while waiting for first WindowUpdateFrame: %v", err)
- }
- wantBack := uint32(len(pad)) + 1 // one byte for the length of the padding
- if wuf, ok := f.(*WindowUpdateFrame); !ok || wuf.Increment != wantBack || wuf.StreamID != 0 {
- return fmt.Errorf("Expected conn WindowUpdateFrame for %d bytes; got %v", wantBack, summarizeFrame(f))
- }
-
- f, err = ct.readNonSettingsFrame()
- if err != nil {
- return fmt.Errorf("ReadFrame while waiting for second WindowUpdateFrame: %v", err)
- }
- if wuf, ok := f.(*WindowUpdateFrame); !ok || wuf.Increment != wantBack || wuf.StreamID == 0 {
- return fmt.Errorf("Expected stream WindowUpdateFrame for %d bytes; got %v", wantBack, summarizeFrame(f))
- }
- unblockClient <- true
- return nil
- }
- ct.run()
-}
-
-// golang.org/issue/16572 -- RoundTrip shouldn't hang when it gets a
-// StreamError as a result of the response HEADERS
-func TestTransportReturnsErrorOnBadResponseHeaders(t *testing.T) {
- ct := newClientTester(t)
-
- ct.client = func() error {
- req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
- res, err := ct.tr.RoundTrip(req)
- if err == nil {
- res.Body.Close()
- return errors.New("unexpected successful GET")
- }
- want := StreamError{1, ErrCodeProtocol, headerFieldNameError(" content-type")}
- if !reflect.DeepEqual(want, err) {
- t.Errorf("RoundTrip error = %#v; want %#v", err, want)
- }
- return nil
- }
- ct.server = func() error {
- ct.greet()
-
- hf, err := ct.firstHeaders()
- if err != nil {
- return err
- }
-
- var buf bytes.Buffer
- enc := hpack.NewEncoder(&buf)
- enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
- enc.WriteField(hpack.HeaderField{Name: " content-type", Value: "bogus"}) // bogus spaces
- ct.fr.WriteHeaders(HeadersFrameParam{
- StreamID: hf.StreamID,
- EndHeaders: true,
- EndStream: false,
- BlockFragment: buf.Bytes(),
- })
-
- for {
- fr, err := ct.readFrame()
- if err != nil {
- return fmt.Errorf("error waiting for RST_STREAM from client: %v", err)
- }
- if _, ok := fr.(*SettingsFrame); ok {
- continue
- }
- if rst, ok := fr.(*RSTStreamFrame); !ok || rst.StreamID != 1 || rst.ErrCode != ErrCodeProtocol {
- t.Errorf("Frame = %v; want RST_STREAM for stream 1 with ErrCodeProtocol", summarizeFrame(fr))
- }
- break
- }
-
- return nil
- }
- ct.run()
-}
-
-// byteAndEOFReader returns is in an io.Reader which reads one byte
-// (the underlying byte) and io.EOF at once in its Read call.
-type byteAndEOFReader byte
-
-func (b byteAndEOFReader) Read(p []byte) (n int, err error) {
- if len(p) == 0 {
- panic("unexpected useless call")
- }
- p[0] = byte(b)
- return 1, io.EOF
-}
-
-// Issue 16788: the Transport had a regression where it started
-// sending a spurious DATA frame with a duplicate END_STREAM bit after
-// the request body writer goroutine had already read an EOF from the
-// Request.Body and included the END_STREAM on a data-carrying DATA
-// frame.
-//
-// Notably, to trigger this, the requests need to use a Request.Body
-// which returns (non-0, io.EOF) and also needs to set the ContentLength
-// explicitly.
-func TestTransportBodyDoubleEndStream(t *testing.T) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- // Nothing.
- }, optOnlyServer)
- defer st.Close()
-
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
-
- for i := 0; i < 2; i++ {
- req, _ := http.NewRequest("POST", st.ts.URL, byteAndEOFReader('a'))
- req.ContentLength = 1
- res, err := tr.RoundTrip(req)
- if err != nil {
- t.Fatalf("failure on req %d: %v", i+1, err)
- }
- defer res.Body.Close()
- }
-}
-
-// golangorg/issue/16847
-func TestTransportRequestPathPseudo(t *testing.T) {
- type result struct {
- path string
- err string
- }
- tests := []struct {
- req *http.Request
- want result
- }{
- 0: {
- req: &http.Request{
- Method: "GET",
- URL: &url.URL{
- Host: "foo.com",
- Path: "/foo",
- },
- },
- want: result{path: "/foo"},
- },
- // I guess we just don't let users request "//foo" as
- // a path, since it's illegal to start with two
- // slashes....
- 1: {
- req: &http.Request{
- Method: "GET",
- URL: &url.URL{
- Host: "foo.com",
- Path: "//foo",
- },
- },
- want: result{err: `invalid request :path "//foo"`},
- },
-
- // Opaque with //$Matching_Hostname/path
- 2: {
- req: &http.Request{
- Method: "GET",
- URL: &url.URL{
- Scheme: "https",
- Opaque: "//foo.com/path",
- Host: "foo.com",
- Path: "/ignored",
- },
- },
- want: result{path: "/path"},
- },
-
- // Opaque with some other Request.Host instead:
- 3: {
- req: &http.Request{
- Method: "GET",
- Host: "bar.com",
- URL: &url.URL{
- Scheme: "https",
- Opaque: "//bar.com/path",
- Host: "foo.com",
- Path: "/ignored",
- },
- },
- want: result{path: "/path"},
- },
-
- // Opaque without the leading "//":
- 4: {
- req: &http.Request{
- Method: "GET",
- URL: &url.URL{
- Opaque: "/path",
- Host: "foo.com",
- Path: "/ignored",
- },
- },
- want: result{path: "/path"},
- },
-
- // Opaque we can't handle:
- 5: {
- req: &http.Request{
- Method: "GET",
- URL: &url.URL{
- Scheme: "https",
- Opaque: "//unknown_host/path",
- Host: "foo.com",
- Path: "/ignored",
- },
- },
- want: result{err: `invalid request :path "https://unknown_host/path" from URL.Opaque = "//unknown_host/path"`},
- },
-
- // A CONNECT request:
- 6: {
- req: &http.Request{
- Method: "CONNECT",
- URL: &url.URL{
- Host: "foo.com",
- },
- },
- want: result{},
- },
- }
- for i, tt := range tests {
- cc := &ClientConn{}
- cc.henc = hpack.NewEncoder(&cc.hbuf)
- cc.mu.Lock()
- hdrs, err := cc.encodeHeaders(tt.req, false, "", -1)
- cc.mu.Unlock()
- var got result
- hpackDec := hpack.NewDecoder(initialHeaderTableSize, func(f hpack.HeaderField) {
- if f.Name == ":path" {
- got.path = f.Value
- }
- })
- if err != nil {
- got.err = err.Error()
- } else if len(hdrs) > 0 {
- if _, err := hpackDec.Write(hdrs); err != nil {
- t.Errorf("%d. bogus hpack: %v", i, err)
- continue
- }
- }
- if got != tt.want {
- t.Errorf("%d. got %+v; want %+v", i, got, tt.want)
- }
-
- }
-
-}
-
-// golang.org/issue/17071 -- don't sniff the first byte of the request body
-// before we've determined that the ClientConn is usable.
-func TestRoundTripDoesntConsumeRequestBodyEarly(t *testing.T) {
- const body = "foo"
- req, _ := http.NewRequest("POST", "http://foo.com/", ioutil.NopCloser(strings.NewReader(body)))
- cc := &ClientConn{
- closed: true,
- }
- _, err := cc.RoundTrip(req)
- if err != errClientConnUnusable {
- t.Fatalf("RoundTrip = %v; want errClientConnUnusable", err)
- }
- slurp, err := ioutil.ReadAll(req.Body)
- if err != nil {
- t.Errorf("ReadAll = %v", err)
- }
- if string(slurp) != body {
- t.Errorf("Body = %q; want %q", slurp, body)
- }
-}
-
-func TestClientConnPing(t *testing.T) {
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {}, optOnlyServer)
- defer st.Close()
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
- cc, err := tr.dialClientConn(st.ts.Listener.Addr().String(), false)
- if err != nil {
- t.Fatal(err)
- }
- if err = cc.Ping(testContext{}); err != nil {
- t.Fatal(err)
- }
-}
-
-// Issue 16974: if the server sent a DATA frame after the user
-// canceled the Transport's Request, the Transport previously wrote to a
-// closed pipe, got an error, and ended up closing the whole TCP
-// connection.
-func TestTransportCancelDataResponseRace(t *testing.T) {
- cancel := make(chan struct{})
- clientGotError := make(chan bool, 1)
-
- const msg = "Hello."
- st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
- if strings.Contains(r.URL.Path, "/hello") {
- time.Sleep(50 * time.Millisecond)
- io.WriteString(w, msg)
- return
- }
- for i := 0; i < 50; i++ {
- io.WriteString(w, "Some data.")
- w.(http.Flusher).Flush()
- if i == 2 {
- close(cancel)
- <-clientGotError
- }
- time.Sleep(10 * time.Millisecond)
- }
- }, optOnlyServer)
- defer st.Close()
-
- tr := &Transport{TLSClientConfig: tlsConfigInsecure}
- defer tr.CloseIdleConnections()
-
- c := &http.Client{Transport: tr}
- req, _ := http.NewRequest("GET", st.ts.URL, nil)
- req.Cancel = cancel
- res, err := c.Do(req)
- if err != nil {
- t.Fatal(err)
- }
- if _, err = io.Copy(ioutil.Discard, res.Body); err == nil {
- t.Fatal("unexpected success")
- }
- clientGotError <- true
-
- res, err = c.Get(st.ts.URL + "/hello")
- if err != nil {
- t.Fatal(err)
- }
- slurp, err := ioutil.ReadAll(res.Body)
- if err != nil {
- t.Fatal(err)
- }
- if string(slurp) != msg {
- t.Errorf("Got = %q; want %q", slurp, msg)
- }
-}
-
-func TestTransportRetryAfterGOAWAY(t *testing.T) {
- var dialer struct {
- sync.Mutex
- count int
- }
- ct1 := make(chan *clientTester)
- ct2 := make(chan *clientTester)
-
- ln := newLocalListener(t)
- defer ln.Close()
-
- tr := &Transport{
- TLSClientConfig: tlsConfigInsecure,
- }
- tr.DialTLS = func(network, addr string, cfg *tls.Config) (net.Conn, error) {
- dialer.Lock()
- defer dialer.Unlock()
- dialer.count++
- if dialer.count == 3 {
- return nil, errors.New("unexpected number of dials")
- }
- cc, err := net.Dial("tcp", ln.Addr().String())
- if err != nil {
- return nil, fmt.Errorf("dial error: %v", err)
- }
- sc, err := ln.Accept()
- if err != nil {
- return nil, fmt.Errorf("accept error: %v", err)
- }
- ct := &clientTester{
- t: t,
- tr: tr,
- cc: cc,
- sc: sc,
- fr: NewFramer(sc, sc),
- }
- switch dialer.count {
- case 1:
- ct1 <- ct
- case 2:
- ct2 <- ct
- }
- return cc, nil
- }
-
- errs := make(chan error, 3)
- done := make(chan struct{})
- defer close(done)
-
- // Client.
- go func() {
- req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
- res, err := tr.RoundTrip(req)
- if res != nil {
- res.Body.Close()
- if got := res.Header.Get("Foo"); got != "bar" {
- err = fmt.Errorf("foo header = %q; want bar", got)
- }
- }
- if err != nil {
- err = fmt.Errorf("RoundTrip: %v", err)
- }
- errs <- err
- }()
-
- connToClose := make(chan io.Closer, 2)
-
- // Server for the first request.
- go func() {
- var ct *clientTester
- select {
- case ct = <-ct1:
- case <-done:
- return
- }
-
- connToClose <- ct.cc
- ct.greet()
- hf, err := ct.firstHeaders()
- if err != nil {
- errs <- fmt.Errorf("server1 failed reading HEADERS: %v", err)
- return
- }
- t.Logf("server1 got %v", hf)
- if err := ct.fr.WriteGoAway(0 /*max id*/, ErrCodeNo, nil); err != nil {
- errs <- fmt.Errorf("server1 failed writing GOAWAY: %v", err)
- return
- }
- errs <- nil
- }()
-
- // Server for the second request.
- go func() {
- var ct *clientTester
- select {
- case ct = <-ct2:
- case <-done:
- return
- }
-
- connToClose <- ct.cc
- ct.greet()
- hf, err := ct.firstHeaders()
- if err != nil {
- errs <- fmt.Errorf("server2 failed reading HEADERS: %v", err)
- return
- }
- t.Logf("server2 got %v", hf)
-
- var buf bytes.Buffer
- enc := hpack.NewEncoder(&buf)
- enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
- enc.WriteField(hpack.HeaderField{Name: "foo", Value: "bar"})
- err = ct.fr.WriteHeaders(HeadersFrameParam{
- StreamID: hf.StreamID,
- EndHeaders: true,
- EndStream: false,
- BlockFragment: buf.Bytes(),
- })
- if err != nil {
- errs <- fmt.Errorf("server2 failed writing response HEADERS: %v", err)
- } else {
- errs <- nil
- }
- }()
-
- for k := 0; k < 3; k++ {
- select {
- case err := <-errs:
- if err != nil {
- t.Error(err)
- }
- case <-time.After(1 * time.Second):
- t.Errorf("timed out")
- }
- }
-
- for {
- select {
- case c := <-connToClose:
- c.Close()
- default:
- return
- }
- }
-}
-
-func TestAuthorityAddr(t *testing.T) {
- tests := []struct {
- scheme, authority string
- want string
- }{
- {"http", "foo.com", "foo.com:80"},
- {"https", "foo.com", "foo.com:443"},
- {"https", "foo.com:1234", "foo.com:1234"},
- {"https", "1.2.3.4:1234", "1.2.3.4:1234"},
- {"https", "1.2.3.4", "1.2.3.4:443"},
- {"https", "[::1]:1234", "[::1]:1234"},
- {"https", "[::1]", "[::1]:443"},
- }
- for _, tt := range tests {
- got := authorityAddr(tt.scheme, tt.authority)
- if got != tt.want {
- t.Errorf("authorityAddr(%q, %q) = %q; want %q", tt.scheme, tt.authority, got, tt.want)
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/write.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/write.go
deleted file mode 100644
index 6b0dfae..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/write.go
+++ /dev/null
@@ -1,370 +0,0 @@
-// 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 http2
-
-import (
- "bytes"
- "fmt"
- "log"
- "net/http"
- "net/url"
- "time"
-
- "golang.org/x/net/http2/hpack"
- "golang.org/x/net/lex/httplex"
-)
-
-// writeFramer is implemented by any type that is used to write frames.
-type writeFramer interface {
- writeFrame(writeContext) error
-
- // staysWithinBuffer reports whether this writer promises that
- // it will only write less than or equal to size bytes, and it
- // won't Flush the write context.
- staysWithinBuffer(size int) bool
-}
-
-// writeContext is the interface needed by the various frame writer
-// types below. All the writeFrame methods below are scheduled via the
-// frame writing scheduler (see writeScheduler in writesched.go).
-//
-// This interface is implemented by *serverConn.
-//
-// TODO: decide whether to a) use this in the client code (which didn't
-// end up using this yet, because it has a simpler design, not
-// currently implementing priorities), or b) delete this and
-// make the server code a bit more concrete.
-type writeContext interface {
- Framer() *Framer
- Flush() error
- CloseConn() error
- // HeaderEncoder returns an HPACK encoder that writes to the
- // returned buffer.
- HeaderEncoder() (*hpack.Encoder, *bytes.Buffer)
-}
-
-// writeEndsStream reports whether w writes a frame that will transition
-// the stream to a half-closed local state. This returns false for RST_STREAM,
-// which closes the entire stream (not just the local half).
-func writeEndsStream(w writeFramer) bool {
- switch v := w.(type) {
- case *writeData:
- return v.endStream
- case *writeResHeaders:
- return v.endStream
- case nil:
- // This can only happen if the caller reuses w after it's
- // been intentionally nil'ed out to prevent use. Keep this
- // here to catch future refactoring breaking it.
- panic("writeEndsStream called on nil writeFramer")
- }
- return false
-}
-
-type flushFrameWriter struct{}
-
-func (flushFrameWriter) writeFrame(ctx writeContext) error {
- return ctx.Flush()
-}
-
-func (flushFrameWriter) staysWithinBuffer(max int) bool { return false }
-
-type writeSettings []Setting
-
-func (s writeSettings) staysWithinBuffer(max int) bool {
- const settingSize = 6 // uint16 + uint32
- return frameHeaderLen+settingSize*len(s) <= max
-
-}
-
-func (s writeSettings) writeFrame(ctx writeContext) error {
- return ctx.Framer().WriteSettings([]Setting(s)...)
-}
-
-type writeGoAway struct {
- maxStreamID uint32
- code ErrCode
-}
-
-func (p *writeGoAway) writeFrame(ctx writeContext) error {
- err := ctx.Framer().WriteGoAway(p.maxStreamID, p.code, nil)
- if p.code != 0 {
- ctx.Flush() // ignore error: we're hanging up on them anyway
- time.Sleep(50 * time.Millisecond)
- ctx.CloseConn()
- }
- return err
-}
-
-func (*writeGoAway) staysWithinBuffer(max int) bool { return false } // flushes
-
-type writeData struct {
- streamID uint32
- p []byte
- endStream bool
-}
-
-func (w *writeData) String() string {
- return fmt.Sprintf("writeData(stream=%d, p=%d, endStream=%v)", w.streamID, len(w.p), w.endStream)
-}
-
-func (w *writeData) writeFrame(ctx writeContext) error {
- return ctx.Framer().WriteData(w.streamID, w.endStream, w.p)
-}
-
-func (w *writeData) staysWithinBuffer(max int) bool {
- return frameHeaderLen+len(w.p) <= max
-}
-
-// handlerPanicRST is the message sent from handler goroutines when
-// the handler panics.
-type handlerPanicRST struct {
- StreamID uint32
-}
-
-func (hp handlerPanicRST) writeFrame(ctx writeContext) error {
- return ctx.Framer().WriteRSTStream(hp.StreamID, ErrCodeInternal)
-}
-
-func (hp handlerPanicRST) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
-
-func (se StreamError) writeFrame(ctx writeContext) error {
- return ctx.Framer().WriteRSTStream(se.StreamID, se.Code)
-}
-
-func (se StreamError) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
-
-type writePingAck struct{ pf *PingFrame }
-
-func (w writePingAck) writeFrame(ctx writeContext) error {
- return ctx.Framer().WritePing(true, w.pf.Data)
-}
-
-func (w writePingAck) staysWithinBuffer(max int) bool { return frameHeaderLen+len(w.pf.Data) <= max }
-
-type writeSettingsAck struct{}
-
-func (writeSettingsAck) writeFrame(ctx writeContext) error {
- return ctx.Framer().WriteSettingsAck()
-}
-
-func (writeSettingsAck) staysWithinBuffer(max int) bool { return frameHeaderLen <= max }
-
-// splitHeaderBlock splits headerBlock into fragments so that each fragment fits
-// in a single frame, then calls fn for each fragment. firstFrag/lastFrag are true
-// for the first/last fragment, respectively.
-func splitHeaderBlock(ctx writeContext, headerBlock []byte, fn func(ctx writeContext, frag []byte, firstFrag, lastFrag bool) error) error {
- // For now we're lazy and just pick the minimum MAX_FRAME_SIZE
- // that all peers must support (16KB). Later we could care
- // more and send larger frames if the peer advertised it, but
- // there's little point. Most headers are small anyway (so we
- // generally won't have CONTINUATION frames), and extra frames
- // only waste 9 bytes anyway.
- const maxFrameSize = 16384
-
- first := true
- for len(headerBlock) > 0 {
- frag := headerBlock
- if len(frag) > maxFrameSize {
- frag = frag[:maxFrameSize]
- }
- headerBlock = headerBlock[len(frag):]
- if err := fn(ctx, frag, first, len(headerBlock) == 0); err != nil {
- return err
- }
- first = false
- }
- return nil
-}
-
-// writeResHeaders is a request to write a HEADERS and 0+ CONTINUATION frames
-// for HTTP response headers or trailers from a server handler.
-type writeResHeaders struct {
- streamID uint32
- httpResCode int // 0 means no ":status" line
- h http.Header // may be nil
- trailers []string // if non-nil, which keys of h to write. nil means all.
- endStream bool
-
- date string
- contentType string
- contentLength string
-}
-
-func encKV(enc *hpack.Encoder, k, v string) {
- if VerboseLogs {
- log.Printf("http2: server encoding header %q = %q", k, v)
- }
- enc.WriteField(hpack.HeaderField{Name: k, Value: v})
-}
-
-func (w *writeResHeaders) staysWithinBuffer(max int) bool {
- // TODO: this is a common one. It'd be nice to return true
- // here and get into the fast path if we could be clever and
- // calculate the size fast enough, or at least a conservative
- // uppper bound that usually fires. (Maybe if w.h and
- // w.trailers are nil, so we don't need to enumerate it.)
- // Otherwise I'm afraid that just calculating the length to
- // answer this question would be slower than the ~2µs benefit.
- return false
-}
-
-func (w *writeResHeaders) writeFrame(ctx writeContext) error {
- enc, buf := ctx.HeaderEncoder()
- buf.Reset()
-
- if w.httpResCode != 0 {
- encKV(enc, ":status", httpCodeString(w.httpResCode))
- }
-
- encodeHeaders(enc, w.h, w.trailers)
-
- if w.contentType != "" {
- encKV(enc, "content-type", w.contentType)
- }
- if w.contentLength != "" {
- encKV(enc, "content-length", w.contentLength)
- }
- if w.date != "" {
- encKV(enc, "date", w.date)
- }
-
- headerBlock := buf.Bytes()
- if len(headerBlock) == 0 && w.trailers == nil {
- panic("unexpected empty hpack")
- }
-
- return splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
-}
-
-func (w *writeResHeaders) writeHeaderBlock(ctx writeContext, frag []byte, firstFrag, lastFrag bool) error {
- if firstFrag {
- return ctx.Framer().WriteHeaders(HeadersFrameParam{
- StreamID: w.streamID,
- BlockFragment: frag,
- EndStream: w.endStream,
- EndHeaders: lastFrag,
- })
- } else {
- return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
- }
-}
-
-// writePushPromise is a request to write a PUSH_PROMISE and 0+ CONTINUATION frames.
-type writePushPromise struct {
- streamID uint32 // pusher stream
- method string // for :method
- url *url.URL // for :scheme, :authority, :path
- h http.Header
-
- // Creates an ID for a pushed stream. This runs on serveG just before
- // the frame is written. The returned ID is copied to promisedID.
- allocatePromisedID func() (uint32, error)
- promisedID uint32
-}
-
-func (w *writePushPromise) staysWithinBuffer(max int) bool {
- // TODO: see writeResHeaders.staysWithinBuffer
- return false
-}
-
-func (w *writePushPromise) writeFrame(ctx writeContext) error {
- enc, buf := ctx.HeaderEncoder()
- buf.Reset()
-
- encKV(enc, ":method", w.method)
- encKV(enc, ":scheme", w.url.Scheme)
- encKV(enc, ":authority", w.url.Host)
- encKV(enc, ":path", w.url.RequestURI())
- encodeHeaders(enc, w.h, nil)
-
- headerBlock := buf.Bytes()
- if len(headerBlock) == 0 {
- panic("unexpected empty hpack")
- }
-
- return splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
-}
-
-func (w *writePushPromise) writeHeaderBlock(ctx writeContext, frag []byte, firstFrag, lastFrag bool) error {
- if firstFrag {
- return ctx.Framer().WritePushPromise(PushPromiseParam{
- StreamID: w.streamID,
- PromiseID: w.promisedID,
- BlockFragment: frag,
- EndHeaders: lastFrag,
- })
- } else {
- return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
- }
-}
-
-type write100ContinueHeadersFrame struct {
- streamID uint32
-}
-
-func (w write100ContinueHeadersFrame) writeFrame(ctx writeContext) error {
- enc, buf := ctx.HeaderEncoder()
- buf.Reset()
- encKV(enc, ":status", "100")
- return ctx.Framer().WriteHeaders(HeadersFrameParam{
- StreamID: w.streamID,
- BlockFragment: buf.Bytes(),
- EndStream: false,
- EndHeaders: true,
- })
-}
-
-func (w write100ContinueHeadersFrame) staysWithinBuffer(max int) bool {
- // Sloppy but conservative:
- return 9+2*(len(":status")+len("100")) <= max
-}
-
-type writeWindowUpdate struct {
- streamID uint32 // or 0 for conn-level
- n uint32
-}
-
-func (wu writeWindowUpdate) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
-
-func (wu writeWindowUpdate) writeFrame(ctx writeContext) error {
- return ctx.Framer().WriteWindowUpdate(wu.streamID, wu.n)
-}
-
-// encodeHeaders encodes an http.Header. If keys is not nil, then (k, h[k])
-// is encoded only only if k is in keys.
-func encodeHeaders(enc *hpack.Encoder, h http.Header, keys []string) {
- if keys == nil {
- sorter := sorterPool.Get().(*sorter)
- // Using defer here, since the returned keys from the
- // sorter.Keys method is only valid until the sorter
- // is returned:
- defer sorterPool.Put(sorter)
- keys = sorter.Keys(h)
- }
- for _, k := range keys {
- vv := h[k]
- k = lowerHeader(k)
- if !validWireHeaderFieldName(k) {
- // Skip it as backup paranoia. Per
- // golang.org/issue/14048, these should
- // already be rejected at a higher level.
- continue
- }
- isTE := k == "transfer-encoding"
- for _, v := range vv {
- if !httplex.ValidHeaderFieldValue(v) {
- // TODO: return an error? golang.org/issue/14048
- // For now just omit it.
- continue
- }
- // TODO: more of "8.1.2.2 Connection-Specific Header Fields"
- if isTE && v != "trailers" {
- continue
- }
- encKV(enc, k, v)
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched.go
deleted file mode 100644
index 4fe3073..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched.go
+++ /dev/null
@@ -1,242 +0,0 @@
-// 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 http2
-
-import "fmt"
-
-// WriteScheduler is the interface implemented by HTTP/2 write schedulers.
-// Methods are never called concurrently.
-type WriteScheduler interface {
- // OpenStream opens a new stream in the write scheduler.
- // It is illegal to call this with streamID=0 or with a streamID that is
- // already open -- the call may panic.
- OpenStream(streamID uint32, options OpenStreamOptions)
-
- // CloseStream closes a stream in the write scheduler. Any frames queued on
- // this stream should be discarded. It is illegal to call this on a stream
- // that is not open -- the call may panic.
- CloseStream(streamID uint32)
-
- // AdjustStream adjusts the priority of the given stream. This may be called
- // on a stream that has not yet been opened or has been closed. Note that
- // RFC 7540 allows PRIORITY frames to be sent on streams in any state. See:
- // https://tools.ietf.org/html/rfc7540#section-5.1
- AdjustStream(streamID uint32, priority PriorityParam)
-
- // Push queues a frame in the scheduler. In most cases, this will not be
- // called with wr.StreamID()!=0 unless that stream is currently open. The one
- // exception is RST_STREAM frames, which may be sent on idle or closed streams.
- Push(wr FrameWriteRequest)
-
- // Pop dequeues the next frame to write. Returns false if no frames can
- // be written. Frames with a given wr.StreamID() are Pop'd in the same
- // order they are Push'd.
- Pop() (wr FrameWriteRequest, ok bool)
-}
-
-// OpenStreamOptions specifies extra options for WriteScheduler.OpenStream.
-type OpenStreamOptions struct {
- // PusherID is zero if the stream was initiated by the client. Otherwise,
- // PusherID names the stream that pushed the newly opened stream.
- PusherID uint32
-}
-
-// FrameWriteRequest is a request to write a frame.
-type FrameWriteRequest struct {
- // write is the interface value that does the writing, once the
- // WriteScheduler has selected this frame to write. The write
- // functions are all defined in write.go.
- write writeFramer
-
- // stream is the stream on which this frame will be written.
- // nil for non-stream frames like PING and SETTINGS.
- stream *stream
-
- // done, if non-nil, must be a buffered channel with space for
- // 1 message and is sent the return value from write (or an
- // earlier error) when the frame has been written.
- done chan error
-}
-
-// StreamID returns the id of the stream this frame will be written to.
-// 0 is used for non-stream frames such as PING and SETTINGS.
-func (wr FrameWriteRequest) StreamID() uint32 {
- if wr.stream == nil {
- if se, ok := wr.write.(StreamError); ok {
- // (*serverConn).resetStream doesn't set
- // stream because it doesn't necessarily have
- // one. So special case this type of write
- // message.
- return se.StreamID
- }
- return 0
- }
- return wr.stream.id
-}
-
-// DataSize returns the number of flow control bytes that must be consumed
-// to write this entire frame. This is 0 for non-DATA frames.
-func (wr FrameWriteRequest) DataSize() int {
- if wd, ok := wr.write.(*writeData); ok {
- return len(wd.p)
- }
- return 0
-}
-
-// Consume consumes min(n, available) bytes from this frame, where available
-// is the number of flow control bytes available on the stream. Consume returns
-// 0, 1, or 2 frames, where the integer return value gives the number of frames
-// returned.
-//
-// If flow control prevents consuming any bytes, this returns (_, _, 0). If
-// the entire frame was consumed, this returns (wr, _, 1). Otherwise, this
-// returns (consumed, rest, 2), where 'consumed' contains the consumed bytes and
-// 'rest' contains the remaining bytes. The consumed bytes are deducted from the
-// underlying stream's flow control budget.
-func (wr FrameWriteRequest) Consume(n int32) (FrameWriteRequest, FrameWriteRequest, int) {
- var empty FrameWriteRequest
-
- // Non-DATA frames are always consumed whole.
- wd, ok := wr.write.(*writeData)
- if !ok || len(wd.p) == 0 {
- return wr, empty, 1
- }
-
- // Might need to split after applying limits.
- allowed := wr.stream.flow.available()
- if n < allowed {
- allowed = n
- }
- if wr.stream.sc.maxFrameSize < allowed {
- allowed = wr.stream.sc.maxFrameSize
- }
- if allowed <= 0 {
- return empty, empty, 0
- }
- if len(wd.p) > int(allowed) {
- wr.stream.flow.take(allowed)
- consumed := FrameWriteRequest{
- stream: wr.stream,
- write: &writeData{
- streamID: wd.streamID,
- p: wd.p[:allowed],
- // Even if the original had endStream set, there
- // are bytes remaining because len(wd.p) > allowed,
- // so we know endStream is false.
- endStream: false,
- },
- // Our caller is blocking on the final DATA frame, not
- // this intermediate frame, so no need to wait.
- done: nil,
- }
- rest := FrameWriteRequest{
- stream: wr.stream,
- write: &writeData{
- streamID: wd.streamID,
- p: wd.p[allowed:],
- endStream: wd.endStream,
- },
- done: wr.done,
- }
- return consumed, rest, 2
- }
-
- // The frame is consumed whole.
- // NB: This cast cannot overflow because allowed is <= math.MaxInt32.
- wr.stream.flow.take(int32(len(wd.p)))
- return wr, empty, 1
-}
-
-// String is for debugging only.
-func (wr FrameWriteRequest) String() string {
- var des string
- if s, ok := wr.write.(fmt.Stringer); ok {
- des = s.String()
- } else {
- des = fmt.Sprintf("%T", wr.write)
- }
- return fmt.Sprintf("[FrameWriteRequest stream=%d, ch=%v, writer=%v]", wr.StreamID(), wr.done != nil, des)
-}
-
-// replyToWriter sends err to wr.done and panics if the send must block
-// This does nothing if wr.done is nil.
-func (wr *FrameWriteRequest) replyToWriter(err error) {
- if wr.done == nil {
- return
- }
- select {
- case wr.done <- err:
- default:
- panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wr.write))
- }
- wr.write = nil // prevent use (assume it's tainted after wr.done send)
-}
-
-// writeQueue is used by implementations of WriteScheduler.
-type writeQueue struct {
- s []FrameWriteRequest
-}
-
-func (q *writeQueue) empty() bool { return len(q.s) == 0 }
-
-func (q *writeQueue) push(wr FrameWriteRequest) {
- q.s = append(q.s, wr)
-}
-
-func (q *writeQueue) shift() FrameWriteRequest {
- if len(q.s) == 0 {
- panic("invalid use of queue")
- }
- wr := q.s[0]
- // TODO: less copy-happy queue.
- copy(q.s, q.s[1:])
- q.s[len(q.s)-1] = FrameWriteRequest{}
- q.s = q.s[:len(q.s)-1]
- return wr
-}
-
-// consume consumes up to n bytes from q.s[0]. If the frame is
-// entirely consumed, it is removed from the queue. If the frame
-// is partially consumed, the frame is kept with the consumed
-// bytes removed. Returns true iff any bytes were consumed.
-func (q *writeQueue) consume(n int32) (FrameWriteRequest, bool) {
- if len(q.s) == 0 {
- return FrameWriteRequest{}, false
- }
- consumed, rest, numresult := q.s[0].Consume(n)
- switch numresult {
- case 0:
- return FrameWriteRequest{}, false
- case 1:
- q.shift()
- case 2:
- q.s[0] = rest
- }
- return consumed, true
-}
-
-type writeQueuePool []*writeQueue
-
-// put inserts an unused writeQueue into the pool.
-func (p *writeQueuePool) put(q *writeQueue) {
- for i := range q.s {
- q.s[i] = FrameWriteRequest{}
- }
- q.s = q.s[:0]
- *p = append(*p, q)
-}
-
-// get returns an empty writeQueue.
-func (p *writeQueuePool) get() *writeQueue {
- ln := len(*p)
- if ln == 0 {
- return new(writeQueue)
- }
- x := ln - 1
- q := (*p)[x]
- (*p)[x] = nil
- *p = (*p)[:x]
- return q
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_priority.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_priority.go
deleted file mode 100644
index 0113272..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_priority.go
+++ /dev/null
@@ -1,452 +0,0 @@
-// 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 http2
-
-import (
- "fmt"
- "math"
- "sort"
-)
-
-// RFC 7540, Section 5.3.5: the default weight is 16.
-const priorityDefaultWeight = 15 // 16 = 15 + 1
-
-// PriorityWriteSchedulerConfig configures a priorityWriteScheduler.
-type PriorityWriteSchedulerConfig struct {
- // MaxClosedNodesInTree controls the maximum number of closed streams to
- // retain in the priority tree. Setting this to zero saves a small amount
- // of memory at the cost of performance.
- //
- // See RFC 7540, Section 5.3.4:
- // "It is possible for a stream to become closed while prioritization
- // information ... is in transit. ... This potentially creates suboptimal
- // prioritization, since the stream could be given a priority that is
- // different from what is intended. To avoid these problems, an endpoint
- // SHOULD retain stream prioritization state for a period after streams
- // become closed. The longer state is retained, the lower the chance that
- // streams are assigned incorrect or default priority values."
- MaxClosedNodesInTree int
-
- // MaxIdleNodesInTree controls the maximum number of idle streams to
- // retain in the priority tree. Setting this to zero saves a small amount
- // of memory at the cost of performance.
- //
- // See RFC 7540, Section 5.3.4:
- // Similarly, streams that are in the "idle" state can be assigned
- // priority or become a parent of other streams. This allows for the
- // creation of a grouping node in the dependency tree, which enables
- // more flexible expressions of priority. Idle streams begin with a
- // default priority (Section 5.3.5).
- MaxIdleNodesInTree int
-
- // ThrottleOutOfOrderWrites enables write throttling to help ensure that
- // data is delivered in priority order. This works around a race where
- // stream B depends on stream A and both streams are about to call Write
- // to queue DATA frames. If B wins the race, a naive scheduler would eagerly
- // write as much data from B as possible, but this is suboptimal because A
- // is a higher-priority stream. With throttling enabled, we write a small
- // amount of data from B to minimize the amount of bandwidth that B can
- // steal from A.
- ThrottleOutOfOrderWrites bool
-}
-
-// NewPriorityWriteScheduler constructs a WriteScheduler that schedules
-// frames by following HTTP/2 priorities as described in RFC 7340 Section 5.3.
-// If cfg is nil, default options are used.
-func NewPriorityWriteScheduler(cfg *PriorityWriteSchedulerConfig) WriteScheduler {
- if cfg == nil {
- // For justification of these defaults, see:
- // https://docs.google.com/document/d/1oLhNg1skaWD4_DtaoCxdSRN5erEXrH-KnLrMwEpOtFY
- cfg = &PriorityWriteSchedulerConfig{
- MaxClosedNodesInTree: 10,
- MaxIdleNodesInTree: 10,
- ThrottleOutOfOrderWrites: false,
- }
- }
-
- ws := &priorityWriteScheduler{
- nodes: make(map[uint32]*priorityNode),
- maxClosedNodesInTree: cfg.MaxClosedNodesInTree,
- maxIdleNodesInTree: cfg.MaxIdleNodesInTree,
- enableWriteThrottle: cfg.ThrottleOutOfOrderWrites,
- }
- ws.nodes[0] = &ws.root
- if cfg.ThrottleOutOfOrderWrites {
- ws.writeThrottleLimit = 1024
- } else {
- ws.writeThrottleLimit = math.MaxInt32
- }
- return ws
-}
-
-type priorityNodeState int
-
-const (
- priorityNodeOpen priorityNodeState = iota
- priorityNodeClosed
- priorityNodeIdle
-)
-
-// priorityNode is a node in an HTTP/2 priority tree.
-// Each node is associated with a single stream ID.
-// See RFC 7540, Section 5.3.
-type priorityNode struct {
- q writeQueue // queue of pending frames to write
- id uint32 // id of the stream, or 0 for the root of the tree
- weight uint8 // the actual weight is weight+1, so the value is in [1,256]
- state priorityNodeState // open | closed | idle
- bytes int64 // number of bytes written by this node, or 0 if closed
- subtreeBytes int64 // sum(node.bytes) of all nodes in this subtree
-
- // These links form the priority tree.
- parent *priorityNode
- kids *priorityNode // start of the kids list
- prev, next *priorityNode // doubly-linked list of siblings
-}
-
-func (n *priorityNode) setParent(parent *priorityNode) {
- if n == parent {
- panic("setParent to self")
- }
- if n.parent == parent {
- return
- }
- // Unlink from current parent.
- if parent := n.parent; parent != nil {
- if n.prev == nil {
- parent.kids = n.next
- } else {
- n.prev.next = n.next
- }
- if n.next != nil {
- n.next.prev = n.prev
- }
- }
- // Link to new parent.
- // If parent=nil, remove n from the tree.
- // Always insert at the head of parent.kids (this is assumed by walkReadyInOrder).
- n.parent = parent
- if parent == nil {
- n.next = nil
- n.prev = nil
- } else {
- n.next = parent.kids
- n.prev = nil
- if n.next != nil {
- n.next.prev = n
- }
- parent.kids = n
- }
-}
-
-func (n *priorityNode) addBytes(b int64) {
- n.bytes += b
- for ; n != nil; n = n.parent {
- n.subtreeBytes += b
- }
-}
-
-// walkReadyInOrder iterates over the tree in priority order, calling f for each node
-// with a non-empty write queue. When f returns true, this funcion returns true and the
-// walk halts. tmp is used as scratch space for sorting.
-//
-// f(n, openParent) takes two arguments: the node to visit, n, and a bool that is true
-// if any ancestor p of n is still open (ignoring the root node).
-func (n *priorityNode) walkReadyInOrder(openParent bool, tmp *[]*priorityNode, f func(*priorityNode, bool) bool) bool {
- if !n.q.empty() && f(n, openParent) {
- return true
- }
- if n.kids == nil {
- return false
- }
-
- // Don't consider the root "open" when updating openParent since
- // we can't send data frames on the root stream (only control frames).
- if n.id != 0 {
- openParent = openParent || (n.state == priorityNodeOpen)
- }
-
- // Common case: only one kid or all kids have the same weight.
- // Some clients don't use weights; other clients (like web browsers)
- // use mostly-linear priority trees.
- w := n.kids.weight
- needSort := false
- for k := n.kids.next; k != nil; k = k.next {
- if k.weight != w {
- needSort = true
- break
- }
- }
- if !needSort {
- for k := n.kids; k != nil; k = k.next {
- if k.walkReadyInOrder(openParent, tmp, f) {
- return true
- }
- }
- return false
- }
-
- // Uncommon case: sort the child nodes. We remove the kids from the parent,
- // then re-insert after sorting so we can reuse tmp for future sort calls.
- *tmp = (*tmp)[:0]
- for n.kids != nil {
- *tmp = append(*tmp, n.kids)
- n.kids.setParent(nil)
- }
- sort.Sort(sortPriorityNodeSiblings(*tmp))
- for i := len(*tmp) - 1; i >= 0; i-- {
- (*tmp)[i].setParent(n) // setParent inserts at the head of n.kids
- }
- for k := n.kids; k != nil; k = k.next {
- if k.walkReadyInOrder(openParent, tmp, f) {
- return true
- }
- }
- return false
-}
-
-type sortPriorityNodeSiblings []*priorityNode
-
-func (z sortPriorityNodeSiblings) Len() int { return len(z) }
-func (z sortPriorityNodeSiblings) Swap(i, k int) { z[i], z[k] = z[k], z[i] }
-func (z sortPriorityNodeSiblings) Less(i, k int) bool {
- // Prefer the subtree that has sent fewer bytes relative to its weight.
- // See sections 5.3.2 and 5.3.4.
- wi, bi := float64(z[i].weight+1), float64(z[i].subtreeBytes)
- wk, bk := float64(z[k].weight+1), float64(z[k].subtreeBytes)
- if bi == 0 && bk == 0 {
- return wi >= wk
- }
- if bk == 0 {
- return false
- }
- return bi/bk <= wi/wk
-}
-
-type priorityWriteScheduler struct {
- // root is the root of the priority tree, where root.id = 0.
- // The root queues control frames that are not associated with any stream.
- root priorityNode
-
- // nodes maps stream ids to priority tree nodes.
- nodes map[uint32]*priorityNode
-
- // maxID is the maximum stream id in nodes.
- maxID uint32
-
- // lists of nodes that have been closed or are idle, but are kept in
- // the tree for improved prioritization. When the lengths exceed either
- // maxClosedNodesInTree or maxIdleNodesInTree, old nodes are discarded.
- closedNodes, idleNodes []*priorityNode
-
- // From the config.
- maxClosedNodesInTree int
- maxIdleNodesInTree int
- writeThrottleLimit int32
- enableWriteThrottle bool
-
- // tmp is scratch space for priorityNode.walkReadyInOrder to reduce allocations.
- tmp []*priorityNode
-
- // pool of empty queues for reuse.
- queuePool writeQueuePool
-}
-
-func (ws *priorityWriteScheduler) OpenStream(streamID uint32, options OpenStreamOptions) {
- // The stream may be currently idle but cannot be opened or closed.
- if curr := ws.nodes[streamID]; curr != nil {
- if curr.state != priorityNodeIdle {
- panic(fmt.Sprintf("stream %d already opened", streamID))
- }
- curr.state = priorityNodeOpen
- return
- }
-
- // RFC 7540, Section 5.3.5:
- // "All streams are initially assigned a non-exclusive dependency on stream 0x0.
- // Pushed streams initially depend on their associated stream. In both cases,
- // streams are assigned a default weight of 16."
- parent := ws.nodes[options.PusherID]
- if parent == nil {
- parent = &ws.root
- }
- n := &priorityNode{
- q: *ws.queuePool.get(),
- id: streamID,
- weight: priorityDefaultWeight,
- state: priorityNodeOpen,
- }
- n.setParent(parent)
- ws.nodes[streamID] = n
- if streamID > ws.maxID {
- ws.maxID = streamID
- }
-}
-
-func (ws *priorityWriteScheduler) CloseStream(streamID uint32) {
- if streamID == 0 {
- panic("violation of WriteScheduler interface: cannot close stream 0")
- }
- if ws.nodes[streamID] == nil {
- panic(fmt.Sprintf("violation of WriteScheduler interface: unknown stream %d", streamID))
- }
- if ws.nodes[streamID].state != priorityNodeOpen {
- panic(fmt.Sprintf("violation of WriteScheduler interface: stream %d already closed", streamID))
- }
-
- n := ws.nodes[streamID]
- n.state = priorityNodeClosed
- n.addBytes(-n.bytes)
-
- q := n.q
- ws.queuePool.put(&q)
- n.q.s = nil
- if ws.maxClosedNodesInTree > 0 {
- ws.addClosedOrIdleNode(&ws.closedNodes, ws.maxClosedNodesInTree, n)
- } else {
- ws.removeNode(n)
- }
-}
-
-func (ws *priorityWriteScheduler) AdjustStream(streamID uint32, priority PriorityParam) {
- if streamID == 0 {
- panic("adjustPriority on root")
- }
-
- // If streamID does not exist, there are two cases:
- // - A closed stream that has been removed (this will have ID <= maxID)
- // - An idle stream that is being used for "grouping" (this will have ID > maxID)
- n := ws.nodes[streamID]
- if n == nil {
- if streamID <= ws.maxID || ws.maxIdleNodesInTree == 0 {
- return
- }
- ws.maxID = streamID
- n = &priorityNode{
- q: *ws.queuePool.get(),
- id: streamID,
- weight: priorityDefaultWeight,
- state: priorityNodeIdle,
- }
- n.setParent(&ws.root)
- ws.nodes[streamID] = n
- ws.addClosedOrIdleNode(&ws.idleNodes, ws.maxIdleNodesInTree, n)
- }
-
- // Section 5.3.1: A dependency on a stream that is not currently in the tree
- // results in that stream being given a default priority (Section 5.3.5).
- parent := ws.nodes[priority.StreamDep]
- if parent == nil {
- n.setParent(&ws.root)
- n.weight = priorityDefaultWeight
- return
- }
-
- // Ignore if the client tries to make a node its own parent.
- if n == parent {
- return
- }
-
- // Section 5.3.3:
- // "If a stream is made dependent on one of its own dependencies, the
- // formerly dependent stream is first moved to be dependent on the
- // reprioritized stream's previous parent. The moved dependency retains
- // its weight."
- //
- // That is: if parent depends on n, move parent to depend on n.parent.
- for x := parent.parent; x != nil; x = x.parent {
- if x == n {
- parent.setParent(n.parent)
- break
- }
- }
-
- // Section 5.3.3: The exclusive flag causes the stream to become the sole
- // dependency of its parent stream, causing other dependencies to become
- // dependent on the exclusive stream.
- if priority.Exclusive {
- k := parent.kids
- for k != nil {
- next := k.next
- if k != n {
- k.setParent(n)
- }
- k = next
- }
- }
-
- n.setParent(parent)
- n.weight = priority.Weight
-}
-
-func (ws *priorityWriteScheduler) Push(wr FrameWriteRequest) {
- var n *priorityNode
- if id := wr.StreamID(); id == 0 {
- n = &ws.root
- } else {
- n = ws.nodes[id]
- if n == nil {
- // id is an idle or closed stream. wr should not be a HEADERS or
- // DATA frame. However, wr can be a RST_STREAM. In this case, we
- // push wr onto the root, rather than creating a new priorityNode,
- // since RST_STREAM is tiny and the stream's priority is unknown
- // anyway. See issue #17919.
- if wr.DataSize() > 0 {
- panic("add DATA on non-open stream")
- }
- n = &ws.root
- }
- }
- n.q.push(wr)
-}
-
-func (ws *priorityWriteScheduler) Pop() (wr FrameWriteRequest, ok bool) {
- ws.root.walkReadyInOrder(false, &ws.tmp, func(n *priorityNode, openParent bool) bool {
- limit := int32(math.MaxInt32)
- if openParent {
- limit = ws.writeThrottleLimit
- }
- wr, ok = n.q.consume(limit)
- if !ok {
- return false
- }
- n.addBytes(int64(wr.DataSize()))
- // If B depends on A and B continuously has data available but A
- // does not, gradually increase the throttling limit to allow B to
- // steal more and more bandwidth from A.
- if openParent {
- ws.writeThrottleLimit += 1024
- if ws.writeThrottleLimit < 0 {
- ws.writeThrottleLimit = math.MaxInt32
- }
- } else if ws.enableWriteThrottle {
- ws.writeThrottleLimit = 1024
- }
- return true
- })
- return wr, ok
-}
-
-func (ws *priorityWriteScheduler) addClosedOrIdleNode(list *[]*priorityNode, maxSize int, n *priorityNode) {
- if maxSize == 0 {
- return
- }
- if len(*list) == maxSize {
- // Remove the oldest node, then shift left.
- ws.removeNode((*list)[0])
- x := (*list)[1:]
- copy(*list, x)
- *list = (*list)[:len(x)]
- }
- *list = append(*list, n)
-}
-
-func (ws *priorityWriteScheduler) removeNode(n *priorityNode) {
- for k := n.kids; k != nil; k = k.next {
- k.setParent(n.parent)
- }
- n.setParent(nil)
- delete(ws.nodes, n.id)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_priority_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_priority_test.go
deleted file mode 100644
index f2b535a..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_priority_test.go
+++ /dev/null
@@ -1,541 +0,0 @@
-// 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 http2
-
-import (
- "bytes"
- "fmt"
- "sort"
- "testing"
-)
-
-func defaultPriorityWriteScheduler() *priorityWriteScheduler {
- return NewPriorityWriteScheduler(nil).(*priorityWriteScheduler)
-}
-
-func checkPriorityWellFormed(ws *priorityWriteScheduler) error {
- for id, n := range ws.nodes {
- if id != n.id {
- return fmt.Errorf("bad ws.nodes: ws.nodes[%d] = %d", id, n.id)
- }
- if n.parent == nil {
- if n.next != nil || n.prev != nil {
- return fmt.Errorf("bad node %d: nil parent but prev/next not nil", id)
- }
- continue
- }
- found := false
- for k := n.parent.kids; k != nil; k = k.next {
- if k.id == id {
- found = true
- break
- }
- }
- if !found {
- return fmt.Errorf("bad node %d: not found in parent %d kids list", id, n.parent.id)
- }
- }
- return nil
-}
-
-func fmtTree(ws *priorityWriteScheduler, fmtNode func(*priorityNode) string) string {
- var ids []int
- for _, n := range ws.nodes {
- ids = append(ids, int(n.id))
- }
- sort.Ints(ids)
-
- var buf bytes.Buffer
- for _, id := range ids {
- if buf.Len() != 0 {
- buf.WriteString(" ")
- }
- if id == 0 {
- buf.WriteString(fmtNode(&ws.root))
- } else {
- buf.WriteString(fmtNode(ws.nodes[uint32(id)]))
- }
- }
- return buf.String()
-}
-
-func fmtNodeParentSkipRoot(n *priorityNode) string {
- switch {
- case n.id == 0:
- return ""
- case n.parent == nil:
- return fmt.Sprintf("%d{parent:nil}", n.id)
- default:
- return fmt.Sprintf("%d{parent:%d}", n.id, n.parent.id)
- }
-}
-
-func fmtNodeWeightParentSkipRoot(n *priorityNode) string {
- switch {
- case n.id == 0:
- return ""
- case n.parent == nil:
- return fmt.Sprintf("%d{weight:%d,parent:nil}", n.id, n.weight)
- default:
- return fmt.Sprintf("%d{weight:%d,parent:%d}", n.id, n.weight, n.parent.id)
- }
-}
-
-func TestPriorityTwoStreams(t *testing.T) {
- ws := defaultPriorityWriteScheduler()
- ws.OpenStream(1, OpenStreamOptions{})
- ws.OpenStream(2, OpenStreamOptions{})
-
- want := "1{weight:15,parent:0} 2{weight:15,parent:0}"
- if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want {
- t.Errorf("After open\ngot %q\nwant %q", got, want)
- }
-
- // Move 1's parent to 2.
- ws.AdjustStream(1, PriorityParam{
- StreamDep: 2,
- Weight: 32,
- Exclusive: false,
- })
- want = "1{weight:32,parent:2} 2{weight:15,parent:0}"
- if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want {
- t.Errorf("After adjust\ngot %q\nwant %q", got, want)
- }
-
- if err := checkPriorityWellFormed(ws); err != nil {
- t.Error(err)
- }
-}
-
-func TestPriorityAdjustExclusiveZero(t *testing.T) {
- // 1, 2, and 3 are all children of the 0 stream.
- // Exclusive reprioritization to any of the streams should bring
- // the rest of the streams under the reprioritized stream.
- ws := defaultPriorityWriteScheduler()
- ws.OpenStream(1, OpenStreamOptions{})
- ws.OpenStream(2, OpenStreamOptions{})
- ws.OpenStream(3, OpenStreamOptions{})
-
- want := "1{weight:15,parent:0} 2{weight:15,parent:0} 3{weight:15,parent:0}"
- if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want {
- t.Errorf("After open\ngot %q\nwant %q", got, want)
- }
-
- ws.AdjustStream(2, PriorityParam{
- StreamDep: 0,
- Weight: 20,
- Exclusive: true,
- })
- want = "1{weight:15,parent:2} 2{weight:20,parent:0} 3{weight:15,parent:2}"
- if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want {
- t.Errorf("After adjust\ngot %q\nwant %q", got, want)
- }
-
- if err := checkPriorityWellFormed(ws); err != nil {
- t.Error(err)
- }
-}
-
-func TestPriorityAdjustOwnParent(t *testing.T) {
- // Assigning a node as its own parent should have no effect.
- ws := defaultPriorityWriteScheduler()
- ws.OpenStream(1, OpenStreamOptions{})
- ws.OpenStream(2, OpenStreamOptions{})
- ws.AdjustStream(2, PriorityParam{
- StreamDep: 2,
- Weight: 20,
- Exclusive: true,
- })
- want := "1{weight:15,parent:0} 2{weight:15,parent:0}"
- if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want {
- t.Errorf("After adjust\ngot %q\nwant %q", got, want)
- }
- if err := checkPriorityWellFormed(ws); err != nil {
- t.Error(err)
- }
-}
-
-func TestPriorityClosedStreams(t *testing.T) {
- ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{MaxClosedNodesInTree: 2}).(*priorityWriteScheduler)
- ws.OpenStream(1, OpenStreamOptions{})
- ws.OpenStream(2, OpenStreamOptions{PusherID: 1})
- ws.OpenStream(3, OpenStreamOptions{PusherID: 2})
- ws.OpenStream(4, OpenStreamOptions{PusherID: 3})
-
- // Close the first three streams. We lose 1, but keep 2 and 3.
- ws.CloseStream(1)
- ws.CloseStream(2)
- ws.CloseStream(3)
-
- want := "2{weight:15,parent:0} 3{weight:15,parent:2} 4{weight:15,parent:3}"
- if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want {
- t.Errorf("After close\ngot %q\nwant %q", got, want)
- }
- if err := checkPriorityWellFormed(ws); err != nil {
- t.Error(err)
- }
-
- // Adding a stream as an exclusive child of 1 gives it default
- // priorities, since 1 is gone.
- ws.OpenStream(5, OpenStreamOptions{})
- ws.AdjustStream(5, PriorityParam{StreamDep: 1, Weight: 15, Exclusive: true})
-
- // Adding a stream as an exclusive child of 2 should work, since 2 is not gone.
- ws.OpenStream(6, OpenStreamOptions{})
- ws.AdjustStream(6, PriorityParam{StreamDep: 2, Weight: 15, Exclusive: true})
-
- want = "2{weight:15,parent:0} 3{weight:15,parent:6} 4{weight:15,parent:3} 5{weight:15,parent:0} 6{weight:15,parent:2}"
- if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want {
- t.Errorf("After add streams\ngot %q\nwant %q", got, want)
- }
- if err := checkPriorityWellFormed(ws); err != nil {
- t.Error(err)
- }
-}
-
-func TestPriorityClosedStreamsDisabled(t *testing.T) {
- ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{}).(*priorityWriteScheduler)
- ws.OpenStream(1, OpenStreamOptions{})
- ws.OpenStream(2, OpenStreamOptions{PusherID: 1})
- ws.OpenStream(3, OpenStreamOptions{PusherID: 2})
-
- // Close the first two streams. We keep only 3.
- ws.CloseStream(1)
- ws.CloseStream(2)
-
- want := "3{weight:15,parent:0}"
- if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want {
- t.Errorf("After close\ngot %q\nwant %q", got, want)
- }
- if err := checkPriorityWellFormed(ws); err != nil {
- t.Error(err)
- }
-}
-
-func TestPriorityIdleStreams(t *testing.T) {
- ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{MaxIdleNodesInTree: 2}).(*priorityWriteScheduler)
- ws.AdjustStream(1, PriorityParam{StreamDep: 0, Weight: 15}) // idle
- ws.AdjustStream(2, PriorityParam{StreamDep: 0, Weight: 15}) // idle
- ws.AdjustStream(3, PriorityParam{StreamDep: 2, Weight: 20}) // idle
- ws.OpenStream(4, OpenStreamOptions{})
- ws.OpenStream(5, OpenStreamOptions{})
- ws.OpenStream(6, OpenStreamOptions{})
- ws.AdjustStream(4, PriorityParam{StreamDep: 1, Weight: 15})
- ws.AdjustStream(5, PriorityParam{StreamDep: 2, Weight: 15})
- ws.AdjustStream(6, PriorityParam{StreamDep: 3, Weight: 15})
-
- want := "2{weight:15,parent:0} 3{weight:20,parent:2} 4{weight:15,parent:0} 5{weight:15,parent:2} 6{weight:15,parent:3}"
- if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want {
- t.Errorf("After open\ngot %q\nwant %q", got, want)
- }
- if err := checkPriorityWellFormed(ws); err != nil {
- t.Error(err)
- }
-}
-
-func TestPriorityIdleStreamsDisabled(t *testing.T) {
- ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{}).(*priorityWriteScheduler)
- ws.AdjustStream(1, PriorityParam{StreamDep: 0, Weight: 15}) // idle
- ws.AdjustStream(2, PriorityParam{StreamDep: 0, Weight: 15}) // idle
- ws.AdjustStream(3, PriorityParam{StreamDep: 2, Weight: 20}) // idle
- ws.OpenStream(4, OpenStreamOptions{})
-
- want := "4{weight:15,parent:0}"
- if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want {
- t.Errorf("After open\ngot %q\nwant %q", got, want)
- }
- if err := checkPriorityWellFormed(ws); err != nil {
- t.Error(err)
- }
-}
-
-func TestPrioritySection531NonExclusive(t *testing.T) {
- // Example from RFC 7540 Section 5.3.1.
- // A,B,C,D = 1,2,3,4
- ws := defaultPriorityWriteScheduler()
- ws.OpenStream(1, OpenStreamOptions{})
- ws.OpenStream(2, OpenStreamOptions{PusherID: 1})
- ws.OpenStream(3, OpenStreamOptions{PusherID: 1})
- ws.OpenStream(4, OpenStreamOptions{})
- ws.AdjustStream(4, PriorityParam{
- StreamDep: 1,
- Weight: 15,
- Exclusive: false,
- })
- want := "1{parent:0} 2{parent:1} 3{parent:1} 4{parent:1}"
- if got := fmtTree(ws, fmtNodeParentSkipRoot); got != want {
- t.Errorf("After adjust\ngot %q\nwant %q", got, want)
- }
- if err := checkPriorityWellFormed(ws); err != nil {
- t.Error(err)
- }
-}
-
-func TestPrioritySection531Exclusive(t *testing.T) {
- // Example from RFC 7540 Section 5.3.1.
- // A,B,C,D = 1,2,3,4
- ws := defaultPriorityWriteScheduler()
- ws.OpenStream(1, OpenStreamOptions{})
- ws.OpenStream(2, OpenStreamOptions{PusherID: 1})
- ws.OpenStream(3, OpenStreamOptions{PusherID: 1})
- ws.OpenStream(4, OpenStreamOptions{})
- ws.AdjustStream(4, PriorityParam{
- StreamDep: 1,
- Weight: 15,
- Exclusive: true,
- })
- want := "1{parent:0} 2{parent:4} 3{parent:4} 4{parent:1}"
- if got := fmtTree(ws, fmtNodeParentSkipRoot); got != want {
- t.Errorf("After adjust\ngot %q\nwant %q", got, want)
- }
- if err := checkPriorityWellFormed(ws); err != nil {
- t.Error(err)
- }
-}
-
-func makeSection533Tree() *priorityWriteScheduler {
- // Initial tree from RFC 7540 Section 5.3.3.
- // A,B,C,D,E,F = 1,2,3,4,5,6
- ws := defaultPriorityWriteScheduler()
- ws.OpenStream(1, OpenStreamOptions{})
- ws.OpenStream(2, OpenStreamOptions{PusherID: 1})
- ws.OpenStream(3, OpenStreamOptions{PusherID: 1})
- ws.OpenStream(4, OpenStreamOptions{PusherID: 3})
- ws.OpenStream(5, OpenStreamOptions{PusherID: 3})
- ws.OpenStream(6, OpenStreamOptions{PusherID: 4})
- return ws
-}
-
-func TestPrioritySection533NonExclusive(t *testing.T) {
- // Example from RFC 7540 Section 5.3.3.
- // A,B,C,D,E,F = 1,2,3,4,5,6
- ws := defaultPriorityWriteScheduler()
- ws.OpenStream(1, OpenStreamOptions{})
- ws.OpenStream(2, OpenStreamOptions{PusherID: 1})
- ws.OpenStream(3, OpenStreamOptions{PusherID: 1})
- ws.OpenStream(4, OpenStreamOptions{PusherID: 3})
- ws.OpenStream(5, OpenStreamOptions{PusherID: 3})
- ws.OpenStream(6, OpenStreamOptions{PusherID: 4})
- ws.AdjustStream(1, PriorityParam{
- StreamDep: 4,
- Weight: 15,
- Exclusive: false,
- })
- want := "1{parent:4} 2{parent:1} 3{parent:1} 4{parent:0} 5{parent:3} 6{parent:4}"
- if got := fmtTree(ws, fmtNodeParentSkipRoot); got != want {
- t.Errorf("After adjust\ngot %q\nwant %q", got, want)
- }
- if err := checkPriorityWellFormed(ws); err != nil {
- t.Error(err)
- }
-}
-
-func TestPrioritySection533Exclusive(t *testing.T) {
- // Example from RFC 7540 Section 5.3.3.
- // A,B,C,D,E,F = 1,2,3,4,5,6
- ws := defaultPriorityWriteScheduler()
- ws.OpenStream(1, OpenStreamOptions{})
- ws.OpenStream(2, OpenStreamOptions{PusherID: 1})
- ws.OpenStream(3, OpenStreamOptions{PusherID: 1})
- ws.OpenStream(4, OpenStreamOptions{PusherID: 3})
- ws.OpenStream(5, OpenStreamOptions{PusherID: 3})
- ws.OpenStream(6, OpenStreamOptions{PusherID: 4})
- ws.AdjustStream(1, PriorityParam{
- StreamDep: 4,
- Weight: 15,
- Exclusive: true,
- })
- want := "1{parent:4} 2{parent:1} 3{parent:1} 4{parent:0} 5{parent:3} 6{parent:1}"
- if got := fmtTree(ws, fmtNodeParentSkipRoot); got != want {
- t.Errorf("After adjust\ngot %q\nwant %q", got, want)
- }
- if err := checkPriorityWellFormed(ws); err != nil {
- t.Error(err)
- }
-}
-
-func checkPopAll(ws WriteScheduler, order []uint32) error {
- for k, id := range order {
- wr, ok := ws.Pop()
- if !ok {
- return fmt.Errorf("Pop[%d]: got ok=false, want %d (order=%v)", k, id, order)
- }
- if got := wr.StreamID(); got != id {
- return fmt.Errorf("Pop[%d]: got %v, want %d (order=%v)", k, got, id, order)
- }
- }
- wr, ok := ws.Pop()
- if ok {
- return fmt.Errorf("Pop[%d]: got %v, want ok=false (order=%v)", len(order), wr.StreamID(), order)
- }
- return nil
-}
-
-func TestPriorityPopFrom533Tree(t *testing.T) {
- ws := makeSection533Tree()
-
- ws.Push(makeWriteHeadersRequest(3 /*C*/))
- ws.Push(makeWriteNonStreamRequest())
- ws.Push(makeWriteHeadersRequest(5 /*E*/))
- ws.Push(makeWriteHeadersRequest(1 /*A*/))
- t.Log("tree:", fmtTree(ws, fmtNodeParentSkipRoot))
-
- if err := checkPopAll(ws, []uint32{0 /*NonStream*/, 1, 3, 5}); err != nil {
- t.Error(err)
- }
-}
-
-func TestPriorityPopFromLinearTree(t *testing.T) {
- ws := defaultPriorityWriteScheduler()
- ws.OpenStream(1, OpenStreamOptions{})
- ws.OpenStream(2, OpenStreamOptions{PusherID: 1})
- ws.OpenStream(3, OpenStreamOptions{PusherID: 2})
- ws.OpenStream(4, OpenStreamOptions{PusherID: 3})
-
- ws.Push(makeWriteHeadersRequest(3))
- ws.Push(makeWriteHeadersRequest(4))
- ws.Push(makeWriteHeadersRequest(1))
- ws.Push(makeWriteHeadersRequest(2))
- ws.Push(makeWriteNonStreamRequest())
- ws.Push(makeWriteNonStreamRequest())
- t.Log("tree:", fmtTree(ws, fmtNodeParentSkipRoot))
-
- if err := checkPopAll(ws, []uint32{0, 0 /*NonStreams*/, 1, 2, 3, 4}); err != nil {
- t.Error(err)
- }
-}
-
-func TestPriorityFlowControl(t *testing.T) {
- ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{ThrottleOutOfOrderWrites: false})
- ws.OpenStream(1, OpenStreamOptions{})
- ws.OpenStream(2, OpenStreamOptions{PusherID: 1})
-
- sc := &serverConn{maxFrameSize: 16}
- st1 := &stream{id: 1, sc: sc}
- st2 := &stream{id: 2, sc: sc}
-
- ws.Push(FrameWriteRequest{&writeData{1, make([]byte, 16), false}, st1, nil})
- ws.Push(FrameWriteRequest{&writeData{2, make([]byte, 16), false}, st2, nil})
- ws.AdjustStream(2, PriorityParam{StreamDep: 1})
-
- // No flow-control bytes available.
- if wr, ok := ws.Pop(); ok {
- t.Fatalf("Pop(limited by flow control)=%v,true, want false", wr)
- }
-
- // Add enough flow-control bytes to write st2 in two Pop calls.
- // Should write data from st2 even though it's lower priority than st1.
- for i := 1; i <= 2; i++ {
- st2.flow.add(8)
- wr, ok := ws.Pop()
- if !ok {
- t.Fatalf("Pop(%d)=false, want true", i)
- }
- if got, want := wr.DataSize(), 8; got != want {
- t.Fatalf("Pop(%d)=%d bytes, want %d bytes", i, got, want)
- }
- }
-}
-
-func TestPriorityThrottleOutOfOrderWrites(t *testing.T) {
- ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{ThrottleOutOfOrderWrites: true})
- ws.OpenStream(1, OpenStreamOptions{})
- ws.OpenStream(2, OpenStreamOptions{PusherID: 1})
-
- sc := &serverConn{maxFrameSize: 4096}
- st1 := &stream{id: 1, sc: sc}
- st2 := &stream{id: 2, sc: sc}
- st1.flow.add(4096)
- st2.flow.add(4096)
- ws.Push(FrameWriteRequest{&writeData{2, make([]byte, 4096), false}, st2, nil})
- ws.AdjustStream(2, PriorityParam{StreamDep: 1})
-
- // We have enough flow-control bytes to write st2 in a single Pop call.
- // However, due to out-of-order write throttling, the first call should
- // only write 1KB.
- wr, ok := ws.Pop()
- if !ok {
- t.Fatalf("Pop(st2.first)=false, want true")
- }
- if got, want := wr.StreamID(), uint32(2); got != want {
- t.Fatalf("Pop(st2.first)=stream %d, want stream %d", got, want)
- }
- if got, want := wr.DataSize(), 1024; got != want {
- t.Fatalf("Pop(st2.first)=%d bytes, want %d bytes", got, want)
- }
-
- // Now add data on st1. This should take precedence.
- ws.Push(FrameWriteRequest{&writeData{1, make([]byte, 4096), false}, st1, nil})
- wr, ok = ws.Pop()
- if !ok {
- t.Fatalf("Pop(st1)=false, want true")
- }
- if got, want := wr.StreamID(), uint32(1); got != want {
- t.Fatalf("Pop(st1)=stream %d, want stream %d", got, want)
- }
- if got, want := wr.DataSize(), 4096; got != want {
- t.Fatalf("Pop(st1)=%d bytes, want %d bytes", got, want)
- }
-
- // Should go back to writing 1KB from st2.
- wr, ok = ws.Pop()
- if !ok {
- t.Fatalf("Pop(st2.last)=false, want true")
- }
- if got, want := wr.StreamID(), uint32(2); got != want {
- t.Fatalf("Pop(st2.last)=stream %d, want stream %d", got, want)
- }
- if got, want := wr.DataSize(), 1024; got != want {
- t.Fatalf("Pop(st2.last)=%d bytes, want %d bytes", got, want)
- }
-}
-
-func TestPriorityWeights(t *testing.T) {
- ws := defaultPriorityWriteScheduler()
- ws.OpenStream(1, OpenStreamOptions{})
- ws.OpenStream(2, OpenStreamOptions{})
-
- sc := &serverConn{maxFrameSize: 8}
- st1 := &stream{id: 1, sc: sc}
- st2 := &stream{id: 2, sc: sc}
- st1.flow.add(40)
- st2.flow.add(40)
-
- ws.Push(FrameWriteRequest{&writeData{1, make([]byte, 40), false}, st1, nil})
- ws.Push(FrameWriteRequest{&writeData{2, make([]byte, 40), false}, st2, nil})
- ws.AdjustStream(1, PriorityParam{StreamDep: 0, Weight: 34})
- ws.AdjustStream(2, PriorityParam{StreamDep: 0, Weight: 9})
-
- // st1 gets 3.5x the bandwidth of st2 (3.5 = (34+1)/(9+1)).
- // The maximum frame size is 8 bytes. The write sequence should be:
- // st1, total bytes so far is (st1=8, st=0)
- // st2, total bytes so far is (st1=8, st=8)
- // st1, total bytes so far is (st1=16, st=8)
- // st1, total bytes so far is (st1=24, st=8) // 3x bandwidth
- // st1, total bytes so far is (st1=32, st=8) // 4x bandwidth
- // st2, total bytes so far is (st1=32, st=16) // 2x bandwidth
- // st1, total bytes so far is (st1=40, st=16)
- // st2, total bytes so far is (st1=40, st=24)
- // st2, total bytes so far is (st1=40, st=32)
- // st2, total bytes so far is (st1=40, st=40)
- if err := checkPopAll(ws, []uint32{1, 2, 1, 1, 1, 2, 1, 2, 2, 2}); err != nil {
- t.Error(err)
- }
-}
-
-func TestPriorityRstStreamOnNonOpenStreams(t *testing.T) {
- ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{
- MaxClosedNodesInTree: 0,
- MaxIdleNodesInTree: 0,
- })
- ws.OpenStream(1, OpenStreamOptions{})
- ws.CloseStream(1)
- ws.Push(FrameWriteRequest{write: streamError(1, ErrCodeProtocol)})
- ws.Push(FrameWriteRequest{write: streamError(2, ErrCodeProtocol)})
-
- if err := checkPopAll(ws, []uint32{1, 2}); err != nil {
- t.Error(err)
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_random.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_random.go
deleted file mode 100644
index 36d7919..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_random.go
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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 http2
-
-import "math"
-
-// NewRandomWriteScheduler constructs a WriteScheduler that ignores HTTP/2
-// priorities. Control frames like SETTINGS and PING are written before DATA
-// frames, but if no control frames are queued and multiple streams have queued
-// HEADERS or DATA frames, Pop selects a ready stream arbitrarily.
-func NewRandomWriteScheduler() WriteScheduler {
- return &randomWriteScheduler{sq: make(map[uint32]*writeQueue)}
-}
-
-type randomWriteScheduler struct {
- // zero are frames not associated with a specific stream.
- zero writeQueue
-
- // sq contains the stream-specific queues, keyed by stream ID.
- // When a stream is idle or closed, it's deleted from the map.
- sq map[uint32]*writeQueue
-
- // pool of empty queues for reuse.
- queuePool writeQueuePool
-}
-
-func (ws *randomWriteScheduler) OpenStream(streamID uint32, options OpenStreamOptions) {
- // no-op: idle streams are not tracked
-}
-
-func (ws *randomWriteScheduler) CloseStream(streamID uint32) {
- q, ok := ws.sq[streamID]
- if !ok {
- return
- }
- delete(ws.sq, streamID)
- ws.queuePool.put(q)
-}
-
-func (ws *randomWriteScheduler) AdjustStream(streamID uint32, priority PriorityParam) {
- // no-op: priorities are ignored
-}
-
-func (ws *randomWriteScheduler) Push(wr FrameWriteRequest) {
- id := wr.StreamID()
- if id == 0 {
- ws.zero.push(wr)
- return
- }
- q, ok := ws.sq[id]
- if !ok {
- q = ws.queuePool.get()
- ws.sq[id] = q
- }
- q.push(wr)
-}
-
-func (ws *randomWriteScheduler) Pop() (FrameWriteRequest, bool) {
- // Control frames first.
- if !ws.zero.empty() {
- return ws.zero.shift(), true
- }
- // Iterate over all non-idle streams until finding one that can be consumed.
- for _, q := range ws.sq {
- if wr, ok := q.consume(math.MaxInt32); ok {
- return wr, true
- }
- }
- return FrameWriteRequest{}, false
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_random_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_random_test.go
deleted file mode 100644
index 3bf4aa3..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_random_test.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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 http2
-
-import "testing"
-
-func TestRandomScheduler(t *testing.T) {
- ws := NewRandomWriteScheduler()
- ws.Push(makeWriteHeadersRequest(3))
- ws.Push(makeWriteHeadersRequest(4))
- ws.Push(makeWriteHeadersRequest(1))
- ws.Push(makeWriteHeadersRequest(2))
- ws.Push(makeWriteNonStreamRequest())
- ws.Push(makeWriteNonStreamRequest())
-
- // Pop all frames. Should get the non-stream requests first,
- // followed by the stream requests in any order.
- var order []FrameWriteRequest
- for {
- wr, ok := ws.Pop()
- if !ok {
- break
- }
- order = append(order, wr)
- }
- t.Logf("got frames: %v", order)
- if len(order) != 6 {
- t.Fatalf("got %d frames, expected 6", len(order))
- }
- if order[0].StreamID() != 0 || order[1].StreamID() != 0 {
- t.Fatal("expected non-stream frames first", order[0], order[1])
- }
- got := make(map[uint32]bool)
- for _, wr := range order[2:] {
- got[wr.StreamID()] = true
- }
- for id := uint32(1); id <= 4; id++ {
- if !got[id] {
- t.Errorf("frame not found for stream %d", id)
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_test.go
deleted file mode 100644
index 0807056..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_test.go
+++ /dev/null
@@ -1,125 +0,0 @@
-// 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 http2
-
-import (
- "fmt"
- "math"
- "reflect"
- "testing"
-)
-
-func makeWriteNonStreamRequest() FrameWriteRequest {
- return FrameWriteRequest{writeSettingsAck{}, nil, nil}
-}
-
-func makeWriteHeadersRequest(streamID uint32) FrameWriteRequest {
- st := &stream{id: streamID}
- return FrameWriteRequest{&writeResHeaders{streamID: streamID, httpResCode: 200}, st, nil}
-}
-
-func checkConsume(wr FrameWriteRequest, nbytes int32, want []FrameWriteRequest) error {
- consumed, rest, n := wr.Consume(nbytes)
- var wantConsumed, wantRest FrameWriteRequest
- switch len(want) {
- case 0:
- case 1:
- wantConsumed = want[0]
- case 2:
- wantConsumed = want[0]
- wantRest = want[1]
- }
- if !reflect.DeepEqual(consumed, wantConsumed) || !reflect.DeepEqual(rest, wantRest) || n != len(want) {
- return fmt.Errorf("got %v, %v, %v\nwant %v, %v, %v", consumed, rest, n, wantConsumed, wantRest, len(want))
- }
- return nil
-}
-
-func TestFrameWriteRequestNonData(t *testing.T) {
- wr := makeWriteNonStreamRequest()
- if got, want := wr.DataSize(), 0; got != want {
- t.Errorf("DataSize: got %v, want %v", got, want)
- }
-
- // Non-DATA frames are always consumed whole.
- if err := checkConsume(wr, 0, []FrameWriteRequest{wr}); err != nil {
- t.Errorf("Consume:\n%v", err)
- }
-}
-
-func TestFrameWriteRequestData(t *testing.T) {
- st := &stream{
- id: 1,
- sc: &serverConn{maxFrameSize: 16},
- }
- const size = 32
- wr := FrameWriteRequest{&writeData{st.id, make([]byte, size), true}, st, make(chan error)}
- if got, want := wr.DataSize(), size; got != want {
- t.Errorf("DataSize: got %v, want %v", got, want)
- }
-
- // No flow-control bytes available: cannot consume anything.
- if err := checkConsume(wr, math.MaxInt32, []FrameWriteRequest{}); err != nil {
- t.Errorf("Consume(limited by flow control):\n%v", err)
- }
-
- // Add enough flow-control bytes to consume the entire frame,
- // but we're now restricted by st.sc.maxFrameSize.
- st.flow.add(size)
- want := []FrameWriteRequest{
- {
- write: &writeData{st.id, make([]byte, st.sc.maxFrameSize), false},
- stream: st,
- done: nil,
- },
- {
- write: &writeData{st.id, make([]byte, size-st.sc.maxFrameSize), true},
- stream: st,
- done: wr.done,
- },
- }
- if err := checkConsume(wr, math.MaxInt32, want); err != nil {
- t.Errorf("Consume(limited by maxFrameSize):\n%v", err)
- }
- rest := want[1]
-
- // Consume 8 bytes from the remaining frame.
- want = []FrameWriteRequest{
- {
- write: &writeData{st.id, make([]byte, 8), false},
- stream: st,
- done: nil,
- },
- {
- write: &writeData{st.id, make([]byte, size-st.sc.maxFrameSize-8), true},
- stream: st,
- done: wr.done,
- },
- }
- if err := checkConsume(rest, 8, want); err != nil {
- t.Errorf("Consume(8):\n%v", err)
- }
- rest = want[1]
-
- // Consume all remaining bytes.
- want = []FrameWriteRequest{
- {
- write: &writeData{st.id, make([]byte, size-st.sc.maxFrameSize-8), true},
- stream: st,
- done: wr.done,
- },
- }
- if err := checkConsume(rest, math.MaxInt32, want); err != nil {
- t.Errorf("Consume(remainder):\n%v", err)
- }
-}
-
-func TestFrameWriteRequest_StreamID(t *testing.T) {
- const streamID = 123
- wr := FrameWriteRequest{write: streamError(streamID, ErrCodeNo)}
- if got := wr.StreamID(); got != streamID {
- t.Errorf("FrameWriteRequest(StreamError) = %v; want %v", got, streamID)
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/z_spec_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/z_spec_test.go
deleted file mode 100644
index 610b2cd..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/z_spec_test.go
+++ /dev/null
@@ -1,356 +0,0 @@
-// 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 http2
-
-import (
- "bytes"
- "encoding/xml"
- "flag"
- "fmt"
- "io"
- "os"
- "reflect"
- "regexp"
- "sort"
- "strconv"
- "strings"
- "sync"
- "testing"
-)
-
-var coverSpec = flag.Bool("coverspec", false, "Run spec coverage tests")
-
-// The global map of sentence coverage for the http2 spec.
-var defaultSpecCoverage specCoverage
-
-var loadSpecOnce sync.Once
-
-func loadSpec() {
- if f, err := os.Open("testdata/draft-ietf-httpbis-http2.xml"); err != nil {
- panic(err)
- } else {
- defaultSpecCoverage = readSpecCov(f)
- f.Close()
- }
-}
-
-// covers marks all sentences for section sec in defaultSpecCoverage. Sentences not
-// "covered" will be included in report outputted by TestSpecCoverage.
-func covers(sec, sentences string) {
- loadSpecOnce.Do(loadSpec)
- defaultSpecCoverage.cover(sec, sentences)
-}
-
-type specPart struct {
- section string
- sentence string
-}
-
-func (ss specPart) Less(oo specPart) bool {
- atoi := func(s string) int {
- n, err := strconv.Atoi(s)
- if err != nil {
- panic(err)
- }
- return n
- }
- a := strings.Split(ss.section, ".")
- b := strings.Split(oo.section, ".")
- for len(a) > 0 {
- if len(b) == 0 {
- return false
- }
- x, y := atoi(a[0]), atoi(b[0])
- if x == y {
- a, b = a[1:], b[1:]
- continue
- }
- return x < y
- }
- if len(b) > 0 {
- return true
- }
- return false
-}
-
-type bySpecSection []specPart
-
-func (a bySpecSection) Len() int { return len(a) }
-func (a bySpecSection) Less(i, j int) bool { return a[i].Less(a[j]) }
-func (a bySpecSection) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
-
-type specCoverage struct {
- coverage map[specPart]bool
- d *xml.Decoder
-}
-
-func joinSection(sec []int) string {
- s := fmt.Sprintf("%d", sec[0])
- for _, n := range sec[1:] {
- s = fmt.Sprintf("%s.%d", s, n)
- }
- return s
-}
-
-func (sc specCoverage) readSection(sec []int) {
- var (
- buf = new(bytes.Buffer)
- sub = 0
- )
- for {
- tk, err := sc.d.Token()
- if err != nil {
- if err == io.EOF {
- return
- }
- panic(err)
- }
- switch v := tk.(type) {
- case xml.StartElement:
- if skipElement(v) {
- if err := sc.d.Skip(); err != nil {
- panic(err)
- }
- if v.Name.Local == "section" {
- sub++
- }
- break
- }
- switch v.Name.Local {
- case "section":
- sub++
- sc.readSection(append(sec, sub))
- case "xref":
- buf.Write(sc.readXRef(v))
- }
- case xml.CharData:
- if len(sec) == 0 {
- break
- }
- buf.Write(v)
- case xml.EndElement:
- if v.Name.Local == "section" {
- sc.addSentences(joinSection(sec), buf.String())
- return
- }
- }
- }
-}
-
-func (sc specCoverage) readXRef(se xml.StartElement) []byte {
- var b []byte
- for {
- tk, err := sc.d.Token()
- if err != nil {
- panic(err)
- }
- switch v := tk.(type) {
- case xml.CharData:
- if b != nil {
- panic("unexpected CharData")
- }
- b = []byte(string(v))
- case xml.EndElement:
- if v.Name.Local != "xref" {
- panic("expected </xref>")
- }
- if b != nil {
- return b
- }
- sig := attrSig(se)
- switch sig {
- case "target":
- return []byte(fmt.Sprintf("[%s]", attrValue(se, "target")))
- case "fmt-of,rel,target", "fmt-,,rel,target":
- return []byte(fmt.Sprintf("[%s, %s]", attrValue(se, "target"), attrValue(se, "rel")))
- case "fmt-of,sec,target", "fmt-,,sec,target":
- return []byte(fmt.Sprintf("[section %s of %s]", attrValue(se, "sec"), attrValue(se, "target")))
- case "fmt-of,rel,sec,target":
- return []byte(fmt.Sprintf("[section %s of %s, %s]", attrValue(se, "sec"), attrValue(se, "target"), attrValue(se, "rel")))
- default:
- panic(fmt.Sprintf("unknown attribute signature %q in %#v", sig, fmt.Sprintf("%#v", se)))
- }
- default:
- panic(fmt.Sprintf("unexpected tag %q", v))
- }
- }
-}
-
-var skipAnchor = map[string]bool{
- "intro": true,
- "Overview": true,
-}
-
-var skipTitle = map[string]bool{
- "Acknowledgements": true,
- "Change Log": true,
- "Document Organization": true,
- "Conventions and Terminology": true,
-}
-
-func skipElement(s xml.StartElement) bool {
- switch s.Name.Local {
- case "artwork":
- return true
- case "section":
- for _, attr := range s.Attr {
- switch attr.Name.Local {
- case "anchor":
- if skipAnchor[attr.Value] || strings.HasPrefix(attr.Value, "changes.since.") {
- return true
- }
- case "title":
- if skipTitle[attr.Value] {
- return true
- }
- }
- }
- }
- return false
-}
-
-func readSpecCov(r io.Reader) specCoverage {
- sc := specCoverage{
- coverage: map[specPart]bool{},
- d: xml.NewDecoder(r)}
- sc.readSection(nil)
- return sc
-}
-
-func (sc specCoverage) addSentences(sec string, sentence string) {
- for _, s := range parseSentences(sentence) {
- sc.coverage[specPart{sec, s}] = false
- }
-}
-
-func (sc specCoverage) cover(sec string, sentence string) {
- for _, s := range parseSentences(sentence) {
- p := specPart{sec, s}
- if _, ok := sc.coverage[p]; !ok {
- panic(fmt.Sprintf("Not found in spec: %q, %q", sec, s))
- }
- sc.coverage[specPart{sec, s}] = true
- }
-
-}
-
-var whitespaceRx = regexp.MustCompile(`\s+`)
-
-func parseSentences(sens string) []string {
- sens = strings.TrimSpace(sens)
- if sens == "" {
- return nil
- }
- ss := strings.Split(whitespaceRx.ReplaceAllString(sens, " "), ". ")
- for i, s := range ss {
- s = strings.TrimSpace(s)
- if !strings.HasSuffix(s, ".") {
- s += "."
- }
- ss[i] = s
- }
- return ss
-}
-
-func TestSpecParseSentences(t *testing.T) {
- tests := []struct {
- ss string
- want []string
- }{
- {"Sentence 1. Sentence 2.",
- []string{
- "Sentence 1.",
- "Sentence 2.",
- }},
- {"Sentence 1. \nSentence 2.\tSentence 3.",
- []string{
- "Sentence 1.",
- "Sentence 2.",
- "Sentence 3.",
- }},
- }
-
- for i, tt := range tests {
- got := parseSentences(tt.ss)
- if !reflect.DeepEqual(got, tt.want) {
- t.Errorf("%d: got = %q, want %q", i, got, tt.want)
- }
- }
-}
-
-func TestSpecCoverage(t *testing.T) {
- if !*coverSpec {
- t.Skip()
- }
-
- loadSpecOnce.Do(loadSpec)
-
- var (
- list []specPart
- cv = defaultSpecCoverage.coverage
- total = len(cv)
- complete = 0
- )
-
- for sp, touched := range defaultSpecCoverage.coverage {
- if touched {
- complete++
- } else {
- list = append(list, sp)
- }
- }
- sort.Stable(bySpecSection(list))
-
- if testing.Short() && len(list) > 5 {
- list = list[:5]
- }
-
- for _, p := range list {
- t.Errorf("\tSECTION %s: %s", p.section, p.sentence)
- }
-
- t.Logf("%d/%d (%d%%) sentences covered", complete, total, (complete/total)*100)
-}
-
-func attrSig(se xml.StartElement) string {
- var names []string
- for _, attr := range se.Attr {
- if attr.Name.Local == "fmt" {
- names = append(names, "fmt-"+attr.Value)
- } else {
- names = append(names, attr.Name.Local)
- }
- }
- sort.Strings(names)
- return strings.Join(names, ",")
-}
-
-func attrValue(se xml.StartElement, attr string) string {
- for _, a := range se.Attr {
- if a.Name.Local == attr {
- return a.Value
- }
- }
- panic("unknown attribute " + attr)
-}
-
-func TestSpecPartLess(t *testing.T) {
- tests := []struct {
- sec1, sec2 string
- want bool
- }{
- {"6.2.1", "6.2", false},
- {"6.2", "6.2.1", true},
- {"6.10", "6.10.1", true},
- {"6.10", "6.1.1", false}, // 10, not 1
- {"6.1", "6.1", false}, // equal, so not less
- }
- for _, tt := range tests {
- got := (specPart{tt.sec1, "foo"}).Less(specPart{tt.sec2, "foo"})
- if got != tt.want {
- t.Errorf("Less(%q, %q) = %v; want %v", tt.sec1, tt.sec2, got, tt.want)
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/transform/examples_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/transform/examples_test.go
deleted file mode 100644
index f2e284d..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/transform/examples_test.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package transform_test
-
-import (
- "fmt"
- "unicode"
-
- "golang.org/x/text/transform"
- "golang.org/x/text/unicode/norm"
-)
-
-func ExampleRemoveFunc() {
- input := []byte(`tschüß; до свидания`)
-
- b := make([]byte, len(input))
-
- t := transform.RemoveFunc(unicode.IsSpace)
- n, _, _ := t.Transform(b, input, true)
- fmt.Println(string(b[:n]))
-
- t = transform.RemoveFunc(func(r rune) bool {
- return !unicode.Is(unicode.Latin, r)
- })
- n, _, _ = t.Transform(b, input, true)
- fmt.Println(string(b[:n]))
-
- n, _, _ = t.Transform(b, norm.NFD.Bytes(input), true)
- fmt.Println(string(b[:n]))
-
- // Output:
- // tschüß;досвидания
- // tschüß
- // tschuß
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/transform/transform.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/transform/transform.go
deleted file mode 100644
index fe47b9b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/transform/transform.go
+++ /dev/null
@@ -1,705 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package transform provides reader and writer wrappers that transform the
-// bytes passing through as well as various transformations. Example
-// transformations provided by other packages include normalization and
-// conversion between character sets.
-package transform // import "golang.org/x/text/transform"
-
-import (
- "bytes"
- "errors"
- "io"
- "unicode/utf8"
-)
-
-var (
- // ErrShortDst means that the destination buffer was too short to
- // receive all of the transformed bytes.
- ErrShortDst = errors.New("transform: short destination buffer")
-
- // ErrShortSrc means that the source buffer has insufficient data to
- // complete the transformation.
- ErrShortSrc = errors.New("transform: short source buffer")
-
- // ErrEndOfSpan means that the input and output (the transformed input)
- // are not identical.
- ErrEndOfSpan = errors.New("transform: input and output are not identical")
-
- // errInconsistentByteCount means that Transform returned success (nil
- // error) but also returned nSrc inconsistent with the src argument.
- errInconsistentByteCount = errors.New("transform: inconsistent byte count returned")
-
- // errShortInternal means that an internal buffer is not large enough
- // to make progress and the Transform operation must be aborted.
- errShortInternal = errors.New("transform: short internal buffer")
-)
-
-// Transformer transforms bytes.
-type Transformer interface {
- // Transform writes to dst the transformed bytes read from src, and
- // returns the number of dst bytes written and src bytes read. The
- // atEOF argument tells whether src represents the last bytes of the
- // input.
- //
- // Callers should always process the nDst bytes produced and account
- // for the nSrc bytes consumed before considering the error err.
- //
- // A nil error means that all of the transformed bytes (whether freshly
- // transformed from src or left over from previous Transform calls)
- // were written to dst. A nil error can be returned regardless of
- // whether atEOF is true. If err is nil then nSrc must equal len(src);
- // the converse is not necessarily true.
- //
- // ErrShortDst means that dst was too short to receive all of the
- // transformed bytes. ErrShortSrc means that src had insufficient data
- // to complete the transformation. If both conditions apply, then
- // either error may be returned. Other than the error conditions listed
- // here, implementations are free to report other errors that arise.
- Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error)
-
- // Reset resets the state and allows a Transformer to be reused.
- Reset()
-}
-
-// SpanningTransformer extends the Transformer interface with a Span method
-// that determines how much of the input already conforms to the Transformer.
-type SpanningTransformer interface {
- Transformer
-
- // Span returns a position in src such that transforming src[:n] results in
- // identical output src[:n] for these bytes. It does not necessarily return
- // the largest such n. The atEOF argument tells whether src represents the
- // last bytes of the input.
- //
- // Callers should always account for the n bytes consumed before
- // considering the error err.
- //
- // A nil error means that all input bytes are known to be identical to the
- // output produced by the Transformer. A nil error can be be returned
- // regardless of whether atEOF is true. If err is nil, then then n must
- // equal len(src); the converse is not necessarily true.
- //
- // ErrEndOfSpan means that the Transformer output may differ from the
- // input after n bytes. Note that n may be len(src), meaning that the output
- // would contain additional bytes after otherwise identical output.
- // ErrShortSrc means that src had insufficient data to determine whether the
- // remaining bytes would change. Other than the error conditions listed
- // here, implementations are free to report other errors that arise.
- //
- // Calling Span can modify the Transformer state as a side effect. In
- // effect, it does the transformation just as calling Transform would, only
- // without copying to a destination buffer and only up to a point it can
- // determine the input and output bytes are the same. This is obviously more
- // limited than calling Transform, but can be more efficient in terms of
- // copying and allocating buffers. Calls to Span and Transform may be
- // interleaved.
- Span(src []byte, atEOF bool) (n int, err error)
-}
-
-// NopResetter can be embedded by implementations of Transformer to add a nop
-// Reset method.
-type NopResetter struct{}
-
-// Reset implements the Reset method of the Transformer interface.
-func (NopResetter) Reset() {}
-
-// Reader wraps another io.Reader by transforming the bytes read.
-type Reader struct {
- r io.Reader
- t Transformer
- err error
-
- // dst[dst0:dst1] contains bytes that have been transformed by t but
- // not yet copied out via Read.
- dst []byte
- dst0, dst1 int
-
- // src[src0:src1] contains bytes that have been read from r but not
- // yet transformed through t.
- src []byte
- src0, src1 int
-
- // transformComplete is whether the transformation is complete,
- // regardless of whether or not it was successful.
- transformComplete bool
-}
-
-const defaultBufSize = 4096
-
-// NewReader returns a new Reader that wraps r by transforming the bytes read
-// via t. It calls Reset on t.
-func NewReader(r io.Reader, t Transformer) *Reader {
- t.Reset()
- return &Reader{
- r: r,
- t: t,
- dst: make([]byte, defaultBufSize),
- src: make([]byte, defaultBufSize),
- }
-}
-
-// Read implements the io.Reader interface.
-func (r *Reader) Read(p []byte) (int, error) {
- n, err := 0, error(nil)
- for {
- // Copy out any transformed bytes and return the final error if we are done.
- if r.dst0 != r.dst1 {
- n = copy(p, r.dst[r.dst0:r.dst1])
- r.dst0 += n
- if r.dst0 == r.dst1 && r.transformComplete {
- return n, r.err
- }
- return n, nil
- } else if r.transformComplete {
- return 0, r.err
- }
-
- // Try to transform some source bytes, or to flush the transformer if we
- // are out of source bytes. We do this even if r.r.Read returned an error.
- // As the io.Reader documentation says, "process the n > 0 bytes returned
- // before considering the error".
- if r.src0 != r.src1 || r.err != nil {
- r.dst0 = 0
- r.dst1, n, err = r.t.Transform(r.dst, r.src[r.src0:r.src1], r.err == io.EOF)
- r.src0 += n
-
- switch {
- case err == nil:
- if r.src0 != r.src1 {
- r.err = errInconsistentByteCount
- }
- // The Transform call was successful; we are complete if we
- // cannot read more bytes into src.
- r.transformComplete = r.err != nil
- continue
- case err == ErrShortDst && (r.dst1 != 0 || n != 0):
- // Make room in dst by copying out, and try again.
- continue
- case err == ErrShortSrc && r.src1-r.src0 != len(r.src) && r.err == nil:
- // Read more bytes into src via the code below, and try again.
- default:
- r.transformComplete = true
- // The reader error (r.err) takes precedence over the
- // transformer error (err) unless r.err is nil or io.EOF.
- if r.err == nil || r.err == io.EOF {
- r.err = err
- }
- continue
- }
- }
-
- // Move any untransformed source bytes to the start of the buffer
- // and read more bytes.
- if r.src0 != 0 {
- r.src0, r.src1 = 0, copy(r.src, r.src[r.src0:r.src1])
- }
- n, r.err = r.r.Read(r.src[r.src1:])
- r.src1 += n
- }
-}
-
-// TODO: implement ReadByte (and ReadRune??).
-
-// Writer wraps another io.Writer by transforming the bytes read.
-// The user needs to call Close to flush unwritten bytes that may
-// be buffered.
-type Writer struct {
- w io.Writer
- t Transformer
- dst []byte
-
- // src[:n] contains bytes that have not yet passed through t.
- src []byte
- n int
-}
-
-// NewWriter returns a new Writer that wraps w by transforming the bytes written
-// via t. It calls Reset on t.
-func NewWriter(w io.Writer, t Transformer) *Writer {
- t.Reset()
- return &Writer{
- w: w,
- t: t,
- dst: make([]byte, defaultBufSize),
- src: make([]byte, defaultBufSize),
- }
-}
-
-// Write implements the io.Writer interface. If there are not enough
-// bytes available to complete a Transform, the bytes will be buffered
-// for the next write. Call Close to convert the remaining bytes.
-func (w *Writer) Write(data []byte) (n int, err error) {
- src := data
- if w.n > 0 {
- // Append bytes from data to the last remainder.
- // TODO: limit the amount copied on first try.
- n = copy(w.src[w.n:], data)
- w.n += n
- src = w.src[:w.n]
- }
- for {
- nDst, nSrc, err := w.t.Transform(w.dst, src, false)
- if _, werr := w.w.Write(w.dst[:nDst]); werr != nil {
- return n, werr
- }
- src = src[nSrc:]
- if w.n == 0 {
- n += nSrc
- } else if len(src) <= n {
- // Enough bytes from w.src have been consumed. We make src point
- // to data instead to reduce the copying.
- w.n = 0
- n -= len(src)
- src = data[n:]
- if n < len(data) && (err == nil || err == ErrShortSrc) {
- continue
- }
- }
- switch err {
- case ErrShortDst:
- // This error is okay as long as we are making progress.
- if nDst > 0 || nSrc > 0 {
- continue
- }
- case ErrShortSrc:
- if len(src) < len(w.src) {
- m := copy(w.src, src)
- // If w.n > 0, bytes from data were already copied to w.src and n
- // was already set to the number of bytes consumed.
- if w.n == 0 {
- n += m
- }
- w.n = m
- err = nil
- } else if nDst > 0 || nSrc > 0 {
- // Not enough buffer to store the remainder. Keep processing as
- // long as there is progress. Without this case, transforms that
- // require a lookahead larger than the buffer may result in an
- // error. This is not something one may expect to be common in
- // practice, but it may occur when buffers are set to small
- // sizes during testing.
- continue
- }
- case nil:
- if w.n > 0 {
- err = errInconsistentByteCount
- }
- }
- return n, err
- }
-}
-
-// Close implements the io.Closer interface.
-func (w *Writer) Close() error {
- src := w.src[:w.n]
- for {
- nDst, nSrc, err := w.t.Transform(w.dst, src, true)
- if _, werr := w.w.Write(w.dst[:nDst]); werr != nil {
- return werr
- }
- if err != ErrShortDst {
- return err
- }
- src = src[nSrc:]
- }
-}
-
-type nop struct{ NopResetter }
-
-func (nop) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- n := copy(dst, src)
- if n < len(src) {
- err = ErrShortDst
- }
- return n, n, err
-}
-
-func (nop) Span(src []byte, atEOF bool) (n int, err error) {
- return len(src), nil
-}
-
-type discard struct{ NopResetter }
-
-func (discard) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- return 0, len(src), nil
-}
-
-var (
- // Discard is a Transformer for which all Transform calls succeed
- // by consuming all bytes and writing nothing.
- Discard Transformer = discard{}
-
- // Nop is a SpanningTransformer that copies src to dst.
- Nop SpanningTransformer = nop{}
-)
-
-// chain is a sequence of links. A chain with N Transformers has N+1 links and
-// N+1 buffers. Of those N+1 buffers, the first and last are the src and dst
-// buffers given to chain.Transform and the middle N-1 buffers are intermediate
-// buffers owned by the chain. The i'th link transforms bytes from the i'th
-// buffer chain.link[i].b at read offset chain.link[i].p to the i+1'th buffer
-// chain.link[i+1].b at write offset chain.link[i+1].n, for i in [0, N).
-type chain struct {
- link []link
- err error
- // errStart is the index at which the error occurred plus 1. Processing
- // errStart at this level at the next call to Transform. As long as
- // errStart > 0, chain will not consume any more source bytes.
- errStart int
-}
-
-func (c *chain) fatalError(errIndex int, err error) {
- if i := errIndex + 1; i > c.errStart {
- c.errStart = i
- c.err = err
- }
-}
-
-type link struct {
- t Transformer
- // b[p:n] holds the bytes to be transformed by t.
- b []byte
- p int
- n int
-}
-
-func (l *link) src() []byte {
- return l.b[l.p:l.n]
-}
-
-func (l *link) dst() []byte {
- return l.b[l.n:]
-}
-
-// Chain returns a Transformer that applies t in sequence.
-func Chain(t ...Transformer) Transformer {
- if len(t) == 0 {
- return nop{}
- }
- c := &chain{link: make([]link, len(t)+1)}
- for i, tt := range t {
- c.link[i].t = tt
- }
- // Allocate intermediate buffers.
- b := make([][defaultBufSize]byte, len(t)-1)
- for i := range b {
- c.link[i+1].b = b[i][:]
- }
- return c
-}
-
-// Reset resets the state of Chain. It calls Reset on all the Transformers.
-func (c *chain) Reset() {
- for i, l := range c.link {
- if l.t != nil {
- l.t.Reset()
- }
- c.link[i].p, c.link[i].n = 0, 0
- }
-}
-
-// TODO: make chain use Span (is going to be fun to implement!)
-
-// Transform applies the transformers of c in sequence.
-func (c *chain) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- // Set up src and dst in the chain.
- srcL := &c.link[0]
- dstL := &c.link[len(c.link)-1]
- srcL.b, srcL.p, srcL.n = src, 0, len(src)
- dstL.b, dstL.n = dst, 0
- var lastFull, needProgress bool // for detecting progress
-
- // i is the index of the next Transformer to apply, for i in [low, high].
- // low is the lowest index for which c.link[low] may still produce bytes.
- // high is the highest index for which c.link[high] has a Transformer.
- // The error returned by Transform determines whether to increase or
- // decrease i. We try to completely fill a buffer before converting it.
- for low, i, high := c.errStart, c.errStart, len(c.link)-2; low <= i && i <= high; {
- in, out := &c.link[i], &c.link[i+1]
- nDst, nSrc, err0 := in.t.Transform(out.dst(), in.src(), atEOF && low == i)
- out.n += nDst
- in.p += nSrc
- if i > 0 && in.p == in.n {
- in.p, in.n = 0, 0
- }
- needProgress, lastFull = lastFull, false
- switch err0 {
- case ErrShortDst:
- // Process the destination buffer next. Return if we are already
- // at the high index.
- if i == high {
- return dstL.n, srcL.p, ErrShortDst
- }
- if out.n != 0 {
- i++
- // If the Transformer at the next index is not able to process any
- // source bytes there is nothing that can be done to make progress
- // and the bytes will remain unprocessed. lastFull is used to
- // detect this and break out of the loop with a fatal error.
- lastFull = true
- continue
- }
- // The destination buffer was too small, but is completely empty.
- // Return a fatal error as this transformation can never complete.
- c.fatalError(i, errShortInternal)
- case ErrShortSrc:
- if i == 0 {
- // Save ErrShortSrc in err. All other errors take precedence.
- err = ErrShortSrc
- break
- }
- // Source bytes were depleted before filling up the destination buffer.
- // Verify we made some progress, move the remaining bytes to the errStart
- // and try to get more source bytes.
- if needProgress && nSrc == 0 || in.n-in.p == len(in.b) {
- // There were not enough source bytes to proceed while the source
- // buffer cannot hold any more bytes. Return a fatal error as this
- // transformation can never complete.
- c.fatalError(i, errShortInternal)
- break
- }
- // in.b is an internal buffer and we can make progress.
- in.p, in.n = 0, copy(in.b, in.src())
- fallthrough
- case nil:
- // if i == low, we have depleted the bytes at index i or any lower levels.
- // In that case we increase low and i. In all other cases we decrease i to
- // fetch more bytes before proceeding to the next index.
- if i > low {
- i--
- continue
- }
- default:
- c.fatalError(i, err0)
- }
- // Exhausted level low or fatal error: increase low and continue
- // to process the bytes accepted so far.
- i++
- low = i
- }
-
- // If c.errStart > 0, this means we found a fatal error. We will clear
- // all upstream buffers. At this point, no more progress can be made
- // downstream, as Transform would have bailed while handling ErrShortDst.
- if c.errStart > 0 {
- for i := 1; i < c.errStart; i++ {
- c.link[i].p, c.link[i].n = 0, 0
- }
- err, c.errStart, c.err = c.err, 0, nil
- }
- return dstL.n, srcL.p, err
-}
-
-// Deprecated: use runes.Remove instead.
-func RemoveFunc(f func(r rune) bool) Transformer {
- return removeF(f)
-}
-
-type removeF func(r rune) bool
-
-func (removeF) Reset() {}
-
-// Transform implements the Transformer interface.
-func (t removeF) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- for r, sz := rune(0), 0; len(src) > 0; src = src[sz:] {
-
- if r = rune(src[0]); r < utf8.RuneSelf {
- sz = 1
- } else {
- r, sz = utf8.DecodeRune(src)
-
- if sz == 1 {
- // Invalid rune.
- if !atEOF && !utf8.FullRune(src) {
- err = ErrShortSrc
- break
- }
- // We replace illegal bytes with RuneError. Not doing so might
- // otherwise turn a sequence of invalid UTF-8 into valid UTF-8.
- // The resulting byte sequence may subsequently contain runes
- // for which t(r) is true that were passed unnoticed.
- if !t(r) {
- if nDst+3 > len(dst) {
- err = ErrShortDst
- break
- }
- nDst += copy(dst[nDst:], "\uFFFD")
- }
- nSrc++
- continue
- }
- }
-
- if !t(r) {
- if nDst+sz > len(dst) {
- err = ErrShortDst
- break
- }
- nDst += copy(dst[nDst:], src[:sz])
- }
- nSrc += sz
- }
- return
-}
-
-// grow returns a new []byte that is longer than b, and copies the first n bytes
-// of b to the start of the new slice.
-func grow(b []byte, n int) []byte {
- m := len(b)
- if m <= 32 {
- m = 64
- } else if m <= 256 {
- m *= 2
- } else {
- m += m >> 1
- }
- buf := make([]byte, m)
- copy(buf, b[:n])
- return buf
-}
-
-const initialBufSize = 128
-
-// String returns a string with the result of converting s[:n] using t, where
-// n <= len(s). If err == nil, n will be len(s). It calls Reset on t.
-func String(t Transformer, s string) (result string, n int, err error) {
- t.Reset()
- if s == "" {
- // Fast path for the common case for empty input. Results in about a
- // 86% reduction of running time for BenchmarkStringLowerEmpty.
- if _, _, err := t.Transform(nil, nil, true); err == nil {
- return "", 0, nil
- }
- }
-
- // Allocate only once. Note that both dst and src escape when passed to
- // Transform.
- buf := [2 * initialBufSize]byte{}
- dst := buf[:initialBufSize:initialBufSize]
- src := buf[initialBufSize : 2*initialBufSize]
-
- // The input string s is transformed in multiple chunks (starting with a
- // chunk size of initialBufSize). nDst and nSrc are per-chunk (or
- // per-Transform-call) indexes, pDst and pSrc are overall indexes.
- nDst, nSrc := 0, 0
- pDst, pSrc := 0, 0
-
- // pPrefix is the length of a common prefix: the first pPrefix bytes of the
- // result will equal the first pPrefix bytes of s. It is not guaranteed to
- // be the largest such value, but if pPrefix, len(result) and len(s) are
- // all equal after the final transform (i.e. calling Transform with atEOF
- // being true returned nil error) then we don't need to allocate a new
- // result string.
- pPrefix := 0
- for {
- // Invariant: pDst == pPrefix && pSrc == pPrefix.
-
- n := copy(src, s[pSrc:])
- nDst, nSrc, err = t.Transform(dst, src[:n], pSrc+n == len(s))
- pDst += nDst
- pSrc += nSrc
-
- // TODO: let transformers implement an optional Spanner interface, akin
- // to norm's QuickSpan. This would even allow us to avoid any allocation.
- if !bytes.Equal(dst[:nDst], src[:nSrc]) {
- break
- }
- pPrefix = pSrc
- if err == ErrShortDst {
- // A buffer can only be short if a transformer modifies its input.
- break
- } else if err == ErrShortSrc {
- if nSrc == 0 {
- // No progress was made.
- break
- }
- // Equal so far and !atEOF, so continue checking.
- } else if err != nil || pPrefix == len(s) {
- return string(s[:pPrefix]), pPrefix, err
- }
- }
- // Post-condition: pDst == pPrefix + nDst && pSrc == pPrefix + nSrc.
-
- // We have transformed the first pSrc bytes of the input s to become pDst
- // transformed bytes. Those transformed bytes are discontiguous: the first
- // pPrefix of them equal s[:pPrefix] and the last nDst of them equal
- // dst[:nDst]. We copy them around, into a new dst buffer if necessary, so
- // that they become one contiguous slice: dst[:pDst].
- if pPrefix != 0 {
- newDst := dst
- if pDst > len(newDst) {
- newDst = make([]byte, len(s)+nDst-nSrc)
- }
- copy(newDst[pPrefix:pDst], dst[:nDst])
- copy(newDst[:pPrefix], s[:pPrefix])
- dst = newDst
- }
-
- // Prevent duplicate Transform calls with atEOF being true at the end of
- // the input. Also return if we have an unrecoverable error.
- if (err == nil && pSrc == len(s)) ||
- (err != nil && err != ErrShortDst && err != ErrShortSrc) {
- return string(dst[:pDst]), pSrc, err
- }
-
- // Transform the remaining input, growing dst and src buffers as necessary.
- for {
- n := copy(src, s[pSrc:])
- nDst, nSrc, err := t.Transform(dst[pDst:], src[:n], pSrc+n == len(s))
- pDst += nDst
- pSrc += nSrc
-
- // If we got ErrShortDst or ErrShortSrc, do not grow as long as we can
- // make progress. This may avoid excessive allocations.
- if err == ErrShortDst {
- if nDst == 0 {
- dst = grow(dst, pDst)
- }
- } else if err == ErrShortSrc {
- if nSrc == 0 {
- src = grow(src, 0)
- }
- } else if err != nil || pSrc == len(s) {
- return string(dst[:pDst]), pSrc, err
- }
- }
-}
-
-// Bytes returns a new byte slice with the result of converting b[:n] using t,
-// where n <= len(b). If err == nil, n will be len(b). It calls Reset on t.
-func Bytes(t Transformer, b []byte) (result []byte, n int, err error) {
- return doAppend(t, 0, make([]byte, len(b)), b)
-}
-
-// Append appends the result of converting src[:n] using t to dst, where
-// n <= len(src), If err == nil, n will be len(src). It calls Reset on t.
-func Append(t Transformer, dst, src []byte) (result []byte, n int, err error) {
- if len(dst) == cap(dst) {
- n := len(src) + len(dst) // It is okay for this to be 0.
- b := make([]byte, n)
- dst = b[:copy(b, dst)]
- }
- return doAppend(t, len(dst), dst[:cap(dst)], src)
-}
-
-func doAppend(t Transformer, pDst int, dst, src []byte) (result []byte, n int, err error) {
- t.Reset()
- pSrc := 0
- for {
- nDst, nSrc, err := t.Transform(dst[pDst:], src[pSrc:], true)
- pDst += nDst
- pSrc += nSrc
- if err != ErrShortDst {
- return dst[:pDst], pSrc, err
- }
-
- // Grow the destination buffer, but do not grow as long as we can make
- // progress. This may avoid excessive allocations.
- if nDst == 0 {
- dst = grow(dst, pDst)
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/transform/transform_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/transform/transform_test.go
deleted file mode 100644
index 771633d..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/transform/transform_test.go
+++ /dev/null
@@ -1,1317 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package transform
-
-import (
- "bytes"
- "errors"
- "fmt"
- "io/ioutil"
- "strconv"
- "strings"
- "testing"
- "time"
- "unicode/utf8"
-
- "golang.org/x/text/internal/testtext"
-)
-
-type lowerCaseASCII struct{ NopResetter }
-
-func (lowerCaseASCII) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- n := len(src)
- if n > len(dst) {
- n, err = len(dst), ErrShortDst
- }
- for i, c := range src[:n] {
- if 'A' <= c && c <= 'Z' {
- c += 'a' - 'A'
- }
- dst[i] = c
- }
- return n, n, err
-}
-
-// lowerCaseASCIILookahead lowercases the string and reports ErrShortSrc as long
-// as the input is not atEOF.
-type lowerCaseASCIILookahead struct{ NopResetter }
-
-func (lowerCaseASCIILookahead) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- n := len(src)
- if n > len(dst) {
- n, err = len(dst), ErrShortDst
- }
- for i, c := range src[:n] {
- if 'A' <= c && c <= 'Z' {
- c += 'a' - 'A'
- }
- dst[i] = c
- }
- if !atEOF {
- err = ErrShortSrc
- }
- return n, n, err
-}
-
-var errYouMentionedX = errors.New("you mentioned X")
-
-type dontMentionX struct{ NopResetter }
-
-func (dontMentionX) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- n := len(src)
- if n > len(dst) {
- n, err = len(dst), ErrShortDst
- }
- for i, c := range src[:n] {
- if c == 'X' {
- return i, i, errYouMentionedX
- }
- dst[i] = c
- }
- return n, n, err
-}
-
-var errAtEnd = errors.New("error after all text")
-
-type errorAtEnd struct{ NopResetter }
-
-func (errorAtEnd) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- n := copy(dst, src)
- if n < len(src) {
- return n, n, ErrShortDst
- }
- if atEOF {
- return n, n, errAtEnd
- }
- return n, n, nil
-}
-
-type replaceWithConstant struct {
- replacement string
- written int
-}
-
-func (t *replaceWithConstant) Reset() {
- t.written = 0
-}
-
-func (t *replaceWithConstant) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- if atEOF {
- nDst = copy(dst, t.replacement[t.written:])
- t.written += nDst
- if t.written < len(t.replacement) {
- err = ErrShortDst
- }
- }
- return nDst, len(src), err
-}
-
-type addAnXAtTheEnd struct{ NopResetter }
-
-func (addAnXAtTheEnd) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- n := copy(dst, src)
- if n < len(src) {
- return n, n, ErrShortDst
- }
- if !atEOF {
- return n, n, nil
- }
- if len(dst) == n {
- return n, n, ErrShortDst
- }
- dst[n] = 'X'
- return n + 1, n, nil
-}
-
-// doublerAtEOF is a strange Transformer that transforms "this" to "tthhiiss",
-// but only if atEOF is true.
-type doublerAtEOF struct{ NopResetter }
-
-func (doublerAtEOF) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- if !atEOF {
- return 0, 0, ErrShortSrc
- }
- for i, c := range src {
- if 2*i+2 >= len(dst) {
- return 2 * i, i, ErrShortDst
- }
- dst[2*i+0] = c
- dst[2*i+1] = c
- }
- return 2 * len(src), len(src), nil
-}
-
-// rleDecode and rleEncode implement a toy run-length encoding: "aabbbbbbbbbb"
-// is encoded as "2a10b". The decoding is assumed to not contain any numbers.
-
-type rleDecode struct{ NopResetter }
-
-func (rleDecode) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
-loop:
- for len(src) > 0 {
- n := 0
- for i, c := range src {
- if '0' <= c && c <= '9' {
- n = 10*n + int(c-'0')
- continue
- }
- if i == 0 {
- return nDst, nSrc, errors.New("rleDecode: bad input")
- }
- if n > len(dst) {
- return nDst, nSrc, ErrShortDst
- }
- for j := 0; j < n; j++ {
- dst[j] = c
- }
- dst, src = dst[n:], src[i+1:]
- nDst, nSrc = nDst+n, nSrc+i+1
- continue loop
- }
- if atEOF {
- return nDst, nSrc, errors.New("rleDecode: bad input")
- }
- return nDst, nSrc, ErrShortSrc
- }
- return nDst, nSrc, nil
-}
-
-type rleEncode struct {
- NopResetter
-
- // allowStutter means that "xxxxxxxx" can be encoded as "5x3x"
- // instead of always as "8x".
- allowStutter bool
-}
-
-func (e rleEncode) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- for len(src) > 0 {
- n, c0 := len(src), src[0]
- for i, c := range src[1:] {
- if c != c0 {
- n = i + 1
- break
- }
- }
- if n == len(src) && !atEOF && !e.allowStutter {
- return nDst, nSrc, ErrShortSrc
- }
- s := strconv.Itoa(n)
- if len(s) >= len(dst) {
- return nDst, nSrc, ErrShortDst
- }
- copy(dst, s)
- dst[len(s)] = c0
- dst, src = dst[len(s)+1:], src[n:]
- nDst, nSrc = nDst+len(s)+1, nSrc+n
- }
- return nDst, nSrc, nil
-}
-
-// trickler consumes all input bytes, but writes a single byte at a time to dst.
-type trickler []byte
-
-func (t *trickler) Reset() {
- *t = nil
-}
-
-func (t *trickler) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- *t = append(*t, src...)
- if len(*t) == 0 {
- return 0, 0, nil
- }
- if len(dst) == 0 {
- return 0, len(src), ErrShortDst
- }
- dst[0] = (*t)[0]
- *t = (*t)[1:]
- if len(*t) > 0 {
- err = ErrShortDst
- }
- return 1, len(src), err
-}
-
-// delayedTrickler is like trickler, but delays writing output to dst. This is
-// highly unlikely to be relevant in practice, but it seems like a good idea
-// to have some tolerance as long as progress can be detected.
-type delayedTrickler []byte
-
-func (t *delayedTrickler) Reset() {
- *t = nil
-}
-
-func (t *delayedTrickler) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- if len(*t) > 0 && len(dst) > 0 {
- dst[0] = (*t)[0]
- *t = (*t)[1:]
- nDst = 1
- }
- *t = append(*t, src...)
- if len(*t) > 0 {
- err = ErrShortDst
- }
- return nDst, len(src), err
-}
-
-type testCase struct {
- desc string
- t Transformer
- src string
- dstSize int
- srcSize int
- ioSize int
- wantStr string
- wantErr error
- wantIter int // number of iterations taken; 0 means we don't care.
-}
-
-func (t testCase) String() string {
- return tstr(t.t) + "; " + t.desc
-}
-
-func tstr(t Transformer) string {
- if stringer, ok := t.(fmt.Stringer); ok {
- return stringer.String()
- }
- s := fmt.Sprintf("%T", t)
- return s[1+strings.Index(s, "."):]
-}
-
-func (c chain) String() string {
- buf := &bytes.Buffer{}
- buf.WriteString("Chain(")
- for i, l := range c.link[:len(c.link)-1] {
- if i != 0 {
- fmt.Fprint(buf, ", ")
- }
- buf.WriteString(tstr(l.t))
- }
- buf.WriteString(")")
- return buf.String()
-}
-
-var testCases = []testCase{
- {
- desc: "empty",
- t: lowerCaseASCII{},
- src: "",
- dstSize: 100,
- srcSize: 100,
- wantStr: "",
- },
-
- {
- desc: "basic",
- t: lowerCaseASCII{},
- src: "Hello WORLD.",
- dstSize: 100,
- srcSize: 100,
- wantStr: "hello world.",
- },
-
- {
- desc: "small dst",
- t: lowerCaseASCII{},
- src: "Hello WORLD.",
- dstSize: 3,
- srcSize: 100,
- wantStr: "hello world.",
- },
-
- {
- desc: "small src",
- t: lowerCaseASCII{},
- src: "Hello WORLD.",
- dstSize: 100,
- srcSize: 4,
- wantStr: "hello world.",
- },
-
- {
- desc: "small buffers",
- t: lowerCaseASCII{},
- src: "Hello WORLD.",
- dstSize: 3,
- srcSize: 4,
- wantStr: "hello world.",
- },
-
- {
- desc: "very small buffers",
- t: lowerCaseASCII{},
- src: "Hello WORLD.",
- dstSize: 1,
- srcSize: 1,
- wantStr: "hello world.",
- },
-
- {
- desc: "small dst with lookahead",
- t: lowerCaseASCIILookahead{},
- src: "Hello WORLD.",
- dstSize: 3,
- srcSize: 100,
- wantStr: "hello world.",
- },
-
- {
- desc: "small src with lookahead",
- t: lowerCaseASCIILookahead{},
- src: "Hello WORLD.",
- dstSize: 100,
- srcSize: 4,
- wantStr: "hello world.",
- },
-
- {
- desc: "small buffers with lookahead",
- t: lowerCaseASCIILookahead{},
- src: "Hello WORLD.",
- dstSize: 3,
- srcSize: 4,
- wantStr: "hello world.",
- },
-
- {
- desc: "very small buffers with lookahead",
- t: lowerCaseASCIILookahead{},
- src: "Hello WORLD.",
- dstSize: 1,
- srcSize: 2,
- wantStr: "hello world.",
- },
-
- {
- desc: "user error",
- t: dontMentionX{},
- src: "The First Rule of Transform Club: don't mention Mister X, ever.",
- dstSize: 100,
- srcSize: 100,
- wantStr: "The First Rule of Transform Club: don't mention Mister ",
- wantErr: errYouMentionedX,
- },
-
- {
- desc: "user error at end",
- t: errorAtEnd{},
- src: "All goes well until it doesn't.",
- dstSize: 100,
- srcSize: 100,
- wantStr: "All goes well until it doesn't.",
- wantErr: errAtEnd,
- },
-
- {
- desc: "user error at end, incremental",
- t: errorAtEnd{},
- src: "All goes well until it doesn't.",
- dstSize: 10,
- srcSize: 10,
- wantStr: "All goes well until it doesn't.",
- wantErr: errAtEnd,
- },
-
- {
- desc: "replace entire non-empty string with one byte",
- t: &replaceWithConstant{replacement: "X"},
- src: "none of this will be copied",
- dstSize: 1,
- srcSize: 10,
- wantStr: "X",
- },
-
- {
- desc: "replace entire empty string with one byte",
- t: &replaceWithConstant{replacement: "X"},
- src: "",
- dstSize: 1,
- srcSize: 10,
- wantStr: "X",
- },
-
- {
- desc: "replace entire empty string with seven bytes",
- t: &replaceWithConstant{replacement: "ABCDEFG"},
- src: "",
- dstSize: 3,
- srcSize: 10,
- wantStr: "ABCDEFG",
- },
-
- {
- desc: "add an X (initialBufSize-1)",
- t: addAnXAtTheEnd{},
- src: aaa[:initialBufSize-1],
- dstSize: 10,
- srcSize: 10,
- wantStr: aaa[:initialBufSize-1] + "X",
- },
-
- {
- desc: "add an X (initialBufSize+0)",
- t: addAnXAtTheEnd{},
- src: aaa[:initialBufSize+0],
- dstSize: 10,
- srcSize: 10,
- wantStr: aaa[:initialBufSize+0] + "X",
- },
-
- {
- desc: "add an X (initialBufSize+1)",
- t: addAnXAtTheEnd{},
- src: aaa[:initialBufSize+1],
- dstSize: 10,
- srcSize: 10,
- wantStr: aaa[:initialBufSize+1] + "X",
- },
-
- {
- desc: "small buffers",
- t: dontMentionX{},
- src: "The First Rule of Transform Club: don't mention Mister X, ever.",
- dstSize: 10,
- srcSize: 10,
- wantStr: "The First Rule of Transform Club: don't mention Mister ",
- wantErr: errYouMentionedX,
- },
-
- {
- desc: "very small buffers",
- t: dontMentionX{},
- src: "The First Rule of Transform Club: don't mention Mister X, ever.",
- dstSize: 1,
- srcSize: 1,
- wantStr: "The First Rule of Transform Club: don't mention Mister ",
- wantErr: errYouMentionedX,
- },
-
- {
- desc: "only transform at EOF",
- t: doublerAtEOF{},
- src: "this",
- dstSize: 100,
- srcSize: 100,
- wantStr: "tthhiiss",
- },
-
- {
- desc: "basic",
- t: rleDecode{},
- src: "1a2b3c10d11e0f1g",
- dstSize: 100,
- srcSize: 100,
- wantStr: "abbcccddddddddddeeeeeeeeeeeg",
- },
-
- {
- desc: "long",
- t: rleDecode{},
- src: "12a23b34c45d56e99z",
- dstSize: 100,
- srcSize: 100,
- wantStr: strings.Repeat("a", 12) +
- strings.Repeat("b", 23) +
- strings.Repeat("c", 34) +
- strings.Repeat("d", 45) +
- strings.Repeat("e", 56) +
- strings.Repeat("z", 99),
- },
-
- {
- desc: "tight buffers",
- t: rleDecode{},
- src: "1a2b3c10d11e0f1g",
- dstSize: 11,
- srcSize: 3,
- wantStr: "abbcccddddddddddeeeeeeeeeeeg",
- },
-
- {
- desc: "short dst",
- t: rleDecode{},
- src: "1a2b3c10d11e0f1g",
- dstSize: 10,
- srcSize: 3,
- wantStr: "abbcccdddddddddd",
- wantErr: ErrShortDst,
- },
-
- {
- desc: "short src",
- t: rleDecode{},
- src: "1a2b3c10d11e0f1g",
- dstSize: 11,
- srcSize: 2,
- ioSize: 2,
- wantStr: "abbccc",
- wantErr: ErrShortSrc,
- },
-
- {
- desc: "basic",
- t: rleEncode{},
- src: "abbcccddddddddddeeeeeeeeeeeg",
- dstSize: 100,
- srcSize: 100,
- wantStr: "1a2b3c10d11e1g",
- },
-
- {
- desc: "long",
- t: rleEncode{},
- src: strings.Repeat("a", 12) +
- strings.Repeat("b", 23) +
- strings.Repeat("c", 34) +
- strings.Repeat("d", 45) +
- strings.Repeat("e", 56) +
- strings.Repeat("z", 99),
- dstSize: 100,
- srcSize: 100,
- wantStr: "12a23b34c45d56e99z",
- },
-
- {
- desc: "tight buffers",
- t: rleEncode{},
- src: "abbcccddddddddddeeeeeeeeeeeg",
- dstSize: 3,
- srcSize: 12,
- wantStr: "1a2b3c10d11e1g",
- },
-
- {
- desc: "short dst",
- t: rleEncode{},
- src: "abbcccddddddddddeeeeeeeeeeeg",
- dstSize: 2,
- srcSize: 12,
- wantStr: "1a2b3c",
- wantErr: ErrShortDst,
- },
-
- {
- desc: "short src",
- t: rleEncode{},
- src: "abbcccddddddddddeeeeeeeeeeeg",
- dstSize: 3,
- srcSize: 11,
- ioSize: 11,
- wantStr: "1a2b3c10d",
- wantErr: ErrShortSrc,
- },
-
- {
- desc: "allowStutter = false",
- t: rleEncode{allowStutter: false},
- src: "aaaabbbbbbbbccccddddd",
- dstSize: 10,
- srcSize: 10,
- wantStr: "4a8b4c5d",
- },
-
- {
- desc: "allowStutter = true",
- t: rleEncode{allowStutter: true},
- src: "aaaabbbbbbbbccccddddd",
- dstSize: 10,
- srcSize: 10,
- ioSize: 10,
- wantStr: "4a6b2b4c4d1d",
- },
-
- {
- desc: "trickler",
- t: &trickler{},
- src: "abcdefghijklm",
- dstSize: 3,
- srcSize: 15,
- wantStr: "abcdefghijklm",
- },
-
- {
- desc: "delayedTrickler",
- t: &delayedTrickler{},
- src: "abcdefghijklm",
- dstSize: 3,
- srcSize: 15,
- wantStr: "abcdefghijklm",
- },
-}
-
-func TestReader(t *testing.T) {
- for _, tc := range testCases {
- testtext.Run(t, tc.desc, func(t *testing.T) {
- r := NewReader(strings.NewReader(tc.src), tc.t)
- // Differently sized dst and src buffers are not part of the
- // exported API. We override them manually.
- r.dst = make([]byte, tc.dstSize)
- r.src = make([]byte, tc.srcSize)
- got, err := ioutil.ReadAll(r)
- str := string(got)
- if str != tc.wantStr || err != tc.wantErr {
- t.Errorf("\ngot %q, %v\nwant %q, %v", str, err, tc.wantStr, tc.wantErr)
- }
- })
- }
-}
-
-func TestWriter(t *testing.T) {
- tests := append(testCases, chainTests()...)
- for _, tc := range tests {
- sizes := []int{1, 2, 3, 4, 5, 10, 100, 1000}
- if tc.ioSize > 0 {
- sizes = []int{tc.ioSize}
- }
- for _, sz := range sizes {
- testtext.Run(t, fmt.Sprintf("%s/%d", tc.desc, sz), func(t *testing.T) {
- bb := &bytes.Buffer{}
- w := NewWriter(bb, tc.t)
- // Differently sized dst and src buffers are not part of the
- // exported API. We override them manually.
- w.dst = make([]byte, tc.dstSize)
- w.src = make([]byte, tc.srcSize)
- src := make([]byte, sz)
- var err error
- for b := tc.src; len(b) > 0 && err == nil; {
- n := copy(src, b)
- b = b[n:]
- m := 0
- m, err = w.Write(src[:n])
- if m != n && err == nil {
- t.Errorf("did not consume all bytes %d < %d", m, n)
- }
- }
- if err == nil {
- err = w.Close()
- }
- str := bb.String()
- if str != tc.wantStr || err != tc.wantErr {
- t.Errorf("\ngot %q, %v\nwant %q, %v", str, err, tc.wantStr, tc.wantErr)
- }
- })
- }
- }
-}
-
-func TestNop(t *testing.T) {
- testCases := []struct {
- str string
- dstSize int
- err error
- }{
- {"", 0, nil},
- {"", 10, nil},
- {"a", 0, ErrShortDst},
- {"a", 1, nil},
- {"a", 10, nil},
- }
- for i, tc := range testCases {
- dst := make([]byte, tc.dstSize)
- nDst, nSrc, err := Nop.Transform(dst, []byte(tc.str), true)
- want := tc.str
- if tc.dstSize < len(want) {
- want = want[:tc.dstSize]
- }
- if got := string(dst[:nDst]); got != want || err != tc.err || nSrc != nDst {
- t.Errorf("%d:\ngot %q, %d, %v\nwant %q, %d, %v", i, got, nSrc, err, want, nDst, tc.err)
- }
- }
-}
-
-func TestDiscard(t *testing.T) {
- testCases := []struct {
- str string
- dstSize int
- }{
- {"", 0},
- {"", 10},
- {"a", 0},
- {"ab", 10},
- }
- for i, tc := range testCases {
- nDst, nSrc, err := Discard.Transform(make([]byte, tc.dstSize), []byte(tc.str), true)
- if nDst != 0 || nSrc != len(tc.str) || err != nil {
- t.Errorf("%d:\ngot %q, %d, %v\nwant 0, %d, nil", i, nDst, nSrc, err, len(tc.str))
- }
- }
-}
-
-// mkChain creates a Chain transformer. x must be alternating between transformer
-// and bufSize, like T, (sz, T)*
-func mkChain(x ...interface{}) *chain {
- t := []Transformer{}
- for i := 0; i < len(x); i += 2 {
- t = append(t, x[i].(Transformer))
- }
- c := Chain(t...).(*chain)
- for i, j := 1, 1; i < len(x); i, j = i+2, j+1 {
- c.link[j].b = make([]byte, x[i].(int))
- }
- return c
-}
-
-func chainTests() []testCase {
- return []testCase{
- {
- desc: "nil error",
- t: mkChain(rleEncode{}, 100, lowerCaseASCII{}),
- src: "ABB",
- dstSize: 100,
- srcSize: 100,
- wantStr: "1a2b",
- wantErr: nil,
- wantIter: 1,
- },
-
- {
- desc: "short dst buffer",
- t: mkChain(lowerCaseASCII{}, 3, rleDecode{}),
- src: "1a2b3c10d11e0f1g",
- dstSize: 10,
- srcSize: 3,
- wantStr: "abbcccdddddddddd",
- wantErr: ErrShortDst,
- },
-
- {
- desc: "short internal dst buffer",
- t: mkChain(lowerCaseASCII{}, 3, rleDecode{}, 10, Nop),
- src: "1a2b3c10d11e0f1g",
- dstSize: 100,
- srcSize: 3,
- wantStr: "abbcccdddddddddd",
- wantErr: errShortInternal,
- },
-
- {
- desc: "short internal dst buffer from input",
- t: mkChain(rleDecode{}, 10, Nop),
- src: "1a2b3c10d11e0f1g",
- dstSize: 100,
- srcSize: 3,
- wantStr: "abbcccdddddddddd",
- wantErr: errShortInternal,
- },
-
- {
- desc: "empty short internal dst buffer",
- t: mkChain(lowerCaseASCII{}, 3, rleDecode{}, 10, Nop),
- src: "4a7b11e0f1g",
- dstSize: 100,
- srcSize: 3,
- wantStr: "aaaabbbbbbb",
- wantErr: errShortInternal,
- },
-
- {
- desc: "empty short internal dst buffer from input",
- t: mkChain(rleDecode{}, 10, Nop),
- src: "4a7b11e0f1g",
- dstSize: 100,
- srcSize: 3,
- wantStr: "aaaabbbbbbb",
- wantErr: errShortInternal,
- },
-
- {
- desc: "short internal src buffer after full dst buffer",
- t: mkChain(Nop, 5, rleEncode{}, 10, Nop),
- src: "cccccddddd",
- dstSize: 100,
- srcSize: 100,
- wantStr: "",
- wantErr: errShortInternal,
- wantIter: 1,
- },
-
- {
- desc: "short internal src buffer after short dst buffer; test lastFull",
- t: mkChain(rleDecode{}, 5, rleEncode{}, 4, Nop),
- src: "2a1b4c6d",
- dstSize: 100,
- srcSize: 100,
- wantStr: "2a1b",
- wantErr: errShortInternal,
- },
-
- {
- desc: "short internal src buffer after successful complete fill",
- t: mkChain(Nop, 3, rleDecode{}),
- src: "123a4b",
- dstSize: 4,
- srcSize: 3,
- wantStr: "",
- wantErr: errShortInternal,
- wantIter: 1,
- },
-
- {
- desc: "short internal src buffer after short dst buffer; test lastFull",
- t: mkChain(rleDecode{}, 5, rleEncode{}),
- src: "2a1b4c6d",
- dstSize: 4,
- srcSize: 100,
- wantStr: "2a1b",
- wantErr: errShortInternal,
- },
-
- {
- desc: "short src buffer",
- t: mkChain(rleEncode{}, 5, Nop),
- src: "abbcccddddeeeee",
- dstSize: 4,
- srcSize: 4,
- ioSize: 4,
- wantStr: "1a2b3c",
- wantErr: ErrShortSrc,
- },
-
- {
- desc: "process all in one go",
- t: mkChain(rleEncode{}, 5, Nop),
- src: "abbcccddddeeeeeffffff",
- dstSize: 100,
- srcSize: 100,
- wantStr: "1a2b3c4d5e6f",
- wantErr: nil,
- wantIter: 1,
- },
-
- {
- desc: "complete processing downstream after error",
- t: mkChain(dontMentionX{}, 2, rleDecode{}, 5, Nop),
- src: "3a4b5eX",
- dstSize: 100,
- srcSize: 100,
- ioSize: 100,
- wantStr: "aaabbbbeeeee",
- wantErr: errYouMentionedX,
- },
-
- {
- desc: "return downstream fatal errors first (followed by short dst)",
- t: mkChain(dontMentionX{}, 8, rleDecode{}, 4, Nop),
- src: "3a4b5eX",
- dstSize: 100,
- srcSize: 100,
- ioSize: 100,
- wantStr: "aaabbbb",
- wantErr: errShortInternal,
- },
-
- {
- desc: "return downstream fatal errors first (followed by short src)",
- t: mkChain(dontMentionX{}, 5, Nop, 1, rleDecode{}),
- src: "1a5bX",
- dstSize: 100,
- srcSize: 100,
- ioSize: 100,
- wantStr: "",
- wantErr: errShortInternal,
- },
-
- {
- desc: "short internal",
- t: mkChain(Nop, 11, rleEncode{}, 3, Nop),
- src: "abbcccddddddddddeeeeeeeeeeeg",
- dstSize: 3,
- srcSize: 100,
- wantStr: "1a2b3c10d",
- wantErr: errShortInternal,
- },
- }
-}
-
-func doTransform(tc testCase) (res string, iter int, err error) {
- tc.t.Reset()
- dst := make([]byte, tc.dstSize)
- out, in := make([]byte, 0, 2*len(tc.src)), []byte(tc.src)
- for {
- iter++
- src, atEOF := in, true
- if len(src) > tc.srcSize {
- src, atEOF = src[:tc.srcSize], false
- }
- nDst, nSrc, err := tc.t.Transform(dst, src, atEOF)
- out = append(out, dst[:nDst]...)
- in = in[nSrc:]
- switch {
- case err == nil && len(in) != 0:
- case err == ErrShortSrc && nSrc > 0:
- case err == ErrShortDst && (nDst > 0 || nSrc > 0):
- default:
- return string(out), iter, err
- }
- }
-}
-
-func TestChain(t *testing.T) {
- if c, ok := Chain().(nop); !ok {
- t.Errorf("empty chain: %v; want Nop", c)
- }
-
- // Test Chain for a single Transformer.
- for _, tc := range testCases {
- tc.t = Chain(tc.t)
- str, _, err := doTransform(tc)
- if str != tc.wantStr || err != tc.wantErr {
- t.Errorf("%s:\ngot %q, %v\nwant %q, %v", tc, str, err, tc.wantStr, tc.wantErr)
- }
- }
-
- tests := chainTests()
- sizes := []int{1, 2, 3, 4, 5, 7, 10, 100, 1000}
- addTest := func(tc testCase, t *chain) {
- if t.link[0].t != tc.t && tc.wantErr == ErrShortSrc {
- tc.wantErr = errShortInternal
- }
- if t.link[len(t.link)-2].t != tc.t && tc.wantErr == ErrShortDst {
- tc.wantErr = errShortInternal
- }
- tc.t = t
- tests = append(tests, tc)
- }
- for _, tc := range testCases {
- for _, sz := range sizes {
- tt := tc
- tt.dstSize = sz
- addTest(tt, mkChain(tc.t, tc.dstSize, Nop))
- addTest(tt, mkChain(tc.t, tc.dstSize, Nop, 2, Nop))
- addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop))
- if sz >= tc.dstSize && (tc.wantErr != ErrShortDst || sz == tc.dstSize) {
- addTest(tt, mkChain(Nop, tc.srcSize, tc.t))
- addTest(tt, mkChain(Nop, 100, Nop, tc.srcSize, tc.t))
- }
- }
- }
- for _, tc := range testCases {
- tt := tc
- tt.dstSize = 1
- tt.wantStr = ""
- addTest(tt, mkChain(tc.t, tc.dstSize, Discard))
- addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Discard))
- addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, tc.dstSize, Discard))
- }
- for _, tc := range testCases {
- tt := tc
- tt.dstSize = 100
- tt.wantStr = strings.Replace(tc.src, "0f", "", -1)
- // Chain encoders and decoders.
- if _, ok := tc.t.(rleEncode); ok && tc.wantErr == nil {
- addTest(tt, mkChain(tc.t, tc.dstSize, Nop, 1000, rleDecode{}))
- addTest(tt, mkChain(tc.t, tc.dstSize, Nop, tc.dstSize, rleDecode{}))
- addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 100, rleDecode{}))
- // decoding needs larger destinations
- addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, rleDecode{}, 100, Nop))
- addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 100, rleDecode{}, 100, Nop))
- } else if _, ok := tc.t.(rleDecode); ok && tc.wantErr == nil {
- // The internal buffer size may need to be the sum of the maximum segment
- // size of the two encoders!
- addTest(tt, mkChain(tc.t, 2*tc.dstSize, rleEncode{}))
- addTest(tt, mkChain(tc.t, tc.dstSize, Nop, 101, rleEncode{}))
- addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 100, rleEncode{}))
- addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 200, rleEncode{}, 100, Nop))
- }
- }
- for _, tc := range tests {
- str, iter, err := doTransform(tc)
- mi := tc.wantIter != 0 && tc.wantIter != iter
- if str != tc.wantStr || err != tc.wantErr || mi {
- t.Errorf("%s:\ngot iter:%d, %q, %v\nwant iter:%d, %q, %v", tc, iter, str, err, tc.wantIter, tc.wantStr, tc.wantErr)
- }
- break
- }
-}
-
-func TestRemoveFunc(t *testing.T) {
- filter := RemoveFunc(func(r rune) bool {
- return strings.IndexRune("ab\u0300\u1234,", r) != -1
- })
- tests := []testCase{
- {
- src: ",",
- wantStr: "",
- },
-
- {
- src: "c",
- wantStr: "c",
- },
-
- {
- src: "\u2345",
- wantStr: "\u2345",
- },
-
- {
- src: "tschüß",
- wantStr: "tschüß",
- },
-
- {
- src: ",до,свидания,",
- wantStr: "досвидания",
- },
-
- {
- src: "a\xbd\xb2=\xbc ⌘",
- wantStr: "\uFFFD\uFFFD=\uFFFD ⌘",
- },
-
- {
- // If we didn't replace illegal bytes with RuneError, the result
- // would be \u0300 or the code would need to be more complex.
- src: "\xcc\u0300\x80",
- wantStr: "\uFFFD\uFFFD",
- },
-
- {
- src: "\xcc\u0300\x80",
- dstSize: 3,
- wantStr: "\uFFFD\uFFFD",
- wantIter: 2,
- },
-
- {
- // Test a long buffer greater than the internal buffer size
- src: "hello\xcc\xcc\xccworld",
- srcSize: 13,
- wantStr: "hello\uFFFD\uFFFD\uFFFDworld",
- wantIter: 1,
- },
-
- {
- src: "\u2345",
- dstSize: 2,
- wantStr: "",
- wantErr: ErrShortDst,
- },
-
- {
- src: "\xcc",
- dstSize: 2,
- wantStr: "",
- wantErr: ErrShortDst,
- },
-
- {
- src: "\u0300",
- dstSize: 2,
- srcSize: 1,
- wantStr: "",
- wantErr: ErrShortSrc,
- },
-
- {
- t: RemoveFunc(func(r rune) bool {
- return r == utf8.RuneError
- }),
- src: "\xcc\u0300\x80",
- wantStr: "\u0300",
- },
- }
-
- for _, tc := range tests {
- tc.desc = tc.src
- if tc.t == nil {
- tc.t = filter
- }
- if tc.dstSize == 0 {
- tc.dstSize = 100
- }
- if tc.srcSize == 0 {
- tc.srcSize = 100
- }
- str, iter, err := doTransform(tc)
- mi := tc.wantIter != 0 && tc.wantIter != iter
- if str != tc.wantStr || err != tc.wantErr || mi {
- t.Errorf("%+q:\ngot iter:%d, %+q, %v\nwant iter:%d, %+q, %v", tc.src, iter, str, err, tc.wantIter, tc.wantStr, tc.wantErr)
- }
-
- tc.src = str
- idem, _, _ := doTransform(tc)
- if str != idem {
- t.Errorf("%+q: found %+q; want %+q", tc.src, idem, str)
- }
- }
-}
-
-func testString(t *testing.T, f func(Transformer, string) (string, int, error)) {
- for _, tt := range append(testCases, chainTests()...) {
- if tt.desc == "allowStutter = true" {
- // We don't have control over the buffer size, so we eliminate tests
- // that depend on a specific buffer size being set.
- continue
- }
- if tt.wantErr == ErrShortDst || tt.wantErr == ErrShortSrc {
- // The result string will be different.
- continue
- }
- testtext.Run(t, tt.desc, func(t *testing.T) {
- got, n, err := f(tt.t, tt.src)
- if tt.wantErr != err {
- t.Errorf("error: got %v; want %v", err, tt.wantErr)
- }
- // Check that err == nil implies that n == len(tt.src). Note that vice
- // versa isn't necessarily true.
- if err == nil && n != len(tt.src) {
- t.Errorf("err == nil: got %d bytes, want %d", n, err)
- }
- if got != tt.wantStr {
- t.Errorf("string: got %q; want %q", got, tt.wantStr)
- }
- })
- }
-}
-
-func TestBytes(t *testing.T) {
- testString(t, func(z Transformer, s string) (string, int, error) {
- b, n, err := Bytes(z, []byte(s))
- return string(b), n, err
- })
-}
-
-func TestAppend(t *testing.T) {
- // Create a bunch of subtests for different buffer sizes.
- testCases := [][]byte{
- nil,
- make([]byte, 0, 0),
- make([]byte, 0, 1),
- make([]byte, 1, 1),
- make([]byte, 1, 5),
- make([]byte, 100, 100),
- make([]byte, 100, 200),
- }
- for _, tc := range testCases {
- testString(t, func(z Transformer, s string) (string, int, error) {
- b, n, err := Append(z, tc, []byte(s))
- return string(b[len(tc):]), n, err
- })
- }
-}
-
-func TestString(t *testing.T) {
- testtext.Run(t, "transform", func(t *testing.T) { testString(t, String) })
-
- // Overrun the internal destination buffer.
- for i, s := range []string{
- aaa[:1*initialBufSize-1],
- aaa[:1*initialBufSize+0],
- aaa[:1*initialBufSize+1],
- AAA[:1*initialBufSize-1],
- AAA[:1*initialBufSize+0],
- AAA[:1*initialBufSize+1],
- AAA[:2*initialBufSize-1],
- AAA[:2*initialBufSize+0],
- AAA[:2*initialBufSize+1],
- aaa[:1*initialBufSize-2] + "A",
- aaa[:1*initialBufSize-1] + "A",
- aaa[:1*initialBufSize+0] + "A",
- aaa[:1*initialBufSize+1] + "A",
- } {
- testtext.Run(t, fmt.Sprint("dst buffer test using lower/", i), func(t *testing.T) {
- got, _, _ := String(lowerCaseASCII{}, s)
- if want := strings.ToLower(s); got != want {
- t.Errorf("got %s (%d); want %s (%d)", got, len(got), want, len(want))
- }
- })
- }
-
- // Overrun the internal source buffer.
- for i, s := range []string{
- aaa[:1*initialBufSize-1],
- aaa[:1*initialBufSize+0],
- aaa[:1*initialBufSize+1],
- aaa[:2*initialBufSize+1],
- aaa[:2*initialBufSize+0],
- aaa[:2*initialBufSize+1],
- } {
- testtext.Run(t, fmt.Sprint("src buffer test using rleEncode/", i), func(t *testing.T) {
- got, _, _ := String(rleEncode{}, s)
- if want := fmt.Sprintf("%da", len(s)); got != want {
- t.Errorf("got %s (%d); want %s (%d)", got, len(got), want, len(want))
- }
- })
- }
-
- // Test allocations for non-changing strings.
- // Note we still need to allocate a single buffer.
- for i, s := range []string{
- "",
- "123456789",
- aaa[:initialBufSize-1],
- aaa[:initialBufSize+0],
- aaa[:initialBufSize+1],
- aaa[:10*initialBufSize],
- } {
- testtext.Run(t, fmt.Sprint("alloc/", i), func(t *testing.T) {
- if n := testtext.AllocsPerRun(5, func() { String(&lowerCaseASCIILookahead{}, s) }); n > 1 {
- t.Errorf("#allocs was %f; want 1", n)
- }
- })
- }
-}
-
-// TestBytesAllocation tests that buffer growth stays limited with the trickler
-// transformer, which behaves oddly but within spec. In case buffer growth is
-// not correctly handled, the test will either panic with a failed allocation or
-// thrash. To ensure the tests terminate under the last condition, we time out
-// after some sufficiently long period of time.
-func TestBytesAllocation(t *testing.T) {
- done := make(chan bool)
- go func() {
- in := bytes.Repeat([]byte{'a'}, 1000)
- tr := trickler(make([]byte, 1))
- Bytes(&tr, in)
- done <- true
- }()
- select {
- case <-done:
- case <-time.After(3 * time.Second):
- t.Error("time out, likely due to excessive allocation")
- }
-}
-
-// TestStringAllocation tests that buffer growth stays limited with the trickler
-// transformer, which behaves oddly but within spec. In case buffer growth is
-// not correctly handled, the test will either panic with a failed allocation or
-// thrash. To ensure the tests terminate under the last condition, we time out
-// after some sufficiently long period of time.
-func TestStringAllocation(t *testing.T) {
- done := make(chan bool)
- go func() {
- tr := trickler(make([]byte, 1))
- String(&tr, aaa[:1000])
- done <- true
- }()
- select {
- case <-done:
- case <-time.After(3 * time.Second):
- t.Error("time out, likely due to excessive allocation")
- }
-}
-
-func BenchmarkStringLowerEmpty(b *testing.B) {
- for i := 0; i < b.N; i++ {
- String(&lowerCaseASCIILookahead{}, "")
- }
-}
-
-func BenchmarkStringLowerIdentical(b *testing.B) {
- for i := 0; i < b.N; i++ {
- String(&lowerCaseASCIILookahead{}, aaa[:4096])
- }
-}
-
-func BenchmarkStringLowerChanged(b *testing.B) {
- for i := 0; i < b.N; i++ {
- String(&lowerCaseASCIILookahead{}, AAA[:4096])
- }
-}
-
-var (
- aaa = strings.Repeat("a", 4096)
- AAA = strings.Repeat("A", 4096)
-)
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/composition.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/composition.go
deleted file mode 100644
index d17b278..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/composition.go
+++ /dev/null
@@ -1,514 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package norm
-
-import "unicode/utf8"
-
-const (
- maxNonStarters = 30
- // The maximum number of characters needed for a buffer is
- // maxNonStarters + 1 for the starter + 1 for the GCJ
- maxBufferSize = maxNonStarters + 2
- maxNFCExpansion = 3 // NFC(0x1D160)
- maxNFKCExpansion = 18 // NFKC(0xFDFA)
-
- maxByteBufferSize = utf8.UTFMax * maxBufferSize // 128
-)
-
-// ssState is used for reporting the segment state after inserting a rune.
-// It is returned by streamSafe.next.
-type ssState int
-
-const (
- // Indicates a rune was successfully added to the segment.
- ssSuccess ssState = iota
- // Indicates a rune starts a new segment and should not be added.
- ssStarter
- // Indicates a rune caused a segment overflow and a CGJ should be inserted.
- ssOverflow
-)
-
-// streamSafe implements the policy of when a CGJ should be inserted.
-type streamSafe uint8
-
-// mkStreamSafe is a shorthand for declaring a streamSafe var and calling
-// first on it.
-func mkStreamSafe(p Properties) streamSafe {
- return streamSafe(p.nTrailingNonStarters())
-}
-
-// first inserts the first rune of a segment.
-func (ss *streamSafe) first(p Properties) {
- if *ss != 0 {
- panic("!= 0")
- }
- *ss = streamSafe(p.nTrailingNonStarters())
-}
-
-// insert returns a ssState value to indicate whether a rune represented by p
-// can be inserted.
-func (ss *streamSafe) next(p Properties) ssState {
- if *ss > maxNonStarters {
- panic("streamSafe was not reset")
- }
- n := p.nLeadingNonStarters()
- if *ss += streamSafe(n); *ss > maxNonStarters {
- *ss = 0
- return ssOverflow
- }
- // The Stream-Safe Text Processing prescribes that the counting can stop
- // as soon as a starter is encountered. However, there are some starters,
- // like Jamo V and T, that can combine with other runes, leaving their
- // successive non-starters appended to the previous, possibly causing an
- // overflow. We will therefore consider any rune with a non-zero nLead to
- // be a non-starter. Note that it always hold that if nLead > 0 then
- // nLead == nTrail.
- if n == 0 {
- *ss = 0
- return ssStarter
- }
- return ssSuccess
-}
-
-// backwards is used for checking for overflow and segment starts
-// when traversing a string backwards. Users do not need to call first
-// for the first rune. The state of the streamSafe retains the count of
-// the non-starters loaded.
-func (ss *streamSafe) backwards(p Properties) ssState {
- if *ss > maxNonStarters {
- panic("streamSafe was not reset")
- }
- c := *ss + streamSafe(p.nTrailingNonStarters())
- if c > maxNonStarters {
- return ssOverflow
- }
- *ss = c
- if p.nLeadingNonStarters() == 0 {
- return ssStarter
- }
- return ssSuccess
-}
-
-func (ss streamSafe) isMax() bool {
- return ss == maxNonStarters
-}
-
-// GraphemeJoiner is inserted after maxNonStarters non-starter runes.
-const GraphemeJoiner = "\u034F"
-
-// reorderBuffer is used to normalize a single segment. Characters inserted with
-// insert are decomposed and reordered based on CCC. The compose method can
-// be used to recombine characters. Note that the byte buffer does not hold
-// the UTF-8 characters in order. Only the rune array is maintained in sorted
-// order. flush writes the resulting segment to a byte array.
-type reorderBuffer struct {
- rune [maxBufferSize]Properties // Per character info.
- byte [maxByteBufferSize]byte // UTF-8 buffer. Referenced by runeInfo.pos.
- nbyte uint8 // Number or bytes.
- ss streamSafe // For limiting length of non-starter sequence.
- nrune int // Number of runeInfos.
- f formInfo
-
- src input
- nsrc int
- tmpBytes input
-
- out []byte
- flushF func(*reorderBuffer) bool
-}
-
-func (rb *reorderBuffer) init(f Form, src []byte) {
- rb.f = *formTable[f]
- rb.src.setBytes(src)
- rb.nsrc = len(src)
- rb.ss = 0
-}
-
-func (rb *reorderBuffer) initString(f Form, src string) {
- rb.f = *formTable[f]
- rb.src.setString(src)
- rb.nsrc = len(src)
- rb.ss = 0
-}
-
-func (rb *reorderBuffer) setFlusher(out []byte, f func(*reorderBuffer) bool) {
- rb.out = out
- rb.flushF = f
-}
-
-// reset discards all characters from the buffer.
-func (rb *reorderBuffer) reset() {
- rb.nrune = 0
- rb.nbyte = 0
- rb.ss = 0
-}
-
-func (rb *reorderBuffer) doFlush() bool {
- if rb.f.composing {
- rb.compose()
- }
- res := rb.flushF(rb)
- rb.reset()
- return res
-}
-
-// appendFlush appends the normalized segment to rb.out.
-func appendFlush(rb *reorderBuffer) bool {
- for i := 0; i < rb.nrune; i++ {
- start := rb.rune[i].pos
- end := start + rb.rune[i].size
- rb.out = append(rb.out, rb.byte[start:end]...)
- }
- return true
-}
-
-// flush appends the normalized segment to out and resets rb.
-func (rb *reorderBuffer) flush(out []byte) []byte {
- for i := 0; i < rb.nrune; i++ {
- start := rb.rune[i].pos
- end := start + rb.rune[i].size
- out = append(out, rb.byte[start:end]...)
- }
- rb.reset()
- return out
-}
-
-// flushCopy copies the normalized segment to buf and resets rb.
-// It returns the number of bytes written to buf.
-func (rb *reorderBuffer) flushCopy(buf []byte) int {
- p := 0
- for i := 0; i < rb.nrune; i++ {
- runep := rb.rune[i]
- p += copy(buf[p:], rb.byte[runep.pos:runep.pos+runep.size])
- }
- rb.reset()
- return p
-}
-
-// insertOrdered inserts a rune in the buffer, ordered by Canonical Combining Class.
-// It returns false if the buffer is not large enough to hold the rune.
-// It is used internally by insert and insertString only.
-func (rb *reorderBuffer) insertOrdered(info Properties) {
- n := rb.nrune
- b := rb.rune[:]
- cc := info.ccc
- if cc > 0 {
- // Find insertion position + move elements to make room.
- for ; n > 0; n-- {
- if b[n-1].ccc <= cc {
- break
- }
- b[n] = b[n-1]
- }
- }
- rb.nrune += 1
- pos := uint8(rb.nbyte)
- rb.nbyte += utf8.UTFMax
- info.pos = pos
- b[n] = info
-}
-
-// insertErr is an error code returned by insert. Using this type instead
-// of error improves performance up to 20% for many of the benchmarks.
-type insertErr int
-
-const (
- iSuccess insertErr = -iota
- iShortDst
- iShortSrc
-)
-
-// insertFlush inserts the given rune in the buffer ordered by CCC.
-// If a decomposition with multiple segments are encountered, they leading
-// ones are flushed.
-// It returns a non-zero error code if the rune was not inserted.
-func (rb *reorderBuffer) insertFlush(src input, i int, info Properties) insertErr {
- if rune := src.hangul(i); rune != 0 {
- rb.decomposeHangul(rune)
- return iSuccess
- }
- if info.hasDecomposition() {
- return rb.insertDecomposed(info.Decomposition())
- }
- rb.insertSingle(src, i, info)
- return iSuccess
-}
-
-// insertUnsafe inserts the given rune in the buffer ordered by CCC.
-// It is assumed there is sufficient space to hold the runes. It is the
-// responsibility of the caller to ensure this. This can be done by checking
-// the state returned by the streamSafe type.
-func (rb *reorderBuffer) insertUnsafe(src input, i int, info Properties) {
- if rune := src.hangul(i); rune != 0 {
- rb.decomposeHangul(rune)
- }
- if info.hasDecomposition() {
- // TODO: inline.
- rb.insertDecomposed(info.Decomposition())
- } else {
- rb.insertSingle(src, i, info)
- }
-}
-
-// insertDecomposed inserts an entry in to the reorderBuffer for each rune
-// in dcomp. dcomp must be a sequence of decomposed UTF-8-encoded runes.
-// It flushes the buffer on each new segment start.
-func (rb *reorderBuffer) insertDecomposed(dcomp []byte) insertErr {
- rb.tmpBytes.setBytes(dcomp)
- for i := 0; i < len(dcomp); {
- info := rb.f.info(rb.tmpBytes, i)
- if info.BoundaryBefore() && rb.nrune > 0 && !rb.doFlush() {
- return iShortDst
- }
- i += copy(rb.byte[rb.nbyte:], dcomp[i:i+int(info.size)])
- rb.insertOrdered(info)
- }
- return iSuccess
-}
-
-// insertSingle inserts an entry in the reorderBuffer for the rune at
-// position i. info is the runeInfo for the rune at position i.
-func (rb *reorderBuffer) insertSingle(src input, i int, info Properties) {
- src.copySlice(rb.byte[rb.nbyte:], i, i+int(info.size))
- rb.insertOrdered(info)
-}
-
-// insertCGJ inserts a Combining Grapheme Joiner (0x034f) into rb.
-func (rb *reorderBuffer) insertCGJ() {
- rb.insertSingle(input{str: GraphemeJoiner}, 0, Properties{size: uint8(len(GraphemeJoiner))})
-}
-
-// appendRune inserts a rune at the end of the buffer. It is used for Hangul.
-func (rb *reorderBuffer) appendRune(r rune) {
- bn := rb.nbyte
- sz := utf8.EncodeRune(rb.byte[bn:], rune(r))
- rb.nbyte += utf8.UTFMax
- rb.rune[rb.nrune] = Properties{pos: bn, size: uint8(sz)}
- rb.nrune++
-}
-
-// assignRune sets a rune at position pos. It is used for Hangul and recomposition.
-func (rb *reorderBuffer) assignRune(pos int, r rune) {
- bn := rb.rune[pos].pos
- sz := utf8.EncodeRune(rb.byte[bn:], rune(r))
- rb.rune[pos] = Properties{pos: bn, size: uint8(sz)}
-}
-
-// runeAt returns the rune at position n. It is used for Hangul and recomposition.
-func (rb *reorderBuffer) runeAt(n int) rune {
- inf := rb.rune[n]
- r, _ := utf8.DecodeRune(rb.byte[inf.pos : inf.pos+inf.size])
- return r
-}
-
-// bytesAt returns the UTF-8 encoding of the rune at position n.
-// It is used for Hangul and recomposition.
-func (rb *reorderBuffer) bytesAt(n int) []byte {
- inf := rb.rune[n]
- return rb.byte[inf.pos : int(inf.pos)+int(inf.size)]
-}
-
-// For Hangul we combine algorithmically, instead of using tables.
-const (
- hangulBase = 0xAC00 // UTF-8(hangulBase) -> EA B0 80
- hangulBase0 = 0xEA
- hangulBase1 = 0xB0
- hangulBase2 = 0x80
-
- hangulEnd = hangulBase + jamoLVTCount // UTF-8(0xD7A4) -> ED 9E A4
- hangulEnd0 = 0xED
- hangulEnd1 = 0x9E
- hangulEnd2 = 0xA4
-
- jamoLBase = 0x1100 // UTF-8(jamoLBase) -> E1 84 00
- jamoLBase0 = 0xE1
- jamoLBase1 = 0x84
- jamoLEnd = 0x1113
- jamoVBase = 0x1161
- jamoVEnd = 0x1176
- jamoTBase = 0x11A7
- jamoTEnd = 0x11C3
-
- jamoTCount = 28
- jamoVCount = 21
- jamoVTCount = 21 * 28
- jamoLVTCount = 19 * 21 * 28
-)
-
-const hangulUTF8Size = 3
-
-func isHangul(b []byte) bool {
- if len(b) < hangulUTF8Size {
- return false
- }
- b0 := b[0]
- if b0 < hangulBase0 {
- return false
- }
- b1 := b[1]
- switch {
- case b0 == hangulBase0:
- return b1 >= hangulBase1
- case b0 < hangulEnd0:
- return true
- case b0 > hangulEnd0:
- return false
- case b1 < hangulEnd1:
- return true
- }
- return b1 == hangulEnd1 && b[2] < hangulEnd2
-}
-
-func isHangulString(b string) bool {
- if len(b) < hangulUTF8Size {
- return false
- }
- b0 := b[0]
- if b0 < hangulBase0 {
- return false
- }
- b1 := b[1]
- switch {
- case b0 == hangulBase0:
- return b1 >= hangulBase1
- case b0 < hangulEnd0:
- return true
- case b0 > hangulEnd0:
- return false
- case b1 < hangulEnd1:
- return true
- }
- return b1 == hangulEnd1 && b[2] < hangulEnd2
-}
-
-// Caller must ensure len(b) >= 2.
-func isJamoVT(b []byte) bool {
- // True if (rune & 0xff00) == jamoLBase
- return b[0] == jamoLBase0 && (b[1]&0xFC) == jamoLBase1
-}
-
-func isHangulWithoutJamoT(b []byte) bool {
- c, _ := utf8.DecodeRune(b)
- c -= hangulBase
- return c < jamoLVTCount && c%jamoTCount == 0
-}
-
-// decomposeHangul writes the decomposed Hangul to buf and returns the number
-// of bytes written. len(buf) should be at least 9.
-func decomposeHangul(buf []byte, r rune) int {
- const JamoUTF8Len = 3
- r -= hangulBase
- x := r % jamoTCount
- r /= jamoTCount
- utf8.EncodeRune(buf, jamoLBase+r/jamoVCount)
- utf8.EncodeRune(buf[JamoUTF8Len:], jamoVBase+r%jamoVCount)
- if x != 0 {
- utf8.EncodeRune(buf[2*JamoUTF8Len:], jamoTBase+x)
- return 3 * JamoUTF8Len
- }
- return 2 * JamoUTF8Len
-}
-
-// decomposeHangul algorithmically decomposes a Hangul rune into
-// its Jamo components.
-// See http://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul.
-func (rb *reorderBuffer) decomposeHangul(r rune) {
- r -= hangulBase
- x := r % jamoTCount
- r /= jamoTCount
- rb.appendRune(jamoLBase + r/jamoVCount)
- rb.appendRune(jamoVBase + r%jamoVCount)
- if x != 0 {
- rb.appendRune(jamoTBase + x)
- }
-}
-
-// combineHangul algorithmically combines Jamo character components into Hangul.
-// See http://unicode.org/reports/tr15/#Hangul for details on combining Hangul.
-func (rb *reorderBuffer) combineHangul(s, i, k int) {
- b := rb.rune[:]
- bn := rb.nrune
- for ; i < bn; i++ {
- cccB := b[k-1].ccc
- cccC := b[i].ccc
- if cccB == 0 {
- s = k - 1
- }
- if s != k-1 && cccB >= cccC {
- // b[i] is blocked by greater-equal cccX below it
- b[k] = b[i]
- k++
- } else {
- l := rb.runeAt(s) // also used to compare to hangulBase
- v := rb.runeAt(i) // also used to compare to jamoT
- switch {
- case jamoLBase <= l && l < jamoLEnd &&
- jamoVBase <= v && v < jamoVEnd:
- // 11xx plus 116x to LV
- rb.assignRune(s, hangulBase+
- (l-jamoLBase)*jamoVTCount+(v-jamoVBase)*jamoTCount)
- case hangulBase <= l && l < hangulEnd &&
- jamoTBase < v && v < jamoTEnd &&
- ((l-hangulBase)%jamoTCount) == 0:
- // ACxx plus 11Ax to LVT
- rb.assignRune(s, l+v-jamoTBase)
- default:
- b[k] = b[i]
- k++
- }
- }
- }
- rb.nrune = k
-}
-
-// compose recombines the runes in the buffer.
-// It should only be used to recompose a single segment, as it will not
-// handle alternations between Hangul and non-Hangul characters correctly.
-func (rb *reorderBuffer) compose() {
- // UAX #15, section X5 , including Corrigendum #5
- // "In any character sequence beginning with starter S, a character C is
- // blocked from S if and only if there is some character B between S
- // and C, and either B is a starter or it has the same or higher
- // combining class as C."
- bn := rb.nrune
- if bn == 0 {
- return
- }
- k := 1
- b := rb.rune[:]
- for s, i := 0, 1; i < bn; i++ {
- if isJamoVT(rb.bytesAt(i)) {
- // Redo from start in Hangul mode. Necessary to support
- // U+320E..U+321E in NFKC mode.
- rb.combineHangul(s, i, k)
- return
- }
- ii := b[i]
- // We can only use combineForward as a filter if we later
- // get the info for the combined character. This is more
- // expensive than using the filter. Using combinesBackward()
- // is safe.
- if ii.combinesBackward() {
- cccB := b[k-1].ccc
- cccC := ii.ccc
- blocked := false // b[i] blocked by starter or greater or equal CCC?
- if cccB == 0 {
- s = k - 1
- } else {
- blocked = s != k-1 && cccB >= cccC
- }
- if !blocked {
- combined := combine(rb.runeAt(s), rb.runeAt(i))
- if combined != 0 {
- rb.assignRune(s, combined)
- continue
- }
- }
- }
- b[k] = b[i]
- k++
- }
- rb.nrune = k
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/composition_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/composition_test.go
deleted file mode 100644
index 1168406..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/composition_test.go
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package norm
-
-import "testing"
-
-// TestCase is used for most tests.
-type TestCase struct {
- in []rune
- out []rune
-}
-
-func runTests(t *testing.T, name string, fm Form, tests []TestCase) {
- rb := reorderBuffer{}
- rb.init(fm, nil)
- for i, test := range tests {
- rb.setFlusher(nil, appendFlush)
- for j, rune := range test.in {
- b := []byte(string(rune))
- src := inputBytes(b)
- info := rb.f.info(src, 0)
- if j == 0 {
- rb.ss.first(info)
- } else {
- rb.ss.next(info)
- }
- if rb.insertFlush(src, 0, info) < 0 {
- t.Errorf("%s:%d: insert failed for rune %d", name, i, j)
- }
- }
- rb.doFlush()
- was := string(rb.out)
- want := string(test.out)
- if len(was) != len(want) {
- t.Errorf("%s:%d: length = %d; want %d", name, i, len(was), len(want))
- }
- if was != want {
- k, pfx := pidx(was, want)
- t.Errorf("%s:%d: \nwas %s%+q; \nwant %s%+q", name, i, pfx, was[k:], pfx, want[k:])
- }
- }
-}
-
-func TestFlush(t *testing.T) {
- const (
- hello = "Hello "
- world = "world!"
- )
- buf := make([]byte, maxByteBufferSize)
- p := copy(buf, hello)
- out := buf[p:]
- rb := reorderBuffer{}
- rb.initString(NFC, world)
- if i := rb.flushCopy(out); i != 0 {
- t.Errorf("wrote bytes on flush of empty buffer. (len(out) = %d)", i)
- }
-
- for i := range world {
- // No need to set streamSafe values for this test.
- rb.insertFlush(rb.src, i, rb.f.info(rb.src, i))
- n := rb.flushCopy(out)
- out = out[n:]
- p += n
- }
-
- was := buf[:p]
- want := hello + world
- if string(was) != want {
- t.Errorf(`output after flush was "%s"; want "%s"`, string(was), want)
- }
- if rb.nrune != 0 {
- t.Errorf("non-null size of info buffer (rb.nrune == %d)", rb.nrune)
- }
- if rb.nbyte != 0 {
- t.Errorf("non-null size of byte buffer (rb.nbyte == %d)", rb.nbyte)
- }
-}
-
-var insertTests = []TestCase{
- {[]rune{'a'}, []rune{'a'}},
- {[]rune{0x300}, []rune{0x300}},
- {[]rune{0x300, 0x316}, []rune{0x316, 0x300}}, // CCC(0x300)==230; CCC(0x316)==220
- {[]rune{0x316, 0x300}, []rune{0x316, 0x300}},
- {[]rune{0x41, 0x316, 0x300}, []rune{0x41, 0x316, 0x300}},
- {[]rune{0x41, 0x300, 0x316}, []rune{0x41, 0x316, 0x300}},
- {[]rune{0x300, 0x316, 0x41}, []rune{0x316, 0x300, 0x41}},
- {[]rune{0x41, 0x300, 0x40, 0x316}, []rune{0x41, 0x300, 0x40, 0x316}},
-}
-
-func TestInsert(t *testing.T) {
- runTests(t, "TestInsert", NFD, insertTests)
-}
-
-var decompositionNFDTest = []TestCase{
- {[]rune{0xC0}, []rune{0x41, 0x300}},
- {[]rune{0xAC00}, []rune{0x1100, 0x1161}},
- {[]rune{0x01C4}, []rune{0x01C4}},
- {[]rune{0x320E}, []rune{0x320E}},
- {[]rune("음ẻ과"), []rune{0x110B, 0x1173, 0x11B7, 0x65, 0x309, 0x1100, 0x116A}},
-}
-
-var decompositionNFKDTest = []TestCase{
- {[]rune{0xC0}, []rune{0x41, 0x300}},
- {[]rune{0xAC00}, []rune{0x1100, 0x1161}},
- {[]rune{0x01C4}, []rune{0x44, 0x5A, 0x030C}},
- {[]rune{0x320E}, []rune{0x28, 0x1100, 0x1161, 0x29}},
-}
-
-func TestDecomposition(t *testing.T) {
- runTests(t, "TestDecompositionNFD", NFD, decompositionNFDTest)
- runTests(t, "TestDecompositionNFKD", NFKD, decompositionNFKDTest)
-}
-
-var compositionTest = []TestCase{
- {[]rune{0x41, 0x300}, []rune{0xC0}},
- {[]rune{0x41, 0x316}, []rune{0x41, 0x316}},
- {[]rune{0x41, 0x300, 0x35D}, []rune{0xC0, 0x35D}},
- {[]rune{0x41, 0x316, 0x300}, []rune{0xC0, 0x316}},
- // blocking starter
- {[]rune{0x41, 0x316, 0x40, 0x300}, []rune{0x41, 0x316, 0x40, 0x300}},
- {[]rune{0x1100, 0x1161}, []rune{0xAC00}},
- // parenthesized Hangul, alternate between ASCII and Hangul.
- {[]rune{0x28, 0x1100, 0x1161, 0x29}, []rune{0x28, 0xAC00, 0x29}},
-}
-
-func TestComposition(t *testing.T) {
- runTests(t, "TestComposition", NFC, compositionTest)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/example_iter_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/example_iter_test.go
deleted file mode 100644
index 82df89c..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/example_iter_test.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package norm_test
-
-import (
- "bytes"
- "fmt"
- "unicode/utf8"
-
- "golang.org/x/text/unicode/norm"
-)
-
-// EqualSimple uses a norm.Iter to compare two non-normalized
-// strings for equivalence.
-func EqualSimple(a, b string) bool {
- var ia, ib norm.Iter
- ia.InitString(norm.NFKD, a)
- ib.InitString(norm.NFKD, b)
- for !ia.Done() && !ib.Done() {
- if !bytes.Equal(ia.Next(), ib.Next()) {
- return false
- }
- }
- return ia.Done() && ib.Done()
-}
-
-// FindPrefix finds the longest common prefix of ASCII characters
-// of a and b.
-func FindPrefix(a, b string) int {
- i := 0
- for ; i < len(a) && i < len(b) && a[i] < utf8.RuneSelf && a[i] == b[i]; i++ {
- }
- return i
-}
-
-// EqualOpt is like EqualSimple, but optimizes the special
-// case for ASCII characters.
-func EqualOpt(a, b string) bool {
- n := FindPrefix(a, b)
- a, b = a[n:], b[n:]
- var ia, ib norm.Iter
- ia.InitString(norm.NFKD, a)
- ib.InitString(norm.NFKD, b)
- for !ia.Done() && !ib.Done() {
- if !bytes.Equal(ia.Next(), ib.Next()) {
- return false
- }
- if n := int64(FindPrefix(a[ia.Pos():], b[ib.Pos():])); n != 0 {
- ia.Seek(n, 1)
- ib.Seek(n, 1)
- }
- }
- return ia.Done() && ib.Done()
-}
-
-var compareTests = []struct{ a, b string }{
- {"aaa", "aaa"},
- {"aaa", "aab"},
- {"a\u0300a", "\u00E0a"},
- {"a\u0300\u0320b", "a\u0320\u0300b"},
- {"\u1E0A\u0323", "\x44\u0323\u0307"},
- // A character that decomposes into multiple segments
- // spans several iterations.
- {"\u3304", "\u30A4\u30CB\u30F3\u30AF\u3099"},
-}
-
-func ExampleIter() {
- for i, t := range compareTests {
- r0 := EqualSimple(t.a, t.b)
- r1 := EqualOpt(t.a, t.b)
- fmt.Printf("%d: %v %v\n", i, r0, r1)
- }
- // Output:
- // 0: true true
- // 1: false false
- // 2: true true
- // 3: true true
- // 4: true true
- // 5: true true
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/example_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/example_test.go
deleted file mode 100644
index f2bec5b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/example_test.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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 norm_test
-
-import (
- "fmt"
-
- "golang.org/x/text/unicode/norm"
-)
-
-func ExampleNextBoundary() {
- s := norm.NFD.String("Mêlée")
-
- for i := 0; i < len(s); {
- d := norm.NFC.NextBoundaryInString(s[i:], true)
- fmt.Printf("%[1]s: %+[1]q\n", s[i:i+d])
- i += d
- }
- // Output:
- // M: "M"
- // ê: "e\u0302"
- // l: "l"
- // é: "e\u0301"
- // e: "e"
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/forminfo.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/forminfo.go
deleted file mode 100644
index 15a67c6..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/forminfo.go
+++ /dev/null
@@ -1,256 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package norm
-
-// This file contains Form-specific logic and wrappers for data in tables.go.
-
-// Rune info is stored in a separate trie per composing form. A composing form
-// and its corresponding decomposing form share the same trie. Each trie maps
-// a rune to a uint16. The values take two forms. For v >= 0x8000:
-// bits
-// 15: 1 (inverse of NFD_QD bit of qcInfo)
-// 13..7: qcInfo (see below). isYesD is always true (no decompostion).
-// 6..0: ccc (compressed CCC value).
-// For v < 0x8000, the respective rune has a decomposition and v is an index
-// into a byte array of UTF-8 decomposition sequences and additional info and
-// has the form:
-// <header> <decomp_byte>* [<tccc> [<lccc>]]
-// The header contains the number of bytes in the decomposition (excluding this
-// length byte). The two most significant bits of this length byte correspond
-// to bit 5 and 4 of qcInfo (see below). The byte sequence itself starts at v+1.
-// The byte sequence is followed by a trailing and leading CCC if the values
-// for these are not zero. The value of v determines which ccc are appended
-// to the sequences. For v < firstCCC, there are none, for v >= firstCCC,
-// the sequence is followed by a trailing ccc, and for v >= firstLeadingCC
-// there is an additional leading ccc. The value of tccc itself is the
-// trailing CCC shifted left 2 bits. The two least-significant bits of tccc
-// are the number of trailing non-starters.
-
-const (
- qcInfoMask = 0x3F // to clear all but the relevant bits in a qcInfo
- headerLenMask = 0x3F // extract the length value from the header byte
- headerFlagsMask = 0xC0 // extract the qcInfo bits from the header byte
-)
-
-// Properties provides access to normalization properties of a rune.
-type Properties struct {
- pos uint8 // start position in reorderBuffer; used in composition.go
- size uint8 // length of UTF-8 encoding of this rune
- ccc uint8 // leading canonical combining class (ccc if not decomposition)
- tccc uint8 // trailing canonical combining class (ccc if not decomposition)
- nLead uint8 // number of leading non-starters.
- flags qcInfo // quick check flags
- index uint16
-}
-
-// functions dispatchable per form
-type lookupFunc func(b input, i int) Properties
-
-// formInfo holds Form-specific functions and tables.
-type formInfo struct {
- form Form
- composing, compatibility bool // form type
- info lookupFunc
- nextMain iterFunc
-}
-
-var formTable []*formInfo
-
-func init() {
- formTable = make([]*formInfo, 4)
-
- for i := range formTable {
- f := &formInfo{}
- formTable[i] = f
- f.form = Form(i)
- if Form(i) == NFKD || Form(i) == NFKC {
- f.compatibility = true
- f.info = lookupInfoNFKC
- } else {
- f.info = lookupInfoNFC
- }
- f.nextMain = nextDecomposed
- if Form(i) == NFC || Form(i) == NFKC {
- f.nextMain = nextComposed
- f.composing = true
- }
- }
-}
-
-// We do not distinguish between boundaries for NFC, NFD, etc. to avoid
-// unexpected behavior for the user. For example, in NFD, there is a boundary
-// after 'a'. However, 'a' might combine with modifiers, so from the application's
-// perspective it is not a good boundary. We will therefore always use the
-// boundaries for the combining variants.
-
-// BoundaryBefore returns true if this rune starts a new segment and
-// cannot combine with any rune on the left.
-func (p Properties) BoundaryBefore() bool {
- if p.ccc == 0 && !p.combinesBackward() {
- return true
- }
- // We assume that the CCC of the first character in a decomposition
- // is always non-zero if different from info.ccc and that we can return
- // false at this point. This is verified by maketables.
- return false
-}
-
-// BoundaryAfter returns true if runes cannot combine with or otherwise
-// interact with this or previous runes.
-func (p Properties) BoundaryAfter() bool {
- // TODO: loosen these conditions.
- return p.isInert()
-}
-
-// We pack quick check data in 4 bits:
-// 5: Combines forward (0 == false, 1 == true)
-// 4..3: NFC_QC Yes(00), No (10), or Maybe (11)
-// 2: NFD_QC Yes (0) or No (1). No also means there is a decomposition.
-// 1..0: Number of trailing non-starters.
-//
-// When all 4 bits are zero, the character is inert, meaning it is never
-// influenced by normalization.
-type qcInfo uint8
-
-func (p Properties) isYesC() bool { return p.flags&0x10 == 0 }
-func (p Properties) isYesD() bool { return p.flags&0x4 == 0 }
-
-func (p Properties) combinesForward() bool { return p.flags&0x20 != 0 }
-func (p Properties) combinesBackward() bool { return p.flags&0x8 != 0 } // == isMaybe
-func (p Properties) hasDecomposition() bool { return p.flags&0x4 != 0 } // == isNoD
-
-func (p Properties) isInert() bool {
- return p.flags&qcInfoMask == 0 && p.ccc == 0
-}
-
-func (p Properties) multiSegment() bool {
- return p.index >= firstMulti && p.index < endMulti
-}
-
-func (p Properties) nLeadingNonStarters() uint8 {
- return p.nLead
-}
-
-func (p Properties) nTrailingNonStarters() uint8 {
- return uint8(p.flags & 0x03)
-}
-
-// Decomposition returns the decomposition for the underlying rune
-// or nil if there is none.
-func (p Properties) Decomposition() []byte {
- // TODO: create the decomposition for Hangul?
- if p.index == 0 {
- return nil
- }
- i := p.index
- n := decomps[i] & headerLenMask
- i++
- return decomps[i : i+uint16(n)]
-}
-
-// Size returns the length of UTF-8 encoding of the rune.
-func (p Properties) Size() int {
- return int(p.size)
-}
-
-// CCC returns the canonical combining class of the underlying rune.
-func (p Properties) CCC() uint8 {
- if p.index >= firstCCCZeroExcept {
- return 0
- }
- return ccc[p.ccc]
-}
-
-// LeadCCC returns the CCC of the first rune in the decomposition.
-// If there is no decomposition, LeadCCC equals CCC.
-func (p Properties) LeadCCC() uint8 {
- return ccc[p.ccc]
-}
-
-// TrailCCC returns the CCC of the last rune in the decomposition.
-// If there is no decomposition, TrailCCC equals CCC.
-func (p Properties) TrailCCC() uint8 {
- return ccc[p.tccc]
-}
-
-// Recomposition
-// We use 32-bit keys instead of 64-bit for the two codepoint keys.
-// This clips off the bits of three entries, but we know this will not
-// result in a collision. In the unlikely event that changes to
-// UnicodeData.txt introduce collisions, the compiler will catch it.
-// Note that the recomposition map for NFC and NFKC are identical.
-
-// combine returns the combined rune or 0 if it doesn't exist.
-func combine(a, b rune) rune {
- key := uint32(uint16(a))<<16 + uint32(uint16(b))
- return recompMap[key]
-}
-
-func lookupInfoNFC(b input, i int) Properties {
- v, sz := b.charinfoNFC(i)
- return compInfo(v, sz)
-}
-
-func lookupInfoNFKC(b input, i int) Properties {
- v, sz := b.charinfoNFKC(i)
- return compInfo(v, sz)
-}
-
-// Properties returns properties for the first rune in s.
-func (f Form) Properties(s []byte) Properties {
- if f == NFC || f == NFD {
- return compInfo(nfcData.lookup(s))
- }
- return compInfo(nfkcData.lookup(s))
-}
-
-// PropertiesString returns properties for the first rune in s.
-func (f Form) PropertiesString(s string) Properties {
- if f == NFC || f == NFD {
- return compInfo(nfcData.lookupString(s))
- }
- return compInfo(nfkcData.lookupString(s))
-}
-
-// compInfo converts the information contained in v and sz
-// to a Properties. See the comment at the top of the file
-// for more information on the format.
-func compInfo(v uint16, sz int) Properties {
- if v == 0 {
- return Properties{size: uint8(sz)}
- } else if v >= 0x8000 {
- p := Properties{
- size: uint8(sz),
- ccc: uint8(v),
- tccc: uint8(v),
- flags: qcInfo(v >> 8),
- }
- if p.ccc > 0 || p.combinesBackward() {
- p.nLead = uint8(p.flags & 0x3)
- }
- return p
- }
- // has decomposition
- h := decomps[v]
- f := (qcInfo(h&headerFlagsMask) >> 2) | 0x4
- p := Properties{size: uint8(sz), flags: f, index: v}
- if v >= firstCCC {
- v += uint16(h&headerLenMask) + 1
- c := decomps[v]
- p.tccc = c >> 2
- p.flags |= qcInfo(c & 0x3)
- if v >= firstLeadingCCC {
- p.nLead = c & 0x3
- if v >= firstStarterWithNLead {
- // We were tricked. Remove the decomposition.
- p.flags &= 0x03
- p.index = 0
- return p
- }
- p.ccc = decomps[v+1]
- }
- }
- return p
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/forminfo_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/forminfo_test.go
deleted file mode 100644
index e15ba9b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/forminfo_test.go
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build test
-
-package norm
-
-import "testing"
-
-func TestProperties(t *testing.T) {
- var d runeData
- CK := [2]string{"C", "K"}
- for k, r := 1, rune(0); r < 0x2ffff; r++ {
- if k < len(testData) && r == testData[k].r {
- d = testData[k]
- k++
- }
- s := string(r)
- for j, p := range []Properties{NFC.PropertiesString(s), NFKC.PropertiesString(s)} {
- f := d.f[j]
- if p.CCC() != d.ccc {
- t.Errorf("%U: ccc(%s): was %d; want %d %X", r, CK[j], p.CCC(), d.ccc, p.index)
- }
- if p.isYesC() != (f.qc == Yes) {
- t.Errorf("%U: YesC(%s): was %v; want %v", r, CK[j], p.isYesC(), f.qc == Yes)
- }
- if p.combinesBackward() != (f.qc == Maybe) {
- t.Errorf("%U: combines backwards(%s): was %v; want %v", r, CK[j], p.combinesBackward(), f.qc == Maybe)
- }
- if p.nLeadingNonStarters() != d.nLead {
- t.Errorf("%U: nLead(%s): was %d; want %d %#v %#v", r, CK[j], p.nLeadingNonStarters(), d.nLead, p, d)
- }
- if p.nTrailingNonStarters() != d.nTrail {
- t.Errorf("%U: nTrail(%s): was %d; want %d %#v %#v", r, CK[j], p.nTrailingNonStarters(), d.nTrail, p, d)
- }
- if p.combinesForward() != f.combinesForward {
- t.Errorf("%U: combines forward(%s): was %v; want %v %#v", r, CK[j], p.combinesForward(), f.combinesForward, p)
- }
- // Skip Hangul as it is algorithmically computed.
- if r >= hangulBase && r < hangulEnd {
- continue
- }
- if p.hasDecomposition() {
- if has := f.decomposition != ""; !has {
- t.Errorf("%U: hasDecomposition(%s): was %v; want %v", r, CK[j], p.hasDecomposition(), has)
- }
- if string(p.Decomposition()) != f.decomposition {
- t.Errorf("%U: decomp(%s): was %+q; want %+q", r, CK[j], p.Decomposition(), f.decomposition)
- }
- }
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/input.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/input.go
deleted file mode 100644
index 045d4cc..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/input.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package norm
-
-import "unicode/utf8"
-
-type input struct {
- str string
- bytes []byte
-}
-
-func inputBytes(str []byte) input {
- return input{bytes: str}
-}
-
-func inputString(str string) input {
- return input{str: str}
-}
-
-func (in *input) setBytes(str []byte) {
- in.str = ""
- in.bytes = str
-}
-
-func (in *input) setString(str string) {
- in.str = str
- in.bytes = nil
-}
-
-func (in *input) _byte(p int) byte {
- if in.bytes == nil {
- return in.str[p]
- }
- return in.bytes[p]
-}
-
-func (in *input) skipASCII(p, max int) int {
- if in.bytes == nil {
- for ; p < max && in.str[p] < utf8.RuneSelf; p++ {
- }
- } else {
- for ; p < max && in.bytes[p] < utf8.RuneSelf; p++ {
- }
- }
- return p
-}
-
-func (in *input) skipContinuationBytes(p int) int {
- if in.bytes == nil {
- for ; p < len(in.str) && !utf8.RuneStart(in.str[p]); p++ {
- }
- } else {
- for ; p < len(in.bytes) && !utf8.RuneStart(in.bytes[p]); p++ {
- }
- }
- return p
-}
-
-func (in *input) appendSlice(buf []byte, b, e int) []byte {
- if in.bytes != nil {
- return append(buf, in.bytes[b:e]...)
- }
- for i := b; i < e; i++ {
- buf = append(buf, in.str[i])
- }
- return buf
-}
-
-func (in *input) copySlice(buf []byte, b, e int) int {
- if in.bytes == nil {
- return copy(buf, in.str[b:e])
- }
- return copy(buf, in.bytes[b:e])
-}
-
-func (in *input) charinfoNFC(p int) (uint16, int) {
- if in.bytes == nil {
- return nfcData.lookupString(in.str[p:])
- }
- return nfcData.lookup(in.bytes[p:])
-}
-
-func (in *input) charinfoNFKC(p int) (uint16, int) {
- if in.bytes == nil {
- return nfkcData.lookupString(in.str[p:])
- }
- return nfkcData.lookup(in.bytes[p:])
-}
-
-func (in *input) hangul(p int) (r rune) {
- if in.bytes == nil {
- if !isHangulString(in.str[p:]) {
- return 0
- }
- r, _ = utf8.DecodeRuneInString(in.str[p:])
- } else {
- if !isHangul(in.bytes[p:]) {
- return 0
- }
- r, _ = utf8.DecodeRune(in.bytes[p:])
- }
- return r
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/iter.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/iter.go
deleted file mode 100644
index 0a42a72..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/iter.go
+++ /dev/null
@@ -1,450 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package norm
-
-import (
- "fmt"
- "unicode/utf8"
-)
-
-// MaxSegmentSize is the maximum size of a byte buffer needed to consider any
-// sequence of starter and non-starter runes for the purpose of normalization.
-const MaxSegmentSize = maxByteBufferSize
-
-// An Iter iterates over a string or byte slice, while normalizing it
-// to a given Form.
-type Iter struct {
- rb reorderBuffer
- buf [maxByteBufferSize]byte
- info Properties // first character saved from previous iteration
- next iterFunc // implementation of next depends on form
- asciiF iterFunc
-
- p int // current position in input source
- multiSeg []byte // remainder of multi-segment decomposition
-}
-
-type iterFunc func(*Iter) []byte
-
-// Init initializes i to iterate over src after normalizing it to Form f.
-func (i *Iter) Init(f Form, src []byte) {
- i.p = 0
- if len(src) == 0 {
- i.setDone()
- i.rb.nsrc = 0
- return
- }
- i.multiSeg = nil
- i.rb.init(f, src)
- i.next = i.rb.f.nextMain
- i.asciiF = nextASCIIBytes
- i.info = i.rb.f.info(i.rb.src, i.p)
-}
-
-// InitString initializes i to iterate over src after normalizing it to Form f.
-func (i *Iter) InitString(f Form, src string) {
- i.p = 0
- if len(src) == 0 {
- i.setDone()
- i.rb.nsrc = 0
- return
- }
- i.multiSeg = nil
- i.rb.initString(f, src)
- i.next = i.rb.f.nextMain
- i.asciiF = nextASCIIString
- i.info = i.rb.f.info(i.rb.src, i.p)
-}
-
-// Seek sets the segment to be returned by the next call to Next to start
-// at position p. It is the responsibility of the caller to set p to the
-// start of a UTF8 rune.
-func (i *Iter) Seek(offset int64, whence int) (int64, error) {
- var abs int64
- switch whence {
- case 0:
- abs = offset
- case 1:
- abs = int64(i.p) + offset
- case 2:
- abs = int64(i.rb.nsrc) + offset
- default:
- return 0, fmt.Errorf("norm: invalid whence")
- }
- if abs < 0 {
- return 0, fmt.Errorf("norm: negative position")
- }
- if int(abs) >= i.rb.nsrc {
- i.setDone()
- return int64(i.p), nil
- }
- i.p = int(abs)
- i.multiSeg = nil
- i.next = i.rb.f.nextMain
- i.info = i.rb.f.info(i.rb.src, i.p)
- return abs, nil
-}
-
-// returnSlice returns a slice of the underlying input type as a byte slice.
-// If the underlying is of type []byte, it will simply return a slice.
-// If the underlying is of type string, it will copy the slice to the buffer
-// and return that.
-func (i *Iter) returnSlice(a, b int) []byte {
- if i.rb.src.bytes == nil {
- return i.buf[:copy(i.buf[:], i.rb.src.str[a:b])]
- }
- return i.rb.src.bytes[a:b]
-}
-
-// Pos returns the byte position at which the next call to Next will commence processing.
-func (i *Iter) Pos() int {
- return i.p
-}
-
-func (i *Iter) setDone() {
- i.next = nextDone
- i.p = i.rb.nsrc
-}
-
-// Done returns true if there is no more input to process.
-func (i *Iter) Done() bool {
- return i.p >= i.rb.nsrc
-}
-
-// Next returns f(i.input[i.Pos():n]), where n is a boundary of i.input.
-// For any input a and b for which f(a) == f(b), subsequent calls
-// to Next will return the same segments.
-// Modifying runes are grouped together with the preceding starter, if such a starter exists.
-// Although not guaranteed, n will typically be the smallest possible n.
-func (i *Iter) Next() []byte {
- return i.next(i)
-}
-
-func nextASCIIBytes(i *Iter) []byte {
- p := i.p + 1
- if p >= i.rb.nsrc {
- i.setDone()
- return i.rb.src.bytes[i.p:p]
- }
- if i.rb.src.bytes[p] < utf8.RuneSelf {
- p0 := i.p
- i.p = p
- return i.rb.src.bytes[p0:p]
- }
- i.info = i.rb.f.info(i.rb.src, i.p)
- i.next = i.rb.f.nextMain
- return i.next(i)
-}
-
-func nextASCIIString(i *Iter) []byte {
- p := i.p + 1
- if p >= i.rb.nsrc {
- i.buf[0] = i.rb.src.str[i.p]
- i.setDone()
- return i.buf[:1]
- }
- if i.rb.src.str[p] < utf8.RuneSelf {
- i.buf[0] = i.rb.src.str[i.p]
- i.p = p
- return i.buf[:1]
- }
- i.info = i.rb.f.info(i.rb.src, i.p)
- i.next = i.rb.f.nextMain
- return i.next(i)
-}
-
-func nextHangul(i *Iter) []byte {
- p := i.p
- next := p + hangulUTF8Size
- if next >= i.rb.nsrc {
- i.setDone()
- } else if i.rb.src.hangul(next) == 0 {
- i.info = i.rb.f.info(i.rb.src, i.p)
- i.next = i.rb.f.nextMain
- return i.next(i)
- }
- i.p = next
- return i.buf[:decomposeHangul(i.buf[:], i.rb.src.hangul(p))]
-}
-
-func nextDone(i *Iter) []byte {
- return nil
-}
-
-// nextMulti is used for iterating over multi-segment decompositions
-// for decomposing normal forms.
-func nextMulti(i *Iter) []byte {
- j := 0
- d := i.multiSeg
- // skip first rune
- for j = 1; j < len(d) && !utf8.RuneStart(d[j]); j++ {
- }
- for j < len(d) {
- info := i.rb.f.info(input{bytes: d}, j)
- if info.BoundaryBefore() {
- i.multiSeg = d[j:]
- return d[:j]
- }
- j += int(info.size)
- }
- // treat last segment as normal decomposition
- i.next = i.rb.f.nextMain
- return i.next(i)
-}
-
-// nextMultiNorm is used for iterating over multi-segment decompositions
-// for composing normal forms.
-func nextMultiNorm(i *Iter) []byte {
- j := 0
- d := i.multiSeg
- for j < len(d) {
- info := i.rb.f.info(input{bytes: d}, j)
- if info.BoundaryBefore() {
- i.rb.compose()
- seg := i.buf[:i.rb.flushCopy(i.buf[:])]
- i.rb.ss.first(info)
- i.rb.insertUnsafe(input{bytes: d}, j, info)
- i.multiSeg = d[j+int(info.size):]
- return seg
- }
- i.rb.ss.next(info)
- i.rb.insertUnsafe(input{bytes: d}, j, info)
- j += int(info.size)
- }
- i.multiSeg = nil
- i.next = nextComposed
- return doNormComposed(i)
-}
-
-// nextDecomposed is the implementation of Next for forms NFD and NFKD.
-func nextDecomposed(i *Iter) (next []byte) {
- outp := 0
- inCopyStart, outCopyStart := i.p, 0
- ss := mkStreamSafe(i.info)
- for {
- if sz := int(i.info.size); sz <= 1 {
- p := i.p
- i.p++ // ASCII or illegal byte. Either way, advance by 1.
- if i.p >= i.rb.nsrc {
- i.setDone()
- return i.returnSlice(p, i.p)
- } else if i.rb.src._byte(i.p) < utf8.RuneSelf {
- i.next = i.asciiF
- return i.returnSlice(p, i.p)
- }
- outp++
- } else if d := i.info.Decomposition(); d != nil {
- // Note: If leading CCC != 0, then len(d) == 2 and last is also non-zero.
- // Case 1: there is a leftover to copy. In this case the decomposition
- // must begin with a modifier and should always be appended.
- // Case 2: no leftover. Simply return d if followed by a ccc == 0 value.
- p := outp + len(d)
- if outp > 0 {
- i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p)
- if p > len(i.buf) {
- return i.buf[:outp]
- }
- } else if i.info.multiSegment() {
- // outp must be 0 as multi-segment decompositions always
- // start a new segment.
- if i.multiSeg == nil {
- i.multiSeg = d
- i.next = nextMulti
- return nextMulti(i)
- }
- // We are in the last segment. Treat as normal decomposition.
- d = i.multiSeg
- i.multiSeg = nil
- p = len(d)
- }
- prevCC := i.info.tccc
- if i.p += sz; i.p >= i.rb.nsrc {
- i.setDone()
- i.info = Properties{} // Force BoundaryBefore to succeed.
- } else {
- i.info = i.rb.f.info(i.rb.src, i.p)
- }
- switch ss.next(i.info) {
- case ssOverflow:
- i.next = nextCGJDecompose
- fallthrough
- case ssStarter:
- if outp > 0 {
- copy(i.buf[outp:], d)
- return i.buf[:p]
- }
- return d
- }
- copy(i.buf[outp:], d)
- outp = p
- inCopyStart, outCopyStart = i.p, outp
- if i.info.ccc < prevCC {
- goto doNorm
- }
- continue
- } else if r := i.rb.src.hangul(i.p); r != 0 {
- outp = decomposeHangul(i.buf[:], r)
- i.p += hangulUTF8Size
- inCopyStart, outCopyStart = i.p, outp
- if i.p >= i.rb.nsrc {
- i.setDone()
- break
- } else if i.rb.src.hangul(i.p) != 0 {
- i.next = nextHangul
- return i.buf[:outp]
- }
- } else {
- p := outp + sz
- if p > len(i.buf) {
- break
- }
- outp = p
- i.p += sz
- }
- if i.p >= i.rb.nsrc {
- i.setDone()
- break
- }
- prevCC := i.info.tccc
- i.info = i.rb.f.info(i.rb.src, i.p)
- if v := ss.next(i.info); v == ssStarter {
- break
- } else if v == ssOverflow {
- i.next = nextCGJDecompose
- break
- }
- if i.info.ccc < prevCC {
- goto doNorm
- }
- }
- if outCopyStart == 0 {
- return i.returnSlice(inCopyStart, i.p)
- } else if inCopyStart < i.p {
- i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p)
- }
- return i.buf[:outp]
-doNorm:
- // Insert what we have decomposed so far in the reorderBuffer.
- // As we will only reorder, there will always be enough room.
- i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p)
- i.rb.insertDecomposed(i.buf[0:outp])
- return doNormDecomposed(i)
-}
-
-func doNormDecomposed(i *Iter) []byte {
- for {
- if s := i.rb.ss.next(i.info); s == ssOverflow {
- i.next = nextCGJDecompose
- break
- }
- i.rb.insertUnsafe(i.rb.src, i.p, i.info)
- if i.p += int(i.info.size); i.p >= i.rb.nsrc {
- i.setDone()
- break
- }
- i.info = i.rb.f.info(i.rb.src, i.p)
- if i.info.ccc == 0 {
- break
- }
- }
- // new segment or too many combining characters: exit normalization
- return i.buf[:i.rb.flushCopy(i.buf[:])]
-}
-
-func nextCGJDecompose(i *Iter) []byte {
- i.rb.ss = 0
- i.rb.insertCGJ()
- i.next = nextDecomposed
- buf := doNormDecomposed(i)
- return buf
-}
-
-// nextComposed is the implementation of Next for forms NFC and NFKC.
-func nextComposed(i *Iter) []byte {
- outp, startp := 0, i.p
- var prevCC uint8
- ss := mkStreamSafe(i.info)
- for {
- if !i.info.isYesC() {
- goto doNorm
- }
- prevCC = i.info.tccc
- sz := int(i.info.size)
- if sz == 0 {
- sz = 1 // illegal rune: copy byte-by-byte
- }
- p := outp + sz
- if p > len(i.buf) {
- break
- }
- outp = p
- i.p += sz
- if i.p >= i.rb.nsrc {
- i.setDone()
- break
- } else if i.rb.src._byte(i.p) < utf8.RuneSelf {
- i.next = i.asciiF
- break
- }
- i.info = i.rb.f.info(i.rb.src, i.p)
- if v := ss.next(i.info); v == ssStarter {
- break
- } else if v == ssOverflow {
- i.next = nextCGJCompose
- break
- }
- if i.info.ccc < prevCC {
- goto doNorm
- }
- }
- return i.returnSlice(startp, i.p)
-doNorm:
- i.p = startp
- i.info = i.rb.f.info(i.rb.src, i.p)
- if i.info.multiSegment() {
- d := i.info.Decomposition()
- info := i.rb.f.info(input{bytes: d}, 0)
- i.rb.insertUnsafe(input{bytes: d}, 0, info)
- i.multiSeg = d[int(info.size):]
- i.next = nextMultiNorm
- return nextMultiNorm(i)
- }
- i.rb.ss.first(i.info)
- i.rb.insertUnsafe(i.rb.src, i.p, i.info)
- return doNormComposed(i)
-}
-
-func doNormComposed(i *Iter) []byte {
- // First rune should already be inserted.
- for {
- if i.p += int(i.info.size); i.p >= i.rb.nsrc {
- i.setDone()
- break
- }
- i.info = i.rb.f.info(i.rb.src, i.p)
- if s := i.rb.ss.next(i.info); s == ssStarter {
- break
- } else if s == ssOverflow {
- i.next = nextCGJCompose
- break
- }
- i.rb.insertUnsafe(i.rb.src, i.p, i.info)
- }
- i.rb.compose()
- seg := i.buf[:i.rb.flushCopy(i.buf[:])]
- return seg
-}
-
-func nextCGJCompose(i *Iter) []byte {
- i.rb.ss = 0 // instead of first
- i.rb.insertCGJ()
- i.next = nextComposed
- // Note that we treat any rune with nLeadingNonStarters > 0 as a non-starter,
- // even if they are not. This is particularly dubious for U+FF9E and UFF9A.
- // If we ever change that, insert a check here.
- i.rb.ss.first(i.info)
- i.rb.insertUnsafe(i.rb.src, i.p, i.info)
- return doNormComposed(i)
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/iter_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/iter_test.go
deleted file mode 100644
index e2aa6f2..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/iter_test.go
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package norm
-
-import (
- "strings"
- "testing"
-)
-
-func doIterNorm(f Form, s string) []byte {
- acc := []byte{}
- i := Iter{}
- i.InitString(f, s)
- for !i.Done() {
- acc = append(acc, i.Next()...)
- }
- return acc
-}
-
-func TestIterNext(t *testing.T) {
- runNormTests(t, "IterNext", func(f Form, out []byte, s string) []byte {
- return doIterNorm(f, string(append(out, s...)))
- })
-}
-
-type SegmentTest struct {
- in string
- out []string
-}
-
-var segmentTests = []SegmentTest{
- {"\u1E0A\u0323a", []string{"\x44\u0323\u0307", "a", ""}},
- {rep('a', segSize), append(strings.Split(rep('a', segSize), ""), "")},
- {rep('a', segSize+2), append(strings.Split(rep('a', segSize+2), ""), "")},
- {rep('a', segSize) + "\u0300aa",
- append(strings.Split(rep('a', segSize-1), ""), "a\u0300", "a", "a", "")},
-
- // U+0f73 is NOT treated as a starter as it is a modifier
- {"a" + grave(29) + "\u0f73", []string{"a" + grave(29), cgj + "\u0f73"}},
- {"a\u0f73", []string{"a\u0f73"}},
-
- // U+ff9e is treated as a non-starter.
- // TODO: should we? Note that this will only affect iteration, as whether
- // or not we do so does not affect the normalization output and will either
- // way result in consistent iteration output.
- {"a" + grave(30) + "\uff9e", []string{"a" + grave(30), cgj + "\uff9e"}},
- {"a\uff9e", []string{"a\uff9e"}},
-}
-
-var segmentTestsK = []SegmentTest{
- {"\u3332", []string{"\u30D5", "\u30A1", "\u30E9", "\u30C3", "\u30C8\u3099", ""}},
- // last segment of multi-segment decomposition needs normalization
- {"\u3332\u093C", []string{"\u30D5", "\u30A1", "\u30E9", "\u30C3", "\u30C8\u093C\u3099", ""}},
- {"\u320E", []string{"\x28", "\uAC00", "\x29"}},
-
- // last segment should be copied to start of buffer.
- {"\ufdfa", []string{"\u0635", "\u0644", "\u0649", " ", "\u0627", "\u0644", "\u0644", "\u0647", " ", "\u0639", "\u0644", "\u064a", "\u0647", " ", "\u0648", "\u0633", "\u0644", "\u0645", ""}},
- {"\ufdfa" + grave(30), []string{"\u0635", "\u0644", "\u0649", " ", "\u0627", "\u0644", "\u0644", "\u0647", " ", "\u0639", "\u0644", "\u064a", "\u0647", " ", "\u0648", "\u0633", "\u0644", "\u0645" + grave(30), ""}},
- {"\uFDFA" + grave(64), []string{"\u0635", "\u0644", "\u0649", " ", "\u0627", "\u0644", "\u0644", "\u0647", " ", "\u0639", "\u0644", "\u064a", "\u0647", " ", "\u0648", "\u0633", "\u0644", "\u0645" + grave(30), cgj + grave(30), cgj + grave(4), ""}},
-
- // Hangul and Jamo are grouped togeter.
- {"\uAC00", []string{"\u1100\u1161", ""}},
- {"\uAC01", []string{"\u1100\u1161\u11A8", ""}},
- {"\u1100\u1161", []string{"\u1100\u1161", ""}},
-}
-
-// Note that, by design, segmentation is equal for composing and decomposing forms.
-func TestIterSegmentation(t *testing.T) {
- segmentTest(t, "SegmentTestD", NFD, segmentTests)
- segmentTest(t, "SegmentTestC", NFC, segmentTests)
- segmentTest(t, "SegmentTestKD", NFKD, segmentTestsK)
- segmentTest(t, "SegmentTestKC", NFKC, segmentTestsK)
-}
-
-func segmentTest(t *testing.T, name string, f Form, tests []SegmentTest) {
- iter := Iter{}
- for i, tt := range tests {
- iter.InitString(f, tt.in)
- for j, seg := range tt.out {
- if seg == "" {
- if !iter.Done() {
- res := string(iter.Next())
- t.Errorf(`%s:%d:%d: expected Done()==true, found segment %+q`, name, i, j, res)
- }
- continue
- }
- if iter.Done() {
- t.Errorf("%s:%d:%d: Done()==true, want false", name, i, j)
- }
- seg = f.String(seg)
- if res := string(iter.Next()); res != seg {
- t.Errorf(`%s:%d:%d" segment was %+q (%d); want %+q (%d)`, name, i, j, pc(res), len(res), pc(seg), len(seg))
- }
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/maketables.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/maketables.go
deleted file mode 100644
index 07bdff6..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/maketables.go
+++ /dev/null
@@ -1,978 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-// Normalization table generator.
-// Data read from the web.
-// See forminfo.go for a description of the trie values associated with each rune.
-
-package main
-
-import (
- "bytes"
- "flag"
- "fmt"
- "io"
- "log"
- "sort"
- "strconv"
- "strings"
-
- "golang.org/x/text/internal/gen"
- "golang.org/x/text/internal/triegen"
- "golang.org/x/text/internal/ucd"
-)
-
-func main() {
- gen.Init()
- loadUnicodeData()
- compactCCC()
- loadCompositionExclusions()
- completeCharFields(FCanonical)
- completeCharFields(FCompatibility)
- computeNonStarterCounts()
- verifyComputed()
- printChars()
- if *test {
- testDerived()
- printTestdata()
- } else {
- makeTables()
- }
-}
-
-var (
- tablelist = flag.String("tables",
- "all",
- "comma-separated list of which tables to generate; "+
- "can be 'decomp', 'recomp', 'info' and 'all'")
- test = flag.Bool("test",
- false,
- "test existing tables against DerivedNormalizationProps and generate test data for regression testing")
- verbose = flag.Bool("verbose",
- false,
- "write data to stdout as it is parsed")
-)
-
-const MaxChar = 0x10FFFF // anything above this shouldn't exist
-
-// Quick Check properties of runes allow us to quickly
-// determine whether a rune may occur in a normal form.
-// For a given normal form, a rune may be guaranteed to occur
-// verbatim (QC=Yes), may or may not combine with another
-// rune (QC=Maybe), or may not occur (QC=No).
-type QCResult int
-
-const (
- QCUnknown QCResult = iota
- QCYes
- QCNo
- QCMaybe
-)
-
-func (r QCResult) String() string {
- switch r {
- case QCYes:
- return "Yes"
- case QCNo:
- return "No"
- case QCMaybe:
- return "Maybe"
- }
- return "***UNKNOWN***"
-}
-
-const (
- FCanonical = iota // NFC or NFD
- FCompatibility // NFKC or NFKD
- FNumberOfFormTypes
-)
-
-const (
- MComposed = iota // NFC or NFKC
- MDecomposed // NFD or NFKD
- MNumberOfModes
-)
-
-// This contains only the properties we're interested in.
-type Char struct {
- name string
- codePoint rune // if zero, this index is not a valid code point.
- ccc uint8 // canonical combining class
- origCCC uint8
- excludeInComp bool // from CompositionExclusions.txt
- compatDecomp bool // it has a compatibility expansion
-
- nTrailingNonStarters uint8
- nLeadingNonStarters uint8 // must be equal to trailing if non-zero
-
- forms [FNumberOfFormTypes]FormInfo // For FCanonical and FCompatibility
-
- state State
-}
-
-var chars = make([]Char, MaxChar+1)
-var cccMap = make(map[uint8]uint8)
-
-func (c Char) String() string {
- buf := new(bytes.Buffer)
-
- fmt.Fprintf(buf, "%U [%s]:\n", c.codePoint, c.name)
- fmt.Fprintf(buf, " ccc: %v\n", c.ccc)
- fmt.Fprintf(buf, " excludeInComp: %v\n", c.excludeInComp)
- fmt.Fprintf(buf, " compatDecomp: %v\n", c.compatDecomp)
- fmt.Fprintf(buf, " state: %v\n", c.state)
- fmt.Fprintf(buf, " NFC:\n")
- fmt.Fprint(buf, c.forms[FCanonical])
- fmt.Fprintf(buf, " NFKC:\n")
- fmt.Fprint(buf, c.forms[FCompatibility])
-
- return buf.String()
-}
-
-// In UnicodeData.txt, some ranges are marked like this:
-// 3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
-// 4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;
-// parseCharacter keeps a state variable indicating the weirdness.
-type State int
-
-const (
- SNormal State = iota // known to be zero for the type
- SFirst
- SLast
- SMissing
-)
-
-var lastChar = rune('\u0000')
-
-func (c Char) isValid() bool {
- return c.codePoint != 0 && c.state != SMissing
-}
-
-type FormInfo struct {
- quickCheck [MNumberOfModes]QCResult // index: MComposed or MDecomposed
- verified [MNumberOfModes]bool // index: MComposed or MDecomposed
-
- combinesForward bool // May combine with rune on the right
- combinesBackward bool // May combine with rune on the left
- isOneWay bool // Never appears in result
- inDecomp bool // Some decompositions result in this char.
- decomp Decomposition
- expandedDecomp Decomposition
-}
-
-func (f FormInfo) String() string {
- buf := bytes.NewBuffer(make([]byte, 0))
-
- fmt.Fprintf(buf, " quickCheck[C]: %v\n", f.quickCheck[MComposed])
- fmt.Fprintf(buf, " quickCheck[D]: %v\n", f.quickCheck[MDecomposed])
- fmt.Fprintf(buf, " cmbForward: %v\n", f.combinesForward)
- fmt.Fprintf(buf, " cmbBackward: %v\n", f.combinesBackward)
- fmt.Fprintf(buf, " isOneWay: %v\n", f.isOneWay)
- fmt.Fprintf(buf, " inDecomp: %v\n", f.inDecomp)
- fmt.Fprintf(buf, " decomposition: %X\n", f.decomp)
- fmt.Fprintf(buf, " expandedDecomp: %X\n", f.expandedDecomp)
-
- return buf.String()
-}
-
-type Decomposition []rune
-
-func parseDecomposition(s string, skipfirst bool) (a []rune, err error) {
- decomp := strings.Split(s, " ")
- if len(decomp) > 0 && skipfirst {
- decomp = decomp[1:]
- }
- for _, d := range decomp {
- point, err := strconv.ParseUint(d, 16, 64)
- if err != nil {
- return a, err
- }
- a = append(a, rune(point))
- }
- return a, nil
-}
-
-func loadUnicodeData() {
- f := gen.OpenUCDFile("UnicodeData.txt")
- defer f.Close()
- p := ucd.New(f)
- for p.Next() {
- r := p.Rune(ucd.CodePoint)
- char := &chars[r]
-
- char.ccc = uint8(p.Uint(ucd.CanonicalCombiningClass))
- decmap := p.String(ucd.DecompMapping)
-
- exp, err := parseDecomposition(decmap, false)
- isCompat := false
- if err != nil {
- if len(decmap) > 0 {
- exp, err = parseDecomposition(decmap, true)
- if err != nil {
- log.Fatalf(`%U: bad decomp |%v|: "%s"`, r, decmap, err)
- }
- isCompat = true
- }
- }
-
- char.name = p.String(ucd.Name)
- char.codePoint = r
- char.forms[FCompatibility].decomp = exp
- if !isCompat {
- char.forms[FCanonical].decomp = exp
- } else {
- char.compatDecomp = true
- }
- if len(decmap) > 0 {
- char.forms[FCompatibility].decomp = exp
- }
- }
- if err := p.Err(); err != nil {
- log.Fatal(err)
- }
-}
-
-// compactCCC converts the sparse set of CCC values to a continguous one,
-// reducing the number of bits needed from 8 to 6.
-func compactCCC() {
- m := make(map[uint8]uint8)
- for i := range chars {
- c := &chars[i]
- m[c.ccc] = 0
- }
- cccs := []int{}
- for v, _ := range m {
- cccs = append(cccs, int(v))
- }
- sort.Ints(cccs)
- for i, c := range cccs {
- cccMap[uint8(i)] = uint8(c)
- m[uint8(c)] = uint8(i)
- }
- for i := range chars {
- c := &chars[i]
- c.origCCC = c.ccc
- c.ccc = m[c.ccc]
- }
- if len(m) >= 1<<6 {
- log.Fatalf("too many difference CCC values: %d >= 64", len(m))
- }
-}
-
-// CompositionExclusions.txt has form:
-// 0958 # ...
-// See http://unicode.org/reports/tr44/ for full explanation
-func loadCompositionExclusions() {
- f := gen.OpenUCDFile("CompositionExclusions.txt")
- defer f.Close()
- p := ucd.New(f)
- for p.Next() {
- c := &chars[p.Rune(0)]
- if c.excludeInComp {
- log.Fatalf("%U: Duplicate entry in exclusions.", c.codePoint)
- }
- c.excludeInComp = true
- }
- if e := p.Err(); e != nil {
- log.Fatal(e)
- }
-}
-
-// hasCompatDecomp returns true if any of the recursive
-// decompositions contains a compatibility expansion.
-// In this case, the character may not occur in NFK*.
-func hasCompatDecomp(r rune) bool {
- c := &chars[r]
- if c.compatDecomp {
- return true
- }
- for _, d := range c.forms[FCompatibility].decomp {
- if hasCompatDecomp(d) {
- return true
- }
- }
- return false
-}
-
-// Hangul related constants.
-const (
- HangulBase = 0xAC00
- HangulEnd = 0xD7A4 // hangulBase + Jamo combinations (19 * 21 * 28)
-
- JamoLBase = 0x1100
- JamoLEnd = 0x1113
- JamoVBase = 0x1161
- JamoVEnd = 0x1176
- JamoTBase = 0x11A8
- JamoTEnd = 0x11C3
-
- JamoLVTCount = 19 * 21 * 28
- JamoTCount = 28
-)
-
-func isHangul(r rune) bool {
- return HangulBase <= r && r < HangulEnd
-}
-
-func isHangulWithoutJamoT(r rune) bool {
- if !isHangul(r) {
- return false
- }
- r -= HangulBase
- return r < JamoLVTCount && r%JamoTCount == 0
-}
-
-func ccc(r rune) uint8 {
- return chars[r].ccc
-}
-
-// Insert a rune in a buffer, ordered by Canonical Combining Class.
-func insertOrdered(b Decomposition, r rune) Decomposition {
- n := len(b)
- b = append(b, 0)
- cc := ccc(r)
- if cc > 0 {
- // Use bubble sort.
- for ; n > 0; n-- {
- if ccc(b[n-1]) <= cc {
- break
- }
- b[n] = b[n-1]
- }
- }
- b[n] = r
- return b
-}
-
-// Recursively decompose.
-func decomposeRecursive(form int, r rune, d Decomposition) Decomposition {
- dcomp := chars[r].forms[form].decomp
- if len(dcomp) == 0 {
- return insertOrdered(d, r)
- }
- for _, c := range dcomp {
- d = decomposeRecursive(form, c, d)
- }
- return d
-}
-
-func completeCharFields(form int) {
- // Phase 0: pre-expand decomposition.
- for i := range chars {
- f := &chars[i].forms[form]
- if len(f.decomp) == 0 {
- continue
- }
- exp := make(Decomposition, 0)
- for _, c := range f.decomp {
- exp = decomposeRecursive(form, c, exp)
- }
- f.expandedDecomp = exp
- }
-
- // Phase 1: composition exclusion, mark decomposition.
- for i := range chars {
- c := &chars[i]
- f := &c.forms[form]
-
- // Marks script-specific exclusions and version restricted.
- f.isOneWay = c.excludeInComp
-
- // Singletons
- f.isOneWay = f.isOneWay || len(f.decomp) == 1
-
- // Non-starter decompositions
- if len(f.decomp) > 1 {
- chk := c.ccc != 0 || chars[f.decomp[0]].ccc != 0
- f.isOneWay = f.isOneWay || chk
- }
-
- // Runes that decompose into more than two runes.
- f.isOneWay = f.isOneWay || len(f.decomp) > 2
-
- if form == FCompatibility {
- f.isOneWay = f.isOneWay || hasCompatDecomp(c.codePoint)
- }
-
- for _, r := range f.decomp {
- chars[r].forms[form].inDecomp = true
- }
- }
-
- // Phase 2: forward and backward combining.
- for i := range chars {
- c := &chars[i]
- f := &c.forms[form]
-
- if !f.isOneWay && len(f.decomp) == 2 {
- f0 := &chars[f.decomp[0]].forms[form]
- f1 := &chars[f.decomp[1]].forms[form]
- if !f0.isOneWay {
- f0.combinesForward = true
- }
- if !f1.isOneWay {
- f1.combinesBackward = true
- }
- }
- if isHangulWithoutJamoT(rune(i)) {
- f.combinesForward = true
- }
- }
-
- // Phase 3: quick check values.
- for i := range chars {
- c := &chars[i]
- f := &c.forms[form]
-
- switch {
- case len(f.decomp) > 0:
- f.quickCheck[MDecomposed] = QCNo
- case isHangul(rune(i)):
- f.quickCheck[MDecomposed] = QCNo
- default:
- f.quickCheck[MDecomposed] = QCYes
- }
- switch {
- case f.isOneWay:
- f.quickCheck[MComposed] = QCNo
- case (i & 0xffff00) == JamoLBase:
- f.quickCheck[MComposed] = QCYes
- if JamoLBase <= i && i < JamoLEnd {
- f.combinesForward = true
- }
- if JamoVBase <= i && i < JamoVEnd {
- f.quickCheck[MComposed] = QCMaybe
- f.combinesBackward = true
- f.combinesForward = true
- }
- if JamoTBase <= i && i < JamoTEnd {
- f.quickCheck[MComposed] = QCMaybe
- f.combinesBackward = true
- }
- case !f.combinesBackward:
- f.quickCheck[MComposed] = QCYes
- default:
- f.quickCheck[MComposed] = QCMaybe
- }
- }
-}
-
-func computeNonStarterCounts() {
- // Phase 4: leading and trailing non-starter count
- for i := range chars {
- c := &chars[i]
-
- runes := []rune{rune(i)}
- // We always use FCompatibility so that the CGJ insertion points do not
- // change for repeated normalizations with different forms.
- if exp := c.forms[FCompatibility].expandedDecomp; len(exp) > 0 {
- runes = exp
- }
- // We consider runes that combine backwards to be non-starters for the
- // purpose of Stream-Safe Text Processing.
- for _, r := range runes {
- if cr := &chars[r]; cr.ccc == 0 && !cr.forms[FCompatibility].combinesBackward {
- break
- }
- c.nLeadingNonStarters++
- }
- for i := len(runes) - 1; i >= 0; i-- {
- if cr := &chars[runes[i]]; cr.ccc == 0 && !cr.forms[FCompatibility].combinesBackward {
- break
- }
- c.nTrailingNonStarters++
- }
- if c.nTrailingNonStarters > 3 {
- log.Fatalf("%U: Decomposition with more than 3 (%d) trailing modifiers (%U)", i, c.nTrailingNonStarters, runes)
- }
-
- if isHangul(rune(i)) {
- c.nTrailingNonStarters = 2
- if isHangulWithoutJamoT(rune(i)) {
- c.nTrailingNonStarters = 1
- }
- }
-
- if l, t := c.nLeadingNonStarters, c.nTrailingNonStarters; l > 0 && l != t {
- log.Fatalf("%U: number of leading and trailing non-starters should be equal (%d vs %d)", i, l, t)
- }
- if t := c.nTrailingNonStarters; t > 3 {
- log.Fatalf("%U: number of trailing non-starters is %d > 3", t)
- }
- }
-}
-
-func printBytes(w io.Writer, b []byte, name string) {
- fmt.Fprintf(w, "// %s: %d bytes\n", name, len(b))
- fmt.Fprintf(w, "var %s = [...]byte {", name)
- for i, c := range b {
- switch {
- case i%64 == 0:
- fmt.Fprintf(w, "\n// Bytes %x - %x\n", i, i+63)
- case i%8 == 0:
- fmt.Fprintf(w, "\n")
- }
- fmt.Fprintf(w, "0x%.2X, ", c)
- }
- fmt.Fprint(w, "\n}\n\n")
-}
-
-// See forminfo.go for format.
-func makeEntry(f *FormInfo, c *Char) uint16 {
- e := uint16(0)
- if r := c.codePoint; HangulBase <= r && r < HangulEnd {
- e |= 0x40
- }
- if f.combinesForward {
- e |= 0x20
- }
- if f.quickCheck[MDecomposed] == QCNo {
- e |= 0x4
- }
- switch f.quickCheck[MComposed] {
- case QCYes:
- case QCNo:
- e |= 0x10
- case QCMaybe:
- e |= 0x18
- default:
- log.Fatalf("Illegal quickcheck value %v.", f.quickCheck[MComposed])
- }
- e |= uint16(c.nTrailingNonStarters)
- return e
-}
-
-// decompSet keeps track of unique decompositions, grouped by whether
-// the decomposition is followed by a trailing and/or leading CCC.
-type decompSet [7]map[string]bool
-
-const (
- normalDecomp = iota
- firstMulti
- firstCCC
- endMulti
- firstLeadingCCC
- firstCCCZeroExcept
- firstStarterWithNLead
- lastDecomp
-)
-
-var cname = []string{"firstMulti", "firstCCC", "endMulti", "firstLeadingCCC", "firstCCCZeroExcept", "firstStarterWithNLead", "lastDecomp"}
-
-func makeDecompSet() decompSet {
- m := decompSet{}
- for i := range m {
- m[i] = make(map[string]bool)
- }
- return m
-}
-func (m *decompSet) insert(key int, s string) {
- m[key][s] = true
-}
-
-func printCharInfoTables(w io.Writer) int {
- mkstr := func(r rune, f *FormInfo) (int, string) {
- d := f.expandedDecomp
- s := string([]rune(d))
- if max := 1 << 6; len(s) >= max {
- const msg = "%U: too many bytes in decomposition: %d >= %d"
- log.Fatalf(msg, r, len(s), max)
- }
- head := uint8(len(s))
- if f.quickCheck[MComposed] != QCYes {
- head |= 0x40
- }
- if f.combinesForward {
- head |= 0x80
- }
- s = string([]byte{head}) + s
-
- lccc := ccc(d[0])
- tccc := ccc(d[len(d)-1])
- cc := ccc(r)
- if cc != 0 && lccc == 0 && tccc == 0 {
- log.Fatalf("%U: trailing and leading ccc are 0 for non-zero ccc %d", r, cc)
- }
- if tccc < lccc && lccc != 0 {
- const msg = "%U: lccc (%d) must be <= tcc (%d)"
- log.Fatalf(msg, r, lccc, tccc)
- }
- index := normalDecomp
- nTrail := chars[r].nTrailingNonStarters
- if tccc > 0 || lccc > 0 || nTrail > 0 {
- tccc <<= 2
- tccc |= nTrail
- s += string([]byte{tccc})
- index = endMulti
- for _, r := range d[1:] {
- if ccc(r) == 0 {
- index = firstCCC
- }
- }
- if lccc > 0 {
- s += string([]byte{lccc})
- if index == firstCCC {
- log.Fatalf("%U: multi-segment decomposition not supported for decompositions with leading CCC != 0", r)
- }
- index = firstLeadingCCC
- }
- if cc != lccc {
- if cc != 0 {
- log.Fatalf("%U: for lccc != ccc, expected ccc to be 0; was %d", r, cc)
- }
- index = firstCCCZeroExcept
- }
- } else if len(d) > 1 {
- index = firstMulti
- }
- return index, s
- }
-
- decompSet := makeDecompSet()
- const nLeadStr = "\x00\x01" // 0-byte length and tccc with nTrail.
- decompSet.insert(firstStarterWithNLead, nLeadStr)
-
- // Store the uniqued decompositions in a byte buffer,
- // preceded by their byte length.
- for _, c := range chars {
- for _, f := range c.forms {
- if len(f.expandedDecomp) == 0 {
- continue
- }
- if f.combinesBackward {
- log.Fatalf("%U: combinesBackward and decompose", c.codePoint)
- }
- index, s := mkstr(c.codePoint, &f)
- decompSet.insert(index, s)
- }
- }
-
- decompositions := bytes.NewBuffer(make([]byte, 0, 10000))
- size := 0
- positionMap := make(map[string]uint16)
- decompositions.WriteString("\000")
- fmt.Fprintln(w, "const (")
- for i, m := range decompSet {
- sa := []string{}
- for s := range m {
- sa = append(sa, s)
- }
- sort.Strings(sa)
- for _, s := range sa {
- p := decompositions.Len()
- decompositions.WriteString(s)
- positionMap[s] = uint16(p)
- }
- if cname[i] != "" {
- fmt.Fprintf(w, "%s = 0x%X\n", cname[i], decompositions.Len())
- }
- }
- fmt.Fprintln(w, "maxDecomp = 0x8000")
- fmt.Fprintln(w, ")")
- b := decompositions.Bytes()
- printBytes(w, b, "decomps")
- size += len(b)
-
- varnames := []string{"nfc", "nfkc"}
- for i := 0; i < FNumberOfFormTypes; i++ {
- trie := triegen.NewTrie(varnames[i])
-
- for r, c := range chars {
- f := c.forms[i]
- d := f.expandedDecomp
- if len(d) != 0 {
- _, key := mkstr(c.codePoint, &f)
- trie.Insert(rune(r), uint64(positionMap[key]))
- if c.ccc != ccc(d[0]) {
- // We assume the lead ccc of a decomposition !=0 in this case.
- if ccc(d[0]) == 0 {
- log.Fatalf("Expected leading CCC to be non-zero; ccc is %d", c.ccc)
- }
- }
- } else if c.nLeadingNonStarters > 0 && len(f.expandedDecomp) == 0 && c.ccc == 0 && !f.combinesBackward {
- // Handle cases where it can't be detected that the nLead should be equal
- // to nTrail.
- trie.Insert(c.codePoint, uint64(positionMap[nLeadStr]))
- } else if v := makeEntry(&f, &c)<<8 | uint16(c.ccc); v != 0 {
- trie.Insert(c.codePoint, uint64(0x8000|v))
- }
- }
- sz, err := trie.Gen(w, triegen.Compact(&normCompacter{name: varnames[i]}))
- if err != nil {
- log.Fatal(err)
- }
- size += sz
- }
- return size
-}
-
-func contains(sa []string, s string) bool {
- for _, a := range sa {
- if a == s {
- return true
- }
- }
- return false
-}
-
-func makeTables() {
- w := &bytes.Buffer{}
-
- size := 0
- if *tablelist == "" {
- return
- }
- list := strings.Split(*tablelist, ",")
- if *tablelist == "all" {
- list = []string{"recomp", "info"}
- }
-
- // Compute maximum decomposition size.
- max := 0
- for _, c := range chars {
- if n := len(string(c.forms[FCompatibility].expandedDecomp)); n > max {
- max = n
- }
- }
-
- fmt.Fprintln(w, "const (")
- fmt.Fprintln(w, "\t// Version is the Unicode edition from which the tables are derived.")
- fmt.Fprintf(w, "\tVersion = %q\n", gen.UnicodeVersion())
- fmt.Fprintln(w)
- fmt.Fprintln(w, "\t// MaxTransformChunkSize indicates the maximum number of bytes that Transform")
- fmt.Fprintln(w, "\t// may need to write atomically for any Form. Making a destination buffer at")
- fmt.Fprintln(w, "\t// least this size ensures that Transform can always make progress and that")
- fmt.Fprintln(w, "\t// the user does not need to grow the buffer on an ErrShortDst.")
- fmt.Fprintf(w, "\tMaxTransformChunkSize = %d+maxNonStarters*4\n", len(string(0x034F))+max)
- fmt.Fprintln(w, ")\n")
-
- // Print the CCC remap table.
- size += len(cccMap)
- fmt.Fprintf(w, "var ccc = [%d]uint8{", len(cccMap))
- for i := 0; i < len(cccMap); i++ {
- if i%8 == 0 {
- fmt.Fprintln(w)
- }
- fmt.Fprintf(w, "%3d, ", cccMap[uint8(i)])
- }
- fmt.Fprintln(w, "\n}\n")
-
- if contains(list, "info") {
- size += printCharInfoTables(w)
- }
-
- if contains(list, "recomp") {
- // Note that we use 32 bit keys, instead of 64 bit.
- // This clips the bits of three entries, but we know
- // this won't cause a collision. The compiler will catch
- // any changes made to UnicodeData.txt that introduces
- // a collision.
- // Note that the recomposition map for NFC and NFKC
- // are identical.
-
- // Recomposition map
- nrentries := 0
- for _, c := range chars {
- f := c.forms[FCanonical]
- if !f.isOneWay && len(f.decomp) > 0 {
- nrentries++
- }
- }
- sz := nrentries * 8
- size += sz
- fmt.Fprintf(w, "// recompMap: %d bytes (entries only)\n", sz)
- fmt.Fprintln(w, "var recompMap = map[uint32]rune{")
- for i, c := range chars {
- f := c.forms[FCanonical]
- d := f.decomp
- if !f.isOneWay && len(d) > 0 {
- key := uint32(uint16(d[0]))<<16 + uint32(uint16(d[1]))
- fmt.Fprintf(w, "0x%.8X: 0x%.4X,\n", key, i)
- }
- }
- fmt.Fprintf(w, "}\n\n")
- }
-
- fmt.Fprintf(w, "// Total size of tables: %dKB (%d bytes)\n", (size+512)/1024, size)
- gen.WriteGoFile("tables.go", "norm", w.Bytes())
-}
-
-func printChars() {
- if *verbose {
- for _, c := range chars {
- if !c.isValid() || c.state == SMissing {
- continue
- }
- fmt.Println(c)
- }
- }
-}
-
-// verifyComputed does various consistency tests.
-func verifyComputed() {
- for i, c := range chars {
- for _, f := range c.forms {
- isNo := (f.quickCheck[MDecomposed] == QCNo)
- if (len(f.decomp) > 0) != isNo && !isHangul(rune(i)) {
- log.Fatalf("%U: NF*D QC must be No if rune decomposes", i)
- }
-
- isMaybe := f.quickCheck[MComposed] == QCMaybe
- if f.combinesBackward != isMaybe {
- log.Fatalf("%U: NF*C QC must be Maybe if combinesBackward", i)
- }
- if len(f.decomp) > 0 && f.combinesForward && isMaybe {
- log.Fatalf("%U: NF*C QC must be Yes or No if combinesForward and decomposes", i)
- }
-
- if len(f.expandedDecomp) != 0 {
- continue
- }
- if a, b := c.nLeadingNonStarters > 0, (c.ccc > 0 || f.combinesBackward); a != b {
- // We accept these runes to be treated differently (it only affects
- // segment breaking in iteration, most likely on improper use), but
- // reconsider if more characters are added.
- // U+FF9E HALFWIDTH KATAKANA VOICED SOUND MARK;Lm;0;L;<narrow> 3099;;;;N;;;;;
- // U+FF9F HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK;Lm;0;L;<narrow> 309A;;;;N;;;;;
- // U+3133 HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<compat> 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;;
- // U+318E HANGUL LETTER ARAEAE;Lo;0;L;<compat> 11A1;;;;N;HANGUL LETTER ALAE AE;;;;
- // U+FFA3 HALFWIDTH HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<narrow> 3133;;;;N;HALFWIDTH HANGUL LETTER GIYEOG SIOS;;;;
- // U+FFDC HALFWIDTH HANGUL LETTER I;Lo;0;L;<narrow> 3163;;;;N;;;;;
- if i != 0xFF9E && i != 0xFF9F && !(0x3133 <= i && i <= 0x318E) && !(0xFFA3 <= i && i <= 0xFFDC) {
- log.Fatalf("%U: nLead was %v; want %v", i, a, b)
- }
- }
- }
- nfc := c.forms[FCanonical]
- nfkc := c.forms[FCompatibility]
- if nfc.combinesBackward != nfkc.combinesBackward {
- log.Fatalf("%U: Cannot combine combinesBackward\n", c.codePoint)
- }
- }
-}
-
-// Use values in DerivedNormalizationProps.txt to compare against the
-// values we computed.
-// DerivedNormalizationProps.txt has form:
-// 00C0..00C5 ; NFD_QC; N # ...
-// 0374 ; NFD_QC; N # ...
-// See http://unicode.org/reports/tr44/ for full explanation
-func testDerived() {
- f := gen.OpenUCDFile("DerivedNormalizationProps.txt")
- defer f.Close()
- p := ucd.New(f)
- for p.Next() {
- r := p.Rune(0)
- c := &chars[r]
-
- var ftype, mode int
- qt := p.String(1)
- switch qt {
- case "NFC_QC":
- ftype, mode = FCanonical, MComposed
- case "NFD_QC":
- ftype, mode = FCanonical, MDecomposed
- case "NFKC_QC":
- ftype, mode = FCompatibility, MComposed
- case "NFKD_QC":
- ftype, mode = FCompatibility, MDecomposed
- default:
- continue
- }
- var qr QCResult
- switch p.String(2) {
- case "Y":
- qr = QCYes
- case "N":
- qr = QCNo
- case "M":
- qr = QCMaybe
- default:
- log.Fatalf(`Unexpected quick check value "%s"`, p.String(2))
- }
- if got := c.forms[ftype].quickCheck[mode]; got != qr {
- log.Printf("%U: FAILED %s (was %v need %v)\n", r, qt, got, qr)
- }
- c.forms[ftype].verified[mode] = true
- }
- if err := p.Err(); err != nil {
- log.Fatal(err)
- }
- // Any unspecified value must be QCYes. Verify this.
- for i, c := range chars {
- for j, fd := range c.forms {
- for k, qr := range fd.quickCheck {
- if !fd.verified[k] && qr != QCYes {
- m := "%U: FAIL F:%d M:%d (was %v need Yes) %s\n"
- log.Printf(m, i, j, k, qr, c.name)
- }
- }
- }
- }
-}
-
-var testHeader = `const (
- Yes = iota
- No
- Maybe
-)
-
-type formData struct {
- qc uint8
- combinesForward bool
- decomposition string
-}
-
-type runeData struct {
- r rune
- ccc uint8
- nLead uint8
- nTrail uint8
- f [2]formData // 0: canonical; 1: compatibility
-}
-
-func f(qc uint8, cf bool, dec string) [2]formData {
- return [2]formData{{qc, cf, dec}, {qc, cf, dec}}
-}
-
-func g(qc, qck uint8, cf, cfk bool, d, dk string) [2]formData {
- return [2]formData{{qc, cf, d}, {qck, cfk, dk}}
-}
-
-var testData = []runeData{
-`
-
-func printTestdata() {
- type lastInfo struct {
- ccc uint8
- nLead uint8
- nTrail uint8
- f string
- }
-
- last := lastInfo{}
- w := &bytes.Buffer{}
- fmt.Fprintf(w, testHeader)
- for r, c := range chars {
- f := c.forms[FCanonical]
- qc, cf, d := f.quickCheck[MComposed], f.combinesForward, string(f.expandedDecomp)
- f = c.forms[FCompatibility]
- qck, cfk, dk := f.quickCheck[MComposed], f.combinesForward, string(f.expandedDecomp)
- s := ""
- if d == dk && qc == qck && cf == cfk {
- s = fmt.Sprintf("f(%s, %v, %q)", qc, cf, d)
- } else {
- s = fmt.Sprintf("g(%s, %s, %v, %v, %q, %q)", qc, qck, cf, cfk, d, dk)
- }
- current := lastInfo{c.ccc, c.nLeadingNonStarters, c.nTrailingNonStarters, s}
- if last != current {
- fmt.Fprintf(w, "\t{0x%x, %d, %d, %d, %s},\n", r, c.origCCC, c.nLeadingNonStarters, c.nTrailingNonStarters, s)
- last = current
- }
- }
- fmt.Fprintln(w, "}")
- gen.WriteGoFile("data_test.go", "norm", w.Bytes())
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/norm_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/norm_test.go
deleted file mode 100644
index 12dacfc..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/norm_test.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package norm_test
-
-import (
- "testing"
-)
-
-func TestPlaceHolder(t *testing.T) {
- // Does nothing, just allows the Makefile to be canonical
- // while waiting for the package itself to be written.
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/normalize.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/normalize.go
deleted file mode 100644
index bba8ce9..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/normalize.go
+++ /dev/null
@@ -1,608 +0,0 @@
-// 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.
-
-//go:generate go run maketables.go triegen.go
-//go:generate go run maketables.go triegen.go -test
-
-// Package norm contains types and functions for normalizing Unicode strings.
-package norm // import "golang.org/x/text/unicode/norm"
-
-import (
- "unicode/utf8"
-
- "golang.org/x/text/transform"
-)
-
-// A Form denotes a canonical representation of Unicode code points.
-// The Unicode-defined normalization and equivalence forms are:
-//
-// NFC Unicode Normalization Form C
-// NFD Unicode Normalization Form D
-// NFKC Unicode Normalization Form KC
-// NFKD Unicode Normalization Form KD
-//
-// For a Form f, this documentation uses the notation f(x) to mean
-// the bytes or string x converted to the given form.
-// A position n in x is called a boundary if conversion to the form can
-// proceed independently on both sides:
-// f(x) == append(f(x[0:n]), f(x[n:])...)
-//
-// References: http://unicode.org/reports/tr15/ and
-// http://unicode.org/notes/tn5/.
-type Form int
-
-const (
- NFC Form = iota
- NFD
- NFKC
- NFKD
-)
-
-// Bytes returns f(b). May return b if f(b) = b.
-func (f Form) Bytes(b []byte) []byte {
- src := inputBytes(b)
- ft := formTable[f]
- n, ok := ft.quickSpan(src, 0, len(b), true)
- if ok {
- return b
- }
- out := make([]byte, n, len(b))
- copy(out, b[0:n])
- rb := reorderBuffer{f: *ft, src: src, nsrc: len(b), out: out, flushF: appendFlush}
- return doAppendInner(&rb, n)
-}
-
-// String returns f(s).
-func (f Form) String(s string) string {
- src := inputString(s)
- ft := formTable[f]
- n, ok := ft.quickSpan(src, 0, len(s), true)
- if ok {
- return s
- }
- out := make([]byte, n, len(s))
- copy(out, s[0:n])
- rb := reorderBuffer{f: *ft, src: src, nsrc: len(s), out: out, flushF: appendFlush}
- return string(doAppendInner(&rb, n))
-}
-
-// IsNormal returns true if b == f(b).
-func (f Form) IsNormal(b []byte) bool {
- src := inputBytes(b)
- ft := formTable[f]
- bp, ok := ft.quickSpan(src, 0, len(b), true)
- if ok {
- return true
- }
- rb := reorderBuffer{f: *ft, src: src, nsrc: len(b)}
- rb.setFlusher(nil, cmpNormalBytes)
- for bp < len(b) {
- rb.out = b[bp:]
- if bp = decomposeSegment(&rb, bp, true); bp < 0 {
- return false
- }
- bp, _ = rb.f.quickSpan(rb.src, bp, len(b), true)
- }
- return true
-}
-
-func cmpNormalBytes(rb *reorderBuffer) bool {
- b := rb.out
- for i := 0; i < rb.nrune; i++ {
- info := rb.rune[i]
- if int(info.size) > len(b) {
- return false
- }
- p := info.pos
- pe := p + info.size
- for ; p < pe; p++ {
- if b[0] != rb.byte[p] {
- return false
- }
- b = b[1:]
- }
- }
- return true
-}
-
-// IsNormalString returns true if s == f(s).
-func (f Form) IsNormalString(s string) bool {
- src := inputString(s)
- ft := formTable[f]
- bp, ok := ft.quickSpan(src, 0, len(s), true)
- if ok {
- return true
- }
- rb := reorderBuffer{f: *ft, src: src, nsrc: len(s)}
- rb.setFlusher(nil, func(rb *reorderBuffer) bool {
- for i := 0; i < rb.nrune; i++ {
- info := rb.rune[i]
- if bp+int(info.size) > len(s) {
- return false
- }
- p := info.pos
- pe := p + info.size
- for ; p < pe; p++ {
- if s[bp] != rb.byte[p] {
- return false
- }
- bp++
- }
- }
- return true
- })
- for bp < len(s) {
- if bp = decomposeSegment(&rb, bp, true); bp < 0 {
- return false
- }
- bp, _ = rb.f.quickSpan(rb.src, bp, len(s), true)
- }
- return true
-}
-
-// patchTail fixes a case where a rune may be incorrectly normalized
-// if it is followed by illegal continuation bytes. It returns the
-// patched buffer and whether the decomposition is still in progress.
-func patchTail(rb *reorderBuffer) bool {
- info, p := lastRuneStart(&rb.f, rb.out)
- if p == -1 || info.size == 0 {
- return true
- }
- end := p + int(info.size)
- extra := len(rb.out) - end
- if extra > 0 {
- // Potentially allocating memory. However, this only
- // happens with ill-formed UTF-8.
- x := make([]byte, 0)
- x = append(x, rb.out[len(rb.out)-extra:]...)
- rb.out = rb.out[:end]
- decomposeToLastBoundary(rb)
- rb.doFlush()
- rb.out = append(rb.out, x...)
- return false
- }
- buf := rb.out[p:]
- rb.out = rb.out[:p]
- decomposeToLastBoundary(rb)
- if s := rb.ss.next(info); s == ssStarter {
- rb.doFlush()
- rb.ss.first(info)
- } else if s == ssOverflow {
- rb.doFlush()
- rb.insertCGJ()
- rb.ss = 0
- }
- rb.insertUnsafe(inputBytes(buf), 0, info)
- return true
-}
-
-func appendQuick(rb *reorderBuffer, i int) int {
- if rb.nsrc == i {
- return i
- }
- end, _ := rb.f.quickSpan(rb.src, i, rb.nsrc, true)
- rb.out = rb.src.appendSlice(rb.out, i, end)
- return end
-}
-
-// Append returns f(append(out, b...)).
-// The buffer out must be nil, empty, or equal to f(out).
-func (f Form) Append(out []byte, src ...byte) []byte {
- return f.doAppend(out, inputBytes(src), len(src))
-}
-
-func (f Form) doAppend(out []byte, src input, n int) []byte {
- if n == 0 {
- return out
- }
- ft := formTable[f]
- // Attempt to do a quickSpan first so we can avoid initializing the reorderBuffer.
- if len(out) == 0 {
- p, _ := ft.quickSpan(src, 0, n, true)
- out = src.appendSlice(out, 0, p)
- if p == n {
- return out
- }
- rb := reorderBuffer{f: *ft, src: src, nsrc: n, out: out, flushF: appendFlush}
- return doAppendInner(&rb, p)
- }
- rb := reorderBuffer{f: *ft, src: src, nsrc: n}
- return doAppend(&rb, out, 0)
-}
-
-func doAppend(rb *reorderBuffer, out []byte, p int) []byte {
- rb.setFlusher(out, appendFlush)
- src, n := rb.src, rb.nsrc
- doMerge := len(out) > 0
- if q := src.skipContinuationBytes(p); q > p {
- // Move leading non-starters to destination.
- rb.out = src.appendSlice(rb.out, p, q)
- p = q
- doMerge = patchTail(rb)
- }
- fd := &rb.f
- if doMerge {
- var info Properties
- if p < n {
- info = fd.info(src, p)
- if !info.BoundaryBefore() || info.nLeadingNonStarters() > 0 {
- if p == 0 {
- decomposeToLastBoundary(rb)
- }
- p = decomposeSegment(rb, p, true)
- }
- }
- if info.size == 0 {
- rb.doFlush()
- // Append incomplete UTF-8 encoding.
- return src.appendSlice(rb.out, p, n)
- }
- if rb.nrune > 0 {
- return doAppendInner(rb, p)
- }
- }
- p = appendQuick(rb, p)
- return doAppendInner(rb, p)
-}
-
-func doAppendInner(rb *reorderBuffer, p int) []byte {
- for n := rb.nsrc; p < n; {
- p = decomposeSegment(rb, p, true)
- p = appendQuick(rb, p)
- }
- return rb.out
-}
-
-// AppendString returns f(append(out, []byte(s))).
-// The buffer out must be nil, empty, or equal to f(out).
-func (f Form) AppendString(out []byte, src string) []byte {
- return f.doAppend(out, inputString(src), len(src))
-}
-
-// QuickSpan returns a boundary n such that b[0:n] == f(b[0:n]).
-// It is not guaranteed to return the largest such n.
-func (f Form) QuickSpan(b []byte) int {
- n, _ := formTable[f].quickSpan(inputBytes(b), 0, len(b), true)
- return n
-}
-
-// Span implements transform.SpanningTransformer. It returns a boundary n such
-// that b[0:n] == f(b[0:n]). It is not guaranteed to return the largest such n.
-func (f Form) Span(b []byte, atEOF bool) (n int, err error) {
- n, ok := formTable[f].quickSpan(inputBytes(b), 0, len(b), atEOF)
- if n < len(b) {
- if !ok {
- err = transform.ErrEndOfSpan
- } else {
- err = transform.ErrShortSrc
- }
- }
- return n, err
-}
-
-// SpanString returns a boundary n such that s[0:n] == f(s[0:n]).
-// It is not guaranteed to return the largest such n.
-func (f Form) SpanString(s string, atEOF bool) (n int, err error) {
- n, ok := formTable[f].quickSpan(inputString(s), 0, len(s), atEOF)
- if n < len(s) {
- if !ok {
- err = transform.ErrEndOfSpan
- } else {
- err = transform.ErrShortSrc
- }
- }
- return n, err
-}
-
-// quickSpan returns a boundary n such that src[0:n] == f(src[0:n]) and
-// whether any non-normalized parts were found. If atEOF is false, n will
-// not point past the last segment if this segment might be become
-// non-normalized by appending other runes.
-func (f *formInfo) quickSpan(src input, i, end int, atEOF bool) (n int, ok bool) {
- var lastCC uint8
- ss := streamSafe(0)
- lastSegStart := i
- for n = end; i < n; {
- if j := src.skipASCII(i, n); i != j {
- i = j
- lastSegStart = i - 1
- lastCC = 0
- ss = 0
- continue
- }
- info := f.info(src, i)
- if info.size == 0 {
- if atEOF {
- // include incomplete runes
- return n, true
- }
- return lastSegStart, true
- }
- // This block needs to be before the next, because it is possible to
- // have an overflow for runes that are starters (e.g. with U+FF9E).
- switch ss.next(info) {
- case ssStarter:
- ss.first(info)
- lastSegStart = i
- case ssOverflow:
- return lastSegStart, false
- case ssSuccess:
- if lastCC > info.ccc {
- return lastSegStart, false
- }
- }
- if f.composing {
- if !info.isYesC() {
- break
- }
- } else {
- if !info.isYesD() {
- break
- }
- }
- lastCC = info.ccc
- i += int(info.size)
- }
- if i == n {
- if !atEOF {
- n = lastSegStart
- }
- return n, true
- }
- return lastSegStart, false
-}
-
-// QuickSpanString returns a boundary n such that s[0:n] == f(s[0:n]).
-// It is not guaranteed to return the largest such n.
-func (f Form) QuickSpanString(s string) int {
- n, _ := formTable[f].quickSpan(inputString(s), 0, len(s), true)
- return n
-}
-
-// FirstBoundary returns the position i of the first boundary in b
-// or -1 if b contains no boundary.
-func (f Form) FirstBoundary(b []byte) int {
- return f.firstBoundary(inputBytes(b), len(b))
-}
-
-func (f Form) firstBoundary(src input, nsrc int) int {
- i := src.skipContinuationBytes(0)
- if i >= nsrc {
- return -1
- }
- fd := formTable[f]
- ss := streamSafe(0)
- // We should call ss.first here, but we can't as the first rune is
- // skipped already. This means FirstBoundary can't really determine
- // CGJ insertion points correctly. Luckily it doesn't have to.
- for {
- info := fd.info(src, i)
- if info.size == 0 {
- return -1
- }
- if s := ss.next(info); s != ssSuccess {
- return i
- }
- i += int(info.size)
- if i >= nsrc {
- if !info.BoundaryAfter() && !ss.isMax() {
- return -1
- }
- return nsrc
- }
- }
-}
-
-// FirstBoundaryInString returns the position i of the first boundary in s
-// or -1 if s contains no boundary.
-func (f Form) FirstBoundaryInString(s string) int {
- return f.firstBoundary(inputString(s), len(s))
-}
-
-// NextBoundary reports the index of the boundary between the first and next
-// segment in b or -1 if atEOF is false and there are not enough bytes to
-// determine this boundary.
-func (f Form) NextBoundary(b []byte, atEOF bool) int {
- return f.nextBoundary(inputBytes(b), len(b), atEOF)
-}
-
-// NextBoundaryInString reports the index of the boundary between the first and
-// next segment in b or -1 if atEOF is false and there are not enough bytes to
-// determine this boundary.
-func (f Form) NextBoundaryInString(s string, atEOF bool) int {
- return f.nextBoundary(inputString(s), len(s), atEOF)
-}
-
-func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int {
- if nsrc == 0 {
- if atEOF {
- return 0
- }
- return -1
- }
- fd := formTable[f]
- info := fd.info(src, 0)
- if info.size == 0 {
- if atEOF {
- return 1
- }
- return -1
- }
- ss := streamSafe(0)
- ss.first(info)
-
- for i := int(info.size); i < nsrc; i += int(info.size) {
- info = fd.info(src, i)
- if info.size == 0 {
- if atEOF {
- return i
- }
- return -1
- }
- if s := ss.next(info); s != ssSuccess {
- return i
- }
- }
- if !atEOF && !info.BoundaryAfter() && !ss.isMax() {
- return -1
- }
- return nsrc
-}
-
-// LastBoundary returns the position i of the last boundary in b
-// or -1 if b contains no boundary.
-func (f Form) LastBoundary(b []byte) int {
- return lastBoundary(formTable[f], b)
-}
-
-func lastBoundary(fd *formInfo, b []byte) int {
- i := len(b)
- info, p := lastRuneStart(fd, b)
- if p == -1 {
- return -1
- }
- if info.size == 0 { // ends with incomplete rune
- if p == 0 { // starts with incomplete rune
- return -1
- }
- i = p
- info, p = lastRuneStart(fd, b[:i])
- if p == -1 { // incomplete UTF-8 encoding or non-starter bytes without a starter
- return i
- }
- }
- if p+int(info.size) != i { // trailing non-starter bytes: illegal UTF-8
- return i
- }
- if info.BoundaryAfter() {
- return i
- }
- ss := streamSafe(0)
- v := ss.backwards(info)
- for i = p; i >= 0 && v != ssStarter; i = p {
- info, p = lastRuneStart(fd, b[:i])
- if v = ss.backwards(info); v == ssOverflow {
- break
- }
- if p+int(info.size) != i {
- if p == -1 { // no boundary found
- return -1
- }
- return i // boundary after an illegal UTF-8 encoding
- }
- }
- return i
-}
-
-// decomposeSegment scans the first segment in src into rb. It inserts 0x034f
-// (Grapheme Joiner) when it encounters a sequence of more than 30 non-starters
-// and returns the number of bytes consumed from src or iShortDst or iShortSrc.
-func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int {
- // Force one character to be consumed.
- info := rb.f.info(rb.src, sp)
- if info.size == 0 {
- return 0
- }
- if rb.nrune > 0 {
- if s := rb.ss.next(info); s == ssStarter {
- goto end
- } else if s == ssOverflow {
- rb.insertCGJ()
- goto end
- }
- } else {
- rb.ss.first(info)
- }
- if err := rb.insertFlush(rb.src, sp, info); err != iSuccess {
- return int(err)
- }
- for {
- sp += int(info.size)
- if sp >= rb.nsrc {
- if !atEOF && !info.BoundaryAfter() {
- return int(iShortSrc)
- }
- break
- }
- info = rb.f.info(rb.src, sp)
- if info.size == 0 {
- if !atEOF {
- return int(iShortSrc)
- }
- break
- }
- if s := rb.ss.next(info); s == ssStarter {
- break
- } else if s == ssOverflow {
- rb.insertCGJ()
- break
- }
- if err := rb.insertFlush(rb.src, sp, info); err != iSuccess {
- return int(err)
- }
- }
-end:
- if !rb.doFlush() {
- return int(iShortDst)
- }
- return sp
-}
-
-// lastRuneStart returns the runeInfo and position of the last
-// rune in buf or the zero runeInfo and -1 if no rune was found.
-func lastRuneStart(fd *formInfo, buf []byte) (Properties, int) {
- p := len(buf) - 1
- for ; p >= 0 && !utf8.RuneStart(buf[p]); p-- {
- }
- if p < 0 {
- return Properties{}, -1
- }
- return fd.info(inputBytes(buf), p), p
-}
-
-// decomposeToLastBoundary finds an open segment at the end of the buffer
-// and scans it into rb. Returns the buffer minus the last segment.
-func decomposeToLastBoundary(rb *reorderBuffer) {
- fd := &rb.f
- info, i := lastRuneStart(fd, rb.out)
- if int(info.size) != len(rb.out)-i {
- // illegal trailing continuation bytes
- return
- }
- if info.BoundaryAfter() {
- return
- }
- var add [maxNonStarters + 1]Properties // stores runeInfo in reverse order
- padd := 0
- ss := streamSafe(0)
- p := len(rb.out)
- for {
- add[padd] = info
- v := ss.backwards(info)
- if v == ssOverflow {
- // Note that if we have an overflow, it the string we are appending to
- // is not correctly normalized. In this case the behavior is undefined.
- break
- }
- padd++
- p -= int(info.size)
- if v == ssStarter || p < 0 {
- break
- }
- info, i = lastRuneStart(fd, rb.out[:p])
- if int(info.size) != p-i {
- break
- }
- }
- rb.ss = ss
- // Copy bytes for insertion as we may need to overwrite rb.out.
- var buf [maxBufferSize * utf8.UTFMax]byte
- cp := buf[:copy(buf[:], rb.out[p:])]
- rb.out = rb.out[:p]
- for padd--; padd >= 0; padd-- {
- info = add[padd]
- rb.insertUnsafe(inputBytes(cp), 0, info)
- cp = cp[info.size:]
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/normalize_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/normalize_test.go
deleted file mode 100644
index 04810e7..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/normalize_test.go
+++ /dev/null
@@ -1,1226 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package norm
-
-import (
- "bytes"
- "flag"
- "fmt"
- "io"
- "log"
- "strings"
- "testing"
- "unicode/utf8"
-
- "golang.org/x/text/internal/testtext"
- "golang.org/x/text/transform"
-)
-
-var (
- testn = flag.Int("testn", -1, "specific test number to run or -1 for all")
-)
-
-// pc replaces any rune r that is repeated n times, for n > 1, with r{n}.
-func pc(s string) []byte {
- b := bytes.NewBuffer(make([]byte, 0, len(s)))
- for i := 0; i < len(s); {
- r, sz := utf8.DecodeRuneInString(s[i:])
- n := 0
- if sz == 1 {
- // Special-case one-byte case to handle repetition for invalid UTF-8.
- for c := s[i]; i+n < len(s) && s[i+n] == c; n++ {
- }
- } else {
- for _, r2 := range s[i:] {
- if r2 != r {
- break
- }
- n++
- }
- }
- b.WriteString(s[i : i+sz])
- if n > 1 {
- fmt.Fprintf(b, "{%d}", n)
- }
- i += sz * n
- }
- return b.Bytes()
-}
-
-// pidx finds the index from which two strings start to differ, plus context.
-// It returns the index and ellipsis if the index is greater than 0.
-func pidx(a, b string) (i int, prefix string) {
- for ; i < len(a) && i < len(b) && a[i] == b[i]; i++ {
- }
- if i < 8 {
- return 0, ""
- }
- i -= 3 // ensure taking at least one full rune before the difference.
- for k := i - 7; i > k && !utf8.RuneStart(a[i]); i-- {
- }
- return i, "..."
-}
-
-type PositionTest struct {
- input string
- pos int
- buffer string // expected contents of reorderBuffer, if applicable
-}
-
-type positionFunc func(rb *reorderBuffer, s string) (int, []byte)
-
-func runPosTests(t *testing.T, name string, f Form, fn positionFunc, tests []PositionTest) {
- rb := reorderBuffer{}
- rb.init(f, nil)
- for i, test := range tests {
- rb.reset()
- rb.src = inputString(test.input)
- rb.nsrc = len(test.input)
- pos, out := fn(&rb, test.input)
- if pos != test.pos {
- t.Errorf("%s:%d: position is %d; want %d", name, i, pos, test.pos)
- }
- if outs := string(out); outs != test.buffer {
- k, pfx := pidx(outs, test.buffer)
- t.Errorf("%s:%d: buffer \nwas %s%+q; \nwant %s%+q", name, i, pfx, pc(outs[k:]), pfx, pc(test.buffer[k:]))
- }
- }
-}
-
-func grave(n int) string {
- return rep(0x0300, n)
-}
-
-func rep(r rune, n int) string {
- return strings.Repeat(string(r), n)
-}
-
-const segSize = maxByteBufferSize
-
-var cgj = GraphemeJoiner
-
-var decomposeSegmentTests = []PositionTest{
- // illegal runes
- {"\xC2", 0, ""},
- {"\xC0", 1, "\xC0"},
- {"\u00E0\x80", 2, "\u0061\u0300"},
- // starter
- {"a", 1, "a"},
- {"ab", 1, "a"},
- // starter + composing
- {"a\u0300", 3, "a\u0300"},
- {"a\u0300b", 3, "a\u0300"},
- // with decomposition
- {"\u00C0", 2, "A\u0300"},
- {"\u00C0b", 2, "A\u0300"},
- // long
- {grave(31), 60, grave(30) + cgj},
- {"a" + grave(31), 61, "a" + grave(30) + cgj},
-
- // Stability tests: see http://www.unicode.org/review/pr-29.html.
- // U+0300 COMBINING GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING GRAVE;;;;
- // U+0B47 ORIYA VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
- // U+0B3E ORIYA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
- // U+1100 HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;;;;
- // U+1161 HANGUL JUNGSEONG A;Lo;0;L;;;;;N;;;;;
- {"\u0B47\u0300\u0B3E", 8, "\u0B47\u0300\u0B3E"},
- {"\u1100\u0300\u1161", 8, "\u1100\u0300\u1161"},
- {"\u0B47\u0B3E", 6, "\u0B47\u0B3E"},
- {"\u1100\u1161", 6, "\u1100\u1161"},
-
- // U+04DA MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;;
- // Sequence of decomposing characters that are starters and modifiers.
- {"\u0d4a" + strings.Repeat("\u0d3e", 31), 90, "\u0d46" + strings.Repeat("\u0d3e", 30) + cgj},
-
- {grave(30), 60, grave(30)},
- // U+FF9E is a starter, but decomposes to U+3099, which is not.
- {grave(30) + "\uff9e", 60, grave(30) + cgj},
- // ends with incomplete UTF-8 encoding
- {"\xCC", 0, ""},
- {"\u0300\xCC", 2, "\u0300"},
-}
-
-func decomposeSegmentF(rb *reorderBuffer, s string) (int, []byte) {
- rb.initString(NFD, s)
- rb.setFlusher(nil, appendFlush)
- p := decomposeSegment(rb, 0, true)
- return p, rb.out
-}
-
-func TestDecomposeSegment(t *testing.T) {
- runPosTests(t, "TestDecomposeSegment", NFC, decomposeSegmentF, decomposeSegmentTests)
-}
-
-var firstBoundaryTests = []PositionTest{
- // no boundary
- {"", -1, ""},
- {"\u0300", -1, ""},
- {"\x80\x80", -1, ""},
- // illegal runes
- {"\xff", 0, ""},
- {"\u0300\xff", 2, ""},
- {"\u0300\xc0\x80\x80", 2, ""},
- // boundaries
- {"a", 0, ""},
- {"\u0300a", 2, ""},
- // Hangul
- {"\u1103\u1161", 0, ""},
- {"\u110B\u1173\u11B7", 0, ""},
- {"\u1161\u110B\u1173\u11B7", 3, ""},
- {"\u1173\u11B7\u1103\u1161", 6, ""},
- // too many combining characters.
- {grave(maxNonStarters - 1), -1, ""},
- {grave(maxNonStarters), 60, ""},
- {grave(maxNonStarters + 1), 60, ""},
-}
-
-func firstBoundaryF(rb *reorderBuffer, s string) (int, []byte) {
- return rb.f.form.FirstBoundary([]byte(s)), nil
-}
-
-func firstBoundaryStringF(rb *reorderBuffer, s string) (int, []byte) {
- return rb.f.form.FirstBoundaryInString(s), nil
-}
-
-func TestFirstBoundary(t *testing.T) {
- runPosTests(t, "TestFirstBoundary", NFC, firstBoundaryF, firstBoundaryTests)
- runPosTests(t, "TestFirstBoundaryInString", NFC, firstBoundaryStringF, firstBoundaryTests)
-}
-
-func TestNextBoundary(t *testing.T) {
- testCases := []struct {
- input string
- atEOF bool
- want int
- }{
- // no boundary
- {"", true, 0},
- {"", false, -1},
- {"\u0300", true, 2},
- {"\u0300", false, -1},
- {"\x80\x80", true, 1},
- {"\x80\x80", false, 1},
- // illegal runes
- {"\xff", false, 1},
- {"\u0300\xff", false, 2},
- {"\u0300\xc0\x80\x80", false, 2},
- {"\xc2\x80\x80", false, 2},
- {"\xc2", false, -1},
- {"\xc2", true, 1},
- {"a\u0300\xc2", false, -1},
- {"a\u0300\xc2", true, 3},
- // boundaries
- {"a", true, 1},
- {"a", false, -1},
- {"aa", false, 1},
- {"\u0300", true, 2},
- {"\u0300", false, -1},
- {"\u0300a", false, 2},
- // Hangul
- {"\u1103\u1161", true, 6},
- {"\u1103\u1161", false, -1},
- {"\u110B\u1173\u11B7", false, -1},
- {"\u110B\u1173\u11B7\u110B\u1173\u11B7", false, 9},
- {"\u1161\u110B\u1173\u11B7", false, 3},
- {"\u1173\u11B7\u1103\u1161", false, 6},
- // too many combining characters.
- {grave(maxNonStarters - 1), false, -1},
- {grave(maxNonStarters), false, 60},
- {grave(maxNonStarters + 1), false, 60},
- }
-
- for _, tc := range testCases {
- if got := NFC.NextBoundary([]byte(tc.input), tc.atEOF); got != tc.want {
- t.Errorf("NextBoundary(%+q, %v) = %d; want %d", tc.input, tc.atEOF, got, tc.want)
- }
- if got := NFC.NextBoundaryInString(tc.input, tc.atEOF); got != tc.want {
- t.Errorf("NextBoundaryInString(%+q, %v) = %d; want %d", tc.input, tc.atEOF, got, tc.want)
- }
- }
-}
-
-var decomposeToLastTests = []PositionTest{
- // ends with inert character
- {"Hello!", 6, ""},
- {"\u0632", 2, ""},
- {"a\u0301\u0635", 5, ""},
- // ends with non-inert starter
- {"a", 0, "a"},
- {"a\u0301a", 3, "a"},
- {"a\u0301\u03B9", 3, "\u03B9"},
- {"a\u0327", 0, "a\u0327"},
- // illegal runes
- {"\xFF", 1, ""},
- {"aa\xFF", 3, ""},
- {"\xC0\x80\x80", 3, ""},
- {"\xCC\x80\x80", 3, ""},
- // ends with incomplete UTF-8 encoding
- {"a\xCC", 2, ""},
- // ends with combining characters
- {"\u0300\u0301", 0, "\u0300\u0301"},
- {"a\u0300\u0301", 0, "a\u0300\u0301"},
- {"a\u0301\u0308", 0, "a\u0301\u0308"},
- {"a\u0308\u0301", 0, "a\u0308\u0301"},
- {"aaaa\u0300\u0301", 3, "a\u0300\u0301"},
- {"\u0300a\u0300\u0301", 2, "a\u0300\u0301"},
- {"\u00C0", 0, "A\u0300"},
- {"a\u00C0", 1, "A\u0300"},
- // decomposing
- {"a\u0300\u00E0", 3, "a\u0300"},
- // multisegment decompositions (flushes leading segments)
- {"a\u0300\uFDC0", 7, "\u064A"},
- {"\uFDC0" + grave(29), 4, "\u064A" + grave(29)},
- {"\uFDC0" + grave(30), 4, "\u064A" + grave(30)},
- {"\uFDC0" + grave(31), 5, grave(30)},
- {"\uFDFA" + grave(14), 31, "\u0645" + grave(14)},
- // Overflow
- {"\u00E0" + grave(29), 0, "a" + grave(30)},
- {"\u00E0" + grave(30), 2, grave(30)},
- // Hangul
- {"a\u1103", 1, "\u1103"},
- {"a\u110B", 1, "\u110B"},
- {"a\u110B\u1173", 1, "\u110B\u1173"},
- // See comment in composition.go:compBoundaryAfter.
- {"a\u110B\u1173\u11B7", 1, "\u110B\u1173\u11B7"},
- {"a\uC73C", 1, "\u110B\u1173"},
- {"다음", 3, "\u110B\u1173\u11B7"},
- {"다", 0, "\u1103\u1161"},
- {"\u1103\u1161\u110B\u1173\u11B7", 6, "\u110B\u1173\u11B7"},
- {"\u110B\u1173\u11B7\u1103\u1161", 9, "\u1103\u1161"},
- {"다음음", 6, "\u110B\u1173\u11B7"},
- {"음다다", 6, "\u1103\u1161"},
- // maximized buffer
- {"a" + grave(30), 0, "a" + grave(30)},
- // Buffer overflow
- {"a" + grave(31), 3, grave(30)},
- // weird UTF-8
- {"a\u0300\u11B7", 0, "a\u0300\u11B7"},
-}
-
-func decomposeToLast(rb *reorderBuffer, s string) (int, []byte) {
- rb.setFlusher([]byte(s), appendFlush)
- decomposeToLastBoundary(rb)
- buf := rb.flush(nil)
- return len(rb.out), buf
-}
-
-func TestDecomposeToLastBoundary(t *testing.T) {
- runPosTests(t, "TestDecomposeToLastBoundary", NFKC, decomposeToLast, decomposeToLastTests)
-}
-
-var lastBoundaryTests = []PositionTest{
- // ends with inert character
- {"Hello!", 6, ""},
- {"\u0632", 2, ""},
- // ends with non-inert starter
- {"a", 0, ""},
- // illegal runes
- {"\xff", 1, ""},
- {"aa\xff", 3, ""},
- {"a\xff\u0300", 1, ""}, // TODO: should probably be 2.
- {"\xc0\x80\x80", 3, ""},
- {"\xc0\x80\x80\u0300", 3, ""},
- // ends with incomplete UTF-8 encoding
- {"\xCC", -1, ""},
- {"\xE0\x80", -1, ""},
- {"\xF0\x80\x80", -1, ""},
- {"a\xCC", 0, ""},
- {"\x80\xCC", 1, ""},
- {"\xCC\xCC", 1, ""},
- // ends with combining characters
- {"a\u0300\u0301", 0, ""},
- {"aaaa\u0300\u0301", 3, ""},
- {"\u0300a\u0300\u0301", 2, ""},
- {"\u00C2", 0, ""},
- {"a\u00C2", 1, ""},
- // decomposition may recombine
- {"\u0226", 0, ""},
- // no boundary
- {"", -1, ""},
- {"\u0300\u0301", -1, ""},
- {"\u0300", -1, ""},
- {"\x80\x80", -1, ""},
- {"\x80\x80\u0301", -1, ""},
- // Hangul
- {"다음", 3, ""},
- {"다", 0, ""},
- {"\u1103\u1161\u110B\u1173\u11B7", 6, ""},
- {"\u110B\u1173\u11B7\u1103\u1161", 9, ""},
- // too many combining characters.
- {grave(maxNonStarters - 1), -1, ""},
- // May still be preceded with a non-starter.
- {grave(maxNonStarters), -1, ""},
- // May still need to insert a cgj after the last combiner.
- {grave(maxNonStarters + 1), 2, ""},
- {grave(maxNonStarters + 2), 4, ""},
-
- {"a" + grave(maxNonStarters-1), 0, ""},
- {"a" + grave(maxNonStarters), 0, ""},
- // May still need to insert a cgj after the last combiner.
- {"a" + grave(maxNonStarters+1), 3, ""},
- {"a" + grave(maxNonStarters+2), 5, ""},
-}
-
-func lastBoundaryF(rb *reorderBuffer, s string) (int, []byte) {
- return rb.f.form.LastBoundary([]byte(s)), nil
-}
-
-func TestLastBoundary(t *testing.T) {
- runPosTests(t, "TestLastBoundary", NFC, lastBoundaryF, lastBoundaryTests)
-}
-
-type spanTest struct {
- input string
- atEOF bool
- n int
- err error
-}
-
-var quickSpanTests = []spanTest{
- {"", true, 0, nil},
- // starters
- {"a", true, 1, nil},
- {"abc", true, 3, nil},
- {"\u043Eb", true, 3, nil},
- // incomplete last rune.
- {"\xCC", true, 1, nil},
- {"\xCC", false, 0, transform.ErrShortSrc},
- {"a\xCC", true, 2, nil},
- {"a\xCC", false, 0, transform.ErrShortSrc}, // TODO: could be 1 for NFD
- // incorrectly ordered combining characters
- {"\u0300\u0316", true, 0, transform.ErrEndOfSpan},
- {"\u0300\u0316", false, 0, transform.ErrEndOfSpan},
- {"\u0300\u0316cd", true, 0, transform.ErrEndOfSpan},
- {"\u0300\u0316cd", false, 0, transform.ErrEndOfSpan},
- // have a maximum number of combining characters.
- {rep(0x035D, 30) + "\u035B", true, 0, transform.ErrEndOfSpan},
- {"a" + rep(0x035D, 30) + "\u035B", true, 0, transform.ErrEndOfSpan},
- {"Ɵ" + rep(0x035D, 30) + "\u035B", true, 0, transform.ErrEndOfSpan},
- {"aa" + rep(0x035D, 30) + "\u035B", true, 1, transform.ErrEndOfSpan},
- {rep(0x035D, 30) + cgj + "\u035B", true, 64, nil},
- {"a" + rep(0x035D, 30) + cgj + "\u035B", true, 65, nil},
- {"Ɵ" + rep(0x035D, 30) + cgj + "\u035B", true, 66, nil},
- {"aa" + rep(0x035D, 30) + cgj + "\u035B", true, 66, nil},
-
- {"a" + rep(0x035D, 30) + cgj + "\u035B", false, 61, transform.ErrShortSrc},
- {"Ɵ" + rep(0x035D, 30) + cgj + "\u035B", false, 62, transform.ErrShortSrc},
- {"aa" + rep(0x035D, 30) + cgj + "\u035B", false, 62, transform.ErrShortSrc},
-}
-
-var quickSpanNFDTests = []spanTest{
- // needs decomposing
- {"\u00C0", true, 0, transform.ErrEndOfSpan},
- {"abc\u00C0", true, 3, transform.ErrEndOfSpan},
- // correctly ordered combining characters
- {"\u0300", true, 2, nil},
- {"ab\u0300", true, 4, nil},
- {"ab\u0300cd", true, 6, nil},
- {"\u0300cd", true, 4, nil},
- {"\u0316\u0300", true, 4, nil},
- {"ab\u0316\u0300", true, 6, nil},
- {"ab\u0316\u0300cd", true, 8, nil},
- {"ab\u0316\u0300\u00C0", true, 6, transform.ErrEndOfSpan},
- {"\u0316\u0300cd", true, 6, nil},
- {"\u043E\u0308b", true, 5, nil},
- // incorrectly ordered combining characters
- {"ab\u0300\u0316", true, 1, transform.ErrEndOfSpan}, // TODO: we could skip 'b' as well.
- {"ab\u0300\u0316cd", true, 1, transform.ErrEndOfSpan},
- // Hangul
- {"같은", true, 0, transform.ErrEndOfSpan},
-}
-
-var quickSpanNFCTests = []spanTest{
- // okay composed
- {"\u00C0", true, 2, nil},
- {"abc\u00C0", true, 5, nil},
- // correctly ordered combining characters
- // TODO: b may combine with modifiers, which is why this fails. We could
- // make a more precise test that that actually checks whether last
- // characters combines. Probably not worth it.
- {"ab\u0300", true, 1, transform.ErrEndOfSpan},
- {"ab\u0300cd", true, 1, transform.ErrEndOfSpan},
- {"ab\u0316\u0300", true, 1, transform.ErrEndOfSpan},
- {"ab\u0316\u0300cd", true, 1, transform.ErrEndOfSpan},
- {"\u00C0\u035D", true, 4, nil},
- // we do not special case leading combining characters
- {"\u0300cd", true, 0, transform.ErrEndOfSpan},
- {"\u0300", true, 0, transform.ErrEndOfSpan},
- {"\u0316\u0300", true, 0, transform.ErrEndOfSpan},
- {"\u0316\u0300cd", true, 0, transform.ErrEndOfSpan},
- // incorrectly ordered combining characters
- {"ab\u0300\u0316", true, 1, transform.ErrEndOfSpan},
- {"ab\u0300\u0316cd", true, 1, transform.ErrEndOfSpan},
- // Hangul
- {"같은", true, 6, nil},
- {"같은", false, 3, transform.ErrShortSrc},
- // We return the start of the violating segment in case of overflow.
- {grave(30) + "\uff9e", true, 0, transform.ErrEndOfSpan},
- {grave(30), true, 0, transform.ErrEndOfSpan},
-}
-
-func runSpanTests(t *testing.T, name string, f Form, testCases []spanTest) {
- for i, tc := range testCases {
- s := fmt.Sprintf("Bytes/%s/%d=%+q/atEOF=%v", name, i, pc(tc.input), tc.atEOF)
- ok := testtext.Run(t, s, func(t *testing.T) {
- n, err := f.Span([]byte(tc.input), tc.atEOF)
- if n != tc.n || err != tc.err {
- t.Errorf("\n got %d, %v;\nwant %d, %v", n, err, tc.n, tc.err)
- }
- })
- if !ok {
- continue // Don't do the String variant if the Bytes variant failed.
- }
- s = fmt.Sprintf("String/%s/%d=%+q/atEOF=%v", name, i, pc(tc.input), tc.atEOF)
- testtext.Run(t, s, func(t *testing.T) {
- n, err := f.SpanString(tc.input, tc.atEOF)
- if n != tc.n || err != tc.err {
- t.Errorf("\n got %d, %v;\nwant %d, %v", n, err, tc.n, tc.err)
- }
- })
- }
-}
-
-func TestSpan(t *testing.T) {
- runSpanTests(t, "NFD", NFD, quickSpanTests)
- runSpanTests(t, "NFD", NFD, quickSpanNFDTests)
- runSpanTests(t, "NFC", NFC, quickSpanTests)
- runSpanTests(t, "NFC", NFC, quickSpanNFCTests)
-}
-
-var isNormalTests = []PositionTest{
- {"", 1, ""},
- // illegal runes
- {"\xff", 1, ""},
- // starters
- {"a", 1, ""},
- {"abc", 1, ""},
- {"\u043Eb", 1, ""},
- // incorrectly ordered combining characters
- {"\u0300\u0316", 0, ""},
- {"ab\u0300\u0316", 0, ""},
- {"ab\u0300\u0316cd", 0, ""},
- {"\u0300\u0316cd", 0, ""},
-}
-var isNormalNFDTests = []PositionTest{
- // needs decomposing
- {"\u00C0", 0, ""},
- {"abc\u00C0", 0, ""},
- // correctly ordered combining characters
- {"\u0300", 1, ""},
- {"ab\u0300", 1, ""},
- {"ab\u0300cd", 1, ""},
- {"\u0300cd", 1, ""},
- {"\u0316\u0300", 1, ""},
- {"ab\u0316\u0300", 1, ""},
- {"ab\u0316\u0300cd", 1, ""},
- {"\u0316\u0300cd", 1, ""},
- {"\u043E\u0308b", 1, ""},
- // Hangul
- {"같은", 0, ""},
-}
-var isNormalNFCTests = []PositionTest{
- // okay composed
- {"\u00C0", 1, ""},
- {"abc\u00C0", 1, ""},
- // need reordering
- {"a\u0300", 0, ""},
- {"a\u0300cd", 0, ""},
- {"a\u0316\u0300", 0, ""},
- {"a\u0316\u0300cd", 0, ""},
- // correctly ordered combining characters
- {"ab\u0300", 1, ""},
- {"ab\u0300cd", 1, ""},
- {"ab\u0316\u0300", 1, ""},
- {"ab\u0316\u0300cd", 1, ""},
- {"\u00C0\u035D", 1, ""},
- {"\u0300", 1, ""},
- {"\u0316\u0300cd", 1, ""},
- // Hangul
- {"같은", 1, ""},
-}
-
-var isNormalNFKXTests = []PositionTest{
- // Special case.
- {"\u00BC", 0, ""},
-}
-
-func isNormalF(rb *reorderBuffer, s string) (int, []byte) {
- if rb.f.form.IsNormal([]byte(s)) {
- return 1, nil
- }
- return 0, nil
-}
-
-func isNormalStringF(rb *reorderBuffer, s string) (int, []byte) {
- if rb.f.form.IsNormalString(s) {
- return 1, nil
- }
- return 0, nil
-}
-
-func TestIsNormal(t *testing.T) {
- runPosTests(t, "TestIsNormalNFD1", NFD, isNormalF, isNormalTests)
- runPosTests(t, "TestIsNormalNFD2", NFD, isNormalF, isNormalNFDTests)
- runPosTests(t, "TestIsNormalNFC1", NFC, isNormalF, isNormalTests)
- runPosTests(t, "TestIsNormalNFC2", NFC, isNormalF, isNormalNFCTests)
- runPosTests(t, "TestIsNormalNFKD1", NFKD, isNormalF, isNormalTests)
- runPosTests(t, "TestIsNormalNFKD2", NFKD, isNormalF, isNormalNFDTests)
- runPosTests(t, "TestIsNormalNFKD3", NFKD, isNormalF, isNormalNFKXTests)
- runPosTests(t, "TestIsNormalNFKC1", NFKC, isNormalF, isNormalTests)
- runPosTests(t, "TestIsNormalNFKC2", NFKC, isNormalF, isNormalNFCTests)
- runPosTests(t, "TestIsNormalNFKC3", NFKC, isNormalF, isNormalNFKXTests)
-}
-
-func TestIsNormalString(t *testing.T) {
- runPosTests(t, "TestIsNormalNFD1", NFD, isNormalStringF, isNormalTests)
- runPosTests(t, "TestIsNormalNFD2", NFD, isNormalStringF, isNormalNFDTests)
- runPosTests(t, "TestIsNormalNFC1", NFC, isNormalStringF, isNormalTests)
- runPosTests(t, "TestIsNormalNFC2", NFC, isNormalStringF, isNormalNFCTests)
-}
-
-type AppendTest struct {
- left string
- right string
- out string
-}
-
-type appendFunc func(f Form, out []byte, s string) []byte
-
-var fstr = []string{"NFC", "NFD", "NFKC", "NFKD"}
-
-func runNormTests(t *testing.T, name string, fn appendFunc) {
- for f := NFC; f <= NFKD; f++ {
- runAppendTests(t, name, f, fn, normTests[f])
- }
-}
-
-func runAppendTests(t *testing.T, name string, f Form, fn appendFunc, tests []AppendTest) {
- for i, test := range tests {
- if *testn >= 0 && i != *testn {
- continue
- }
- out := []byte(test.left)
- have := string(fn(f, out, test.right))
- if len(have) != len(test.out) {
- t.Errorf("%s.%s:%d: length is %d; want %d (%+q vs %+q)", fstr[f], name, i, len(have), len(test.out), pc(have), pc(test.out))
- }
- if have != test.out {
- k, pf := pidx(have, test.out)
- t.Errorf("%s.%s:%d: \nwas %s%+q; \nwant %s%+q", fstr[f], name, i, pf, pc(have[k:]), pf, pc(test.out[k:]))
- }
-
- // Bootstrap by normalizing input. Ensures that the various variants
- // behave the same.
- for g := NFC; g <= NFKD; g++ {
- if f == g {
- continue
- }
- want := g.String(test.left + test.right)
- have := string(fn(g, g.AppendString(nil, test.left), test.right))
- if len(have) != len(want) {
- t.Errorf("%s(%s.%s):%d: length is %d; want %d (%+q vs %+q)", fstr[g], fstr[f], name, i, len(have), len(want), pc(have), pc(want))
- }
- if have != want {
- k, pf := pidx(have, want)
- t.Errorf("%s(%s.%s):%d: \nwas %s%+q; \nwant %s%+q", fstr[g], fstr[f], name, i, pf, pc(have[k:]), pf, pc(want[k:]))
- }
- }
- }
-}
-
-var normTests = [][]AppendTest{
- appendTestsNFC,
- appendTestsNFD,
- appendTestsNFKC,
- appendTestsNFKD,
-}
-
-var appendTestsNFC = []AppendTest{
- {"", ascii, ascii},
- {"", txt_all, txt_all},
- {"\uff9e", grave(30), "\uff9e" + grave(29) + cgj + grave(1)},
- {grave(30), "\uff9e", grave(30) + cgj + "\uff9e"},
-
- // Tests designed for Iter.
- { // ordering of non-composing combining characters
- "",
- "\u0305\u0316",
- "\u0316\u0305",
- },
- { // segment overflow
- "",
- "a" + rep(0x0305, maxNonStarters+4) + "\u0316",
- "a" + rep(0x0305, maxNonStarters) + cgj + "\u0316" + rep(0x305, 4),
- },
-
- { // Combine across non-blocking non-starters.
- // U+0327 COMBINING CEDILLA;Mn;202;NSM;;;;;N;NON-SPACING CEDILLA;;;;
- // U+0325 COMBINING RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RING BELOW;;;;
- "", "a\u0327\u0325", "\u1e01\u0327",
- },
-
- { // Jamo V+T does not combine.
- "",
- "\u1161\u11a8",
- "\u1161\u11a8",
- },
-
- // Stability tests: see http://www.unicode.org/review/pr-29.html.
- {"", "\u0b47\u0300\u0b3e", "\u0b47\u0300\u0b3e"},
- {"", "\u1100\u0300\u1161", "\u1100\u0300\u1161"},
- {"", "\u0b47\u0b3e", "\u0b4b"},
- {"", "\u1100\u1161", "\uac00"},
-
- // U+04DA MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;;
- { // 0d4a starts a new segment.
- "",
- "\u0d4a" + strings.Repeat("\u0d3e", 15) + "\u0d4a" + strings.Repeat("\u0d3e", 15),
- "\u0d4a" + strings.Repeat("\u0d3e", 15) + "\u0d4a" + strings.Repeat("\u0d3e", 15),
- },
-
- { // Split combining characters.
- // TODO: don't insert CGJ before starters.
- "",
- "\u0d46" + strings.Repeat("\u0d3e", 31),
- "\u0d4a" + strings.Repeat("\u0d3e", 29) + cgj + "\u0d3e",
- },
-
- { // Split combining characters.
- "",
- "\u0d4a" + strings.Repeat("\u0d3e", 30),
- "\u0d4a" + strings.Repeat("\u0d3e", 29) + cgj + "\u0d3e",
- },
-}
-
-var appendTestsNFD = []AppendTest{
-// TODO: Move some of the tests here.
-}
-
-var appendTestsNFKC = []AppendTest{
- // empty buffers
- {"", "", ""},
- {"a", "", "a"},
- {"", "a", "a"},
- {"", "\u0041\u0307\u0304", "\u01E0"},
- // segment split across buffers
- {"", "a\u0300b", "\u00E0b"},
- {"a", "\u0300b", "\u00E0b"},
- {"a", "\u0300\u0316", "\u00E0\u0316"},
- {"a", "\u0316\u0300", "\u00E0\u0316"},
- {"a", "\u0300a\u0300", "\u00E0\u00E0"},
- {"a", "\u0300a\u0300a\u0300", "\u00E0\u00E0\u00E0"},
- {"a", "\u0300aaa\u0300aaa\u0300", "\u00E0aa\u00E0aa\u00E0"},
- {"a\u0300", "\u0327", "\u00E0\u0327"},
- {"a\u0327", "\u0300", "\u00E0\u0327"},
- {"a\u0316", "\u0300", "\u00E0\u0316"},
- {"\u0041\u0307", "\u0304", "\u01E0"},
- // Hangul
- {"", "\u110B\u1173", "\uC73C"},
- {"", "\u1103\u1161", "\uB2E4"},
- {"", "\u110B\u1173\u11B7", "\uC74C"},
- {"", "\u320E", "\x28\uAC00\x29"},
- {"", "\x28\u1100\u1161\x29", "\x28\uAC00\x29"},
- {"\u1103", "\u1161", "\uB2E4"},
- {"\u110B", "\u1173\u11B7", "\uC74C"},
- {"\u110B\u1173", "\u11B7", "\uC74C"},
- {"\uC73C", "\u11B7", "\uC74C"},
- // UTF-8 encoding split across buffers
- {"a\xCC", "\x80", "\u00E0"},
- {"a\xCC", "\x80b", "\u00E0b"},
- {"a\xCC", "\x80a\u0300", "\u00E0\u00E0"},
- {"a\xCC", "\x80\x80", "\u00E0\x80"},
- {"a\xCC", "\x80\xCC", "\u00E0\xCC"},
- {"a\u0316\xCC", "\x80a\u0316\u0300", "\u00E0\u0316\u00E0\u0316"},
- // ending in incomplete UTF-8 encoding
- {"", "\xCC", "\xCC"},
- {"a", "\xCC", "a\xCC"},
- {"a", "b\xCC", "ab\xCC"},
- {"\u0226", "\xCC", "\u0226\xCC"},
- // illegal runes
- {"", "\x80", "\x80"},
- {"", "\x80\x80\x80", "\x80\x80\x80"},
- {"", "\xCC\x80\x80\x80", "\xCC\x80\x80\x80"},
- {"", "a\x80", "a\x80"},
- {"", "a\x80\x80\x80", "a\x80\x80\x80"},
- {"", "a\x80\x80\x80\x80\x80\x80", "a\x80\x80\x80\x80\x80\x80"},
- {"a", "\x80\x80\x80", "a\x80\x80\x80"},
- // overflow
- {"", strings.Repeat("\x80", 33), strings.Repeat("\x80", 33)},
- {strings.Repeat("\x80", 33), "", strings.Repeat("\x80", 33)},
- {strings.Repeat("\x80", 33), strings.Repeat("\x80", 33), strings.Repeat("\x80", 66)},
- // overflow of combining characters
- {"", grave(34), grave(30) + cgj + grave(4)},
- {"", grave(36), grave(30) + cgj + grave(6)},
- {grave(29), grave(5), grave(30) + cgj + grave(4)},
- {grave(30), grave(4), grave(30) + cgj + grave(4)},
- {grave(30), grave(3), grave(30) + cgj + grave(3)},
- {grave(30) + "\xCC", "\x80", grave(30) + cgj + grave(1)},
- {"", "\uFDFA" + grave(14), "\u0635\u0644\u0649 \u0627\u0644\u0644\u0647 \u0639\u0644\u064a\u0647 \u0648\u0633\u0644\u0645" + grave(14)},
- {"", "\uFDFA" + grave(28) + "\u0316", "\u0635\u0644\u0649 \u0627\u0644\u0644\u0647 \u0639\u0644\u064a\u0647 \u0648\u0633\u0644\u0645\u0316" + grave(28)},
- // - First rune has a trailing non-starter.
- {"\u00d5", grave(30), "\u00d5" + grave(29) + cgj + grave(1)},
- // - U+FF9E decomposes into a non-starter in compatibility mode. A CGJ must be
- // inserted even when FF9E starts a new segment.
- {"\uff9e", grave(30), "\u3099" + grave(29) + cgj + grave(1)},
- {grave(30), "\uff9e", grave(30) + cgj + "\u3099"},
- // - Many non-starter decompositions in a row causing overflow.
- {"", rep(0x340, 31), rep(0x300, 30) + cgj + "\u0300"},
- {"", rep(0xFF9E, 31), rep(0x3099, 30) + cgj + "\u3099"},
- // weird UTF-8
- {"\u00E0\xE1", "\x86", "\u00E0\xE1\x86"},
- {"a\u0300\u11B7", "\u0300", "\u00E0\u11B7\u0300"},
- {"a\u0300\u11B7\u0300", "\u0300", "\u00E0\u11B7\u0300\u0300"},
- {"\u0300", "\xF8\x80\x80\x80\x80\u0300", "\u0300\xF8\x80\x80\x80\x80\u0300"},
- {"\u0300", "\xFC\x80\x80\x80\x80\x80\u0300", "\u0300\xFC\x80\x80\x80\x80\x80\u0300"},
- {"\xF8\x80\x80\x80\x80\u0300", "\u0300", "\xF8\x80\x80\x80\x80\u0300\u0300"},
- {"\xFC\x80\x80\x80\x80\x80\u0300", "\u0300", "\xFC\x80\x80\x80\x80\x80\u0300\u0300"},
- {"\xF8\x80\x80\x80", "\x80\u0300\u0300", "\xF8\x80\x80\x80\x80\u0300\u0300"},
-
- {"", strings.Repeat("a\u0316\u0300", 6), strings.Repeat("\u00E0\u0316", 6)},
- // large input.
- {"", strings.Repeat("a\u0300\u0316", 4000), strings.Repeat("\u00E0\u0316", 4000)},
- {"", strings.Repeat("\x80\x80", 4000), strings.Repeat("\x80\x80", 4000)},
- {"", "\u0041\u0307\u0304", "\u01E0"},
-}
-
-var appendTestsNFKD = []AppendTest{
- {"", "a" + grave(64), "a" + grave(30) + cgj + grave(30) + cgj + grave(4)},
-
- { // segment overflow on unchanged character
- "",
- "a" + grave(64) + "\u0316",
- "a" + grave(30) + cgj + grave(30) + cgj + "\u0316" + grave(4),
- },
- { // segment overflow on unchanged character + start value
- "",
- "a" + grave(98) + "\u0316",
- "a" + grave(30) + cgj + grave(30) + cgj + grave(30) + cgj + "\u0316" + grave(8),
- },
- { // segment overflow on decomposition. (U+0340 decomposes to U+0300.)
- "",
- "a" + grave(59) + "\u0340",
- "a" + grave(30) + cgj + grave(30),
- },
- { // segment overflow on non-starter decomposition
- "",
- "a" + grave(33) + "\u0340" + grave(30) + "\u0320",
- "a" + grave(30) + cgj + grave(30) + cgj + "\u0320" + grave(4),
- },
- { // start value after ASCII overflow
- "",
- rep('a', segSize) + grave(32) + "\u0320",
- rep('a', segSize) + grave(30) + cgj + "\u0320" + grave(2),
- },
- { // Jamo overflow
- "",
- "\u1100\u1161" + grave(30) + "\u0320" + grave(2),
- "\u1100\u1161" + grave(29) + cgj + "\u0320" + grave(3),
- },
- { // Hangul
- "",
- "\uac00",
- "\u1100\u1161",
- },
- { // Hangul overflow
- "",
- "\uac00" + grave(32) + "\u0320",
- "\u1100\u1161" + grave(29) + cgj + "\u0320" + grave(3),
- },
- { // Hangul overflow in Hangul mode.
- "",
- "\uac00\uac00" + grave(32) + "\u0320",
- "\u1100\u1161\u1100\u1161" + grave(29) + cgj + "\u0320" + grave(3),
- },
- { // Hangul overflow in Hangul mode.
- "",
- strings.Repeat("\uac00", 3) + grave(32) + "\u0320",
- strings.Repeat("\u1100\u1161", 3) + grave(29) + cgj + "\u0320" + grave(3),
- },
- { // start value after cc=0
- "",
- "您您" + grave(34) + "\u0320",
- "您您" + grave(30) + cgj + "\u0320" + grave(4),
- },
- { // start value after normalization
- "",
- "\u0300\u0320a" + grave(34) + "\u0320",
- "\u0320\u0300a" + grave(30) + cgj + "\u0320" + grave(4),
- },
-}
-
-func TestAppend(t *testing.T) {
- runNormTests(t, "Append", func(f Form, out []byte, s string) []byte {
- return f.Append(out, []byte(s)...)
- })
-}
-
-func TestAppendString(t *testing.T) {
- runNormTests(t, "AppendString", func(f Form, out []byte, s string) []byte {
- return f.AppendString(out, s)
- })
-}
-
-func TestBytes(t *testing.T) {
- runNormTests(t, "Bytes", func(f Form, out []byte, s string) []byte {
- buf := []byte{}
- buf = append(buf, out...)
- buf = append(buf, s...)
- return f.Bytes(buf)
- })
-}
-
-func TestString(t *testing.T) {
- runNormTests(t, "String", func(f Form, out []byte, s string) []byte {
- outs := string(out) + s
- return []byte(f.String(outs))
- })
-}
-
-func appendBench(f Form, in []byte) func() {
- buf := make([]byte, 0, 4*len(in))
- return func() {
- f.Append(buf, in...)
- }
-}
-
-func bytesBench(f Form, in []byte) func() {
- return func() {
- f.Bytes(in)
- }
-}
-
-func iterBench(f Form, in []byte) func() {
- iter := Iter{}
- return func() {
- iter.Init(f, in)
- for !iter.Done() {
- iter.Next()
- }
- }
-}
-
-func transformBench(f Form, in []byte) func() {
- buf := make([]byte, 4*len(in))
- return func() {
- if _, n, err := f.Transform(buf, in, true); err != nil || len(in) != n {
- log.Panic(n, len(in), err)
- }
- }
-}
-
-func readerBench(f Form, in []byte) func() {
- buf := make([]byte, 4*len(in))
- return func() {
- r := f.Reader(bytes.NewReader(in))
- var err error
- for err == nil {
- _, err = r.Read(buf)
- }
- if err != io.EOF {
- panic("")
- }
- }
-}
-
-func writerBench(f Form, in []byte) func() {
- buf := make([]byte, 0, 4*len(in))
- return func() {
- r := f.Writer(bytes.NewBuffer(buf))
- if _, err := r.Write(in); err != nil {
- panic("")
- }
- }
-}
-
-func appendBenchmarks(bm []func(), f Form, in []byte) []func() {
- bm = append(bm, appendBench(f, in))
- bm = append(bm, iterBench(f, in))
- bm = append(bm, transformBench(f, in))
- bm = append(bm, readerBench(f, in))
- bm = append(bm, writerBench(f, in))
- return bm
-}
-
-func doFormBenchmark(b *testing.B, inf, f Form, s string) {
- b.StopTimer()
- in := inf.Bytes([]byte(s))
- bm := appendBenchmarks(nil, f, in)
- b.SetBytes(int64(len(in) * len(bm)))
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- for _, fn := range bm {
- fn()
- }
- }
-}
-
-func doSingle(b *testing.B, f func(Form, []byte) func(), s []byte) {
- b.StopTimer()
- fn := f(NFC, s)
- b.SetBytes(int64(len(s)))
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- fn()
- }
-}
-
-var (
- smallNoChange = []byte("nörmalization")
- smallChange = []byte("No\u0308rmalization")
- ascii = strings.Repeat("There is nothing to change here! ", 500)
-)
-
-func lowerBench(f Form, in []byte) func() {
- // Use package strings instead of bytes as it doesn't allocate memory
- // if there aren't any changes.
- s := string(in)
- return func() {
- strings.ToLower(s)
- }
-}
-
-func BenchmarkLowerCaseNoChange(b *testing.B) {
- doSingle(b, lowerBench, smallNoChange)
-}
-func BenchmarkLowerCaseChange(b *testing.B) {
- doSingle(b, lowerBench, smallChange)
-}
-
-func quickSpanBench(f Form, in []byte) func() {
- return func() {
- f.QuickSpan(in)
- }
-}
-
-func BenchmarkQuickSpanChangeNFC(b *testing.B) {
- doSingle(b, quickSpanBench, smallNoChange)
-}
-
-func BenchmarkBytesNoChangeNFC(b *testing.B) {
- doSingle(b, bytesBench, smallNoChange)
-}
-func BenchmarkBytesChangeNFC(b *testing.B) {
- doSingle(b, bytesBench, smallChange)
-}
-
-func BenchmarkAppendNoChangeNFC(b *testing.B) {
- doSingle(b, appendBench, smallNoChange)
-}
-func BenchmarkAppendChangeNFC(b *testing.B) {
- doSingle(b, appendBench, smallChange)
-}
-func BenchmarkAppendLargeNFC(b *testing.B) {
- doSingle(b, appendBench, txt_all_bytes)
-}
-
-func BenchmarkIterNoChangeNFC(b *testing.B) {
- doSingle(b, iterBench, smallNoChange)
-}
-func BenchmarkIterChangeNFC(b *testing.B) {
- doSingle(b, iterBench, smallChange)
-}
-func BenchmarkIterLargeNFC(b *testing.B) {
- doSingle(b, iterBench, txt_all_bytes)
-}
-
-func BenchmarkTransformNoChangeNFC(b *testing.B) {
- doSingle(b, transformBench, smallNoChange)
-}
-func BenchmarkTransformChangeNFC(b *testing.B) {
- doSingle(b, transformBench, smallChange)
-}
-func BenchmarkTransformLargeNFC(b *testing.B) {
- doSingle(b, transformBench, txt_all_bytes)
-}
-
-func BenchmarkNormalizeAsciiNFC(b *testing.B) {
- doFormBenchmark(b, NFC, NFC, ascii)
-}
-func BenchmarkNormalizeAsciiNFD(b *testing.B) {
- doFormBenchmark(b, NFC, NFD, ascii)
-}
-func BenchmarkNormalizeAsciiNFKC(b *testing.B) {
- doFormBenchmark(b, NFC, NFKC, ascii)
-}
-func BenchmarkNormalizeAsciiNFKD(b *testing.B) {
- doFormBenchmark(b, NFC, NFKD, ascii)
-}
-
-func BenchmarkNormalizeNFC2NFC(b *testing.B) {
- doFormBenchmark(b, NFC, NFC, txt_all)
-}
-func BenchmarkNormalizeNFC2NFD(b *testing.B) {
- doFormBenchmark(b, NFC, NFD, txt_all)
-}
-func BenchmarkNormalizeNFD2NFC(b *testing.B) {
- doFormBenchmark(b, NFD, NFC, txt_all)
-}
-func BenchmarkNormalizeNFD2NFD(b *testing.B) {
- doFormBenchmark(b, NFD, NFD, txt_all)
-}
-
-// Hangul is often special-cased, so we test it separately.
-func BenchmarkNormalizeHangulNFC2NFC(b *testing.B) {
- doFormBenchmark(b, NFC, NFC, txt_kr)
-}
-func BenchmarkNormalizeHangulNFC2NFD(b *testing.B) {
- doFormBenchmark(b, NFC, NFD, txt_kr)
-}
-func BenchmarkNormalizeHangulNFD2NFC(b *testing.B) {
- doFormBenchmark(b, NFD, NFC, txt_kr)
-}
-func BenchmarkNormalizeHangulNFD2NFD(b *testing.B) {
- doFormBenchmark(b, NFD, NFD, txt_kr)
-}
-
-var forms = []Form{NFC, NFD, NFKC, NFKD}
-
-func doTextBenchmark(b *testing.B, s string) {
- b.StopTimer()
- in := []byte(s)
- bm := []func(){}
- for _, f := range forms {
- bm = appendBenchmarks(bm, f, in)
- }
- b.SetBytes(int64(len(s) * len(bm)))
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- for _, f := range bm {
- f()
- }
- }
-}
-
-func BenchmarkCanonicalOrdering(b *testing.B) {
- doTextBenchmark(b, txt_canon)
-}
-func BenchmarkExtendedLatin(b *testing.B) {
- doTextBenchmark(b, txt_vn)
-}
-func BenchmarkMiscTwoByteUtf8(b *testing.B) {
- doTextBenchmark(b, twoByteUtf8)
-}
-func BenchmarkMiscThreeByteUtf8(b *testing.B) {
- doTextBenchmark(b, threeByteUtf8)
-}
-func BenchmarkHangul(b *testing.B) {
- doTextBenchmark(b, txt_kr)
-}
-func BenchmarkJapanese(b *testing.B) {
- doTextBenchmark(b, txt_jp)
-}
-func BenchmarkChinese(b *testing.B) {
- doTextBenchmark(b, txt_cn)
-}
-func BenchmarkOverflow(b *testing.B) {
- doTextBenchmark(b, overflow)
-}
-
-var overflow = string(bytes.Repeat([]byte("\u035D"), 4096)) + "\u035B"
-
-// Tests sampled from the Canonical ordering tests (Part 2) of
-// http://unicode.org/Public/UNIDATA/NormalizationTest.txt
-const txt_canon = `\u0061\u0315\u0300\u05AE\u0300\u0062 \u0061\u0300\u0315\u0300\u05AE\u0062
-\u0061\u0302\u0315\u0300\u05AE\u0062 \u0061\u0307\u0315\u0300\u05AE\u0062
-\u0061\u0315\u0300\u05AE\u030A\u0062 \u0061\u059A\u0316\u302A\u031C\u0062
-\u0061\u032E\u059A\u0316\u302A\u0062 \u0061\u0338\u093C\u0334\u0062
-\u0061\u059A\u0316\u302A\u0339 \u0061\u0341\u0315\u0300\u05AE\u0062
-\u0061\u0348\u059A\u0316\u302A\u0062 \u0061\u0361\u0345\u035D\u035C\u0062
-\u0061\u0366\u0315\u0300\u05AE\u0062 \u0061\u0315\u0300\u05AE\u0486\u0062
-\u0061\u05A4\u059A\u0316\u302A\u0062 \u0061\u0315\u0300\u05AE\u0613\u0062
-\u0061\u0315\u0300\u05AE\u0615\u0062 \u0061\u0617\u0315\u0300\u05AE\u0062
-\u0061\u0619\u0618\u064D\u064E\u0062 \u0061\u0315\u0300\u05AE\u0654\u0062
-\u0061\u0315\u0300\u05AE\u06DC\u0062 \u0061\u0733\u0315\u0300\u05AE\u0062
-\u0061\u0744\u059A\u0316\u302A\u0062 \u0061\u0315\u0300\u05AE\u0745\u0062
-\u0061\u09CD\u05B0\u094D\u3099\u0062 \u0061\u0E38\u0E48\u0E38\u0C56\u0062
-\u0061\u0EB8\u0E48\u0E38\u0E49\u0062 \u0061\u0F72\u0F71\u0EC8\u0F71\u0062
-\u0061\u1039\u05B0\u094D\u3099\u0062 \u0061\u05B0\u094D\u3099\u1A60\u0062
-\u0061\u3099\u093C\u0334\u1BE6\u0062 \u0061\u3099\u093C\u0334\u1C37\u0062
-\u0061\u1CD9\u059A\u0316\u302A\u0062 \u0061\u2DED\u0315\u0300\u05AE\u0062
-\u0061\u2DEF\u0315\u0300\u05AE\u0062 \u0061\u302D\u302E\u059A\u0316\u0062`
-
-// Taken from http://creativecommons.org/licenses/by-sa/3.0/vn/
-const txt_vn = `Với các điều kiện sau: Ghi nhận công của tác giả.
-Nếu bạn sử dụng, chuyển đổi, hoặc xây dựng dự án từ
-nội dung được chia sẻ này, bạn phải áp dụng giấy phép này hoặc
-một giấy phép khác có các điều khoản tương tự như giấy phép này
-cho dự án của bạn. Hiểu rằng: Miễn — Bất kỳ các điều kiện nào
-trên đây cũng có thể được miễn bỏ nếu bạn được sự cho phép của
-người sở hữu bản quyền. Phạm vi công chúng — Khi tác phẩm hoặc
-bất kỳ chương nào của tác phẩm đã trong vùng dành cho công
-chúng theo quy định của pháp luật thì tình trạng của nó không
-bị ảnh hưởng bởi giấy phép trong bất kỳ trường hợp nào.`
-
-// Taken from http://creativecommons.org/licenses/by-sa/1.0/deed.ru
-const txt_ru = `При обязательном соблюдении следующих условий:
-Attribution — Вы должны атрибутировать произведение (указывать
-автора и источник) в порядке, предусмотренном автором или
-лицензиаром (но только так, чтобы никоим образом не подразумевалось,
-что они поддерживают вас или использование вами данного произведения).
-Υπό τις ακόλουθες προϋποθέσεις:`
-
-// Taken from http://creativecommons.org/licenses/by-sa/3.0/gr/
-const txt_gr = `Αναφορά Δημιουργού — Θα πρέπει να κάνετε την αναφορά στο έργο με τον
-τρόπο που έχει οριστεί από το δημιουργό ή το χορηγούντο την άδεια
-(χωρίς όμως να εννοείται με οποιονδήποτε τρόπο ότι εγκρίνουν εσάς ή
-τη χρήση του έργου από εσάς). Παρόμοια Διανομή — Εάν αλλοιώσετε,
-τροποποιήσετε ή δημιουργήσετε περαιτέρω βασισμένοι στο έργο θα
-μπορείτε να διανέμετε το έργο που θα προκύψει μόνο με την ίδια ή
-παρόμοια άδεια.`
-
-// Taken from http://creativecommons.org/licenses/by-sa/3.0/deed.ar
-const txt_ar = `بموجب الشروط التالية نسب المصنف — يجب عليك أن
-تنسب العمل بالطريقة التي تحددها المؤلف أو المرخص (ولكن ليس بأي حال من
-الأحوال أن توحي وتقترح بتحول أو استخدامك للعمل).
-المشاركة على قدم المساواة — إذا كنت يعدل ، والتغيير ، أو الاستفادة
-من هذا العمل ، قد ينتج عن توزيع العمل إلا في ظل تشابه او تطابق فى واحد
-لهذا الترخيص.`
-
-// Taken from http://creativecommons.org/licenses/by-sa/1.0/il/
-const txt_il = `בכפוף לתנאים הבאים: ייחוס — עליך לייחס את היצירה (לתת קרדיט) באופן
-המצויין על-ידי היוצר או מעניק הרישיון (אך לא בשום אופן המרמז על כך
-שהם תומכים בך או בשימוש שלך ביצירה). שיתוף זהה — אם תחליט/י לשנות,
-לעבד או ליצור יצירה נגזרת בהסתמך על יצירה זו, תוכל/י להפיץ את יצירתך
-החדשה רק תחת אותו הרישיון או רישיון דומה לרישיון זה.`
-
-const twoByteUtf8 = txt_ru + txt_gr + txt_ar + txt_il
-
-// Taken from http://creativecommons.org/licenses/by-sa/2.0/kr/
-const txt_kr = `다음과 같은 조건을 따라야 합니다: 저작자표시
-(Attribution) — 저작자나 이용허락자가 정한 방법으로 저작물의
-원저작자를 표시하여야 합니다(그러나 원저작자가 이용자나 이용자의
-이용을 보증하거나 추천한다는 의미로 표시해서는 안됩니다).
-동일조건변경허락 — 이 저작물을 이용하여 만든 이차적 저작물에는 본
-라이선스와 동일한 라이선스를 적용해야 합니다.`
-
-// Taken from http://creativecommons.org/licenses/by-sa/3.0/th/
-const txt_th = `ภายใต้เงื่อนไข ดังต่อไปนี้ : แสดงที่มา — คุณต้องแสดงที่
-มาของงานดังกล่าว ตามรูปแบบที่ผู้สร้างสรรค์หรือผู้อนุญาตกำหนด (แต่
-ไม่ใช่ในลักษณะที่ว่า พวกเขาสนับสนุนคุณหรือสนับสนุนการที่
-คุณนำงานไปใช้) อนุญาตแบบเดียวกัน — หากคุณดัดแปลง เปลี่ยนรูป หรื
-อต่อเติมงานนี้ คุณต้องใช้สัญญาอนุญาตแบบเดียวกันหรือแบบที่เหมื
-อนกับสัญญาอนุญาตที่ใช้กับงานนี้เท่านั้น`
-
-const threeByteUtf8 = txt_th
-
-// Taken from http://creativecommons.org/licenses/by-sa/2.0/jp/
-const txt_jp = `あなたの従うべき条件は以下の通りです。
-表示 — あなたは原著作者のクレジットを表示しなければなりません。
-継承 — もしあなたがこの作品を改変、変形または加工した場合、
-あなたはその結果生じた作品をこの作品と同一の許諾条件の下でのみ
-頒布することができます。`
-
-// http://creativecommons.org/licenses/by-sa/2.5/cn/
-const txt_cn = `您可以自由: 复制、发行、展览、表演、放映、
-广播或通过信息网络传播本作品 创作演绎作品
-对本作品进行商业性使用 惟须遵守下列条件:
-署名 — 您必须按照作者或者许可人指定的方式对作品进行署名。
-相同方式共享 — 如果您改变、转换本作品或者以本作品为基础进行创作,
-您只能采用与本协议相同的许可协议发布基于本作品的演绎作品。`
-
-const txt_cjk = txt_cn + txt_jp + txt_kr
-const txt_all = txt_vn + twoByteUtf8 + threeByteUtf8 + txt_cjk
-
-var txt_all_bytes = []byte(txt_all)
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/readwriter.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/readwriter.go
deleted file mode 100644
index 4fa0e04..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/readwriter.go
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package norm
-
-import "io"
-
-type normWriter struct {
- rb reorderBuffer
- w io.Writer
- buf []byte
-}
-
-// Write implements the standard write interface. If the last characters are
-// not at a normalization boundary, the bytes will be buffered for the next
-// write. The remaining bytes will be written on close.
-func (w *normWriter) Write(data []byte) (n int, err error) {
- // Process data in pieces to keep w.buf size bounded.
- const chunk = 4000
-
- for len(data) > 0 {
- // Normalize into w.buf.
- m := len(data)
- if m > chunk {
- m = chunk
- }
- w.rb.src = inputBytes(data[:m])
- w.rb.nsrc = m
- w.buf = doAppend(&w.rb, w.buf, 0)
- data = data[m:]
- n += m
-
- // Write out complete prefix, save remainder.
- // Note that lastBoundary looks back at most 31 runes.
- i := lastBoundary(&w.rb.f, w.buf)
- if i == -1 {
- i = 0
- }
- if i > 0 {
- if _, err = w.w.Write(w.buf[:i]); err != nil {
- break
- }
- bn := copy(w.buf, w.buf[i:])
- w.buf = w.buf[:bn]
- }
- }
- return n, err
-}
-
-// Close forces data that remains in the buffer to be written.
-func (w *normWriter) Close() error {
- if len(w.buf) > 0 {
- _, err := w.w.Write(w.buf)
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-// Writer returns a new writer that implements Write(b)
-// by writing f(b) to w. The returned writer may use an
-// an internal buffer to maintain state across Write calls.
-// Calling its Close method writes any buffered data to w.
-func (f Form) Writer(w io.Writer) io.WriteCloser {
- wr := &normWriter{rb: reorderBuffer{}, w: w}
- wr.rb.init(f, nil)
- return wr
-}
-
-type normReader struct {
- rb reorderBuffer
- r io.Reader
- inbuf []byte
- outbuf []byte
- bufStart int
- lastBoundary int
- err error
-}
-
-// Read implements the standard read interface.
-func (r *normReader) Read(p []byte) (int, error) {
- for {
- if r.lastBoundary-r.bufStart > 0 {
- n := copy(p, r.outbuf[r.bufStart:r.lastBoundary])
- r.bufStart += n
- if r.lastBoundary-r.bufStart > 0 {
- return n, nil
- }
- return n, r.err
- }
- if r.err != nil {
- return 0, r.err
- }
- outn := copy(r.outbuf, r.outbuf[r.lastBoundary:])
- r.outbuf = r.outbuf[0:outn]
- r.bufStart = 0
-
- n, err := r.r.Read(r.inbuf)
- r.rb.src = inputBytes(r.inbuf[0:n])
- r.rb.nsrc, r.err = n, err
- if n > 0 {
- r.outbuf = doAppend(&r.rb, r.outbuf, 0)
- }
- if err == io.EOF {
- r.lastBoundary = len(r.outbuf)
- } else {
- r.lastBoundary = lastBoundary(&r.rb.f, r.outbuf)
- if r.lastBoundary == -1 {
- r.lastBoundary = 0
- }
- }
- }
- panic("should not reach here")
-}
-
-// Reader returns a new reader that implements Read
-// by reading data from r and returning f(data).
-func (f Form) Reader(r io.Reader) io.Reader {
- const chunk = 4000
- buf := make([]byte, chunk)
- rr := &normReader{rb: reorderBuffer{}, r: r, inbuf: buf}
- rr.rb.init(f, buf)
- return rr
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/readwriter_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/readwriter_test.go
deleted file mode 100644
index b7756ba..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/readwriter_test.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package norm
-
-import (
- "bytes"
- "fmt"
- "testing"
-)
-
-var bufSizes = []int{1, 2, 3, 4, 5, 6, 7, 8, 100, 101, 102, 103, 4000, 4001, 4002, 4003}
-
-func readFunc(size int) appendFunc {
- return func(f Form, out []byte, s string) []byte {
- out = append(out, s...)
- r := f.Reader(bytes.NewBuffer(out))
- buf := make([]byte, size)
- result := []byte{}
- for n, err := 0, error(nil); err == nil; {
- n, err = r.Read(buf)
- result = append(result, buf[:n]...)
- }
- return result
- }
-}
-
-func TestReader(t *testing.T) {
- for _, s := range bufSizes {
- name := fmt.Sprintf("TestReader%d", s)
- runNormTests(t, name, readFunc(s))
- }
-}
-
-func writeFunc(size int) appendFunc {
- return func(f Form, out []byte, s string) []byte {
- in := append(out, s...)
- result := new(bytes.Buffer)
- w := f.Writer(result)
- buf := make([]byte, size)
- for n := 0; len(in) > 0; in = in[n:] {
- n = copy(buf, in)
- _, _ = w.Write(buf[:n])
- }
- w.Close()
- return result.Bytes()
- }
-}
-
-func TestWriter(t *testing.T) {
- for _, s := range bufSizes {
- name := fmt.Sprintf("TestWriter%d", s)
- runNormTests(t, name, writeFunc(s))
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/tables.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/tables.go
deleted file mode 100644
index a56697b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/tables.go
+++ /dev/null
@@ -1,7627 +0,0 @@
-// This file was generated by go generate; DO NOT EDIT
-
-package norm
-
-const (
- // Version is the Unicode edition from which the tables are derived.
- Version = "9.0.0"
-
- // MaxTransformChunkSize indicates the maximum number of bytes that Transform
- // may need to write atomically for any Form. Making a destination buffer at
- // least this size ensures that Transform can always make progress and that
- // the user does not need to grow the buffer on an ErrShortDst.
- MaxTransformChunkSize = 35 + maxNonStarters*4
-)
-
-var ccc = [55]uint8{
- 0, 1, 7, 8, 9, 10, 11, 12,
- 13, 14, 15, 16, 17, 18, 19, 20,
- 21, 22, 23, 24, 25, 26, 27, 28,
- 29, 30, 31, 32, 33, 34, 35, 36,
- 84, 91, 103, 107, 118, 122, 129, 130,
- 132, 202, 214, 216, 218, 220, 222, 224,
- 226, 228, 230, 232, 233, 234, 240,
-}
-
-const (
- firstMulti = 0x186D
- firstCCC = 0x2C9E
- endMulti = 0x2F60
- firstLeadingCCC = 0x4A44
- firstCCCZeroExcept = 0x4A5A
- firstStarterWithNLead = 0x4A81
- lastDecomp = 0x4A83
- maxDecomp = 0x8000
-)
-
-// decomps: 19075 bytes
-var decomps = [...]byte{
- // Bytes 0 - 3f
- 0x00, 0x41, 0x20, 0x41, 0x21, 0x41, 0x22, 0x41,
- 0x23, 0x41, 0x24, 0x41, 0x25, 0x41, 0x26, 0x41,
- 0x27, 0x41, 0x28, 0x41, 0x29, 0x41, 0x2A, 0x41,
- 0x2B, 0x41, 0x2C, 0x41, 0x2D, 0x41, 0x2E, 0x41,
- 0x2F, 0x41, 0x30, 0x41, 0x31, 0x41, 0x32, 0x41,
- 0x33, 0x41, 0x34, 0x41, 0x35, 0x41, 0x36, 0x41,
- 0x37, 0x41, 0x38, 0x41, 0x39, 0x41, 0x3A, 0x41,
- 0x3B, 0x41, 0x3C, 0x41, 0x3D, 0x41, 0x3E, 0x41,
- // Bytes 40 - 7f
- 0x3F, 0x41, 0x40, 0x41, 0x41, 0x41, 0x42, 0x41,
- 0x43, 0x41, 0x44, 0x41, 0x45, 0x41, 0x46, 0x41,
- 0x47, 0x41, 0x48, 0x41, 0x49, 0x41, 0x4A, 0x41,
- 0x4B, 0x41, 0x4C, 0x41, 0x4D, 0x41, 0x4E, 0x41,
- 0x4F, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41,
- 0x53, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41,
- 0x57, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x41,
- 0x5B, 0x41, 0x5C, 0x41, 0x5D, 0x41, 0x5E, 0x41,
- // Bytes 80 - bf
- 0x5F, 0x41, 0x60, 0x41, 0x61, 0x41, 0x62, 0x41,
- 0x63, 0x41, 0x64, 0x41, 0x65, 0x41, 0x66, 0x41,
- 0x67, 0x41, 0x68, 0x41, 0x69, 0x41, 0x6A, 0x41,
- 0x6B, 0x41, 0x6C, 0x41, 0x6D, 0x41, 0x6E, 0x41,
- 0x6F, 0x41, 0x70, 0x41, 0x71, 0x41, 0x72, 0x41,
- 0x73, 0x41, 0x74, 0x41, 0x75, 0x41, 0x76, 0x41,
- 0x77, 0x41, 0x78, 0x41, 0x79, 0x41, 0x7A, 0x41,
- 0x7B, 0x41, 0x7C, 0x41, 0x7D, 0x41, 0x7E, 0x42,
- // Bytes c0 - ff
- 0xC2, 0xA2, 0x42, 0xC2, 0xA3, 0x42, 0xC2, 0xA5,
- 0x42, 0xC2, 0xA6, 0x42, 0xC2, 0xAC, 0x42, 0xC2,
- 0xB7, 0x42, 0xC3, 0x86, 0x42, 0xC3, 0xB0, 0x42,
- 0xC4, 0xA6, 0x42, 0xC4, 0xA7, 0x42, 0xC4, 0xB1,
- 0x42, 0xC5, 0x8B, 0x42, 0xC5, 0x93, 0x42, 0xC6,
- 0x8E, 0x42, 0xC6, 0x90, 0x42, 0xC6, 0xAB, 0x42,
- 0xC8, 0xA2, 0x42, 0xC8, 0xB7, 0x42, 0xC9, 0x90,
- 0x42, 0xC9, 0x91, 0x42, 0xC9, 0x92, 0x42, 0xC9,
- // Bytes 100 - 13f
- 0x94, 0x42, 0xC9, 0x95, 0x42, 0xC9, 0x99, 0x42,
- 0xC9, 0x9B, 0x42, 0xC9, 0x9C, 0x42, 0xC9, 0x9F,
- 0x42, 0xC9, 0xA1, 0x42, 0xC9, 0xA3, 0x42, 0xC9,
- 0xA5, 0x42, 0xC9, 0xA6, 0x42, 0xC9, 0xA8, 0x42,
- 0xC9, 0xA9, 0x42, 0xC9, 0xAA, 0x42, 0xC9, 0xAB,
- 0x42, 0xC9, 0xAD, 0x42, 0xC9, 0xAF, 0x42, 0xC9,
- 0xB0, 0x42, 0xC9, 0xB1, 0x42, 0xC9, 0xB2, 0x42,
- 0xC9, 0xB3, 0x42, 0xC9, 0xB4, 0x42, 0xC9, 0xB5,
- // Bytes 140 - 17f
- 0x42, 0xC9, 0xB8, 0x42, 0xC9, 0xB9, 0x42, 0xC9,
- 0xBB, 0x42, 0xCA, 0x81, 0x42, 0xCA, 0x82, 0x42,
- 0xCA, 0x83, 0x42, 0xCA, 0x89, 0x42, 0xCA, 0x8A,
- 0x42, 0xCA, 0x8B, 0x42, 0xCA, 0x8C, 0x42, 0xCA,
- 0x90, 0x42, 0xCA, 0x91, 0x42, 0xCA, 0x92, 0x42,
- 0xCA, 0x95, 0x42, 0xCA, 0x9D, 0x42, 0xCA, 0x9F,
- 0x42, 0xCA, 0xB9, 0x42, 0xCE, 0x91, 0x42, 0xCE,
- 0x92, 0x42, 0xCE, 0x93, 0x42, 0xCE, 0x94, 0x42,
- // Bytes 180 - 1bf
- 0xCE, 0x95, 0x42, 0xCE, 0x96, 0x42, 0xCE, 0x97,
- 0x42, 0xCE, 0x98, 0x42, 0xCE, 0x99, 0x42, 0xCE,
- 0x9A, 0x42, 0xCE, 0x9B, 0x42, 0xCE, 0x9C, 0x42,
- 0xCE, 0x9D, 0x42, 0xCE, 0x9E, 0x42, 0xCE, 0x9F,
- 0x42, 0xCE, 0xA0, 0x42, 0xCE, 0xA1, 0x42, 0xCE,
- 0xA3, 0x42, 0xCE, 0xA4, 0x42, 0xCE, 0xA5, 0x42,
- 0xCE, 0xA6, 0x42, 0xCE, 0xA7, 0x42, 0xCE, 0xA8,
- 0x42, 0xCE, 0xA9, 0x42, 0xCE, 0xB1, 0x42, 0xCE,
- // Bytes 1c0 - 1ff
- 0xB2, 0x42, 0xCE, 0xB3, 0x42, 0xCE, 0xB4, 0x42,
- 0xCE, 0xB5, 0x42, 0xCE, 0xB6, 0x42, 0xCE, 0xB7,
- 0x42, 0xCE, 0xB8, 0x42, 0xCE, 0xB9, 0x42, 0xCE,
- 0xBA, 0x42, 0xCE, 0xBB, 0x42, 0xCE, 0xBC, 0x42,
- 0xCE, 0xBD, 0x42, 0xCE, 0xBE, 0x42, 0xCE, 0xBF,
- 0x42, 0xCF, 0x80, 0x42, 0xCF, 0x81, 0x42, 0xCF,
- 0x82, 0x42, 0xCF, 0x83, 0x42, 0xCF, 0x84, 0x42,
- 0xCF, 0x85, 0x42, 0xCF, 0x86, 0x42, 0xCF, 0x87,
- // Bytes 200 - 23f
- 0x42, 0xCF, 0x88, 0x42, 0xCF, 0x89, 0x42, 0xCF,
- 0x9C, 0x42, 0xCF, 0x9D, 0x42, 0xD0, 0xBD, 0x42,
- 0xD1, 0x8A, 0x42, 0xD1, 0x8C, 0x42, 0xD7, 0x90,
- 0x42, 0xD7, 0x91, 0x42, 0xD7, 0x92, 0x42, 0xD7,
- 0x93, 0x42, 0xD7, 0x94, 0x42, 0xD7, 0x9B, 0x42,
- 0xD7, 0x9C, 0x42, 0xD7, 0x9D, 0x42, 0xD7, 0xA2,
- 0x42, 0xD7, 0xA8, 0x42, 0xD7, 0xAA, 0x42, 0xD8,
- 0xA1, 0x42, 0xD8, 0xA7, 0x42, 0xD8, 0xA8, 0x42,
- // Bytes 240 - 27f
- 0xD8, 0xA9, 0x42, 0xD8, 0xAA, 0x42, 0xD8, 0xAB,
- 0x42, 0xD8, 0xAC, 0x42, 0xD8, 0xAD, 0x42, 0xD8,
- 0xAE, 0x42, 0xD8, 0xAF, 0x42, 0xD8, 0xB0, 0x42,
- 0xD8, 0xB1, 0x42, 0xD8, 0xB2, 0x42, 0xD8, 0xB3,
- 0x42, 0xD8, 0xB4, 0x42, 0xD8, 0xB5, 0x42, 0xD8,
- 0xB6, 0x42, 0xD8, 0xB7, 0x42, 0xD8, 0xB8, 0x42,
- 0xD8, 0xB9, 0x42, 0xD8, 0xBA, 0x42, 0xD9, 0x81,
- 0x42, 0xD9, 0x82, 0x42, 0xD9, 0x83, 0x42, 0xD9,
- // Bytes 280 - 2bf
- 0x84, 0x42, 0xD9, 0x85, 0x42, 0xD9, 0x86, 0x42,
- 0xD9, 0x87, 0x42, 0xD9, 0x88, 0x42, 0xD9, 0x89,
- 0x42, 0xD9, 0x8A, 0x42, 0xD9, 0xAE, 0x42, 0xD9,
- 0xAF, 0x42, 0xD9, 0xB1, 0x42, 0xD9, 0xB9, 0x42,
- 0xD9, 0xBA, 0x42, 0xD9, 0xBB, 0x42, 0xD9, 0xBE,
- 0x42, 0xD9, 0xBF, 0x42, 0xDA, 0x80, 0x42, 0xDA,
- 0x83, 0x42, 0xDA, 0x84, 0x42, 0xDA, 0x86, 0x42,
- 0xDA, 0x87, 0x42, 0xDA, 0x88, 0x42, 0xDA, 0x8C,
- // Bytes 2c0 - 2ff
- 0x42, 0xDA, 0x8D, 0x42, 0xDA, 0x8E, 0x42, 0xDA,
- 0x91, 0x42, 0xDA, 0x98, 0x42, 0xDA, 0xA1, 0x42,
- 0xDA, 0xA4, 0x42, 0xDA, 0xA6, 0x42, 0xDA, 0xA9,
- 0x42, 0xDA, 0xAD, 0x42, 0xDA, 0xAF, 0x42, 0xDA,
- 0xB1, 0x42, 0xDA, 0xB3, 0x42, 0xDA, 0xBA, 0x42,
- 0xDA, 0xBB, 0x42, 0xDA, 0xBE, 0x42, 0xDB, 0x81,
- 0x42, 0xDB, 0x85, 0x42, 0xDB, 0x86, 0x42, 0xDB,
- 0x87, 0x42, 0xDB, 0x88, 0x42, 0xDB, 0x89, 0x42,
- // Bytes 300 - 33f
- 0xDB, 0x8B, 0x42, 0xDB, 0x8C, 0x42, 0xDB, 0x90,
- 0x42, 0xDB, 0x92, 0x43, 0xE0, 0xBC, 0x8B, 0x43,
- 0xE1, 0x83, 0x9C, 0x43, 0xE1, 0x84, 0x80, 0x43,
- 0xE1, 0x84, 0x81, 0x43, 0xE1, 0x84, 0x82, 0x43,
- 0xE1, 0x84, 0x83, 0x43, 0xE1, 0x84, 0x84, 0x43,
- 0xE1, 0x84, 0x85, 0x43, 0xE1, 0x84, 0x86, 0x43,
- 0xE1, 0x84, 0x87, 0x43, 0xE1, 0x84, 0x88, 0x43,
- 0xE1, 0x84, 0x89, 0x43, 0xE1, 0x84, 0x8A, 0x43,
- // Bytes 340 - 37f
- 0xE1, 0x84, 0x8B, 0x43, 0xE1, 0x84, 0x8C, 0x43,
- 0xE1, 0x84, 0x8D, 0x43, 0xE1, 0x84, 0x8E, 0x43,
- 0xE1, 0x84, 0x8F, 0x43, 0xE1, 0x84, 0x90, 0x43,
- 0xE1, 0x84, 0x91, 0x43, 0xE1, 0x84, 0x92, 0x43,
- 0xE1, 0x84, 0x94, 0x43, 0xE1, 0x84, 0x95, 0x43,
- 0xE1, 0x84, 0x9A, 0x43, 0xE1, 0x84, 0x9C, 0x43,
- 0xE1, 0x84, 0x9D, 0x43, 0xE1, 0x84, 0x9E, 0x43,
- 0xE1, 0x84, 0xA0, 0x43, 0xE1, 0x84, 0xA1, 0x43,
- // Bytes 380 - 3bf
- 0xE1, 0x84, 0xA2, 0x43, 0xE1, 0x84, 0xA3, 0x43,
- 0xE1, 0x84, 0xA7, 0x43, 0xE1, 0x84, 0xA9, 0x43,
- 0xE1, 0x84, 0xAB, 0x43, 0xE1, 0x84, 0xAC, 0x43,
- 0xE1, 0x84, 0xAD, 0x43, 0xE1, 0x84, 0xAE, 0x43,
- 0xE1, 0x84, 0xAF, 0x43, 0xE1, 0x84, 0xB2, 0x43,
- 0xE1, 0x84, 0xB6, 0x43, 0xE1, 0x85, 0x80, 0x43,
- 0xE1, 0x85, 0x87, 0x43, 0xE1, 0x85, 0x8C, 0x43,
- 0xE1, 0x85, 0x97, 0x43, 0xE1, 0x85, 0x98, 0x43,
- // Bytes 3c0 - 3ff
- 0xE1, 0x85, 0x99, 0x43, 0xE1, 0x85, 0xA0, 0x43,
- 0xE1, 0x86, 0x84, 0x43, 0xE1, 0x86, 0x85, 0x43,
- 0xE1, 0x86, 0x88, 0x43, 0xE1, 0x86, 0x91, 0x43,
- 0xE1, 0x86, 0x92, 0x43, 0xE1, 0x86, 0x94, 0x43,
- 0xE1, 0x86, 0x9E, 0x43, 0xE1, 0x86, 0xA1, 0x43,
- 0xE1, 0x87, 0x87, 0x43, 0xE1, 0x87, 0x88, 0x43,
- 0xE1, 0x87, 0x8C, 0x43, 0xE1, 0x87, 0x8E, 0x43,
- 0xE1, 0x87, 0x93, 0x43, 0xE1, 0x87, 0x97, 0x43,
- // Bytes 400 - 43f
- 0xE1, 0x87, 0x99, 0x43, 0xE1, 0x87, 0x9D, 0x43,
- 0xE1, 0x87, 0x9F, 0x43, 0xE1, 0x87, 0xB1, 0x43,
- 0xE1, 0x87, 0xB2, 0x43, 0xE1, 0xB4, 0x82, 0x43,
- 0xE1, 0xB4, 0x96, 0x43, 0xE1, 0xB4, 0x97, 0x43,
- 0xE1, 0xB4, 0x9C, 0x43, 0xE1, 0xB4, 0x9D, 0x43,
- 0xE1, 0xB4, 0xA5, 0x43, 0xE1, 0xB5, 0xBB, 0x43,
- 0xE1, 0xB6, 0x85, 0x43, 0xE2, 0x80, 0x82, 0x43,
- 0xE2, 0x80, 0x83, 0x43, 0xE2, 0x80, 0x90, 0x43,
- // Bytes 440 - 47f
- 0xE2, 0x80, 0x93, 0x43, 0xE2, 0x80, 0x94, 0x43,
- 0xE2, 0x82, 0xA9, 0x43, 0xE2, 0x86, 0x90, 0x43,
- 0xE2, 0x86, 0x91, 0x43, 0xE2, 0x86, 0x92, 0x43,
- 0xE2, 0x86, 0x93, 0x43, 0xE2, 0x88, 0x82, 0x43,
- 0xE2, 0x88, 0x87, 0x43, 0xE2, 0x88, 0x91, 0x43,
- 0xE2, 0x88, 0x92, 0x43, 0xE2, 0x94, 0x82, 0x43,
- 0xE2, 0x96, 0xA0, 0x43, 0xE2, 0x97, 0x8B, 0x43,
- 0xE2, 0xA6, 0x85, 0x43, 0xE2, 0xA6, 0x86, 0x43,
- // Bytes 480 - 4bf
- 0xE2, 0xB5, 0xA1, 0x43, 0xE3, 0x80, 0x81, 0x43,
- 0xE3, 0x80, 0x82, 0x43, 0xE3, 0x80, 0x88, 0x43,
- 0xE3, 0x80, 0x89, 0x43, 0xE3, 0x80, 0x8A, 0x43,
- 0xE3, 0x80, 0x8B, 0x43, 0xE3, 0x80, 0x8C, 0x43,
- 0xE3, 0x80, 0x8D, 0x43, 0xE3, 0x80, 0x8E, 0x43,
- 0xE3, 0x80, 0x8F, 0x43, 0xE3, 0x80, 0x90, 0x43,
- 0xE3, 0x80, 0x91, 0x43, 0xE3, 0x80, 0x92, 0x43,
- 0xE3, 0x80, 0x94, 0x43, 0xE3, 0x80, 0x95, 0x43,
- // Bytes 4c0 - 4ff
- 0xE3, 0x80, 0x96, 0x43, 0xE3, 0x80, 0x97, 0x43,
- 0xE3, 0x82, 0xA1, 0x43, 0xE3, 0x82, 0xA2, 0x43,
- 0xE3, 0x82, 0xA3, 0x43, 0xE3, 0x82, 0xA4, 0x43,
- 0xE3, 0x82, 0xA5, 0x43, 0xE3, 0x82, 0xA6, 0x43,
- 0xE3, 0x82, 0xA7, 0x43, 0xE3, 0x82, 0xA8, 0x43,
- 0xE3, 0x82, 0xA9, 0x43, 0xE3, 0x82, 0xAA, 0x43,
- 0xE3, 0x82, 0xAB, 0x43, 0xE3, 0x82, 0xAD, 0x43,
- 0xE3, 0x82, 0xAF, 0x43, 0xE3, 0x82, 0xB1, 0x43,
- // Bytes 500 - 53f
- 0xE3, 0x82, 0xB3, 0x43, 0xE3, 0x82, 0xB5, 0x43,
- 0xE3, 0x82, 0xB7, 0x43, 0xE3, 0x82, 0xB9, 0x43,
- 0xE3, 0x82, 0xBB, 0x43, 0xE3, 0x82, 0xBD, 0x43,
- 0xE3, 0x82, 0xBF, 0x43, 0xE3, 0x83, 0x81, 0x43,
- 0xE3, 0x83, 0x83, 0x43, 0xE3, 0x83, 0x84, 0x43,
- 0xE3, 0x83, 0x86, 0x43, 0xE3, 0x83, 0x88, 0x43,
- 0xE3, 0x83, 0x8A, 0x43, 0xE3, 0x83, 0x8B, 0x43,
- 0xE3, 0x83, 0x8C, 0x43, 0xE3, 0x83, 0x8D, 0x43,
- // Bytes 540 - 57f
- 0xE3, 0x83, 0x8E, 0x43, 0xE3, 0x83, 0x8F, 0x43,
- 0xE3, 0x83, 0x92, 0x43, 0xE3, 0x83, 0x95, 0x43,
- 0xE3, 0x83, 0x98, 0x43, 0xE3, 0x83, 0x9B, 0x43,
- 0xE3, 0x83, 0x9E, 0x43, 0xE3, 0x83, 0x9F, 0x43,
- 0xE3, 0x83, 0xA0, 0x43, 0xE3, 0x83, 0xA1, 0x43,
- 0xE3, 0x83, 0xA2, 0x43, 0xE3, 0x83, 0xA3, 0x43,
- 0xE3, 0x83, 0xA4, 0x43, 0xE3, 0x83, 0xA5, 0x43,
- 0xE3, 0x83, 0xA6, 0x43, 0xE3, 0x83, 0xA7, 0x43,
- // Bytes 580 - 5bf
- 0xE3, 0x83, 0xA8, 0x43, 0xE3, 0x83, 0xA9, 0x43,
- 0xE3, 0x83, 0xAA, 0x43, 0xE3, 0x83, 0xAB, 0x43,
- 0xE3, 0x83, 0xAC, 0x43, 0xE3, 0x83, 0xAD, 0x43,
- 0xE3, 0x83, 0xAF, 0x43, 0xE3, 0x83, 0xB0, 0x43,
- 0xE3, 0x83, 0xB1, 0x43, 0xE3, 0x83, 0xB2, 0x43,
- 0xE3, 0x83, 0xB3, 0x43, 0xE3, 0x83, 0xBB, 0x43,
- 0xE3, 0x83, 0xBC, 0x43, 0xE3, 0x92, 0x9E, 0x43,
- 0xE3, 0x92, 0xB9, 0x43, 0xE3, 0x92, 0xBB, 0x43,
- // Bytes 5c0 - 5ff
- 0xE3, 0x93, 0x9F, 0x43, 0xE3, 0x94, 0x95, 0x43,
- 0xE3, 0x9B, 0xAE, 0x43, 0xE3, 0x9B, 0xBC, 0x43,
- 0xE3, 0x9E, 0x81, 0x43, 0xE3, 0xA0, 0xAF, 0x43,
- 0xE3, 0xA1, 0xA2, 0x43, 0xE3, 0xA1, 0xBC, 0x43,
- 0xE3, 0xA3, 0x87, 0x43, 0xE3, 0xA3, 0xA3, 0x43,
- 0xE3, 0xA4, 0x9C, 0x43, 0xE3, 0xA4, 0xBA, 0x43,
- 0xE3, 0xA8, 0xAE, 0x43, 0xE3, 0xA9, 0xAC, 0x43,
- 0xE3, 0xAB, 0xA4, 0x43, 0xE3, 0xAC, 0x88, 0x43,
- // Bytes 600 - 63f
- 0xE3, 0xAC, 0x99, 0x43, 0xE3, 0xAD, 0x89, 0x43,
- 0xE3, 0xAE, 0x9D, 0x43, 0xE3, 0xB0, 0x98, 0x43,
- 0xE3, 0xB1, 0x8E, 0x43, 0xE3, 0xB4, 0xB3, 0x43,
- 0xE3, 0xB6, 0x96, 0x43, 0xE3, 0xBA, 0xAC, 0x43,
- 0xE3, 0xBA, 0xB8, 0x43, 0xE3, 0xBC, 0x9B, 0x43,
- 0xE3, 0xBF, 0xBC, 0x43, 0xE4, 0x80, 0x88, 0x43,
- 0xE4, 0x80, 0x98, 0x43, 0xE4, 0x80, 0xB9, 0x43,
- 0xE4, 0x81, 0x86, 0x43, 0xE4, 0x82, 0x96, 0x43,
- // Bytes 640 - 67f
- 0xE4, 0x83, 0xA3, 0x43, 0xE4, 0x84, 0xAF, 0x43,
- 0xE4, 0x88, 0x82, 0x43, 0xE4, 0x88, 0xA7, 0x43,
- 0xE4, 0x8A, 0xA0, 0x43, 0xE4, 0x8C, 0x81, 0x43,
- 0xE4, 0x8C, 0xB4, 0x43, 0xE4, 0x8D, 0x99, 0x43,
- 0xE4, 0x8F, 0x95, 0x43, 0xE4, 0x8F, 0x99, 0x43,
- 0xE4, 0x90, 0x8B, 0x43, 0xE4, 0x91, 0xAB, 0x43,
- 0xE4, 0x94, 0xAB, 0x43, 0xE4, 0x95, 0x9D, 0x43,
- 0xE4, 0x95, 0xA1, 0x43, 0xE4, 0x95, 0xAB, 0x43,
- // Bytes 680 - 6bf
- 0xE4, 0x97, 0x97, 0x43, 0xE4, 0x97, 0xB9, 0x43,
- 0xE4, 0x98, 0xB5, 0x43, 0xE4, 0x9A, 0xBE, 0x43,
- 0xE4, 0x9B, 0x87, 0x43, 0xE4, 0xA6, 0x95, 0x43,
- 0xE4, 0xA7, 0xA6, 0x43, 0xE4, 0xA9, 0xAE, 0x43,
- 0xE4, 0xA9, 0xB6, 0x43, 0xE4, 0xAA, 0xB2, 0x43,
- 0xE4, 0xAC, 0xB3, 0x43, 0xE4, 0xAF, 0x8E, 0x43,
- 0xE4, 0xB3, 0x8E, 0x43, 0xE4, 0xB3, 0xAD, 0x43,
- 0xE4, 0xB3, 0xB8, 0x43, 0xE4, 0xB5, 0x96, 0x43,
- // Bytes 6c0 - 6ff
- 0xE4, 0xB8, 0x80, 0x43, 0xE4, 0xB8, 0x81, 0x43,
- 0xE4, 0xB8, 0x83, 0x43, 0xE4, 0xB8, 0x89, 0x43,
- 0xE4, 0xB8, 0x8A, 0x43, 0xE4, 0xB8, 0x8B, 0x43,
- 0xE4, 0xB8, 0x8D, 0x43, 0xE4, 0xB8, 0x99, 0x43,
- 0xE4, 0xB8, 0xA6, 0x43, 0xE4, 0xB8, 0xA8, 0x43,
- 0xE4, 0xB8, 0xAD, 0x43, 0xE4, 0xB8, 0xB2, 0x43,
- 0xE4, 0xB8, 0xB6, 0x43, 0xE4, 0xB8, 0xB8, 0x43,
- 0xE4, 0xB8, 0xB9, 0x43, 0xE4, 0xB8, 0xBD, 0x43,
- // Bytes 700 - 73f
- 0xE4, 0xB8, 0xBF, 0x43, 0xE4, 0xB9, 0x81, 0x43,
- 0xE4, 0xB9, 0x99, 0x43, 0xE4, 0xB9, 0x9D, 0x43,
- 0xE4, 0xBA, 0x82, 0x43, 0xE4, 0xBA, 0x85, 0x43,
- 0xE4, 0xBA, 0x86, 0x43, 0xE4, 0xBA, 0x8C, 0x43,
- 0xE4, 0xBA, 0x94, 0x43, 0xE4, 0xBA, 0xA0, 0x43,
- 0xE4, 0xBA, 0xA4, 0x43, 0xE4, 0xBA, 0xAE, 0x43,
- 0xE4, 0xBA, 0xBA, 0x43, 0xE4, 0xBB, 0x80, 0x43,
- 0xE4, 0xBB, 0x8C, 0x43, 0xE4, 0xBB, 0xA4, 0x43,
- // Bytes 740 - 77f
- 0xE4, 0xBC, 0x81, 0x43, 0xE4, 0xBC, 0x91, 0x43,
- 0xE4, 0xBD, 0xA0, 0x43, 0xE4, 0xBE, 0x80, 0x43,
- 0xE4, 0xBE, 0x86, 0x43, 0xE4, 0xBE, 0x8B, 0x43,
- 0xE4, 0xBE, 0xAE, 0x43, 0xE4, 0xBE, 0xBB, 0x43,
- 0xE4, 0xBE, 0xBF, 0x43, 0xE5, 0x80, 0x82, 0x43,
- 0xE5, 0x80, 0xAB, 0x43, 0xE5, 0x81, 0xBA, 0x43,
- 0xE5, 0x82, 0x99, 0x43, 0xE5, 0x83, 0x8F, 0x43,
- 0xE5, 0x83, 0x9A, 0x43, 0xE5, 0x83, 0xA7, 0x43,
- // Bytes 780 - 7bf
- 0xE5, 0x84, 0xAA, 0x43, 0xE5, 0x84, 0xBF, 0x43,
- 0xE5, 0x85, 0x80, 0x43, 0xE5, 0x85, 0x85, 0x43,
- 0xE5, 0x85, 0x8D, 0x43, 0xE5, 0x85, 0x94, 0x43,
- 0xE5, 0x85, 0xA4, 0x43, 0xE5, 0x85, 0xA5, 0x43,
- 0xE5, 0x85, 0xA7, 0x43, 0xE5, 0x85, 0xA8, 0x43,
- 0xE5, 0x85, 0xA9, 0x43, 0xE5, 0x85, 0xAB, 0x43,
- 0xE5, 0x85, 0xAD, 0x43, 0xE5, 0x85, 0xB7, 0x43,
- 0xE5, 0x86, 0x80, 0x43, 0xE5, 0x86, 0x82, 0x43,
- // Bytes 7c0 - 7ff
- 0xE5, 0x86, 0x8D, 0x43, 0xE5, 0x86, 0x92, 0x43,
- 0xE5, 0x86, 0x95, 0x43, 0xE5, 0x86, 0x96, 0x43,
- 0xE5, 0x86, 0x97, 0x43, 0xE5, 0x86, 0x99, 0x43,
- 0xE5, 0x86, 0xA4, 0x43, 0xE5, 0x86, 0xAB, 0x43,
- 0xE5, 0x86, 0xAC, 0x43, 0xE5, 0x86, 0xB5, 0x43,
- 0xE5, 0x86, 0xB7, 0x43, 0xE5, 0x87, 0x89, 0x43,
- 0xE5, 0x87, 0x8C, 0x43, 0xE5, 0x87, 0x9C, 0x43,
- 0xE5, 0x87, 0x9E, 0x43, 0xE5, 0x87, 0xA0, 0x43,
- // Bytes 800 - 83f
- 0xE5, 0x87, 0xB5, 0x43, 0xE5, 0x88, 0x80, 0x43,
- 0xE5, 0x88, 0x83, 0x43, 0xE5, 0x88, 0x87, 0x43,
- 0xE5, 0x88, 0x97, 0x43, 0xE5, 0x88, 0x9D, 0x43,
- 0xE5, 0x88, 0xA9, 0x43, 0xE5, 0x88, 0xBA, 0x43,
- 0xE5, 0x88, 0xBB, 0x43, 0xE5, 0x89, 0x86, 0x43,
- 0xE5, 0x89, 0x8D, 0x43, 0xE5, 0x89, 0xB2, 0x43,
- 0xE5, 0x89, 0xB7, 0x43, 0xE5, 0x8A, 0x89, 0x43,
- 0xE5, 0x8A, 0x9B, 0x43, 0xE5, 0x8A, 0xA3, 0x43,
- // Bytes 840 - 87f
- 0xE5, 0x8A, 0xB3, 0x43, 0xE5, 0x8A, 0xB4, 0x43,
- 0xE5, 0x8B, 0x87, 0x43, 0xE5, 0x8B, 0x89, 0x43,
- 0xE5, 0x8B, 0x92, 0x43, 0xE5, 0x8B, 0x9E, 0x43,
- 0xE5, 0x8B, 0xA4, 0x43, 0xE5, 0x8B, 0xB5, 0x43,
- 0xE5, 0x8B, 0xB9, 0x43, 0xE5, 0x8B, 0xBA, 0x43,
- 0xE5, 0x8C, 0x85, 0x43, 0xE5, 0x8C, 0x86, 0x43,
- 0xE5, 0x8C, 0x95, 0x43, 0xE5, 0x8C, 0x97, 0x43,
- 0xE5, 0x8C, 0x9A, 0x43, 0xE5, 0x8C, 0xB8, 0x43,
- // Bytes 880 - 8bf
- 0xE5, 0x8C, 0xBB, 0x43, 0xE5, 0x8C, 0xBF, 0x43,
- 0xE5, 0x8D, 0x81, 0x43, 0xE5, 0x8D, 0x84, 0x43,
- 0xE5, 0x8D, 0x85, 0x43, 0xE5, 0x8D, 0x89, 0x43,
- 0xE5, 0x8D, 0x91, 0x43, 0xE5, 0x8D, 0x94, 0x43,
- 0xE5, 0x8D, 0x9A, 0x43, 0xE5, 0x8D, 0x9C, 0x43,
- 0xE5, 0x8D, 0xA9, 0x43, 0xE5, 0x8D, 0xB0, 0x43,
- 0xE5, 0x8D, 0xB3, 0x43, 0xE5, 0x8D, 0xB5, 0x43,
- 0xE5, 0x8D, 0xBD, 0x43, 0xE5, 0x8D, 0xBF, 0x43,
- // Bytes 8c0 - 8ff
- 0xE5, 0x8E, 0x82, 0x43, 0xE5, 0x8E, 0xB6, 0x43,
- 0xE5, 0x8F, 0x83, 0x43, 0xE5, 0x8F, 0x88, 0x43,
- 0xE5, 0x8F, 0x8A, 0x43, 0xE5, 0x8F, 0x8C, 0x43,
- 0xE5, 0x8F, 0x9F, 0x43, 0xE5, 0x8F, 0xA3, 0x43,
- 0xE5, 0x8F, 0xA5, 0x43, 0xE5, 0x8F, 0xAB, 0x43,
- 0xE5, 0x8F, 0xAF, 0x43, 0xE5, 0x8F, 0xB1, 0x43,
- 0xE5, 0x8F, 0xB3, 0x43, 0xE5, 0x90, 0x86, 0x43,
- 0xE5, 0x90, 0x88, 0x43, 0xE5, 0x90, 0x8D, 0x43,
- // Bytes 900 - 93f
- 0xE5, 0x90, 0x8F, 0x43, 0xE5, 0x90, 0x9D, 0x43,
- 0xE5, 0x90, 0xB8, 0x43, 0xE5, 0x90, 0xB9, 0x43,
- 0xE5, 0x91, 0x82, 0x43, 0xE5, 0x91, 0x88, 0x43,
- 0xE5, 0x91, 0xA8, 0x43, 0xE5, 0x92, 0x9E, 0x43,
- 0xE5, 0x92, 0xA2, 0x43, 0xE5, 0x92, 0xBD, 0x43,
- 0xE5, 0x93, 0xB6, 0x43, 0xE5, 0x94, 0x90, 0x43,
- 0xE5, 0x95, 0x8F, 0x43, 0xE5, 0x95, 0x93, 0x43,
- 0xE5, 0x95, 0x95, 0x43, 0xE5, 0x95, 0xA3, 0x43,
- // Bytes 940 - 97f
- 0xE5, 0x96, 0x84, 0x43, 0xE5, 0x96, 0x87, 0x43,
- 0xE5, 0x96, 0x99, 0x43, 0xE5, 0x96, 0x9D, 0x43,
- 0xE5, 0x96, 0xAB, 0x43, 0xE5, 0x96, 0xB3, 0x43,
- 0xE5, 0x96, 0xB6, 0x43, 0xE5, 0x97, 0x80, 0x43,
- 0xE5, 0x97, 0x82, 0x43, 0xE5, 0x97, 0xA2, 0x43,
- 0xE5, 0x98, 0x86, 0x43, 0xE5, 0x99, 0x91, 0x43,
- 0xE5, 0x99, 0xA8, 0x43, 0xE5, 0x99, 0xB4, 0x43,
- 0xE5, 0x9B, 0x97, 0x43, 0xE5, 0x9B, 0x9B, 0x43,
- // Bytes 980 - 9bf
- 0xE5, 0x9B, 0xB9, 0x43, 0xE5, 0x9C, 0x96, 0x43,
- 0xE5, 0x9C, 0x97, 0x43, 0xE5, 0x9C, 0x9F, 0x43,
- 0xE5, 0x9C, 0xB0, 0x43, 0xE5, 0x9E, 0x8B, 0x43,
- 0xE5, 0x9F, 0x8E, 0x43, 0xE5, 0x9F, 0xB4, 0x43,
- 0xE5, 0xA0, 0x8D, 0x43, 0xE5, 0xA0, 0xB1, 0x43,
- 0xE5, 0xA0, 0xB2, 0x43, 0xE5, 0xA1, 0x80, 0x43,
- 0xE5, 0xA1, 0x9A, 0x43, 0xE5, 0xA1, 0x9E, 0x43,
- 0xE5, 0xA2, 0xA8, 0x43, 0xE5, 0xA2, 0xAC, 0x43,
- // Bytes 9c0 - 9ff
- 0xE5, 0xA2, 0xB3, 0x43, 0xE5, 0xA3, 0x98, 0x43,
- 0xE5, 0xA3, 0x9F, 0x43, 0xE5, 0xA3, 0xAB, 0x43,
- 0xE5, 0xA3, 0xAE, 0x43, 0xE5, 0xA3, 0xB0, 0x43,
- 0xE5, 0xA3, 0xB2, 0x43, 0xE5, 0xA3, 0xB7, 0x43,
- 0xE5, 0xA4, 0x82, 0x43, 0xE5, 0xA4, 0x86, 0x43,
- 0xE5, 0xA4, 0x8A, 0x43, 0xE5, 0xA4, 0x95, 0x43,
- 0xE5, 0xA4, 0x9A, 0x43, 0xE5, 0xA4, 0x9C, 0x43,
- 0xE5, 0xA4, 0xA2, 0x43, 0xE5, 0xA4, 0xA7, 0x43,
- // Bytes a00 - a3f
- 0xE5, 0xA4, 0xA9, 0x43, 0xE5, 0xA5, 0x84, 0x43,
- 0xE5, 0xA5, 0x88, 0x43, 0xE5, 0xA5, 0x91, 0x43,
- 0xE5, 0xA5, 0x94, 0x43, 0xE5, 0xA5, 0xA2, 0x43,
- 0xE5, 0xA5, 0xB3, 0x43, 0xE5, 0xA7, 0x98, 0x43,
- 0xE5, 0xA7, 0xAC, 0x43, 0xE5, 0xA8, 0x9B, 0x43,
- 0xE5, 0xA8, 0xA7, 0x43, 0xE5, 0xA9, 0xA2, 0x43,
- 0xE5, 0xA9, 0xA6, 0x43, 0xE5, 0xAA, 0xB5, 0x43,
- 0xE5, 0xAC, 0x88, 0x43, 0xE5, 0xAC, 0xA8, 0x43,
- // Bytes a40 - a7f
- 0xE5, 0xAC, 0xBE, 0x43, 0xE5, 0xAD, 0x90, 0x43,
- 0xE5, 0xAD, 0x97, 0x43, 0xE5, 0xAD, 0xA6, 0x43,
- 0xE5, 0xAE, 0x80, 0x43, 0xE5, 0xAE, 0x85, 0x43,
- 0xE5, 0xAE, 0x97, 0x43, 0xE5, 0xAF, 0x83, 0x43,
- 0xE5, 0xAF, 0x98, 0x43, 0xE5, 0xAF, 0xA7, 0x43,
- 0xE5, 0xAF, 0xAE, 0x43, 0xE5, 0xAF, 0xB3, 0x43,
- 0xE5, 0xAF, 0xB8, 0x43, 0xE5, 0xAF, 0xBF, 0x43,
- 0xE5, 0xB0, 0x86, 0x43, 0xE5, 0xB0, 0x8F, 0x43,
- // Bytes a80 - abf
- 0xE5, 0xB0, 0xA2, 0x43, 0xE5, 0xB0, 0xB8, 0x43,
- 0xE5, 0xB0, 0xBF, 0x43, 0xE5, 0xB1, 0xA0, 0x43,
- 0xE5, 0xB1, 0xA2, 0x43, 0xE5, 0xB1, 0xA4, 0x43,
- 0xE5, 0xB1, 0xA5, 0x43, 0xE5, 0xB1, 0xAE, 0x43,
- 0xE5, 0xB1, 0xB1, 0x43, 0xE5, 0xB2, 0x8D, 0x43,
- 0xE5, 0xB3, 0x80, 0x43, 0xE5, 0xB4, 0x99, 0x43,
- 0xE5, 0xB5, 0x83, 0x43, 0xE5, 0xB5, 0x90, 0x43,
- 0xE5, 0xB5, 0xAB, 0x43, 0xE5, 0xB5, 0xAE, 0x43,
- // Bytes ac0 - aff
- 0xE5, 0xB5, 0xBC, 0x43, 0xE5, 0xB6, 0xB2, 0x43,
- 0xE5, 0xB6, 0xBA, 0x43, 0xE5, 0xB7, 0x9B, 0x43,
- 0xE5, 0xB7, 0xA1, 0x43, 0xE5, 0xB7, 0xA2, 0x43,
- 0xE5, 0xB7, 0xA5, 0x43, 0xE5, 0xB7, 0xA6, 0x43,
- 0xE5, 0xB7, 0xB1, 0x43, 0xE5, 0xB7, 0xBD, 0x43,
- 0xE5, 0xB7, 0xBE, 0x43, 0xE5, 0xB8, 0xA8, 0x43,
- 0xE5, 0xB8, 0xBD, 0x43, 0xE5, 0xB9, 0xA9, 0x43,
- 0xE5, 0xB9, 0xB2, 0x43, 0xE5, 0xB9, 0xB4, 0x43,
- // Bytes b00 - b3f
- 0xE5, 0xB9, 0xBA, 0x43, 0xE5, 0xB9, 0xBC, 0x43,
- 0xE5, 0xB9, 0xBF, 0x43, 0xE5, 0xBA, 0xA6, 0x43,
- 0xE5, 0xBA, 0xB0, 0x43, 0xE5, 0xBA, 0xB3, 0x43,
- 0xE5, 0xBA, 0xB6, 0x43, 0xE5, 0xBB, 0x89, 0x43,
- 0xE5, 0xBB, 0x8A, 0x43, 0xE5, 0xBB, 0x92, 0x43,
- 0xE5, 0xBB, 0x93, 0x43, 0xE5, 0xBB, 0x99, 0x43,
- 0xE5, 0xBB, 0xAC, 0x43, 0xE5, 0xBB, 0xB4, 0x43,
- 0xE5, 0xBB, 0xBE, 0x43, 0xE5, 0xBC, 0x84, 0x43,
- // Bytes b40 - b7f
- 0xE5, 0xBC, 0x8B, 0x43, 0xE5, 0xBC, 0x93, 0x43,
- 0xE5, 0xBC, 0xA2, 0x43, 0xE5, 0xBD, 0x90, 0x43,
- 0xE5, 0xBD, 0x93, 0x43, 0xE5, 0xBD, 0xA1, 0x43,
- 0xE5, 0xBD, 0xA2, 0x43, 0xE5, 0xBD, 0xA9, 0x43,
- 0xE5, 0xBD, 0xAB, 0x43, 0xE5, 0xBD, 0xB3, 0x43,
- 0xE5, 0xBE, 0x8B, 0x43, 0xE5, 0xBE, 0x8C, 0x43,
- 0xE5, 0xBE, 0x97, 0x43, 0xE5, 0xBE, 0x9A, 0x43,
- 0xE5, 0xBE, 0xA9, 0x43, 0xE5, 0xBE, 0xAD, 0x43,
- // Bytes b80 - bbf
- 0xE5, 0xBF, 0x83, 0x43, 0xE5, 0xBF, 0x8D, 0x43,
- 0xE5, 0xBF, 0x97, 0x43, 0xE5, 0xBF, 0xB5, 0x43,
- 0xE5, 0xBF, 0xB9, 0x43, 0xE6, 0x80, 0x92, 0x43,
- 0xE6, 0x80, 0x9C, 0x43, 0xE6, 0x81, 0xB5, 0x43,
- 0xE6, 0x82, 0x81, 0x43, 0xE6, 0x82, 0x94, 0x43,
- 0xE6, 0x83, 0x87, 0x43, 0xE6, 0x83, 0x98, 0x43,
- 0xE6, 0x83, 0xA1, 0x43, 0xE6, 0x84, 0x88, 0x43,
- 0xE6, 0x85, 0x84, 0x43, 0xE6, 0x85, 0x88, 0x43,
- // Bytes bc0 - bff
- 0xE6, 0x85, 0x8C, 0x43, 0xE6, 0x85, 0x8E, 0x43,
- 0xE6, 0x85, 0xA0, 0x43, 0xE6, 0x85, 0xA8, 0x43,
- 0xE6, 0x85, 0xBA, 0x43, 0xE6, 0x86, 0x8E, 0x43,
- 0xE6, 0x86, 0x90, 0x43, 0xE6, 0x86, 0xA4, 0x43,
- 0xE6, 0x86, 0xAF, 0x43, 0xE6, 0x86, 0xB2, 0x43,
- 0xE6, 0x87, 0x9E, 0x43, 0xE6, 0x87, 0xB2, 0x43,
- 0xE6, 0x87, 0xB6, 0x43, 0xE6, 0x88, 0x80, 0x43,
- 0xE6, 0x88, 0x88, 0x43, 0xE6, 0x88, 0x90, 0x43,
- // Bytes c00 - c3f
- 0xE6, 0x88, 0x9B, 0x43, 0xE6, 0x88, 0xAE, 0x43,
- 0xE6, 0x88, 0xB4, 0x43, 0xE6, 0x88, 0xB6, 0x43,
- 0xE6, 0x89, 0x8B, 0x43, 0xE6, 0x89, 0x93, 0x43,
- 0xE6, 0x89, 0x9D, 0x43, 0xE6, 0x8A, 0x95, 0x43,
- 0xE6, 0x8A, 0xB1, 0x43, 0xE6, 0x8B, 0x89, 0x43,
- 0xE6, 0x8B, 0x8F, 0x43, 0xE6, 0x8B, 0x93, 0x43,
- 0xE6, 0x8B, 0x94, 0x43, 0xE6, 0x8B, 0xBC, 0x43,
- 0xE6, 0x8B, 0xBE, 0x43, 0xE6, 0x8C, 0x87, 0x43,
- // Bytes c40 - c7f
- 0xE6, 0x8C, 0xBD, 0x43, 0xE6, 0x8D, 0x90, 0x43,
- 0xE6, 0x8D, 0x95, 0x43, 0xE6, 0x8D, 0xA8, 0x43,
- 0xE6, 0x8D, 0xBB, 0x43, 0xE6, 0x8E, 0x83, 0x43,
- 0xE6, 0x8E, 0xA0, 0x43, 0xE6, 0x8E, 0xA9, 0x43,
- 0xE6, 0x8F, 0x84, 0x43, 0xE6, 0x8F, 0x85, 0x43,
- 0xE6, 0x8F, 0xA4, 0x43, 0xE6, 0x90, 0x9C, 0x43,
- 0xE6, 0x90, 0xA2, 0x43, 0xE6, 0x91, 0x92, 0x43,
- 0xE6, 0x91, 0xA9, 0x43, 0xE6, 0x91, 0xB7, 0x43,
- // Bytes c80 - cbf
- 0xE6, 0x91, 0xBE, 0x43, 0xE6, 0x92, 0x9A, 0x43,
- 0xE6, 0x92, 0x9D, 0x43, 0xE6, 0x93, 0x84, 0x43,
- 0xE6, 0x94, 0xAF, 0x43, 0xE6, 0x94, 0xB4, 0x43,
- 0xE6, 0x95, 0x8F, 0x43, 0xE6, 0x95, 0x96, 0x43,
- 0xE6, 0x95, 0xAC, 0x43, 0xE6, 0x95, 0xB8, 0x43,
- 0xE6, 0x96, 0x87, 0x43, 0xE6, 0x96, 0x97, 0x43,
- 0xE6, 0x96, 0x99, 0x43, 0xE6, 0x96, 0xA4, 0x43,
- 0xE6, 0x96, 0xB0, 0x43, 0xE6, 0x96, 0xB9, 0x43,
- // Bytes cc0 - cff
- 0xE6, 0x97, 0x85, 0x43, 0xE6, 0x97, 0xA0, 0x43,
- 0xE6, 0x97, 0xA2, 0x43, 0xE6, 0x97, 0xA3, 0x43,
- 0xE6, 0x97, 0xA5, 0x43, 0xE6, 0x98, 0x93, 0x43,
- 0xE6, 0x98, 0xA0, 0x43, 0xE6, 0x99, 0x89, 0x43,
- 0xE6, 0x99, 0xB4, 0x43, 0xE6, 0x9A, 0x88, 0x43,
- 0xE6, 0x9A, 0x91, 0x43, 0xE6, 0x9A, 0x9C, 0x43,
- 0xE6, 0x9A, 0xB4, 0x43, 0xE6, 0x9B, 0x86, 0x43,
- 0xE6, 0x9B, 0xB0, 0x43, 0xE6, 0x9B, 0xB4, 0x43,
- // Bytes d00 - d3f
- 0xE6, 0x9B, 0xB8, 0x43, 0xE6, 0x9C, 0x80, 0x43,
- 0xE6, 0x9C, 0x88, 0x43, 0xE6, 0x9C, 0x89, 0x43,
- 0xE6, 0x9C, 0x97, 0x43, 0xE6, 0x9C, 0x9B, 0x43,
- 0xE6, 0x9C, 0xA1, 0x43, 0xE6, 0x9C, 0xA8, 0x43,
- 0xE6, 0x9D, 0x8E, 0x43, 0xE6, 0x9D, 0x93, 0x43,
- 0xE6, 0x9D, 0x96, 0x43, 0xE6, 0x9D, 0x9E, 0x43,
- 0xE6, 0x9D, 0xBB, 0x43, 0xE6, 0x9E, 0x85, 0x43,
- 0xE6, 0x9E, 0x97, 0x43, 0xE6, 0x9F, 0xB3, 0x43,
- // Bytes d40 - d7f
- 0xE6, 0x9F, 0xBA, 0x43, 0xE6, 0xA0, 0x97, 0x43,
- 0xE6, 0xA0, 0x9F, 0x43, 0xE6, 0xA0, 0xAA, 0x43,
- 0xE6, 0xA1, 0x92, 0x43, 0xE6, 0xA2, 0x81, 0x43,
- 0xE6, 0xA2, 0x85, 0x43, 0xE6, 0xA2, 0x8E, 0x43,
- 0xE6, 0xA2, 0xA8, 0x43, 0xE6, 0xA4, 0x94, 0x43,
- 0xE6, 0xA5, 0x82, 0x43, 0xE6, 0xA6, 0xA3, 0x43,
- 0xE6, 0xA7, 0xAA, 0x43, 0xE6, 0xA8, 0x82, 0x43,
- 0xE6, 0xA8, 0x93, 0x43, 0xE6, 0xAA, 0xA8, 0x43,
- // Bytes d80 - dbf
- 0xE6, 0xAB, 0x93, 0x43, 0xE6, 0xAB, 0x9B, 0x43,
- 0xE6, 0xAC, 0x84, 0x43, 0xE6, 0xAC, 0xA0, 0x43,
- 0xE6, 0xAC, 0xA1, 0x43, 0xE6, 0xAD, 0x94, 0x43,
- 0xE6, 0xAD, 0xA2, 0x43, 0xE6, 0xAD, 0xA3, 0x43,
- 0xE6, 0xAD, 0xB2, 0x43, 0xE6, 0xAD, 0xB7, 0x43,
- 0xE6, 0xAD, 0xB9, 0x43, 0xE6, 0xAE, 0x9F, 0x43,
- 0xE6, 0xAE, 0xAE, 0x43, 0xE6, 0xAE, 0xB3, 0x43,
- 0xE6, 0xAE, 0xBA, 0x43, 0xE6, 0xAE, 0xBB, 0x43,
- // Bytes dc0 - dff
- 0xE6, 0xAF, 0x8B, 0x43, 0xE6, 0xAF, 0x8D, 0x43,
- 0xE6, 0xAF, 0x94, 0x43, 0xE6, 0xAF, 0x9B, 0x43,
- 0xE6, 0xB0, 0x8F, 0x43, 0xE6, 0xB0, 0x94, 0x43,
- 0xE6, 0xB0, 0xB4, 0x43, 0xE6, 0xB1, 0x8E, 0x43,
- 0xE6, 0xB1, 0xA7, 0x43, 0xE6, 0xB2, 0x88, 0x43,
- 0xE6, 0xB2, 0xBF, 0x43, 0xE6, 0xB3, 0x8C, 0x43,
- 0xE6, 0xB3, 0x8D, 0x43, 0xE6, 0xB3, 0xA5, 0x43,
- 0xE6, 0xB3, 0xA8, 0x43, 0xE6, 0xB4, 0x96, 0x43,
- // Bytes e00 - e3f
- 0xE6, 0xB4, 0x9B, 0x43, 0xE6, 0xB4, 0x9E, 0x43,
- 0xE6, 0xB4, 0xB4, 0x43, 0xE6, 0xB4, 0xBE, 0x43,
- 0xE6, 0xB5, 0x81, 0x43, 0xE6, 0xB5, 0xA9, 0x43,
- 0xE6, 0xB5, 0xAA, 0x43, 0xE6, 0xB5, 0xB7, 0x43,
- 0xE6, 0xB5, 0xB8, 0x43, 0xE6, 0xB6, 0x85, 0x43,
- 0xE6, 0xB7, 0x8B, 0x43, 0xE6, 0xB7, 0x9A, 0x43,
- 0xE6, 0xB7, 0xAA, 0x43, 0xE6, 0xB7, 0xB9, 0x43,
- 0xE6, 0xB8, 0x9A, 0x43, 0xE6, 0xB8, 0xAF, 0x43,
- // Bytes e40 - e7f
- 0xE6, 0xB9, 0xAE, 0x43, 0xE6, 0xBA, 0x80, 0x43,
- 0xE6, 0xBA, 0x9C, 0x43, 0xE6, 0xBA, 0xBA, 0x43,
- 0xE6, 0xBB, 0x87, 0x43, 0xE6, 0xBB, 0x8B, 0x43,
- 0xE6, 0xBB, 0x91, 0x43, 0xE6, 0xBB, 0x9B, 0x43,
- 0xE6, 0xBC, 0x8F, 0x43, 0xE6, 0xBC, 0x94, 0x43,
- 0xE6, 0xBC, 0xA2, 0x43, 0xE6, 0xBC, 0xA3, 0x43,
- 0xE6, 0xBD, 0xAE, 0x43, 0xE6, 0xBF, 0x86, 0x43,
- 0xE6, 0xBF, 0xAB, 0x43, 0xE6, 0xBF, 0xBE, 0x43,
- // Bytes e80 - ebf
- 0xE7, 0x80, 0x9B, 0x43, 0xE7, 0x80, 0x9E, 0x43,
- 0xE7, 0x80, 0xB9, 0x43, 0xE7, 0x81, 0x8A, 0x43,
- 0xE7, 0x81, 0xAB, 0x43, 0xE7, 0x81, 0xB0, 0x43,
- 0xE7, 0x81, 0xB7, 0x43, 0xE7, 0x81, 0xBD, 0x43,
- 0xE7, 0x82, 0x99, 0x43, 0xE7, 0x82, 0xAD, 0x43,
- 0xE7, 0x83, 0x88, 0x43, 0xE7, 0x83, 0x99, 0x43,
- 0xE7, 0x84, 0xA1, 0x43, 0xE7, 0x85, 0x85, 0x43,
- 0xE7, 0x85, 0x89, 0x43, 0xE7, 0x85, 0xAE, 0x43,
- // Bytes ec0 - eff
- 0xE7, 0x86, 0x9C, 0x43, 0xE7, 0x87, 0x8E, 0x43,
- 0xE7, 0x87, 0x90, 0x43, 0xE7, 0x88, 0x90, 0x43,
- 0xE7, 0x88, 0x9B, 0x43, 0xE7, 0x88, 0xA8, 0x43,
- 0xE7, 0x88, 0xAA, 0x43, 0xE7, 0x88, 0xAB, 0x43,
- 0xE7, 0x88, 0xB5, 0x43, 0xE7, 0x88, 0xB6, 0x43,
- 0xE7, 0x88, 0xBB, 0x43, 0xE7, 0x88, 0xBF, 0x43,
- 0xE7, 0x89, 0x87, 0x43, 0xE7, 0x89, 0x90, 0x43,
- 0xE7, 0x89, 0x99, 0x43, 0xE7, 0x89, 0x9B, 0x43,
- // Bytes f00 - f3f
- 0xE7, 0x89, 0xA2, 0x43, 0xE7, 0x89, 0xB9, 0x43,
- 0xE7, 0x8A, 0x80, 0x43, 0xE7, 0x8A, 0x95, 0x43,
- 0xE7, 0x8A, 0xAC, 0x43, 0xE7, 0x8A, 0xAF, 0x43,
- 0xE7, 0x8B, 0x80, 0x43, 0xE7, 0x8B, 0xBC, 0x43,
- 0xE7, 0x8C, 0xAA, 0x43, 0xE7, 0x8D, 0xB5, 0x43,
- 0xE7, 0x8D, 0xBA, 0x43, 0xE7, 0x8E, 0x84, 0x43,
- 0xE7, 0x8E, 0x87, 0x43, 0xE7, 0x8E, 0x89, 0x43,
- 0xE7, 0x8E, 0x8B, 0x43, 0xE7, 0x8E, 0xA5, 0x43,
- // Bytes f40 - f7f
- 0xE7, 0x8E, 0xB2, 0x43, 0xE7, 0x8F, 0x9E, 0x43,
- 0xE7, 0x90, 0x86, 0x43, 0xE7, 0x90, 0x89, 0x43,
- 0xE7, 0x90, 0xA2, 0x43, 0xE7, 0x91, 0x87, 0x43,
- 0xE7, 0x91, 0x9C, 0x43, 0xE7, 0x91, 0xA9, 0x43,
- 0xE7, 0x91, 0xB1, 0x43, 0xE7, 0x92, 0x85, 0x43,
- 0xE7, 0x92, 0x89, 0x43, 0xE7, 0x92, 0x98, 0x43,
- 0xE7, 0x93, 0x8A, 0x43, 0xE7, 0x93, 0x9C, 0x43,
- 0xE7, 0x93, 0xA6, 0x43, 0xE7, 0x94, 0x86, 0x43,
- // Bytes f80 - fbf
- 0xE7, 0x94, 0x98, 0x43, 0xE7, 0x94, 0x9F, 0x43,
- 0xE7, 0x94, 0xA4, 0x43, 0xE7, 0x94, 0xA8, 0x43,
- 0xE7, 0x94, 0xB0, 0x43, 0xE7, 0x94, 0xB2, 0x43,
- 0xE7, 0x94, 0xB3, 0x43, 0xE7, 0x94, 0xB7, 0x43,
- 0xE7, 0x94, 0xBB, 0x43, 0xE7, 0x94, 0xBE, 0x43,
- 0xE7, 0x95, 0x99, 0x43, 0xE7, 0x95, 0xA5, 0x43,
- 0xE7, 0x95, 0xB0, 0x43, 0xE7, 0x96, 0x8B, 0x43,
- 0xE7, 0x96, 0x92, 0x43, 0xE7, 0x97, 0xA2, 0x43,
- // Bytes fc0 - fff
- 0xE7, 0x98, 0x90, 0x43, 0xE7, 0x98, 0x9D, 0x43,
- 0xE7, 0x98, 0x9F, 0x43, 0xE7, 0x99, 0x82, 0x43,
- 0xE7, 0x99, 0xA9, 0x43, 0xE7, 0x99, 0xB6, 0x43,
- 0xE7, 0x99, 0xBD, 0x43, 0xE7, 0x9A, 0xAE, 0x43,
- 0xE7, 0x9A, 0xBF, 0x43, 0xE7, 0x9B, 0x8A, 0x43,
- 0xE7, 0x9B, 0x9B, 0x43, 0xE7, 0x9B, 0xA3, 0x43,
- 0xE7, 0x9B, 0xA7, 0x43, 0xE7, 0x9B, 0xAE, 0x43,
- 0xE7, 0x9B, 0xB4, 0x43, 0xE7, 0x9C, 0x81, 0x43,
- // Bytes 1000 - 103f
- 0xE7, 0x9C, 0x9E, 0x43, 0xE7, 0x9C, 0x9F, 0x43,
- 0xE7, 0x9D, 0x80, 0x43, 0xE7, 0x9D, 0x8A, 0x43,
- 0xE7, 0x9E, 0x8B, 0x43, 0xE7, 0x9E, 0xA7, 0x43,
- 0xE7, 0x9F, 0x9B, 0x43, 0xE7, 0x9F, 0xA2, 0x43,
- 0xE7, 0x9F, 0xB3, 0x43, 0xE7, 0xA1, 0x8E, 0x43,
- 0xE7, 0xA1, 0xAB, 0x43, 0xE7, 0xA2, 0x8C, 0x43,
- 0xE7, 0xA2, 0x91, 0x43, 0xE7, 0xA3, 0x8A, 0x43,
- 0xE7, 0xA3, 0x8C, 0x43, 0xE7, 0xA3, 0xBB, 0x43,
- // Bytes 1040 - 107f
- 0xE7, 0xA4, 0xAA, 0x43, 0xE7, 0xA4, 0xBA, 0x43,
- 0xE7, 0xA4, 0xBC, 0x43, 0xE7, 0xA4, 0xBE, 0x43,
- 0xE7, 0xA5, 0x88, 0x43, 0xE7, 0xA5, 0x89, 0x43,
- 0xE7, 0xA5, 0x90, 0x43, 0xE7, 0xA5, 0x96, 0x43,
- 0xE7, 0xA5, 0x9D, 0x43, 0xE7, 0xA5, 0x9E, 0x43,
- 0xE7, 0xA5, 0xA5, 0x43, 0xE7, 0xA5, 0xBF, 0x43,
- 0xE7, 0xA6, 0x81, 0x43, 0xE7, 0xA6, 0x8D, 0x43,
- 0xE7, 0xA6, 0x8E, 0x43, 0xE7, 0xA6, 0x8F, 0x43,
- // Bytes 1080 - 10bf
- 0xE7, 0xA6, 0xAE, 0x43, 0xE7, 0xA6, 0xB8, 0x43,
- 0xE7, 0xA6, 0xBE, 0x43, 0xE7, 0xA7, 0x8A, 0x43,
- 0xE7, 0xA7, 0x98, 0x43, 0xE7, 0xA7, 0xAB, 0x43,
- 0xE7, 0xA8, 0x9C, 0x43, 0xE7, 0xA9, 0x80, 0x43,
- 0xE7, 0xA9, 0x8A, 0x43, 0xE7, 0xA9, 0x8F, 0x43,
- 0xE7, 0xA9, 0xB4, 0x43, 0xE7, 0xA9, 0xBA, 0x43,
- 0xE7, 0xAA, 0x81, 0x43, 0xE7, 0xAA, 0xB1, 0x43,
- 0xE7, 0xAB, 0x8B, 0x43, 0xE7, 0xAB, 0xAE, 0x43,
- // Bytes 10c0 - 10ff
- 0xE7, 0xAB, 0xB9, 0x43, 0xE7, 0xAC, 0xA0, 0x43,
- 0xE7, 0xAE, 0x8F, 0x43, 0xE7, 0xAF, 0x80, 0x43,
- 0xE7, 0xAF, 0x86, 0x43, 0xE7, 0xAF, 0x89, 0x43,
- 0xE7, 0xB0, 0xBE, 0x43, 0xE7, 0xB1, 0xA0, 0x43,
- 0xE7, 0xB1, 0xB3, 0x43, 0xE7, 0xB1, 0xBB, 0x43,
- 0xE7, 0xB2, 0x92, 0x43, 0xE7, 0xB2, 0xBE, 0x43,
- 0xE7, 0xB3, 0x92, 0x43, 0xE7, 0xB3, 0x96, 0x43,
- 0xE7, 0xB3, 0xA3, 0x43, 0xE7, 0xB3, 0xA7, 0x43,
- // Bytes 1100 - 113f
- 0xE7, 0xB3, 0xA8, 0x43, 0xE7, 0xB3, 0xB8, 0x43,
- 0xE7, 0xB4, 0x80, 0x43, 0xE7, 0xB4, 0x90, 0x43,
- 0xE7, 0xB4, 0xA2, 0x43, 0xE7, 0xB4, 0xAF, 0x43,
- 0xE7, 0xB5, 0x82, 0x43, 0xE7, 0xB5, 0x9B, 0x43,
- 0xE7, 0xB5, 0xA3, 0x43, 0xE7, 0xB6, 0xA0, 0x43,
- 0xE7, 0xB6, 0xBE, 0x43, 0xE7, 0xB7, 0x87, 0x43,
- 0xE7, 0xB7, 0xB4, 0x43, 0xE7, 0xB8, 0x82, 0x43,
- 0xE7, 0xB8, 0x89, 0x43, 0xE7, 0xB8, 0xB7, 0x43,
- // Bytes 1140 - 117f
- 0xE7, 0xB9, 0x81, 0x43, 0xE7, 0xB9, 0x85, 0x43,
- 0xE7, 0xBC, 0xB6, 0x43, 0xE7, 0xBC, 0xBE, 0x43,
- 0xE7, 0xBD, 0x91, 0x43, 0xE7, 0xBD, 0xB2, 0x43,
- 0xE7, 0xBD, 0xB9, 0x43, 0xE7, 0xBD, 0xBA, 0x43,
- 0xE7, 0xBE, 0x85, 0x43, 0xE7, 0xBE, 0x8A, 0x43,
- 0xE7, 0xBE, 0x95, 0x43, 0xE7, 0xBE, 0x9A, 0x43,
- 0xE7, 0xBE, 0xBD, 0x43, 0xE7, 0xBF, 0xBA, 0x43,
- 0xE8, 0x80, 0x81, 0x43, 0xE8, 0x80, 0x85, 0x43,
- // Bytes 1180 - 11bf
- 0xE8, 0x80, 0x8C, 0x43, 0xE8, 0x80, 0x92, 0x43,
- 0xE8, 0x80, 0xB3, 0x43, 0xE8, 0x81, 0x86, 0x43,
- 0xE8, 0x81, 0xA0, 0x43, 0xE8, 0x81, 0xAF, 0x43,
- 0xE8, 0x81, 0xB0, 0x43, 0xE8, 0x81, 0xBE, 0x43,
- 0xE8, 0x81, 0xBF, 0x43, 0xE8, 0x82, 0x89, 0x43,
- 0xE8, 0x82, 0x8B, 0x43, 0xE8, 0x82, 0xAD, 0x43,
- 0xE8, 0x82, 0xB2, 0x43, 0xE8, 0x84, 0x83, 0x43,
- 0xE8, 0x84, 0xBE, 0x43, 0xE8, 0x87, 0x98, 0x43,
- // Bytes 11c0 - 11ff
- 0xE8, 0x87, 0xA3, 0x43, 0xE8, 0x87, 0xA8, 0x43,
- 0xE8, 0x87, 0xAA, 0x43, 0xE8, 0x87, 0xAD, 0x43,
- 0xE8, 0x87, 0xB3, 0x43, 0xE8, 0x87, 0xBC, 0x43,
- 0xE8, 0x88, 0x81, 0x43, 0xE8, 0x88, 0x84, 0x43,
- 0xE8, 0x88, 0x8C, 0x43, 0xE8, 0x88, 0x98, 0x43,
- 0xE8, 0x88, 0x9B, 0x43, 0xE8, 0x88, 0x9F, 0x43,
- 0xE8, 0x89, 0xAE, 0x43, 0xE8, 0x89, 0xAF, 0x43,
- 0xE8, 0x89, 0xB2, 0x43, 0xE8, 0x89, 0xB8, 0x43,
- // Bytes 1200 - 123f
- 0xE8, 0x89, 0xB9, 0x43, 0xE8, 0x8A, 0x8B, 0x43,
- 0xE8, 0x8A, 0x91, 0x43, 0xE8, 0x8A, 0x9D, 0x43,
- 0xE8, 0x8A, 0xB1, 0x43, 0xE8, 0x8A, 0xB3, 0x43,
- 0xE8, 0x8A, 0xBD, 0x43, 0xE8, 0x8B, 0xA5, 0x43,
- 0xE8, 0x8B, 0xA6, 0x43, 0xE8, 0x8C, 0x9D, 0x43,
- 0xE8, 0x8C, 0xA3, 0x43, 0xE8, 0x8C, 0xB6, 0x43,
- 0xE8, 0x8D, 0x92, 0x43, 0xE8, 0x8D, 0x93, 0x43,
- 0xE8, 0x8D, 0xA3, 0x43, 0xE8, 0x8E, 0xAD, 0x43,
- // Bytes 1240 - 127f
- 0xE8, 0x8E, 0xBD, 0x43, 0xE8, 0x8F, 0x89, 0x43,
- 0xE8, 0x8F, 0x8A, 0x43, 0xE8, 0x8F, 0x8C, 0x43,
- 0xE8, 0x8F, 0x9C, 0x43, 0xE8, 0x8F, 0xA7, 0x43,
- 0xE8, 0x8F, 0xAF, 0x43, 0xE8, 0x8F, 0xB1, 0x43,
- 0xE8, 0x90, 0xBD, 0x43, 0xE8, 0x91, 0x89, 0x43,
- 0xE8, 0x91, 0x97, 0x43, 0xE8, 0x93, 0xAE, 0x43,
- 0xE8, 0x93, 0xB1, 0x43, 0xE8, 0x93, 0xB3, 0x43,
- 0xE8, 0x93, 0xBC, 0x43, 0xE8, 0x94, 0x96, 0x43,
- // Bytes 1280 - 12bf
- 0xE8, 0x95, 0xA4, 0x43, 0xE8, 0x97, 0x8D, 0x43,
- 0xE8, 0x97, 0xBA, 0x43, 0xE8, 0x98, 0x86, 0x43,
- 0xE8, 0x98, 0x92, 0x43, 0xE8, 0x98, 0xAD, 0x43,
- 0xE8, 0x98, 0xBF, 0x43, 0xE8, 0x99, 0x8D, 0x43,
- 0xE8, 0x99, 0x90, 0x43, 0xE8, 0x99, 0x9C, 0x43,
- 0xE8, 0x99, 0xA7, 0x43, 0xE8, 0x99, 0xA9, 0x43,
- 0xE8, 0x99, 0xAB, 0x43, 0xE8, 0x9A, 0x88, 0x43,
- 0xE8, 0x9A, 0xA9, 0x43, 0xE8, 0x9B, 0xA2, 0x43,
- // Bytes 12c0 - 12ff
- 0xE8, 0x9C, 0x8E, 0x43, 0xE8, 0x9C, 0xA8, 0x43,
- 0xE8, 0x9D, 0xAB, 0x43, 0xE8, 0x9D, 0xB9, 0x43,
- 0xE8, 0x9E, 0x86, 0x43, 0xE8, 0x9E, 0xBA, 0x43,
- 0xE8, 0x9F, 0xA1, 0x43, 0xE8, 0xA0, 0x81, 0x43,
- 0xE8, 0xA0, 0x9F, 0x43, 0xE8, 0xA1, 0x80, 0x43,
- 0xE8, 0xA1, 0x8C, 0x43, 0xE8, 0xA1, 0xA0, 0x43,
- 0xE8, 0xA1, 0xA3, 0x43, 0xE8, 0xA3, 0x82, 0x43,
- 0xE8, 0xA3, 0x8F, 0x43, 0xE8, 0xA3, 0x97, 0x43,
- // Bytes 1300 - 133f
- 0xE8, 0xA3, 0x9E, 0x43, 0xE8, 0xA3, 0xA1, 0x43,
- 0xE8, 0xA3, 0xB8, 0x43, 0xE8, 0xA3, 0xBA, 0x43,
- 0xE8, 0xA4, 0x90, 0x43, 0xE8, 0xA5, 0x81, 0x43,
- 0xE8, 0xA5, 0xA4, 0x43, 0xE8, 0xA5, 0xBE, 0x43,
- 0xE8, 0xA6, 0x86, 0x43, 0xE8, 0xA6, 0x8B, 0x43,
- 0xE8, 0xA6, 0x96, 0x43, 0xE8, 0xA7, 0x92, 0x43,
- 0xE8, 0xA7, 0xA3, 0x43, 0xE8, 0xA8, 0x80, 0x43,
- 0xE8, 0xAA, 0xA0, 0x43, 0xE8, 0xAA, 0xAA, 0x43,
- // Bytes 1340 - 137f
- 0xE8, 0xAA, 0xBF, 0x43, 0xE8, 0xAB, 0x8B, 0x43,
- 0xE8, 0xAB, 0x92, 0x43, 0xE8, 0xAB, 0x96, 0x43,
- 0xE8, 0xAB, 0xAD, 0x43, 0xE8, 0xAB, 0xB8, 0x43,
- 0xE8, 0xAB, 0xBE, 0x43, 0xE8, 0xAC, 0x81, 0x43,
- 0xE8, 0xAC, 0xB9, 0x43, 0xE8, 0xAD, 0x98, 0x43,
- 0xE8, 0xAE, 0x80, 0x43, 0xE8, 0xAE, 0x8A, 0x43,
- 0xE8, 0xB0, 0xB7, 0x43, 0xE8, 0xB1, 0x86, 0x43,
- 0xE8, 0xB1, 0x88, 0x43, 0xE8, 0xB1, 0x95, 0x43,
- // Bytes 1380 - 13bf
- 0xE8, 0xB1, 0xB8, 0x43, 0xE8, 0xB2, 0x9D, 0x43,
- 0xE8, 0xB2, 0xA1, 0x43, 0xE8, 0xB2, 0xA9, 0x43,
- 0xE8, 0xB2, 0xAB, 0x43, 0xE8, 0xB3, 0x81, 0x43,
- 0xE8, 0xB3, 0x82, 0x43, 0xE8, 0xB3, 0x87, 0x43,
- 0xE8, 0xB3, 0x88, 0x43, 0xE8, 0xB3, 0x93, 0x43,
- 0xE8, 0xB4, 0x88, 0x43, 0xE8, 0xB4, 0x9B, 0x43,
- 0xE8, 0xB5, 0xA4, 0x43, 0xE8, 0xB5, 0xB0, 0x43,
- 0xE8, 0xB5, 0xB7, 0x43, 0xE8, 0xB6, 0xB3, 0x43,
- // Bytes 13c0 - 13ff
- 0xE8, 0xB6, 0xBC, 0x43, 0xE8, 0xB7, 0x8B, 0x43,
- 0xE8, 0xB7, 0xAF, 0x43, 0xE8, 0xB7, 0xB0, 0x43,
- 0xE8, 0xBA, 0xAB, 0x43, 0xE8, 0xBB, 0x8A, 0x43,
- 0xE8, 0xBB, 0x94, 0x43, 0xE8, 0xBC, 0xA6, 0x43,
- 0xE8, 0xBC, 0xAA, 0x43, 0xE8, 0xBC, 0xB8, 0x43,
- 0xE8, 0xBC, 0xBB, 0x43, 0xE8, 0xBD, 0xA2, 0x43,
- 0xE8, 0xBE, 0x9B, 0x43, 0xE8, 0xBE, 0x9E, 0x43,
- 0xE8, 0xBE, 0xB0, 0x43, 0xE8, 0xBE, 0xB5, 0x43,
- // Bytes 1400 - 143f
- 0xE8, 0xBE, 0xB6, 0x43, 0xE9, 0x80, 0xA3, 0x43,
- 0xE9, 0x80, 0xB8, 0x43, 0xE9, 0x81, 0x8A, 0x43,
- 0xE9, 0x81, 0xA9, 0x43, 0xE9, 0x81, 0xB2, 0x43,
- 0xE9, 0x81, 0xBC, 0x43, 0xE9, 0x82, 0x8F, 0x43,
- 0xE9, 0x82, 0x91, 0x43, 0xE9, 0x82, 0x94, 0x43,
- 0xE9, 0x83, 0x8E, 0x43, 0xE9, 0x83, 0x9E, 0x43,
- 0xE9, 0x83, 0xB1, 0x43, 0xE9, 0x83, 0xBD, 0x43,
- 0xE9, 0x84, 0x91, 0x43, 0xE9, 0x84, 0x9B, 0x43,
- // Bytes 1440 - 147f
- 0xE9, 0x85, 0x89, 0x43, 0xE9, 0x85, 0x8D, 0x43,
- 0xE9, 0x85, 0xAA, 0x43, 0xE9, 0x86, 0x99, 0x43,
- 0xE9, 0x86, 0xB4, 0x43, 0xE9, 0x87, 0x86, 0x43,
- 0xE9, 0x87, 0x8C, 0x43, 0xE9, 0x87, 0x8F, 0x43,
- 0xE9, 0x87, 0x91, 0x43, 0xE9, 0x88, 0xB4, 0x43,
- 0xE9, 0x88, 0xB8, 0x43, 0xE9, 0x89, 0xB6, 0x43,
- 0xE9, 0x89, 0xBC, 0x43, 0xE9, 0x8B, 0x97, 0x43,
- 0xE9, 0x8B, 0x98, 0x43, 0xE9, 0x8C, 0x84, 0x43,
- // Bytes 1480 - 14bf
- 0xE9, 0x8D, 0x8A, 0x43, 0xE9, 0x8F, 0xB9, 0x43,
- 0xE9, 0x90, 0x95, 0x43, 0xE9, 0x95, 0xB7, 0x43,
- 0xE9, 0x96, 0x80, 0x43, 0xE9, 0x96, 0x8B, 0x43,
- 0xE9, 0x96, 0xAD, 0x43, 0xE9, 0x96, 0xB7, 0x43,
- 0xE9, 0x98, 0x9C, 0x43, 0xE9, 0x98, 0xAE, 0x43,
- 0xE9, 0x99, 0x8B, 0x43, 0xE9, 0x99, 0x8D, 0x43,
- 0xE9, 0x99, 0xB5, 0x43, 0xE9, 0x99, 0xB8, 0x43,
- 0xE9, 0x99, 0xBC, 0x43, 0xE9, 0x9A, 0x86, 0x43,
- // Bytes 14c0 - 14ff
- 0xE9, 0x9A, 0xA3, 0x43, 0xE9, 0x9A, 0xB6, 0x43,
- 0xE9, 0x9A, 0xB7, 0x43, 0xE9, 0x9A, 0xB8, 0x43,
- 0xE9, 0x9A, 0xB9, 0x43, 0xE9, 0x9B, 0x83, 0x43,
- 0xE9, 0x9B, 0xA2, 0x43, 0xE9, 0x9B, 0xA3, 0x43,
- 0xE9, 0x9B, 0xA8, 0x43, 0xE9, 0x9B, 0xB6, 0x43,
- 0xE9, 0x9B, 0xB7, 0x43, 0xE9, 0x9C, 0xA3, 0x43,
- 0xE9, 0x9C, 0xB2, 0x43, 0xE9, 0x9D, 0x88, 0x43,
- 0xE9, 0x9D, 0x91, 0x43, 0xE9, 0x9D, 0x96, 0x43,
- // Bytes 1500 - 153f
- 0xE9, 0x9D, 0x9E, 0x43, 0xE9, 0x9D, 0xA2, 0x43,
- 0xE9, 0x9D, 0xA9, 0x43, 0xE9, 0x9F, 0x8B, 0x43,
- 0xE9, 0x9F, 0x9B, 0x43, 0xE9, 0x9F, 0xA0, 0x43,
- 0xE9, 0x9F, 0xAD, 0x43, 0xE9, 0x9F, 0xB3, 0x43,
- 0xE9, 0x9F, 0xBF, 0x43, 0xE9, 0xA0, 0x81, 0x43,
- 0xE9, 0xA0, 0x85, 0x43, 0xE9, 0xA0, 0x8B, 0x43,
- 0xE9, 0xA0, 0x98, 0x43, 0xE9, 0xA0, 0xA9, 0x43,
- 0xE9, 0xA0, 0xBB, 0x43, 0xE9, 0xA1, 0x9E, 0x43,
- // Bytes 1540 - 157f
- 0xE9, 0xA2, 0xA8, 0x43, 0xE9, 0xA3, 0x9B, 0x43,
- 0xE9, 0xA3, 0x9F, 0x43, 0xE9, 0xA3, 0xA2, 0x43,
- 0xE9, 0xA3, 0xAF, 0x43, 0xE9, 0xA3, 0xBC, 0x43,
- 0xE9, 0xA4, 0xA8, 0x43, 0xE9, 0xA4, 0xA9, 0x43,
- 0xE9, 0xA6, 0x96, 0x43, 0xE9, 0xA6, 0x99, 0x43,
- 0xE9, 0xA6, 0xA7, 0x43, 0xE9, 0xA6, 0xAC, 0x43,
- 0xE9, 0xA7, 0x82, 0x43, 0xE9, 0xA7, 0xB1, 0x43,
- 0xE9, 0xA7, 0xBE, 0x43, 0xE9, 0xA9, 0xAA, 0x43,
- // Bytes 1580 - 15bf
- 0xE9, 0xAA, 0xA8, 0x43, 0xE9, 0xAB, 0x98, 0x43,
- 0xE9, 0xAB, 0x9F, 0x43, 0xE9, 0xAC, 0x92, 0x43,
- 0xE9, 0xAC, 0xA5, 0x43, 0xE9, 0xAC, 0xAF, 0x43,
- 0xE9, 0xAC, 0xB2, 0x43, 0xE9, 0xAC, 0xBC, 0x43,
- 0xE9, 0xAD, 0x9A, 0x43, 0xE9, 0xAD, 0xAF, 0x43,
- 0xE9, 0xB1, 0x80, 0x43, 0xE9, 0xB1, 0x97, 0x43,
- 0xE9, 0xB3, 0xA5, 0x43, 0xE9, 0xB3, 0xBD, 0x43,
- 0xE9, 0xB5, 0xA7, 0x43, 0xE9, 0xB6, 0xB4, 0x43,
- // Bytes 15c0 - 15ff
- 0xE9, 0xB7, 0xBA, 0x43, 0xE9, 0xB8, 0x9E, 0x43,
- 0xE9, 0xB9, 0xB5, 0x43, 0xE9, 0xB9, 0xBF, 0x43,
- 0xE9, 0xBA, 0x97, 0x43, 0xE9, 0xBA, 0x9F, 0x43,
- 0xE9, 0xBA, 0xA5, 0x43, 0xE9, 0xBA, 0xBB, 0x43,
- 0xE9, 0xBB, 0x83, 0x43, 0xE9, 0xBB, 0x8D, 0x43,
- 0xE9, 0xBB, 0x8E, 0x43, 0xE9, 0xBB, 0x91, 0x43,
- 0xE9, 0xBB, 0xB9, 0x43, 0xE9, 0xBB, 0xBD, 0x43,
- 0xE9, 0xBB, 0xBE, 0x43, 0xE9, 0xBC, 0x85, 0x43,
- // Bytes 1600 - 163f
- 0xE9, 0xBC, 0x8E, 0x43, 0xE9, 0xBC, 0x8F, 0x43,
- 0xE9, 0xBC, 0x93, 0x43, 0xE9, 0xBC, 0x96, 0x43,
- 0xE9, 0xBC, 0xA0, 0x43, 0xE9, 0xBC, 0xBB, 0x43,
- 0xE9, 0xBD, 0x83, 0x43, 0xE9, 0xBD, 0x8A, 0x43,
- 0xE9, 0xBD, 0x92, 0x43, 0xE9, 0xBE, 0x8D, 0x43,
- 0xE9, 0xBE, 0x8E, 0x43, 0xE9, 0xBE, 0x9C, 0x43,
- 0xE9, 0xBE, 0x9F, 0x43, 0xE9, 0xBE, 0xA0, 0x43,
- 0xEA, 0x9C, 0xA7, 0x43, 0xEA, 0x9D, 0xAF, 0x43,
- // Bytes 1640 - 167f
- 0xEA, 0xAC, 0xB7, 0x43, 0xEA, 0xAD, 0x92, 0x44,
- 0xF0, 0xA0, 0x84, 0xA2, 0x44, 0xF0, 0xA0, 0x94,
- 0x9C, 0x44, 0xF0, 0xA0, 0x94, 0xA5, 0x44, 0xF0,
- 0xA0, 0x95, 0x8B, 0x44, 0xF0, 0xA0, 0x98, 0xBA,
- 0x44, 0xF0, 0xA0, 0xA0, 0x84, 0x44, 0xF0, 0xA0,
- 0xA3, 0x9E, 0x44, 0xF0, 0xA0, 0xA8, 0xAC, 0x44,
- 0xF0, 0xA0, 0xAD, 0xA3, 0x44, 0xF0, 0xA1, 0x93,
- 0xA4, 0x44, 0xF0, 0xA1, 0x9A, 0xA8, 0x44, 0xF0,
- // Bytes 1680 - 16bf
- 0xA1, 0x9B, 0xAA, 0x44, 0xF0, 0xA1, 0xA7, 0x88,
- 0x44, 0xF0, 0xA1, 0xAC, 0x98, 0x44, 0xF0, 0xA1,
- 0xB4, 0x8B, 0x44, 0xF0, 0xA1, 0xB7, 0xA4, 0x44,
- 0xF0, 0xA1, 0xB7, 0xA6, 0x44, 0xF0, 0xA2, 0x86,
- 0x83, 0x44, 0xF0, 0xA2, 0x86, 0x9F, 0x44, 0xF0,
- 0xA2, 0x8C, 0xB1, 0x44, 0xF0, 0xA2, 0x9B, 0x94,
- 0x44, 0xF0, 0xA2, 0xA1, 0x84, 0x44, 0xF0, 0xA2,
- 0xA1, 0x8A, 0x44, 0xF0, 0xA2, 0xAC, 0x8C, 0x44,
- // Bytes 16c0 - 16ff
- 0xF0, 0xA2, 0xAF, 0xB1, 0x44, 0xF0, 0xA3, 0x80,
- 0x8A, 0x44, 0xF0, 0xA3, 0x8A, 0xB8, 0x44, 0xF0,
- 0xA3, 0x8D, 0x9F, 0x44, 0xF0, 0xA3, 0x8E, 0x93,
- 0x44, 0xF0, 0xA3, 0x8E, 0x9C, 0x44, 0xF0, 0xA3,
- 0x8F, 0x83, 0x44, 0xF0, 0xA3, 0x8F, 0x95, 0x44,
- 0xF0, 0xA3, 0x91, 0xAD, 0x44, 0xF0, 0xA3, 0x9A,
- 0xA3, 0x44, 0xF0, 0xA3, 0xA2, 0xA7, 0x44, 0xF0,
- 0xA3, 0xAA, 0x8D, 0x44, 0xF0, 0xA3, 0xAB, 0xBA,
- // Bytes 1700 - 173f
- 0x44, 0xF0, 0xA3, 0xB2, 0xBC, 0x44, 0xF0, 0xA3,
- 0xB4, 0x9E, 0x44, 0xF0, 0xA3, 0xBB, 0x91, 0x44,
- 0xF0, 0xA3, 0xBD, 0x9E, 0x44, 0xF0, 0xA3, 0xBE,
- 0x8E, 0x44, 0xF0, 0xA4, 0x89, 0xA3, 0x44, 0xF0,
- 0xA4, 0x8B, 0xAE, 0x44, 0xF0, 0xA4, 0x8E, 0xAB,
- 0x44, 0xF0, 0xA4, 0x98, 0x88, 0x44, 0xF0, 0xA4,
- 0x9C, 0xB5, 0x44, 0xF0, 0xA4, 0xA0, 0x94, 0x44,
- 0xF0, 0xA4, 0xB0, 0xB6, 0x44, 0xF0, 0xA4, 0xB2,
- // Bytes 1740 - 177f
- 0x92, 0x44, 0xF0, 0xA4, 0xBE, 0xA1, 0x44, 0xF0,
- 0xA4, 0xBE, 0xB8, 0x44, 0xF0, 0xA5, 0x81, 0x84,
- 0x44, 0xF0, 0xA5, 0x83, 0xB2, 0x44, 0xF0, 0xA5,
- 0x83, 0xB3, 0x44, 0xF0, 0xA5, 0x84, 0x99, 0x44,
- 0xF0, 0xA5, 0x84, 0xB3, 0x44, 0xF0, 0xA5, 0x89,
- 0x89, 0x44, 0xF0, 0xA5, 0x90, 0x9D, 0x44, 0xF0,
- 0xA5, 0x98, 0xA6, 0x44, 0xF0, 0xA5, 0x9A, 0x9A,
- 0x44, 0xF0, 0xA5, 0x9B, 0x85, 0x44, 0xF0, 0xA5,
- // Bytes 1780 - 17bf
- 0xA5, 0xBC, 0x44, 0xF0, 0xA5, 0xAA, 0xA7, 0x44,
- 0xF0, 0xA5, 0xAE, 0xAB, 0x44, 0xF0, 0xA5, 0xB2,
- 0x80, 0x44, 0xF0, 0xA5, 0xB3, 0x90, 0x44, 0xF0,
- 0xA5, 0xBE, 0x86, 0x44, 0xF0, 0xA6, 0x87, 0x9A,
- 0x44, 0xF0, 0xA6, 0x88, 0xA8, 0x44, 0xF0, 0xA6,
- 0x89, 0x87, 0x44, 0xF0, 0xA6, 0x8B, 0x99, 0x44,
- 0xF0, 0xA6, 0x8C, 0xBE, 0x44, 0xF0, 0xA6, 0x93,
- 0x9A, 0x44, 0xF0, 0xA6, 0x94, 0xA3, 0x44, 0xF0,
- // Bytes 17c0 - 17ff
- 0xA6, 0x96, 0xA8, 0x44, 0xF0, 0xA6, 0x9E, 0xA7,
- 0x44, 0xF0, 0xA6, 0x9E, 0xB5, 0x44, 0xF0, 0xA6,
- 0xAC, 0xBC, 0x44, 0xF0, 0xA6, 0xB0, 0xB6, 0x44,
- 0xF0, 0xA6, 0xB3, 0x95, 0x44, 0xF0, 0xA6, 0xB5,
- 0xAB, 0x44, 0xF0, 0xA6, 0xBC, 0xAC, 0x44, 0xF0,
- 0xA6, 0xBE, 0xB1, 0x44, 0xF0, 0xA7, 0x83, 0x92,
- 0x44, 0xF0, 0xA7, 0x8F, 0x8A, 0x44, 0xF0, 0xA7,
- 0x99, 0xA7, 0x44, 0xF0, 0xA7, 0xA2, 0xAE, 0x44,
- // Bytes 1800 - 183f
- 0xF0, 0xA7, 0xA5, 0xA6, 0x44, 0xF0, 0xA7, 0xB2,
- 0xA8, 0x44, 0xF0, 0xA7, 0xBB, 0x93, 0x44, 0xF0,
- 0xA7, 0xBC, 0xAF, 0x44, 0xF0, 0xA8, 0x97, 0x92,
- 0x44, 0xF0, 0xA8, 0x97, 0xAD, 0x44, 0xF0, 0xA8,
- 0x9C, 0xAE, 0x44, 0xF0, 0xA8, 0xAF, 0xBA, 0x44,
- 0xF0, 0xA8, 0xB5, 0xB7, 0x44, 0xF0, 0xA9, 0x85,
- 0x85, 0x44, 0xF0, 0xA9, 0x87, 0x9F, 0x44, 0xF0,
- 0xA9, 0x88, 0x9A, 0x44, 0xF0, 0xA9, 0x90, 0x8A,
- // Bytes 1840 - 187f
- 0x44, 0xF0, 0xA9, 0x92, 0x96, 0x44, 0xF0, 0xA9,
- 0x96, 0xB6, 0x44, 0xF0, 0xA9, 0xAC, 0xB0, 0x44,
- 0xF0, 0xAA, 0x83, 0x8E, 0x44, 0xF0, 0xAA, 0x84,
- 0x85, 0x44, 0xF0, 0xAA, 0x88, 0x8E, 0x44, 0xF0,
- 0xAA, 0x8A, 0x91, 0x44, 0xF0, 0xAA, 0x8E, 0x92,
- 0x44, 0xF0, 0xAA, 0x98, 0x80, 0x42, 0x21, 0x21,
- 0x42, 0x21, 0x3F, 0x42, 0x2E, 0x2E, 0x42, 0x30,
- 0x2C, 0x42, 0x30, 0x2E, 0x42, 0x31, 0x2C, 0x42,
- // Bytes 1880 - 18bf
- 0x31, 0x2E, 0x42, 0x31, 0x30, 0x42, 0x31, 0x31,
- 0x42, 0x31, 0x32, 0x42, 0x31, 0x33, 0x42, 0x31,
- 0x34, 0x42, 0x31, 0x35, 0x42, 0x31, 0x36, 0x42,
- 0x31, 0x37, 0x42, 0x31, 0x38, 0x42, 0x31, 0x39,
- 0x42, 0x32, 0x2C, 0x42, 0x32, 0x2E, 0x42, 0x32,
- 0x30, 0x42, 0x32, 0x31, 0x42, 0x32, 0x32, 0x42,
- 0x32, 0x33, 0x42, 0x32, 0x34, 0x42, 0x32, 0x35,
- 0x42, 0x32, 0x36, 0x42, 0x32, 0x37, 0x42, 0x32,
- // Bytes 18c0 - 18ff
- 0x38, 0x42, 0x32, 0x39, 0x42, 0x33, 0x2C, 0x42,
- 0x33, 0x2E, 0x42, 0x33, 0x30, 0x42, 0x33, 0x31,
- 0x42, 0x33, 0x32, 0x42, 0x33, 0x33, 0x42, 0x33,
- 0x34, 0x42, 0x33, 0x35, 0x42, 0x33, 0x36, 0x42,
- 0x33, 0x37, 0x42, 0x33, 0x38, 0x42, 0x33, 0x39,
- 0x42, 0x34, 0x2C, 0x42, 0x34, 0x2E, 0x42, 0x34,
- 0x30, 0x42, 0x34, 0x31, 0x42, 0x34, 0x32, 0x42,
- 0x34, 0x33, 0x42, 0x34, 0x34, 0x42, 0x34, 0x35,
- // Bytes 1900 - 193f
- 0x42, 0x34, 0x36, 0x42, 0x34, 0x37, 0x42, 0x34,
- 0x38, 0x42, 0x34, 0x39, 0x42, 0x35, 0x2C, 0x42,
- 0x35, 0x2E, 0x42, 0x35, 0x30, 0x42, 0x36, 0x2C,
- 0x42, 0x36, 0x2E, 0x42, 0x37, 0x2C, 0x42, 0x37,
- 0x2E, 0x42, 0x38, 0x2C, 0x42, 0x38, 0x2E, 0x42,
- 0x39, 0x2C, 0x42, 0x39, 0x2E, 0x42, 0x3D, 0x3D,
- 0x42, 0x3F, 0x21, 0x42, 0x3F, 0x3F, 0x42, 0x41,
- 0x55, 0x42, 0x42, 0x71, 0x42, 0x43, 0x44, 0x42,
- // Bytes 1940 - 197f
- 0x44, 0x4A, 0x42, 0x44, 0x5A, 0x42, 0x44, 0x7A,
- 0x42, 0x47, 0x42, 0x42, 0x47, 0x79, 0x42, 0x48,
- 0x50, 0x42, 0x48, 0x56, 0x42, 0x48, 0x67, 0x42,
- 0x48, 0x7A, 0x42, 0x49, 0x49, 0x42, 0x49, 0x4A,
- 0x42, 0x49, 0x55, 0x42, 0x49, 0x56, 0x42, 0x49,
- 0x58, 0x42, 0x4B, 0x42, 0x42, 0x4B, 0x4B, 0x42,
- 0x4B, 0x4D, 0x42, 0x4C, 0x4A, 0x42, 0x4C, 0x6A,
- 0x42, 0x4D, 0x42, 0x42, 0x4D, 0x43, 0x42, 0x4D,
- // Bytes 1980 - 19bf
- 0x44, 0x42, 0x4D, 0x56, 0x42, 0x4D, 0x57, 0x42,
- 0x4E, 0x4A, 0x42, 0x4E, 0x6A, 0x42, 0x4E, 0x6F,
- 0x42, 0x50, 0x48, 0x42, 0x50, 0x52, 0x42, 0x50,
- 0x61, 0x42, 0x52, 0x73, 0x42, 0x53, 0x44, 0x42,
- 0x53, 0x4D, 0x42, 0x53, 0x53, 0x42, 0x53, 0x76,
- 0x42, 0x54, 0x4D, 0x42, 0x56, 0x49, 0x42, 0x57,
- 0x43, 0x42, 0x57, 0x5A, 0x42, 0x57, 0x62, 0x42,
- 0x58, 0x49, 0x42, 0x63, 0x63, 0x42, 0x63, 0x64,
- // Bytes 19c0 - 19ff
- 0x42, 0x63, 0x6D, 0x42, 0x64, 0x42, 0x42, 0x64,
- 0x61, 0x42, 0x64, 0x6C, 0x42, 0x64, 0x6D, 0x42,
- 0x64, 0x7A, 0x42, 0x65, 0x56, 0x42, 0x66, 0x66,
- 0x42, 0x66, 0x69, 0x42, 0x66, 0x6C, 0x42, 0x66,
- 0x6D, 0x42, 0x68, 0x61, 0x42, 0x69, 0x69, 0x42,
- 0x69, 0x6A, 0x42, 0x69, 0x6E, 0x42, 0x69, 0x76,
- 0x42, 0x69, 0x78, 0x42, 0x6B, 0x41, 0x42, 0x6B,
- 0x56, 0x42, 0x6B, 0x57, 0x42, 0x6B, 0x67, 0x42,
- // Bytes 1a00 - 1a3f
- 0x6B, 0x6C, 0x42, 0x6B, 0x6D, 0x42, 0x6B, 0x74,
- 0x42, 0x6C, 0x6A, 0x42, 0x6C, 0x6D, 0x42, 0x6C,
- 0x6E, 0x42, 0x6C, 0x78, 0x42, 0x6D, 0x32, 0x42,
- 0x6D, 0x33, 0x42, 0x6D, 0x41, 0x42, 0x6D, 0x56,
- 0x42, 0x6D, 0x57, 0x42, 0x6D, 0x62, 0x42, 0x6D,
- 0x67, 0x42, 0x6D, 0x6C, 0x42, 0x6D, 0x6D, 0x42,
- 0x6D, 0x73, 0x42, 0x6E, 0x41, 0x42, 0x6E, 0x46,
- 0x42, 0x6E, 0x56, 0x42, 0x6E, 0x57, 0x42, 0x6E,
- // Bytes 1a40 - 1a7f
- 0x6A, 0x42, 0x6E, 0x6D, 0x42, 0x6E, 0x73, 0x42,
- 0x6F, 0x56, 0x42, 0x70, 0x41, 0x42, 0x70, 0x46,
- 0x42, 0x70, 0x56, 0x42, 0x70, 0x57, 0x42, 0x70,
- 0x63, 0x42, 0x70, 0x73, 0x42, 0x73, 0x72, 0x42,
- 0x73, 0x74, 0x42, 0x76, 0x69, 0x42, 0x78, 0x69,
- 0x43, 0x28, 0x31, 0x29, 0x43, 0x28, 0x32, 0x29,
- 0x43, 0x28, 0x33, 0x29, 0x43, 0x28, 0x34, 0x29,
- 0x43, 0x28, 0x35, 0x29, 0x43, 0x28, 0x36, 0x29,
- // Bytes 1a80 - 1abf
- 0x43, 0x28, 0x37, 0x29, 0x43, 0x28, 0x38, 0x29,
- 0x43, 0x28, 0x39, 0x29, 0x43, 0x28, 0x41, 0x29,
- 0x43, 0x28, 0x42, 0x29, 0x43, 0x28, 0x43, 0x29,
- 0x43, 0x28, 0x44, 0x29, 0x43, 0x28, 0x45, 0x29,
- 0x43, 0x28, 0x46, 0x29, 0x43, 0x28, 0x47, 0x29,
- 0x43, 0x28, 0x48, 0x29, 0x43, 0x28, 0x49, 0x29,
- 0x43, 0x28, 0x4A, 0x29, 0x43, 0x28, 0x4B, 0x29,
- 0x43, 0x28, 0x4C, 0x29, 0x43, 0x28, 0x4D, 0x29,
- // Bytes 1ac0 - 1aff
- 0x43, 0x28, 0x4E, 0x29, 0x43, 0x28, 0x4F, 0x29,
- 0x43, 0x28, 0x50, 0x29, 0x43, 0x28, 0x51, 0x29,
- 0x43, 0x28, 0x52, 0x29, 0x43, 0x28, 0x53, 0x29,
- 0x43, 0x28, 0x54, 0x29, 0x43, 0x28, 0x55, 0x29,
- 0x43, 0x28, 0x56, 0x29, 0x43, 0x28, 0x57, 0x29,
- 0x43, 0x28, 0x58, 0x29, 0x43, 0x28, 0x59, 0x29,
- 0x43, 0x28, 0x5A, 0x29, 0x43, 0x28, 0x61, 0x29,
- 0x43, 0x28, 0x62, 0x29, 0x43, 0x28, 0x63, 0x29,
- // Bytes 1b00 - 1b3f
- 0x43, 0x28, 0x64, 0x29, 0x43, 0x28, 0x65, 0x29,
- 0x43, 0x28, 0x66, 0x29, 0x43, 0x28, 0x67, 0x29,
- 0x43, 0x28, 0x68, 0x29, 0x43, 0x28, 0x69, 0x29,
- 0x43, 0x28, 0x6A, 0x29, 0x43, 0x28, 0x6B, 0x29,
- 0x43, 0x28, 0x6C, 0x29, 0x43, 0x28, 0x6D, 0x29,
- 0x43, 0x28, 0x6E, 0x29, 0x43, 0x28, 0x6F, 0x29,
- 0x43, 0x28, 0x70, 0x29, 0x43, 0x28, 0x71, 0x29,
- 0x43, 0x28, 0x72, 0x29, 0x43, 0x28, 0x73, 0x29,
- // Bytes 1b40 - 1b7f
- 0x43, 0x28, 0x74, 0x29, 0x43, 0x28, 0x75, 0x29,
- 0x43, 0x28, 0x76, 0x29, 0x43, 0x28, 0x77, 0x29,
- 0x43, 0x28, 0x78, 0x29, 0x43, 0x28, 0x79, 0x29,
- 0x43, 0x28, 0x7A, 0x29, 0x43, 0x2E, 0x2E, 0x2E,
- 0x43, 0x31, 0x30, 0x2E, 0x43, 0x31, 0x31, 0x2E,
- 0x43, 0x31, 0x32, 0x2E, 0x43, 0x31, 0x33, 0x2E,
- 0x43, 0x31, 0x34, 0x2E, 0x43, 0x31, 0x35, 0x2E,
- 0x43, 0x31, 0x36, 0x2E, 0x43, 0x31, 0x37, 0x2E,
- // Bytes 1b80 - 1bbf
- 0x43, 0x31, 0x38, 0x2E, 0x43, 0x31, 0x39, 0x2E,
- 0x43, 0x32, 0x30, 0x2E, 0x43, 0x3A, 0x3A, 0x3D,
- 0x43, 0x3D, 0x3D, 0x3D, 0x43, 0x43, 0x6F, 0x2E,
- 0x43, 0x46, 0x41, 0x58, 0x43, 0x47, 0x48, 0x7A,
- 0x43, 0x47, 0x50, 0x61, 0x43, 0x49, 0x49, 0x49,
- 0x43, 0x4C, 0x54, 0x44, 0x43, 0x4C, 0xC2, 0xB7,
- 0x43, 0x4D, 0x48, 0x7A, 0x43, 0x4D, 0x50, 0x61,
- 0x43, 0x4D, 0xCE, 0xA9, 0x43, 0x50, 0x50, 0x4D,
- // Bytes 1bc0 - 1bff
- 0x43, 0x50, 0x50, 0x56, 0x43, 0x50, 0x54, 0x45,
- 0x43, 0x54, 0x45, 0x4C, 0x43, 0x54, 0x48, 0x7A,
- 0x43, 0x56, 0x49, 0x49, 0x43, 0x58, 0x49, 0x49,
- 0x43, 0x61, 0x2F, 0x63, 0x43, 0x61, 0x2F, 0x73,
- 0x43, 0x61, 0xCA, 0xBE, 0x43, 0x62, 0x61, 0x72,
- 0x43, 0x63, 0x2F, 0x6F, 0x43, 0x63, 0x2F, 0x75,
- 0x43, 0x63, 0x61, 0x6C, 0x43, 0x63, 0x6D, 0x32,
- 0x43, 0x63, 0x6D, 0x33, 0x43, 0x64, 0x6D, 0x32,
- // Bytes 1c00 - 1c3f
- 0x43, 0x64, 0x6D, 0x33, 0x43, 0x65, 0x72, 0x67,
- 0x43, 0x66, 0x66, 0x69, 0x43, 0x66, 0x66, 0x6C,
- 0x43, 0x67, 0x61, 0x6C, 0x43, 0x68, 0x50, 0x61,
- 0x43, 0x69, 0x69, 0x69, 0x43, 0x6B, 0x48, 0x7A,
- 0x43, 0x6B, 0x50, 0x61, 0x43, 0x6B, 0x6D, 0x32,
- 0x43, 0x6B, 0x6D, 0x33, 0x43, 0x6B, 0xCE, 0xA9,
- 0x43, 0x6C, 0x6F, 0x67, 0x43, 0x6C, 0xC2, 0xB7,
- 0x43, 0x6D, 0x69, 0x6C, 0x43, 0x6D, 0x6D, 0x32,
- // Bytes 1c40 - 1c7f
- 0x43, 0x6D, 0x6D, 0x33, 0x43, 0x6D, 0x6F, 0x6C,
- 0x43, 0x72, 0x61, 0x64, 0x43, 0x76, 0x69, 0x69,
- 0x43, 0x78, 0x69, 0x69, 0x43, 0xC2, 0xB0, 0x43,
- 0x43, 0xC2, 0xB0, 0x46, 0x43, 0xCA, 0xBC, 0x6E,
- 0x43, 0xCE, 0xBC, 0x41, 0x43, 0xCE, 0xBC, 0x46,
- 0x43, 0xCE, 0xBC, 0x56, 0x43, 0xCE, 0xBC, 0x57,
- 0x43, 0xCE, 0xBC, 0x67, 0x43, 0xCE, 0xBC, 0x6C,
- 0x43, 0xCE, 0xBC, 0x6D, 0x43, 0xCE, 0xBC, 0x73,
- // Bytes 1c80 - 1cbf
- 0x44, 0x28, 0x31, 0x30, 0x29, 0x44, 0x28, 0x31,
- 0x31, 0x29, 0x44, 0x28, 0x31, 0x32, 0x29, 0x44,
- 0x28, 0x31, 0x33, 0x29, 0x44, 0x28, 0x31, 0x34,
- 0x29, 0x44, 0x28, 0x31, 0x35, 0x29, 0x44, 0x28,
- 0x31, 0x36, 0x29, 0x44, 0x28, 0x31, 0x37, 0x29,
- 0x44, 0x28, 0x31, 0x38, 0x29, 0x44, 0x28, 0x31,
- 0x39, 0x29, 0x44, 0x28, 0x32, 0x30, 0x29, 0x44,
- 0x30, 0xE7, 0x82, 0xB9, 0x44, 0x31, 0xE2, 0x81,
- // Bytes 1cc0 - 1cff
- 0x84, 0x44, 0x31, 0xE6, 0x97, 0xA5, 0x44, 0x31,
- 0xE6, 0x9C, 0x88, 0x44, 0x31, 0xE7, 0x82, 0xB9,
- 0x44, 0x32, 0xE6, 0x97, 0xA5, 0x44, 0x32, 0xE6,
- 0x9C, 0x88, 0x44, 0x32, 0xE7, 0x82, 0xB9, 0x44,
- 0x33, 0xE6, 0x97, 0xA5, 0x44, 0x33, 0xE6, 0x9C,
- 0x88, 0x44, 0x33, 0xE7, 0x82, 0xB9, 0x44, 0x34,
- 0xE6, 0x97, 0xA5, 0x44, 0x34, 0xE6, 0x9C, 0x88,
- 0x44, 0x34, 0xE7, 0x82, 0xB9, 0x44, 0x35, 0xE6,
- // Bytes 1d00 - 1d3f
- 0x97, 0xA5, 0x44, 0x35, 0xE6, 0x9C, 0x88, 0x44,
- 0x35, 0xE7, 0x82, 0xB9, 0x44, 0x36, 0xE6, 0x97,
- 0xA5, 0x44, 0x36, 0xE6, 0x9C, 0x88, 0x44, 0x36,
- 0xE7, 0x82, 0xB9, 0x44, 0x37, 0xE6, 0x97, 0xA5,
- 0x44, 0x37, 0xE6, 0x9C, 0x88, 0x44, 0x37, 0xE7,
- 0x82, 0xB9, 0x44, 0x38, 0xE6, 0x97, 0xA5, 0x44,
- 0x38, 0xE6, 0x9C, 0x88, 0x44, 0x38, 0xE7, 0x82,
- 0xB9, 0x44, 0x39, 0xE6, 0x97, 0xA5, 0x44, 0x39,
- // Bytes 1d40 - 1d7f
- 0xE6, 0x9C, 0x88, 0x44, 0x39, 0xE7, 0x82, 0xB9,
- 0x44, 0x56, 0x49, 0x49, 0x49, 0x44, 0x61, 0x2E,
- 0x6D, 0x2E, 0x44, 0x6B, 0x63, 0x61, 0x6C, 0x44,
- 0x70, 0x2E, 0x6D, 0x2E, 0x44, 0x76, 0x69, 0x69,
- 0x69, 0x44, 0xD5, 0xA5, 0xD6, 0x82, 0x44, 0xD5,
- 0xB4, 0xD5, 0xA5, 0x44, 0xD5, 0xB4, 0xD5, 0xAB,
- 0x44, 0xD5, 0xB4, 0xD5, 0xAD, 0x44, 0xD5, 0xB4,
- 0xD5, 0xB6, 0x44, 0xD5, 0xBE, 0xD5, 0xB6, 0x44,
- // Bytes 1d80 - 1dbf
- 0xD7, 0x90, 0xD7, 0x9C, 0x44, 0xD8, 0xA7, 0xD9,
- 0xB4, 0x44, 0xD8, 0xA8, 0xD8, 0xAC, 0x44, 0xD8,
- 0xA8, 0xD8, 0xAD, 0x44, 0xD8, 0xA8, 0xD8, 0xAE,
- 0x44, 0xD8, 0xA8, 0xD8, 0xB1, 0x44, 0xD8, 0xA8,
- 0xD8, 0xB2, 0x44, 0xD8, 0xA8, 0xD9, 0x85, 0x44,
- 0xD8, 0xA8, 0xD9, 0x86, 0x44, 0xD8, 0xA8, 0xD9,
- 0x87, 0x44, 0xD8, 0xA8, 0xD9, 0x89, 0x44, 0xD8,
- 0xA8, 0xD9, 0x8A, 0x44, 0xD8, 0xAA, 0xD8, 0xAC,
- // Bytes 1dc0 - 1dff
- 0x44, 0xD8, 0xAA, 0xD8, 0xAD, 0x44, 0xD8, 0xAA,
- 0xD8, 0xAE, 0x44, 0xD8, 0xAA, 0xD8, 0xB1, 0x44,
- 0xD8, 0xAA, 0xD8, 0xB2, 0x44, 0xD8, 0xAA, 0xD9,
- 0x85, 0x44, 0xD8, 0xAA, 0xD9, 0x86, 0x44, 0xD8,
- 0xAA, 0xD9, 0x87, 0x44, 0xD8, 0xAA, 0xD9, 0x89,
- 0x44, 0xD8, 0xAA, 0xD9, 0x8A, 0x44, 0xD8, 0xAB,
- 0xD8, 0xAC, 0x44, 0xD8, 0xAB, 0xD8, 0xB1, 0x44,
- 0xD8, 0xAB, 0xD8, 0xB2, 0x44, 0xD8, 0xAB, 0xD9,
- // Bytes 1e00 - 1e3f
- 0x85, 0x44, 0xD8, 0xAB, 0xD9, 0x86, 0x44, 0xD8,
- 0xAB, 0xD9, 0x87, 0x44, 0xD8, 0xAB, 0xD9, 0x89,
- 0x44, 0xD8, 0xAB, 0xD9, 0x8A, 0x44, 0xD8, 0xAC,
- 0xD8, 0xAD, 0x44, 0xD8, 0xAC, 0xD9, 0x85, 0x44,
- 0xD8, 0xAC, 0xD9, 0x89, 0x44, 0xD8, 0xAC, 0xD9,
- 0x8A, 0x44, 0xD8, 0xAD, 0xD8, 0xAC, 0x44, 0xD8,
- 0xAD, 0xD9, 0x85, 0x44, 0xD8, 0xAD, 0xD9, 0x89,
- 0x44, 0xD8, 0xAD, 0xD9, 0x8A, 0x44, 0xD8, 0xAE,
- // Bytes 1e40 - 1e7f
- 0xD8, 0xAC, 0x44, 0xD8, 0xAE, 0xD8, 0xAD, 0x44,
- 0xD8, 0xAE, 0xD9, 0x85, 0x44, 0xD8, 0xAE, 0xD9,
- 0x89, 0x44, 0xD8, 0xAE, 0xD9, 0x8A, 0x44, 0xD8,
- 0xB3, 0xD8, 0xAC, 0x44, 0xD8, 0xB3, 0xD8, 0xAD,
- 0x44, 0xD8, 0xB3, 0xD8, 0xAE, 0x44, 0xD8, 0xB3,
- 0xD8, 0xB1, 0x44, 0xD8, 0xB3, 0xD9, 0x85, 0x44,
- 0xD8, 0xB3, 0xD9, 0x87, 0x44, 0xD8, 0xB3, 0xD9,
- 0x89, 0x44, 0xD8, 0xB3, 0xD9, 0x8A, 0x44, 0xD8,
- // Bytes 1e80 - 1ebf
- 0xB4, 0xD8, 0xAC, 0x44, 0xD8, 0xB4, 0xD8, 0xAD,
- 0x44, 0xD8, 0xB4, 0xD8, 0xAE, 0x44, 0xD8, 0xB4,
- 0xD8, 0xB1, 0x44, 0xD8, 0xB4, 0xD9, 0x85, 0x44,
- 0xD8, 0xB4, 0xD9, 0x87, 0x44, 0xD8, 0xB4, 0xD9,
- 0x89, 0x44, 0xD8, 0xB4, 0xD9, 0x8A, 0x44, 0xD8,
- 0xB5, 0xD8, 0xAD, 0x44, 0xD8, 0xB5, 0xD8, 0xAE,
- 0x44, 0xD8, 0xB5, 0xD8, 0xB1, 0x44, 0xD8, 0xB5,
- 0xD9, 0x85, 0x44, 0xD8, 0xB5, 0xD9, 0x89, 0x44,
- // Bytes 1ec0 - 1eff
- 0xD8, 0xB5, 0xD9, 0x8A, 0x44, 0xD8, 0xB6, 0xD8,
- 0xAC, 0x44, 0xD8, 0xB6, 0xD8, 0xAD, 0x44, 0xD8,
- 0xB6, 0xD8, 0xAE, 0x44, 0xD8, 0xB6, 0xD8, 0xB1,
- 0x44, 0xD8, 0xB6, 0xD9, 0x85, 0x44, 0xD8, 0xB6,
- 0xD9, 0x89, 0x44, 0xD8, 0xB6, 0xD9, 0x8A, 0x44,
- 0xD8, 0xB7, 0xD8, 0xAD, 0x44, 0xD8, 0xB7, 0xD9,
- 0x85, 0x44, 0xD8, 0xB7, 0xD9, 0x89, 0x44, 0xD8,
- 0xB7, 0xD9, 0x8A, 0x44, 0xD8, 0xB8, 0xD9, 0x85,
- // Bytes 1f00 - 1f3f
- 0x44, 0xD8, 0xB9, 0xD8, 0xAC, 0x44, 0xD8, 0xB9,
- 0xD9, 0x85, 0x44, 0xD8, 0xB9, 0xD9, 0x89, 0x44,
- 0xD8, 0xB9, 0xD9, 0x8A, 0x44, 0xD8, 0xBA, 0xD8,
- 0xAC, 0x44, 0xD8, 0xBA, 0xD9, 0x85, 0x44, 0xD8,
- 0xBA, 0xD9, 0x89, 0x44, 0xD8, 0xBA, 0xD9, 0x8A,
- 0x44, 0xD9, 0x81, 0xD8, 0xAC, 0x44, 0xD9, 0x81,
- 0xD8, 0xAD, 0x44, 0xD9, 0x81, 0xD8, 0xAE, 0x44,
- 0xD9, 0x81, 0xD9, 0x85, 0x44, 0xD9, 0x81, 0xD9,
- // Bytes 1f40 - 1f7f
- 0x89, 0x44, 0xD9, 0x81, 0xD9, 0x8A, 0x44, 0xD9,
- 0x82, 0xD8, 0xAD, 0x44, 0xD9, 0x82, 0xD9, 0x85,
- 0x44, 0xD9, 0x82, 0xD9, 0x89, 0x44, 0xD9, 0x82,
- 0xD9, 0x8A, 0x44, 0xD9, 0x83, 0xD8, 0xA7, 0x44,
- 0xD9, 0x83, 0xD8, 0xAC, 0x44, 0xD9, 0x83, 0xD8,
- 0xAD, 0x44, 0xD9, 0x83, 0xD8, 0xAE, 0x44, 0xD9,
- 0x83, 0xD9, 0x84, 0x44, 0xD9, 0x83, 0xD9, 0x85,
- 0x44, 0xD9, 0x83, 0xD9, 0x89, 0x44, 0xD9, 0x83,
- // Bytes 1f80 - 1fbf
- 0xD9, 0x8A, 0x44, 0xD9, 0x84, 0xD8, 0xA7, 0x44,
- 0xD9, 0x84, 0xD8, 0xAC, 0x44, 0xD9, 0x84, 0xD8,
- 0xAD, 0x44, 0xD9, 0x84, 0xD8, 0xAE, 0x44, 0xD9,
- 0x84, 0xD9, 0x85, 0x44, 0xD9, 0x84, 0xD9, 0x87,
- 0x44, 0xD9, 0x84, 0xD9, 0x89, 0x44, 0xD9, 0x84,
- 0xD9, 0x8A, 0x44, 0xD9, 0x85, 0xD8, 0xA7, 0x44,
- 0xD9, 0x85, 0xD8, 0xAC, 0x44, 0xD9, 0x85, 0xD8,
- 0xAD, 0x44, 0xD9, 0x85, 0xD8, 0xAE, 0x44, 0xD9,
- // Bytes 1fc0 - 1fff
- 0x85, 0xD9, 0x85, 0x44, 0xD9, 0x85, 0xD9, 0x89,
- 0x44, 0xD9, 0x85, 0xD9, 0x8A, 0x44, 0xD9, 0x86,
- 0xD8, 0xAC, 0x44, 0xD9, 0x86, 0xD8, 0xAD, 0x44,
- 0xD9, 0x86, 0xD8, 0xAE, 0x44, 0xD9, 0x86, 0xD8,
- 0xB1, 0x44, 0xD9, 0x86, 0xD8, 0xB2, 0x44, 0xD9,
- 0x86, 0xD9, 0x85, 0x44, 0xD9, 0x86, 0xD9, 0x86,
- 0x44, 0xD9, 0x86, 0xD9, 0x87, 0x44, 0xD9, 0x86,
- 0xD9, 0x89, 0x44, 0xD9, 0x86, 0xD9, 0x8A, 0x44,
- // Bytes 2000 - 203f
- 0xD9, 0x87, 0xD8, 0xAC, 0x44, 0xD9, 0x87, 0xD9,
- 0x85, 0x44, 0xD9, 0x87, 0xD9, 0x89, 0x44, 0xD9,
- 0x87, 0xD9, 0x8A, 0x44, 0xD9, 0x88, 0xD9, 0xB4,
- 0x44, 0xD9, 0x8A, 0xD8, 0xAC, 0x44, 0xD9, 0x8A,
- 0xD8, 0xAD, 0x44, 0xD9, 0x8A, 0xD8, 0xAE, 0x44,
- 0xD9, 0x8A, 0xD8, 0xB1, 0x44, 0xD9, 0x8A, 0xD8,
- 0xB2, 0x44, 0xD9, 0x8A, 0xD9, 0x85, 0x44, 0xD9,
- 0x8A, 0xD9, 0x86, 0x44, 0xD9, 0x8A, 0xD9, 0x87,
- // Bytes 2040 - 207f
- 0x44, 0xD9, 0x8A, 0xD9, 0x89, 0x44, 0xD9, 0x8A,
- 0xD9, 0x8A, 0x44, 0xD9, 0x8A, 0xD9, 0xB4, 0x44,
- 0xDB, 0x87, 0xD9, 0xB4, 0x45, 0x28, 0xE1, 0x84,
- 0x80, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x82, 0x29,
- 0x45, 0x28, 0xE1, 0x84, 0x83, 0x29, 0x45, 0x28,
- 0xE1, 0x84, 0x85, 0x29, 0x45, 0x28, 0xE1, 0x84,
- 0x86, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x87, 0x29,
- 0x45, 0x28, 0xE1, 0x84, 0x89, 0x29, 0x45, 0x28,
- // Bytes 2080 - 20bf
- 0xE1, 0x84, 0x8B, 0x29, 0x45, 0x28, 0xE1, 0x84,
- 0x8C, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x8E, 0x29,
- 0x45, 0x28, 0xE1, 0x84, 0x8F, 0x29, 0x45, 0x28,
- 0xE1, 0x84, 0x90, 0x29, 0x45, 0x28, 0xE1, 0x84,
- 0x91, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x92, 0x29,
- 0x45, 0x28, 0xE4, 0xB8, 0x80, 0x29, 0x45, 0x28,
- 0xE4, 0xB8, 0x83, 0x29, 0x45, 0x28, 0xE4, 0xB8,
- 0x89, 0x29, 0x45, 0x28, 0xE4, 0xB9, 0x9D, 0x29,
- // Bytes 20c0 - 20ff
- 0x45, 0x28, 0xE4, 0xBA, 0x8C, 0x29, 0x45, 0x28,
- 0xE4, 0xBA, 0x94, 0x29, 0x45, 0x28, 0xE4, 0xBB,
- 0xA3, 0x29, 0x45, 0x28, 0xE4, 0xBC, 0x81, 0x29,
- 0x45, 0x28, 0xE4, 0xBC, 0x91, 0x29, 0x45, 0x28,
- 0xE5, 0x85, 0xAB, 0x29, 0x45, 0x28, 0xE5, 0x85,
- 0xAD, 0x29, 0x45, 0x28, 0xE5, 0x8A, 0xB4, 0x29,
- 0x45, 0x28, 0xE5, 0x8D, 0x81, 0x29, 0x45, 0x28,
- 0xE5, 0x8D, 0x94, 0x29, 0x45, 0x28, 0xE5, 0x90,
- // Bytes 2100 - 213f
- 0x8D, 0x29, 0x45, 0x28, 0xE5, 0x91, 0xBC, 0x29,
- 0x45, 0x28, 0xE5, 0x9B, 0x9B, 0x29, 0x45, 0x28,
- 0xE5, 0x9C, 0x9F, 0x29, 0x45, 0x28, 0xE5, 0xAD,
- 0xA6, 0x29, 0x45, 0x28, 0xE6, 0x97, 0xA5, 0x29,
- 0x45, 0x28, 0xE6, 0x9C, 0x88, 0x29, 0x45, 0x28,
- 0xE6, 0x9C, 0x89, 0x29, 0x45, 0x28, 0xE6, 0x9C,
- 0xA8, 0x29, 0x45, 0x28, 0xE6, 0xA0, 0xAA, 0x29,
- 0x45, 0x28, 0xE6, 0xB0, 0xB4, 0x29, 0x45, 0x28,
- // Bytes 2140 - 217f
- 0xE7, 0x81, 0xAB, 0x29, 0x45, 0x28, 0xE7, 0x89,
- 0xB9, 0x29, 0x45, 0x28, 0xE7, 0x9B, 0xA3, 0x29,
- 0x45, 0x28, 0xE7, 0xA4, 0xBE, 0x29, 0x45, 0x28,
- 0xE7, 0xA5, 0x9D, 0x29, 0x45, 0x28, 0xE7, 0xA5,
- 0xAD, 0x29, 0x45, 0x28, 0xE8, 0x87, 0xAA, 0x29,
- 0x45, 0x28, 0xE8, 0x87, 0xB3, 0x29, 0x45, 0x28,
- 0xE8, 0xB2, 0xA1, 0x29, 0x45, 0x28, 0xE8, 0xB3,
- 0x87, 0x29, 0x45, 0x28, 0xE9, 0x87, 0x91, 0x29,
- // Bytes 2180 - 21bf
- 0x45, 0x30, 0xE2, 0x81, 0x84, 0x33, 0x45, 0x31,
- 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x30, 0xE6,
- 0x9C, 0x88, 0x45, 0x31, 0x30, 0xE7, 0x82, 0xB9,
- 0x45, 0x31, 0x31, 0xE6, 0x97, 0xA5, 0x45, 0x31,
- 0x31, 0xE6, 0x9C, 0x88, 0x45, 0x31, 0x31, 0xE7,
- 0x82, 0xB9, 0x45, 0x31, 0x32, 0xE6, 0x97, 0xA5,
- 0x45, 0x31, 0x32, 0xE6, 0x9C, 0x88, 0x45, 0x31,
- 0x32, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x33, 0xE6,
- // Bytes 21c0 - 21ff
- 0x97, 0xA5, 0x45, 0x31, 0x33, 0xE7, 0x82, 0xB9,
- 0x45, 0x31, 0x34, 0xE6, 0x97, 0xA5, 0x45, 0x31,
- 0x34, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x35, 0xE6,
- 0x97, 0xA5, 0x45, 0x31, 0x35, 0xE7, 0x82, 0xB9,
- 0x45, 0x31, 0x36, 0xE6, 0x97, 0xA5, 0x45, 0x31,
- 0x36, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x37, 0xE6,
- 0x97, 0xA5, 0x45, 0x31, 0x37, 0xE7, 0x82, 0xB9,
- 0x45, 0x31, 0x38, 0xE6, 0x97, 0xA5, 0x45, 0x31,
- // Bytes 2200 - 223f
- 0x38, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x39, 0xE6,
- 0x97, 0xA5, 0x45, 0x31, 0x39, 0xE7, 0x82, 0xB9,
- 0x45, 0x31, 0xE2, 0x81, 0x84, 0x32, 0x45, 0x31,
- 0xE2, 0x81, 0x84, 0x33, 0x45, 0x31, 0xE2, 0x81,
- 0x84, 0x34, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x35,
- 0x45, 0x31, 0xE2, 0x81, 0x84, 0x36, 0x45, 0x31,
- 0xE2, 0x81, 0x84, 0x37, 0x45, 0x31, 0xE2, 0x81,
- 0x84, 0x38, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x39,
- // Bytes 2240 - 227f
- 0x45, 0x32, 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x32,
- 0x30, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x31, 0xE6,
- 0x97, 0xA5, 0x45, 0x32, 0x31, 0xE7, 0x82, 0xB9,
- 0x45, 0x32, 0x32, 0xE6, 0x97, 0xA5, 0x45, 0x32,
- 0x32, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x33, 0xE6,
- 0x97, 0xA5, 0x45, 0x32, 0x33, 0xE7, 0x82, 0xB9,
- 0x45, 0x32, 0x34, 0xE6, 0x97, 0xA5, 0x45, 0x32,
- 0x34, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x35, 0xE6,
- // Bytes 2280 - 22bf
- 0x97, 0xA5, 0x45, 0x32, 0x36, 0xE6, 0x97, 0xA5,
- 0x45, 0x32, 0x37, 0xE6, 0x97, 0xA5, 0x45, 0x32,
- 0x38, 0xE6, 0x97, 0xA5, 0x45, 0x32, 0x39, 0xE6,
- 0x97, 0xA5, 0x45, 0x32, 0xE2, 0x81, 0x84, 0x33,
- 0x45, 0x32, 0xE2, 0x81, 0x84, 0x35, 0x45, 0x33,
- 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x33, 0x31, 0xE6,
- 0x97, 0xA5, 0x45, 0x33, 0xE2, 0x81, 0x84, 0x34,
- 0x45, 0x33, 0xE2, 0x81, 0x84, 0x35, 0x45, 0x33,
- // Bytes 22c0 - 22ff
- 0xE2, 0x81, 0x84, 0x38, 0x45, 0x34, 0xE2, 0x81,
- 0x84, 0x35, 0x45, 0x35, 0xE2, 0x81, 0x84, 0x36,
- 0x45, 0x35, 0xE2, 0x81, 0x84, 0x38, 0x45, 0x37,
- 0xE2, 0x81, 0x84, 0x38, 0x45, 0x41, 0xE2, 0x88,
- 0x95, 0x6D, 0x45, 0x56, 0xE2, 0x88, 0x95, 0x6D,
- 0x45, 0x6D, 0xE2, 0x88, 0x95, 0x73, 0x46, 0x31,
- 0xE2, 0x81, 0x84, 0x31, 0x30, 0x46, 0x43, 0xE2,
- 0x88, 0x95, 0x6B, 0x67, 0x46, 0x6D, 0xE2, 0x88,
- // Bytes 2300 - 233f
- 0x95, 0x73, 0x32, 0x46, 0xD8, 0xA8, 0xD8, 0xAD,
- 0xD9, 0x8A, 0x46, 0xD8, 0xA8, 0xD8, 0xAE, 0xD9,
- 0x8A, 0x46, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x85,
- 0x46, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x89, 0x46,
- 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD8,
- 0xAA, 0xD8, 0xAD, 0xD8, 0xAC, 0x46, 0xD8, 0xAA,
- 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD8, 0xAA, 0xD8,
- 0xAE, 0xD9, 0x85, 0x46, 0xD8, 0xAA, 0xD8, 0xAE,
- // Bytes 2340 - 237f
- 0xD9, 0x89, 0x46, 0xD8, 0xAA, 0xD8, 0xAE, 0xD9,
- 0x8A, 0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAC,
- 0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAD, 0x46,
- 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAE, 0x46, 0xD8,
- 0xAA, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xAA,
- 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xAC, 0xD8,
- 0xAD, 0xD9, 0x89, 0x46, 0xD8, 0xAC, 0xD8, 0xAD,
- 0xD9, 0x8A, 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD8,
- // Bytes 2380 - 23bf
- 0xAD, 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x89,
- 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x8A, 0x46,
- 0xD8, 0xAD, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD8,
- 0xAD, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xAD,
- 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xB3, 0xD8,
- 0xAC, 0xD8, 0xAD, 0x46, 0xD8, 0xB3, 0xD8, 0xAC,
- 0xD9, 0x89, 0x46, 0xD8, 0xB3, 0xD8, 0xAD, 0xD8,
- 0xAC, 0x46, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x89,
- // Bytes 23c0 - 23ff
- 0x46, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x8A, 0x46,
- 0xD8, 0xB3, 0xD9, 0x85, 0xD8, 0xAC, 0x46, 0xD8,
- 0xB3, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8, 0xB3,
- 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB4, 0xD8,
- 0xAC, 0xD9, 0x8A, 0x46, 0xD8, 0xB4, 0xD8, 0xAD,
- 0xD9, 0x85, 0x46, 0xD8, 0xB4, 0xD8, 0xAD, 0xD9,
- 0x8A, 0x46, 0xD8, 0xB4, 0xD9, 0x85, 0xD8, 0xAE,
- 0x46, 0xD8, 0xB4, 0xD9, 0x85, 0xD9, 0x85, 0x46,
- // Bytes 2400 - 243f
- 0xD8, 0xB5, 0xD8, 0xAD, 0xD8, 0xAD, 0x46, 0xD8,
- 0xB5, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD8, 0xB5,
- 0xD9, 0x84, 0xD9, 0x89, 0x46, 0xD8, 0xB5, 0xD9,
- 0x84, 0xDB, 0x92, 0x46, 0xD8, 0xB5, 0xD9, 0x85,
- 0xD9, 0x85, 0x46, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9,
- 0x89, 0x46, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x8A,
- 0x46, 0xD8, 0xB6, 0xD8, 0xAE, 0xD9, 0x85, 0x46,
- 0xD8, 0xB7, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8,
- // Bytes 2440 - 247f
- 0xB7, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB7,
- 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xB9, 0xD8,
- 0xAC, 0xD9, 0x85, 0x46, 0xD8, 0xB9, 0xD9, 0x85,
- 0xD9, 0x85, 0x46, 0xD8, 0xB9, 0xD9, 0x85, 0xD9,
- 0x89, 0x46, 0xD8, 0xB9, 0xD9, 0x85, 0xD9, 0x8A,
- 0x46, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x85, 0x46,
- 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8,
- 0xBA, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x81,
- // Bytes 2480 - 24bf
- 0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD9, 0x81, 0xD9,
- 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x82, 0xD9, 0x84,
- 0xDB, 0x92, 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD8,
- 0xAD, 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x85,
- 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x8A, 0x46,
- 0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD9,
- 0x83, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x84,
- 0xD8, 0xAC, 0xD8, 0xAC, 0x46, 0xD9, 0x84, 0xD8,
- // Bytes 24c0 - 24ff
- 0xAC, 0xD9, 0x85, 0x46, 0xD9, 0x84, 0xD8, 0xAC,
- 0xD9, 0x8A, 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9,
- 0x85, 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x89,
- 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x8A, 0x46,
- 0xD9, 0x84, 0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD9,
- 0x84, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD9, 0x84,
- 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x85, 0xD8,
- 0xAC, 0xD8, 0xAD, 0x46, 0xD9, 0x85, 0xD8, 0xAC,
- // Bytes 2500 - 253f
- 0xD8, 0xAE, 0x46, 0xD9, 0x85, 0xD8, 0xAC, 0xD9,
- 0x85, 0x46, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x8A,
- 0x46, 0xD9, 0x85, 0xD8, 0xAD, 0xD8, 0xAC, 0x46,
- 0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD9,
- 0x85, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD9, 0x85,
- 0xD8, 0xAE, 0xD8, 0xAC, 0x46, 0xD9, 0x85, 0xD8,
- 0xAE, 0xD9, 0x85, 0x46, 0xD9, 0x85, 0xD8, 0xAE,
- 0xD9, 0x8A, 0x46, 0xD9, 0x85, 0xD9, 0x85, 0xD9,
- // Bytes 2540 - 257f
- 0x8A, 0x46, 0xD9, 0x86, 0xD8, 0xAC, 0xD8, 0xAD,
- 0x46, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x85, 0x46,
- 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x89, 0x46, 0xD9,
- 0x86, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x86,
- 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD9, 0x86, 0xD8,
- 0xAD, 0xD9, 0x89, 0x46, 0xD9, 0x86, 0xD8, 0xAD,
- 0xD9, 0x8A, 0x46, 0xD9, 0x86, 0xD9, 0x85, 0xD9,
- 0x89, 0x46, 0xD9, 0x86, 0xD9, 0x85, 0xD9, 0x8A,
- // Bytes 2580 - 25bf
- 0x46, 0xD9, 0x87, 0xD9, 0x85, 0xD8, 0xAC, 0x46,
- 0xD9, 0x87, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD9,
- 0x8A, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x8A,
- 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD9, 0x8A, 0xD9,
- 0x85, 0xD9, 0x85, 0x46, 0xD9, 0x8A, 0xD9, 0x85,
- 0xD9, 0x8A, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8,
- 0xA7, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAC,
- 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAD, 0x46,
- // Bytes 25c0 - 25ff
- 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAE, 0x46, 0xD9,
- 0x8A, 0xD9, 0x94, 0xD8, 0xB1, 0x46, 0xD9, 0x8A,
- 0xD9, 0x94, 0xD8, 0xB2, 0x46, 0xD9, 0x8A, 0xD9,
- 0x94, 0xD9, 0x85, 0x46, 0xD9, 0x8A, 0xD9, 0x94,
- 0xD9, 0x86, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9,
- 0x87, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x88,
- 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x89, 0x46,
- 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x8A, 0x46, 0xD9,
- // Bytes 2600 - 263f
- 0x8A, 0xD9, 0x94, 0xDB, 0x86, 0x46, 0xD9, 0x8A,
- 0xD9, 0x94, 0xDB, 0x87, 0x46, 0xD9, 0x8A, 0xD9,
- 0x94, 0xDB, 0x88, 0x46, 0xD9, 0x8A, 0xD9, 0x94,
- 0xDB, 0x90, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xDB,
- 0x95, 0x46, 0xE0, 0xB9, 0x8D, 0xE0, 0xB8, 0xB2,
- 0x46, 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0x99, 0x46,
- 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0xA1, 0x46, 0xE0,
- 0xBB, 0x8D, 0xE0, 0xBA, 0xB2, 0x46, 0xE0, 0xBD,
- // Bytes 2640 - 267f
- 0x80, 0xE0, 0xBE, 0xB5, 0x46, 0xE0, 0xBD, 0x82,
- 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBD, 0x8C, 0xE0,
- 0xBE, 0xB7, 0x46, 0xE0, 0xBD, 0x91, 0xE0, 0xBE,
- 0xB7, 0x46, 0xE0, 0xBD, 0x96, 0xE0, 0xBE, 0xB7,
- 0x46, 0xE0, 0xBD, 0x9B, 0xE0, 0xBE, 0xB7, 0x46,
- 0xE0, 0xBE, 0x90, 0xE0, 0xBE, 0xB5, 0x46, 0xE0,
- 0xBE, 0x92, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE,
- 0x9C, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xA1,
- // Bytes 2680 - 26bf
- 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xA6, 0xE0,
- 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xAB, 0xE0, 0xBE,
- 0xB7, 0x46, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
- 0x46, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0x46,
- 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0x46, 0xE2,
- 0x88, 0xAE, 0xE2, 0x88, 0xAE, 0x46, 0xE3, 0x81,
- 0xBB, 0xE3, 0x81, 0x8B, 0x46, 0xE3, 0x82, 0x88,
- 0xE3, 0x82, 0x8A, 0x46, 0xE3, 0x82, 0xAD, 0xE3,
- // Bytes 26c0 - 26ff
- 0x83, 0xAD, 0x46, 0xE3, 0x82, 0xB3, 0xE3, 0x82,
- 0xB3, 0x46, 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0x88,
- 0x46, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xB3, 0x46,
- 0xE3, 0x83, 0x8A, 0xE3, 0x83, 0x8E, 0x46, 0xE3,
- 0x83, 0x9B, 0xE3, 0x83, 0xB3, 0x46, 0xE3, 0x83,
- 0x9F, 0xE3, 0x83, 0xAA, 0x46, 0xE3, 0x83, 0xAA,
- 0xE3, 0x83, 0xA9, 0x46, 0xE3, 0x83, 0xAC, 0xE3,
- 0x83, 0xA0, 0x46, 0xE5, 0xA4, 0xA7, 0xE6, 0xAD,
- // Bytes 2700 - 273f
- 0xA3, 0x46, 0xE5, 0xB9, 0xB3, 0xE6, 0x88, 0x90,
- 0x46, 0xE6, 0x98, 0x8E, 0xE6, 0xB2, 0xBB, 0x46,
- 0xE6, 0x98, 0xAD, 0xE5, 0x92, 0x8C, 0x47, 0x72,
- 0x61, 0x64, 0xE2, 0x88, 0x95, 0x73, 0x47, 0xE3,
- 0x80, 0x94, 0x53, 0xE3, 0x80, 0x95, 0x48, 0x28,
- 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1, 0x29, 0x48,
- 0x28, 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x29,
- 0x48, 0x28, 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1,
- // Bytes 2740 - 277f
- 0x29, 0x48, 0x28, 0xE1, 0x84, 0x85, 0xE1, 0x85,
- 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x86, 0xE1,
- 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x87,
- 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84,
- 0x89, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1,
- 0x84, 0x8B, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28,
- 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1, 0x29, 0x48,
- 0x28, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xAE, 0x29,
- // Bytes 2780 - 27bf
- 0x48, 0x28, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1,
- 0x29, 0x48, 0x28, 0xE1, 0x84, 0x8F, 0xE1, 0x85,
- 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x90, 0xE1,
- 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x91,
- 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84,
- 0x92, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x72, 0x61,
- 0x64, 0xE2, 0x88, 0x95, 0x73, 0x32, 0x48, 0xD8,
- 0xA7, 0xD9, 0x83, 0xD8, 0xA8, 0xD8, 0xB1, 0x48,
- // Bytes 27c0 - 27ff
- 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x84, 0xD9, 0x87,
- 0x48, 0xD8, 0xB1, 0xD8, 0xB3, 0xD9, 0x88, 0xD9,
- 0x84, 0x48, 0xD8, 0xB1, 0xDB, 0x8C, 0xD8, 0xA7,
- 0xD9, 0x84, 0x48, 0xD8, 0xB5, 0xD9, 0x84, 0xD8,
- 0xB9, 0xD9, 0x85, 0x48, 0xD8, 0xB9, 0xD9, 0x84,
- 0xD9, 0x8A, 0xD9, 0x87, 0x48, 0xD9, 0x85, 0xD8,
- 0xAD, 0xD9, 0x85, 0xD8, 0xAF, 0x48, 0xD9, 0x88,
- 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x49, 0xE2,
- // Bytes 2800 - 283f
- 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
- 0x49, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0xE2,
- 0x80, 0xB5, 0x49, 0xE2, 0x88, 0xAB, 0xE2, 0x88,
- 0xAB, 0xE2, 0x88, 0xAB, 0x49, 0xE2, 0x88, 0xAE,
- 0xE2, 0x88, 0xAE, 0xE2, 0x88, 0xAE, 0x49, 0xE3,
- 0x80, 0x94, 0xE4, 0xB8, 0x89, 0xE3, 0x80, 0x95,
- 0x49, 0xE3, 0x80, 0x94, 0xE4, 0xBA, 0x8C, 0xE3,
- 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE5, 0x8B,
- // Bytes 2840 - 287f
- 0x9D, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94,
- 0xE5, 0xAE, 0x89, 0xE3, 0x80, 0x95, 0x49, 0xE3,
- 0x80, 0x94, 0xE6, 0x89, 0x93, 0xE3, 0x80, 0x95,
- 0x49, 0xE3, 0x80, 0x94, 0xE6, 0x95, 0x97, 0xE3,
- 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE6, 0x9C,
- 0xAC, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94,
- 0xE7, 0x82, 0xB9, 0xE3, 0x80, 0x95, 0x49, 0xE3,
- 0x80, 0x94, 0xE7, 0x9B, 0x97, 0xE3, 0x80, 0x95,
- // Bytes 2880 - 28bf
- 0x49, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xBC, 0xE3,
- 0x83, 0xAB, 0x49, 0xE3, 0x82, 0xA4, 0xE3, 0x83,
- 0xB3, 0xE3, 0x83, 0x81, 0x49, 0xE3, 0x82, 0xA6,
- 0xE3, 0x82, 0xA9, 0xE3, 0x83, 0xB3, 0x49, 0xE3,
- 0x82, 0xAA, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB9,
- 0x49, 0xE3, 0x82, 0xAA, 0xE3, 0x83, 0xBC, 0xE3,
- 0x83, 0xA0, 0x49, 0xE3, 0x82, 0xAB, 0xE3, 0x82,
- 0xA4, 0xE3, 0x83, 0xAA, 0x49, 0xE3, 0x82, 0xB1,
- // Bytes 28c0 - 28ff
- 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xB9, 0x49, 0xE3,
- 0x82, 0xB3, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x8A,
- 0x49, 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3,
- 0x83, 0x81, 0x49, 0xE3, 0x82, 0xBB, 0xE3, 0x83,
- 0xB3, 0xE3, 0x83, 0x88, 0x49, 0xE3, 0x83, 0x86,
- 0xE3, 0x82, 0x99, 0xE3, 0x82, 0xB7, 0x49, 0xE3,
- 0x83, 0x88, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB,
- 0x49, 0xE3, 0x83, 0x8E, 0xE3, 0x83, 0x83, 0xE3,
- // Bytes 2900 - 293f
- 0x83, 0x88, 0x49, 0xE3, 0x83, 0x8F, 0xE3, 0x82,
- 0xA4, 0xE3, 0x83, 0x84, 0x49, 0xE3, 0x83, 0x92,
- 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB, 0x49, 0xE3,
- 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xB3,
- 0x49, 0xE3, 0x83, 0x95, 0xE3, 0x83, 0xA9, 0xE3,
- 0x83, 0xB3, 0x49, 0xE3, 0x83, 0x98, 0xE3, 0x82,
- 0x9A, 0xE3, 0x82, 0xBD, 0x49, 0xE3, 0x83, 0x98,
- 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x84, 0x49, 0xE3,
- // Bytes 2940 - 297f
- 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB,
- 0x49, 0xE3, 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3,
- 0x83, 0xB3, 0x49, 0xE3, 0x83, 0x9E, 0xE3, 0x82,
- 0xA4, 0xE3, 0x83, 0xAB, 0x49, 0xE3, 0x83, 0x9E,
- 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x8F, 0x49, 0xE3,
- 0x83, 0x9E, 0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xAF,
- 0x49, 0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xBC, 0xE3,
- 0x83, 0xAB, 0x49, 0xE3, 0x83, 0xA6, 0xE3, 0x82,
- // Bytes 2980 - 29bf
- 0xA2, 0xE3, 0x83, 0xB3, 0x49, 0xE3, 0x83, 0xAF,
- 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0x4C, 0xE2,
- 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
- 0xE2, 0x80, 0xB2, 0x4C, 0xE2, 0x88, 0xAB, 0xE2,
- 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB,
- 0x4C, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xAB, 0xE3,
- 0x83, 0x95, 0xE3, 0x82, 0xA1, 0x4C, 0xE3, 0x82,
- 0xA8, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xAB, 0xE3,
- // Bytes 29c0 - 29ff
- 0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x82,
- 0x99, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xB3, 0x4C,
- 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83,
- 0xB3, 0xE3, 0x83, 0x9E, 0x4C, 0xE3, 0x82, 0xAB,
- 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0x83, 0xE3, 0x83,
- 0x88, 0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x83, 0xAD,
- 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC, 0x4C, 0xE3,
- 0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0x8B,
- // Bytes 2a00 - 2a3f
- 0xE3, 0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAD, 0xE3,
- 0x83, 0xA5, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC,
- 0x4C, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3,
- 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0x4C, 0xE3, 0x82,
- 0xAF, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xBC, 0xE3,
- 0x83, 0x8D, 0x4C, 0xE3, 0x82, 0xB5, 0xE3, 0x82,
- 0xA4, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x4C,
- 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
- // Bytes 2a40 - 2a7f
- 0xBC, 0xE3, 0x82, 0xB9, 0x4C, 0xE3, 0x83, 0x8F,
- 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
- 0x84, 0x4C, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A,
- 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x4C, 0xE3,
- 0x83, 0x95, 0xE3, 0x82, 0xA3, 0xE3, 0x83, 0xBC,
- 0xE3, 0x83, 0x88, 0x4C, 0xE3, 0x83, 0x98, 0xE3,
- 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xBF,
- 0x4C, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3,
- // Bytes 2a80 - 2abf
- 0x83, 0x8B, 0xE3, 0x83, 0x92, 0x4C, 0xE3, 0x83,
- 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xB3, 0xE3,
- 0x82, 0xB9, 0x4C, 0xE3, 0x83, 0x9B, 0xE3, 0x82,
- 0x99, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x88, 0x4C,
- 0xE3, 0x83, 0x9E, 0xE3, 0x82, 0xA4, 0xE3, 0x82,
- 0xAF, 0xE3, 0x83, 0xAD, 0x4C, 0xE3, 0x83, 0x9F,
- 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAD, 0xE3, 0x83,
- 0xB3, 0x4C, 0xE3, 0x83, 0xA1, 0xE3, 0x83, 0xBC,
- // Bytes 2ac0 - 2aff
- 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0x4C, 0xE3,
- 0x83, 0xAA, 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88,
- 0xE3, 0x83, 0xAB, 0x4C, 0xE3, 0x83, 0xAB, 0xE3,
- 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC,
- 0x4C, 0xE6, 0xA0, 0xAA, 0xE5, 0xBC, 0x8F, 0xE4,
- 0xBC, 0x9A, 0xE7, 0xA4, 0xBE, 0x4E, 0x28, 0xE1,
- 0x84, 0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x92,
- 0xE1, 0x85, 0xAE, 0x29, 0x4F, 0xD8, 0xAC, 0xD9,
- // Bytes 2b00 - 2b3f
- 0x84, 0x20, 0xD8, 0xAC, 0xD9, 0x84, 0xD8, 0xA7,
- 0xD9, 0x84, 0xD9, 0x87, 0x4F, 0xE3, 0x82, 0xA2,
- 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83,
- 0xBC, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x82, 0xA2,
- 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x98, 0xE3, 0x82,
- 0x9A, 0xE3, 0x82, 0xA2, 0x4F, 0xE3, 0x82, 0xAD,
- 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xAF, 0xE3, 0x83,
- 0x83, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x82, 0xB5,
- // Bytes 2b40 - 2b7f
- 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x81, 0xE3, 0x83,
- 0xBC, 0xE3, 0x83, 0xA0, 0x4F, 0xE3, 0x83, 0x8F,
- 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
- 0xAC, 0xE3, 0x83, 0xAB, 0x4F, 0xE3, 0x83, 0x98,
- 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0xBF, 0xE3, 0x83,
- 0xBC, 0xE3, 0x83, 0xAB, 0x4F, 0xE3, 0x83, 0x9B,
- 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xA4, 0xE3, 0x83,
- 0xB3, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x83, 0x9E,
- // Bytes 2b80 - 2bbf
- 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB7, 0xE3, 0x83,
- 0xA7, 0xE3, 0x83, 0xB3, 0x4F, 0xE3, 0x83, 0xA1,
- 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83,
- 0x88, 0xE3, 0x83, 0xB3, 0x4F, 0xE3, 0x83, 0xAB,
- 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x95, 0xE3, 0x82,
- 0x99, 0xE3, 0x83, 0xAB, 0x51, 0x28, 0xE1, 0x84,
- 0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x8C, 0xE1,
- 0x85, 0xA5, 0xE1, 0x86, 0xAB, 0x29, 0x52, 0xE3,
- // Bytes 2bc0 - 2bff
- 0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB,
- 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
- 0xBC, 0x52, 0xE3, 0x82, 0xAD, 0xE3, 0x83, 0xAD,
- 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
- 0xA9, 0xE3, 0x83, 0xA0, 0x52, 0xE3, 0x82, 0xAD,
- 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xA1, 0xE3, 0x83,
- 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0x52,
- 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
- // Bytes 2c00 - 2c3f
- 0xA9, 0xE3, 0x83, 0xA0, 0xE3, 0x83, 0x88, 0xE3,
- 0x83, 0xB3, 0x52, 0xE3, 0x82, 0xAF, 0xE3, 0x83,
- 0xAB, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0xE3,
- 0x82, 0xA4, 0xE3, 0x83, 0xAD, 0x52, 0xE3, 0x83,
- 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3,
- 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88,
- 0x52, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3,
- 0x82, 0xA2, 0xE3, 0x82, 0xB9, 0xE3, 0x83, 0x88,
- // Bytes 2c40 - 2c7f
- 0xE3, 0x83, 0xAB, 0x52, 0xE3, 0x83, 0x95, 0xE3,
- 0x82, 0x99, 0xE3, 0x83, 0x83, 0xE3, 0x82, 0xB7,
- 0xE3, 0x82, 0xA7, 0xE3, 0x83, 0xAB, 0x52, 0xE3,
- 0x83, 0x9F, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0x8F,
- 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
- 0xAB, 0x52, 0xE3, 0x83, 0xAC, 0xE3, 0x83, 0xB3,
- 0xE3, 0x83, 0x88, 0xE3, 0x82, 0xB1, 0xE3, 0x82,
- 0x99, 0xE3, 0x83, 0xB3, 0x61, 0xD8, 0xB5, 0xD9,
- // Bytes 2c80 - 2cbf
- 0x84, 0xD9, 0x89, 0x20, 0xD8, 0xA7, 0xD9, 0x84,
- 0xD9, 0x84, 0xD9, 0x87, 0x20, 0xD8, 0xB9, 0xD9,
- 0x84, 0xD9, 0x8A, 0xD9, 0x87, 0x20, 0xD9, 0x88,
- 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x06, 0xE0,
- 0xA7, 0x87, 0xE0, 0xA6, 0xBE, 0x01, 0x06, 0xE0,
- 0xA7, 0x87, 0xE0, 0xA7, 0x97, 0x01, 0x06, 0xE0,
- 0xAD, 0x87, 0xE0, 0xAC, 0xBE, 0x01, 0x06, 0xE0,
- 0xAD, 0x87, 0xE0, 0xAD, 0x96, 0x01, 0x06, 0xE0,
- // Bytes 2cc0 - 2cff
- 0xAD, 0x87, 0xE0, 0xAD, 0x97, 0x01, 0x06, 0xE0,
- 0xAE, 0x92, 0xE0, 0xAF, 0x97, 0x01, 0x06, 0xE0,
- 0xAF, 0x86, 0xE0, 0xAE, 0xBE, 0x01, 0x06, 0xE0,
- 0xAF, 0x86, 0xE0, 0xAF, 0x97, 0x01, 0x06, 0xE0,
- 0xAF, 0x87, 0xE0, 0xAE, 0xBE, 0x01, 0x06, 0xE0,
- 0xB2, 0xBF, 0xE0, 0xB3, 0x95, 0x01, 0x06, 0xE0,
- 0xB3, 0x86, 0xE0, 0xB3, 0x95, 0x01, 0x06, 0xE0,
- 0xB3, 0x86, 0xE0, 0xB3, 0x96, 0x01, 0x06, 0xE0,
- // Bytes 2d00 - 2d3f
- 0xB5, 0x86, 0xE0, 0xB4, 0xBE, 0x01, 0x06, 0xE0,
- 0xB5, 0x86, 0xE0, 0xB5, 0x97, 0x01, 0x06, 0xE0,
- 0xB5, 0x87, 0xE0, 0xB4, 0xBE, 0x01, 0x06, 0xE0,
- 0xB7, 0x99, 0xE0, 0xB7, 0x9F, 0x01, 0x06, 0xE1,
- 0x80, 0xA5, 0xE1, 0x80, 0xAE, 0x01, 0x06, 0xE1,
- 0xAC, 0x85, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
- 0xAC, 0x87, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
- 0xAC, 0x89, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
- // Bytes 2d40 - 2d7f
- 0xAC, 0x8B, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
- 0xAC, 0x8D, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
- 0xAC, 0x91, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
- 0xAC, 0xBA, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
- 0xAC, 0xBC, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
- 0xAC, 0xBE, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
- 0xAC, 0xBF, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
- 0xAD, 0x82, 0xE1, 0xAC, 0xB5, 0x01, 0x08, 0xF0,
- // Bytes 2d80 - 2dbf
- 0x91, 0x84, 0xB1, 0xF0, 0x91, 0x84, 0xA7, 0x01,
- 0x08, 0xF0, 0x91, 0x84, 0xB2, 0xF0, 0x91, 0x84,
- 0xA7, 0x01, 0x08, 0xF0, 0x91, 0x8D, 0x87, 0xF0,
- 0x91, 0x8C, 0xBE, 0x01, 0x08, 0xF0, 0x91, 0x8D,
- 0x87, 0xF0, 0x91, 0x8D, 0x97, 0x01, 0x08, 0xF0,
- 0x91, 0x92, 0xB9, 0xF0, 0x91, 0x92, 0xB0, 0x01,
- 0x08, 0xF0, 0x91, 0x92, 0xB9, 0xF0, 0x91, 0x92,
- 0xBA, 0x01, 0x08, 0xF0, 0x91, 0x92, 0xB9, 0xF0,
- // Bytes 2dc0 - 2dff
- 0x91, 0x92, 0xBD, 0x01, 0x08, 0xF0, 0x91, 0x96,
- 0xB8, 0xF0, 0x91, 0x96, 0xAF, 0x01, 0x08, 0xF0,
- 0x91, 0x96, 0xB9, 0xF0, 0x91, 0x96, 0xAF, 0x01,
- 0x09, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0xE0,
- 0xB3, 0x95, 0x02, 0x09, 0xE0, 0xB7, 0x99, 0xE0,
- 0xB7, 0x8F, 0xE0, 0xB7, 0x8A, 0x12, 0x44, 0x44,
- 0x5A, 0xCC, 0x8C, 0xC9, 0x44, 0x44, 0x7A, 0xCC,
- 0x8C, 0xC9, 0x44, 0x64, 0x7A, 0xCC, 0x8C, 0xC9,
- // Bytes 2e00 - 2e3f
- 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x93, 0xC9,
- 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x94, 0xC9,
- 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x95, 0xB5,
- 0x46, 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1, 0x01,
- 0x46, 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x01,
- 0x46, 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1, 0x01,
- 0x46, 0xE1, 0x84, 0x85, 0xE1, 0x85, 0xA1, 0x01,
- 0x46, 0xE1, 0x84, 0x86, 0xE1, 0x85, 0xA1, 0x01,
- // Bytes 2e40 - 2e7f
- 0x46, 0xE1, 0x84, 0x87, 0xE1, 0x85, 0xA1, 0x01,
- 0x46, 0xE1, 0x84, 0x89, 0xE1, 0x85, 0xA1, 0x01,
- 0x46, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xA1, 0x01,
- 0x46, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xAE, 0x01,
- 0x46, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1, 0x01,
- 0x46, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1, 0x01,
- 0x46, 0xE1, 0x84, 0x8F, 0xE1, 0x85, 0xA1, 0x01,
- 0x46, 0xE1, 0x84, 0x90, 0xE1, 0x85, 0xA1, 0x01,
- // Bytes 2e80 - 2ebf
- 0x46, 0xE1, 0x84, 0x91, 0xE1, 0x85, 0xA1, 0x01,
- 0x46, 0xE1, 0x84, 0x92, 0xE1, 0x85, 0xA1, 0x01,
- 0x49, 0xE3, 0x83, 0xA1, 0xE3, 0x82, 0xAB, 0xE3,
- 0x82, 0x99, 0x0D, 0x4C, 0xE1, 0x84, 0x8C, 0xE1,
- 0x85, 0xAE, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xB4,
- 0x01, 0x4C, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99,
- 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0D, 0x4C,
- 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
- // Bytes 2ec0 - 2eff
- 0x9B, 0xE3, 0x82, 0x9A, 0x0D, 0x4C, 0xE3, 0x83,
- 0xA4, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3,
- 0x82, 0x99, 0x0D, 0x4F, 0xE1, 0x84, 0x8E, 0xE1,
- 0x85, 0xA1, 0xE1, 0x86, 0xB7, 0xE1, 0x84, 0x80,
- 0xE1, 0x85, 0xA9, 0x01, 0x4F, 0xE3, 0x82, 0xA4,
- 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0xB3, 0xE3, 0x82,
- 0xAF, 0xE3, 0x82, 0x99, 0x0D, 0x4F, 0xE3, 0x82,
- 0xB7, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xB3, 0xE3,
- // Bytes 2f00 - 2f3f
- 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x0D, 0x4F, 0xE3,
- 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC,
- 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x0D, 0x4F,
- 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0xE3, 0x83,
- 0xB3, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D,
- 0x52, 0xE3, 0x82, 0xA8, 0xE3, 0x82, 0xB9, 0xE3,
- 0x82, 0xAF, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88,
- 0xE3, 0x82, 0x99, 0x0D, 0x52, 0xE3, 0x83, 0x95,
- // Bytes 2f40 - 2f7f
- 0xE3, 0x82, 0xA1, 0xE3, 0x83, 0xA9, 0xE3, 0x83,
- 0x83, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D,
- 0x86, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0x01,
- 0x86, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8F, 0x01,
- 0x03, 0x3C, 0xCC, 0xB8, 0x05, 0x03, 0x3D, 0xCC,
- 0xB8, 0x05, 0x03, 0x3E, 0xCC, 0xB8, 0x05, 0x03,
- 0x41, 0xCC, 0x80, 0xC9, 0x03, 0x41, 0xCC, 0x81,
- 0xC9, 0x03, 0x41, 0xCC, 0x83, 0xC9, 0x03, 0x41,
- // Bytes 2f80 - 2fbf
- 0xCC, 0x84, 0xC9, 0x03, 0x41, 0xCC, 0x89, 0xC9,
- 0x03, 0x41, 0xCC, 0x8C, 0xC9, 0x03, 0x41, 0xCC,
- 0x8F, 0xC9, 0x03, 0x41, 0xCC, 0x91, 0xC9, 0x03,
- 0x41, 0xCC, 0xA5, 0xB5, 0x03, 0x41, 0xCC, 0xA8,
- 0xA5, 0x03, 0x42, 0xCC, 0x87, 0xC9, 0x03, 0x42,
- 0xCC, 0xA3, 0xB5, 0x03, 0x42, 0xCC, 0xB1, 0xB5,
- 0x03, 0x43, 0xCC, 0x81, 0xC9, 0x03, 0x43, 0xCC,
- 0x82, 0xC9, 0x03, 0x43, 0xCC, 0x87, 0xC9, 0x03,
- // Bytes 2fc0 - 2fff
- 0x43, 0xCC, 0x8C, 0xC9, 0x03, 0x44, 0xCC, 0x87,
- 0xC9, 0x03, 0x44, 0xCC, 0x8C, 0xC9, 0x03, 0x44,
- 0xCC, 0xA3, 0xB5, 0x03, 0x44, 0xCC, 0xA7, 0xA5,
- 0x03, 0x44, 0xCC, 0xAD, 0xB5, 0x03, 0x44, 0xCC,
- 0xB1, 0xB5, 0x03, 0x45, 0xCC, 0x80, 0xC9, 0x03,
- 0x45, 0xCC, 0x81, 0xC9, 0x03, 0x45, 0xCC, 0x83,
- 0xC9, 0x03, 0x45, 0xCC, 0x86, 0xC9, 0x03, 0x45,
- 0xCC, 0x87, 0xC9, 0x03, 0x45, 0xCC, 0x88, 0xC9,
- // Bytes 3000 - 303f
- 0x03, 0x45, 0xCC, 0x89, 0xC9, 0x03, 0x45, 0xCC,
- 0x8C, 0xC9, 0x03, 0x45, 0xCC, 0x8F, 0xC9, 0x03,
- 0x45, 0xCC, 0x91, 0xC9, 0x03, 0x45, 0xCC, 0xA8,
- 0xA5, 0x03, 0x45, 0xCC, 0xAD, 0xB5, 0x03, 0x45,
- 0xCC, 0xB0, 0xB5, 0x03, 0x46, 0xCC, 0x87, 0xC9,
- 0x03, 0x47, 0xCC, 0x81, 0xC9, 0x03, 0x47, 0xCC,
- 0x82, 0xC9, 0x03, 0x47, 0xCC, 0x84, 0xC9, 0x03,
- 0x47, 0xCC, 0x86, 0xC9, 0x03, 0x47, 0xCC, 0x87,
- // Bytes 3040 - 307f
- 0xC9, 0x03, 0x47, 0xCC, 0x8C, 0xC9, 0x03, 0x47,
- 0xCC, 0xA7, 0xA5, 0x03, 0x48, 0xCC, 0x82, 0xC9,
- 0x03, 0x48, 0xCC, 0x87, 0xC9, 0x03, 0x48, 0xCC,
- 0x88, 0xC9, 0x03, 0x48, 0xCC, 0x8C, 0xC9, 0x03,
- 0x48, 0xCC, 0xA3, 0xB5, 0x03, 0x48, 0xCC, 0xA7,
- 0xA5, 0x03, 0x48, 0xCC, 0xAE, 0xB5, 0x03, 0x49,
- 0xCC, 0x80, 0xC9, 0x03, 0x49, 0xCC, 0x81, 0xC9,
- 0x03, 0x49, 0xCC, 0x82, 0xC9, 0x03, 0x49, 0xCC,
- // Bytes 3080 - 30bf
- 0x83, 0xC9, 0x03, 0x49, 0xCC, 0x84, 0xC9, 0x03,
- 0x49, 0xCC, 0x86, 0xC9, 0x03, 0x49, 0xCC, 0x87,
- 0xC9, 0x03, 0x49, 0xCC, 0x89, 0xC9, 0x03, 0x49,
- 0xCC, 0x8C, 0xC9, 0x03, 0x49, 0xCC, 0x8F, 0xC9,
- 0x03, 0x49, 0xCC, 0x91, 0xC9, 0x03, 0x49, 0xCC,
- 0xA3, 0xB5, 0x03, 0x49, 0xCC, 0xA8, 0xA5, 0x03,
- 0x49, 0xCC, 0xB0, 0xB5, 0x03, 0x4A, 0xCC, 0x82,
- 0xC9, 0x03, 0x4B, 0xCC, 0x81, 0xC9, 0x03, 0x4B,
- // Bytes 30c0 - 30ff
- 0xCC, 0x8C, 0xC9, 0x03, 0x4B, 0xCC, 0xA3, 0xB5,
- 0x03, 0x4B, 0xCC, 0xA7, 0xA5, 0x03, 0x4B, 0xCC,
- 0xB1, 0xB5, 0x03, 0x4C, 0xCC, 0x81, 0xC9, 0x03,
- 0x4C, 0xCC, 0x8C, 0xC9, 0x03, 0x4C, 0xCC, 0xA7,
- 0xA5, 0x03, 0x4C, 0xCC, 0xAD, 0xB5, 0x03, 0x4C,
- 0xCC, 0xB1, 0xB5, 0x03, 0x4D, 0xCC, 0x81, 0xC9,
- 0x03, 0x4D, 0xCC, 0x87, 0xC9, 0x03, 0x4D, 0xCC,
- 0xA3, 0xB5, 0x03, 0x4E, 0xCC, 0x80, 0xC9, 0x03,
- // Bytes 3100 - 313f
- 0x4E, 0xCC, 0x81, 0xC9, 0x03, 0x4E, 0xCC, 0x83,
- 0xC9, 0x03, 0x4E, 0xCC, 0x87, 0xC9, 0x03, 0x4E,
- 0xCC, 0x8C, 0xC9, 0x03, 0x4E, 0xCC, 0xA3, 0xB5,
- 0x03, 0x4E, 0xCC, 0xA7, 0xA5, 0x03, 0x4E, 0xCC,
- 0xAD, 0xB5, 0x03, 0x4E, 0xCC, 0xB1, 0xB5, 0x03,
- 0x4F, 0xCC, 0x80, 0xC9, 0x03, 0x4F, 0xCC, 0x81,
- 0xC9, 0x03, 0x4F, 0xCC, 0x86, 0xC9, 0x03, 0x4F,
- 0xCC, 0x89, 0xC9, 0x03, 0x4F, 0xCC, 0x8B, 0xC9,
- // Bytes 3140 - 317f
- 0x03, 0x4F, 0xCC, 0x8C, 0xC9, 0x03, 0x4F, 0xCC,
- 0x8F, 0xC9, 0x03, 0x4F, 0xCC, 0x91, 0xC9, 0x03,
- 0x50, 0xCC, 0x81, 0xC9, 0x03, 0x50, 0xCC, 0x87,
- 0xC9, 0x03, 0x52, 0xCC, 0x81, 0xC9, 0x03, 0x52,
- 0xCC, 0x87, 0xC9, 0x03, 0x52, 0xCC, 0x8C, 0xC9,
- 0x03, 0x52, 0xCC, 0x8F, 0xC9, 0x03, 0x52, 0xCC,
- 0x91, 0xC9, 0x03, 0x52, 0xCC, 0xA7, 0xA5, 0x03,
- 0x52, 0xCC, 0xB1, 0xB5, 0x03, 0x53, 0xCC, 0x82,
- // Bytes 3180 - 31bf
- 0xC9, 0x03, 0x53, 0xCC, 0x87, 0xC9, 0x03, 0x53,
- 0xCC, 0xA6, 0xB5, 0x03, 0x53, 0xCC, 0xA7, 0xA5,
- 0x03, 0x54, 0xCC, 0x87, 0xC9, 0x03, 0x54, 0xCC,
- 0x8C, 0xC9, 0x03, 0x54, 0xCC, 0xA3, 0xB5, 0x03,
- 0x54, 0xCC, 0xA6, 0xB5, 0x03, 0x54, 0xCC, 0xA7,
- 0xA5, 0x03, 0x54, 0xCC, 0xAD, 0xB5, 0x03, 0x54,
- 0xCC, 0xB1, 0xB5, 0x03, 0x55, 0xCC, 0x80, 0xC9,
- 0x03, 0x55, 0xCC, 0x81, 0xC9, 0x03, 0x55, 0xCC,
- // Bytes 31c0 - 31ff
- 0x82, 0xC9, 0x03, 0x55, 0xCC, 0x86, 0xC9, 0x03,
- 0x55, 0xCC, 0x89, 0xC9, 0x03, 0x55, 0xCC, 0x8A,
- 0xC9, 0x03, 0x55, 0xCC, 0x8B, 0xC9, 0x03, 0x55,
- 0xCC, 0x8C, 0xC9, 0x03, 0x55, 0xCC, 0x8F, 0xC9,
- 0x03, 0x55, 0xCC, 0x91, 0xC9, 0x03, 0x55, 0xCC,
- 0xA3, 0xB5, 0x03, 0x55, 0xCC, 0xA4, 0xB5, 0x03,
- 0x55, 0xCC, 0xA8, 0xA5, 0x03, 0x55, 0xCC, 0xAD,
- 0xB5, 0x03, 0x55, 0xCC, 0xB0, 0xB5, 0x03, 0x56,
- // Bytes 3200 - 323f
- 0xCC, 0x83, 0xC9, 0x03, 0x56, 0xCC, 0xA3, 0xB5,
- 0x03, 0x57, 0xCC, 0x80, 0xC9, 0x03, 0x57, 0xCC,
- 0x81, 0xC9, 0x03, 0x57, 0xCC, 0x82, 0xC9, 0x03,
- 0x57, 0xCC, 0x87, 0xC9, 0x03, 0x57, 0xCC, 0x88,
- 0xC9, 0x03, 0x57, 0xCC, 0xA3, 0xB5, 0x03, 0x58,
- 0xCC, 0x87, 0xC9, 0x03, 0x58, 0xCC, 0x88, 0xC9,
- 0x03, 0x59, 0xCC, 0x80, 0xC9, 0x03, 0x59, 0xCC,
- 0x81, 0xC9, 0x03, 0x59, 0xCC, 0x82, 0xC9, 0x03,
- // Bytes 3240 - 327f
- 0x59, 0xCC, 0x83, 0xC9, 0x03, 0x59, 0xCC, 0x84,
- 0xC9, 0x03, 0x59, 0xCC, 0x87, 0xC9, 0x03, 0x59,
- 0xCC, 0x88, 0xC9, 0x03, 0x59, 0xCC, 0x89, 0xC9,
- 0x03, 0x59, 0xCC, 0xA3, 0xB5, 0x03, 0x5A, 0xCC,
- 0x81, 0xC9, 0x03, 0x5A, 0xCC, 0x82, 0xC9, 0x03,
- 0x5A, 0xCC, 0x87, 0xC9, 0x03, 0x5A, 0xCC, 0x8C,
- 0xC9, 0x03, 0x5A, 0xCC, 0xA3, 0xB5, 0x03, 0x5A,
- 0xCC, 0xB1, 0xB5, 0x03, 0x61, 0xCC, 0x80, 0xC9,
- // Bytes 3280 - 32bf
- 0x03, 0x61, 0xCC, 0x81, 0xC9, 0x03, 0x61, 0xCC,
- 0x83, 0xC9, 0x03, 0x61, 0xCC, 0x84, 0xC9, 0x03,
- 0x61, 0xCC, 0x89, 0xC9, 0x03, 0x61, 0xCC, 0x8C,
- 0xC9, 0x03, 0x61, 0xCC, 0x8F, 0xC9, 0x03, 0x61,
- 0xCC, 0x91, 0xC9, 0x03, 0x61, 0xCC, 0xA5, 0xB5,
- 0x03, 0x61, 0xCC, 0xA8, 0xA5, 0x03, 0x62, 0xCC,
- 0x87, 0xC9, 0x03, 0x62, 0xCC, 0xA3, 0xB5, 0x03,
- 0x62, 0xCC, 0xB1, 0xB5, 0x03, 0x63, 0xCC, 0x81,
- // Bytes 32c0 - 32ff
- 0xC9, 0x03, 0x63, 0xCC, 0x82, 0xC9, 0x03, 0x63,
- 0xCC, 0x87, 0xC9, 0x03, 0x63, 0xCC, 0x8C, 0xC9,
- 0x03, 0x64, 0xCC, 0x87, 0xC9, 0x03, 0x64, 0xCC,
- 0x8C, 0xC9, 0x03, 0x64, 0xCC, 0xA3, 0xB5, 0x03,
- 0x64, 0xCC, 0xA7, 0xA5, 0x03, 0x64, 0xCC, 0xAD,
- 0xB5, 0x03, 0x64, 0xCC, 0xB1, 0xB5, 0x03, 0x65,
- 0xCC, 0x80, 0xC9, 0x03, 0x65, 0xCC, 0x81, 0xC9,
- 0x03, 0x65, 0xCC, 0x83, 0xC9, 0x03, 0x65, 0xCC,
- // Bytes 3300 - 333f
- 0x86, 0xC9, 0x03, 0x65, 0xCC, 0x87, 0xC9, 0x03,
- 0x65, 0xCC, 0x88, 0xC9, 0x03, 0x65, 0xCC, 0x89,
- 0xC9, 0x03, 0x65, 0xCC, 0x8C, 0xC9, 0x03, 0x65,
- 0xCC, 0x8F, 0xC9, 0x03, 0x65, 0xCC, 0x91, 0xC9,
- 0x03, 0x65, 0xCC, 0xA8, 0xA5, 0x03, 0x65, 0xCC,
- 0xAD, 0xB5, 0x03, 0x65, 0xCC, 0xB0, 0xB5, 0x03,
- 0x66, 0xCC, 0x87, 0xC9, 0x03, 0x67, 0xCC, 0x81,
- 0xC9, 0x03, 0x67, 0xCC, 0x82, 0xC9, 0x03, 0x67,
- // Bytes 3340 - 337f
- 0xCC, 0x84, 0xC9, 0x03, 0x67, 0xCC, 0x86, 0xC9,
- 0x03, 0x67, 0xCC, 0x87, 0xC9, 0x03, 0x67, 0xCC,
- 0x8C, 0xC9, 0x03, 0x67, 0xCC, 0xA7, 0xA5, 0x03,
- 0x68, 0xCC, 0x82, 0xC9, 0x03, 0x68, 0xCC, 0x87,
- 0xC9, 0x03, 0x68, 0xCC, 0x88, 0xC9, 0x03, 0x68,
- 0xCC, 0x8C, 0xC9, 0x03, 0x68, 0xCC, 0xA3, 0xB5,
- 0x03, 0x68, 0xCC, 0xA7, 0xA5, 0x03, 0x68, 0xCC,
- 0xAE, 0xB5, 0x03, 0x68, 0xCC, 0xB1, 0xB5, 0x03,
- // Bytes 3380 - 33bf
- 0x69, 0xCC, 0x80, 0xC9, 0x03, 0x69, 0xCC, 0x81,
- 0xC9, 0x03, 0x69, 0xCC, 0x82, 0xC9, 0x03, 0x69,
- 0xCC, 0x83, 0xC9, 0x03, 0x69, 0xCC, 0x84, 0xC9,
- 0x03, 0x69, 0xCC, 0x86, 0xC9, 0x03, 0x69, 0xCC,
- 0x89, 0xC9, 0x03, 0x69, 0xCC, 0x8C, 0xC9, 0x03,
- 0x69, 0xCC, 0x8F, 0xC9, 0x03, 0x69, 0xCC, 0x91,
- 0xC9, 0x03, 0x69, 0xCC, 0xA3, 0xB5, 0x03, 0x69,
- 0xCC, 0xA8, 0xA5, 0x03, 0x69, 0xCC, 0xB0, 0xB5,
- // Bytes 33c0 - 33ff
- 0x03, 0x6A, 0xCC, 0x82, 0xC9, 0x03, 0x6A, 0xCC,
- 0x8C, 0xC9, 0x03, 0x6B, 0xCC, 0x81, 0xC9, 0x03,
- 0x6B, 0xCC, 0x8C, 0xC9, 0x03, 0x6B, 0xCC, 0xA3,
- 0xB5, 0x03, 0x6B, 0xCC, 0xA7, 0xA5, 0x03, 0x6B,
- 0xCC, 0xB1, 0xB5, 0x03, 0x6C, 0xCC, 0x81, 0xC9,
- 0x03, 0x6C, 0xCC, 0x8C, 0xC9, 0x03, 0x6C, 0xCC,
- 0xA7, 0xA5, 0x03, 0x6C, 0xCC, 0xAD, 0xB5, 0x03,
- 0x6C, 0xCC, 0xB1, 0xB5, 0x03, 0x6D, 0xCC, 0x81,
- // Bytes 3400 - 343f
- 0xC9, 0x03, 0x6D, 0xCC, 0x87, 0xC9, 0x03, 0x6D,
- 0xCC, 0xA3, 0xB5, 0x03, 0x6E, 0xCC, 0x80, 0xC9,
- 0x03, 0x6E, 0xCC, 0x81, 0xC9, 0x03, 0x6E, 0xCC,
- 0x83, 0xC9, 0x03, 0x6E, 0xCC, 0x87, 0xC9, 0x03,
- 0x6E, 0xCC, 0x8C, 0xC9, 0x03, 0x6E, 0xCC, 0xA3,
- 0xB5, 0x03, 0x6E, 0xCC, 0xA7, 0xA5, 0x03, 0x6E,
- 0xCC, 0xAD, 0xB5, 0x03, 0x6E, 0xCC, 0xB1, 0xB5,
- 0x03, 0x6F, 0xCC, 0x80, 0xC9, 0x03, 0x6F, 0xCC,
- // Bytes 3440 - 347f
- 0x81, 0xC9, 0x03, 0x6F, 0xCC, 0x86, 0xC9, 0x03,
- 0x6F, 0xCC, 0x89, 0xC9, 0x03, 0x6F, 0xCC, 0x8B,
- 0xC9, 0x03, 0x6F, 0xCC, 0x8C, 0xC9, 0x03, 0x6F,
- 0xCC, 0x8F, 0xC9, 0x03, 0x6F, 0xCC, 0x91, 0xC9,
- 0x03, 0x70, 0xCC, 0x81, 0xC9, 0x03, 0x70, 0xCC,
- 0x87, 0xC9, 0x03, 0x72, 0xCC, 0x81, 0xC9, 0x03,
- 0x72, 0xCC, 0x87, 0xC9, 0x03, 0x72, 0xCC, 0x8C,
- 0xC9, 0x03, 0x72, 0xCC, 0x8F, 0xC9, 0x03, 0x72,
- // Bytes 3480 - 34bf
- 0xCC, 0x91, 0xC9, 0x03, 0x72, 0xCC, 0xA7, 0xA5,
- 0x03, 0x72, 0xCC, 0xB1, 0xB5, 0x03, 0x73, 0xCC,
- 0x82, 0xC9, 0x03, 0x73, 0xCC, 0x87, 0xC9, 0x03,
- 0x73, 0xCC, 0xA6, 0xB5, 0x03, 0x73, 0xCC, 0xA7,
- 0xA5, 0x03, 0x74, 0xCC, 0x87, 0xC9, 0x03, 0x74,
- 0xCC, 0x88, 0xC9, 0x03, 0x74, 0xCC, 0x8C, 0xC9,
- 0x03, 0x74, 0xCC, 0xA3, 0xB5, 0x03, 0x74, 0xCC,
- 0xA6, 0xB5, 0x03, 0x74, 0xCC, 0xA7, 0xA5, 0x03,
- // Bytes 34c0 - 34ff
- 0x74, 0xCC, 0xAD, 0xB5, 0x03, 0x74, 0xCC, 0xB1,
- 0xB5, 0x03, 0x75, 0xCC, 0x80, 0xC9, 0x03, 0x75,
- 0xCC, 0x81, 0xC9, 0x03, 0x75, 0xCC, 0x82, 0xC9,
- 0x03, 0x75, 0xCC, 0x86, 0xC9, 0x03, 0x75, 0xCC,
- 0x89, 0xC9, 0x03, 0x75, 0xCC, 0x8A, 0xC9, 0x03,
- 0x75, 0xCC, 0x8B, 0xC9, 0x03, 0x75, 0xCC, 0x8C,
- 0xC9, 0x03, 0x75, 0xCC, 0x8F, 0xC9, 0x03, 0x75,
- 0xCC, 0x91, 0xC9, 0x03, 0x75, 0xCC, 0xA3, 0xB5,
- // Bytes 3500 - 353f
- 0x03, 0x75, 0xCC, 0xA4, 0xB5, 0x03, 0x75, 0xCC,
- 0xA8, 0xA5, 0x03, 0x75, 0xCC, 0xAD, 0xB5, 0x03,
- 0x75, 0xCC, 0xB0, 0xB5, 0x03, 0x76, 0xCC, 0x83,
- 0xC9, 0x03, 0x76, 0xCC, 0xA3, 0xB5, 0x03, 0x77,
- 0xCC, 0x80, 0xC9, 0x03, 0x77, 0xCC, 0x81, 0xC9,
- 0x03, 0x77, 0xCC, 0x82, 0xC9, 0x03, 0x77, 0xCC,
- 0x87, 0xC9, 0x03, 0x77, 0xCC, 0x88, 0xC9, 0x03,
- 0x77, 0xCC, 0x8A, 0xC9, 0x03, 0x77, 0xCC, 0xA3,
- // Bytes 3540 - 357f
- 0xB5, 0x03, 0x78, 0xCC, 0x87, 0xC9, 0x03, 0x78,
- 0xCC, 0x88, 0xC9, 0x03, 0x79, 0xCC, 0x80, 0xC9,
- 0x03, 0x79, 0xCC, 0x81, 0xC9, 0x03, 0x79, 0xCC,
- 0x82, 0xC9, 0x03, 0x79, 0xCC, 0x83, 0xC9, 0x03,
- 0x79, 0xCC, 0x84, 0xC9, 0x03, 0x79, 0xCC, 0x87,
- 0xC9, 0x03, 0x79, 0xCC, 0x88, 0xC9, 0x03, 0x79,
- 0xCC, 0x89, 0xC9, 0x03, 0x79, 0xCC, 0x8A, 0xC9,
- 0x03, 0x79, 0xCC, 0xA3, 0xB5, 0x03, 0x7A, 0xCC,
- // Bytes 3580 - 35bf
- 0x81, 0xC9, 0x03, 0x7A, 0xCC, 0x82, 0xC9, 0x03,
- 0x7A, 0xCC, 0x87, 0xC9, 0x03, 0x7A, 0xCC, 0x8C,
- 0xC9, 0x03, 0x7A, 0xCC, 0xA3, 0xB5, 0x03, 0x7A,
- 0xCC, 0xB1, 0xB5, 0x04, 0xC2, 0xA8, 0xCC, 0x80,
- 0xCA, 0x04, 0xC2, 0xA8, 0xCC, 0x81, 0xCA, 0x04,
- 0xC2, 0xA8, 0xCD, 0x82, 0xCA, 0x04, 0xC3, 0x86,
- 0xCC, 0x81, 0xC9, 0x04, 0xC3, 0x86, 0xCC, 0x84,
- 0xC9, 0x04, 0xC3, 0x98, 0xCC, 0x81, 0xC9, 0x04,
- // Bytes 35c0 - 35ff
- 0xC3, 0xA6, 0xCC, 0x81, 0xC9, 0x04, 0xC3, 0xA6,
- 0xCC, 0x84, 0xC9, 0x04, 0xC3, 0xB8, 0xCC, 0x81,
- 0xC9, 0x04, 0xC5, 0xBF, 0xCC, 0x87, 0xC9, 0x04,
- 0xC6, 0xB7, 0xCC, 0x8C, 0xC9, 0x04, 0xCA, 0x92,
- 0xCC, 0x8C, 0xC9, 0x04, 0xCE, 0x91, 0xCC, 0x80,
- 0xC9, 0x04, 0xCE, 0x91, 0xCC, 0x81, 0xC9, 0x04,
- 0xCE, 0x91, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0x91,
- 0xCC, 0x86, 0xC9, 0x04, 0xCE, 0x91, 0xCD, 0x85,
- // Bytes 3600 - 363f
- 0xD9, 0x04, 0xCE, 0x95, 0xCC, 0x80, 0xC9, 0x04,
- 0xCE, 0x95, 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0x97,
- 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x97, 0xCC, 0x81,
- 0xC9, 0x04, 0xCE, 0x97, 0xCD, 0x85, 0xD9, 0x04,
- 0xCE, 0x99, 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x99,
- 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0x99, 0xCC, 0x84,
- 0xC9, 0x04, 0xCE, 0x99, 0xCC, 0x86, 0xC9, 0x04,
- 0xCE, 0x99, 0xCC, 0x88, 0xC9, 0x04, 0xCE, 0x9F,
- // Bytes 3640 - 367f
- 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x9F, 0xCC, 0x81,
- 0xC9, 0x04, 0xCE, 0xA1, 0xCC, 0x94, 0xC9, 0x04,
- 0xCE, 0xA5, 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0xA5,
- 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0xA5, 0xCC, 0x84,
- 0xC9, 0x04, 0xCE, 0xA5, 0xCC, 0x86, 0xC9, 0x04,
- 0xCE, 0xA5, 0xCC, 0x88, 0xC9, 0x04, 0xCE, 0xA9,
- 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0xA9, 0xCC, 0x81,
- 0xC9, 0x04, 0xCE, 0xA9, 0xCD, 0x85, 0xD9, 0x04,
- // Bytes 3680 - 36bf
- 0xCE, 0xB1, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0xB1,
- 0xCC, 0x86, 0xC9, 0x04, 0xCE, 0xB1, 0xCD, 0x85,
- 0xD9, 0x04, 0xCE, 0xB5, 0xCC, 0x80, 0xC9, 0x04,
- 0xCE, 0xB5, 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0xB7,
- 0xCD, 0x85, 0xD9, 0x04, 0xCE, 0xB9, 0xCC, 0x80,
- 0xC9, 0x04, 0xCE, 0xB9, 0xCC, 0x81, 0xC9, 0x04,
- 0xCE, 0xB9, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0xB9,
- 0xCC, 0x86, 0xC9, 0x04, 0xCE, 0xB9, 0xCD, 0x82,
- // Bytes 36c0 - 36ff
- 0xC9, 0x04, 0xCE, 0xBF, 0xCC, 0x80, 0xC9, 0x04,
- 0xCE, 0xBF, 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x81,
- 0xCC, 0x93, 0xC9, 0x04, 0xCF, 0x81, 0xCC, 0x94,
- 0xC9, 0x04, 0xCF, 0x85, 0xCC, 0x80, 0xC9, 0x04,
- 0xCF, 0x85, 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x85,
- 0xCC, 0x84, 0xC9, 0x04, 0xCF, 0x85, 0xCC, 0x86,
- 0xC9, 0x04, 0xCF, 0x85, 0xCD, 0x82, 0xC9, 0x04,
- 0xCF, 0x89, 0xCD, 0x85, 0xD9, 0x04, 0xCF, 0x92,
- // Bytes 3700 - 373f
- 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x92, 0xCC, 0x88,
- 0xC9, 0x04, 0xD0, 0x86, 0xCC, 0x88, 0xC9, 0x04,
- 0xD0, 0x90, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0x90,
- 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x93, 0xCC, 0x81,
- 0xC9, 0x04, 0xD0, 0x95, 0xCC, 0x80, 0xC9, 0x04,
- 0xD0, 0x95, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0x95,
- 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x96, 0xCC, 0x86,
- 0xC9, 0x04, 0xD0, 0x96, 0xCC, 0x88, 0xC9, 0x04,
- // Bytes 3740 - 377f
- 0xD0, 0x97, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x98,
- 0xCC, 0x80, 0xC9, 0x04, 0xD0, 0x98, 0xCC, 0x84,
- 0xC9, 0x04, 0xD0, 0x98, 0xCC, 0x86, 0xC9, 0x04,
- 0xD0, 0x98, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x9A,
- 0xCC, 0x81, 0xC9, 0x04, 0xD0, 0x9E, 0xCC, 0x88,
- 0xC9, 0x04, 0xD0, 0xA3, 0xCC, 0x84, 0xC9, 0x04,
- 0xD0, 0xA3, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xA3,
- 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xA3, 0xCC, 0x8B,
- // Bytes 3780 - 37bf
- 0xC9, 0x04, 0xD0, 0xA7, 0xCC, 0x88, 0xC9, 0x04,
- 0xD0, 0xAB, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xAD,
- 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xB0, 0xCC, 0x86,
- 0xC9, 0x04, 0xD0, 0xB0, 0xCC, 0x88, 0xC9, 0x04,
- 0xD0, 0xB3, 0xCC, 0x81, 0xC9, 0x04, 0xD0, 0xB5,
- 0xCC, 0x80, 0xC9, 0x04, 0xD0, 0xB5, 0xCC, 0x86,
- 0xC9, 0x04, 0xD0, 0xB5, 0xCC, 0x88, 0xC9, 0x04,
- 0xD0, 0xB6, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xB6,
- // Bytes 37c0 - 37ff
- 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xB7, 0xCC, 0x88,
- 0xC9, 0x04, 0xD0, 0xB8, 0xCC, 0x80, 0xC9, 0x04,
- 0xD0, 0xB8, 0xCC, 0x84, 0xC9, 0x04, 0xD0, 0xB8,
- 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xB8, 0xCC, 0x88,
- 0xC9, 0x04, 0xD0, 0xBA, 0xCC, 0x81, 0xC9, 0x04,
- 0xD0, 0xBE, 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0x83,
- 0xCC, 0x84, 0xC9, 0x04, 0xD1, 0x83, 0xCC, 0x86,
- 0xC9, 0x04, 0xD1, 0x83, 0xCC, 0x88, 0xC9, 0x04,
- // Bytes 3800 - 383f
- 0xD1, 0x83, 0xCC, 0x8B, 0xC9, 0x04, 0xD1, 0x87,
- 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0x8B, 0xCC, 0x88,
- 0xC9, 0x04, 0xD1, 0x8D, 0xCC, 0x88, 0xC9, 0x04,
- 0xD1, 0x96, 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0xB4,
- 0xCC, 0x8F, 0xC9, 0x04, 0xD1, 0xB5, 0xCC, 0x8F,
- 0xC9, 0x04, 0xD3, 0x98, 0xCC, 0x88, 0xC9, 0x04,
- 0xD3, 0x99, 0xCC, 0x88, 0xC9, 0x04, 0xD3, 0xA8,
- 0xCC, 0x88, 0xC9, 0x04, 0xD3, 0xA9, 0xCC, 0x88,
- // Bytes 3840 - 387f
- 0xC9, 0x04, 0xD8, 0xA7, 0xD9, 0x93, 0xC9, 0x04,
- 0xD8, 0xA7, 0xD9, 0x94, 0xC9, 0x04, 0xD8, 0xA7,
- 0xD9, 0x95, 0xB5, 0x04, 0xD9, 0x88, 0xD9, 0x94,
- 0xC9, 0x04, 0xD9, 0x8A, 0xD9, 0x94, 0xC9, 0x04,
- 0xDB, 0x81, 0xD9, 0x94, 0xC9, 0x04, 0xDB, 0x92,
- 0xD9, 0x94, 0xC9, 0x04, 0xDB, 0x95, 0xD9, 0x94,
- 0xC9, 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x80, 0xCA,
- 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05,
- // Bytes 3880 - 38bf
- 0x41, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x41,
- 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x41, 0xCC,
- 0x86, 0xCC, 0x80, 0xCA, 0x05, 0x41, 0xCC, 0x86,
- 0xCC, 0x81, 0xCA, 0x05, 0x41, 0xCC, 0x86, 0xCC,
- 0x83, 0xCA, 0x05, 0x41, 0xCC, 0x86, 0xCC, 0x89,
- 0xCA, 0x05, 0x41, 0xCC, 0x87, 0xCC, 0x84, 0xCA,
- 0x05, 0x41, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05,
- 0x41, 0xCC, 0x8A, 0xCC, 0x81, 0xCA, 0x05, 0x41,
- // Bytes 38c0 - 38ff
- 0xCC, 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x41, 0xCC,
- 0xA3, 0xCC, 0x86, 0xCA, 0x05, 0x43, 0xCC, 0xA7,
- 0xCC, 0x81, 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC,
- 0x80, 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x81,
- 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x83, 0xCA,
- 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05,
- 0x45, 0xCC, 0x84, 0xCC, 0x80, 0xCA, 0x05, 0x45,
- 0xCC, 0x84, 0xCC, 0x81, 0xCA, 0x05, 0x45, 0xCC,
- // Bytes 3900 - 393f
- 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x45, 0xCC, 0xA7,
- 0xCC, 0x86, 0xCA, 0x05, 0x49, 0xCC, 0x88, 0xCC,
- 0x81, 0xCA, 0x05, 0x4C, 0xCC, 0xA3, 0xCC, 0x84,
- 0xCA, 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x80, 0xCA,
- 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05,
- 0x4F, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x4F,
- 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x4F, 0xCC,
- 0x83, 0xCC, 0x81, 0xCA, 0x05, 0x4F, 0xCC, 0x83,
- // Bytes 3940 - 397f
- 0xCC, 0x84, 0xCA, 0x05, 0x4F, 0xCC, 0x83, 0xCC,
- 0x88, 0xCA, 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x80,
- 0xCA, 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x81, 0xCA,
- 0x05, 0x4F, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05,
- 0x4F, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x4F,
- 0xCC, 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x4F, 0xCC,
- 0x9B, 0xCC, 0x81, 0xCA, 0x05, 0x4F, 0xCC, 0x9B,
- 0xCC, 0x83, 0xCA, 0x05, 0x4F, 0xCC, 0x9B, 0xCC,
- // Bytes 3980 - 39bf
- 0x89, 0xCA, 0x05, 0x4F, 0xCC, 0x9B, 0xCC, 0xA3,
- 0xB6, 0x05, 0x4F, 0xCC, 0xA3, 0xCC, 0x82, 0xCA,
- 0x05, 0x4F, 0xCC, 0xA8, 0xCC, 0x84, 0xCA, 0x05,
- 0x52, 0xCC, 0xA3, 0xCC, 0x84, 0xCA, 0x05, 0x53,
- 0xCC, 0x81, 0xCC, 0x87, 0xCA, 0x05, 0x53, 0xCC,
- 0x8C, 0xCC, 0x87, 0xCA, 0x05, 0x53, 0xCC, 0xA3,
- 0xCC, 0x87, 0xCA, 0x05, 0x55, 0xCC, 0x83, 0xCC,
- 0x81, 0xCA, 0x05, 0x55, 0xCC, 0x84, 0xCC, 0x88,
- // Bytes 39c0 - 39ff
- 0xCA, 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x80, 0xCA,
- 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x05,
- 0x55, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x55,
- 0xCC, 0x88, 0xCC, 0x8C, 0xCA, 0x05, 0x55, 0xCC,
- 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x55, 0xCC, 0x9B,
- 0xCC, 0x81, 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC,
- 0x83, 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC, 0x89,
- 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6,
- // Bytes 3a00 - 3a3f
- 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x80, 0xCA, 0x05,
- 0x61, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, 0x61,
- 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x61, 0xCC,
- 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x61, 0xCC, 0x86,
- 0xCC, 0x80, 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC,
- 0x81, 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x83,
- 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x89, 0xCA,
- 0x05, 0x61, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05,
- // Bytes 3a40 - 3a7f
- 0x61, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x61,
- 0xCC, 0x8A, 0xCC, 0x81, 0xCA, 0x05, 0x61, 0xCC,
- 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x61, 0xCC, 0xA3,
- 0xCC, 0x86, 0xCA, 0x05, 0x63, 0xCC, 0xA7, 0xCC,
- 0x81, 0xCA, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x80,
- 0xCA, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x81, 0xCA,
- 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05,
- 0x65, 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x65,
- // Bytes 3a80 - 3abf
- 0xCC, 0x84, 0xCC, 0x80, 0xCA, 0x05, 0x65, 0xCC,
- 0x84, 0xCC, 0x81, 0xCA, 0x05, 0x65, 0xCC, 0xA3,
- 0xCC, 0x82, 0xCA, 0x05, 0x65, 0xCC, 0xA7, 0xCC,
- 0x86, 0xCA, 0x05, 0x69, 0xCC, 0x88, 0xCC, 0x81,
- 0xCA, 0x05, 0x6C, 0xCC, 0xA3, 0xCC, 0x84, 0xCA,
- 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x80, 0xCA, 0x05,
- 0x6F, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, 0x6F,
- 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x6F, 0xCC,
- // Bytes 3ac0 - 3aff
- 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x6F, 0xCC, 0x83,
- 0xCC, 0x81, 0xCA, 0x05, 0x6F, 0xCC, 0x83, 0xCC,
- 0x84, 0xCA, 0x05, 0x6F, 0xCC, 0x83, 0xCC, 0x88,
- 0xCA, 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x80, 0xCA,
- 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x81, 0xCA, 0x05,
- 0x6F, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05, 0x6F,
- 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x6F, 0xCC,
- 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x6F, 0xCC, 0x9B,
- // Bytes 3b00 - 3b3f
- 0xCC, 0x81, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC,
- 0x83, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0x89,
- 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6,
- 0x05, 0x6F, 0xCC, 0xA3, 0xCC, 0x82, 0xCA, 0x05,
- 0x6F, 0xCC, 0xA8, 0xCC, 0x84, 0xCA, 0x05, 0x72,
- 0xCC, 0xA3, 0xCC, 0x84, 0xCA, 0x05, 0x73, 0xCC,
- 0x81, 0xCC, 0x87, 0xCA, 0x05, 0x73, 0xCC, 0x8C,
- 0xCC, 0x87, 0xCA, 0x05, 0x73, 0xCC, 0xA3, 0xCC,
- // Bytes 3b40 - 3b7f
- 0x87, 0xCA, 0x05, 0x75, 0xCC, 0x83, 0xCC, 0x81,
- 0xCA, 0x05, 0x75, 0xCC, 0x84, 0xCC, 0x88, 0xCA,
- 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x80, 0xCA, 0x05,
- 0x75, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x05, 0x75,
- 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x75, 0xCC,
- 0x88, 0xCC, 0x8C, 0xCA, 0x05, 0x75, 0xCC, 0x9B,
- 0xCC, 0x80, 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC,
- 0x81, 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x83,
- // Bytes 3b80 - 3bbf
- 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x89, 0xCA,
- 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6, 0x05,
- 0xE1, 0xBE, 0xBF, 0xCC, 0x80, 0xCA, 0x05, 0xE1,
- 0xBE, 0xBF, 0xCC, 0x81, 0xCA, 0x05, 0xE1, 0xBE,
- 0xBF, 0xCD, 0x82, 0xCA, 0x05, 0xE1, 0xBF, 0xBE,
- 0xCC, 0x80, 0xCA, 0x05, 0xE1, 0xBF, 0xBE, 0xCC,
- 0x81, 0xCA, 0x05, 0xE1, 0xBF, 0xBE, 0xCD, 0x82,
- 0xCA, 0x05, 0xE2, 0x86, 0x90, 0xCC, 0xB8, 0x05,
- // Bytes 3bc0 - 3bff
- 0x05, 0xE2, 0x86, 0x92, 0xCC, 0xB8, 0x05, 0x05,
- 0xE2, 0x86, 0x94, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
- 0x87, 0x90, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x87,
- 0x92, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x87, 0x94,
- 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x88, 0x83, 0xCC,
- 0xB8, 0x05, 0x05, 0xE2, 0x88, 0x88, 0xCC, 0xB8,
- 0x05, 0x05, 0xE2, 0x88, 0x8B, 0xCC, 0xB8, 0x05,
- 0x05, 0xE2, 0x88, 0xA3, 0xCC, 0xB8, 0x05, 0x05,
- // Bytes 3c00 - 3c3f
- 0xE2, 0x88, 0xA5, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
- 0x88, 0xBC, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89,
- 0x83, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x85,
- 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x88, 0xCC,
- 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x8D, 0xCC, 0xB8,
- 0x05, 0x05, 0xE2, 0x89, 0xA1, 0xCC, 0xB8, 0x05,
- 0x05, 0xE2, 0x89, 0xA4, 0xCC, 0xB8, 0x05, 0x05,
- 0xE2, 0x89, 0xA5, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
- // Bytes 3c40 - 3c7f
- 0x89, 0xB2, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89,
- 0xB3, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xB6,
- 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xB7, 0xCC,
- 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xBA, 0xCC, 0xB8,
- 0x05, 0x05, 0xE2, 0x89, 0xBB, 0xCC, 0xB8, 0x05,
- 0x05, 0xE2, 0x89, 0xBC, 0xCC, 0xB8, 0x05, 0x05,
- 0xE2, 0x89, 0xBD, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
- 0x8A, 0x82, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A,
- // Bytes 3c80 - 3cbf
- 0x83, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x86,
- 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x87, 0xCC,
- 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x91, 0xCC, 0xB8,
- 0x05, 0x05, 0xE2, 0x8A, 0x92, 0xCC, 0xB8, 0x05,
- 0x05, 0xE2, 0x8A, 0xA2, 0xCC, 0xB8, 0x05, 0x05,
- 0xE2, 0x8A, 0xA8, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
- 0x8A, 0xA9, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A,
- 0xAB, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB2,
- // Bytes 3cc0 - 3cff
- 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB3, 0xCC,
- 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB4, 0xCC, 0xB8,
- 0x05, 0x05, 0xE2, 0x8A, 0xB5, 0xCC, 0xB8, 0x05,
- 0x06, 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
- 0x06, 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
- 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
- 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
- 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
- // Bytes 3d00 - 3d3f
- 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
- 0x06, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
- 0x06, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
- 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
- 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
- 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCD, 0x82, 0xCA,
- 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
- 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
- // Bytes 3d40 - 3d7f
- 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCD, 0x82, 0xCA,
- 0x06, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
- 0x06, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
- 0x06, 0xCE, 0x9F, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
- 0x06, 0xCE, 0x9F, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
- 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
- 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
- 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCD, 0x82, 0xCA,
- // Bytes 3d80 - 3dbf
- 0x06, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
- 0x06, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
- 0x06, 0xCE, 0xB1, 0xCC, 0x80, 0xCD, 0x85, 0xDA,
- 0x06, 0xCE, 0xB1, 0xCC, 0x81, 0xCD, 0x85, 0xDA,
- 0x06, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
- 0x06, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
- 0x06, 0xCE, 0xB1, 0xCD, 0x82, 0xCD, 0x85, 0xDA,
- 0x06, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
- // Bytes 3dc0 - 3dff
- 0x06, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
- 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
- 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
- 0x06, 0xCE, 0xB7, 0xCC, 0x80, 0xCD, 0x85, 0xDA,
- 0x06, 0xCE, 0xB7, 0xCC, 0x81, 0xCD, 0x85, 0xDA,
- 0x06, 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
- 0x06, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
- 0x06, 0xCE, 0xB7, 0xCD, 0x82, 0xCD, 0x85, 0xDA,
- // Bytes 3e00 - 3e3f
- 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x80, 0xCA,
- 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x81, 0xCA,
- 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCD, 0x82, 0xCA,
- 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
- 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
- 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCD, 0x82, 0xCA,
- 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
- 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
- // Bytes 3e40 - 3e7f
- 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCD, 0x82, 0xCA,
- 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
- 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
- 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
- 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
- 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x80, 0xCA,
- 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81, 0xCA,
- 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCD, 0x82, 0xCA,
- // Bytes 3e80 - 3ebf
- 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
- 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
- 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCD, 0x82, 0xCA,
- 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
- 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
- 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCD, 0x82, 0xCA,
- 0x06, 0xCF, 0x89, 0xCC, 0x80, 0xCD, 0x85, 0xDA,
- 0x06, 0xCF, 0x89, 0xCC, 0x81, 0xCD, 0x85, 0xDA,
- // Bytes 3ec0 - 3eff
- 0x06, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
- 0x06, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
- 0x06, 0xCF, 0x89, 0xCD, 0x82, 0xCD, 0x85, 0xDA,
- 0x06, 0xE0, 0xA4, 0xA8, 0xE0, 0xA4, 0xBC, 0x09,
- 0x06, 0xE0, 0xA4, 0xB0, 0xE0, 0xA4, 0xBC, 0x09,
- 0x06, 0xE0, 0xA4, 0xB3, 0xE0, 0xA4, 0xBC, 0x09,
- 0x06, 0xE0, 0xB1, 0x86, 0xE0, 0xB1, 0x96, 0x85,
- 0x06, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8A, 0x11,
- // Bytes 3f00 - 3f3f
- 0x06, 0xE3, 0x81, 0x86, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0x8B, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0x8D, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0x8F, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0x91, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0x95, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0x97, 0xE3, 0x82, 0x99, 0x0D,
- // Bytes 3f40 - 3f7f
- 0x06, 0xE3, 0x81, 0x99, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0x9B, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0x9D, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0x9F, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0xA4, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0xA6, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0xA8, 0xE3, 0x82, 0x99, 0x0D,
- // Bytes 3f80 - 3fbf
- 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x9A, 0x0D,
- 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x9A, 0x0D,
- 0x06, 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x9A, 0x0D,
- 0x06, 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x9A, 0x0D,
- // Bytes 3fc0 - 3fff
- 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x9A, 0x0D,
- 0x06, 0xE3, 0x82, 0x9D, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x82, 0xA6, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x82, 0xB1, 0xE3, 0x82, 0x99, 0x0D,
- // Bytes 4000 - 403f
- 0x06, 0xE3, 0x82, 0xB3, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x82, 0xB5, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x82, 0xBD, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x83, 0x81, 0xE3, 0x82, 0x99, 0x0D,
- // Bytes 4040 - 407f
- 0x06, 0xE3, 0x83, 0x84, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x83, 0x86, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0x0D,
- 0x06, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0x0D,
- 0x06, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x99, 0x0D,
- // Bytes 4080 - 40bf
- 0x06, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x9A, 0x0D,
- 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0x0D,
- 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0x0D,
- 0x06, 0xE3, 0x83, 0xAF, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x83, 0xB0, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x83, 0xB1, 0xE3, 0x82, 0x99, 0x0D,
- // Bytes 40c0 - 40ff
- 0x06, 0xE3, 0x83, 0xB2, 0xE3, 0x82, 0x99, 0x0D,
- 0x06, 0xE3, 0x83, 0xBD, 0xE3, 0x82, 0x99, 0x0D,
- 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCD,
- 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC,
- 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC,
- 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
- 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB,
- 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x81, 0xCD,
- // Bytes 4100 - 413f
- 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCD,
- 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC,
- 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
- 0x97, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB,
- 0x08, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82, 0xCD,
- 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC, 0x94, 0xCC,
- 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC,
- 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
- // Bytes 4140 - 417f
- 0x97, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB,
- 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCD,
- 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC,
- 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC,
- 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
- 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB,
- 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81, 0xCD,
- 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCD,
- // Bytes 4180 - 41bf
- 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC,
- 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
- 0xB1, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB,
- 0x08, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCD,
- 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC, 0x94, 0xCC,
- 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC,
- 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
- 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB,
- // Bytes 41c0 - 41ff
- 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80, 0xCD,
- 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC,
- 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC,
- 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
- 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB,
- 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0xCD,
- 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCD,
- 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC,
- // Bytes 4200 - 423f
- 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCF,
- 0x89, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB,
- 0x08, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCD,
- 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC, 0x94, 0xCC,
- 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC,
- 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCF,
- 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB,
- 0x08, 0xF0, 0x91, 0x82, 0x99, 0xF0, 0x91, 0x82,
- // Bytes 4240 - 427f
- 0xBA, 0x09, 0x08, 0xF0, 0x91, 0x82, 0x9B, 0xF0,
- 0x91, 0x82, 0xBA, 0x09, 0x08, 0xF0, 0x91, 0x82,
- 0xA5, 0xF0, 0x91, 0x82, 0xBA, 0x09, 0x42, 0xC2,
- 0xB4, 0x01, 0x43, 0x20, 0xCC, 0x81, 0xC9, 0x43,
- 0x20, 0xCC, 0x83, 0xC9, 0x43, 0x20, 0xCC, 0x84,
- 0xC9, 0x43, 0x20, 0xCC, 0x85, 0xC9, 0x43, 0x20,
- 0xCC, 0x86, 0xC9, 0x43, 0x20, 0xCC, 0x87, 0xC9,
- 0x43, 0x20, 0xCC, 0x88, 0xC9, 0x43, 0x20, 0xCC,
- // Bytes 4280 - 42bf
- 0x8A, 0xC9, 0x43, 0x20, 0xCC, 0x8B, 0xC9, 0x43,
- 0x20, 0xCC, 0x93, 0xC9, 0x43, 0x20, 0xCC, 0x94,
- 0xC9, 0x43, 0x20, 0xCC, 0xA7, 0xA5, 0x43, 0x20,
- 0xCC, 0xA8, 0xA5, 0x43, 0x20, 0xCC, 0xB3, 0xB5,
- 0x43, 0x20, 0xCD, 0x82, 0xC9, 0x43, 0x20, 0xCD,
- 0x85, 0xD9, 0x43, 0x20, 0xD9, 0x8B, 0x59, 0x43,
- 0x20, 0xD9, 0x8C, 0x5D, 0x43, 0x20, 0xD9, 0x8D,
- 0x61, 0x43, 0x20, 0xD9, 0x8E, 0x65, 0x43, 0x20,
- // Bytes 42c0 - 42ff
- 0xD9, 0x8F, 0x69, 0x43, 0x20, 0xD9, 0x90, 0x6D,
- 0x43, 0x20, 0xD9, 0x91, 0x71, 0x43, 0x20, 0xD9,
- 0x92, 0x75, 0x43, 0x41, 0xCC, 0x8A, 0xC9, 0x43,
- 0x73, 0xCC, 0x87, 0xC9, 0x43, 0xE1, 0x85, 0xA1,
- 0x01, 0x43, 0xE1, 0x85, 0xA2, 0x01, 0x43, 0xE1,
- 0x85, 0xA3, 0x01, 0x43, 0xE1, 0x85, 0xA4, 0x01,
- 0x43, 0xE1, 0x85, 0xA5, 0x01, 0x43, 0xE1, 0x85,
- 0xA6, 0x01, 0x43, 0xE1, 0x85, 0xA7, 0x01, 0x43,
- // Bytes 4300 - 433f
- 0xE1, 0x85, 0xA8, 0x01, 0x43, 0xE1, 0x85, 0xA9,
- 0x01, 0x43, 0xE1, 0x85, 0xAA, 0x01, 0x43, 0xE1,
- 0x85, 0xAB, 0x01, 0x43, 0xE1, 0x85, 0xAC, 0x01,
- 0x43, 0xE1, 0x85, 0xAD, 0x01, 0x43, 0xE1, 0x85,
- 0xAE, 0x01, 0x43, 0xE1, 0x85, 0xAF, 0x01, 0x43,
- 0xE1, 0x85, 0xB0, 0x01, 0x43, 0xE1, 0x85, 0xB1,
- 0x01, 0x43, 0xE1, 0x85, 0xB2, 0x01, 0x43, 0xE1,
- 0x85, 0xB3, 0x01, 0x43, 0xE1, 0x85, 0xB4, 0x01,
- // Bytes 4340 - 437f
- 0x43, 0xE1, 0x85, 0xB5, 0x01, 0x43, 0xE1, 0x86,
- 0xAA, 0x01, 0x43, 0xE1, 0x86, 0xAC, 0x01, 0x43,
- 0xE1, 0x86, 0xAD, 0x01, 0x43, 0xE1, 0x86, 0xB0,
- 0x01, 0x43, 0xE1, 0x86, 0xB1, 0x01, 0x43, 0xE1,
- 0x86, 0xB2, 0x01, 0x43, 0xE1, 0x86, 0xB3, 0x01,
- 0x43, 0xE1, 0x86, 0xB4, 0x01, 0x43, 0xE1, 0x86,
- 0xB5, 0x01, 0x44, 0x20, 0xE3, 0x82, 0x99, 0x0D,
- 0x44, 0x20, 0xE3, 0x82, 0x9A, 0x0D, 0x44, 0xC2,
- // Bytes 4380 - 43bf
- 0xA8, 0xCC, 0x81, 0xCA, 0x44, 0xCE, 0x91, 0xCC,
- 0x81, 0xC9, 0x44, 0xCE, 0x95, 0xCC, 0x81, 0xC9,
- 0x44, 0xCE, 0x97, 0xCC, 0x81, 0xC9, 0x44, 0xCE,
- 0x99, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0x9F, 0xCC,
- 0x81, 0xC9, 0x44, 0xCE, 0xA5, 0xCC, 0x81, 0xC9,
- 0x44, 0xCE, 0xA5, 0xCC, 0x88, 0xC9, 0x44, 0xCE,
- 0xA9, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xB1, 0xCC,
- 0x81, 0xC9, 0x44, 0xCE, 0xB5, 0xCC, 0x81, 0xC9,
- // Bytes 43c0 - 43ff
- 0x44, 0xCE, 0xB7, 0xCC, 0x81, 0xC9, 0x44, 0xCE,
- 0xB9, 0xCC, 0x81, 0xC9, 0x44, 0xCE, 0xBF, 0xCC,
- 0x81, 0xC9, 0x44, 0xCF, 0x85, 0xCC, 0x81, 0xC9,
- 0x44, 0xCF, 0x89, 0xCC, 0x81, 0xC9, 0x44, 0xD7,
- 0x90, 0xD6, 0xB7, 0x31, 0x44, 0xD7, 0x90, 0xD6,
- 0xB8, 0x35, 0x44, 0xD7, 0x90, 0xD6, 0xBC, 0x41,
- 0x44, 0xD7, 0x91, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
- 0x91, 0xD6, 0xBF, 0x49, 0x44, 0xD7, 0x92, 0xD6,
- // Bytes 4400 - 443f
- 0xBC, 0x41, 0x44, 0xD7, 0x93, 0xD6, 0xBC, 0x41,
- 0x44, 0xD7, 0x94, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
- 0x95, 0xD6, 0xB9, 0x39, 0x44, 0xD7, 0x95, 0xD6,
- 0xBC, 0x41, 0x44, 0xD7, 0x96, 0xD6, 0xBC, 0x41,
- 0x44, 0xD7, 0x98, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
- 0x99, 0xD6, 0xB4, 0x25, 0x44, 0xD7, 0x99, 0xD6,
- 0xBC, 0x41, 0x44, 0xD7, 0x9A, 0xD6, 0xBC, 0x41,
- 0x44, 0xD7, 0x9B, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
- // Bytes 4440 - 447f
- 0x9B, 0xD6, 0xBF, 0x49, 0x44, 0xD7, 0x9C, 0xD6,
- 0xBC, 0x41, 0x44, 0xD7, 0x9E, 0xD6, 0xBC, 0x41,
- 0x44, 0xD7, 0xA0, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
- 0xA1, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA3, 0xD6,
- 0xBC, 0x41, 0x44, 0xD7, 0xA4, 0xD6, 0xBC, 0x41,
- 0x44, 0xD7, 0xA4, 0xD6, 0xBF, 0x49, 0x44, 0xD7,
- 0xA6, 0xD6, 0xBC, 0x41, 0x44, 0xD7, 0xA7, 0xD6,
- 0xBC, 0x41, 0x44, 0xD7, 0xA8, 0xD6, 0xBC, 0x41,
- // Bytes 4480 - 44bf
- 0x44, 0xD7, 0xA9, 0xD6, 0xBC, 0x41, 0x44, 0xD7,
- 0xA9, 0xD7, 0x81, 0x4D, 0x44, 0xD7, 0xA9, 0xD7,
- 0x82, 0x51, 0x44, 0xD7, 0xAA, 0xD6, 0xBC, 0x41,
- 0x44, 0xD7, 0xB2, 0xD6, 0xB7, 0x31, 0x44, 0xD8,
- 0xA7, 0xD9, 0x8B, 0x59, 0x44, 0xD8, 0xA7, 0xD9,
- 0x93, 0xC9, 0x44, 0xD8, 0xA7, 0xD9, 0x94, 0xC9,
- 0x44, 0xD8, 0xA7, 0xD9, 0x95, 0xB5, 0x44, 0xD8,
- 0xB0, 0xD9, 0xB0, 0x79, 0x44, 0xD8, 0xB1, 0xD9,
- // Bytes 44c0 - 44ff
- 0xB0, 0x79, 0x44, 0xD9, 0x80, 0xD9, 0x8B, 0x59,
- 0x44, 0xD9, 0x80, 0xD9, 0x8E, 0x65, 0x44, 0xD9,
- 0x80, 0xD9, 0x8F, 0x69, 0x44, 0xD9, 0x80, 0xD9,
- 0x90, 0x6D, 0x44, 0xD9, 0x80, 0xD9, 0x91, 0x71,
- 0x44, 0xD9, 0x80, 0xD9, 0x92, 0x75, 0x44, 0xD9,
- 0x87, 0xD9, 0xB0, 0x79, 0x44, 0xD9, 0x88, 0xD9,
- 0x94, 0xC9, 0x44, 0xD9, 0x89, 0xD9, 0xB0, 0x79,
- 0x44, 0xD9, 0x8A, 0xD9, 0x94, 0xC9, 0x44, 0xDB,
- // Bytes 4500 - 453f
- 0x92, 0xD9, 0x94, 0xC9, 0x44, 0xDB, 0x95, 0xD9,
- 0x94, 0xC9, 0x45, 0x20, 0xCC, 0x88, 0xCC, 0x80,
- 0xCA, 0x45, 0x20, 0xCC, 0x88, 0xCC, 0x81, 0xCA,
- 0x45, 0x20, 0xCC, 0x88, 0xCD, 0x82, 0xCA, 0x45,
- 0x20, 0xCC, 0x93, 0xCC, 0x80, 0xCA, 0x45, 0x20,
- 0xCC, 0x93, 0xCC, 0x81, 0xCA, 0x45, 0x20, 0xCC,
- 0x93, 0xCD, 0x82, 0xCA, 0x45, 0x20, 0xCC, 0x94,
- 0xCC, 0x80, 0xCA, 0x45, 0x20, 0xCC, 0x94, 0xCC,
- // Bytes 4540 - 457f
- 0x81, 0xCA, 0x45, 0x20, 0xCC, 0x94, 0xCD, 0x82,
- 0xCA, 0x45, 0x20, 0xD9, 0x8C, 0xD9, 0x91, 0x72,
- 0x45, 0x20, 0xD9, 0x8D, 0xD9, 0x91, 0x72, 0x45,
- 0x20, 0xD9, 0x8E, 0xD9, 0x91, 0x72, 0x45, 0x20,
- 0xD9, 0x8F, 0xD9, 0x91, 0x72, 0x45, 0x20, 0xD9,
- 0x90, 0xD9, 0x91, 0x72, 0x45, 0x20, 0xD9, 0x91,
- 0xD9, 0xB0, 0x7A, 0x45, 0xE2, 0xAB, 0x9D, 0xCC,
- 0xB8, 0x05, 0x46, 0xCE, 0xB9, 0xCC, 0x88, 0xCC,
- // Bytes 4580 - 45bf
- 0x81, 0xCA, 0x46, 0xCF, 0x85, 0xCC, 0x88, 0xCC,
- 0x81, 0xCA, 0x46, 0xD7, 0xA9, 0xD6, 0xBC, 0xD7,
- 0x81, 0x4E, 0x46, 0xD7, 0xA9, 0xD6, 0xBC, 0xD7,
- 0x82, 0x52, 0x46, 0xD9, 0x80, 0xD9, 0x8E, 0xD9,
- 0x91, 0x72, 0x46, 0xD9, 0x80, 0xD9, 0x8F, 0xD9,
- 0x91, 0x72, 0x46, 0xD9, 0x80, 0xD9, 0x90, 0xD9,
- 0x91, 0x72, 0x46, 0xE0, 0xA4, 0x95, 0xE0, 0xA4,
- 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x96, 0xE0, 0xA4,
- // Bytes 45c0 - 45ff
- 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x97, 0xE0, 0xA4,
- 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0x9C, 0xE0, 0xA4,
- 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xA1, 0xE0, 0xA4,
- 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xA2, 0xE0, 0xA4,
- 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xAB, 0xE0, 0xA4,
- 0xBC, 0x09, 0x46, 0xE0, 0xA4, 0xAF, 0xE0, 0xA4,
- 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xA1, 0xE0, 0xA6,
- 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xA2, 0xE0, 0xA6,
- // Bytes 4600 - 463f
- 0xBC, 0x09, 0x46, 0xE0, 0xA6, 0xAF, 0xE0, 0xA6,
- 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x96, 0xE0, 0xA8,
- 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x97, 0xE0, 0xA8,
- 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0x9C, 0xE0, 0xA8,
- 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xAB, 0xE0, 0xA8,
- 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xB2, 0xE0, 0xA8,
- 0xBC, 0x09, 0x46, 0xE0, 0xA8, 0xB8, 0xE0, 0xA8,
- 0xBC, 0x09, 0x46, 0xE0, 0xAC, 0xA1, 0xE0, 0xAC,
- // Bytes 4640 - 467f
- 0xBC, 0x09, 0x46, 0xE0, 0xAC, 0xA2, 0xE0, 0xAC,
- 0xBC, 0x09, 0x46, 0xE0, 0xBE, 0xB2, 0xE0, 0xBE,
- 0x80, 0x9D, 0x46, 0xE0, 0xBE, 0xB3, 0xE0, 0xBE,
- 0x80, 0x9D, 0x46, 0xE3, 0x83, 0x86, 0xE3, 0x82,
- 0x99, 0x0D, 0x48, 0xF0, 0x9D, 0x85, 0x97, 0xF0,
- 0x9D, 0x85, 0xA5, 0xAD, 0x48, 0xF0, 0x9D, 0x85,
- 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xAD, 0x48, 0xF0,
- 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xAD,
- // Bytes 4680 - 46bf
- 0x48, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85,
- 0xA5, 0xAD, 0x49, 0xE0, 0xBE, 0xB2, 0xE0, 0xBD,
- 0xB1, 0xE0, 0xBE, 0x80, 0x9E, 0x49, 0xE0, 0xBE,
- 0xB3, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x9E,
- 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85,
- 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xAE, 0x4C, 0xF0,
- 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0,
- 0x9D, 0x85, 0xAF, 0xAE, 0x4C, 0xF0, 0x9D, 0x85,
- // Bytes 46c0 - 46ff
- 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85,
- 0xB0, 0xAE, 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0,
- 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB1, 0xAE,
- 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85,
- 0xA5, 0xF0, 0x9D, 0x85, 0xB2, 0xAE, 0x4C, 0xF0,
- 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0,
- 0x9D, 0x85, 0xAE, 0xAE, 0x4C, 0xF0, 0x9D, 0x86,
- 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85,
- // Bytes 4700 - 473f
- 0xAF, 0xAE, 0x4C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0,
- 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xAE,
- 0x4C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85,
- 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0xAE, 0x83, 0x41,
- 0xCC, 0x82, 0xC9, 0x83, 0x41, 0xCC, 0x86, 0xC9,
- 0x83, 0x41, 0xCC, 0x87, 0xC9, 0x83, 0x41, 0xCC,
- 0x88, 0xC9, 0x83, 0x41, 0xCC, 0x8A, 0xC9, 0x83,
- 0x41, 0xCC, 0xA3, 0xB5, 0x83, 0x43, 0xCC, 0xA7,
- // Bytes 4740 - 477f
- 0xA5, 0x83, 0x45, 0xCC, 0x82, 0xC9, 0x83, 0x45,
- 0xCC, 0x84, 0xC9, 0x83, 0x45, 0xCC, 0xA3, 0xB5,
- 0x83, 0x45, 0xCC, 0xA7, 0xA5, 0x83, 0x49, 0xCC,
- 0x88, 0xC9, 0x83, 0x4C, 0xCC, 0xA3, 0xB5, 0x83,
- 0x4F, 0xCC, 0x82, 0xC9, 0x83, 0x4F, 0xCC, 0x83,
- 0xC9, 0x83, 0x4F, 0xCC, 0x84, 0xC9, 0x83, 0x4F,
- 0xCC, 0x87, 0xC9, 0x83, 0x4F, 0xCC, 0x88, 0xC9,
- 0x83, 0x4F, 0xCC, 0x9B, 0xAD, 0x83, 0x4F, 0xCC,
- // Bytes 4780 - 47bf
- 0xA3, 0xB5, 0x83, 0x4F, 0xCC, 0xA8, 0xA5, 0x83,
- 0x52, 0xCC, 0xA3, 0xB5, 0x83, 0x53, 0xCC, 0x81,
- 0xC9, 0x83, 0x53, 0xCC, 0x8C, 0xC9, 0x83, 0x53,
- 0xCC, 0xA3, 0xB5, 0x83, 0x55, 0xCC, 0x83, 0xC9,
- 0x83, 0x55, 0xCC, 0x84, 0xC9, 0x83, 0x55, 0xCC,
- 0x88, 0xC9, 0x83, 0x55, 0xCC, 0x9B, 0xAD, 0x83,
- 0x61, 0xCC, 0x82, 0xC9, 0x83, 0x61, 0xCC, 0x86,
- 0xC9, 0x83, 0x61, 0xCC, 0x87, 0xC9, 0x83, 0x61,
- // Bytes 47c0 - 47ff
- 0xCC, 0x88, 0xC9, 0x83, 0x61, 0xCC, 0x8A, 0xC9,
- 0x83, 0x61, 0xCC, 0xA3, 0xB5, 0x83, 0x63, 0xCC,
- 0xA7, 0xA5, 0x83, 0x65, 0xCC, 0x82, 0xC9, 0x83,
- 0x65, 0xCC, 0x84, 0xC9, 0x83, 0x65, 0xCC, 0xA3,
- 0xB5, 0x83, 0x65, 0xCC, 0xA7, 0xA5, 0x83, 0x69,
- 0xCC, 0x88, 0xC9, 0x83, 0x6C, 0xCC, 0xA3, 0xB5,
- 0x83, 0x6F, 0xCC, 0x82, 0xC9, 0x83, 0x6F, 0xCC,
- 0x83, 0xC9, 0x83, 0x6F, 0xCC, 0x84, 0xC9, 0x83,
- // Bytes 4800 - 483f
- 0x6F, 0xCC, 0x87, 0xC9, 0x83, 0x6F, 0xCC, 0x88,
- 0xC9, 0x83, 0x6F, 0xCC, 0x9B, 0xAD, 0x83, 0x6F,
- 0xCC, 0xA3, 0xB5, 0x83, 0x6F, 0xCC, 0xA8, 0xA5,
- 0x83, 0x72, 0xCC, 0xA3, 0xB5, 0x83, 0x73, 0xCC,
- 0x81, 0xC9, 0x83, 0x73, 0xCC, 0x8C, 0xC9, 0x83,
- 0x73, 0xCC, 0xA3, 0xB5, 0x83, 0x75, 0xCC, 0x83,
- 0xC9, 0x83, 0x75, 0xCC, 0x84, 0xC9, 0x83, 0x75,
- 0xCC, 0x88, 0xC9, 0x83, 0x75, 0xCC, 0x9B, 0xAD,
- // Bytes 4840 - 487f
- 0x84, 0xCE, 0x91, 0xCC, 0x93, 0xC9, 0x84, 0xCE,
- 0x91, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0x95, 0xCC,
- 0x93, 0xC9, 0x84, 0xCE, 0x95, 0xCC, 0x94, 0xC9,
- 0x84, 0xCE, 0x97, 0xCC, 0x93, 0xC9, 0x84, 0xCE,
- 0x97, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0x99, 0xCC,
- 0x93, 0xC9, 0x84, 0xCE, 0x99, 0xCC, 0x94, 0xC9,
- 0x84, 0xCE, 0x9F, 0xCC, 0x93, 0xC9, 0x84, 0xCE,
- 0x9F, 0xCC, 0x94, 0xC9, 0x84, 0xCE, 0xA5, 0xCC,
- // Bytes 4880 - 48bf
- 0x94, 0xC9, 0x84, 0xCE, 0xA9, 0xCC, 0x93, 0xC9,
- 0x84, 0xCE, 0xA9, 0xCC, 0x94, 0xC9, 0x84, 0xCE,
- 0xB1, 0xCC, 0x80, 0xC9, 0x84, 0xCE, 0xB1, 0xCC,
- 0x81, 0xC9, 0x84, 0xCE, 0xB1, 0xCC, 0x93, 0xC9,
- 0x84, 0xCE, 0xB1, 0xCC, 0x94, 0xC9, 0x84, 0xCE,
- 0xB1, 0xCD, 0x82, 0xC9, 0x84, 0xCE, 0xB5, 0xCC,
- 0x93, 0xC9, 0x84, 0xCE, 0xB5, 0xCC, 0x94, 0xC9,
- 0x84, 0xCE, 0xB7, 0xCC, 0x80, 0xC9, 0x84, 0xCE,
- // Bytes 48c0 - 48ff
- 0xB7, 0xCC, 0x81, 0xC9, 0x84, 0xCE, 0xB7, 0xCC,
- 0x93, 0xC9, 0x84, 0xCE, 0xB7, 0xCC, 0x94, 0xC9,
- 0x84, 0xCE, 0xB7, 0xCD, 0x82, 0xC9, 0x84, 0xCE,
- 0xB9, 0xCC, 0x88, 0xC9, 0x84, 0xCE, 0xB9, 0xCC,
- 0x93, 0xC9, 0x84, 0xCE, 0xB9, 0xCC, 0x94, 0xC9,
- 0x84, 0xCE, 0xBF, 0xCC, 0x93, 0xC9, 0x84, 0xCE,
- 0xBF, 0xCC, 0x94, 0xC9, 0x84, 0xCF, 0x85, 0xCC,
- 0x88, 0xC9, 0x84, 0xCF, 0x85, 0xCC, 0x93, 0xC9,
- // Bytes 4900 - 493f
- 0x84, 0xCF, 0x85, 0xCC, 0x94, 0xC9, 0x84, 0xCF,
- 0x89, 0xCC, 0x80, 0xC9, 0x84, 0xCF, 0x89, 0xCC,
- 0x81, 0xC9, 0x84, 0xCF, 0x89, 0xCC, 0x93, 0xC9,
- 0x84, 0xCF, 0x89, 0xCC, 0x94, 0xC9, 0x84, 0xCF,
- 0x89, 0xCD, 0x82, 0xC9, 0x86, 0xCE, 0x91, 0xCC,
- 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x91, 0xCC,
- 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x91, 0xCC,
- 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0x91, 0xCC,
- // Bytes 4940 - 497f
- 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x91, 0xCC,
- 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x91, 0xCC,
- 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
- 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
- 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
- 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
- 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
- 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0x97, 0xCC,
- // Bytes 4980 - 49bf
- 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
- 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
- 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
- 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
- 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
- 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xA9, 0xCC,
- 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
- 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
- // Bytes 49c0 - 49ff
- 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
- 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
- 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
- 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB1, 0xCC,
- 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
- 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
- 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
- 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
- // Bytes 4a00 - 4a3f
- 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
- 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCE, 0xB7, 0xCC,
- 0x94, 0xCD, 0x82, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
- 0x93, 0xCC, 0x80, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
- 0x93, 0xCC, 0x81, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
- 0x93, 0xCD, 0x82, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
- 0x94, 0xCC, 0x80, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
- 0x94, 0xCC, 0x81, 0xCA, 0x86, 0xCF, 0x89, 0xCC,
- // Bytes 4a40 - 4a7f
- 0x94, 0xCD, 0x82, 0xCA, 0x42, 0xCC, 0x80, 0xC9,
- 0x32, 0x42, 0xCC, 0x81, 0xC9, 0x32, 0x42, 0xCC,
- 0x93, 0xC9, 0x32, 0x44, 0xCC, 0x88, 0xCC, 0x81,
- 0xCA, 0x32, 0x43, 0xE3, 0x82, 0x99, 0x0D, 0x03,
- 0x43, 0xE3, 0x82, 0x9A, 0x0D, 0x03, 0x46, 0xE0,
- 0xBD, 0xB1, 0xE0, 0xBD, 0xB2, 0x9E, 0x26, 0x46,
- 0xE0, 0xBD, 0xB1, 0xE0, 0xBD, 0xB4, 0xA2, 0x26,
- 0x46, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x9E,
- // Bytes 4a80 - 4abf
- 0x26, 0x00, 0x01,
-}
-
-// 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 *nfcTrie) lookup(s []byte) (v uint16, sz int) {
- c0 := s[0]
- switch {
- case c0 < 0x80: // is ASCII
- return nfcValues[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 := nfcIndex[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 := nfcIndex[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 = nfcIndex[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 := nfcIndex[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 = nfcIndex[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 = nfcIndex[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 *nfcTrie) lookupUnsafe(s []byte) uint16 {
- c0 := s[0]
- if c0 < 0x80 { // is ASCII
- return nfcValues[c0]
- }
- i := nfcIndex[c0]
- if c0 < 0xE0 { // 2-byte UTF-8
- return t.lookupValue(uint32(i), s[1])
- }
- i = nfcIndex[uint32(i)<<6+uint32(s[1])]
- if c0 < 0xF0 { // 3-byte UTF-8
- return t.lookupValue(uint32(i), s[2])
- }
- i = nfcIndex[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 *nfcTrie) lookupString(s string) (v uint16, sz int) {
- c0 := s[0]
- switch {
- case c0 < 0x80: // is ASCII
- return nfcValues[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 := nfcIndex[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 := nfcIndex[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 = nfcIndex[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 := nfcIndex[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 = nfcIndex[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 = nfcIndex[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 *nfcTrie) lookupStringUnsafe(s string) uint16 {
- c0 := s[0]
- if c0 < 0x80 { // is ASCII
- return nfcValues[c0]
- }
- i := nfcIndex[c0]
- if c0 < 0xE0 { // 2-byte UTF-8
- return t.lookupValue(uint32(i), s[1])
- }
- i = nfcIndex[uint32(i)<<6+uint32(s[1])]
- if c0 < 0xF0 { // 3-byte UTF-8
- return t.lookupValue(uint32(i), s[2])
- }
- i = nfcIndex[uint32(i)<<6+uint32(s[2])]
- if c0 < 0xF8 { // 4-byte UTF-8
- return t.lookupValue(uint32(i), s[3])
- }
- return 0
-}
-
-// nfcTrie. Total size: 10332 bytes (10.09 KiB). Checksum: ad355b768fddb1b6.
-type nfcTrie struct{}
-
-func newNfcTrie(i int) *nfcTrie {
- return &nfcTrie{}
-}
-
-// lookupValue determines the type of block n and looks up the value for b.
-func (t *nfcTrie) lookupValue(n uint32, b byte) uint16 {
- switch {
- case n < 44:
- return uint16(nfcValues[n<<6+uint32(b)])
- default:
- n -= 44
- return uint16(nfcSparse.lookup(n, b))
- }
-}
-
-// nfcValues: 46 blocks, 2944 entries, 5888 bytes
-// The third block is the zero block.
-var nfcValues = [2944]uint16{
- // Block 0x0, offset 0x0
- 0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000,
- // Block 0x1, offset 0x40
- 0x41: 0xa000, 0x42: 0xa000, 0x43: 0xa000, 0x44: 0xa000, 0x45: 0xa000,
- 0x46: 0xa000, 0x47: 0xa000, 0x48: 0xa000, 0x49: 0xa000, 0x4a: 0xa000, 0x4b: 0xa000,
- 0x4c: 0xa000, 0x4d: 0xa000, 0x4e: 0xa000, 0x4f: 0xa000, 0x50: 0xa000,
- 0x52: 0xa000, 0x53: 0xa000, 0x54: 0xa000, 0x55: 0xa000, 0x56: 0xa000, 0x57: 0xa000,
- 0x58: 0xa000, 0x59: 0xa000, 0x5a: 0xa000,
- 0x61: 0xa000, 0x62: 0xa000, 0x63: 0xa000,
- 0x64: 0xa000, 0x65: 0xa000, 0x66: 0xa000, 0x67: 0xa000, 0x68: 0xa000, 0x69: 0xa000,
- 0x6a: 0xa000, 0x6b: 0xa000, 0x6c: 0xa000, 0x6d: 0xa000, 0x6e: 0xa000, 0x6f: 0xa000,
- 0x70: 0xa000, 0x72: 0xa000, 0x73: 0xa000, 0x74: 0xa000, 0x75: 0xa000,
- 0x76: 0xa000, 0x77: 0xa000, 0x78: 0xa000, 0x79: 0xa000, 0x7a: 0xa000,
- // Block 0x2, offset 0x80
- // Block 0x3, offset 0xc0
- 0xc0: 0x2f6f, 0xc1: 0x2f74, 0xc2: 0x471e, 0xc3: 0x2f79, 0xc4: 0x472d, 0xc5: 0x4732,
- 0xc6: 0xa000, 0xc7: 0x473c, 0xc8: 0x2fe2, 0xc9: 0x2fe7, 0xca: 0x4741, 0xcb: 0x2ffb,
- 0xcc: 0x306e, 0xcd: 0x3073, 0xce: 0x3078, 0xcf: 0x4755, 0xd1: 0x3104,
- 0xd2: 0x3127, 0xd3: 0x312c, 0xd4: 0x475f, 0xd5: 0x4764, 0xd6: 0x4773,
- 0xd8: 0xa000, 0xd9: 0x31b3, 0xda: 0x31b8, 0xdb: 0x31bd, 0xdc: 0x47a5, 0xdd: 0x3235,
- 0xe0: 0x327b, 0xe1: 0x3280, 0xe2: 0x47af, 0xe3: 0x3285,
- 0xe4: 0x47be, 0xe5: 0x47c3, 0xe6: 0xa000, 0xe7: 0x47cd, 0xe8: 0x32ee, 0xe9: 0x32f3,
- 0xea: 0x47d2, 0xeb: 0x3307, 0xec: 0x337f, 0xed: 0x3384, 0xee: 0x3389, 0xef: 0x47e6,
- 0xf1: 0x3415, 0xf2: 0x3438, 0xf3: 0x343d, 0xf4: 0x47f0, 0xf5: 0x47f5,
- 0xf6: 0x4804, 0xf8: 0xa000, 0xf9: 0x34c9, 0xfa: 0x34ce, 0xfb: 0x34d3,
- 0xfc: 0x4836, 0xfd: 0x3550, 0xff: 0x3569,
- // Block 0x4, offset 0x100
- 0x100: 0x2f7e, 0x101: 0x328a, 0x102: 0x4723, 0x103: 0x47b4, 0x104: 0x2f9c, 0x105: 0x32a8,
- 0x106: 0x2fb0, 0x107: 0x32bc, 0x108: 0x2fb5, 0x109: 0x32c1, 0x10a: 0x2fba, 0x10b: 0x32c6,
- 0x10c: 0x2fbf, 0x10d: 0x32cb, 0x10e: 0x2fc9, 0x10f: 0x32d5,
- 0x112: 0x4746, 0x113: 0x47d7, 0x114: 0x2ff1, 0x115: 0x32fd, 0x116: 0x2ff6, 0x117: 0x3302,
- 0x118: 0x3014, 0x119: 0x3320, 0x11a: 0x3005, 0x11b: 0x3311, 0x11c: 0x302d, 0x11d: 0x3339,
- 0x11e: 0x3037, 0x11f: 0x3343, 0x120: 0x303c, 0x121: 0x3348, 0x122: 0x3046, 0x123: 0x3352,
- 0x124: 0x304b, 0x125: 0x3357, 0x128: 0x307d, 0x129: 0x338e,
- 0x12a: 0x3082, 0x12b: 0x3393, 0x12c: 0x3087, 0x12d: 0x3398, 0x12e: 0x30aa, 0x12f: 0x33b6,
- 0x130: 0x308c, 0x134: 0x30b4, 0x135: 0x33c0,
- 0x136: 0x30c8, 0x137: 0x33d9, 0x139: 0x30d2, 0x13a: 0x33e3, 0x13b: 0x30dc,
- 0x13c: 0x33ed, 0x13d: 0x30d7, 0x13e: 0x33e8,
- // Block 0x5, offset 0x140
- 0x143: 0x30ff, 0x144: 0x3410, 0x145: 0x3118,
- 0x146: 0x3429, 0x147: 0x310e, 0x148: 0x341f,
- 0x14c: 0x4769, 0x14d: 0x47fa, 0x14e: 0x3131, 0x14f: 0x3442, 0x150: 0x313b, 0x151: 0x344c,
- 0x154: 0x3159, 0x155: 0x346a, 0x156: 0x3172, 0x157: 0x3483,
- 0x158: 0x3163, 0x159: 0x3474, 0x15a: 0x478c, 0x15b: 0x481d, 0x15c: 0x317c, 0x15d: 0x348d,
- 0x15e: 0x318b, 0x15f: 0x349c, 0x160: 0x4791, 0x161: 0x4822, 0x162: 0x31a4, 0x163: 0x34ba,
- 0x164: 0x3195, 0x165: 0x34ab, 0x168: 0x479b, 0x169: 0x482c,
- 0x16a: 0x47a0, 0x16b: 0x4831, 0x16c: 0x31c2, 0x16d: 0x34d8, 0x16e: 0x31cc, 0x16f: 0x34e2,
- 0x170: 0x31d1, 0x171: 0x34e7, 0x172: 0x31ef, 0x173: 0x3505, 0x174: 0x3212, 0x175: 0x3528,
- 0x176: 0x323a, 0x177: 0x3555, 0x178: 0x324e, 0x179: 0x325d, 0x17a: 0x357d, 0x17b: 0x3267,
- 0x17c: 0x3587, 0x17d: 0x326c, 0x17e: 0x358c, 0x17f: 0xa000,
- // Block 0x6, offset 0x180
- 0x184: 0x8100, 0x185: 0x8100,
- 0x186: 0x8100,
- 0x18d: 0x2f88, 0x18e: 0x3294, 0x18f: 0x3096, 0x190: 0x33a2, 0x191: 0x3140,
- 0x192: 0x3451, 0x193: 0x31d6, 0x194: 0x34ec, 0x195: 0x39cf, 0x196: 0x3b5e, 0x197: 0x39c8,
- 0x198: 0x3b57, 0x199: 0x39d6, 0x19a: 0x3b65, 0x19b: 0x39c1, 0x19c: 0x3b50,
- 0x19e: 0x38b0, 0x19f: 0x3a3f, 0x1a0: 0x38a9, 0x1a1: 0x3a38, 0x1a2: 0x35b3, 0x1a3: 0x35c5,
- 0x1a6: 0x3041, 0x1a7: 0x334d, 0x1a8: 0x30be, 0x1a9: 0x33cf,
- 0x1aa: 0x4782, 0x1ab: 0x4813, 0x1ac: 0x3990, 0x1ad: 0x3b1f, 0x1ae: 0x35d7, 0x1af: 0x35dd,
- 0x1b0: 0x33c5, 0x1b4: 0x3028, 0x1b5: 0x3334,
- 0x1b8: 0x30fa, 0x1b9: 0x340b, 0x1ba: 0x38b7, 0x1bb: 0x3a46,
- 0x1bc: 0x35ad, 0x1bd: 0x35bf, 0x1be: 0x35b9, 0x1bf: 0x35cb,
- // Block 0x7, offset 0x1c0
- 0x1c0: 0x2f8d, 0x1c1: 0x3299, 0x1c2: 0x2f92, 0x1c3: 0x329e, 0x1c4: 0x300a, 0x1c5: 0x3316,
- 0x1c6: 0x300f, 0x1c7: 0x331b, 0x1c8: 0x309b, 0x1c9: 0x33a7, 0x1ca: 0x30a0, 0x1cb: 0x33ac,
- 0x1cc: 0x3145, 0x1cd: 0x3456, 0x1ce: 0x314a, 0x1cf: 0x345b, 0x1d0: 0x3168, 0x1d1: 0x3479,
- 0x1d2: 0x316d, 0x1d3: 0x347e, 0x1d4: 0x31db, 0x1d5: 0x34f1, 0x1d6: 0x31e0, 0x1d7: 0x34f6,
- 0x1d8: 0x3186, 0x1d9: 0x3497, 0x1da: 0x319f, 0x1db: 0x34b5,
- 0x1de: 0x305a, 0x1df: 0x3366,
- 0x1e6: 0x4728, 0x1e7: 0x47b9, 0x1e8: 0x4750, 0x1e9: 0x47e1,
- 0x1ea: 0x395f, 0x1eb: 0x3aee, 0x1ec: 0x393c, 0x1ed: 0x3acb, 0x1ee: 0x476e, 0x1ef: 0x47ff,
- 0x1f0: 0x3958, 0x1f1: 0x3ae7, 0x1f2: 0x3244, 0x1f3: 0x355f,
- // Block 0x8, offset 0x200
- 0x200: 0x9932, 0x201: 0x9932, 0x202: 0x9932, 0x203: 0x9932, 0x204: 0x9932, 0x205: 0x8132,
- 0x206: 0x9932, 0x207: 0x9932, 0x208: 0x9932, 0x209: 0x9932, 0x20a: 0x9932, 0x20b: 0x9932,
- 0x20c: 0x9932, 0x20d: 0x8132, 0x20e: 0x8132, 0x20f: 0x9932, 0x210: 0x8132, 0x211: 0x9932,
- 0x212: 0x8132, 0x213: 0x9932, 0x214: 0x9932, 0x215: 0x8133, 0x216: 0x812d, 0x217: 0x812d,
- 0x218: 0x812d, 0x219: 0x812d, 0x21a: 0x8133, 0x21b: 0x992b, 0x21c: 0x812d, 0x21d: 0x812d,
- 0x21e: 0x812d, 0x21f: 0x812d, 0x220: 0x812d, 0x221: 0x8129, 0x222: 0x8129, 0x223: 0x992d,
- 0x224: 0x992d, 0x225: 0x992d, 0x226: 0x992d, 0x227: 0x9929, 0x228: 0x9929, 0x229: 0x812d,
- 0x22a: 0x812d, 0x22b: 0x812d, 0x22c: 0x812d, 0x22d: 0x992d, 0x22e: 0x992d, 0x22f: 0x812d,
- 0x230: 0x992d, 0x231: 0x992d, 0x232: 0x812d, 0x233: 0x812d, 0x234: 0x8101, 0x235: 0x8101,
- 0x236: 0x8101, 0x237: 0x8101, 0x238: 0x9901, 0x239: 0x812d, 0x23a: 0x812d, 0x23b: 0x812d,
- 0x23c: 0x812d, 0x23d: 0x8132, 0x23e: 0x8132, 0x23f: 0x8132,
- // Block 0x9, offset 0x240
- 0x240: 0x4a44, 0x241: 0x4a49, 0x242: 0x9932, 0x243: 0x4a4e, 0x244: 0x4a53, 0x245: 0x9936,
- 0x246: 0x8132, 0x247: 0x812d, 0x248: 0x812d, 0x249: 0x812d, 0x24a: 0x8132, 0x24b: 0x8132,
- 0x24c: 0x8132, 0x24d: 0x812d, 0x24e: 0x812d, 0x250: 0x8132, 0x251: 0x8132,
- 0x252: 0x8132, 0x253: 0x812d, 0x254: 0x812d, 0x255: 0x812d, 0x256: 0x812d, 0x257: 0x8132,
- 0x258: 0x8133, 0x259: 0x812d, 0x25a: 0x812d, 0x25b: 0x8132, 0x25c: 0x8134, 0x25d: 0x8135,
- 0x25e: 0x8135, 0x25f: 0x8134, 0x260: 0x8135, 0x261: 0x8135, 0x262: 0x8134, 0x263: 0x8132,
- 0x264: 0x8132, 0x265: 0x8132, 0x266: 0x8132, 0x267: 0x8132, 0x268: 0x8132, 0x269: 0x8132,
- 0x26a: 0x8132, 0x26b: 0x8132, 0x26c: 0x8132, 0x26d: 0x8132, 0x26e: 0x8132, 0x26f: 0x8132,
- 0x274: 0x0170,
- 0x27a: 0x8100,
- 0x27e: 0x0037,
- // Block 0xa, offset 0x280
- 0x284: 0x8100, 0x285: 0x35a1,
- 0x286: 0x35e9, 0x287: 0x00ce, 0x288: 0x3607, 0x289: 0x3613, 0x28a: 0x3625,
- 0x28c: 0x3643, 0x28e: 0x3655, 0x28f: 0x3673, 0x290: 0x3e08, 0x291: 0xa000,
- 0x295: 0xa000, 0x297: 0xa000,
- 0x299: 0xa000,
- 0x29f: 0xa000, 0x2a1: 0xa000,
- 0x2a5: 0xa000, 0x2a9: 0xa000,
- 0x2aa: 0x3637, 0x2ab: 0x3667, 0x2ac: 0x4894, 0x2ad: 0x3697, 0x2ae: 0x48be, 0x2af: 0x36a9,
- 0x2b0: 0x3e70, 0x2b1: 0xa000, 0x2b5: 0xa000,
- 0x2b7: 0xa000, 0x2b9: 0xa000,
- 0x2bf: 0xa000,
- // Block 0xb, offset 0x2c0
- 0x2c0: 0x3721, 0x2c1: 0x372d, 0x2c3: 0x371b,
- 0x2c6: 0xa000, 0x2c7: 0x3709,
- 0x2cc: 0x375d, 0x2cd: 0x3745, 0x2ce: 0x376f, 0x2d0: 0xa000,
- 0x2d3: 0xa000, 0x2d5: 0xa000, 0x2d6: 0xa000, 0x2d7: 0xa000,
- 0x2d8: 0xa000, 0x2d9: 0x3751, 0x2da: 0xa000,
- 0x2de: 0xa000, 0x2e3: 0xa000,
- 0x2e7: 0xa000,
- 0x2eb: 0xa000, 0x2ed: 0xa000,
- 0x2f0: 0xa000, 0x2f3: 0xa000, 0x2f5: 0xa000,
- 0x2f6: 0xa000, 0x2f7: 0xa000, 0x2f8: 0xa000, 0x2f9: 0x37d5, 0x2fa: 0xa000,
- 0x2fe: 0xa000,
- // Block 0xc, offset 0x300
- 0x301: 0x3733, 0x302: 0x37b7,
- 0x310: 0x370f, 0x311: 0x3793,
- 0x312: 0x3715, 0x313: 0x3799, 0x316: 0x3727, 0x317: 0x37ab,
- 0x318: 0xa000, 0x319: 0xa000, 0x31a: 0x3829, 0x31b: 0x382f, 0x31c: 0x3739, 0x31d: 0x37bd,
- 0x31e: 0x373f, 0x31f: 0x37c3, 0x322: 0x374b, 0x323: 0x37cf,
- 0x324: 0x3757, 0x325: 0x37db, 0x326: 0x3763, 0x327: 0x37e7, 0x328: 0xa000, 0x329: 0xa000,
- 0x32a: 0x3835, 0x32b: 0x383b, 0x32c: 0x378d, 0x32d: 0x3811, 0x32e: 0x3769, 0x32f: 0x37ed,
- 0x330: 0x3775, 0x331: 0x37f9, 0x332: 0x377b, 0x333: 0x37ff, 0x334: 0x3781, 0x335: 0x3805,
- 0x338: 0x3787, 0x339: 0x380b,
- // Block 0xd, offset 0x340
- 0x351: 0x812d,
- 0x352: 0x8132, 0x353: 0x8132, 0x354: 0x8132, 0x355: 0x8132, 0x356: 0x812d, 0x357: 0x8132,
- 0x358: 0x8132, 0x359: 0x8132, 0x35a: 0x812e, 0x35b: 0x812d, 0x35c: 0x8132, 0x35d: 0x8132,
- 0x35e: 0x8132, 0x35f: 0x8132, 0x360: 0x8132, 0x361: 0x8132, 0x362: 0x812d, 0x363: 0x812d,
- 0x364: 0x812d, 0x365: 0x812d, 0x366: 0x812d, 0x367: 0x812d, 0x368: 0x8132, 0x369: 0x8132,
- 0x36a: 0x812d, 0x36b: 0x8132, 0x36c: 0x8132, 0x36d: 0x812e, 0x36e: 0x8131, 0x36f: 0x8132,
- 0x370: 0x8105, 0x371: 0x8106, 0x372: 0x8107, 0x373: 0x8108, 0x374: 0x8109, 0x375: 0x810a,
- 0x376: 0x810b, 0x377: 0x810c, 0x378: 0x810d, 0x379: 0x810e, 0x37a: 0x810e, 0x37b: 0x810f,
- 0x37c: 0x8110, 0x37d: 0x8111, 0x37f: 0x8112,
- // Block 0xe, offset 0x380
- 0x388: 0xa000, 0x38a: 0xa000, 0x38b: 0x8116,
- 0x38c: 0x8117, 0x38d: 0x8118, 0x38e: 0x8119, 0x38f: 0x811a, 0x390: 0x811b, 0x391: 0x811c,
- 0x392: 0x811d, 0x393: 0x9932, 0x394: 0x9932, 0x395: 0x992d, 0x396: 0x812d, 0x397: 0x8132,
- 0x398: 0x8132, 0x399: 0x8132, 0x39a: 0x8132, 0x39b: 0x8132, 0x39c: 0x812d, 0x39d: 0x8132,
- 0x39e: 0x8132, 0x39f: 0x812d,
- 0x3b0: 0x811e,
- // Block 0xf, offset 0x3c0
- 0x3c5: 0xa000,
- 0x3c6: 0x2d26, 0x3c7: 0xa000, 0x3c8: 0x2d2e, 0x3c9: 0xa000, 0x3ca: 0x2d36, 0x3cb: 0xa000,
- 0x3cc: 0x2d3e, 0x3cd: 0xa000, 0x3ce: 0x2d46, 0x3d1: 0xa000,
- 0x3d2: 0x2d4e,
- 0x3f4: 0x8102, 0x3f5: 0x9900,
- 0x3fa: 0xa000, 0x3fb: 0x2d56,
- 0x3fc: 0xa000, 0x3fd: 0x2d5e, 0x3fe: 0xa000, 0x3ff: 0xa000,
- // Block 0x10, offset 0x400
- 0x400: 0x2f97, 0x401: 0x32a3, 0x402: 0x2fa1, 0x403: 0x32ad, 0x404: 0x2fa6, 0x405: 0x32b2,
- 0x406: 0x2fab, 0x407: 0x32b7, 0x408: 0x38cc, 0x409: 0x3a5b, 0x40a: 0x2fc4, 0x40b: 0x32d0,
- 0x40c: 0x2fce, 0x40d: 0x32da, 0x40e: 0x2fdd, 0x40f: 0x32e9, 0x410: 0x2fd3, 0x411: 0x32df,
- 0x412: 0x2fd8, 0x413: 0x32e4, 0x414: 0x38ef, 0x415: 0x3a7e, 0x416: 0x38f6, 0x417: 0x3a85,
- 0x418: 0x3019, 0x419: 0x3325, 0x41a: 0x301e, 0x41b: 0x332a, 0x41c: 0x3904, 0x41d: 0x3a93,
- 0x41e: 0x3023, 0x41f: 0x332f, 0x420: 0x3032, 0x421: 0x333e, 0x422: 0x3050, 0x423: 0x335c,
- 0x424: 0x305f, 0x425: 0x336b, 0x426: 0x3055, 0x427: 0x3361, 0x428: 0x3064, 0x429: 0x3370,
- 0x42a: 0x3069, 0x42b: 0x3375, 0x42c: 0x30af, 0x42d: 0x33bb, 0x42e: 0x390b, 0x42f: 0x3a9a,
- 0x430: 0x30b9, 0x431: 0x33ca, 0x432: 0x30c3, 0x433: 0x33d4, 0x434: 0x30cd, 0x435: 0x33de,
- 0x436: 0x475a, 0x437: 0x47eb, 0x438: 0x3912, 0x439: 0x3aa1, 0x43a: 0x30e6, 0x43b: 0x33f7,
- 0x43c: 0x30e1, 0x43d: 0x33f2, 0x43e: 0x30eb, 0x43f: 0x33fc,
- // Block 0x11, offset 0x440
- 0x440: 0x30f0, 0x441: 0x3401, 0x442: 0x30f5, 0x443: 0x3406, 0x444: 0x3109, 0x445: 0x341a,
- 0x446: 0x3113, 0x447: 0x3424, 0x448: 0x3122, 0x449: 0x3433, 0x44a: 0x311d, 0x44b: 0x342e,
- 0x44c: 0x3935, 0x44d: 0x3ac4, 0x44e: 0x3943, 0x44f: 0x3ad2, 0x450: 0x394a, 0x451: 0x3ad9,
- 0x452: 0x3951, 0x453: 0x3ae0, 0x454: 0x314f, 0x455: 0x3460, 0x456: 0x3154, 0x457: 0x3465,
- 0x458: 0x315e, 0x459: 0x346f, 0x45a: 0x4787, 0x45b: 0x4818, 0x45c: 0x3997, 0x45d: 0x3b26,
- 0x45e: 0x3177, 0x45f: 0x3488, 0x460: 0x3181, 0x461: 0x3492, 0x462: 0x4796, 0x463: 0x4827,
- 0x464: 0x399e, 0x465: 0x3b2d, 0x466: 0x39a5, 0x467: 0x3b34, 0x468: 0x39ac, 0x469: 0x3b3b,
- 0x46a: 0x3190, 0x46b: 0x34a1, 0x46c: 0x319a, 0x46d: 0x34b0, 0x46e: 0x31ae, 0x46f: 0x34c4,
- 0x470: 0x31a9, 0x471: 0x34bf, 0x472: 0x31ea, 0x473: 0x3500, 0x474: 0x31f9, 0x475: 0x350f,
- 0x476: 0x31f4, 0x477: 0x350a, 0x478: 0x39b3, 0x479: 0x3b42, 0x47a: 0x39ba, 0x47b: 0x3b49,
- 0x47c: 0x31fe, 0x47d: 0x3514, 0x47e: 0x3203, 0x47f: 0x3519,
- // Block 0x12, offset 0x480
- 0x480: 0x3208, 0x481: 0x351e, 0x482: 0x320d, 0x483: 0x3523, 0x484: 0x321c, 0x485: 0x3532,
- 0x486: 0x3217, 0x487: 0x352d, 0x488: 0x3221, 0x489: 0x353c, 0x48a: 0x3226, 0x48b: 0x3541,
- 0x48c: 0x322b, 0x48d: 0x3546, 0x48e: 0x3249, 0x48f: 0x3564, 0x490: 0x3262, 0x491: 0x3582,
- 0x492: 0x3271, 0x493: 0x3591, 0x494: 0x3276, 0x495: 0x3596, 0x496: 0x337a, 0x497: 0x34a6,
- 0x498: 0x3537, 0x499: 0x3573, 0x49b: 0x35d1,
- 0x4a0: 0x4737, 0x4a1: 0x47c8, 0x4a2: 0x2f83, 0x4a3: 0x328f,
- 0x4a4: 0x3878, 0x4a5: 0x3a07, 0x4a6: 0x3871, 0x4a7: 0x3a00, 0x4a8: 0x3886, 0x4a9: 0x3a15,
- 0x4aa: 0x387f, 0x4ab: 0x3a0e, 0x4ac: 0x38be, 0x4ad: 0x3a4d, 0x4ae: 0x3894, 0x4af: 0x3a23,
- 0x4b0: 0x388d, 0x4b1: 0x3a1c, 0x4b2: 0x38a2, 0x4b3: 0x3a31, 0x4b4: 0x389b, 0x4b5: 0x3a2a,
- 0x4b6: 0x38c5, 0x4b7: 0x3a54, 0x4b8: 0x474b, 0x4b9: 0x47dc, 0x4ba: 0x3000, 0x4bb: 0x330c,
- 0x4bc: 0x2fec, 0x4bd: 0x32f8, 0x4be: 0x38da, 0x4bf: 0x3a69,
- // Block 0x13, offset 0x4c0
- 0x4c0: 0x38d3, 0x4c1: 0x3a62, 0x4c2: 0x38e8, 0x4c3: 0x3a77, 0x4c4: 0x38e1, 0x4c5: 0x3a70,
- 0x4c6: 0x38fd, 0x4c7: 0x3a8c, 0x4c8: 0x3091, 0x4c9: 0x339d, 0x4ca: 0x30a5, 0x4cb: 0x33b1,
- 0x4cc: 0x477d, 0x4cd: 0x480e, 0x4ce: 0x3136, 0x4cf: 0x3447, 0x4d0: 0x3920, 0x4d1: 0x3aaf,
- 0x4d2: 0x3919, 0x4d3: 0x3aa8, 0x4d4: 0x392e, 0x4d5: 0x3abd, 0x4d6: 0x3927, 0x4d7: 0x3ab6,
- 0x4d8: 0x3989, 0x4d9: 0x3b18, 0x4da: 0x396d, 0x4db: 0x3afc, 0x4dc: 0x3966, 0x4dd: 0x3af5,
- 0x4de: 0x397b, 0x4df: 0x3b0a, 0x4e0: 0x3974, 0x4e1: 0x3b03, 0x4e2: 0x3982, 0x4e3: 0x3b11,
- 0x4e4: 0x31e5, 0x4e5: 0x34fb, 0x4e6: 0x31c7, 0x4e7: 0x34dd, 0x4e8: 0x39e4, 0x4e9: 0x3b73,
- 0x4ea: 0x39dd, 0x4eb: 0x3b6c, 0x4ec: 0x39f2, 0x4ed: 0x3b81, 0x4ee: 0x39eb, 0x4ef: 0x3b7a,
- 0x4f0: 0x39f9, 0x4f1: 0x3b88, 0x4f2: 0x3230, 0x4f3: 0x354b, 0x4f4: 0x3258, 0x4f5: 0x3578,
- 0x4f6: 0x3253, 0x4f7: 0x356e, 0x4f8: 0x323f, 0x4f9: 0x355a,
- // Block 0x14, offset 0x500
- 0x500: 0x489a, 0x501: 0x48a0, 0x502: 0x49b4, 0x503: 0x49cc, 0x504: 0x49bc, 0x505: 0x49d4,
- 0x506: 0x49c4, 0x507: 0x49dc, 0x508: 0x4840, 0x509: 0x4846, 0x50a: 0x4924, 0x50b: 0x493c,
- 0x50c: 0x492c, 0x50d: 0x4944, 0x50e: 0x4934, 0x50f: 0x494c, 0x510: 0x48ac, 0x511: 0x48b2,
- 0x512: 0x3db8, 0x513: 0x3dc8, 0x514: 0x3dc0, 0x515: 0x3dd0,
- 0x518: 0x484c, 0x519: 0x4852, 0x51a: 0x3ce8, 0x51b: 0x3cf8, 0x51c: 0x3cf0, 0x51d: 0x3d00,
- 0x520: 0x48c4, 0x521: 0x48ca, 0x522: 0x49e4, 0x523: 0x49fc,
- 0x524: 0x49ec, 0x525: 0x4a04, 0x526: 0x49f4, 0x527: 0x4a0c, 0x528: 0x4858, 0x529: 0x485e,
- 0x52a: 0x4954, 0x52b: 0x496c, 0x52c: 0x495c, 0x52d: 0x4974, 0x52e: 0x4964, 0x52f: 0x497c,
- 0x530: 0x48dc, 0x531: 0x48e2, 0x532: 0x3e18, 0x533: 0x3e30, 0x534: 0x3e20, 0x535: 0x3e38,
- 0x536: 0x3e28, 0x537: 0x3e40, 0x538: 0x4864, 0x539: 0x486a, 0x53a: 0x3d18, 0x53b: 0x3d30,
- 0x53c: 0x3d20, 0x53d: 0x3d38, 0x53e: 0x3d28, 0x53f: 0x3d40,
- // Block 0x15, offset 0x540
- 0x540: 0x48e8, 0x541: 0x48ee, 0x542: 0x3e48, 0x543: 0x3e58, 0x544: 0x3e50, 0x545: 0x3e60,
- 0x548: 0x4870, 0x549: 0x4876, 0x54a: 0x3d48, 0x54b: 0x3d58,
- 0x54c: 0x3d50, 0x54d: 0x3d60, 0x550: 0x48fa, 0x551: 0x4900,
- 0x552: 0x3e80, 0x553: 0x3e98, 0x554: 0x3e88, 0x555: 0x3ea0, 0x556: 0x3e90, 0x557: 0x3ea8,
- 0x559: 0x487c, 0x55b: 0x3d68, 0x55d: 0x3d70,
- 0x55f: 0x3d78, 0x560: 0x4912, 0x561: 0x4918, 0x562: 0x4a14, 0x563: 0x4a2c,
- 0x564: 0x4a1c, 0x565: 0x4a34, 0x566: 0x4a24, 0x567: 0x4a3c, 0x568: 0x4882, 0x569: 0x4888,
- 0x56a: 0x4984, 0x56b: 0x499c, 0x56c: 0x498c, 0x56d: 0x49a4, 0x56e: 0x4994, 0x56f: 0x49ac,
- 0x570: 0x488e, 0x571: 0x43b4, 0x572: 0x3691, 0x573: 0x43ba, 0x574: 0x48b8, 0x575: 0x43c0,
- 0x576: 0x36a3, 0x577: 0x43c6, 0x578: 0x36c1, 0x579: 0x43cc, 0x57a: 0x36d9, 0x57b: 0x43d2,
- 0x57c: 0x4906, 0x57d: 0x43d8,
- // Block 0x16, offset 0x580
- 0x580: 0x3da0, 0x581: 0x3da8, 0x582: 0x4184, 0x583: 0x41a2, 0x584: 0x418e, 0x585: 0x41ac,
- 0x586: 0x4198, 0x587: 0x41b6, 0x588: 0x3cd8, 0x589: 0x3ce0, 0x58a: 0x40d0, 0x58b: 0x40ee,
- 0x58c: 0x40da, 0x58d: 0x40f8, 0x58e: 0x40e4, 0x58f: 0x4102, 0x590: 0x3de8, 0x591: 0x3df0,
- 0x592: 0x41c0, 0x593: 0x41de, 0x594: 0x41ca, 0x595: 0x41e8, 0x596: 0x41d4, 0x597: 0x41f2,
- 0x598: 0x3d08, 0x599: 0x3d10, 0x59a: 0x410c, 0x59b: 0x412a, 0x59c: 0x4116, 0x59d: 0x4134,
- 0x59e: 0x4120, 0x59f: 0x413e, 0x5a0: 0x3ec0, 0x5a1: 0x3ec8, 0x5a2: 0x41fc, 0x5a3: 0x421a,
- 0x5a4: 0x4206, 0x5a5: 0x4224, 0x5a6: 0x4210, 0x5a7: 0x422e, 0x5a8: 0x3d80, 0x5a9: 0x3d88,
- 0x5aa: 0x4148, 0x5ab: 0x4166, 0x5ac: 0x4152, 0x5ad: 0x4170, 0x5ae: 0x415c, 0x5af: 0x417a,
- 0x5b0: 0x3685, 0x5b1: 0x367f, 0x5b2: 0x3d90, 0x5b3: 0x368b, 0x5b4: 0x3d98,
- 0x5b6: 0x48a6, 0x5b7: 0x3db0, 0x5b8: 0x35f5, 0x5b9: 0x35ef, 0x5ba: 0x35e3, 0x5bb: 0x4384,
- 0x5bc: 0x35fb, 0x5bd: 0x8100, 0x5be: 0x01d3, 0x5bf: 0xa100,
- // Block 0x17, offset 0x5c0
- 0x5c0: 0x8100, 0x5c1: 0x35a7, 0x5c2: 0x3dd8, 0x5c3: 0x369d, 0x5c4: 0x3de0,
- 0x5c6: 0x48d0, 0x5c7: 0x3df8, 0x5c8: 0x3601, 0x5c9: 0x438a, 0x5ca: 0x360d, 0x5cb: 0x4390,
- 0x5cc: 0x3619, 0x5cd: 0x3b8f, 0x5ce: 0x3b96, 0x5cf: 0x3b9d, 0x5d0: 0x36b5, 0x5d1: 0x36af,
- 0x5d2: 0x3e00, 0x5d3: 0x457a, 0x5d6: 0x36bb, 0x5d7: 0x3e10,
- 0x5d8: 0x3631, 0x5d9: 0x362b, 0x5da: 0x361f, 0x5db: 0x4396, 0x5dd: 0x3ba4,
- 0x5de: 0x3bab, 0x5df: 0x3bb2, 0x5e0: 0x36eb, 0x5e1: 0x36e5, 0x5e2: 0x3e68, 0x5e3: 0x4582,
- 0x5e4: 0x36cd, 0x5e5: 0x36d3, 0x5e6: 0x36f1, 0x5e7: 0x3e78, 0x5e8: 0x3661, 0x5e9: 0x365b,
- 0x5ea: 0x364f, 0x5eb: 0x43a2, 0x5ec: 0x3649, 0x5ed: 0x359b, 0x5ee: 0x437e, 0x5ef: 0x0081,
- 0x5f2: 0x3eb0, 0x5f3: 0x36f7, 0x5f4: 0x3eb8,
- 0x5f6: 0x491e, 0x5f7: 0x3ed0, 0x5f8: 0x363d, 0x5f9: 0x439c, 0x5fa: 0x366d, 0x5fb: 0x43ae,
- 0x5fc: 0x3679, 0x5fd: 0x4256, 0x5fe: 0xa100,
- // Block 0x18, offset 0x600
- 0x601: 0x3c06, 0x603: 0xa000, 0x604: 0x3c0d, 0x605: 0xa000,
- 0x607: 0x3c14, 0x608: 0xa000, 0x609: 0x3c1b,
- 0x60d: 0xa000,
- 0x620: 0x2f65, 0x621: 0xa000, 0x622: 0x3c29,
- 0x624: 0xa000, 0x625: 0xa000,
- 0x62d: 0x3c22, 0x62e: 0x2f60, 0x62f: 0x2f6a,
- 0x630: 0x3c30, 0x631: 0x3c37, 0x632: 0xa000, 0x633: 0xa000, 0x634: 0x3c3e, 0x635: 0x3c45,
- 0x636: 0xa000, 0x637: 0xa000, 0x638: 0x3c4c, 0x639: 0x3c53, 0x63a: 0xa000, 0x63b: 0xa000,
- 0x63c: 0xa000, 0x63d: 0xa000,
- // Block 0x19, offset 0x640
- 0x640: 0x3c5a, 0x641: 0x3c61, 0x642: 0xa000, 0x643: 0xa000, 0x644: 0x3c76, 0x645: 0x3c7d,
- 0x646: 0xa000, 0x647: 0xa000, 0x648: 0x3c84, 0x649: 0x3c8b,
- 0x651: 0xa000,
- 0x652: 0xa000,
- 0x662: 0xa000,
- 0x668: 0xa000, 0x669: 0xa000,
- 0x66b: 0xa000, 0x66c: 0x3ca0, 0x66d: 0x3ca7, 0x66e: 0x3cae, 0x66f: 0x3cb5,
- 0x672: 0xa000, 0x673: 0xa000, 0x674: 0xa000, 0x675: 0xa000,
- // Block 0x1a, offset 0x680
- 0x686: 0xa000, 0x68b: 0xa000,
- 0x68c: 0x3f08, 0x68d: 0xa000, 0x68e: 0x3f10, 0x68f: 0xa000, 0x690: 0x3f18, 0x691: 0xa000,
- 0x692: 0x3f20, 0x693: 0xa000, 0x694: 0x3f28, 0x695: 0xa000, 0x696: 0x3f30, 0x697: 0xa000,
- 0x698: 0x3f38, 0x699: 0xa000, 0x69a: 0x3f40, 0x69b: 0xa000, 0x69c: 0x3f48, 0x69d: 0xa000,
- 0x69e: 0x3f50, 0x69f: 0xa000, 0x6a0: 0x3f58, 0x6a1: 0xa000, 0x6a2: 0x3f60,
- 0x6a4: 0xa000, 0x6a5: 0x3f68, 0x6a6: 0xa000, 0x6a7: 0x3f70, 0x6a8: 0xa000, 0x6a9: 0x3f78,
- 0x6af: 0xa000,
- 0x6b0: 0x3f80, 0x6b1: 0x3f88, 0x6b2: 0xa000, 0x6b3: 0x3f90, 0x6b4: 0x3f98, 0x6b5: 0xa000,
- 0x6b6: 0x3fa0, 0x6b7: 0x3fa8, 0x6b8: 0xa000, 0x6b9: 0x3fb0, 0x6ba: 0x3fb8, 0x6bb: 0xa000,
- 0x6bc: 0x3fc0, 0x6bd: 0x3fc8,
- // Block 0x1b, offset 0x6c0
- 0x6d4: 0x3f00,
- 0x6d9: 0x9903, 0x6da: 0x9903, 0x6db: 0x8100, 0x6dc: 0x8100, 0x6dd: 0xa000,
- 0x6de: 0x3fd0,
- 0x6e6: 0xa000,
- 0x6eb: 0xa000, 0x6ec: 0x3fe0, 0x6ed: 0xa000, 0x6ee: 0x3fe8, 0x6ef: 0xa000,
- 0x6f0: 0x3ff0, 0x6f1: 0xa000, 0x6f2: 0x3ff8, 0x6f3: 0xa000, 0x6f4: 0x4000, 0x6f5: 0xa000,
- 0x6f6: 0x4008, 0x6f7: 0xa000, 0x6f8: 0x4010, 0x6f9: 0xa000, 0x6fa: 0x4018, 0x6fb: 0xa000,
- 0x6fc: 0x4020, 0x6fd: 0xa000, 0x6fe: 0x4028, 0x6ff: 0xa000,
- // Block 0x1c, offset 0x700
- 0x700: 0x4030, 0x701: 0xa000, 0x702: 0x4038, 0x704: 0xa000, 0x705: 0x4040,
- 0x706: 0xa000, 0x707: 0x4048, 0x708: 0xa000, 0x709: 0x4050,
- 0x70f: 0xa000, 0x710: 0x4058, 0x711: 0x4060,
- 0x712: 0xa000, 0x713: 0x4068, 0x714: 0x4070, 0x715: 0xa000, 0x716: 0x4078, 0x717: 0x4080,
- 0x718: 0xa000, 0x719: 0x4088, 0x71a: 0x4090, 0x71b: 0xa000, 0x71c: 0x4098, 0x71d: 0x40a0,
- 0x72f: 0xa000,
- 0x730: 0xa000, 0x731: 0xa000, 0x732: 0xa000, 0x734: 0x3fd8,
- 0x737: 0x40a8, 0x738: 0x40b0, 0x739: 0x40b8, 0x73a: 0x40c0,
- 0x73d: 0xa000, 0x73e: 0x40c8,
- // Block 0x1d, offset 0x740
- 0x740: 0x1377, 0x741: 0x0cfb, 0x742: 0x13d3, 0x743: 0x139f, 0x744: 0x0e57, 0x745: 0x06eb,
- 0x746: 0x08df, 0x747: 0x162b, 0x748: 0x162b, 0x749: 0x0a0b, 0x74a: 0x145f, 0x74b: 0x0943,
- 0x74c: 0x0a07, 0x74d: 0x0bef, 0x74e: 0x0fcf, 0x74f: 0x115f, 0x750: 0x1297, 0x751: 0x12d3,
- 0x752: 0x1307, 0x753: 0x141b, 0x754: 0x0d73, 0x755: 0x0dff, 0x756: 0x0eab, 0x757: 0x0f43,
- 0x758: 0x125f, 0x759: 0x1447, 0x75a: 0x1573, 0x75b: 0x070f, 0x75c: 0x08b3, 0x75d: 0x0d87,
- 0x75e: 0x0ecf, 0x75f: 0x1293, 0x760: 0x15c3, 0x761: 0x0ab3, 0x762: 0x0e77, 0x763: 0x1283,
- 0x764: 0x1317, 0x765: 0x0c23, 0x766: 0x11bb, 0x767: 0x12df, 0x768: 0x0b1f, 0x769: 0x0d0f,
- 0x76a: 0x0e17, 0x76b: 0x0f1b, 0x76c: 0x1427, 0x76d: 0x074f, 0x76e: 0x07e7, 0x76f: 0x0853,
- 0x770: 0x0c8b, 0x771: 0x0d7f, 0x772: 0x0ecb, 0x773: 0x0fef, 0x774: 0x1177, 0x775: 0x128b,
- 0x776: 0x12a3, 0x777: 0x13c7, 0x778: 0x14ef, 0x779: 0x15a3, 0x77a: 0x15bf, 0x77b: 0x102b,
- 0x77c: 0x106b, 0x77d: 0x1123, 0x77e: 0x1243, 0x77f: 0x147b,
- // Block 0x1e, offset 0x780
- 0x780: 0x15cb, 0x781: 0x134b, 0x782: 0x09c7, 0x783: 0x0b3b, 0x784: 0x10db, 0x785: 0x119b,
- 0x786: 0x0eff, 0x787: 0x1033, 0x788: 0x1397, 0x789: 0x14e7, 0x78a: 0x09c3, 0x78b: 0x0a8f,
- 0x78c: 0x0d77, 0x78d: 0x0e2b, 0x78e: 0x0e5f, 0x78f: 0x1113, 0x790: 0x113b, 0x791: 0x14a7,
- 0x792: 0x084f, 0x793: 0x11a7, 0x794: 0x07f3, 0x795: 0x07ef, 0x796: 0x1097, 0x797: 0x1127,
- 0x798: 0x125b, 0x799: 0x14af, 0x79a: 0x1367, 0x79b: 0x0c27, 0x79c: 0x0d73, 0x79d: 0x1357,
- 0x79e: 0x06f7, 0x79f: 0x0a63, 0x7a0: 0x0b93, 0x7a1: 0x0f2f, 0x7a2: 0x0faf, 0x7a3: 0x0873,
- 0x7a4: 0x103b, 0x7a5: 0x075f, 0x7a6: 0x0b77, 0x7a7: 0x06d7, 0x7a8: 0x0deb, 0x7a9: 0x0ca3,
- 0x7aa: 0x110f, 0x7ab: 0x08c7, 0x7ac: 0x09b3, 0x7ad: 0x0ffb, 0x7ae: 0x1263, 0x7af: 0x133b,
- 0x7b0: 0x0db7, 0x7b1: 0x13f7, 0x7b2: 0x0de3, 0x7b3: 0x0c37, 0x7b4: 0x121b, 0x7b5: 0x0c57,
- 0x7b6: 0x0fab, 0x7b7: 0x072b, 0x7b8: 0x07a7, 0x7b9: 0x07eb, 0x7ba: 0x0d53, 0x7bb: 0x10fb,
- 0x7bc: 0x11f3, 0x7bd: 0x1347, 0x7be: 0x145b, 0x7bf: 0x085b,
- // Block 0x1f, offset 0x7c0
- 0x7c0: 0x090f, 0x7c1: 0x0a17, 0x7c2: 0x0b2f, 0x7c3: 0x0cbf, 0x7c4: 0x0e7b, 0x7c5: 0x103f,
- 0x7c6: 0x1497, 0x7c7: 0x157b, 0x7c8: 0x15cf, 0x7c9: 0x15e7, 0x7ca: 0x0837, 0x7cb: 0x0cf3,
- 0x7cc: 0x0da3, 0x7cd: 0x13eb, 0x7ce: 0x0afb, 0x7cf: 0x0bd7, 0x7d0: 0x0bf3, 0x7d1: 0x0c83,
- 0x7d2: 0x0e6b, 0x7d3: 0x0eb7, 0x7d4: 0x0f67, 0x7d5: 0x108b, 0x7d6: 0x112f, 0x7d7: 0x1193,
- 0x7d8: 0x13db, 0x7d9: 0x126b, 0x7da: 0x1403, 0x7db: 0x147f, 0x7dc: 0x080f, 0x7dd: 0x083b,
- 0x7de: 0x0923, 0x7df: 0x0ea7, 0x7e0: 0x12f3, 0x7e1: 0x133b, 0x7e2: 0x0b1b, 0x7e3: 0x0b8b,
- 0x7e4: 0x0c4f, 0x7e5: 0x0daf, 0x7e6: 0x10d7, 0x7e7: 0x0f23, 0x7e8: 0x073b, 0x7e9: 0x097f,
- 0x7ea: 0x0a63, 0x7eb: 0x0ac7, 0x7ec: 0x0b97, 0x7ed: 0x0f3f, 0x7ee: 0x0f5b, 0x7ef: 0x116b,
- 0x7f0: 0x118b, 0x7f1: 0x1463, 0x7f2: 0x14e3, 0x7f3: 0x14f3, 0x7f4: 0x152f, 0x7f5: 0x0753,
- 0x7f6: 0x107f, 0x7f7: 0x144f, 0x7f8: 0x14cb, 0x7f9: 0x0baf, 0x7fa: 0x0717, 0x7fb: 0x0777,
- 0x7fc: 0x0a67, 0x7fd: 0x0a87, 0x7fe: 0x0caf, 0x7ff: 0x0d73,
- // Block 0x20, offset 0x800
- 0x800: 0x0ec3, 0x801: 0x0fcb, 0x802: 0x1277, 0x803: 0x1417, 0x804: 0x1623, 0x805: 0x0ce3,
- 0x806: 0x14a3, 0x807: 0x0833, 0x808: 0x0d2f, 0x809: 0x0d3b, 0x80a: 0x0e0f, 0x80b: 0x0e47,
- 0x80c: 0x0f4b, 0x80d: 0x0fa7, 0x80e: 0x1027, 0x80f: 0x110b, 0x810: 0x153b, 0x811: 0x07af,
- 0x812: 0x0c03, 0x813: 0x14b3, 0x814: 0x0767, 0x815: 0x0aab, 0x816: 0x0e2f, 0x817: 0x13df,
- 0x818: 0x0b67, 0x819: 0x0bb7, 0x81a: 0x0d43, 0x81b: 0x0f2f, 0x81c: 0x14bb, 0x81d: 0x0817,
- 0x81e: 0x08ff, 0x81f: 0x0a97, 0x820: 0x0cd3, 0x821: 0x0d1f, 0x822: 0x0d5f, 0x823: 0x0df3,
- 0x824: 0x0f47, 0x825: 0x0fbb, 0x826: 0x1157, 0x827: 0x12f7, 0x828: 0x1303, 0x829: 0x1457,
- 0x82a: 0x14d7, 0x82b: 0x0883, 0x82c: 0x0e4b, 0x82d: 0x0903, 0x82e: 0x0ec7, 0x82f: 0x0f6b,
- 0x830: 0x1287, 0x831: 0x14bf, 0x832: 0x15ab, 0x833: 0x15d3, 0x834: 0x0d37, 0x835: 0x0e27,
- 0x836: 0x11c3, 0x837: 0x10b7, 0x838: 0x10c3, 0x839: 0x10e7, 0x83a: 0x0f17, 0x83b: 0x0e9f,
- 0x83c: 0x1363, 0x83d: 0x0733, 0x83e: 0x122b, 0x83f: 0x081b,
- // Block 0x21, offset 0x840
- 0x840: 0x080b, 0x841: 0x0b0b, 0x842: 0x0c2b, 0x843: 0x10f3, 0x844: 0x0a53, 0x845: 0x0e03,
- 0x846: 0x0cef, 0x847: 0x13e7, 0x848: 0x12e7, 0x849: 0x14ab, 0x84a: 0x1323, 0x84b: 0x0b27,
- 0x84c: 0x0787, 0x84d: 0x095b, 0x850: 0x09af,
- 0x852: 0x0cdf, 0x855: 0x07f7, 0x856: 0x0f1f, 0x857: 0x0fe3,
- 0x858: 0x1047, 0x859: 0x1063, 0x85a: 0x1067, 0x85b: 0x107b, 0x85c: 0x14fb, 0x85d: 0x10eb,
- 0x85e: 0x116f, 0x860: 0x128f, 0x862: 0x1353,
- 0x865: 0x1407, 0x866: 0x1433,
- 0x86a: 0x154f, 0x86b: 0x1553, 0x86c: 0x1557, 0x86d: 0x15bb, 0x86e: 0x142b, 0x86f: 0x14c7,
- 0x870: 0x0757, 0x871: 0x077b, 0x872: 0x078f, 0x873: 0x084b, 0x874: 0x0857, 0x875: 0x0897,
- 0x876: 0x094b, 0x877: 0x0967, 0x878: 0x096f, 0x879: 0x09ab, 0x87a: 0x09b7, 0x87b: 0x0a93,
- 0x87c: 0x0a9b, 0x87d: 0x0ba3, 0x87e: 0x0bcb, 0x87f: 0x0bd3,
- // Block 0x22, offset 0x880
- 0x880: 0x0beb, 0x881: 0x0c97, 0x882: 0x0cc7, 0x883: 0x0ce7, 0x884: 0x0d57, 0x885: 0x0e1b,
- 0x886: 0x0e37, 0x887: 0x0e67, 0x888: 0x0ebb, 0x889: 0x0edb, 0x88a: 0x0f4f, 0x88b: 0x102f,
- 0x88c: 0x104b, 0x88d: 0x1053, 0x88e: 0x104f, 0x88f: 0x1057, 0x890: 0x105b, 0x891: 0x105f,
- 0x892: 0x1073, 0x893: 0x1077, 0x894: 0x109b, 0x895: 0x10af, 0x896: 0x10cb, 0x897: 0x112f,
- 0x898: 0x1137, 0x899: 0x113f, 0x89a: 0x1153, 0x89b: 0x117b, 0x89c: 0x11cb, 0x89d: 0x11ff,
- 0x89e: 0x11ff, 0x89f: 0x1267, 0x8a0: 0x130f, 0x8a1: 0x1327, 0x8a2: 0x135b, 0x8a3: 0x135f,
- 0x8a4: 0x13a3, 0x8a5: 0x13a7, 0x8a6: 0x13ff, 0x8a7: 0x1407, 0x8a8: 0x14db, 0x8a9: 0x151f,
- 0x8aa: 0x1537, 0x8ab: 0x0b9b, 0x8ac: 0x171e, 0x8ad: 0x11e3,
- 0x8b0: 0x06df, 0x8b1: 0x07e3, 0x8b2: 0x07a3, 0x8b3: 0x074b, 0x8b4: 0x078b, 0x8b5: 0x07b7,
- 0x8b6: 0x0847, 0x8b7: 0x0863, 0x8b8: 0x094b, 0x8b9: 0x0937, 0x8ba: 0x0947, 0x8bb: 0x0963,
- 0x8bc: 0x09af, 0x8bd: 0x09bf, 0x8be: 0x0a03, 0x8bf: 0x0a0f,
- // Block 0x23, offset 0x8c0
- 0x8c0: 0x0a2b, 0x8c1: 0x0a3b, 0x8c2: 0x0b23, 0x8c3: 0x0b2b, 0x8c4: 0x0b5b, 0x8c5: 0x0b7b,
- 0x8c6: 0x0bab, 0x8c7: 0x0bc3, 0x8c8: 0x0bb3, 0x8c9: 0x0bd3, 0x8ca: 0x0bc7, 0x8cb: 0x0beb,
- 0x8cc: 0x0c07, 0x8cd: 0x0c5f, 0x8ce: 0x0c6b, 0x8cf: 0x0c73, 0x8d0: 0x0c9b, 0x8d1: 0x0cdf,
- 0x8d2: 0x0d0f, 0x8d3: 0x0d13, 0x8d4: 0x0d27, 0x8d5: 0x0da7, 0x8d6: 0x0db7, 0x8d7: 0x0e0f,
- 0x8d8: 0x0e5b, 0x8d9: 0x0e53, 0x8da: 0x0e67, 0x8db: 0x0e83, 0x8dc: 0x0ebb, 0x8dd: 0x1013,
- 0x8de: 0x0edf, 0x8df: 0x0f13, 0x8e0: 0x0f1f, 0x8e1: 0x0f5f, 0x8e2: 0x0f7b, 0x8e3: 0x0f9f,
- 0x8e4: 0x0fc3, 0x8e5: 0x0fc7, 0x8e6: 0x0fe3, 0x8e7: 0x0fe7, 0x8e8: 0x0ff7, 0x8e9: 0x100b,
- 0x8ea: 0x1007, 0x8eb: 0x1037, 0x8ec: 0x10b3, 0x8ed: 0x10cb, 0x8ee: 0x10e3, 0x8ef: 0x111b,
- 0x8f0: 0x112f, 0x8f1: 0x114b, 0x8f2: 0x117b, 0x8f3: 0x122f, 0x8f4: 0x1257, 0x8f5: 0x12cb,
- 0x8f6: 0x1313, 0x8f7: 0x131f, 0x8f8: 0x1327, 0x8f9: 0x133f, 0x8fa: 0x1353, 0x8fb: 0x1343,
- 0x8fc: 0x135b, 0x8fd: 0x1357, 0x8fe: 0x134f, 0x8ff: 0x135f,
- // Block 0x24, offset 0x900
- 0x900: 0x136b, 0x901: 0x13a7, 0x902: 0x13e3, 0x903: 0x1413, 0x904: 0x144b, 0x905: 0x146b,
- 0x906: 0x14b7, 0x907: 0x14db, 0x908: 0x14fb, 0x909: 0x150f, 0x90a: 0x151f, 0x90b: 0x152b,
- 0x90c: 0x1537, 0x90d: 0x158b, 0x90e: 0x162b, 0x90f: 0x16b5, 0x910: 0x16b0, 0x911: 0x16e2,
- 0x912: 0x0607, 0x913: 0x062f, 0x914: 0x0633, 0x915: 0x1764, 0x916: 0x1791, 0x917: 0x1809,
- 0x918: 0x1617, 0x919: 0x1627,
- // Block 0x25, offset 0x940
- 0x940: 0x06fb, 0x941: 0x06f3, 0x942: 0x0703, 0x943: 0x1647, 0x944: 0x0747, 0x945: 0x0757,
- 0x946: 0x075b, 0x947: 0x0763, 0x948: 0x076b, 0x949: 0x076f, 0x94a: 0x077b, 0x94b: 0x0773,
- 0x94c: 0x05b3, 0x94d: 0x165b, 0x94e: 0x078f, 0x94f: 0x0793, 0x950: 0x0797, 0x951: 0x07b3,
- 0x952: 0x164c, 0x953: 0x05b7, 0x954: 0x079f, 0x955: 0x07bf, 0x956: 0x1656, 0x957: 0x07cf,
- 0x958: 0x07d7, 0x959: 0x0737, 0x95a: 0x07df, 0x95b: 0x07e3, 0x95c: 0x1831, 0x95d: 0x07ff,
- 0x95e: 0x0807, 0x95f: 0x05bf, 0x960: 0x081f, 0x961: 0x0823, 0x962: 0x082b, 0x963: 0x082f,
- 0x964: 0x05c3, 0x965: 0x0847, 0x966: 0x084b, 0x967: 0x0857, 0x968: 0x0863, 0x969: 0x0867,
- 0x96a: 0x086b, 0x96b: 0x0873, 0x96c: 0x0893, 0x96d: 0x0897, 0x96e: 0x089f, 0x96f: 0x08af,
- 0x970: 0x08b7, 0x971: 0x08bb, 0x972: 0x08bb, 0x973: 0x08bb, 0x974: 0x166a, 0x975: 0x0e93,
- 0x976: 0x08cf, 0x977: 0x08d7, 0x978: 0x166f, 0x979: 0x08e3, 0x97a: 0x08eb, 0x97b: 0x08f3,
- 0x97c: 0x091b, 0x97d: 0x0907, 0x97e: 0x0913, 0x97f: 0x0917,
- // Block 0x26, offset 0x980
- 0x980: 0x091f, 0x981: 0x0927, 0x982: 0x092b, 0x983: 0x0933, 0x984: 0x093b, 0x985: 0x093f,
- 0x986: 0x093f, 0x987: 0x0947, 0x988: 0x094f, 0x989: 0x0953, 0x98a: 0x095f, 0x98b: 0x0983,
- 0x98c: 0x0967, 0x98d: 0x0987, 0x98e: 0x096b, 0x98f: 0x0973, 0x990: 0x080b, 0x991: 0x09cf,
- 0x992: 0x0997, 0x993: 0x099b, 0x994: 0x099f, 0x995: 0x0993, 0x996: 0x09a7, 0x997: 0x09a3,
- 0x998: 0x09bb, 0x999: 0x1674, 0x99a: 0x09d7, 0x99b: 0x09db, 0x99c: 0x09e3, 0x99d: 0x09ef,
- 0x99e: 0x09f7, 0x99f: 0x0a13, 0x9a0: 0x1679, 0x9a1: 0x167e, 0x9a2: 0x0a1f, 0x9a3: 0x0a23,
- 0x9a4: 0x0a27, 0x9a5: 0x0a1b, 0x9a6: 0x0a2f, 0x9a7: 0x05c7, 0x9a8: 0x05cb, 0x9a9: 0x0a37,
- 0x9aa: 0x0a3f, 0x9ab: 0x0a3f, 0x9ac: 0x1683, 0x9ad: 0x0a5b, 0x9ae: 0x0a5f, 0x9af: 0x0a63,
- 0x9b0: 0x0a6b, 0x9b1: 0x1688, 0x9b2: 0x0a73, 0x9b3: 0x0a77, 0x9b4: 0x0b4f, 0x9b5: 0x0a7f,
- 0x9b6: 0x05cf, 0x9b7: 0x0a8b, 0x9b8: 0x0a9b, 0x9b9: 0x0aa7, 0x9ba: 0x0aa3, 0x9bb: 0x1692,
- 0x9bc: 0x0aaf, 0x9bd: 0x1697, 0x9be: 0x0abb, 0x9bf: 0x0ab7,
- // Block 0x27, offset 0x9c0
- 0x9c0: 0x0abf, 0x9c1: 0x0acf, 0x9c2: 0x0ad3, 0x9c3: 0x05d3, 0x9c4: 0x0ae3, 0x9c5: 0x0aeb,
- 0x9c6: 0x0aef, 0x9c7: 0x0af3, 0x9c8: 0x05d7, 0x9c9: 0x169c, 0x9ca: 0x05db, 0x9cb: 0x0b0f,
- 0x9cc: 0x0b13, 0x9cd: 0x0b17, 0x9ce: 0x0b1f, 0x9cf: 0x1863, 0x9d0: 0x0b37, 0x9d1: 0x16a6,
- 0x9d2: 0x16a6, 0x9d3: 0x11d7, 0x9d4: 0x0b47, 0x9d5: 0x0b47, 0x9d6: 0x05df, 0x9d7: 0x16c9,
- 0x9d8: 0x179b, 0x9d9: 0x0b57, 0x9da: 0x0b5f, 0x9db: 0x05e3, 0x9dc: 0x0b73, 0x9dd: 0x0b83,
- 0x9de: 0x0b87, 0x9df: 0x0b8f, 0x9e0: 0x0b9f, 0x9e1: 0x05eb, 0x9e2: 0x05e7, 0x9e3: 0x0ba3,
- 0x9e4: 0x16ab, 0x9e5: 0x0ba7, 0x9e6: 0x0bbb, 0x9e7: 0x0bbf, 0x9e8: 0x0bc3, 0x9e9: 0x0bbf,
- 0x9ea: 0x0bcf, 0x9eb: 0x0bd3, 0x9ec: 0x0be3, 0x9ed: 0x0bdb, 0x9ee: 0x0bdf, 0x9ef: 0x0be7,
- 0x9f0: 0x0beb, 0x9f1: 0x0bef, 0x9f2: 0x0bfb, 0x9f3: 0x0bff, 0x9f4: 0x0c17, 0x9f5: 0x0c1f,
- 0x9f6: 0x0c2f, 0x9f7: 0x0c43, 0x9f8: 0x16ba, 0x9f9: 0x0c3f, 0x9fa: 0x0c33, 0x9fb: 0x0c4b,
- 0x9fc: 0x0c53, 0x9fd: 0x0c67, 0x9fe: 0x16bf, 0x9ff: 0x0c6f,
- // Block 0x28, offset 0xa00
- 0xa00: 0x0c63, 0xa01: 0x0c5b, 0xa02: 0x05ef, 0xa03: 0x0c77, 0xa04: 0x0c7f, 0xa05: 0x0c87,
- 0xa06: 0x0c7b, 0xa07: 0x05f3, 0xa08: 0x0c97, 0xa09: 0x0c9f, 0xa0a: 0x16c4, 0xa0b: 0x0ccb,
- 0xa0c: 0x0cff, 0xa0d: 0x0cdb, 0xa0e: 0x05ff, 0xa0f: 0x0ce7, 0xa10: 0x05fb, 0xa11: 0x05f7,
- 0xa12: 0x07c3, 0xa13: 0x07c7, 0xa14: 0x0d03, 0xa15: 0x0ceb, 0xa16: 0x11ab, 0xa17: 0x0663,
- 0xa18: 0x0d0f, 0xa19: 0x0d13, 0xa1a: 0x0d17, 0xa1b: 0x0d2b, 0xa1c: 0x0d23, 0xa1d: 0x16dd,
- 0xa1e: 0x0603, 0xa1f: 0x0d3f, 0xa20: 0x0d33, 0xa21: 0x0d4f, 0xa22: 0x0d57, 0xa23: 0x16e7,
- 0xa24: 0x0d5b, 0xa25: 0x0d47, 0xa26: 0x0d63, 0xa27: 0x0607, 0xa28: 0x0d67, 0xa29: 0x0d6b,
- 0xa2a: 0x0d6f, 0xa2b: 0x0d7b, 0xa2c: 0x16ec, 0xa2d: 0x0d83, 0xa2e: 0x060b, 0xa2f: 0x0d8f,
- 0xa30: 0x16f1, 0xa31: 0x0d93, 0xa32: 0x060f, 0xa33: 0x0d9f, 0xa34: 0x0dab, 0xa35: 0x0db7,
- 0xa36: 0x0dbb, 0xa37: 0x16f6, 0xa38: 0x168d, 0xa39: 0x16fb, 0xa3a: 0x0ddb, 0xa3b: 0x1700,
- 0xa3c: 0x0de7, 0xa3d: 0x0def, 0xa3e: 0x0ddf, 0xa3f: 0x0dfb,
- // Block 0x29, offset 0xa40
- 0xa40: 0x0e0b, 0xa41: 0x0e1b, 0xa42: 0x0e0f, 0xa43: 0x0e13, 0xa44: 0x0e1f, 0xa45: 0x0e23,
- 0xa46: 0x1705, 0xa47: 0x0e07, 0xa48: 0x0e3b, 0xa49: 0x0e3f, 0xa4a: 0x0613, 0xa4b: 0x0e53,
- 0xa4c: 0x0e4f, 0xa4d: 0x170a, 0xa4e: 0x0e33, 0xa4f: 0x0e6f, 0xa50: 0x170f, 0xa51: 0x1714,
- 0xa52: 0x0e73, 0xa53: 0x0e87, 0xa54: 0x0e83, 0xa55: 0x0e7f, 0xa56: 0x0617, 0xa57: 0x0e8b,
- 0xa58: 0x0e9b, 0xa59: 0x0e97, 0xa5a: 0x0ea3, 0xa5b: 0x1651, 0xa5c: 0x0eb3, 0xa5d: 0x1719,
- 0xa5e: 0x0ebf, 0xa5f: 0x1723, 0xa60: 0x0ed3, 0xa61: 0x0edf, 0xa62: 0x0ef3, 0xa63: 0x1728,
- 0xa64: 0x0f07, 0xa65: 0x0f0b, 0xa66: 0x172d, 0xa67: 0x1732, 0xa68: 0x0f27, 0xa69: 0x0f37,
- 0xa6a: 0x061b, 0xa6b: 0x0f3b, 0xa6c: 0x061f, 0xa6d: 0x061f, 0xa6e: 0x0f53, 0xa6f: 0x0f57,
- 0xa70: 0x0f5f, 0xa71: 0x0f63, 0xa72: 0x0f6f, 0xa73: 0x0623, 0xa74: 0x0f87, 0xa75: 0x1737,
- 0xa76: 0x0fa3, 0xa77: 0x173c, 0xa78: 0x0faf, 0xa79: 0x16a1, 0xa7a: 0x0fbf, 0xa7b: 0x1741,
- 0xa7c: 0x1746, 0xa7d: 0x174b, 0xa7e: 0x0627, 0xa7f: 0x062b,
- // Block 0x2a, offset 0xa80
- 0xa80: 0x0ff7, 0xa81: 0x1755, 0xa82: 0x1750, 0xa83: 0x175a, 0xa84: 0x175f, 0xa85: 0x0fff,
- 0xa86: 0x1003, 0xa87: 0x1003, 0xa88: 0x100b, 0xa89: 0x0633, 0xa8a: 0x100f, 0xa8b: 0x0637,
- 0xa8c: 0x063b, 0xa8d: 0x1769, 0xa8e: 0x1023, 0xa8f: 0x102b, 0xa90: 0x1037, 0xa91: 0x063f,
- 0xa92: 0x176e, 0xa93: 0x105b, 0xa94: 0x1773, 0xa95: 0x1778, 0xa96: 0x107b, 0xa97: 0x1093,
- 0xa98: 0x0643, 0xa99: 0x109b, 0xa9a: 0x109f, 0xa9b: 0x10a3, 0xa9c: 0x177d, 0xa9d: 0x1782,
- 0xa9e: 0x1782, 0xa9f: 0x10bb, 0xaa0: 0x0647, 0xaa1: 0x1787, 0xaa2: 0x10cf, 0xaa3: 0x10d3,
- 0xaa4: 0x064b, 0xaa5: 0x178c, 0xaa6: 0x10ef, 0xaa7: 0x064f, 0xaa8: 0x10ff, 0xaa9: 0x10f7,
- 0xaaa: 0x1107, 0xaab: 0x1796, 0xaac: 0x111f, 0xaad: 0x0653, 0xaae: 0x112b, 0xaaf: 0x1133,
- 0xab0: 0x1143, 0xab1: 0x0657, 0xab2: 0x17a0, 0xab3: 0x17a5, 0xab4: 0x065b, 0xab5: 0x17aa,
- 0xab6: 0x115b, 0xab7: 0x17af, 0xab8: 0x1167, 0xab9: 0x1173, 0xaba: 0x117b, 0xabb: 0x17b4,
- 0xabc: 0x17b9, 0xabd: 0x118f, 0xabe: 0x17be, 0xabf: 0x1197,
- // Block 0x2b, offset 0xac0
- 0xac0: 0x16ce, 0xac1: 0x065f, 0xac2: 0x11af, 0xac3: 0x11b3, 0xac4: 0x0667, 0xac5: 0x11b7,
- 0xac6: 0x0a33, 0xac7: 0x17c3, 0xac8: 0x17c8, 0xac9: 0x16d3, 0xaca: 0x16d8, 0xacb: 0x11d7,
- 0xacc: 0x11db, 0xacd: 0x13f3, 0xace: 0x066b, 0xacf: 0x1207, 0xad0: 0x1203, 0xad1: 0x120b,
- 0xad2: 0x083f, 0xad3: 0x120f, 0xad4: 0x1213, 0xad5: 0x1217, 0xad6: 0x121f, 0xad7: 0x17cd,
- 0xad8: 0x121b, 0xad9: 0x1223, 0xada: 0x1237, 0xadb: 0x123b, 0xadc: 0x1227, 0xadd: 0x123f,
- 0xade: 0x1253, 0xadf: 0x1267, 0xae0: 0x1233, 0xae1: 0x1247, 0xae2: 0x124b, 0xae3: 0x124f,
- 0xae4: 0x17d2, 0xae5: 0x17dc, 0xae6: 0x17d7, 0xae7: 0x066f, 0xae8: 0x126f, 0xae9: 0x1273,
- 0xaea: 0x127b, 0xaeb: 0x17f0, 0xaec: 0x127f, 0xaed: 0x17e1, 0xaee: 0x0673, 0xaef: 0x0677,
- 0xaf0: 0x17e6, 0xaf1: 0x17eb, 0xaf2: 0x067b, 0xaf3: 0x129f, 0xaf4: 0x12a3, 0xaf5: 0x12a7,
- 0xaf6: 0x12ab, 0xaf7: 0x12b7, 0xaf8: 0x12b3, 0xaf9: 0x12bf, 0xafa: 0x12bb, 0xafb: 0x12cb,
- 0xafc: 0x12c3, 0xafd: 0x12c7, 0xafe: 0x12cf, 0xaff: 0x067f,
- // Block 0x2c, offset 0xb00
- 0xb00: 0x12d7, 0xb01: 0x12db, 0xb02: 0x0683, 0xb03: 0x12eb, 0xb04: 0x12ef, 0xb05: 0x17f5,
- 0xb06: 0x12fb, 0xb07: 0x12ff, 0xb08: 0x0687, 0xb09: 0x130b, 0xb0a: 0x05bb, 0xb0b: 0x17fa,
- 0xb0c: 0x17ff, 0xb0d: 0x068b, 0xb0e: 0x068f, 0xb0f: 0x1337, 0xb10: 0x134f, 0xb11: 0x136b,
- 0xb12: 0x137b, 0xb13: 0x1804, 0xb14: 0x138f, 0xb15: 0x1393, 0xb16: 0x13ab, 0xb17: 0x13b7,
- 0xb18: 0x180e, 0xb19: 0x1660, 0xb1a: 0x13c3, 0xb1b: 0x13bf, 0xb1c: 0x13cb, 0xb1d: 0x1665,
- 0xb1e: 0x13d7, 0xb1f: 0x13e3, 0xb20: 0x1813, 0xb21: 0x1818, 0xb22: 0x1423, 0xb23: 0x142f,
- 0xb24: 0x1437, 0xb25: 0x181d, 0xb26: 0x143b, 0xb27: 0x1467, 0xb28: 0x1473, 0xb29: 0x1477,
- 0xb2a: 0x146f, 0xb2b: 0x1483, 0xb2c: 0x1487, 0xb2d: 0x1822, 0xb2e: 0x1493, 0xb2f: 0x0693,
- 0xb30: 0x149b, 0xb31: 0x1827, 0xb32: 0x0697, 0xb33: 0x14d3, 0xb34: 0x0ac3, 0xb35: 0x14eb,
- 0xb36: 0x182c, 0xb37: 0x1836, 0xb38: 0x069b, 0xb39: 0x069f, 0xb3a: 0x1513, 0xb3b: 0x183b,
- 0xb3c: 0x06a3, 0xb3d: 0x1840, 0xb3e: 0x152b, 0xb3f: 0x152b,
- // Block 0x2d, offset 0xb40
- 0xb40: 0x1533, 0xb41: 0x1845, 0xb42: 0x154b, 0xb43: 0x06a7, 0xb44: 0x155b, 0xb45: 0x1567,
- 0xb46: 0x156f, 0xb47: 0x1577, 0xb48: 0x06ab, 0xb49: 0x184a, 0xb4a: 0x158b, 0xb4b: 0x15a7,
- 0xb4c: 0x15b3, 0xb4d: 0x06af, 0xb4e: 0x06b3, 0xb4f: 0x15b7, 0xb50: 0x184f, 0xb51: 0x06b7,
- 0xb52: 0x1854, 0xb53: 0x1859, 0xb54: 0x185e, 0xb55: 0x15db, 0xb56: 0x06bb, 0xb57: 0x15ef,
- 0xb58: 0x15f7, 0xb59: 0x15fb, 0xb5a: 0x1603, 0xb5b: 0x160b, 0xb5c: 0x1613, 0xb5d: 0x1868,
-}
-
-// nfcIndex: 22 blocks, 1408 entries, 1408 bytes
-// Block 0 is the zero block.
-var nfcIndex = [1408]uint8{
- // Block 0x0, offset 0x0
- // Block 0x1, offset 0x40
- // Block 0x2, offset 0x80
- // Block 0x3, offset 0xc0
- 0xc2: 0x2c, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x2d, 0xc7: 0x04,
- 0xc8: 0x05, 0xca: 0x2e, 0xcb: 0x2f, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x30,
- 0xd0: 0x09, 0xd1: 0x31, 0xd2: 0x32, 0xd3: 0x0a, 0xd6: 0x0b, 0xd7: 0x33,
- 0xd8: 0x34, 0xd9: 0x0c, 0xdb: 0x35, 0xdc: 0x36, 0xdd: 0x37, 0xdf: 0x38,
- 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05,
- 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a,
- 0xf0: 0x13,
- // Block 0x4, offset 0x100
- 0x120: 0x39, 0x121: 0x3a, 0x123: 0x3b, 0x124: 0x3c, 0x125: 0x3d, 0x126: 0x3e, 0x127: 0x3f,
- 0x128: 0x40, 0x129: 0x41, 0x12a: 0x42, 0x12b: 0x43, 0x12c: 0x3e, 0x12d: 0x44, 0x12e: 0x45, 0x12f: 0x46,
- 0x131: 0x47, 0x132: 0x48, 0x133: 0x49, 0x134: 0x4a, 0x135: 0x4b, 0x137: 0x4c,
- 0x138: 0x4d, 0x139: 0x4e, 0x13a: 0x4f, 0x13b: 0x50, 0x13c: 0x51, 0x13d: 0x52, 0x13e: 0x53, 0x13f: 0x54,
- // Block 0x5, offset 0x140
- 0x140: 0x55, 0x142: 0x56, 0x144: 0x57, 0x145: 0x58, 0x146: 0x59, 0x147: 0x5a,
- 0x14d: 0x5b,
- 0x15c: 0x5c, 0x15f: 0x5d,
- 0x162: 0x5e, 0x164: 0x5f,
- 0x168: 0x60, 0x169: 0x61, 0x16a: 0x62, 0x16c: 0x0d, 0x16d: 0x63, 0x16e: 0x64, 0x16f: 0x65,
- 0x170: 0x66, 0x173: 0x67, 0x177: 0x68,
- 0x178: 0x0e, 0x179: 0x0f, 0x17a: 0x10, 0x17b: 0x11, 0x17c: 0x12, 0x17d: 0x13, 0x17e: 0x14, 0x17f: 0x15,
- // Block 0x6, offset 0x180
- 0x180: 0x69, 0x183: 0x6a, 0x184: 0x6b, 0x186: 0x6c, 0x187: 0x6d,
- 0x188: 0x6e, 0x189: 0x16, 0x18a: 0x17, 0x18b: 0x6f, 0x18c: 0x70,
- 0x1ab: 0x71,
- 0x1b3: 0x72, 0x1b5: 0x73, 0x1b7: 0x74,
- // Block 0x7, offset 0x1c0
- 0x1c0: 0x75, 0x1c1: 0x18, 0x1c2: 0x19, 0x1c3: 0x1a, 0x1c4: 0x76, 0x1c5: 0x77,
- 0x1c9: 0x78, 0x1cc: 0x79, 0x1cd: 0x7a,
- // Block 0x8, offset 0x200
- 0x219: 0x7b, 0x21a: 0x7c, 0x21b: 0x7d,
- 0x220: 0x7e, 0x223: 0x7f, 0x224: 0x80, 0x225: 0x81, 0x226: 0x82, 0x227: 0x83,
- 0x22a: 0x84, 0x22b: 0x85, 0x22f: 0x86,
- 0x230: 0x87, 0x231: 0x88, 0x232: 0x89, 0x233: 0x8a, 0x234: 0x8b, 0x235: 0x8c, 0x236: 0x8d, 0x237: 0x87,
- 0x238: 0x88, 0x239: 0x89, 0x23a: 0x8a, 0x23b: 0x8b, 0x23c: 0x8c, 0x23d: 0x8d, 0x23e: 0x87, 0x23f: 0x88,
- // Block 0x9, offset 0x240
- 0x240: 0x89, 0x241: 0x8a, 0x242: 0x8b, 0x243: 0x8c, 0x244: 0x8d, 0x245: 0x87, 0x246: 0x88, 0x247: 0x89,
- 0x248: 0x8a, 0x249: 0x8b, 0x24a: 0x8c, 0x24b: 0x8d, 0x24c: 0x87, 0x24d: 0x88, 0x24e: 0x89, 0x24f: 0x8a,
- 0x250: 0x8b, 0x251: 0x8c, 0x252: 0x8d, 0x253: 0x87, 0x254: 0x88, 0x255: 0x89, 0x256: 0x8a, 0x257: 0x8b,
- 0x258: 0x8c, 0x259: 0x8d, 0x25a: 0x87, 0x25b: 0x88, 0x25c: 0x89, 0x25d: 0x8a, 0x25e: 0x8b, 0x25f: 0x8c,
- 0x260: 0x8d, 0x261: 0x87, 0x262: 0x88, 0x263: 0x89, 0x264: 0x8a, 0x265: 0x8b, 0x266: 0x8c, 0x267: 0x8d,
- 0x268: 0x87, 0x269: 0x88, 0x26a: 0x89, 0x26b: 0x8a, 0x26c: 0x8b, 0x26d: 0x8c, 0x26e: 0x8d, 0x26f: 0x87,
- 0x270: 0x88, 0x271: 0x89, 0x272: 0x8a, 0x273: 0x8b, 0x274: 0x8c, 0x275: 0x8d, 0x276: 0x87, 0x277: 0x88,
- 0x278: 0x89, 0x279: 0x8a, 0x27a: 0x8b, 0x27b: 0x8c, 0x27c: 0x8d, 0x27d: 0x87, 0x27e: 0x88, 0x27f: 0x89,
- // Block 0xa, offset 0x280
- 0x280: 0x8a, 0x281: 0x8b, 0x282: 0x8c, 0x283: 0x8d, 0x284: 0x87, 0x285: 0x88, 0x286: 0x89, 0x287: 0x8a,
- 0x288: 0x8b, 0x289: 0x8c, 0x28a: 0x8d, 0x28b: 0x87, 0x28c: 0x88, 0x28d: 0x89, 0x28e: 0x8a, 0x28f: 0x8b,
- 0x290: 0x8c, 0x291: 0x8d, 0x292: 0x87, 0x293: 0x88, 0x294: 0x89, 0x295: 0x8a, 0x296: 0x8b, 0x297: 0x8c,
- 0x298: 0x8d, 0x299: 0x87, 0x29a: 0x88, 0x29b: 0x89, 0x29c: 0x8a, 0x29d: 0x8b, 0x29e: 0x8c, 0x29f: 0x8d,
- 0x2a0: 0x87, 0x2a1: 0x88, 0x2a2: 0x89, 0x2a3: 0x8a, 0x2a4: 0x8b, 0x2a5: 0x8c, 0x2a6: 0x8d, 0x2a7: 0x87,
- 0x2a8: 0x88, 0x2a9: 0x89, 0x2aa: 0x8a, 0x2ab: 0x8b, 0x2ac: 0x8c, 0x2ad: 0x8d, 0x2ae: 0x87, 0x2af: 0x88,
- 0x2b0: 0x89, 0x2b1: 0x8a, 0x2b2: 0x8b, 0x2b3: 0x8c, 0x2b4: 0x8d, 0x2b5: 0x87, 0x2b6: 0x88, 0x2b7: 0x89,
- 0x2b8: 0x8a, 0x2b9: 0x8b, 0x2ba: 0x8c, 0x2bb: 0x8d, 0x2bc: 0x87, 0x2bd: 0x88, 0x2be: 0x89, 0x2bf: 0x8a,
- // Block 0xb, offset 0x2c0
- 0x2c0: 0x8b, 0x2c1: 0x8c, 0x2c2: 0x8d, 0x2c3: 0x87, 0x2c4: 0x88, 0x2c5: 0x89, 0x2c6: 0x8a, 0x2c7: 0x8b,
- 0x2c8: 0x8c, 0x2c9: 0x8d, 0x2ca: 0x87, 0x2cb: 0x88, 0x2cc: 0x89, 0x2cd: 0x8a, 0x2ce: 0x8b, 0x2cf: 0x8c,
- 0x2d0: 0x8d, 0x2d1: 0x87, 0x2d2: 0x88, 0x2d3: 0x89, 0x2d4: 0x8a, 0x2d5: 0x8b, 0x2d6: 0x8c, 0x2d7: 0x8d,
- 0x2d8: 0x87, 0x2d9: 0x88, 0x2da: 0x89, 0x2db: 0x8a, 0x2dc: 0x8b, 0x2dd: 0x8c, 0x2de: 0x8e,
- // Block 0xc, offset 0x300
- 0x324: 0x1b, 0x325: 0x1c, 0x326: 0x1d, 0x327: 0x1e,
- 0x328: 0x1f, 0x329: 0x20, 0x32a: 0x21, 0x32b: 0x22, 0x32c: 0x8f, 0x32d: 0x90, 0x32e: 0x91,
- 0x331: 0x92, 0x332: 0x93, 0x333: 0x94, 0x334: 0x95,
- 0x338: 0x96, 0x339: 0x97, 0x33a: 0x98, 0x33b: 0x99, 0x33e: 0x9a, 0x33f: 0x9b,
- // Block 0xd, offset 0x340
- 0x347: 0x9c,
- 0x34b: 0x9d, 0x34d: 0x9e,
- 0x368: 0x9f, 0x36b: 0xa0,
- // Block 0xe, offset 0x380
- 0x381: 0xa1, 0x382: 0xa2, 0x384: 0xa3, 0x385: 0x82, 0x387: 0xa4,
- 0x388: 0xa5, 0x38b: 0xa6, 0x38c: 0x3e, 0x38d: 0xa7,
- 0x391: 0xa8, 0x392: 0xa9, 0x393: 0xaa, 0x396: 0xab, 0x397: 0xac,
- 0x398: 0x73, 0x39a: 0xad, 0x39c: 0xae,
- 0x3b0: 0x73,
- // Block 0xf, offset 0x3c0
- 0x3eb: 0xaf, 0x3ec: 0xb0,
- // Block 0x10, offset 0x400
- 0x432: 0xb1,
- // Block 0x11, offset 0x440
- 0x445: 0xb2, 0x446: 0xb3, 0x447: 0xb4,
- 0x449: 0xb5,
- // Block 0x12, offset 0x480
- 0x480: 0xb6,
- 0x4a3: 0xb7, 0x4a5: 0xb8,
- // Block 0x13, offset 0x4c0
- 0x4c8: 0xb9,
- // Block 0x14, offset 0x500
- 0x520: 0x23, 0x521: 0x24, 0x522: 0x25, 0x523: 0x26, 0x524: 0x27, 0x525: 0x28, 0x526: 0x29, 0x527: 0x2a,
- 0x528: 0x2b,
- // Block 0x15, offset 0x540
- 0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d,
- 0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11,
- 0x56f: 0x12,
-}
-
-// nfcSparseOffset: 142 entries, 284 bytes
-var nfcSparseOffset = []uint16{0x0, 0x5, 0x9, 0xb, 0xd, 0x18, 0x28, 0x2a, 0x2f, 0x3a, 0x49, 0x56, 0x5e, 0x62, 0x67, 0x69, 0x7a, 0x82, 0x89, 0x8c, 0x93, 0x97, 0x9b, 0x9d, 0x9f, 0xa8, 0xac, 0xb3, 0xb8, 0xbb, 0xc5, 0xc7, 0xce, 0xd6, 0xd9, 0xdb, 0xdd, 0xdf, 0xe4, 0xf5, 0x101, 0x103, 0x109, 0x10b, 0x10d, 0x10f, 0x111, 0x113, 0x115, 0x118, 0x11b, 0x11d, 0x120, 0x123, 0x127, 0x12c, 0x135, 0x137, 0x13a, 0x13c, 0x147, 0x157, 0x15b, 0x169, 0x16c, 0x172, 0x178, 0x183, 0x187, 0x189, 0x18b, 0x18d, 0x18f, 0x191, 0x197, 0x19b, 0x19d, 0x19f, 0x1a7, 0x1ab, 0x1ae, 0x1b0, 0x1b2, 0x1b4, 0x1b7, 0x1b9, 0x1bb, 0x1bd, 0x1bf, 0x1c5, 0x1c8, 0x1ca, 0x1d1, 0x1d7, 0x1dd, 0x1e5, 0x1eb, 0x1f1, 0x1f7, 0x1fb, 0x209, 0x212, 0x215, 0x218, 0x21a, 0x21d, 0x21f, 0x223, 0x228, 0x22a, 0x22c, 0x231, 0x237, 0x239, 0x23b, 0x23d, 0x243, 0x246, 0x249, 0x251, 0x258, 0x25b, 0x25e, 0x260, 0x268, 0x26b, 0x272, 0x275, 0x27b, 0x27d, 0x280, 0x282, 0x284, 0x286, 0x288, 0x295, 0x29f, 0x2a1, 0x2a3, 0x2a9, 0x2ab, 0x2ae}
-
-// nfcSparseValues: 688 entries, 2752 bytes
-var nfcSparseValues = [688]valueRange{
- // Block 0x0, offset 0x0
- {value: 0x0000, lo: 0x04},
- {value: 0xa100, lo: 0xa8, hi: 0xa8},
- {value: 0x8100, lo: 0xaf, hi: 0xaf},
- {value: 0x8100, lo: 0xb4, hi: 0xb4},
- {value: 0x8100, lo: 0xb8, hi: 0xb8},
- // Block 0x1, offset 0x5
- {value: 0x0091, lo: 0x03},
- {value: 0x4778, lo: 0xa0, hi: 0xa1},
- {value: 0x47aa, lo: 0xaf, hi: 0xb0},
- {value: 0xa000, lo: 0xb7, hi: 0xb7},
- // Block 0x2, offset 0x9
- {value: 0x0000, lo: 0x01},
- {value: 0xa000, lo: 0x92, hi: 0x92},
- // Block 0x3, offset 0xb
- {value: 0x0000, lo: 0x01},
- {value: 0x8100, lo: 0x98, hi: 0x9d},
- // Block 0x4, offset 0xd
- {value: 0x0006, lo: 0x0a},
- {value: 0xa000, lo: 0x81, hi: 0x81},
- {value: 0xa000, lo: 0x85, hi: 0x85},
- {value: 0xa000, lo: 0x89, hi: 0x89},
- {value: 0x48d6, lo: 0x8a, hi: 0x8a},
- {value: 0x48f4, lo: 0x8b, hi: 0x8b},
- {value: 0x36c7, lo: 0x8c, hi: 0x8c},
- {value: 0x36df, lo: 0x8d, hi: 0x8d},
- {value: 0x490c, lo: 0x8e, hi: 0x8e},
- {value: 0xa000, lo: 0x92, hi: 0x92},
- {value: 0x36fd, lo: 0x93, hi: 0x94},
- // Block 0x5, offset 0x18
- {value: 0x0000, lo: 0x0f},
- {value: 0xa000, lo: 0x83, hi: 0x83},
- {value: 0xa000, lo: 0x87, hi: 0x87},
- {value: 0xa000, lo: 0x8b, hi: 0x8b},
- {value: 0xa000, lo: 0x8d, hi: 0x8d},
- {value: 0x37a5, lo: 0x90, hi: 0x90},
- {value: 0x37b1, lo: 0x91, hi: 0x91},
- {value: 0x379f, lo: 0x93, hi: 0x93},
- {value: 0xa000, lo: 0x96, hi: 0x96},
- {value: 0x3817, lo: 0x97, hi: 0x97},
- {value: 0x37e1, lo: 0x9c, hi: 0x9c},
- {value: 0x37c9, lo: 0x9d, hi: 0x9d},
- {value: 0x37f3, lo: 0x9e, hi: 0x9e},
- {value: 0xa000, lo: 0xb4, hi: 0xb5},
- {value: 0x381d, lo: 0xb6, hi: 0xb6},
- {value: 0x3823, lo: 0xb7, hi: 0xb7},
- // Block 0x6, offset 0x28
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0x83, hi: 0x87},
- // Block 0x7, offset 0x2a
- {value: 0x0001, lo: 0x04},
- {value: 0x8113, lo: 0x81, hi: 0x82},
- {value: 0x8132, lo: 0x84, hi: 0x84},
- {value: 0x812d, lo: 0x85, hi: 0x85},
- {value: 0x810d, lo: 0x87, hi: 0x87},
- // Block 0x8, offset 0x2f
- {value: 0x0000, lo: 0x0a},
- {value: 0x8132, lo: 0x90, hi: 0x97},
- {value: 0x8119, lo: 0x98, hi: 0x98},
- {value: 0x811a, lo: 0x99, hi: 0x99},
- {value: 0x811b, lo: 0x9a, hi: 0x9a},
- {value: 0x3841, lo: 0xa2, hi: 0xa2},
- {value: 0x3847, lo: 0xa3, hi: 0xa3},
- {value: 0x3853, lo: 0xa4, hi: 0xa4},
- {value: 0x384d, lo: 0xa5, hi: 0xa5},
- {value: 0x3859, lo: 0xa6, hi: 0xa6},
- {value: 0xa000, lo: 0xa7, hi: 0xa7},
- // Block 0x9, offset 0x3a
- {value: 0x0000, lo: 0x0e},
- {value: 0x386b, lo: 0x80, hi: 0x80},
- {value: 0xa000, lo: 0x81, hi: 0x81},
- {value: 0x385f, lo: 0x82, hi: 0x82},
- {value: 0xa000, lo: 0x92, hi: 0x92},
- {value: 0x3865, lo: 0x93, hi: 0x93},
- {value: 0xa000, lo: 0x95, hi: 0x95},
- {value: 0x8132, lo: 0x96, hi: 0x9c},
- {value: 0x8132, lo: 0x9f, hi: 0xa2},
- {value: 0x812d, lo: 0xa3, hi: 0xa3},
- {value: 0x8132, lo: 0xa4, hi: 0xa4},
- {value: 0x8132, lo: 0xa7, hi: 0xa8},
- {value: 0x812d, lo: 0xaa, hi: 0xaa},
- {value: 0x8132, lo: 0xab, hi: 0xac},
- {value: 0x812d, lo: 0xad, hi: 0xad},
- // Block 0xa, offset 0x49
- {value: 0x0000, lo: 0x0c},
- {value: 0x811f, lo: 0x91, hi: 0x91},
- {value: 0x8132, lo: 0xb0, hi: 0xb0},
- {value: 0x812d, lo: 0xb1, hi: 0xb1},
- {value: 0x8132, lo: 0xb2, hi: 0xb3},
- {value: 0x812d, lo: 0xb4, hi: 0xb4},
- {value: 0x8132, lo: 0xb5, hi: 0xb6},
- {value: 0x812d, lo: 0xb7, hi: 0xb9},
- {value: 0x8132, lo: 0xba, hi: 0xba},
- {value: 0x812d, lo: 0xbb, hi: 0xbc},
- {value: 0x8132, lo: 0xbd, hi: 0xbd},
- {value: 0x812d, lo: 0xbe, hi: 0xbe},
- {value: 0x8132, lo: 0xbf, hi: 0xbf},
- // Block 0xb, offset 0x56
- {value: 0x0005, lo: 0x07},
- {value: 0x8132, lo: 0x80, hi: 0x80},
- {value: 0x8132, lo: 0x81, hi: 0x81},
- {value: 0x812d, lo: 0x82, hi: 0x83},
- {value: 0x812d, lo: 0x84, hi: 0x85},
- {value: 0x812d, lo: 0x86, hi: 0x87},
- {value: 0x812d, lo: 0x88, hi: 0x89},
- {value: 0x8132, lo: 0x8a, hi: 0x8a},
- // Block 0xc, offset 0x5e
- {value: 0x0000, lo: 0x03},
- {value: 0x8132, lo: 0xab, hi: 0xb1},
- {value: 0x812d, lo: 0xb2, hi: 0xb2},
- {value: 0x8132, lo: 0xb3, hi: 0xb3},
- // Block 0xd, offset 0x62
- {value: 0x0000, lo: 0x04},
- {value: 0x8132, lo: 0x96, hi: 0x99},
- {value: 0x8132, lo: 0x9b, hi: 0xa3},
- {value: 0x8132, lo: 0xa5, hi: 0xa7},
- {value: 0x8132, lo: 0xa9, hi: 0xad},
- // Block 0xe, offset 0x67
- {value: 0x0000, lo: 0x01},
- {value: 0x812d, lo: 0x99, hi: 0x9b},
- // Block 0xf, offset 0x69
- {value: 0x0000, lo: 0x10},
- {value: 0x8132, lo: 0x94, hi: 0xa1},
- {value: 0x812d, lo: 0xa3, hi: 0xa3},
- {value: 0x8132, lo: 0xa4, hi: 0xa5},
- {value: 0x812d, lo: 0xa6, hi: 0xa6},
- {value: 0x8132, lo: 0xa7, hi: 0xa8},
- {value: 0x812d, lo: 0xa9, hi: 0xa9},
- {value: 0x8132, lo: 0xaa, hi: 0xac},
- {value: 0x812d, lo: 0xad, hi: 0xaf},
- {value: 0x8116, lo: 0xb0, hi: 0xb0},
- {value: 0x8117, lo: 0xb1, hi: 0xb1},
- {value: 0x8118, lo: 0xb2, hi: 0xb2},
- {value: 0x8132, lo: 0xb3, hi: 0xb5},
- {value: 0x812d, lo: 0xb6, hi: 0xb6},
- {value: 0x8132, lo: 0xb7, hi: 0xb8},
- {value: 0x812d, lo: 0xb9, hi: 0xba},
- {value: 0x8132, lo: 0xbb, hi: 0xbf},
- // Block 0x10, offset 0x7a
- {value: 0x0000, lo: 0x07},
- {value: 0xa000, lo: 0xa8, hi: 0xa8},
- {value: 0x3ed8, lo: 0xa9, hi: 0xa9},
- {value: 0xa000, lo: 0xb0, hi: 0xb0},
- {value: 0x3ee0, lo: 0xb1, hi: 0xb1},
- {value: 0xa000, lo: 0xb3, hi: 0xb3},
- {value: 0x3ee8, lo: 0xb4, hi: 0xb4},
- {value: 0x9902, lo: 0xbc, hi: 0xbc},
- // Block 0x11, offset 0x82
- {value: 0x0008, lo: 0x06},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x8132, lo: 0x91, hi: 0x91},
- {value: 0x812d, lo: 0x92, hi: 0x92},
- {value: 0x8132, lo: 0x93, hi: 0x93},
- {value: 0x8132, lo: 0x94, hi: 0x94},
- {value: 0x45b2, lo: 0x98, hi: 0x9f},
- // Block 0x12, offset 0x89
- {value: 0x0000, lo: 0x02},
- {value: 0x8102, lo: 0xbc, hi: 0xbc},
- {value: 0x9900, lo: 0xbe, hi: 0xbe},
- // Block 0x13, offset 0x8c
- {value: 0x0008, lo: 0x06},
- {value: 0xa000, lo: 0x87, hi: 0x87},
- {value: 0x2c9e, lo: 0x8b, hi: 0x8c},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x9900, lo: 0x97, hi: 0x97},
- {value: 0x45f2, lo: 0x9c, hi: 0x9d},
- {value: 0x4602, lo: 0x9f, hi: 0x9f},
- // Block 0x14, offset 0x93
- {value: 0x0000, lo: 0x03},
- {value: 0x462a, lo: 0xb3, hi: 0xb3},
- {value: 0x4632, lo: 0xb6, hi: 0xb6},
- {value: 0x8102, lo: 0xbc, hi: 0xbc},
- // Block 0x15, offset 0x97
- {value: 0x0008, lo: 0x03},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x460a, lo: 0x99, hi: 0x9b},
- {value: 0x4622, lo: 0x9e, hi: 0x9e},
- // Block 0x16, offset 0x9b
- {value: 0x0000, lo: 0x01},
- {value: 0x8102, lo: 0xbc, hi: 0xbc},
- // Block 0x17, offset 0x9d
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- // Block 0x18, offset 0x9f
- {value: 0x0000, lo: 0x08},
- {value: 0xa000, lo: 0x87, hi: 0x87},
- {value: 0x2cb6, lo: 0x88, hi: 0x88},
- {value: 0x2cae, lo: 0x8b, hi: 0x8b},
- {value: 0x2cbe, lo: 0x8c, hi: 0x8c},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x9900, lo: 0x96, hi: 0x97},
- {value: 0x463a, lo: 0x9c, hi: 0x9c},
- {value: 0x4642, lo: 0x9d, hi: 0x9d},
- // Block 0x19, offset 0xa8
- {value: 0x0000, lo: 0x03},
- {value: 0xa000, lo: 0x92, hi: 0x92},
- {value: 0x2cc6, lo: 0x94, hi: 0x94},
- {value: 0x9900, lo: 0xbe, hi: 0xbe},
- // Block 0x1a, offset 0xac
- {value: 0x0000, lo: 0x06},
- {value: 0xa000, lo: 0x86, hi: 0x87},
- {value: 0x2cce, lo: 0x8a, hi: 0x8a},
- {value: 0x2cde, lo: 0x8b, hi: 0x8b},
- {value: 0x2cd6, lo: 0x8c, hi: 0x8c},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x9900, lo: 0x97, hi: 0x97},
- // Block 0x1b, offset 0xb3
- {value: 0x1801, lo: 0x04},
- {value: 0xa000, lo: 0x86, hi: 0x86},
- {value: 0x3ef0, lo: 0x88, hi: 0x88},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x8120, lo: 0x95, hi: 0x96},
- // Block 0x1c, offset 0xb8
- {value: 0x0000, lo: 0x02},
- {value: 0x8102, lo: 0xbc, hi: 0xbc},
- {value: 0xa000, lo: 0xbf, hi: 0xbf},
- // Block 0x1d, offset 0xbb
- {value: 0x0000, lo: 0x09},
- {value: 0x2ce6, lo: 0x80, hi: 0x80},
- {value: 0x9900, lo: 0x82, hi: 0x82},
- {value: 0xa000, lo: 0x86, hi: 0x86},
- {value: 0x2cee, lo: 0x87, hi: 0x87},
- {value: 0x2cf6, lo: 0x88, hi: 0x88},
- {value: 0x2f50, lo: 0x8a, hi: 0x8a},
- {value: 0x2dd8, lo: 0x8b, hi: 0x8b},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x9900, lo: 0x95, hi: 0x96},
- // Block 0x1e, offset 0xc5
- {value: 0x0000, lo: 0x01},
- {value: 0x9900, lo: 0xbe, hi: 0xbe},
- // Block 0x1f, offset 0xc7
- {value: 0x0000, lo: 0x06},
- {value: 0xa000, lo: 0x86, hi: 0x87},
- {value: 0x2cfe, lo: 0x8a, hi: 0x8a},
- {value: 0x2d0e, lo: 0x8b, hi: 0x8b},
- {value: 0x2d06, lo: 0x8c, hi: 0x8c},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x9900, lo: 0x97, hi: 0x97},
- // Block 0x20, offset 0xce
- {value: 0x6bea, lo: 0x07},
- {value: 0x9904, lo: 0x8a, hi: 0x8a},
- {value: 0x9900, lo: 0x8f, hi: 0x8f},
- {value: 0xa000, lo: 0x99, hi: 0x99},
- {value: 0x3ef8, lo: 0x9a, hi: 0x9a},
- {value: 0x2f58, lo: 0x9c, hi: 0x9c},
- {value: 0x2de3, lo: 0x9d, hi: 0x9d},
- {value: 0x2d16, lo: 0x9e, hi: 0x9f},
- // Block 0x21, offset 0xd6
- {value: 0x0000, lo: 0x02},
- {value: 0x8122, lo: 0xb8, hi: 0xb9},
- {value: 0x8104, lo: 0xba, hi: 0xba},
- // Block 0x22, offset 0xd9
- {value: 0x0000, lo: 0x01},
- {value: 0x8123, lo: 0x88, hi: 0x8b},
- // Block 0x23, offset 0xdb
- {value: 0x0000, lo: 0x01},
- {value: 0x8124, lo: 0xb8, hi: 0xb9},
- // Block 0x24, offset 0xdd
- {value: 0x0000, lo: 0x01},
- {value: 0x8125, lo: 0x88, hi: 0x8b},
- // Block 0x25, offset 0xdf
- {value: 0x0000, lo: 0x04},
- {value: 0x812d, lo: 0x98, hi: 0x99},
- {value: 0x812d, lo: 0xb5, hi: 0xb5},
- {value: 0x812d, lo: 0xb7, hi: 0xb7},
- {value: 0x812b, lo: 0xb9, hi: 0xb9},
- // Block 0x26, offset 0xe4
- {value: 0x0000, lo: 0x10},
- {value: 0x2644, lo: 0x83, hi: 0x83},
- {value: 0x264b, lo: 0x8d, hi: 0x8d},
- {value: 0x2652, lo: 0x92, hi: 0x92},
- {value: 0x2659, lo: 0x97, hi: 0x97},
- {value: 0x2660, lo: 0x9c, hi: 0x9c},
- {value: 0x263d, lo: 0xa9, hi: 0xa9},
- {value: 0x8126, lo: 0xb1, hi: 0xb1},
- {value: 0x8127, lo: 0xb2, hi: 0xb2},
- {value: 0x4a66, lo: 0xb3, hi: 0xb3},
- {value: 0x8128, lo: 0xb4, hi: 0xb4},
- {value: 0x4a6f, lo: 0xb5, hi: 0xb5},
- {value: 0x464a, lo: 0xb6, hi: 0xb6},
- {value: 0x8200, lo: 0xb7, hi: 0xb7},
- {value: 0x4652, lo: 0xb8, hi: 0xb8},
- {value: 0x8200, lo: 0xb9, hi: 0xb9},
- {value: 0x8127, lo: 0xba, hi: 0xbd},
- // Block 0x27, offset 0xf5
- {value: 0x0000, lo: 0x0b},
- {value: 0x8127, lo: 0x80, hi: 0x80},
- {value: 0x4a78, lo: 0x81, hi: 0x81},
- {value: 0x8132, lo: 0x82, hi: 0x83},
- {value: 0x8104, lo: 0x84, hi: 0x84},
- {value: 0x8132, lo: 0x86, hi: 0x87},
- {value: 0x266e, lo: 0x93, hi: 0x93},
- {value: 0x2675, lo: 0x9d, hi: 0x9d},
- {value: 0x267c, lo: 0xa2, hi: 0xa2},
- {value: 0x2683, lo: 0xa7, hi: 0xa7},
- {value: 0x268a, lo: 0xac, hi: 0xac},
- {value: 0x2667, lo: 0xb9, hi: 0xb9},
- // Block 0x28, offset 0x101
- {value: 0x0000, lo: 0x01},
- {value: 0x812d, lo: 0x86, hi: 0x86},
- // Block 0x29, offset 0x103
- {value: 0x0000, lo: 0x05},
- {value: 0xa000, lo: 0xa5, hi: 0xa5},
- {value: 0x2d1e, lo: 0xa6, hi: 0xa6},
- {value: 0x9900, lo: 0xae, hi: 0xae},
- {value: 0x8102, lo: 0xb7, hi: 0xb7},
- {value: 0x8104, lo: 0xb9, hi: 0xba},
- // Block 0x2a, offset 0x109
- {value: 0x0000, lo: 0x01},
- {value: 0x812d, lo: 0x8d, hi: 0x8d},
- // Block 0x2b, offset 0x10b
- {value: 0x0000, lo: 0x01},
- {value: 0xa000, lo: 0x80, hi: 0x92},
- // Block 0x2c, offset 0x10d
- {value: 0x0000, lo: 0x01},
- {value: 0xb900, lo: 0xa1, hi: 0xb5},
- // Block 0x2d, offset 0x10f
- {value: 0x0000, lo: 0x01},
- {value: 0x9900, lo: 0xa8, hi: 0xbf},
- // Block 0x2e, offset 0x111
- {value: 0x0000, lo: 0x01},
- {value: 0x9900, lo: 0x80, hi: 0x82},
- // Block 0x2f, offset 0x113
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0x9d, hi: 0x9f},
- // Block 0x30, offset 0x115
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0x94, hi: 0x94},
- {value: 0x8104, lo: 0xb4, hi: 0xb4},
- // Block 0x31, offset 0x118
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0x92, hi: 0x92},
- {value: 0x8132, lo: 0x9d, hi: 0x9d},
- // Block 0x32, offset 0x11b
- {value: 0x0000, lo: 0x01},
- {value: 0x8131, lo: 0xa9, hi: 0xa9},
- // Block 0x33, offset 0x11d
- {value: 0x0004, lo: 0x02},
- {value: 0x812e, lo: 0xb9, hi: 0xba},
- {value: 0x812d, lo: 0xbb, hi: 0xbb},
- // Block 0x34, offset 0x120
- {value: 0x0000, lo: 0x02},
- {value: 0x8132, lo: 0x97, hi: 0x97},
- {value: 0x812d, lo: 0x98, hi: 0x98},
- // Block 0x35, offset 0x123
- {value: 0x0000, lo: 0x03},
- {value: 0x8104, lo: 0xa0, hi: 0xa0},
- {value: 0x8132, lo: 0xb5, hi: 0xbc},
- {value: 0x812d, lo: 0xbf, hi: 0xbf},
- // Block 0x36, offset 0x127
- {value: 0x0000, lo: 0x04},
- {value: 0x8132, lo: 0xb0, hi: 0xb4},
- {value: 0x812d, lo: 0xb5, hi: 0xba},
- {value: 0x8132, lo: 0xbb, hi: 0xbc},
- {value: 0x812d, lo: 0xbd, hi: 0xbd},
- // Block 0x37, offset 0x12c
- {value: 0x0000, lo: 0x08},
- {value: 0x2d66, lo: 0x80, hi: 0x80},
- {value: 0x2d6e, lo: 0x81, hi: 0x81},
- {value: 0xa000, lo: 0x82, hi: 0x82},
- {value: 0x2d76, lo: 0x83, hi: 0x83},
- {value: 0x8104, lo: 0x84, hi: 0x84},
- {value: 0x8132, lo: 0xab, hi: 0xab},
- {value: 0x812d, lo: 0xac, hi: 0xac},
- {value: 0x8132, lo: 0xad, hi: 0xb3},
- // Block 0x38, offset 0x135
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0xaa, hi: 0xab},
- // Block 0x39, offset 0x137
- {value: 0x0000, lo: 0x02},
- {value: 0x8102, lo: 0xa6, hi: 0xa6},
- {value: 0x8104, lo: 0xb2, hi: 0xb3},
- // Block 0x3a, offset 0x13a
- {value: 0x0000, lo: 0x01},
- {value: 0x8102, lo: 0xb7, hi: 0xb7},
- // Block 0x3b, offset 0x13c
- {value: 0x0000, lo: 0x0a},
- {value: 0x8132, lo: 0x90, hi: 0x92},
- {value: 0x8101, lo: 0x94, hi: 0x94},
- {value: 0x812d, lo: 0x95, hi: 0x99},
- {value: 0x8132, lo: 0x9a, hi: 0x9b},
- {value: 0x812d, lo: 0x9c, hi: 0x9f},
- {value: 0x8132, lo: 0xa0, hi: 0xa0},
- {value: 0x8101, lo: 0xa2, hi: 0xa8},
- {value: 0x812d, lo: 0xad, hi: 0xad},
- {value: 0x8132, lo: 0xb4, hi: 0xb4},
- {value: 0x8132, lo: 0xb8, hi: 0xb9},
- // Block 0x3c, offset 0x147
- {value: 0x0000, lo: 0x0f},
- {value: 0x8132, lo: 0x80, hi: 0x81},
- {value: 0x812d, lo: 0x82, hi: 0x82},
- {value: 0x8132, lo: 0x83, hi: 0x89},
- {value: 0x812d, lo: 0x8a, hi: 0x8a},
- {value: 0x8132, lo: 0x8b, hi: 0x8c},
- {value: 0x8135, lo: 0x8d, hi: 0x8d},
- {value: 0x812a, lo: 0x8e, hi: 0x8e},
- {value: 0x812d, lo: 0x8f, hi: 0x8f},
- {value: 0x8129, lo: 0x90, hi: 0x90},
- {value: 0x8132, lo: 0x91, hi: 0xb5},
- {value: 0x8132, lo: 0xbb, hi: 0xbb},
- {value: 0x8134, lo: 0xbc, hi: 0xbc},
- {value: 0x812d, lo: 0xbd, hi: 0xbd},
- {value: 0x8132, lo: 0xbe, hi: 0xbe},
- {value: 0x812d, lo: 0xbf, hi: 0xbf},
- // Block 0x3d, offset 0x157
- {value: 0x0004, lo: 0x03},
- {value: 0x0433, lo: 0x80, hi: 0x81},
- {value: 0x8100, lo: 0x97, hi: 0x97},
- {value: 0x8100, lo: 0xbe, hi: 0xbe},
- // Block 0x3e, offset 0x15b
- {value: 0x0000, lo: 0x0d},
- {value: 0x8132, lo: 0x90, hi: 0x91},
- {value: 0x8101, lo: 0x92, hi: 0x93},
- {value: 0x8132, lo: 0x94, hi: 0x97},
- {value: 0x8101, lo: 0x98, hi: 0x9a},
- {value: 0x8132, lo: 0x9b, hi: 0x9c},
- {value: 0x8132, lo: 0xa1, hi: 0xa1},
- {value: 0x8101, lo: 0xa5, hi: 0xa6},
- {value: 0x8132, lo: 0xa7, hi: 0xa7},
- {value: 0x812d, lo: 0xa8, hi: 0xa8},
- {value: 0x8132, lo: 0xa9, hi: 0xa9},
- {value: 0x8101, lo: 0xaa, hi: 0xab},
- {value: 0x812d, lo: 0xac, hi: 0xaf},
- {value: 0x8132, lo: 0xb0, hi: 0xb0},
- // Block 0x3f, offset 0x169
- {value: 0x427b, lo: 0x02},
- {value: 0x01b8, lo: 0xa6, hi: 0xa6},
- {value: 0x0057, lo: 0xaa, hi: 0xab},
- // Block 0x40, offset 0x16c
- {value: 0x0007, lo: 0x05},
- {value: 0xa000, lo: 0x90, hi: 0x90},
- {value: 0xa000, lo: 0x92, hi: 0x92},
- {value: 0xa000, lo: 0x94, hi: 0x94},
- {value: 0x3bb9, lo: 0x9a, hi: 0x9b},
- {value: 0x3bc7, lo: 0xae, hi: 0xae},
- // Block 0x41, offset 0x172
- {value: 0x000e, lo: 0x05},
- {value: 0x3bce, lo: 0x8d, hi: 0x8e},
- {value: 0x3bd5, lo: 0x8f, hi: 0x8f},
- {value: 0xa000, lo: 0x90, hi: 0x90},
- {value: 0xa000, lo: 0x92, hi: 0x92},
- {value: 0xa000, lo: 0x94, hi: 0x94},
- // Block 0x42, offset 0x178
- {value: 0x6408, lo: 0x0a},
- {value: 0xa000, lo: 0x83, hi: 0x83},
- {value: 0x3be3, lo: 0x84, hi: 0x84},
- {value: 0xa000, lo: 0x88, hi: 0x88},
- {value: 0x3bea, lo: 0x89, hi: 0x89},
- {value: 0xa000, lo: 0x8b, hi: 0x8b},
- {value: 0x3bf1, lo: 0x8c, hi: 0x8c},
- {value: 0xa000, lo: 0xa3, hi: 0xa3},
- {value: 0x3bf8, lo: 0xa4, hi: 0xa5},
- {value: 0x3bff, lo: 0xa6, hi: 0xa6},
- {value: 0xa000, lo: 0xbc, hi: 0xbc},
- // Block 0x43, offset 0x183
- {value: 0x0007, lo: 0x03},
- {value: 0x3c68, lo: 0xa0, hi: 0xa1},
- {value: 0x3c92, lo: 0xa2, hi: 0xa3},
- {value: 0x3cbc, lo: 0xaa, hi: 0xad},
- // Block 0x44, offset 0x187
- {value: 0x0004, lo: 0x01},
- {value: 0x048b, lo: 0xa9, hi: 0xaa},
- // Block 0x45, offset 0x189
- {value: 0x0000, lo: 0x01},
- {value: 0x4573, lo: 0x9c, hi: 0x9c},
- // Block 0x46, offset 0x18b
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0xaf, hi: 0xb1},
- // Block 0x47, offset 0x18d
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0xbf, hi: 0xbf},
- // Block 0x48, offset 0x18f
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0xa0, hi: 0xbf},
- // Block 0x49, offset 0x191
- {value: 0x0000, lo: 0x05},
- {value: 0x812c, lo: 0xaa, hi: 0xaa},
- {value: 0x8131, lo: 0xab, hi: 0xab},
- {value: 0x8133, lo: 0xac, hi: 0xac},
- {value: 0x812e, lo: 0xad, hi: 0xad},
- {value: 0x812f, lo: 0xae, hi: 0xaf},
- // Block 0x4a, offset 0x197
- {value: 0x0000, lo: 0x03},
- {value: 0x4a81, lo: 0xb3, hi: 0xb3},
- {value: 0x4a81, lo: 0xb5, hi: 0xb6},
- {value: 0x4a81, lo: 0xba, hi: 0xbf},
- // Block 0x4b, offset 0x19b
- {value: 0x0000, lo: 0x01},
- {value: 0x4a81, lo: 0x8f, hi: 0xa3},
- // Block 0x4c, offset 0x19d
- {value: 0x0000, lo: 0x01},
- {value: 0x8100, lo: 0xae, hi: 0xbe},
- // Block 0x4d, offset 0x19f
- {value: 0x0000, lo: 0x07},
- {value: 0x8100, lo: 0x84, hi: 0x84},
- {value: 0x8100, lo: 0x87, hi: 0x87},
- {value: 0x8100, lo: 0x90, hi: 0x90},
- {value: 0x8100, lo: 0x9e, hi: 0x9e},
- {value: 0x8100, lo: 0xa1, hi: 0xa1},
- {value: 0x8100, lo: 0xb2, hi: 0xb2},
- {value: 0x8100, lo: 0xbb, hi: 0xbb},
- // Block 0x4e, offset 0x1a7
- {value: 0x0000, lo: 0x03},
- {value: 0x8100, lo: 0x80, hi: 0x80},
- {value: 0x8100, lo: 0x8b, hi: 0x8b},
- {value: 0x8100, lo: 0x8e, hi: 0x8e},
- // Block 0x4f, offset 0x1ab
- {value: 0x0000, lo: 0x02},
- {value: 0x8132, lo: 0xaf, hi: 0xaf},
- {value: 0x8132, lo: 0xb4, hi: 0xbd},
- // Block 0x50, offset 0x1ae
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0x9e, hi: 0x9f},
- // Block 0x51, offset 0x1b0
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0xb0, hi: 0xb1},
- // Block 0x52, offset 0x1b2
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0x86, hi: 0x86},
- // Block 0x53, offset 0x1b4
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0x84, hi: 0x84},
- {value: 0x8132, lo: 0xa0, hi: 0xb1},
- // Block 0x54, offset 0x1b7
- {value: 0x0000, lo: 0x01},
- {value: 0x812d, lo: 0xab, hi: 0xad},
- // Block 0x55, offset 0x1b9
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0x93, hi: 0x93},
- // Block 0x56, offset 0x1bb
- {value: 0x0000, lo: 0x01},
- {value: 0x8102, lo: 0xb3, hi: 0xb3},
- // Block 0x57, offset 0x1bd
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0x80, hi: 0x80},
- // Block 0x58, offset 0x1bf
- {value: 0x0000, lo: 0x05},
- {value: 0x8132, lo: 0xb0, hi: 0xb0},
- {value: 0x8132, lo: 0xb2, hi: 0xb3},
- {value: 0x812d, lo: 0xb4, hi: 0xb4},
- {value: 0x8132, lo: 0xb7, hi: 0xb8},
- {value: 0x8132, lo: 0xbe, hi: 0xbf},
- // Block 0x59, offset 0x1c5
- {value: 0x0000, lo: 0x02},
- {value: 0x8132, lo: 0x81, hi: 0x81},
- {value: 0x8104, lo: 0xb6, hi: 0xb6},
- // Block 0x5a, offset 0x1c8
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0xad, hi: 0xad},
- // Block 0x5b, offset 0x1ca
- {value: 0x0000, lo: 0x06},
- {value: 0xe500, lo: 0x80, hi: 0x80},
- {value: 0xc600, lo: 0x81, hi: 0x9b},
- {value: 0xe500, lo: 0x9c, hi: 0x9c},
- {value: 0xc600, lo: 0x9d, hi: 0xb7},
- {value: 0xe500, lo: 0xb8, hi: 0xb8},
- {value: 0xc600, lo: 0xb9, hi: 0xbf},
- // Block 0x5c, offset 0x1d1
- {value: 0x0000, lo: 0x05},
- {value: 0xc600, lo: 0x80, hi: 0x93},
- {value: 0xe500, lo: 0x94, hi: 0x94},
- {value: 0xc600, lo: 0x95, hi: 0xaf},
- {value: 0xe500, lo: 0xb0, hi: 0xb0},
- {value: 0xc600, lo: 0xb1, hi: 0xbf},
- // Block 0x5d, offset 0x1d7
- {value: 0x0000, lo: 0x05},
- {value: 0xc600, lo: 0x80, hi: 0x8b},
- {value: 0xe500, lo: 0x8c, hi: 0x8c},
- {value: 0xc600, lo: 0x8d, hi: 0xa7},
- {value: 0xe500, lo: 0xa8, hi: 0xa8},
- {value: 0xc600, lo: 0xa9, hi: 0xbf},
- // Block 0x5e, offset 0x1dd
- {value: 0x0000, lo: 0x07},
- {value: 0xc600, lo: 0x80, hi: 0x83},
- {value: 0xe500, lo: 0x84, hi: 0x84},
- {value: 0xc600, lo: 0x85, hi: 0x9f},
- {value: 0xe500, lo: 0xa0, hi: 0xa0},
- {value: 0xc600, lo: 0xa1, hi: 0xbb},
- {value: 0xe500, lo: 0xbc, hi: 0xbc},
- {value: 0xc600, lo: 0xbd, hi: 0xbf},
- // Block 0x5f, offset 0x1e5
- {value: 0x0000, lo: 0x05},
- {value: 0xc600, lo: 0x80, hi: 0x97},
- {value: 0xe500, lo: 0x98, hi: 0x98},
- {value: 0xc600, lo: 0x99, hi: 0xb3},
- {value: 0xe500, lo: 0xb4, hi: 0xb4},
- {value: 0xc600, lo: 0xb5, hi: 0xbf},
- // Block 0x60, offset 0x1eb
- {value: 0x0000, lo: 0x05},
- {value: 0xc600, lo: 0x80, hi: 0x8f},
- {value: 0xe500, lo: 0x90, hi: 0x90},
- {value: 0xc600, lo: 0x91, hi: 0xab},
- {value: 0xe500, lo: 0xac, hi: 0xac},
- {value: 0xc600, lo: 0xad, hi: 0xbf},
- // Block 0x61, offset 0x1f1
- {value: 0x0000, lo: 0x05},
- {value: 0xc600, lo: 0x80, hi: 0x87},
- {value: 0xe500, lo: 0x88, hi: 0x88},
- {value: 0xc600, lo: 0x89, hi: 0xa3},
- {value: 0xe500, lo: 0xa4, hi: 0xa4},
- {value: 0xc600, lo: 0xa5, hi: 0xbf},
- // Block 0x62, offset 0x1f7
- {value: 0x0000, lo: 0x03},
- {value: 0xc600, lo: 0x80, hi: 0x87},
- {value: 0xe500, lo: 0x88, hi: 0x88},
- {value: 0xc600, lo: 0x89, hi: 0xa3},
- // Block 0x63, offset 0x1fb
- {value: 0x0006, lo: 0x0d},
- {value: 0x4426, lo: 0x9d, hi: 0x9d},
- {value: 0x8115, lo: 0x9e, hi: 0x9e},
- {value: 0x4498, lo: 0x9f, hi: 0x9f},
- {value: 0x4486, lo: 0xaa, hi: 0xab},
- {value: 0x458a, lo: 0xac, hi: 0xac},
- {value: 0x4592, lo: 0xad, hi: 0xad},
- {value: 0x43de, lo: 0xae, hi: 0xb1},
- {value: 0x43fc, lo: 0xb2, hi: 0xb4},
- {value: 0x4414, lo: 0xb5, hi: 0xb6},
- {value: 0x4420, lo: 0xb8, hi: 0xb8},
- {value: 0x442c, lo: 0xb9, hi: 0xbb},
- {value: 0x4444, lo: 0xbc, hi: 0xbc},
- {value: 0x444a, lo: 0xbe, hi: 0xbe},
- // Block 0x64, offset 0x209
- {value: 0x0006, lo: 0x08},
- {value: 0x4450, lo: 0x80, hi: 0x81},
- {value: 0x445c, lo: 0x83, hi: 0x84},
- {value: 0x446e, lo: 0x86, hi: 0x89},
- {value: 0x4492, lo: 0x8a, hi: 0x8a},
- {value: 0x440e, lo: 0x8b, hi: 0x8b},
- {value: 0x43f6, lo: 0x8c, hi: 0x8c},
- {value: 0x443e, lo: 0x8d, hi: 0x8d},
- {value: 0x4468, lo: 0x8e, hi: 0x8e},
- // Block 0x65, offset 0x212
- {value: 0x0000, lo: 0x02},
- {value: 0x8100, lo: 0xa4, hi: 0xa5},
- {value: 0x8100, lo: 0xb0, hi: 0xb1},
- // Block 0x66, offset 0x215
- {value: 0x0000, lo: 0x02},
- {value: 0x8100, lo: 0x9b, hi: 0x9d},
- {value: 0x8200, lo: 0x9e, hi: 0xa3},
- // Block 0x67, offset 0x218
- {value: 0x0000, lo: 0x01},
- {value: 0x8100, lo: 0x90, hi: 0x90},
- // Block 0x68, offset 0x21a
- {value: 0x0000, lo: 0x02},
- {value: 0x8100, lo: 0x99, hi: 0x99},
- {value: 0x8200, lo: 0xb2, hi: 0xb4},
- // Block 0x69, offset 0x21d
- {value: 0x0000, lo: 0x01},
- {value: 0x8100, lo: 0xbc, hi: 0xbd},
- // Block 0x6a, offset 0x21f
- {value: 0x0000, lo: 0x03},
- {value: 0x8132, lo: 0xa0, hi: 0xa6},
- {value: 0x812d, lo: 0xa7, hi: 0xad},
- {value: 0x8132, lo: 0xae, hi: 0xaf},
- // Block 0x6b, offset 0x223
- {value: 0x0000, lo: 0x04},
- {value: 0x8100, lo: 0x89, hi: 0x8c},
- {value: 0x8100, lo: 0xb0, hi: 0xb2},
- {value: 0x8100, lo: 0xb4, hi: 0xb4},
- {value: 0x8100, lo: 0xb6, hi: 0xbf},
- // Block 0x6c, offset 0x228
- {value: 0x0000, lo: 0x01},
- {value: 0x8100, lo: 0x81, hi: 0x8c},
- // Block 0x6d, offset 0x22a
- {value: 0x0000, lo: 0x01},
- {value: 0x8100, lo: 0xb5, hi: 0xba},
- // Block 0x6e, offset 0x22c
- {value: 0x0000, lo: 0x04},
- {value: 0x4a81, lo: 0x9e, hi: 0x9f},
- {value: 0x4a81, lo: 0xa3, hi: 0xa3},
- {value: 0x4a81, lo: 0xa5, hi: 0xa6},
- {value: 0x4a81, lo: 0xaa, hi: 0xaf},
- // Block 0x6f, offset 0x231
- {value: 0x0000, lo: 0x05},
- {value: 0x4a81, lo: 0x82, hi: 0x87},
- {value: 0x4a81, lo: 0x8a, hi: 0x8f},
- {value: 0x4a81, lo: 0x92, hi: 0x97},
- {value: 0x4a81, lo: 0x9a, hi: 0x9c},
- {value: 0x8100, lo: 0xa3, hi: 0xa3},
- // Block 0x70, offset 0x237
- {value: 0x0000, lo: 0x01},
- {value: 0x812d, lo: 0xbd, hi: 0xbd},
- // Block 0x71, offset 0x239
- {value: 0x0000, lo: 0x01},
- {value: 0x812d, lo: 0xa0, hi: 0xa0},
- // Block 0x72, offset 0x23b
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0xb6, hi: 0xba},
- // Block 0x73, offset 0x23d
- {value: 0x002c, lo: 0x05},
- {value: 0x812d, lo: 0x8d, hi: 0x8d},
- {value: 0x8132, lo: 0x8f, hi: 0x8f},
- {value: 0x8132, lo: 0xb8, hi: 0xb8},
- {value: 0x8101, lo: 0xb9, hi: 0xba},
- {value: 0x8104, lo: 0xbf, hi: 0xbf},
- // Block 0x74, offset 0x243
- {value: 0x0000, lo: 0x02},
- {value: 0x8132, lo: 0xa5, hi: 0xa5},
- {value: 0x812d, lo: 0xa6, hi: 0xa6},
- // Block 0x75, offset 0x246
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0x86, hi: 0x86},
- {value: 0x8104, lo: 0xbf, hi: 0xbf},
- // Block 0x76, offset 0x249
- {value: 0x17fe, lo: 0x07},
- {value: 0xa000, lo: 0x99, hi: 0x99},
- {value: 0x4238, lo: 0x9a, hi: 0x9a},
- {value: 0xa000, lo: 0x9b, hi: 0x9b},
- {value: 0x4242, lo: 0x9c, hi: 0x9c},
- {value: 0xa000, lo: 0xa5, hi: 0xa5},
- {value: 0x424c, lo: 0xab, hi: 0xab},
- {value: 0x8104, lo: 0xb9, hi: 0xba},
- // Block 0x77, offset 0x251
- {value: 0x0000, lo: 0x06},
- {value: 0x8132, lo: 0x80, hi: 0x82},
- {value: 0x9900, lo: 0xa7, hi: 0xa7},
- {value: 0x2d7e, lo: 0xae, hi: 0xae},
- {value: 0x2d88, lo: 0xaf, hi: 0xaf},
- {value: 0xa000, lo: 0xb1, hi: 0xb2},
- {value: 0x8104, lo: 0xb3, hi: 0xb4},
- // Block 0x78, offset 0x258
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0x80, hi: 0x80},
- {value: 0x8102, lo: 0x8a, hi: 0x8a},
- // Block 0x79, offset 0x25b
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0xb5, hi: 0xb5},
- {value: 0x8102, lo: 0xb6, hi: 0xb6},
- // Block 0x7a, offset 0x25e
- {value: 0x0002, lo: 0x01},
- {value: 0x8102, lo: 0xa9, hi: 0xaa},
- // Block 0x7b, offset 0x260
- {value: 0x0000, lo: 0x07},
- {value: 0xa000, lo: 0x87, hi: 0x87},
- {value: 0x2d92, lo: 0x8b, hi: 0x8b},
- {value: 0x2d9c, lo: 0x8c, hi: 0x8c},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x9900, lo: 0x97, hi: 0x97},
- {value: 0x8132, lo: 0xa6, hi: 0xac},
- {value: 0x8132, lo: 0xb0, hi: 0xb4},
- // Block 0x7c, offset 0x268
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0x82, hi: 0x82},
- {value: 0x8102, lo: 0x86, hi: 0x86},
- // Block 0x7d, offset 0x26b
- {value: 0x6b5a, lo: 0x06},
- {value: 0x9900, lo: 0xb0, hi: 0xb0},
- {value: 0xa000, lo: 0xb9, hi: 0xb9},
- {value: 0x9900, lo: 0xba, hi: 0xba},
- {value: 0x2db0, lo: 0xbb, hi: 0xbb},
- {value: 0x2da6, lo: 0xbc, hi: 0xbd},
- {value: 0x2dba, lo: 0xbe, hi: 0xbe},
- // Block 0x7e, offset 0x272
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0x82, hi: 0x82},
- {value: 0x8102, lo: 0x83, hi: 0x83},
- // Block 0x7f, offset 0x275
- {value: 0x0000, lo: 0x05},
- {value: 0x9900, lo: 0xaf, hi: 0xaf},
- {value: 0xa000, lo: 0xb8, hi: 0xb9},
- {value: 0x2dc4, lo: 0xba, hi: 0xba},
- {value: 0x2dce, lo: 0xbb, hi: 0xbb},
- {value: 0x8104, lo: 0xbf, hi: 0xbf},
- // Block 0x80, offset 0x27b
- {value: 0x0000, lo: 0x01},
- {value: 0x8102, lo: 0x80, hi: 0x80},
- // Block 0x81, offset 0x27d
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0xb6, hi: 0xb6},
- {value: 0x8102, lo: 0xb7, hi: 0xb7},
- // Block 0x82, offset 0x280
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0xab, hi: 0xab},
- // Block 0x83, offset 0x282
- {value: 0x0000, lo: 0x01},
- {value: 0x8101, lo: 0xb0, hi: 0xb4},
- // Block 0x84, offset 0x284
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0xb0, hi: 0xb6},
- // Block 0x85, offset 0x286
- {value: 0x0000, lo: 0x01},
- {value: 0x8101, lo: 0x9e, hi: 0x9e},
- // Block 0x86, offset 0x288
- {value: 0x0000, lo: 0x0c},
- {value: 0x4662, lo: 0x9e, hi: 0x9e},
- {value: 0x466c, lo: 0x9f, hi: 0x9f},
- {value: 0x46a0, lo: 0xa0, hi: 0xa0},
- {value: 0x46ae, lo: 0xa1, hi: 0xa1},
- {value: 0x46bc, lo: 0xa2, hi: 0xa2},
- {value: 0x46ca, lo: 0xa3, hi: 0xa3},
- {value: 0x46d8, lo: 0xa4, hi: 0xa4},
- {value: 0x812b, lo: 0xa5, hi: 0xa6},
- {value: 0x8101, lo: 0xa7, hi: 0xa9},
- {value: 0x8130, lo: 0xad, hi: 0xad},
- {value: 0x812b, lo: 0xae, hi: 0xb2},
- {value: 0x812d, lo: 0xbb, hi: 0xbf},
- // Block 0x87, offset 0x295
- {value: 0x0000, lo: 0x09},
- {value: 0x812d, lo: 0x80, hi: 0x82},
- {value: 0x8132, lo: 0x85, hi: 0x89},
- {value: 0x812d, lo: 0x8a, hi: 0x8b},
- {value: 0x8132, lo: 0xaa, hi: 0xad},
- {value: 0x4676, lo: 0xbb, hi: 0xbb},
- {value: 0x4680, lo: 0xbc, hi: 0xbc},
- {value: 0x46e6, lo: 0xbd, hi: 0xbd},
- {value: 0x4702, lo: 0xbe, hi: 0xbe},
- {value: 0x46f4, lo: 0xbf, hi: 0xbf},
- // Block 0x88, offset 0x29f
- {value: 0x0000, lo: 0x01},
- {value: 0x4710, lo: 0x80, hi: 0x80},
- // Block 0x89, offset 0x2a1
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0x82, hi: 0x84},
- // Block 0x8a, offset 0x2a3
- {value: 0x0000, lo: 0x05},
- {value: 0x8132, lo: 0x80, hi: 0x86},
- {value: 0x8132, lo: 0x88, hi: 0x98},
- {value: 0x8132, lo: 0x9b, hi: 0xa1},
- {value: 0x8132, lo: 0xa3, hi: 0xa4},
- {value: 0x8132, lo: 0xa6, hi: 0xaa},
- // Block 0x8b, offset 0x2a9
- {value: 0x0000, lo: 0x01},
- {value: 0x812d, lo: 0x90, hi: 0x96},
- // Block 0x8c, offset 0x2ab
- {value: 0x0000, lo: 0x02},
- {value: 0x8132, lo: 0x84, hi: 0x89},
- {value: 0x8102, lo: 0x8a, hi: 0x8a},
- // Block 0x8d, offset 0x2ae
- {value: 0x0000, lo: 0x01},
- {value: 0x8100, lo: 0x93, hi: 0x93},
-}
-
-// 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 *nfkcTrie) lookup(s []byte) (v uint16, sz int) {
- c0 := s[0]
- switch {
- case c0 < 0x80: // is ASCII
- return nfkcValues[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 := nfkcIndex[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 := nfkcIndex[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 = nfkcIndex[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 := nfkcIndex[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 = nfkcIndex[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 = nfkcIndex[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 *nfkcTrie) lookupUnsafe(s []byte) uint16 {
- c0 := s[0]
- if c0 < 0x80 { // is ASCII
- return nfkcValues[c0]
- }
- i := nfkcIndex[c0]
- if c0 < 0xE0 { // 2-byte UTF-8
- return t.lookupValue(uint32(i), s[1])
- }
- i = nfkcIndex[uint32(i)<<6+uint32(s[1])]
- if c0 < 0xF0 { // 3-byte UTF-8
- return t.lookupValue(uint32(i), s[2])
- }
- i = nfkcIndex[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 *nfkcTrie) lookupString(s string) (v uint16, sz int) {
- c0 := s[0]
- switch {
- case c0 < 0x80: // is ASCII
- return nfkcValues[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 := nfkcIndex[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 := nfkcIndex[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 = nfkcIndex[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 := nfkcIndex[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 = nfkcIndex[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 = nfkcIndex[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 *nfkcTrie) lookupStringUnsafe(s string) uint16 {
- c0 := s[0]
- if c0 < 0x80 { // is ASCII
- return nfkcValues[c0]
- }
- i := nfkcIndex[c0]
- if c0 < 0xE0 { // 2-byte UTF-8
- return t.lookupValue(uint32(i), s[1])
- }
- i = nfkcIndex[uint32(i)<<6+uint32(s[1])]
- if c0 < 0xF0 { // 3-byte UTF-8
- return t.lookupValue(uint32(i), s[2])
- }
- i = nfkcIndex[uint32(i)<<6+uint32(s[2])]
- if c0 < 0xF8 { // 4-byte UTF-8
- return t.lookupValue(uint32(i), s[3])
- }
- return 0
-}
-
-// nfkcTrie. Total size: 16994 bytes (16.60 KiB). Checksum: 146925fc21092b17.
-type nfkcTrie struct{}
-
-func newNfkcTrie(i int) *nfkcTrie {
- return &nfkcTrie{}
-}
-
-// lookupValue determines the type of block n and looks up the value for b.
-func (t *nfkcTrie) lookupValue(n uint32, b byte) uint16 {
- switch {
- case n < 90:
- return uint16(nfkcValues[n<<6+uint32(b)])
- default:
- n -= 90
- return uint16(nfkcSparse.lookup(n, b))
- }
-}
-
-// nfkcValues: 92 blocks, 5888 entries, 11776 bytes
-// The third block is the zero block.
-var nfkcValues = [5888]uint16{
- // Block 0x0, offset 0x0
- 0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000,
- // Block 0x1, offset 0x40
- 0x41: 0xa000, 0x42: 0xa000, 0x43: 0xa000, 0x44: 0xa000, 0x45: 0xa000,
- 0x46: 0xa000, 0x47: 0xa000, 0x48: 0xa000, 0x49: 0xa000, 0x4a: 0xa000, 0x4b: 0xa000,
- 0x4c: 0xa000, 0x4d: 0xa000, 0x4e: 0xa000, 0x4f: 0xa000, 0x50: 0xa000,
- 0x52: 0xa000, 0x53: 0xa000, 0x54: 0xa000, 0x55: 0xa000, 0x56: 0xa000, 0x57: 0xa000,
- 0x58: 0xa000, 0x59: 0xa000, 0x5a: 0xa000,
- 0x61: 0xa000, 0x62: 0xa000, 0x63: 0xa000,
- 0x64: 0xa000, 0x65: 0xa000, 0x66: 0xa000, 0x67: 0xa000, 0x68: 0xa000, 0x69: 0xa000,
- 0x6a: 0xa000, 0x6b: 0xa000, 0x6c: 0xa000, 0x6d: 0xa000, 0x6e: 0xa000, 0x6f: 0xa000,
- 0x70: 0xa000, 0x72: 0xa000, 0x73: 0xa000, 0x74: 0xa000, 0x75: 0xa000,
- 0x76: 0xa000, 0x77: 0xa000, 0x78: 0xa000, 0x79: 0xa000, 0x7a: 0xa000,
- // Block 0x2, offset 0x80
- // Block 0x3, offset 0xc0
- 0xc0: 0x2f6f, 0xc1: 0x2f74, 0xc2: 0x471e, 0xc3: 0x2f79, 0xc4: 0x472d, 0xc5: 0x4732,
- 0xc6: 0xa000, 0xc7: 0x473c, 0xc8: 0x2fe2, 0xc9: 0x2fe7, 0xca: 0x4741, 0xcb: 0x2ffb,
- 0xcc: 0x306e, 0xcd: 0x3073, 0xce: 0x3078, 0xcf: 0x4755, 0xd1: 0x3104,
- 0xd2: 0x3127, 0xd3: 0x312c, 0xd4: 0x475f, 0xd5: 0x4764, 0xd6: 0x4773,
- 0xd8: 0xa000, 0xd9: 0x31b3, 0xda: 0x31b8, 0xdb: 0x31bd, 0xdc: 0x47a5, 0xdd: 0x3235,
- 0xe0: 0x327b, 0xe1: 0x3280, 0xe2: 0x47af, 0xe3: 0x3285,
- 0xe4: 0x47be, 0xe5: 0x47c3, 0xe6: 0xa000, 0xe7: 0x47cd, 0xe8: 0x32ee, 0xe9: 0x32f3,
- 0xea: 0x47d2, 0xeb: 0x3307, 0xec: 0x337f, 0xed: 0x3384, 0xee: 0x3389, 0xef: 0x47e6,
- 0xf1: 0x3415, 0xf2: 0x3438, 0xf3: 0x343d, 0xf4: 0x47f0, 0xf5: 0x47f5,
- 0xf6: 0x4804, 0xf8: 0xa000, 0xf9: 0x34c9, 0xfa: 0x34ce, 0xfb: 0x34d3,
- 0xfc: 0x4836, 0xfd: 0x3550, 0xff: 0x3569,
- // Block 0x4, offset 0x100
- 0x100: 0x2f7e, 0x101: 0x328a, 0x102: 0x4723, 0x103: 0x47b4, 0x104: 0x2f9c, 0x105: 0x32a8,
- 0x106: 0x2fb0, 0x107: 0x32bc, 0x108: 0x2fb5, 0x109: 0x32c1, 0x10a: 0x2fba, 0x10b: 0x32c6,
- 0x10c: 0x2fbf, 0x10d: 0x32cb, 0x10e: 0x2fc9, 0x10f: 0x32d5,
- 0x112: 0x4746, 0x113: 0x47d7, 0x114: 0x2ff1, 0x115: 0x32fd, 0x116: 0x2ff6, 0x117: 0x3302,
- 0x118: 0x3014, 0x119: 0x3320, 0x11a: 0x3005, 0x11b: 0x3311, 0x11c: 0x302d, 0x11d: 0x3339,
- 0x11e: 0x3037, 0x11f: 0x3343, 0x120: 0x303c, 0x121: 0x3348, 0x122: 0x3046, 0x123: 0x3352,
- 0x124: 0x304b, 0x125: 0x3357, 0x128: 0x307d, 0x129: 0x338e,
- 0x12a: 0x3082, 0x12b: 0x3393, 0x12c: 0x3087, 0x12d: 0x3398, 0x12e: 0x30aa, 0x12f: 0x33b6,
- 0x130: 0x308c, 0x132: 0x195d, 0x133: 0x19e7, 0x134: 0x30b4, 0x135: 0x33c0,
- 0x136: 0x30c8, 0x137: 0x33d9, 0x139: 0x30d2, 0x13a: 0x33e3, 0x13b: 0x30dc,
- 0x13c: 0x33ed, 0x13d: 0x30d7, 0x13e: 0x33e8, 0x13f: 0x1bac,
- // Block 0x5, offset 0x140
- 0x140: 0x1c34, 0x143: 0x30ff, 0x144: 0x3410, 0x145: 0x3118,
- 0x146: 0x3429, 0x147: 0x310e, 0x148: 0x341f, 0x149: 0x1c5c,
- 0x14c: 0x4769, 0x14d: 0x47fa, 0x14e: 0x3131, 0x14f: 0x3442, 0x150: 0x313b, 0x151: 0x344c,
- 0x154: 0x3159, 0x155: 0x346a, 0x156: 0x3172, 0x157: 0x3483,
- 0x158: 0x3163, 0x159: 0x3474, 0x15a: 0x478c, 0x15b: 0x481d, 0x15c: 0x317c, 0x15d: 0x348d,
- 0x15e: 0x318b, 0x15f: 0x349c, 0x160: 0x4791, 0x161: 0x4822, 0x162: 0x31a4, 0x163: 0x34ba,
- 0x164: 0x3195, 0x165: 0x34ab, 0x168: 0x479b, 0x169: 0x482c,
- 0x16a: 0x47a0, 0x16b: 0x4831, 0x16c: 0x31c2, 0x16d: 0x34d8, 0x16e: 0x31cc, 0x16f: 0x34e2,
- 0x170: 0x31d1, 0x171: 0x34e7, 0x172: 0x31ef, 0x173: 0x3505, 0x174: 0x3212, 0x175: 0x3528,
- 0x176: 0x323a, 0x177: 0x3555, 0x178: 0x324e, 0x179: 0x325d, 0x17a: 0x357d, 0x17b: 0x3267,
- 0x17c: 0x3587, 0x17d: 0x326c, 0x17e: 0x358c, 0x17f: 0x00a7,
- // Block 0x6, offset 0x180
- 0x184: 0x2dee, 0x185: 0x2df4,
- 0x186: 0x2dfa, 0x187: 0x1972, 0x188: 0x1975, 0x189: 0x1a08, 0x18a: 0x1987, 0x18b: 0x198a,
- 0x18c: 0x1a3e, 0x18d: 0x2f88, 0x18e: 0x3294, 0x18f: 0x3096, 0x190: 0x33a2, 0x191: 0x3140,
- 0x192: 0x3451, 0x193: 0x31d6, 0x194: 0x34ec, 0x195: 0x39cf, 0x196: 0x3b5e, 0x197: 0x39c8,
- 0x198: 0x3b57, 0x199: 0x39d6, 0x19a: 0x3b65, 0x19b: 0x39c1, 0x19c: 0x3b50,
- 0x19e: 0x38b0, 0x19f: 0x3a3f, 0x1a0: 0x38a9, 0x1a1: 0x3a38, 0x1a2: 0x35b3, 0x1a3: 0x35c5,
- 0x1a6: 0x3041, 0x1a7: 0x334d, 0x1a8: 0x30be, 0x1a9: 0x33cf,
- 0x1aa: 0x4782, 0x1ab: 0x4813, 0x1ac: 0x3990, 0x1ad: 0x3b1f, 0x1ae: 0x35d7, 0x1af: 0x35dd,
- 0x1b0: 0x33c5, 0x1b1: 0x1942, 0x1b2: 0x1945, 0x1b3: 0x19cf, 0x1b4: 0x3028, 0x1b5: 0x3334,
- 0x1b8: 0x30fa, 0x1b9: 0x340b, 0x1ba: 0x38b7, 0x1bb: 0x3a46,
- 0x1bc: 0x35ad, 0x1bd: 0x35bf, 0x1be: 0x35b9, 0x1bf: 0x35cb,
- // Block 0x7, offset 0x1c0
- 0x1c0: 0x2f8d, 0x1c1: 0x3299, 0x1c2: 0x2f92, 0x1c3: 0x329e, 0x1c4: 0x300a, 0x1c5: 0x3316,
- 0x1c6: 0x300f, 0x1c7: 0x331b, 0x1c8: 0x309b, 0x1c9: 0x33a7, 0x1ca: 0x30a0, 0x1cb: 0x33ac,
- 0x1cc: 0x3145, 0x1cd: 0x3456, 0x1ce: 0x314a, 0x1cf: 0x345b, 0x1d0: 0x3168, 0x1d1: 0x3479,
- 0x1d2: 0x316d, 0x1d3: 0x347e, 0x1d4: 0x31db, 0x1d5: 0x34f1, 0x1d6: 0x31e0, 0x1d7: 0x34f6,
- 0x1d8: 0x3186, 0x1d9: 0x3497, 0x1da: 0x319f, 0x1db: 0x34b5,
- 0x1de: 0x305a, 0x1df: 0x3366,
- 0x1e6: 0x4728, 0x1e7: 0x47b9, 0x1e8: 0x4750, 0x1e9: 0x47e1,
- 0x1ea: 0x395f, 0x1eb: 0x3aee, 0x1ec: 0x393c, 0x1ed: 0x3acb, 0x1ee: 0x476e, 0x1ef: 0x47ff,
- 0x1f0: 0x3958, 0x1f1: 0x3ae7, 0x1f2: 0x3244, 0x1f3: 0x355f,
- // Block 0x8, offset 0x200
- 0x200: 0x9932, 0x201: 0x9932, 0x202: 0x9932, 0x203: 0x9932, 0x204: 0x9932, 0x205: 0x8132,
- 0x206: 0x9932, 0x207: 0x9932, 0x208: 0x9932, 0x209: 0x9932, 0x20a: 0x9932, 0x20b: 0x9932,
- 0x20c: 0x9932, 0x20d: 0x8132, 0x20e: 0x8132, 0x20f: 0x9932, 0x210: 0x8132, 0x211: 0x9932,
- 0x212: 0x8132, 0x213: 0x9932, 0x214: 0x9932, 0x215: 0x8133, 0x216: 0x812d, 0x217: 0x812d,
- 0x218: 0x812d, 0x219: 0x812d, 0x21a: 0x8133, 0x21b: 0x992b, 0x21c: 0x812d, 0x21d: 0x812d,
- 0x21e: 0x812d, 0x21f: 0x812d, 0x220: 0x812d, 0x221: 0x8129, 0x222: 0x8129, 0x223: 0x992d,
- 0x224: 0x992d, 0x225: 0x992d, 0x226: 0x992d, 0x227: 0x9929, 0x228: 0x9929, 0x229: 0x812d,
- 0x22a: 0x812d, 0x22b: 0x812d, 0x22c: 0x812d, 0x22d: 0x992d, 0x22e: 0x992d, 0x22f: 0x812d,
- 0x230: 0x992d, 0x231: 0x992d, 0x232: 0x812d, 0x233: 0x812d, 0x234: 0x8101, 0x235: 0x8101,
- 0x236: 0x8101, 0x237: 0x8101, 0x238: 0x9901, 0x239: 0x812d, 0x23a: 0x812d, 0x23b: 0x812d,
- 0x23c: 0x812d, 0x23d: 0x8132, 0x23e: 0x8132, 0x23f: 0x8132,
- // Block 0x9, offset 0x240
- 0x240: 0x4a44, 0x241: 0x4a49, 0x242: 0x9932, 0x243: 0x4a4e, 0x244: 0x4a53, 0x245: 0x9936,
- 0x246: 0x8132, 0x247: 0x812d, 0x248: 0x812d, 0x249: 0x812d, 0x24a: 0x8132, 0x24b: 0x8132,
- 0x24c: 0x8132, 0x24d: 0x812d, 0x24e: 0x812d, 0x250: 0x8132, 0x251: 0x8132,
- 0x252: 0x8132, 0x253: 0x812d, 0x254: 0x812d, 0x255: 0x812d, 0x256: 0x812d, 0x257: 0x8132,
- 0x258: 0x8133, 0x259: 0x812d, 0x25a: 0x812d, 0x25b: 0x8132, 0x25c: 0x8134, 0x25d: 0x8135,
- 0x25e: 0x8135, 0x25f: 0x8134, 0x260: 0x8135, 0x261: 0x8135, 0x262: 0x8134, 0x263: 0x8132,
- 0x264: 0x8132, 0x265: 0x8132, 0x266: 0x8132, 0x267: 0x8132, 0x268: 0x8132, 0x269: 0x8132,
- 0x26a: 0x8132, 0x26b: 0x8132, 0x26c: 0x8132, 0x26d: 0x8132, 0x26e: 0x8132, 0x26f: 0x8132,
- 0x274: 0x0170,
- 0x27a: 0x42a5,
- 0x27e: 0x0037,
- // Block 0xa, offset 0x280
- 0x284: 0x425a, 0x285: 0x4511,
- 0x286: 0x35e9, 0x287: 0x00ce, 0x288: 0x3607, 0x289: 0x3613, 0x28a: 0x3625,
- 0x28c: 0x3643, 0x28e: 0x3655, 0x28f: 0x3673, 0x290: 0x3e08, 0x291: 0xa000,
- 0x295: 0xa000, 0x297: 0xa000,
- 0x299: 0xa000,
- 0x29f: 0xa000, 0x2a1: 0xa000,
- 0x2a5: 0xa000, 0x2a9: 0xa000,
- 0x2aa: 0x3637, 0x2ab: 0x3667, 0x2ac: 0x4894, 0x2ad: 0x3697, 0x2ae: 0x48be, 0x2af: 0x36a9,
- 0x2b0: 0x3e70, 0x2b1: 0xa000, 0x2b5: 0xa000,
- 0x2b7: 0xa000, 0x2b9: 0xa000,
- 0x2bf: 0xa000,
- // Block 0xb, offset 0x2c0
- 0x2c1: 0xa000, 0x2c5: 0xa000,
- 0x2c9: 0xa000, 0x2ca: 0x48d6, 0x2cb: 0x48f4,
- 0x2cc: 0x36c7, 0x2cd: 0x36df, 0x2ce: 0x490c, 0x2d0: 0x01be, 0x2d1: 0x01d0,
- 0x2d2: 0x01ac, 0x2d3: 0x43a2, 0x2d4: 0x43a8, 0x2d5: 0x01fa, 0x2d6: 0x01e8,
- 0x2f0: 0x01d6, 0x2f1: 0x01eb, 0x2f2: 0x01ee, 0x2f4: 0x0188, 0x2f5: 0x01c7,
- 0x2f9: 0x01a6,
- // Block 0xc, offset 0x300
- 0x300: 0x3721, 0x301: 0x372d, 0x303: 0x371b,
- 0x306: 0xa000, 0x307: 0x3709,
- 0x30c: 0x375d, 0x30d: 0x3745, 0x30e: 0x376f, 0x310: 0xa000,
- 0x313: 0xa000, 0x315: 0xa000, 0x316: 0xa000, 0x317: 0xa000,
- 0x318: 0xa000, 0x319: 0x3751, 0x31a: 0xa000,
- 0x31e: 0xa000, 0x323: 0xa000,
- 0x327: 0xa000,
- 0x32b: 0xa000, 0x32d: 0xa000,
- 0x330: 0xa000, 0x333: 0xa000, 0x335: 0xa000,
- 0x336: 0xa000, 0x337: 0xa000, 0x338: 0xa000, 0x339: 0x37d5, 0x33a: 0xa000,
- 0x33e: 0xa000,
- // Block 0xd, offset 0x340
- 0x341: 0x3733, 0x342: 0x37b7,
- 0x350: 0x370f, 0x351: 0x3793,
- 0x352: 0x3715, 0x353: 0x3799, 0x356: 0x3727, 0x357: 0x37ab,
- 0x358: 0xa000, 0x359: 0xa000, 0x35a: 0x3829, 0x35b: 0x382f, 0x35c: 0x3739, 0x35d: 0x37bd,
- 0x35e: 0x373f, 0x35f: 0x37c3, 0x362: 0x374b, 0x363: 0x37cf,
- 0x364: 0x3757, 0x365: 0x37db, 0x366: 0x3763, 0x367: 0x37e7, 0x368: 0xa000, 0x369: 0xa000,
- 0x36a: 0x3835, 0x36b: 0x383b, 0x36c: 0x378d, 0x36d: 0x3811, 0x36e: 0x3769, 0x36f: 0x37ed,
- 0x370: 0x3775, 0x371: 0x37f9, 0x372: 0x377b, 0x373: 0x37ff, 0x374: 0x3781, 0x375: 0x3805,
- 0x378: 0x3787, 0x379: 0x380b,
- // Block 0xe, offset 0x380
- 0x387: 0x1d61,
- 0x391: 0x812d,
- 0x392: 0x8132, 0x393: 0x8132, 0x394: 0x8132, 0x395: 0x8132, 0x396: 0x812d, 0x397: 0x8132,
- 0x398: 0x8132, 0x399: 0x8132, 0x39a: 0x812e, 0x39b: 0x812d, 0x39c: 0x8132, 0x39d: 0x8132,
- 0x39e: 0x8132, 0x39f: 0x8132, 0x3a0: 0x8132, 0x3a1: 0x8132, 0x3a2: 0x812d, 0x3a3: 0x812d,
- 0x3a4: 0x812d, 0x3a5: 0x812d, 0x3a6: 0x812d, 0x3a7: 0x812d, 0x3a8: 0x8132, 0x3a9: 0x8132,
- 0x3aa: 0x812d, 0x3ab: 0x8132, 0x3ac: 0x8132, 0x3ad: 0x812e, 0x3ae: 0x8131, 0x3af: 0x8132,
- 0x3b0: 0x8105, 0x3b1: 0x8106, 0x3b2: 0x8107, 0x3b3: 0x8108, 0x3b4: 0x8109, 0x3b5: 0x810a,
- 0x3b6: 0x810b, 0x3b7: 0x810c, 0x3b8: 0x810d, 0x3b9: 0x810e, 0x3ba: 0x810e, 0x3bb: 0x810f,
- 0x3bc: 0x8110, 0x3bd: 0x8111, 0x3bf: 0x8112,
- // Block 0xf, offset 0x3c0
- 0x3c8: 0xa000, 0x3ca: 0xa000, 0x3cb: 0x8116,
- 0x3cc: 0x8117, 0x3cd: 0x8118, 0x3ce: 0x8119, 0x3cf: 0x811a, 0x3d0: 0x811b, 0x3d1: 0x811c,
- 0x3d2: 0x811d, 0x3d3: 0x9932, 0x3d4: 0x9932, 0x3d5: 0x992d, 0x3d6: 0x812d, 0x3d7: 0x8132,
- 0x3d8: 0x8132, 0x3d9: 0x8132, 0x3da: 0x8132, 0x3db: 0x8132, 0x3dc: 0x812d, 0x3dd: 0x8132,
- 0x3de: 0x8132, 0x3df: 0x812d,
- 0x3f0: 0x811e, 0x3f5: 0x1d84,
- 0x3f6: 0x2013, 0x3f7: 0x204f, 0x3f8: 0x204a,
- // Block 0x10, offset 0x400
- 0x405: 0xa000,
- 0x406: 0x2d26, 0x407: 0xa000, 0x408: 0x2d2e, 0x409: 0xa000, 0x40a: 0x2d36, 0x40b: 0xa000,
- 0x40c: 0x2d3e, 0x40d: 0xa000, 0x40e: 0x2d46, 0x411: 0xa000,
- 0x412: 0x2d4e,
- 0x434: 0x8102, 0x435: 0x9900,
- 0x43a: 0xa000, 0x43b: 0x2d56,
- 0x43c: 0xa000, 0x43d: 0x2d5e, 0x43e: 0xa000, 0x43f: 0xa000,
- // Block 0x11, offset 0x440
- 0x440: 0x0069, 0x441: 0x006b, 0x442: 0x006f, 0x443: 0x0083, 0x444: 0x00f5, 0x445: 0x00f8,
- 0x446: 0x0413, 0x447: 0x0085, 0x448: 0x0089, 0x449: 0x008b, 0x44a: 0x0104, 0x44b: 0x0107,
- 0x44c: 0x010a, 0x44d: 0x008f, 0x44f: 0x0097, 0x450: 0x009b, 0x451: 0x00e0,
- 0x452: 0x009f, 0x453: 0x00fe, 0x454: 0x0417, 0x455: 0x041b, 0x456: 0x00a1, 0x457: 0x00a9,
- 0x458: 0x00ab, 0x459: 0x0423, 0x45a: 0x012b, 0x45b: 0x00ad, 0x45c: 0x0427, 0x45d: 0x01be,
- 0x45e: 0x01c1, 0x45f: 0x01c4, 0x460: 0x01fa, 0x461: 0x01fd, 0x462: 0x0093, 0x463: 0x00a5,
- 0x464: 0x00ab, 0x465: 0x00ad, 0x466: 0x01be, 0x467: 0x01c1, 0x468: 0x01eb, 0x469: 0x01fa,
- 0x46a: 0x01fd,
- 0x478: 0x020c,
- // Block 0x12, offset 0x480
- 0x49b: 0x00fb, 0x49c: 0x0087, 0x49d: 0x0101,
- 0x49e: 0x00d4, 0x49f: 0x010a, 0x4a0: 0x008d, 0x4a1: 0x010d, 0x4a2: 0x0110, 0x4a3: 0x0116,
- 0x4a4: 0x011c, 0x4a5: 0x011f, 0x4a6: 0x0122, 0x4a7: 0x042b, 0x4a8: 0x016a, 0x4a9: 0x0128,
- 0x4aa: 0x042f, 0x4ab: 0x016d, 0x4ac: 0x0131, 0x4ad: 0x012e, 0x4ae: 0x0134, 0x4af: 0x0137,
- 0x4b0: 0x013a, 0x4b1: 0x013d, 0x4b2: 0x0140, 0x4b3: 0x014c, 0x4b4: 0x014f, 0x4b5: 0x00ec,
- 0x4b6: 0x0152, 0x4b7: 0x0155, 0x4b8: 0x041f, 0x4b9: 0x0158, 0x4ba: 0x015b, 0x4bb: 0x00b5,
- 0x4bc: 0x015e, 0x4bd: 0x0161, 0x4be: 0x0164, 0x4bf: 0x01d0,
- // Block 0x13, offset 0x4c0
- 0x4c0: 0x2f97, 0x4c1: 0x32a3, 0x4c2: 0x2fa1, 0x4c3: 0x32ad, 0x4c4: 0x2fa6, 0x4c5: 0x32b2,
- 0x4c6: 0x2fab, 0x4c7: 0x32b7, 0x4c8: 0x38cc, 0x4c9: 0x3a5b, 0x4ca: 0x2fc4, 0x4cb: 0x32d0,
- 0x4cc: 0x2fce, 0x4cd: 0x32da, 0x4ce: 0x2fdd, 0x4cf: 0x32e9, 0x4d0: 0x2fd3, 0x4d1: 0x32df,
- 0x4d2: 0x2fd8, 0x4d3: 0x32e4, 0x4d4: 0x38ef, 0x4d5: 0x3a7e, 0x4d6: 0x38f6, 0x4d7: 0x3a85,
- 0x4d8: 0x3019, 0x4d9: 0x3325, 0x4da: 0x301e, 0x4db: 0x332a, 0x4dc: 0x3904, 0x4dd: 0x3a93,
- 0x4de: 0x3023, 0x4df: 0x332f, 0x4e0: 0x3032, 0x4e1: 0x333e, 0x4e2: 0x3050, 0x4e3: 0x335c,
- 0x4e4: 0x305f, 0x4e5: 0x336b, 0x4e6: 0x3055, 0x4e7: 0x3361, 0x4e8: 0x3064, 0x4e9: 0x3370,
- 0x4ea: 0x3069, 0x4eb: 0x3375, 0x4ec: 0x30af, 0x4ed: 0x33bb, 0x4ee: 0x390b, 0x4ef: 0x3a9a,
- 0x4f0: 0x30b9, 0x4f1: 0x33ca, 0x4f2: 0x30c3, 0x4f3: 0x33d4, 0x4f4: 0x30cd, 0x4f5: 0x33de,
- 0x4f6: 0x475a, 0x4f7: 0x47eb, 0x4f8: 0x3912, 0x4f9: 0x3aa1, 0x4fa: 0x30e6, 0x4fb: 0x33f7,
- 0x4fc: 0x30e1, 0x4fd: 0x33f2, 0x4fe: 0x30eb, 0x4ff: 0x33fc,
- // Block 0x14, offset 0x500
- 0x500: 0x30f0, 0x501: 0x3401, 0x502: 0x30f5, 0x503: 0x3406, 0x504: 0x3109, 0x505: 0x341a,
- 0x506: 0x3113, 0x507: 0x3424, 0x508: 0x3122, 0x509: 0x3433, 0x50a: 0x311d, 0x50b: 0x342e,
- 0x50c: 0x3935, 0x50d: 0x3ac4, 0x50e: 0x3943, 0x50f: 0x3ad2, 0x510: 0x394a, 0x511: 0x3ad9,
- 0x512: 0x3951, 0x513: 0x3ae0, 0x514: 0x314f, 0x515: 0x3460, 0x516: 0x3154, 0x517: 0x3465,
- 0x518: 0x315e, 0x519: 0x346f, 0x51a: 0x4787, 0x51b: 0x4818, 0x51c: 0x3997, 0x51d: 0x3b26,
- 0x51e: 0x3177, 0x51f: 0x3488, 0x520: 0x3181, 0x521: 0x3492, 0x522: 0x4796, 0x523: 0x4827,
- 0x524: 0x399e, 0x525: 0x3b2d, 0x526: 0x39a5, 0x527: 0x3b34, 0x528: 0x39ac, 0x529: 0x3b3b,
- 0x52a: 0x3190, 0x52b: 0x34a1, 0x52c: 0x319a, 0x52d: 0x34b0, 0x52e: 0x31ae, 0x52f: 0x34c4,
- 0x530: 0x31a9, 0x531: 0x34bf, 0x532: 0x31ea, 0x533: 0x3500, 0x534: 0x31f9, 0x535: 0x350f,
- 0x536: 0x31f4, 0x537: 0x350a, 0x538: 0x39b3, 0x539: 0x3b42, 0x53a: 0x39ba, 0x53b: 0x3b49,
- 0x53c: 0x31fe, 0x53d: 0x3514, 0x53e: 0x3203, 0x53f: 0x3519,
- // Block 0x15, offset 0x540
- 0x540: 0x3208, 0x541: 0x351e, 0x542: 0x320d, 0x543: 0x3523, 0x544: 0x321c, 0x545: 0x3532,
- 0x546: 0x3217, 0x547: 0x352d, 0x548: 0x3221, 0x549: 0x353c, 0x54a: 0x3226, 0x54b: 0x3541,
- 0x54c: 0x322b, 0x54d: 0x3546, 0x54e: 0x3249, 0x54f: 0x3564, 0x550: 0x3262, 0x551: 0x3582,
- 0x552: 0x3271, 0x553: 0x3591, 0x554: 0x3276, 0x555: 0x3596, 0x556: 0x337a, 0x557: 0x34a6,
- 0x558: 0x3537, 0x559: 0x3573, 0x55a: 0x1be0, 0x55b: 0x42d7,
- 0x560: 0x4737, 0x561: 0x47c8, 0x562: 0x2f83, 0x563: 0x328f,
- 0x564: 0x3878, 0x565: 0x3a07, 0x566: 0x3871, 0x567: 0x3a00, 0x568: 0x3886, 0x569: 0x3a15,
- 0x56a: 0x387f, 0x56b: 0x3a0e, 0x56c: 0x38be, 0x56d: 0x3a4d, 0x56e: 0x3894, 0x56f: 0x3a23,
- 0x570: 0x388d, 0x571: 0x3a1c, 0x572: 0x38a2, 0x573: 0x3a31, 0x574: 0x389b, 0x575: 0x3a2a,
- 0x576: 0x38c5, 0x577: 0x3a54, 0x578: 0x474b, 0x579: 0x47dc, 0x57a: 0x3000, 0x57b: 0x330c,
- 0x57c: 0x2fec, 0x57d: 0x32f8, 0x57e: 0x38da, 0x57f: 0x3a69,
- // Block 0x16, offset 0x580
- 0x580: 0x38d3, 0x581: 0x3a62, 0x582: 0x38e8, 0x583: 0x3a77, 0x584: 0x38e1, 0x585: 0x3a70,
- 0x586: 0x38fd, 0x587: 0x3a8c, 0x588: 0x3091, 0x589: 0x339d, 0x58a: 0x30a5, 0x58b: 0x33b1,
- 0x58c: 0x477d, 0x58d: 0x480e, 0x58e: 0x3136, 0x58f: 0x3447, 0x590: 0x3920, 0x591: 0x3aaf,
- 0x592: 0x3919, 0x593: 0x3aa8, 0x594: 0x392e, 0x595: 0x3abd, 0x596: 0x3927, 0x597: 0x3ab6,
- 0x598: 0x3989, 0x599: 0x3b18, 0x59a: 0x396d, 0x59b: 0x3afc, 0x59c: 0x3966, 0x59d: 0x3af5,
- 0x59e: 0x397b, 0x59f: 0x3b0a, 0x5a0: 0x3974, 0x5a1: 0x3b03, 0x5a2: 0x3982, 0x5a3: 0x3b11,
- 0x5a4: 0x31e5, 0x5a5: 0x34fb, 0x5a6: 0x31c7, 0x5a7: 0x34dd, 0x5a8: 0x39e4, 0x5a9: 0x3b73,
- 0x5aa: 0x39dd, 0x5ab: 0x3b6c, 0x5ac: 0x39f2, 0x5ad: 0x3b81, 0x5ae: 0x39eb, 0x5af: 0x3b7a,
- 0x5b0: 0x39f9, 0x5b1: 0x3b88, 0x5b2: 0x3230, 0x5b3: 0x354b, 0x5b4: 0x3258, 0x5b5: 0x3578,
- 0x5b6: 0x3253, 0x5b7: 0x356e, 0x5b8: 0x323f, 0x5b9: 0x355a,
- // Block 0x17, offset 0x5c0
- 0x5c0: 0x489a, 0x5c1: 0x48a0, 0x5c2: 0x49b4, 0x5c3: 0x49cc, 0x5c4: 0x49bc, 0x5c5: 0x49d4,
- 0x5c6: 0x49c4, 0x5c7: 0x49dc, 0x5c8: 0x4840, 0x5c9: 0x4846, 0x5ca: 0x4924, 0x5cb: 0x493c,
- 0x5cc: 0x492c, 0x5cd: 0x4944, 0x5ce: 0x4934, 0x5cf: 0x494c, 0x5d0: 0x48ac, 0x5d1: 0x48b2,
- 0x5d2: 0x3db8, 0x5d3: 0x3dc8, 0x5d4: 0x3dc0, 0x5d5: 0x3dd0,
- 0x5d8: 0x484c, 0x5d9: 0x4852, 0x5da: 0x3ce8, 0x5db: 0x3cf8, 0x5dc: 0x3cf0, 0x5dd: 0x3d00,
- 0x5e0: 0x48c4, 0x5e1: 0x48ca, 0x5e2: 0x49e4, 0x5e3: 0x49fc,
- 0x5e4: 0x49ec, 0x5e5: 0x4a04, 0x5e6: 0x49f4, 0x5e7: 0x4a0c, 0x5e8: 0x4858, 0x5e9: 0x485e,
- 0x5ea: 0x4954, 0x5eb: 0x496c, 0x5ec: 0x495c, 0x5ed: 0x4974, 0x5ee: 0x4964, 0x5ef: 0x497c,
- 0x5f0: 0x48dc, 0x5f1: 0x48e2, 0x5f2: 0x3e18, 0x5f3: 0x3e30, 0x5f4: 0x3e20, 0x5f5: 0x3e38,
- 0x5f6: 0x3e28, 0x5f7: 0x3e40, 0x5f8: 0x4864, 0x5f9: 0x486a, 0x5fa: 0x3d18, 0x5fb: 0x3d30,
- 0x5fc: 0x3d20, 0x5fd: 0x3d38, 0x5fe: 0x3d28, 0x5ff: 0x3d40,
- // Block 0x18, offset 0x600
- 0x600: 0x48e8, 0x601: 0x48ee, 0x602: 0x3e48, 0x603: 0x3e58, 0x604: 0x3e50, 0x605: 0x3e60,
- 0x608: 0x4870, 0x609: 0x4876, 0x60a: 0x3d48, 0x60b: 0x3d58,
- 0x60c: 0x3d50, 0x60d: 0x3d60, 0x610: 0x48fa, 0x611: 0x4900,
- 0x612: 0x3e80, 0x613: 0x3e98, 0x614: 0x3e88, 0x615: 0x3ea0, 0x616: 0x3e90, 0x617: 0x3ea8,
- 0x619: 0x487c, 0x61b: 0x3d68, 0x61d: 0x3d70,
- 0x61f: 0x3d78, 0x620: 0x4912, 0x621: 0x4918, 0x622: 0x4a14, 0x623: 0x4a2c,
- 0x624: 0x4a1c, 0x625: 0x4a34, 0x626: 0x4a24, 0x627: 0x4a3c, 0x628: 0x4882, 0x629: 0x4888,
- 0x62a: 0x4984, 0x62b: 0x499c, 0x62c: 0x498c, 0x62d: 0x49a4, 0x62e: 0x4994, 0x62f: 0x49ac,
- 0x630: 0x488e, 0x631: 0x43b4, 0x632: 0x3691, 0x633: 0x43ba, 0x634: 0x48b8, 0x635: 0x43c0,
- 0x636: 0x36a3, 0x637: 0x43c6, 0x638: 0x36c1, 0x639: 0x43cc, 0x63a: 0x36d9, 0x63b: 0x43d2,
- 0x63c: 0x4906, 0x63d: 0x43d8,
- // Block 0x19, offset 0x640
- 0x640: 0x3da0, 0x641: 0x3da8, 0x642: 0x4184, 0x643: 0x41a2, 0x644: 0x418e, 0x645: 0x41ac,
- 0x646: 0x4198, 0x647: 0x41b6, 0x648: 0x3cd8, 0x649: 0x3ce0, 0x64a: 0x40d0, 0x64b: 0x40ee,
- 0x64c: 0x40da, 0x64d: 0x40f8, 0x64e: 0x40e4, 0x64f: 0x4102, 0x650: 0x3de8, 0x651: 0x3df0,
- 0x652: 0x41c0, 0x653: 0x41de, 0x654: 0x41ca, 0x655: 0x41e8, 0x656: 0x41d4, 0x657: 0x41f2,
- 0x658: 0x3d08, 0x659: 0x3d10, 0x65a: 0x410c, 0x65b: 0x412a, 0x65c: 0x4116, 0x65d: 0x4134,
- 0x65e: 0x4120, 0x65f: 0x413e, 0x660: 0x3ec0, 0x661: 0x3ec8, 0x662: 0x41fc, 0x663: 0x421a,
- 0x664: 0x4206, 0x665: 0x4224, 0x666: 0x4210, 0x667: 0x422e, 0x668: 0x3d80, 0x669: 0x3d88,
- 0x66a: 0x4148, 0x66b: 0x4166, 0x66c: 0x4152, 0x66d: 0x4170, 0x66e: 0x415c, 0x66f: 0x417a,
- 0x670: 0x3685, 0x671: 0x367f, 0x672: 0x3d90, 0x673: 0x368b, 0x674: 0x3d98,
- 0x676: 0x48a6, 0x677: 0x3db0, 0x678: 0x35f5, 0x679: 0x35ef, 0x67a: 0x35e3, 0x67b: 0x4384,
- 0x67c: 0x35fb, 0x67d: 0x4287, 0x67e: 0x01d3, 0x67f: 0x4287,
- // Block 0x1a, offset 0x680
- 0x680: 0x42a0, 0x681: 0x4518, 0x682: 0x3dd8, 0x683: 0x369d, 0x684: 0x3de0,
- 0x686: 0x48d0, 0x687: 0x3df8, 0x688: 0x3601, 0x689: 0x438a, 0x68a: 0x360d, 0x68b: 0x4390,
- 0x68c: 0x3619, 0x68d: 0x451f, 0x68e: 0x4526, 0x68f: 0x452d, 0x690: 0x36b5, 0x691: 0x36af,
- 0x692: 0x3e00, 0x693: 0x457a, 0x696: 0x36bb, 0x697: 0x3e10,
- 0x698: 0x3631, 0x699: 0x362b, 0x69a: 0x361f, 0x69b: 0x4396, 0x69d: 0x4534,
- 0x69e: 0x453b, 0x69f: 0x4542, 0x6a0: 0x36eb, 0x6a1: 0x36e5, 0x6a2: 0x3e68, 0x6a3: 0x4582,
- 0x6a4: 0x36cd, 0x6a5: 0x36d3, 0x6a6: 0x36f1, 0x6a7: 0x3e78, 0x6a8: 0x3661, 0x6a9: 0x365b,
- 0x6aa: 0x364f, 0x6ab: 0x43a2, 0x6ac: 0x3649, 0x6ad: 0x450a, 0x6ae: 0x4511, 0x6af: 0x0081,
- 0x6b2: 0x3eb0, 0x6b3: 0x36f7, 0x6b4: 0x3eb8,
- 0x6b6: 0x491e, 0x6b7: 0x3ed0, 0x6b8: 0x363d, 0x6b9: 0x439c, 0x6ba: 0x366d, 0x6bb: 0x43ae,
- 0x6bc: 0x3679, 0x6bd: 0x425a, 0x6be: 0x428c,
- // Block 0x1b, offset 0x6c0
- 0x6c0: 0x1bd8, 0x6c1: 0x1bdc, 0x6c2: 0x0047, 0x6c3: 0x1c54, 0x6c5: 0x1be8,
- 0x6c6: 0x1bec, 0x6c7: 0x00e9, 0x6c9: 0x1c58, 0x6ca: 0x008f, 0x6cb: 0x0051,
- 0x6cc: 0x0051, 0x6cd: 0x0051, 0x6ce: 0x0091, 0x6cf: 0x00da, 0x6d0: 0x0053, 0x6d1: 0x0053,
- 0x6d2: 0x0059, 0x6d3: 0x0099, 0x6d5: 0x005d, 0x6d6: 0x198d,
- 0x6d9: 0x0061, 0x6da: 0x0063, 0x6db: 0x0065, 0x6dc: 0x0065, 0x6dd: 0x0065,
- 0x6e0: 0x199f, 0x6e1: 0x1bc8, 0x6e2: 0x19a8,
- 0x6e4: 0x0075, 0x6e6: 0x01b8, 0x6e8: 0x0075,
- 0x6ea: 0x0057, 0x6eb: 0x42d2, 0x6ec: 0x0045, 0x6ed: 0x0047, 0x6ef: 0x008b,
- 0x6f0: 0x004b, 0x6f1: 0x004d, 0x6f3: 0x005b, 0x6f4: 0x009f, 0x6f5: 0x0215,
- 0x6f6: 0x0218, 0x6f7: 0x021b, 0x6f8: 0x021e, 0x6f9: 0x0093, 0x6fb: 0x1b98,
- 0x6fc: 0x01e8, 0x6fd: 0x01c1, 0x6fe: 0x0179, 0x6ff: 0x01a0,
- // Block 0x1c, offset 0x700
- 0x700: 0x0463, 0x705: 0x0049,
- 0x706: 0x0089, 0x707: 0x008b, 0x708: 0x0093, 0x709: 0x0095,
- 0x710: 0x222e, 0x711: 0x223a,
- 0x712: 0x22ee, 0x713: 0x2216, 0x714: 0x229a, 0x715: 0x2222, 0x716: 0x22a0, 0x717: 0x22b8,
- 0x718: 0x22c4, 0x719: 0x2228, 0x71a: 0x22ca, 0x71b: 0x2234, 0x71c: 0x22be, 0x71d: 0x22d0,
- 0x71e: 0x22d6, 0x71f: 0x1cbc, 0x720: 0x0053, 0x721: 0x195a, 0x722: 0x1ba4, 0x723: 0x1963,
- 0x724: 0x006d, 0x725: 0x19ab, 0x726: 0x1bd0, 0x727: 0x1d48, 0x728: 0x1966, 0x729: 0x0071,
- 0x72a: 0x19b7, 0x72b: 0x1bd4, 0x72c: 0x0059, 0x72d: 0x0047, 0x72e: 0x0049, 0x72f: 0x005b,
- 0x730: 0x0093, 0x731: 0x19e4, 0x732: 0x1c18, 0x733: 0x19ed, 0x734: 0x00ad, 0x735: 0x1a62,
- 0x736: 0x1c4c, 0x737: 0x1d5c, 0x738: 0x19f0, 0x739: 0x00b1, 0x73a: 0x1a65, 0x73b: 0x1c50,
- 0x73c: 0x0099, 0x73d: 0x0087, 0x73e: 0x0089, 0x73f: 0x009b,
- // Block 0x1d, offset 0x740
- 0x741: 0x3c06, 0x743: 0xa000, 0x744: 0x3c0d, 0x745: 0xa000,
- 0x747: 0x3c14, 0x748: 0xa000, 0x749: 0x3c1b,
- 0x74d: 0xa000,
- 0x760: 0x2f65, 0x761: 0xa000, 0x762: 0x3c29,
- 0x764: 0xa000, 0x765: 0xa000,
- 0x76d: 0x3c22, 0x76e: 0x2f60, 0x76f: 0x2f6a,
- 0x770: 0x3c30, 0x771: 0x3c37, 0x772: 0xa000, 0x773: 0xa000, 0x774: 0x3c3e, 0x775: 0x3c45,
- 0x776: 0xa000, 0x777: 0xa000, 0x778: 0x3c4c, 0x779: 0x3c53, 0x77a: 0xa000, 0x77b: 0xa000,
- 0x77c: 0xa000, 0x77d: 0xa000,
- // Block 0x1e, offset 0x780
- 0x780: 0x3c5a, 0x781: 0x3c61, 0x782: 0xa000, 0x783: 0xa000, 0x784: 0x3c76, 0x785: 0x3c7d,
- 0x786: 0xa000, 0x787: 0xa000, 0x788: 0x3c84, 0x789: 0x3c8b,
- 0x791: 0xa000,
- 0x792: 0xa000,
- 0x7a2: 0xa000,
- 0x7a8: 0xa000, 0x7a9: 0xa000,
- 0x7ab: 0xa000, 0x7ac: 0x3ca0, 0x7ad: 0x3ca7, 0x7ae: 0x3cae, 0x7af: 0x3cb5,
- 0x7b2: 0xa000, 0x7b3: 0xa000, 0x7b4: 0xa000, 0x7b5: 0xa000,
- // Block 0x1f, offset 0x7c0
- 0x7e0: 0x0023, 0x7e1: 0x0025, 0x7e2: 0x0027, 0x7e3: 0x0029,
- 0x7e4: 0x002b, 0x7e5: 0x002d, 0x7e6: 0x002f, 0x7e7: 0x0031, 0x7e8: 0x0033, 0x7e9: 0x1882,
- 0x7ea: 0x1885, 0x7eb: 0x1888, 0x7ec: 0x188b, 0x7ed: 0x188e, 0x7ee: 0x1891, 0x7ef: 0x1894,
- 0x7f0: 0x1897, 0x7f1: 0x189a, 0x7f2: 0x189d, 0x7f3: 0x18a6, 0x7f4: 0x1a68, 0x7f5: 0x1a6c,
- 0x7f6: 0x1a70, 0x7f7: 0x1a74, 0x7f8: 0x1a78, 0x7f9: 0x1a7c, 0x7fa: 0x1a80, 0x7fb: 0x1a84,
- 0x7fc: 0x1a88, 0x7fd: 0x1c80, 0x7fe: 0x1c85, 0x7ff: 0x1c8a,
- // Block 0x20, offset 0x800
- 0x800: 0x1c8f, 0x801: 0x1c94, 0x802: 0x1c99, 0x803: 0x1c9e, 0x804: 0x1ca3, 0x805: 0x1ca8,
- 0x806: 0x1cad, 0x807: 0x1cb2, 0x808: 0x187f, 0x809: 0x18a3, 0x80a: 0x18c7, 0x80b: 0x18eb,
- 0x80c: 0x190f, 0x80d: 0x1918, 0x80e: 0x191e, 0x80f: 0x1924, 0x810: 0x192a, 0x811: 0x1b60,
- 0x812: 0x1b64, 0x813: 0x1b68, 0x814: 0x1b6c, 0x815: 0x1b70, 0x816: 0x1b74, 0x817: 0x1b78,
- 0x818: 0x1b7c, 0x819: 0x1b80, 0x81a: 0x1b84, 0x81b: 0x1b88, 0x81c: 0x1af4, 0x81d: 0x1af8,
- 0x81e: 0x1afc, 0x81f: 0x1b00, 0x820: 0x1b04, 0x821: 0x1b08, 0x822: 0x1b0c, 0x823: 0x1b10,
- 0x824: 0x1b14, 0x825: 0x1b18, 0x826: 0x1b1c, 0x827: 0x1b20, 0x828: 0x1b24, 0x829: 0x1b28,
- 0x82a: 0x1b2c, 0x82b: 0x1b30, 0x82c: 0x1b34, 0x82d: 0x1b38, 0x82e: 0x1b3c, 0x82f: 0x1b40,
- 0x830: 0x1b44, 0x831: 0x1b48, 0x832: 0x1b4c, 0x833: 0x1b50, 0x834: 0x1b54, 0x835: 0x1b58,
- 0x836: 0x0043, 0x837: 0x0045, 0x838: 0x0047, 0x839: 0x0049, 0x83a: 0x004b, 0x83b: 0x004d,
- 0x83c: 0x004f, 0x83d: 0x0051, 0x83e: 0x0053, 0x83f: 0x0055,
- // Block 0x21, offset 0x840
- 0x840: 0x06bf, 0x841: 0x06e3, 0x842: 0x06ef, 0x843: 0x06ff, 0x844: 0x0707, 0x845: 0x0713,
- 0x846: 0x071b, 0x847: 0x0723, 0x848: 0x072f, 0x849: 0x0783, 0x84a: 0x079b, 0x84b: 0x07ab,
- 0x84c: 0x07bb, 0x84d: 0x07cb, 0x84e: 0x07db, 0x84f: 0x07fb, 0x850: 0x07ff, 0x851: 0x0803,
- 0x852: 0x0837, 0x853: 0x085f, 0x854: 0x086f, 0x855: 0x0877, 0x856: 0x087b, 0x857: 0x0887,
- 0x858: 0x08a3, 0x859: 0x08a7, 0x85a: 0x08bf, 0x85b: 0x08c3, 0x85c: 0x08cb, 0x85d: 0x08db,
- 0x85e: 0x0977, 0x85f: 0x098b, 0x860: 0x09cb, 0x861: 0x09df, 0x862: 0x09e7, 0x863: 0x09eb,
- 0x864: 0x09fb, 0x865: 0x0a17, 0x866: 0x0a43, 0x867: 0x0a4f, 0x868: 0x0a6f, 0x869: 0x0a7b,
- 0x86a: 0x0a7f, 0x86b: 0x0a83, 0x86c: 0x0a9b, 0x86d: 0x0a9f, 0x86e: 0x0acb, 0x86f: 0x0ad7,
- 0x870: 0x0adf, 0x871: 0x0ae7, 0x872: 0x0af7, 0x873: 0x0aff, 0x874: 0x0b07, 0x875: 0x0b33,
- 0x876: 0x0b37, 0x877: 0x0b3f, 0x878: 0x0b43, 0x879: 0x0b4b, 0x87a: 0x0b53, 0x87b: 0x0b63,
- 0x87c: 0x0b7f, 0x87d: 0x0bf7, 0x87e: 0x0c0b, 0x87f: 0x0c0f,
- // Block 0x22, offset 0x880
- 0x880: 0x0c8f, 0x881: 0x0c93, 0x882: 0x0ca7, 0x883: 0x0cab, 0x884: 0x0cb3, 0x885: 0x0cbb,
- 0x886: 0x0cc3, 0x887: 0x0ccf, 0x888: 0x0cf7, 0x889: 0x0d07, 0x88a: 0x0d1b, 0x88b: 0x0d8b,
- 0x88c: 0x0d97, 0x88d: 0x0da7, 0x88e: 0x0db3, 0x88f: 0x0dbf, 0x890: 0x0dc7, 0x891: 0x0dcb,
- 0x892: 0x0dcf, 0x893: 0x0dd3, 0x894: 0x0dd7, 0x895: 0x0e8f, 0x896: 0x0ed7, 0x897: 0x0ee3,
- 0x898: 0x0ee7, 0x899: 0x0eeb, 0x89a: 0x0eef, 0x89b: 0x0ef7, 0x89c: 0x0efb, 0x89d: 0x0f0f,
- 0x89e: 0x0f2b, 0x89f: 0x0f33, 0x8a0: 0x0f73, 0x8a1: 0x0f77, 0x8a2: 0x0f7f, 0x8a3: 0x0f83,
- 0x8a4: 0x0f8b, 0x8a5: 0x0f8f, 0x8a6: 0x0fb3, 0x8a7: 0x0fb7, 0x8a8: 0x0fd3, 0x8a9: 0x0fd7,
- 0x8aa: 0x0fdb, 0x8ab: 0x0fdf, 0x8ac: 0x0ff3, 0x8ad: 0x1017, 0x8ae: 0x101b, 0x8af: 0x101f,
- 0x8b0: 0x1043, 0x8b1: 0x1083, 0x8b2: 0x1087, 0x8b3: 0x10a7, 0x8b4: 0x10b7, 0x8b5: 0x10bf,
- 0x8b6: 0x10df, 0x8b7: 0x1103, 0x8b8: 0x1147, 0x8b9: 0x114f, 0x8ba: 0x1163, 0x8bb: 0x116f,
- 0x8bc: 0x1177, 0x8bd: 0x117f, 0x8be: 0x1183, 0x8bf: 0x1187,
- // Block 0x23, offset 0x8c0
- 0x8c0: 0x119f, 0x8c1: 0x11a3, 0x8c2: 0x11bf, 0x8c3: 0x11c7, 0x8c4: 0x11cf, 0x8c5: 0x11d3,
- 0x8c6: 0x11df, 0x8c7: 0x11e7, 0x8c8: 0x11eb, 0x8c9: 0x11ef, 0x8ca: 0x11f7, 0x8cb: 0x11fb,
- 0x8cc: 0x129b, 0x8cd: 0x12af, 0x8ce: 0x12e3, 0x8cf: 0x12e7, 0x8d0: 0x12ef, 0x8d1: 0x131b,
- 0x8d2: 0x1323, 0x8d3: 0x132b, 0x8d4: 0x1333, 0x8d5: 0x136f, 0x8d6: 0x1373, 0x8d7: 0x137b,
- 0x8d8: 0x137f, 0x8d9: 0x1383, 0x8da: 0x13af, 0x8db: 0x13b3, 0x8dc: 0x13bb, 0x8dd: 0x13cf,
- 0x8de: 0x13d3, 0x8df: 0x13ef, 0x8e0: 0x13f7, 0x8e1: 0x13fb, 0x8e2: 0x141f, 0x8e3: 0x143f,
- 0x8e4: 0x1453, 0x8e5: 0x1457, 0x8e6: 0x145f, 0x8e7: 0x148b, 0x8e8: 0x148f, 0x8e9: 0x149f,
- 0x8ea: 0x14c3, 0x8eb: 0x14cf, 0x8ec: 0x14df, 0x8ed: 0x14f7, 0x8ee: 0x14ff, 0x8ef: 0x1503,
- 0x8f0: 0x1507, 0x8f1: 0x150b, 0x8f2: 0x1517, 0x8f3: 0x151b, 0x8f4: 0x1523, 0x8f5: 0x153f,
- 0x8f6: 0x1543, 0x8f7: 0x1547, 0x8f8: 0x155f, 0x8f9: 0x1563, 0x8fa: 0x156b, 0x8fb: 0x157f,
- 0x8fc: 0x1583, 0x8fd: 0x1587, 0x8fe: 0x158f, 0x8ff: 0x1593,
- // Block 0x24, offset 0x900
- 0x906: 0xa000, 0x90b: 0xa000,
- 0x90c: 0x3f08, 0x90d: 0xa000, 0x90e: 0x3f10, 0x90f: 0xa000, 0x910: 0x3f18, 0x911: 0xa000,
- 0x912: 0x3f20, 0x913: 0xa000, 0x914: 0x3f28, 0x915: 0xa000, 0x916: 0x3f30, 0x917: 0xa000,
- 0x918: 0x3f38, 0x919: 0xa000, 0x91a: 0x3f40, 0x91b: 0xa000, 0x91c: 0x3f48, 0x91d: 0xa000,
- 0x91e: 0x3f50, 0x91f: 0xa000, 0x920: 0x3f58, 0x921: 0xa000, 0x922: 0x3f60,
- 0x924: 0xa000, 0x925: 0x3f68, 0x926: 0xa000, 0x927: 0x3f70, 0x928: 0xa000, 0x929: 0x3f78,
- 0x92f: 0xa000,
- 0x930: 0x3f80, 0x931: 0x3f88, 0x932: 0xa000, 0x933: 0x3f90, 0x934: 0x3f98, 0x935: 0xa000,
- 0x936: 0x3fa0, 0x937: 0x3fa8, 0x938: 0xa000, 0x939: 0x3fb0, 0x93a: 0x3fb8, 0x93b: 0xa000,
- 0x93c: 0x3fc0, 0x93d: 0x3fc8,
- // Block 0x25, offset 0x940
- 0x954: 0x3f00,
- 0x959: 0x9903, 0x95a: 0x9903, 0x95b: 0x4372, 0x95c: 0x4378, 0x95d: 0xa000,
- 0x95e: 0x3fd0, 0x95f: 0x26b4,
- 0x966: 0xa000,
- 0x96b: 0xa000, 0x96c: 0x3fe0, 0x96d: 0xa000, 0x96e: 0x3fe8, 0x96f: 0xa000,
- 0x970: 0x3ff0, 0x971: 0xa000, 0x972: 0x3ff8, 0x973: 0xa000, 0x974: 0x4000, 0x975: 0xa000,
- 0x976: 0x4008, 0x977: 0xa000, 0x978: 0x4010, 0x979: 0xa000, 0x97a: 0x4018, 0x97b: 0xa000,
- 0x97c: 0x4020, 0x97d: 0xa000, 0x97e: 0x4028, 0x97f: 0xa000,
- // Block 0x26, offset 0x980
- 0x980: 0x4030, 0x981: 0xa000, 0x982: 0x4038, 0x984: 0xa000, 0x985: 0x4040,
- 0x986: 0xa000, 0x987: 0x4048, 0x988: 0xa000, 0x989: 0x4050,
- 0x98f: 0xa000, 0x990: 0x4058, 0x991: 0x4060,
- 0x992: 0xa000, 0x993: 0x4068, 0x994: 0x4070, 0x995: 0xa000, 0x996: 0x4078, 0x997: 0x4080,
- 0x998: 0xa000, 0x999: 0x4088, 0x99a: 0x4090, 0x99b: 0xa000, 0x99c: 0x4098, 0x99d: 0x40a0,
- 0x9af: 0xa000,
- 0x9b0: 0xa000, 0x9b1: 0xa000, 0x9b2: 0xa000, 0x9b4: 0x3fd8,
- 0x9b7: 0x40a8, 0x9b8: 0x40b0, 0x9b9: 0x40b8, 0x9ba: 0x40c0,
- 0x9bd: 0xa000, 0x9be: 0x40c8, 0x9bf: 0x26c9,
- // Block 0x27, offset 0x9c0
- 0x9c0: 0x0367, 0x9c1: 0x032b, 0x9c2: 0x032f, 0x9c3: 0x0333, 0x9c4: 0x037b, 0x9c5: 0x0337,
- 0x9c6: 0x033b, 0x9c7: 0x033f, 0x9c8: 0x0343, 0x9c9: 0x0347, 0x9ca: 0x034b, 0x9cb: 0x034f,
- 0x9cc: 0x0353, 0x9cd: 0x0357, 0x9ce: 0x035b, 0x9cf: 0x42dc, 0x9d0: 0x42e1, 0x9d1: 0x42e6,
- 0x9d2: 0x42eb, 0x9d3: 0x42f0, 0x9d4: 0x42f5, 0x9d5: 0x42fa, 0x9d6: 0x42ff, 0x9d7: 0x4304,
- 0x9d8: 0x4309, 0x9d9: 0x430e, 0x9da: 0x4313, 0x9db: 0x4318, 0x9dc: 0x431d, 0x9dd: 0x4322,
- 0x9de: 0x4327, 0x9df: 0x432c, 0x9e0: 0x4331, 0x9e1: 0x4336, 0x9e2: 0x433b, 0x9e3: 0x4340,
- 0x9e4: 0x03c3, 0x9e5: 0x035f, 0x9e6: 0x0363, 0x9e7: 0x03e7, 0x9e8: 0x03eb, 0x9e9: 0x03ef,
- 0x9ea: 0x03f3, 0x9eb: 0x03f7, 0x9ec: 0x03fb, 0x9ed: 0x03ff, 0x9ee: 0x036b, 0x9ef: 0x0403,
- 0x9f0: 0x0407, 0x9f1: 0x036f, 0x9f2: 0x0373, 0x9f3: 0x0377, 0x9f4: 0x037f, 0x9f5: 0x0383,
- 0x9f6: 0x0387, 0x9f7: 0x038b, 0x9f8: 0x038f, 0x9f9: 0x0393, 0x9fa: 0x0397, 0x9fb: 0x039b,
- 0x9fc: 0x039f, 0x9fd: 0x03a3, 0x9fe: 0x03a7, 0x9ff: 0x03ab,
- // Block 0x28, offset 0xa00
- 0xa00: 0x03af, 0xa01: 0x03b3, 0xa02: 0x040b, 0xa03: 0x040f, 0xa04: 0x03b7, 0xa05: 0x03bb,
- 0xa06: 0x03bf, 0xa07: 0x03c7, 0xa08: 0x03cb, 0xa09: 0x03cf, 0xa0a: 0x03d3, 0xa0b: 0x03d7,
- 0xa0c: 0x03db, 0xa0d: 0x03df, 0xa0e: 0x03e3,
- 0xa12: 0x06bf, 0xa13: 0x071b, 0xa14: 0x06cb, 0xa15: 0x097b, 0xa16: 0x06cf, 0xa17: 0x06e7,
- 0xa18: 0x06d3, 0xa19: 0x0f93, 0xa1a: 0x0707, 0xa1b: 0x06db, 0xa1c: 0x06c3, 0xa1d: 0x09ff,
- 0xa1e: 0x098f, 0xa1f: 0x072f,
- // Block 0x29, offset 0xa40
- 0xa40: 0x2054, 0xa41: 0x205a, 0xa42: 0x2060, 0xa43: 0x2066, 0xa44: 0x206c, 0xa45: 0x2072,
- 0xa46: 0x2078, 0xa47: 0x207e, 0xa48: 0x2084, 0xa49: 0x208a, 0xa4a: 0x2090, 0xa4b: 0x2096,
- 0xa4c: 0x209c, 0xa4d: 0x20a2, 0xa4e: 0x2726, 0xa4f: 0x272f, 0xa50: 0x2738, 0xa51: 0x2741,
- 0xa52: 0x274a, 0xa53: 0x2753, 0xa54: 0x275c, 0xa55: 0x2765, 0xa56: 0x276e, 0xa57: 0x2780,
- 0xa58: 0x2789, 0xa59: 0x2792, 0xa5a: 0x279b, 0xa5b: 0x27a4, 0xa5c: 0x2777, 0xa5d: 0x2bac,
- 0xa5e: 0x2aed, 0xa60: 0x20a8, 0xa61: 0x20c0, 0xa62: 0x20b4, 0xa63: 0x2108,
- 0xa64: 0x20c6, 0xa65: 0x20e4, 0xa66: 0x20ae, 0xa67: 0x20de, 0xa68: 0x20ba, 0xa69: 0x20f0,
- 0xa6a: 0x2120, 0xa6b: 0x213e, 0xa6c: 0x2138, 0xa6d: 0x212c, 0xa6e: 0x217a, 0xa6f: 0x210e,
- 0xa70: 0x211a, 0xa71: 0x2132, 0xa72: 0x2126, 0xa73: 0x2150, 0xa74: 0x20fc, 0xa75: 0x2144,
- 0xa76: 0x216e, 0xa77: 0x2156, 0xa78: 0x20ea, 0xa79: 0x20cc, 0xa7a: 0x2102, 0xa7b: 0x2114,
- 0xa7c: 0x214a, 0xa7d: 0x20d2, 0xa7e: 0x2174, 0xa7f: 0x20f6,
- // Block 0x2a, offset 0xa80
- 0xa80: 0x215c, 0xa81: 0x20d8, 0xa82: 0x2162, 0xa83: 0x2168, 0xa84: 0x092f, 0xa85: 0x0b03,
- 0xa86: 0x0ca7, 0xa87: 0x10c7,
- 0xa90: 0x1bc4, 0xa91: 0x18a9,
- 0xa92: 0x18ac, 0xa93: 0x18af, 0xa94: 0x18b2, 0xa95: 0x18b5, 0xa96: 0x18b8, 0xa97: 0x18bb,
- 0xa98: 0x18be, 0xa99: 0x18c1, 0xa9a: 0x18ca, 0xa9b: 0x18cd, 0xa9c: 0x18d0, 0xa9d: 0x18d3,
- 0xa9e: 0x18d6, 0xa9f: 0x18d9, 0xaa0: 0x0313, 0xaa1: 0x031b, 0xaa2: 0x031f, 0xaa3: 0x0327,
- 0xaa4: 0x032b, 0xaa5: 0x032f, 0xaa6: 0x0337, 0xaa7: 0x033f, 0xaa8: 0x0343, 0xaa9: 0x034b,
- 0xaaa: 0x034f, 0xaab: 0x0353, 0xaac: 0x0357, 0xaad: 0x035b, 0xaae: 0x2e18, 0xaaf: 0x2e20,
- 0xab0: 0x2e28, 0xab1: 0x2e30, 0xab2: 0x2e38, 0xab3: 0x2e40, 0xab4: 0x2e48, 0xab5: 0x2e50,
- 0xab6: 0x2e60, 0xab7: 0x2e68, 0xab8: 0x2e70, 0xab9: 0x2e78, 0xaba: 0x2e80, 0xabb: 0x2e88,
- 0xabc: 0x2ed3, 0xabd: 0x2e9b, 0xabe: 0x2e58,
- // Block 0x2b, offset 0xac0
- 0xac0: 0x06bf, 0xac1: 0x071b, 0xac2: 0x06cb, 0xac3: 0x097b, 0xac4: 0x071f, 0xac5: 0x07af,
- 0xac6: 0x06c7, 0xac7: 0x07ab, 0xac8: 0x070b, 0xac9: 0x0887, 0xaca: 0x0d07, 0xacb: 0x0e8f,
- 0xacc: 0x0dd7, 0xacd: 0x0d1b, 0xace: 0x145f, 0xacf: 0x098b, 0xad0: 0x0ccf, 0xad1: 0x0d4b,
- 0xad2: 0x0d0b, 0xad3: 0x104b, 0xad4: 0x08fb, 0xad5: 0x0f03, 0xad6: 0x1387, 0xad7: 0x105f,
- 0xad8: 0x0843, 0xad9: 0x108f, 0xada: 0x0f9b, 0xadb: 0x0a17, 0xadc: 0x140f, 0xadd: 0x077f,
- 0xade: 0x08ab, 0xadf: 0x0df7, 0xae0: 0x1527, 0xae1: 0x0743, 0xae2: 0x07d3, 0xae3: 0x0d9b,
- 0xae4: 0x06cf, 0xae5: 0x06e7, 0xae6: 0x06d3, 0xae7: 0x0adb, 0xae8: 0x08ef, 0xae9: 0x087f,
- 0xaea: 0x0a57, 0xaeb: 0x0a4b, 0xaec: 0x0feb, 0xaed: 0x073f, 0xaee: 0x139b, 0xaef: 0x089b,
- 0xaf0: 0x09f3, 0xaf1: 0x18dc, 0xaf2: 0x18df, 0xaf3: 0x18e2, 0xaf4: 0x18e5, 0xaf5: 0x18ee,
- 0xaf6: 0x18f1, 0xaf7: 0x18f4, 0xaf8: 0x18f7, 0xaf9: 0x18fa, 0xafa: 0x18fd, 0xafb: 0x1900,
- 0xafc: 0x1903, 0xafd: 0x1906, 0xafe: 0x1909, 0xaff: 0x1912,
- // Block 0x2c, offset 0xb00
- 0xb00: 0x1cc6, 0xb01: 0x1cd5, 0xb02: 0x1ce4, 0xb03: 0x1cf3, 0xb04: 0x1d02, 0xb05: 0x1d11,
- 0xb06: 0x1d20, 0xb07: 0x1d2f, 0xb08: 0x1d3e, 0xb09: 0x218c, 0xb0a: 0x219e, 0xb0b: 0x21b0,
- 0xb0c: 0x1954, 0xb0d: 0x1c04, 0xb0e: 0x19d2, 0xb0f: 0x1ba8, 0xb10: 0x04cb, 0xb11: 0x04d3,
- 0xb12: 0x04db, 0xb13: 0x04e3, 0xb14: 0x04eb, 0xb15: 0x04ef, 0xb16: 0x04f3, 0xb17: 0x04f7,
- 0xb18: 0x04fb, 0xb19: 0x04ff, 0xb1a: 0x0503, 0xb1b: 0x0507, 0xb1c: 0x050b, 0xb1d: 0x050f,
- 0xb1e: 0x0513, 0xb1f: 0x0517, 0xb20: 0x051b, 0xb21: 0x0523, 0xb22: 0x0527, 0xb23: 0x052b,
- 0xb24: 0x052f, 0xb25: 0x0533, 0xb26: 0x0537, 0xb27: 0x053b, 0xb28: 0x053f, 0xb29: 0x0543,
- 0xb2a: 0x0547, 0xb2b: 0x054b, 0xb2c: 0x054f, 0xb2d: 0x0553, 0xb2e: 0x0557, 0xb2f: 0x055b,
- 0xb30: 0x055f, 0xb31: 0x0563, 0xb32: 0x0567, 0xb33: 0x056f, 0xb34: 0x0577, 0xb35: 0x057f,
- 0xb36: 0x0583, 0xb37: 0x0587, 0xb38: 0x058b, 0xb39: 0x058f, 0xb3a: 0x0593, 0xb3b: 0x0597,
- 0xb3c: 0x059b, 0xb3d: 0x059f, 0xb3e: 0x05a3,
- // Block 0x2d, offset 0xb40
- 0xb40: 0x2b0c, 0xb41: 0x29a8, 0xb42: 0x2b1c, 0xb43: 0x2880, 0xb44: 0x2ee4, 0xb45: 0x288a,
- 0xb46: 0x2894, 0xb47: 0x2f28, 0xb48: 0x29b5, 0xb49: 0x289e, 0xb4a: 0x28a8, 0xb4b: 0x28b2,
- 0xb4c: 0x29dc, 0xb4d: 0x29e9, 0xb4e: 0x29c2, 0xb4f: 0x29cf, 0xb50: 0x2ea9, 0xb51: 0x29f6,
- 0xb52: 0x2a03, 0xb53: 0x2bbe, 0xb54: 0x26bb, 0xb55: 0x2bd1, 0xb56: 0x2be4, 0xb57: 0x2b2c,
- 0xb58: 0x2a10, 0xb59: 0x2bf7, 0xb5a: 0x2c0a, 0xb5b: 0x2a1d, 0xb5c: 0x28bc, 0xb5d: 0x28c6,
- 0xb5e: 0x2eb7, 0xb5f: 0x2a2a, 0xb60: 0x2b3c, 0xb61: 0x2ef5, 0xb62: 0x28d0, 0xb63: 0x28da,
- 0xb64: 0x2a37, 0xb65: 0x28e4, 0xb66: 0x28ee, 0xb67: 0x26d0, 0xb68: 0x26d7, 0xb69: 0x28f8,
- 0xb6a: 0x2902, 0xb6b: 0x2c1d, 0xb6c: 0x2a44, 0xb6d: 0x2b4c, 0xb6e: 0x2c30, 0xb6f: 0x2a51,
- 0xb70: 0x2916, 0xb71: 0x290c, 0xb72: 0x2f3c, 0xb73: 0x2a5e, 0xb74: 0x2c43, 0xb75: 0x2920,
- 0xb76: 0x2b5c, 0xb77: 0x292a, 0xb78: 0x2a78, 0xb79: 0x2934, 0xb7a: 0x2a85, 0xb7b: 0x2f06,
- 0xb7c: 0x2a6b, 0xb7d: 0x2b6c, 0xb7e: 0x2a92, 0xb7f: 0x26de,
- // Block 0x2e, offset 0xb80
- 0xb80: 0x2f17, 0xb81: 0x293e, 0xb82: 0x2948, 0xb83: 0x2a9f, 0xb84: 0x2952, 0xb85: 0x295c,
- 0xb86: 0x2966, 0xb87: 0x2b7c, 0xb88: 0x2aac, 0xb89: 0x26e5, 0xb8a: 0x2c56, 0xb8b: 0x2e90,
- 0xb8c: 0x2b8c, 0xb8d: 0x2ab9, 0xb8e: 0x2ec5, 0xb8f: 0x2970, 0xb90: 0x297a, 0xb91: 0x2ac6,
- 0xb92: 0x26ec, 0xb93: 0x2ad3, 0xb94: 0x2b9c, 0xb95: 0x26f3, 0xb96: 0x2c69, 0xb97: 0x2984,
- 0xb98: 0x1cb7, 0xb99: 0x1ccb, 0xb9a: 0x1cda, 0xb9b: 0x1ce9, 0xb9c: 0x1cf8, 0xb9d: 0x1d07,
- 0xb9e: 0x1d16, 0xb9f: 0x1d25, 0xba0: 0x1d34, 0xba1: 0x1d43, 0xba2: 0x2192, 0xba3: 0x21a4,
- 0xba4: 0x21b6, 0xba5: 0x21c2, 0xba6: 0x21ce, 0xba7: 0x21da, 0xba8: 0x21e6, 0xba9: 0x21f2,
- 0xbaa: 0x21fe, 0xbab: 0x220a, 0xbac: 0x2246, 0xbad: 0x2252, 0xbae: 0x225e, 0xbaf: 0x226a,
- 0xbb0: 0x2276, 0xbb1: 0x1c14, 0xbb2: 0x19c6, 0xbb3: 0x1936, 0xbb4: 0x1be4, 0xbb5: 0x1a47,
- 0xbb6: 0x1a56, 0xbb7: 0x19cc, 0xbb8: 0x1bfc, 0xbb9: 0x1c00, 0xbba: 0x1960, 0xbbb: 0x2701,
- 0xbbc: 0x270f, 0xbbd: 0x26fa, 0xbbe: 0x2708, 0xbbf: 0x2ae0,
- // Block 0x2f, offset 0xbc0
- 0xbc0: 0x1a4a, 0xbc1: 0x1a32, 0xbc2: 0x1c60, 0xbc3: 0x1a1a, 0xbc4: 0x19f3, 0xbc5: 0x1969,
- 0xbc6: 0x1978, 0xbc7: 0x1948, 0xbc8: 0x1bf0, 0xbc9: 0x1d52, 0xbca: 0x1a4d, 0xbcb: 0x1a35,
- 0xbcc: 0x1c64, 0xbcd: 0x1c70, 0xbce: 0x1a26, 0xbcf: 0x19fc, 0xbd0: 0x1957, 0xbd1: 0x1c1c,
- 0xbd2: 0x1bb0, 0xbd3: 0x1b9c, 0xbd4: 0x1bcc, 0xbd5: 0x1c74, 0xbd6: 0x1a29, 0xbd7: 0x19c9,
- 0xbd8: 0x19ff, 0xbd9: 0x19de, 0xbda: 0x1a41, 0xbdb: 0x1c78, 0xbdc: 0x1a2c, 0xbdd: 0x19c0,
- 0xbde: 0x1a02, 0xbdf: 0x1c3c, 0xbe0: 0x1bf4, 0xbe1: 0x1a14, 0xbe2: 0x1c24, 0xbe3: 0x1c40,
- 0xbe4: 0x1bf8, 0xbe5: 0x1a17, 0xbe6: 0x1c28, 0xbe7: 0x22e8, 0xbe8: 0x22fc, 0xbe9: 0x1996,
- 0xbea: 0x1c20, 0xbeb: 0x1bb4, 0xbec: 0x1ba0, 0xbed: 0x1c48, 0xbee: 0x2716, 0xbef: 0x27ad,
- 0xbf0: 0x1a59, 0xbf1: 0x1a44, 0xbf2: 0x1c7c, 0xbf3: 0x1a2f, 0xbf4: 0x1a50, 0xbf5: 0x1a38,
- 0xbf6: 0x1c68, 0xbf7: 0x1a1d, 0xbf8: 0x19f6, 0xbf9: 0x1981, 0xbfa: 0x1a53, 0xbfb: 0x1a3b,
- 0xbfc: 0x1c6c, 0xbfd: 0x1a20, 0xbfe: 0x19f9, 0xbff: 0x1984,
- // Block 0x30, offset 0xc00
- 0xc00: 0x1c2c, 0xc01: 0x1bb8, 0xc02: 0x1d4d, 0xc03: 0x1939, 0xc04: 0x19ba, 0xc05: 0x19bd,
- 0xc06: 0x22f5, 0xc07: 0x1b94, 0xc08: 0x19c3, 0xc09: 0x194b, 0xc0a: 0x19e1, 0xc0b: 0x194e,
- 0xc0c: 0x19ea, 0xc0d: 0x196c, 0xc0e: 0x196f, 0xc0f: 0x1a05, 0xc10: 0x1a0b, 0xc11: 0x1a0e,
- 0xc12: 0x1c30, 0xc13: 0x1a11, 0xc14: 0x1a23, 0xc15: 0x1c38, 0xc16: 0x1c44, 0xc17: 0x1990,
- 0xc18: 0x1d57, 0xc19: 0x1bbc, 0xc1a: 0x1993, 0xc1b: 0x1a5c, 0xc1c: 0x19a5, 0xc1d: 0x19b4,
- 0xc1e: 0x22e2, 0xc1f: 0x22dc, 0xc20: 0x1cc1, 0xc21: 0x1cd0, 0xc22: 0x1cdf, 0xc23: 0x1cee,
- 0xc24: 0x1cfd, 0xc25: 0x1d0c, 0xc26: 0x1d1b, 0xc27: 0x1d2a, 0xc28: 0x1d39, 0xc29: 0x2186,
- 0xc2a: 0x2198, 0xc2b: 0x21aa, 0xc2c: 0x21bc, 0xc2d: 0x21c8, 0xc2e: 0x21d4, 0xc2f: 0x21e0,
- 0xc30: 0x21ec, 0xc31: 0x21f8, 0xc32: 0x2204, 0xc33: 0x2240, 0xc34: 0x224c, 0xc35: 0x2258,
- 0xc36: 0x2264, 0xc37: 0x2270, 0xc38: 0x227c, 0xc39: 0x2282, 0xc3a: 0x2288, 0xc3b: 0x228e,
- 0xc3c: 0x2294, 0xc3d: 0x22a6, 0xc3e: 0x22ac, 0xc3f: 0x1c10,
- // Block 0x31, offset 0xc40
- 0xc40: 0x1377, 0xc41: 0x0cfb, 0xc42: 0x13d3, 0xc43: 0x139f, 0xc44: 0x0e57, 0xc45: 0x06eb,
- 0xc46: 0x08df, 0xc47: 0x162b, 0xc48: 0x162b, 0xc49: 0x0a0b, 0xc4a: 0x145f, 0xc4b: 0x0943,
- 0xc4c: 0x0a07, 0xc4d: 0x0bef, 0xc4e: 0x0fcf, 0xc4f: 0x115f, 0xc50: 0x1297, 0xc51: 0x12d3,
- 0xc52: 0x1307, 0xc53: 0x141b, 0xc54: 0x0d73, 0xc55: 0x0dff, 0xc56: 0x0eab, 0xc57: 0x0f43,
- 0xc58: 0x125f, 0xc59: 0x1447, 0xc5a: 0x1573, 0xc5b: 0x070f, 0xc5c: 0x08b3, 0xc5d: 0x0d87,
- 0xc5e: 0x0ecf, 0xc5f: 0x1293, 0xc60: 0x15c3, 0xc61: 0x0ab3, 0xc62: 0x0e77, 0xc63: 0x1283,
- 0xc64: 0x1317, 0xc65: 0x0c23, 0xc66: 0x11bb, 0xc67: 0x12df, 0xc68: 0x0b1f, 0xc69: 0x0d0f,
- 0xc6a: 0x0e17, 0xc6b: 0x0f1b, 0xc6c: 0x1427, 0xc6d: 0x074f, 0xc6e: 0x07e7, 0xc6f: 0x0853,
- 0xc70: 0x0c8b, 0xc71: 0x0d7f, 0xc72: 0x0ecb, 0xc73: 0x0fef, 0xc74: 0x1177, 0xc75: 0x128b,
- 0xc76: 0x12a3, 0xc77: 0x13c7, 0xc78: 0x14ef, 0xc79: 0x15a3, 0xc7a: 0x15bf, 0xc7b: 0x102b,
- 0xc7c: 0x106b, 0xc7d: 0x1123, 0xc7e: 0x1243, 0xc7f: 0x147b,
- // Block 0x32, offset 0xc80
- 0xc80: 0x15cb, 0xc81: 0x134b, 0xc82: 0x09c7, 0xc83: 0x0b3b, 0xc84: 0x10db, 0xc85: 0x119b,
- 0xc86: 0x0eff, 0xc87: 0x1033, 0xc88: 0x1397, 0xc89: 0x14e7, 0xc8a: 0x09c3, 0xc8b: 0x0a8f,
- 0xc8c: 0x0d77, 0xc8d: 0x0e2b, 0xc8e: 0x0e5f, 0xc8f: 0x1113, 0xc90: 0x113b, 0xc91: 0x14a7,
- 0xc92: 0x084f, 0xc93: 0x11a7, 0xc94: 0x07f3, 0xc95: 0x07ef, 0xc96: 0x1097, 0xc97: 0x1127,
- 0xc98: 0x125b, 0xc99: 0x14af, 0xc9a: 0x1367, 0xc9b: 0x0c27, 0xc9c: 0x0d73, 0xc9d: 0x1357,
- 0xc9e: 0x06f7, 0xc9f: 0x0a63, 0xca0: 0x0b93, 0xca1: 0x0f2f, 0xca2: 0x0faf, 0xca3: 0x0873,
- 0xca4: 0x103b, 0xca5: 0x075f, 0xca6: 0x0b77, 0xca7: 0x06d7, 0xca8: 0x0deb, 0xca9: 0x0ca3,
- 0xcaa: 0x110f, 0xcab: 0x08c7, 0xcac: 0x09b3, 0xcad: 0x0ffb, 0xcae: 0x1263, 0xcaf: 0x133b,
- 0xcb0: 0x0db7, 0xcb1: 0x13f7, 0xcb2: 0x0de3, 0xcb3: 0x0c37, 0xcb4: 0x121b, 0xcb5: 0x0c57,
- 0xcb6: 0x0fab, 0xcb7: 0x072b, 0xcb8: 0x07a7, 0xcb9: 0x07eb, 0xcba: 0x0d53, 0xcbb: 0x10fb,
- 0xcbc: 0x11f3, 0xcbd: 0x1347, 0xcbe: 0x145b, 0xcbf: 0x085b,
- // Block 0x33, offset 0xcc0
- 0xcc0: 0x090f, 0xcc1: 0x0a17, 0xcc2: 0x0b2f, 0xcc3: 0x0cbf, 0xcc4: 0x0e7b, 0xcc5: 0x103f,
- 0xcc6: 0x1497, 0xcc7: 0x157b, 0xcc8: 0x15cf, 0xcc9: 0x15e7, 0xcca: 0x0837, 0xccb: 0x0cf3,
- 0xccc: 0x0da3, 0xccd: 0x13eb, 0xcce: 0x0afb, 0xccf: 0x0bd7, 0xcd0: 0x0bf3, 0xcd1: 0x0c83,
- 0xcd2: 0x0e6b, 0xcd3: 0x0eb7, 0xcd4: 0x0f67, 0xcd5: 0x108b, 0xcd6: 0x112f, 0xcd7: 0x1193,
- 0xcd8: 0x13db, 0xcd9: 0x126b, 0xcda: 0x1403, 0xcdb: 0x147f, 0xcdc: 0x080f, 0xcdd: 0x083b,
- 0xcde: 0x0923, 0xcdf: 0x0ea7, 0xce0: 0x12f3, 0xce1: 0x133b, 0xce2: 0x0b1b, 0xce3: 0x0b8b,
- 0xce4: 0x0c4f, 0xce5: 0x0daf, 0xce6: 0x10d7, 0xce7: 0x0f23, 0xce8: 0x073b, 0xce9: 0x097f,
- 0xcea: 0x0a63, 0xceb: 0x0ac7, 0xcec: 0x0b97, 0xced: 0x0f3f, 0xcee: 0x0f5b, 0xcef: 0x116b,
- 0xcf0: 0x118b, 0xcf1: 0x1463, 0xcf2: 0x14e3, 0xcf3: 0x14f3, 0xcf4: 0x152f, 0xcf5: 0x0753,
- 0xcf6: 0x107f, 0xcf7: 0x144f, 0xcf8: 0x14cb, 0xcf9: 0x0baf, 0xcfa: 0x0717, 0xcfb: 0x0777,
- 0xcfc: 0x0a67, 0xcfd: 0x0a87, 0xcfe: 0x0caf, 0xcff: 0x0d73,
- // Block 0x34, offset 0xd00
- 0xd00: 0x0ec3, 0xd01: 0x0fcb, 0xd02: 0x1277, 0xd03: 0x1417, 0xd04: 0x1623, 0xd05: 0x0ce3,
- 0xd06: 0x14a3, 0xd07: 0x0833, 0xd08: 0x0d2f, 0xd09: 0x0d3b, 0xd0a: 0x0e0f, 0xd0b: 0x0e47,
- 0xd0c: 0x0f4b, 0xd0d: 0x0fa7, 0xd0e: 0x1027, 0xd0f: 0x110b, 0xd10: 0x153b, 0xd11: 0x07af,
- 0xd12: 0x0c03, 0xd13: 0x14b3, 0xd14: 0x0767, 0xd15: 0x0aab, 0xd16: 0x0e2f, 0xd17: 0x13df,
- 0xd18: 0x0b67, 0xd19: 0x0bb7, 0xd1a: 0x0d43, 0xd1b: 0x0f2f, 0xd1c: 0x14bb, 0xd1d: 0x0817,
- 0xd1e: 0x08ff, 0xd1f: 0x0a97, 0xd20: 0x0cd3, 0xd21: 0x0d1f, 0xd22: 0x0d5f, 0xd23: 0x0df3,
- 0xd24: 0x0f47, 0xd25: 0x0fbb, 0xd26: 0x1157, 0xd27: 0x12f7, 0xd28: 0x1303, 0xd29: 0x1457,
- 0xd2a: 0x14d7, 0xd2b: 0x0883, 0xd2c: 0x0e4b, 0xd2d: 0x0903, 0xd2e: 0x0ec7, 0xd2f: 0x0f6b,
- 0xd30: 0x1287, 0xd31: 0x14bf, 0xd32: 0x15ab, 0xd33: 0x15d3, 0xd34: 0x0d37, 0xd35: 0x0e27,
- 0xd36: 0x11c3, 0xd37: 0x10b7, 0xd38: 0x10c3, 0xd39: 0x10e7, 0xd3a: 0x0f17, 0xd3b: 0x0e9f,
- 0xd3c: 0x1363, 0xd3d: 0x0733, 0xd3e: 0x122b, 0xd3f: 0x081b,
- // Block 0x35, offset 0xd40
- 0xd40: 0x080b, 0xd41: 0x0b0b, 0xd42: 0x0c2b, 0xd43: 0x10f3, 0xd44: 0x0a53, 0xd45: 0x0e03,
- 0xd46: 0x0cef, 0xd47: 0x13e7, 0xd48: 0x12e7, 0xd49: 0x14ab, 0xd4a: 0x1323, 0xd4b: 0x0b27,
- 0xd4c: 0x0787, 0xd4d: 0x095b, 0xd50: 0x09af,
- 0xd52: 0x0cdf, 0xd55: 0x07f7, 0xd56: 0x0f1f, 0xd57: 0x0fe3,
- 0xd58: 0x1047, 0xd59: 0x1063, 0xd5a: 0x1067, 0xd5b: 0x107b, 0xd5c: 0x14fb, 0xd5d: 0x10eb,
- 0xd5e: 0x116f, 0xd60: 0x128f, 0xd62: 0x1353,
- 0xd65: 0x1407, 0xd66: 0x1433,
- 0xd6a: 0x154f, 0xd6b: 0x1553, 0xd6c: 0x1557, 0xd6d: 0x15bb, 0xd6e: 0x142b, 0xd6f: 0x14c7,
- 0xd70: 0x0757, 0xd71: 0x077b, 0xd72: 0x078f, 0xd73: 0x084b, 0xd74: 0x0857, 0xd75: 0x0897,
- 0xd76: 0x094b, 0xd77: 0x0967, 0xd78: 0x096f, 0xd79: 0x09ab, 0xd7a: 0x09b7, 0xd7b: 0x0a93,
- 0xd7c: 0x0a9b, 0xd7d: 0x0ba3, 0xd7e: 0x0bcb, 0xd7f: 0x0bd3,
- // Block 0x36, offset 0xd80
- 0xd80: 0x0beb, 0xd81: 0x0c97, 0xd82: 0x0cc7, 0xd83: 0x0ce7, 0xd84: 0x0d57, 0xd85: 0x0e1b,
- 0xd86: 0x0e37, 0xd87: 0x0e67, 0xd88: 0x0ebb, 0xd89: 0x0edb, 0xd8a: 0x0f4f, 0xd8b: 0x102f,
- 0xd8c: 0x104b, 0xd8d: 0x1053, 0xd8e: 0x104f, 0xd8f: 0x1057, 0xd90: 0x105b, 0xd91: 0x105f,
- 0xd92: 0x1073, 0xd93: 0x1077, 0xd94: 0x109b, 0xd95: 0x10af, 0xd96: 0x10cb, 0xd97: 0x112f,
- 0xd98: 0x1137, 0xd99: 0x113f, 0xd9a: 0x1153, 0xd9b: 0x117b, 0xd9c: 0x11cb, 0xd9d: 0x11ff,
- 0xd9e: 0x11ff, 0xd9f: 0x1267, 0xda0: 0x130f, 0xda1: 0x1327, 0xda2: 0x135b, 0xda3: 0x135f,
- 0xda4: 0x13a3, 0xda5: 0x13a7, 0xda6: 0x13ff, 0xda7: 0x1407, 0xda8: 0x14db, 0xda9: 0x151f,
- 0xdaa: 0x1537, 0xdab: 0x0b9b, 0xdac: 0x171e, 0xdad: 0x11e3,
- 0xdb0: 0x06df, 0xdb1: 0x07e3, 0xdb2: 0x07a3, 0xdb3: 0x074b, 0xdb4: 0x078b, 0xdb5: 0x07b7,
- 0xdb6: 0x0847, 0xdb7: 0x0863, 0xdb8: 0x094b, 0xdb9: 0x0937, 0xdba: 0x0947, 0xdbb: 0x0963,
- 0xdbc: 0x09af, 0xdbd: 0x09bf, 0xdbe: 0x0a03, 0xdbf: 0x0a0f,
- // Block 0x37, offset 0xdc0
- 0xdc0: 0x0a2b, 0xdc1: 0x0a3b, 0xdc2: 0x0b23, 0xdc3: 0x0b2b, 0xdc4: 0x0b5b, 0xdc5: 0x0b7b,
- 0xdc6: 0x0bab, 0xdc7: 0x0bc3, 0xdc8: 0x0bb3, 0xdc9: 0x0bd3, 0xdca: 0x0bc7, 0xdcb: 0x0beb,
- 0xdcc: 0x0c07, 0xdcd: 0x0c5f, 0xdce: 0x0c6b, 0xdcf: 0x0c73, 0xdd0: 0x0c9b, 0xdd1: 0x0cdf,
- 0xdd2: 0x0d0f, 0xdd3: 0x0d13, 0xdd4: 0x0d27, 0xdd5: 0x0da7, 0xdd6: 0x0db7, 0xdd7: 0x0e0f,
- 0xdd8: 0x0e5b, 0xdd9: 0x0e53, 0xdda: 0x0e67, 0xddb: 0x0e83, 0xddc: 0x0ebb, 0xddd: 0x1013,
- 0xdde: 0x0edf, 0xddf: 0x0f13, 0xde0: 0x0f1f, 0xde1: 0x0f5f, 0xde2: 0x0f7b, 0xde3: 0x0f9f,
- 0xde4: 0x0fc3, 0xde5: 0x0fc7, 0xde6: 0x0fe3, 0xde7: 0x0fe7, 0xde8: 0x0ff7, 0xde9: 0x100b,
- 0xdea: 0x1007, 0xdeb: 0x1037, 0xdec: 0x10b3, 0xded: 0x10cb, 0xdee: 0x10e3, 0xdef: 0x111b,
- 0xdf0: 0x112f, 0xdf1: 0x114b, 0xdf2: 0x117b, 0xdf3: 0x122f, 0xdf4: 0x1257, 0xdf5: 0x12cb,
- 0xdf6: 0x1313, 0xdf7: 0x131f, 0xdf8: 0x1327, 0xdf9: 0x133f, 0xdfa: 0x1353, 0xdfb: 0x1343,
- 0xdfc: 0x135b, 0xdfd: 0x1357, 0xdfe: 0x134f, 0xdff: 0x135f,
- // Block 0x38, offset 0xe00
- 0xe00: 0x136b, 0xe01: 0x13a7, 0xe02: 0x13e3, 0xe03: 0x1413, 0xe04: 0x144b, 0xe05: 0x146b,
- 0xe06: 0x14b7, 0xe07: 0x14db, 0xe08: 0x14fb, 0xe09: 0x150f, 0xe0a: 0x151f, 0xe0b: 0x152b,
- 0xe0c: 0x1537, 0xe0d: 0x158b, 0xe0e: 0x162b, 0xe0f: 0x16b5, 0xe10: 0x16b0, 0xe11: 0x16e2,
- 0xe12: 0x0607, 0xe13: 0x062f, 0xe14: 0x0633, 0xe15: 0x1764, 0xe16: 0x1791, 0xe17: 0x1809,
- 0xe18: 0x1617, 0xe19: 0x1627,
- // Block 0x39, offset 0xe40
- 0xe40: 0x19d5, 0xe41: 0x19d8, 0xe42: 0x19db, 0xe43: 0x1c08, 0xe44: 0x1c0c, 0xe45: 0x1a5f,
- 0xe46: 0x1a5f,
- 0xe53: 0x1d75, 0xe54: 0x1d66, 0xe55: 0x1d6b, 0xe56: 0x1d7a, 0xe57: 0x1d70,
- 0xe5d: 0x4426,
- 0xe5e: 0x8115, 0xe5f: 0x4498, 0xe60: 0x022d, 0xe61: 0x0215, 0xe62: 0x021e, 0xe63: 0x0221,
- 0xe64: 0x0224, 0xe65: 0x0227, 0xe66: 0x022a, 0xe67: 0x0230, 0xe68: 0x0233, 0xe69: 0x0017,
- 0xe6a: 0x4486, 0xe6b: 0x448c, 0xe6c: 0x458a, 0xe6d: 0x4592, 0xe6e: 0x43de, 0xe6f: 0x43e4,
- 0xe70: 0x43ea, 0xe71: 0x43f0, 0xe72: 0x43fc, 0xe73: 0x4402, 0xe74: 0x4408, 0xe75: 0x4414,
- 0xe76: 0x441a, 0xe78: 0x4420, 0xe79: 0x442c, 0xe7a: 0x4432, 0xe7b: 0x4438,
- 0xe7c: 0x4444, 0xe7e: 0x444a,
- // Block 0x3a, offset 0xe80
- 0xe80: 0x4450, 0xe81: 0x4456, 0xe83: 0x445c, 0xe84: 0x4462,
- 0xe86: 0x446e, 0xe87: 0x4474, 0xe88: 0x447a, 0xe89: 0x4480, 0xe8a: 0x4492, 0xe8b: 0x440e,
- 0xe8c: 0x43f6, 0xe8d: 0x443e, 0xe8e: 0x4468, 0xe8f: 0x1d7f, 0xe90: 0x0299, 0xe91: 0x0299,
- 0xe92: 0x02a2, 0xe93: 0x02a2, 0xe94: 0x02a2, 0xe95: 0x02a2, 0xe96: 0x02a5, 0xe97: 0x02a5,
- 0xe98: 0x02a5, 0xe99: 0x02a5, 0xe9a: 0x02ab, 0xe9b: 0x02ab, 0xe9c: 0x02ab, 0xe9d: 0x02ab,
- 0xe9e: 0x029f, 0xe9f: 0x029f, 0xea0: 0x029f, 0xea1: 0x029f, 0xea2: 0x02a8, 0xea3: 0x02a8,
- 0xea4: 0x02a8, 0xea5: 0x02a8, 0xea6: 0x029c, 0xea7: 0x029c, 0xea8: 0x029c, 0xea9: 0x029c,
- 0xeaa: 0x02cf, 0xeab: 0x02cf, 0xeac: 0x02cf, 0xead: 0x02cf, 0xeae: 0x02d2, 0xeaf: 0x02d2,
- 0xeb0: 0x02d2, 0xeb1: 0x02d2, 0xeb2: 0x02b1, 0xeb3: 0x02b1, 0xeb4: 0x02b1, 0xeb5: 0x02b1,
- 0xeb6: 0x02ae, 0xeb7: 0x02ae, 0xeb8: 0x02ae, 0xeb9: 0x02ae, 0xeba: 0x02b4, 0xebb: 0x02b4,
- 0xebc: 0x02b4, 0xebd: 0x02b4, 0xebe: 0x02b7, 0xebf: 0x02b7,
- // Block 0x3b, offset 0xec0
- 0xec0: 0x02b7, 0xec1: 0x02b7, 0xec2: 0x02c0, 0xec3: 0x02c0, 0xec4: 0x02bd, 0xec5: 0x02bd,
- 0xec6: 0x02c3, 0xec7: 0x02c3, 0xec8: 0x02ba, 0xec9: 0x02ba, 0xeca: 0x02c9, 0xecb: 0x02c9,
- 0xecc: 0x02c6, 0xecd: 0x02c6, 0xece: 0x02d5, 0xecf: 0x02d5, 0xed0: 0x02d5, 0xed1: 0x02d5,
- 0xed2: 0x02db, 0xed3: 0x02db, 0xed4: 0x02db, 0xed5: 0x02db, 0xed6: 0x02e1, 0xed7: 0x02e1,
- 0xed8: 0x02e1, 0xed9: 0x02e1, 0xeda: 0x02de, 0xedb: 0x02de, 0xedc: 0x02de, 0xedd: 0x02de,
- 0xede: 0x02e4, 0xedf: 0x02e4, 0xee0: 0x02e7, 0xee1: 0x02e7, 0xee2: 0x02e7, 0xee3: 0x02e7,
- 0xee4: 0x4504, 0xee5: 0x4504, 0xee6: 0x02ed, 0xee7: 0x02ed, 0xee8: 0x02ed, 0xee9: 0x02ed,
- 0xeea: 0x02ea, 0xeeb: 0x02ea, 0xeec: 0x02ea, 0xeed: 0x02ea, 0xeee: 0x0308, 0xeef: 0x0308,
- 0xef0: 0x44fe, 0xef1: 0x44fe,
- // Block 0x3c, offset 0xf00
- 0xf13: 0x02d8, 0xf14: 0x02d8, 0xf15: 0x02d8, 0xf16: 0x02d8, 0xf17: 0x02f6,
- 0xf18: 0x02f6, 0xf19: 0x02f3, 0xf1a: 0x02f3, 0xf1b: 0x02f9, 0xf1c: 0x02f9, 0xf1d: 0x204f,
- 0xf1e: 0x02ff, 0xf1f: 0x02ff, 0xf20: 0x02f0, 0xf21: 0x02f0, 0xf22: 0x02fc, 0xf23: 0x02fc,
- 0xf24: 0x0305, 0xf25: 0x0305, 0xf26: 0x0305, 0xf27: 0x0305, 0xf28: 0x028d, 0xf29: 0x028d,
- 0xf2a: 0x25aa, 0xf2b: 0x25aa, 0xf2c: 0x261a, 0xf2d: 0x261a, 0xf2e: 0x25e9, 0xf2f: 0x25e9,
- 0xf30: 0x2605, 0xf31: 0x2605, 0xf32: 0x25fe, 0xf33: 0x25fe, 0xf34: 0x260c, 0xf35: 0x260c,
- 0xf36: 0x2613, 0xf37: 0x2613, 0xf38: 0x2613, 0xf39: 0x25f0, 0xf3a: 0x25f0, 0xf3b: 0x25f0,
- 0xf3c: 0x0302, 0xf3d: 0x0302, 0xf3e: 0x0302, 0xf3f: 0x0302,
- // Block 0x3d, offset 0xf40
- 0xf40: 0x25b1, 0xf41: 0x25b8, 0xf42: 0x25d4, 0xf43: 0x25f0, 0xf44: 0x25f7, 0xf45: 0x1d89,
- 0xf46: 0x1d8e, 0xf47: 0x1d93, 0xf48: 0x1da2, 0xf49: 0x1db1, 0xf4a: 0x1db6, 0xf4b: 0x1dbb,
- 0xf4c: 0x1dc0, 0xf4d: 0x1dc5, 0xf4e: 0x1dd4, 0xf4f: 0x1de3, 0xf50: 0x1de8, 0xf51: 0x1ded,
- 0xf52: 0x1dfc, 0xf53: 0x1e0b, 0xf54: 0x1e10, 0xf55: 0x1e15, 0xf56: 0x1e1a, 0xf57: 0x1e29,
- 0xf58: 0x1e2e, 0xf59: 0x1e3d, 0xf5a: 0x1e42, 0xf5b: 0x1e47, 0xf5c: 0x1e56, 0xf5d: 0x1e5b,
- 0xf5e: 0x1e60, 0xf5f: 0x1e6a, 0xf60: 0x1ea6, 0xf61: 0x1eb5, 0xf62: 0x1ec4, 0xf63: 0x1ec9,
- 0xf64: 0x1ece, 0xf65: 0x1ed8, 0xf66: 0x1ee7, 0xf67: 0x1eec, 0xf68: 0x1efb, 0xf69: 0x1f00,
- 0xf6a: 0x1f05, 0xf6b: 0x1f14, 0xf6c: 0x1f19, 0xf6d: 0x1f28, 0xf6e: 0x1f2d, 0xf6f: 0x1f32,
- 0xf70: 0x1f37, 0xf71: 0x1f3c, 0xf72: 0x1f41, 0xf73: 0x1f46, 0xf74: 0x1f4b, 0xf75: 0x1f50,
- 0xf76: 0x1f55, 0xf77: 0x1f5a, 0xf78: 0x1f5f, 0xf79: 0x1f64, 0xf7a: 0x1f69, 0xf7b: 0x1f6e,
- 0xf7c: 0x1f73, 0xf7d: 0x1f78, 0xf7e: 0x1f7d, 0xf7f: 0x1f87,
- // Block 0x3e, offset 0xf80
- 0xf80: 0x1f8c, 0xf81: 0x1f91, 0xf82: 0x1f96, 0xf83: 0x1fa0, 0xf84: 0x1fa5, 0xf85: 0x1faf,
- 0xf86: 0x1fb4, 0xf87: 0x1fb9, 0xf88: 0x1fbe, 0xf89: 0x1fc3, 0xf8a: 0x1fc8, 0xf8b: 0x1fcd,
- 0xf8c: 0x1fd2, 0xf8d: 0x1fd7, 0xf8e: 0x1fe6, 0xf8f: 0x1ff5, 0xf90: 0x1ffa, 0xf91: 0x1fff,
- 0xf92: 0x2004, 0xf93: 0x2009, 0xf94: 0x200e, 0xf95: 0x2018, 0xf96: 0x201d, 0xf97: 0x2022,
- 0xf98: 0x2031, 0xf99: 0x2040, 0xf9a: 0x2045, 0xf9b: 0x44b6, 0xf9c: 0x44bc, 0xf9d: 0x44f2,
- 0xf9e: 0x4549, 0xf9f: 0x4550, 0xfa0: 0x4557, 0xfa1: 0x455e, 0xfa2: 0x4565, 0xfa3: 0x456c,
- 0xfa4: 0x25c6, 0xfa5: 0x25cd, 0xfa6: 0x25d4, 0xfa7: 0x25db, 0xfa8: 0x25f0, 0xfa9: 0x25f7,
- 0xfaa: 0x1d98, 0xfab: 0x1d9d, 0xfac: 0x1da2, 0xfad: 0x1da7, 0xfae: 0x1db1, 0xfaf: 0x1db6,
- 0xfb0: 0x1dca, 0xfb1: 0x1dcf, 0xfb2: 0x1dd4, 0xfb3: 0x1dd9, 0xfb4: 0x1de3, 0xfb5: 0x1de8,
- 0xfb6: 0x1df2, 0xfb7: 0x1df7, 0xfb8: 0x1dfc, 0xfb9: 0x1e01, 0xfba: 0x1e0b, 0xfbb: 0x1e10,
- 0xfbc: 0x1f3c, 0xfbd: 0x1f41, 0xfbe: 0x1f50, 0xfbf: 0x1f55,
- // Block 0x3f, offset 0xfc0
- 0xfc0: 0x1f5a, 0xfc1: 0x1f6e, 0xfc2: 0x1f73, 0xfc3: 0x1f78, 0xfc4: 0x1f7d, 0xfc5: 0x1f96,
- 0xfc6: 0x1fa0, 0xfc7: 0x1fa5, 0xfc8: 0x1faa, 0xfc9: 0x1fbe, 0xfca: 0x1fdc, 0xfcb: 0x1fe1,
- 0xfcc: 0x1fe6, 0xfcd: 0x1feb, 0xfce: 0x1ff5, 0xfcf: 0x1ffa, 0xfd0: 0x44f2, 0xfd1: 0x2027,
- 0xfd2: 0x202c, 0xfd3: 0x2031, 0xfd4: 0x2036, 0xfd5: 0x2040, 0xfd6: 0x2045, 0xfd7: 0x25b1,
- 0xfd8: 0x25b8, 0xfd9: 0x25bf, 0xfda: 0x25d4, 0xfdb: 0x25e2, 0xfdc: 0x1d89, 0xfdd: 0x1d8e,
- 0xfde: 0x1d93, 0xfdf: 0x1da2, 0xfe0: 0x1dac, 0xfe1: 0x1dbb, 0xfe2: 0x1dc0, 0xfe3: 0x1dc5,
- 0xfe4: 0x1dd4, 0xfe5: 0x1dde, 0xfe6: 0x1dfc, 0xfe7: 0x1e15, 0xfe8: 0x1e1a, 0xfe9: 0x1e29,
- 0xfea: 0x1e2e, 0xfeb: 0x1e3d, 0xfec: 0x1e47, 0xfed: 0x1e56, 0xfee: 0x1e5b, 0xfef: 0x1e60,
- 0xff0: 0x1e6a, 0xff1: 0x1ea6, 0xff2: 0x1eab, 0xff3: 0x1eb5, 0xff4: 0x1ec4, 0xff5: 0x1ec9,
- 0xff6: 0x1ece, 0xff7: 0x1ed8, 0xff8: 0x1ee7, 0xff9: 0x1efb, 0xffa: 0x1f00, 0xffb: 0x1f05,
- 0xffc: 0x1f14, 0xffd: 0x1f19, 0xffe: 0x1f28, 0xfff: 0x1f2d,
- // Block 0x40, offset 0x1000
- 0x1000: 0x1f32, 0x1001: 0x1f37, 0x1002: 0x1f46, 0x1003: 0x1f4b, 0x1004: 0x1f5f, 0x1005: 0x1f64,
- 0x1006: 0x1f69, 0x1007: 0x1f6e, 0x1008: 0x1f73, 0x1009: 0x1f87, 0x100a: 0x1f8c, 0x100b: 0x1f91,
- 0x100c: 0x1f96, 0x100d: 0x1f9b, 0x100e: 0x1faf, 0x100f: 0x1fb4, 0x1010: 0x1fb9, 0x1011: 0x1fbe,
- 0x1012: 0x1fcd, 0x1013: 0x1fd2, 0x1014: 0x1fd7, 0x1015: 0x1fe6, 0x1016: 0x1ff0, 0x1017: 0x1fff,
- 0x1018: 0x2004, 0x1019: 0x44e6, 0x101a: 0x2018, 0x101b: 0x201d, 0x101c: 0x2022, 0x101d: 0x2031,
- 0x101e: 0x203b, 0x101f: 0x25d4, 0x1020: 0x25e2, 0x1021: 0x1da2, 0x1022: 0x1dac, 0x1023: 0x1dd4,
- 0x1024: 0x1dde, 0x1025: 0x1dfc, 0x1026: 0x1e06, 0x1027: 0x1e6a, 0x1028: 0x1e6f, 0x1029: 0x1e92,
- 0x102a: 0x1e97, 0x102b: 0x1f6e, 0x102c: 0x1f73, 0x102d: 0x1f96, 0x102e: 0x1fe6, 0x102f: 0x1ff0,
- 0x1030: 0x2031, 0x1031: 0x203b, 0x1032: 0x459a, 0x1033: 0x45a2, 0x1034: 0x45aa, 0x1035: 0x1ef1,
- 0x1036: 0x1ef6, 0x1037: 0x1f0a, 0x1038: 0x1f0f, 0x1039: 0x1f1e, 0x103a: 0x1f23, 0x103b: 0x1e74,
- 0x103c: 0x1e79, 0x103d: 0x1e9c, 0x103e: 0x1ea1, 0x103f: 0x1e33,
- // Block 0x41, offset 0x1040
- 0x1040: 0x1e38, 0x1041: 0x1e1f, 0x1042: 0x1e24, 0x1043: 0x1e4c, 0x1044: 0x1e51, 0x1045: 0x1eba,
- 0x1046: 0x1ebf, 0x1047: 0x1edd, 0x1048: 0x1ee2, 0x1049: 0x1e7e, 0x104a: 0x1e83, 0x104b: 0x1e88,
- 0x104c: 0x1e92, 0x104d: 0x1e8d, 0x104e: 0x1e65, 0x104f: 0x1eb0, 0x1050: 0x1ed3, 0x1051: 0x1ef1,
- 0x1052: 0x1ef6, 0x1053: 0x1f0a, 0x1054: 0x1f0f, 0x1055: 0x1f1e, 0x1056: 0x1f23, 0x1057: 0x1e74,
- 0x1058: 0x1e79, 0x1059: 0x1e9c, 0x105a: 0x1ea1, 0x105b: 0x1e33, 0x105c: 0x1e38, 0x105d: 0x1e1f,
- 0x105e: 0x1e24, 0x105f: 0x1e4c, 0x1060: 0x1e51, 0x1061: 0x1eba, 0x1062: 0x1ebf, 0x1063: 0x1edd,
- 0x1064: 0x1ee2, 0x1065: 0x1e7e, 0x1066: 0x1e83, 0x1067: 0x1e88, 0x1068: 0x1e92, 0x1069: 0x1e8d,
- 0x106a: 0x1e65, 0x106b: 0x1eb0, 0x106c: 0x1ed3, 0x106d: 0x1e7e, 0x106e: 0x1e83, 0x106f: 0x1e88,
- 0x1070: 0x1e92, 0x1071: 0x1e6f, 0x1072: 0x1e97, 0x1073: 0x1eec, 0x1074: 0x1e56, 0x1075: 0x1e5b,
- 0x1076: 0x1e60, 0x1077: 0x1e7e, 0x1078: 0x1e83, 0x1079: 0x1e88, 0x107a: 0x1eec, 0x107b: 0x1efb,
- 0x107c: 0x449e, 0x107d: 0x449e,
- // Block 0x42, offset 0x1080
- 0x1090: 0x2311, 0x1091: 0x2326,
- 0x1092: 0x2326, 0x1093: 0x232d, 0x1094: 0x2334, 0x1095: 0x2349, 0x1096: 0x2350, 0x1097: 0x2357,
- 0x1098: 0x237a, 0x1099: 0x237a, 0x109a: 0x239d, 0x109b: 0x2396, 0x109c: 0x23b2, 0x109d: 0x23a4,
- 0x109e: 0x23ab, 0x109f: 0x23ce, 0x10a0: 0x23ce, 0x10a1: 0x23c7, 0x10a2: 0x23d5, 0x10a3: 0x23d5,
- 0x10a4: 0x23ff, 0x10a5: 0x23ff, 0x10a6: 0x241b, 0x10a7: 0x23e3, 0x10a8: 0x23e3, 0x10a9: 0x23dc,
- 0x10aa: 0x23f1, 0x10ab: 0x23f1, 0x10ac: 0x23f8, 0x10ad: 0x23f8, 0x10ae: 0x2422, 0x10af: 0x2430,
- 0x10b0: 0x2430, 0x10b1: 0x2437, 0x10b2: 0x2437, 0x10b3: 0x243e, 0x10b4: 0x2445, 0x10b5: 0x244c,
- 0x10b6: 0x2453, 0x10b7: 0x2453, 0x10b8: 0x245a, 0x10b9: 0x2468, 0x10ba: 0x2476, 0x10bb: 0x246f,
- 0x10bc: 0x247d, 0x10bd: 0x247d, 0x10be: 0x2492, 0x10bf: 0x2499,
- // Block 0x43, offset 0x10c0
- 0x10c0: 0x24ca, 0x10c1: 0x24d8, 0x10c2: 0x24d1, 0x10c3: 0x24b5, 0x10c4: 0x24b5, 0x10c5: 0x24df,
- 0x10c6: 0x24df, 0x10c7: 0x24e6, 0x10c8: 0x24e6, 0x10c9: 0x2510, 0x10ca: 0x2517, 0x10cb: 0x251e,
- 0x10cc: 0x24f4, 0x10cd: 0x2502, 0x10ce: 0x2525, 0x10cf: 0x252c,
- 0x10d2: 0x24fb, 0x10d3: 0x2580, 0x10d4: 0x2587, 0x10d5: 0x255d, 0x10d6: 0x2564, 0x10d7: 0x2548,
- 0x10d8: 0x2548, 0x10d9: 0x254f, 0x10da: 0x2579, 0x10db: 0x2572, 0x10dc: 0x259c, 0x10dd: 0x259c,
- 0x10de: 0x230a, 0x10df: 0x231f, 0x10e0: 0x2318, 0x10e1: 0x2342, 0x10e2: 0x233b, 0x10e3: 0x2365,
- 0x10e4: 0x235e, 0x10e5: 0x2388, 0x10e6: 0x236c, 0x10e7: 0x2381, 0x10e8: 0x23b9, 0x10e9: 0x2406,
- 0x10ea: 0x23ea, 0x10eb: 0x2429, 0x10ec: 0x24c3, 0x10ed: 0x24ed, 0x10ee: 0x2595, 0x10ef: 0x258e,
- 0x10f0: 0x25a3, 0x10f1: 0x253a, 0x10f2: 0x24a0, 0x10f3: 0x256b, 0x10f4: 0x2492, 0x10f5: 0x24ca,
- 0x10f6: 0x2461, 0x10f7: 0x24ae, 0x10f8: 0x2541, 0x10f9: 0x2533, 0x10fa: 0x24bc, 0x10fb: 0x24a7,
- 0x10fc: 0x24bc, 0x10fd: 0x2541, 0x10fe: 0x2373, 0x10ff: 0x238f,
- // Block 0x44, offset 0x1100
- 0x1100: 0x2509, 0x1101: 0x2484, 0x1102: 0x2303, 0x1103: 0x24a7, 0x1104: 0x244c, 0x1105: 0x241b,
- 0x1106: 0x23c0, 0x1107: 0x2556,
- 0x1130: 0x2414, 0x1131: 0x248b, 0x1132: 0x27bf, 0x1133: 0x27b6, 0x1134: 0x27ec, 0x1135: 0x27da,
- 0x1136: 0x27c8, 0x1137: 0x27e3, 0x1138: 0x27f5, 0x1139: 0x240d, 0x113a: 0x2c7c, 0x113b: 0x2afc,
- 0x113c: 0x27d1,
- // Block 0x45, offset 0x1140
- 0x1150: 0x0019, 0x1151: 0x0483,
- 0x1152: 0x0487, 0x1153: 0x0035, 0x1154: 0x0037, 0x1155: 0x0003, 0x1156: 0x003f, 0x1157: 0x04bf,
- 0x1158: 0x04c3, 0x1159: 0x1b5c,
- 0x1160: 0x8132, 0x1161: 0x8132, 0x1162: 0x8132, 0x1163: 0x8132,
- 0x1164: 0x8132, 0x1165: 0x8132, 0x1166: 0x8132, 0x1167: 0x812d, 0x1168: 0x812d, 0x1169: 0x812d,
- 0x116a: 0x812d, 0x116b: 0x812d, 0x116c: 0x812d, 0x116d: 0x812d, 0x116e: 0x8132, 0x116f: 0x8132,
- 0x1170: 0x1873, 0x1171: 0x0443, 0x1172: 0x043f, 0x1173: 0x007f, 0x1174: 0x007f, 0x1175: 0x0011,
- 0x1176: 0x0013, 0x1177: 0x00b7, 0x1178: 0x00bb, 0x1179: 0x04b7, 0x117a: 0x04bb, 0x117b: 0x04ab,
- 0x117c: 0x04af, 0x117d: 0x0493, 0x117e: 0x0497, 0x117f: 0x048b,
- // Block 0x46, offset 0x1180
- 0x1180: 0x048f, 0x1181: 0x049b, 0x1182: 0x049f, 0x1183: 0x04a3, 0x1184: 0x04a7,
- 0x1187: 0x0077, 0x1188: 0x007b, 0x1189: 0x4269, 0x118a: 0x4269, 0x118b: 0x4269,
- 0x118c: 0x4269, 0x118d: 0x007f, 0x118e: 0x007f, 0x118f: 0x007f, 0x1190: 0x0019, 0x1191: 0x0483,
- 0x1192: 0x001d, 0x1194: 0x0037, 0x1195: 0x0035, 0x1196: 0x003f, 0x1197: 0x0003,
- 0x1198: 0x0443, 0x1199: 0x0011, 0x119a: 0x0013, 0x119b: 0x00b7, 0x119c: 0x00bb, 0x119d: 0x04b7,
- 0x119e: 0x04bb, 0x119f: 0x0007, 0x11a0: 0x000d, 0x11a1: 0x0015, 0x11a2: 0x0017, 0x11a3: 0x001b,
- 0x11a4: 0x0039, 0x11a5: 0x003d, 0x11a6: 0x003b, 0x11a8: 0x0079, 0x11a9: 0x0009,
- 0x11aa: 0x000b, 0x11ab: 0x0041,
- 0x11b0: 0x42aa, 0x11b1: 0x44c2, 0x11b2: 0x42af, 0x11b4: 0x42b4,
- 0x11b6: 0x42b9, 0x11b7: 0x44c8, 0x11b8: 0x42be, 0x11b9: 0x44ce, 0x11ba: 0x42c3, 0x11bb: 0x44d4,
- 0x11bc: 0x42c8, 0x11bd: 0x44da, 0x11be: 0x42cd, 0x11bf: 0x44e0,
- // Block 0x47, offset 0x11c0
- 0x11c0: 0x0236, 0x11c1: 0x44a4, 0x11c2: 0x44a4, 0x11c3: 0x44aa, 0x11c4: 0x44aa, 0x11c5: 0x44ec,
- 0x11c6: 0x44ec, 0x11c7: 0x44b0, 0x11c8: 0x44b0, 0x11c9: 0x44f8, 0x11ca: 0x44f8, 0x11cb: 0x44f8,
- 0x11cc: 0x44f8, 0x11cd: 0x0239, 0x11ce: 0x0239, 0x11cf: 0x023c, 0x11d0: 0x023c, 0x11d1: 0x023c,
- 0x11d2: 0x023c, 0x11d3: 0x023f, 0x11d4: 0x023f, 0x11d5: 0x0242, 0x11d6: 0x0242, 0x11d7: 0x0242,
- 0x11d8: 0x0242, 0x11d9: 0x0245, 0x11da: 0x0245, 0x11db: 0x0245, 0x11dc: 0x0245, 0x11dd: 0x0248,
- 0x11de: 0x0248, 0x11df: 0x0248, 0x11e0: 0x0248, 0x11e1: 0x024b, 0x11e2: 0x024b, 0x11e3: 0x024b,
- 0x11e4: 0x024b, 0x11e5: 0x024e, 0x11e6: 0x024e, 0x11e7: 0x024e, 0x11e8: 0x024e, 0x11e9: 0x0251,
- 0x11ea: 0x0251, 0x11eb: 0x0254, 0x11ec: 0x0254, 0x11ed: 0x0257, 0x11ee: 0x0257, 0x11ef: 0x025a,
- 0x11f0: 0x025a, 0x11f1: 0x025d, 0x11f2: 0x025d, 0x11f3: 0x025d, 0x11f4: 0x025d, 0x11f5: 0x0260,
- 0x11f6: 0x0260, 0x11f7: 0x0260, 0x11f8: 0x0260, 0x11f9: 0x0263, 0x11fa: 0x0263, 0x11fb: 0x0263,
- 0x11fc: 0x0263, 0x11fd: 0x0266, 0x11fe: 0x0266, 0x11ff: 0x0266,
- // Block 0x48, offset 0x1200
- 0x1200: 0x0266, 0x1201: 0x0269, 0x1202: 0x0269, 0x1203: 0x0269, 0x1204: 0x0269, 0x1205: 0x026c,
- 0x1206: 0x026c, 0x1207: 0x026c, 0x1208: 0x026c, 0x1209: 0x026f, 0x120a: 0x026f, 0x120b: 0x026f,
- 0x120c: 0x026f, 0x120d: 0x0272, 0x120e: 0x0272, 0x120f: 0x0272, 0x1210: 0x0272, 0x1211: 0x0275,
- 0x1212: 0x0275, 0x1213: 0x0275, 0x1214: 0x0275, 0x1215: 0x0278, 0x1216: 0x0278, 0x1217: 0x0278,
- 0x1218: 0x0278, 0x1219: 0x027b, 0x121a: 0x027b, 0x121b: 0x027b, 0x121c: 0x027b, 0x121d: 0x027e,
- 0x121e: 0x027e, 0x121f: 0x027e, 0x1220: 0x027e, 0x1221: 0x0281, 0x1222: 0x0281, 0x1223: 0x0281,
- 0x1224: 0x0281, 0x1225: 0x0284, 0x1226: 0x0284, 0x1227: 0x0284, 0x1228: 0x0284, 0x1229: 0x0287,
- 0x122a: 0x0287, 0x122b: 0x0287, 0x122c: 0x0287, 0x122d: 0x028a, 0x122e: 0x028a, 0x122f: 0x028d,
- 0x1230: 0x028d, 0x1231: 0x0290, 0x1232: 0x0290, 0x1233: 0x0290, 0x1234: 0x0290, 0x1235: 0x2e00,
- 0x1236: 0x2e00, 0x1237: 0x2e08, 0x1238: 0x2e08, 0x1239: 0x2e10, 0x123a: 0x2e10, 0x123b: 0x1f82,
- 0x123c: 0x1f82,
- // Block 0x49, offset 0x1240
- 0x1240: 0x0081, 0x1241: 0x0083, 0x1242: 0x0085, 0x1243: 0x0087, 0x1244: 0x0089, 0x1245: 0x008b,
- 0x1246: 0x008d, 0x1247: 0x008f, 0x1248: 0x0091, 0x1249: 0x0093, 0x124a: 0x0095, 0x124b: 0x0097,
- 0x124c: 0x0099, 0x124d: 0x009b, 0x124e: 0x009d, 0x124f: 0x009f, 0x1250: 0x00a1, 0x1251: 0x00a3,
- 0x1252: 0x00a5, 0x1253: 0x00a7, 0x1254: 0x00a9, 0x1255: 0x00ab, 0x1256: 0x00ad, 0x1257: 0x00af,
- 0x1258: 0x00b1, 0x1259: 0x00b3, 0x125a: 0x00b5, 0x125b: 0x00b7, 0x125c: 0x00b9, 0x125d: 0x00bb,
- 0x125e: 0x00bd, 0x125f: 0x0477, 0x1260: 0x047b, 0x1261: 0x0487, 0x1262: 0x049b, 0x1263: 0x049f,
- 0x1264: 0x0483, 0x1265: 0x05ab, 0x1266: 0x05a3, 0x1267: 0x04c7, 0x1268: 0x04cf, 0x1269: 0x04d7,
- 0x126a: 0x04df, 0x126b: 0x04e7, 0x126c: 0x056b, 0x126d: 0x0573, 0x126e: 0x057b, 0x126f: 0x051f,
- 0x1270: 0x05af, 0x1271: 0x04cb, 0x1272: 0x04d3, 0x1273: 0x04db, 0x1274: 0x04e3, 0x1275: 0x04eb,
- 0x1276: 0x04ef, 0x1277: 0x04f3, 0x1278: 0x04f7, 0x1279: 0x04fb, 0x127a: 0x04ff, 0x127b: 0x0503,
- 0x127c: 0x0507, 0x127d: 0x050b, 0x127e: 0x050f, 0x127f: 0x0513,
- // Block 0x4a, offset 0x1280
- 0x1280: 0x0517, 0x1281: 0x051b, 0x1282: 0x0523, 0x1283: 0x0527, 0x1284: 0x052b, 0x1285: 0x052f,
- 0x1286: 0x0533, 0x1287: 0x0537, 0x1288: 0x053b, 0x1289: 0x053f, 0x128a: 0x0543, 0x128b: 0x0547,
- 0x128c: 0x054b, 0x128d: 0x054f, 0x128e: 0x0553, 0x128f: 0x0557, 0x1290: 0x055b, 0x1291: 0x055f,
- 0x1292: 0x0563, 0x1293: 0x0567, 0x1294: 0x056f, 0x1295: 0x0577, 0x1296: 0x057f, 0x1297: 0x0583,
- 0x1298: 0x0587, 0x1299: 0x058b, 0x129a: 0x058f, 0x129b: 0x0593, 0x129c: 0x0597, 0x129d: 0x05a7,
- 0x129e: 0x4a5a, 0x129f: 0x4a60, 0x12a0: 0x03c3, 0x12a1: 0x0313, 0x12a2: 0x0317, 0x12a3: 0x4345,
- 0x12a4: 0x031b, 0x12a5: 0x434a, 0x12a6: 0x434f, 0x12a7: 0x031f, 0x12a8: 0x0323, 0x12a9: 0x0327,
- 0x12aa: 0x4354, 0x12ab: 0x4359, 0x12ac: 0x435e, 0x12ad: 0x4363, 0x12ae: 0x4368, 0x12af: 0x436d,
- 0x12b0: 0x0367, 0x12b1: 0x032b, 0x12b2: 0x032f, 0x12b3: 0x0333, 0x12b4: 0x037b, 0x12b5: 0x0337,
- 0x12b6: 0x033b, 0x12b7: 0x033f, 0x12b8: 0x0343, 0x12b9: 0x0347, 0x12ba: 0x034b, 0x12bb: 0x034f,
- 0x12bc: 0x0353, 0x12bd: 0x0357, 0x12be: 0x035b,
- // Block 0x4b, offset 0x12c0
- 0x12c2: 0x42dc, 0x12c3: 0x42e1, 0x12c4: 0x42e6, 0x12c5: 0x42eb,
- 0x12c6: 0x42f0, 0x12c7: 0x42f5, 0x12ca: 0x42fa, 0x12cb: 0x42ff,
- 0x12cc: 0x4304, 0x12cd: 0x4309, 0x12ce: 0x430e, 0x12cf: 0x4313,
- 0x12d2: 0x4318, 0x12d3: 0x431d, 0x12d4: 0x4322, 0x12d5: 0x4327, 0x12d6: 0x432c, 0x12d7: 0x4331,
- 0x12da: 0x4336, 0x12db: 0x433b, 0x12dc: 0x4340,
- 0x12e0: 0x00bf, 0x12e1: 0x00c2, 0x12e2: 0x00cb, 0x12e3: 0x4264,
- 0x12e4: 0x00c8, 0x12e5: 0x00c5, 0x12e6: 0x0447, 0x12e8: 0x046b, 0x12e9: 0x044b,
- 0x12ea: 0x044f, 0x12eb: 0x0453, 0x12ec: 0x0457, 0x12ed: 0x046f, 0x12ee: 0x0473,
- // Block 0x4c, offset 0x1300
- 0x1300: 0x0063, 0x1301: 0x0065, 0x1302: 0x0067, 0x1303: 0x0069, 0x1304: 0x006b, 0x1305: 0x006d,
- 0x1306: 0x006f, 0x1307: 0x0071, 0x1308: 0x0073, 0x1309: 0x0075, 0x130a: 0x0083, 0x130b: 0x0085,
- 0x130c: 0x0087, 0x130d: 0x0089, 0x130e: 0x008b, 0x130f: 0x008d, 0x1310: 0x008f, 0x1311: 0x0091,
- 0x1312: 0x0093, 0x1313: 0x0095, 0x1314: 0x0097, 0x1315: 0x0099, 0x1316: 0x009b, 0x1317: 0x009d,
- 0x1318: 0x009f, 0x1319: 0x00a1, 0x131a: 0x00a3, 0x131b: 0x00a5, 0x131c: 0x00a7, 0x131d: 0x00a9,
- 0x131e: 0x00ab, 0x131f: 0x00ad, 0x1320: 0x00af, 0x1321: 0x00b1, 0x1322: 0x00b3, 0x1323: 0x00b5,
- 0x1324: 0x00dd, 0x1325: 0x00f2, 0x1328: 0x0173, 0x1329: 0x0176,
- 0x132a: 0x0179, 0x132b: 0x017c, 0x132c: 0x017f, 0x132d: 0x0182, 0x132e: 0x0185, 0x132f: 0x0188,
- 0x1330: 0x018b, 0x1331: 0x018e, 0x1332: 0x0191, 0x1333: 0x0194, 0x1334: 0x0197, 0x1335: 0x019a,
- 0x1336: 0x019d, 0x1337: 0x01a0, 0x1338: 0x01a3, 0x1339: 0x0188, 0x133a: 0x01a6, 0x133b: 0x01a9,
- 0x133c: 0x01ac, 0x133d: 0x01af, 0x133e: 0x01b2, 0x133f: 0x01b5,
- // Block 0x4d, offset 0x1340
- 0x1340: 0x01fd, 0x1341: 0x0200, 0x1342: 0x0203, 0x1343: 0x045b, 0x1344: 0x01c7, 0x1345: 0x01d0,
- 0x1346: 0x01d6, 0x1347: 0x01fa, 0x1348: 0x01eb, 0x1349: 0x01e8, 0x134a: 0x0206, 0x134b: 0x0209,
- 0x134e: 0x0021, 0x134f: 0x0023, 0x1350: 0x0025, 0x1351: 0x0027,
- 0x1352: 0x0029, 0x1353: 0x002b, 0x1354: 0x002d, 0x1355: 0x002f, 0x1356: 0x0031, 0x1357: 0x0033,
- 0x1358: 0x0021, 0x1359: 0x0023, 0x135a: 0x0025, 0x135b: 0x0027, 0x135c: 0x0029, 0x135d: 0x002b,
- 0x135e: 0x002d, 0x135f: 0x002f, 0x1360: 0x0031, 0x1361: 0x0033, 0x1362: 0x0021, 0x1363: 0x0023,
- 0x1364: 0x0025, 0x1365: 0x0027, 0x1366: 0x0029, 0x1367: 0x002b, 0x1368: 0x002d, 0x1369: 0x002f,
- 0x136a: 0x0031, 0x136b: 0x0033, 0x136c: 0x0021, 0x136d: 0x0023, 0x136e: 0x0025, 0x136f: 0x0027,
- 0x1370: 0x0029, 0x1371: 0x002b, 0x1372: 0x002d, 0x1373: 0x002f, 0x1374: 0x0031, 0x1375: 0x0033,
- 0x1376: 0x0021, 0x1377: 0x0023, 0x1378: 0x0025, 0x1379: 0x0027, 0x137a: 0x0029, 0x137b: 0x002b,
- 0x137c: 0x002d, 0x137d: 0x002f, 0x137e: 0x0031, 0x137f: 0x0033,
- // Block 0x4e, offset 0x1380
- 0x1380: 0x0239, 0x1381: 0x023c, 0x1382: 0x0248, 0x1383: 0x0251, 0x1385: 0x028a,
- 0x1386: 0x025a, 0x1387: 0x024b, 0x1388: 0x0269, 0x1389: 0x0290, 0x138a: 0x027b, 0x138b: 0x027e,
- 0x138c: 0x0281, 0x138d: 0x0284, 0x138e: 0x025d, 0x138f: 0x026f, 0x1390: 0x0275, 0x1391: 0x0263,
- 0x1392: 0x0278, 0x1393: 0x0257, 0x1394: 0x0260, 0x1395: 0x0242, 0x1396: 0x0245, 0x1397: 0x024e,
- 0x1398: 0x0254, 0x1399: 0x0266, 0x139a: 0x026c, 0x139b: 0x0272, 0x139c: 0x0293, 0x139d: 0x02e4,
- 0x139e: 0x02cc, 0x139f: 0x0296, 0x13a1: 0x023c, 0x13a2: 0x0248,
- 0x13a4: 0x0287, 0x13a7: 0x024b, 0x13a9: 0x0290,
- 0x13aa: 0x027b, 0x13ab: 0x027e, 0x13ac: 0x0281, 0x13ad: 0x0284, 0x13ae: 0x025d, 0x13af: 0x026f,
- 0x13b0: 0x0275, 0x13b1: 0x0263, 0x13b2: 0x0278, 0x13b4: 0x0260, 0x13b5: 0x0242,
- 0x13b6: 0x0245, 0x13b7: 0x024e, 0x13b9: 0x0266, 0x13bb: 0x0272,
- // Block 0x4f, offset 0x13c0
- 0x13c2: 0x0248,
- 0x13c7: 0x024b, 0x13c9: 0x0290, 0x13cb: 0x027e,
- 0x13cd: 0x0284, 0x13ce: 0x025d, 0x13cf: 0x026f, 0x13d1: 0x0263,
- 0x13d2: 0x0278, 0x13d4: 0x0260, 0x13d7: 0x024e,
- 0x13d9: 0x0266, 0x13db: 0x0272, 0x13dd: 0x02e4,
- 0x13df: 0x0296, 0x13e1: 0x023c, 0x13e2: 0x0248,
- 0x13e4: 0x0287, 0x13e7: 0x024b, 0x13e8: 0x0269, 0x13e9: 0x0290,
- 0x13ea: 0x027b, 0x13ec: 0x0281, 0x13ed: 0x0284, 0x13ee: 0x025d, 0x13ef: 0x026f,
- 0x13f0: 0x0275, 0x13f1: 0x0263, 0x13f2: 0x0278, 0x13f4: 0x0260, 0x13f5: 0x0242,
- 0x13f6: 0x0245, 0x13f7: 0x024e, 0x13f9: 0x0266, 0x13fa: 0x026c, 0x13fb: 0x0272,
- 0x13fc: 0x0293, 0x13fe: 0x02cc,
- // Block 0x50, offset 0x1400
- 0x1400: 0x0239, 0x1401: 0x023c, 0x1402: 0x0248, 0x1403: 0x0251, 0x1404: 0x0287, 0x1405: 0x028a,
- 0x1406: 0x025a, 0x1407: 0x024b, 0x1408: 0x0269, 0x1409: 0x0290, 0x140b: 0x027e,
- 0x140c: 0x0281, 0x140d: 0x0284, 0x140e: 0x025d, 0x140f: 0x026f, 0x1410: 0x0275, 0x1411: 0x0263,
- 0x1412: 0x0278, 0x1413: 0x0257, 0x1414: 0x0260, 0x1415: 0x0242, 0x1416: 0x0245, 0x1417: 0x024e,
- 0x1418: 0x0254, 0x1419: 0x0266, 0x141a: 0x026c, 0x141b: 0x0272,
- 0x1421: 0x023c, 0x1422: 0x0248, 0x1423: 0x0251,
- 0x1425: 0x028a, 0x1426: 0x025a, 0x1427: 0x024b, 0x1428: 0x0269, 0x1429: 0x0290,
- 0x142b: 0x027e, 0x142c: 0x0281, 0x142d: 0x0284, 0x142e: 0x025d, 0x142f: 0x026f,
- 0x1430: 0x0275, 0x1431: 0x0263, 0x1432: 0x0278, 0x1433: 0x0257, 0x1434: 0x0260, 0x1435: 0x0242,
- 0x1436: 0x0245, 0x1437: 0x024e, 0x1438: 0x0254, 0x1439: 0x0266, 0x143a: 0x026c, 0x143b: 0x0272,
- // Block 0x51, offset 0x1440
- 0x1440: 0x1879, 0x1441: 0x1876, 0x1442: 0x187c, 0x1443: 0x18a0, 0x1444: 0x18c4, 0x1445: 0x18e8,
- 0x1446: 0x190c, 0x1447: 0x1915, 0x1448: 0x191b, 0x1449: 0x1921, 0x144a: 0x1927,
- 0x1450: 0x1a8c, 0x1451: 0x1a90,
- 0x1452: 0x1a94, 0x1453: 0x1a98, 0x1454: 0x1a9c, 0x1455: 0x1aa0, 0x1456: 0x1aa4, 0x1457: 0x1aa8,
- 0x1458: 0x1aac, 0x1459: 0x1ab0, 0x145a: 0x1ab4, 0x145b: 0x1ab8, 0x145c: 0x1abc, 0x145d: 0x1ac0,
- 0x145e: 0x1ac4, 0x145f: 0x1ac8, 0x1460: 0x1acc, 0x1461: 0x1ad0, 0x1462: 0x1ad4, 0x1463: 0x1ad8,
- 0x1464: 0x1adc, 0x1465: 0x1ae0, 0x1466: 0x1ae4, 0x1467: 0x1ae8, 0x1468: 0x1aec, 0x1469: 0x1af0,
- 0x146a: 0x271e, 0x146b: 0x0047, 0x146c: 0x0065, 0x146d: 0x193c, 0x146e: 0x19b1,
- 0x1470: 0x0043, 0x1471: 0x0045, 0x1472: 0x0047, 0x1473: 0x0049, 0x1474: 0x004b, 0x1475: 0x004d,
- 0x1476: 0x004f, 0x1477: 0x0051, 0x1478: 0x0053, 0x1479: 0x0055, 0x147a: 0x0057, 0x147b: 0x0059,
- 0x147c: 0x005b, 0x147d: 0x005d, 0x147e: 0x005f, 0x147f: 0x0061,
- // Block 0x52, offset 0x1480
- 0x1480: 0x26ad, 0x1481: 0x26c2, 0x1482: 0x0503,
- 0x1490: 0x0c0f, 0x1491: 0x0a47,
- 0x1492: 0x08d3, 0x1493: 0x465a, 0x1494: 0x071b, 0x1495: 0x09ef, 0x1496: 0x132f, 0x1497: 0x09ff,
- 0x1498: 0x0727, 0x1499: 0x0cd7, 0x149a: 0x0eaf, 0x149b: 0x0caf, 0x149c: 0x0827, 0x149d: 0x0b6b,
- 0x149e: 0x07bf, 0x149f: 0x0cb7, 0x14a0: 0x0813, 0x14a1: 0x1117, 0x14a2: 0x0f83, 0x14a3: 0x138b,
- 0x14a4: 0x09d3, 0x14a5: 0x090b, 0x14a6: 0x0e63, 0x14a7: 0x0c1b, 0x14a8: 0x0c47, 0x14a9: 0x06bf,
- 0x14aa: 0x06cb, 0x14ab: 0x140b, 0x14ac: 0x0adb, 0x14ad: 0x06e7, 0x14ae: 0x08ef, 0x14af: 0x0c3b,
- 0x14b0: 0x13b3, 0x14b1: 0x0c13, 0x14b2: 0x106f, 0x14b3: 0x10ab, 0x14b4: 0x08f7, 0x14b5: 0x0e43,
- 0x14b6: 0x0d0b, 0x14b7: 0x0d07, 0x14b8: 0x0f97, 0x14b9: 0x082b, 0x14ba: 0x0957, 0x14bb: 0x1443,
- // Block 0x53, offset 0x14c0
- 0x14c0: 0x06fb, 0x14c1: 0x06f3, 0x14c2: 0x0703, 0x14c3: 0x1647, 0x14c4: 0x0747, 0x14c5: 0x0757,
- 0x14c6: 0x075b, 0x14c7: 0x0763, 0x14c8: 0x076b, 0x14c9: 0x076f, 0x14ca: 0x077b, 0x14cb: 0x0773,
- 0x14cc: 0x05b3, 0x14cd: 0x165b, 0x14ce: 0x078f, 0x14cf: 0x0793, 0x14d0: 0x0797, 0x14d1: 0x07b3,
- 0x14d2: 0x164c, 0x14d3: 0x05b7, 0x14d4: 0x079f, 0x14d5: 0x07bf, 0x14d6: 0x1656, 0x14d7: 0x07cf,
- 0x14d8: 0x07d7, 0x14d9: 0x0737, 0x14da: 0x07df, 0x14db: 0x07e3, 0x14dc: 0x1831, 0x14dd: 0x07ff,
- 0x14de: 0x0807, 0x14df: 0x05bf, 0x14e0: 0x081f, 0x14e1: 0x0823, 0x14e2: 0x082b, 0x14e3: 0x082f,
- 0x14e4: 0x05c3, 0x14e5: 0x0847, 0x14e6: 0x084b, 0x14e7: 0x0857, 0x14e8: 0x0863, 0x14e9: 0x0867,
- 0x14ea: 0x086b, 0x14eb: 0x0873, 0x14ec: 0x0893, 0x14ed: 0x0897, 0x14ee: 0x089f, 0x14ef: 0x08af,
- 0x14f0: 0x08b7, 0x14f1: 0x08bb, 0x14f2: 0x08bb, 0x14f3: 0x08bb, 0x14f4: 0x166a, 0x14f5: 0x0e93,
- 0x14f6: 0x08cf, 0x14f7: 0x08d7, 0x14f8: 0x166f, 0x14f9: 0x08e3, 0x14fa: 0x08eb, 0x14fb: 0x08f3,
- 0x14fc: 0x091b, 0x14fd: 0x0907, 0x14fe: 0x0913, 0x14ff: 0x0917,
- // Block 0x54, offset 0x1500
- 0x1500: 0x091f, 0x1501: 0x0927, 0x1502: 0x092b, 0x1503: 0x0933, 0x1504: 0x093b, 0x1505: 0x093f,
- 0x1506: 0x093f, 0x1507: 0x0947, 0x1508: 0x094f, 0x1509: 0x0953, 0x150a: 0x095f, 0x150b: 0x0983,
- 0x150c: 0x0967, 0x150d: 0x0987, 0x150e: 0x096b, 0x150f: 0x0973, 0x1510: 0x080b, 0x1511: 0x09cf,
- 0x1512: 0x0997, 0x1513: 0x099b, 0x1514: 0x099f, 0x1515: 0x0993, 0x1516: 0x09a7, 0x1517: 0x09a3,
- 0x1518: 0x09bb, 0x1519: 0x1674, 0x151a: 0x09d7, 0x151b: 0x09db, 0x151c: 0x09e3, 0x151d: 0x09ef,
- 0x151e: 0x09f7, 0x151f: 0x0a13, 0x1520: 0x1679, 0x1521: 0x167e, 0x1522: 0x0a1f, 0x1523: 0x0a23,
- 0x1524: 0x0a27, 0x1525: 0x0a1b, 0x1526: 0x0a2f, 0x1527: 0x05c7, 0x1528: 0x05cb, 0x1529: 0x0a37,
- 0x152a: 0x0a3f, 0x152b: 0x0a3f, 0x152c: 0x1683, 0x152d: 0x0a5b, 0x152e: 0x0a5f, 0x152f: 0x0a63,
- 0x1530: 0x0a6b, 0x1531: 0x1688, 0x1532: 0x0a73, 0x1533: 0x0a77, 0x1534: 0x0b4f, 0x1535: 0x0a7f,
- 0x1536: 0x05cf, 0x1537: 0x0a8b, 0x1538: 0x0a9b, 0x1539: 0x0aa7, 0x153a: 0x0aa3, 0x153b: 0x1692,
- 0x153c: 0x0aaf, 0x153d: 0x1697, 0x153e: 0x0abb, 0x153f: 0x0ab7,
- // Block 0x55, offset 0x1540
- 0x1540: 0x0abf, 0x1541: 0x0acf, 0x1542: 0x0ad3, 0x1543: 0x05d3, 0x1544: 0x0ae3, 0x1545: 0x0aeb,
- 0x1546: 0x0aef, 0x1547: 0x0af3, 0x1548: 0x05d7, 0x1549: 0x169c, 0x154a: 0x05db, 0x154b: 0x0b0f,
- 0x154c: 0x0b13, 0x154d: 0x0b17, 0x154e: 0x0b1f, 0x154f: 0x1863, 0x1550: 0x0b37, 0x1551: 0x16a6,
- 0x1552: 0x16a6, 0x1553: 0x11d7, 0x1554: 0x0b47, 0x1555: 0x0b47, 0x1556: 0x05df, 0x1557: 0x16c9,
- 0x1558: 0x179b, 0x1559: 0x0b57, 0x155a: 0x0b5f, 0x155b: 0x05e3, 0x155c: 0x0b73, 0x155d: 0x0b83,
- 0x155e: 0x0b87, 0x155f: 0x0b8f, 0x1560: 0x0b9f, 0x1561: 0x05eb, 0x1562: 0x05e7, 0x1563: 0x0ba3,
- 0x1564: 0x16ab, 0x1565: 0x0ba7, 0x1566: 0x0bbb, 0x1567: 0x0bbf, 0x1568: 0x0bc3, 0x1569: 0x0bbf,
- 0x156a: 0x0bcf, 0x156b: 0x0bd3, 0x156c: 0x0be3, 0x156d: 0x0bdb, 0x156e: 0x0bdf, 0x156f: 0x0be7,
- 0x1570: 0x0beb, 0x1571: 0x0bef, 0x1572: 0x0bfb, 0x1573: 0x0bff, 0x1574: 0x0c17, 0x1575: 0x0c1f,
- 0x1576: 0x0c2f, 0x1577: 0x0c43, 0x1578: 0x16ba, 0x1579: 0x0c3f, 0x157a: 0x0c33, 0x157b: 0x0c4b,
- 0x157c: 0x0c53, 0x157d: 0x0c67, 0x157e: 0x16bf, 0x157f: 0x0c6f,
- // Block 0x56, offset 0x1580
- 0x1580: 0x0c63, 0x1581: 0x0c5b, 0x1582: 0x05ef, 0x1583: 0x0c77, 0x1584: 0x0c7f, 0x1585: 0x0c87,
- 0x1586: 0x0c7b, 0x1587: 0x05f3, 0x1588: 0x0c97, 0x1589: 0x0c9f, 0x158a: 0x16c4, 0x158b: 0x0ccb,
- 0x158c: 0x0cff, 0x158d: 0x0cdb, 0x158e: 0x05ff, 0x158f: 0x0ce7, 0x1590: 0x05fb, 0x1591: 0x05f7,
- 0x1592: 0x07c3, 0x1593: 0x07c7, 0x1594: 0x0d03, 0x1595: 0x0ceb, 0x1596: 0x11ab, 0x1597: 0x0663,
- 0x1598: 0x0d0f, 0x1599: 0x0d13, 0x159a: 0x0d17, 0x159b: 0x0d2b, 0x159c: 0x0d23, 0x159d: 0x16dd,
- 0x159e: 0x0603, 0x159f: 0x0d3f, 0x15a0: 0x0d33, 0x15a1: 0x0d4f, 0x15a2: 0x0d57, 0x15a3: 0x16e7,
- 0x15a4: 0x0d5b, 0x15a5: 0x0d47, 0x15a6: 0x0d63, 0x15a7: 0x0607, 0x15a8: 0x0d67, 0x15a9: 0x0d6b,
- 0x15aa: 0x0d6f, 0x15ab: 0x0d7b, 0x15ac: 0x16ec, 0x15ad: 0x0d83, 0x15ae: 0x060b, 0x15af: 0x0d8f,
- 0x15b0: 0x16f1, 0x15b1: 0x0d93, 0x15b2: 0x060f, 0x15b3: 0x0d9f, 0x15b4: 0x0dab, 0x15b5: 0x0db7,
- 0x15b6: 0x0dbb, 0x15b7: 0x16f6, 0x15b8: 0x168d, 0x15b9: 0x16fb, 0x15ba: 0x0ddb, 0x15bb: 0x1700,
- 0x15bc: 0x0de7, 0x15bd: 0x0def, 0x15be: 0x0ddf, 0x15bf: 0x0dfb,
- // Block 0x57, offset 0x15c0
- 0x15c0: 0x0e0b, 0x15c1: 0x0e1b, 0x15c2: 0x0e0f, 0x15c3: 0x0e13, 0x15c4: 0x0e1f, 0x15c5: 0x0e23,
- 0x15c6: 0x1705, 0x15c7: 0x0e07, 0x15c8: 0x0e3b, 0x15c9: 0x0e3f, 0x15ca: 0x0613, 0x15cb: 0x0e53,
- 0x15cc: 0x0e4f, 0x15cd: 0x170a, 0x15ce: 0x0e33, 0x15cf: 0x0e6f, 0x15d0: 0x170f, 0x15d1: 0x1714,
- 0x15d2: 0x0e73, 0x15d3: 0x0e87, 0x15d4: 0x0e83, 0x15d5: 0x0e7f, 0x15d6: 0x0617, 0x15d7: 0x0e8b,
- 0x15d8: 0x0e9b, 0x15d9: 0x0e97, 0x15da: 0x0ea3, 0x15db: 0x1651, 0x15dc: 0x0eb3, 0x15dd: 0x1719,
- 0x15de: 0x0ebf, 0x15df: 0x1723, 0x15e0: 0x0ed3, 0x15e1: 0x0edf, 0x15e2: 0x0ef3, 0x15e3: 0x1728,
- 0x15e4: 0x0f07, 0x15e5: 0x0f0b, 0x15e6: 0x172d, 0x15e7: 0x1732, 0x15e8: 0x0f27, 0x15e9: 0x0f37,
- 0x15ea: 0x061b, 0x15eb: 0x0f3b, 0x15ec: 0x061f, 0x15ed: 0x061f, 0x15ee: 0x0f53, 0x15ef: 0x0f57,
- 0x15f0: 0x0f5f, 0x15f1: 0x0f63, 0x15f2: 0x0f6f, 0x15f3: 0x0623, 0x15f4: 0x0f87, 0x15f5: 0x1737,
- 0x15f6: 0x0fa3, 0x15f7: 0x173c, 0x15f8: 0x0faf, 0x15f9: 0x16a1, 0x15fa: 0x0fbf, 0x15fb: 0x1741,
- 0x15fc: 0x1746, 0x15fd: 0x174b, 0x15fe: 0x0627, 0x15ff: 0x062b,
- // Block 0x58, offset 0x1600
- 0x1600: 0x0ff7, 0x1601: 0x1755, 0x1602: 0x1750, 0x1603: 0x175a, 0x1604: 0x175f, 0x1605: 0x0fff,
- 0x1606: 0x1003, 0x1607: 0x1003, 0x1608: 0x100b, 0x1609: 0x0633, 0x160a: 0x100f, 0x160b: 0x0637,
- 0x160c: 0x063b, 0x160d: 0x1769, 0x160e: 0x1023, 0x160f: 0x102b, 0x1610: 0x1037, 0x1611: 0x063f,
- 0x1612: 0x176e, 0x1613: 0x105b, 0x1614: 0x1773, 0x1615: 0x1778, 0x1616: 0x107b, 0x1617: 0x1093,
- 0x1618: 0x0643, 0x1619: 0x109b, 0x161a: 0x109f, 0x161b: 0x10a3, 0x161c: 0x177d, 0x161d: 0x1782,
- 0x161e: 0x1782, 0x161f: 0x10bb, 0x1620: 0x0647, 0x1621: 0x1787, 0x1622: 0x10cf, 0x1623: 0x10d3,
- 0x1624: 0x064b, 0x1625: 0x178c, 0x1626: 0x10ef, 0x1627: 0x064f, 0x1628: 0x10ff, 0x1629: 0x10f7,
- 0x162a: 0x1107, 0x162b: 0x1796, 0x162c: 0x111f, 0x162d: 0x0653, 0x162e: 0x112b, 0x162f: 0x1133,
- 0x1630: 0x1143, 0x1631: 0x0657, 0x1632: 0x17a0, 0x1633: 0x17a5, 0x1634: 0x065b, 0x1635: 0x17aa,
- 0x1636: 0x115b, 0x1637: 0x17af, 0x1638: 0x1167, 0x1639: 0x1173, 0x163a: 0x117b, 0x163b: 0x17b4,
- 0x163c: 0x17b9, 0x163d: 0x118f, 0x163e: 0x17be, 0x163f: 0x1197,
- // Block 0x59, offset 0x1640
- 0x1640: 0x16ce, 0x1641: 0x065f, 0x1642: 0x11af, 0x1643: 0x11b3, 0x1644: 0x0667, 0x1645: 0x11b7,
- 0x1646: 0x0a33, 0x1647: 0x17c3, 0x1648: 0x17c8, 0x1649: 0x16d3, 0x164a: 0x16d8, 0x164b: 0x11d7,
- 0x164c: 0x11db, 0x164d: 0x13f3, 0x164e: 0x066b, 0x164f: 0x1207, 0x1650: 0x1203, 0x1651: 0x120b,
- 0x1652: 0x083f, 0x1653: 0x120f, 0x1654: 0x1213, 0x1655: 0x1217, 0x1656: 0x121f, 0x1657: 0x17cd,
- 0x1658: 0x121b, 0x1659: 0x1223, 0x165a: 0x1237, 0x165b: 0x123b, 0x165c: 0x1227, 0x165d: 0x123f,
- 0x165e: 0x1253, 0x165f: 0x1267, 0x1660: 0x1233, 0x1661: 0x1247, 0x1662: 0x124b, 0x1663: 0x124f,
- 0x1664: 0x17d2, 0x1665: 0x17dc, 0x1666: 0x17d7, 0x1667: 0x066f, 0x1668: 0x126f, 0x1669: 0x1273,
- 0x166a: 0x127b, 0x166b: 0x17f0, 0x166c: 0x127f, 0x166d: 0x17e1, 0x166e: 0x0673, 0x166f: 0x0677,
- 0x1670: 0x17e6, 0x1671: 0x17eb, 0x1672: 0x067b, 0x1673: 0x129f, 0x1674: 0x12a3, 0x1675: 0x12a7,
- 0x1676: 0x12ab, 0x1677: 0x12b7, 0x1678: 0x12b3, 0x1679: 0x12bf, 0x167a: 0x12bb, 0x167b: 0x12cb,
- 0x167c: 0x12c3, 0x167d: 0x12c7, 0x167e: 0x12cf, 0x167f: 0x067f,
- // Block 0x5a, offset 0x1680
- 0x1680: 0x12d7, 0x1681: 0x12db, 0x1682: 0x0683, 0x1683: 0x12eb, 0x1684: 0x12ef, 0x1685: 0x17f5,
- 0x1686: 0x12fb, 0x1687: 0x12ff, 0x1688: 0x0687, 0x1689: 0x130b, 0x168a: 0x05bb, 0x168b: 0x17fa,
- 0x168c: 0x17ff, 0x168d: 0x068b, 0x168e: 0x068f, 0x168f: 0x1337, 0x1690: 0x134f, 0x1691: 0x136b,
- 0x1692: 0x137b, 0x1693: 0x1804, 0x1694: 0x138f, 0x1695: 0x1393, 0x1696: 0x13ab, 0x1697: 0x13b7,
- 0x1698: 0x180e, 0x1699: 0x1660, 0x169a: 0x13c3, 0x169b: 0x13bf, 0x169c: 0x13cb, 0x169d: 0x1665,
- 0x169e: 0x13d7, 0x169f: 0x13e3, 0x16a0: 0x1813, 0x16a1: 0x1818, 0x16a2: 0x1423, 0x16a3: 0x142f,
- 0x16a4: 0x1437, 0x16a5: 0x181d, 0x16a6: 0x143b, 0x16a7: 0x1467, 0x16a8: 0x1473, 0x16a9: 0x1477,
- 0x16aa: 0x146f, 0x16ab: 0x1483, 0x16ac: 0x1487, 0x16ad: 0x1822, 0x16ae: 0x1493, 0x16af: 0x0693,
- 0x16b0: 0x149b, 0x16b1: 0x1827, 0x16b2: 0x0697, 0x16b3: 0x14d3, 0x16b4: 0x0ac3, 0x16b5: 0x14eb,
- 0x16b6: 0x182c, 0x16b7: 0x1836, 0x16b8: 0x069b, 0x16b9: 0x069f, 0x16ba: 0x1513, 0x16bb: 0x183b,
- 0x16bc: 0x06a3, 0x16bd: 0x1840, 0x16be: 0x152b, 0x16bf: 0x152b,
- // Block 0x5b, offset 0x16c0
- 0x16c0: 0x1533, 0x16c1: 0x1845, 0x16c2: 0x154b, 0x16c3: 0x06a7, 0x16c4: 0x155b, 0x16c5: 0x1567,
- 0x16c6: 0x156f, 0x16c7: 0x1577, 0x16c8: 0x06ab, 0x16c9: 0x184a, 0x16ca: 0x158b, 0x16cb: 0x15a7,
- 0x16cc: 0x15b3, 0x16cd: 0x06af, 0x16ce: 0x06b3, 0x16cf: 0x15b7, 0x16d0: 0x184f, 0x16d1: 0x06b7,
- 0x16d2: 0x1854, 0x16d3: 0x1859, 0x16d4: 0x185e, 0x16d5: 0x15db, 0x16d6: 0x06bb, 0x16d7: 0x15ef,
- 0x16d8: 0x15f7, 0x16d9: 0x15fb, 0x16da: 0x1603, 0x16db: 0x160b, 0x16dc: 0x1613, 0x16dd: 0x1868,
-}
-
-// nfkcIndex: 22 blocks, 1408 entries, 1408 bytes
-// Block 0 is the zero block.
-var nfkcIndex = [1408]uint8{
- // Block 0x0, offset 0x0
- // Block 0x1, offset 0x40
- // Block 0x2, offset 0x80
- // Block 0x3, offset 0xc0
- 0xc2: 0x5a, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x5b, 0xc7: 0x04,
- 0xc8: 0x05, 0xca: 0x5c, 0xcb: 0x5d, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x09,
- 0xd0: 0x0a, 0xd1: 0x5e, 0xd2: 0x5f, 0xd3: 0x0b, 0xd6: 0x0c, 0xd7: 0x60,
- 0xd8: 0x61, 0xd9: 0x0d, 0xdb: 0x62, 0xdc: 0x63, 0xdd: 0x64, 0xdf: 0x65,
- 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05,
- 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a,
- 0xf0: 0x13,
- // Block 0x4, offset 0x100
- 0x120: 0x66, 0x121: 0x67, 0x123: 0x68, 0x124: 0x69, 0x125: 0x6a, 0x126: 0x6b, 0x127: 0x6c,
- 0x128: 0x6d, 0x129: 0x6e, 0x12a: 0x6f, 0x12b: 0x70, 0x12c: 0x6b, 0x12d: 0x71, 0x12e: 0x72, 0x12f: 0x73,
- 0x131: 0x74, 0x132: 0x75, 0x133: 0x76, 0x134: 0x77, 0x135: 0x78, 0x137: 0x79,
- 0x138: 0x7a, 0x139: 0x7b, 0x13a: 0x7c, 0x13b: 0x7d, 0x13c: 0x7e, 0x13d: 0x7f, 0x13e: 0x80, 0x13f: 0x81,
- // Block 0x5, offset 0x140
- 0x140: 0x82, 0x142: 0x83, 0x143: 0x84, 0x144: 0x85, 0x145: 0x86, 0x146: 0x87, 0x147: 0x88,
- 0x14d: 0x89,
- 0x15c: 0x8a, 0x15f: 0x8b,
- 0x162: 0x8c, 0x164: 0x8d,
- 0x168: 0x8e, 0x169: 0x8f, 0x16a: 0x90, 0x16c: 0x0e, 0x16d: 0x91, 0x16e: 0x92, 0x16f: 0x93,
- 0x170: 0x94, 0x173: 0x95, 0x174: 0x96, 0x175: 0x0f, 0x176: 0x10, 0x177: 0x97,
- 0x178: 0x11, 0x179: 0x12, 0x17a: 0x13, 0x17b: 0x14, 0x17c: 0x15, 0x17d: 0x16, 0x17e: 0x17, 0x17f: 0x18,
- // Block 0x6, offset 0x180
- 0x180: 0x98, 0x181: 0x99, 0x182: 0x9a, 0x183: 0x9b, 0x184: 0x19, 0x185: 0x1a, 0x186: 0x9c, 0x187: 0x9d,
- 0x188: 0x9e, 0x189: 0x1b, 0x18a: 0x1c, 0x18b: 0x9f, 0x18c: 0xa0,
- 0x191: 0x1d, 0x192: 0x1e, 0x193: 0xa1,
- 0x1a8: 0xa2, 0x1a9: 0xa3, 0x1ab: 0xa4,
- 0x1b1: 0xa5, 0x1b3: 0xa6, 0x1b5: 0xa7, 0x1b7: 0xa8,
- 0x1ba: 0xa9, 0x1bb: 0xaa, 0x1bc: 0x1f, 0x1bd: 0x20, 0x1be: 0x21, 0x1bf: 0xab,
- // Block 0x7, offset 0x1c0
- 0x1c0: 0xac, 0x1c1: 0x22, 0x1c2: 0x23, 0x1c3: 0x24, 0x1c4: 0xad, 0x1c5: 0x25, 0x1c6: 0x26,
- 0x1c8: 0x27, 0x1c9: 0x28, 0x1ca: 0x29, 0x1cb: 0x2a, 0x1cc: 0x2b, 0x1cd: 0x2c, 0x1ce: 0x2d, 0x1cf: 0x2e,
- // Block 0x8, offset 0x200
- 0x219: 0xae, 0x21a: 0xaf, 0x21b: 0xb0, 0x21d: 0xb1, 0x21f: 0xb2,
- 0x220: 0xb3, 0x223: 0xb4, 0x224: 0xb5, 0x225: 0xb6, 0x226: 0xb7, 0x227: 0xb8,
- 0x22a: 0xb9, 0x22b: 0xba, 0x22d: 0xbb, 0x22f: 0xbc,
- 0x230: 0xbd, 0x231: 0xbe, 0x232: 0xbf, 0x233: 0xc0, 0x234: 0xc1, 0x235: 0xc2, 0x236: 0xc3, 0x237: 0xbd,
- 0x238: 0xbe, 0x239: 0xbf, 0x23a: 0xc0, 0x23b: 0xc1, 0x23c: 0xc2, 0x23d: 0xc3, 0x23e: 0xbd, 0x23f: 0xbe,
- // Block 0x9, offset 0x240
- 0x240: 0xbf, 0x241: 0xc0, 0x242: 0xc1, 0x243: 0xc2, 0x244: 0xc3, 0x245: 0xbd, 0x246: 0xbe, 0x247: 0xbf,
- 0x248: 0xc0, 0x249: 0xc1, 0x24a: 0xc2, 0x24b: 0xc3, 0x24c: 0xbd, 0x24d: 0xbe, 0x24e: 0xbf, 0x24f: 0xc0,
- 0x250: 0xc1, 0x251: 0xc2, 0x252: 0xc3, 0x253: 0xbd, 0x254: 0xbe, 0x255: 0xbf, 0x256: 0xc0, 0x257: 0xc1,
- 0x258: 0xc2, 0x259: 0xc3, 0x25a: 0xbd, 0x25b: 0xbe, 0x25c: 0xbf, 0x25d: 0xc0, 0x25e: 0xc1, 0x25f: 0xc2,
- 0x260: 0xc3, 0x261: 0xbd, 0x262: 0xbe, 0x263: 0xbf, 0x264: 0xc0, 0x265: 0xc1, 0x266: 0xc2, 0x267: 0xc3,
- 0x268: 0xbd, 0x269: 0xbe, 0x26a: 0xbf, 0x26b: 0xc0, 0x26c: 0xc1, 0x26d: 0xc2, 0x26e: 0xc3, 0x26f: 0xbd,
- 0x270: 0xbe, 0x271: 0xbf, 0x272: 0xc0, 0x273: 0xc1, 0x274: 0xc2, 0x275: 0xc3, 0x276: 0xbd, 0x277: 0xbe,
- 0x278: 0xbf, 0x279: 0xc0, 0x27a: 0xc1, 0x27b: 0xc2, 0x27c: 0xc3, 0x27d: 0xbd, 0x27e: 0xbe, 0x27f: 0xbf,
- // Block 0xa, offset 0x280
- 0x280: 0xc0, 0x281: 0xc1, 0x282: 0xc2, 0x283: 0xc3, 0x284: 0xbd, 0x285: 0xbe, 0x286: 0xbf, 0x287: 0xc0,
- 0x288: 0xc1, 0x289: 0xc2, 0x28a: 0xc3, 0x28b: 0xbd, 0x28c: 0xbe, 0x28d: 0xbf, 0x28e: 0xc0, 0x28f: 0xc1,
- 0x290: 0xc2, 0x291: 0xc3, 0x292: 0xbd, 0x293: 0xbe, 0x294: 0xbf, 0x295: 0xc0, 0x296: 0xc1, 0x297: 0xc2,
- 0x298: 0xc3, 0x299: 0xbd, 0x29a: 0xbe, 0x29b: 0xbf, 0x29c: 0xc0, 0x29d: 0xc1, 0x29e: 0xc2, 0x29f: 0xc3,
- 0x2a0: 0xbd, 0x2a1: 0xbe, 0x2a2: 0xbf, 0x2a3: 0xc0, 0x2a4: 0xc1, 0x2a5: 0xc2, 0x2a6: 0xc3, 0x2a7: 0xbd,
- 0x2a8: 0xbe, 0x2a9: 0xbf, 0x2aa: 0xc0, 0x2ab: 0xc1, 0x2ac: 0xc2, 0x2ad: 0xc3, 0x2ae: 0xbd, 0x2af: 0xbe,
- 0x2b0: 0xbf, 0x2b1: 0xc0, 0x2b2: 0xc1, 0x2b3: 0xc2, 0x2b4: 0xc3, 0x2b5: 0xbd, 0x2b6: 0xbe, 0x2b7: 0xbf,
- 0x2b8: 0xc0, 0x2b9: 0xc1, 0x2ba: 0xc2, 0x2bb: 0xc3, 0x2bc: 0xbd, 0x2bd: 0xbe, 0x2be: 0xbf, 0x2bf: 0xc0,
- // Block 0xb, offset 0x2c0
- 0x2c0: 0xc1, 0x2c1: 0xc2, 0x2c2: 0xc3, 0x2c3: 0xbd, 0x2c4: 0xbe, 0x2c5: 0xbf, 0x2c6: 0xc0, 0x2c7: 0xc1,
- 0x2c8: 0xc2, 0x2c9: 0xc3, 0x2ca: 0xbd, 0x2cb: 0xbe, 0x2cc: 0xbf, 0x2cd: 0xc0, 0x2ce: 0xc1, 0x2cf: 0xc2,
- 0x2d0: 0xc3, 0x2d1: 0xbd, 0x2d2: 0xbe, 0x2d3: 0xbf, 0x2d4: 0xc0, 0x2d5: 0xc1, 0x2d6: 0xc2, 0x2d7: 0xc3,
- 0x2d8: 0xbd, 0x2d9: 0xbe, 0x2da: 0xbf, 0x2db: 0xc0, 0x2dc: 0xc1, 0x2dd: 0xc2, 0x2de: 0xc4,
- // Block 0xc, offset 0x300
- 0x324: 0x2f, 0x325: 0x30, 0x326: 0x31, 0x327: 0x32,
- 0x328: 0x33, 0x329: 0x34, 0x32a: 0x35, 0x32b: 0x36, 0x32c: 0x37, 0x32d: 0x38, 0x32e: 0x39, 0x32f: 0x3a,
- 0x330: 0x3b, 0x331: 0x3c, 0x332: 0x3d, 0x333: 0x3e, 0x334: 0x3f, 0x335: 0x40, 0x336: 0x41, 0x337: 0x42,
- 0x338: 0x43, 0x339: 0x44, 0x33a: 0x45, 0x33b: 0x46, 0x33c: 0xc5, 0x33d: 0x47, 0x33e: 0x48, 0x33f: 0x49,
- // Block 0xd, offset 0x340
- 0x347: 0xc6,
- 0x34b: 0xc7, 0x34d: 0xc8,
- 0x368: 0xc9, 0x36b: 0xca,
- // Block 0xe, offset 0x380
- 0x381: 0xcb, 0x382: 0xcc, 0x384: 0xcd, 0x385: 0xb7, 0x387: 0xce,
- 0x388: 0xcf, 0x38b: 0xd0, 0x38c: 0x6b, 0x38d: 0xd1,
- 0x391: 0xd2, 0x392: 0xd3, 0x393: 0xd4, 0x396: 0xd5, 0x397: 0xd6,
- 0x398: 0xd7, 0x39a: 0xd8, 0x39c: 0xd9,
- 0x3b0: 0xd7,
- // Block 0xf, offset 0x3c0
- 0x3eb: 0xda, 0x3ec: 0xdb,
- // Block 0x10, offset 0x400
- 0x432: 0xdc,
- // Block 0x11, offset 0x440
- 0x445: 0xdd, 0x446: 0xde, 0x447: 0xdf,
- 0x449: 0xe0,
- 0x450: 0xe1, 0x451: 0xe2, 0x452: 0xe3, 0x453: 0xe4, 0x454: 0xe5, 0x455: 0xe6, 0x456: 0xe7, 0x457: 0xe8,
- 0x458: 0xe9, 0x459: 0xea, 0x45a: 0x4a, 0x45b: 0xeb, 0x45c: 0xec, 0x45d: 0xed, 0x45e: 0xee, 0x45f: 0x4b,
- // Block 0x12, offset 0x480
- 0x480: 0xef,
- 0x4a3: 0xf0, 0x4a5: 0xf1,
- 0x4b8: 0x4c, 0x4b9: 0x4d, 0x4ba: 0x4e,
- // Block 0x13, offset 0x4c0
- 0x4c4: 0x4f, 0x4c5: 0xf2, 0x4c6: 0xf3,
- 0x4c8: 0x50, 0x4c9: 0xf4,
- // Block 0x14, offset 0x500
- 0x520: 0x51, 0x521: 0x52, 0x522: 0x53, 0x523: 0x54, 0x524: 0x55, 0x525: 0x56, 0x526: 0x57, 0x527: 0x58,
- 0x528: 0x59,
- // Block 0x15, offset 0x540
- 0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d,
- 0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11,
- 0x56f: 0x12,
-}
-
-// nfkcSparseOffset: 155 entries, 310 bytes
-var nfkcSparseOffset = []uint16{0x0, 0xe, 0x12, 0x1b, 0x25, 0x35, 0x37, 0x3c, 0x47, 0x56, 0x63, 0x6b, 0x6f, 0x74, 0x76, 0x87, 0x8f, 0x96, 0x99, 0xa0, 0xa4, 0xa8, 0xaa, 0xac, 0xb5, 0xb9, 0xc0, 0xc5, 0xc8, 0xd2, 0xd4, 0xdb, 0xe3, 0xe7, 0xe9, 0xec, 0xf0, 0xf6, 0x107, 0x113, 0x115, 0x11b, 0x11d, 0x11f, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12c, 0x12f, 0x131, 0x134, 0x137, 0x13b, 0x140, 0x149, 0x14b, 0x14e, 0x150, 0x15b, 0x166, 0x176, 0x184, 0x192, 0x1a2, 0x1b0, 0x1b7, 0x1bd, 0x1cc, 0x1d0, 0x1d2, 0x1d6, 0x1d8, 0x1db, 0x1dd, 0x1e0, 0x1e2, 0x1e5, 0x1e7, 0x1e9, 0x1eb, 0x1f7, 0x201, 0x20b, 0x20e, 0x212, 0x214, 0x216, 0x218, 0x21a, 0x21d, 0x21f, 0x221, 0x223, 0x225, 0x22b, 0x22e, 0x232, 0x234, 0x23b, 0x241, 0x247, 0x24f, 0x255, 0x25b, 0x261, 0x265, 0x267, 0x269, 0x26b, 0x26d, 0x273, 0x276, 0x279, 0x281, 0x288, 0x28b, 0x28e, 0x290, 0x298, 0x29b, 0x2a2, 0x2a5, 0x2ab, 0x2ad, 0x2af, 0x2b2, 0x2b4, 0x2b6, 0x2b8, 0x2ba, 0x2c7, 0x2d1, 0x2d3, 0x2d5, 0x2d9, 0x2de, 0x2ea, 0x2ef, 0x2f8, 0x2fe, 0x303, 0x307, 0x30c, 0x310, 0x320, 0x32e, 0x33c, 0x34a, 0x350, 0x352, 0x355, 0x35f, 0x361}
-
-// nfkcSparseValues: 875 entries, 3500 bytes
-var nfkcSparseValues = [875]valueRange{
- // Block 0x0, offset 0x0
- {value: 0x0002, lo: 0x0d},
- {value: 0x0001, lo: 0xa0, hi: 0xa0},
- {value: 0x4278, lo: 0xa8, hi: 0xa8},
- {value: 0x0083, lo: 0xaa, hi: 0xaa},
- {value: 0x4264, lo: 0xaf, hi: 0xaf},
- {value: 0x0025, lo: 0xb2, hi: 0xb3},
- {value: 0x425a, lo: 0xb4, hi: 0xb4},
- {value: 0x01dc, lo: 0xb5, hi: 0xb5},
- {value: 0x4291, lo: 0xb8, hi: 0xb8},
- {value: 0x0023, lo: 0xb9, hi: 0xb9},
- {value: 0x009f, lo: 0xba, hi: 0xba},
- {value: 0x221c, lo: 0xbc, hi: 0xbc},
- {value: 0x2210, lo: 0xbd, hi: 0xbd},
- {value: 0x22b2, lo: 0xbe, hi: 0xbe},
- // Block 0x1, offset 0xe
- {value: 0x0091, lo: 0x03},
- {value: 0x4778, lo: 0xa0, hi: 0xa1},
- {value: 0x47aa, lo: 0xaf, hi: 0xb0},
- {value: 0xa000, lo: 0xb7, hi: 0xb7},
- // Block 0x2, offset 0x12
- {value: 0x0003, lo: 0x08},
- {value: 0xa000, lo: 0x92, hi: 0x92},
- {value: 0x0091, lo: 0xb0, hi: 0xb0},
- {value: 0x0119, lo: 0xb1, hi: 0xb1},
- {value: 0x0095, lo: 0xb2, hi: 0xb2},
- {value: 0x00a5, lo: 0xb3, hi: 0xb3},
- {value: 0x0143, lo: 0xb4, hi: 0xb6},
- {value: 0x00af, lo: 0xb7, hi: 0xb7},
- {value: 0x00b3, lo: 0xb8, hi: 0xb8},
- // Block 0x3, offset 0x1b
- {value: 0x000a, lo: 0x09},
- {value: 0x426e, lo: 0x98, hi: 0x98},
- {value: 0x4273, lo: 0x99, hi: 0x9a},
- {value: 0x4296, lo: 0x9b, hi: 0x9b},
- {value: 0x425f, lo: 0x9c, hi: 0x9c},
- {value: 0x4282, lo: 0x9d, hi: 0x9d},
- {value: 0x0113, lo: 0xa0, hi: 0xa0},
- {value: 0x0099, lo: 0xa1, hi: 0xa1},
- {value: 0x00a7, lo: 0xa2, hi: 0xa3},
- {value: 0x0167, lo: 0xa4, hi: 0xa4},
- // Block 0x4, offset 0x25
- {value: 0x0000, lo: 0x0f},
- {value: 0xa000, lo: 0x83, hi: 0x83},
- {value: 0xa000, lo: 0x87, hi: 0x87},
- {value: 0xa000, lo: 0x8b, hi: 0x8b},
- {value: 0xa000, lo: 0x8d, hi: 0x8d},
- {value: 0x37a5, lo: 0x90, hi: 0x90},
- {value: 0x37b1, lo: 0x91, hi: 0x91},
- {value: 0x379f, lo: 0x93, hi: 0x93},
- {value: 0xa000, lo: 0x96, hi: 0x96},
- {value: 0x3817, lo: 0x97, hi: 0x97},
- {value: 0x37e1, lo: 0x9c, hi: 0x9c},
- {value: 0x37c9, lo: 0x9d, hi: 0x9d},
- {value: 0x37f3, lo: 0x9e, hi: 0x9e},
- {value: 0xa000, lo: 0xb4, hi: 0xb5},
- {value: 0x381d, lo: 0xb6, hi: 0xb6},
- {value: 0x3823, lo: 0xb7, hi: 0xb7},
- // Block 0x5, offset 0x35
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0x83, hi: 0x87},
- // Block 0x6, offset 0x37
- {value: 0x0001, lo: 0x04},
- {value: 0x8113, lo: 0x81, hi: 0x82},
- {value: 0x8132, lo: 0x84, hi: 0x84},
- {value: 0x812d, lo: 0x85, hi: 0x85},
- {value: 0x810d, lo: 0x87, hi: 0x87},
- // Block 0x7, offset 0x3c
- {value: 0x0000, lo: 0x0a},
- {value: 0x8132, lo: 0x90, hi: 0x97},
- {value: 0x8119, lo: 0x98, hi: 0x98},
- {value: 0x811a, lo: 0x99, hi: 0x99},
- {value: 0x811b, lo: 0x9a, hi: 0x9a},
- {value: 0x3841, lo: 0xa2, hi: 0xa2},
- {value: 0x3847, lo: 0xa3, hi: 0xa3},
- {value: 0x3853, lo: 0xa4, hi: 0xa4},
- {value: 0x384d, lo: 0xa5, hi: 0xa5},
- {value: 0x3859, lo: 0xa6, hi: 0xa6},
- {value: 0xa000, lo: 0xa7, hi: 0xa7},
- // Block 0x8, offset 0x47
- {value: 0x0000, lo: 0x0e},
- {value: 0x386b, lo: 0x80, hi: 0x80},
- {value: 0xa000, lo: 0x81, hi: 0x81},
- {value: 0x385f, lo: 0x82, hi: 0x82},
- {value: 0xa000, lo: 0x92, hi: 0x92},
- {value: 0x3865, lo: 0x93, hi: 0x93},
- {value: 0xa000, lo: 0x95, hi: 0x95},
- {value: 0x8132, lo: 0x96, hi: 0x9c},
- {value: 0x8132, lo: 0x9f, hi: 0xa2},
- {value: 0x812d, lo: 0xa3, hi: 0xa3},
- {value: 0x8132, lo: 0xa4, hi: 0xa4},
- {value: 0x8132, lo: 0xa7, hi: 0xa8},
- {value: 0x812d, lo: 0xaa, hi: 0xaa},
- {value: 0x8132, lo: 0xab, hi: 0xac},
- {value: 0x812d, lo: 0xad, hi: 0xad},
- // Block 0x9, offset 0x56
- {value: 0x0000, lo: 0x0c},
- {value: 0x811f, lo: 0x91, hi: 0x91},
- {value: 0x8132, lo: 0xb0, hi: 0xb0},
- {value: 0x812d, lo: 0xb1, hi: 0xb1},
- {value: 0x8132, lo: 0xb2, hi: 0xb3},
- {value: 0x812d, lo: 0xb4, hi: 0xb4},
- {value: 0x8132, lo: 0xb5, hi: 0xb6},
- {value: 0x812d, lo: 0xb7, hi: 0xb9},
- {value: 0x8132, lo: 0xba, hi: 0xba},
- {value: 0x812d, lo: 0xbb, hi: 0xbc},
- {value: 0x8132, lo: 0xbd, hi: 0xbd},
- {value: 0x812d, lo: 0xbe, hi: 0xbe},
- {value: 0x8132, lo: 0xbf, hi: 0xbf},
- // Block 0xa, offset 0x63
- {value: 0x0005, lo: 0x07},
- {value: 0x8132, lo: 0x80, hi: 0x80},
- {value: 0x8132, lo: 0x81, hi: 0x81},
- {value: 0x812d, lo: 0x82, hi: 0x83},
- {value: 0x812d, lo: 0x84, hi: 0x85},
- {value: 0x812d, lo: 0x86, hi: 0x87},
- {value: 0x812d, lo: 0x88, hi: 0x89},
- {value: 0x8132, lo: 0x8a, hi: 0x8a},
- // Block 0xb, offset 0x6b
- {value: 0x0000, lo: 0x03},
- {value: 0x8132, lo: 0xab, hi: 0xb1},
- {value: 0x812d, lo: 0xb2, hi: 0xb2},
- {value: 0x8132, lo: 0xb3, hi: 0xb3},
- // Block 0xc, offset 0x6f
- {value: 0x0000, lo: 0x04},
- {value: 0x8132, lo: 0x96, hi: 0x99},
- {value: 0x8132, lo: 0x9b, hi: 0xa3},
- {value: 0x8132, lo: 0xa5, hi: 0xa7},
- {value: 0x8132, lo: 0xa9, hi: 0xad},
- // Block 0xd, offset 0x74
- {value: 0x0000, lo: 0x01},
- {value: 0x812d, lo: 0x99, hi: 0x9b},
- // Block 0xe, offset 0x76
- {value: 0x0000, lo: 0x10},
- {value: 0x8132, lo: 0x94, hi: 0xa1},
- {value: 0x812d, lo: 0xa3, hi: 0xa3},
- {value: 0x8132, lo: 0xa4, hi: 0xa5},
- {value: 0x812d, lo: 0xa6, hi: 0xa6},
- {value: 0x8132, lo: 0xa7, hi: 0xa8},
- {value: 0x812d, lo: 0xa9, hi: 0xa9},
- {value: 0x8132, lo: 0xaa, hi: 0xac},
- {value: 0x812d, lo: 0xad, hi: 0xaf},
- {value: 0x8116, lo: 0xb0, hi: 0xb0},
- {value: 0x8117, lo: 0xb1, hi: 0xb1},
- {value: 0x8118, lo: 0xb2, hi: 0xb2},
- {value: 0x8132, lo: 0xb3, hi: 0xb5},
- {value: 0x812d, lo: 0xb6, hi: 0xb6},
- {value: 0x8132, lo: 0xb7, hi: 0xb8},
- {value: 0x812d, lo: 0xb9, hi: 0xba},
- {value: 0x8132, lo: 0xbb, hi: 0xbf},
- // Block 0xf, offset 0x87
- {value: 0x0000, lo: 0x07},
- {value: 0xa000, lo: 0xa8, hi: 0xa8},
- {value: 0x3ed8, lo: 0xa9, hi: 0xa9},
- {value: 0xa000, lo: 0xb0, hi: 0xb0},
- {value: 0x3ee0, lo: 0xb1, hi: 0xb1},
- {value: 0xa000, lo: 0xb3, hi: 0xb3},
- {value: 0x3ee8, lo: 0xb4, hi: 0xb4},
- {value: 0x9902, lo: 0xbc, hi: 0xbc},
- // Block 0x10, offset 0x8f
- {value: 0x0008, lo: 0x06},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x8132, lo: 0x91, hi: 0x91},
- {value: 0x812d, lo: 0x92, hi: 0x92},
- {value: 0x8132, lo: 0x93, hi: 0x93},
- {value: 0x8132, lo: 0x94, hi: 0x94},
- {value: 0x45b2, lo: 0x98, hi: 0x9f},
- // Block 0x11, offset 0x96
- {value: 0x0000, lo: 0x02},
- {value: 0x8102, lo: 0xbc, hi: 0xbc},
- {value: 0x9900, lo: 0xbe, hi: 0xbe},
- // Block 0x12, offset 0x99
- {value: 0x0008, lo: 0x06},
- {value: 0xa000, lo: 0x87, hi: 0x87},
- {value: 0x2c9e, lo: 0x8b, hi: 0x8c},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x9900, lo: 0x97, hi: 0x97},
- {value: 0x45f2, lo: 0x9c, hi: 0x9d},
- {value: 0x4602, lo: 0x9f, hi: 0x9f},
- // Block 0x13, offset 0xa0
- {value: 0x0000, lo: 0x03},
- {value: 0x462a, lo: 0xb3, hi: 0xb3},
- {value: 0x4632, lo: 0xb6, hi: 0xb6},
- {value: 0x8102, lo: 0xbc, hi: 0xbc},
- // Block 0x14, offset 0xa4
- {value: 0x0008, lo: 0x03},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x460a, lo: 0x99, hi: 0x9b},
- {value: 0x4622, lo: 0x9e, hi: 0x9e},
- // Block 0x15, offset 0xa8
- {value: 0x0000, lo: 0x01},
- {value: 0x8102, lo: 0xbc, hi: 0xbc},
- // Block 0x16, offset 0xaa
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- // Block 0x17, offset 0xac
- {value: 0x0000, lo: 0x08},
- {value: 0xa000, lo: 0x87, hi: 0x87},
- {value: 0x2cb6, lo: 0x88, hi: 0x88},
- {value: 0x2cae, lo: 0x8b, hi: 0x8b},
- {value: 0x2cbe, lo: 0x8c, hi: 0x8c},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x9900, lo: 0x96, hi: 0x97},
- {value: 0x463a, lo: 0x9c, hi: 0x9c},
- {value: 0x4642, lo: 0x9d, hi: 0x9d},
- // Block 0x18, offset 0xb5
- {value: 0x0000, lo: 0x03},
- {value: 0xa000, lo: 0x92, hi: 0x92},
- {value: 0x2cc6, lo: 0x94, hi: 0x94},
- {value: 0x9900, lo: 0xbe, hi: 0xbe},
- // Block 0x19, offset 0xb9
- {value: 0x0000, lo: 0x06},
- {value: 0xa000, lo: 0x86, hi: 0x87},
- {value: 0x2cce, lo: 0x8a, hi: 0x8a},
- {value: 0x2cde, lo: 0x8b, hi: 0x8b},
- {value: 0x2cd6, lo: 0x8c, hi: 0x8c},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x9900, lo: 0x97, hi: 0x97},
- // Block 0x1a, offset 0xc0
- {value: 0x1801, lo: 0x04},
- {value: 0xa000, lo: 0x86, hi: 0x86},
- {value: 0x3ef0, lo: 0x88, hi: 0x88},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x8120, lo: 0x95, hi: 0x96},
- // Block 0x1b, offset 0xc5
- {value: 0x0000, lo: 0x02},
- {value: 0x8102, lo: 0xbc, hi: 0xbc},
- {value: 0xa000, lo: 0xbf, hi: 0xbf},
- // Block 0x1c, offset 0xc8
- {value: 0x0000, lo: 0x09},
- {value: 0x2ce6, lo: 0x80, hi: 0x80},
- {value: 0x9900, lo: 0x82, hi: 0x82},
- {value: 0xa000, lo: 0x86, hi: 0x86},
- {value: 0x2cee, lo: 0x87, hi: 0x87},
- {value: 0x2cf6, lo: 0x88, hi: 0x88},
- {value: 0x2f50, lo: 0x8a, hi: 0x8a},
- {value: 0x2dd8, lo: 0x8b, hi: 0x8b},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x9900, lo: 0x95, hi: 0x96},
- // Block 0x1d, offset 0xd2
- {value: 0x0000, lo: 0x01},
- {value: 0x9900, lo: 0xbe, hi: 0xbe},
- // Block 0x1e, offset 0xd4
- {value: 0x0000, lo: 0x06},
- {value: 0xa000, lo: 0x86, hi: 0x87},
- {value: 0x2cfe, lo: 0x8a, hi: 0x8a},
- {value: 0x2d0e, lo: 0x8b, hi: 0x8b},
- {value: 0x2d06, lo: 0x8c, hi: 0x8c},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x9900, lo: 0x97, hi: 0x97},
- // Block 0x1f, offset 0xdb
- {value: 0x6bea, lo: 0x07},
- {value: 0x9904, lo: 0x8a, hi: 0x8a},
- {value: 0x9900, lo: 0x8f, hi: 0x8f},
- {value: 0xa000, lo: 0x99, hi: 0x99},
- {value: 0x3ef8, lo: 0x9a, hi: 0x9a},
- {value: 0x2f58, lo: 0x9c, hi: 0x9c},
- {value: 0x2de3, lo: 0x9d, hi: 0x9d},
- {value: 0x2d16, lo: 0x9e, hi: 0x9f},
- // Block 0x20, offset 0xe3
- {value: 0x0000, lo: 0x03},
- {value: 0x2621, lo: 0xb3, hi: 0xb3},
- {value: 0x8122, lo: 0xb8, hi: 0xb9},
- {value: 0x8104, lo: 0xba, hi: 0xba},
- // Block 0x21, offset 0xe7
- {value: 0x0000, lo: 0x01},
- {value: 0x8123, lo: 0x88, hi: 0x8b},
- // Block 0x22, offset 0xe9
- {value: 0x0000, lo: 0x02},
- {value: 0x2636, lo: 0xb3, hi: 0xb3},
- {value: 0x8124, lo: 0xb8, hi: 0xb9},
- // Block 0x23, offset 0xec
- {value: 0x0000, lo: 0x03},
- {value: 0x8125, lo: 0x88, hi: 0x8b},
- {value: 0x2628, lo: 0x9c, hi: 0x9c},
- {value: 0x262f, lo: 0x9d, hi: 0x9d},
- // Block 0x24, offset 0xf0
- {value: 0x0000, lo: 0x05},
- {value: 0x030b, lo: 0x8c, hi: 0x8c},
- {value: 0x812d, lo: 0x98, hi: 0x99},
- {value: 0x812d, lo: 0xb5, hi: 0xb5},
- {value: 0x812d, lo: 0xb7, hi: 0xb7},
- {value: 0x812b, lo: 0xb9, hi: 0xb9},
- // Block 0x25, offset 0xf6
- {value: 0x0000, lo: 0x10},
- {value: 0x2644, lo: 0x83, hi: 0x83},
- {value: 0x264b, lo: 0x8d, hi: 0x8d},
- {value: 0x2652, lo: 0x92, hi: 0x92},
- {value: 0x2659, lo: 0x97, hi: 0x97},
- {value: 0x2660, lo: 0x9c, hi: 0x9c},
- {value: 0x263d, lo: 0xa9, hi: 0xa9},
- {value: 0x8126, lo: 0xb1, hi: 0xb1},
- {value: 0x8127, lo: 0xb2, hi: 0xb2},
- {value: 0x4a66, lo: 0xb3, hi: 0xb3},
- {value: 0x8128, lo: 0xb4, hi: 0xb4},
- {value: 0x4a6f, lo: 0xb5, hi: 0xb5},
- {value: 0x464a, lo: 0xb6, hi: 0xb6},
- {value: 0x468a, lo: 0xb7, hi: 0xb7},
- {value: 0x4652, lo: 0xb8, hi: 0xb8},
- {value: 0x4695, lo: 0xb9, hi: 0xb9},
- {value: 0x8127, lo: 0xba, hi: 0xbd},
- // Block 0x26, offset 0x107
- {value: 0x0000, lo: 0x0b},
- {value: 0x8127, lo: 0x80, hi: 0x80},
- {value: 0x4a78, lo: 0x81, hi: 0x81},
- {value: 0x8132, lo: 0x82, hi: 0x83},
- {value: 0x8104, lo: 0x84, hi: 0x84},
- {value: 0x8132, lo: 0x86, hi: 0x87},
- {value: 0x266e, lo: 0x93, hi: 0x93},
- {value: 0x2675, lo: 0x9d, hi: 0x9d},
- {value: 0x267c, lo: 0xa2, hi: 0xa2},
- {value: 0x2683, lo: 0xa7, hi: 0xa7},
- {value: 0x268a, lo: 0xac, hi: 0xac},
- {value: 0x2667, lo: 0xb9, hi: 0xb9},
- // Block 0x27, offset 0x113
- {value: 0x0000, lo: 0x01},
- {value: 0x812d, lo: 0x86, hi: 0x86},
- // Block 0x28, offset 0x115
- {value: 0x0000, lo: 0x05},
- {value: 0xa000, lo: 0xa5, hi: 0xa5},
- {value: 0x2d1e, lo: 0xa6, hi: 0xa6},
- {value: 0x9900, lo: 0xae, hi: 0xae},
- {value: 0x8102, lo: 0xb7, hi: 0xb7},
- {value: 0x8104, lo: 0xb9, hi: 0xba},
- // Block 0x29, offset 0x11b
- {value: 0x0000, lo: 0x01},
- {value: 0x812d, lo: 0x8d, hi: 0x8d},
- // Block 0x2a, offset 0x11d
- {value: 0x0000, lo: 0x01},
- {value: 0x030f, lo: 0xbc, hi: 0xbc},
- // Block 0x2b, offset 0x11f
- {value: 0x0000, lo: 0x01},
- {value: 0xa000, lo: 0x80, hi: 0x92},
- // Block 0x2c, offset 0x121
- {value: 0x0000, lo: 0x01},
- {value: 0xb900, lo: 0xa1, hi: 0xb5},
- // Block 0x2d, offset 0x123
- {value: 0x0000, lo: 0x01},
- {value: 0x9900, lo: 0xa8, hi: 0xbf},
- // Block 0x2e, offset 0x125
- {value: 0x0000, lo: 0x01},
- {value: 0x9900, lo: 0x80, hi: 0x82},
- // Block 0x2f, offset 0x127
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0x9d, hi: 0x9f},
- // Block 0x30, offset 0x129
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0x94, hi: 0x94},
- {value: 0x8104, lo: 0xb4, hi: 0xb4},
- // Block 0x31, offset 0x12c
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0x92, hi: 0x92},
- {value: 0x8132, lo: 0x9d, hi: 0x9d},
- // Block 0x32, offset 0x12f
- {value: 0x0000, lo: 0x01},
- {value: 0x8131, lo: 0xa9, hi: 0xa9},
- // Block 0x33, offset 0x131
- {value: 0x0004, lo: 0x02},
- {value: 0x812e, lo: 0xb9, hi: 0xba},
- {value: 0x812d, lo: 0xbb, hi: 0xbb},
- // Block 0x34, offset 0x134
- {value: 0x0000, lo: 0x02},
- {value: 0x8132, lo: 0x97, hi: 0x97},
- {value: 0x812d, lo: 0x98, hi: 0x98},
- // Block 0x35, offset 0x137
- {value: 0x0000, lo: 0x03},
- {value: 0x8104, lo: 0xa0, hi: 0xa0},
- {value: 0x8132, lo: 0xb5, hi: 0xbc},
- {value: 0x812d, lo: 0xbf, hi: 0xbf},
- // Block 0x36, offset 0x13b
- {value: 0x0000, lo: 0x04},
- {value: 0x8132, lo: 0xb0, hi: 0xb4},
- {value: 0x812d, lo: 0xb5, hi: 0xba},
- {value: 0x8132, lo: 0xbb, hi: 0xbc},
- {value: 0x812d, lo: 0xbd, hi: 0xbd},
- // Block 0x37, offset 0x140
- {value: 0x0000, lo: 0x08},
- {value: 0x2d66, lo: 0x80, hi: 0x80},
- {value: 0x2d6e, lo: 0x81, hi: 0x81},
- {value: 0xa000, lo: 0x82, hi: 0x82},
- {value: 0x2d76, lo: 0x83, hi: 0x83},
- {value: 0x8104, lo: 0x84, hi: 0x84},
- {value: 0x8132, lo: 0xab, hi: 0xab},
- {value: 0x812d, lo: 0xac, hi: 0xac},
- {value: 0x8132, lo: 0xad, hi: 0xb3},
- // Block 0x38, offset 0x149
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0xaa, hi: 0xab},
- // Block 0x39, offset 0x14b
- {value: 0x0000, lo: 0x02},
- {value: 0x8102, lo: 0xa6, hi: 0xa6},
- {value: 0x8104, lo: 0xb2, hi: 0xb3},
- // Block 0x3a, offset 0x14e
- {value: 0x0000, lo: 0x01},
- {value: 0x8102, lo: 0xb7, hi: 0xb7},
- // Block 0x3b, offset 0x150
- {value: 0x0000, lo: 0x0a},
- {value: 0x8132, lo: 0x90, hi: 0x92},
- {value: 0x8101, lo: 0x94, hi: 0x94},
- {value: 0x812d, lo: 0x95, hi: 0x99},
- {value: 0x8132, lo: 0x9a, hi: 0x9b},
- {value: 0x812d, lo: 0x9c, hi: 0x9f},
- {value: 0x8132, lo: 0xa0, hi: 0xa0},
- {value: 0x8101, lo: 0xa2, hi: 0xa8},
- {value: 0x812d, lo: 0xad, hi: 0xad},
- {value: 0x8132, lo: 0xb4, hi: 0xb4},
- {value: 0x8132, lo: 0xb8, hi: 0xb9},
- // Block 0x3c, offset 0x15b
- {value: 0x0002, lo: 0x0a},
- {value: 0x0043, lo: 0xac, hi: 0xac},
- {value: 0x00d1, lo: 0xad, hi: 0xad},
- {value: 0x0045, lo: 0xae, hi: 0xae},
- {value: 0x0049, lo: 0xb0, hi: 0xb1},
- {value: 0x00e6, lo: 0xb2, hi: 0xb2},
- {value: 0x004f, lo: 0xb3, hi: 0xba},
- {value: 0x005f, lo: 0xbc, hi: 0xbc},
- {value: 0x00ef, lo: 0xbd, hi: 0xbd},
- {value: 0x0061, lo: 0xbe, hi: 0xbe},
- {value: 0x0065, lo: 0xbf, hi: 0xbf},
- // Block 0x3d, offset 0x166
- {value: 0x0000, lo: 0x0f},
- {value: 0x8132, lo: 0x80, hi: 0x81},
- {value: 0x812d, lo: 0x82, hi: 0x82},
- {value: 0x8132, lo: 0x83, hi: 0x89},
- {value: 0x812d, lo: 0x8a, hi: 0x8a},
- {value: 0x8132, lo: 0x8b, hi: 0x8c},
- {value: 0x8135, lo: 0x8d, hi: 0x8d},
- {value: 0x812a, lo: 0x8e, hi: 0x8e},
- {value: 0x812d, lo: 0x8f, hi: 0x8f},
- {value: 0x8129, lo: 0x90, hi: 0x90},
- {value: 0x8132, lo: 0x91, hi: 0xb5},
- {value: 0x8132, lo: 0xbb, hi: 0xbb},
- {value: 0x8134, lo: 0xbc, hi: 0xbc},
- {value: 0x812d, lo: 0xbd, hi: 0xbd},
- {value: 0x8132, lo: 0xbe, hi: 0xbe},
- {value: 0x812d, lo: 0xbf, hi: 0xbf},
- // Block 0x3e, offset 0x176
- {value: 0x0000, lo: 0x0d},
- {value: 0x0001, lo: 0x80, hi: 0x8a},
- {value: 0x043b, lo: 0x91, hi: 0x91},
- {value: 0x429b, lo: 0x97, hi: 0x97},
- {value: 0x001d, lo: 0xa4, hi: 0xa4},
- {value: 0x1873, lo: 0xa5, hi: 0xa5},
- {value: 0x1b5c, lo: 0xa6, hi: 0xa6},
- {value: 0x0001, lo: 0xaf, hi: 0xaf},
- {value: 0x2691, lo: 0xb3, hi: 0xb3},
- {value: 0x27fe, lo: 0xb4, hi: 0xb4},
- {value: 0x2698, lo: 0xb6, hi: 0xb6},
- {value: 0x2808, lo: 0xb7, hi: 0xb7},
- {value: 0x186d, lo: 0xbc, hi: 0xbc},
- {value: 0x4269, lo: 0xbe, hi: 0xbe},
- // Block 0x3f, offset 0x184
- {value: 0x0002, lo: 0x0d},
- {value: 0x1933, lo: 0x87, hi: 0x87},
- {value: 0x1930, lo: 0x88, hi: 0x88},
- {value: 0x1870, lo: 0x89, hi: 0x89},
- {value: 0x298e, lo: 0x97, hi: 0x97},
- {value: 0x0001, lo: 0x9f, hi: 0x9f},
- {value: 0x0021, lo: 0xb0, hi: 0xb0},
- {value: 0x0093, lo: 0xb1, hi: 0xb1},
- {value: 0x0029, lo: 0xb4, hi: 0xb9},
- {value: 0x0017, lo: 0xba, hi: 0xba},
- {value: 0x0467, lo: 0xbb, hi: 0xbb},
- {value: 0x003b, lo: 0xbc, hi: 0xbc},
- {value: 0x0011, lo: 0xbd, hi: 0xbe},
- {value: 0x009d, lo: 0xbf, hi: 0xbf},
- // Block 0x40, offset 0x192
- {value: 0x0002, lo: 0x0f},
- {value: 0x0021, lo: 0x80, hi: 0x89},
- {value: 0x0017, lo: 0x8a, hi: 0x8a},
- {value: 0x0467, lo: 0x8b, hi: 0x8b},
- {value: 0x003b, lo: 0x8c, hi: 0x8c},
- {value: 0x0011, lo: 0x8d, hi: 0x8e},
- {value: 0x0083, lo: 0x90, hi: 0x90},
- {value: 0x008b, lo: 0x91, hi: 0x91},
- {value: 0x009f, lo: 0x92, hi: 0x92},
- {value: 0x00b1, lo: 0x93, hi: 0x93},
- {value: 0x0104, lo: 0x94, hi: 0x94},
- {value: 0x0091, lo: 0x95, hi: 0x95},
- {value: 0x0097, lo: 0x96, hi: 0x99},
- {value: 0x00a1, lo: 0x9a, hi: 0x9a},
- {value: 0x00a7, lo: 0x9b, hi: 0x9c},
- {value: 0x1999, lo: 0xa8, hi: 0xa8},
- // Block 0x41, offset 0x1a2
- {value: 0x0000, lo: 0x0d},
- {value: 0x8132, lo: 0x90, hi: 0x91},
- {value: 0x8101, lo: 0x92, hi: 0x93},
- {value: 0x8132, lo: 0x94, hi: 0x97},
- {value: 0x8101, lo: 0x98, hi: 0x9a},
- {value: 0x8132, lo: 0x9b, hi: 0x9c},
- {value: 0x8132, lo: 0xa1, hi: 0xa1},
- {value: 0x8101, lo: 0xa5, hi: 0xa6},
- {value: 0x8132, lo: 0xa7, hi: 0xa7},
- {value: 0x812d, lo: 0xa8, hi: 0xa8},
- {value: 0x8132, lo: 0xa9, hi: 0xa9},
- {value: 0x8101, lo: 0xaa, hi: 0xab},
- {value: 0x812d, lo: 0xac, hi: 0xaf},
- {value: 0x8132, lo: 0xb0, hi: 0xb0},
- // Block 0x42, offset 0x1b0
- {value: 0x0007, lo: 0x06},
- {value: 0x2180, lo: 0x89, hi: 0x89},
- {value: 0xa000, lo: 0x90, hi: 0x90},
- {value: 0xa000, lo: 0x92, hi: 0x92},
- {value: 0xa000, lo: 0x94, hi: 0x94},
- {value: 0x3bb9, lo: 0x9a, hi: 0x9b},
- {value: 0x3bc7, lo: 0xae, hi: 0xae},
- // Block 0x43, offset 0x1b7
- {value: 0x000e, lo: 0x05},
- {value: 0x3bce, lo: 0x8d, hi: 0x8e},
- {value: 0x3bd5, lo: 0x8f, hi: 0x8f},
- {value: 0xa000, lo: 0x90, hi: 0x90},
- {value: 0xa000, lo: 0x92, hi: 0x92},
- {value: 0xa000, lo: 0x94, hi: 0x94},
- // Block 0x44, offset 0x1bd
- {value: 0x0173, lo: 0x0e},
- {value: 0xa000, lo: 0x83, hi: 0x83},
- {value: 0x3be3, lo: 0x84, hi: 0x84},
- {value: 0xa000, lo: 0x88, hi: 0x88},
- {value: 0x3bea, lo: 0x89, hi: 0x89},
- {value: 0xa000, lo: 0x8b, hi: 0x8b},
- {value: 0x3bf1, lo: 0x8c, hi: 0x8c},
- {value: 0xa000, lo: 0xa3, hi: 0xa3},
- {value: 0x3bf8, lo: 0xa4, hi: 0xa4},
- {value: 0xa000, lo: 0xa5, hi: 0xa5},
- {value: 0x3bff, lo: 0xa6, hi: 0xa6},
- {value: 0x269f, lo: 0xac, hi: 0xad},
- {value: 0x26a6, lo: 0xaf, hi: 0xaf},
- {value: 0x281c, lo: 0xb0, hi: 0xb0},
- {value: 0xa000, lo: 0xbc, hi: 0xbc},
- // Block 0x45, offset 0x1cc
- {value: 0x0007, lo: 0x03},
- {value: 0x3c68, lo: 0xa0, hi: 0xa1},
- {value: 0x3c92, lo: 0xa2, hi: 0xa3},
- {value: 0x3cbc, lo: 0xaa, hi: 0xad},
- // Block 0x46, offset 0x1d0
- {value: 0x0004, lo: 0x01},
- {value: 0x048b, lo: 0xa9, hi: 0xaa},
- // Block 0x47, offset 0x1d2
- {value: 0x0002, lo: 0x03},
- {value: 0x0057, lo: 0x80, hi: 0x8f},
- {value: 0x0083, lo: 0x90, hi: 0xa9},
- {value: 0x0021, lo: 0xaa, hi: 0xaa},
- // Block 0x48, offset 0x1d6
- {value: 0x0000, lo: 0x01},
- {value: 0x299b, lo: 0x8c, hi: 0x8c},
- // Block 0x49, offset 0x1d8
- {value: 0x0263, lo: 0x02},
- {value: 0x1b8c, lo: 0xb4, hi: 0xb4},
- {value: 0x192d, lo: 0xb5, hi: 0xb6},
- // Block 0x4a, offset 0x1db
- {value: 0x0000, lo: 0x01},
- {value: 0x4573, lo: 0x9c, hi: 0x9c},
- // Block 0x4b, offset 0x1dd
- {value: 0x0000, lo: 0x02},
- {value: 0x0095, lo: 0xbc, hi: 0xbc},
- {value: 0x006d, lo: 0xbd, hi: 0xbd},
- // Block 0x4c, offset 0x1e0
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0xaf, hi: 0xb1},
- // Block 0x4d, offset 0x1e2
- {value: 0x0000, lo: 0x02},
- {value: 0x047f, lo: 0xaf, hi: 0xaf},
- {value: 0x8104, lo: 0xbf, hi: 0xbf},
- // Block 0x4e, offset 0x1e5
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0xa0, hi: 0xbf},
- // Block 0x4f, offset 0x1e7
- {value: 0x0000, lo: 0x01},
- {value: 0x0dc3, lo: 0x9f, hi: 0x9f},
- // Block 0x50, offset 0x1e9
- {value: 0x0000, lo: 0x01},
- {value: 0x162f, lo: 0xb3, hi: 0xb3},
- // Block 0x51, offset 0x1eb
- {value: 0x0004, lo: 0x0b},
- {value: 0x1597, lo: 0x80, hi: 0x82},
- {value: 0x15af, lo: 0x83, hi: 0x83},
- {value: 0x15c7, lo: 0x84, hi: 0x85},
- {value: 0x15d7, lo: 0x86, hi: 0x89},
- {value: 0x15eb, lo: 0x8a, hi: 0x8c},
- {value: 0x15ff, lo: 0x8d, hi: 0x8d},
- {value: 0x1607, lo: 0x8e, hi: 0x8e},
- {value: 0x160f, lo: 0x8f, hi: 0x90},
- {value: 0x161b, lo: 0x91, hi: 0x93},
- {value: 0x162b, lo: 0x94, hi: 0x94},
- {value: 0x1633, lo: 0x95, hi: 0x95},
- // Block 0x52, offset 0x1f7
- {value: 0x0004, lo: 0x09},
- {value: 0x0001, lo: 0x80, hi: 0x80},
- {value: 0x812c, lo: 0xaa, hi: 0xaa},
- {value: 0x8131, lo: 0xab, hi: 0xab},
- {value: 0x8133, lo: 0xac, hi: 0xac},
- {value: 0x812e, lo: 0xad, hi: 0xad},
- {value: 0x812f, lo: 0xae, hi: 0xae},
- {value: 0x812f, lo: 0xaf, hi: 0xaf},
- {value: 0x04b3, lo: 0xb6, hi: 0xb6},
- {value: 0x0887, lo: 0xb8, hi: 0xba},
- // Block 0x53, offset 0x201
- {value: 0x0005, lo: 0x09},
- {value: 0x0313, lo: 0xb1, hi: 0xb1},
- {value: 0x0317, lo: 0xb2, hi: 0xb2},
- {value: 0x4345, lo: 0xb3, hi: 0xb3},
- {value: 0x031b, lo: 0xb4, hi: 0xb4},
- {value: 0x434a, lo: 0xb5, hi: 0xb6},
- {value: 0x031f, lo: 0xb7, hi: 0xb7},
- {value: 0x0323, lo: 0xb8, hi: 0xb8},
- {value: 0x0327, lo: 0xb9, hi: 0xb9},
- {value: 0x4354, lo: 0xba, hi: 0xbf},
- // Block 0x54, offset 0x20b
- {value: 0x0000, lo: 0x02},
- {value: 0x8132, lo: 0xaf, hi: 0xaf},
- {value: 0x8132, lo: 0xb4, hi: 0xbd},
- // Block 0x55, offset 0x20e
- {value: 0x0000, lo: 0x03},
- {value: 0x020f, lo: 0x9c, hi: 0x9c},
- {value: 0x0212, lo: 0x9d, hi: 0x9d},
- {value: 0x8132, lo: 0x9e, hi: 0x9f},
- // Block 0x56, offset 0x212
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0xb0, hi: 0xb1},
- // Block 0x57, offset 0x214
- {value: 0x0000, lo: 0x01},
- {value: 0x163b, lo: 0xb0, hi: 0xb0},
- // Block 0x58, offset 0x216
- {value: 0x000c, lo: 0x01},
- {value: 0x00d7, lo: 0xb8, hi: 0xb9},
- // Block 0x59, offset 0x218
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0x86, hi: 0x86},
- // Block 0x5a, offset 0x21a
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0x84, hi: 0x84},
- {value: 0x8132, lo: 0xa0, hi: 0xb1},
- // Block 0x5b, offset 0x21d
- {value: 0x0000, lo: 0x01},
- {value: 0x812d, lo: 0xab, hi: 0xad},
- // Block 0x5c, offset 0x21f
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0x93, hi: 0x93},
- // Block 0x5d, offset 0x221
- {value: 0x0000, lo: 0x01},
- {value: 0x8102, lo: 0xb3, hi: 0xb3},
- // Block 0x5e, offset 0x223
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0x80, hi: 0x80},
- // Block 0x5f, offset 0x225
- {value: 0x0000, lo: 0x05},
- {value: 0x8132, lo: 0xb0, hi: 0xb0},
- {value: 0x8132, lo: 0xb2, hi: 0xb3},
- {value: 0x812d, lo: 0xb4, hi: 0xb4},
- {value: 0x8132, lo: 0xb7, hi: 0xb8},
- {value: 0x8132, lo: 0xbe, hi: 0xbf},
- // Block 0x60, offset 0x22b
- {value: 0x0000, lo: 0x02},
- {value: 0x8132, lo: 0x81, hi: 0x81},
- {value: 0x8104, lo: 0xb6, hi: 0xb6},
- // Block 0x61, offset 0x22e
- {value: 0x0008, lo: 0x03},
- {value: 0x1637, lo: 0x9c, hi: 0x9d},
- {value: 0x0125, lo: 0x9e, hi: 0x9e},
- {value: 0x1643, lo: 0x9f, hi: 0x9f},
- // Block 0x62, offset 0x232
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0xad, hi: 0xad},
- // Block 0x63, offset 0x234
- {value: 0x0000, lo: 0x06},
- {value: 0xe500, lo: 0x80, hi: 0x80},
- {value: 0xc600, lo: 0x81, hi: 0x9b},
- {value: 0xe500, lo: 0x9c, hi: 0x9c},
- {value: 0xc600, lo: 0x9d, hi: 0xb7},
- {value: 0xe500, lo: 0xb8, hi: 0xb8},
- {value: 0xc600, lo: 0xb9, hi: 0xbf},
- // Block 0x64, offset 0x23b
- {value: 0x0000, lo: 0x05},
- {value: 0xc600, lo: 0x80, hi: 0x93},
- {value: 0xe500, lo: 0x94, hi: 0x94},
- {value: 0xc600, lo: 0x95, hi: 0xaf},
- {value: 0xe500, lo: 0xb0, hi: 0xb0},
- {value: 0xc600, lo: 0xb1, hi: 0xbf},
- // Block 0x65, offset 0x241
- {value: 0x0000, lo: 0x05},
- {value: 0xc600, lo: 0x80, hi: 0x8b},
- {value: 0xe500, lo: 0x8c, hi: 0x8c},
- {value: 0xc600, lo: 0x8d, hi: 0xa7},
- {value: 0xe500, lo: 0xa8, hi: 0xa8},
- {value: 0xc600, lo: 0xa9, hi: 0xbf},
- // Block 0x66, offset 0x247
- {value: 0x0000, lo: 0x07},
- {value: 0xc600, lo: 0x80, hi: 0x83},
- {value: 0xe500, lo: 0x84, hi: 0x84},
- {value: 0xc600, lo: 0x85, hi: 0x9f},
- {value: 0xe500, lo: 0xa0, hi: 0xa0},
- {value: 0xc600, lo: 0xa1, hi: 0xbb},
- {value: 0xe500, lo: 0xbc, hi: 0xbc},
- {value: 0xc600, lo: 0xbd, hi: 0xbf},
- // Block 0x67, offset 0x24f
- {value: 0x0000, lo: 0x05},
- {value: 0xc600, lo: 0x80, hi: 0x97},
- {value: 0xe500, lo: 0x98, hi: 0x98},
- {value: 0xc600, lo: 0x99, hi: 0xb3},
- {value: 0xe500, lo: 0xb4, hi: 0xb4},
- {value: 0xc600, lo: 0xb5, hi: 0xbf},
- // Block 0x68, offset 0x255
- {value: 0x0000, lo: 0x05},
- {value: 0xc600, lo: 0x80, hi: 0x8f},
- {value: 0xe500, lo: 0x90, hi: 0x90},
- {value: 0xc600, lo: 0x91, hi: 0xab},
- {value: 0xe500, lo: 0xac, hi: 0xac},
- {value: 0xc600, lo: 0xad, hi: 0xbf},
- // Block 0x69, offset 0x25b
- {value: 0x0000, lo: 0x05},
- {value: 0xc600, lo: 0x80, hi: 0x87},
- {value: 0xe500, lo: 0x88, hi: 0x88},
- {value: 0xc600, lo: 0x89, hi: 0xa3},
- {value: 0xe500, lo: 0xa4, hi: 0xa4},
- {value: 0xc600, lo: 0xa5, hi: 0xbf},
- // Block 0x6a, offset 0x261
- {value: 0x0000, lo: 0x03},
- {value: 0xc600, lo: 0x80, hi: 0x87},
- {value: 0xe500, lo: 0x88, hi: 0x88},
- {value: 0xc600, lo: 0x89, hi: 0xa3},
- // Block 0x6b, offset 0x265
- {value: 0x0002, lo: 0x01},
- {value: 0x0003, lo: 0x81, hi: 0xbf},
- // Block 0x6c, offset 0x267
- {value: 0x0000, lo: 0x01},
- {value: 0x812d, lo: 0xbd, hi: 0xbd},
- // Block 0x6d, offset 0x269
- {value: 0x0000, lo: 0x01},
- {value: 0x812d, lo: 0xa0, hi: 0xa0},
- // Block 0x6e, offset 0x26b
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0xb6, hi: 0xba},
- // Block 0x6f, offset 0x26d
- {value: 0x002c, lo: 0x05},
- {value: 0x812d, lo: 0x8d, hi: 0x8d},
- {value: 0x8132, lo: 0x8f, hi: 0x8f},
- {value: 0x8132, lo: 0xb8, hi: 0xb8},
- {value: 0x8101, lo: 0xb9, hi: 0xba},
- {value: 0x8104, lo: 0xbf, hi: 0xbf},
- // Block 0x70, offset 0x273
- {value: 0x0000, lo: 0x02},
- {value: 0x8132, lo: 0xa5, hi: 0xa5},
- {value: 0x812d, lo: 0xa6, hi: 0xa6},
- // Block 0x71, offset 0x276
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0x86, hi: 0x86},
- {value: 0x8104, lo: 0xbf, hi: 0xbf},
- // Block 0x72, offset 0x279
- {value: 0x17fe, lo: 0x07},
- {value: 0xa000, lo: 0x99, hi: 0x99},
- {value: 0x4238, lo: 0x9a, hi: 0x9a},
- {value: 0xa000, lo: 0x9b, hi: 0x9b},
- {value: 0x4242, lo: 0x9c, hi: 0x9c},
- {value: 0xa000, lo: 0xa5, hi: 0xa5},
- {value: 0x424c, lo: 0xab, hi: 0xab},
- {value: 0x8104, lo: 0xb9, hi: 0xba},
- // Block 0x73, offset 0x281
- {value: 0x0000, lo: 0x06},
- {value: 0x8132, lo: 0x80, hi: 0x82},
- {value: 0x9900, lo: 0xa7, hi: 0xa7},
- {value: 0x2d7e, lo: 0xae, hi: 0xae},
- {value: 0x2d88, lo: 0xaf, hi: 0xaf},
- {value: 0xa000, lo: 0xb1, hi: 0xb2},
- {value: 0x8104, lo: 0xb3, hi: 0xb4},
- // Block 0x74, offset 0x288
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0x80, hi: 0x80},
- {value: 0x8102, lo: 0x8a, hi: 0x8a},
- // Block 0x75, offset 0x28b
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0xb5, hi: 0xb5},
- {value: 0x8102, lo: 0xb6, hi: 0xb6},
- // Block 0x76, offset 0x28e
- {value: 0x0002, lo: 0x01},
- {value: 0x8102, lo: 0xa9, hi: 0xaa},
- // Block 0x77, offset 0x290
- {value: 0x0000, lo: 0x07},
- {value: 0xa000, lo: 0x87, hi: 0x87},
- {value: 0x2d92, lo: 0x8b, hi: 0x8b},
- {value: 0x2d9c, lo: 0x8c, hi: 0x8c},
- {value: 0x8104, lo: 0x8d, hi: 0x8d},
- {value: 0x9900, lo: 0x97, hi: 0x97},
- {value: 0x8132, lo: 0xa6, hi: 0xac},
- {value: 0x8132, lo: 0xb0, hi: 0xb4},
- // Block 0x78, offset 0x298
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0x82, hi: 0x82},
- {value: 0x8102, lo: 0x86, hi: 0x86},
- // Block 0x79, offset 0x29b
- {value: 0x6b5a, lo: 0x06},
- {value: 0x9900, lo: 0xb0, hi: 0xb0},
- {value: 0xa000, lo: 0xb9, hi: 0xb9},
- {value: 0x9900, lo: 0xba, hi: 0xba},
- {value: 0x2db0, lo: 0xbb, hi: 0xbb},
- {value: 0x2da6, lo: 0xbc, hi: 0xbd},
- {value: 0x2dba, lo: 0xbe, hi: 0xbe},
- // Block 0x7a, offset 0x2a2
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0x82, hi: 0x82},
- {value: 0x8102, lo: 0x83, hi: 0x83},
- // Block 0x7b, offset 0x2a5
- {value: 0x0000, lo: 0x05},
- {value: 0x9900, lo: 0xaf, hi: 0xaf},
- {value: 0xa000, lo: 0xb8, hi: 0xb9},
- {value: 0x2dc4, lo: 0xba, hi: 0xba},
- {value: 0x2dce, lo: 0xbb, hi: 0xbb},
- {value: 0x8104, lo: 0xbf, hi: 0xbf},
- // Block 0x7c, offset 0x2ab
- {value: 0x0000, lo: 0x01},
- {value: 0x8102, lo: 0x80, hi: 0x80},
- // Block 0x7d, offset 0x2ad
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0xbf, hi: 0xbf},
- // Block 0x7e, offset 0x2af
- {value: 0x0000, lo: 0x02},
- {value: 0x8104, lo: 0xb6, hi: 0xb6},
- {value: 0x8102, lo: 0xb7, hi: 0xb7},
- // Block 0x7f, offset 0x2b2
- {value: 0x0000, lo: 0x01},
- {value: 0x8104, lo: 0xab, hi: 0xab},
- // Block 0x80, offset 0x2b4
- {value: 0x0000, lo: 0x01},
- {value: 0x8101, lo: 0xb0, hi: 0xb4},
- // Block 0x81, offset 0x2b6
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0xb0, hi: 0xb6},
- // Block 0x82, offset 0x2b8
- {value: 0x0000, lo: 0x01},
- {value: 0x8101, lo: 0x9e, hi: 0x9e},
- // Block 0x83, offset 0x2ba
- {value: 0x0000, lo: 0x0c},
- {value: 0x4662, lo: 0x9e, hi: 0x9e},
- {value: 0x466c, lo: 0x9f, hi: 0x9f},
- {value: 0x46a0, lo: 0xa0, hi: 0xa0},
- {value: 0x46ae, lo: 0xa1, hi: 0xa1},
- {value: 0x46bc, lo: 0xa2, hi: 0xa2},
- {value: 0x46ca, lo: 0xa3, hi: 0xa3},
- {value: 0x46d8, lo: 0xa4, hi: 0xa4},
- {value: 0x812b, lo: 0xa5, hi: 0xa6},
- {value: 0x8101, lo: 0xa7, hi: 0xa9},
- {value: 0x8130, lo: 0xad, hi: 0xad},
- {value: 0x812b, lo: 0xae, hi: 0xb2},
- {value: 0x812d, lo: 0xbb, hi: 0xbf},
- // Block 0x84, offset 0x2c7
- {value: 0x0000, lo: 0x09},
- {value: 0x812d, lo: 0x80, hi: 0x82},
- {value: 0x8132, lo: 0x85, hi: 0x89},
- {value: 0x812d, lo: 0x8a, hi: 0x8b},
- {value: 0x8132, lo: 0xaa, hi: 0xad},
- {value: 0x4676, lo: 0xbb, hi: 0xbb},
- {value: 0x4680, lo: 0xbc, hi: 0xbc},
- {value: 0x46e6, lo: 0xbd, hi: 0xbd},
- {value: 0x4702, lo: 0xbe, hi: 0xbe},
- {value: 0x46f4, lo: 0xbf, hi: 0xbf},
- // Block 0x85, offset 0x2d1
- {value: 0x0000, lo: 0x01},
- {value: 0x4710, lo: 0x80, hi: 0x80},
- // Block 0x86, offset 0x2d3
- {value: 0x0000, lo: 0x01},
- {value: 0x8132, lo: 0x82, hi: 0x84},
- // Block 0x87, offset 0x2d5
- {value: 0x0002, lo: 0x03},
- {value: 0x0043, lo: 0x80, hi: 0x99},
- {value: 0x0083, lo: 0x9a, hi: 0xb3},
- {value: 0x0043, lo: 0xb4, hi: 0xbf},
- // Block 0x88, offset 0x2d9
- {value: 0x0002, lo: 0x04},
- {value: 0x005b, lo: 0x80, hi: 0x8d},
- {value: 0x0083, lo: 0x8e, hi: 0x94},
- {value: 0x0093, lo: 0x96, hi: 0xa7},
- {value: 0x0043, lo: 0xa8, hi: 0xbf},
- // Block 0x89, offset 0x2de
- {value: 0x0002, lo: 0x0b},
- {value: 0x0073, lo: 0x80, hi: 0x81},
- {value: 0x0083, lo: 0x82, hi: 0x9b},
- {value: 0x0043, lo: 0x9c, hi: 0x9c},
- {value: 0x0047, lo: 0x9e, hi: 0x9f},
- {value: 0x004f, lo: 0xa2, hi: 0xa2},
- {value: 0x0055, lo: 0xa5, hi: 0xa6},
- {value: 0x005d, lo: 0xa9, hi: 0xac},
- {value: 0x0067, lo: 0xae, hi: 0xb5},
- {value: 0x0083, lo: 0xb6, hi: 0xb9},
- {value: 0x008d, lo: 0xbb, hi: 0xbb},
- {value: 0x0091, lo: 0xbd, hi: 0xbf},
- // Block 0x8a, offset 0x2ea
- {value: 0x0002, lo: 0x04},
- {value: 0x0097, lo: 0x80, hi: 0x83},
- {value: 0x00a1, lo: 0x85, hi: 0x8f},
- {value: 0x0043, lo: 0x90, hi: 0xa9},
- {value: 0x0083, lo: 0xaa, hi: 0xbf},
- // Block 0x8b, offset 0x2ef
- {value: 0x0002, lo: 0x08},
- {value: 0x00af, lo: 0x80, hi: 0x83},
- {value: 0x0043, lo: 0x84, hi: 0x85},
- {value: 0x0049, lo: 0x87, hi: 0x8a},
- {value: 0x0055, lo: 0x8d, hi: 0x94},
- {value: 0x0067, lo: 0x96, hi: 0x9c},
- {value: 0x0083, lo: 0x9e, hi: 0xb7},
- {value: 0x0043, lo: 0xb8, hi: 0xb9},
- {value: 0x0049, lo: 0xbb, hi: 0xbe},
- // Block 0x8c, offset 0x2f8
- {value: 0x0002, lo: 0x05},
- {value: 0x0053, lo: 0x80, hi: 0x84},
- {value: 0x005f, lo: 0x86, hi: 0x86},
- {value: 0x0067, lo: 0x8a, hi: 0x90},
- {value: 0x0083, lo: 0x92, hi: 0xab},
- {value: 0x0043, lo: 0xac, hi: 0xbf},
- // Block 0x8d, offset 0x2fe
- {value: 0x0002, lo: 0x04},
- {value: 0x006b, lo: 0x80, hi: 0x85},
- {value: 0x0083, lo: 0x86, hi: 0x9f},
- {value: 0x0043, lo: 0xa0, hi: 0xb9},
- {value: 0x0083, lo: 0xba, hi: 0xbf},
- // Block 0x8e, offset 0x303
- {value: 0x0002, lo: 0x03},
- {value: 0x008f, lo: 0x80, hi: 0x93},
- {value: 0x0043, lo: 0x94, hi: 0xad},
- {value: 0x0083, lo: 0xae, hi: 0xbf},
- // Block 0x8f, offset 0x307
- {value: 0x0002, lo: 0x04},
- {value: 0x00a7, lo: 0x80, hi: 0x87},
- {value: 0x0043, lo: 0x88, hi: 0xa1},
- {value: 0x0083, lo: 0xa2, hi: 0xbb},
- {value: 0x0043, lo: 0xbc, hi: 0xbf},
- // Block 0x90, offset 0x30c
- {value: 0x0002, lo: 0x03},
- {value: 0x004b, lo: 0x80, hi: 0x95},
- {value: 0x0083, lo: 0x96, hi: 0xaf},
- {value: 0x0043, lo: 0xb0, hi: 0xbf},
- // Block 0x91, offset 0x310
- {value: 0x0003, lo: 0x0f},
- {value: 0x01b8, lo: 0x80, hi: 0x80},
- {value: 0x045f, lo: 0x81, hi: 0x81},
- {value: 0x01bb, lo: 0x82, hi: 0x9a},
- {value: 0x045b, lo: 0x9b, hi: 0x9b},
- {value: 0x01c7, lo: 0x9c, hi: 0x9c},
- {value: 0x01d0, lo: 0x9d, hi: 0x9d},
- {value: 0x01d6, lo: 0x9e, hi: 0x9e},
- {value: 0x01fa, lo: 0x9f, hi: 0x9f},
- {value: 0x01eb, lo: 0xa0, hi: 0xa0},
- {value: 0x01e8, lo: 0xa1, hi: 0xa1},
- {value: 0x0173, lo: 0xa2, hi: 0xb2},
- {value: 0x0188, lo: 0xb3, hi: 0xb3},
- {value: 0x01a6, lo: 0xb4, hi: 0xba},
- {value: 0x045f, lo: 0xbb, hi: 0xbb},
- {value: 0x01bb, lo: 0xbc, hi: 0xbf},
- // Block 0x92, offset 0x320
- {value: 0x0003, lo: 0x0d},
- {value: 0x01c7, lo: 0x80, hi: 0x94},
- {value: 0x045b, lo: 0x95, hi: 0x95},
- {value: 0x01c7, lo: 0x96, hi: 0x96},
- {value: 0x01d0, lo: 0x97, hi: 0x97},
- {value: 0x01d6, lo: 0x98, hi: 0x98},
- {value: 0x01fa, lo: 0x99, hi: 0x99},
- {value: 0x01eb, lo: 0x9a, hi: 0x9a},
- {value: 0x01e8, lo: 0x9b, hi: 0x9b},
- {value: 0x0173, lo: 0x9c, hi: 0xac},
- {value: 0x0188, lo: 0xad, hi: 0xad},
- {value: 0x01a6, lo: 0xae, hi: 0xb4},
- {value: 0x045f, lo: 0xb5, hi: 0xb5},
- {value: 0x01bb, lo: 0xb6, hi: 0xbf},
- // Block 0x93, offset 0x32e
- {value: 0x0003, lo: 0x0d},
- {value: 0x01d9, lo: 0x80, hi: 0x8e},
- {value: 0x045b, lo: 0x8f, hi: 0x8f},
- {value: 0x01c7, lo: 0x90, hi: 0x90},
- {value: 0x01d0, lo: 0x91, hi: 0x91},
- {value: 0x01d6, lo: 0x92, hi: 0x92},
- {value: 0x01fa, lo: 0x93, hi: 0x93},
- {value: 0x01eb, lo: 0x94, hi: 0x94},
- {value: 0x01e8, lo: 0x95, hi: 0x95},
- {value: 0x0173, lo: 0x96, hi: 0xa6},
- {value: 0x0188, lo: 0xa7, hi: 0xa7},
- {value: 0x01a6, lo: 0xa8, hi: 0xae},
- {value: 0x045f, lo: 0xaf, hi: 0xaf},
- {value: 0x01bb, lo: 0xb0, hi: 0xbf},
- // Block 0x94, offset 0x33c
- {value: 0x0003, lo: 0x0d},
- {value: 0x01eb, lo: 0x80, hi: 0x88},
- {value: 0x045b, lo: 0x89, hi: 0x89},
- {value: 0x01c7, lo: 0x8a, hi: 0x8a},
- {value: 0x01d0, lo: 0x8b, hi: 0x8b},
- {value: 0x01d6, lo: 0x8c, hi: 0x8c},
- {value: 0x01fa, lo: 0x8d, hi: 0x8d},
- {value: 0x01eb, lo: 0x8e, hi: 0x8e},
- {value: 0x01e8, lo: 0x8f, hi: 0x8f},
- {value: 0x0173, lo: 0x90, hi: 0xa0},
- {value: 0x0188, lo: 0xa1, hi: 0xa1},
- {value: 0x01a6, lo: 0xa2, hi: 0xa8},
- {value: 0x045f, lo: 0xa9, hi: 0xa9},
- {value: 0x01bb, lo: 0xaa, hi: 0xbf},
- // Block 0x95, offset 0x34a
- {value: 0x0000, lo: 0x05},
- {value: 0x8132, lo: 0x80, hi: 0x86},
- {value: 0x8132, lo: 0x88, hi: 0x98},
- {value: 0x8132, lo: 0x9b, hi: 0xa1},
- {value: 0x8132, lo: 0xa3, hi: 0xa4},
- {value: 0x8132, lo: 0xa6, hi: 0xaa},
- // Block 0x96, offset 0x350
- {value: 0x0000, lo: 0x01},
- {value: 0x812d, lo: 0x90, hi: 0x96},
- // Block 0x97, offset 0x352
- {value: 0x0000, lo: 0x02},
- {value: 0x8132, lo: 0x84, hi: 0x89},
- {value: 0x8102, lo: 0x8a, hi: 0x8a},
- // Block 0x98, offset 0x355
- {value: 0x0002, lo: 0x09},
- {value: 0x0063, lo: 0x80, hi: 0x89},
- {value: 0x1951, lo: 0x8a, hi: 0x8a},
- {value: 0x1981, lo: 0x8b, hi: 0x8b},
- {value: 0x199c, lo: 0x8c, hi: 0x8c},
- {value: 0x19a2, lo: 0x8d, hi: 0x8d},
- {value: 0x1bc0, lo: 0x8e, hi: 0x8e},
- {value: 0x19ae, lo: 0x8f, hi: 0x8f},
- {value: 0x197b, lo: 0xaa, hi: 0xaa},
- {value: 0x197e, lo: 0xab, hi: 0xab},
- // Block 0x99, offset 0x35f
- {value: 0x0000, lo: 0x01},
- {value: 0x193f, lo: 0x90, hi: 0x90},
- // Block 0x9a, offset 0x361
- {value: 0x0028, lo: 0x09},
- {value: 0x2862, lo: 0x80, hi: 0x80},
- {value: 0x2826, lo: 0x81, hi: 0x81},
- {value: 0x2830, lo: 0x82, hi: 0x82},
- {value: 0x2844, lo: 0x83, hi: 0x84},
- {value: 0x284e, lo: 0x85, hi: 0x86},
- {value: 0x283a, lo: 0x87, hi: 0x87},
- {value: 0x2858, lo: 0x88, hi: 0x88},
- {value: 0x0b6f, lo: 0x90, hi: 0x90},
- {value: 0x08e7, lo: 0x91, hi: 0x91},
-}
-
-// recompMap: 7520 bytes (entries only)
-var recompMap = map[uint32]rune{
- 0x00410300: 0x00C0,
- 0x00410301: 0x00C1,
- 0x00410302: 0x00C2,
- 0x00410303: 0x00C3,
- 0x00410308: 0x00C4,
- 0x0041030A: 0x00C5,
- 0x00430327: 0x00C7,
- 0x00450300: 0x00C8,
- 0x00450301: 0x00C9,
- 0x00450302: 0x00CA,
- 0x00450308: 0x00CB,
- 0x00490300: 0x00CC,
- 0x00490301: 0x00CD,
- 0x00490302: 0x00CE,
- 0x00490308: 0x00CF,
- 0x004E0303: 0x00D1,
- 0x004F0300: 0x00D2,
- 0x004F0301: 0x00D3,
- 0x004F0302: 0x00D4,
- 0x004F0303: 0x00D5,
- 0x004F0308: 0x00D6,
- 0x00550300: 0x00D9,
- 0x00550301: 0x00DA,
- 0x00550302: 0x00DB,
- 0x00550308: 0x00DC,
- 0x00590301: 0x00DD,
- 0x00610300: 0x00E0,
- 0x00610301: 0x00E1,
- 0x00610302: 0x00E2,
- 0x00610303: 0x00E3,
- 0x00610308: 0x00E4,
- 0x0061030A: 0x00E5,
- 0x00630327: 0x00E7,
- 0x00650300: 0x00E8,
- 0x00650301: 0x00E9,
- 0x00650302: 0x00EA,
- 0x00650308: 0x00EB,
- 0x00690300: 0x00EC,
- 0x00690301: 0x00ED,
- 0x00690302: 0x00EE,
- 0x00690308: 0x00EF,
- 0x006E0303: 0x00F1,
- 0x006F0300: 0x00F2,
- 0x006F0301: 0x00F3,
- 0x006F0302: 0x00F4,
- 0x006F0303: 0x00F5,
- 0x006F0308: 0x00F6,
- 0x00750300: 0x00F9,
- 0x00750301: 0x00FA,
- 0x00750302: 0x00FB,
- 0x00750308: 0x00FC,
- 0x00790301: 0x00FD,
- 0x00790308: 0x00FF,
- 0x00410304: 0x0100,
- 0x00610304: 0x0101,
- 0x00410306: 0x0102,
- 0x00610306: 0x0103,
- 0x00410328: 0x0104,
- 0x00610328: 0x0105,
- 0x00430301: 0x0106,
- 0x00630301: 0x0107,
- 0x00430302: 0x0108,
- 0x00630302: 0x0109,
- 0x00430307: 0x010A,
- 0x00630307: 0x010B,
- 0x0043030C: 0x010C,
- 0x0063030C: 0x010D,
- 0x0044030C: 0x010E,
- 0x0064030C: 0x010F,
- 0x00450304: 0x0112,
- 0x00650304: 0x0113,
- 0x00450306: 0x0114,
- 0x00650306: 0x0115,
- 0x00450307: 0x0116,
- 0x00650307: 0x0117,
- 0x00450328: 0x0118,
- 0x00650328: 0x0119,
- 0x0045030C: 0x011A,
- 0x0065030C: 0x011B,
- 0x00470302: 0x011C,
- 0x00670302: 0x011D,
- 0x00470306: 0x011E,
- 0x00670306: 0x011F,
- 0x00470307: 0x0120,
- 0x00670307: 0x0121,
- 0x00470327: 0x0122,
- 0x00670327: 0x0123,
- 0x00480302: 0x0124,
- 0x00680302: 0x0125,
- 0x00490303: 0x0128,
- 0x00690303: 0x0129,
- 0x00490304: 0x012A,
- 0x00690304: 0x012B,
- 0x00490306: 0x012C,
- 0x00690306: 0x012D,
- 0x00490328: 0x012E,
- 0x00690328: 0x012F,
- 0x00490307: 0x0130,
- 0x004A0302: 0x0134,
- 0x006A0302: 0x0135,
- 0x004B0327: 0x0136,
- 0x006B0327: 0x0137,
- 0x004C0301: 0x0139,
- 0x006C0301: 0x013A,
- 0x004C0327: 0x013B,
- 0x006C0327: 0x013C,
- 0x004C030C: 0x013D,
- 0x006C030C: 0x013E,
- 0x004E0301: 0x0143,
- 0x006E0301: 0x0144,
- 0x004E0327: 0x0145,
- 0x006E0327: 0x0146,
- 0x004E030C: 0x0147,
- 0x006E030C: 0x0148,
- 0x004F0304: 0x014C,
- 0x006F0304: 0x014D,
- 0x004F0306: 0x014E,
- 0x006F0306: 0x014F,
- 0x004F030B: 0x0150,
- 0x006F030B: 0x0151,
- 0x00520301: 0x0154,
- 0x00720301: 0x0155,
- 0x00520327: 0x0156,
- 0x00720327: 0x0157,
- 0x0052030C: 0x0158,
- 0x0072030C: 0x0159,
- 0x00530301: 0x015A,
- 0x00730301: 0x015B,
- 0x00530302: 0x015C,
- 0x00730302: 0x015D,
- 0x00530327: 0x015E,
- 0x00730327: 0x015F,
- 0x0053030C: 0x0160,
- 0x0073030C: 0x0161,
- 0x00540327: 0x0162,
- 0x00740327: 0x0163,
- 0x0054030C: 0x0164,
- 0x0074030C: 0x0165,
- 0x00550303: 0x0168,
- 0x00750303: 0x0169,
- 0x00550304: 0x016A,
- 0x00750304: 0x016B,
- 0x00550306: 0x016C,
- 0x00750306: 0x016D,
- 0x0055030A: 0x016E,
- 0x0075030A: 0x016F,
- 0x0055030B: 0x0170,
- 0x0075030B: 0x0171,
- 0x00550328: 0x0172,
- 0x00750328: 0x0173,
- 0x00570302: 0x0174,
- 0x00770302: 0x0175,
- 0x00590302: 0x0176,
- 0x00790302: 0x0177,
- 0x00590308: 0x0178,
- 0x005A0301: 0x0179,
- 0x007A0301: 0x017A,
- 0x005A0307: 0x017B,
- 0x007A0307: 0x017C,
- 0x005A030C: 0x017D,
- 0x007A030C: 0x017E,
- 0x004F031B: 0x01A0,
- 0x006F031B: 0x01A1,
- 0x0055031B: 0x01AF,
- 0x0075031B: 0x01B0,
- 0x0041030C: 0x01CD,
- 0x0061030C: 0x01CE,
- 0x0049030C: 0x01CF,
- 0x0069030C: 0x01D0,
- 0x004F030C: 0x01D1,
- 0x006F030C: 0x01D2,
- 0x0055030C: 0x01D3,
- 0x0075030C: 0x01D4,
- 0x00DC0304: 0x01D5,
- 0x00FC0304: 0x01D6,
- 0x00DC0301: 0x01D7,
- 0x00FC0301: 0x01D8,
- 0x00DC030C: 0x01D9,
- 0x00FC030C: 0x01DA,
- 0x00DC0300: 0x01DB,
- 0x00FC0300: 0x01DC,
- 0x00C40304: 0x01DE,
- 0x00E40304: 0x01DF,
- 0x02260304: 0x01E0,
- 0x02270304: 0x01E1,
- 0x00C60304: 0x01E2,
- 0x00E60304: 0x01E3,
- 0x0047030C: 0x01E6,
- 0x0067030C: 0x01E7,
- 0x004B030C: 0x01E8,
- 0x006B030C: 0x01E9,
- 0x004F0328: 0x01EA,
- 0x006F0328: 0x01EB,
- 0x01EA0304: 0x01EC,
- 0x01EB0304: 0x01ED,
- 0x01B7030C: 0x01EE,
- 0x0292030C: 0x01EF,
- 0x006A030C: 0x01F0,
- 0x00470301: 0x01F4,
- 0x00670301: 0x01F5,
- 0x004E0300: 0x01F8,
- 0x006E0300: 0x01F9,
- 0x00C50301: 0x01FA,
- 0x00E50301: 0x01FB,
- 0x00C60301: 0x01FC,
- 0x00E60301: 0x01FD,
- 0x00D80301: 0x01FE,
- 0x00F80301: 0x01FF,
- 0x0041030F: 0x0200,
- 0x0061030F: 0x0201,
- 0x00410311: 0x0202,
- 0x00610311: 0x0203,
- 0x0045030F: 0x0204,
- 0x0065030F: 0x0205,
- 0x00450311: 0x0206,
- 0x00650311: 0x0207,
- 0x0049030F: 0x0208,
- 0x0069030F: 0x0209,
- 0x00490311: 0x020A,
- 0x00690311: 0x020B,
- 0x004F030F: 0x020C,
- 0x006F030F: 0x020D,
- 0x004F0311: 0x020E,
- 0x006F0311: 0x020F,
- 0x0052030F: 0x0210,
- 0x0072030F: 0x0211,
- 0x00520311: 0x0212,
- 0x00720311: 0x0213,
- 0x0055030F: 0x0214,
- 0x0075030F: 0x0215,
- 0x00550311: 0x0216,
- 0x00750311: 0x0217,
- 0x00530326: 0x0218,
- 0x00730326: 0x0219,
- 0x00540326: 0x021A,
- 0x00740326: 0x021B,
- 0x0048030C: 0x021E,
- 0x0068030C: 0x021F,
- 0x00410307: 0x0226,
- 0x00610307: 0x0227,
- 0x00450327: 0x0228,
- 0x00650327: 0x0229,
- 0x00D60304: 0x022A,
- 0x00F60304: 0x022B,
- 0x00D50304: 0x022C,
- 0x00F50304: 0x022D,
- 0x004F0307: 0x022E,
- 0x006F0307: 0x022F,
- 0x022E0304: 0x0230,
- 0x022F0304: 0x0231,
- 0x00590304: 0x0232,
- 0x00790304: 0x0233,
- 0x00A80301: 0x0385,
- 0x03910301: 0x0386,
- 0x03950301: 0x0388,
- 0x03970301: 0x0389,
- 0x03990301: 0x038A,
- 0x039F0301: 0x038C,
- 0x03A50301: 0x038E,
- 0x03A90301: 0x038F,
- 0x03CA0301: 0x0390,
- 0x03990308: 0x03AA,
- 0x03A50308: 0x03AB,
- 0x03B10301: 0x03AC,
- 0x03B50301: 0x03AD,
- 0x03B70301: 0x03AE,
- 0x03B90301: 0x03AF,
- 0x03CB0301: 0x03B0,
- 0x03B90308: 0x03CA,
- 0x03C50308: 0x03CB,
- 0x03BF0301: 0x03CC,
- 0x03C50301: 0x03CD,
- 0x03C90301: 0x03CE,
- 0x03D20301: 0x03D3,
- 0x03D20308: 0x03D4,
- 0x04150300: 0x0400,
- 0x04150308: 0x0401,
- 0x04130301: 0x0403,
- 0x04060308: 0x0407,
- 0x041A0301: 0x040C,
- 0x04180300: 0x040D,
- 0x04230306: 0x040E,
- 0x04180306: 0x0419,
- 0x04380306: 0x0439,
- 0x04350300: 0x0450,
- 0x04350308: 0x0451,
- 0x04330301: 0x0453,
- 0x04560308: 0x0457,
- 0x043A0301: 0x045C,
- 0x04380300: 0x045D,
- 0x04430306: 0x045E,
- 0x0474030F: 0x0476,
- 0x0475030F: 0x0477,
- 0x04160306: 0x04C1,
- 0x04360306: 0x04C2,
- 0x04100306: 0x04D0,
- 0x04300306: 0x04D1,
- 0x04100308: 0x04D2,
- 0x04300308: 0x04D3,
- 0x04150306: 0x04D6,
- 0x04350306: 0x04D7,
- 0x04D80308: 0x04DA,
- 0x04D90308: 0x04DB,
- 0x04160308: 0x04DC,
- 0x04360308: 0x04DD,
- 0x04170308: 0x04DE,
- 0x04370308: 0x04DF,
- 0x04180304: 0x04E2,
- 0x04380304: 0x04E3,
- 0x04180308: 0x04E4,
- 0x04380308: 0x04E5,
- 0x041E0308: 0x04E6,
- 0x043E0308: 0x04E7,
- 0x04E80308: 0x04EA,
- 0x04E90308: 0x04EB,
- 0x042D0308: 0x04EC,
- 0x044D0308: 0x04ED,
- 0x04230304: 0x04EE,
- 0x04430304: 0x04EF,
- 0x04230308: 0x04F0,
- 0x04430308: 0x04F1,
- 0x0423030B: 0x04F2,
- 0x0443030B: 0x04F3,
- 0x04270308: 0x04F4,
- 0x04470308: 0x04F5,
- 0x042B0308: 0x04F8,
- 0x044B0308: 0x04F9,
- 0x06270653: 0x0622,
- 0x06270654: 0x0623,
- 0x06480654: 0x0624,
- 0x06270655: 0x0625,
- 0x064A0654: 0x0626,
- 0x06D50654: 0x06C0,
- 0x06C10654: 0x06C2,
- 0x06D20654: 0x06D3,
- 0x0928093C: 0x0929,
- 0x0930093C: 0x0931,
- 0x0933093C: 0x0934,
- 0x09C709BE: 0x09CB,
- 0x09C709D7: 0x09CC,
- 0x0B470B56: 0x0B48,
- 0x0B470B3E: 0x0B4B,
- 0x0B470B57: 0x0B4C,
- 0x0B920BD7: 0x0B94,
- 0x0BC60BBE: 0x0BCA,
- 0x0BC70BBE: 0x0BCB,
- 0x0BC60BD7: 0x0BCC,
- 0x0C460C56: 0x0C48,
- 0x0CBF0CD5: 0x0CC0,
- 0x0CC60CD5: 0x0CC7,
- 0x0CC60CD6: 0x0CC8,
- 0x0CC60CC2: 0x0CCA,
- 0x0CCA0CD5: 0x0CCB,
- 0x0D460D3E: 0x0D4A,
- 0x0D470D3E: 0x0D4B,
- 0x0D460D57: 0x0D4C,
- 0x0DD90DCA: 0x0DDA,
- 0x0DD90DCF: 0x0DDC,
- 0x0DDC0DCA: 0x0DDD,
- 0x0DD90DDF: 0x0DDE,
- 0x1025102E: 0x1026,
- 0x1B051B35: 0x1B06,
- 0x1B071B35: 0x1B08,
- 0x1B091B35: 0x1B0A,
- 0x1B0B1B35: 0x1B0C,
- 0x1B0D1B35: 0x1B0E,
- 0x1B111B35: 0x1B12,
- 0x1B3A1B35: 0x1B3B,
- 0x1B3C1B35: 0x1B3D,
- 0x1B3E1B35: 0x1B40,
- 0x1B3F1B35: 0x1B41,
- 0x1B421B35: 0x1B43,
- 0x00410325: 0x1E00,
- 0x00610325: 0x1E01,
- 0x00420307: 0x1E02,
- 0x00620307: 0x1E03,
- 0x00420323: 0x1E04,
- 0x00620323: 0x1E05,
- 0x00420331: 0x1E06,
- 0x00620331: 0x1E07,
- 0x00C70301: 0x1E08,
- 0x00E70301: 0x1E09,
- 0x00440307: 0x1E0A,
- 0x00640307: 0x1E0B,
- 0x00440323: 0x1E0C,
- 0x00640323: 0x1E0D,
- 0x00440331: 0x1E0E,
- 0x00640331: 0x1E0F,
- 0x00440327: 0x1E10,
- 0x00640327: 0x1E11,
- 0x0044032D: 0x1E12,
- 0x0064032D: 0x1E13,
- 0x01120300: 0x1E14,
- 0x01130300: 0x1E15,
- 0x01120301: 0x1E16,
- 0x01130301: 0x1E17,
- 0x0045032D: 0x1E18,
- 0x0065032D: 0x1E19,
- 0x00450330: 0x1E1A,
- 0x00650330: 0x1E1B,
- 0x02280306: 0x1E1C,
- 0x02290306: 0x1E1D,
- 0x00460307: 0x1E1E,
- 0x00660307: 0x1E1F,
- 0x00470304: 0x1E20,
- 0x00670304: 0x1E21,
- 0x00480307: 0x1E22,
- 0x00680307: 0x1E23,
- 0x00480323: 0x1E24,
- 0x00680323: 0x1E25,
- 0x00480308: 0x1E26,
- 0x00680308: 0x1E27,
- 0x00480327: 0x1E28,
- 0x00680327: 0x1E29,
- 0x0048032E: 0x1E2A,
- 0x0068032E: 0x1E2B,
- 0x00490330: 0x1E2C,
- 0x00690330: 0x1E2D,
- 0x00CF0301: 0x1E2E,
- 0x00EF0301: 0x1E2F,
- 0x004B0301: 0x1E30,
- 0x006B0301: 0x1E31,
- 0x004B0323: 0x1E32,
- 0x006B0323: 0x1E33,
- 0x004B0331: 0x1E34,
- 0x006B0331: 0x1E35,
- 0x004C0323: 0x1E36,
- 0x006C0323: 0x1E37,
- 0x1E360304: 0x1E38,
- 0x1E370304: 0x1E39,
- 0x004C0331: 0x1E3A,
- 0x006C0331: 0x1E3B,
- 0x004C032D: 0x1E3C,
- 0x006C032D: 0x1E3D,
- 0x004D0301: 0x1E3E,
- 0x006D0301: 0x1E3F,
- 0x004D0307: 0x1E40,
- 0x006D0307: 0x1E41,
- 0x004D0323: 0x1E42,
- 0x006D0323: 0x1E43,
- 0x004E0307: 0x1E44,
- 0x006E0307: 0x1E45,
- 0x004E0323: 0x1E46,
- 0x006E0323: 0x1E47,
- 0x004E0331: 0x1E48,
- 0x006E0331: 0x1E49,
- 0x004E032D: 0x1E4A,
- 0x006E032D: 0x1E4B,
- 0x00D50301: 0x1E4C,
- 0x00F50301: 0x1E4D,
- 0x00D50308: 0x1E4E,
- 0x00F50308: 0x1E4F,
- 0x014C0300: 0x1E50,
- 0x014D0300: 0x1E51,
- 0x014C0301: 0x1E52,
- 0x014D0301: 0x1E53,
- 0x00500301: 0x1E54,
- 0x00700301: 0x1E55,
- 0x00500307: 0x1E56,
- 0x00700307: 0x1E57,
- 0x00520307: 0x1E58,
- 0x00720307: 0x1E59,
- 0x00520323: 0x1E5A,
- 0x00720323: 0x1E5B,
- 0x1E5A0304: 0x1E5C,
- 0x1E5B0304: 0x1E5D,
- 0x00520331: 0x1E5E,
- 0x00720331: 0x1E5F,
- 0x00530307: 0x1E60,
- 0x00730307: 0x1E61,
- 0x00530323: 0x1E62,
- 0x00730323: 0x1E63,
- 0x015A0307: 0x1E64,
- 0x015B0307: 0x1E65,
- 0x01600307: 0x1E66,
- 0x01610307: 0x1E67,
- 0x1E620307: 0x1E68,
- 0x1E630307: 0x1E69,
- 0x00540307: 0x1E6A,
- 0x00740307: 0x1E6B,
- 0x00540323: 0x1E6C,
- 0x00740323: 0x1E6D,
- 0x00540331: 0x1E6E,
- 0x00740331: 0x1E6F,
- 0x0054032D: 0x1E70,
- 0x0074032D: 0x1E71,
- 0x00550324: 0x1E72,
- 0x00750324: 0x1E73,
- 0x00550330: 0x1E74,
- 0x00750330: 0x1E75,
- 0x0055032D: 0x1E76,
- 0x0075032D: 0x1E77,
- 0x01680301: 0x1E78,
- 0x01690301: 0x1E79,
- 0x016A0308: 0x1E7A,
- 0x016B0308: 0x1E7B,
- 0x00560303: 0x1E7C,
- 0x00760303: 0x1E7D,
- 0x00560323: 0x1E7E,
- 0x00760323: 0x1E7F,
- 0x00570300: 0x1E80,
- 0x00770300: 0x1E81,
- 0x00570301: 0x1E82,
- 0x00770301: 0x1E83,
- 0x00570308: 0x1E84,
- 0x00770308: 0x1E85,
- 0x00570307: 0x1E86,
- 0x00770307: 0x1E87,
- 0x00570323: 0x1E88,
- 0x00770323: 0x1E89,
- 0x00580307: 0x1E8A,
- 0x00780307: 0x1E8B,
- 0x00580308: 0x1E8C,
- 0x00780308: 0x1E8D,
- 0x00590307: 0x1E8E,
- 0x00790307: 0x1E8F,
- 0x005A0302: 0x1E90,
- 0x007A0302: 0x1E91,
- 0x005A0323: 0x1E92,
- 0x007A0323: 0x1E93,
- 0x005A0331: 0x1E94,
- 0x007A0331: 0x1E95,
- 0x00680331: 0x1E96,
- 0x00740308: 0x1E97,
- 0x0077030A: 0x1E98,
- 0x0079030A: 0x1E99,
- 0x017F0307: 0x1E9B,
- 0x00410323: 0x1EA0,
- 0x00610323: 0x1EA1,
- 0x00410309: 0x1EA2,
- 0x00610309: 0x1EA3,
- 0x00C20301: 0x1EA4,
- 0x00E20301: 0x1EA5,
- 0x00C20300: 0x1EA6,
- 0x00E20300: 0x1EA7,
- 0x00C20309: 0x1EA8,
- 0x00E20309: 0x1EA9,
- 0x00C20303: 0x1EAA,
- 0x00E20303: 0x1EAB,
- 0x1EA00302: 0x1EAC,
- 0x1EA10302: 0x1EAD,
- 0x01020301: 0x1EAE,
- 0x01030301: 0x1EAF,
- 0x01020300: 0x1EB0,
- 0x01030300: 0x1EB1,
- 0x01020309: 0x1EB2,
- 0x01030309: 0x1EB3,
- 0x01020303: 0x1EB4,
- 0x01030303: 0x1EB5,
- 0x1EA00306: 0x1EB6,
- 0x1EA10306: 0x1EB7,
- 0x00450323: 0x1EB8,
- 0x00650323: 0x1EB9,
- 0x00450309: 0x1EBA,
- 0x00650309: 0x1EBB,
- 0x00450303: 0x1EBC,
- 0x00650303: 0x1EBD,
- 0x00CA0301: 0x1EBE,
- 0x00EA0301: 0x1EBF,
- 0x00CA0300: 0x1EC0,
- 0x00EA0300: 0x1EC1,
- 0x00CA0309: 0x1EC2,
- 0x00EA0309: 0x1EC3,
- 0x00CA0303: 0x1EC4,
- 0x00EA0303: 0x1EC5,
- 0x1EB80302: 0x1EC6,
- 0x1EB90302: 0x1EC7,
- 0x00490309: 0x1EC8,
- 0x00690309: 0x1EC9,
- 0x00490323: 0x1ECA,
- 0x00690323: 0x1ECB,
- 0x004F0323: 0x1ECC,
- 0x006F0323: 0x1ECD,
- 0x004F0309: 0x1ECE,
- 0x006F0309: 0x1ECF,
- 0x00D40301: 0x1ED0,
- 0x00F40301: 0x1ED1,
- 0x00D40300: 0x1ED2,
- 0x00F40300: 0x1ED3,
- 0x00D40309: 0x1ED4,
- 0x00F40309: 0x1ED5,
- 0x00D40303: 0x1ED6,
- 0x00F40303: 0x1ED7,
- 0x1ECC0302: 0x1ED8,
- 0x1ECD0302: 0x1ED9,
- 0x01A00301: 0x1EDA,
- 0x01A10301: 0x1EDB,
- 0x01A00300: 0x1EDC,
- 0x01A10300: 0x1EDD,
- 0x01A00309: 0x1EDE,
- 0x01A10309: 0x1EDF,
- 0x01A00303: 0x1EE0,
- 0x01A10303: 0x1EE1,
- 0x01A00323: 0x1EE2,
- 0x01A10323: 0x1EE3,
- 0x00550323: 0x1EE4,
- 0x00750323: 0x1EE5,
- 0x00550309: 0x1EE6,
- 0x00750309: 0x1EE7,
- 0x01AF0301: 0x1EE8,
- 0x01B00301: 0x1EE9,
- 0x01AF0300: 0x1EEA,
- 0x01B00300: 0x1EEB,
- 0x01AF0309: 0x1EEC,
- 0x01B00309: 0x1EED,
- 0x01AF0303: 0x1EEE,
- 0x01B00303: 0x1EEF,
- 0x01AF0323: 0x1EF0,
- 0x01B00323: 0x1EF1,
- 0x00590300: 0x1EF2,
- 0x00790300: 0x1EF3,
- 0x00590323: 0x1EF4,
- 0x00790323: 0x1EF5,
- 0x00590309: 0x1EF6,
- 0x00790309: 0x1EF7,
- 0x00590303: 0x1EF8,
- 0x00790303: 0x1EF9,
- 0x03B10313: 0x1F00,
- 0x03B10314: 0x1F01,
- 0x1F000300: 0x1F02,
- 0x1F010300: 0x1F03,
- 0x1F000301: 0x1F04,
- 0x1F010301: 0x1F05,
- 0x1F000342: 0x1F06,
- 0x1F010342: 0x1F07,
- 0x03910313: 0x1F08,
- 0x03910314: 0x1F09,
- 0x1F080300: 0x1F0A,
- 0x1F090300: 0x1F0B,
- 0x1F080301: 0x1F0C,
- 0x1F090301: 0x1F0D,
- 0x1F080342: 0x1F0E,
- 0x1F090342: 0x1F0F,
- 0x03B50313: 0x1F10,
- 0x03B50314: 0x1F11,
- 0x1F100300: 0x1F12,
- 0x1F110300: 0x1F13,
- 0x1F100301: 0x1F14,
- 0x1F110301: 0x1F15,
- 0x03950313: 0x1F18,
- 0x03950314: 0x1F19,
- 0x1F180300: 0x1F1A,
- 0x1F190300: 0x1F1B,
- 0x1F180301: 0x1F1C,
- 0x1F190301: 0x1F1D,
- 0x03B70313: 0x1F20,
- 0x03B70314: 0x1F21,
- 0x1F200300: 0x1F22,
- 0x1F210300: 0x1F23,
- 0x1F200301: 0x1F24,
- 0x1F210301: 0x1F25,
- 0x1F200342: 0x1F26,
- 0x1F210342: 0x1F27,
- 0x03970313: 0x1F28,
- 0x03970314: 0x1F29,
- 0x1F280300: 0x1F2A,
- 0x1F290300: 0x1F2B,
- 0x1F280301: 0x1F2C,
- 0x1F290301: 0x1F2D,
- 0x1F280342: 0x1F2E,
- 0x1F290342: 0x1F2F,
- 0x03B90313: 0x1F30,
- 0x03B90314: 0x1F31,
- 0x1F300300: 0x1F32,
- 0x1F310300: 0x1F33,
- 0x1F300301: 0x1F34,
- 0x1F310301: 0x1F35,
- 0x1F300342: 0x1F36,
- 0x1F310342: 0x1F37,
- 0x03990313: 0x1F38,
- 0x03990314: 0x1F39,
- 0x1F380300: 0x1F3A,
- 0x1F390300: 0x1F3B,
- 0x1F380301: 0x1F3C,
- 0x1F390301: 0x1F3D,
- 0x1F380342: 0x1F3E,
- 0x1F390342: 0x1F3F,
- 0x03BF0313: 0x1F40,
- 0x03BF0314: 0x1F41,
- 0x1F400300: 0x1F42,
- 0x1F410300: 0x1F43,
- 0x1F400301: 0x1F44,
- 0x1F410301: 0x1F45,
- 0x039F0313: 0x1F48,
- 0x039F0314: 0x1F49,
- 0x1F480300: 0x1F4A,
- 0x1F490300: 0x1F4B,
- 0x1F480301: 0x1F4C,
- 0x1F490301: 0x1F4D,
- 0x03C50313: 0x1F50,
- 0x03C50314: 0x1F51,
- 0x1F500300: 0x1F52,
- 0x1F510300: 0x1F53,
- 0x1F500301: 0x1F54,
- 0x1F510301: 0x1F55,
- 0x1F500342: 0x1F56,
- 0x1F510342: 0x1F57,
- 0x03A50314: 0x1F59,
- 0x1F590300: 0x1F5B,
- 0x1F590301: 0x1F5D,
- 0x1F590342: 0x1F5F,
- 0x03C90313: 0x1F60,
- 0x03C90314: 0x1F61,
- 0x1F600300: 0x1F62,
- 0x1F610300: 0x1F63,
- 0x1F600301: 0x1F64,
- 0x1F610301: 0x1F65,
- 0x1F600342: 0x1F66,
- 0x1F610342: 0x1F67,
- 0x03A90313: 0x1F68,
- 0x03A90314: 0x1F69,
- 0x1F680300: 0x1F6A,
- 0x1F690300: 0x1F6B,
- 0x1F680301: 0x1F6C,
- 0x1F690301: 0x1F6D,
- 0x1F680342: 0x1F6E,
- 0x1F690342: 0x1F6F,
- 0x03B10300: 0x1F70,
- 0x03B50300: 0x1F72,
- 0x03B70300: 0x1F74,
- 0x03B90300: 0x1F76,
- 0x03BF0300: 0x1F78,
- 0x03C50300: 0x1F7A,
- 0x03C90300: 0x1F7C,
- 0x1F000345: 0x1F80,
- 0x1F010345: 0x1F81,
- 0x1F020345: 0x1F82,
- 0x1F030345: 0x1F83,
- 0x1F040345: 0x1F84,
- 0x1F050345: 0x1F85,
- 0x1F060345: 0x1F86,
- 0x1F070345: 0x1F87,
- 0x1F080345: 0x1F88,
- 0x1F090345: 0x1F89,
- 0x1F0A0345: 0x1F8A,
- 0x1F0B0345: 0x1F8B,
- 0x1F0C0345: 0x1F8C,
- 0x1F0D0345: 0x1F8D,
- 0x1F0E0345: 0x1F8E,
- 0x1F0F0345: 0x1F8F,
- 0x1F200345: 0x1F90,
- 0x1F210345: 0x1F91,
- 0x1F220345: 0x1F92,
- 0x1F230345: 0x1F93,
- 0x1F240345: 0x1F94,
- 0x1F250345: 0x1F95,
- 0x1F260345: 0x1F96,
- 0x1F270345: 0x1F97,
- 0x1F280345: 0x1F98,
- 0x1F290345: 0x1F99,
- 0x1F2A0345: 0x1F9A,
- 0x1F2B0345: 0x1F9B,
- 0x1F2C0345: 0x1F9C,
- 0x1F2D0345: 0x1F9D,
- 0x1F2E0345: 0x1F9E,
- 0x1F2F0345: 0x1F9F,
- 0x1F600345: 0x1FA0,
- 0x1F610345: 0x1FA1,
- 0x1F620345: 0x1FA2,
- 0x1F630345: 0x1FA3,
- 0x1F640345: 0x1FA4,
- 0x1F650345: 0x1FA5,
- 0x1F660345: 0x1FA6,
- 0x1F670345: 0x1FA7,
- 0x1F680345: 0x1FA8,
- 0x1F690345: 0x1FA9,
- 0x1F6A0345: 0x1FAA,
- 0x1F6B0345: 0x1FAB,
- 0x1F6C0345: 0x1FAC,
- 0x1F6D0345: 0x1FAD,
- 0x1F6E0345: 0x1FAE,
- 0x1F6F0345: 0x1FAF,
- 0x03B10306: 0x1FB0,
- 0x03B10304: 0x1FB1,
- 0x1F700345: 0x1FB2,
- 0x03B10345: 0x1FB3,
- 0x03AC0345: 0x1FB4,
- 0x03B10342: 0x1FB6,
- 0x1FB60345: 0x1FB7,
- 0x03910306: 0x1FB8,
- 0x03910304: 0x1FB9,
- 0x03910300: 0x1FBA,
- 0x03910345: 0x1FBC,
- 0x00A80342: 0x1FC1,
- 0x1F740345: 0x1FC2,
- 0x03B70345: 0x1FC3,
- 0x03AE0345: 0x1FC4,
- 0x03B70342: 0x1FC6,
- 0x1FC60345: 0x1FC7,
- 0x03950300: 0x1FC8,
- 0x03970300: 0x1FCA,
- 0x03970345: 0x1FCC,
- 0x1FBF0300: 0x1FCD,
- 0x1FBF0301: 0x1FCE,
- 0x1FBF0342: 0x1FCF,
- 0x03B90306: 0x1FD0,
- 0x03B90304: 0x1FD1,
- 0x03CA0300: 0x1FD2,
- 0x03B90342: 0x1FD6,
- 0x03CA0342: 0x1FD7,
- 0x03990306: 0x1FD8,
- 0x03990304: 0x1FD9,
- 0x03990300: 0x1FDA,
- 0x1FFE0300: 0x1FDD,
- 0x1FFE0301: 0x1FDE,
- 0x1FFE0342: 0x1FDF,
- 0x03C50306: 0x1FE0,
- 0x03C50304: 0x1FE1,
- 0x03CB0300: 0x1FE2,
- 0x03C10313: 0x1FE4,
- 0x03C10314: 0x1FE5,
- 0x03C50342: 0x1FE6,
- 0x03CB0342: 0x1FE7,
- 0x03A50306: 0x1FE8,
- 0x03A50304: 0x1FE9,
- 0x03A50300: 0x1FEA,
- 0x03A10314: 0x1FEC,
- 0x00A80300: 0x1FED,
- 0x1F7C0345: 0x1FF2,
- 0x03C90345: 0x1FF3,
- 0x03CE0345: 0x1FF4,
- 0x03C90342: 0x1FF6,
- 0x1FF60345: 0x1FF7,
- 0x039F0300: 0x1FF8,
- 0x03A90300: 0x1FFA,
- 0x03A90345: 0x1FFC,
- 0x21900338: 0x219A,
- 0x21920338: 0x219B,
- 0x21940338: 0x21AE,
- 0x21D00338: 0x21CD,
- 0x21D40338: 0x21CE,
- 0x21D20338: 0x21CF,
- 0x22030338: 0x2204,
- 0x22080338: 0x2209,
- 0x220B0338: 0x220C,
- 0x22230338: 0x2224,
- 0x22250338: 0x2226,
- 0x223C0338: 0x2241,
- 0x22430338: 0x2244,
- 0x22450338: 0x2247,
- 0x22480338: 0x2249,
- 0x003D0338: 0x2260,
- 0x22610338: 0x2262,
- 0x224D0338: 0x226D,
- 0x003C0338: 0x226E,
- 0x003E0338: 0x226F,
- 0x22640338: 0x2270,
- 0x22650338: 0x2271,
- 0x22720338: 0x2274,
- 0x22730338: 0x2275,
- 0x22760338: 0x2278,
- 0x22770338: 0x2279,
- 0x227A0338: 0x2280,
- 0x227B0338: 0x2281,
- 0x22820338: 0x2284,
- 0x22830338: 0x2285,
- 0x22860338: 0x2288,
- 0x22870338: 0x2289,
- 0x22A20338: 0x22AC,
- 0x22A80338: 0x22AD,
- 0x22A90338: 0x22AE,
- 0x22AB0338: 0x22AF,
- 0x227C0338: 0x22E0,
- 0x227D0338: 0x22E1,
- 0x22910338: 0x22E2,
- 0x22920338: 0x22E3,
- 0x22B20338: 0x22EA,
- 0x22B30338: 0x22EB,
- 0x22B40338: 0x22EC,
- 0x22B50338: 0x22ED,
- 0x304B3099: 0x304C,
- 0x304D3099: 0x304E,
- 0x304F3099: 0x3050,
- 0x30513099: 0x3052,
- 0x30533099: 0x3054,
- 0x30553099: 0x3056,
- 0x30573099: 0x3058,
- 0x30593099: 0x305A,
- 0x305B3099: 0x305C,
- 0x305D3099: 0x305E,
- 0x305F3099: 0x3060,
- 0x30613099: 0x3062,
- 0x30643099: 0x3065,
- 0x30663099: 0x3067,
- 0x30683099: 0x3069,
- 0x306F3099: 0x3070,
- 0x306F309A: 0x3071,
- 0x30723099: 0x3073,
- 0x3072309A: 0x3074,
- 0x30753099: 0x3076,
- 0x3075309A: 0x3077,
- 0x30783099: 0x3079,
- 0x3078309A: 0x307A,
- 0x307B3099: 0x307C,
- 0x307B309A: 0x307D,
- 0x30463099: 0x3094,
- 0x309D3099: 0x309E,
- 0x30AB3099: 0x30AC,
- 0x30AD3099: 0x30AE,
- 0x30AF3099: 0x30B0,
- 0x30B13099: 0x30B2,
- 0x30B33099: 0x30B4,
- 0x30B53099: 0x30B6,
- 0x30B73099: 0x30B8,
- 0x30B93099: 0x30BA,
- 0x30BB3099: 0x30BC,
- 0x30BD3099: 0x30BE,
- 0x30BF3099: 0x30C0,
- 0x30C13099: 0x30C2,
- 0x30C43099: 0x30C5,
- 0x30C63099: 0x30C7,
- 0x30C83099: 0x30C9,
- 0x30CF3099: 0x30D0,
- 0x30CF309A: 0x30D1,
- 0x30D23099: 0x30D3,
- 0x30D2309A: 0x30D4,
- 0x30D53099: 0x30D6,
- 0x30D5309A: 0x30D7,
- 0x30D83099: 0x30D9,
- 0x30D8309A: 0x30DA,
- 0x30DB3099: 0x30DC,
- 0x30DB309A: 0x30DD,
- 0x30A63099: 0x30F4,
- 0x30EF3099: 0x30F7,
- 0x30F03099: 0x30F8,
- 0x30F13099: 0x30F9,
- 0x30F23099: 0x30FA,
- 0x30FD3099: 0x30FE,
- 0x109910BA: 0x1109A,
- 0x109B10BA: 0x1109C,
- 0x10A510BA: 0x110AB,
- 0x11311127: 0x1112E,
- 0x11321127: 0x1112F,
- 0x1347133E: 0x1134B,
- 0x13471357: 0x1134C,
- 0x14B914BA: 0x114BB,
- 0x14B914B0: 0x114BC,
- 0x14B914BD: 0x114BE,
- 0x15B815AF: 0x115BA,
- 0x15B915AF: 0x115BB,
-}
-
-// Total size of tables: 53KB (53976 bytes)
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/transform.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/transform.go
deleted file mode 100644
index 8589067..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/transform.go
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package norm
-
-import (
- "unicode/utf8"
-
- "golang.org/x/text/transform"
-)
-
-// Reset implements the Reset method of the transform.Transformer interface.
-func (Form) Reset() {}
-
-// Transform implements the Transform method of the transform.Transformer
-// interface. It may need to write segments of up to MaxSegmentSize at once.
-// Users should either catch ErrShortDst and allow dst to grow or have dst be at
-// least of size MaxTransformChunkSize to be guaranteed of progress.
-func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- n := 0
- // Cap the maximum number of src bytes to check.
- b := src
- eof := atEOF
- if ns := len(dst); ns < len(b) {
- err = transform.ErrShortDst
- eof = false
- b = b[:ns]
- }
- i, ok := formTable[f].quickSpan(inputBytes(b), n, len(b), eof)
- n += copy(dst[n:], b[n:i])
- if !ok {
- nDst, nSrc, err = f.transform(dst[n:], src[n:], atEOF)
- return nDst + n, nSrc + n, err
- }
- if n < len(src) && !atEOF {
- err = transform.ErrShortSrc
- }
- return n, n, err
-}
-
-func flushTransform(rb *reorderBuffer) bool {
- // Write out (must fully fit in dst, or else it is a ErrShortDst).
- if len(rb.out) < rb.nrune*utf8.UTFMax {
- return false
- }
- rb.out = rb.out[rb.flushCopy(rb.out):]
- return true
-}
-
-var errs = []error{nil, transform.ErrShortDst, transform.ErrShortSrc}
-
-// transform implements the transform.Transformer interface. It is only called
-// when quickSpan does not pass for a given string.
-func (f Form) transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
- // TODO: get rid of reorderBuffer. See CL 23460044.
- rb := reorderBuffer{}
- rb.init(f, src)
- for {
- // Load segment into reorder buffer.
- rb.setFlusher(dst[nDst:], flushTransform)
- end := decomposeSegment(&rb, nSrc, atEOF)
- if end < 0 {
- return nDst, nSrc, errs[-end]
- }
- nDst = len(dst) - len(rb.out)
- nSrc = end
-
- // Next quickSpan.
- end = rb.nsrc
- eof := atEOF
- if n := nSrc + len(dst) - nDst; n < end {
- err = transform.ErrShortDst
- end = n
- eof = false
- }
- end, ok := rb.f.quickSpan(rb.src, nSrc, end, eof)
- n := copy(dst[nDst:], rb.src.bytes[nSrc:end])
- nSrc += n
- nDst += n
- if ok {
- if n < rb.nsrc && !atEOF {
- err = transform.ErrShortSrc
- }
- return nDst, nSrc, err
- }
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/transform_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/transform_test.go
deleted file mode 100644
index 987d680..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/transform_test.go
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package norm
-
-import (
- "fmt"
- "testing"
-
- "golang.org/x/text/transform"
-)
-
-func TestTransform(t *testing.T) {
- tests := []struct {
- f Form
- in, out string
- eof bool
- dstSize int
- err error
- }{
- {NFC, "ab", "ab", true, 2, nil},
- {NFC, "qx", "qx", true, 2, nil},
- {NFD, "qx", "qx", true, 2, nil},
- {NFC, "", "", true, 1, nil},
- {NFD, "", "", true, 1, nil},
- {NFC, "", "", false, 1, nil},
- {NFD, "", "", false, 1, nil},
-
- // Normalized segment does not fit in destination.
- {NFD, "ö", "", true, 1, transform.ErrShortDst},
- {NFD, "ö", "", true, 2, transform.ErrShortDst},
-
- // As an artifact of the algorithm, only full segments are written.
- // This is not strictly required, and some bytes could be written.
- // In practice, for Transform to not block, the destination buffer
- // should be at least MaxSegmentSize to work anyway and these edge
- // conditions will be relatively rare.
- {NFC, "ab", "", true, 1, transform.ErrShortDst},
- // This is even true for inert runes.
- {NFC, "qx", "", true, 1, transform.ErrShortDst},
- {NFC, "a\u0300abc", "\u00e0a", true, 4, transform.ErrShortDst},
-
- // We cannot write a segment if succesive runes could still change the result.
- {NFD, "ö", "", false, 3, transform.ErrShortSrc},
- {NFC, "a\u0300", "", false, 4, transform.ErrShortSrc},
- {NFD, "a\u0300", "", false, 4, transform.ErrShortSrc},
- {NFC, "ö", "", false, 3, transform.ErrShortSrc},
-
- {NFC, "a\u0300", "", true, 1, transform.ErrShortDst},
- // Theoretically could fit, but won't due to simplified checks.
- {NFC, "a\u0300", "", true, 2, transform.ErrShortDst},
- {NFC, "a\u0300", "", true, 3, transform.ErrShortDst},
- {NFC, "a\u0300", "\u00e0", true, 4, nil},
-
- {NFD, "öa\u0300", "o\u0308", false, 8, transform.ErrShortSrc},
- {NFD, "öa\u0300ö", "o\u0308a\u0300", true, 8, transform.ErrShortDst},
- {NFD, "öa\u0300ö", "o\u0308a\u0300", false, 12, transform.ErrShortSrc},
-
- // Illegal input is copied verbatim.
- {NFD, "\xbd\xb2=\xbc ", "\xbd\xb2=\xbc ", true, 8, nil},
- }
- b := make([]byte, 100)
- for i, tt := range tests {
- nDst, _, err := tt.f.Transform(b[:tt.dstSize], []byte(tt.in), tt.eof)
- out := string(b[:nDst])
- if out != tt.out || err != tt.err {
- t.Errorf("%d: was %+q (%v); want %+q (%v)", i, out, err, tt.out, tt.err)
- }
- if want := tt.f.String(tt.in)[:nDst]; want != out {
- t.Errorf("%d: incorect normalization: was %+q; want %+q", i, out, want)
- }
- }
-}
-
-var transBufSizes = []int{
- MaxTransformChunkSize,
- 3 * MaxTransformChunkSize / 2,
- 2 * MaxTransformChunkSize,
- 3 * MaxTransformChunkSize,
- 100 * MaxTransformChunkSize,
-}
-
-func doTransNorm(f Form, buf []byte, b []byte) []byte {
- acc := []byte{}
- for p := 0; p < len(b); {
- nd, ns, _ := f.Transform(buf[:], b[p:], true)
- p += ns
- acc = append(acc, buf[:nd]...)
- }
- return acc
-}
-
-func TestTransformNorm(t *testing.T) {
- for _, sz := range transBufSizes {
- buf := make([]byte, sz)
- runNormTests(t, fmt.Sprintf("Transform:%d", sz), func(f Form, out []byte, s string) []byte {
- return doTransNorm(f, buf, append(out, s...))
- })
- }
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/trie.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/trie.go
deleted file mode 100644
index 423386b..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/trie.go
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package norm
-
-type valueRange struct {
- value uint16 // header: value:stride
- lo, hi byte // header: lo:n
-}
-
-type sparseBlocks struct {
- values []valueRange
- offset []uint16
-}
-
-var nfcSparse = sparseBlocks{
- values: nfcSparseValues[:],
- offset: nfcSparseOffset[:],
-}
-
-var nfkcSparse = sparseBlocks{
- values: nfkcSparseValues[:],
- offset: nfkcSparseOffset[:],
-}
-
-var (
- nfcData = newNfcTrie(0)
- nfkcData = newNfkcTrie(0)
-)
-
-// lookupValue determines the type of block n and looks up the value for b.
-// For n < t.cutoff, the block is a simple lookup table. Otherwise, the block
-// is a list of ranges with an accompanying value. Given a matching range r,
-// the value for b is by r.value + (b - r.lo) * stride.
-func (t *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
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/triegen.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/triegen.go
deleted file mode 100644
index 45d7119..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/triegen.go
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-// Trie table generator.
-// Used by make*tables tools to generate a go file with trie data structures
-// for mapping UTF-8 to a 16-bit value. All but the last byte in a UTF-8 byte
-// sequence are used to lookup offsets in the index table to be used for the
-// next byte. The last byte is used to index into a table with 16-bit values.
-
-package main
-
-import (
- "fmt"
- "io"
-)
-
-const maxSparseEntries = 16
-
-type normCompacter struct {
- sparseBlocks [][]uint64
- sparseOffset []uint16
- sparseCount int
- name string
-}
-
-func mostFrequentStride(a []uint64) int {
- counts := make(map[int]int)
- var v int
- for _, x := range a {
- if stride := int(x) - v; v != 0 && stride >= 0 {
- counts[stride]++
- }
- v = int(x)
- }
- var maxs, maxc int
- for stride, cnt := range counts {
- if cnt > maxc || (cnt == maxc && stride < maxs) {
- maxs, maxc = stride, cnt
- }
- }
- return maxs
-}
-
-func countSparseEntries(a []uint64) int {
- stride := mostFrequentStride(a)
- var v, count int
- for _, tv := range a {
- if int(tv)-v != stride {
- if tv != 0 {
- count++
- }
- }
- v = int(tv)
- }
- return count
-}
-
-func (c *normCompacter) Size(v []uint64) (sz int, ok bool) {
- if n := countSparseEntries(v); n <= maxSparseEntries {
- return (n+1)*4 + 2, true
- }
- return 0, false
-}
-
-func (c *normCompacter) Store(v []uint64) uint32 {
- h := uint32(len(c.sparseOffset))
- c.sparseBlocks = append(c.sparseBlocks, v)
- c.sparseOffset = append(c.sparseOffset, uint16(c.sparseCount))
- c.sparseCount += countSparseEntries(v) + 1
- return h
-}
-
-func (c *normCompacter) Handler() string {
- return c.name + "Sparse.lookup"
-}
-
-func (c *normCompacter) Print(w io.Writer) (retErr error) {
- p := func(f string, x ...interface{}) {
- if _, err := fmt.Fprintf(w, f, x...); retErr == nil && err != nil {
- retErr = err
- }
- }
-
- ls := len(c.sparseBlocks)
- p("// %sSparseOffset: %d entries, %d bytes\n", c.name, ls, ls*2)
- p("var %sSparseOffset = %#v\n\n", c.name, c.sparseOffset)
-
- ns := c.sparseCount
- p("// %sSparseValues: %d entries, %d bytes\n", c.name, ns, ns*4)
- p("var %sSparseValues = [%d]valueRange {", c.name, ns)
- for i, b := range c.sparseBlocks {
- p("\n// Block %#x, offset %#x", i, c.sparseOffset[i])
- var v int
- stride := mostFrequentStride(b)
- n := countSparseEntries(b)
- p("\n{value:%#04x,lo:%#02x},", stride, uint8(n))
- for i, nv := range b {
- if int(nv)-v != stride {
- if v != 0 {
- p(",hi:%#02x},", 0x80+i-1)
- }
- if nv != 0 {
- p("\n{value:%#04x,lo:%#02x", nv, 0x80+i)
- }
- }
- v = int(nv)
- }
- if v != 0 {
- p(",hi:%#02x},", 0x80+len(b)-1)
- }
- }
- p("\n}\n\n")
- return
-}
diff --git a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/ucd_test.go b/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/ucd_test.go
deleted file mode 100644
index 29205a6..0000000
--- a/examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/ucd_test.go
+++ /dev/null
@@ -1,275 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package norm
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "regexp"
- "runtime"
- "strconv"
- "strings"
- "sync"
- "testing"
- "time"
- "unicode/utf8"
-
- "golang.org/x/text/internal/gen"
- "golang.org/x/text/internal/testtext"
-)
-
-var once sync.Once
-
-func skipShort(t *testing.T) {
- testtext.SkipIfNotLong(t)
-
- once.Do(func() { loadTestData(t) })
-}
-
-// This regression test runs the test set in NormalizationTest.txt
-// (taken from http://www.unicode.org/Public/<unicode.Version>/ucd/).
-//
-// NormalizationTest.txt has form:
-// @Part0 # Specific cases
-// #
-// 1E0A;1E0A;0044 0307;1E0A;0044 0307; # (Ḋ; Ḋ; D◌̇; Ḋ; D◌̇; ) LATIN CAPITAL LETTER D WITH DOT ABOVE
-// 1E0C;1E0C;0044 0323;1E0C;0044 0323; # (Ḍ; Ḍ; D◌̣; Ḍ; D◌̣; ) LATIN CAPITAL LETTER D WITH DOT BELOW
-//
-// Each test has 5 columns (c1, c2, c3, c4, c5), where
-// (c1, c2, c3, c4, c5) == (c1, NFC(c1), NFD(c1), NFKC(c1), NFKD(c1))
-//
-// CONFORMANCE:
-// 1. The following invariants must be true for all conformant implementations
-//
-// NFC
-// c2 == NFC(c1) == NFC(c2) == NFC(c3)
-// c4 == NFC(c4) == NFC(c5)
-//
-// NFD
-// c3 == NFD(c1) == NFD(c2) == NFD(c3)
-// c5 == NFD(c4) == NFD(c5)
-//
-// NFKC
-// c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5)
-//
-// NFKD
-// c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5)
-//
-// 2. For every code point X assigned in this version of Unicode that is not
-// specifically listed in Part 1, the following invariants must be true
-// for all conformant implementations:
-//
-// X == NFC(X) == NFD(X) == NFKC(X) == NFKD(X)
-//
-
-// Column types.
-const (
- cRaw = iota
- cNFC
- cNFD
- cNFKC
- cNFKD
- cMaxColumns
-)
-
-// Holds data from NormalizationTest.txt
-var part []Part
-
-type Part struct {
- name string
- number int
- tests []Test
-}
-
-type Test struct {
- name string
- partnr int
- number int
- r rune // used for character by character test
- cols [cMaxColumns]string // Each has 5 entries, see below.
-}
-
-func (t Test) Name() string {
- if t.number < 0 {
- return part[t.partnr].name
- }
- return fmt.Sprintf("%s:%d", part[t.partnr].name, t.number)
-}
-
-var partRe = regexp.MustCompile(`@Part(\d) # (.*)$`)
-var testRe = regexp.MustCompile(`^` + strings.Repeat(`([\dA-F ]+);`, 5) + ` # (.*)$`)
-
-var counter int
-
-// Load the data form NormalizationTest.txt
-func loadTestData(t *testing.T) {
- f := gen.OpenUCDFile("NormalizationTest.txt")
- defer f.Close()
- scanner := bufio.NewScanner(f)
- for scanner.Scan() {
- line := scanner.Text()
- if len(line) == 0 || line[0] == '#' {
- continue
- }
- m := partRe.FindStringSubmatch(line)
- if m != nil {
- if len(m) < 3 {
- t.Fatal("Failed to parse Part: ", line)
- }
- i, err := strconv.Atoi(m[1])
- if err != nil {
- t.Fatal(err)
- }
- name := m[2]
- part = append(part, Part{name: name[:len(name)-1], number: i})
- continue
- }
- m = testRe.FindStringSubmatch(line)
- if m == nil || len(m) < 7 {
- t.Fatalf(`Failed to parse: "%s" result: %#v`, line, m)
- }
- test := Test{name: m[6], partnr: len(part) - 1, number: counter}
- counter++
- for j := 1; j < len(m)-1; j++ {
- for _, split := range strings.Split(m[j], " ") {
- r, err := strconv.ParseUint(split, 16, 64)
- if err != nil {
- t.Fatal(err)
- }
- if test.r == 0 {
- // save for CharacterByCharacterTests
- test.r = rune(r)
- }
- var buf [utf8.UTFMax]byte
- sz := utf8.EncodeRune(buf[:], rune(r))
- test.cols[j-1] += string(buf[:sz])
- }
- }
- part := &part[len(part)-1]
- part.tests = append(part.tests, test)
- }
- if scanner.Err() != nil {
- t.Fatal(scanner.Err())
- }
-}
-
-func cmpResult(t *testing.T, tc *Test, name string, f Form, gold, test, result string) {
- if gold != result {
- t.Errorf("%s:%s: %s(%+q)=%+q; want %+q: %s",
- tc.Name(), name, fstr[f], test, result, gold, tc.name)
- }
-}
-
-func cmpIsNormal(t *testing.T, tc *Test, name string, f Form, test string, result, want bool) {
- if result != want {
- t.Errorf("%s:%s: %s(%+q)=%v; want %v", tc.Name(), name, fstr[f], test, result, want)
- }
-}
-
-func doTest(t *testing.T, tc *Test, f Form, gold, test string) {
- testb := []byte(test)
- result := f.Bytes(testb)
- cmpResult(t, tc, "Bytes", f, gold, test, string(result))
-
- sresult := f.String(test)
- cmpResult(t, tc, "String", f, gold, test, sresult)
-
- acc := []byte{}
- i := Iter{}
- i.InitString(f, test)
- for !i.Done() {
- acc = append(acc, i.Next()...)
- }
- cmpResult(t, tc, "Iter.Next", f, gold, test, string(acc))
-
- buf := make([]byte, 128)
- acc = nil
- for p := 0; p < len(testb); {
- nDst, nSrc, _ := f.Transform(buf, testb[p:], true)
- acc = append(acc, buf[:nDst]...)
- p += nSrc
- }
- cmpResult(t, tc, "Transform", f, gold, test, string(acc))
-
- for i := range test {
- out := f.Append(f.Bytes([]byte(test[:i])), []byte(test[i:])...)
- cmpResult(t, tc, fmt.Sprintf(":Append:%d", i), f, gold, test, string(out))
- }
- cmpIsNormal(t, tc, "IsNormal", f, test, f.IsNormal([]byte(test)), test == gold)
- cmpIsNormal(t, tc, "IsNormalString", f, test, f.IsNormalString(test), test == gold)
-}
-
-func doConformanceTests(t *testing.T, tc *Test, partn int) {
- for i := 0; i <= 2; i++ {
- doTest(t, tc, NFC, tc.cols[1], tc.cols[i])
- doTest(t, tc, NFD, tc.cols[2], tc.cols[i])
- doTest(t, tc, NFKC, tc.cols[3], tc.cols[i])
- doTest(t, tc, NFKD, tc.cols[4], tc.cols[i])
- }
- for i := 3; i <= 4; i++ {
- doTest(t, tc, NFC, tc.cols[3], tc.cols[i])
- doTest(t, tc, NFD, tc.cols[4], tc.cols[i])
- doTest(t, tc, NFKC, tc.cols[3], tc.cols[i])
- doTest(t, tc, NFKD, tc.cols[4], tc.cols[i])
- }
-}
-
-func TestCharacterByCharacter(t *testing.T) {
- skipShort(t)
- tests := part[1].tests
- var last rune = 0
- for i := 0; i <= len(tests); i++ { // last one is special case
- var r rune
- if i == len(tests) {
- r = 0x2FA1E // Don't have to go to 0x10FFFF
- } else {
- r = tests[i].r
- }
- for last++; last < r; last++ {
- // Check all characters that were not explicitly listed in the test.
- tc := &Test{partnr: 1, number: -1}
- char := string(last)
- doTest(t, tc, NFC, char, char)
- doTest(t, tc, NFD, char, char)
- doTest(t, tc, NFKC, char, char)
- doTest(t, tc, NFKD, char, char)
- }
- if i < len(tests) {
- doConformanceTests(t, &tests[i], 1)
- }
- }
-}
-
-func TestStandardTests(t *testing.T) {
- skipShort(t)
- for _, j := range []int{0, 2, 3} {
- for _, test := range part[j].tests {
- doConformanceTests(t, &test, j)
- }
- }
-}
-
-// TestPerformance verifies that normalization is O(n). If any of the
-// code does not properly check for maxCombiningChars, normalization
-// may exhibit O(n**2) behavior.
-func TestPerformance(t *testing.T) {
- skipShort(t)
- runtime.GOMAXPROCS(2)
- success := make(chan bool, 1)
- go func() {
- buf := bytes.Repeat([]byte("\u035D"), 1024*1024)
- buf = append(buf, "\u035B"...)
- NFC.Append(nil, buf...)
- success <- true
- }()
- timeout := time.After(1 * time.Second)
- select {
- case <-success:
- // test completed before the timeout
- case <-timeout:
- t.Errorf(`unexpectedly long time to complete PerformanceTest`)
- }
-}
diff --git a/examples/docker/admin/content/.hold b/examples/docker/admin/content/.hold
deleted file mode 100644
index e69de29..0000000
--- a/examples/docker/admin/content/.hold
+++ /dev/null
diff --git a/examples/docker/admin/content/song.go b/examples/docker/admin/content/song.go
deleted file mode 100644
index fa5e802..0000000
--- a/examples/docker/admin/content/song.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package content
-
-import (
- "fmt"
-
- "github.com/ponzu-cms/ponzu/management/editor"
- "github.com/ponzu-cms/ponzu/system/item"
-)
-
-type Song struct {
- item.Item
-
- Title string `json:"title"`
- Artist string `json:"artist"`
- Rating int `json:"rating"`
- Opinion string `json:"opinion"`
- SpotifyUrl string `json:"spotify_url"`
-}
-
-// MarshalEditor writes a buffer of html to edit a Song within the CMS
-// and implements editor.Editable
-func (s *Song) MarshalEditor() ([]byte, error) {
- view, err := editor.Form(s,
- // Take note that the first argument to these Input-like functions
- // is the string version of each Song field, and must follow
- // this pattern for auto-decoding and auto-encoding reasons:
- editor.Field{
- View: editor.Input("Title", s, map[string]string{
- "label": "Title",
- "type": "text",
- "placeholder": "Enter the Title here",
- }),
- },
- editor.Field{
- View: editor.Input("Artist", s, map[string]string{
- "label": "Artist",
- "type": "text",
- "placeholder": "Enter the Artist here",
- }),
- },
- editor.Field{
- View: editor.Input("Rating", s, map[string]string{
- "label": "Rating",
- "type": "text",
- "placeholder": "Enter the Rating here",
- }),
- },
- editor.Field{
- View: editor.Input("Opinion", s, map[string]string{
- "label": "Opinion",
- "type": "text",
- "placeholder": "Enter the Opinion here",
- }),
- },
- editor.Field{
- View: editor.Input("SpotifyUrl", s, map[string]string{
- "label": "SpotifyUrl",
- "type": "text",
- "placeholder": "Enter the SpotifyUrl here",
- }),
- },
- )
-
- if err != nil {
- return nil, fmt.Errorf("Failed to render Song editor view: %s", err.Error())
- }
-
- return view, nil
-}
-
-func init() {
- item.Types["Song"] = func() interface{} { return new(Song) }
-}
diff --git a/examples/docker/admin/deployment/README.md b/examples/docker/admin/deployment/README.md
deleted file mode 100644
index 7fad586..0000000
--- a/examples/docker/admin/deployment/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Deployment
-
-This is a set of deployment scripts for starting up `ponzu-server` processes on
-system boot and run levels.
-
-To add one for a missing platform / OS, fork the ponzu repository and create a
-new pull request with the script inside a directory named by the corresponding
-init system.
-
-Questions? Reach out to [@ponzu_cms](https://twitter.com/ponzu_cms) on Twitter,
-or open an issue at https://github.com/ponzu-cms/ponzu
diff --git a/examples/docker/admin/deployment/sysv/ponzu-server b/examples/docker/admin/deployment/sysv/ponzu-server
deleted file mode 100644
index 0a0e724..0000000
--- a/examples/docker/admin/deployment/sysv/ponzu-server
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/bin/sh
-### BEGIN INIT INFO
-# Provides: ponzu-server
-# Required-Start: $local_fs $network $named $time $syslog
-# Required-Stop: $local_fs $network $named $time $syslog
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Description: Ponzu API & Admin server
-### END INIT INFO
-
-PROJECT_DIR=<PROJECT DIRECTORY>
-SCRIPT='cd $PROJECT_DIR && ponzu --port=80 run'
-RUNAS=<USER>
-
-PIDFILE=/var/run/ponzu-server.pid
-LOGFILE=/var/log/ponzu-server.log
-
-start() {
- if [ -f /var/run/$PIDNAME ] && kill -0 $(cat /var/run/$PIDNAME); then
- echo 'Service already running' >&2
- return 1
- fi
- echo 'Starting service…' >&2
- local CMD="$SCRIPT &> \"$LOGFILE\" & echo \$!"
- su -c "$CMD" $RUNAS > "$PIDFILE"
- echo 'Service started' >&2
-}
-
-stop() {
- if [ ! -f "$PIDFILE" ] || ! kill -0 $(cat "$PIDFILE"); then
- echo 'Service not running' >&2
- return 1
- fi
- echo 'Stopping service…' >&2
- kill -15 $(cat "$PIDFILE") && rm -f "$PIDFILE"
- echo 'Service stopped' >&2
-}
-
-uninstall() {
- echo -n "Are you really sure you want to uninstall this service? That cannot be undone. [yes|No] "
- local SURE
- read SURE
- if [ "$SURE" = "yes" ]; then
- stop
- rm -f "$PIDFILE"
- echo "Notice: log file is not be removed: '$LOGFILE'" >&2
- update-rc.d -f <NAME> remove
- rm -fv "$0"
- fi
-}
-
-case "$1" in
- start)
- start
- ;;
- stop)
- stop
- ;;
- uninstall)
- uninstall
- ;;
- restart)
- stop
- start
- ;;
- *)
- echo "Usage: $0 {start|stop|restart|uninstall}"
-esac
diff --git a/examples/docker/admin/start_admin.sh b/examples/docker/admin/start_admin.sh
deleted file mode 100755
index 986963d..0000000
--- a/examples/docker/admin/start_admin.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-echo "creating the volume assets"
-mkdir -p $PONZU_SHARE/uploads
-mkdir -p $PONZU_SHARE/search
-touch $PONZU_SHARE/system.db
-touch $PONZU_SHARE/analytics.db
-
-echo "linking the volume assets"
-ln -sf $PONZU_SHARE/uploads $PROJECT_FOLDER/uploads
-ln -sf $PONZU_SHARE/search $PROJECT_FOLDER/search
-ln -sf $PONZU_SHARE/system.db $PROJECT_FOLDER/system.db
-ln -sf $PONZU_SHARE/analytics.db $PROJECT_FOLDER/analytics.db
-
-if [ "$1" = "start" ]; then
- echo "building ponzu from project directory"
- cd $PROJECT_FOLDER && ponzu build
-
- echo "starting ponzu admin and api"
- cd $PROJECT_FOLDER && ponzu -port=8080 --https run admin,api &>> $PONZU_SHARE/server.log
-
- # this line starts and pipes to log, then continues terminal.
- # cd $PROJECT_FOLDER && nohup ponzu -port=8080 --https run admin,api &> $PONZU_SHARE/server.log &
- #
-
- echo "Ponzu server started"
-fi
-
diff --git a/examples/docker/docker-compose.yml b/examples/docker/docker-compose.yml
deleted file mode 100644
index e3d4b8e..0000000
--- a/examples/docker/docker-compose.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-# service configuration for our dockerized Ponzu app
-admin:
-
- # use the Dockerfile in the ponzu directory
- build: ./admin
-
- # expose the port we configured Ponzu to publish
- expose:
- - "8080"
-
- volumes:
- - ./admin:/go/src/project
-
- command: bash /go/src/project/start_admin.sh start
-
-# service configuration for our web server
-web:
-
- # use the dockerfile in the web directory
- build: ./web
-
- volumes:
- - ./web/public:/public
-
- # makes the web container aware of the admin container
- links:
- - admin
-
- # expose the port we configured Nginx to bind to
- ports:
- #host will listen on port 3000 in dev
- - "3000:80"
diff --git a/examples/docker/web/Dockerfile b/examples/docker/web/Dockerfile
deleted file mode 100644
index 57845aa..0000000
--- a/examples/docker/web/Dockerfile
+++ /dev/null
@@ -1,2 +0,0 @@
-FROM nginx
-COPY nginx.conf /etc/nginx/conf.d/default.conf \ No newline at end of file
diff --git a/examples/docker/web/nginx.conf b/examples/docker/web/nginx.conf
deleted file mode 100644
index 9606fc5..0000000
--- a/examples/docker/web/nginx.conf
+++ /dev/null
@@ -1,34 +0,0 @@
-upstream ponzu {
- server admin:8080;
-}
-
-server {
-
- listen 80 default_server;
- listen [::]:80 default_server ipv6only=on;
-
- root /public;
- index index.html index.htm;
-
- location ~ /api(.*)$ {
- try_files $uri @ponzu;
- }
-
- location ~ /admin(.*)$ {
- try_files $uri @ponzu;
- }
-
- location / {
- # First attempt to serve request as file, then
- # as directory, then fall back to displaying a 404.
- try_files $uri $uri/ /index.html;
- }
-
- location @ponzu {
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header Host $http_host;
- proxy_redirect off;
- proxy_pass http://ponzu;
- }
-} \ No newline at end of file
diff --git a/examples/docker/web/public/css/main.css b/examples/docker/web/public/css/main.css
deleted file mode 100644
index f2eebc7..0000000
--- a/examples/docker/web/public/css/main.css
+++ /dev/null
@@ -1,22 +0,0 @@
-main{
- margin-top: 25vh !important;
- margin-bottom: 25vh !important;
-}
-article{
- margin: 0 0 1rem;
- padding-bottom: 2rem;
- border-bottom: 1px solid #666;
-}
-
-article p{
- margin: 0;
-}
-
-article h3 {
- margin-bottom: 0.5rem;
-}
-
-article h6{
- font-size:1.1rem;
- margin-bottom: 0.4rem;
-} \ No newline at end of file
diff --git a/examples/docker/web/public/css/normalize.css b/examples/docker/web/public/css/normalize.css
deleted file mode 100644
index 81c6f31..0000000
--- a/examples/docker/web/public/css/normalize.css
+++ /dev/null
@@ -1,427 +0,0 @@
-/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
-
-/**
- * 1. Set default font family to sans-serif.
- * 2. Prevent iOS text size adjust after orientation change, without disabling
- * user zoom.
- */
-
-html {
- font-family: sans-serif; /* 1 */
- -ms-text-size-adjust: 100%; /* 2 */
- -webkit-text-size-adjust: 100%; /* 2 */
-}
-
-/**
- * Remove default margin.
- */
-
-body {
- margin: 0;
-}
-
-/* HTML5 display definitions
- ========================================================================== */
-
-/**
- * Correct `block` display not defined for any HTML5 element in IE 8/9.
- * Correct `block` display not defined for `details` or `summary` in IE 10/11
- * and Firefox.
- * Correct `block` display not defined for `main` in IE 11.
- */
-
-article,
-aside,
-details,
-figcaption,
-figure,
-footer,
-header,
-hgroup,
-main,
-menu,
-nav,
-section,
-summary {
- display: block;
-}
-
-/**
- * 1. Correct `inline-block` display not defined in IE 8/9.
- * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
- */
-
-audio,
-canvas,
-progress,
-video {
- display: inline-block; /* 1 */
- vertical-align: baseline; /* 2 */
-}
-
-/**
- * Prevent modern browsers from displaying `audio` without controls.
- * Remove excess height in iOS 5 devices.
- */
-
-audio:not([controls]) {
- display: none;
- height: 0;
-}
-
-/**
- * Address `[hidden]` styling not present in IE 8/9/10.
- * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
- */
-
-[hidden],
-template {
- display: none;
-}
-
-/* Links
- ========================================================================== */
-
-/**
- * Remove the gray background color from active links in IE 10.
- */
-
-a {
- background-color: transparent;
-}
-
-/**
- * Improve readability when focused and also mouse hovered in all browsers.
- */
-
-a:active,
-a:hover {
- outline: 0;
-}
-
-/* Text-level semantics
- ========================================================================== */
-
-/**
- * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
- */
-
-abbr[title] {
- border-bottom: 1px dotted;
-}
-
-/**
- * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
- */
-
-b,
-strong {
- font-weight: bold;
-}
-
-/**
- * Address styling not present in Safari and Chrome.
- */
-
-dfn {
- font-style: italic;
-}
-
-/**
- * Address variable `h1` font-size and margin within `section` and `article`
- * contexts in Firefox 4+, Safari, and Chrome.
- */
-
-h1 {
- font-size: 2em;
- margin: 0.67em 0;
-}
-
-/**
- * Address styling not present in IE 8/9.
- */
-
-mark {
- background: #ff0;
- color: #000;
-}
-
-/**
- * Address inconsistent and variable font size in all browsers.
- */
-
-small {
- font-size: 80%;
-}
-
-/**
- * Prevent `sub` and `sup` affecting `line-height` in all browsers.
- */
-
-sub,
-sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline;
-}
-
-sup {
- top: -0.5em;
-}
-
-sub {
- bottom: -0.25em;
-}
-
-/* Embedded content
- ========================================================================== */
-
-/**
- * Remove border when inside `a` element in IE 8/9/10.
- */
-
-img {
- border: 0;
-}
-
-/**
- * Correct overflow not hidden in IE 9/10/11.
- */
-
-svg:not(:root) {
- overflow: hidden;
-}
-
-/* Grouping content
- ========================================================================== */
-
-/**
- * Address margin not present in IE 8/9 and Safari.
- */
-
-figure {
- margin: 1em 40px;
-}
-
-/**
- * Address differences between Firefox and other browsers.
- */
-
-hr {
- -moz-box-sizing: content-box;
- box-sizing: content-box;
- height: 0;
-}
-
-/**
- * Contain overflow in all browsers.
- */
-
-pre {
- overflow: auto;
-}
-
-/**
- * Address odd `em`-unit font size rendering in all browsers.
- */
-
-code,
-kbd,
-pre,
-samp {
- font-family: monospace, monospace;
- font-size: 1em;
-}
-
-/* Forms
- ========================================================================== */
-
-/**
- * Known limitation: by default, Chrome and Safari on OS X allow very limited
- * styling of `select`, unless a `border` property is set.
- */
-
-/**
- * 1. Correct color not being inherited.
- * Known issue: affects color of disabled elements.
- * 2. Correct font properties not being inherited.
- * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
- */
-
-button,
-input,
-optgroup,
-select,
-textarea {
- color: inherit; /* 1 */
- font: inherit; /* 2 */
- margin: 0; /* 3 */
-}
-
-/**
- * Address `overflow` set to `hidden` in IE 8/9/10/11.
- */
-
-button {
- overflow: visible;
-}
-
-/**
- * Address inconsistent `text-transform` inheritance for `button` and `select`.
- * All other form control elements do not inherit `text-transform` values.
- * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
- * Correct `select` style inheritance in Firefox.
- */
-
-button,
-select {
- text-transform: none;
-}
-
-/**
- * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
- * and `video` controls.
- * 2. Correct inability to style clickable `input` types in iOS.
- * 3. Improve usability and consistency of cursor style between image-type
- * `input` and others.
- */
-
-button,
-html input[type="button"], /* 1 */
-input[type="reset"],
-input[type="submit"] {
- -webkit-appearance: button; /* 2 */
- cursor: pointer; /* 3 */
-}
-
-/**
- * Re-set default cursor for disabled elements.
- */
-
-button[disabled],
-html input[disabled] {
- cursor: default;
-}
-
-/**
- * Remove inner padding and border in Firefox 4+.
- */
-
-button::-moz-focus-inner,
-input::-moz-focus-inner {
- border: 0;
- padding: 0;
-}
-
-/**
- * Address Firefox 4+ setting `line-height` on `input` using `!important` in
- * the UA stylesheet.
- */
-
-input {
- line-height: normal;
-}
-
-/**
- * It's recommended that you don't attempt to style these elements.
- * Firefox's implementation doesn't respect box-sizing, padding, or width.
- *
- * 1. Address box sizing set to `content-box` in IE 8/9/10.
- * 2. Remove excess padding in IE 8/9/10.
- */
-
-input[type="checkbox"],
-input[type="radio"] {
- box-sizing: border-box; /* 1 */
- padding: 0; /* 2 */
-}
-
-/**
- * Fix the cursor style for Chrome's increment/decrement buttons. For certain
- * `font-size` values of the `input`, it causes the cursor style of the
- * decrement button to change from `default` to `text`.
- */
-
-input[type="number"]::-webkit-inner-spin-button,
-input[type="number"]::-webkit-outer-spin-button {
- height: auto;
-}
-
-/**
- * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
- * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
- * (include `-moz` to future-proof).
- */
-
-input[type="search"] {
- -webkit-appearance: textfield; /* 1 */
- -moz-box-sizing: content-box;
- -webkit-box-sizing: content-box; /* 2 */
- box-sizing: content-box;
-}
-
-/**
- * Remove inner padding and search cancel button in Safari and Chrome on OS X.
- * Safari (but not Chrome) clips the cancel button when the search input has
- * padding (and `textfield` appearance).
- */
-
-input[type="search"]::-webkit-search-cancel-button,
-input[type="search"]::-webkit-search-decoration {
- -webkit-appearance: none;
-}
-
-/**
- * Define consistent border, margin, and padding.
- */
-
-fieldset {
- border: 1px solid #c0c0c0;
- margin: 0 2px;
- padding: 0.35em 0.625em 0.75em;
-}
-
-/**
- * 1. Correct `color` not being inherited in IE 8/9/10/11.
- * 2. Remove padding so people aren't caught out if they zero out fieldsets.
- */
-
-legend {
- border: 0; /* 1 */
- padding: 0; /* 2 */
-}
-
-/**
- * Remove default vertical scrollbar in IE 8/9/10/11.
- */
-
-textarea {
- overflow: auto;
-}
-
-/**
- * Don't inherit the `font-weight` (applied by a rule above).
- * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
- */
-
-optgroup {
- font-weight: bold;
-}
-
-/* Tables
- ========================================================================== */
-
-/**
- * Remove most spacing between table cells.
- */
-
-table {
- border-collapse: collapse;
- border-spacing: 0;
-}
-
-td,
-th {
- padding: 0;
-} \ No newline at end of file
diff --git a/examples/docker/web/public/css/skeleton.css b/examples/docker/web/public/css/skeleton.css
deleted file mode 100644
index f28bf6c..0000000
--- a/examples/docker/web/public/css/skeleton.css
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
-* Skeleton V2.0.4
-* Copyright 2014, Dave Gamache
-* www.getskeleton.com
-* Free to use under the MIT license.
-* http://www.opensource.org/licenses/mit-license.php
-* 12/29/2014
-*/
-
-
-/* Table of contents
-––––––––––––––––––––––––––––––––––––––––––––––––––
-- Grid
-- Base Styles
-- Typography
-- Links
-- Buttons
-- Forms
-- Lists
-- Code
-- Tables
-- Spacing
-- Utilities
-- Clearing
-- Media Queries
-*/
-
-
-/* Grid
-–––––––––––––––––––––––––––––––––––––––––––––––––– */
-.container {
- position: relative;
- width: 100%;
- max-width: 960px;
- margin: 0 auto;
- padding: 0 20px;
- box-sizing: border-box; }
-.column,
-.columns {
- width: 100%;
- float: left;
- box-sizing: border-box; }
-
-/* For devices larger than 400px */
-@media (min-width: 400px) {
- .container {
- width: 85%;
- padding: 0; }
-}
-
-/* For devices larger than 550px */
-@media (min-width: 550px) {
- .container {
- width: 80%; }
- .column,
- .columns {
- margin-left: 4%; }
- .column:first-child,
- .columns:first-child {
- margin-left: 0; }
-
- .one.column,
- .one.columns { width: 4.66666666667%; }
- .two.columns { width: 13.3333333333%; }
- .three.columns { width: 22%; }
- .four.columns { width: 30.6666666667%; }
- .five.columns { width: 39.3333333333%; }
- .six.columns { width: 48%; }
- .seven.columns { width: 56.6666666667%; }
- .eight.columns { width: 65.3333333333%; }
- .nine.columns { width: 74.0%; }
- .ten.columns { width: 82.6666666667%; }
- .eleven.columns { width: 91.3333333333%; }
- .twelve.columns { width: 100%; margin-left: 0; }
-
- .one-third.column { width: 30.6666666667%; }
- .two-thirds.column { width: 65.3333333333%; }
-
- .one-half.column { width: 48%; }
-
- /* Offsets */
- .offset-by-one.column,
- .offset-by-one.columns { margin-left: 8.66666666667%; }
- .offset-by-two.column,
- .offset-by-two.columns { margin-left: 17.3333333333%; }
- .offset-by-three.column,
- .offset-by-three.columns { margin-left: 26%; }
- .offset-by-four.column,
- .offset-by-four.columns { margin-left: 34.6666666667%; }
- .offset-by-five.column,
- .offset-by-five.columns { margin-left: 43.3333333333%; }
- .offset-by-six.column,
- .offset-by-six.columns { margin-left: 52%; }
- .offset-by-seven.column,
- .offset-by-seven.columns { margin-left: 60.6666666667%; }
- .offset-by-eight.column,
- .offset-by-eight.columns { margin-left: 69.3333333333%; }
- .offset-by-nine.column,
- .offset-by-nine.columns { margin-left: 78.0%; }
- .offset-by-ten.column,
- .offset-by-ten.columns { margin-left: 86.6666666667%; }
- .offset-by-eleven.column,
- .offset-by-eleven.columns { margin-left: 95.3333333333%; }
-
- .offset-by-one-third.column,
- .offset-by-one-third.columns { margin-left: 34.6666666667%; }
- .offset-by-two-thirds.column,
- .offset-by-two-thirds.columns { margin-left: 69.3333333333%; }
-
- .offset-by-one-half.column,
- .offset-by-one-half.columns { margin-left: 52%; }
-
-}
-
-
-/* Base Styles
-–––––––––––––––––––––––––––––––––––––––––––––––––– */
-/* NOTE
-html is set to 62.5% so that all the REM measurements throughout Skeleton
-are based on 10px sizing. So basically 1.5rem = 15px :) */
-html {
- font-size: 62.5%; }
-body {
- font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
- line-height: 1.6;
- font-weight: 400;
- font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
- color: #222; }
-
-
-/* Typography
-–––––––––––––––––––––––––––––––––––––––––––––––––– */
-h1, h2, h3, h4, h5, h6 {
- margin-top: 0;
- margin-bottom: 2rem;
- font-weight: 300; }
-h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
-h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
-h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
-h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
-h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
-h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
-
-/* Larger than phablet */
-@media (min-width: 550px) {
- h1 { font-size: 5.0rem; }
- h2 { font-size: 4.2rem; }
- h3 { font-size: 3.6rem; }
- h4 { font-size: 3.0rem; }
- h5 { font-size: 2.4rem; }
- h6 { font-size: 1.5rem; }
-}
-
-p {
- margin-top: 0; }
-
-
-/* Links
-–––––––––––––––––––––––––––––––––––––––––––––––––– */
-a {
- color: #1EAEDB; }
-a:hover {
- color: #0FA0CE; }
-
-
-/* Buttons
-–––––––––––––––––––––––––––––––––––––––––––––––––– */
-.button,
-button,
-input[type="submit"],
-input[type="reset"],
-input[type="button"] {
- display: inline-block;
- height: 38px;
- padding: 0 30px;
- color: #555;
- text-align: center;
- font-size: 11px;
- font-weight: 600;
- line-height: 38px;
- letter-spacing: .1rem;
- text-transform: uppercase;
- text-decoration: none;
- white-space: nowrap;
- background-color: transparent;
- border-radius: 4px;
- border: 1px solid #bbb;
- cursor: pointer;
- box-sizing: border-box; }
-.button:hover,
-button:hover,
-input[type="submit"]:hover,
-input[type="reset"]:hover,
-input[type="button"]:hover,
-.button:focus,
-button:focus,
-input[type="submit"]:focus,
-input[type="reset"]:focus,
-input[type="button"]:focus {
- color: #333;
- border-color: #888;
- outline: 0; }
-.button.button-primary,
-button.button-primary,
-input[type="submit"].button-primary,
-input[type="reset"].button-primary,
-input[type="button"].button-primary {
- color: #FFF;
- background-color: #33C3F0;
- border-color: #33C3F0; }
-.button.button-primary:hover,
-button.button-primary:hover,
-input[type="submit"].button-primary:hover,
-input[type="reset"].button-primary:hover,
-input[type="button"].button-primary:hover,
-.button.button-primary:focus,
-button.button-primary:focus,
-input[type="submit"].button-primary:focus,
-input[type="reset"].button-primary:focus,
-input[type="button"].button-primary:focus {
- color: #FFF;
- background-color: #1EAEDB;
- border-color: #1EAEDB; }
-
-
-/* Forms
-–––––––––––––––––––––––––––––––––––––––––––––––––– */
-input[type="email"],
-input[type="number"],
-input[type="search"],
-input[type="text"],
-input[type="tel"],
-input[type="url"],
-input[type="password"],
-textarea,
-select {
- height: 38px;
- padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
- background-color: #fff;
- border: 1px solid #D1D1D1;
- border-radius: 4px;
- box-shadow: none;
- box-sizing: border-box; }
-/* Removes awkward default styles on some inputs for iOS */
-input[type="email"],
-input[type="number"],
-input[type="search"],
-input[type="text"],
-input[type="tel"],
-input[type="url"],
-input[type="password"],
-textarea {
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none; }
-textarea {
- min-height: 65px;
- padding-top: 6px;
- padding-bottom: 6px; }
-input[type="email"]:focus,
-input[type="number"]:focus,
-input[type="search"]:focus,
-input[type="text"]:focus,
-input[type="tel"]:focus,
-input[type="url"]:focus,
-input[type="password"]:focus,
-textarea:focus,
-select:focus {
- border: 1px solid #33C3F0;
- outline: 0; }
-label,
-legend {
- display: block;
- margin-bottom: .5rem;
- font-weight: 600; }
-fieldset {
- padding: 0;
- border-width: 0; }
-input[type="checkbox"],
-input[type="radio"] {
- display: inline; }
-label > .label-body {
- display: inline-block;
- margin-left: .5rem;
- font-weight: normal; }
-
-
-/* Lists
-–––––––––––––––––––––––––––––––––––––––––––––––––– */
-ul {
- list-style: circle inside; }
-ol {
- list-style: decimal inside; }
-ol, ul {
- padding-left: 0;
- margin-top: 0; }
-ul ul,
-ul ol,
-ol ol,
-ol ul {
- margin: 1.5rem 0 1.5rem 3rem;
- font-size: 90%; }
-li {
- margin-bottom: 1rem; }
-
-
-/* Code
-–––––––––––––––––––––––––––––––––––––––––––––––––– */
-code {
- padding: .2rem .5rem;
- margin: 0 .2rem;
- font-size: 90%;
- white-space: nowrap;
- background: #F1F1F1;
- border: 1px solid #E1E1E1;
- border-radius: 4px; }
-pre > code {
- display: block;
- padding: 1rem 1.5rem;
- white-space: pre; }
-
-
-/* Tables
-–––––––––––––––––––––––––––––––––––––––––––––––––– */
-th,
-td {
- padding: 12px 15px;
- text-align: left;
- border-bottom: 1px solid #E1E1E1; }
-th:first-child,
-td:first-child {
- padding-left: 0; }
-th:last-child,
-td:last-child {
- padding-right: 0; }
-
-
-/* Spacing
-–––––––––––––––––––––––––––––––––––––––––––––––––– */
-button,
-.button {
- margin-bottom: 1rem; }
-input,
-textarea,
-select,
-fieldset {
- margin-bottom: 1.5rem; }
-pre,
-blockquote,
-dl,
-figure,
-table,
-p,
-ul,
-ol,
-form {
- margin-bottom: 2.5rem; }
-
-
-/* Utilities
-–––––––––––––––––––––––––––––––––––––––––––––––––– */
-.u-full-width {
- width: 100%;
- box-sizing: border-box; }
-.u-max-full-width {
- max-width: 100%;
- box-sizing: border-box; }
-.u-pull-right {
- float: right; }
-.u-pull-left {
- float: left; }
-
-
-/* Misc
-–––––––––––––––––––––––––––––––––––––––––––––––––– */
-hr {
- margin-top: 3rem;
- margin-bottom: 3.5rem;
- border-width: 0;
- border-top: 1px solid #E1E1E1; }
-
-
-/* Clearing
-–––––––––––––––––––––––––––––––––––––––––––––––––– */
-
-/* Self Clearing Goodness */
-.container:after,
-.row:after,
-.u-cf {
- content: "";
- display: table;
- clear: both; }
-
-
-/* Media Queries
-–––––––––––––––––––––––––––––––––––––––––––––––––– */
-/*
-Note: The best way to structure the use of media queries is to create the queries
-near the relevant code. For example, if you wanted to change the styles for buttons
-on small devices, paste the mobile query code up in the buttons section and style it
-there.
-*/
-
-
-/* Larger than mobile */
-@media (min-width: 400px) {}
-
-/* Larger than phablet (also point when grid becomes active) */
-@media (min-width: 550px) {}
-
-/* Larger than tablet */
-@media (min-width: 750px) {}
-
-/* Larger than desktop */
-@media (min-width: 1000px) {}
-
-/* Larger than Desktop HD */
-@media (min-width: 1200px) {}
diff --git a/examples/docker/web/public/index.html b/examples/docker/web/public/index.html
deleted file mode 100644
index 62f89dd..0000000
--- a/examples/docker/web/public/index.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-
- <meta charset="utf-8">
- <title>Ponzu Docker Example</title>
-
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link href="//fonts.googleapis.com/css?family=Raleway:400,300,600" rel="stylesheet" type="text/css">
- <link rel="stylesheet" href="/css/normalize.css">
- <link rel="stylesheet" href="/css/skeleton.css">
- <link rel="stylesheet" href="/css/main.css">
- <script src="/js/main.js"></script>
-</head>
-<body>
-
- <!-- Primary Page Layout
- –––––––––––––––––––––––––––––––––––––––––––––––––– -->
- <main class="container">
- <div class="row">
- <div class="one-half column">
- <h1>Ponzu Docker Example</h1>
- <p>The reviews are being served from the Ponzu admin. See this <a href="https://github.com/ponzu-cms/ponzu/tree/master/examples/docker">example project on github</a>.<p>
- <section id='main'>
- loading
- </section>
- </div>
- </div>
- </main>
-
-<!-- End Document
- –––––––––––––––––––––––––––––––––––––––––––––––––– -->
-</body>
-</html>
diff --git a/examples/docker/web/public/js/main.js b/examples/docker/web/public/js/main.js
deleted file mode 100644
index f9ae5fc..0000000
--- a/examples/docker/web/public/js/main.js
+++ /dev/null
@@ -1,43 +0,0 @@
-(function() {
-
- function loadHomepage() {
- const xhr = new XMLHttpRequest();
- xhr.open('GET', '/api/contents?type=Song');
- xhr.onreadystatechange = renderHomepage;
- xhr.send(null);
- }
-
- function renderHomepage(event) {
- const DONE = 4;
- const OK = 200;
- let xhr = event.currentTarget;
- let html = '';
-
- if (xhr.readyState === DONE) {
- if (xhr.status === OK) {
- const songs = window.JSON.parse(xhr.responseText).data;
- console.log(songs);
- if(songs.length === 0){
- html = '<p><strong>There have not been any Songs added, <a href="/admin">go add some at /admin</a></strong></p>';
- } else {
- html = songs.map(function(song) {
- return `
- <article>
- <h3>${song.title || 'Unknown'} by ${song.artist || 'Unknown'}</h3>
- <p>rating: ${song.rating}</p>
- <h6>opinion:</h6>
- <div>${song.opinion || 'none'}
- </article>
- `;
- }).join();
- }
- } else {
- html = '<p><strong>The /api endpoint did not respond correctly :-(</strong></p>';
- }
-
- document.querySelector('#main').innerHTML = html;
- }
- }
-
- document.addEventListener("DOMContentLoaded", loadHomepage);
-})(); \ No newline at end of file