Browse Source

依赖更新为 go mod

lijian 1 year ago
parent
commit
48c2e0e9f9
100 changed files with 15108 additions and 5150 deletions
  1. BIN
      .DS_Store
  2. 157 0
      go.mod
  3. 668 0
      go.sum
  4. 2 2
      pkg/online/online.go
  5. 4 5
      pkg/ruleEngine/nodes/mqtt_broker_node.go
  6. 1 1
      pkg/server/log.go
  7. 1 2
      pkg/server/server.go
  8. 2 3
      pkg/server/server_manager.go
  9. 9 9
      pkg/tlv/tlv_test.go
  10. BIN
      services/.DS_Store
  11. 244 0
      services/emqx-agent/main.go
  12. 3455 0
      services/emqx-agent/protobuf/exhook.pb.go
  13. 499 0
      services/emqx-agent/protobuf/exhook.proto
  14. 868 0
      services/emqx-agent/protobuf/exhook_grpc.pb.go
  15. 9 9
      tests/device/device.go
  16. BIN
      vendor/.DS_Store
  17. 0 69
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/CONTRIBUTING.md
  18. 0 15
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/DISTRIBUTION
  19. 0 87
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/LICENSE
  20. 0 62
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/README.md
  21. 0 41
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/about.html
  22. 0 521
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/client.go
  23. 0 31
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/components.go
  24. 0 70
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/epl-v10
  25. 0 258
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/filestore.go
  26. 0 119
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/memstore.go
  27. 0 104
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/message.go
  28. 0 61
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/messageids.go
  29. 0 275
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/net.go
  30. 0 108
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/notice.html
  31. 0 27
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/oops.go
  32. 0 270
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/options.go
  33. 0 57
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/connack.go
  34. 0 128
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/connect.go
  35. 0 44
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/disconnect.go
  36. 0 324
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/packets.go
  37. 0 44
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/pingreq.go
  38. 0 44
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/pingresp.go
  39. 0 50
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/puback.go
  40. 0 50
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/pubcomp.go
  41. 0 82
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/publish.go
  42. 0 50
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/pubrec.go
  43. 0 50
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/pubrel.go
  44. 0 58
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/suback.go
  45. 0 68
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/subscribe.go
  46. 0 50
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/unsuback.go
  47. 0 61
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/unsubscribe.go
  48. 0 73
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/ping.go
  49. 0 162
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/router.go
  50. 0 125
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/store.go
  51. 0 156
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/token.go
  52. 0 82
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/topic.go
  53. 0 36
      vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/trace.go
  54. BIN
      vendor/github.com/.DS_Store
  55. 2 0
      vendor/github.com/BurntSushi/toml/.gitignore
  56. 0 3
      vendor/github.com/BurntSushi/toml/COMPATIBLE
  57. 21 14
      vendor/github.com/BurntSushi/toml/COPYING
  58. 0 19
      vendor/github.com/BurntSushi/toml/Makefile
  59. 120 0
      vendor/github.com/BurntSushi/toml/README.md
  60. 299 206
      vendor/github.com/BurntSushi/toml/decode.go
  61. 19 0
      vendor/github.com/BurntSushi/toml/decode_go116.go
  62. 0 121
      vendor/github.com/BurntSushi/toml/decode_meta.go
  63. 29 0
      vendor/github.com/BurntSushi/toml/deprecated.go
  64. 10 26
      vendor/github.com/BurntSushi/toml/doc.go
  65. 406 215
      vendor/github.com/BurntSushi/toml/encode.go
  66. 0 19
      vendor/github.com/BurntSushi/toml/encoding_types.go
  67. 0 18
      vendor/github.com/BurntSushi/toml/encoding_types_1.1.go
  68. 279 0
      vendor/github.com/BurntSushi/toml/error.go
  69. 36 0
      vendor/github.com/BurntSushi/toml/internal/tz.go
  70. 527 224
      vendor/github.com/BurntSushi/toml/lex.go
  71. 121 0
      vendor/github.com/BurntSushi/toml/meta.go
  72. 467 248
      vendor/github.com/BurntSushi/toml/parse.go
  73. 0 1
      vendor/github.com/BurntSushi/toml/session.vim
  74. 0 91
      vendor/github.com/BurntSushi/toml/type_check.go
  75. 2 2
      vendor/github.com/BurntSushi/toml/type_fields.go
  76. 70 0
      vendor/github.com/BurntSushi/toml/type_toml.go
  77. 21 0
      vendor/github.com/CloudyKit/fastprinter/LICENSE
  78. 2 0
      vendor/github.com/CloudyKit/fastprinter/README.md
  79. 369 0
      vendor/github.com/CloudyKit/fastprinter/decimal.go
  80. 668 0
      vendor/github.com/CloudyKit/fastprinter/extfloat.go
  81. 278 0
      vendor/github.com/CloudyKit/fastprinter/float.go
  82. 225 0
      vendor/github.com/CloudyKit/fastprinter/printers.go
  83. 2 0
      vendor/github.com/CloudyKit/jet/v4/.gitignore
  84. 8 0
      vendor/github.com/CloudyKit/jet/v4/.travis.yml
  85. 0 0
      vendor/github.com/CloudyKit/jet/v4/LICENSE
  86. 46 0
      vendor/github.com/CloudyKit/jet/v4/README.md
  87. 34 0
      vendor/github.com/CloudyKit/jet/v4/appveyor.yml
  88. 240 0
      vendor/github.com/CloudyKit/jet/v4/constructors.go
  89. 204 0
      vendor/github.com/CloudyKit/jet/v4/default.go
  90. 1581 0
      vendor/github.com/CloudyKit/jet/v4/eval.go
  91. 160 0
      vendor/github.com/CloudyKit/jet/v4/func.go
  92. 684 0
      vendor/github.com/CloudyKit/jet/v4/lex.go
  93. 60 0
      vendor/github.com/CloudyKit/jet/v4/loader.go
  94. 695 0
      vendor/github.com/CloudyKit/jet/v4/node.go
  95. 1004 0
      vendor/github.com/CloudyKit/jet/v4/parse.go
  96. 8 0
      vendor/github.com/CloudyKit/jet/v4/profile.sh
  97. 152 0
      vendor/github.com/CloudyKit/jet/v4/ranger.go
  98. 11 0
      vendor/github.com/CloudyKit/jet/v4/stress.bash
  99. 327 0
      vendor/github.com/CloudyKit/jet/v4/template.go
  100. 2 0
      vendor/github.com/CloudyKit/jet/v6/.gitignore

BIN
.DS_Store


+ 157 - 0
go.mod

@@ -0,0 +1,157 @@
+module sparrow
+
+go 1.21.4
+
+require (
+	github.com/dgrijalva/jwt-go v3.2.0+incompatible
+	github.com/eclipse/paho.mqtt.golang v1.4.3
+	github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab
+	github.com/go-sql-driver/mysql v1.7.1
+	github.com/gogf/gf v1.16.9
+	github.com/influxdata/influxdb-client-go/v2 v2.13.0
+	github.com/iris-contrib/middleware/cors v0.0.0-20231105204038-60b21ca77167
+	github.com/iris-contrib/middleware/jwt v0.0.0-20231105204038-60b21ca77167
+	github.com/jinzhu/gorm v1.9.16
+	github.com/kataras/iris v0.0.2
+	github.com/martini-contrib/binding v0.0.0-20160701174519-05d3e151b6cf
+	github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11
+	github.com/opentracing/opentracing-go v1.2.0
+	github.com/prometheus/client_golang v1.18.0
+	github.com/robertkrimen/otto v0.3.0
+	github.com/robfig/cron v1.2.0
+	github.com/satori/go.uuid v1.2.0
+	github.com/segmentio/kafka-go v0.4.47
+	github.com/sirupsen/logrus v1.9.3
+	github.com/streadway/amqp v1.1.0
+	github.com/stretchr/testify v1.8.4
+	github.com/uber/jaeger-client-go v2.30.0+incompatible
+	go.etcd.io/etcd/client/v3 v3.5.11
+	golang.org/x/net v0.19.0
+	golang.org/x/time v0.5.0
+	google.golang.org/grpc v1.60.1
+	google.golang.org/protobuf v1.32.0
+	labix.org/v2/mgo v0.0.0-20140701140051-000000000287
+)
+
+require (
+	github.com/BurntSushi/toml v1.3.2 // indirect
+	github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 // indirect
+	github.com/CloudyKit/jet/v4 v4.1.0 // indirect
+	github.com/CloudyKit/jet/v6 v6.2.0 // indirect
+	github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
+	github.com/Joker/jade v1.1.3 // indirect
+	github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect
+	github.com/ajg/form v1.5.1 // indirect
+	github.com/andybalholm/brotli v1.0.6 // indirect
+	github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
+	github.com/aymerick/douceur v0.2.0 // indirect
+	github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible // indirect
+	github.com/beorn7/perks v1.0.1 // indirect
+	github.com/cespare/xxhash/v2 v2.2.0 // indirect
+	github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 // indirect
+	github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect
+	github.com/coreos/go-semver v0.3.0 // indirect
+	github.com/coreos/go-systemd/v22 v22.3.2 // indirect
+	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 // indirect
+	github.com/fatih/color v1.15.0 // indirect
+	github.com/fatih/structs v1.1.0 // indirect
+	github.com/flosch/pongo2/v4 v4.0.2 // indirect
+	github.com/fsnotify/fsnotify v1.7.0 // indirect
+	github.com/gobwas/glob v0.2.3 // indirect
+	github.com/gobwas/httphead v0.1.0 // indirect
+	github.com/gobwas/pool v0.2.1 // indirect
+	github.com/gobwas/ws v1.3.0 // indirect
+	github.com/gogo/protobuf v1.3.2 // indirect
+	github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
+	github.com/golang/protobuf v1.5.3 // indirect
+	github.com/golang/snappy v0.0.4 // indirect
+	github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 // indirect
+	github.com/gomodule/redigo v1.8.5 // indirect
+	github.com/google/go-querystring v1.1.0 // indirect
+	github.com/google/uuid v1.4.0 // indirect
+	github.com/gorilla/css v1.0.0 // indirect
+	github.com/gorilla/websocket v1.5.0 // indirect
+	github.com/grokify/html-strip-tags-go v0.0.1 // indirect
+	github.com/hashicorp/go-version v1.2.1 // indirect
+	github.com/imkira/go-interpol v1.1.0 // indirect
+	github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
+	github.com/iris-contrib/go.uuid v2.0.0+incompatible // indirect
+	github.com/iris-contrib/httpexpect/v2 v2.15.2 // indirect
+	github.com/iris-contrib/jade v1.1.4 // indirect
+	github.com/iris-contrib/pongo2 v0.0.1 // indirect
+	github.com/iris-contrib/schema v0.0.6 // indirect
+	github.com/jinzhu/inflection v1.0.0 // indirect
+	github.com/josharian/intern v1.0.0 // indirect
+	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/kataras/blocks v0.0.8 // indirect
+	github.com/kataras/golog v0.1.11 // indirect
+	github.com/kataras/iris/v12 v12.2.8 // indirect
+	github.com/kataras/neffos v0.0.22 // indirect
+	github.com/kataras/pio v0.0.13 // indirect
+	github.com/kataras/sitemap v0.0.6 // indirect
+	github.com/kataras/tunnel v0.0.4 // indirect
+	github.com/klauspost/compress v1.17.2 // indirect
+	github.com/mailgun/raymond/v2 v2.0.48 // indirect
+	github.com/mailru/easyjson v0.7.7 // indirect
+	github.com/mattn/go-colorable v0.1.13 // indirect
+	github.com/mattn/go-isatty v0.0.19 // indirect
+	github.com/mattn/go-runewidth v0.0.9 // indirect
+	github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
+	github.com/mediocregopher/radix/v3 v3.8.1 // indirect
+	github.com/microcosm-cc/bluemonday v1.0.26 // indirect
+	github.com/mitchellh/go-wordwrap v1.0.1 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/nats-io/nats.go v1.28.0 // indirect
+	github.com/nats-io/nkeys v0.4.6 // indirect
+	github.com/nats-io/nuid v1.0.1 // indirect
+	github.com/oapi-codegen/runtime v1.0.0 // indirect
+	github.com/olekukonko/tablewriter v0.0.5 // indirect
+	github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
+	github.com/pierrec/lz4/v4 v4.1.15 // indirect
+	github.com/pkg/errors v0.8.1 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/prometheus/client_model v0.5.0 // indirect
+	github.com/prometheus/common v0.45.0 // indirect
+	github.com/prometheus/procfs v0.12.0 // indirect
+	github.com/russross/blackfriday/v2 v2.1.0 // indirect
+	github.com/ryanuber/columnize v2.1.0+incompatible // indirect
+	github.com/sanity-io/litter v1.5.5 // indirect
+	github.com/schollz/closestmatch v2.1.0+incompatible // indirect
+	github.com/sergi/go-diff v1.1.0 // indirect
+	github.com/tdewolff/minify/v2 v2.20.6 // indirect
+	github.com/tdewolff/parse/v2 v2.7.4 // indirect
+	github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
+	github.com/valyala/bytebufferpool v1.0.0 // indirect
+	github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
+	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
+	github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
+	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
+	github.com/xeipuuv/gojsonschema v1.2.0 // indirect
+	github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 // indirect
+	github.com/yosssi/ace v0.0.5 // indirect
+	github.com/yudai/gojsondiff v1.0.0 // indirect
+	github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
+	go.etcd.io/etcd/api/v3 v3.5.11 // indirect
+	go.etcd.io/etcd/client/pkg/v3 v3.5.11 // indirect
+	go.opentelemetry.io/otel v1.0.0 // indirect
+	go.opentelemetry.io/otel/trace v1.0.0 // indirect
+	go.uber.org/atomic v1.7.0 // indirect
+	go.uber.org/multierr v1.6.0 // indirect
+	go.uber.org/zap v1.17.0 // indirect
+	golang.org/x/crypto v0.16.0 // indirect
+	golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
+	golang.org/x/sync v0.4.0 // indirect
+	golang.org/x/sys v0.15.0 // indirect
+	golang.org/x/text v0.14.0 // indirect
+	golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
+	google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect
+	gopkg.in/ini.v1 v1.67.0 // indirect
+	gopkg.in/sourcemap.v1 v1.0.5 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+	launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect
+	moul.io/http2curl/v2 v2.3.0 // indirect
+)

+ 668 - 0
go.sum

@@ -0,0 +1,668 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
+github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c=
+github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
+github.com/CloudyKit/jet/v4 v4.1.0 h1:EvZLdRZYZ6iljADEhrfWSCSNOJRDntNqEJJmeP0Sjg0=
+github.com/CloudyKit/jet/v4 v4.1.0/go.mod h1:DhUsGNEpjPmBD0zmGNP8DaSV1dGO8g9U4adIK8BCWmw=
+github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME=
+github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4=
+github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
+github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
+github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
+github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc=
+github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
+github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk=
+github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
+github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
+github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
+github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0=
+github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM=
+github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
+github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
+github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
+github.com/andybalholm/brotli v1.0.1-0.20200619015827-c3da72aa01ed/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
+github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
+github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
+github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
+github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
+github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
+github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
+github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible h1:Ppm0npCCsmuR9oQaBtRuZcmILVE74aXE+AmrJj8L2ns=
+github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE=
+github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 h1:LdXxtjzvZYhhUaonAaAKArG3pyC67kGL3YY+6hGG8G4=
+github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
+github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
+github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
+github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
+github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM=
+github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik=
+github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
+github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
+github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
+github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
+github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
+github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
+github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
+github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
+github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
+github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw=
+github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8=
+github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI=
+github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk=
+github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
+github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
+github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
+github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
+github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
+github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
+github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
+github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
+github.com/gobwas/ws v1.0.3/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
+github.com/gobwas/ws v1.3.0 h1:sbeU3Y4Qzlb+MOzIe6mQGf7QR4Hkv6ZD0qhGkBFL2O0=
+github.com/gobwas/ws v1.3.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogf/gf v1.16.9 h1:Q803UmmRo59+Ws08sMVFOcd8oNpkSWL9vS33hlo/Cyk=
+github.com/gogf/gf v1.16.9/go.mod h1:8Q/kw05nlVRp+4vv7XASBsMe9L1tsVKiGoeP2AHnlkk=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
+github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
+github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 h1:EcQR3gusLHN46TAD+G+EbaaqJArt5vHhNpXAa12PQf4=
+github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
+github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
+github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc=
+github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/uuid v1.1.2-0.20200519141726-cb32006e483f/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
+github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
+github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
+github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
+github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
+github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
+github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/influxdata/influxdb-client-go/v2 v2.13.0 h1:ioBbLmR5NMbAjP4UVA5r9b5xGjpABD7j65pI8kFphDM=
+github.com/influxdata/influxdb-client-go/v2 v2.13.0/go.mod h1:k+spCbt9hcvqvUiz0sr5D8LolXHqAAOfPw9v/RIRHl4=
+github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
+github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
+github.com/iris-contrib/go.uuid v2.0.0+incompatible h1:XZubAYg61/JwnJNbZilGjf3b3pB80+OQg2qf6c8BfWE=
+github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
+github.com/iris-contrib/httpexpect/v2 v2.0.5/go.mod h1:JpRu+DEVVCA6KHLKUAs72QoaevQESqLHuG5s1CQ+QiA=
+github.com/iris-contrib/httpexpect/v2 v2.15.2 h1:T9THsdP1woyAqKHwjkEsbCnMefsAFvk8iJJKokcJ3Go=
+github.com/iris-contrib/httpexpect/v2 v2.15.2/go.mod h1:JLDgIqnFy5loDSUv1OA2j0mb6p/rDhiCqigP22Uq9xE=
+github.com/iris-contrib/jade v1.1.4 h1:WoYdfyJFfZIUgqNAeOyRfTNQZOksSlZ6+FnXR3AEpX0=
+github.com/iris-contrib/jade v1.1.4/go.mod h1:EDqR+ur9piDl6DUgs6qRrlfzmlx/D5UybogqrXvJTBE=
+github.com/iris-contrib/middleware/cors v0.0.0-20231105204038-60b21ca77167 h1:zs9HA+Jn+NsbXTH6tER40sFDcnaFUtBljj5YAnwUfk4=
+github.com/iris-contrib/middleware/cors v0.0.0-20231105204038-60b21ca77167/go.mod h1:D/Xr6gLnI2E5jZJ6FC6pLiF1inXUWqnft6DibmTUuBo=
+github.com/iris-contrib/middleware/jwt v0.0.0-20231105204038-60b21ca77167 h1:x2POmaLt4fmAoO8ZvxrqLPRDtB7ZUiR5LC9ftNY8JYc=
+github.com/iris-contrib/middleware/jwt v0.0.0-20231105204038-60b21ca77167/go.mod h1:txkPY4oCyoRH302p0mx6IsAupinDtULtZ84V7L4dN+A=
+github.com/iris-contrib/pongo2 v0.0.1 h1:zGP7pW51oi5eQZMIlGA3I+FHY9/HOQWDB+572yin0to=
+github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
+github.com/iris-contrib/schema v0.0.2/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA=
+github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw=
+github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA=
+github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
+github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
+github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
+github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
+github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
+github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
+github.com/kataras/blocks v0.0.2/go.mod h1:KPyOYc1M3MgzsznVcdjErtcYWO3AZXQbQ8fMYWcr3oA=
+github.com/kataras/blocks v0.0.8 h1:MrpVhoFTCR2v1iOOfGng5VJSILKeZZI+7NGfxEh3SUM=
+github.com/kataras/blocks v0.0.8/go.mod h1:9Jm5zx6BB+06NwA+OhTbHW1xkMOYxahnqTN5DveZ2Yg=
+github.com/kataras/golog v0.0.18/go.mod h1:jRYl7dFYqP8aQj9VkwdBUXYZSfUktm+YYg1arJILfyw=
+github.com/kataras/golog v0.1.11 h1:dGkcCVsIpqiAMWTlebn/ZULHxFvfG4K43LF1cNWSh20=
+github.com/kataras/golog v0.1.11/go.mod h1:mAkt1vbPowFUuUGvexyQ5NFW6djEgGyxQBIARJ0AH4A=
+github.com/kataras/iris v0.0.2 h1:Tteb6pXLN9QiXvTCXCP31LRHu1LHlVA6Rappr9vWa1c=
+github.com/kataras/iris v0.0.2/go.mod h1:ab8yy1jWHFgoI+/B+zoIsQpVY/XUY+NNvVCXJ27Zat8=
+github.com/kataras/iris/v12 v12.2.8 h1:p+PcqyO45dSib8B4I8Wc0fz+6B/CVkOsikCpbeNOkuo=
+github.com/kataras/iris/v12 v12.2.8/go.mod h1:on94BX0C5jhuxgWKDZVpcTqymksZDIxWFN+nL7axjRA=
+github.com/kataras/neffos v0.0.16/go.mod h1:BqWkF1c6cSyqw85dfCdqXxK5cMo/hyBGhtNuFkxHyMg=
+github.com/kataras/neffos v0.0.22 h1:3M4lHrUl//2OKmS9t9z3AKIZqwha6ABeA6WoF03HEv8=
+github.com/kataras/neffos v0.0.22/go.mod h1:IIJZcUDvwBxJGlDj942dqQgyznVKYDti91f8Ez+RRxE=
+github.com/kataras/pio v0.0.8/go.mod h1:NFfMp2kVP1rmV4N6gH6qgWpuoDKlrOeYi3VrAIWCGsE=
+github.com/kataras/pio v0.0.13 h1:x0rXVX0fviDTXOOLOmr4MUxOabu1InVSTu5itF8CXCM=
+github.com/kataras/pio v0.0.13/go.mod h1:k3HNuSw+eJ8Pm2lA4lRhg3DiCjVgHlP8hmXApSej3oM=
+github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
+github.com/kataras/sitemap v0.0.6 h1:w71CRMMKYMJh6LR2wTgnk5hSgjVNB9KL60n5e2KHvLY=
+github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4=
+github.com/kataras/tunnel v0.0.1/go.mod h1:Gslr6f+Y0esb704OqMi8hNOfFImgXcmg4KiN2zScgvs=
+github.com/kataras/tunnel v0.0.4 h1:sCAqWuJV7nPzGrlb0os3j49lk2JhILT0rID38NHNLpA=
+github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
+github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
+github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
+github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw=
+github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/martini-contrib/binding v0.0.0-20160701174519-05d3e151b6cf h1:6YSkbjZVghliN7zwJC/U3QQG+OVXOrij3qQ8sxfPIMg=
+github.com/martini-contrib/binding v0.0.0-20160701174519-05d3e151b6cf/go.mod h1:aCggxkm1kuifLw/LEQUbz91N1ZM6PhV7dz03xPQduZA=
+github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11 h1:YFh+sjyJTMQSYjKwM4dFKhJPJC/wfo98tPUc17HdoYw=
+github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11/go.mod h1:Ah2dBMoxZEqk118as2T4u4fjfXarE0pPnMJaArZQZsI=
+github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
+github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
+github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
+github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
+github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
+github.com/mediocregopher/radix/v3 v3.5.0/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
+github.com/mediocregopher/radix/v3 v3.5.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
+github.com/mediocregopher/radix/v3 v3.8.1 h1:rOkHflVuulFKlwsLY01/M2cM2tWCjDoETcMqKbAWu1M=
+github.com/mediocregopher/radix/v3 v3.8.1/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
+github.com/microcosm-cc/bluemonday v1.0.3/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
+github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
+github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
+github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
+github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
+github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI=
+github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
+github.com/nats-io/jwt/v2 v2.5.3 h1:/9SWvzc6hTfamcgXJ3uYRpgj+QuY2aLNqRiqrKcrpEo=
+github.com/nats-io/jwt/v2 v2.5.3/go.mod h1:iysuPemFcc7p4IoYots3IuELSI4EDe9Y0bQMe+I3Bf4=
+github.com/nats-io/nats-server/v2 v2.9.11 h1:4y5SwWvWI59V5mcqtuoqKq6L9NDUydOP3Ekwuwl8cZI=
+github.com/nats-io/nats-server/v2 v2.9.11/go.mod h1:b0oVuxSlkvS3ZjMkncFeACGyZohbO4XhSqW1Lt7iRRY=
+github.com/nats-io/nats.go v1.9.2/go.mod h1:AjGArbfyR50+afOUotNX2Xs5SYHf+CoOa5HH1eEl2HE=
+github.com/nats-io/nats.go v1.28.0 h1:Th4G6zdsz2d0OqXdfzKLClo6bOfoI/b1kInhRtFIy5c=
+github.com/nats-io/nats.go v1.28.0/go.mod h1:XpbWUlOElGwTYbMR7imivs7jJj9GtK7ypv321Wp6pjc=
+github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nkeys v0.1.4/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s=
+github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY=
+github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts=
+github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
+github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
+github.com/oapi-codegen/runtime v1.0.0 h1:P4rqFX5fMFWqRzY9M/3YF9+aPSPPB06IzP2P7oOxrWo=
+github.com/oapi-codegen/runtime v1.0.0/go.mod h1:LmCUMQuPB4M/nLXilQXhHw+BLZdDb18B34OO356yJ/A=
+github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
+github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
+github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
+github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
+github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
+github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
+github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
+github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
+github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
+github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
+github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
+github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
+github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
+github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
+github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
+github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
+github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
+github.com/robertkrimen/otto v0.3.0 h1:5RI+8860NSxvXywDY9ddF5HcPw0puRsd8EgbXV0oqRE=
+github.com/robertkrimen/otto v0.3.0/go.mod h1:uW9yN1CYflmUQYvAMS0m+ZiNo3dMzRUDQJX0jWbzgxw=
+github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
+github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s=
+github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
+github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
+github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
+github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
+github.com/segmentio/kafka-go v0.4.47 h1:IqziR4pA3vrZq7YdRxaT3w1/5fvIH5qpCwstUanQQB0=
+github.com/segmentio/kafka-go v0.4.47/go.mod h1:HjF6XbOKh0Pjlkr5GVZxt6CsjjwnmhVOfURM5KMd8qg=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
+github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
+github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693/go.mod h1:6hSY48PjDm4UObWmGLyJE9DxYVKTgR9kbCspXXJEhcU=
+github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM=
+github.com/streadway/amqp v1.1.0/go.mod h1:WYSrTEYHOXHd0nwFeUXAe2G2hRnQT+deZJJf88uS9Bg=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8=
+github.com/tdewolff/minify/v2 v2.20.6 h1:R4+Iw1ZqJxrqH52WWHtCpukMuhmO/EasY8YlDiSxphw=
+github.com/tdewolff/minify/v2 v2.20.6/go.mod h1:9t0EY9xySGt1vrP8iscmJfywQwDCQyQBYN6ge+9GwP0=
+github.com/tdewolff/parse/v2 v2.7.4 h1:zrUn2CFg9+5llbUZcsycctFlNRyV1D5gFBZRxuGzdzk=
+github.com/tdewolff/parse/v2 v2.7.4/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
+github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52 h1:gAQliwn+zJrkjAHVcBEYW/RFvd2St4yYimisvozAYlA=
+github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
+github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
+github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
+github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
+github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/vmihailenco/msgpack/v4 v4.3.11/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
+github.com/vmihailenco/msgpack/v5 v5.0.0-beta.1/go.mod h1:xlngVLeyQ/Qi05oQxhQ+oTuqa03RjMwMfk/7/TCs+QI=
+github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
+github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
+github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
+github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
+github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
+github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
+github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
+github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
+github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
+github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
+github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=
+github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
+github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
+github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
+github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
+github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
+github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI=
+github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.etcd.io/etcd/api/v3 v3.5.11 h1:B54KwXbWDHyD3XYAwprxNzTe7vlhR69LuBgZnMVvS7E=
+go.etcd.io/etcd/api/v3 v3.5.11/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4=
+go.etcd.io/etcd/client/pkg/v3 v3.5.11 h1:bT2xVspdiCj2910T0V+/KHcVKjkUrCZVtk8J2JF2z1A=
+go.etcd.io/etcd/client/pkg/v3 v3.5.11/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4=
+go.etcd.io/etcd/client/v3 v3.5.11 h1:ajWtgoNSZJ1gmS8k+icvPtqsqEav+iUorF7b0qozgUU=
+go.etcd.io/etcd/client/v3 v3.5.11/go.mod h1:a6xQUEqFJ8vztO1agJh/KQKOMfFI8og52ZconzcDJwE=
+go.opentelemetry.io/otel v1.0.0 h1:qTTn6x71GVBvoafHK/yaRUmFzI4LcONZD0/kXxl5PHI=
+go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg=
+go.opentelemetry.io/otel/trace v1.0.0 h1:TSBr8GTEtKevYMG/2d21M989r5WJYVimhTHBKVEZuh4=
+go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs=
+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
+go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
+go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
+go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
+golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
+golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
+golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
+golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
+golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
+golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
+golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
+golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
+gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
+gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
+gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0=
+google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk=
+google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU=
+google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 h1:6GQBEOdGkX6MMTLT9V+TjtIRZCw9VPD5Z+yHY9wMgS0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
+google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
+google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
+gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
+gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+labix.org/v2/mgo v0.0.0-20140701140051-000000000287 h1:L0cnkNl4TfAXzvdrqsYEmxOHOCv2p5I3taaReO8BWFs=
+labix.org/v2/mgo v0.0.0-20140701140051-000000000287/go.mod h1:Lg7AYkt1uXJoR9oeSZ3W/8IXLdvOfIITgZnommstyz4=
+launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54=
+launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM=
+moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
+moul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs=
+moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

+ 2 - 2
pkg/online/online.go

@@ -21,12 +21,12 @@ type Manager struct {
 }
 
 func NewManager(host string, port, db int) *Manager {
-	gredis.SetConfig(gredis.Config{
+	gredis.SetConfig(&gredis.Config{
 		Host:      host,
 		Port:      port,
 		Db:        db,
 		MaxActive: 100,
-	})
+	}, "")
 	mgr := &Manager{
 		redisClient: gredis.Instance(),
 	}

+ 4 - 5
pkg/ruleEngine/nodes/mqtt_broker_node.go

@@ -3,7 +3,7 @@ package nodes
 import (
 	"encoding/json"
 	"fmt"
-	MQTT "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
+	MQTT "github.com/eclipse/paho.mqtt.golang"
 	"github.com/gogf/gf/util/guid"
 	"html/template"
 	"sparrow/pkg/protocol"
@@ -18,9 +18,9 @@ const defaultTimeout = 5
 
 // MQTTBrokerNode Publish incoming message payload to the topic of the configured MQTT broker with QoS AT_LEAST_ONCE.
 // In case of successful message publishing, original Message will be passed to the next nodes via Success chain,
-//otherwise Failure chain is used.
+// otherwise Failure chain is used.
 type MQTTBrokerNode struct {
-	mqttClient *MQTT.Client
+	mqttClient MQTT.Client
 	config     *MQTTBrokerNodeCfg
 }
 
@@ -71,7 +71,7 @@ func (M *MQTTBrokerNode) Init(ctx ruleEngine.Context, config string) error {
 	var opt MQTT.ClientOptions
 	opt.ClientID = "MQTT_NODE_" + guid.S()
 	opt.CleanSession = M.config.ClearSession
-	opt.KeepAlive = time.Second * 30
+	opt.KeepAlive = 30
 	opt.ConnectTimeout = time.Duration(M.config.Timeout) * time.Second
 	switch M.config.Credentials {
 	case "Basic":
@@ -88,7 +88,6 @@ func (M *MQTTBrokerNode) Init(ctx ruleEngine.Context, config string) error {
 	opt.AddBroker(fmt.Sprintf("tcp://%s:%d", M.config.Host, M.config.Port))
 	c := MQTT.NewClient(&opt)
 	M.mqttClient = c
-	fmt.Printf("M.mqttClient = c:%v\r\n", c)
 	go func() {
 		if token := c.Connect(); token.Wait() && token.Error() != nil {
 			return

+ 1 - 1
pkg/server/log.go

@@ -3,7 +3,7 @@
 package server
 
 import (
-	"github.com/Sirupsen/logrus"
+	"github.com/sirupsen/logrus"
 )
 
 var Log *logrus.Entry

+ 1 - 2
pkg/server/server.go

@@ -8,9 +8,8 @@ package server
 
 import (
 	"context"
-	"github.com/opentracing/opentracing-go"
-	// "github.com/vharitonsky/iniflags"
 	"flag"
+	"github.com/opentracing/opentracing-go"
 	"net/http"
 	"net/rpc"
 	"sparrow/pkg/tracing"

+ 2 - 3
pkg/server/server_manager.go

@@ -5,13 +5,12 @@ package server
 import (
 	"errors"
 	"fmt"
-	"go.etcd.io/etcd/clientv3"
+	clientv3 "go.etcd.io/etcd/client/v3"
+	"golang.org/x/net/context"
 	"os"
 	"strings"
 	"sync"
 	"time"
-
-	"golang.org/x/net/context"
 )
 
 const (

+ 9 - 9
pkg/tlv/tlv_test.go

@@ -70,15 +70,15 @@ func TestTlvLen(t *testing.T) {
 	}
 }
 
-func TestUintAndByte(t *testing.T) {
-	value := uint16(100)
-	byteValue := Uint16ToByte(value)
-	newValue := ByteToUint16(byteValue)
-
-	if value != newValue {
-		t.Errorf("origin: %d, now: %d\n", value, newValue)
-	}
-}
+//func TestUintAndByte(t *testing.T) {
+//	value := uint16(100)
+//	byteValue := Uint16ToByte(value)
+//	newValue := ByteToUint16(byteValue)
+//
+//	if value != newValue {
+//		t.Errorf("origin: %d, now: %d\n", value, newValue)
+//	}
+//}
 
 func TestTlvs(t *testing.T) {
 	str := "itachili"

BIN
services/.DS_Store


+ 244 - 0
services/emqx-agent/main.go

@@ -0,0 +1,244 @@
+package main
+
+import (
+	"context"
+	"log"
+	"math"
+	"sparrow/pkg/rpcs"
+	"sparrow/pkg/server"
+	"sync"
+	"time"
+
+	"google.golang.org/grpc"
+	pb "sparrow/services/emqx-agent/protobuf"
+)
+
+type Counter struct {
+	count    int64
+	start    int64
+	duration int64
+	maxCount int64
+	lock     sync.Mutex
+}
+
+func NewCounter(duration int64, maxCount int64) *Counter {
+	counter := &Counter{}
+	counter.count = 0
+	counter.start = time.Now().UnixNano() / 1e6 // 当前毫秒时间戳
+	if duration == 0 {
+		counter.duration = math.MaxInt64 // duration传0表示没有时间间隔限制,计数器不刷新
+	} else {
+		counter.duration = duration
+	}
+	counter.maxCount = maxCount
+	return counter
+}
+
+// Count 计数器计数
+// n: 计数值
+// refersh: 计数器是否刷新
+// limit: 是否达到计数最大值
+// num: 计数后计数器的值
+func (counter *Counter) Count(n int64) (refresh bool, limit bool, num int64) {
+	now := time.Now().UnixNano() / 1e6
+	counter.lock.Lock()
+	defer counter.lock.Unlock()
+
+	if now-counter.start < counter.duration {
+		counter.count += n
+		num = counter.count
+		limit = num > counter.maxCount
+	} else {
+		// num = counter.count  // 刷新前的最大计数
+		counter.start = now
+		counter.count = 0
+		refresh = true
+	}
+	return
+}
+
+func (counter *Counter) GetCount() (num int64) {
+	counter.lock.Lock()
+	defer counter.lock.Unlock()
+	return counter.count
+}
+
+const (
+	port = ":9000"
+)
+
+var cnter *Counter = NewCounter(0, 100)
+
+// emqttServer is used to implement emqx_exhook_v1.s *emqttServer
+type emqttServer struct {
+	pb.UnimplementedHookProviderServer
+}
+
+// HookProviderServer callbacks
+
+func (s *emqttServer) OnProviderLoaded(ctx context.Context, in *pb.ProviderLoadedRequest) (*pb.LoadedResponse, error) {
+	cnter.Count(1)
+	hooks := []*pb.HookSpec{
+		&pb.HookSpec{Name: "client.connect"},
+		&pb.HookSpec{Name: "client.connack"},
+		&pb.HookSpec{Name: "client.connected"},
+		&pb.HookSpec{Name: "client.disconnected"},
+		&pb.HookSpec{Name: "client.authenticate"},
+		&pb.HookSpec{Name: "client.authorize"},
+		&pb.HookSpec{Name: "client.subscribe"},
+		&pb.HookSpec{Name: "client.unsubscribe"},
+		&pb.HookSpec{Name: "session.created"},
+		&pb.HookSpec{Name: "session.subscribed"},
+		&pb.HookSpec{Name: "session.unsubscribed"},
+		&pb.HookSpec{Name: "session.resumed"},
+		&pb.HookSpec{Name: "session.discarded"},
+		&pb.HookSpec{Name: "session.takenover"},
+		&pb.HookSpec{Name: "session.terminated"},
+		&pb.HookSpec{Name: "message.publish"},
+		&pb.HookSpec{Name: "message.delivered"},
+		&pb.HookSpec{Name: "message.acked"},
+		&pb.HookSpec{Name: "message.dropped"},
+	}
+	return &pb.LoadedResponse{Hooks: hooks}, nil
+}
+
+func (s *emqttServer) OnProviderUnloaded(ctx context.Context, in *pb.ProviderUnloadedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnClientConnect(ctx context.Context, in *pb.ClientConnectRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnClientConnack(ctx context.Context, in *pb.ClientConnackRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnClientConnected(ctx context.Context, in *pb.ClientConnectedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnClientDisconnected(ctx context.Context, in *pb.ClientDisconnectedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnClientAuthenticate(ctx context.Context, in *pb.ClientAuthenticateRequest) (*pb.ValuedResponse, error) {
+	cnter.Count(1)
+	reply := &pb.ValuedResponse{}
+	reply.Type = pb.ValuedResponse_STOP_AND_RETURN
+	reply.Value = &pb.ValuedResponse_BoolResult{BoolResult: true}
+	return reply, nil
+}
+
+func (s *emqttServer) OnClientAuthorize(ctx context.Context, in *pb.ClientAuthorizeRequest) (*pb.ValuedResponse, error) {
+	cnter.Count(1)
+	reply := &pb.ValuedResponse{}
+	reply.Type = pb.ValuedResponse_STOP_AND_RETURN
+	reply.Value = &pb.ValuedResponse_BoolResult{BoolResult: true}
+	return reply, nil
+}
+
+func (s *emqttServer) OnClientSubscribe(ctx context.Context, in *pb.ClientSubscribeRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnClientUnsubscribe(ctx context.Context, in *pb.ClientUnsubscribeRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnSessionCreated(ctx context.Context, in *pb.SessionCreatedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+func (s *emqttServer) OnSessionSubscribed(ctx context.Context, in *pb.SessionSubscribedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnSessionUnsubscribed(ctx context.Context, in *pb.SessionUnsubscribedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnSessionResumed(ctx context.Context, in *pb.SessionResumedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnSessionDiscarded(ctx context.Context, in *pb.SessionDiscardedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnSessionTakenover(ctx context.Context, in *pb.SessionTakenoverRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnSessionTerminated(ctx context.Context, in *pb.SessionTerminatedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnMessagePublish(ctx context.Context, in *pb.MessagePublishRequest) (*pb.ValuedResponse, error) {
+	cnter.Count(1)
+	in.Message.Payload = []byte("hardcode payload by exhook-svr-go :)")
+	reply := &pb.ValuedResponse{}
+	reply.Type = pb.ValuedResponse_STOP_AND_RETURN
+	reply.Value = &pb.ValuedResponse_Message{Message: in.Message}
+	return reply, nil
+}
+
+//case2: stop publish the `t/d` messages
+//func (s *emqttServer) OnMessagePublish(ctx context.Context, in *pb.MessagePublishRequest) (*pb.ValuedResponse, error) {
+//	cnter.Count(1)
+//    if in.Message.Topic == "t/d" {
+//        in.Message.Headers["allow_publish"] = "false"
+//        in.Message.Payload = []byte("")
+//    }
+//	reply := &pb.ValuedResponse{}
+//	reply.Type = pb.ValuedResponse_STOP_AND_RETURN
+//	reply.Value = &pb.ValuedResponse_Message{Message: in.Message}
+//	return reply, nil
+//}
+
+func (s *emqttServer) OnMessageDelivered(ctx context.Context, in *pb.MessageDeliveredRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnMessageDropped(ctx context.Context, in *pb.MessageDroppedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnMessageAcked(ctx context.Context, in *pb.MessageAckedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func main() {
+
+	// init emqttServer
+	err := server.Init(rpcs.HttpAccessName)
+	if err != nil {
+		server.Log.Fatal(err)
+		return
+	}
+	s := grpc.NewServer()
+	pb.RegisterHookProviderServer(s, &emqttServer{})
+	log.Println("Started gRPC emqttServer on ::9000")
+	// register a http handler
+	err = server.RegisterHTTPHandler(s)
+	if err != nil {
+		server.Log.Errorf("RegisterHTTPHandler Error: %s", err)
+		return
+	}
+}

+ 3455 - 0
services/emqx-agent/protobuf/exhook.pb.go

@@ -0,0 +1,3455 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.32.0
+// 	protoc        v4.25.1
+// source: protobuf/exhook.proto
+
+// The exhook proto version should be fixed as `v2` in EMQX v5.x
+// to make sure the exhook proto version is compatible
+
+package exhook
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type ClientAuthorizeRequest_AuthorizeReqType int32
+
+const (
+	ClientAuthorizeRequest_PUBLISH   ClientAuthorizeRequest_AuthorizeReqType = 0
+	ClientAuthorizeRequest_SUBSCRIBE ClientAuthorizeRequest_AuthorizeReqType = 1
+)
+
+// Enum value maps for ClientAuthorizeRequest_AuthorizeReqType.
+var (
+	ClientAuthorizeRequest_AuthorizeReqType_name = map[int32]string{
+		0: "PUBLISH",
+		1: "SUBSCRIBE",
+	}
+	ClientAuthorizeRequest_AuthorizeReqType_value = map[string]int32{
+		"PUBLISH":   0,
+		"SUBSCRIBE": 1,
+	}
+)
+
+func (x ClientAuthorizeRequest_AuthorizeReqType) Enum() *ClientAuthorizeRequest_AuthorizeReqType {
+	p := new(ClientAuthorizeRequest_AuthorizeReqType)
+	*p = x
+	return p
+}
+
+func (x ClientAuthorizeRequest_AuthorizeReqType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ClientAuthorizeRequest_AuthorizeReqType) Descriptor() protoreflect.EnumDescriptor {
+	return file_protobuf_exhook_proto_enumTypes[0].Descriptor()
+}
+
+func (ClientAuthorizeRequest_AuthorizeReqType) Type() protoreflect.EnumType {
+	return &file_protobuf_exhook_proto_enumTypes[0]
+}
+
+func (x ClientAuthorizeRequest_AuthorizeReqType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use ClientAuthorizeRequest_AuthorizeReqType.Descriptor instead.
+func (ClientAuthorizeRequest_AuthorizeReqType) EnumDescriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{7, 0}
+}
+
+// The responded value type
+//  - contiune: Use the responded value and execute the next hook
+//  - ignore: Ignore the responded value
+//  - stop_and_return: Use the responded value and stop the chain executing
+type ValuedResponse_ResponsedType int32
+
+const (
+	ValuedResponse_CONTINUE        ValuedResponse_ResponsedType = 0
+	ValuedResponse_IGNORE          ValuedResponse_ResponsedType = 1
+	ValuedResponse_STOP_AND_RETURN ValuedResponse_ResponsedType = 2
+)
+
+// Enum value maps for ValuedResponse_ResponsedType.
+var (
+	ValuedResponse_ResponsedType_name = map[int32]string{
+		0: "CONTINUE",
+		1: "IGNORE",
+		2: "STOP_AND_RETURN",
+	}
+	ValuedResponse_ResponsedType_value = map[string]int32{
+		"CONTINUE":        0,
+		"IGNORE":          1,
+		"STOP_AND_RETURN": 2,
+	}
+)
+
+func (x ValuedResponse_ResponsedType) Enum() *ValuedResponse_ResponsedType {
+	p := new(ValuedResponse_ResponsedType)
+	*p = x
+	return p
+}
+
+func (x ValuedResponse_ResponsedType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ValuedResponse_ResponsedType) Descriptor() protoreflect.EnumDescriptor {
+	return file_protobuf_exhook_proto_enumTypes[1].Descriptor()
+}
+
+func (ValuedResponse_ResponsedType) Type() protoreflect.EnumType {
+	return &file_protobuf_exhook_proto_enumTypes[1]
+}
+
+func (x ValuedResponse_ResponsedType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use ValuedResponse_ResponsedType.Descriptor instead.
+func (ValuedResponse_ResponsedType) EnumDescriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{22, 0}
+}
+
+type ProviderLoadedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Broker *BrokerInfo  `protobuf:"bytes,1,opt,name=broker,proto3" json:"broker,omitempty"`
+	Meta   *RequestMeta `protobuf:"bytes,2,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ProviderLoadedRequest) Reset() {
+	*x = ProviderLoadedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ProviderLoadedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderLoadedRequest) ProtoMessage() {}
+
+func (x *ProviderLoadedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ProviderLoadedRequest.ProtoReflect.Descriptor instead.
+func (*ProviderLoadedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ProviderLoadedRequest) GetBroker() *BrokerInfo {
+	if x != nil {
+		return x.Broker
+	}
+	return nil
+}
+
+func (x *ProviderLoadedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ProviderUnloadedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ProviderUnloadedRequest) Reset() {
+	*x = ProviderUnloadedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ProviderUnloadedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderUnloadedRequest) ProtoMessage() {}
+
+func (x *ProviderUnloadedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ProviderUnloadedRequest.ProtoReflect.Descriptor instead.
+func (*ProviderUnloadedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ProviderUnloadedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientConnectRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Conninfo *ConnInfo `protobuf:"bytes,1,opt,name=conninfo,proto3" json:"conninfo,omitempty"`
+	// MQTT CONNECT packet's properties (MQTT v5.0)
+	//
+	// It should be empty on MQTT v3.1.1/v3.1 or others protocol
+	Props []*Property  `protobuf:"bytes,2,rep,name=props,proto3" json:"props,omitempty"`
+	Meta  *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientConnectRequest) Reset() {
+	*x = ClientConnectRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientConnectRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientConnectRequest) ProtoMessage() {}
+
+func (x *ClientConnectRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientConnectRequest.ProtoReflect.Descriptor instead.
+func (*ClientConnectRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ClientConnectRequest) GetConninfo() *ConnInfo {
+	if x != nil {
+		return x.Conninfo
+	}
+	return nil
+}
+
+func (x *ClientConnectRequest) GetProps() []*Property {
+	if x != nil {
+		return x.Props
+	}
+	return nil
+}
+
+func (x *ClientConnectRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientConnackRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Conninfo   *ConnInfo    `protobuf:"bytes,1,opt,name=conninfo,proto3" json:"conninfo,omitempty"`
+	ResultCode string       `protobuf:"bytes,2,opt,name=result_code,json=resultCode,proto3" json:"result_code,omitempty"`
+	Props      []*Property  `protobuf:"bytes,3,rep,name=props,proto3" json:"props,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,4,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientConnackRequest) Reset() {
+	*x = ClientConnackRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientConnackRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientConnackRequest) ProtoMessage() {}
+
+func (x *ClientConnackRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientConnackRequest.ProtoReflect.Descriptor instead.
+func (*ClientConnackRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *ClientConnackRequest) GetConninfo() *ConnInfo {
+	if x != nil {
+		return x.Conninfo
+	}
+	return nil
+}
+
+func (x *ClientConnackRequest) GetResultCode() string {
+	if x != nil {
+		return x.ResultCode
+	}
+	return ""
+}
+
+func (x *ClientConnackRequest) GetProps() []*Property {
+	if x != nil {
+		return x.Props
+	}
+	return nil
+}
+
+func (x *ClientConnackRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientConnectedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,2,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientConnectedRequest) Reset() {
+	*x = ClientConnectedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientConnectedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientConnectedRequest) ProtoMessage() {}
+
+func (x *ClientConnectedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientConnectedRequest.ProtoReflect.Descriptor instead.
+func (*ClientConnectedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *ClientConnectedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *ClientConnectedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientDisconnectedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Reason     string       `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientDisconnectedRequest) Reset() {
+	*x = ClientDisconnectedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientDisconnectedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientDisconnectedRequest) ProtoMessage() {}
+
+func (x *ClientDisconnectedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientDisconnectedRequest.ProtoReflect.Descriptor instead.
+func (*ClientDisconnectedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *ClientDisconnectedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *ClientDisconnectedRequest) GetReason() string {
+	if x != nil {
+		return x.Reason
+	}
+	return ""
+}
+
+func (x *ClientDisconnectedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientAuthenticateRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Result     bool         `protobuf:"varint,2,opt,name=result,proto3" json:"result,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientAuthenticateRequest) Reset() {
+	*x = ClientAuthenticateRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientAuthenticateRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientAuthenticateRequest) ProtoMessage() {}
+
+func (x *ClientAuthenticateRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[6]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientAuthenticateRequest.ProtoReflect.Descriptor instead.
+func (*ClientAuthenticateRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *ClientAuthenticateRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *ClientAuthenticateRequest) GetResult() bool {
+	if x != nil {
+		return x.Result
+	}
+	return false
+}
+
+func (x *ClientAuthenticateRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientAuthorizeRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo                             `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Type       ClientAuthorizeRequest_AuthorizeReqType `protobuf:"varint,2,opt,name=type,proto3,enum=emqx.exhook.v2.ClientAuthorizeRequest_AuthorizeReqType" json:"type,omitempty"`
+	Topic      string                                  `protobuf:"bytes,3,opt,name=topic,proto3" json:"topic,omitempty"`
+	Result     bool                                    `protobuf:"varint,4,opt,name=result,proto3" json:"result,omitempty"`
+	Meta       *RequestMeta                            `protobuf:"bytes,5,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientAuthorizeRequest) Reset() {
+	*x = ClientAuthorizeRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientAuthorizeRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientAuthorizeRequest) ProtoMessage() {}
+
+func (x *ClientAuthorizeRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[7]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientAuthorizeRequest.ProtoReflect.Descriptor instead.
+func (*ClientAuthorizeRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *ClientAuthorizeRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *ClientAuthorizeRequest) GetType() ClientAuthorizeRequest_AuthorizeReqType {
+	if x != nil {
+		return x.Type
+	}
+	return ClientAuthorizeRequest_PUBLISH
+}
+
+func (x *ClientAuthorizeRequest) GetTopic() string {
+	if x != nil {
+		return x.Topic
+	}
+	return ""
+}
+
+func (x *ClientAuthorizeRequest) GetResult() bool {
+	if x != nil {
+		return x.Result
+	}
+	return false
+}
+
+func (x *ClientAuthorizeRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientSubscribeRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo   *ClientInfo    `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Props        []*Property    `protobuf:"bytes,2,rep,name=props,proto3" json:"props,omitempty"`
+	TopicFilters []*TopicFilter `protobuf:"bytes,3,rep,name=topic_filters,json=topicFilters,proto3" json:"topic_filters,omitempty"`
+	Meta         *RequestMeta   `protobuf:"bytes,4,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientSubscribeRequest) Reset() {
+	*x = ClientSubscribeRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[8]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientSubscribeRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientSubscribeRequest) ProtoMessage() {}
+
+func (x *ClientSubscribeRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[8]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientSubscribeRequest.ProtoReflect.Descriptor instead.
+func (*ClientSubscribeRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *ClientSubscribeRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *ClientSubscribeRequest) GetProps() []*Property {
+	if x != nil {
+		return x.Props
+	}
+	return nil
+}
+
+func (x *ClientSubscribeRequest) GetTopicFilters() []*TopicFilter {
+	if x != nil {
+		return x.TopicFilters
+	}
+	return nil
+}
+
+func (x *ClientSubscribeRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientUnsubscribeRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo   *ClientInfo    `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Props        []*Property    `protobuf:"bytes,2,rep,name=props,proto3" json:"props,omitempty"`
+	TopicFilters []*TopicFilter `protobuf:"bytes,3,rep,name=topic_filters,json=topicFilters,proto3" json:"topic_filters,omitempty"`
+	Meta         *RequestMeta   `protobuf:"bytes,4,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientUnsubscribeRequest) Reset() {
+	*x = ClientUnsubscribeRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[9]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientUnsubscribeRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientUnsubscribeRequest) ProtoMessage() {}
+
+func (x *ClientUnsubscribeRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[9]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientUnsubscribeRequest.ProtoReflect.Descriptor instead.
+func (*ClientUnsubscribeRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *ClientUnsubscribeRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *ClientUnsubscribeRequest) GetProps() []*Property {
+	if x != nil {
+		return x.Props
+	}
+	return nil
+}
+
+func (x *ClientUnsubscribeRequest) GetTopicFilters() []*TopicFilter {
+	if x != nil {
+		return x.TopicFilters
+	}
+	return nil
+}
+
+func (x *ClientUnsubscribeRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type SessionCreatedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,2,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *SessionCreatedRequest) Reset() {
+	*x = SessionCreatedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[10]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SessionCreatedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionCreatedRequest) ProtoMessage() {}
+
+func (x *SessionCreatedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[10]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SessionCreatedRequest.ProtoReflect.Descriptor instead.
+func (*SessionCreatedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *SessionCreatedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *SessionCreatedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type SessionSubscribedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Topic      string       `protobuf:"bytes,2,opt,name=topic,proto3" json:"topic,omitempty"`
+	Subopts    *SubOpts     `protobuf:"bytes,3,opt,name=subopts,proto3" json:"subopts,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,4,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *SessionSubscribedRequest) Reset() {
+	*x = SessionSubscribedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[11]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SessionSubscribedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionSubscribedRequest) ProtoMessage() {}
+
+func (x *SessionSubscribedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[11]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SessionSubscribedRequest.ProtoReflect.Descriptor instead.
+func (*SessionSubscribedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *SessionSubscribedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *SessionSubscribedRequest) GetTopic() string {
+	if x != nil {
+		return x.Topic
+	}
+	return ""
+}
+
+func (x *SessionSubscribedRequest) GetSubopts() *SubOpts {
+	if x != nil {
+		return x.Subopts
+	}
+	return nil
+}
+
+func (x *SessionSubscribedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type SessionUnsubscribedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Topic      string       `protobuf:"bytes,2,opt,name=topic,proto3" json:"topic,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *SessionUnsubscribedRequest) Reset() {
+	*x = SessionUnsubscribedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[12]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SessionUnsubscribedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionUnsubscribedRequest) ProtoMessage() {}
+
+func (x *SessionUnsubscribedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[12]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SessionUnsubscribedRequest.ProtoReflect.Descriptor instead.
+func (*SessionUnsubscribedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *SessionUnsubscribedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *SessionUnsubscribedRequest) GetTopic() string {
+	if x != nil {
+		return x.Topic
+	}
+	return ""
+}
+
+func (x *SessionUnsubscribedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type SessionResumedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,2,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *SessionResumedRequest) Reset() {
+	*x = SessionResumedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[13]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SessionResumedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionResumedRequest) ProtoMessage() {}
+
+func (x *SessionResumedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[13]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SessionResumedRequest.ProtoReflect.Descriptor instead.
+func (*SessionResumedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{13}
+}
+
+func (x *SessionResumedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *SessionResumedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type SessionDiscardedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,2,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *SessionDiscardedRequest) Reset() {
+	*x = SessionDiscardedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[14]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SessionDiscardedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionDiscardedRequest) ProtoMessage() {}
+
+func (x *SessionDiscardedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[14]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SessionDiscardedRequest.ProtoReflect.Descriptor instead.
+func (*SessionDiscardedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{14}
+}
+
+func (x *SessionDiscardedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *SessionDiscardedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type SessionTakenoverRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,2,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *SessionTakenoverRequest) Reset() {
+	*x = SessionTakenoverRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[15]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SessionTakenoverRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionTakenoverRequest) ProtoMessage() {}
+
+func (x *SessionTakenoverRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[15]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SessionTakenoverRequest.ProtoReflect.Descriptor instead.
+func (*SessionTakenoverRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{15}
+}
+
+func (x *SessionTakenoverRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *SessionTakenoverRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type SessionTerminatedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Reason     string       `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *SessionTerminatedRequest) Reset() {
+	*x = SessionTerminatedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[16]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SessionTerminatedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionTerminatedRequest) ProtoMessage() {}
+
+func (x *SessionTerminatedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[16]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SessionTerminatedRequest.ProtoReflect.Descriptor instead.
+func (*SessionTerminatedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{16}
+}
+
+func (x *SessionTerminatedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *SessionTerminatedRequest) GetReason() string {
+	if x != nil {
+		return x.Reason
+	}
+	return ""
+}
+
+func (x *SessionTerminatedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type MessagePublishRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Message *Message     `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+	Meta    *RequestMeta `protobuf:"bytes,2,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *MessagePublishRequest) Reset() {
+	*x = MessagePublishRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[17]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MessagePublishRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MessagePublishRequest) ProtoMessage() {}
+
+func (x *MessagePublishRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[17]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MessagePublishRequest.ProtoReflect.Descriptor instead.
+func (*MessagePublishRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{17}
+}
+
+func (x *MessagePublishRequest) GetMessage() *Message {
+	if x != nil {
+		return x.Message
+	}
+	return nil
+}
+
+func (x *MessagePublishRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type MessageDeliveredRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Message    *Message     `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *MessageDeliveredRequest) Reset() {
+	*x = MessageDeliveredRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[18]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MessageDeliveredRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MessageDeliveredRequest) ProtoMessage() {}
+
+func (x *MessageDeliveredRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[18]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MessageDeliveredRequest.ProtoReflect.Descriptor instead.
+func (*MessageDeliveredRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{18}
+}
+
+func (x *MessageDeliveredRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *MessageDeliveredRequest) GetMessage() *Message {
+	if x != nil {
+		return x.Message
+	}
+	return nil
+}
+
+func (x *MessageDeliveredRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type MessageDroppedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Message *Message     `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+	Reason  string       `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"`
+	Meta    *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *MessageDroppedRequest) Reset() {
+	*x = MessageDroppedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[19]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MessageDroppedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MessageDroppedRequest) ProtoMessage() {}
+
+func (x *MessageDroppedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[19]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MessageDroppedRequest.ProtoReflect.Descriptor instead.
+func (*MessageDroppedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{19}
+}
+
+func (x *MessageDroppedRequest) GetMessage() *Message {
+	if x != nil {
+		return x.Message
+	}
+	return nil
+}
+
+func (x *MessageDroppedRequest) GetReason() string {
+	if x != nil {
+		return x.Reason
+	}
+	return ""
+}
+
+func (x *MessageDroppedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type MessageAckedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Message    *Message     `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *MessageAckedRequest) Reset() {
+	*x = MessageAckedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[20]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MessageAckedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MessageAckedRequest) ProtoMessage() {}
+
+func (x *MessageAckedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[20]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MessageAckedRequest.ProtoReflect.Descriptor instead.
+func (*MessageAckedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{20}
+}
+
+func (x *MessageAckedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *MessageAckedRequest) GetMessage() *Message {
+	if x != nil {
+		return x.Message
+	}
+	return nil
+}
+
+func (x *MessageAckedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type LoadedResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Hooks []*HookSpec `protobuf:"bytes,1,rep,name=hooks,proto3" json:"hooks,omitempty"`
+}
+
+func (x *LoadedResponse) Reset() {
+	*x = LoadedResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[21]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *LoadedResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LoadedResponse) ProtoMessage() {}
+
+func (x *LoadedResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[21]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use LoadedResponse.ProtoReflect.Descriptor instead.
+func (*LoadedResponse) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{21}
+}
+
+func (x *LoadedResponse) GetHooks() []*HookSpec {
+	if x != nil {
+		return x.Hooks
+	}
+	return nil
+}
+
+type ValuedResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Type ValuedResponse_ResponsedType `protobuf:"varint,1,opt,name=type,proto3,enum=emqx.exhook.v2.ValuedResponse_ResponsedType" json:"type,omitempty"`
+	// Types that are assignable to Value:
+	//	*ValuedResponse_BoolResult
+	//	*ValuedResponse_Message
+	Value isValuedResponse_Value `protobuf_oneof:"value"`
+}
+
+func (x *ValuedResponse) Reset() {
+	*x = ValuedResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[22]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValuedResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValuedResponse) ProtoMessage() {}
+
+func (x *ValuedResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[22]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValuedResponse.ProtoReflect.Descriptor instead.
+func (*ValuedResponse) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{22}
+}
+
+func (x *ValuedResponse) GetType() ValuedResponse_ResponsedType {
+	if x != nil {
+		return x.Type
+	}
+	return ValuedResponse_CONTINUE
+}
+
+func (m *ValuedResponse) GetValue() isValuedResponse_Value {
+	if m != nil {
+		return m.Value
+	}
+	return nil
+}
+
+func (x *ValuedResponse) GetBoolResult() bool {
+	if x, ok := x.GetValue().(*ValuedResponse_BoolResult); ok {
+		return x.BoolResult
+	}
+	return false
+}
+
+func (x *ValuedResponse) GetMessage() *Message {
+	if x, ok := x.GetValue().(*ValuedResponse_Message); ok {
+		return x.Message
+	}
+	return nil
+}
+
+type isValuedResponse_Value interface {
+	isValuedResponse_Value()
+}
+
+type ValuedResponse_BoolResult struct {
+	// Boolean result, used on the 'client.authenticate', 'client.authorize' hooks
+	BoolResult bool `protobuf:"varint,3,opt,name=bool_result,json=boolResult,proto3,oneof"`
+}
+
+type ValuedResponse_Message struct {
+	// Message result, used on the 'message.*' hooks
+	Message *Message `protobuf:"bytes,4,opt,name=message,proto3,oneof"`
+}
+
+func (*ValuedResponse_BoolResult) isValuedResponse_Value() {}
+
+func (*ValuedResponse_Message) isValuedResponse_Value() {}
+
+type EmptySuccess struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *EmptySuccess) Reset() {
+	*x = EmptySuccess{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[23]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *EmptySuccess) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EmptySuccess) ProtoMessage() {}
+
+func (x *EmptySuccess) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[23]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use EmptySuccess.ProtoReflect.Descriptor instead.
+func (*EmptySuccess) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{23}
+}
+
+type BrokerInfo struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Version  string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
+	Sysdescr string `protobuf:"bytes,2,opt,name=sysdescr,proto3" json:"sysdescr,omitempty"`
+	Uptime   int64  `protobuf:"varint,3,opt,name=uptime,proto3" json:"uptime,omitempty"`
+	Datetime string `protobuf:"bytes,4,opt,name=datetime,proto3" json:"datetime,omitempty"`
+}
+
+func (x *BrokerInfo) Reset() {
+	*x = BrokerInfo{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[24]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *BrokerInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BrokerInfo) ProtoMessage() {}
+
+func (x *BrokerInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[24]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BrokerInfo.ProtoReflect.Descriptor instead.
+func (*BrokerInfo) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{24}
+}
+
+func (x *BrokerInfo) GetVersion() string {
+	if x != nil {
+		return x.Version
+	}
+	return ""
+}
+
+func (x *BrokerInfo) GetSysdescr() string {
+	if x != nil {
+		return x.Sysdescr
+	}
+	return ""
+}
+
+func (x *BrokerInfo) GetUptime() int64 {
+	if x != nil {
+		return x.Uptime
+	}
+	return 0
+}
+
+func (x *BrokerInfo) GetDatetime() string {
+	if x != nil {
+		return x.Datetime
+	}
+	return ""
+}
+
+type HookSpec struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The registered hooks name
+	//
+	// Available value:
+	//   "client.connect",      "client.connack"
+	//   "client.connected",    "client.disconnected"
+	//   "client.authenticate", "client.authorize"
+	//   "client.subscribe",    "client.unsubscribe"
+	//
+	//   "session.created",      "session.subscribed"
+	//   "session.unsubscribed", "session.resumed"
+	//   "session.discarded",    "session.takenover"
+	//   "session.terminated"
+	//
+	//   "message.publish", "message.delivered"
+	//   "message.acked",   "message.dropped"
+	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	// The topic filters for message hooks
+	Topics []string `protobuf:"bytes,2,rep,name=topics,proto3" json:"topics,omitempty"`
+}
+
+func (x *HookSpec) Reset() {
+	*x = HookSpec{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[25]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *HookSpec) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*HookSpec) ProtoMessage() {}
+
+func (x *HookSpec) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[25]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use HookSpec.ProtoReflect.Descriptor instead.
+func (*HookSpec) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{25}
+}
+
+func (x *HookSpec) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *HookSpec) GetTopics() []string {
+	if x != nil {
+		return x.Topics
+	}
+	return nil
+}
+
+type ConnInfo struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Node      string `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
+	Clientid  string `protobuf:"bytes,2,opt,name=clientid,proto3" json:"clientid,omitempty"`
+	Username  string `protobuf:"bytes,3,opt,name=username,proto3" json:"username,omitempty"`
+	Peerhost  string `protobuf:"bytes,4,opt,name=peerhost,proto3" json:"peerhost,omitempty"`
+	Sockport  uint32 `protobuf:"varint,5,opt,name=sockport,proto3" json:"sockport,omitempty"`
+	ProtoName string `protobuf:"bytes,6,opt,name=proto_name,json=protoName,proto3" json:"proto_name,omitempty"`
+	ProtoVer  string `protobuf:"bytes,7,opt,name=proto_ver,json=protoVer,proto3" json:"proto_ver,omitempty"`
+	Keepalive uint32 `protobuf:"varint,8,opt,name=keepalive,proto3" json:"keepalive,omitempty"`
+}
+
+func (x *ConnInfo) Reset() {
+	*x = ConnInfo{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[26]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ConnInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ConnInfo) ProtoMessage() {}
+
+func (x *ConnInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[26]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ConnInfo.ProtoReflect.Descriptor instead.
+func (*ConnInfo) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{26}
+}
+
+func (x *ConnInfo) GetNode() string {
+	if x != nil {
+		return x.Node
+	}
+	return ""
+}
+
+func (x *ConnInfo) GetClientid() string {
+	if x != nil {
+		return x.Clientid
+	}
+	return ""
+}
+
+func (x *ConnInfo) GetUsername() string {
+	if x != nil {
+		return x.Username
+	}
+	return ""
+}
+
+func (x *ConnInfo) GetPeerhost() string {
+	if x != nil {
+		return x.Peerhost
+	}
+	return ""
+}
+
+func (x *ConnInfo) GetSockport() uint32 {
+	if x != nil {
+		return x.Sockport
+	}
+	return 0
+}
+
+func (x *ConnInfo) GetProtoName() string {
+	if x != nil {
+		return x.ProtoName
+	}
+	return ""
+}
+
+func (x *ConnInfo) GetProtoVer() string {
+	if x != nil {
+		return x.ProtoVer
+	}
+	return ""
+}
+
+func (x *ConnInfo) GetKeepalive() uint32 {
+	if x != nil {
+		return x.Keepalive
+	}
+	return 0
+}
+
+type ClientInfo struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Node        string `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
+	Clientid    string `protobuf:"bytes,2,opt,name=clientid,proto3" json:"clientid,omitempty"`
+	Username    string `protobuf:"bytes,3,opt,name=username,proto3" json:"username,omitempty"`
+	Password    string `protobuf:"bytes,4,opt,name=password,proto3" json:"password,omitempty"`
+	Peerhost    string `protobuf:"bytes,5,opt,name=peerhost,proto3" json:"peerhost,omitempty"`
+	Sockport    uint32 `protobuf:"varint,6,opt,name=sockport,proto3" json:"sockport,omitempty"`
+	Protocol    string `protobuf:"bytes,7,opt,name=protocol,proto3" json:"protocol,omitempty"`
+	Mountpoint  string `protobuf:"bytes,8,opt,name=mountpoint,proto3" json:"mountpoint,omitempty"`
+	IsSuperuser bool   `protobuf:"varint,9,opt,name=is_superuser,json=isSuperuser,proto3" json:"is_superuser,omitempty"`
+	Anonymous   bool   `protobuf:"varint,10,opt,name=anonymous,proto3" json:"anonymous,omitempty"`
+	// common name of client TLS cert
+	Cn string `protobuf:"bytes,11,opt,name=cn,proto3" json:"cn,omitempty"`
+	// subject of client TLS cert
+	Dn string `protobuf:"bytes,12,opt,name=dn,proto3" json:"dn,omitempty"`
+}
+
+func (x *ClientInfo) Reset() {
+	*x = ClientInfo{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[27]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientInfo) ProtoMessage() {}
+
+func (x *ClientInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[27]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientInfo.ProtoReflect.Descriptor instead.
+func (*ClientInfo) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{27}
+}
+
+func (x *ClientInfo) GetNode() string {
+	if x != nil {
+		return x.Node
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetClientid() string {
+	if x != nil {
+		return x.Clientid
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetUsername() string {
+	if x != nil {
+		return x.Username
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetPassword() string {
+	if x != nil {
+		return x.Password
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetPeerhost() string {
+	if x != nil {
+		return x.Peerhost
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetSockport() uint32 {
+	if x != nil {
+		return x.Sockport
+	}
+	return 0
+}
+
+func (x *ClientInfo) GetProtocol() string {
+	if x != nil {
+		return x.Protocol
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetMountpoint() string {
+	if x != nil {
+		return x.Mountpoint
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetIsSuperuser() bool {
+	if x != nil {
+		return x.IsSuperuser
+	}
+	return false
+}
+
+func (x *ClientInfo) GetAnonymous() bool {
+	if x != nil {
+		return x.Anonymous
+	}
+	return false
+}
+
+func (x *ClientInfo) GetCn() string {
+	if x != nil {
+		return x.Cn
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetDn() string {
+	if x != nil {
+		return x.Dn
+	}
+	return ""
+}
+
+type Message struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Node      string `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
+	Id        string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
+	Qos       uint32 `protobuf:"varint,3,opt,name=qos,proto3" json:"qos,omitempty"`
+	From      string `protobuf:"bytes,4,opt,name=from,proto3" json:"from,omitempty"`
+	Topic     string `protobuf:"bytes,5,opt,name=topic,proto3" json:"topic,omitempty"`
+	Payload   []byte `protobuf:"bytes,6,opt,name=payload,proto3" json:"payload,omitempty"`
+	Timestamp uint64 `protobuf:"varint,7,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	// The key of header can be:
+	//  - username:
+	//    * Readonly
+	//    * The username of sender client
+	//    * Value type: utf8 string
+	//  - protocol:
+	//    * Readonly
+	//    * The protocol name of sender client
+	//    * Value type: string enum with "mqtt", "mqtt-sn", ...
+	//  - peerhost:
+	//    * Readonly
+	//    * The peerhost of sender client
+	//    * Value type: ip address string
+	//  - allow_publish:
+	//    * Writable
+	//    * Whether to allow the message to be published by emqx
+	//    * Value type: string enum with "true", "false", default is "true"
+	//
+	// Notes: All header may be missing, which means that the message does not
+	//   carry these headers. We can guarantee that clients coming from MQTT,
+	//   MQTT-SN, CoAP, LwM2M and other natively supported protocol clients will
+	//   carry these headers, but there is no guarantee that messages published
+	//   by other means will do, e.g. messages published by HTTP-API
+	Headers map[string]string `protobuf:"bytes,8,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *Message) Reset() {
+	*x = Message{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[28]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Message) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Message) ProtoMessage() {}
+
+func (x *Message) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[28]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Message.ProtoReflect.Descriptor instead.
+func (*Message) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{28}
+}
+
+func (x *Message) GetNode() string {
+	if x != nil {
+		return x.Node
+	}
+	return ""
+}
+
+func (x *Message) GetId() string {
+	if x != nil {
+		return x.Id
+	}
+	return ""
+}
+
+func (x *Message) GetQos() uint32 {
+	if x != nil {
+		return x.Qos
+	}
+	return 0
+}
+
+func (x *Message) GetFrom() string {
+	if x != nil {
+		return x.From
+	}
+	return ""
+}
+
+func (x *Message) GetTopic() string {
+	if x != nil {
+		return x.Topic
+	}
+	return ""
+}
+
+func (x *Message) GetPayload() []byte {
+	if x != nil {
+		return x.Payload
+	}
+	return nil
+}
+
+func (x *Message) GetTimestamp() uint64 {
+	if x != nil {
+		return x.Timestamp
+	}
+	return 0
+}
+
+func (x *Message) GetHeaders() map[string]string {
+	if x != nil {
+		return x.Headers
+	}
+	return nil
+}
+
+type Property struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Name  string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
+}
+
+func (x *Property) Reset() {
+	*x = Property{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[29]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Property) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Property) ProtoMessage() {}
+
+func (x *Property) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[29]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Property.ProtoReflect.Descriptor instead.
+func (*Property) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{29}
+}
+
+func (x *Property) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *Property) GetValue() string {
+	if x != nil {
+		return x.Value
+	}
+	return ""
+}
+
+type TopicFilter struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	Qos  uint32 `protobuf:"varint,2,opt,name=qos,proto3" json:"qos,omitempty"`
+}
+
+func (x *TopicFilter) Reset() {
+	*x = TopicFilter{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[30]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *TopicFilter) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopicFilter) ProtoMessage() {}
+
+func (x *TopicFilter) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[30]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use TopicFilter.ProtoReflect.Descriptor instead.
+func (*TopicFilter) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{30}
+}
+
+func (x *TopicFilter) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *TopicFilter) GetQos() uint32 {
+	if x != nil {
+		return x.Qos
+	}
+	return 0
+}
+
+type SubOpts struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The QoS level
+	Qos uint32 `protobuf:"varint,1,opt,name=qos,proto3" json:"qos,omitempty"`
+	// The group name for shared subscription
+	Share string `protobuf:"bytes,2,opt,name=share,proto3" json:"share,omitempty"`
+	// The Retain Handling option (MQTT v5.0)
+	//
+	//  0 = Send retained messages at the time of the subscribe
+	//  1 = Send retained messages at subscribe only if the subscription does
+	//       not currently exist
+	//  2 = Do not send retained messages at the time of the subscribe
+	Rh uint32 `protobuf:"varint,3,opt,name=rh,proto3" json:"rh,omitempty"`
+	// The Retain as Published option (MQTT v5.0)
+	//
+	//  If 1, Application Messages forwarded using this subscription keep the
+	//        RETAIN flag they were published with.
+	//  If 0, Application Messages forwarded using this subscription have the
+	//        RETAIN flag set to 0.
+	// Retained messages sent when the subscription is established have the RETAIN flag set to 1.
+	Rap uint32 `protobuf:"varint,4,opt,name=rap,proto3" json:"rap,omitempty"`
+	// The No Local option (MQTT v5.0)
+	//
+	// If the value is 1, Application Messages MUST NOT be forwarded to a
+	// connection with a ClientID equal to the ClientID of the publishing
+	Nl uint32 `protobuf:"varint,5,opt,name=nl,proto3" json:"nl,omitempty"`
+}
+
+func (x *SubOpts) Reset() {
+	*x = SubOpts{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[31]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SubOpts) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubOpts) ProtoMessage() {}
+
+func (x *SubOpts) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[31]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubOpts.ProtoReflect.Descriptor instead.
+func (*SubOpts) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{31}
+}
+
+func (x *SubOpts) GetQos() uint32 {
+	if x != nil {
+		return x.Qos
+	}
+	return 0
+}
+
+func (x *SubOpts) GetShare() string {
+	if x != nil {
+		return x.Share
+	}
+	return ""
+}
+
+func (x *SubOpts) GetRh() uint32 {
+	if x != nil {
+		return x.Rh
+	}
+	return 0
+}
+
+func (x *SubOpts) GetRap() uint32 {
+	if x != nil {
+		return x.Rap
+	}
+	return 0
+}
+
+func (x *SubOpts) GetNl() uint32 {
+	if x != nil {
+		return x.Nl
+	}
+	return 0
+}
+
+type RequestMeta struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Node        string `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
+	Version     string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
+	Sysdescr    string `protobuf:"bytes,3,opt,name=sysdescr,proto3" json:"sysdescr,omitempty"`
+	ClusterName string `protobuf:"bytes,4,opt,name=cluster_name,json=clusterName,proto3" json:"cluster_name,omitempty"`
+}
+
+func (x *RequestMeta) Reset() {
+	*x = RequestMeta{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[32]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *RequestMeta) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RequestMeta) ProtoMessage() {}
+
+func (x *RequestMeta) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[32]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use RequestMeta.ProtoReflect.Descriptor instead.
+func (*RequestMeta) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{32}
+}
+
+func (x *RequestMeta) GetNode() string {
+	if x != nil {
+		return x.Node
+	}
+	return ""
+}
+
+func (x *RequestMeta) GetVersion() string {
+	if x != nil {
+		return x.Version
+	}
+	return ""
+}
+
+func (x *RequestMeta) GetSysdescr() string {
+	if x != nil {
+		return x.Sysdescr
+	}
+	return ""
+}
+
+func (x *RequestMeta) GetClusterName() string {
+	if x != nil {
+		return x.ClusterName
+	}
+	return ""
+}
+
+var File_protobuf_exhook_proto protoreflect.FileDescriptor
+
+var file_protobuf_exhook_proto_rawDesc = []byte{
+	0x0a, 0x15, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x78, 0x68, 0x6f, 0x6f,
+	0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x22, 0x7c, 0x0a, 0x15, 0x50, 0x72, 0x6f, 0x76, 0x69,
+	0x64, 0x65, 0x72, 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x12, 0x32, 0x0a, 0x06, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76,
+	0x32, 0x2e, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x62, 0x72,
+	0x6f, 0x6b, 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52,
+	0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x4a, 0x0a, 0x17, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
+	0x72, 0x55, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74,
+	0x61, 0x22, 0xad, 0x01, 0x0a, 0x14, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e,
+	0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x08, 0x63, 0x6f,
+	0x6e, 0x6e, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65,
+	0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f,
+	0x6e, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x6e, 0x69, 0x6e, 0x66, 0x6f,
+	0x12, 0x2e, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x18, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73,
+	0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74,
+	0x61, 0x22, 0xce, 0x01, 0x0a, 0x14, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e,
+	0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x08, 0x63, 0x6f,
+	0x6e, 0x6e, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65,
+	0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f,
+	0x6e, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x6e, 0x69, 0x6e, 0x66, 0x6f,
+	0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x64,
+	0x65, 0x12, 0x2e, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x18, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76,
+	0x32, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x70,
+	0x73, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65,
+	0x74, 0x61, 0x22, 0x85, 0x01, 0x0a, 0x16, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e,
+	0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a,
+	0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e,
+	0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74,
+	0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65,
+	0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0xa0, 0x01, 0x0a, 0x19, 0x43,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65,
+	0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65,
+	0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65,
+	0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c,
+	0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
+	0x69, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x04,
+	0x6d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71,
+	0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0xa0, 0x01,
+	0x0a, 0x19, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69,
+	0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c,
+	0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12,
+	0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
+	0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61,
+	0x22, 0xb0, 0x02, 0x0a, 0x16, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f,
+	0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x4b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x37, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68,
+	0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74,
+	0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x75,
+	0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04,
+	0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65,
+	0x73, 0x75, 0x6c, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75,
+	0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76,
+	0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d,
+	0x65, 0x74, 0x61, 0x22, 0x2e, 0x0a, 0x10, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65,
+	0x52, 0x65, 0x71, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x55, 0x42, 0x4c, 0x49,
+	0x53, 0x48, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42,
+	0x45, 0x10, 0x01, 0x22, 0xf7, 0x01, 0x0a, 0x16, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x75,
+	0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a,
+	0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a,
+	0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x05, 0x70, 0x72,
+	0x6f, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65, 0x6d, 0x71, 0x78,
+	0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65,
+	0x72, 0x74, 0x79, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x12, 0x40, 0x0a, 0x0d, 0x74, 0x6f,
+	0x70, 0x69, 0x63, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e,
+	0x76, 0x32, 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0c,
+	0x74, 0x6f, 0x70, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2f, 0x0a, 0x04,
+	0x6d, 0x65, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71,
+	0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0xf9, 0x01,
+	0x0a, 0x18, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72,
+	0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c,
+	0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65,
+	0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x18,
+	0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68,
+	0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52,
+	0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x12, 0x40, 0x0a, 0x0d, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x5f,
+	0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
+	0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x54,
+	0x6f, 0x70, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0c, 0x74, 0x6f, 0x70, 0x69,
+	0x63, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d,
+	0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x84, 0x01, 0x0a, 0x15, 0x53, 0x65,
+	0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66,
+	0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65,
+	0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49,
+	0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12,
+	0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
+	0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61,
+	0x22, 0xd0, 0x01, 0x0a, 0x18, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x75, 0x62, 0x73,
+	0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a,
+	0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e,
+	0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70,
+	0x69, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12,
+	0x31, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6f, 0x70, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x17, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76,
+	0x32, 0x2e, 0x53, 0x75, 0x62, 0x4f, 0x70, 0x74, 0x73, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6f, 0x70,
+	0x74, 0x73, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76,
+	0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d,
+	0x65, 0x74, 0x61, 0x22, 0x9f, 0x01, 0x0a, 0x1a, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x55,
+	0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e,
+	0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x14,
+	0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74,
+	0x6f, 0x70, 0x69, 0x63, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52,
+	0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x84, 0x01, 0x0a, 0x15, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
+	0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+	0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f,
+	0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52,
+	0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x0a, 0x04, 0x6d,
+	0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78,
+	0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x86, 0x01, 0x0a,
+	0x17, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x65,
+	0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65,
+	0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65,
+	0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c,
+	0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
+	0x69, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52,
+	0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x86, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
+	0x6e, 0x54, 0x61, 0x6b, 0x65, 0x6e, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68,
+	0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66,
+	0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x0a,
+	0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d,
+	0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x9f,
+	0x01, 0x0a, 0x18, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e,
+	0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f,
+	0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12,
+	0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
+	0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61,
+	0x22, 0x7b, 0x0a, 0x15, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69,
+	0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x07, 0x6d, 0x65, 0x73,
+	0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x65, 0x6d, 0x71,
+	0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x04,
+	0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71,
+	0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0xb9, 0x01,
+	0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72,
+	0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
+	0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e,
+	0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x31, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,
+	0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d,
+	0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x93, 0x01, 0x0a, 0x15, 0x4d, 0x65,
+	0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f,
+	0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d,
+	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x2f,
+	0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65,
+	0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22,
+	0xb5, 0x01, 0x0a, 0x13, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x41, 0x63, 0x6b, 0x65, 0x64,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e,
+	0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d,
+	0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69,
+	0x6e, 0x66, 0x6f, 0x12, 0x31, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f,
+	0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d,
+	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f,
+	0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74,
+	0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x40, 0x0a, 0x0e, 0x4c, 0x6f, 0x61, 0x64, 0x65,
+	0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x05, 0x68, 0x6f, 0x6f,
+	0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e,
+	0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x53, 0x70,
+	0x65, 0x63, 0x52, 0x05, 0x68, 0x6f, 0x6f, 0x6b, 0x73, 0x22, 0xf3, 0x01, 0x0a, 0x0e, 0x56, 0x61,
+	0x6c, 0x75, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x04,
+	0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x65, 0x6d, 0x71,
+	0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x56, 0x61, 0x6c, 0x75,
+	0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x21,
+	0x0a, 0x0b, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x75, 0x6c,
+	0x74, 0x12, 0x33, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x17, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x07, 0x6d,
+	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x3e, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x4f, 0x4e, 0x54, 0x49,
+	0x4e, 0x55, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x47, 0x4e, 0x4f, 0x52, 0x45, 0x10,
+	0x01, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x54, 0x4f, 0x50, 0x5f, 0x41, 0x4e, 0x44, 0x5f, 0x52, 0x45,
+	0x54, 0x55, 0x52, 0x4e, 0x10, 0x02, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,
+	0x0e, 0x0a, 0x0c, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22,
+	0x76, 0x0a, 0x0a, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a,
+	0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
+	0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x79, 0x73, 0x64, 0x65,
+	0x73, 0x63, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x79, 0x73, 0x64, 0x65,
+	0x73, 0x63, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x64,
+	0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64,
+	0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x36, 0x0a, 0x08, 0x48, 0x6f, 0x6f, 0x6b, 0x53,
+	0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63,
+	0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x22,
+	0xe8, 0x01, 0x0a, 0x08, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04,
+	0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65,
+	0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08,
+	0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+	0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x65, 0x65, 0x72,
+	0x68, 0x6f, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x65, 0x65, 0x72,
+	0x68, 0x6f, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6f, 0x63, 0x6b, 0x70, 0x6f, 0x72, 0x74,
+	0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x6f, 0x63, 0x6b, 0x70, 0x6f, 0x72, 0x74,
+	0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x4e, 0x61, 0x6d, 0x65, 0x12,
+	0x1b, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x56, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09,
+	0x6b, 0x65, 0x65, 0x70, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52,
+	0x09, 0x6b, 0x65, 0x65, 0x70, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x22, 0xc9, 0x02, 0x0a, 0x0a, 0x43,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x64,
+	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a,
+	0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65,
+	0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65,
+	0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
+	0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
+	0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x65, 0x65, 0x72, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x65, 0x65, 0x72, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1a, 0x0a,
+	0x08, 0x73, 0x6f, 0x63, 0x6b, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52,
+	0x08, 0x73, 0x6f, 0x63, 0x6b, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x70, 0x6f,
+	0x69, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
+	0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x73, 0x75, 0x70, 0x65,
+	0x72, 0x75, 0x73, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x53,
+	0x75, 0x70, 0x65, 0x72, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x6e, 0x6f, 0x6e,
+	0x79, 0x6d, 0x6f, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x61, 0x6e, 0x6f,
+	0x6e, 0x79, 0x6d, 0x6f, 0x75, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x63, 0x6e, 0x18, 0x0b, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x02, 0x63, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x64, 0x6e, 0x18, 0x0c, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x02, 0x64, 0x6e, 0x22, 0x9d, 0x02, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x71, 0x6f, 0x73, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x0d, 0x52, 0x03, 0x71, 0x6f, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x14, 0x0a, 0x05,
+	0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70,
+	0x69, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x06, 0x20,
+	0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1c, 0x0a, 0x09,
+	0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3e, 0x0a, 0x07, 0x68, 0x65,
+	0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x65, 0x6d,
+	0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73,
+	0x73, 0x61, 0x67, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72,
+	0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x1a, 0x3a, 0x0a, 0x0c, 0x48, 0x65,
+	0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
+	0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
+	0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x34, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72,
+	0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x33, 0x0a, 0x0b,
+	0x54, 0x6f, 0x70, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e,
+	0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
+	0x10, 0x0a, 0x03, 0x71, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x71, 0x6f,
+	0x73, 0x22, 0x63, 0x0a, 0x07, 0x53, 0x75, 0x62, 0x4f, 0x70, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03,
+	0x71, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x71, 0x6f, 0x73, 0x12, 0x14,
+	0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73,
+	0x68, 0x61, 0x72, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x72, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d,
+	0x52, 0x02, 0x72, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x61, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28,
+	0x0d, 0x52, 0x03, 0x72, 0x61, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x6e, 0x6c, 0x18, 0x05, 0x20, 0x01,
+	0x28, 0x0d, 0x52, 0x02, 0x6e, 0x6c, 0x22, 0x7a, 0x0a, 0x0b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72,
+	0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73,
+	0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x79, 0x73, 0x64, 0x65, 0x73, 0x63, 0x72, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x79, 0x73, 0x64, 0x65, 0x73, 0x63, 0x72, 0x12,
+	0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+	0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61,
+	0x6d, 0x65, 0x32, 0xc7, 0x0f, 0x0a, 0x0c, 0x48, 0x6f, 0x6f, 0x6b, 0x50, 0x72, 0x6f, 0x76, 0x69,
+	0x64, 0x65, 0x72, 0x12, 0x5b, 0x0a, 0x10, 0x4f, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
+	0x72, 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x12, 0x25, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65,
+	0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
+	0x72, 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x4c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
+	0x12, 0x5d, 0x0a, 0x12, 0x4f, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x55, 0x6e,
+	0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x12, 0x27, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
+	0x55, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12,
+	0x57, 0x0a, 0x0f, 0x4f, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
+	0x63, 0x74, 0x12, 0x24, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
+	0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e,
+	0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53,
+	0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x57, 0x0a, 0x0f, 0x4f, 0x6e, 0x43, 0x6c,
+	0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x61, 0x63, 0x6b, 0x12, 0x24, 0x2e, 0x65, 0x6d,
+	0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e,
+	0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22,
+	0x00, 0x12, 0x5b, 0x0a, 0x11, 0x4f, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e,
+	0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x26, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f,
+	0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x61,
+	0x0a, 0x14, 0x4f, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e,
+	0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x29, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x44, 0x69,
+	0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e,
+	0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22,
+	0x00, 0x12, 0x63, 0x0a, 0x14, 0x4f, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74,
+	0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x29, 0x2e, 0x65, 0x6d, 0x71, 0x78,
+	0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e,
+	0x74, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f,
+	0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x11, 0x4f, 0x6e, 0x43, 0x6c, 0x69, 0x65,
+	0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x26, 0x2e, 0x65, 0x6d,
+	0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f,
+	0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5b, 0x0a, 0x11, 0x4f, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e,
+	0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x26, 0x2e, 0x65, 0x6d, 0x71,
+	0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65,
+	0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73,
+	0x22, 0x00, 0x12, 0x5f, 0x0a, 0x13, 0x4f, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x6e,
+	0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x28, 0x2e, 0x65, 0x6d, 0x71, 0x78,
+	0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e,
+	0x74, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f,
+	0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73,
+	0x73, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x10, 0x4f, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
+	0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x25, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65,
+	0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
+	0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x5f,
+	0x0a, 0x13, 0x4f, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x75, 0x62, 0x73, 0x63,
+	0x72, 0x69, 0x62, 0x65, 0x64, 0x12, 0x28, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68,
+	0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x75,
+	0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12,
+	0x63, 0x0a, 0x15, 0x4f, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x55, 0x6e, 0x73, 0x75,
+	0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x12, 0x2a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e,
+	0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
+	0x6e, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f,
+	0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65,
+	0x73, 0x73, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x10, 0x4f, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
+	0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x12, 0x25, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e,
+	0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
+	0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12,
+	0x5d, 0x0a, 0x12, 0x4f, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x69, 0x73, 0x63,
+	0x61, 0x72, 0x64, 0x65, 0x64, 0x12, 0x27, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68,
+	0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x69,
+	0x73, 0x63, 0x61, 0x72, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x5d,
+	0x0a, 0x12, 0x4f, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x61, 0x6b, 0x65, 0x6e,
+	0x6f, 0x76, 0x65, 0x72, 0x12, 0x27, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f,
+	0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x61, 0x6b,
+	0x65, 0x6e, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e,
+	0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x45,
+	0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x5f, 0x0a,
+	0x13, 0x4f, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e,
+	0x61, 0x74, 0x65, 0x64, 0x12, 0x28, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f,
+	0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x72,
+	0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x5b,
+	0x0a, 0x10, 0x4f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69,
+	0x73, 0x68, 0x12, 0x25, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69,
+	0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x65, 0x6d, 0x71, 0x78,
+	0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65,
+	0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x12, 0x4f,
+	0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x65,
+	0x64, 0x12, 0x27, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e,
+	0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65,
+	0x72, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71,
+	0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74,
+	0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x10, 0x4f, 0x6e,
+	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x12, 0x25,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68,
+	0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63,
+	0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x55, 0x0a, 0x0e, 0x4f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x41, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x23, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65,
+	0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x41, 0x63, 0x6b, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65,
+	0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x45, 0x6d,
+	0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x42, 0x49, 0x0a, 0x0e,
+	0x69, 0x6f, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x42, 0x0f,
+	0x45, 0x6d, 0x71, 0x78, 0x45, 0x78, 0x48, 0x6f, 0x6f, 0x6b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50,
+	0x01, 0x5a, 0x13, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x69, 0x6f, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f,
+	0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0xaa, 0x02, 0x0e, 0x45, 0x6d, 0x71, 0x78, 0x2e, 0x45, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_protobuf_exhook_proto_rawDescOnce sync.Once
+	file_protobuf_exhook_proto_rawDescData = file_protobuf_exhook_proto_rawDesc
+)
+
+func file_protobuf_exhook_proto_rawDescGZIP() []byte {
+	file_protobuf_exhook_proto_rawDescOnce.Do(func() {
+		file_protobuf_exhook_proto_rawDescData = protoimpl.X.CompressGZIP(file_protobuf_exhook_proto_rawDescData)
+	})
+	return file_protobuf_exhook_proto_rawDescData
+}
+
+var file_protobuf_exhook_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
+var file_protobuf_exhook_proto_msgTypes = make([]protoimpl.MessageInfo, 34)
+var file_protobuf_exhook_proto_goTypes = []interface{}{
+	(ClientAuthorizeRequest_AuthorizeReqType)(0), // 0: emqx.exhook.v2.ClientAuthorizeRequest.AuthorizeReqType
+	(ValuedResponse_ResponsedType)(0),            // 1: emqx.exhook.v2.ValuedResponse.ResponsedType
+	(*ProviderLoadedRequest)(nil),                // 2: emqx.exhook.v2.ProviderLoadedRequest
+	(*ProviderUnloadedRequest)(nil),              // 3: emqx.exhook.v2.ProviderUnloadedRequest
+	(*ClientConnectRequest)(nil),                 // 4: emqx.exhook.v2.ClientConnectRequest
+	(*ClientConnackRequest)(nil),                 // 5: emqx.exhook.v2.ClientConnackRequest
+	(*ClientConnectedRequest)(nil),               // 6: emqx.exhook.v2.ClientConnectedRequest
+	(*ClientDisconnectedRequest)(nil),            // 7: emqx.exhook.v2.ClientDisconnectedRequest
+	(*ClientAuthenticateRequest)(nil),            // 8: emqx.exhook.v2.ClientAuthenticateRequest
+	(*ClientAuthorizeRequest)(nil),               // 9: emqx.exhook.v2.ClientAuthorizeRequest
+	(*ClientSubscribeRequest)(nil),               // 10: emqx.exhook.v2.ClientSubscribeRequest
+	(*ClientUnsubscribeRequest)(nil),             // 11: emqx.exhook.v2.ClientUnsubscribeRequest
+	(*SessionCreatedRequest)(nil),                // 12: emqx.exhook.v2.SessionCreatedRequest
+	(*SessionSubscribedRequest)(nil),             // 13: emqx.exhook.v2.SessionSubscribedRequest
+	(*SessionUnsubscribedRequest)(nil),           // 14: emqx.exhook.v2.SessionUnsubscribedRequest
+	(*SessionResumedRequest)(nil),                // 15: emqx.exhook.v2.SessionResumedRequest
+	(*SessionDiscardedRequest)(nil),              // 16: emqx.exhook.v2.SessionDiscardedRequest
+	(*SessionTakenoverRequest)(nil),              // 17: emqx.exhook.v2.SessionTakenoverRequest
+	(*SessionTerminatedRequest)(nil),             // 18: emqx.exhook.v2.SessionTerminatedRequest
+	(*MessagePublishRequest)(nil),                // 19: emqx.exhook.v2.MessagePublishRequest
+	(*MessageDeliveredRequest)(nil),              // 20: emqx.exhook.v2.MessageDeliveredRequest
+	(*MessageDroppedRequest)(nil),                // 21: emqx.exhook.v2.MessageDroppedRequest
+	(*MessageAckedRequest)(nil),                  // 22: emqx.exhook.v2.MessageAckedRequest
+	(*LoadedResponse)(nil),                       // 23: emqx.exhook.v2.LoadedResponse
+	(*ValuedResponse)(nil),                       // 24: emqx.exhook.v2.ValuedResponse
+	(*EmptySuccess)(nil),                         // 25: emqx.exhook.v2.EmptySuccess
+	(*BrokerInfo)(nil),                           // 26: emqx.exhook.v2.BrokerInfo
+	(*HookSpec)(nil),                             // 27: emqx.exhook.v2.HookSpec
+	(*ConnInfo)(nil),                             // 28: emqx.exhook.v2.ConnInfo
+	(*ClientInfo)(nil),                           // 29: emqx.exhook.v2.ClientInfo
+	(*Message)(nil),                              // 30: emqx.exhook.v2.Message
+	(*Property)(nil),                             // 31: emqx.exhook.v2.Property
+	(*TopicFilter)(nil),                          // 32: emqx.exhook.v2.TopicFilter
+	(*SubOpts)(nil),                              // 33: emqx.exhook.v2.SubOpts
+	(*RequestMeta)(nil),                          // 34: emqx.exhook.v2.RequestMeta
+	nil,                                          // 35: emqx.exhook.v2.Message.HeadersEntry
+}
+var file_protobuf_exhook_proto_depIdxs = []int32{
+	26, // 0: emqx.exhook.v2.ProviderLoadedRequest.broker:type_name -> emqx.exhook.v2.BrokerInfo
+	34, // 1: emqx.exhook.v2.ProviderLoadedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	34, // 2: emqx.exhook.v2.ProviderUnloadedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	28, // 3: emqx.exhook.v2.ClientConnectRequest.conninfo:type_name -> emqx.exhook.v2.ConnInfo
+	31, // 4: emqx.exhook.v2.ClientConnectRequest.props:type_name -> emqx.exhook.v2.Property
+	34, // 5: emqx.exhook.v2.ClientConnectRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	28, // 6: emqx.exhook.v2.ClientConnackRequest.conninfo:type_name -> emqx.exhook.v2.ConnInfo
+	31, // 7: emqx.exhook.v2.ClientConnackRequest.props:type_name -> emqx.exhook.v2.Property
+	34, // 8: emqx.exhook.v2.ClientConnackRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 9: emqx.exhook.v2.ClientConnectedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 10: emqx.exhook.v2.ClientConnectedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 11: emqx.exhook.v2.ClientDisconnectedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 12: emqx.exhook.v2.ClientDisconnectedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 13: emqx.exhook.v2.ClientAuthenticateRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 14: emqx.exhook.v2.ClientAuthenticateRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 15: emqx.exhook.v2.ClientAuthorizeRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	0,  // 16: emqx.exhook.v2.ClientAuthorizeRequest.type:type_name -> emqx.exhook.v2.ClientAuthorizeRequest.AuthorizeReqType
+	34, // 17: emqx.exhook.v2.ClientAuthorizeRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 18: emqx.exhook.v2.ClientSubscribeRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	31, // 19: emqx.exhook.v2.ClientSubscribeRequest.props:type_name -> emqx.exhook.v2.Property
+	32, // 20: emqx.exhook.v2.ClientSubscribeRequest.topic_filters:type_name -> emqx.exhook.v2.TopicFilter
+	34, // 21: emqx.exhook.v2.ClientSubscribeRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 22: emqx.exhook.v2.ClientUnsubscribeRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	31, // 23: emqx.exhook.v2.ClientUnsubscribeRequest.props:type_name -> emqx.exhook.v2.Property
+	32, // 24: emqx.exhook.v2.ClientUnsubscribeRequest.topic_filters:type_name -> emqx.exhook.v2.TopicFilter
+	34, // 25: emqx.exhook.v2.ClientUnsubscribeRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 26: emqx.exhook.v2.SessionCreatedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 27: emqx.exhook.v2.SessionCreatedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 28: emqx.exhook.v2.SessionSubscribedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	33, // 29: emqx.exhook.v2.SessionSubscribedRequest.subopts:type_name -> emqx.exhook.v2.SubOpts
+	34, // 30: emqx.exhook.v2.SessionSubscribedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 31: emqx.exhook.v2.SessionUnsubscribedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 32: emqx.exhook.v2.SessionUnsubscribedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 33: emqx.exhook.v2.SessionResumedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 34: emqx.exhook.v2.SessionResumedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 35: emqx.exhook.v2.SessionDiscardedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 36: emqx.exhook.v2.SessionDiscardedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 37: emqx.exhook.v2.SessionTakenoverRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 38: emqx.exhook.v2.SessionTakenoverRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 39: emqx.exhook.v2.SessionTerminatedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 40: emqx.exhook.v2.SessionTerminatedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	30, // 41: emqx.exhook.v2.MessagePublishRequest.message:type_name -> emqx.exhook.v2.Message
+	34, // 42: emqx.exhook.v2.MessagePublishRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 43: emqx.exhook.v2.MessageDeliveredRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	30, // 44: emqx.exhook.v2.MessageDeliveredRequest.message:type_name -> emqx.exhook.v2.Message
+	34, // 45: emqx.exhook.v2.MessageDeliveredRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	30, // 46: emqx.exhook.v2.MessageDroppedRequest.message:type_name -> emqx.exhook.v2.Message
+	34, // 47: emqx.exhook.v2.MessageDroppedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 48: emqx.exhook.v2.MessageAckedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	30, // 49: emqx.exhook.v2.MessageAckedRequest.message:type_name -> emqx.exhook.v2.Message
+	34, // 50: emqx.exhook.v2.MessageAckedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	27, // 51: emqx.exhook.v2.LoadedResponse.hooks:type_name -> emqx.exhook.v2.HookSpec
+	1,  // 52: emqx.exhook.v2.ValuedResponse.type:type_name -> emqx.exhook.v2.ValuedResponse.ResponsedType
+	30, // 53: emqx.exhook.v2.ValuedResponse.message:type_name -> emqx.exhook.v2.Message
+	35, // 54: emqx.exhook.v2.Message.headers:type_name -> emqx.exhook.v2.Message.HeadersEntry
+	2,  // 55: emqx.exhook.v2.HookProvider.OnProviderLoaded:input_type -> emqx.exhook.v2.ProviderLoadedRequest
+	3,  // 56: emqx.exhook.v2.HookProvider.OnProviderUnloaded:input_type -> emqx.exhook.v2.ProviderUnloadedRequest
+	4,  // 57: emqx.exhook.v2.HookProvider.OnClientConnect:input_type -> emqx.exhook.v2.ClientConnectRequest
+	5,  // 58: emqx.exhook.v2.HookProvider.OnClientConnack:input_type -> emqx.exhook.v2.ClientConnackRequest
+	6,  // 59: emqx.exhook.v2.HookProvider.OnClientConnected:input_type -> emqx.exhook.v2.ClientConnectedRequest
+	7,  // 60: emqx.exhook.v2.HookProvider.OnClientDisconnected:input_type -> emqx.exhook.v2.ClientDisconnectedRequest
+	8,  // 61: emqx.exhook.v2.HookProvider.OnClientAuthenticate:input_type -> emqx.exhook.v2.ClientAuthenticateRequest
+	9,  // 62: emqx.exhook.v2.HookProvider.OnClientAuthorize:input_type -> emqx.exhook.v2.ClientAuthorizeRequest
+	10, // 63: emqx.exhook.v2.HookProvider.OnClientSubscribe:input_type -> emqx.exhook.v2.ClientSubscribeRequest
+	11, // 64: emqx.exhook.v2.HookProvider.OnClientUnsubscribe:input_type -> emqx.exhook.v2.ClientUnsubscribeRequest
+	12, // 65: emqx.exhook.v2.HookProvider.OnSessionCreated:input_type -> emqx.exhook.v2.SessionCreatedRequest
+	13, // 66: emqx.exhook.v2.HookProvider.OnSessionSubscribed:input_type -> emqx.exhook.v2.SessionSubscribedRequest
+	14, // 67: emqx.exhook.v2.HookProvider.OnSessionUnsubscribed:input_type -> emqx.exhook.v2.SessionUnsubscribedRequest
+	15, // 68: emqx.exhook.v2.HookProvider.OnSessionResumed:input_type -> emqx.exhook.v2.SessionResumedRequest
+	16, // 69: emqx.exhook.v2.HookProvider.OnSessionDiscarded:input_type -> emqx.exhook.v2.SessionDiscardedRequest
+	17, // 70: emqx.exhook.v2.HookProvider.OnSessionTakenover:input_type -> emqx.exhook.v2.SessionTakenoverRequest
+	18, // 71: emqx.exhook.v2.HookProvider.OnSessionTerminated:input_type -> emqx.exhook.v2.SessionTerminatedRequest
+	19, // 72: emqx.exhook.v2.HookProvider.OnMessagePublish:input_type -> emqx.exhook.v2.MessagePublishRequest
+	20, // 73: emqx.exhook.v2.HookProvider.OnMessageDelivered:input_type -> emqx.exhook.v2.MessageDeliveredRequest
+	21, // 74: emqx.exhook.v2.HookProvider.OnMessageDropped:input_type -> emqx.exhook.v2.MessageDroppedRequest
+	22, // 75: emqx.exhook.v2.HookProvider.OnMessageAcked:input_type -> emqx.exhook.v2.MessageAckedRequest
+	23, // 76: emqx.exhook.v2.HookProvider.OnProviderLoaded:output_type -> emqx.exhook.v2.LoadedResponse
+	25, // 77: emqx.exhook.v2.HookProvider.OnProviderUnloaded:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 78: emqx.exhook.v2.HookProvider.OnClientConnect:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 79: emqx.exhook.v2.HookProvider.OnClientConnack:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 80: emqx.exhook.v2.HookProvider.OnClientConnected:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 81: emqx.exhook.v2.HookProvider.OnClientDisconnected:output_type -> emqx.exhook.v2.EmptySuccess
+	24, // 82: emqx.exhook.v2.HookProvider.OnClientAuthenticate:output_type -> emqx.exhook.v2.ValuedResponse
+	24, // 83: emqx.exhook.v2.HookProvider.OnClientAuthorize:output_type -> emqx.exhook.v2.ValuedResponse
+	25, // 84: emqx.exhook.v2.HookProvider.OnClientSubscribe:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 85: emqx.exhook.v2.HookProvider.OnClientUnsubscribe:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 86: emqx.exhook.v2.HookProvider.OnSessionCreated:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 87: emqx.exhook.v2.HookProvider.OnSessionSubscribed:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 88: emqx.exhook.v2.HookProvider.OnSessionUnsubscribed:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 89: emqx.exhook.v2.HookProvider.OnSessionResumed:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 90: emqx.exhook.v2.HookProvider.OnSessionDiscarded:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 91: emqx.exhook.v2.HookProvider.OnSessionTakenover:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 92: emqx.exhook.v2.HookProvider.OnSessionTerminated:output_type -> emqx.exhook.v2.EmptySuccess
+	24, // 93: emqx.exhook.v2.HookProvider.OnMessagePublish:output_type -> emqx.exhook.v2.ValuedResponse
+	25, // 94: emqx.exhook.v2.HookProvider.OnMessageDelivered:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 95: emqx.exhook.v2.HookProvider.OnMessageDropped:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 96: emqx.exhook.v2.HookProvider.OnMessageAcked:output_type -> emqx.exhook.v2.EmptySuccess
+	76, // [76:97] is the sub-list for method output_type
+	55, // [55:76] is the sub-list for method input_type
+	55, // [55:55] is the sub-list for extension type_name
+	55, // [55:55] is the sub-list for extension extendee
+	0,  // [0:55] is the sub-list for field type_name
+}
+
+func init() { file_protobuf_exhook_proto_init() }
+func file_protobuf_exhook_proto_init() {
+	if File_protobuf_exhook_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_protobuf_exhook_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ProviderLoadedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ProviderUnloadedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientConnectRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientConnackRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientConnectedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientDisconnectedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientAuthenticateRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientAuthorizeRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientSubscribeRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientUnsubscribeRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SessionCreatedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SessionSubscribedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SessionUnsubscribedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SessionResumedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SessionDiscardedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SessionTakenoverRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SessionTerminatedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MessagePublishRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MessageDeliveredRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MessageDroppedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MessageAckedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*LoadedResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValuedResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*EmptySuccess); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*BrokerInfo); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*HookSpec); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ConnInfo); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientInfo); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Message); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Property); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TopicFilter); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SubOpts); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*RequestMeta); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	file_protobuf_exhook_proto_msgTypes[22].OneofWrappers = []interface{}{
+		(*ValuedResponse_BoolResult)(nil),
+		(*ValuedResponse_Message)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_protobuf_exhook_proto_rawDesc,
+			NumEnums:      2,
+			NumMessages:   34,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_protobuf_exhook_proto_goTypes,
+		DependencyIndexes: file_protobuf_exhook_proto_depIdxs,
+		EnumInfos:         file_protobuf_exhook_proto_enumTypes,
+		MessageInfos:      file_protobuf_exhook_proto_msgTypes,
+	}.Build()
+	File_protobuf_exhook_proto = out.File
+	file_protobuf_exhook_proto_rawDesc = nil
+	file_protobuf_exhook_proto_goTypes = nil
+	file_protobuf_exhook_proto_depIdxs = nil
+}

+ 499 - 0
services/emqx-agent/protobuf/exhook.proto

@@ -0,0 +1,499 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+syntax = "proto3";
+
+option csharp_namespace = "Emqx.Exhook.V2";
+option go_package = "emqx.io/grpc/exhook";
+option java_multiple_files = true;
+option java_package = "io.emqx.exhook";
+option java_outer_classname = "EmqxExHookProto";
+
+// The exhook proto version should be fixed as `v2` in EMQX v5.x
+// to make sure the exhook proto version is compatible
+package emqx.exhook.v2;
+
+service HookProvider {
+
+  rpc OnProviderLoaded(ProviderLoadedRequest) returns (LoadedResponse) {};
+
+  rpc OnProviderUnloaded(ProviderUnloadedRequest) returns (EmptySuccess) {};
+
+  rpc OnClientConnect(ClientConnectRequest) returns (EmptySuccess) {};
+
+  rpc OnClientConnack(ClientConnackRequest) returns (EmptySuccess) {};
+
+  rpc OnClientConnected(ClientConnectedRequest) returns (EmptySuccess) {};
+
+  rpc OnClientDisconnected(ClientDisconnectedRequest) returns (EmptySuccess) {};
+
+  rpc OnClientAuthenticate(ClientAuthenticateRequest) returns (ValuedResponse) {};
+
+  rpc OnClientAuthorize(ClientAuthorizeRequest) returns (ValuedResponse) {};
+
+  rpc OnClientSubscribe(ClientSubscribeRequest) returns (EmptySuccess) {};
+
+  rpc OnClientUnsubscribe(ClientUnsubscribeRequest) returns (EmptySuccess) {};
+
+  rpc OnSessionCreated(SessionCreatedRequest) returns (EmptySuccess) {};
+
+  rpc OnSessionSubscribed(SessionSubscribedRequest) returns (EmptySuccess) {};
+
+  rpc OnSessionUnsubscribed(SessionUnsubscribedRequest) returns (EmptySuccess) {};
+
+  rpc OnSessionResumed(SessionResumedRequest) returns (EmptySuccess) {};
+
+  rpc OnSessionDiscarded(SessionDiscardedRequest) returns (EmptySuccess) {};
+
+  rpc OnSessionTakenover(SessionTakenoverRequest) returns (EmptySuccess) {};
+
+  rpc OnSessionTerminated(SessionTerminatedRequest) returns (EmptySuccess) {};
+
+  rpc OnMessagePublish(MessagePublishRequest) returns (ValuedResponse) {};
+
+  rpc OnMessageDelivered(MessageDeliveredRequest) returns (EmptySuccess) {};
+
+  rpc OnMessageDropped(MessageDroppedRequest) returns (EmptySuccess) {};
+
+  rpc OnMessageAcked(MessageAckedRequest) returns (EmptySuccess) {};
+}
+
+//------------------------------------------------------------------------------
+// Request
+//------------------------------------------------------------------------------
+
+message ProviderLoadedRequest {
+
+  BrokerInfo broker = 1;
+
+  RequestMeta meta = 2;
+}
+
+message ProviderUnloadedRequest {
+
+  RequestMeta meta = 1;
+}
+
+message ClientConnectRequest {
+
+  ConnInfo conninfo = 1;
+
+  // MQTT CONNECT packet's properties (MQTT v5.0)
+  //
+  // It should be empty on MQTT v3.1.1/v3.1 or others protocol
+  repeated Property props = 2;
+
+  RequestMeta meta = 3;
+}
+
+message ClientConnackRequest {
+
+  ConnInfo conninfo = 1;
+
+  string result_code = 2;
+
+  repeated Property props = 3;
+
+  RequestMeta meta = 4;
+}
+
+message ClientConnectedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  RequestMeta meta = 2;
+}
+
+message ClientDisconnectedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  string reason = 2;
+
+  RequestMeta meta = 3;
+}
+
+message ClientAuthenticateRequest {
+
+  ClientInfo clientinfo = 1;
+
+  bool result = 2;
+
+  RequestMeta meta = 3;
+}
+
+message ClientAuthorizeRequest {
+
+  ClientInfo clientinfo = 1;
+
+  enum AuthorizeReqType {
+
+    PUBLISH = 0;
+
+    SUBSCRIBE = 1;
+  }
+
+  AuthorizeReqType type = 2;
+
+  string topic = 3;
+
+  bool result = 4;
+
+  RequestMeta meta = 5;
+}
+
+message ClientSubscribeRequest {
+
+  ClientInfo clientinfo = 1;
+
+  repeated Property props = 2;
+
+  repeated TopicFilter topic_filters = 3;
+
+  RequestMeta meta = 4;
+}
+
+message ClientUnsubscribeRequest {
+
+  ClientInfo clientinfo = 1;
+
+  repeated Property props = 2;
+
+  repeated TopicFilter topic_filters = 3;
+
+  RequestMeta meta = 4;
+}
+
+message SessionCreatedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  RequestMeta meta = 2;
+}
+
+message SessionSubscribedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  string topic = 2;
+
+  SubOpts subopts = 3;
+
+  RequestMeta meta = 4;
+}
+
+message SessionUnsubscribedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  string topic = 2;
+
+  RequestMeta meta = 3;
+}
+
+message SessionResumedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  RequestMeta meta = 2;
+}
+
+message SessionDiscardedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  RequestMeta meta = 2;
+}
+
+message SessionTakenoverRequest {
+
+  ClientInfo clientinfo = 1;
+
+  RequestMeta meta = 2;
+}
+
+message SessionTerminatedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  string reason = 2;
+
+  RequestMeta meta = 3;
+}
+
+message MessagePublishRequest {
+
+  Message message = 1;
+
+  RequestMeta meta = 2;
+}
+
+message MessageDeliveredRequest {
+
+  ClientInfo clientinfo = 1;
+
+  Message message = 2;
+
+  RequestMeta meta = 3;
+}
+
+message MessageDroppedRequest {
+
+  Message message = 1;
+
+  string reason = 2;
+
+  RequestMeta meta = 3;
+}
+
+message MessageAckedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  Message message = 2;
+
+  RequestMeta meta = 3;
+}
+
+//------------------------------------------------------------------------------
+// Response
+//------------------------------------------------------------------------------
+
+// Responsed by `ProviderLoadedRequest`
+
+message LoadedResponse {
+
+  repeated HookSpec hooks = 1;
+}
+
+// Responsed by `ClientAuthenticateRequest` `ClientAuthorizeRequest` `MessagePublishRequest`
+
+message ValuedResponse {
+
+  // The responded value type
+  //  - contiune: Use the responded value and execute the next hook
+  //  - ignore: Ignore the responded value
+  //  - stop_and_return: Use the responded value and stop the chain executing
+  enum ResponsedType {
+
+    CONTINUE = 0;
+
+    IGNORE = 1;
+
+    STOP_AND_RETURN = 2;
+  }
+
+  ResponsedType type = 1;
+
+  oneof value {
+
+    // Boolean result, used on the 'client.authenticate', 'client.authorize' hooks
+    bool bool_result = 3;
+
+    // Message result, used on the 'message.*' hooks
+    Message message = 4;
+  }
+}
+
+// no Response by other Requests
+
+message EmptySuccess {}
+
+//------------------------------------------------------------------------------
+// Basic data types
+//------------------------------------------------------------------------------
+
+message BrokerInfo {
+
+  string version = 1;
+
+  string sysdescr = 2;
+
+  int64 uptime = 3;
+
+  string datetime = 4;
+}
+
+
+message HookSpec {
+
+  // The registered hooks name
+  //
+  // Available value:
+  //   "client.connect",      "client.connack"
+  //   "client.connected",    "client.disconnected"
+  //   "client.authenticate", "client.authorize"
+  //   "client.subscribe",    "client.unsubscribe"
+  //
+  //   "session.created",      "session.subscribed"
+  //   "session.unsubscribed", "session.resumed"
+  //   "session.discarded",    "session.takenover"
+  //   "session.terminated"
+  //
+  //   "message.publish", "message.delivered"
+  //   "message.acked",   "message.dropped"
+  string name = 1;
+
+  // The topic filters for message hooks
+  repeated string topics = 2;
+}
+
+message ConnInfo {
+
+  string node = 1;
+
+  string clientid = 2;
+
+  string username = 3;
+
+  string peerhost = 4;
+
+  uint32 sockport = 5;
+
+  string proto_name = 6;
+
+  string proto_ver = 7;
+
+  uint32 keepalive = 8;
+}
+
+message ClientInfo {
+
+  string node = 1;
+
+  string clientid = 2;
+
+  string username = 3;
+
+  string password = 4;
+
+  string peerhost = 5;
+
+  uint32 sockport = 6;
+
+  string protocol = 7;
+
+  string mountpoint = 8;
+
+  bool  is_superuser = 9;
+
+  bool  anonymous = 10;
+
+  // common name of client TLS cert
+  string cn = 11;
+
+  // subject of client TLS cert
+  string dn = 12;
+}
+
+message Message {
+
+  string node = 1;
+
+  string id = 2;
+
+  uint32 qos = 3;
+
+  string from = 4;
+
+  string topic = 5;
+
+  bytes  payload = 6;
+
+  uint64 timestamp = 7;
+
+  // The key of header can be:
+  //  - username:
+  //    * Readonly
+  //    * The username of sender client
+  //    * Value type: utf8 string
+  //  - protocol:
+  //    * Readonly
+  //    * The protocol name of sender client
+  //    * Value type: string enum with "mqtt", "mqtt-sn", ...
+  //  - peerhost:
+  //    * Readonly
+  //    * The peerhost of sender client
+  //    * Value type: ip address string
+  //  - allow_publish:
+  //    * Writable
+  //    * Whether to allow the message to be published by emqx
+  //    * Value type: string enum with "true", "false", default is "true"
+  //
+  // Notes: All header may be missing, which means that the message does not
+  //   carry these headers. We can guarantee that clients coming from MQTT,
+  //   MQTT-SN, CoAP, LwM2M and other natively supported protocol clients will
+  //   carry these headers, but there is no guarantee that messages published
+  //   by other means will do, e.g. messages published by HTTP-API
+  map<string, string> headers = 8;
+}
+
+message Property {
+
+  string name = 1;
+
+  string value = 2;
+}
+
+message TopicFilter {
+
+  string name = 1;
+
+  uint32 qos = 2;
+}
+
+message SubOpts {
+
+  // The QoS level
+  uint32 qos = 1;
+
+  // The group name for shared subscription
+  string share = 2;
+
+  // The Retain Handling option (MQTT v5.0)
+  //
+  //  0 = Send retained messages at the time of the subscribe
+  //  1 = Send retained messages at subscribe only if the subscription does
+  //       not currently exist
+  //  2 = Do not send retained messages at the time of the subscribe
+  uint32 rh = 3;
+
+  // The Retain as Published option (MQTT v5.0)
+  //
+  //  If 1, Application Messages forwarded using this subscription keep the
+  //        RETAIN flag they were published with.
+  //  If 0, Application Messages forwarded using this subscription have the
+  //        RETAIN flag set to 0.
+  // Retained messages sent when the subscription is established have the RETAIN flag set to 1.
+  uint32 rap = 4;
+
+  // The No Local option (MQTT v5.0)
+  //
+  // If the value is 1, Application Messages MUST NOT be forwarded to a
+  // connection with a ClientID equal to the ClientID of the publishing
+  uint32 nl = 5;
+}
+
+message RequestMeta {
+
+  string node = 1;
+
+  string version = 2;
+
+  string sysdescr = 3;
+
+  string cluster_name = 4;
+}

+ 868 - 0
services/emqx-agent/protobuf/exhook_grpc.pb.go

@@ -0,0 +1,868 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.3.0
+// - protoc             v4.25.1
+// source: protobuf/exhook.proto
+
+// The exhook proto version should be fixed as `v2` in EMQX v5.x
+// to make sure the exhook proto version is compatible
+
+package exhook
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+const (
+	HookProvider_OnProviderLoaded_FullMethodName      = "/emqx.exhook.v2.HookProvider/OnProviderLoaded"
+	HookProvider_OnProviderUnloaded_FullMethodName    = "/emqx.exhook.v2.HookProvider/OnProviderUnloaded"
+	HookProvider_OnClientConnect_FullMethodName       = "/emqx.exhook.v2.HookProvider/OnClientConnect"
+	HookProvider_OnClientConnack_FullMethodName       = "/emqx.exhook.v2.HookProvider/OnClientConnack"
+	HookProvider_OnClientConnected_FullMethodName     = "/emqx.exhook.v2.HookProvider/OnClientConnected"
+	HookProvider_OnClientDisconnected_FullMethodName  = "/emqx.exhook.v2.HookProvider/OnClientDisconnected"
+	HookProvider_OnClientAuthenticate_FullMethodName  = "/emqx.exhook.v2.HookProvider/OnClientAuthenticate"
+	HookProvider_OnClientAuthorize_FullMethodName     = "/emqx.exhook.v2.HookProvider/OnClientAuthorize"
+	HookProvider_OnClientSubscribe_FullMethodName     = "/emqx.exhook.v2.HookProvider/OnClientSubscribe"
+	HookProvider_OnClientUnsubscribe_FullMethodName   = "/emqx.exhook.v2.HookProvider/OnClientUnsubscribe"
+	HookProvider_OnSessionCreated_FullMethodName      = "/emqx.exhook.v2.HookProvider/OnSessionCreated"
+	HookProvider_OnSessionSubscribed_FullMethodName   = "/emqx.exhook.v2.HookProvider/OnSessionSubscribed"
+	HookProvider_OnSessionUnsubscribed_FullMethodName = "/emqx.exhook.v2.HookProvider/OnSessionUnsubscribed"
+	HookProvider_OnSessionResumed_FullMethodName      = "/emqx.exhook.v2.HookProvider/OnSessionResumed"
+	HookProvider_OnSessionDiscarded_FullMethodName    = "/emqx.exhook.v2.HookProvider/OnSessionDiscarded"
+	HookProvider_OnSessionTakenover_FullMethodName    = "/emqx.exhook.v2.HookProvider/OnSessionTakenover"
+	HookProvider_OnSessionTerminated_FullMethodName   = "/emqx.exhook.v2.HookProvider/OnSessionTerminated"
+	HookProvider_OnMessagePublish_FullMethodName      = "/emqx.exhook.v2.HookProvider/OnMessagePublish"
+	HookProvider_OnMessageDelivered_FullMethodName    = "/emqx.exhook.v2.HookProvider/OnMessageDelivered"
+	HookProvider_OnMessageDropped_FullMethodName      = "/emqx.exhook.v2.HookProvider/OnMessageDropped"
+	HookProvider_OnMessageAcked_FullMethodName        = "/emqx.exhook.v2.HookProvider/OnMessageAcked"
+)
+
+// HookProviderClient is the client API for HookProvider service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type HookProviderClient interface {
+	OnProviderLoaded(ctx context.Context, in *ProviderLoadedRequest, opts ...grpc.CallOption) (*LoadedResponse, error)
+	OnProviderUnloaded(ctx context.Context, in *ProviderUnloadedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnClientConnect(ctx context.Context, in *ClientConnectRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnClientConnack(ctx context.Context, in *ClientConnackRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnClientConnected(ctx context.Context, in *ClientConnectedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnClientDisconnected(ctx context.Context, in *ClientDisconnectedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnClientAuthenticate(ctx context.Context, in *ClientAuthenticateRequest, opts ...grpc.CallOption) (*ValuedResponse, error)
+	OnClientAuthorize(ctx context.Context, in *ClientAuthorizeRequest, opts ...grpc.CallOption) (*ValuedResponse, error)
+	OnClientSubscribe(ctx context.Context, in *ClientSubscribeRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnClientUnsubscribe(ctx context.Context, in *ClientUnsubscribeRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnSessionCreated(ctx context.Context, in *SessionCreatedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnSessionSubscribed(ctx context.Context, in *SessionSubscribedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnSessionUnsubscribed(ctx context.Context, in *SessionUnsubscribedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnSessionResumed(ctx context.Context, in *SessionResumedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnSessionDiscarded(ctx context.Context, in *SessionDiscardedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnSessionTakenover(ctx context.Context, in *SessionTakenoverRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnSessionTerminated(ctx context.Context, in *SessionTerminatedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnMessagePublish(ctx context.Context, in *MessagePublishRequest, opts ...grpc.CallOption) (*ValuedResponse, error)
+	OnMessageDelivered(ctx context.Context, in *MessageDeliveredRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnMessageDropped(ctx context.Context, in *MessageDroppedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnMessageAcked(ctx context.Context, in *MessageAckedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+}
+
+type hookProviderClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewHookProviderClient(cc grpc.ClientConnInterface) HookProviderClient {
+	return &hookProviderClient{cc}
+}
+
+func (c *hookProviderClient) OnProviderLoaded(ctx context.Context, in *ProviderLoadedRequest, opts ...grpc.CallOption) (*LoadedResponse, error) {
+	out := new(LoadedResponse)
+	err := c.cc.Invoke(ctx, HookProvider_OnProviderLoaded_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnProviderUnloaded(ctx context.Context, in *ProviderUnloadedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnProviderUnloaded_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientConnect(ctx context.Context, in *ClientConnectRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientConnect_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientConnack(ctx context.Context, in *ClientConnackRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientConnack_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientConnected(ctx context.Context, in *ClientConnectedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientConnected_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientDisconnected(ctx context.Context, in *ClientDisconnectedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientDisconnected_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientAuthenticate(ctx context.Context, in *ClientAuthenticateRequest, opts ...grpc.CallOption) (*ValuedResponse, error) {
+	out := new(ValuedResponse)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientAuthenticate_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientAuthorize(ctx context.Context, in *ClientAuthorizeRequest, opts ...grpc.CallOption) (*ValuedResponse, error) {
+	out := new(ValuedResponse)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientAuthorize_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientSubscribe(ctx context.Context, in *ClientSubscribeRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientSubscribe_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientUnsubscribe(ctx context.Context, in *ClientUnsubscribeRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientUnsubscribe_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnSessionCreated(ctx context.Context, in *SessionCreatedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnSessionCreated_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnSessionSubscribed(ctx context.Context, in *SessionSubscribedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnSessionSubscribed_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnSessionUnsubscribed(ctx context.Context, in *SessionUnsubscribedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnSessionUnsubscribed_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnSessionResumed(ctx context.Context, in *SessionResumedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnSessionResumed_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnSessionDiscarded(ctx context.Context, in *SessionDiscardedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnSessionDiscarded_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnSessionTakenover(ctx context.Context, in *SessionTakenoverRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnSessionTakenover_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnSessionTerminated(ctx context.Context, in *SessionTerminatedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnSessionTerminated_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnMessagePublish(ctx context.Context, in *MessagePublishRequest, opts ...grpc.CallOption) (*ValuedResponse, error) {
+	out := new(ValuedResponse)
+	err := c.cc.Invoke(ctx, HookProvider_OnMessagePublish_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnMessageDelivered(ctx context.Context, in *MessageDeliveredRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnMessageDelivered_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnMessageDropped(ctx context.Context, in *MessageDroppedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnMessageDropped_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnMessageAcked(ctx context.Context, in *MessageAckedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnMessageAcked_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// HookProviderServer is the server API for HookProvider service.
+// All implementations must embed UnimplementedHookProviderServer
+// for forward compatibility
+type HookProviderServer interface {
+	OnProviderLoaded(context.Context, *ProviderLoadedRequest) (*LoadedResponse, error)
+	OnProviderUnloaded(context.Context, *ProviderUnloadedRequest) (*EmptySuccess, error)
+	OnClientConnect(context.Context, *ClientConnectRequest) (*EmptySuccess, error)
+	OnClientConnack(context.Context, *ClientConnackRequest) (*EmptySuccess, error)
+	OnClientConnected(context.Context, *ClientConnectedRequest) (*EmptySuccess, error)
+	OnClientDisconnected(context.Context, *ClientDisconnectedRequest) (*EmptySuccess, error)
+	OnClientAuthenticate(context.Context, *ClientAuthenticateRequest) (*ValuedResponse, error)
+	OnClientAuthorize(context.Context, *ClientAuthorizeRequest) (*ValuedResponse, error)
+	OnClientSubscribe(context.Context, *ClientSubscribeRequest) (*EmptySuccess, error)
+	OnClientUnsubscribe(context.Context, *ClientUnsubscribeRequest) (*EmptySuccess, error)
+	OnSessionCreated(context.Context, *SessionCreatedRequest) (*EmptySuccess, error)
+	OnSessionSubscribed(context.Context, *SessionSubscribedRequest) (*EmptySuccess, error)
+	OnSessionUnsubscribed(context.Context, *SessionUnsubscribedRequest) (*EmptySuccess, error)
+	OnSessionResumed(context.Context, *SessionResumedRequest) (*EmptySuccess, error)
+	OnSessionDiscarded(context.Context, *SessionDiscardedRequest) (*EmptySuccess, error)
+	OnSessionTakenover(context.Context, *SessionTakenoverRequest) (*EmptySuccess, error)
+	OnSessionTerminated(context.Context, *SessionTerminatedRequest) (*EmptySuccess, error)
+	OnMessagePublish(context.Context, *MessagePublishRequest) (*ValuedResponse, error)
+	OnMessageDelivered(context.Context, *MessageDeliveredRequest) (*EmptySuccess, error)
+	OnMessageDropped(context.Context, *MessageDroppedRequest) (*EmptySuccess, error)
+	OnMessageAcked(context.Context, *MessageAckedRequest) (*EmptySuccess, error)
+	mustEmbedUnimplementedHookProviderServer()
+}
+
+// UnimplementedHookProviderServer must be embedded to have forward compatible implementations.
+type UnimplementedHookProviderServer struct {
+}
+
+func (UnimplementedHookProviderServer) OnProviderLoaded(context.Context, *ProviderLoadedRequest) (*LoadedResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnProviderLoaded not implemented")
+}
+func (UnimplementedHookProviderServer) OnProviderUnloaded(context.Context, *ProviderUnloadedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnProviderUnloaded not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientConnect(context.Context, *ClientConnectRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientConnect not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientConnack(context.Context, *ClientConnackRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientConnack not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientConnected(context.Context, *ClientConnectedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientConnected not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientDisconnected(context.Context, *ClientDisconnectedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientDisconnected not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientAuthenticate(context.Context, *ClientAuthenticateRequest) (*ValuedResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientAuthenticate not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientAuthorize(context.Context, *ClientAuthorizeRequest) (*ValuedResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientAuthorize not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientSubscribe(context.Context, *ClientSubscribeRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientSubscribe not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientUnsubscribe(context.Context, *ClientUnsubscribeRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientUnsubscribe not implemented")
+}
+func (UnimplementedHookProviderServer) OnSessionCreated(context.Context, *SessionCreatedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnSessionCreated not implemented")
+}
+func (UnimplementedHookProviderServer) OnSessionSubscribed(context.Context, *SessionSubscribedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnSessionSubscribed not implemented")
+}
+func (UnimplementedHookProviderServer) OnSessionUnsubscribed(context.Context, *SessionUnsubscribedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnSessionUnsubscribed not implemented")
+}
+func (UnimplementedHookProviderServer) OnSessionResumed(context.Context, *SessionResumedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnSessionResumed not implemented")
+}
+func (UnimplementedHookProviderServer) OnSessionDiscarded(context.Context, *SessionDiscardedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnSessionDiscarded not implemented")
+}
+func (UnimplementedHookProviderServer) OnSessionTakenover(context.Context, *SessionTakenoverRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnSessionTakenover not implemented")
+}
+func (UnimplementedHookProviderServer) OnSessionTerminated(context.Context, *SessionTerminatedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnSessionTerminated not implemented")
+}
+func (UnimplementedHookProviderServer) OnMessagePublish(context.Context, *MessagePublishRequest) (*ValuedResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnMessagePublish not implemented")
+}
+func (UnimplementedHookProviderServer) OnMessageDelivered(context.Context, *MessageDeliveredRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnMessageDelivered not implemented")
+}
+func (UnimplementedHookProviderServer) OnMessageDropped(context.Context, *MessageDroppedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnMessageDropped not implemented")
+}
+func (UnimplementedHookProviderServer) OnMessageAcked(context.Context, *MessageAckedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnMessageAcked not implemented")
+}
+func (UnimplementedHookProviderServer) mustEmbedUnimplementedHookProviderServer() {}
+
+// UnsafeHookProviderServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to HookProviderServer will
+// result in compilation errors.
+type UnsafeHookProviderServer interface {
+	mustEmbedUnimplementedHookProviderServer()
+}
+
+func RegisterHookProviderServer(s grpc.ServiceRegistrar, srv HookProviderServer) {
+	s.RegisterService(&HookProvider_ServiceDesc, srv)
+}
+
+func _HookProvider_OnProviderLoaded_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ProviderLoadedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnProviderLoaded(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnProviderLoaded_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnProviderLoaded(ctx, req.(*ProviderLoadedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnProviderUnloaded_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ProviderUnloadedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnProviderUnloaded(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnProviderUnloaded_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnProviderUnloaded(ctx, req.(*ProviderUnloadedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientConnect_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientConnectRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientConnect(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientConnect_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientConnect(ctx, req.(*ClientConnectRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientConnack_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientConnackRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientConnack(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientConnack_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientConnack(ctx, req.(*ClientConnackRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientConnected_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientConnectedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientConnected(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientConnected_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientConnected(ctx, req.(*ClientConnectedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientDisconnected_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientDisconnectedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientDisconnected(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientDisconnected_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientDisconnected(ctx, req.(*ClientDisconnectedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientAuthenticate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientAuthenticateRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientAuthenticate(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientAuthenticate_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientAuthenticate(ctx, req.(*ClientAuthenticateRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientAuthorize_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientAuthorizeRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientAuthorize(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientAuthorize_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientAuthorize(ctx, req.(*ClientAuthorizeRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientSubscribe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientSubscribeRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientSubscribe(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientSubscribe_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientSubscribe(ctx, req.(*ClientSubscribeRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientUnsubscribe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientUnsubscribeRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientUnsubscribe(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientUnsubscribe_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientUnsubscribe(ctx, req.(*ClientUnsubscribeRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnSessionCreated_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SessionCreatedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnSessionCreated(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnSessionCreated_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnSessionCreated(ctx, req.(*SessionCreatedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnSessionSubscribed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SessionSubscribedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnSessionSubscribed(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnSessionSubscribed_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnSessionSubscribed(ctx, req.(*SessionSubscribedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnSessionUnsubscribed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SessionUnsubscribedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnSessionUnsubscribed(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnSessionUnsubscribed_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnSessionUnsubscribed(ctx, req.(*SessionUnsubscribedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnSessionResumed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SessionResumedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnSessionResumed(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnSessionResumed_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnSessionResumed(ctx, req.(*SessionResumedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnSessionDiscarded_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SessionDiscardedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnSessionDiscarded(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnSessionDiscarded_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnSessionDiscarded(ctx, req.(*SessionDiscardedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnSessionTakenover_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SessionTakenoverRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnSessionTakenover(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnSessionTakenover_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnSessionTakenover(ctx, req.(*SessionTakenoverRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnSessionTerminated_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SessionTerminatedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnSessionTerminated(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnSessionTerminated_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnSessionTerminated(ctx, req.(*SessionTerminatedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnMessagePublish_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(MessagePublishRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnMessagePublish(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnMessagePublish_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnMessagePublish(ctx, req.(*MessagePublishRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnMessageDelivered_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(MessageDeliveredRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnMessageDelivered(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnMessageDelivered_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnMessageDelivered(ctx, req.(*MessageDeliveredRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnMessageDropped_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(MessageDroppedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnMessageDropped(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnMessageDropped_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnMessageDropped(ctx, req.(*MessageDroppedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnMessageAcked_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(MessageAckedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnMessageAcked(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnMessageAcked_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnMessageAcked(ctx, req.(*MessageAckedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// HookProvider_ServiceDesc is the grpc.ServiceDesc for HookProvider service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var HookProvider_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "emqx.exhook.v2.HookProvider",
+	HandlerType: (*HookProviderServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "OnProviderLoaded",
+			Handler:    _HookProvider_OnProviderLoaded_Handler,
+		},
+		{
+			MethodName: "OnProviderUnloaded",
+			Handler:    _HookProvider_OnProviderUnloaded_Handler,
+		},
+		{
+			MethodName: "OnClientConnect",
+			Handler:    _HookProvider_OnClientConnect_Handler,
+		},
+		{
+			MethodName: "OnClientConnack",
+			Handler:    _HookProvider_OnClientConnack_Handler,
+		},
+		{
+			MethodName: "OnClientConnected",
+			Handler:    _HookProvider_OnClientConnected_Handler,
+		},
+		{
+			MethodName: "OnClientDisconnected",
+			Handler:    _HookProvider_OnClientDisconnected_Handler,
+		},
+		{
+			MethodName: "OnClientAuthenticate",
+			Handler:    _HookProvider_OnClientAuthenticate_Handler,
+		},
+		{
+			MethodName: "OnClientAuthorize",
+			Handler:    _HookProvider_OnClientAuthorize_Handler,
+		},
+		{
+			MethodName: "OnClientSubscribe",
+			Handler:    _HookProvider_OnClientSubscribe_Handler,
+		},
+		{
+			MethodName: "OnClientUnsubscribe",
+			Handler:    _HookProvider_OnClientUnsubscribe_Handler,
+		},
+		{
+			MethodName: "OnSessionCreated",
+			Handler:    _HookProvider_OnSessionCreated_Handler,
+		},
+		{
+			MethodName: "OnSessionSubscribed",
+			Handler:    _HookProvider_OnSessionSubscribed_Handler,
+		},
+		{
+			MethodName: "OnSessionUnsubscribed",
+			Handler:    _HookProvider_OnSessionUnsubscribed_Handler,
+		},
+		{
+			MethodName: "OnSessionResumed",
+			Handler:    _HookProvider_OnSessionResumed_Handler,
+		},
+		{
+			MethodName: "OnSessionDiscarded",
+			Handler:    _HookProvider_OnSessionDiscarded_Handler,
+		},
+		{
+			MethodName: "OnSessionTakenover",
+			Handler:    _HookProvider_OnSessionTakenover_Handler,
+		},
+		{
+			MethodName: "OnSessionTerminated",
+			Handler:    _HookProvider_OnSessionTerminated_Handler,
+		},
+		{
+			MethodName: "OnMessagePublish",
+			Handler:    _HookProvider_OnMessagePublish_Handler,
+		},
+		{
+			MethodName: "OnMessageDelivered",
+			Handler:    _HookProvider_OnMessageDelivered_Handler,
+		},
+		{
+			MethodName: "OnMessageDropped",
+			Handler:    _HookProvider_OnMessageDropped_Handler,
+		},
+		{
+			MethodName: "OnMessageAcked",
+			Handler:    _HookProvider_OnMessageAcked_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "protobuf/exhook.proto",
+}

+ 9 - 9
tests/device/device.go

@@ -15,7 +15,7 @@ import (
 	"sparrow/pkg/tlv"
 	"time"
 
-	MQTT "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
+	MQTT "github.com/eclipse/paho.mqtt.golang"
 )
 
 const (
@@ -166,7 +166,7 @@ func (d *Device) DoLogin() error {
 	return nil
 }
 
-func (d *Device) reportStatus(client *MQTT.Client) {
+func (d *Device) reportStatus(client MQTT.Client) {
 	for {
 		time.Sleep(2 * time.Second)
 		rand.Seed(time.Now().UnixNano())
@@ -190,7 +190,7 @@ func (d *Device) reportStatus(client *MQTT.Client) {
 	}
 
 }
-func (d *Device) reportStatus2(client *MQTT.Client) {
+func (d *Device) reportStatus2(client MQTT.Client) {
 	for {
 		time.Sleep(2 * time.Second)
 		rand.Seed(time.Now().UnixNano())
@@ -265,7 +265,7 @@ func (d *Device) coapReportStatus(conn *net.UDPConn) {
 	}
 }
 
-func (d *Device) reportEvent(client *MQTT.Client) {
+func (d *Device) reportEvent(client MQTT.Client) {
 	for {
 		time.Sleep(2 * time.Second)
 
@@ -288,7 +288,7 @@ func (d *Device) reportEvent(client *MQTT.Client) {
 	}
 }
 
-func (d *Device) statusHandler(client *MQTT.Client, msg MQTT.Message) {
+func (d *Device) statusHandler(client MQTT.Client, msg MQTT.Message) {
 	status := protocol.Data{}
 
 	err := status.UnMarshal(msg.Payload())
@@ -307,7 +307,7 @@ func (d *Device) statusHandler(client *MQTT.Client, msg MQTT.Message) {
 }
 
 // 子设备上线
-func (d *Device) subDeviceLogin(client *MQTT.Client) {
+func (d *Device) subDeviceLogin(client MQTT.Client) {
 	for {
 		dd := &klink.DevLogin{
 			Action:      "devLogin",
@@ -326,7 +326,7 @@ func (d *Device) subDeviceLogin(client *MQTT.Client) {
 }
 
 // 子设备上线
-func (d *Device) deviceNetConfig(client *MQTT.Client) {
+func (d *Device) deviceNetConfig(client MQTT.Client) {
 	j := `{
   "action": "devNetConfig",
   "timestamp": 12312312,
@@ -338,7 +338,7 @@ func (d *Device) deviceNetConfig(client *MQTT.Client) {
 
 }
 
-func (d *Device) commandHandler(client *MQTT.Client, msg MQTT.Message) {
+func (d *Device) commandHandler(client MQTT.Client, msg MQTT.Message) {
 	j, err := gjson.DecodeToJson(msg.Payload())
 	if err != nil {
 		panic("错误的报文格式")
@@ -346,7 +346,7 @@ func (d *Device) commandHandler(client *MQTT.Client, msg MQTT.Message) {
 	fmt.Printf("%v", j.MustToJsonString())
 }
 
-func (d *Device) messageHandler(client *MQTT.Client, msg MQTT.Message) {
+func (d *Device) messageHandler(client MQTT.Client, msg MQTT.Message) {
 	fmt.Printf("TOPIC: %s\n", msg.Topic())
 	fmt.Printf("MSG: %x\n", msg.Payload())
 	msgtype := msg.Topic()

BIN
vendor/.DS_Store


+ 0 - 69
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/CONTRIBUTING.md

@@ -1,69 +0,0 @@
-Contributing to Paho
-====================
-
-Thanks for your interest in this project.
-
-Project description:
---------------------
-
-The Paho project has been created to provide scalable open-source implementations of open and standard messaging protocols aimed at new, existing, and emerging applications for Machine-to-Machine (M2M) and Internet of Things (IoT).
-Paho reflects the inherent physical and cost constraints of device connectivity. Its objectives include effective levels of decoupling between devices and applications, designed to keep markets open and encourage the rapid growth of scalable Web and Enterprise middleware and applications. Paho is being kicked off with MQTT publish/subscribe client implementations for use on embedded platforms, along with corresponding server support as determined by the community.
-
-- https://projects.eclipse.org/projects/technology.paho
-
-Developer resources:
---------------------
-
-Information regarding source code management, builds, coding standards, and more.
-
-- https://projects.eclipse.org/projects/technology.paho/developer
-
-Contributor License Agreement:
-------------------------------
-
-Before your contribution can be accepted by the project, you need to create and electronically sign the Eclipse Foundation Contributor License Agreement (CLA).
-
-- http://www.eclipse.org/legal/CLA.php
-
-Contributing Code:
-------------------
-
-The Go client uses git with Gerrit for code review, use the following URLs for Gerrit access;
-
-ssh://<username>@git.eclipse.org:29418/paho/org.eclipse.paho.mqtt.golang
-
-Configure a remote called review to push your changes to;
-
-git config remote.review.url ssh://<username>@git.eclipse.org:29418/paho/org.eclipse.paho.mqtt.golang
-git config remote.review.push HEAD:refs/for/<branch>
-
-When you have made and committed a change you can push it to Gerrit for review with;
-
-git push review
-
-See https://wiki.eclipse.org/Gerrit for more details on how Gerrit is used in Eclipse, https://wiki.eclipse.org/Gerrit#Gerrit_Code_Review_Cheatsheet has some particularly useful information.
-
-Git commit messages should follow the style described here;
-
-http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
-
-Contact:
---------
-
-Contact the project developers via the project's "dev" list.
-
-- https://dev.eclipse.org/mailman/listinfo/paho-dev
-
-Search for bugs:
-----------------
-
-This project uses Bugzilla to track ongoing development and issues.
-
-- https://bugs.eclipse.org/bugs/buglist.cgi?product=Paho&component=MQTT-Go
-
-Create a new bug:
------------------
-
-Be sure to search for existing bugs before you create another one. Remember that contributions are always welcome!
-
-- https://bugs.eclipse.org/bugs/enter_bug.cgi?product=Paho

+ 0 - 15
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/DISTRIBUTION

@@ -1,15 +0,0 @@
-
-
-Eclipse Distribution License - v 1.0
-
-Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors.
-
-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 Eclipse Foundation, 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.

+ 0 - 87
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/LICENSE

@@ -1,87 +0,0 @@
-Eclipse Public License - v 1.0
-
-THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
-
-1. DEFINITIONS
-
-"Contribution" means:
-
-a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
-
-b) in the case of each subsequent Contributor:
-
-i) changes to the Program, and
-
-ii) additions to the Program;
-
-where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
-
-"Contributor" means any person or entity that distributes the Program.
-
-"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.
-
-"Program" means the Contributions distributed in accordance with this Agreement.
-
-"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
-
-2. GRANT OF RIGHTS
-
-a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
-
-b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
-
-c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
-
-d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
-
-3. REQUIREMENTS
-
-A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
-
-a) it complies with the terms and conditions of this Agreement; and
-
-b) its license agreement:
-
-i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
-
-ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
-
-iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
-
-iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
-
-When the Program is made available in source code form:
-
-a) it must be made available under this Agreement; and
-
-b) a copy of this Agreement must be included with each copy of the Program.
-
-Contributors may not remove or alter any copyright notices contained within the Program.
-
-Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.
-
-4. COMMERCIAL DISTRIBUTION
-
-Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.
-
-For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.
-
-5. NO WARRANTY
-
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
-
-6. DISCLAIMER OF LIABILITY
-
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
-7. GENERAL
-
-If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
-
-If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.
-
-All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.
-
-Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
-
-This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.

+ 0 - 62
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/README.md

@@ -1,62 +0,0 @@
-Eclipse Paho MQTT Go client
-===========================
-
-
-This repository contains the source code for the [Eclipse Paho](http://eclipse.org/paho) MQTT Go client library. 
-
-This code builds a library which enable applications to connect to an [MQTT](http://mqtt.org) broker to publish messages, and to subscribe to topics and receive published messages.
-
-This library supports a fully asynchronous mode of operation.
-
-
-Installation and Build
-----------------------
-
-This client is designed to work with the standard Go tools, so installation is as easy as:
-
-```
-go get git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git
-```
-
-The client depends on Google's [websockets](http://godoc.org/code.google.com/p/go.net/websocket) package, 
-also easily installed with the command:
-
-```
-go get code.google.com/p/go.net/websocket
-```
-
-
-Usage and API
--------------
-
-Detailed API documentation is available by using to godoc tool, or can be browsed online
-using the [godoc.org](http://godoc.org/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git) service.
-
-Make use of the library by importing it in your Go client source code. For example,
-```
-import MQTT "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
-```
-
-Samples are available in the `/samples` directory for reference.
-
-
-Runtime tracing
----------------
-
-Tracing is enabled by assigning logs (from the Go log package) to the logging endpoints, ERROR, CRITICAL, WARN and DEBUG
-
-
-Reporting bugs
---------------
-
-Please report bugs under the "MQTT-Go" Component in [Eclipse Bugzilla](http://bugs.eclipse.org/bugs/) for the Paho Technology project. This is a very new library as of Q1 2014, so there are sure to be bugs.
-
-
-More information
-----------------
-
-Discussion of the Paho clients takes place on the [Eclipse paho-dev mailing list](https://dev.eclipse.org/mailman/listinfo/paho-dev).
-
-General questions about the MQTT protocol are discussed in the [MQTT Google Group](https://groups.google.com/forum/?hl=en-US&fromgroups#!forum/mqtt).
-
-There is much more information available via the [MQTT community site](http://mqtt.org).

+ 0 - 41
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/about.html

@@ -1,41 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml"><head>
-<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-<title>About</title>
-</head>
-<body lang="EN-US">
-<h2>About This Content</h2>
- 
-<p><em>December 9, 2013</em></p>	
-<h3>License</h3>
-
-<p>The Eclipse Foundation makes available all content in this plug-in ("Content").  Unless otherwise 
-indicated below, the Content is provided to you under the terms and conditions of the
-Eclipse Public License Version 1.0 ("EPL") and Eclipse Distribution License Version 1.0 ("EDL").
-A copy of the EPL is available at 
-<a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> 
-and a copy of the EDL is available at 
-<a href="http://www.eclipse.org/org/documents/edl-v10.php">http://www.eclipse.org/org/documents/edl-v10.php</a>. 
-For purposes of the EPL, "Program" will mean the Content.</p>
-
-<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is 
-being redistributed by another party ("Redistributor") and different terms and conditions may
-apply to your use of any object code in the Content.  Check the Redistributor's license that was 
-provided with the Content.  If no such license exists, contact the Redistributor.  Unless otherwise
-indicated below, the terms and conditions of the EPL still apply to any source code in the Content
-and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
-
-		
-		<h3>Third Party Content</h3>
-		<p>The Content includes items that have been sourced from third parties as set out below. If you 
-		did not receive this Content directly from the Eclipse Foundation, the following is provided 
-		for informational purposes only, and you should look to the Redistributor's license for 
-		terms and conditions of use.</p>
-		<p><em>
-		<strong>None</strong> <br><br>
-		<br><br> 
-		</em></p>
-
-
-
-</body></html>

+ 0 - 521
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/client.go

@@ -1,521 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Seth Hoenig
- *    Allan Stockdill-Mander
- *    Mike Robertson
- */
-
-// Package mqtt provides an MQTT v3.1.1 client library.
-package mqtt
-
-import (
-	"errors"
-	"fmt"
-	"git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets"
-	"net"
-	"sync"
-	"time"
-)
-
-// ClientInt is the interface definition for a Client as used by this
-// library, the interface is primarily to allow mocking tests.
-type ClientInt interface {
-	IsConnected() bool
-	Connect() Token
-	Disconnect(uint)
-	disconnect()
-	Publish(string, byte, bool, interface{}) Token
-	Subscribe(string, byte, MessageHandler) Token
-	SubscribeMultiple(map[string]byte, MessageHandler) Token
-	Unsubscribe(...string) Token
-}
-
-// Client is an MQTT v3.1.1 client for communicating
-// with an MQTT server using non-blocking methods that allow work
-// to be done in the background.
-// An application may connect to an MQTT server using:
-//   A plain TCP socket
-//   A secure SSL/TLS socket
-//   A websocket
-// To enable ensured message delivery at Quality of Service (QoS) levels
-// described in the MQTT spec, a message persistence mechanism must be
-// used. This is done by providing a type which implements the Store
-// interface. For convenience, FileStore and MemoryStore are provided
-// implementations that should be sufficient for most use cases. More
-// information can be found in their respective documentation.
-// Numerous connection options may be specified by configuring a
-// and then supplying a ClientOptions type.
-type Client struct {
-	sync.RWMutex
-	messageIds
-	conn            net.Conn
-	ibound          chan packets.ControlPacket
-	obound          chan *PacketAndToken
-	oboundP         chan *PacketAndToken
-	msgRouter       *router
-	stopRouter      chan bool
-	incomingPubChan chan *packets.PublishPacket
-	errors          chan error
-	stop            chan struct{}
-	persist         Store
-	options         ClientOptions
-	lastContact     lastcontact
-	pingOutstanding bool
-	connected       bool
-	workers         sync.WaitGroup
-}
-
-// NewClient will create an MQTT v3.1.1 client with all of the options specified
-// in the provided ClientOptions. The client must have the Start method called
-// on it before it may be used. This is to make sure resources (such as a net
-// connection) are created before the application is actually ready.
-func NewClient(o *ClientOptions) *Client {
-	c := &Client{}
-	c.options = *o
-
-	if c.options.Store == nil {
-		c.options.Store = NewMemoryStore()
-	}
-	switch c.options.ProtocolVersion {
-	case 3, 4:
-		c.options.protocolVersionExplicit = true
-	default:
-		c.options.ProtocolVersion = 4
-		c.options.protocolVersionExplicit = false
-	}
-	c.persist = c.options.Store
-	c.connected = false
-	c.messageIds = messageIds{index: make(map[uint16]Token)}
-	c.msgRouter, c.stopRouter = newRouter()
-	c.msgRouter.setDefaultHandler(c.options.DefaultPublishHander)
-	return c
-}
-
-// IsConnected returns a bool signifying whether
-// the client is connected or not.
-func (c *Client) IsConnected() bool {
-	c.RLock()
-	defer c.RUnlock()
-	return c.connected
-}
-
-func (c *Client) setConnected(status bool) {
-	c.Lock()
-	defer c.Unlock()
-	c.connected = status
-}
-
-//ErrNotConnected is the error returned from function calls that are
-//made when the client is not connected to a broker
-var ErrNotConnected = errors.New("Not Connected")
-
-// Connect will create a connection to the message broker
-// If clean session is false, then a slice will
-// be returned containing Receipts for all messages
-// that were in-flight at the last disconnect.
-// If clean session is true, then any existing client
-// state will be removed.
-func (c *Client) Connect() Token {
-	var err error
-	t := newToken(packets.Connect).(*ConnectToken)
-	DEBUG.Println(CLI, "Connect()")
-
-	go func() {
-		var rc byte
-		cm := newConnectMsgFromOptions(&c.options)
-
-		for _, broker := range c.options.Servers {
-		CONN:
-			DEBUG.Println(CLI, "about to write new connect msg")
-			c.conn, err = openConnection(broker, &c.options.TLSConfig, c.options.ConnectTimeout)
-			if err == nil {
-				DEBUG.Println(CLI, "socket connected to broker")
-				switch c.options.ProtocolVersion {
-				case 3:
-					DEBUG.Println(CLI, "Using MQTT 3.1 protocol")
-					cm.ProtocolName = "MQIsdp"
-					cm.ProtocolVersion = 3
-				default:
-					DEBUG.Println(CLI, "Using MQTT 3.1.1 protocol")
-					c.options.ProtocolVersion = 4
-					cm.ProtocolName = "MQTT"
-					cm.ProtocolVersion = 4
-				}
-				cm.Write(c.conn)
-
-				rc = c.connect()
-				if rc != packets.Accepted {
-					c.conn.Close()
-					c.conn = nil
-					//if the protocol version was explicitly set don't do any fallback
-					if c.options.protocolVersionExplicit {
-						ERROR.Println(CLI, "Connecting to", broker, "CONNACK was not CONN_ACCEPTED, but rather", packets.ConnackReturnCodes[rc])
-						continue
-					}
-					if c.options.ProtocolVersion == 4 {
-						DEBUG.Println(CLI, "Trying reconnect using MQTT 3.1 protocol")
-						c.options.ProtocolVersion = 3
-						goto CONN
-					}
-				}
-				break
-			} else {
-				ERROR.Println(CLI, err.Error())
-				WARN.Println(CLI, "failed to connect to broker, trying next")
-				rc = packets.ErrNetworkError
-			}
-		}
-
-		if c.conn == nil {
-			ERROR.Println(CLI, "Failed to connect to a broker")
-			t.returnCode = rc
-			if rc != packets.ErrNetworkError {
-				t.err = packets.ConnErrors[rc]
-			} else {
-				t.err = fmt.Errorf("%s : %s", packets.ConnErrors[rc], err)
-			}
-			t.flowComplete()
-			return
-		}
-
-		c.lastContact.update()
-		c.persist.Open()
-
-		c.obound = make(chan *PacketAndToken, 100)
-		c.oboundP = make(chan *PacketAndToken, 100)
-		c.ibound = make(chan packets.ControlPacket)
-		c.errors = make(chan error)
-		c.stop = make(chan struct{})
-
-		c.incomingPubChan = make(chan *packets.PublishPacket, 100)
-		c.msgRouter.matchAndDispatch(c.incomingPubChan, c.options.Order, c)
-
-		c.workers.Add(1)
-		go outgoing(c)
-		go alllogic(c)
-
-		c.connected = true
-		DEBUG.Println(CLI, "client is connected")
-		if c.options.OnConnect != nil {
-			go c.options.OnConnect(c)
-		}
-
-		if c.options.KeepAlive != 0 {
-			c.workers.Add(1)
-			go keepalive(c)
-		}
-
-		// Take care of any messages in the store
-		//var leftovers []Receipt
-		if c.options.CleanSession == false {
-			//leftovers = c.resume()
-		} else {
-			c.persist.Reset()
-		}
-
-		// Do not start incoming until resume has completed
-		c.workers.Add(1)
-		go incoming(c)
-
-		DEBUG.Println(CLI, "exit startClient")
-		t.flowComplete()
-	}()
-	return t
-}
-
-// internal function used to reconnect the client when it loses its connection
-func (c *Client) reconnect() {
-	DEBUG.Println(CLI, "enter reconnect")
-	var rc byte = 1
-	var sleep uint = 1
-	var err error
-
-	for rc != 0 {
-		cm := newConnectMsgFromOptions(&c.options)
-
-		for _, broker := range c.options.Servers {
-		CONN:
-			DEBUG.Println(CLI, "about to write new connect msg")
-			c.conn, err = openConnection(broker, &c.options.TLSConfig, c.options.ConnectTimeout)
-			if err == nil {
-				DEBUG.Println(CLI, "socket connected to broker")
-				switch c.options.ProtocolVersion {
-				case 3:
-					DEBUG.Println(CLI, "Using MQTT 3.1 protocol")
-					cm.ProtocolName = "MQIsdp"
-					cm.ProtocolVersion = 3
-				default:
-					DEBUG.Println(CLI, "Using MQTT 3.1.1 protocol")
-					c.options.ProtocolVersion = 4
-					cm.ProtocolName = "MQTT"
-					cm.ProtocolVersion = 4
-				}
-				cm.Write(c.conn)
-
-				rc = c.connect()
-				if rc != packets.Accepted {
-					c.conn.Close()
-					c.conn = nil
-					//if the protocol version was explicitly set don't do any fallback
-					if c.options.protocolVersionExplicit {
-						ERROR.Println(CLI, "Connecting to", broker, "CONNACK was not Accepted, but rather", packets.ConnackReturnCodes[rc])
-						continue
-					}
-					if c.options.ProtocolVersion == 4 {
-						DEBUG.Println(CLI, "Trying reconnect using MQTT 3.1 protocol")
-						c.options.ProtocolVersion = 3
-						goto CONN
-					}
-				}
-				break
-			} else {
-				ERROR.Println(CLI, err.Error())
-				WARN.Println(CLI, "failed to connect to broker, trying next")
-				rc = packets.ErrNetworkError
-			}
-		}
-		if rc != 0 {
-			DEBUG.Println(CLI, "Reconnect failed, sleeping for", sleep, "seconds")
-			time.Sleep(time.Duration(sleep) * time.Second)
-			if sleep <= uint(c.options.MaxReconnectInterval.Seconds()) {
-				sleep *= 2
-			}
-		}
-	}
-
-	c.lastContact.update()
-	c.stop = make(chan struct{})
-
-	c.workers.Add(1)
-	go outgoing(c)
-	go alllogic(c)
-
-	c.setConnected(true)
-	DEBUG.Println(CLI, "client is reconnected")
-	if c.options.OnConnect != nil {
-		go c.options.OnConnect(c)
-	}
-
-	if c.options.KeepAlive != 0 {
-		c.workers.Add(1)
-		go keepalive(c)
-	}
-	c.workers.Add(1)
-	go incoming(c)
-}
-
-// This function is only used for receiving a connack
-// when the connection is first started.
-// This prevents receiving incoming data while resume
-// is in progress if clean session is false.
-func (c *Client) connect() byte {
-	DEBUG.Println(NET, "connect started")
-
-	ca, err := packets.ReadPacket(c.conn)
-	if err != nil {
-		ERROR.Println(NET, "connect got error", err)
-		return packets.ErrNetworkError
-	}
-	if ca == nil {
-		ERROR.Println(NET, "received nil packet")
-		return packets.ErrNetworkError
-	}
-
-	msg, ok := ca.(*packets.ConnackPacket)
-	if !ok {
-		ERROR.Println(NET, "received msg that was not CONNACK")
-		return packets.ErrNetworkError
-	}
-
-	DEBUG.Println(NET, "received connack")
-	return msg.ReturnCode
-}
-
-// Disconnect will end the connection with the server, but not before waiting
-// the specified number of milliseconds to wait for existing work to be
-// completed.
-func (c *Client) Disconnect(quiesce uint) {
-	if !c.IsConnected() {
-		WARN.Println(CLI, "already disconnected")
-		return
-	}
-	DEBUG.Println(CLI, "disconnecting")
-	c.setConnected(false)
-
-	dm := packets.NewControlPacket(packets.Disconnect).(*packets.DisconnectPacket)
-	dt := newToken(packets.Disconnect)
-	c.oboundP <- &PacketAndToken{p: dm, t: dt}
-
-	// wait for work to finish, or quiesce time consumed
-	dt.WaitTimeout(time.Duration(quiesce) * time.Millisecond)
-	c.disconnect()
-}
-
-// ForceDisconnect will end the connection with the mqtt broker immediately.
-func (c *Client) forceDisconnect() {
-	if !c.IsConnected() {
-		WARN.Println(CLI, "already disconnected")
-		return
-	}
-	c.setConnected(false)
-	c.conn.Close()
-	DEBUG.Println(CLI, "forcefully disconnecting")
-	c.disconnect()
-}
-
-func (c *Client) internalConnLost(err error) {
-	close(c.stop)
-	c.conn.Close()
-	c.workers.Wait()
-	if c.IsConnected() {
-		if c.options.OnConnectionLost != nil {
-			go c.options.OnConnectionLost(c, err)
-		}
-		if c.options.AutoReconnect {
-			go c.reconnect()
-		} else {
-			c.setConnected(false)
-		}
-	}
-}
-
-func (c *Client) disconnect() {
-	select {
-	case <-c.stop:
-		//someone else has already closed the channel, must be error
-	default:
-		close(c.stop)
-	}
-	c.conn.Close()
-	c.workers.Wait()
-	close(c.stopRouter)
-	DEBUG.Println(CLI, "disconnected")
-	c.persist.Close()
-}
-
-// Publish will publish a message with the specified QoS
-// and content to the specified topic.
-// Returns a read only channel used to track
-// the delivery of the message.
-func (c *Client) Publish(topic string, qos byte, retained bool, payload interface{}) Token {
-	token := newToken(packets.Publish).(*PublishToken)
-	DEBUG.Println(CLI, "enter Publish")
-	if !c.IsConnected() {
-		token.err = ErrNotConnected
-		token.flowComplete()
-		return token
-	}
-	pub := packets.NewControlPacket(packets.Publish).(*packets.PublishPacket)
-	pub.Qos = qos
-	pub.TopicName = topic
-	pub.Retain = retained
-	switch payload.(type) {
-	case string:
-		pub.Payload = []byte(payload.(string))
-	case []byte:
-		pub.Payload = payload.([]byte)
-	default:
-		token.err = errors.New("Unknown payload type")
-		token.flowComplete()
-		return token
-	}
-
-	DEBUG.Println(CLI, "sending publish message, topic:", topic)
-	c.obound <- &PacketAndToken{p: pub, t: token}
-	return token
-}
-
-// Subscribe starts a new subscription. Provide a MessageHandler to be executed when
-// a message is published on the topic provided.
-func (c *Client) Subscribe(topic string, qos byte, callback MessageHandler) Token {
-	token := newToken(packets.Subscribe).(*SubscribeToken)
-	DEBUG.Println(CLI, "enter Subscribe")
-	if !c.IsConnected() {
-		token.err = ErrNotConnected
-		token.flowComplete()
-		return token
-	}
-	sub := packets.NewControlPacket(packets.Subscribe).(*packets.SubscribePacket)
-	if err := validateTopicAndQos(topic, qos); err != nil {
-		token.err = err
-		return token
-	}
-	sub.Topics = append(sub.Topics, topic)
-	sub.Qoss = append(sub.Qoss, qos)
-	DEBUG.Println(sub.String())
-
-	if callback != nil {
-		c.msgRouter.addRoute(topic, callback)
-	}
-
-	token.subs = append(token.subs, topic)
-	c.oboundP <- &PacketAndToken{p: sub, t: token}
-	DEBUG.Println(CLI, "exit Subscribe")
-	return token
-}
-
-// SubscribeMultiple starts a new subscription for multiple topics. Provide a MessageHandler to
-// be executed when a message is published on one of the topics provided.
-func (c *Client) SubscribeMultiple(filters map[string]byte, callback MessageHandler) Token {
-	var err error
-	token := newToken(packets.Subscribe).(*SubscribeToken)
-	DEBUG.Println(CLI, "enter SubscribeMultiple")
-	if !c.IsConnected() {
-		token.err = ErrNotConnected
-		token.flowComplete()
-		return token
-	}
-	sub := packets.NewControlPacket(packets.Subscribe).(*packets.SubscribePacket)
-	if sub.Topics, sub.Qoss, err = validateSubscribeMap(filters); err != nil {
-		token.err = err
-		return token
-	}
-
-	if callback != nil {
-		for topic := range filters {
-			c.msgRouter.addRoute(topic, callback)
-		}
-	}
-	token.subs = make([]string, len(sub.Topics))
-	copy(token.subs, sub.Topics)
-	c.oboundP <- &PacketAndToken{p: sub, t: token}
-	DEBUG.Println(CLI, "exit SubscribeMultiple")
-	return token
-}
-
-// Unsubscribe will end the subscription from each of the topics provided.
-// Messages published to those topics from other clients will no longer be
-// received.
-func (c *Client) Unsubscribe(topics ...string) Token {
-	token := newToken(packets.Unsubscribe).(*UnsubscribeToken)
-	DEBUG.Println(CLI, "enter Unsubscribe")
-	if !c.IsConnected() {
-		token.err = ErrNotConnected
-		token.flowComplete()
-		return token
-	}
-	unsub := packets.NewControlPacket(packets.Unsubscribe).(*packets.UnsubscribePacket)
-	unsub.Topics = make([]string, len(topics))
-	copy(unsub.Topics, topics)
-
-	c.oboundP <- &PacketAndToken{p: unsub, t: token}
-	for _, topic := range topics {
-		c.msgRouter.deleteRoute(topic)
-	}
-
-	DEBUG.Println(CLI, "exit Unsubscribe")
-	return token
-}
-
-//DefaultConnectionLostHandler is a definition of a function that simply
-//reports to the DEBUG log the reason for the client losing a connection.
-func DefaultConnectionLostHandler(client *Client, reason error) {
-	DEBUG.Println("Connection lost:", reason.Error())
-}

+ 0 - 31
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/components.go

@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Seth Hoenig
- *    Allan Stockdill-Mander
- *    Mike Robertson
- */
-
-package mqtt
-
-type component string
-
-// Component names for debug output
-const (
-	NET component = "[net]     "
-	PNG component = "[pinger]  "
-	CLI component = "[client]  "
-	DEC component = "[decode]  "
-	MES component = "[message] "
-	STR component = "[store]   "
-	MID component = "[msgids]  "
-	TST component = "[test]    "
-	STA component = "[state]   "
-	ERR component = "[error]   "
-)

+ 0 - 70
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/epl-v10

@@ -1,70 +0,0 @@
-Eclipse Public License - v 1.0
-
-THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
-
-1. DEFINITIONS
-
-"Contribution" means:
-
-a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
-b) in the case of each subsequent Contributor:
-i) changes to the Program, and
-ii) additions to the Program;
-where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
-"Contributor" means any person or entity that distributes the Program.
-
-"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.
-
-"Program" means the Contributions distributed in accordance with this Agreement.
-
-"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
-
-2. GRANT OF RIGHTS
-
-a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
-b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
-c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
-d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
-3. REQUIREMENTS
-
-A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
-
-a) it complies with the terms and conditions of this Agreement; and
-b) its license agreement:
-i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
-ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
-iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
-iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
-When the Program is made available in source code form:
-
-a) it must be made available under this Agreement; and
-b) a copy of this Agreement must be included with each copy of the Program.
-Contributors may not remove or alter any copyright notices contained within the Program.
-
-Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.
-
-4. COMMERCIAL DISTRIBUTION
-
-Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.
-
-For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.
-
-5. NO WARRANTY
-
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
-
-6. DISCLAIMER OF LIABILITY
-
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
-7. GENERAL
-
-If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
-
-If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.
-
-All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.
-
-Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
-
-This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.

+ 0 - 258
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/filestore.go

@@ -1,258 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Seth Hoenig
- *    Allan Stockdill-Mander
- *    Mike Robertson
- */
-
-package mqtt
-
-import (
-	"git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets"
-	"io"
-	"io/ioutil"
-	"os"
-	"path"
-	"sync"
-)
-
-const (
-	msgExt = ".msg"
-	bkpExt = ".bkp"
-)
-
-// FileStore implements the store interface using the filesystem to provide
-// true persistence, even across client failure. This is designed to use a
-// single directory per running client. If you are running multiple clients
-// on the same filesystem, you will need to be careful to specify unique
-// store directories for each.
-type FileStore struct {
-	sync.RWMutex
-	directory string
-	opened    bool
-}
-
-// NewFileStore will create a new FileStore which stores its messages in the
-// directory provided.
-func NewFileStore(directory string) *FileStore {
-	store := &FileStore{
-		directory: directory,
-		opened:    false,
-	}
-	return store
-}
-
-// Open will allow the FileStore to be used.
-func (store *FileStore) Open() {
-	store.Lock()
-	defer store.Unlock()
-	// if no store directory was specified in ClientOpts, by default use the
-	// current working directory
-	if store.directory == "" {
-		store.directory, _ = os.Getwd()
-	}
-
-	// if store dir exists, great, otherwise, create it
-	if !exists(store.directory) {
-		perms := os.FileMode(0770)
-		merr := os.MkdirAll(store.directory, perms)
-		chkerr(merr)
-	}
-	store.opened = true
-	DEBUG.Println(STR, "store is opened at", store.directory)
-}
-
-// Close will disallow the FileStore from being used.
-func (store *FileStore) Close() {
-	store.Lock()
-	defer store.Unlock()
-	store.opened = false
-	WARN.Println(STR, "store is not open")
-}
-
-// Put will put a message into the store, associated with the provided
-// key value.
-func (store *FileStore) Put(key string, m packets.ControlPacket) {
-	store.Lock()
-	defer store.Unlock()
-	chkcond(store.opened)
-	full := fullpath(store.directory, key)
-	if exists(full) {
-		backup(store.directory, key) // make a copy of what already exists
-		defer unbackup(store.directory, key)
-	}
-	write(store.directory, key, m)
-	chkcond(exists(full))
-}
-
-// Get will retrieve a message from the store, the one associated with
-// the provided key value.
-func (store *FileStore) Get(key string) packets.ControlPacket {
-	store.RLock()
-	defer store.RUnlock()
-	chkcond(store.opened)
-	filepath := fullpath(store.directory, key)
-	if !exists(filepath) {
-		return nil
-	}
-	mfile, oerr := os.Open(filepath)
-	chkerr(oerr)
-	//all, rerr := ioutil.ReadAll(mfile)
-	//chkerr(rerr)
-	msg, rerr := packets.ReadPacket(mfile)
-	chkerr(rerr)
-	cerr := mfile.Close()
-	chkerr(cerr)
-	return msg
-}
-
-// All will provide a list of all of the keys associated with messages
-// currenly residing in the FileStore.
-func (store *FileStore) All() []string {
-	store.RLock()
-	defer store.RUnlock()
-	return store.all()
-}
-
-// Del will remove the persisted message associated with the provided
-// key from the FileStore.
-func (store *FileStore) Del(key string) {
-	store.Lock()
-	defer store.Unlock()
-	store.del(key)
-}
-
-// Reset will remove all persisted messages from the FileStore.
-func (store *FileStore) Reset() {
-	store.Lock()
-	defer store.Unlock()
-	WARN.Println(STR, "FileStore Reset")
-	for _, key := range store.all() {
-		store.del(key)
-	}
-}
-
-// lockless
-func (store *FileStore) all() []string {
-	chkcond(store.opened)
-	keys := []string{}
-	files, rderr := ioutil.ReadDir(store.directory)
-	chkerr(rderr)
-	for _, f := range files {
-		DEBUG.Println(STR, "file in All():", f.Name())
-		key := f.Name()[0 : len(f.Name())-4] // remove file extension
-		keys = append(keys, key)
-	}
-	return keys
-}
-
-// lockless
-func (store *FileStore) del(key string) {
-	chkcond(store.opened)
-	DEBUG.Println(STR, "store del filepath:", store.directory)
-	DEBUG.Println(STR, "store delete key:", key)
-	filepath := fullpath(store.directory, key)
-	DEBUG.Println(STR, "path of deletion:", filepath)
-	if !exists(filepath) {
-		WARN.Println(STR, "store could not delete key:", key)
-		return
-	}
-	rerr := os.Remove(filepath)
-	chkerr(rerr)
-	DEBUG.Println(STR, "del msg:", key)
-	chkcond(!exists(filepath))
-}
-
-func fullpath(store string, key string) string {
-	p := path.Join(store, key+msgExt)
-	return p
-}
-
-func bkppath(store string, key string) string {
-	p := path.Join(store, key+bkpExt)
-	return p
-}
-
-// create file called "X.[messageid].msg" located in the store
-// the contents of the file is the bytes of the message
-// if a message with m's message id already exists, it will
-// be overwritten
-// X will be 'i' for inbound messages, and O for outbound messages
-func write(store, key string, m packets.ControlPacket) {
-	filepath := fullpath(store, key)
-	f, err := os.Create(filepath)
-	chkerr(err)
-	werr := m.Write(f)
-	chkerr(werr)
-	cerr := f.Close()
-	chkerr(cerr)
-}
-
-func exists(file string) bool {
-	if _, err := os.Stat(file); err != nil {
-		if os.IsNotExist(err) {
-			return false
-		}
-		chkerr(err)
-	}
-	return true
-}
-
-func backup(store, key string) {
-	bkpp := bkppath(store, key)
-	fulp := fullpath(store, key)
-	backup, err := os.Create(bkpp)
-	chkerr(err)
-	mfile, oerr := os.Open(fulp)
-	chkerr(oerr)
-	_, cerr := io.Copy(backup, mfile)
-	chkerr(cerr)
-	clberr := backup.Close()
-	chkerr(clberr)
-	clmerr := mfile.Close()
-	chkerr(clmerr)
-}
-
-// Identify .bkp files in the store and turn them into .msg files,
-// whether or not it overwrites an existing file. This is safe because
-// I'm copying the Paho Java client and they say it is.
-func restore(store string) {
-	files, rderr := ioutil.ReadDir(store)
-	chkerr(rderr)
-	for _, f := range files {
-		fname := f.Name()
-		if len(fname) > 4 {
-			if fname[len(fname)-4:] == bkpExt {
-				key := fname[0 : len(fname)-4]
-				fulp := fullpath(store, key)
-				msg, cerr := os.Create(fulp)
-				chkerr(cerr)
-				bkpp := path.Join(store, fname)
-				bkp, oerr := os.Open(bkpp)
-				chkerr(oerr)
-				n, cerr := io.Copy(msg, bkp)
-				chkerr(cerr)
-				chkcond(n > 0)
-				clmerr := msg.Close()
-				chkerr(clmerr)
-				clberr := bkp.Close()
-				chkerr(clberr)
-				remerr := os.Remove(bkpp)
-				chkerr(remerr)
-			}
-		}
-	}
-}
-
-func unbackup(store, key string) {
-	bkpp := bkppath(store, key)
-	remerr := os.Remove(bkpp)
-	chkerr(remerr)
-}

+ 0 - 119
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/memstore.go

@@ -1,119 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Seth Hoenig
- *    Allan Stockdill-Mander
- *    Mike Robertson
- */
-
-package mqtt
-
-import (
-	"git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets"
-	"sync"
-)
-
-// MemoryStore implements the store interface to provide a "persistence"
-// mechanism wholly stored in memory. This is only useful for
-// as long as the client instance exists.
-type MemoryStore struct {
-	sync.RWMutex
-	messages map[string]packets.ControlPacket
-	opened   bool
-}
-
-// NewMemoryStore returns a pointer to a new instance of
-// MemoryStore, the instance is not initialized and ready to
-// use until Open() has been called on it.
-func NewMemoryStore() *MemoryStore {
-	store := &MemoryStore{
-		messages: make(map[string]packets.ControlPacket),
-		opened:   false,
-	}
-	return store
-}
-
-// Open initializes a MemoryStore instance.
-func (store *MemoryStore) Open() {
-	store.Lock()
-	defer store.Unlock()
-	store.opened = true
-	DEBUG.Println(STR, "memorystore initialized")
-}
-
-// Put takes a key and a pointer to a Message and stores the
-// message.
-func (store *MemoryStore) Put(key string, message packets.ControlPacket) {
-	store.Lock()
-	defer store.Unlock()
-	chkcond(store.opened)
-	store.messages[key] = message
-}
-
-// Get takes a key and looks in the store for a matching Message
-// returning either the Message pointer or nil.
-func (store *MemoryStore) Get(key string) packets.ControlPacket {
-	store.RLock()
-	defer store.RUnlock()
-	chkcond(store.opened)
-	mid := mIDFromKey(key)
-	m := store.messages[key]
-	if m == nil {
-		CRITICAL.Println(STR, "memorystore get: message", mid, "not found")
-	} else {
-		DEBUG.Println(STR, "memorystore get: message", mid, "found")
-	}
-	return m
-}
-
-// All returns a slice of strings containing all the keys currently
-// in the MemoryStore.
-func (store *MemoryStore) All() []string {
-	store.RLock()
-	defer store.RUnlock()
-	chkcond(store.opened)
-	keys := []string{}
-	for k := range store.messages {
-		keys = append(keys, k)
-	}
-	return keys
-}
-
-// Del takes a key, searches the MemoryStore and if the key is found
-// deletes the Message pointer associated with it.
-func (store *MemoryStore) Del(key string) {
-	store.Lock()
-	defer store.Unlock()
-	mid := mIDFromKey(key)
-	m := store.messages[key]
-	if m == nil {
-		WARN.Println(STR, "memorystore del: message", mid, "not found")
-	} else {
-		store.messages[key] = nil
-		DEBUG.Println(STR, "memorystore del: message", mid, "was deleted")
-	}
-}
-
-// Close will disallow modifications to the state of the store.
-func (store *MemoryStore) Close() {
-	store.Lock()
-	defer store.Unlock()
-	chkcond(store.opened)
-	store.opened = false
-	DEBUG.Println(STR, "memorystore closed")
-}
-
-// Reset eliminates all persisted message data in the store.
-func (store *MemoryStore) Reset() {
-	store.Lock()
-	defer store.Unlock()
-	chkcond(store.opened)
-	store.messages = make(map[string]packets.ControlPacket)
-	WARN.Println(STR, "memorystore wiped")
-}

+ 0 - 104
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/message.go

@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Seth Hoenig
- *    Allan Stockdill-Mander
- *    Mike Robertson
- */
-
-package mqtt
-
-import (
-	"git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets"
-)
-
-// Message defines the externals that a message implementation must support
-// these are received messages that are passed to the callbacks, not internal
-// messages
-type Message interface {
-	Duplicate() bool
-	Qos() byte
-	Retained() bool
-	Topic() string
-	MessageID() uint16
-	Payload() []byte
-}
-
-type message struct {
-	duplicate bool
-	qos       byte
-	retained  bool
-	topic     string
-	messageID uint16
-	payload   []byte
-}
-
-func (m *message) Duplicate() bool {
-	return m.duplicate
-}
-
-func (m *message) Qos() byte {
-	return m.qos
-}
-
-func (m *message) Retained() bool {
-	return m.retained
-}
-
-func (m *message) Topic() string {
-	return m.topic
-}
-
-func (m *message) MessageID() uint16 {
-	return m.messageID
-}
-
-func (m *message) Payload() []byte {
-	return m.payload
-}
-
-func messageFromPublish(p *packets.PublishPacket) Message {
-	return &message{
-		duplicate: p.Dup,
-		qos:       p.Qos,
-		retained:  p.Retain,
-		topic:     p.TopicName,
-		messageID: p.MessageID,
-		payload:   p.Payload,
-	}
-}
-
-func newConnectMsgFromOptions(options *ClientOptions) *packets.ConnectPacket {
-	m := packets.NewControlPacket(packets.Connect).(*packets.ConnectPacket)
-
-	m.CleanSession = options.CleanSession
-	m.WillFlag = options.WillEnabled
-	m.WillRetain = options.WillRetained
-	m.ClientIdentifier = options.ClientID
-
-	if options.WillEnabled {
-		m.WillQos = options.WillQos
-		m.WillTopic = options.WillTopic
-		m.WillMessage = options.WillPayload
-	}
-
-	if options.Username != "" {
-		m.UsernameFlag = true
-		m.Username = options.Username
-		//mustn't have password without user as well
-		if options.Password != "" {
-			m.PasswordFlag = true
-			m.Password = []byte(options.Password)
-		}
-	}
-
-	m.KeepaliveTimer = uint16(options.KeepAlive)
-
-	return m
-}

+ 0 - 61
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/messageids.go

@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Seth Hoenig
- *    Allan Stockdill-Mander
- *    Mike Robertson
- */
-
-package mqtt
-
-import (
-	"sync"
-)
-
-// MId is 16 bit message id as specified by the MQTT spec.
-// In general, these values should not be depended upon by
-// the client application.
-type MId uint16
-
-type messageIds struct {
-	sync.RWMutex
-	index map[uint16]Token
-}
-
-const (
-	midMin uint16 = 1
-	midMax uint16 = 65535
-)
-
-func (mids *messageIds) freeID(id uint16) {
-	mids.Lock()
-	defer mids.Unlock()
-	delete(mids.index, id)
-}
-
-func (mids *messageIds) getID(t Token) uint16 {
-	mids.Lock()
-	defer mids.Unlock()
-	for i := midMin; i < midMax; i++ {
-		if _, ok := mids.index[i]; !ok {
-			mids.index[i] = t
-			return i
-		}
-	}
-	return 0
-}
-
-func (mids *messageIds) getToken(id uint16) Token {
-	mids.RLock()
-	defer mids.RUnlock()
-	if token, ok := mids.index[id]; ok {
-		return token
-	}
-	return nil
-}

+ 0 - 275
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/net.go

@@ -1,275 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Seth Hoenig
- *    Allan Stockdill-Mander
- *    Mike Robertson
- */
-
-package mqtt
-
-import (
-	"crypto/tls"
-	"errors"
-	"git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets"
-	"golang.org/x/net/websocket"
-	"net"
-	"net/url"
-	"reflect"
-	"time"
-)
-
-func openConnection(uri *url.URL, tlsc *tls.Config, timeout time.Duration) (net.Conn, error) {
-	switch uri.Scheme {
-	case "ws":
-		conn, err := websocket.Dial(uri.String(), "mqtt", "ws://localhost")
-		if err != nil {
-			return nil, err
-		}
-		conn.PayloadType = websocket.BinaryFrame
-		return conn, err
-	case "wss":
-		config, _ := websocket.NewConfig(uri.String(), "ws://localhost")
-		config.Protocol = []string{"mqtt"}
-		config.TlsConfig = tlsc
-		conn, err := websocket.DialConfig(config)
-		if err != nil {
-			return nil, err
-		}
-		conn.PayloadType = websocket.BinaryFrame
-		return conn, err
-	case "tcp":
-		conn, err := net.DialTimeout("tcp", uri.Host, timeout)
-		if err != nil {
-			return nil, err
-		}
-		return conn, nil
-	case "ssl":
-		fallthrough
-	case "tls":
-		fallthrough
-	case "tcps":
-		conn, err := tls.DialWithDialer(&net.Dialer{Timeout: timeout}, "tcp", uri.Host, tlsc)
-		if err != nil {
-			return nil, err
-		}
-		return conn, nil
-	}
-	return nil, errors.New("Unknown protocol")
-}
-
-// actually read incoming messages off the wire
-// send Message object into ibound channel
-func incoming(c *Client) {
-	defer c.workers.Done()
-	var err error
-	var cp packets.ControlPacket
-
-	DEBUG.Println(NET, "incoming started")
-
-	for {
-		if cp, err = packets.ReadPacket(c.conn); err != nil {
-			break
-		}
-		DEBUG.Println(NET, "Received Message")
-		c.ibound <- cp
-	}
-	// We received an error on read.
-	// If disconnect is in progress, swallow error and return
-	select {
-	case <-c.stop:
-		DEBUG.Println(NET, "incoming stopped")
-		return
-		// Not trying to disconnect, send the error to the errors channel
-	default:
-		ERROR.Println(NET, "incoming stopped with error")
-		c.errors <- err
-		return
-	}
-}
-
-// receive a Message object on obound, and then
-// actually send outgoing message to the wire
-func outgoing(c *Client) {
-	defer c.workers.Done()
-	DEBUG.Println(NET, "outgoing started")
-
-	for {
-		DEBUG.Println(NET, "outgoing waiting for an outbound message")
-		select {
-		case <-c.stop:
-			DEBUG.Println(NET, "outgoing stopped")
-			return
-		case pub := <-c.obound:
-			msg := pub.p.(*packets.PublishPacket)
-			if msg.Qos != 0 && msg.MessageID == 0 {
-				msg.MessageID = c.getID(pub.t)
-				pub.t.(*PublishToken).messageID = msg.MessageID
-			}
-			//persist_obound(c.persist, msg)
-
-			if c.options.WriteTimeout > 0 {
-				c.conn.SetWriteDeadline(time.Now().Add(c.options.WriteTimeout))
-			}
-
-			if err := msg.Write(c.conn); err != nil {
-				ERROR.Println(NET, "outgoing stopped with error")
-				c.errors <- err
-				return
-			}
-
-			if c.options.WriteTimeout > 0 {
-				// If we successfully wrote, we don't want the timeout to happen during an idle period
-				// so we reset it to infinite.
-				c.conn.SetWriteDeadline(time.Time{})
-			}
-
-			if msg.Qos == 0 {
-				pub.t.flowComplete()
-			}
-
-			c.lastContact.update()
-			DEBUG.Println(NET, "obound wrote msg, id:", msg.MessageID)
-		case msg := <-c.oboundP:
-			switch msg.p.(type) {
-			case *packets.SubscribePacket:
-				msg.p.(*packets.SubscribePacket).MessageID = c.getID(msg.t)
-			case *packets.UnsubscribePacket:
-				msg.p.(*packets.UnsubscribePacket).MessageID = c.getID(msg.t)
-			}
-			DEBUG.Println(NET, "obound priority msg to write, type", reflect.TypeOf(msg.p))
-			if err := msg.p.Write(c.conn); err != nil {
-				ERROR.Println(NET, "outgoing stopped with error")
-				c.errors <- err
-				return
-			}
-			c.lastContact.update()
-			switch msg.p.(type) {
-			case *packets.DisconnectPacket:
-				msg.t.(*DisconnectToken).flowComplete()
-				DEBUG.Println(NET, "outbound wrote disconnect, stopping")
-				return
-			}
-		}
-	}
-}
-
-// receive Message objects on ibound
-// store messages if necessary
-// send replies on obound
-// delete messages from store if necessary
-func alllogic(c *Client) {
-
-	DEBUG.Println(NET, "logic started")
-
-	for {
-		DEBUG.Println(NET, "logic waiting for msg on ibound")
-
-		select {
-		case msg := <-c.ibound:
-			DEBUG.Println(NET, "logic got msg on ibound")
-			//persist_ibound(c.persist, msg)
-			switch msg.(type) {
-			case *packets.PingrespPacket:
-				DEBUG.Println(NET, "received pingresp")
-				c.pingOutstanding = false
-			case *packets.SubackPacket:
-				sa := msg.(*packets.SubackPacket)
-				DEBUG.Println(NET, "received suback, id:", sa.MessageID)
-				token := c.getToken(sa.MessageID).(*SubscribeToken)
-				DEBUG.Println(NET, "granted qoss", sa.GrantedQoss)
-				for i, qos := range sa.GrantedQoss {
-					token.subResult[token.subs[i]] = qos
-				}
-				token.flowComplete()
-				go c.freeID(sa.MessageID)
-			case *packets.UnsubackPacket:
-				ua := msg.(*packets.UnsubackPacket)
-				DEBUG.Println(NET, "received unsuback, id:", ua.MessageID)
-				token := c.getToken(ua.MessageID).(*UnsubscribeToken)
-				token.flowComplete()
-				go c.freeID(ua.MessageID)
-			case *packets.PublishPacket:
-				pp := msg.(*packets.PublishPacket)
-				DEBUG.Println(NET, "received publish, msgId:", pp.MessageID)
-				DEBUG.Println(NET, "putting msg on onPubChan")
-				switch pp.Qos {
-				case 2:
-					c.incomingPubChan <- pp
-					DEBUG.Println(NET, "done putting msg on incomingPubChan")
-					pr := packets.NewControlPacket(packets.Pubrec).(*packets.PubrecPacket)
-					pr.MessageID = pp.MessageID
-					DEBUG.Println(NET, "putting pubrec msg on obound")
-					c.oboundP <- &PacketAndToken{p: pr, t: nil}
-					DEBUG.Println(NET, "done putting pubrec msg on obound")
-				case 1:
-					c.incomingPubChan <- pp
-					DEBUG.Println(NET, "done putting msg on incomingPubChan")
-					pa := packets.NewControlPacket(packets.Puback).(*packets.PubackPacket)
-					pa.MessageID = pp.MessageID
-					DEBUG.Println(NET, "putting puback msg on obound")
-					c.oboundP <- &PacketAndToken{p: pa, t: nil}
-					DEBUG.Println(NET, "done putting puback msg on obound")
-				case 0:
-					select {
-					case c.incomingPubChan <- pp:
-						DEBUG.Println(NET, "done putting msg on incomingPubChan")
-					case err, ok := <-c.errors:
-						DEBUG.Println(NET, "error while putting msg on pubChanZero")
-						// We are unblocked, but need to put the error back on so the outer
-						// select can handle it appropriately.
-						if ok {
-							go func(errVal error, errChan chan error) {
-								errChan <- errVal
-							}(err, c.errors)
-						}
-					}
-				}
-			case *packets.PubackPacket:
-				pa := msg.(*packets.PubackPacket)
-				DEBUG.Println(NET, "received puback, id:", pa.MessageID)
-				// c.receipts.get(msg.MsgId()) <- Receipt{}
-				// c.receipts.end(msg.MsgId())
-				c.getToken(pa.MessageID).flowComplete()
-				c.freeID(pa.MessageID)
-			case *packets.PubrecPacket:
-				prec := msg.(*packets.PubrecPacket)
-				DEBUG.Println(NET, "received pubrec, id:", prec.MessageID)
-				prel := packets.NewControlPacket(packets.Pubrel).(*packets.PubrelPacket)
-				prel.MessageID = prec.MessageID
-				select {
-				case c.oboundP <- &PacketAndToken{p: prel, t: nil}:
-				case <-time.After(time.Second):
-				}
-			case *packets.PubrelPacket:
-				pr := msg.(*packets.PubrelPacket)
-				DEBUG.Println(NET, "received pubrel, id:", pr.MessageID)
-				pc := packets.NewControlPacket(packets.Pubcomp).(*packets.PubcompPacket)
-				pc.MessageID = pr.MessageID
-				select {
-				case c.oboundP <- &PacketAndToken{p: pc, t: nil}:
-				case <-time.After(time.Second):
-				}
-			case *packets.PubcompPacket:
-				pc := msg.(*packets.PubcompPacket)
-				DEBUG.Println(NET, "received pubcomp, id:", pc.MessageID)
-				c.getToken(pc.MessageID).flowComplete()
-				c.freeID(pc.MessageID)
-			}
-		case <-c.stop:
-			WARN.Println(NET, "logic stopped")
-			return
-		case err := <-c.errors:
-			ERROR.Println(NET, "logic got error")
-			c.internalConnLost(err)
-			return
-		}
-		c.lastContact.update()
-	}
-}

+ 0 - 108
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/notice.html

@@ -1,108 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
-<title>Eclipse Foundation Software User Agreement</title>
-</head>
-
-<body lang="EN-US">
-<h2>Eclipse Foundation Software User Agreement</h2>
-<p>February 1, 2011</p>
-
-<h3>Usage Of Content</h3>
-
-<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
-   (COLLECTIVELY &quot;CONTENT&quot;).  USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
-   CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU AGREE THAT YOUR USE
-   OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
-   NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
-   CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
-
-<h3>Applicable Licenses</h3>
-
-<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
-   (&quot;EPL&quot;).  A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
-   For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
-
-<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
-   repository (&quot;Repository&quot;) in software modules (&quot;Modules&quot;) and made available as downloadable archives (&quot;Downloads&quot;).</p>
-
-<ul>
-       <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content.  Typical modules may include plug-ins (&quot;Plug-ins&quot;), plug-in fragments (&quot;Fragments&quot;), and features (&quot;Features&quot;).</li>
-       <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java&trade; ARchive) in a directory named &quot;plugins&quot;.</li>
-       <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.  Each Feature may be packaged as a sub-directory in a directory named &quot;features&quot;.  Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of the Plug-ins
-      and/or Fragments associated with that Feature.</li>
-       <li>Features may also include other Features (&quot;Included Features&quot;). Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of Included Features.</li>
-</ul>
-
-<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named &quot;about.html&quot; (&quot;Abouts&quot;). The terms and conditions governing Features and
-Included Features should be contained in files named &quot;license.html&quot; (&quot;Feature Licenses&quot;).  Abouts and Feature Licenses may be located in any directory of a Download or Module
-including, but not limited to the following locations:</p>
-
-<ul>
-       <li>The top-level (root) directory</li>
-       <li>Plug-in and Fragment directories</li>
-       <li>Inside Plug-ins and Fragments packaged as JARs</li>
-       <li>Sub-directories of the directory named &quot;src&quot; of certain Plug-ins</li>
-       <li>Feature directories</li>
-</ul>
-
-<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license (&quot;Feature Update License&quot;) during the
-installation process.  If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
-inform you where you can locate them.  Feature Update Licenses may be found in the &quot;license&quot; property of files named &quot;feature.properties&quot; found within a Feature.
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
-that directory.</p>
-
-<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.  SOME OF THESE
-OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
-
-<ul>
-       <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
-       <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
-       <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
-       <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
-       <li>Metro Link Public License 1.00 (available at <a href="http://www.opengroup.org/openmotif/supporters/metrolink/license.html">http://www.opengroup.org/openmotif/supporters/metrolink/license.html</a>)</li>
-       <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
-</ul>
-
-<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT.  If no About, Feature License, or Feature Update License is provided, please
-contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
-
-
-<h3>Use of Provisioning Technology</h3>
-
-<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
-   Update Manager (&quot;Provisioning Technology&quot;) for the purpose of allowing users to install software, documentation, information and/or
-   other materials (collectively &quot;Installable Software&quot;). This capability is provided with the intent of allowing such users to
-   install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a
-       href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
-   (&quot;Specification&quot;).</p>
-
-<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
-   applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
-   in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
-   Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
-
-<ol>
-       <li>A series of actions may occur (&quot;Provisioning Process&quot;) in which a user may execute the Provisioning Technology
-       on a machine (&quot;Target Machine&quot;) with the intent of installing, extending or updating the functionality of an Eclipse-based
-       product.</li>
-       <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
-       accessed and copied to the Target Machine.</li>
-       <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
-       Software (&quot;Installable Software Agreement&quot;) and such Installable Software Agreement shall be accessed from the Target
-       Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
-       the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
-       indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
-</ol>
-
-<h3>Cryptography</h3>
-
-<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
-   another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
-   possession, or use, and re-export of encryption software, to see if this is permitted.</p>
-
-<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
-</body>
-</html>

+ 0 - 27
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/oops.go

@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Seth Hoenig
- *    Allan Stockdill-Mander
- *    Mike Robertson
- */
-
-package mqtt
-
-func chkerr(e error) {
-	if e != nil {
-		panic(e)
-	}
-}
-
-func chkcond(b bool) {
-	if !b {
-		panic("oops")
-	}
-}

+ 0 - 270
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/options.go

@@ -1,270 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Seth Hoenig
- *    Allan Stockdill-Mander
- *    Mike Robertson
- */
-
-package mqtt
-
-import (
-	"crypto/tls"
-	"net/url"
-	"time"
-)
-
-// MessageHandler is a callback type which can be set to be
-// executed upon the arrival of messages published to topics
-// to which the client is subscribed.
-type MessageHandler func(*Client, Message)
-
-// ConnectionLostHandler is a callback type which can be set to be
-// executed upon an unintended disconnection from the MQTT broker.
-// Disconnects caused by calling Disconnect or ForceDisconnect will
-// not cause an OnConnectionLost callback to execute.
-type ConnectionLostHandler func(*Client, error)
-
-// OnConnectHandler is a callback that is called when the client
-// state changes from unconnected/disconnected to connected. Both
-// at initial connection and on reconnection
-type OnConnectHandler func(*Client)
-
-// ClientOptions contains configurable options for an Client.
-type ClientOptions struct {
-	Servers                 []*url.URL
-	ClientID                string
-	Username                string
-	Password                string
-	CleanSession            bool
-	Order                   bool
-	WillEnabled             bool
-	WillTopic               string
-	WillPayload             []byte
-	WillQos                 byte
-	WillRetained            bool
-	ProtocolVersion         uint
-	protocolVersionExplicit bool
-	TLSConfig               tls.Config
-	KeepAlive               time.Duration
-	ConnectTimeout          time.Duration
-	MaxReconnectInterval    time.Duration
-	AutoReconnect           bool
-	Store                   Store
-	DefaultPublishHander    MessageHandler
-	OnConnect               OnConnectHandler
-	OnConnectionLost        ConnectionLostHandler
-	WriteTimeout            time.Duration
-}
-
-// NewClientOptions will create a new ClientClientOptions type with some
-// default values.
-//   Port: 1883
-//   CleanSession: True
-//   Order: True
-//   KeepAlive: 30 (seconds)
-//   ConnectTimeout: 30 (seconds)
-//   MaxReconnectInterval 10 (minutes)
-//   AutoReconnect: True
-func NewClientOptions() *ClientOptions {
-	o := &ClientOptions{
-		Servers:                 nil,
-		ClientID:                "",
-		Username:                "",
-		Password:                "",
-		CleanSession:            true,
-		Order:                   true,
-		WillEnabled:             false,
-		WillTopic:               "",
-		WillPayload:             nil,
-		WillQos:                 0,
-		WillRetained:            false,
-		ProtocolVersion:         0,
-		protocolVersionExplicit: false,
-		TLSConfig:               tls.Config{},
-		KeepAlive:               30 * time.Second,
-		ConnectTimeout:          30 * time.Second,
-		MaxReconnectInterval:    10 * time.Minute,
-		AutoReconnect:           true,
-		Store:                   nil,
-		OnConnect:               nil,
-		OnConnectionLost:        DefaultConnectionLostHandler,
-		WriteTimeout:            0, // 0 represents timeout disabled
-	}
-	return o
-}
-
-// AddBroker adds a broker URI to the list of brokers to be used. The format should be
-// scheme://host:port
-// Where "scheme" is one of "tcp", "ssl", or "ws", "host" is the ip-address (or hostname)
-// and "port" is the port on which the broker is accepting connections.
-func (o *ClientOptions) AddBroker(server string) *ClientOptions {
-	brokerURI, _ := url.Parse(server)
-	o.Servers = append(o.Servers, brokerURI)
-	return o
-}
-
-// SetClientID will set the client id to be used by this client when
-// connecting to the MQTT broker. According to the MQTT v3.1 specification,
-// a client id mus be no longer than 23 characters.
-func (o *ClientOptions) SetClientID(id string) *ClientOptions {
-	o.ClientID = id
-	return o
-}
-
-// SetUsername will set the username to be used by this client when connecting
-// to the MQTT broker. Note: without the use of SSL/TLS, this information will
-// be sent in plaintext accross the wire.
-func (o *ClientOptions) SetUsername(u string) *ClientOptions {
-	o.Username = u
-	return o
-}
-
-// SetPassword will set the password to be used by this client when connecting
-// to the MQTT broker. Note: without the use of SSL/TLS, this information will
-// be sent in plaintext accross the wire.
-func (o *ClientOptions) SetPassword(p string) *ClientOptions {
-	o.Password = p
-	return o
-}
-
-// SetCleanSession will set the "clean session" flag in the connect message
-// when this client connects to an MQTT broker. By setting this flag, you are
-// indicating that no messages saved by the broker for this client should be
-// delivered. Any messages that were going to be sent by this client before
-// diconnecting previously but didn't will not be sent upon connecting to the
-// broker.
-func (o *ClientOptions) SetCleanSession(clean bool) *ClientOptions {
-	o.CleanSession = clean
-	return o
-}
-
-// SetOrderMatters will set the message routing to guarantee order within
-// each QoS level. By default, this value is true. If set to false,
-// this flag indicates that messages can be delivered asynchronously
-// from the client to the application and possibly arrive out of order.
-func (o *ClientOptions) SetOrderMatters(order bool) *ClientOptions {
-	o.Order = order
-	return o
-}
-
-// SetTLSConfig will set an SSL/TLS configuration to be used when connecting
-// to an MQTT broker. Please read the official Go documentation for more
-// information.
-func (o *ClientOptions) SetTLSConfig(t *tls.Config) *ClientOptions {
-	o.TLSConfig = *t
-	return o
-}
-
-// SetStore will set the implementation of the Store interface
-// used to provide message persistence in cases where QoS levels
-// QoS_ONE or QoS_TWO are used. If no store is provided, then the
-// client will use MemoryStore by default.
-func (o *ClientOptions) SetStore(s Store) *ClientOptions {
-	o.Store = s
-	return o
-}
-
-// SetKeepAlive will set the amount of time (in seconds) that the client
-// should wait before sending a PING request to the broker. This will
-// allow the client to know that a connection has not been lost with the
-// server.
-func (o *ClientOptions) SetKeepAlive(k time.Duration) *ClientOptions {
-	o.KeepAlive = k
-	return o
-}
-
-// SetProtocolVersion sets the MQTT version to be used to connect to the
-// broker. Legitimate values are currently 3 - MQTT 3.1 or 4 - MQTT 3.1.1
-func (o *ClientOptions) SetProtocolVersion(pv uint) *ClientOptions {
-	if pv >= 3 && pv <= 4 {
-		o.ProtocolVersion = pv
-		o.protocolVersionExplicit = true
-	}
-	return o
-}
-
-// UnsetWill will cause any set will message to be disregarded.
-func (o *ClientOptions) UnsetWill() *ClientOptions {
-	o.WillEnabled = false
-	return o
-}
-
-// SetWill accepts a string will message to be set. When the client connects,
-// it will give this will message to the broker, which will then publish the
-// provided payload (the will) to any clients that are subscribed to the provided
-// topic.
-func (o *ClientOptions) SetWill(topic string, payload string, qos byte, retained bool) *ClientOptions {
-	o.SetBinaryWill(topic, []byte(payload), qos, retained)
-	return o
-}
-
-// SetBinaryWill accepts a []byte will message to be set. When the client connects,
-// it will give this will message to the broker, which will then publish the
-// provided payload (the will) to any clients that are subscribed to the provided
-// topic.
-func (o *ClientOptions) SetBinaryWill(topic string, payload []byte, qos byte, retained bool) *ClientOptions {
-	o.WillEnabled = true
-	o.WillTopic = topic
-	o.WillPayload = payload
-	o.WillQos = qos
-	o.WillRetained = retained
-	return o
-}
-
-// SetDefaultPublishHandler sets the MessageHandler that will be called when a message
-// is received that does not match any known subscriptions.
-func (o *ClientOptions) SetDefaultPublishHandler(defaultHandler MessageHandler) *ClientOptions {
-	o.DefaultPublishHander = defaultHandler
-	return o
-}
-
-// SetOnConnectHandler sets the function to be called when the client is connected. Both
-// at initial connection time and upon automatic reconnect.
-func (o *ClientOptions) SetOnConnectHandler(onConn OnConnectHandler) *ClientOptions {
-	o.OnConnect = onConn
-	return o
-}
-
-// SetConnectionLostHandler will set the OnConnectionLost callback to be executed
-// in the case where the client unexpectedly loses connection with the MQTT broker.
-func (o *ClientOptions) SetConnectionLostHandler(onLost ConnectionLostHandler) *ClientOptions {
-	o.OnConnectionLost = onLost
-	return o
-}
-
-// SetWriteTimeout puts a limit on how long a mqtt publish should block until it unblocks with a
-// timeout error. A duration of 0 never times out. Default 30 seconds
-func (o *ClientOptions) SetWriteTimeout(t time.Duration) *ClientOptions {
-	o.WriteTimeout = t
-	return o
-}
-
-// SetConnectTimeout limits how long the client will wait when trying to open a connection
-// to an MQTT server before timeing out and erroring the attempt. A duration of 0 never times out.
-// Default 30 seconds. Currently only operational on TCP/TLS connections.
-func (o *ClientOptions) SetConnectTimeout(t time.Duration) *ClientOptions {
-	o.ConnectTimeout = t
-	return o
-}
-
-// SetMaxReconnectInterval sets the maximum time that will be waited between reconnection attempts
-// when connection is lost
-func (o *ClientOptions) SetMaxReconnectInterval(t time.Duration) *ClientOptions {
-	o.MaxReconnectInterval = t
-	return o
-}
-
-// SetAutoReconnect sets whether the automatic reconnection logic should be used
-// when the connection is lost, even if disabled the ConnectionLostHandler is still
-// called
-func (o *ClientOptions) SetAutoReconnect(a bool) *ClientOptions {
-	o.AutoReconnect = a
-	return o
-}

+ 0 - 57
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/connack.go

@@ -1,57 +0,0 @@
-package packets
-
-import (
-	"bytes"
-	"fmt"
-	"github.com/pborman/uuid"
-	"io"
-)
-
-//ConnackPacket is an internal representation of the fields of the
-//Connack MQTT packet
-type ConnackPacket struct {
-	FixedHeader
-	TopicNameCompression byte
-	ReturnCode           byte
-	uuid                 uuid.UUID
-}
-
-func (ca *ConnackPacket) String() string {
-	str := fmt.Sprintf("%s\n", ca.FixedHeader)
-	str += fmt.Sprintf("returncode: %d", ca.ReturnCode)
-	return str
-}
-
-func (ca *ConnackPacket) Write(w io.Writer) error {
-	var body bytes.Buffer
-	var err error
-
-	body.WriteByte(ca.TopicNameCompression)
-	body.WriteByte(ca.ReturnCode)
-	ca.FixedHeader.RemainingLength = 2
-	packet := ca.FixedHeader.pack()
-	packet.Write(body.Bytes())
-	_, err = packet.WriteTo(w)
-
-	return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (ca *ConnackPacket) Unpack(b io.Reader) {
-	ca.TopicNameCompression = decodeByte(b)
-	ca.ReturnCode = decodeByte(b)
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (ca *ConnackPacket) Details() Details {
-	return Details{Qos: 0, MessageID: 0}
-}
-
-//UUID returns the unique ID assigned to the ControlPacket when
-//it was originally received. Note: this is not related to the
-//MessageID field for MQTT packets
-func (ca *ConnackPacket) UUID() uuid.UUID {
-	return ca.uuid
-}

+ 0 - 128
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/connect.go

@@ -1,128 +0,0 @@
-package packets
-
-import (
-	"bytes"
-	"fmt"
-	"github.com/pborman/uuid"
-	"io"
-)
-
-//ConnectPacket is an internal representation of the fields of the
-//Connect MQTT packet
-type ConnectPacket struct {
-	FixedHeader
-	ProtocolName    string
-	ProtocolVersion byte
-	CleanSession    bool
-	WillFlag        bool
-	WillQos         byte
-	WillRetain      bool
-	UsernameFlag    bool
-	PasswordFlag    bool
-	ReservedBit     byte
-	KeepaliveTimer  uint16
-
-	ClientIdentifier string
-	WillTopic        string
-	WillMessage      []byte
-	Username         string
-	Password         []byte
-	uuid             uuid.UUID
-}
-
-func (c *ConnectPacket) String() string {
-	str := fmt.Sprintf("%s\n", c.FixedHeader)
-	str += fmt.Sprintf("protocolversion: %d protocolname: %s cleansession: %t willflag: %t WillQos: %d WillRetain: %t Usernameflag: %t Passwordflag: %t keepalivetimer: %d\nclientId: %s\nwilltopic: %s\nwillmessage: %s\nUsername: %s\nPassword: %s\n", c.ProtocolVersion, c.ProtocolName, c.CleanSession, c.WillFlag, c.WillQos, c.WillRetain, c.UsernameFlag, c.PasswordFlag, c.KeepaliveTimer, c.ClientIdentifier, c.WillTopic, c.WillMessage, c.Username, c.Password)
-	return str
-}
-
-func (c *ConnectPacket) Write(w io.Writer) error {
-	var body bytes.Buffer
-	var err error
-
-	body.Write(encodeString(c.ProtocolName))
-	body.WriteByte(c.ProtocolVersion)
-	body.WriteByte(boolToByte(c.CleanSession)<<1 | boolToByte(c.WillFlag)<<2 | c.WillQos<<3 | boolToByte(c.WillRetain)<<5 | boolToByte(c.PasswordFlag)<<6 | boolToByte(c.UsernameFlag)<<7)
-	body.Write(encodeUint16(c.KeepaliveTimer))
-	body.Write(encodeString(c.ClientIdentifier))
-	if c.WillFlag {
-		body.Write(encodeString(c.WillTopic))
-		body.Write(encodeBytes(c.WillMessage))
-	}
-	if c.UsernameFlag {
-		body.Write(encodeString(c.Username))
-	}
-	if c.PasswordFlag {
-		body.Write(encodeBytes(c.Password))
-	}
-	c.FixedHeader.RemainingLength = body.Len()
-	packet := c.FixedHeader.pack()
-	packet.Write(body.Bytes())
-	_, err = packet.WriteTo(w)
-
-	return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (c *ConnectPacket) Unpack(b io.Reader) {
-	c.ProtocolName = decodeString(b)
-	c.ProtocolVersion = decodeByte(b)
-	options := decodeByte(b)
-	c.ReservedBit = 1 & options
-	c.CleanSession = 1&(options>>1) > 0
-	c.WillFlag = 1&(options>>2) > 0
-	c.WillQos = 3 & (options >> 3)
-	c.WillRetain = 1&(options>>5) > 0
-	c.PasswordFlag = 1&(options>>6) > 0
-	c.UsernameFlag = 1&(options>>7) > 0
-	c.KeepaliveTimer = decodeUint16(b)
-	c.ClientIdentifier = decodeString(b)
-	if c.WillFlag {
-		c.WillTopic = decodeString(b)
-		c.WillMessage = decodeBytes(b)
-	}
-	if c.UsernameFlag {
-		c.Username = decodeString(b)
-	}
-	if c.PasswordFlag {
-		c.Password = decodeBytes(b)
-	}
-}
-
-//Validate performs validation of the fields of a Connect packet
-func (c *ConnectPacket) Validate() byte {
-	if c.PasswordFlag && !c.UsernameFlag {
-		return ErrRefusedBadUsernameOrPassword
-	}
-	if c.ReservedBit != 0 {
-		//Bad reserved bit
-		return ErrProtocolViolation
-	}
-	if (c.ProtocolName == "MQIsdp" && c.ProtocolVersion != 3) || (c.ProtocolName == "MQTT" && c.ProtocolVersion != 4) {
-		//Mismatched or unsupported protocol version
-		return ErrRefusedBadProtocolVersion
-	}
-	if c.ProtocolName != "MQIsdp" && c.ProtocolName != "MQTT" {
-		//Bad protocol name
-		return ErrProtocolViolation
-	}
-	if len(c.ClientIdentifier) > 65535 || len(c.Username) > 65535 || len(c.Password) > 65535 {
-		//Bad size field
-		return ErrProtocolViolation
-	}
-	return Accepted
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (c *ConnectPacket) Details() Details {
-	return Details{Qos: 0, MessageID: 0}
-}
-
-//UUID returns the unique ID assigned to the ControlPacket when
-//it was originally received. Note: this is not related to the
-//MessageID field for MQTT packets
-func (c *ConnectPacket) UUID() uuid.UUID {
-	return c.uuid
-}

+ 0 - 44
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/disconnect.go

@@ -1,44 +0,0 @@
-package packets
-
-import (
-	"fmt"
-	"github.com/pborman/uuid"
-	"io"
-)
-
-//DisconnectPacket is an internal representation of the fields of the
-//Disconnect MQTT packet
-type DisconnectPacket struct {
-	FixedHeader
-	uuid uuid.UUID
-}
-
-func (d *DisconnectPacket) String() string {
-	str := fmt.Sprintf("%s\n", d.FixedHeader)
-	return str
-}
-
-func (d *DisconnectPacket) Write(w io.Writer) error {
-	packet := d.FixedHeader.pack()
-	_, err := packet.WriteTo(w)
-
-	return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (d *DisconnectPacket) Unpack(b io.Reader) {
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (d *DisconnectPacket) Details() Details {
-	return Details{Qos: 0, MessageID: 0}
-}
-
-//UUID returns the unique ID assigned to the ControlPacket when
-//it was originally received. Note: this is not related to the
-//MessageID field for MQTT packets
-func (d *DisconnectPacket) UUID() uuid.UUID {
-	return d.uuid
-}

+ 0 - 324
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/packets.go

@@ -1,324 +0,0 @@
-package packets
-
-import (
-	"bytes"
-	"encoding/binary"
-	"errors"
-	"fmt"
-	"github.com/pborman/uuid"
-	"io"
-)
-
-//ControlPacket defines the interface for structs intended to hold
-//decoded MQTT packets, either from being read or before being
-//written
-type ControlPacket interface {
-	Write(io.Writer) error
-	Unpack(io.Reader)
-	String() string
-	Details() Details
-	UUID() uuid.UUID
-}
-
-//PacketNames maps the constants for each of the MQTT packet types
-//to a string representation of their name.
-var PacketNames = map[uint8]string{
-	1:  "CONNECT",
-	2:  "CONNACK",
-	3:  "PUBLISH",
-	4:  "PUBACK",
-	5:  "PUBREC",
-	6:  "PUBREL",
-	7:  "PUBCOMP",
-	8:  "SUBSCRIBE",
-	9:  "SUBACK",
-	10: "UNSUBSCRIBE",
-	11: "UNSUBACK",
-	12: "PINGREQ",
-	13: "PINGRESP",
-	14: "DISCONNECT",
-}
-
-//Below are the constants assigned to each of the MQTT packet types
-const (
-	Connect     = 1
-	Connack     = 2
-	Publish     = 3
-	Puback      = 4
-	Pubrec      = 5
-	Pubrel      = 6
-	Pubcomp     = 7
-	Subscribe   = 8
-	Suback      = 9
-	Unsubscribe = 10
-	Unsuback    = 11
-	Pingreq     = 12
-	Pingresp    = 13
-	Disconnect  = 14
-)
-
-//Below are the const definitions for error codes returned by
-//Connect()
-const (
-	Accepted                        = 0x00
-	ErrRefusedBadProtocolVersion    = 0x01
-	ErrRefusedIDRejected            = 0x02
-	ErrRefusedServerUnavailable     = 0x03
-	ErrRefusedBadUsernameOrPassword = 0x04
-	ErrRefusedNotAuthorised         = 0x05
-	ErrNetworkError                 = 0xFE
-	ErrProtocolViolation            = 0xFF
-)
-
-//ConnackReturnCodes is a map of the error codes constants for Connect()
-//to a string representation of the error
-var ConnackReturnCodes = map[uint8]string{
-	0:   "Connection Accepted",
-	1:   "Connection Refused: Bad Protocol Version",
-	2:   "Connection Refused: Client Identifier Rejected",
-	3:   "Connection Refused: Server Unavailable",
-	4:   "Connection Refused: Username or Password in unknown format",
-	5:   "Connection Refused: Not Authorised",
-	254: "Connection Error",
-	255: "Connection Refused: Protocol Violation",
-}
-
-//ConnErrors is a map of the errors codes constants for Connect()
-//to a Go error
-var ConnErrors = map[byte]error{
-	Accepted:                        nil,
-	ErrRefusedBadProtocolVersion:    errors.New("Unnacceptable protocol version"),
-	ErrRefusedIDRejected:            errors.New("Identifier rejected"),
-	ErrRefusedServerUnavailable:     errors.New("Server Unavailable"),
-	ErrRefusedBadUsernameOrPassword: errors.New("Bad user name or password"),
-	ErrRefusedNotAuthorised:         errors.New("Not Authorized"),
-	ErrNetworkError:                 errors.New("Network Error"),
-	ErrProtocolViolation:            errors.New("Protocol Violation"),
-}
-
-//ReadPacket takes an instance of an io.Reader (such as net.Conn) and attempts
-//to read an MQTT packet from the stream. It returns a ControlPacket
-//representing the decoded MQTT packet and an error. One of these returns will
-//always be nil, a nil ControlPacket indicating an error occurred.
-func ReadPacket(r io.Reader) (cp ControlPacket, err error) {
-	var fh FixedHeader
-	b := make([]byte, 1)
-
-	_, err = io.ReadFull(r, b)
-	if err != nil {
-		return nil, err
-	}
-	fh.unpack(b[0], r)
-	cp = NewControlPacketWithHeader(fh)
-	if cp == nil {
-		return nil, errors.New("Bad data from client")
-	}
-	packetBytes := make([]byte, fh.RemainingLength)
-	_, err = io.ReadFull(r, packetBytes)
-	if err != nil {
-		return nil, err
-	}
-	cp.Unpack(bytes.NewBuffer(packetBytes))
-	return cp, nil
-}
-
-//NewControlPacket is used to create a new ControlPacket of the type specified
-//by packetType, this is usually done by reference to the packet type constants
-//defined in packets.go. The newly created ControlPacket is empty and a pointer
-//is returned.
-func NewControlPacket(packetType byte) (cp ControlPacket) {
-	switch packetType {
-	case Connect:
-		cp = &ConnectPacket{FixedHeader: FixedHeader{MessageType: Connect}, uuid: uuid.NewUUID()}
-	case Connack:
-		cp = &ConnackPacket{FixedHeader: FixedHeader{MessageType: Connack}, uuid: uuid.NewUUID()}
-	case Disconnect:
-		cp = &DisconnectPacket{FixedHeader: FixedHeader{MessageType: Disconnect}, uuid: uuid.NewUUID()}
-	case Publish:
-		cp = &PublishPacket{FixedHeader: FixedHeader{MessageType: Publish}, uuid: uuid.NewUUID()}
-	case Puback:
-		cp = &PubackPacket{FixedHeader: FixedHeader{MessageType: Puback}, uuid: uuid.NewUUID()}
-	case Pubrec:
-		cp = &PubrecPacket{FixedHeader: FixedHeader{MessageType: Pubrec}, uuid: uuid.NewUUID()}
-	case Pubrel:
-		cp = &PubrelPacket{FixedHeader: FixedHeader{MessageType: Pubrel, Qos: 1}, uuid: uuid.NewUUID()}
-	case Pubcomp:
-		cp = &PubcompPacket{FixedHeader: FixedHeader{MessageType: Pubcomp}, uuid: uuid.NewUUID()}
-	case Subscribe:
-		cp = &SubscribePacket{FixedHeader: FixedHeader{MessageType: Subscribe, Qos: 1}, uuid: uuid.NewUUID()}
-	case Suback:
-		cp = &SubackPacket{FixedHeader: FixedHeader{MessageType: Suback}, uuid: uuid.NewUUID()}
-	case Unsubscribe:
-		cp = &UnsubscribePacket{FixedHeader: FixedHeader{MessageType: Unsubscribe, Qos: 1}, uuid: uuid.NewUUID()}
-	case Unsuback:
-		cp = &UnsubackPacket{FixedHeader: FixedHeader{MessageType: Unsuback}, uuid: uuid.NewUUID()}
-	case Pingreq:
-		cp = &PingreqPacket{FixedHeader: FixedHeader{MessageType: Pingreq}, uuid: uuid.NewUUID()}
-	case Pingresp:
-		cp = &PingrespPacket{FixedHeader: FixedHeader{MessageType: Pingresp}, uuid: uuid.NewUUID()}
-	default:
-		return nil
-	}
-	return cp
-}
-
-//NewControlPacketWithHeader is used to create a new ControlPacket of the type
-//specified within the FixedHeader that is passed to the function.
-//The newly created ControlPacket is empty and a pointer is returned.
-func NewControlPacketWithHeader(fh FixedHeader) (cp ControlPacket) {
-	switch fh.MessageType {
-	case Connect:
-		cp = &ConnectPacket{FixedHeader: fh, uuid: uuid.NewUUID()}
-	case Connack:
-		cp = &ConnackPacket{FixedHeader: fh, uuid: uuid.NewUUID()}
-	case Disconnect:
-		cp = &DisconnectPacket{FixedHeader: fh, uuid: uuid.NewUUID()}
-	case Publish:
-		cp = &PublishPacket{FixedHeader: fh, uuid: uuid.NewUUID()}
-	case Puback:
-		cp = &PubackPacket{FixedHeader: fh, uuid: uuid.NewUUID()}
-	case Pubrec:
-		cp = &PubrecPacket{FixedHeader: fh, uuid: uuid.NewUUID()}
-	case Pubrel:
-		cp = &PubrelPacket{FixedHeader: fh, uuid: uuid.NewUUID()}
-	case Pubcomp:
-		cp = &PubcompPacket{FixedHeader: fh, uuid: uuid.NewUUID()}
-	case Subscribe:
-		cp = &SubscribePacket{FixedHeader: fh, uuid: uuid.NewUUID()}
-	case Suback:
-		cp = &SubackPacket{FixedHeader: fh, uuid: uuid.NewUUID()}
-	case Unsubscribe:
-		cp = &UnsubscribePacket{FixedHeader: fh, uuid: uuid.NewUUID()}
-	case Unsuback:
-		cp = &UnsubackPacket{FixedHeader: fh, uuid: uuid.NewUUID()}
-	case Pingreq:
-		cp = &PingreqPacket{FixedHeader: fh, uuid: uuid.NewUUID()}
-	case Pingresp:
-		cp = &PingrespPacket{FixedHeader: fh, uuid: uuid.NewUUID()}
-	default:
-		return nil
-	}
-	return cp
-}
-
-//Details struct returned by the Details() function called on
-//ControlPackets to present details of the Qos and MessageID
-//of the ControlPacket
-type Details struct {
-	Qos       byte
-	MessageID uint16
-}
-
-//FixedHeader is a struct to hold the decoded information from
-//the fixed header of an MQTT ControlPacket
-type FixedHeader struct {
-	MessageType     byte
-	Dup             bool
-	Qos             byte
-	Retain          bool
-	RemainingLength int
-}
-
-func (fh FixedHeader) String() string {
-	return fmt.Sprintf("%s: dup: %t qos: %d retain: %t rLength: %d", PacketNames[fh.MessageType], fh.Dup, fh.Qos, fh.Retain, fh.RemainingLength)
-}
-
-func boolToByte(b bool) byte {
-	switch b {
-	case true:
-		return 1
-	default:
-		return 0
-	}
-}
-
-func (fh *FixedHeader) pack() bytes.Buffer {
-	var header bytes.Buffer
-	header.WriteByte(fh.MessageType<<4 | boolToByte(fh.Dup)<<3 | fh.Qos<<1 | boolToByte(fh.Retain))
-	header.Write(encodeLength(fh.RemainingLength))
-	return header
-}
-
-func (fh *FixedHeader) unpack(typeAndFlags byte, r io.Reader) {
-	fh.MessageType = typeAndFlags >> 4
-	fh.Dup = (typeAndFlags>>3)&0x01 > 0
-	fh.Qos = (typeAndFlags >> 1) & 0x03
-	fh.Retain = typeAndFlags&0x01 > 0
-	fh.RemainingLength = decodeLength(r)
-}
-
-func decodeByte(b io.Reader) byte {
-	num := make([]byte, 1)
-	b.Read(num)
-	return num[0]
-}
-
-func decodeUint16(b io.Reader) uint16 {
-	num := make([]byte, 2)
-	b.Read(num)
-	return binary.BigEndian.Uint16(num)
-}
-
-func encodeUint16(num uint16) []byte {
-	bytes := make([]byte, 2)
-	binary.BigEndian.PutUint16(bytes, num)
-	return bytes
-}
-
-func encodeString(field string) []byte {
-	fieldLength := make([]byte, 2)
-	binary.BigEndian.PutUint16(fieldLength, uint16(len(field)))
-	return append(fieldLength, []byte(field)...)
-}
-
-func decodeString(b io.Reader) string {
-	fieldLength := decodeUint16(b)
-	field := make([]byte, fieldLength)
-	b.Read(field)
-	return string(field)
-}
-
-func decodeBytes(b io.Reader) []byte {
-	fieldLength := decodeUint16(b)
-	field := make([]byte, fieldLength)
-	b.Read(field)
-	return field
-}
-
-func encodeBytes(field []byte) []byte {
-	fieldLength := make([]byte, 2)
-	binary.BigEndian.PutUint16(fieldLength, uint16(len(field)))
-	return append(fieldLength, field...)
-}
-
-func encodeLength(length int) []byte {
-	var encLength []byte
-	for {
-		digit := byte(length % 128)
-		length /= 128
-		if length > 0 {
-			digit |= 0x80
-		}
-		encLength = append(encLength, digit)
-		if length == 0 {
-			break
-		}
-	}
-	return encLength
-}
-
-func decodeLength(r io.Reader) int {
-	var rLength uint32
-	var multiplier uint32
-	b := make([]byte, 1)
-	for {
-		io.ReadFull(r, b)
-		digit := b[0]
-		rLength |= uint32(digit&127) << multiplier
-		if (digit & 128) == 0 {
-			break
-		}
-		multiplier += 7
-	}
-	return int(rLength)
-}

+ 0 - 44
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/pingreq.go

@@ -1,44 +0,0 @@
-package packets
-
-import (
-	"fmt"
-	"github.com/pborman/uuid"
-	"io"
-)
-
-//PingreqPacket is an internal representation of the fields of the
-//Pingreq MQTT packet
-type PingreqPacket struct {
-	FixedHeader
-	uuid uuid.UUID
-}
-
-func (pr *PingreqPacket) String() string {
-	str := fmt.Sprintf("%s", pr.FixedHeader)
-	return str
-}
-
-func (pr *PingreqPacket) Write(w io.Writer) error {
-	packet := pr.FixedHeader.pack()
-	_, err := packet.WriteTo(w)
-
-	return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (pr *PingreqPacket) Unpack(b io.Reader) {
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (pr *PingreqPacket) Details() Details {
-	return Details{Qos: 0, MessageID: 0}
-}
-
-//UUID returns the unique ID assigned to the ControlPacket when
-//it was originally received. Note: this is not related to the
-//MessageID field for MQTT packets
-func (pr *PingreqPacket) UUID() uuid.UUID {
-	return pr.uuid
-}

+ 0 - 44
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/pingresp.go

@@ -1,44 +0,0 @@
-package packets
-
-import (
-	"fmt"
-	"github.com/pborman/uuid"
-	"io"
-)
-
-//PingrespPacket is an internal representation of the fields of the
-//Pingresp MQTT packet
-type PingrespPacket struct {
-	FixedHeader
-	uuid uuid.UUID
-}
-
-func (pr *PingrespPacket) String() string {
-	str := fmt.Sprintf("%s", pr.FixedHeader)
-	return str
-}
-
-func (pr *PingrespPacket) Write(w io.Writer) error {
-	packet := pr.FixedHeader.pack()
-	_, err := packet.WriteTo(w)
-
-	return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (pr *PingrespPacket) Unpack(b io.Reader) {
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (pr *PingrespPacket) Details() Details {
-	return Details{Qos: 0, MessageID: 0}
-}
-
-//UUID returns the unique ID assigned to the ControlPacket when
-//it was originally received. Note: this is not related to the
-//MessageID field for MQTT packets
-func (pr *PingrespPacket) UUID() uuid.UUID {
-	return pr.uuid
-}

+ 0 - 50
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/puback.go

@@ -1,50 +0,0 @@
-package packets
-
-import (
-	"fmt"
-	"github.com/pborman/uuid"
-	"io"
-)
-
-//PubackPacket is an internal representation of the fields of the
-//Puback MQTT packet
-type PubackPacket struct {
-	FixedHeader
-	MessageID uint16
-	uuid      uuid.UUID
-}
-
-func (pa *PubackPacket) String() string {
-	str := fmt.Sprintf("%s\n", pa.FixedHeader)
-	str += fmt.Sprintf("messageID: %d", pa.MessageID)
-	return str
-}
-
-func (pa *PubackPacket) Write(w io.Writer) error {
-	var err error
-	pa.FixedHeader.RemainingLength = 2
-	packet := pa.FixedHeader.pack()
-	packet.Write(encodeUint16(pa.MessageID))
-	_, err = packet.WriteTo(w)
-
-	return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (pa *PubackPacket) Unpack(b io.Reader) {
-	pa.MessageID = decodeUint16(b)
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (pa *PubackPacket) Details() Details {
-	return Details{Qos: pa.Qos, MessageID: pa.MessageID}
-}
-
-//UUID returns the unique ID assigned to the ControlPacket when
-//it was originally received. Note: this is not related to the
-//MessageID field for MQTT packets
-func (pa *PubackPacket) UUID() uuid.UUID {
-	return pa.uuid
-}

+ 0 - 50
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/pubcomp.go

@@ -1,50 +0,0 @@
-package packets
-
-import (
-	"fmt"
-	"github.com/pborman/uuid"
-	"io"
-)
-
-//PubcompPacket is an internal representation of the fields of the
-//Pubcomp MQTT packet
-type PubcompPacket struct {
-	FixedHeader
-	MessageID uint16
-	uuid      uuid.UUID
-}
-
-func (pc *PubcompPacket) String() string {
-	str := fmt.Sprintf("%s\n", pc.FixedHeader)
-	str += fmt.Sprintf("MessageID: %d", pc.MessageID)
-	return str
-}
-
-func (pc *PubcompPacket) Write(w io.Writer) error {
-	var err error
-	pc.FixedHeader.RemainingLength = 2
-	packet := pc.FixedHeader.pack()
-	packet.Write(encodeUint16(pc.MessageID))
-	_, err = packet.WriteTo(w)
-
-	return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (pc *PubcompPacket) Unpack(b io.Reader) {
-	pc.MessageID = decodeUint16(b)
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (pc *PubcompPacket) Details() Details {
-	return Details{Qos: pc.Qos, MessageID: pc.MessageID}
-}
-
-//UUID returns the unique ID assigned to the ControlPacket when
-//it was originally received. Note: this is not related to the
-//MessageID field for MQTT packets
-func (pc *PubcompPacket) UUID() uuid.UUID {
-	return pc.uuid
-}

+ 0 - 82
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/publish.go

@@ -1,82 +0,0 @@
-package packets
-
-import (
-	"bytes"
-	"fmt"
-	"github.com/pborman/uuid"
-	"io"
-)
-
-//PublishPacket is an internal representation of the fields of the
-//Publish MQTT packet
-type PublishPacket struct {
-	FixedHeader
-	TopicName string
-	MessageID uint16
-	Payload   []byte
-	uuid      uuid.UUID
-}
-
-func (p *PublishPacket) String() string {
-	str := fmt.Sprintf("%s\n", p.FixedHeader)
-	str += fmt.Sprintf("topicName: %s MessageID: %d\n", p.TopicName, p.MessageID)
-	str += fmt.Sprintf("payload: %s\n", string(p.Payload))
-	return str
-}
-
-func (p *PublishPacket) Write(w io.Writer) error {
-	var body bytes.Buffer
-	var err error
-
-	body.Write(encodeString(p.TopicName))
-	if p.Qos > 0 {
-		body.Write(encodeUint16(p.MessageID))
-	}
-	p.FixedHeader.RemainingLength = body.Len() + len(p.Payload)
-	packet := p.FixedHeader.pack()
-	packet.Write(body.Bytes())
-	packet.Write(p.Payload)
-	_, err = w.Write(packet.Bytes())
-
-	return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (p *PublishPacket) Unpack(b io.Reader) {
-	var payloadLength = p.FixedHeader.RemainingLength
-	p.TopicName = decodeString(b)
-	if p.Qos > 0 {
-		p.MessageID = decodeUint16(b)
-		payloadLength -= len(p.TopicName) + 4
-	} else {
-		payloadLength -= len(p.TopicName) + 2
-	}
-	p.Payload = make([]byte, payloadLength)
-	b.Read(p.Payload)
-}
-
-//Copy creates a new PublishPacket with the same topic and payload
-//but an empty fixed header, useful for when you want to deliver
-//a message with different properties such as Qos but the same
-//content
-func (p *PublishPacket) Copy() *PublishPacket {
-	newP := NewControlPacket(Publish).(*PublishPacket)
-	newP.TopicName = p.TopicName
-	newP.Payload = p.Payload
-
-	return newP
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (p *PublishPacket) Details() Details {
-	return Details{Qos: p.Qos, MessageID: p.MessageID}
-}
-
-//UUID returns the unique ID assigned to the ControlPacket when
-//it was originally received. Note: this is not related to the
-//MessageID field for MQTT packets
-func (p *PublishPacket) UUID() uuid.UUID {
-	return p.uuid
-}

+ 0 - 50
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/pubrec.go

@@ -1,50 +0,0 @@
-package packets
-
-import (
-	"fmt"
-	"github.com/pborman/uuid"
-	"io"
-)
-
-//PubrecPacket is an internal representation of the fields of the
-//Pubrec MQTT packet
-type PubrecPacket struct {
-	FixedHeader
-	MessageID uint16
-	uuid      uuid.UUID
-}
-
-func (pr *PubrecPacket) String() string {
-	str := fmt.Sprintf("%s\n", pr.FixedHeader)
-	str += fmt.Sprintf("MessageID: %d", pr.MessageID)
-	return str
-}
-
-func (pr *PubrecPacket) Write(w io.Writer) error {
-	var err error
-	pr.FixedHeader.RemainingLength = 2
-	packet := pr.FixedHeader.pack()
-	packet.Write(encodeUint16(pr.MessageID))
-	_, err = packet.WriteTo(w)
-
-	return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (pr *PubrecPacket) Unpack(b io.Reader) {
-	pr.MessageID = decodeUint16(b)
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (pr *PubrecPacket) Details() Details {
-	return Details{Qos: pr.Qos, MessageID: pr.MessageID}
-}
-
-//UUID returns the unique ID assigned to the ControlPacket when
-//it was originally received. Note: this is not related to the
-//MessageID field for MQTT packets
-func (pr *PubrecPacket) UUID() uuid.UUID {
-	return pr.uuid
-}

+ 0 - 50
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/pubrel.go

@@ -1,50 +0,0 @@
-package packets
-
-import (
-	"fmt"
-	"github.com/pborman/uuid"
-	"io"
-)
-
-//PubrelPacket is an internal representation of the fields of the
-//Pubrel MQTT packet
-type PubrelPacket struct {
-	FixedHeader
-	MessageID uint16
-	uuid      uuid.UUID
-}
-
-func (pr *PubrelPacket) String() string {
-	str := fmt.Sprintf("%s\n", pr.FixedHeader)
-	str += fmt.Sprintf("MessageID: %d", pr.MessageID)
-	return str
-}
-
-func (pr *PubrelPacket) Write(w io.Writer) error {
-	var err error
-	pr.FixedHeader.RemainingLength = 2
-	packet := pr.FixedHeader.pack()
-	packet.Write(encodeUint16(pr.MessageID))
-	_, err = packet.WriteTo(w)
-
-	return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (pr *PubrelPacket) Unpack(b io.Reader) {
-	pr.MessageID = decodeUint16(b)
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (pr *PubrelPacket) Details() Details {
-	return Details{Qos: pr.Qos, MessageID: pr.MessageID}
-}
-
-//UUID returns the unique ID assigned to the ControlPacket when
-//it was originally received. Note: this is not related to the
-//MessageID field for MQTT packets
-func (pr *PubrelPacket) UUID() uuid.UUID {
-	return pr.uuid
-}

+ 0 - 58
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/suback.go

@@ -1,58 +0,0 @@
-package packets
-
-import (
-	"bytes"
-	"fmt"
-	"github.com/pborman/uuid"
-	"io"
-)
-
-//SubackPacket is an internal representation of the fields of the
-//Suback MQTT packet
-type SubackPacket struct {
-	FixedHeader
-	MessageID   uint16
-	GrantedQoss []byte
-	uuid        uuid.UUID
-}
-
-func (sa *SubackPacket) String() string {
-	str := fmt.Sprintf("%s\n", sa.FixedHeader)
-	str += fmt.Sprintf("MessageID: %d", sa.MessageID)
-	return str
-}
-
-func (sa *SubackPacket) Write(w io.Writer) error {
-	var body bytes.Buffer
-	var err error
-	body.Write(encodeUint16(sa.MessageID))
-	body.Write(sa.GrantedQoss)
-	sa.FixedHeader.RemainingLength = body.Len()
-	packet := sa.FixedHeader.pack()
-	packet.Write(body.Bytes())
-	_, err = packet.WriteTo(w)
-
-	return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (sa *SubackPacket) Unpack(b io.Reader) {
-	var qosBuffer bytes.Buffer
-	sa.MessageID = decodeUint16(b)
-	qosBuffer.ReadFrom(b)
-	sa.GrantedQoss = qosBuffer.Bytes()
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (sa *SubackPacket) Details() Details {
-	return Details{Qos: 0, MessageID: sa.MessageID}
-}
-
-//UUID returns the unique ID assigned to the ControlPacket when
-//it was originally received. Note: this is not related to the
-//MessageID field for MQTT packets
-func (sa *SubackPacket) UUID() uuid.UUID {
-	return sa.uuid
-}

+ 0 - 68
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/subscribe.go

@@ -1,68 +0,0 @@
-package packets
-
-import (
-	"bytes"
-	"fmt"
-	"github.com/pborman/uuid"
-	"io"
-)
-
-//SubscribePacket is an internal representation of the fields of the
-//Subscribe MQTT packet
-type SubscribePacket struct {
-	FixedHeader
-	MessageID uint16
-	Topics    []string
-	Qoss      []byte
-	uuid      uuid.UUID
-}
-
-func (s *SubscribePacket) String() string {
-	str := fmt.Sprintf("%s\n", s.FixedHeader)
-	str += fmt.Sprintf("MessageID: %d topics: %s", s.MessageID, s.Topics)
-	return str
-}
-
-func (s *SubscribePacket) Write(w io.Writer) error {
-	var body bytes.Buffer
-	var err error
-
-	body.Write(encodeUint16(s.MessageID))
-	for i, topic := range s.Topics {
-		body.Write(encodeString(topic))
-		body.WriteByte(s.Qoss[i])
-	}
-	s.FixedHeader.RemainingLength = body.Len()
-	packet := s.FixedHeader.pack()
-	packet.Write(body.Bytes())
-	_, err = packet.WriteTo(w)
-
-	return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (s *SubscribePacket) Unpack(b io.Reader) {
-	s.MessageID = decodeUint16(b)
-	payloadLength := s.FixedHeader.RemainingLength - 2
-	for payloadLength > 0 {
-		topic := decodeString(b)
-		s.Topics = append(s.Topics, topic)
-		qos := decodeByte(b)
-		s.Qoss = append(s.Qoss, qos)
-		payloadLength -= 2 + len(topic) + 1 //2 bytes of string length, plus string, plus 1 byte for Qos
-	}
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (s *SubscribePacket) Details() Details {
-	return Details{Qos: 1, MessageID: s.MessageID}
-}
-
-//UUID returns the unique ID assigned to the ControlPacket when
-//it was originally received. Note: this is not related to the
-//MessageID field for MQTT packets
-func (s *SubscribePacket) UUID() uuid.UUID {
-	return s.uuid
-}

+ 0 - 50
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/unsuback.go

@@ -1,50 +0,0 @@
-package packets
-
-import (
-	"fmt"
-	"github.com/pborman/uuid"
-	"io"
-)
-
-//UnsubackPacket is an internal representation of the fields of the
-//Unsuback MQTT packet
-type UnsubackPacket struct {
-	FixedHeader
-	MessageID uint16
-	uuid      uuid.UUID
-}
-
-func (ua *UnsubackPacket) String() string {
-	str := fmt.Sprintf("%s\n", ua.FixedHeader)
-	str += fmt.Sprintf("MessageID: %d", ua.MessageID)
-	return str
-}
-
-func (ua *UnsubackPacket) Write(w io.Writer) error {
-	var err error
-	ua.FixedHeader.RemainingLength = 2
-	packet := ua.FixedHeader.pack()
-	packet.Write(encodeUint16(ua.MessageID))
-	_, err = packet.WriteTo(w)
-
-	return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (ua *UnsubackPacket) Unpack(b io.Reader) {
-	ua.MessageID = decodeUint16(b)
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (ua *UnsubackPacket) Details() Details {
-	return Details{Qos: 0, MessageID: ua.MessageID}
-}
-
-//UUID returns the unique ID assigned to the ControlPacket when
-//it was originally received. Note: this is not related to the
-//MessageID field for MQTT packets
-func (ua *UnsubackPacket) UUID() uuid.UUID {
-	return ua.uuid
-}

+ 0 - 61
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets/unsubscribe.go

@@ -1,61 +0,0 @@
-package packets
-
-import (
-	"bytes"
-	"fmt"
-	"github.com/pborman/uuid"
-	"io"
-)
-
-//UnsubscribePacket is an internal representation of the fields of the
-//Unsubscribe MQTT packet
-type UnsubscribePacket struct {
-	FixedHeader
-	MessageID uint16
-	Topics    []string
-	uuid      uuid.UUID
-}
-
-func (u *UnsubscribePacket) String() string {
-	str := fmt.Sprintf("%s\n", u.FixedHeader)
-	str += fmt.Sprintf("MessageID: %d", u.MessageID)
-	return str
-}
-
-func (u *UnsubscribePacket) Write(w io.Writer) error {
-	var body bytes.Buffer
-	var err error
-	body.Write(encodeUint16(u.MessageID))
-	for _, topic := range u.Topics {
-		body.Write(encodeString(topic))
-	}
-	u.FixedHeader.RemainingLength = body.Len()
-	packet := u.FixedHeader.pack()
-	packet.Write(body.Bytes())
-	_, err = packet.WriteTo(w)
-
-	return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (u *UnsubscribePacket) Unpack(b io.Reader) {
-	u.MessageID = decodeUint16(b)
-	var topic string
-	for topic = decodeString(b); topic != ""; topic = decodeString(b) {
-		u.Topics = append(u.Topics, topic)
-	}
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (u *UnsubscribePacket) Details() Details {
-	return Details{Qos: 1, MessageID: u.MessageID}
-}
-
-//UUID returns the unique ID assigned to the ControlPacket when
-//it was originally received. Note: this is not related to the
-//MessageID field for MQTT packets
-func (u *UnsubscribePacket) UUID() uuid.UUID {
-	return u.uuid
-}

+ 0 - 73
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/ping.go

@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Seth Hoenig
- *    Allan Stockdill-Mander
- *    Mike Robertson
- */
-
-package mqtt
-
-import (
-	"errors"
-	"git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets"
-	"sync"
-	"time"
-)
-
-type lastcontact struct {
-	sync.Mutex
-	lasttime time.Time
-}
-
-func (l *lastcontact) update() {
-	l.Lock()
-	defer l.Unlock()
-	l.lasttime = time.Now()
-
-}
-
-func (l *lastcontact) get() time.Time {
-	l.Lock()
-	defer l.Unlock()
-	return l.lasttime
-}
-
-func keepalive(c *Client) {
-	DEBUG.Println(PNG, "keepalive starting")
-	c.pingOutstanding = false
-
-	for {
-		select {
-		case <-c.stop:
-			DEBUG.Println(PNG, "keepalive stopped")
-			c.workers.Done()
-			return
-		default:
-			last := uint(time.Since(c.lastContact.get()).Seconds())
-			//DEBUG.Printf("%s last contact: %d (timeout: %d)", PNG, last, uint(c.options.KeepAlive.Seconds()))
-			if last > uint(c.options.KeepAlive.Seconds()) {
-				if !c.pingOutstanding {
-					DEBUG.Println(PNG, "keepalive sending ping")
-					ping := packets.NewControlPacket(packets.Pingreq).(*packets.PingreqPacket)
-					c.pingOutstanding = true
-					//We don't want to wait behind large messages being sent, the Write call
-					//will block until it it able to send the packet.
-					ping.Write(c.conn)
-				} else {
-					CRITICAL.Println(PNG, "pingresp not received, disconnecting")
-					c.workers.Done()
-					c.internalConnLost(errors.New("pingresp not received, disconnecting"))
-					return
-				}
-			}
-			time.Sleep(1 * time.Second)
-		}
-	}
-}

+ 0 - 162
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/router.go

@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Seth Hoenig
- *    Allan Stockdill-Mander
- *    Mike Robertson
- */
-
-package mqtt
-
-import (
-	"container/list"
-	"git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets"
-	"strings"
-	"sync"
-)
-
-// route is a type which associates MQTT Topic strings with a
-// callback to be executed upon the arrival of a message associated
-// with a subscription to that topic.
-type route struct {
-	topic    string
-	callback MessageHandler
-}
-
-// match takes a slice of strings which represent the route being tested having been split on '/'
-// separators, and a slice of strings representing the topic string in the published message, similarly
-// split.
-// The function determines if the topic string matches the route according to the MQTT topic rules
-// and returns a boolean of the outcome
-func match(route []string, topic []string) bool {
-	if len(route) == 0 {
-		if len(topic) == 0 {
-			return true
-		}
-		return false
-	}
-
-	if len(topic) == 0 {
-		if route[0] == "#" {
-			return true
-		}
-		return false
-	}
-
-	if route[0] == "#" {
-		return true
-	}
-
-	if (route[0] == "+") || (route[0] == topic[0]) {
-		return match(route[1:], topic[1:])
-	}
-
-	return false
-}
-
-func routeIncludesTopic(route, topic string) bool {
-	return match(strings.Split(route, "/"), strings.Split(topic, "/"))
-}
-
-// match takes the topic string of the published message and does a basic compare to the
-// string of the current Route, if they match it returns true
-func (r *route) match(topic string) bool {
-	return r.topic == topic || routeIncludesTopic(r.topic, topic)
-}
-
-type router struct {
-	sync.RWMutex
-	routes         *list.List
-	defaultHandler MessageHandler
-	messages       chan *packets.PublishPacket
-	stop           chan bool
-}
-
-// newRouter returns a new instance of a Router and channel which can be used to tell the Router
-// to stop
-func newRouter() (*router, chan bool) {
-	router := &router{routes: list.New(), messages: make(chan *packets.PublishPacket), stop: make(chan bool)}
-	stop := router.stop
-	return router, stop
-}
-
-// addRoute takes a topic string and MessageHandler callback. It looks in the current list of
-// routes to see if there is already a matching Route. If there is it replaces the current
-// callback with the new one. If not it add a new entry to the list of Routes.
-func (r *router) addRoute(topic string, callback MessageHandler) {
-	r.Lock()
-	defer r.Unlock()
-	for e := r.routes.Front(); e != nil; e = e.Next() {
-		if e.Value.(*route).match(topic) {
-			r := e.Value.(*route)
-			r.callback = callback
-			return
-		}
-	}
-	r.routes.PushBack(&route{topic: topic, callback: callback})
-}
-
-// deleteRoute takes a route string, looks for a matching Route in the list of Routes. If
-// found it removes the Route from the list.
-func (r *router) deleteRoute(topic string) {
-	r.Lock()
-	defer r.Unlock()
-	for e := r.routes.Front(); e != nil; e = e.Next() {
-		if e.Value.(*route).match(topic) {
-			r.routes.Remove(e)
-			return
-		}
-	}
-}
-
-// setDefaultHandler assigns a default callback that will be called if no matching Route
-// is found for an incoming Publish.
-func (r *router) setDefaultHandler(handler MessageHandler) {
-	r.defaultHandler = handler
-}
-
-// matchAndDispatch takes a channel of Message pointers as input and starts a go routine that
-// takes messages off the channel, matches them against the internal route list and calls the
-// associated callback (or the defaultHandler, if one exists and no other route matched). If
-// anything is sent down the stop channel the function will end.
-func (r *router) matchAndDispatch(messages <-chan *packets.PublishPacket, order bool, client *Client) {
-	go func() {
-		for {
-			select {
-			case message := <-messages:
-				sent := false
-				r.RLock()
-				for e := r.routes.Front(); e != nil; e = e.Next() {
-					if e.Value.(*route).match(message.TopicName) {
-						if order {
-							r.RUnlock()
-							e.Value.(*route).callback(client, messageFromPublish(message))
-							r.RLock()
-						} else {
-							go e.Value.(*route).callback(client, messageFromPublish(message))
-						}
-						sent = true
-					}
-				}
-				r.RUnlock()
-				if !sent && r.defaultHandler != nil {
-					if order {
-						r.RLock()
-						r.defaultHandler(client, messageFromPublish(message))
-						r.RUnlock()
-					} else {
-						go r.defaultHandler(client, messageFromPublish(message))
-					}
-				}
-			case <-r.stop:
-				return
-			}
-		}
-	}()
-}

+ 0 - 125
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/store.go

@@ -1,125 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Seth Hoenig
- *    Allan Stockdill-Mander
- *    Mike Robertson
- */
-
-package mqtt
-
-import (
-	"fmt"
-	"git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets"
-	"strconv"
-)
-
-const (
-	inboundPrefix  = "i."
-	outboundPrefix = "o."
-)
-
-// Store is an interface which can be used to provide implementations
-// for message persistence.
-// Because we may have to store distinct messages with the same
-// message ID, we need a unique key for each message. This is
-// possible by prepending "i." or "o." to each message id
-type Store interface {
-	Open()
-	Put(string, packets.ControlPacket)
-	Get(string) packets.ControlPacket
-	All() []string
-	Del(string)
-	Close()
-	Reset()
-}
-
-// A key MUST have the form "X.[messageid]"
-// where X is 'i' or 'o'
-func mIDFromKey(key string) uint16 {
-	s := key[2:]
-	i, err := strconv.Atoi(s)
-	chkerr(err)
-	return uint16(i)
-}
-
-// Return a string of the form "i.[id]"
-func inboundKeyFromMID(id uint16) string {
-	return fmt.Sprintf("%s%d", inboundPrefix, id)
-}
-
-// Return a string of the form "o.[id]"
-func outboundKeyFromMID(id uint16) string {
-	return fmt.Sprintf("%s%d", outboundPrefix, id)
-}
-
-// govern which outgoing messages are persisted
-func persistOutbound(s Store, m packets.ControlPacket) {
-	switch m.Details().Qos {
-	case 0:
-		switch m.(type) {
-		case *packets.PubackPacket, *packets.PubcompPacket:
-			// Sending puback. delete matching publish
-			// from ibound
-			s.Del(inboundKeyFromMID(m.Details().MessageID))
-		}
-	case 1:
-		switch m.(type) {
-		case *packets.PublishPacket, *packets.PubrelPacket, *packets.SubscribePacket, *packets.UnsubscribePacket:
-			// Sending publish. store in obound
-			// until puback received
-			s.Put(outboundKeyFromMID(m.Details().MessageID), m)
-		default:
-			chkcond(false)
-		}
-	case 2:
-		switch m.(type) {
-		case *packets.PublishPacket:
-			// Sending publish. store in obound
-			// until pubrel received
-			s.Put(outboundKeyFromMID(m.Details().MessageID), m)
-		default:
-			chkcond(false)
-		}
-	}
-}
-
-// govern which incoming messages are persisted
-func persistInbound(s Store, m packets.ControlPacket) {
-	switch m.Details().Qos {
-	case 0:
-		switch m.(type) {
-		case *packets.PubackPacket, *packets.SubackPacket, *packets.UnsubackPacket, *packets.PubcompPacket:
-			// Received a puback. delete matching publish
-			// from obound
-			s.Del(outboundKeyFromMID(m.Details().MessageID))
-		case *packets.PublishPacket, *packets.PubrecPacket, *packets.PingrespPacket, *packets.ConnackPacket:
-		default:
-			chkcond(false)
-		}
-	case 1:
-		switch m.(type) {
-		case *packets.PublishPacket, *packets.PubrelPacket:
-			// Received a publish. store it in ibound
-			// until puback sent
-			s.Put(inboundKeyFromMID(m.Details().MessageID), m)
-		default:
-			chkcond(false)
-		}
-	case 2:
-		switch m.(type) {
-		case *packets.PublishPacket:
-			// Received a publish. store it in ibound
-			// until pubrel received
-			s.Put(inboundKeyFromMID(m.Details().MessageID), m)
-		default:
-			chkcond(false)
-		}
-	}
-}

+ 0 - 156
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/token.go

@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Allan Stockdill-Mander
- */
-
-package mqtt
-
-import (
-	"git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/packets"
-	"sync"
-	"time"
-)
-
-//PacketAndToken is a struct that contains both a ControlPacket and a
-//Token. This struct is passed via channels between the client interface
-//code and the underlying code responsible for sending and receiving
-//MQTT messages.
-type PacketAndToken struct {
-	p packets.ControlPacket
-	t Token
-}
-
-//Token defines the interface for the tokens used to indicate when
-//actions have completed.
-type Token interface {
-	Wait() bool
-	WaitTimeout(time.Duration) bool
-	flowComplete()
-	Error() error
-}
-
-type baseToken struct {
-	m        sync.RWMutex
-	complete chan struct{}
-	ready    bool
-	err      error
-}
-
-// Wait will wait indefinitely for the Token to complete, ie the Publish
-// to be sent and confirmed receipt from the broker
-func (b *baseToken) Wait() bool {
-	b.m.Lock()
-	defer b.m.Unlock()
-	if !b.ready {
-		<-b.complete
-		b.ready = true
-	}
-	return b.ready
-}
-
-// WaitTimeout takes a time in ms to wait for the flow associated with the
-// Token to complete, returns true if it returned before the timeout or
-// returns false if the timeout occurred. In the case of a timeout the Token
-// does not have an error set in case the caller wishes to wait again
-func (b *baseToken) WaitTimeout(d time.Duration) bool {
-	b.m.Lock()
-	defer b.m.Unlock()
-	if !b.ready {
-		select {
-		case <-b.complete:
-			b.ready = true
-		case <-time.After(d):
-		}
-	}
-	return b.ready
-}
-
-func (b *baseToken) flowComplete() {
-	close(b.complete)
-}
-
-func (b *baseToken) Error() error {
-	b.m.RLock()
-	defer b.m.RUnlock()
-	return b.err
-}
-
-func newToken(tType byte) Token {
-	switch tType {
-	case packets.Connect:
-		return &ConnectToken{baseToken: baseToken{complete: make(chan struct{})}}
-	case packets.Subscribe:
-		return &SubscribeToken{baseToken: baseToken{complete: make(chan struct{})}, subResult: make(map[string]byte)}
-	case packets.Publish:
-		return &PublishToken{baseToken: baseToken{complete: make(chan struct{})}}
-	case packets.Unsubscribe:
-		return &UnsubscribeToken{baseToken: baseToken{complete: make(chan struct{})}}
-	case packets.Disconnect:
-		return &DisconnectToken{baseToken: baseToken{complete: make(chan struct{})}}
-	}
-	return nil
-}
-
-//ConnectToken is an extension of Token containing the extra fields
-//required to provide information about calls to Connect()
-type ConnectToken struct {
-	baseToken
-	returnCode byte
-}
-
-//ReturnCode returns the acknowlegement code in the connack sent
-//in response to a Connect()
-func (c *ConnectToken) ReturnCode() byte {
-	c.m.RLock()
-	defer c.m.RUnlock()
-	return c.returnCode
-}
-
-//PublishToken is an extension of Token containing the extra fields
-//required to provide information about calls to Publish()
-type PublishToken struct {
-	baseToken
-	messageID uint16
-}
-
-//MessageID returns the MQTT message ID that was assigned to the
-//Publish packet when it was sent to the broker
-func (p *PublishToken) MessageID() uint16 {
-	return p.messageID
-}
-
-//SubscribeToken is an extension of Token containing the extra fields
-//required to provide information about calls to Subscribe()
-type SubscribeToken struct {
-	baseToken
-	subs      []string
-	subResult map[string]byte
-}
-
-//Result returns a map of topics that were subscribed to along with
-//the matching return code from the broker. This is either the Qos
-//value of the subscription or an error code.
-func (s *SubscribeToken) Result() map[string]byte {
-	s.m.RLock()
-	defer s.m.RUnlock()
-	return s.subResult
-}
-
-//UnsubscribeToken is an extension of Token containing the extra fields
-//required to provide information about calls to Unsubscribe()
-type UnsubscribeToken struct {
-	baseToken
-}
-
-//DisconnectToken is an extension of Token containing the extra fields
-//required to provide information about calls to Disconnect()
-type DisconnectToken struct {
-	baseToken
-}

+ 0 - 82
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/topic.go

@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Seth Hoenig
- *    Allan Stockdill-Mander
- *    Mike Robertson
- */
-
-package mqtt
-
-import (
-	"errors"
-	"strings"
-)
-
-//InvalidQos is the error returned when an packet is to be sent
-//with an invalid Qos value
-var ErrInvalidQos = errors.New("Invalid QoS")
-
-//InvalidTopicEmptyString is the error returned when a topic string
-//is passed in that is 0 length
-var ErrInvalidTopicEmptyString = errors.New("Invalid Topic; empty string")
-
-//InvalidTopicMultilevel is the error returned when a topic string
-//is passed in that has the multi level wildcard in any position but
-//the last
-var ErrInvalidTopicMultilevel = errors.New("Invalid Topic; multi-level wildcard must be last level")
-
-// Topic Names and Topic Filters
-// The MQTT v3.1.1 spec clarifies a number of ambiguities with regard
-// to the validity of Topic strings.
-// - A Topic must be between 1 and 65535 bytes.
-// - A Topic is case sensitive.
-// - A Topic may contain whitespace.
-// - A Topic containing a leading forward slash is different than a Topic without.
-// - A Topic may be "/" (two levels, both empty string).
-// - A Topic must be UTF-8 encoded.
-// - A Topic may contain any number of levels.
-// - A Topic may contain an empty level (two forward slashes in a row).
-// - A TopicName may not contain a wildcard.
-// - A TopicFilter may only have a # (multi-level) wildcard as the last level.
-// - A TopicFilter may contain any number of + (single-level) wildcards.
-// - A TopicFilter with a # will match the absense of a level
-//     Example:  a subscription to "foo/#" will match messages published to "foo".
-
-func validateSubscribeMap(subs map[string]byte) ([]string, []byte, error) {
-	var topics []string
-	var qoss []byte
-	for topic, qos := range subs {
-		if err := validateTopicAndQos(topic, qos); err != nil {
-			return nil, nil, err
-		}
-		topics = append(topics, topic)
-		qoss = append(qoss, qos)
-	}
-
-	return topics, qoss, nil
-}
-
-func validateTopicAndQos(topic string, qos byte) error {
-	if len(topic) == 0 {
-		return ErrInvalidTopicEmptyString
-	}
-
-	levels := strings.Split(topic, "/")
-	for i, level := range levels {
-		if level == "#" && i != len(levels)-1 {
-			return ErrInvalidTopicMultilevel
-		}
-	}
-
-	if qos < 0 || qos > 2 {
-		return ErrInvalidQos
-	}
-	return nil
-}

+ 0 - 36
vendor/git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git/trace.go

@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *    Seth Hoenig
- *    Allan Stockdill-Mander
- *    Mike Robertson
- */
-
-package mqtt
-
-import (
-	"io/ioutil"
-	"log"
-)
-
-// Internal levels of library output that are initialised to not print
-// anything but can be overridden by programmer
-var (
-	ERROR    *log.Logger
-	CRITICAL *log.Logger
-	WARN     *log.Logger
-	DEBUG    *log.Logger
-)
-
-func init() {
-	ERROR = log.New(ioutil.Discard, "", 0)
-	CRITICAL = log.New(ioutil.Discard, "", 0)
-	WARN = log.New(ioutil.Discard, "", 0)
-	DEBUG = log.New(ioutil.Discard, "", 0)
-}

BIN
vendor/github.com/.DS_Store


+ 2 - 0
vendor/github.com/BurntSushi/toml/.gitignore

@@ -0,0 +1,2 @@
+/toml.test
+/toml-test

+ 0 - 3
vendor/github.com/BurntSushi/toml/COMPATIBLE

@@ -1,3 +0,0 @@
-Compatible with TOML version
-[v0.4.0](https://github.com/toml-lang/toml/blob/v0.4.0/versions/en/toml-v0.4.0.md)
-

+ 21 - 14
vendor/github.com/BurntSushi/toml/COPYING

@@ -1,14 +1,21 @@
-            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
-                    Version 2, December 2004
-
- Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
-
- Everyone is permitted to copy and distribute verbatim or modified
- copies of this license document, and changing it is allowed as long
- as the name is changed.
-
-            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. You just DO WHAT THE FUCK YOU WANT TO.
-
+The MIT License (MIT)
+
+Copyright (c) 2013 TOML authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 0 - 19
vendor/github.com/BurntSushi/toml/Makefile

@@ -1,19 +0,0 @@
-install:
-	go install ./...
-
-test: install
-	go test -v
-	toml-test toml-test-decoder
-	toml-test -encoder toml-test-encoder
-
-fmt:
-	gofmt -w *.go */*.go
-	colcheck *.go */*.go
-
-tags:
-	find ./ -name '*.go' -print0 | xargs -0 gotags > TAGS
-
-push:
-	git push origin master
-	git push github master
-

+ 120 - 0
vendor/github.com/BurntSushi/toml/README.md

@@ -0,0 +1,120 @@
+TOML stands for Tom's Obvious, Minimal Language. This Go package provides a
+reflection interface similar to Go's standard library `json` and `xml` packages.
+
+Compatible with TOML version [v1.0.0](https://toml.io/en/v1.0.0).
+
+Documentation: https://godocs.io/github.com/BurntSushi/toml
+
+See the [releases page](https://github.com/BurntSushi/toml/releases) for a
+changelog; this information is also in the git tag annotations (e.g. `git show
+v0.4.0`).
+
+This library requires Go 1.13 or newer; add it to your go.mod with:
+
+    % go get github.com/BurntSushi/toml@latest
+
+It also comes with a TOML validator CLI tool:
+
+    % go install github.com/BurntSushi/toml/cmd/tomlv@latest
+    % tomlv some-toml-file.toml
+
+### Examples
+For the simplest example, consider some TOML file as just a list of keys and
+values:
+
+```toml
+Age = 25
+Cats = [ "Cauchy", "Plato" ]
+Pi = 3.14
+Perfection = [ 6, 28, 496, 8128 ]
+DOB = 1987-07-05T05:45:00Z
+```
+
+Which can be decoded with:
+
+```go
+type Config struct {
+	Age        int
+	Cats       []string
+	Pi         float64
+	Perfection []int
+	DOB        time.Time
+}
+
+var conf Config
+_, err := toml.Decode(tomlData, &conf)
+```
+
+You can also use struct tags if your struct field name doesn't map to a TOML key
+value directly:
+
+```toml
+some_key_NAME = "wat"
+```
+
+```go
+type TOML struct {
+    ObscureKey string `toml:"some_key_NAME"`
+}
+```
+
+Beware that like other decoders **only exported fields** are considered when
+encoding and decoding; private fields are silently ignored.
+
+### Using the `Marshaler` and `encoding.TextUnmarshaler` interfaces
+Here's an example that automatically parses values in a `mail.Address`:
+
+```toml
+contacts = [
+    "Donald Duck <donald@duckburg.com>",
+    "Scrooge McDuck <scrooge@duckburg.com>",
+]
+```
+
+Can be decoded with:
+
+```go
+// Create address type which satisfies the encoding.TextUnmarshaler interface.
+type address struct {
+	*mail.Address
+}
+
+func (a *address) UnmarshalText(text []byte) error {
+	var err error
+	a.Address, err = mail.ParseAddress(string(text))
+	return err
+}
+
+// Decode it.
+func decode() {
+	blob := `
+		contacts = [
+			"Donald Duck <donald@duckburg.com>",
+			"Scrooge McDuck <scrooge@duckburg.com>",
+		]
+	`
+
+	var contacts struct {
+		Contacts []address
+	}
+
+	_, err := toml.Decode(blob, &contacts)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	for _, c := range contacts.Contacts {
+		fmt.Printf("%#v\n", c.Address)
+	}
+
+	// Output:
+	// &mail.Address{Name:"Donald Duck", Address:"donald@duckburg.com"}
+	// &mail.Address{Name:"Scrooge McDuck", Address:"scrooge@duckburg.com"}
+}
+```
+
+To target TOML specifically you can implement `UnmarshalTOML` TOML interface in
+a similar way.
+
+### More complex usage
+See the [`_example/`](/_example) directory for a more complex example.

+ 299 - 206
vendor/github.com/BurntSushi/toml/decode.go

@@ -1,146 +1,188 @@
 package toml
 
 import (
+	"bytes"
+	"encoding"
+	"encoding/json"
 	"fmt"
 	"io"
 	"io/ioutil"
 	"math"
+	"os"
 	"reflect"
+	"strconv"
 	"strings"
 	"time"
 )
 
-func e(format string, args ...interface{}) error {
-	return fmt.Errorf("toml: "+format, args...)
-}
-
 // Unmarshaler is the interface implemented by objects that can unmarshal a
 // TOML description of themselves.
 type Unmarshaler interface {
 	UnmarshalTOML(interface{}) error
 }
 
-// Unmarshal decodes the contents of `p` in TOML format into a pointer `v`.
-func Unmarshal(p []byte, v interface{}) error {
-	_, err := Decode(string(p), v)
+// Unmarshal decodes the contents of data in TOML format into a pointer v.
+//
+// See [Decoder] for a description of the decoding process.
+func Unmarshal(data []byte, v interface{}) error {
+	_, err := NewDecoder(bytes.NewReader(data)).Decode(v)
 	return err
 }
 
+// Decode the TOML data in to the pointer v.
+//
+// See [Decoder] for a description of the decoding process.
+func Decode(data string, v interface{}) (MetaData, error) {
+	return NewDecoder(strings.NewReader(data)).Decode(v)
+}
+
+// DecodeFile reads the contents of a file and decodes it with [Decode].
+func DecodeFile(path string, v interface{}) (MetaData, error) {
+	fp, err := os.Open(path)
+	if err != nil {
+		return MetaData{}, err
+	}
+	defer fp.Close()
+	return NewDecoder(fp).Decode(v)
+}
+
 // Primitive is a TOML value that hasn't been decoded into a Go value.
-// When using the various `Decode*` functions, the type `Primitive` may
-// be given to any value, and its decoding will be delayed.
 //
-// A `Primitive` value can be decoded using the `PrimitiveDecode` function.
+// This type can be used for any value, which will cause decoding to be delayed.
+// You can use [PrimitiveDecode] to "manually" decode these values.
 //
-// The underlying representation of a `Primitive` value is subject to change.
-// Do not rely on it.
+// NOTE: The underlying representation of a `Primitive` value is subject to
+// change. Do not rely on it.
 //
-// N.B. Primitive values are still parsed, so using them will only avoid
-// the overhead of reflection. They can be useful when you don't know the
-// exact type of TOML data until run time.
+// NOTE: Primitive values are still parsed, so using them will only avoid the
+// overhead of reflection. They can be useful when you don't know the exact type
+// of TOML data until runtime.
 type Primitive struct {
 	undecoded interface{}
 	context   Key
 }
 
-// DEPRECATED!
-//
-// Use MetaData.PrimitiveDecode instead.
-func PrimitiveDecode(primValue Primitive, v interface{}) error {
-	md := MetaData{decoded: make(map[string]bool)}
-	return md.unify(primValue.undecoded, rvalue(v))
-}
+// The significand precision for float32 and float64 is 24 and 53 bits; this is
+// the range a natural number can be stored in a float without loss of data.
+const (
+	maxSafeFloat32Int = 16777215                // 2^24-1
+	maxSafeFloat64Int = int64(9007199254740991) // 2^53-1
+)
 
-// PrimitiveDecode is just like the other `Decode*` functions, except it
-// decodes a TOML value that has already been parsed. Valid primitive values
-// can *only* be obtained from values filled by the decoder functions,
-// including this method. (i.e., `v` may contain more `Primitive`
-// values.)
+// Decoder decodes TOML data.
 //
-// Meta data for primitive values is included in the meta data returned by
-// the `Decode*` functions with one exception: keys returned by the Undecoded
-// method will only reflect keys that were decoded. Namely, any keys hidden
-// behind a Primitive will be considered undecoded. Executing this method will
-// update the undecoded keys in the meta data. (See the example.)
-func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
-	md.context = primValue.context
-	defer func() { md.context = nil }()
-	return md.unify(primValue.undecoded, rvalue(v))
-}
-
-// Decode will decode the contents of `data` in TOML format into a pointer
-// `v`.
+// TOML tables correspond to Go structs or maps; they can be used
+// interchangeably, but structs offer better type safety.
 //
-// TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be
-// used interchangeably.)
+// TOML table arrays correspond to either a slice of structs or a slice of maps.
 //
-// TOML arrays of tables correspond to either a slice of structs or a slice
-// of maps.
+// TOML datetimes correspond to [time.Time]. Local datetimes are parsed in the
+// local timezone.
 //
-// TOML datetimes correspond to Go `time.Time` values.
+// [time.Duration] types are treated as nanoseconds if the TOML value is an
+// integer, or they're parsed with time.ParseDuration() if they're strings.
 //
-// All other TOML types (float, string, int, bool and array) correspond
-// to the obvious Go types.
+// All other TOML types (float, string, int, bool and array) correspond to the
+// obvious Go types.
 //
-// An exception to the above rules is if a type implements the
-// encoding.TextUnmarshaler interface. In this case, any primitive TOML value
-// (floats, strings, integers, booleans and datetimes) will be converted to
-// a byte string and given to the value's UnmarshalText method. See the
-// Unmarshaler example for a demonstration with time duration strings.
+// An exception to the above rules is if a type implements the TextUnmarshaler
+// interface, in which case any primitive TOML value (floats, strings, integers,
+// booleans, datetimes) will be converted to a []byte and given to the value's
+// UnmarshalText method. See the Unmarshaler example for a demonstration with
+// email addresses.
 //
-// Key mapping
+// # Key mapping
 //
-// TOML keys can map to either keys in a Go map or field names in a Go
-// struct. The special `toml` struct tag may be used to map TOML keys to
-// struct fields that don't match the key name exactly. (See the example.)
-// A case insensitive match to struct names will be tried if an exact match
-// can't be found.
+// TOML keys can map to either keys in a Go map or field names in a Go struct.
+// The special `toml` struct tag can be used to map TOML keys to struct fields
+// that don't match the key name exactly (see the example). A case insensitive
+// match to struct names will be tried if an exact match can't be found.
 //
-// The mapping between TOML values and Go values is loose. That is, there
-// may exist TOML values that cannot be placed into your representation, and
-// there may be parts of your representation that do not correspond to
-// TOML values. This loose mapping can be made stricter by using the IsDefined
-// and/or Undecoded methods on the MetaData returned.
+// The mapping between TOML values and Go values is loose. That is, there may
+// exist TOML values that cannot be placed into your representation, and there
+// may be parts of your representation that do not correspond to TOML values.
+// This loose mapping can be made stricter by using the IsDefined and/or
+// Undecoded methods on the MetaData returned.
 //
-// This decoder will not handle cyclic types. If a cyclic type is passed,
-// `Decode` will not terminate.
-func Decode(data string, v interface{}) (MetaData, error) {
+// This decoder does not handle cyclic types. Decode will not terminate if a
+// cyclic type is passed.
+type Decoder struct {
+	r io.Reader
+}
+
+// NewDecoder creates a new Decoder.
+func NewDecoder(r io.Reader) *Decoder {
+	return &Decoder{r: r}
+}
+
+var (
+	unmarshalToml = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
+	unmarshalText = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
+	primitiveType = reflect.TypeOf((*Primitive)(nil)).Elem()
+)
+
+// Decode TOML data in to the pointer `v`.
+func (dec *Decoder) Decode(v interface{}) (MetaData, error) {
 	rv := reflect.ValueOf(v)
 	if rv.Kind() != reflect.Ptr {
-		return MetaData{}, e("Decode of non-pointer %s", reflect.TypeOf(v))
+		s := "%q"
+		if reflect.TypeOf(v) == nil {
+			s = "%v"
+		}
+
+		return MetaData{}, fmt.Errorf("toml: cannot decode to non-pointer "+s, reflect.TypeOf(v))
 	}
 	if rv.IsNil() {
-		return MetaData{}, e("Decode of nil %s", reflect.TypeOf(v))
-	}
-	p, err := parse(data)
-	if err != nil {
-		return MetaData{}, err
+		return MetaData{}, fmt.Errorf("toml: cannot decode to nil value of %q", reflect.TypeOf(v))
 	}
-	md := MetaData{
-		p.mapping, p.types, p.ordered,
-		make(map[string]bool, len(p.ordered)), nil,
+
+	// Check if this is a supported type: struct, map, interface{}, or something
+	// that implements UnmarshalTOML or UnmarshalText.
+	rv = indirect(rv)
+	rt := rv.Type()
+	if rv.Kind() != reflect.Struct && rv.Kind() != reflect.Map &&
+		!(rv.Kind() == reflect.Interface && rv.NumMethod() == 0) &&
+		!rt.Implements(unmarshalToml) && !rt.Implements(unmarshalText) {
+		return MetaData{}, fmt.Errorf("toml: cannot decode to type %s", rt)
 	}
-	return md, md.unify(p.mapping, indirect(rv))
-}
 
-// DecodeFile is just like Decode, except it will automatically read the
-// contents of the file at `fpath` and decode it for you.
-func DecodeFile(fpath string, v interface{}) (MetaData, error) {
-	bs, err := ioutil.ReadFile(fpath)
+	// TODO: parser should read from io.Reader? Or at the very least, make it
+	// read from []byte rather than string
+	data, err := ioutil.ReadAll(dec.r)
 	if err != nil {
 		return MetaData{}, err
 	}
-	return Decode(string(bs), v)
-}
 
-// DecodeReader is just like Decode, except it will consume all bytes
-// from the reader and decode it for you.
-func DecodeReader(r io.Reader, v interface{}) (MetaData, error) {
-	bs, err := ioutil.ReadAll(r)
+	p, err := parse(string(data))
 	if err != nil {
 		return MetaData{}, err
 	}
-	return Decode(string(bs), v)
+
+	md := MetaData{
+		mapping: p.mapping,
+		keyInfo: p.keyInfo,
+		keys:    p.ordered,
+		decoded: make(map[string]struct{}, len(p.ordered)),
+		context: nil,
+		data:    data,
+	}
+	return md, md.unify(p.mapping, rv)
+}
+
+// PrimitiveDecode is just like the other Decode* functions, except it decodes a
+// TOML value that has already been parsed. Valid primitive values can *only* be
+// obtained from values filled by the decoder functions, including this method.
+// (i.e., v may contain more [Primitive] values.)
+//
+// Meta data for primitive values is included in the meta data returned by the
+// Decode* functions with one exception: keys returned by the Undecoded method
+// will only reflect keys that were decoded. Namely, any keys hidden behind a
+// Primitive will be considered undecoded. Executing this method will update the
+// undecoded keys in the meta data. (See the example.)
+func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
+	md.context = primValue.context
+	defer func() { md.context = nil }()
+	return md.unify(primValue.undecoded, rvalue(v))
 }
 
 // unify performs a sort of type unification based on the structure of `rv`,
@@ -149,9 +191,9 @@ func DecodeReader(r io.Reader, v interface{}) (MetaData, error) {
 // Any type mismatch produces an error. Finding a type that we don't know
 // how to handle produces an unsupported type error.
 func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
-
 	// Special case. Look for a `Primitive` value.
-	if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() {
+	// TODO: #76 would make this superfluous after implemented.
+	if rv.Type() == primitiveType {
 		// Save the undecoded data and the key context into the primitive
 		// value.
 		context := make(Key, len(md.context))
@@ -163,36 +205,24 @@ func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
 		return nil
 	}
 
-	// Special case. Unmarshaler Interface support.
-	if rv.CanAddr() {
-		if v, ok := rv.Addr().Interface().(Unmarshaler); ok {
-			return v.UnmarshalTOML(data)
-		}
+	rvi := rv.Interface()
+	if v, ok := rvi.(Unmarshaler); ok {
+		return v.UnmarshalTOML(data)
 	}
-
-	// Special case. Handle time.Time values specifically.
-	// TODO: Remove this code when we decide to drop support for Go 1.1.
-	// This isn't necessary in Go 1.2 because time.Time satisfies the encoding
-	// interfaces.
-	if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) {
-		return md.unifyDatetime(data, rv)
-	}
-
-	// Special case. Look for a value satisfying the TextUnmarshaler interface.
-	if v, ok := rv.Interface().(TextUnmarshaler); ok {
+	if v, ok := rvi.(encoding.TextUnmarshaler); ok {
 		return md.unifyText(data, v)
 	}
-	// BUG(burntsushi)
+
+	// TODO:
 	// The behavior here is incorrect whenever a Go type satisfies the
-	// encoding.TextUnmarshaler interface but also corresponds to a TOML
-	// hash or array. In particular, the unmarshaler should only be applied
-	// to primitive TOML values. But at this point, it will be applied to
-	// all kinds of values and produce an incorrect error whenever those values
-	// are hashes or arrays (including arrays of tables).
+	// encoding.TextUnmarshaler interface but also corresponds to a TOML hash or
+	// array. In particular, the unmarshaler should only be applied to primitive
+	// TOML values. But at this point, it will be applied to all kinds of values
+	// and produce an incorrect error whenever those values are hashes or arrays
+	// (including arrays of tables).
 
 	k := rv.Kind()
 
-	// laziness
 	if k >= reflect.Int && k <= reflect.Uint64 {
 		return md.unifyInt(data, rv)
 	}
@@ -218,17 +248,14 @@ func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
 	case reflect.Bool:
 		return md.unifyBool(data, rv)
 	case reflect.Interface:
-		// we only support empty interfaces.
-		if rv.NumMethod() > 0 {
-			return e("unsupported type %s", rv.Type())
+		if rv.NumMethod() > 0 { /// Only empty interfaces are supported.
+			return md.e("unsupported type %s", rv.Type())
 		}
 		return md.unifyAnything(data, rv)
-	case reflect.Float32:
-		fallthrough
-	case reflect.Float64:
+	case reflect.Float32, reflect.Float64:
 		return md.unifyFloat64(data, rv)
 	}
-	return e("unsupported type %s", rv.Kind())
+	return md.e("unsupported type %s", rv.Kind())
 }
 
 func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
@@ -237,7 +264,7 @@ func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
 		if mapping == nil {
 			return nil
 		}
-		return e("type mismatch for %s: expected table but found %T",
+		return md.e("type mismatch for %s: expected table but found %T",
 			rv.Type().String(), mapping)
 	}
 
@@ -259,17 +286,18 @@ func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
 			for _, i := range f.index {
 				subv = indirect(subv.Field(i))
 			}
+
 			if isUnifiable(subv) {
-				md.decoded[md.context.add(key).String()] = true
+				md.decoded[md.context.add(key).String()] = struct{}{}
 				md.context = append(md.context, key)
-				if err := md.unify(datum, subv); err != nil {
+
+				err := md.unify(datum, subv)
+				if err != nil {
 					return err
 				}
 				md.context = md.context[0 : len(md.context)-1]
 			} else if f.name != "" {
-				// Bad user! No soup for you!
-				return e("cannot write unexported field %s.%s",
-					rv.Type().String(), f.name)
+				return md.e("cannot write unexported field %s.%s", rv.Type().String(), f.name)
 			}
 		}
 	}
@@ -277,28 +305,43 @@ func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
 }
 
 func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error {
+	keyType := rv.Type().Key().Kind()
+	if keyType != reflect.String && keyType != reflect.Interface {
+		return fmt.Errorf("toml: cannot decode to a map with non-string key type (%s in %q)",
+			keyType, rv.Type())
+	}
+
 	tmap, ok := mapping.(map[string]interface{})
 	if !ok {
 		if tmap == nil {
 			return nil
 		}
-		return badtype("map", mapping)
+		return md.badtype("map", mapping)
 	}
 	if rv.IsNil() {
 		rv.Set(reflect.MakeMap(rv.Type()))
 	}
 	for k, v := range tmap {
-		md.decoded[md.context.add(k).String()] = true
+		md.decoded[md.context.add(k).String()] = struct{}{}
 		md.context = append(md.context, k)
 
-		rvkey := indirect(reflect.New(rv.Type().Key()))
 		rvval := reflect.Indirect(reflect.New(rv.Type().Elem()))
-		if err := md.unify(v, rvval); err != nil {
+
+		err := md.unify(v, indirect(rvval))
+		if err != nil {
 			return err
 		}
 		md.context = md.context[0 : len(md.context)-1]
 
-		rvkey.SetString(k)
+		rvkey := indirect(reflect.New(rv.Type().Key()))
+
+		switch keyType {
+		case reflect.Interface:
+			rvkey.Set(reflect.ValueOf(k))
+		case reflect.String:
+			rvkey.SetString(k)
+		}
+
 		rv.SetMapIndex(rvkey, rvval)
 	}
 	return nil
@@ -310,12 +353,10 @@ func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error {
 		if !datav.IsValid() {
 			return nil
 		}
-		return badtype("slice", data)
+		return md.badtype("slice", data)
 	}
-	sliceLen := datav.Len()
-	if sliceLen != rv.Len() {
-		return e("expected array length %d; got TOML array of length %d",
-			rv.Len(), sliceLen)
+	if l := datav.Len(); l != rv.Len() {
+		return md.e("expected array length %d; got TOML array of length %d", rv.Len(), l)
 	}
 	return md.unifySliceArray(datav, rv)
 }
@@ -326,7 +367,7 @@ func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error {
 		if !datav.IsValid() {
 			return nil
 		}
-		return badtype("slice", data)
+		return md.badtype("slice", data)
 	}
 	n := datav.Len()
 	if rv.IsNil() || rv.Cap() < n {
@@ -337,37 +378,45 @@ func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error {
 }
 
 func (md *MetaData) unifySliceArray(data, rv reflect.Value) error {
-	sliceLen := data.Len()
-	for i := 0; i < sliceLen; i++ {
-		v := data.Index(i).Interface()
-		sliceval := indirect(rv.Index(i))
-		if err := md.unify(v, sliceval); err != nil {
+	l := data.Len()
+	for i := 0; i < l; i++ {
+		err := md.unify(data.Index(i).Interface(), indirect(rv.Index(i)))
+		if err != nil {
 			return err
 		}
 	}
 	return nil
 }
 
-func (md *MetaData) unifyDatetime(data interface{}, rv reflect.Value) error {
-	if _, ok := data.(time.Time); ok {
-		rv.Set(reflect.ValueOf(data))
+func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error {
+	_, ok := rv.Interface().(json.Number)
+	if ok {
+		if i, ok := data.(int64); ok {
+			rv.SetString(strconv.FormatInt(i, 10))
+		} else if f, ok := data.(float64); ok {
+			rv.SetString(strconv.FormatFloat(f, 'f', -1, 64))
+		} else {
+			return md.badtype("string", data)
+		}
 		return nil
 	}
-	return badtype("time.Time", data)
-}
 
-func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error {
 	if s, ok := data.(string); ok {
 		rv.SetString(s)
 		return nil
 	}
-	return badtype("string", data)
+	return md.badtype("string", data)
 }
 
 func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error {
+	rvk := rv.Kind()
+
 	if num, ok := data.(float64); ok {
-		switch rv.Kind() {
+		switch rvk {
 		case reflect.Float32:
+			if num < -math.MaxFloat32 || num > math.MaxFloat32 {
+				return md.parseErr(errParseRange{i: num, size: rvk.String()})
+			}
 			fallthrough
 		case reflect.Float64:
 			rv.SetFloat(num)
@@ -376,54 +425,60 @@ func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error {
 		}
 		return nil
 	}
-	return badtype("float", data)
+
+	if num, ok := data.(int64); ok {
+		if (rvk == reflect.Float32 && (num < -maxSafeFloat32Int || num > maxSafeFloat32Int)) ||
+			(rvk == reflect.Float64 && (num < -maxSafeFloat64Int || num > maxSafeFloat64Int)) {
+			return md.parseErr(errParseRange{i: num, size: rvk.String()})
+		}
+		rv.SetFloat(float64(num))
+		return nil
+	}
+
+	return md.badtype("float", data)
 }
 
 func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error {
-	if num, ok := data.(int64); ok {
-		if rv.Kind() >= reflect.Int && rv.Kind() <= reflect.Int64 {
-			switch rv.Kind() {
-			case reflect.Int, reflect.Int64:
-				// No bounds checking necessary.
-			case reflect.Int8:
-				if num < math.MinInt8 || num > math.MaxInt8 {
-					return e("value %d is out of range for int8", num)
-				}
-			case reflect.Int16:
-				if num < math.MinInt16 || num > math.MaxInt16 {
-					return e("value %d is out of range for int16", num)
-				}
-			case reflect.Int32:
-				if num < math.MinInt32 || num > math.MaxInt32 {
-					return e("value %d is out of range for int32", num)
-				}
+	_, ok := rv.Interface().(time.Duration)
+	if ok {
+		// Parse as string duration, and fall back to regular integer parsing
+		// (as nanosecond) if this is not a string.
+		if s, ok := data.(string); ok {
+			dur, err := time.ParseDuration(s)
+			if err != nil {
+				return md.parseErr(errParseDuration{s})
 			}
-			rv.SetInt(num)
-		} else if rv.Kind() >= reflect.Uint && rv.Kind() <= reflect.Uint64 {
-			unum := uint64(num)
-			switch rv.Kind() {
-			case reflect.Uint, reflect.Uint64:
-				// No bounds checking necessary.
-			case reflect.Uint8:
-				if num < 0 || unum > math.MaxUint8 {
-					return e("value %d is out of range for uint8", num)
-				}
-			case reflect.Uint16:
-				if num < 0 || unum > math.MaxUint16 {
-					return e("value %d is out of range for uint16", num)
-				}
-			case reflect.Uint32:
-				if num < 0 || unum > math.MaxUint32 {
-					return e("value %d is out of range for uint32", num)
-				}
-			}
-			rv.SetUint(unum)
-		} else {
-			panic("unreachable")
+			rv.SetInt(int64(dur))
+			return nil
 		}
-		return nil
 	}
-	return badtype("integer", data)
+
+	num, ok := data.(int64)
+	if !ok {
+		return md.badtype("integer", data)
+	}
+
+	rvk := rv.Kind()
+	switch {
+	case rvk >= reflect.Int && rvk <= reflect.Int64:
+		if (rvk == reflect.Int8 && (num < math.MinInt8 || num > math.MaxInt8)) ||
+			(rvk == reflect.Int16 && (num < math.MinInt16 || num > math.MaxInt16)) ||
+			(rvk == reflect.Int32 && (num < math.MinInt32 || num > math.MaxInt32)) {
+			return md.parseErr(errParseRange{i: num, size: rvk.String()})
+		}
+		rv.SetInt(num)
+	case rvk >= reflect.Uint && rvk <= reflect.Uint64:
+		unum := uint64(num)
+		if rvk == reflect.Uint8 && (num < 0 || unum > math.MaxUint8) ||
+			rvk == reflect.Uint16 && (num < 0 || unum > math.MaxUint16) ||
+			rvk == reflect.Uint32 && (num < 0 || unum > math.MaxUint32) {
+			return md.parseErr(errParseRange{i: num, size: rvk.String()})
+		}
+		rv.SetUint(unum)
+	default:
+		panic("unreachable")
+	}
+	return nil
 }
 
 func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error {
@@ -431,7 +486,7 @@ func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error {
 		rv.SetBool(b)
 		return nil
 	}
-	return badtype("boolean", data)
+	return md.badtype("boolean", data)
 }
 
 func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error {
@@ -439,10 +494,16 @@ func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error {
 	return nil
 }
 
-func (md *MetaData) unifyText(data interface{}, v TextUnmarshaler) error {
+func (md *MetaData) unifyText(data interface{}, v encoding.TextUnmarshaler) error {
 	var s string
 	switch sdata := data.(type) {
-	case TextMarshaler:
+	case Marshaler:
+		text, err := sdata.MarshalTOML()
+		if err != nil {
+			return err
+		}
+		s = string(text)
+	case encoding.TextMarshaler:
 		text, err := sdata.MarshalText()
 		if err != nil {
 			return err
@@ -459,7 +520,7 @@ func (md *MetaData) unifyText(data interface{}, v TextUnmarshaler) error {
 	case float64:
 		s = fmt.Sprintf("%f", sdata)
 	default:
-		return badtype("primitive (string-like)", data)
+		return md.badtype("primitive (string-like)", data)
 	}
 	if err := v.UnmarshalText([]byte(s)); err != nil {
 		return err
@@ -467,22 +528,54 @@ func (md *MetaData) unifyText(data interface{}, v TextUnmarshaler) error {
 	return nil
 }
 
+func (md *MetaData) badtype(dst string, data interface{}) error {
+	return md.e("incompatible types: TOML value has type %T; destination has type %s", data, dst)
+}
+
+func (md *MetaData) parseErr(err error) error {
+	k := md.context.String()
+	return ParseError{
+		LastKey:  k,
+		Position: md.keyInfo[k].pos,
+		Line:     md.keyInfo[k].pos.Line,
+		err:      err,
+		input:    string(md.data),
+	}
+}
+
+func (md *MetaData) e(format string, args ...interface{}) error {
+	f := "toml: "
+	if len(md.context) > 0 {
+		f = fmt.Sprintf("toml: (last key %q): ", md.context)
+		p := md.keyInfo[md.context.String()].pos
+		if p.Line > 0 {
+			f = fmt.Sprintf("toml: line %d (last key %q): ", p.Line, md.context)
+		}
+	}
+	return fmt.Errorf(f+format, args...)
+}
+
 // rvalue returns a reflect.Value of `v`. All pointers are resolved.
 func rvalue(v interface{}) reflect.Value {
 	return indirect(reflect.ValueOf(v))
 }
 
 // indirect returns the value pointed to by a pointer.
-// Pointers are followed until the value is not a pointer.
-// New values are allocated for each nil pointer.
 //
-// An exception to this rule is if the value satisfies an interface of
-// interest to us (like encoding.TextUnmarshaler).
+// Pointers are followed until the value is not a pointer. New values are
+// allocated for each nil pointer.
+//
+// An exception to this rule is if the value satisfies an interface of interest
+// to us (like encoding.TextUnmarshaler).
 func indirect(v reflect.Value) reflect.Value {
 	if v.Kind() != reflect.Ptr {
 		if v.CanSet() {
 			pv := v.Addr()
-			if _, ok := pv.Interface().(TextUnmarshaler); ok {
+			pvi := pv.Interface()
+			if _, ok := pvi.(encoding.TextUnmarshaler); ok {
+				return pv
+			}
+			if _, ok := pvi.(Unmarshaler); ok {
 				return pv
 			}
 		}
@@ -498,12 +591,12 @@ func isUnifiable(rv reflect.Value) bool {
 	if rv.CanSet() {
 		return true
 	}
-	if _, ok := rv.Interface().(TextUnmarshaler); ok {
+	rvi := rv.Interface()
+	if _, ok := rvi.(encoding.TextUnmarshaler); ok {
+		return true
+	}
+	if _, ok := rvi.(Unmarshaler); ok {
 		return true
 	}
 	return false
 }
-
-func badtype(expected string, data interface{}) error {
-	return e("cannot load TOML value of type %T into a Go %s", data, expected)
-}

+ 19 - 0
vendor/github.com/BurntSushi/toml/decode_go116.go

@@ -0,0 +1,19 @@
+//go:build go1.16
+// +build go1.16
+
+package toml
+
+import (
+	"io/fs"
+)
+
+// DecodeFS reads the contents of a file from [fs.FS] and decodes it with
+// [Decode].
+func DecodeFS(fsys fs.FS, path string, v interface{}) (MetaData, error) {
+	fp, err := fsys.Open(path)
+	if err != nil {
+		return MetaData{}, err
+	}
+	defer fp.Close()
+	return NewDecoder(fp).Decode(v)
+}

+ 0 - 121
vendor/github.com/BurntSushi/toml/decode_meta.go

@@ -1,121 +0,0 @@
-package toml
-
-import "strings"
-
-// MetaData allows access to meta information about TOML data that may not
-// be inferrable via reflection. In particular, whether a key has been defined
-// and the TOML type of a key.
-type MetaData struct {
-	mapping map[string]interface{}
-	types   map[string]tomlType
-	keys    []Key
-	decoded map[string]bool
-	context Key // Used only during decoding.
-}
-
-// IsDefined returns true if the key given exists in the TOML data. The key
-// should be specified hierarchially. e.g.,
-//
-//	// access the TOML key 'a.b.c'
-//	IsDefined("a", "b", "c")
-//
-// IsDefined will return false if an empty key given. Keys are case sensitive.
-func (md *MetaData) IsDefined(key ...string) bool {
-	if len(key) == 0 {
-		return false
-	}
-
-	var hash map[string]interface{}
-	var ok bool
-	var hashOrVal interface{} = md.mapping
-	for _, k := range key {
-		if hash, ok = hashOrVal.(map[string]interface{}); !ok {
-			return false
-		}
-		if hashOrVal, ok = hash[k]; !ok {
-			return false
-		}
-	}
-	return true
-}
-
-// Type returns a string representation of the type of the key specified.
-//
-// Type will return the empty string if given an empty key or a key that
-// does not exist. Keys are case sensitive.
-func (md *MetaData) Type(key ...string) string {
-	fullkey := strings.Join(key, ".")
-	if typ, ok := md.types[fullkey]; ok {
-		return typ.typeString()
-	}
-	return ""
-}
-
-// Key is the type of any TOML key, including key groups. Use (MetaData).Keys
-// to get values of this type.
-type Key []string
-
-func (k Key) String() string {
-	return strings.Join(k, ".")
-}
-
-func (k Key) maybeQuotedAll() string {
-	var ss []string
-	for i := range k {
-		ss = append(ss, k.maybeQuoted(i))
-	}
-	return strings.Join(ss, ".")
-}
-
-func (k Key) maybeQuoted(i int) string {
-	quote := false
-	for _, c := range k[i] {
-		if !isBareKeyChar(c) {
-			quote = true
-			break
-		}
-	}
-	if quote {
-		return "\"" + strings.Replace(k[i], "\"", "\\\"", -1) + "\""
-	}
-	return k[i]
-}
-
-func (k Key) add(piece string) Key {
-	newKey := make(Key, len(k)+1)
-	copy(newKey, k)
-	newKey[len(k)] = piece
-	return newKey
-}
-
-// Keys returns a slice of every key in the TOML data, including key groups.
-// Each key is itself a slice, where the first element is the top of the
-// hierarchy and the last is the most specific.
-//
-// The list will have the same order as the keys appeared in the TOML data.
-//
-// All keys returned are non-empty.
-func (md *MetaData) Keys() []Key {
-	return md.keys
-}
-
-// Undecoded returns all keys that have not been decoded in the order in which
-// they appear in the original TOML document.
-//
-// This includes keys that haven't been decoded because of a Primitive value.
-// Once the Primitive value is decoded, the keys will be considered decoded.
-//
-// Also note that decoding into an empty interface will result in no decoding,
-// and so no keys will be considered decoded.
-//
-// In this sense, the Undecoded keys correspond to keys in the TOML document
-// that do not have a concrete type in your representation.
-func (md *MetaData) Undecoded() []Key {
-	undecoded := make([]Key, 0, len(md.keys))
-	for _, key := range md.keys {
-		if !md.decoded[key.String()] {
-			undecoded = append(undecoded, key)
-		}
-	}
-	return undecoded
-}

+ 29 - 0
vendor/github.com/BurntSushi/toml/deprecated.go

@@ -0,0 +1,29 @@
+package toml
+
+import (
+	"encoding"
+	"io"
+)
+
+// TextMarshaler is an alias for encoding.TextMarshaler.
+//
+// Deprecated: use encoding.TextMarshaler
+type TextMarshaler encoding.TextMarshaler
+
+// TextUnmarshaler is an alias for encoding.TextUnmarshaler.
+//
+// Deprecated: use encoding.TextUnmarshaler
+type TextUnmarshaler encoding.TextUnmarshaler
+
+// PrimitiveDecode is an alias for MetaData.PrimitiveDecode().
+//
+// Deprecated: use MetaData.PrimitiveDecode.
+func PrimitiveDecode(primValue Primitive, v interface{}) error {
+	md := MetaData{decoded: make(map[string]struct{})}
+	return md.unify(primValue.undecoded, rvalue(v))
+}
+
+// DecodeReader is an alias for NewDecoder(r).Decode(v).
+//
+// Deprecated: use NewDecoder(reader).Decode(&value).
+func DecodeReader(r io.Reader, v interface{}) (MetaData, error) { return NewDecoder(r).Decode(v) }

+ 10 - 26
vendor/github.com/BurntSushi/toml/doc.go

@@ -1,27 +1,11 @@
-/*
-Package toml provides facilities for decoding and encoding TOML configuration
-files via reflection. There is also support for delaying decoding with
-the Primitive type, and querying the set of keys in a TOML document with the
-MetaData type.
-
-The specification implemented: https://github.com/toml-lang/toml
-
-The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify
-whether a file is a valid TOML document. It can also be used to print the
-type of each key in a TOML document.
-
-Testing
-
-There are two important types of tests used for this package. The first is
-contained inside '*_test.go' files and uses the standard Go unit testing
-framework. These tests are primarily devoted to holistically testing the
-decoder and encoder.
-
-The second type of testing is used to verify the implementation's adherence
-to the TOML specification. These tests have been factored into their own
-project: https://github.com/BurntSushi/toml-test
-
-The reason the tests are in a separate project is so that they can be used by
-any implementation of TOML. Namely, it is language agnostic.
-*/
+// Package toml implements decoding and encoding of TOML files.
+//
+// This package supports TOML v1.0.0, as specified at https://toml.io
+//
+// There is also support for delaying decoding with the Primitive type, and
+// querying the set of keys in a TOML document with the MetaData type.
+//
+// The github.com/BurntSushi/toml/cmd/tomlv package implements a TOML validator,
+// and can be used to verify if TOML document is valid. It can also be used to
+// print the type of each key.
 package toml

+ 406 - 215
vendor/github.com/BurntSushi/toml/encode.go

@@ -2,57 +2,127 @@ package toml
 
 import (
 	"bufio"
+	"encoding"
+	"encoding/json"
 	"errors"
 	"fmt"
 	"io"
+	"math"
 	"reflect"
 	"sort"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/BurntSushi/toml/internal"
 )
 
 type tomlEncodeError struct{ error }
 
 var (
-	errArrayMixedElementTypes = errors.New(
-		"toml: cannot encode array with mixed element types")
-	errArrayNilElement = errors.New(
-		"toml: cannot encode array with nil element")
-	errNonString = errors.New(
-		"toml: cannot encode a map with non-string key type")
-	errAnonNonStruct = errors.New(
-		"toml: cannot encode an anonymous field that is not a struct")
-	errArrayNoTable = errors.New(
-		"toml: TOML array element cannot contain a table")
-	errNoKey = errors.New(
-		"toml: top-level values must be Go maps or structs")
-	errAnything = errors.New("") // used in testing
+	errArrayNilElement = errors.New("toml: cannot encode array with nil element")
+	errNonString       = errors.New("toml: cannot encode a map with non-string key type")
+	errNoKey           = errors.New("toml: top-level values must be Go maps or structs")
+	errAnything        = errors.New("") // used in testing
 )
 
-var quotedReplacer = strings.NewReplacer(
-	"\t", "\\t",
-	"\n", "\\n",
-	"\r", "\\r",
+var dblQuotedReplacer = strings.NewReplacer(
 	"\"", "\\\"",
 	"\\", "\\\\",
+	"\x00", `\u0000`,
+	"\x01", `\u0001`,
+	"\x02", `\u0002`,
+	"\x03", `\u0003`,
+	"\x04", `\u0004`,
+	"\x05", `\u0005`,
+	"\x06", `\u0006`,
+	"\x07", `\u0007`,
+	"\b", `\b`,
+	"\t", `\t`,
+	"\n", `\n`,
+	"\x0b", `\u000b`,
+	"\f", `\f`,
+	"\r", `\r`,
+	"\x0e", `\u000e`,
+	"\x0f", `\u000f`,
+	"\x10", `\u0010`,
+	"\x11", `\u0011`,
+	"\x12", `\u0012`,
+	"\x13", `\u0013`,
+	"\x14", `\u0014`,
+	"\x15", `\u0015`,
+	"\x16", `\u0016`,
+	"\x17", `\u0017`,
+	"\x18", `\u0018`,
+	"\x19", `\u0019`,
+	"\x1a", `\u001a`,
+	"\x1b", `\u001b`,
+	"\x1c", `\u001c`,
+	"\x1d", `\u001d`,
+	"\x1e", `\u001e`,
+	"\x1f", `\u001f`,
+	"\x7f", `\u007f`,
 )
 
-// Encoder controls the encoding of Go values to a TOML document to some
-// io.Writer.
+var (
+	marshalToml = reflect.TypeOf((*Marshaler)(nil)).Elem()
+	marshalText = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
+	timeType    = reflect.TypeOf((*time.Time)(nil)).Elem()
+)
+
+// Marshaler is the interface implemented by types that can marshal themselves
+// into valid TOML.
+type Marshaler interface {
+	MarshalTOML() ([]byte, error)
+}
+
+// Encoder encodes a Go to a TOML document.
+//
+// The mapping between Go values and TOML values should be precisely the same as
+// for [Decode].
+//
+// time.Time is encoded as a RFC 3339 string, and time.Duration as its string
+// representation.
+//
+// The [Marshaler] and [encoding.TextMarshaler] interfaces are supported to
+// encoding the value as custom TOML.
 //
-// The indentation level can be controlled with the Indent field.
+// If you want to write arbitrary binary data then you will need to use
+// something like base64 since TOML does not have any binary types.
+//
+// When encoding TOML hashes (Go maps or structs), keys without any sub-hashes
+// are encoded first.
+//
+// Go maps will be sorted alphabetically by key for deterministic output.
+//
+// The toml struct tag can be used to provide the key name; if omitted the
+// struct field name will be used. If the "omitempty" option is present the
+// following value will be skipped:
+//
+//   - arrays, slices, maps, and string with len of 0
+//   - struct with all zero values
+//   - bool false
+//
+// If omitzero is given all int and float types with a value of 0 will be
+// skipped.
+//
+// Encoding Go values without a corresponding TOML representation will return an
+// error. Examples of this includes maps with non-string keys, slices with nil
+// elements, embedded non-struct types, and nested slices containing maps or
+// structs. (e.g. [][]map[string]string is not allowed but []map[string]string
+// is okay, as is []map[string][]string).
+//
+// NOTE: only exported keys are encoded due to the use of reflection. Unexported
+// keys are silently discarded.
 type Encoder struct {
-	// A single indentation level. By default it is two spaces.
+	// String to use for a single indentation level; default is two spaces.
 	Indent string
 
-	// hasWritten is whether we have written any output to w yet.
-	hasWritten bool
 	w          *bufio.Writer
+	hasWritten bool // written any output to w yet?
 }
 
-// NewEncoder returns a TOML encoder that encodes Go values to the io.Writer
-// given. By default, a single indentation level is 2 spaces.
+// NewEncoder create a new Encoder.
 func NewEncoder(w io.Writer) *Encoder {
 	return &Encoder{
 		w:      bufio.NewWriter(w),
@@ -60,32 +130,14 @@ func NewEncoder(w io.Writer) *Encoder {
 	}
 }
 
-// Encode writes a TOML representation of the Go value to the underlying
-// io.Writer. If the value given cannot be encoded to a valid TOML document,
-// then an error is returned.
-//
-// The mapping between Go values and TOML values should be precisely the same
-// as for the Decode* functions. Similarly, the TextMarshaler interface is
-// supported by encoding the resulting bytes as strings. (If you want to write
-// arbitrary binary data then you will need to use something like base64 since
-// TOML does not have any binary types.)
-//
-// When encoding TOML hashes (i.e., Go maps or structs), keys without any
-// sub-hashes are encoded first.
+// Encode writes a TOML representation of the Go value to the [Encoder]'s writer.
 //
-// If a Go map is encoded, then its keys are sorted alphabetically for
-// deterministic output. More control over this behavior may be provided if
-// there is demand for it.
-//
-// Encoding Go values without a corresponding TOML representation---like map
-// types with non-string keys---will cause an error to be returned. Similarly
-// for mixed arrays/slices, arrays/slices with nil elements, embedded
-// non-struct types and nested slices containing maps or structs.
-// (e.g., [][]map[string]string is not allowed but []map[string]string is OK
-// and so is []map[string][]string.)
+// An error is returned if the value given cannot be encoded to a valid TOML
+// document.
 func (enc *Encoder) Encode(v interface{}) error {
 	rv := eindirect(reflect.ValueOf(v))
-	if err := enc.safeEncode(Key([]string{}), rv); err != nil {
+	err := enc.safeEncode(Key([]string{}), rv)
+	if err != nil {
 		return err
 	}
 	return enc.w.Flush()
@@ -106,13 +158,15 @@ func (enc *Encoder) safeEncode(key Key, rv reflect.Value) (err error) {
 }
 
 func (enc *Encoder) encode(key Key, rv reflect.Value) {
-	// Special case. Time needs to be in ISO8601 format.
-	// Special case. If we can marshal the type to text, then we used that.
-	// Basically, this prevents the encoder for handling these types as
-	// generic structs (or whatever the underlying type of a TextMarshaler is).
-	switch rv.Interface().(type) {
-	case time.Time, TextMarshaler:
-		enc.keyEqElement(key, rv)
+	// If we can marshal the type to text, then we use that. This prevents the
+	// encoder for handling these types as generic structs (or whatever the
+	// underlying type of a TextMarshaler is).
+	switch {
+	case isMarshaler(rv):
+		enc.writeKeyValue(key, rv, false)
+		return
+	case rv.Type() == primitiveType: // TODO: #76 would make this superfluous after implemented.
+		enc.encode(key, reflect.ValueOf(rv.Interface().(Primitive).undecoded))
 		return
 	}
 
@@ -123,12 +177,12 @@ func (enc *Encoder) encode(key Key, rv reflect.Value) {
 		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
 		reflect.Uint64,
 		reflect.Float32, reflect.Float64, reflect.String, reflect.Bool:
-		enc.keyEqElement(key, rv)
+		enc.writeKeyValue(key, rv, false)
 	case reflect.Array, reflect.Slice:
 		if typeEqual(tomlArrayHash, tomlTypeOfGo(rv)) {
 			enc.eArrayOfTables(key, rv)
 		} else {
-			enc.keyEqElement(key, rv)
+			enc.writeKeyValue(key, rv, false)
 		}
 	case reflect.Interface:
 		if rv.IsNil() {
@@ -148,55 +202,114 @@ func (enc *Encoder) encode(key Key, rv reflect.Value) {
 	case reflect.Struct:
 		enc.eTable(key, rv)
 	default:
-		panic(e("unsupported type for key '%s': %s", key, k))
+		encPanic(fmt.Errorf("unsupported type for key '%s': %s", key, k))
 	}
 }
 
-// eElement encodes any value that can be an array element (primitives and
-// arrays).
+// eElement encodes any value that can be an array element.
 func (enc *Encoder) eElement(rv reflect.Value) {
 	switch v := rv.Interface().(type) {
-	case time.Time:
-		// Special case time.Time as a primitive. Has to come before
-		// TextMarshaler below because time.Time implements
-		// encoding.TextMarshaler, but we need to always use UTC.
-		enc.wf(v.UTC().Format("2006-01-02T15:04:05Z"))
+	case time.Time: // Using TextMarshaler adds extra quotes, which we don't want.
+		format := time.RFC3339Nano
+		switch v.Location() {
+		case internal.LocalDatetime:
+			format = "2006-01-02T15:04:05.999999999"
+		case internal.LocalDate:
+			format = "2006-01-02"
+		case internal.LocalTime:
+			format = "15:04:05.999999999"
+		}
+		switch v.Location() {
+		default:
+			enc.wf(v.Format(format))
+		case internal.LocalDatetime, internal.LocalDate, internal.LocalTime:
+			enc.wf(v.In(time.UTC).Format(format))
+		}
 		return
-	case TextMarshaler:
-		// Special case. Use text marshaler if it's available for this value.
-		if s, err := v.MarshalText(); err != nil {
+	case Marshaler:
+		s, err := v.MarshalTOML()
+		if err != nil {
 			encPanic(err)
-		} else {
-			enc.writeQuoted(string(s))
 		}
+		if s == nil {
+			encPanic(errors.New("MarshalTOML returned nil and no error"))
+		}
+		enc.w.Write(s)
+		return
+	case encoding.TextMarshaler:
+		s, err := v.MarshalText()
+		if err != nil {
+			encPanic(err)
+		}
+		if s == nil {
+			encPanic(errors.New("MarshalText returned nil and no error"))
+		}
+		enc.writeQuoted(string(s))
+		return
+	case time.Duration:
+		enc.writeQuoted(v.String())
 		return
+	case json.Number:
+		n, _ := rv.Interface().(json.Number)
+
+		if n == "" { /// Useful zero value.
+			enc.w.WriteByte('0')
+			return
+		} else if v, err := n.Int64(); err == nil {
+			enc.eElement(reflect.ValueOf(v))
+			return
+		} else if v, err := n.Float64(); err == nil {
+			enc.eElement(reflect.ValueOf(v))
+			return
+		}
+		encPanic(fmt.Errorf("unable to convert %q to int64 or float64", n))
 	}
+
 	switch rv.Kind() {
+	case reflect.Ptr:
+		enc.eElement(rv.Elem())
+		return
+	case reflect.String:
+		enc.writeQuoted(rv.String())
 	case reflect.Bool:
 		enc.wf(strconv.FormatBool(rv.Bool()))
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
-		reflect.Int64:
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 		enc.wf(strconv.FormatInt(rv.Int(), 10))
-	case reflect.Uint, reflect.Uint8, reflect.Uint16,
-		reflect.Uint32, reflect.Uint64:
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 		enc.wf(strconv.FormatUint(rv.Uint(), 10))
 	case reflect.Float32:
-		enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 32)))
+		f := rv.Float()
+		if math.IsNaN(f) {
+			enc.wf("nan")
+		} else if math.IsInf(f, 0) {
+			enc.wf("%cinf", map[bool]byte{true: '-', false: '+'}[math.Signbit(f)])
+		} else {
+			enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 32)))
+		}
 	case reflect.Float64:
-		enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 64)))
+		f := rv.Float()
+		if math.IsNaN(f) {
+			enc.wf("nan")
+		} else if math.IsInf(f, 0) {
+			enc.wf("%cinf", map[bool]byte{true: '-', false: '+'}[math.Signbit(f)])
+		} else {
+			enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 64)))
+		}
 	case reflect.Array, reflect.Slice:
 		enc.eArrayOrSliceElement(rv)
+	case reflect.Struct:
+		enc.eStruct(nil, rv, true)
+	case reflect.Map:
+		enc.eMap(nil, rv, true)
 	case reflect.Interface:
 		enc.eElement(rv.Elem())
-	case reflect.String:
-		enc.writeQuoted(rv.String())
 	default:
-		panic(e("unexpected primitive type: %s", rv.Kind()))
+		encPanic(fmt.Errorf("unexpected type: %T", rv.Interface()))
 	}
 }
 
-// By the TOML spec, all floats must have a decimal with at least one
-// number on either side.
+// By the TOML spec, all floats must have a decimal with at least one number on
+// either side.
 func floatAddDecimal(fstr string) string {
 	if !strings.Contains(fstr, ".") {
 		return fstr + ".0"
@@ -205,14 +318,14 @@ func floatAddDecimal(fstr string) string {
 }
 
 func (enc *Encoder) writeQuoted(s string) {
-	enc.wf("\"%s\"", quotedReplacer.Replace(s))
+	enc.wf("\"%s\"", dblQuotedReplacer.Replace(s))
 }
 
 func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) {
 	length := rv.Len()
 	enc.wf("[")
 	for i := 0; i < length; i++ {
-		elem := rv.Index(i)
+		elem := eindirect(rv.Index(i))
 		enc.eElement(elem)
 		if i != length-1 {
 			enc.wf(", ")
@@ -226,44 +339,43 @@ func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
 		encPanic(errNoKey)
 	}
 	for i := 0; i < rv.Len(); i++ {
-		trv := rv.Index(i)
+		trv := eindirect(rv.Index(i))
 		if isNil(trv) {
 			continue
 		}
-		panicIfInvalidKey(key)
 		enc.newline()
-		enc.wf("%s[[%s]]", enc.indentStr(key), key.maybeQuotedAll())
+		enc.wf("%s[[%s]]", enc.indentStr(key), key)
 		enc.newline()
-		enc.eMapOrStruct(key, trv)
+		enc.eMapOrStruct(key, trv, false)
 	}
 }
 
 func (enc *Encoder) eTable(key Key, rv reflect.Value) {
-	panicIfInvalidKey(key)
 	if len(key) == 1 {
 		// Output an extra newline between top-level tables.
 		// (The newline isn't written if nothing else has been written though.)
 		enc.newline()
 	}
 	if len(key) > 0 {
-		enc.wf("%s[%s]", enc.indentStr(key), key.maybeQuotedAll())
+		enc.wf("%s[%s]", enc.indentStr(key), key)
 		enc.newline()
 	}
-	enc.eMapOrStruct(key, rv)
+	enc.eMapOrStruct(key, rv, false)
 }
 
-func (enc *Encoder) eMapOrStruct(key Key, rv reflect.Value) {
-	switch rv := eindirect(rv); rv.Kind() {
+func (enc *Encoder) eMapOrStruct(key Key, rv reflect.Value, inline bool) {
+	switch rv.Kind() {
 	case reflect.Map:
-		enc.eMap(key, rv)
+		enc.eMap(key, rv, inline)
 	case reflect.Struct:
-		enc.eStruct(key, rv)
+		enc.eStruct(key, rv, inline)
 	default:
+		// Should never happen?
 		panic("eTable: unhandled reflect.Value Kind: " + rv.Kind().String())
 	}
 }
 
-func (enc *Encoder) eMap(key Key, rv reflect.Value) {
+func (enc *Encoder) eMap(key Key, rv reflect.Value, inline bool) {
 	rt := rv.Type()
 	if rt.Key().Kind() != reflect.String {
 		encPanic(errNonString)
@@ -274,68 +386,100 @@ func (enc *Encoder) eMap(key Key, rv reflect.Value) {
 	var mapKeysDirect, mapKeysSub []string
 	for _, mapKey := range rv.MapKeys() {
 		k := mapKey.String()
-		if typeIsHash(tomlTypeOfGo(rv.MapIndex(mapKey))) {
+		if typeIsTable(tomlTypeOfGo(eindirect(rv.MapIndex(mapKey)))) {
 			mapKeysSub = append(mapKeysSub, k)
 		} else {
 			mapKeysDirect = append(mapKeysDirect, k)
 		}
 	}
 
-	var writeMapKeys = func(mapKeys []string) {
+	var writeMapKeys = func(mapKeys []string, trailC bool) {
 		sort.Strings(mapKeys)
-		for _, mapKey := range mapKeys {
-			mrv := rv.MapIndex(reflect.ValueOf(mapKey))
-			if isNil(mrv) {
-				// Don't write anything for nil fields.
+		for i, mapKey := range mapKeys {
+			val := eindirect(rv.MapIndex(reflect.ValueOf(mapKey)))
+			if isNil(val) {
 				continue
 			}
-			enc.encode(key.add(mapKey), mrv)
+
+			if inline {
+				enc.writeKeyValue(Key{mapKey}, val, true)
+				if trailC || i != len(mapKeys)-1 {
+					enc.wf(", ")
+				}
+			} else {
+				enc.encode(key.add(mapKey), val)
+			}
 		}
 	}
-	writeMapKeys(mapKeysDirect)
-	writeMapKeys(mapKeysSub)
+
+	if inline {
+		enc.wf("{")
+	}
+	writeMapKeys(mapKeysDirect, len(mapKeysSub) > 0)
+	writeMapKeys(mapKeysSub, false)
+	if inline {
+		enc.wf("}")
+	}
 }
 
-func (enc *Encoder) eStruct(key Key, rv reflect.Value) {
+const is32Bit = (32 << (^uint(0) >> 63)) == 32
+
+func pointerTo(t reflect.Type) reflect.Type {
+	if t.Kind() == reflect.Ptr {
+		return pointerTo(t.Elem())
+	}
+	return t
+}
+
+func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) {
 	// Write keys for fields directly under this key first, because if we write
-	// a field that creates a new table, then all keys under it will be in that
+	// a field that creates a new table then all keys under it will be in that
 	// table (not the one we're writing here).
-	rt := rv.Type()
-	var fieldsDirect, fieldsSub [][]int
-	var addFields func(rt reflect.Type, rv reflect.Value, start []int)
+	//
+	// Fields is a [][]int: for fieldsDirect this always has one entry (the
+	// struct index). For fieldsSub it contains two entries: the parent field
+	// index from tv, and the field indexes for the fields of the sub.
+	var (
+		rt                      = rv.Type()
+		fieldsDirect, fieldsSub [][]int
+		addFields               func(rt reflect.Type, rv reflect.Value, start []int)
+	)
 	addFields = func(rt reflect.Type, rv reflect.Value, start []int) {
 		for i := 0; i < rt.NumField(); i++ {
 			f := rt.Field(i)
-			// skip unexported fields
-			if f.PkgPath != "" && !f.Anonymous {
+			isEmbed := f.Anonymous && pointerTo(f.Type).Kind() == reflect.Struct
+			if f.PkgPath != "" && !isEmbed { /// Skip unexported fields.
+				continue
+			}
+			opts := getOptions(f.Tag)
+			if opts.skip {
 				continue
 			}
-			frv := rv.Field(i)
-			if f.Anonymous {
-				t := f.Type
-				switch t.Kind() {
-				case reflect.Struct:
-					// Treat anonymous struct fields with
-					// tag names as though they are not
-					// anonymous, like encoding/json does.
-					if getOptions(f.Tag).name == "" {
-						addFields(t, frv, f.Index)
-						continue
-					}
-				case reflect.Ptr:
-					if t.Elem().Kind() == reflect.Struct &&
-						getOptions(f.Tag).name == "" {
-						if !frv.IsNil() {
-							addFields(t.Elem(), frv.Elem(), f.Index)
-						}
-						continue
-					}
-					// Fall through to the normal field encoding logic below
-					// for non-struct anonymous fields.
+
+			frv := eindirect(rv.Field(i))
+
+			if is32Bit {
+				// Copy so it works correct on 32bit archs; not clear why this
+				// is needed. See #314, and https://www.reddit.com/r/golang/comments/pnx8v4
+				// This also works fine on 64bit, but 32bit archs are somewhat
+				// rare and this is a wee bit faster.
+				copyStart := make([]int, len(start))
+				copy(copyStart, start)
+				start = copyStart
+			}
+
+			// Treat anonymous struct fields with tag names as though they are
+			// not anonymous, like encoding/json does.
+			//
+			// Non-struct anonymous fields use the normal encoding logic.
+			if isEmbed {
+				if getOptions(f.Tag).name == "" && frv.Kind() == reflect.Struct {
+					addFields(frv.Type(), frv, append(start, f.Index...))
+					continue
 				}
 			}
 
-			if typeIsHash(tomlTypeOfGo(frv)) {
+			if typeIsTable(tomlTypeOfGo(frv)) {
 				fieldsSub = append(fieldsSub, append(start, f.Index...))
 			} else {
 				fieldsDirect = append(fieldsDirect, append(start, f.Index...))
@@ -344,48 +488,81 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value) {
 	}
 	addFields(rt, rv, nil)
 
-	var writeFields = func(fields [][]int) {
+	writeFields := func(fields [][]int) {
 		for _, fieldIndex := range fields {
-			sft := rt.FieldByIndex(fieldIndex)
-			sf := rv.FieldByIndex(fieldIndex)
-			if isNil(sf) {
-				// Don't write anything for nil fields.
+			fieldType := rt.FieldByIndex(fieldIndex)
+			fieldVal := rv.FieldByIndex(fieldIndex)
+
+			opts := getOptions(fieldType.Tag)
+			if opts.skip {
+				continue
+			}
+			if opts.omitempty && isEmpty(fieldVal) {
 				continue
 			}
 
-			opts := getOptions(sft.Tag)
-			if opts.skip {
+			fieldVal = eindirect(fieldVal)
+
+			if isNil(fieldVal) { /// Don't write anything for nil fields.
 				continue
 			}
-			keyName := sft.Name
+
+			keyName := fieldType.Name
 			if opts.name != "" {
 				keyName = opts.name
 			}
-			if opts.omitempty && isEmpty(sf) {
-				continue
-			}
-			if opts.omitzero && isZero(sf) {
+
+			if opts.omitzero && isZero(fieldVal) {
 				continue
 			}
 
-			enc.encode(key.add(keyName), sf)
+			if inline {
+				enc.writeKeyValue(Key{keyName}, fieldVal, true)
+				if fieldIndex[0] != len(fields)-1 {
+					enc.wf(", ")
+				}
+			} else {
+				enc.encode(key.add(keyName), fieldVal)
+			}
 		}
 	}
+
+	if inline {
+		enc.wf("{")
+	}
 	writeFields(fieldsDirect)
 	writeFields(fieldsSub)
+	if inline {
+		enc.wf("}")
+	}
 }
 
-// tomlTypeName returns the TOML type name of the Go value's type. It is
-// used to determine whether the types of array elements are mixed (which is
-// forbidden). If the Go value is nil, then it is illegal for it to be an array
-// element, and valueIsNil is returned as true.
-
-// Returns the TOML type of a Go value. The type may be `nil`, which means
-// no concrete TOML type could be found.
+// tomlTypeOfGo returns the TOML type name of the Go value's type.
+//
+// It is used to determine whether the types of array elements are mixed (which
+// is forbidden). If the Go value is nil, then it is illegal for it to be an
+// array element, and valueIsNil is returned as true.
+//
+// The type may be `nil`, which means no concrete TOML type could be found.
 func tomlTypeOfGo(rv reflect.Value) tomlType {
 	if isNil(rv) || !rv.IsValid() {
 		return nil
 	}
+
+	if rv.Kind() == reflect.Struct {
+		if rv.Type() == timeType {
+			return tomlDatetime
+		}
+		if isMarshaler(rv) {
+			return tomlString
+		}
+		return tomlHash
+	}
+
+	if isMarshaler(rv) {
+		return tomlString
+	}
+
 	switch rv.Kind() {
 	case reflect.Bool:
 		return tomlBool
@@ -397,7 +574,7 @@ func tomlTypeOfGo(rv reflect.Value) tomlType {
 	case reflect.Float32, reflect.Float64:
 		return tomlFloat
 	case reflect.Array, reflect.Slice:
-		if typeEqual(tomlHash, tomlArrayType(rv)) {
+		if isTableArray(rv) {
 			return tomlArrayHash
 		}
 		return tomlArray
@@ -407,54 +584,35 @@ func tomlTypeOfGo(rv reflect.Value) tomlType {
 		return tomlString
 	case reflect.Map:
 		return tomlHash
-	case reflect.Struct:
-		switch rv.Interface().(type) {
-		case time.Time:
-			return tomlDatetime
-		case TextMarshaler:
-			return tomlString
-		default:
-			return tomlHash
-		}
 	default:
-		panic("unexpected reflect.Kind: " + rv.Kind().String())
+		encPanic(errors.New("unsupported type: " + rv.Kind().String()))
+		panic("unreachable")
 	}
 }
 
-// tomlArrayType returns the element type of a TOML array. The type returned
-// may be nil if it cannot be determined (e.g., a nil slice or a zero length
-// slize). This function may also panic if it finds a type that cannot be
-// expressed in TOML (such as nil elements, heterogeneous arrays or directly
-// nested arrays of tables).
-func tomlArrayType(rv reflect.Value) tomlType {
-	if isNil(rv) || !rv.IsValid() || rv.Len() == 0 {
-		return nil
-	}
-	firstType := tomlTypeOfGo(rv.Index(0))
-	if firstType == nil {
-		encPanic(errArrayNilElement)
+func isMarshaler(rv reflect.Value) bool {
+	return rv.Type().Implements(marshalText) || rv.Type().Implements(marshalToml)
+}
+
+// isTableArray reports if all entries in the array or slice are a table.
+func isTableArray(arr reflect.Value) bool {
+	if isNil(arr) || !arr.IsValid() || arr.Len() == 0 {
+		return false
 	}
 
-	rvlen := rv.Len()
-	for i := 1; i < rvlen; i++ {
-		elem := rv.Index(i)
-		switch elemType := tomlTypeOfGo(elem); {
-		case elemType == nil:
+	ret := true
+	for i := 0; i < arr.Len(); i++ {
+		tt := tomlTypeOfGo(eindirect(arr.Index(i)))
+		// Don't allow nil.
+		if tt == nil {
 			encPanic(errArrayNilElement)
-		case !typeEqual(firstType, elemType):
-			encPanic(errArrayMixedElementTypes)
 		}
-	}
-	// If we have a nested array, then we must make sure that the nested
-	// array contains ONLY primitives.
-	// This checks arbitrarily nested arrays.
-	if typeEqual(firstType, tomlArray) || typeEqual(firstType, tomlArrayHash) {
-		nest := tomlArrayType(eindirect(rv.Index(0)))
-		if typeEqual(nest, tomlHash) || typeEqual(nest, tomlArrayHash) {
-			encPanic(errArrayNoTable)
+
+		if ret && !typeEqual(tomlHash, tt) {
+			ret = false
 		}
 	}
-	return firstType
+	return ret
 }
 
 type tagOptions struct {
@@ -499,8 +657,26 @@ func isEmpty(rv reflect.Value) bool {
 	switch rv.Kind() {
 	case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
 		return rv.Len() == 0
+	case reflect.Struct:
+		if rv.Type().Comparable() {
+			return reflect.Zero(rv.Type()).Interface() == rv.Interface()
+		}
+		// Need to also check if all the fields are empty, otherwise something
+		// like this with uncomparable types will always return true:
+		//
+		//   type a struct{ field b }
+		//   type b struct{ s []string }
+		//   s := a{field: b{s: []string{"AAA"}}}
+		for i := 0; i < rv.NumField(); i++ {
+			if !isEmpty(rv.Field(i)) {
+				return false
+			}
+		}
+		return true
 	case reflect.Bool:
 		return !rv.Bool()
+	case reflect.Ptr:
+		return rv.IsNil()
 	}
 	return false
 }
@@ -511,18 +687,34 @@ func (enc *Encoder) newline() {
 	}
 }
 
-func (enc *Encoder) keyEqElement(key Key, val reflect.Value) {
+// Write a key/value pair:
+//
+//	key = <any value>
+//
+// This is also used for "k = v" in inline tables; so something like this will
+// be written in three calls:
+//
+//	┌───────────────────┐
+//	│      ┌───┐  ┌────┐│
+//	v      v   v  v    vv
+//	key = {k = 1, k2 = 2}
+func (enc *Encoder) writeKeyValue(key Key, val reflect.Value, inline bool) {
+	/// Marshaler used on top-level document; call eElement() to just call
+	/// Marshal{TOML,Text}.
 	if len(key) == 0 {
-		encPanic(errNoKey)
+		enc.eElement(val)
+		return
 	}
-	panicIfInvalidKey(key)
 	enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1))
 	enc.eElement(val)
-	enc.newline()
+	if !inline {
+		enc.newline()
+	}
 }
 
 func (enc *Encoder) wf(format string, v ...interface{}) {
-	if _, err := fmt.Fprintf(enc.w, format, v...); err != nil {
+	_, err := fmt.Fprintf(enc.w, format, v...)
+	if err != nil {
 		encPanic(err)
 	}
 	enc.hasWritten = true
@@ -536,13 +728,25 @@ func encPanic(err error) {
 	panic(tomlEncodeError{err})
 }
 
+// Resolve any level of pointers to the actual value (e.g. **string → string).
 func eindirect(v reflect.Value) reflect.Value {
-	switch v.Kind() {
-	case reflect.Ptr, reflect.Interface:
-		return eindirect(v.Elem())
-	default:
+	if v.Kind() != reflect.Ptr && v.Kind() != reflect.Interface {
+		if isMarshaler(v) {
+			return v
+		}
+		if v.CanAddr() { /// Special case for marshalers; see #358.
+			if pv := v.Addr(); isMarshaler(pv) {
+				return pv
+			}
+		}
 		return v
 	}
+
+	if v.IsNil() {
+		return v
+	}
+
+	return eindirect(v.Elem())
 }
 
 func isNil(rv reflect.Value) bool {
@@ -553,16 +757,3 @@ func isNil(rv reflect.Value) bool {
 		return false
 	}
 }
-
-func panicIfInvalidKey(key Key) {
-	for _, k := range key {
-		if len(k) == 0 {
-			encPanic(e("Key '%s' is not a valid table name. Key names "+
-				"cannot be empty.", key.maybeQuotedAll()))
-		}
-	}
-}
-
-func isValidKeyName(s string) bool {
-	return len(s) != 0
-}

+ 0 - 19
vendor/github.com/BurntSushi/toml/encoding_types.go

@@ -1,19 +0,0 @@
-// +build go1.2
-
-package toml
-
-// In order to support Go 1.1, we define our own TextMarshaler and
-// TextUnmarshaler types. For Go 1.2+, we just alias them with the
-// standard library interfaces.
-
-import (
-	"encoding"
-)
-
-// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here
-// so that Go 1.1 can be supported.
-type TextMarshaler encoding.TextMarshaler
-
-// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined
-// here so that Go 1.1 can be supported.
-type TextUnmarshaler encoding.TextUnmarshaler

+ 0 - 18
vendor/github.com/BurntSushi/toml/encoding_types_1.1.go

@@ -1,18 +0,0 @@
-// +build !go1.2
-
-package toml
-
-// These interfaces were introduced in Go 1.2, so we add them manually when
-// compiling for Go 1.1.
-
-// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here
-// so that Go 1.1 can be supported.
-type TextMarshaler interface {
-	MarshalText() (text []byte, err error)
-}
-
-// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined
-// here so that Go 1.1 can be supported.
-type TextUnmarshaler interface {
-	UnmarshalText(text []byte) error
-}

+ 279 - 0
vendor/github.com/BurntSushi/toml/error.go

@@ -0,0 +1,279 @@
+package toml
+
+import (
+	"fmt"
+	"strings"
+)
+
+// ParseError is returned when there is an error parsing the TOML syntax such as
+// invalid syntax, duplicate keys, etc.
+//
+// In addition to the error message itself, you can also print detailed location
+// information with context by using [ErrorWithPosition]:
+//
+//	toml: error: Key 'fruit' was already created and cannot be used as an array.
+//
+//	At line 4, column 2-7:
+//
+//	      2 | fruit = []
+//	      3 |
+//	      4 | [[fruit]] # Not allowed
+//	            ^^^^^
+//
+// [ErrorWithUsage] can be used to print the above with some more detailed usage
+// guidance:
+//
+//	toml: error: newlines not allowed within inline tables
+//
+//	At line 1, column 18:
+//
+//	      1 | x = [{ key = 42 #
+//	                           ^
+//
+//	Error help:
+//
+//	  Inline tables must always be on a single line:
+//
+//	      table = {key = 42, second = 43}
+//
+//	  It is invalid to split them over multiple lines like so:
+//
+//	      # INVALID
+//	      table = {
+//	          key    = 42,
+//	          second = 43
+//	      }
+//
+//	  Use regular for this:
+//
+//	      [table]
+//	      key    = 42
+//	      second = 43
+type ParseError struct {
+	Message  string   // Short technical message.
+	Usage    string   // Longer message with usage guidance; may be blank.
+	Position Position // Position of the error
+	LastKey  string   // Last parsed key, may be blank.
+
+	// Line the error occurred.
+	//
+	// Deprecated: use [Position].
+	Line int
+
+	err   error
+	input string
+}
+
+// Position of an error.
+type Position struct {
+	Line  int // Line number, starting at 1.
+	Start int // Start of error, as byte offset starting at 0.
+	Len   int // Lenght in bytes.
+}
+
+func (pe ParseError) Error() string {
+	msg := pe.Message
+	if msg == "" { // Error from errorf()
+		msg = pe.err.Error()
+	}
+
+	if pe.LastKey == "" {
+		return fmt.Sprintf("toml: line %d: %s", pe.Position.Line, msg)
+	}
+	return fmt.Sprintf("toml: line %d (last key %q): %s",
+		pe.Position.Line, pe.LastKey, msg)
+}
+
+// ErrorWithPosition returns the error with detailed location context.
+//
+// See the documentation on [ParseError].
+func (pe ParseError) ErrorWithPosition() string {
+	if pe.input == "" { // Should never happen, but just in case.
+		return pe.Error()
+	}
+
+	var (
+		lines = strings.Split(pe.input, "\n")
+		col   = pe.column(lines)
+		b     = new(strings.Builder)
+	)
+
+	msg := pe.Message
+	if msg == "" {
+		msg = pe.err.Error()
+	}
+
+	// TODO: don't show control characters as literals? This may not show up
+	// well everywhere.
+
+	if pe.Position.Len == 1 {
+		fmt.Fprintf(b, "toml: error: %s\n\nAt line %d, column %d:\n\n",
+			msg, pe.Position.Line, col+1)
+	} else {
+		fmt.Fprintf(b, "toml: error: %s\n\nAt line %d, column %d-%d:\n\n",
+			msg, pe.Position.Line, col, col+pe.Position.Len)
+	}
+	if pe.Position.Line > 2 {
+		fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line-2, lines[pe.Position.Line-3])
+	}
+	if pe.Position.Line > 1 {
+		fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line-1, lines[pe.Position.Line-2])
+	}
+	fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line, lines[pe.Position.Line-1])
+	fmt.Fprintf(b, "% 10s%s%s\n", "", strings.Repeat(" ", col), strings.Repeat("^", pe.Position.Len))
+	return b.String()
+}
+
+// ErrorWithUsage returns the error with detailed location context and usage
+// guidance.
+//
+// See the documentation on [ParseError].
+func (pe ParseError) ErrorWithUsage() string {
+	m := pe.ErrorWithPosition()
+	if u, ok := pe.err.(interface{ Usage() string }); ok && u.Usage() != "" {
+		lines := strings.Split(strings.TrimSpace(u.Usage()), "\n")
+		for i := range lines {
+			if lines[i] != "" {
+				lines[i] = "    " + lines[i]
+			}
+		}
+		return m + "Error help:\n\n" + strings.Join(lines, "\n") + "\n"
+	}
+	return m
+}
+
+func (pe ParseError) column(lines []string) int {
+	var pos, col int
+	for i := range lines {
+		ll := len(lines[i]) + 1 // +1 for the removed newline
+		if pos+ll >= pe.Position.Start {
+			col = pe.Position.Start - pos
+			if col < 0 { // Should never happen, but just in case.
+				col = 0
+			}
+			break
+		}
+		pos += ll
+	}
+
+	return col
+}
+
+type (
+	errLexControl       struct{ r rune }
+	errLexEscape        struct{ r rune }
+	errLexUTF8          struct{ b byte }
+	errLexInvalidNum    struct{ v string }
+	errLexInvalidDate   struct{ v string }
+	errLexInlineTableNL struct{}
+	errLexStringNL      struct{}
+	errParseRange       struct {
+		i    interface{} // int or float
+		size string      // "int64", "uint16", etc.
+	}
+	errParseDuration struct{ d string }
+)
+
+func (e errLexControl) Error() string {
+	return fmt.Sprintf("TOML files cannot contain control characters: '0x%02x'", e.r)
+}
+func (e errLexControl) Usage() string { return "" }
+
+func (e errLexEscape) Error() string        { return fmt.Sprintf(`invalid escape in string '\%c'`, e.r) }
+func (e errLexEscape) Usage() string        { return usageEscape }
+func (e errLexUTF8) Error() string          { return fmt.Sprintf("invalid UTF-8 byte: 0x%02x", e.b) }
+func (e errLexUTF8) Usage() string          { return "" }
+func (e errLexInvalidNum) Error() string    { return fmt.Sprintf("invalid number: %q", e.v) }
+func (e errLexInvalidNum) Usage() string    { return "" }
+func (e errLexInvalidDate) Error() string   { return fmt.Sprintf("invalid date: %q", e.v) }
+func (e errLexInvalidDate) Usage() string   { return "" }
+func (e errLexInlineTableNL) Error() string { return "newlines not allowed within inline tables" }
+func (e errLexInlineTableNL) Usage() string { return usageInlineNewline }
+func (e errLexStringNL) Error() string      { return "strings cannot contain newlines" }
+func (e errLexStringNL) Usage() string      { return usageStringNewline }
+func (e errParseRange) Error() string       { return fmt.Sprintf("%v is out of range for %s", e.i, e.size) }
+func (e errParseRange) Usage() string       { return usageIntOverflow }
+func (e errParseDuration) Error() string    { return fmt.Sprintf("invalid duration: %q", e.d) }
+func (e errParseDuration) Usage() string    { return usageDuration }
+
+const usageEscape = `
+A '\' inside a "-delimited string is interpreted as an escape character.
+
+The following escape sequences are supported:
+\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX
+
+To prevent a '\' from being recognized as an escape character, use either:
+
+- a ' or '''-delimited string; escape characters aren't processed in them; or
+- write two backslashes to get a single backslash: '\\'.
+
+If you're trying to add a Windows path (e.g. "C:\Users\martin") then using '/'
+instead of '\' will usually also work: "C:/Users/martin".
+`
+
+const usageInlineNewline = `
+Inline tables must always be on a single line:
+
+    table = {key = 42, second = 43}
+
+It is invalid to split them over multiple lines like so:
+
+    # INVALID
+    table = {
+        key    = 42,
+        second = 43
+    }
+
+Use regular for this:
+
+    [table]
+    key    = 42
+    second = 43
+`
+
+const usageStringNewline = `
+Strings must always be on a single line, and cannot span more than one line:
+
+    # INVALID
+    string = "Hello,
+    world!"
+
+Instead use """ or ''' to split strings over multiple lines:
+
+    string = """Hello,
+    world!"""
+`
+
+const usageIntOverflow = `
+This number is too large; this may be an error in the TOML, but it can also be a
+bug in the program that uses too small of an integer.
+
+The maximum and minimum values are:
+
+    size   │ lowest         │ highest
+    ───────┼────────────────┼──────────
+    int8   │ -128           │ 127
+    int16  │ -32,768        │ 32,767
+    int32  │ -2,147,483,648 │ 2,147,483,647
+    int64  │ -9.2 × 10¹⁷    │ 9.2 × 10¹⁷
+    uint8  │ 0              │ 255
+    uint16 │ 0              │ 65535
+    uint32 │ 0              │ 4294967295
+    uint64 │ 0              │ 1.8 × 10¹⁸
+
+int refers to int32 on 32-bit systems and int64 on 64-bit systems.
+`
+
+const usageDuration = `
+A duration must be as "number<unit>", without any spaces. Valid units are:
+
+    ns         nanoseconds (billionth of a second)
+    us, µs     microseconds (millionth of a second)
+    ms         milliseconds (thousands of a second)
+    s          seconds
+    m          minutes
+    h          hours
+
+You can combine multiple units; for example "5m10s" for 5 minutes and 10
+seconds.
+`

+ 36 - 0
vendor/github.com/BurntSushi/toml/internal/tz.go

@@ -0,0 +1,36 @@
+package internal
+
+import "time"
+
+// Timezones used for local datetime, date, and time TOML types.
+//
+// The exact way times and dates without a timezone should be interpreted is not
+// well-defined in the TOML specification and left to the implementation. These
+// defaults to current local timezone offset of the computer, but this can be
+// changed by changing these variables before decoding.
+//
+// TODO:
+// Ideally we'd like to offer people the ability to configure the used timezone
+// by setting Decoder.Timezone and Encoder.Timezone; however, this is a bit
+// tricky: the reason we use three different variables for this is to support
+// round-tripping – without these specific TZ names we wouldn't know which
+// format to use.
+//
+// There isn't a good way to encode this right now though, and passing this sort
+// of information also ties in to various related issues such as string format
+// encoding, encoding of comments, etc.
+//
+// So, for the time being, just put this in internal until we can write a good
+// comprehensive API for doing all of this.
+//
+// The reason they're exported is because they're referred from in e.g.
+// internal/tag.
+//
+// Note that this behaviour is valid according to the TOML spec as the exact
+// behaviour is left up to implementations.
+var (
+	localOffset   = func() int { _, o := time.Now().Zone(); return o }()
+	LocalDatetime = time.FixedZone("datetime-local", localOffset)
+	LocalDate     = time.FixedZone("date-local", localOffset)
+	LocalTime     = time.FixedZone("time-local", localOffset)
+)

File diff suppressed because it is too large
+ 527 - 224
vendor/github.com/BurntSushi/toml/lex.go


+ 121 - 0
vendor/github.com/BurntSushi/toml/meta.go

@@ -0,0 +1,121 @@
+package toml
+
+import (
+	"strings"
+)
+
+// MetaData allows access to meta information about TOML data that's not
+// accessible otherwise.
+//
+// It allows checking if a key is defined in the TOML data, whether any keys
+// were undecoded, and the TOML type of a key.
+type MetaData struct {
+	context Key // Used only during decoding.
+
+	keyInfo map[string]keyInfo
+	mapping map[string]interface{}
+	keys    []Key
+	decoded map[string]struct{}
+	data    []byte // Input file; for errors.
+}
+
+// IsDefined reports if the key exists in the TOML data.
+//
+// The key should be specified hierarchically, for example to access the TOML
+// key "a.b.c" you would use IsDefined("a", "b", "c"). Keys are case sensitive.
+//
+// Returns false for an empty key.
+func (md *MetaData) IsDefined(key ...string) bool {
+	if len(key) == 0 {
+		return false
+	}
+
+	var (
+		hash      map[string]interface{}
+		ok        bool
+		hashOrVal interface{} = md.mapping
+	)
+	for _, k := range key {
+		if hash, ok = hashOrVal.(map[string]interface{}); !ok {
+			return false
+		}
+		if hashOrVal, ok = hash[k]; !ok {
+			return false
+		}
+	}
+	return true
+}
+
+// Type returns a string representation of the type of the key specified.
+//
+// Type will return the empty string if given an empty key or a key that does
+// not exist. Keys are case sensitive.
+func (md *MetaData) Type(key ...string) string {
+	if ki, ok := md.keyInfo[Key(key).String()]; ok {
+		return ki.tomlType.typeString()
+	}
+	return ""
+}
+
+// Keys returns a slice of every key in the TOML data, including key groups.
+//
+// Each key is itself a slice, where the first element is the top of the
+// hierarchy and the last is the most specific. The list will have the same
+// order as the keys appeared in the TOML data.
+//
+// All keys returned are non-empty.
+func (md *MetaData) Keys() []Key {
+	return md.keys
+}
+
+// Undecoded returns all keys that have not been decoded in the order in which
+// they appear in the original TOML document.
+//
+// This includes keys that haven't been decoded because of a [Primitive] value.
+// Once the Primitive value is decoded, the keys will be considered decoded.
+//
+// Also note that decoding into an empty interface will result in no decoding,
+// and so no keys will be considered decoded.
+//
+// In this sense, the Undecoded keys correspond to keys in the TOML document
+// that do not have a concrete type in your representation.
+func (md *MetaData) Undecoded() []Key {
+	undecoded := make([]Key, 0, len(md.keys))
+	for _, key := range md.keys {
+		if _, ok := md.decoded[key.String()]; !ok {
+			undecoded = append(undecoded, key)
+		}
+	}
+	return undecoded
+}
+
+// Key represents any TOML key, including key groups. Use [MetaData.Keys] to get
+// values of this type.
+type Key []string
+
+func (k Key) String() string {
+	ss := make([]string, len(k))
+	for i := range k {
+		ss[i] = k.maybeQuoted(i)
+	}
+	return strings.Join(ss, ".")
+}
+
+func (k Key) maybeQuoted(i int) string {
+	if k[i] == "" {
+		return `""`
+	}
+	for _, c := range k[i] {
+		if !isBareKeyChar(c, false) {
+			return `"` + dblQuotedReplacer.Replace(k[i]) + `"`
+		}
+	}
+	return k[i]
+}
+
+func (k Key) add(piece string) Key {
+	newKey := make(Key, len(k)+1)
+	copy(newKey, k)
+	newKey[len(k)] = piece
+	return newKey
+}

+ 467 - 248
vendor/github.com/BurntSushi/toml/parse.go

@@ -2,57 +2,80 @@ package toml
 
 import (
 	"fmt"
+	"os"
 	"strconv"
 	"strings"
 	"time"
-	"unicode"
 	"unicode/utf8"
+
+	"github.com/BurntSushi/toml/internal"
 )
 
 type parser struct {
-	mapping map[string]interface{}
-	types   map[string]tomlType
-	lx      *lexer
-
-	// A list of keys in the order that they appear in the TOML data.
-	ordered []Key
-
-	// the full key for the current hash in scope
-	context Key
+	lx         *lexer
+	context    Key      // Full key for the current hash in scope.
+	currentKey string   // Base key name for everything except hashes.
+	pos        Position // Current position in the TOML file.
+	tomlNext   bool
 
-	// the base key name for everything except hashes
-	currentKey string
+	ordered []Key // List of keys in the order that they appear in the TOML data.
 
-	// rough approximation of line number
-	approxLine int
-
-	// A map of 'key.group.names' to whether they were created implicitly.
-	implicits map[string]bool
+	keyInfo   map[string]keyInfo     // Map keyname → info about the TOML key.
+	mapping   map[string]interface{} // Map keyname → key value.
+	implicits map[string]struct{}    // Record implicit keys (e.g. "key.group.names").
 }
 
-type parseError string
-
-func (pe parseError) Error() string {
-	return string(pe)
+type keyInfo struct {
+	pos      Position
+	tomlType tomlType
 }
 
 func parse(data string) (p *parser, err error) {
+	_, tomlNext := os.LookupEnv("BURNTSUSHI_TOML_110")
+
 	defer func() {
 		if r := recover(); r != nil {
-			var ok bool
-			if err, ok = r.(parseError); ok {
+			if pErr, ok := r.(ParseError); ok {
+				pErr.input = data
+				err = pErr
 				return
 			}
 			panic(r)
 		}
 	}()
 
+	// Read over BOM; do this here as the lexer calls utf8.DecodeRuneInString()
+	// which mangles stuff. UTF-16 BOM isn't strictly valid, but some tools add
+	// it anyway.
+	if strings.HasPrefix(data, "\xff\xfe") || strings.HasPrefix(data, "\xfe\xff") { // UTF-16
+		data = data[2:]
+	} else if strings.HasPrefix(data, "\xef\xbb\xbf") { // UTF-8
+		data = data[3:]
+	}
+
+	// Examine first few bytes for NULL bytes; this probably means it's a UTF-16
+	// file (second byte in surrogate pair being NULL). Again, do this here to
+	// avoid having to deal with UTF-8/16 stuff in the lexer.
+	ex := 6
+	if len(data) < 6 {
+		ex = len(data)
+	}
+	if i := strings.IndexRune(data[:ex], 0); i > -1 {
+		return nil, ParseError{
+			Message:  "files cannot contain NULL bytes; probably using UTF-16; TOML files must be UTF-8",
+			Position: Position{Line: 1, Start: i, Len: 1},
+			Line:     1,
+			input:    data,
+		}
+	}
+
 	p = &parser{
+		keyInfo:   make(map[string]keyInfo),
 		mapping:   make(map[string]interface{}),
-		types:     make(map[string]tomlType),
-		lx:        lex(data),
+		lx:        lex(data, tomlNext),
 		ordered:   make([]Key, 0),
-		implicits: make(map[string]bool),
+		implicits: make(map[string]struct{}),
+		tomlNext:  tomlNext,
 	}
 	for {
 		item := p.next()
@@ -65,20 +88,57 @@ func parse(data string) (p *parser, err error) {
 	return p, nil
 }
 
+func (p *parser) panicErr(it item, err error) {
+	panic(ParseError{
+		err:      err,
+		Position: it.pos,
+		Line:     it.pos.Len,
+		LastKey:  p.current(),
+	})
+}
+
+func (p *parser) panicItemf(it item, format string, v ...interface{}) {
+	panic(ParseError{
+		Message:  fmt.Sprintf(format, v...),
+		Position: it.pos,
+		Line:     it.pos.Len,
+		LastKey:  p.current(),
+	})
+}
+
 func (p *parser) panicf(format string, v ...interface{}) {
-	msg := fmt.Sprintf("Near line %d (last key parsed '%s'): %s",
-		p.approxLine, p.current(), fmt.Sprintf(format, v...))
-	panic(parseError(msg))
+	panic(ParseError{
+		Message:  fmt.Sprintf(format, v...),
+		Position: p.pos,
+		Line:     p.pos.Line,
+		LastKey:  p.current(),
+	})
 }
 
 func (p *parser) next() item {
 	it := p.lx.nextItem()
+	//fmt.Printf("ITEM %-18s line %-3d │ %q\n", it.typ, it.pos.Line, it.val)
 	if it.typ == itemError {
-		p.panicf("%s", it.val)
+		if it.err != nil {
+			panic(ParseError{
+				Position: it.pos,
+				Line:     it.pos.Line,
+				LastKey:  p.current(),
+				err:      it.err,
+			})
+		}
+
+		p.panicItemf(it, "%s", it.val)
 	}
 	return it
 }
 
+func (p *parser) nextPos() item {
+	it := p.next()
+	p.pos = it.pos
+	return it
+}
+
 func (p *parser) bug(format string, v ...interface{}) {
 	panic(fmt.Sprintf("BUG: "+format+"\n\n", v...))
 }
@@ -97,44 +157,60 @@ func (p *parser) assertEqual(expected, got itemType) {
 
 func (p *parser) topLevel(item item) {
 	switch item.typ {
-	case itemCommentStart:
-		p.approxLine = item.line
+	case itemCommentStart: // # ..
 		p.expect(itemText)
-	case itemTableStart:
-		kg := p.next()
-		p.approxLine = kg.line
+	case itemTableStart: // [ .. ]
+		name := p.nextPos()
 
 		var key Key
-		for ; kg.typ != itemTableEnd && kg.typ != itemEOF; kg = p.next() {
-			key = append(key, p.keyString(kg))
+		for ; name.typ != itemTableEnd && name.typ != itemEOF; name = p.next() {
+			key = append(key, p.keyString(name))
 		}
-		p.assertEqual(itemTableEnd, kg.typ)
+		p.assertEqual(itemTableEnd, name.typ)
 
-		p.establishContext(key, false)
-		p.setType("", tomlHash)
+		p.addContext(key, false)
+		p.setType("", tomlHash, item.pos)
 		p.ordered = append(p.ordered, key)
-	case itemArrayTableStart:
-		kg := p.next()
-		p.approxLine = kg.line
+	case itemArrayTableStart: // [[ .. ]]
+		name := p.nextPos()
 
 		var key Key
-		for ; kg.typ != itemArrayTableEnd && kg.typ != itemEOF; kg = p.next() {
-			key = append(key, p.keyString(kg))
+		for ; name.typ != itemArrayTableEnd && name.typ != itemEOF; name = p.next() {
+			key = append(key, p.keyString(name))
 		}
-		p.assertEqual(itemArrayTableEnd, kg.typ)
+		p.assertEqual(itemArrayTableEnd, name.typ)
 
-		p.establishContext(key, true)
-		p.setType("", tomlArrayHash)
+		p.addContext(key, true)
+		p.setType("", tomlArrayHash, item.pos)
 		p.ordered = append(p.ordered, key)
-	case itemKeyStart:
-		kname := p.next()
-		p.approxLine = kname.line
-		p.currentKey = p.keyString(kname)
-
-		val, typ := p.value(p.next())
-		p.setValue(p.currentKey, val)
-		p.setType(p.currentKey, typ)
+	case itemKeyStart: // key = ..
+		outerContext := p.context
+		/// Read all the key parts (e.g. 'a' and 'b' in 'a.b')
+		k := p.nextPos()
+		var key Key
+		for ; k.typ != itemKeyEnd && k.typ != itemEOF; k = p.next() {
+			key = append(key, p.keyString(k))
+		}
+		p.assertEqual(itemKeyEnd, k.typ)
+
+		/// The current key is the last part.
+		p.currentKey = key[len(key)-1]
+
+		/// All the other parts (if any) are the context; need to set each part
+		/// as implicit.
+		context := key[:len(key)-1]
+		for i := range context {
+			p.addImplicitContext(append(p.context, context[i:i+1]...))
+		}
 		p.ordered = append(p.ordered, p.context.add(p.currentKey))
+
+		/// Set value.
+		vItem := p.next()
+		val, typ := p.value(vItem, false)
+		p.set(p.currentKey, val, typ, vItem.pos)
+
+		/// Remove the context we added (preserving any context from [tbl] lines).
+		p.context = outerContext
 		p.currentKey = ""
 	default:
 		p.bug("Unexpected type at top level: %s", item.typ)
@@ -148,180 +224,271 @@ func (p *parser) keyString(it item) string {
 		return it.val
 	case itemString, itemMultilineString,
 		itemRawString, itemRawMultilineString:
-		s, _ := p.value(it)
+		s, _ := p.value(it, false)
 		return s.(string)
 	default:
 		p.bug("Unexpected key type: %s", it.typ)
-		panic("unreachable")
 	}
+	panic("unreachable")
 }
 
+var datetimeRepl = strings.NewReplacer(
+	"z", "Z",
+	"t", "T",
+	" ", "T")
+
 // value translates an expected value from the lexer into a Go value wrapped
 // as an empty interface.
-func (p *parser) value(it item) (interface{}, tomlType) {
+func (p *parser) value(it item, parentIsArray bool) (interface{}, tomlType) {
 	switch it.typ {
 	case itemString:
-		return p.replaceEscapes(it.val), p.typeOfPrimitive(it)
+		return p.replaceEscapes(it, it.val), p.typeOfPrimitive(it)
 	case itemMultilineString:
-		trimmed := stripFirstNewline(stripEscapedWhitespace(it.val))
-		return p.replaceEscapes(trimmed), p.typeOfPrimitive(it)
+		return p.replaceEscapes(it, p.stripEscapedNewlines(stripFirstNewline(it.val))), p.typeOfPrimitive(it)
 	case itemRawString:
 		return it.val, p.typeOfPrimitive(it)
 	case itemRawMultilineString:
 		return stripFirstNewline(it.val), p.typeOfPrimitive(it)
+	case itemInteger:
+		return p.valueInteger(it)
+	case itemFloat:
+		return p.valueFloat(it)
 	case itemBool:
 		switch it.val {
 		case "true":
 			return true, p.typeOfPrimitive(it)
 		case "false":
 			return false, p.typeOfPrimitive(it)
+		default:
+			p.bug("Expected boolean value, but got '%s'.", it.val)
 		}
-		p.bug("Expected boolean value, but got '%s'.", it.val)
-	case itemInteger:
-		if !numUnderscoresOK(it.val) {
-			p.panicf("Invalid integer %q: underscores must be surrounded by digits",
-				it.val)
-		}
-		val := strings.Replace(it.val, "_", "", -1)
-		num, err := strconv.ParseInt(val, 10, 64)
-		if err != nil {
-			// Distinguish integer values. Normally, it'd be a bug if the lexer
-			// provides an invalid integer, but it's possible that the number is
-			// out of range of valid values (which the lexer cannot determine).
-			// So mark the former as a bug but the latter as a legitimate user
-			// error.
-			if e, ok := err.(*strconv.NumError); ok &&
-				e.Err == strconv.ErrRange {
-
-				p.panicf("Integer '%s' is out of the range of 64-bit "+
-					"signed integers.", it.val)
-			} else {
-				p.bug("Expected integer value, but got '%s'.", it.val)
-			}
+	case itemDatetime:
+		return p.valueDatetime(it)
+	case itemArray:
+		return p.valueArray(it)
+	case itemInlineTableStart:
+		return p.valueInlineTable(it, parentIsArray)
+	default:
+		p.bug("Unexpected value type: %s", it.typ)
+	}
+	panic("unreachable")
+}
+
+func (p *parser) valueInteger(it item) (interface{}, tomlType) {
+	if !numUnderscoresOK(it.val) {
+		p.panicItemf(it, "Invalid integer %q: underscores must be surrounded by digits", it.val)
+	}
+	if numHasLeadingZero(it.val) {
+		p.panicItemf(it, "Invalid integer %q: cannot have leading zeroes", it.val)
+	}
+
+	num, err := strconv.ParseInt(it.val, 0, 64)
+	if err != nil {
+		// Distinguish integer values. Normally, it'd be a bug if the lexer
+		// provides an invalid integer, but it's possible that the number is
+		// out of range of valid values (which the lexer cannot determine).
+		// So mark the former as a bug but the latter as a legitimate user
+		// error.
+		if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange {
+			p.panicErr(it, errParseRange{i: it.val, size: "int64"})
+		} else {
+			p.bug("Expected integer value, but got '%s'.", it.val)
 		}
-		return num, p.typeOfPrimitive(it)
-	case itemFloat:
-		parts := strings.FieldsFunc(it.val, func(r rune) bool {
-			switch r {
-			case '.', 'e', 'E':
-				return true
-			}
-			return false
-		})
-		for _, part := range parts {
-			if !numUnderscoresOK(part) {
-				p.panicf("Invalid float %q: underscores must be "+
-					"surrounded by digits", it.val)
-			}
+	}
+	return num, p.typeOfPrimitive(it)
+}
+
+func (p *parser) valueFloat(it item) (interface{}, tomlType) {
+	parts := strings.FieldsFunc(it.val, func(r rune) bool {
+		switch r {
+		case '.', 'e', 'E':
+			return true
 		}
-		if !numPeriodsOK(it.val) {
-			// As a special case, numbers like '123.' or '1.e2',
-			// which are valid as far as Go/strconv are concerned,
-			// must be rejected because TOML says that a fractional
-			// part consists of '.' followed by 1+ digits.
-			p.panicf("Invalid float %q: '.' must be followed "+
-				"by one or more digits", it.val)
-		}
-		val := strings.Replace(it.val, "_", "", -1)
-		num, err := strconv.ParseFloat(val, 64)
-		if err != nil {
-			if e, ok := err.(*strconv.NumError); ok &&
-				e.Err == strconv.ErrRange {
-
-				p.panicf("Float '%s' is out of the range of 64-bit "+
-					"IEEE-754 floating-point numbers.", it.val)
-			} else {
-				p.panicf("Invalid float value: %q", it.val)
-			}
+		return false
+	})
+	for _, part := range parts {
+		if !numUnderscoresOK(part) {
+			p.panicItemf(it, "Invalid float %q: underscores must be surrounded by digits", it.val)
 		}
-		return num, p.typeOfPrimitive(it)
-	case itemDatetime:
-		var t time.Time
-		var ok bool
-		var err error
-		for _, format := range []string{
-			"2006-01-02T15:04:05Z07:00",
-			"2006-01-02T15:04:05",
-			"2006-01-02",
-		} {
-			t, err = time.ParseInLocation(format, it.val, time.Local)
-			if err == nil {
-				ok = true
-				break
-			}
+	}
+	if len(parts) > 0 && numHasLeadingZero(parts[0]) {
+		p.panicItemf(it, "Invalid float %q: cannot have leading zeroes", it.val)
+	}
+	if !numPeriodsOK(it.val) {
+		// As a special case, numbers like '123.' or '1.e2',
+		// which are valid as far as Go/strconv are concerned,
+		// must be rejected because TOML says that a fractional
+		// part consists of '.' followed by 1+ digits.
+		p.panicItemf(it, "Invalid float %q: '.' must be followed by one or more digits", it.val)
+	}
+	val := strings.Replace(it.val, "_", "", -1)
+	if val == "+nan" || val == "-nan" { // Go doesn't support this, but TOML spec does.
+		val = "nan"
+	}
+	num, err := strconv.ParseFloat(val, 64)
+	if err != nil {
+		if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange {
+			p.panicErr(it, errParseRange{i: it.val, size: "float64"})
+		} else {
+			p.panicItemf(it, "Invalid float value: %q", it.val)
 		}
-		if !ok {
-			p.panicf("Invalid TOML Datetime: %q.", it.val)
+	}
+	return num, p.typeOfPrimitive(it)
+}
+
+var dtTypes = []struct {
+	fmt  string
+	zone *time.Location
+	next bool
+}{
+	{time.RFC3339Nano, time.Local, false},
+	{"2006-01-02T15:04:05.999999999", internal.LocalDatetime, false},
+	{"2006-01-02", internal.LocalDate, false},
+	{"15:04:05.999999999", internal.LocalTime, false},
+
+	// tomlNext
+	{"2006-01-02T15:04Z07:00", time.Local, true},
+	{"2006-01-02T15:04", internal.LocalDatetime, true},
+	{"15:04", internal.LocalTime, true},
+}
+
+func (p *parser) valueDatetime(it item) (interface{}, tomlType) {
+	it.val = datetimeRepl.Replace(it.val)
+	var (
+		t   time.Time
+		ok  bool
+		err error
+	)
+	for _, dt := range dtTypes {
+		if dt.next && !p.tomlNext {
+			continue
 		}
-		return t, p.typeOfPrimitive(it)
-	case itemArray:
-		array := make([]interface{}, 0)
-		types := make([]tomlType, 0)
+		t, err = time.ParseInLocation(dt.fmt, it.val, dt.zone)
+		if err == nil {
+			ok = true
+			break
+		}
+	}
+	if !ok {
+		p.panicItemf(it, "Invalid TOML Datetime: %q.", it.val)
+	}
+	return t, p.typeOfPrimitive(it)
+}
 
-		for it = p.next(); it.typ != itemArrayEnd; it = p.next() {
-			if it.typ == itemCommentStart {
-				p.expect(itemText)
-				continue
-			}
+func (p *parser) valueArray(it item) (interface{}, tomlType) {
+	p.setType(p.currentKey, tomlArray, it.pos)
+
+	var (
+		types []tomlType
 
-			val, typ := p.value(it)
-			array = append(array, val)
-			types = append(types, typ)
+		// Initialize to a non-nil empty slice. This makes it consistent with
+		// how S = [] decodes into a non-nil slice inside something like struct
+		// { S []string }. See #338
+		array = []interface{}{}
+	)
+	for it = p.next(); it.typ != itemArrayEnd; it = p.next() {
+		if it.typ == itemCommentStart {
+			p.expect(itemText)
+			continue
 		}
-		return array, p.typeOfArray(types)
-	case itemInlineTableStart:
-		var (
-			hash         = make(map[string]interface{})
-			outerContext = p.context
-			outerKey     = p.currentKey
-		)
 
-		p.context = append(p.context, p.currentKey)
-		p.currentKey = ""
-		for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() {
-			if it.typ != itemKeyStart {
-				p.bug("Expected key start but instead found %q, around line %d",
-					it.val, p.approxLine)
-			}
-			if it.typ == itemCommentStart {
-				p.expect(itemText)
-				continue
-			}
+		val, typ := p.value(it, true)
+		array = append(array, val)
+		types = append(types, typ)
+
+		// XXX: types isn't used here, we need it to record the accurate type
+		// information.
+		//
+		// Not entirely sure how to best store this; could use "key[0]",
+		// "key[1]" notation, or maybe store it on the Array type?
+		_ = types
+	}
+	return array, tomlArray
+}
+
+func (p *parser) valueInlineTable(it item, parentIsArray bool) (interface{}, tomlType) {
+	var (
+		hash         = make(map[string]interface{})
+		outerContext = p.context
+		outerKey     = p.currentKey
+	)
+
+	p.context = append(p.context, p.currentKey)
+	prevContext := p.context
+	p.currentKey = ""
 
-			// retrieve key
-			k := p.next()
-			p.approxLine = k.line
-			kname := p.keyString(k)
+	p.addImplicit(p.context)
+	p.addContext(p.context, parentIsArray)
 
-			// retrieve value
-			p.currentKey = kname
-			val, typ := p.value(p.next())
-			// make sure we keep metadata up to date
-			p.setType(kname, typ)
-			p.ordered = append(p.ordered, p.context.add(p.currentKey))
-			hash[kname] = val
+	/// Loop over all table key/value pairs.
+	for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() {
+		if it.typ == itemCommentStart {
+			p.expect(itemText)
+			continue
 		}
-		p.context = outerContext
-		p.currentKey = outerKey
-		return hash, tomlHash
+
+		/// Read all key parts.
+		k := p.nextPos()
+		var key Key
+		for ; k.typ != itemKeyEnd && k.typ != itemEOF; k = p.next() {
+			key = append(key, p.keyString(k))
+		}
+		p.assertEqual(itemKeyEnd, k.typ)
+
+		/// The current key is the last part.
+		p.currentKey = key[len(key)-1]
+
+		/// All the other parts (if any) are the context; need to set each part
+		/// as implicit.
+		context := key[:len(key)-1]
+		for i := range context {
+			p.addImplicitContext(append(p.context, context[i:i+1]...))
+		}
+		p.ordered = append(p.ordered, p.context.add(p.currentKey))
+
+		/// Set the value.
+		val, typ := p.value(p.next(), false)
+		p.set(p.currentKey, val, typ, it.pos)
+		hash[p.currentKey] = val
+
+		/// Restore context.
+		p.context = prevContext
 	}
-	p.bug("Unexpected value type: %s", it.typ)
-	panic("unreachable")
+	p.context = outerContext
+	p.currentKey = outerKey
+	return hash, tomlHash
+}
+
+// numHasLeadingZero checks if this number has leading zeroes, allowing for '0',
+// +/- signs, and base prefixes.
+func numHasLeadingZero(s string) bool {
+	if len(s) > 1 && s[0] == '0' && !(s[1] == 'b' || s[1] == 'o' || s[1] == 'x') { // Allow 0b, 0o, 0x
+		return true
+	}
+	if len(s) > 2 && (s[0] == '-' || s[0] == '+') && s[1] == '0' {
+		return true
+	}
+	return false
 }
 
 // numUnderscoresOK checks whether each underscore in s is surrounded by
 // characters that are not underscores.
 func numUnderscoresOK(s string) bool {
+	switch s {
+	case "nan", "+nan", "-nan", "inf", "-inf", "+inf":
+		return true
+	}
 	accept := false
 	for _, r := range s {
 		if r == '_' {
 			if !accept {
 				return false
 			}
-			accept = false
-			continue
 		}
-		accept = true
+
+		// isHexadecimal is a superset of all the permissable characters
+		// surrounding an underscore.
+		accept = isHexadecimal(r)
 	}
 	return accept
 }
@@ -338,13 +505,12 @@ func numPeriodsOK(s string) bool {
 	return !period
 }
 
-// establishContext sets the current context of the parser,
-// where the context is either a hash or an array of hashes. Which one is
-// set depends on the value of the `array` parameter.
+// Set the current context of the parser, where the context is either a hash or
+// an array of hashes, depending on the value of the `array` parameter.
 //
 // Establishing the context also makes sure that the key isn't a duplicate, and
 // will create implicit hashes automatically.
-func (p *parser) establishContext(key Key, array bool) {
+func (p *parser) addContext(key Key, array bool) {
 	var ok bool
 
 	// Always start at the top level and drill down for our context.
@@ -383,7 +549,7 @@ func (p *parser) establishContext(key Key, array bool) {
 		// list of tables for it.
 		k := key[len(key)-1]
 		if _, ok := hashContext[k]; !ok {
-			hashContext[k] = make([]map[string]interface{}, 0, 5)
+			hashContext[k] = make([]map[string]interface{}, 0, 4)
 		}
 
 		// Add a new table. But make sure the key hasn't already been used
@@ -391,8 +557,7 @@ func (p *parser) establishContext(key Key, array bool) {
 		if hash, ok := hashContext[k].([]map[string]interface{}); ok {
 			hashContext[k] = append(hash, make(map[string]interface{}))
 		} else {
-			p.panicf("Key '%s' was already created and cannot be used as "+
-				"an array.", keyContext)
+			p.panicf("Key '%s' was already created and cannot be used as an array.", key)
 		}
 	} else {
 		p.setValue(key[len(key)-1], make(map[string]interface{}))
@@ -400,15 +565,22 @@ func (p *parser) establishContext(key Key, array bool) {
 	p.context = append(p.context, key[len(key)-1])
 }
 
+// set calls setValue and setType.
+func (p *parser) set(key string, val interface{}, typ tomlType, pos Position) {
+	p.setValue(key, val)
+	p.setType(key, typ, pos)
+}
+
 // setValue sets the given key to the given value in the current context.
 // It will make sure that the key hasn't already been defined, account for
 // implicit key groups.
 func (p *parser) setValue(key string, value interface{}) {
-	var tmpHash interface{}
-	var ok bool
-
-	hash := p.mapping
-	keyContext := make(Key, 0)
+	var (
+		tmpHash    interface{}
+		ok         bool
+		hash       = p.mapping
+		keyContext Key
+	)
 	for _, k := range p.context {
 		keyContext = append(keyContext, k)
 		if tmpHash, ok = hash[k]; !ok {
@@ -422,24 +594,26 @@ func (p *parser) setValue(key string, value interface{}) {
 		case map[string]interface{}:
 			hash = t
 		default:
-			p.bug("Expected hash to have type 'map[string]interface{}', but "+
-				"it has '%T' instead.", tmpHash)
+			p.panicf("Key '%s' has already been defined.", keyContext)
 		}
 	}
 	keyContext = append(keyContext, key)
 
 	if _, ok := hash[key]; ok {
-		// Typically, if the given key has already been set, then we have
-		// to raise an error since duplicate keys are disallowed. However,
-		// it's possible that a key was previously defined implicitly. In this
-		// case, it is allowed to be redefined concretely. (See the
-		// `tests/valid/implicit-and-explicit-after.toml` test in `toml-test`.)
+		// Normally redefining keys isn't allowed, but the key could have been
+		// defined implicitly and it's allowed to be redefined concretely. (See
+		// the `valid/implicit-and-explicit-after.toml` in toml-test)
 		//
 		// But we have to make sure to stop marking it as an implicit. (So that
 		// another redefinition provokes an error.)
 		//
 		// Note that since it has already been defined (as a hash), we don't
 		// want to overwrite it. So our business is done.
+		if p.isArray(keyContext) {
+			p.removeImplicit(keyContext)
+			hash[key] = value
+			return
+		}
 		if p.isImplicit(keyContext) {
 			p.removeImplicit(keyContext)
 			return
@@ -449,41 +623,37 @@ func (p *parser) setValue(key string, value interface{}) {
 		// key, which is *always* wrong.
 		p.panicf("Key '%s' has already been defined.", keyContext)
 	}
+
 	hash[key] = value
 }
 
-// setType sets the type of a particular value at a given key.
-// It should be called immediately AFTER setValue.
+// setType sets the type of a particular value at a given key. It should be
+// called immediately AFTER setValue.
 //
 // Note that if `key` is empty, then the type given will be applied to the
 // current context (which is either a table or an array of tables).
-func (p *parser) setType(key string, typ tomlType) {
+func (p *parser) setType(key string, typ tomlType, pos Position) {
 	keyContext := make(Key, 0, len(p.context)+1)
-	for _, k := range p.context {
-		keyContext = append(keyContext, k)
-	}
+	keyContext = append(keyContext, p.context...)
 	if len(key) > 0 { // allow type setting for hashes
 		keyContext = append(keyContext, key)
 	}
-	p.types[keyContext.String()] = typ
-}
-
-// addImplicit sets the given Key as having been created implicitly.
-func (p *parser) addImplicit(key Key) {
-	p.implicits[key.String()] = true
-}
-
-// removeImplicit stops tagging the given key as having been implicitly
-// created.
-func (p *parser) removeImplicit(key Key) {
-	p.implicits[key.String()] = false
+	// Special case to make empty keys ("" = 1) work.
+	// Without it it will set "" rather than `""`.
+	// TODO: why is this needed? And why is this only needed here?
+	if len(keyContext) == 0 {
+		keyContext = Key{""}
+	}
+	p.keyInfo[keyContext.String()] = keyInfo{tomlType: typ, pos: pos}
 }
 
-// isImplicit returns true if the key group pointed to by the key was created
-// implicitly.
-func (p *parser) isImplicit(key Key) bool {
-	return p.implicits[key.String()]
-}
+// Implicit keys need to be created when tables are implied in "a.b.c.d = 1" and
+// "[a.b.c]" (the "a", "b", and "c" hashes are never created explicitly).
+func (p *parser) addImplicit(key Key)        { p.implicits[key.String()] = struct{}{} }
+func (p *parser) removeImplicit(key Key)     { delete(p.implicits, key.String()) }
+func (p *parser) isImplicit(key Key) bool    { _, ok := p.implicits[key.String()]; return ok }
+func (p *parser) isArray(key Key) bool       { return p.keyInfo[key.String()].tomlType == tomlArray }
+func (p *parser) addImplicitContext(key Key) { p.addImplicit(key); p.addContext(key, false) }
 
 // current returns the full key name of the current context.
 func (p *parser) current() string {
@@ -497,24 +667,67 @@ func (p *parser) current() string {
 }
 
 func stripFirstNewline(s string) string {
-	if len(s) == 0 || s[0] != '\n' {
-		return s
+	if len(s) > 0 && s[0] == '\n' {
+		return s[1:]
+	}
+	if len(s) > 1 && s[0] == '\r' && s[1] == '\n' {
+		return s[2:]
 	}
-	return s[1:]
+	return s
 }
 
-func stripEscapedWhitespace(s string) string {
-	esc := strings.Split(s, "\\\n")
-	if len(esc) > 1 {
-		for i := 1; i < len(esc); i++ {
-			esc[i] = strings.TrimLeftFunc(esc[i], unicode.IsSpace)
+// stripEscapedNewlines removes whitespace after line-ending backslashes in
+// multiline strings.
+//
+// A line-ending backslash is an unescaped \ followed only by whitespace until
+// the next newline. After a line-ending backslash, all whitespace is removed
+// until the next non-whitespace character.
+func (p *parser) stripEscapedNewlines(s string) string {
+	var b strings.Builder
+	var i int
+	for {
+		ix := strings.Index(s[i:], `\`)
+		if ix < 0 {
+			b.WriteString(s)
+			return b.String()
+		}
+		i += ix
+
+		if len(s) > i+1 && s[i+1] == '\\' {
+			// Escaped backslash.
+			i += 2
+			continue
+		}
+		// Scan until the next non-whitespace.
+		j := i + 1
+	whitespaceLoop:
+		for ; j < len(s); j++ {
+			switch s[j] {
+			case ' ', '\t', '\r', '\n':
+			default:
+				break whitespaceLoop
+			}
 		}
+		if j == i+1 {
+			// Not a whitespace escape.
+			i++
+			continue
+		}
+		if !strings.Contains(s[i:j], "\n") {
+			// This is not a line-ending backslash.
+			// (It's a bad escape sequence, but we can let
+			// replaceEscapes catch it.)
+			i++
+			continue
+		}
+		b.WriteString(s[:i])
+		s = s[j:]
+		i = 0
 	}
-	return strings.Join(esc, "")
 }
 
-func (p *parser) replaceEscapes(str string) string {
-	var replaced []rune
+func (p *parser) replaceEscapes(it item, str string) string {
+	replaced := make([]rune, 0, len(str))
 	s := []byte(str)
 	r := 0
 	for r < len(s) {
@@ -532,7 +745,8 @@ func (p *parser) replaceEscapes(str string) string {
 		switch s[r] {
 		default:
 			p.bug("Expected valid escape code after \\, but got %q.", s[r])
-			return ""
+		case ' ', '\t':
+			p.panicItemf(it, "invalid escape: '\\%c'", s[r])
 		case 'b':
 			replaced = append(replaced, rune(0x0008))
 			r += 1
@@ -548,24 +762,35 @@ func (p *parser) replaceEscapes(str string) string {
 		case 'r':
 			replaced = append(replaced, rune(0x000D))
 			r += 1
+		case 'e':
+			if p.tomlNext {
+				replaced = append(replaced, rune(0x001B))
+				r += 1
+			}
 		case '"':
 			replaced = append(replaced, rune(0x0022))
 			r += 1
 		case '\\':
 			replaced = append(replaced, rune(0x005C))
 			r += 1
+		case 'x':
+			if p.tomlNext {
+				escaped := p.asciiEscapeToUnicode(it, s[r+1:r+3])
+				replaced = append(replaced, escaped)
+				r += 3
+			}
 		case 'u':
 			// At this point, we know we have a Unicode escape of the form
 			// `uXXXX` at [r, r+5). (Because the lexer guarantees this
 			// for us.)
-			escaped := p.asciiEscapeToUnicode(s[r+1 : r+5])
+			escaped := p.asciiEscapeToUnicode(it, s[r+1:r+5])
 			replaced = append(replaced, escaped)
 			r += 5
 		case 'U':
 			// At this point, we know we have a Unicode escape of the form
 			// `uXXXX` at [r, r+9). (Because the lexer guarantees this
 			// for us.)
-			escaped := p.asciiEscapeToUnicode(s[r+1 : r+9])
+			escaped := p.asciiEscapeToUnicode(it, s[r+1:r+9])
 			replaced = append(replaced, escaped)
 			r += 9
 		}
@@ -573,20 +798,14 @@ func (p *parser) replaceEscapes(str string) string {
 	return string(replaced)
 }
 
-func (p *parser) asciiEscapeToUnicode(bs []byte) rune {
+func (p *parser) asciiEscapeToUnicode(it item, bs []byte) rune {
 	s := string(bs)
 	hex, err := strconv.ParseUint(strings.ToLower(s), 16, 32)
 	if err != nil {
-		p.bug("Could not parse '%s' as a hexadecimal number, but the "+
-			"lexer claims it's OK: %s", s, err)
+		p.bug("Could not parse '%s' as a hexadecimal number, but the lexer claims it's OK: %s", s, err)
 	}
 	if !utf8.ValidRune(rune(hex)) {
-		p.panicf("Escaped character '\\u%s' is not valid UTF-8.", s)
+		p.panicItemf(it, "Escaped character '\\u%s' is not valid UTF-8.", s)
 	}
 	return rune(hex)
 }
-
-func isStringType(ty itemType) bool {
-	return ty == itemString || ty == itemMultilineString ||
-		ty == itemRawString || ty == itemRawMultilineString
-}

+ 0 - 1
vendor/github.com/BurntSushi/toml/session.vim

@@ -1 +0,0 @@
-au BufWritePost *.go silent!make tags > /dev/null 2>&1

+ 0 - 91
vendor/github.com/BurntSushi/toml/type_check.go

@@ -1,91 +0,0 @@
-package toml
-
-// tomlType represents any Go type that corresponds to a TOML type.
-// While the first draft of the TOML spec has a simplistic type system that
-// probably doesn't need this level of sophistication, we seem to be militating
-// toward adding real composite types.
-type tomlType interface {
-	typeString() string
-}
-
-// typeEqual accepts any two types and returns true if they are equal.
-func typeEqual(t1, t2 tomlType) bool {
-	if t1 == nil || t2 == nil {
-		return false
-	}
-	return t1.typeString() == t2.typeString()
-}
-
-func typeIsHash(t tomlType) bool {
-	return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash)
-}
-
-type tomlBaseType string
-
-func (btype tomlBaseType) typeString() string {
-	return string(btype)
-}
-
-func (btype tomlBaseType) String() string {
-	return btype.typeString()
-}
-
-var (
-	tomlInteger   tomlBaseType = "Integer"
-	tomlFloat     tomlBaseType = "Float"
-	tomlDatetime  tomlBaseType = "Datetime"
-	tomlString    tomlBaseType = "String"
-	tomlBool      tomlBaseType = "Bool"
-	tomlArray     tomlBaseType = "Array"
-	tomlHash      tomlBaseType = "Hash"
-	tomlArrayHash tomlBaseType = "ArrayHash"
-)
-
-// typeOfPrimitive returns a tomlType of any primitive value in TOML.
-// Primitive values are: Integer, Float, Datetime, String and Bool.
-//
-// Passing a lexer item other than the following will cause a BUG message
-// to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime.
-func (p *parser) typeOfPrimitive(lexItem item) tomlType {
-	switch lexItem.typ {
-	case itemInteger:
-		return tomlInteger
-	case itemFloat:
-		return tomlFloat
-	case itemDatetime:
-		return tomlDatetime
-	case itemString:
-		return tomlString
-	case itemMultilineString:
-		return tomlString
-	case itemRawString:
-		return tomlString
-	case itemRawMultilineString:
-		return tomlString
-	case itemBool:
-		return tomlBool
-	}
-	p.bug("Cannot infer primitive type of lex item '%s'.", lexItem)
-	panic("unreachable")
-}
-
-// typeOfArray returns a tomlType for an array given a list of types of its
-// values.
-//
-// In the current spec, if an array is homogeneous, then its type is always
-// "Array". If the array is not homogeneous, an error is generated.
-func (p *parser) typeOfArray(types []tomlType) tomlType {
-	// Empty arrays are cool.
-	if len(types) == 0 {
-		return tomlArray
-	}
-
-	theType := types[0]
-	for _, t := range types[1:] {
-		if !typeEqual(theType, t) {
-			p.panicf("Array contains values of type '%s' and '%s', but "+
-				"arrays must be homogeneous.", theType, t)
-		}
-	}
-	return tomlArray
-}

+ 2 - 2
vendor/github.com/BurntSushi/toml/type_fields.go

@@ -70,8 +70,8 @@ func typeFields(t reflect.Type) []field {
 	next := []field{{typ: t}}
 
 	// Count of queued names for current level and the next.
-	count := map[reflect.Type]int{}
-	nextCount := map[reflect.Type]int{}
+	var count map[reflect.Type]int
+	var nextCount map[reflect.Type]int
 
 	// Types already visited at an earlier level.
 	visited := map[reflect.Type]bool{}

+ 70 - 0
vendor/github.com/BurntSushi/toml/type_toml.go

@@ -0,0 +1,70 @@
+package toml
+
+// tomlType represents any Go type that corresponds to a TOML type.
+// While the first draft of the TOML spec has a simplistic type system that
+// probably doesn't need this level of sophistication, we seem to be militating
+// toward adding real composite types.
+type tomlType interface {
+	typeString() string
+}
+
+// typeEqual accepts any two types and returns true if they are equal.
+func typeEqual(t1, t2 tomlType) bool {
+	if t1 == nil || t2 == nil {
+		return false
+	}
+	return t1.typeString() == t2.typeString()
+}
+
+func typeIsTable(t tomlType) bool {
+	return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash)
+}
+
+type tomlBaseType string
+
+func (btype tomlBaseType) typeString() string {
+	return string(btype)
+}
+
+func (btype tomlBaseType) String() string {
+	return btype.typeString()
+}
+
+var (
+	tomlInteger   tomlBaseType = "Integer"
+	tomlFloat     tomlBaseType = "Float"
+	tomlDatetime  tomlBaseType = "Datetime"
+	tomlString    tomlBaseType = "String"
+	tomlBool      tomlBaseType = "Bool"
+	tomlArray     tomlBaseType = "Array"
+	tomlHash      tomlBaseType = "Hash"
+	tomlArrayHash tomlBaseType = "ArrayHash"
+)
+
+// typeOfPrimitive returns a tomlType of any primitive value in TOML.
+// Primitive values are: Integer, Float, Datetime, String and Bool.
+//
+// Passing a lexer item other than the following will cause a BUG message
+// to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime.
+func (p *parser) typeOfPrimitive(lexItem item) tomlType {
+	switch lexItem.typ {
+	case itemInteger:
+		return tomlInteger
+	case itemFloat:
+		return tomlFloat
+	case itemDatetime:
+		return tomlDatetime
+	case itemString:
+		return tomlString
+	case itemMultilineString:
+		return tomlString
+	case itemRawString:
+		return tomlString
+	case itemRawMultilineString:
+		return tomlString
+	case itemBool:
+		return tomlBool
+	}
+	p.bug("Cannot infer primitive type of lex item '%s'.", lexItem)
+	panic("unreachable")
+}

+ 21 - 0
vendor/github.com/CloudyKit/fastprinter/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 CloudyKit
+
+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.

+ 2 - 0
vendor/github.com/CloudyKit/fastprinter/README.md

@@ -0,0 +1,2 @@
+# fastprinter
+FastPrinter supports write values in io.Writer without allocation

+ 369 - 0
vendor/github.com/CloudyKit/fastprinter/decimal.go

@@ -0,0 +1,369 @@
+// 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.
+
+// Multiprecision decimal numbers.
+// For floating-point formatting only; not general purpose.
+// Only operations are assign and (binary) left/right shift.
+// Can do binary floating point in multiprecision decimal precisely
+// because 2 divides 10; cannot do decimal floating point
+// in multiprecision binary precisely.
+
+package fastprinter
+
+type decimal struct {
+	d     [800]byte // digits, big-endian representation
+	nd    int       // number of digits used
+	dp    int       // decimal point
+	neg   bool
+	trunc bool // discarded nonzero digits beyond d[:nd]
+}
+
+// trim trailing zeros from number.
+// (They are meaningless; the decimal point is tracked
+// independent of the number of digits.)
+func trim(a *decimal) {
+	for a.nd > 0 && a.d[a.nd-1] == '0' {
+		a.nd--
+	}
+	if a.nd == 0 {
+		a.dp = 0
+	}
+}
+
+// Assign v to a.
+func (a *decimal) Assign(v uint64) {
+	var buf [24]byte
+
+	// Write reversed decimal in buf.
+	n := 0
+	for v > 0 {
+		v1 := v / 10
+		v -= 10 * v1
+		buf[n] = byte(v + '0')
+		n++
+		v = v1
+	}
+
+	// Reverse again to produce forward decimal in a.d.
+	a.nd = 0
+	for n--; n >= 0; n-- {
+		a.d[a.nd] = buf[n]
+		a.nd++
+	}
+	a.dp = a.nd
+	trim(a)
+}
+
+// Maximum shift that we can do in one pass without overflow.
+// A uint has 32 or 64 bits, and we have to be able to accommodate 9<<k.
+const uintSize = 32 << (^uint(0) >> 63)
+const maxShift = uintSize - 4
+
+// Binary shift right (/ 2) by k bits.  k <= maxShift to avoid overflow.
+func rightShift(a *decimal, k uint) {
+	r := 0 // read pointer
+	w := 0 // write pointer
+
+	// Pick up enough leading digits to cover first shift.
+	var n uint
+	for ; n>>k == 0; r++ {
+		if r >= a.nd {
+			if n == 0 {
+				// a == 0; shouldn't get here, but handle anyway.
+				a.nd = 0
+				return
+			}
+			for n>>k == 0 {
+				n = n * 10
+				r++
+			}
+			break
+		}
+		c := uint(a.d[r])
+		n = n*10 + c - '0'
+	}
+	a.dp -= r - 1
+
+	// Pick up a digit, put down a digit.
+	for ; r < a.nd; r++ {
+		c := uint(a.d[r])
+		dig := n >> k
+		n -= dig << k
+		a.d[w] = byte(dig + '0')
+		w++
+		n = n*10 + c - '0'
+	}
+
+	// Put down extra digits.
+	for n > 0 {
+		dig := n >> k
+		n -= dig << k
+		if w < len(a.d) {
+			a.d[w] = byte(dig + '0')
+			w++
+		} else if dig > 0 {
+			a.trunc = true
+		}
+		n = n * 10
+	}
+
+	a.nd = w
+	trim(a)
+}
+
+// Cheat sheet for left shift: table indexed by shift count giving
+// number of new digits that will be introduced by that shift.
+//
+// For example, leftcheats[4] = {2, "625"}.  That means that
+// if we are shifting by 4 (multiplying by 16), it will add 2 digits
+// when the string prefix is "625" through "999", and one fewer digit
+// if the string prefix is "000" through "624".
+//
+// Credit for this trick goes to Ken.
+
+type leftCheat struct {
+	delta  int    // number of new digits
+	cutoff string // minus one digit if original < a.
+}
+
+var leftcheats = []leftCheat{
+	// Leading digits of 1/2^i = 5^i.
+	// 5^23 is not an exact 64-bit floating point number,
+	// so have to use bc for the math.
+	// Go up to 60 to be large enough for 32bit and 64bit platforms.
+	/*
+		seq 60 | sed 's/^/5^/' | bc |
+		awk 'BEGIN{ print "\t{ 0, \"\" }," }
+		{
+			log2 = log(2)/log(10)
+			printf("\t{ %d, \"%s\" },\t// * %d\n",
+				int(log2*NR+1), $0, 2**NR)
+		}'
+	*/
+	{0, ""},
+	{1, "5"},                                           // * 2
+	{1, "25"},                                          // * 4
+	{1, "125"},                                         // * 8
+	{2, "625"},                                         // * 16
+	{2, "3125"},                                        // * 32
+	{2, "15625"},                                       // * 64
+	{3, "78125"},                                       // * 128
+	{3, "390625"},                                      // * 256
+	{3, "1953125"},                                     // * 512
+	{4, "9765625"},                                     // * 1024
+	{4, "48828125"},                                    // * 2048
+	{4, "244140625"},                                   // * 4096
+	{4, "1220703125"},                                  // * 8192
+	{5, "6103515625"},                                  // * 16384
+	{5, "30517578125"},                                 // * 32768
+	{5, "152587890625"},                                // * 65536
+	{6, "762939453125"},                                // * 131072
+	{6, "3814697265625"},                               // * 262144
+	{6, "19073486328125"},                              // * 524288
+	{7, "95367431640625"},                              // * 1048576
+	{7, "476837158203125"},                             // * 2097152
+	{7, "2384185791015625"},                            // * 4194304
+	{7, "11920928955078125"},                           // * 8388608
+	{8, "59604644775390625"},                           // * 16777216
+	{8, "298023223876953125"},                          // * 33554432
+	{8, "1490116119384765625"},                         // * 67108864
+	{9, "7450580596923828125"},                         // * 134217728
+	{9, "37252902984619140625"},                        // * 268435456
+	{9, "186264514923095703125"},                       // * 536870912
+	{10, "931322574615478515625"},                      // * 1073741824
+	{10, "4656612873077392578125"},                     // * 2147483648
+	{10, "23283064365386962890625"},                    // * 4294967296
+	{10, "116415321826934814453125"},                   // * 8589934592
+	{11, "582076609134674072265625"},                   // * 17179869184
+	{11, "2910383045673370361328125"},                  // * 34359738368
+	{11, "14551915228366851806640625"},                 // * 68719476736
+	{12, "72759576141834259033203125"},                 // * 137438953472
+	{12, "363797880709171295166015625"},                // * 274877906944
+	{12, "1818989403545856475830078125"},               // * 549755813888
+	{13, "9094947017729282379150390625"},               // * 1099511627776
+	{13, "45474735088646411895751953125"},              // * 2199023255552
+	{13, "227373675443232059478759765625"},             // * 4398046511104
+	{13, "1136868377216160297393798828125"},            // * 8796093022208
+	{14, "5684341886080801486968994140625"},            // * 17592186044416
+	{14, "28421709430404007434844970703125"},           // * 35184372088832
+	{14, "142108547152020037174224853515625"},          // * 70368744177664
+	{15, "710542735760100185871124267578125"},          // * 140737488355328
+	{15, "3552713678800500929355621337890625"},         // * 281474976710656
+	{15, "17763568394002504646778106689453125"},        // * 562949953421312
+	{16, "88817841970012523233890533447265625"},        // * 1125899906842624
+	{16, "444089209850062616169452667236328125"},       // * 2251799813685248
+	{16, "2220446049250313080847263336181640625"},      // * 4503599627370496
+	{16, "11102230246251565404236316680908203125"},     // * 9007199254740992
+	{17, "55511151231257827021181583404541015625"},     // * 18014398509481984
+	{17, "277555756156289135105907917022705078125"},    // * 36028797018963968
+	{17, "1387778780781445675529539585113525390625"},   // * 72057594037927936
+	{18, "6938893903907228377647697925567626953125"},   // * 144115188075855872
+	{18, "34694469519536141888238489627838134765625"},  // * 288230376151711744
+	{18, "173472347597680709441192448139190673828125"}, // * 576460752303423488
+	{19, "867361737988403547205962240695953369140625"}, // * 1152921504606846976
+}
+
+// Is the leading prefix of b lexicographically less than s?
+func prefixIsLessThan(b []byte, s string) bool {
+	for i := 0; i < len(s); i++ {
+		if i >= len(b) {
+			return true
+		}
+		if b[i] != s[i] {
+			return b[i] < s[i]
+		}
+	}
+	return false
+}
+
+// Binary shift left (* 2) by k bits.  k <= maxShift to avoid overflow.
+func leftShift(a *decimal, k uint) {
+	delta := leftcheats[k].delta
+	if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) {
+		delta--
+	}
+
+	r := a.nd         // read index
+	w := a.nd + delta // write index
+
+	// Pick up a digit, put down a digit.
+	var n uint
+	for r--; r >= 0; r-- {
+		n += (uint(a.d[r]) - '0') << k
+		quo := n / 10
+		rem := n - 10*quo
+		w--
+		if w < len(a.d) {
+			a.d[w] = byte(rem + '0')
+		} else if rem != 0 {
+			a.trunc = true
+		}
+		n = quo
+	}
+
+	// Put down extra digits.
+	for n > 0 {
+		quo := n / 10
+		rem := n - 10*quo
+		w--
+		if w < len(a.d) {
+			a.d[w] = byte(rem + '0')
+		} else if rem != 0 {
+			a.trunc = true
+		}
+		n = quo
+	}
+
+	a.nd += delta
+	if a.nd >= len(a.d) {
+		a.nd = len(a.d)
+	}
+	a.dp += delta
+	trim(a)
+}
+
+// Binary shift left (k > 0) or right (k < 0).
+func (a *decimal) Shift(k int) {
+	switch {
+	case a.nd == 0:
+	// nothing to do: a == 0
+	case k > 0:
+		for k > maxShift {
+			leftShift(a, maxShift)
+			k -= maxShift
+		}
+		leftShift(a, uint(k))
+	case k < 0:
+		for k < -maxShift {
+			rightShift(a, maxShift)
+			k += maxShift
+		}
+		rightShift(a, uint(-k))
+	}
+}
+
+// If we chop a at nd digits, should we round up?
+func shouldRoundUp(a *decimal, nd int) bool {
+	if nd < 0 || nd >= a.nd {
+		return false
+	}
+	if a.d[nd] == '5' && nd+1 == a.nd {
+		// exactly halfway - round to even
+		// if we truncated, a little higher than what's recorded - always round up
+		if a.trunc {
+			return true
+		}
+		return nd > 0 && (a.d[nd-1]-'0')%2 != 0
+	}
+	// not halfway - digit tells all
+	return a.d[nd] >= '5'
+}
+
+// Round a to nd digits (or fewer).
+// If nd is zero, it means we're rounding
+// just to the left of the digits, as in
+// 0.09 -> 0.1.
+func (a *decimal) Round(nd int) {
+	if nd < 0 || nd >= a.nd {
+		return
+	}
+	if shouldRoundUp(a, nd) {
+		a.RoundUp(nd)
+	} else {
+		a.RoundDown(nd)
+	}
+}
+
+// Round a down to nd digits (or fewer).
+func (a *decimal) RoundDown(nd int) {
+	if nd < 0 || nd >= a.nd {
+		return
+	}
+	a.nd = nd
+	trim(a)
+}
+
+// Round a up to nd digits (or fewer).
+func (a *decimal) RoundUp(nd int) {
+	if nd < 0 || nd >= a.nd {
+		return
+	}
+
+	// round up
+	for i := nd - 1; i >= 0; i-- {
+		c := a.d[i]
+		if c < '9' {
+			// can stop after this digit
+			a.d[i]++
+			a.nd = i + 1
+			return
+		}
+	}
+
+	// Number is all 9s.
+	// Change to single 1 with adjusted decimal point.
+	a.d[0] = '1'
+	a.nd = 1
+	a.dp++
+}
+
+// Extract integer part, rounded appropriately.
+// No guarantees about overflow.
+func (a *decimal) RoundedInteger() uint64 {
+	if a.dp > 20 {
+		return 0xFFFFFFFFFFFFFFFF
+	}
+	var i int
+	n := uint64(0)
+	for i = 0; i < a.dp && i < a.nd; i++ {
+		n = n*10 + uint64(a.d[i]-'0')
+	}
+	for ; i < a.dp; i++ {
+		n *= 10
+	}
+	if shouldRoundUp(a, a.dp) {
+		n++
+	}
+	return n
+}

+ 668 - 0
vendor/github.com/CloudyKit/fastprinter/extfloat.go

@@ -0,0 +1,668 @@
+// 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 fastprinter
+
+// An extFloat represents an extended floating-point number, with more
+// precision than a float64. It does not try to save bits: the
+// number represented by the structure is mant*(2^exp), with a negative
+// sign if neg is true.
+type extFloat struct {
+	mant uint64
+	exp  int
+	neg  bool
+}
+
+// Powers of ten taken from double-conversion library.
+// http://code.google.com/p/double-conversion/
+const (
+	firstPowerOfTen = -348
+	stepPowerOfTen  = 8
+)
+
+var smallPowersOfTen = [...]extFloat{
+	{1 << 63, -63, false},        // 1
+	{0xa << 60, -60, false},      // 1e1
+	{0x64 << 57, -57, false},     // 1e2
+	{0x3e8 << 54, -54, false},    // 1e3
+	{0x2710 << 50, -50, false},   // 1e4
+	{0x186a0 << 47, -47, false},  // 1e5
+	{0xf4240 << 44, -44, false},  // 1e6
+	{0x989680 << 40, -40, false}, // 1e7
+}
+
+var powersOfTen = [...]extFloat{
+	{0xfa8fd5a0081c0288, -1220, false}, // 10^-348
+	{0xbaaee17fa23ebf76, -1193, false}, // 10^-340
+	{0x8b16fb203055ac76, -1166, false}, // 10^-332
+	{0xcf42894a5dce35ea, -1140, false}, // 10^-324
+	{0x9a6bb0aa55653b2d, -1113, false}, // 10^-316
+	{0xe61acf033d1a45df, -1087, false}, // 10^-308
+	{0xab70fe17c79ac6ca, -1060, false}, // 10^-300
+	{0xff77b1fcbebcdc4f, -1034, false}, // 10^-292
+	{0xbe5691ef416bd60c, -1007, false}, // 10^-284
+	{0x8dd01fad907ffc3c, -980, false},  // 10^-276
+	{0xd3515c2831559a83, -954, false},  // 10^-268
+	{0x9d71ac8fada6c9b5, -927, false},  // 10^-260
+	{0xea9c227723ee8bcb, -901, false},  // 10^-252
+	{0xaecc49914078536d, -874, false},  // 10^-244
+	{0x823c12795db6ce57, -847, false},  // 10^-236
+	{0xc21094364dfb5637, -821, false},  // 10^-228
+	{0x9096ea6f3848984f, -794, false},  // 10^-220
+	{0xd77485cb25823ac7, -768, false},  // 10^-212
+	{0xa086cfcd97bf97f4, -741, false},  // 10^-204
+	{0xef340a98172aace5, -715, false},  // 10^-196
+	{0xb23867fb2a35b28e, -688, false},  // 10^-188
+	{0x84c8d4dfd2c63f3b, -661, false},  // 10^-180
+	{0xc5dd44271ad3cdba, -635, false},  // 10^-172
+	{0x936b9fcebb25c996, -608, false},  // 10^-164
+	{0xdbac6c247d62a584, -582, false},  // 10^-156
+	{0xa3ab66580d5fdaf6, -555, false},  // 10^-148
+	{0xf3e2f893dec3f126, -529, false},  // 10^-140
+	{0xb5b5ada8aaff80b8, -502, false},  // 10^-132
+	{0x87625f056c7c4a8b, -475, false},  // 10^-124
+	{0xc9bcff6034c13053, -449, false},  // 10^-116
+	{0x964e858c91ba2655, -422, false},  // 10^-108
+	{0xdff9772470297ebd, -396, false},  // 10^-100
+	{0xa6dfbd9fb8e5b88f, -369, false},  // 10^-92
+	{0xf8a95fcf88747d94, -343, false},  // 10^-84
+	{0xb94470938fa89bcf, -316, false},  // 10^-76
+	{0x8a08f0f8bf0f156b, -289, false},  // 10^-68
+	{0xcdb02555653131b6, -263, false},  // 10^-60
+	{0x993fe2c6d07b7fac, -236, false},  // 10^-52
+	{0xe45c10c42a2b3b06, -210, false},  // 10^-44
+	{0xaa242499697392d3, -183, false},  // 10^-36
+	{0xfd87b5f28300ca0e, -157, false},  // 10^-28
+	{0xbce5086492111aeb, -130, false},  // 10^-20
+	{0x8cbccc096f5088cc, -103, false},  // 10^-12
+	{0xd1b71758e219652c, -77, false},   // 10^-4
+	{0x9c40000000000000, -50, false},   // 10^4
+	{0xe8d4a51000000000, -24, false},   // 10^12
+	{0xad78ebc5ac620000, 3, false},     // 10^20
+	{0x813f3978f8940984, 30, false},    // 10^28
+	{0xc097ce7bc90715b3, 56, false},    // 10^36
+	{0x8f7e32ce7bea5c70, 83, false},    // 10^44
+	{0xd5d238a4abe98068, 109, false},   // 10^52
+	{0x9f4f2726179a2245, 136, false},   // 10^60
+	{0xed63a231d4c4fb27, 162, false},   // 10^68
+	{0xb0de65388cc8ada8, 189, false},   // 10^76
+	{0x83c7088e1aab65db, 216, false},   // 10^84
+	{0xc45d1df942711d9a, 242, false},   // 10^92
+	{0x924d692ca61be758, 269, false},   // 10^100
+	{0xda01ee641a708dea, 295, false},   // 10^108
+	{0xa26da3999aef774a, 322, false},   // 10^116
+	{0xf209787bb47d6b85, 348, false},   // 10^124
+	{0xb454e4a179dd1877, 375, false},   // 10^132
+	{0x865b86925b9bc5c2, 402, false},   // 10^140
+	{0xc83553c5c8965d3d, 428, false},   // 10^148
+	{0x952ab45cfa97a0b3, 455, false},   // 10^156
+	{0xde469fbd99a05fe3, 481, false},   // 10^164
+	{0xa59bc234db398c25, 508, false},   // 10^172
+	{0xf6c69a72a3989f5c, 534, false},   // 10^180
+	{0xb7dcbf5354e9bece, 561, false},   // 10^188
+	{0x88fcf317f22241e2, 588, false},   // 10^196
+	{0xcc20ce9bd35c78a5, 614, false},   // 10^204
+	{0x98165af37b2153df, 641, false},   // 10^212
+	{0xe2a0b5dc971f303a, 667, false},   // 10^220
+	{0xa8d9d1535ce3b396, 694, false},   // 10^228
+	{0xfb9b7cd9a4a7443c, 720, false},   // 10^236
+	{0xbb764c4ca7a44410, 747, false},   // 10^244
+	{0x8bab8eefb6409c1a, 774, false},   // 10^252
+	{0xd01fef10a657842c, 800, false},   // 10^260
+	{0x9b10a4e5e9913129, 827, false},   // 10^268
+	{0xe7109bfba19c0c9d, 853, false},   // 10^276
+	{0xac2820d9623bf429, 880, false},   // 10^284
+	{0x80444b5e7aa7cf85, 907, false},   // 10^292
+	{0xbf21e44003acdd2d, 933, false},   // 10^300
+	{0x8e679c2f5e44ff8f, 960, false},   // 10^308
+	{0xd433179d9c8cb841, 986, false},   // 10^316
+	{0x9e19db92b4e31ba9, 1013, false},  // 10^324
+	{0xeb96bf6ebadf77d9, 1039, false},  // 10^332
+	{0xaf87023b9bf0ee6b, 1066, false},  // 10^340
+}
+
+// floatBits returns the bits of the float64 that best approximates
+// the extFloat passed as receiver. Overflow is set to true if
+// the resulting float64 is ±Inf.
+func (f *extFloat) floatBits(flt *floatInfo) (bits uint64, overflow bool) {
+	f.Normalize()
+
+	exp := f.exp + 63
+
+	// Exponent too small.
+	if exp < flt.bias+1 {
+		n := flt.bias + 1 - exp
+		f.mant >>= uint(n)
+		exp += n
+	}
+
+	// Extract 1+flt.mantbits bits from the 64-bit mantissa.
+	mant := f.mant >> (63 - flt.mantbits)
+	if f.mant&(1<<(62-flt.mantbits)) != 0 {
+		// Round up.
+		mant += 1
+	}
+
+	// Rounding might have added a bit; shift down.
+	if mant == 2<<flt.mantbits {
+		mant >>= 1
+		exp++
+	}
+
+	// Infinities.
+	if exp-flt.bias >= 1<<flt.expbits-1 {
+		// ±Inf
+		mant = 0
+		exp = 1<<flt.expbits - 1 + flt.bias
+		overflow = true
+	} else if mant&(1<<flt.mantbits) == 0 {
+		// Denormalized?
+		exp = flt.bias
+	}
+	// Assemble bits.
+	bits = mant & (uint64(1)<<flt.mantbits - 1)
+	bits |= uint64((exp-flt.bias)&(1<<flt.expbits-1)) << flt.mantbits
+	if f.neg {
+		bits |= 1 << (flt.mantbits + flt.expbits)
+	}
+	return
+}
+
+// AssignComputeBounds sets f to the floating point value
+// defined by mant, exp and precision given by flt. It returns
+// lower, upper such that any number in the closed interval
+// [lower, upper] is converted back to the same floating point number.
+func (f *extFloat) AssignComputeBounds(mant uint64, exp int, neg bool, flt *floatInfo) (lower, upper extFloat) {
+	f.mant = mant
+	f.exp = exp - int(flt.mantbits)
+	f.neg = neg
+	if f.exp <= 0 && mant == (mant>>uint(-f.exp))<<uint(-f.exp) {
+		// An exact integer
+		f.mant >>= uint(-f.exp)
+		f.exp = 0
+		return *f, *f
+	}
+	expBiased := exp - flt.bias
+
+	upper = extFloat{mant: 2*f.mant + 1, exp: f.exp - 1, neg: f.neg}
+	if mant != 1<<flt.mantbits || expBiased == 1 {
+		lower = extFloat{mant: 2*f.mant - 1, exp: f.exp - 1, neg: f.neg}
+	} else {
+		lower = extFloat{mant: 4*f.mant - 1, exp: f.exp - 2, neg: f.neg}
+	}
+	return
+}
+
+// Normalize normalizes f so that the highest bit of the mantissa is
+// set, and returns the number by which the mantissa was left-shifted.
+func (f *extFloat) Normalize() (shift uint) {
+	mant, exp := f.mant, f.exp
+	if mant == 0 {
+		return 0
+	}
+	if mant>>(64-32) == 0 {
+		mant <<= 32
+		exp -= 32
+	}
+	if mant>>(64-16) == 0 {
+		mant <<= 16
+		exp -= 16
+	}
+	if mant>>(64-8) == 0 {
+		mant <<= 8
+		exp -= 8
+	}
+	if mant>>(64-4) == 0 {
+		mant <<= 4
+		exp -= 4
+	}
+	if mant>>(64-2) == 0 {
+		mant <<= 2
+		exp -= 2
+	}
+	if mant>>(64-1) == 0 {
+		mant <<= 1
+		exp -= 1
+	}
+	shift = uint(f.exp - exp)
+	f.mant, f.exp = mant, exp
+	return
+}
+
+// Multiply sets f to the product f*g: the result is correctly rounded,
+// but not normalized.
+func (f *extFloat) Multiply(g extFloat) {
+	fhi, flo := f.mant>>32, uint64(uint32(f.mant))
+	ghi, glo := g.mant>>32, uint64(uint32(g.mant))
+
+	// Cross products.
+	cross1 := fhi * glo
+	cross2 := flo * ghi
+
+	// f.mant*g.mant is fhi*ghi << 64 + (cross1+cross2) << 32 + flo*glo
+	f.mant = fhi*ghi + (cross1 >> 32) + (cross2 >> 32)
+	rem := uint64(uint32(cross1)) + uint64(uint32(cross2)) + ((flo * glo) >> 32)
+	// Round up.
+	rem += (1 << 31)
+
+	f.mant += (rem >> 32)
+	f.exp = f.exp + g.exp + 64
+}
+
+var uint64pow10 = [...]uint64{
+	1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+	1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+}
+
+// AssignDecimal sets f to an approximate value mantissa*10^exp. It
+// reports whether the value represented by f is guaranteed to be the
+// best approximation of d after being rounded to a float64 or
+// float32 depending on flt.
+func (f *extFloat) AssignDecimal(mantissa uint64, exp10 int, neg bool, trunc bool, flt *floatInfo) (ok bool) {
+	const uint64digits = 19
+	const errorscale = 8
+	errors := 0 // An upper bound for error, computed in errorscale*ulp.
+	if trunc {
+		// the decimal number was truncated.
+		errors += errorscale / 2
+	}
+
+	f.mant = mantissa
+	f.exp = 0
+	f.neg = neg
+
+	// Multiply by powers of ten.
+	i := (exp10 - firstPowerOfTen) / stepPowerOfTen
+	if exp10 < firstPowerOfTen || i >= len(powersOfTen) {
+		return false
+	}
+	adjExp := (exp10 - firstPowerOfTen) % stepPowerOfTen
+
+	// We multiply by exp%step
+	if adjExp < uint64digits && mantissa < uint64pow10[uint64digits-adjExp] {
+		// We can multiply the mantissa exactly.
+		f.mant *= uint64pow10[adjExp]
+		f.Normalize()
+	} else {
+		f.Normalize()
+		f.Multiply(smallPowersOfTen[adjExp])
+		errors += errorscale / 2
+	}
+
+	// We multiply by 10 to the exp - exp%step.
+	f.Multiply(powersOfTen[i])
+	if errors > 0 {
+		errors += 1
+	}
+	errors += errorscale / 2
+
+	// Normalize
+	shift := f.Normalize()
+	errors <<= shift
+
+	// Now f is a good approximation of the decimal.
+	// Check whether the error is too large: that is, if the mantissa
+	// is perturbated by the error, the resulting float64 will change.
+	// The 64 bits mantissa is 1 + 52 bits for float64 + 11 extra bits.
+	//
+	// In many cases the approximation will be good enough.
+	denormalExp := flt.bias - 63
+	var extrabits uint
+	if f.exp <= denormalExp {
+		// f.mant * 2^f.exp is smaller than 2^(flt.bias+1).
+		extrabits = uint(63 - flt.mantbits + 1 + uint(denormalExp-f.exp))
+	} else {
+		extrabits = uint(63 - flt.mantbits)
+	}
+
+	halfway := uint64(1) << (extrabits - 1)
+	mant_extra := f.mant & (1<<extrabits - 1)
+
+	// Do a signed comparison here! If the error estimate could make
+	// the mantissa round differently for the conversion to double,
+	// then we can't give a definite answer.
+	if int64(halfway)-int64(errors) < int64(mant_extra) &&
+		int64(mant_extra) < int64(halfway)+int64(errors) {
+		return false
+	}
+	return true
+}
+
+// Frexp10 is an analogue of math.Frexp for decimal powers. It scales
+// f by an approximate power of ten 10^-exp, and returns exp10, so
+// that f*10^exp10 has the same value as the old f, up to an ulp,
+// as well as the index of 10^-exp in the powersOfTen table.
+func (f *extFloat) frexp10() (exp10, index int) {
+	// The constants expMin and expMax constrain the final value of the
+	// binary exponent of f. We want a small integral part in the result
+	// because finding digits of an integer requires divisions, whereas
+	// digits of the fractional part can be found by repeatedly multiplying
+	// by 10.
+	const expMin = -60
+	const expMax = -32
+	// Find power of ten such that x * 10^n has a binary exponent
+	// between expMin and expMax.
+	approxExp10 := ((expMin+expMax)/2 - f.exp) * 28 / 93 // log(10)/log(2) is close to 93/28.
+	i := (approxExp10 - firstPowerOfTen) / stepPowerOfTen
+Loop:
+	for {
+		exp := f.exp + powersOfTen[i].exp + 64
+		switch {
+		case exp < expMin:
+			i++
+		case exp > expMax:
+			i--
+		default:
+			break Loop
+		}
+	}
+	// Apply the desired decimal shift on f. It will have exponent
+	// in the desired range. This is multiplication by 10^-exp10.
+	f.Multiply(powersOfTen[i])
+
+	return -(firstPowerOfTen + i*stepPowerOfTen), i
+}
+
+// frexp10Many applies a common shift by a power of ten to a, b, c.
+func frexp10Many(a, b, c *extFloat) (exp10 int) {
+	exp10, i := c.frexp10()
+	a.Multiply(powersOfTen[i])
+	b.Multiply(powersOfTen[i])
+	return
+}
+
+// FixedDecimal stores in d the first n significant digits
+// of the decimal representation of f. It returns false
+// if it cannot be sure of the answer.
+func (f *extFloat) FixedDecimal(d *decimalSlice, n int) bool {
+	if f.mant == 0 {
+		d.nd = 0
+		d.dp = 0
+		d.neg = f.neg
+		return true
+	}
+	if n == 0 {
+		panic("strconv: internal error: extFloat.FixedDecimal called with n == 0")
+	}
+	// Multiply by an appropriate power of ten to have a reasonable
+	// number to process.
+	f.Normalize()
+	exp10, _ := f.frexp10()
+
+	shift := uint(-f.exp)
+	integer := uint32(f.mant >> shift)
+	fraction := f.mant - (uint64(integer) << shift)
+	ε := uint64(1) // ε is the uncertainty we have on the mantissa of f.
+
+	// Write exactly n digits to d.
+	needed := n        // how many digits are left to write.
+	integerDigits := 0 // the number of decimal digits of integer.
+	pow10 := uint64(1) // the power of ten by which f was scaled.
+	for i, pow := 0, uint64(1); i < 20; i++ {
+		if pow > uint64(integer) {
+			integerDigits = i
+			break
+		}
+		pow *= 10
+	}
+	rest := integer
+	if integerDigits > needed {
+		// the integral part is already large, trim the last digits.
+		pow10 = uint64pow10[integerDigits-needed]
+		integer /= uint32(pow10)
+		rest -= integer * uint32(pow10)
+	} else {
+		rest = 0
+	}
+
+	// Write the digits of integer: the digits of rest are omitted.
+	var buf [32]byte
+	pos := len(buf)
+	for v := integer; v > 0; {
+		v1 := v / 10
+		v -= 10 * v1
+		pos--
+		buf[pos] = byte(v + '0')
+		v = v1
+	}
+	for i := pos; i < len(buf); i++ {
+		d.d[i-pos] = buf[i]
+	}
+	nd := len(buf) - pos
+	d.nd = nd
+	d.dp = integerDigits + exp10
+	needed -= nd
+
+	if needed > 0 {
+		if rest != 0 || pow10 != 1 {
+			panic("strconv: internal error, rest != 0 but needed > 0")
+		}
+		// Emit digits for the fractional part. Each time, 10*fraction
+		// fits in a uint64 without overflow.
+		for needed > 0 {
+			fraction *= 10
+			ε *= 10 // the uncertainty scales as we multiply by ten.
+			if 2*ε > 1<<shift {
+				// the error is so large it could modify which digit to write, abort.
+				return false
+			}
+			digit := fraction >> shift
+			d.d[nd] = byte(digit + '0')
+			fraction -= digit << shift
+			nd++
+			needed--
+		}
+		d.nd = nd
+	}
+
+	// We have written a truncation of f (a numerator / 10^d.dp). The remaining part
+	// can be interpreted as a small number (< 1) to be added to the last digit of the
+	// numerator.
+	//
+	// If rest > 0, the amount is:
+	//    (rest<<shift | fraction) / (pow10 << shift)
+	//    fraction being known with a ±ε uncertainty.
+	//    The fact that n > 0 guarantees that pow10 << shift does not overflow a uint64.
+	//
+	// If rest = 0, pow10 == 1 and the amount is
+	//    fraction / (1 << shift)
+	//    fraction being known with a ±ε uncertainty.
+	//
+	// We pass this information to the rounding routine for adjustment.
+
+	ok := adjustLastDigitFixed(d, uint64(rest)<<shift|fraction, pow10, shift, ε)
+	if !ok {
+		return false
+	}
+	// Trim trailing zeros.
+	for i := d.nd - 1; i >= 0; i-- {
+		if d.d[i] != '0' {
+			d.nd = i + 1
+			break
+		}
+	}
+	return true
+}
+
+// adjustLastDigitFixed assumes d contains the representation of the integral part
+// of some number, whose fractional part is num / (den << shift). The numerator
+// num is only known up to an uncertainty of size ε, assumed to be less than
+// (den << shift)/2.
+//
+// It will increase the last digit by one to account for correct rounding, typically
+// when the fractional part is greater than 1/2, and will return false if ε is such
+// that no correct answer can be given.
+func adjustLastDigitFixed(d *decimalSlice, num, den uint64, shift uint, ε uint64) bool {
+	if num > den<<shift {
+		panic("strconv: num > den<<shift in adjustLastDigitFixed")
+	}
+	if 2*ε > den<<shift {
+		panic("strconv: ε > (den<<shift)/2")
+	}
+	if 2*(num+ε) < den<<shift {
+		return true
+	}
+	if 2*(num-ε) > den<<shift {
+		// increment d by 1.
+		i := d.nd - 1
+		for ; i >= 0; i-- {
+			if d.d[i] == '9' {
+				d.nd--
+			} else {
+				break
+			}
+		}
+		if i < 0 {
+			d.d[0] = '1'
+			d.nd = 1
+			d.dp++
+		} else {
+			d.d[i]++
+		}
+		return true
+	}
+	return false
+}
+
+// ShortestDecimal stores in d the shortest decimal representation of f
+// which belongs to the open interval (lower, upper), where f is supposed
+// to lie. It returns false whenever the result is unsure. The implementation
+// uses the Grisu3 algorithm.
+func (f *extFloat) ShortestDecimal(d *decimalSlice, lower, upper *extFloat) bool {
+	if f.mant == 0 {
+		d.nd = 0
+		d.dp = 0
+		d.neg = f.neg
+		return true
+	}
+	if f.exp == 0 && *lower == *f && *lower == *upper {
+		// an exact integer.
+		var buf [24]byte
+		n := len(buf) - 1
+		for v := f.mant; v > 0; {
+			v1 := v / 10
+			v -= 10 * v1
+			buf[n] = byte(v + '0')
+			n--
+			v = v1
+		}
+		nd := len(buf) - n - 1
+		for i := 0; i < nd; i++ {
+			d.d[i] = buf[n+1+i]
+		}
+		d.nd, d.dp = nd, nd
+		for d.nd > 0 && d.d[d.nd-1] == '0' {
+			d.nd--
+		}
+		if d.nd == 0 {
+			d.dp = 0
+		}
+		d.neg = f.neg
+		return true
+	}
+	upper.Normalize()
+	// Uniformize exponents.
+	if f.exp > upper.exp {
+		f.mant <<= uint(f.exp - upper.exp)
+		f.exp = upper.exp
+	}
+	if lower.exp > upper.exp {
+		lower.mant <<= uint(lower.exp - upper.exp)
+		lower.exp = upper.exp
+	}
+
+	exp10 := frexp10Many(lower, f, upper)
+	// Take a safety margin due to rounding in frexp10Many, but we lose precision.
+	upper.mant++
+	lower.mant--
+
+	// The shortest representation of f is either rounded up or down, but
+	// in any case, it is a truncation of upper.
+	shift := uint(-upper.exp)
+	integer := uint32(upper.mant >> shift)
+	fraction := upper.mant - (uint64(integer) << shift)
+
+	// How far we can go down from upper until the result is wrong.
+	allowance := upper.mant - lower.mant
+	// How far we should go to get a very precise result.
+	targetDiff := upper.mant - f.mant
+
+	// Count integral digits: there are at most 10.
+	var integerDigits int
+	for i, pow := 0, uint64(1); i < 20; i++ {
+		if pow > uint64(integer) {
+			integerDigits = i
+			break
+		}
+		pow *= 10
+	}
+	for i := 0; i < integerDigits; i++ {
+		pow := uint64pow10[integerDigits-i-1]
+		digit := integer / uint32(pow)
+		d.d[i] = byte(digit + '0')
+		integer -= digit * uint32(pow)
+		// evaluate whether we should stop.
+		if currentDiff := uint64(integer)<<shift + fraction; currentDiff < allowance {
+			d.nd = i + 1
+			d.dp = integerDigits + exp10
+			d.neg = f.neg
+			// Sometimes allowance is so large the last digit might need to be
+			// decremented to get closer to f.
+			return adjustLastDigit(d, currentDiff, targetDiff, allowance, pow<<shift, 2)
+		}
+	}
+	d.nd = integerDigits
+	d.dp = d.nd + exp10
+	d.neg = f.neg
+
+	// Compute digits of the fractional part. At each step fraction does not
+	// overflow. The choice of minExp implies that fraction is less than 2^60.
+	var digit int
+	multiplier := uint64(1)
+	for {
+		fraction *= 10
+		multiplier *= 10
+		digit = int(fraction >> shift)
+		d.d[d.nd] = byte(digit + '0')
+		d.nd++
+		fraction -= uint64(digit) << shift
+		if fraction < allowance*multiplier {
+			// We are in the admissible range. Note that if allowance is about to
+			// overflow, that is, allowance > 2^64/10, the condition is automatically
+			// true due to the limited range of fraction.
+			return adjustLastDigit(d,
+				fraction, targetDiff*multiplier, allowance*multiplier,
+				1<<shift, multiplier*2)
+		}
+	}
+}
+
+// adjustLastDigit modifies d = x-currentDiff*ε, to get closest to
+// d = x-targetDiff*ε, without becoming smaller than x-maxDiff*ε.
+// It assumes that a decimal digit is worth ulpDecimal*ε, and that
+// all data is known with a error estimate of ulpBinary*ε.
+func adjustLastDigit(d *decimalSlice, currentDiff, targetDiff, maxDiff, ulpDecimal, ulpBinary uint64) bool {
+	if ulpDecimal < 2*ulpBinary {
+		// Approximation is too wide.
+		return false
+	}
+	for currentDiff+ulpDecimal/2+ulpBinary < targetDiff {
+		d.d[d.nd-1]--
+		currentDiff += ulpDecimal
+	}
+	if currentDiff+ulpDecimal <= targetDiff+ulpDecimal/2+ulpBinary {
+		// we have two choices, and don't know what to do.
+		return false
+	}
+	if currentDiff < ulpBinary || currentDiff > maxDiff-ulpBinary {
+		// we went too far
+		return false
+	}
+	if d.nd == 1 && d.d[0] == '0' {
+		// the number has actually reached zero.
+		d.nd = 0
+		d.dp = 0
+	}
+	return true
+}

+ 278 - 0
vendor/github.com/CloudyKit/fastprinter/float.go

@@ -0,0 +1,278 @@
+// MIT License
+//
+// Copyright (c) 2017 José Santos <henrique_1609@me.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.
+
+package fastprinter
+
+import (
+	"io"
+	"math"
+)
+
+type floatInfo struct {
+	mantbits uint
+	expbits  uint
+	bias     int
+}
+
+var (
+	float64info      = floatInfo{52, 11, -1023}
+	floatNaN         = []byte("Nan")
+	floatNinf        = []byte("-Inf")
+	floatPinf        = []byte("+Inf")
+	pool_floatBuffer = newByteSliceBufferPool(800)
+)
+
+func PrintFloat(w io.Writer, f float64) (int, error) {
+	return PrintFloatPrecision(w, f, -1)
+}
+
+func PrintFloatPrecision(dst io.Writer, val float64, prec int) (int, error) {
+	var bits uint64
+	var flt *floatInfo
+
+	bits = math.Float64bits(val)
+	flt = &float64info
+
+	neg := bits>>(flt.expbits+flt.mantbits) != 0
+	exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
+	mant := bits & (uint64(1)<<flt.mantbits - 1)
+
+	switch exp {
+	case 1<<flt.expbits - 1:
+		switch {
+		case mant != 0:
+			return dst.Write(floatNaN)
+		case neg:
+			return dst.Write(floatNinf)
+		default:
+			return dst.Write(floatPinf)
+		}
+	case 0:
+		// denormalized
+		exp++
+	default:
+		// add implicit top bit
+		mant |= uint64(1) << flt.mantbits
+	}
+
+	exp += flt.bias
+	var digs decimalSlice
+	ok := false
+
+	// Negative precision means "only as much as needed to be exact."
+	shortest := prec < 0
+	if shortest {
+		// Try Grisu3 algorithm.
+		f := new(extFloat)
+		lower, upper := f.AssignComputeBounds(mant, exp, neg, flt)
+		var buf [32]byte
+		digs.d = buf[:]
+		ok = f.ShortestDecimal(&digs, &lower, &upper)
+		if !ok {
+			return bigFtoa(dst, prec, neg, mant, exp, flt)
+		}
+		// Precision for shortest representation mode.
+		prec = max(digs.nd-digs.dp, 0)
+	}
+	if !ok {
+		return bigFtoa(dst, prec, neg, mant, exp, flt)
+	}
+	return fmtF(dst, neg, digs, prec)
+}
+
+// bigFtoa uses multiprecision computations to format a float.
+func bigFtoa(dst io.Writer, prec int, neg bool, mant uint64, exp int, flt *floatInfo) (int, error) {
+	d := new(decimal)
+	d.Assign(mant)
+	d.Shift(exp - int(flt.mantbits))
+	var digs decimalSlice
+	shortest := prec < 0
+	if shortest {
+		roundShortest(d, mant, exp, flt)
+		digs = decimalSlice{d: d.d[:], nd: d.nd, dp: d.dp}
+		prec = max(digs.nd-digs.dp, 0)
+	} else {
+		d.Round(d.dp + prec)
+		digs = decimalSlice{d: d.d[:], nd: d.nd, dp: d.dp}
+	}
+	return fmtF(dst, neg, digs, prec)
+}
+
+// roundShortest rounds d (= mant * 2^exp) to the shortest number of digits
+// that will let the original floating point value be precisely reconstructed.
+func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
+	// If mantissa is zero, the number is zero; stop now.
+	if mant == 0 {
+		d.nd = 0
+		return
+	}
+
+	// Compute upper and lower such that any decimal number
+	// between upper and lower (possibly inclusive)
+	// will round to the original floating point number.
+
+	// We may see at once that the number is already shortest.
+	//
+	// Suppose d is not denormal, so that 2^exp <= d < 10^dp.
+	// The closest shorter number is at least 10^(dp-nd) away.
+	// The lower/upper bounds computed below are at distance
+	// at most 2^(exp-mantbits).
+	//
+	// So the number is already shortest if 10^(dp-nd) > 2^(exp-mantbits),
+	// or equivalently log2(10)*(dp-nd) > exp-mantbits.
+	// It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32).
+	minexp := flt.bias + 1 // minimum possible exponent
+	if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) {
+		// The number is already shortest.
+		return
+	}
+
+	// d = mant << (exp - mantbits)
+	// Next highest floating point number is mant+1 << exp-mantbits.
+	// Our upper bound is halfway between, mant*2+1 << exp-mantbits-1.
+	upper := new(decimal)
+	upper.Assign(mant*2 + 1)
+	upper.Shift(exp - int(flt.mantbits) - 1)
+
+	// d = mant << (exp - mantbits)
+	// Next lowest floating point number is mant-1 << exp-mantbits,
+	// unless mant-1 drops the significant bit and exp is not the minimum exp,
+	// in which case the next lowest is mant*2-1 << exp-mantbits-1.
+	// Either way, call it mantlo << explo-mantbits.
+	// Our lower bound is halfway between, mantlo*2+1 << explo-mantbits-1.
+	var mantlo uint64
+	var explo int
+	if mant > 1<<flt.mantbits || exp == minexp {
+		mantlo = mant - 1
+		explo = exp
+	} else {
+		mantlo = mant*2 - 1
+		explo = exp - 1
+	}
+	lower := new(decimal)
+	lower.Assign(mantlo*2 + 1)
+	lower.Shift(explo - int(flt.mantbits) - 1)
+
+	// The upper and lower bounds are possible outputs only if
+	// the original mantissa is even, so that IEEE round-to-even
+	// would round to the original mantissa and not the neighbors.
+	inclusive := mant%2 == 0
+
+	// Now we can figure out the minimum number of digits required.
+	// Walk along until d has distinguished itself from upper and lower.
+	for i := 0; i < d.nd; i++ {
+		l := byte('0') // lower digit
+		if i < lower.nd {
+			l = lower.d[i]
+		}
+		m := d.d[i]    // middle digit
+		u := byte('0') // upper digit
+		if i < upper.nd {
+			u = upper.d[i]
+		}
+
+		// Okay to round down (truncate) if lower has a different digit
+		// or if lower is inclusive and is exactly the result of rounding
+		// down (i.e., and we have reached the final digit of lower).
+		okdown := l != m || inclusive && i+1 == lower.nd
+
+		// Okay to round up if upper has a different digit and either upper
+		// is inclusive or upper is bigger than the result of rounding up.
+		okup := m != u && (inclusive || m+1 < u || i+1 < upper.nd)
+
+		// If it's okay to do either, then round to the nearest one.
+		// If it's okay to do only one, do it.
+		switch {
+		case okdown && okup:
+			d.Round(i + 1)
+			return
+		case okdown:
+			d.RoundDown(i + 1)
+			return
+		case okup:
+			d.RoundUp(i + 1)
+			return
+		}
+	}
+}
+
+type decimalSlice struct {
+	d      []byte
+	nd, dp int
+	neg    bool
+}
+
+// %f: -ddddddd.ddddd
+func fmtF(dst io.Writer, neg bool, d decimalSlice, prec int) (n int, err error) {
+	a := pool_floatBuffer.Get().(*byteSliceBuffer)
+	i := 0
+
+	// sign
+	if neg {
+		a.bytes[i] = '-'
+		i++
+	}
+	// integer, padded with zeros as needed.
+	if d.dp > 0 {
+		m := min(d.nd, d.dp)
+		copy(a.bytes[i:], d.d[:m])
+		i += m
+		for ; m < d.dp; m++ {
+			a.bytes[i] = '0'
+			i++
+		}
+	} else {
+		a.bytes[i] = '0'
+		i++
+	}
+
+	// fraction
+	if prec > 0 {
+		a.bytes[i] = '.'
+		i++
+		for j := 0; j < prec; j++ {
+			ch := byte('0')
+			if j := d.dp + j; 0 <= j && j < d.nd {
+				ch = d.d[j]
+			}
+			a.bytes[i] = ch
+			i++
+		}
+	}
+	n, err = dst.Write(a.bytes[0:i])
+	pool_floatBuffer.Put(a)
+	return
+}
+
+func min(a, b int) int {
+	if a < b {
+		return a
+	}
+	return b
+}
+
+func max(a, b int) int {
+	if a > b {
+		return a
+	}
+	return b
+}

+ 225 - 0
vendor/github.com/CloudyKit/fastprinter/printers.go

@@ -0,0 +1,225 @@
+// MIT License
+//
+// Copyright (c) 2017 José Santos <henrique_1609@me.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.
+
+package fastprinter
+
+import (
+	"fmt"
+	"io"
+	"reflect"
+	"sync"
+)
+
+const (
+	stringBufferSize  = 4096
+	integerBufferSize = 20
+)
+
+var (
+	_trueBytes  = ([]byte)("true")
+	_falseBytes = ([]byte)("false")
+
+	pool_integerBuffer = newByteSliceBufferPool(integerBufferSize)
+	pool_stringBuffer  = newByteSliceBufferPool(stringBufferSize)
+
+	errorType       = reflect.TypeOf((*error)(nil)).Elem()
+	fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
+)
+
+type byteSliceBuffer struct {
+	bytes []byte
+}
+
+func newByteSliceBufferPool(size int) sync.Pool {
+	return sync.Pool{
+		New: func() interface{} {
+			return &byteSliceBuffer{make([]byte, size, size)}
+		},
+	}
+}
+
+func Print(w io.Writer, i interface{}) (int, error) {
+	return PrintValue(w, reflect.ValueOf(i))
+}
+
+func PrintPtr(w io.Writer, i interface{}) (int, error) {
+	return PrintValue(w, reflect.ValueOf(i).Elem())
+}
+
+func PrintBool(w io.Writer, b bool) (int, error) {
+	if b {
+		return w.Write(_trueBytes)
+	}
+	return w.Write(_falseBytes)
+}
+
+func PrintString(ww io.Writer, st string) (c int, err error) {
+	if st == "" {
+		return 0, nil
+	}
+
+	numI := len(st) / stringBufferSize
+	nextBucket := 0
+	written := 0
+
+	a := pool_stringBuffer.Get().(*byteSliceBuffer)
+	for i := 0; i < numI; i++ {
+		copy(a.bytes[:], st[nextBucket:nextBucket+stringBufferSize])
+		nextBucket += stringBufferSize
+		written, err = ww.Write(a.bytes[:])
+		c += written
+		if err != nil {
+			return
+		}
+	}
+
+	smallBucket := len(st) % stringBufferSize
+	if smallBucket > 0 {
+		copy(a.bytes[:], st[nextBucket:])
+		written, err = ww.Write(a.bytes[:smallBucket])
+		c += written
+	}
+	pool_stringBuffer.Put(a)
+	return
+}
+
+func PrintUint(w io.Writer, i uint64) (int, error) {
+	return formatBits(w, i, false)
+}
+
+func PrintInt(w io.Writer, i int64) (int, error) {
+	return formatBits(w, uint64(i), i < 0)
+}
+
+// formatBits computes the string representation of u in the given base.
+// If neg is set, u is treated as negative int64 value.
+// Extracted from std package strconv
+func formatBits(dst io.Writer, u uint64, neg bool) (int, error) {
+
+	var a = pool_integerBuffer.Get().(*byteSliceBuffer)
+
+	i := integerBufferSize
+
+	if neg {
+		u = -u
+	}
+
+	// common case: use constants for / because
+	// the compiler can optimize it into a multiply+shift
+
+	if ^uintptr(0)>>32 == 0 {
+		for u > uint64(^uintptr(0)) {
+			q := u / 1e9
+			us := uintptr(u - q*1e9) // us % 1e9 fits into a uintptr
+			for j := 9; j > 0; j-- {
+				i--
+				qs := us / 10
+				a.bytes[i] = byte(us - qs*10 + '0')
+				us = qs
+			}
+			u = q
+		}
+	}
+
+	// u guaranteed to fit into a uintptr
+	us := uintptr(u)
+	for us >= 10 {
+		i--
+		q := us / 10
+		a.bytes[i] = byte(us - q*10 + '0')
+		us = q
+	}
+	// u < 10
+	i--
+	a.bytes[i] = byte(us + '0')
+
+	// add sign, if any
+	if neg {
+		i--
+		a.bytes[i] = '-'
+	}
+	counter, err := dst.Write(a.bytes[i:])
+	pool_integerBuffer.Put(a)
+	return counter, err
+}
+
+// PrintValue prints a reflect.Value
+func PrintValue(w io.Writer, v reflect.Value) (int, error) {
+	v = maybeDereference(v, 2)
+
+	if v.Type().Implements(fmtStringerType) {
+		return PrintString(w, v.Interface().(fmt.Stringer).String())
+	}
+
+	if v.Type().Implements(errorType) {
+		return PrintString(w, v.Interface().(error).Error())
+	}
+
+	k := v.Kind()
+
+	if k == reflect.String {
+		return PrintString(w, v.String())
+	}
+
+	if k >= reflect.Int && k <= reflect.Int64 {
+		return PrintInt(w, v.Int())
+	}
+
+	if k >= reflect.Uint && k <= reflect.Uint64 {
+		return PrintUint(w, v.Uint())
+	}
+
+	if k == reflect.Float64 || k == reflect.Float32 {
+		return PrintFloat(w, v.Float())
+	}
+
+	if k == reflect.Bool {
+		return PrintBool(w, v.Bool())
+	}
+
+	if k == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 {
+		return w.Write(v.Bytes())
+	}
+
+	return fmt.Fprint(w, v.Interface())
+}
+
+// dereference a certain depth of pointer indirection
+func maybeDereference(v reflect.Value, depth int) reflect.Value {
+	if depth <= 0 {
+		return v
+	}
+
+	if !v.IsValid() {
+		return v
+	}
+
+	if v.Kind() != reflect.Ptr || v.IsNil() {
+		return v
+	}
+
+	if v.Type().Implements(fmtStringerType) || v.Type().Implements(errorType) {
+		return v
+	}
+
+	return maybeDereference(reflect.Indirect(v), depth-1)
+}

+ 2 - 0
vendor/github.com/CloudyKit/jet/v4/.gitignore

@@ -0,0 +1,2 @@
+.DS_Store
+.idea

+ 8 - 0
vendor/github.com/CloudyKit/jet/v4/.travis.yml

@@ -0,0 +1,8 @@
+language: go
+go:
+ - "1.13.x"
+ - "1.14.x"
+ - "tip"
+
+script:
+ - env GO111MODULE=on go test -v ./...

+ 0 - 0
vendor/github.com/gavv/monotime/LICENSE → vendor/github.com/CloudyKit/jet/v4/LICENSE


+ 46 - 0
vendor/github.com/CloudyKit/jet/v4/README.md

@@ -0,0 +1,46 @@
+# Jet Template Engine for Go
+
+[![Build Status](https://travis-ci.org/CloudyKit/jet.svg?branch=master)](https://travis-ci.org/CloudyKit/jet) [![Build status](https://ci.appveyor.com/api/projects/status/5g4whw3c6518vvku?svg=true)](https://ci.appveyor.com/project/CloudyKit/jet) [![Join the chat at https://gitter.im/CloudyKit/jet](https://badges.gitter.im/CloudyKit/jet.svg)](https://gitter.im/CloudyKit/jet)
+
+Jet is a template engine developed to be easy to use, powerful, dynamic, yet secure and very fast.
+
+* simple and familiar syntax
+* supports template inheritance (`extends`) and composition (`block`/`yield`, `import`, `include`)
+* descriptive error messages with filename and line number
+* auto-escaping
+* simple C-like expressions
+* very fast execution – Jet can execute templates faster than some pre-compiled template engines
+* very light in terms of allocations and memory footprint
+
+## v4
+
+Version 4 brings a lot of bug fixes and improvements as well as [updated documentation](./docs/index.md), but make sure to read through the [breaking changes](./docs/changes.md) before making the jump.
+
+## Docs
+
+- [Syntax Reference](./docs/syntax.md)
+- [Built-ins](./docs/builtins.md)
+- [Wiki](https://github.com/CloudyKit/jet/wiki) (some things are out of date)
+
+## Example application
+
+An example application is available in the repository. Use `go get -u github.com/CloudyKit/jet` or clone the repository into `$GOPATH/github.com/CloudyKit/jet`, then do:
+```
+  $ cd examples/todos; go run main.go
+```
+
+## IntelliJ Plugin
+
+If you use IntelliJ there is a plugin available at https://github.com/jhsx/GoJetPlugin.
+There is also a very good Go plugin for IntelliJ – see https://github.com/go-lang-plugin-org/go-lang-idea-plugin.
+GoJetPlugin + Go-lang-idea-plugin = happiness!
+
+## Contributing
+
+All contributions are welcome – if you find a bug please report it.
+
+## Contributors
+
+- José Santos (@jhsx)
+- Daniel Lohse (@annismckenzie)
+- Alexander Willing (@sauerbraten)

+ 34 - 0
vendor/github.com/CloudyKit/jet/v4/appveyor.yml

@@ -0,0 +1,34 @@
+version: "{build}"
+
+os: Windows Server 2012 R2
+
+# scripts that are called at very beginning, before repo cloning
+init:
+  - git config --global core.autocrlf true
+
+clone_folder: c:\gopath\src\github.com\CloudyKit\jet
+
+environment:
+  GOPATH: c:\gopath
+  GO111MODULE: on
+  matrix:
+    - GOVERSION: 113
+
+install:
+  - set PATH=%GOPATH%\bin;c:\go%GOVERSION%\bin;%PATH%
+  - set GOROOT=c:\go%GOVERSION%
+  - echo %PATH%
+  - echo %GOPATH%
+  - go version
+  - go env
+
+build: off
+
+test_script:
+  - go test -v ./...
+  - cd examples/asset_packaging/
+  - go run main.go --run-and-exit
+  - go get -u github.com/shurcooL/vfsgen
+  - go generate
+  - go build -tags=deploy_build -o bin/app.exe main.go
+  - .\bin\app.exe --run-and-exit

+ 240 - 0
vendor/github.com/CloudyKit/jet/v4/constructors.go

@@ -0,0 +1,240 @@
+// Copyright 2016 José Santos <henrique_1609@me.com>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+func (t *Template) newSliceExpr(pos Pos, line int, base, index, endIndex Expression) *SliceExprNode {
+	return &SliceExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeSliceExpr, Pos: pos, Line: line}, Index: index, Base: base, EndIndex: endIndex}
+}
+
+func (t *Template) newIndexExpr(pos Pos, line int, base, index Expression) *IndexExprNode {
+	return &IndexExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeIndexExpr, Pos: pos, Line: line}, Index: index, Base: base}
+}
+
+func (t *Template) newTernaryExpr(pos Pos, line int, boolean, left, right Expression) *TernaryExprNode {
+	return &TernaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeTernaryExpr, Pos: pos, Line: line}, Boolean: boolean, Left: left, Right: right}
+}
+
+func (t *Template) newSet(pos Pos, line int, isLet, isIndexExprGetLookup bool, left, right []Expression) *SetNode {
+	return &SetNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeSet, Pos: pos, Line: line}, Let: isLet, IndexExprGetLookup: isIndexExprGetLookup, Left: left, Right: right}
+}
+
+func (t *Template) newCallExpr(pos Pos, line int, expr Expression) *CallExprNode {
+	return &CallExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeCallExpr, Pos: pos, Line: line}, BaseExpr: expr}
+}
+func (t *Template) newNotExpr(pos Pos, line int, expr Expression) *NotExprNode {
+	return &NotExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeNotExpr, Pos: pos, Line: line}, Expr: expr}
+}
+func (t *Template) newNumericComparativeExpr(pos Pos, line int, left, right Expression, item item) *NumericComparativeExprNode {
+	return &NumericComparativeExprNode{binaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeNumericComparativeExpr, Pos: pos, Line: line}, Operator: item, Left: left, Right: right}}
+}
+
+func (t *Template) newComparativeExpr(pos Pos, line int, left, right Expression, item item) *ComparativeExprNode {
+	return &ComparativeExprNode{binaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeComparativeExpr, Pos: pos, Line: line}, Operator: item, Left: left, Right: right}}
+}
+
+func (t *Template) newLogicalExpr(pos Pos, line int, left, right Expression, item item) *LogicalExprNode {
+	return &LogicalExprNode{binaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeLogicalExpr, Pos: pos, Line: line}, Operator: item, Left: left, Right: right}}
+}
+
+func (t *Template) newMultiplicativeExpr(pos Pos, line int, left, right Expression, item item) *MultiplicativeExprNode {
+	return &MultiplicativeExprNode{binaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeMultiplicativeExpr, Pos: pos, Line: line}, Operator: item, Left: left, Right: right}}
+}
+
+func (t *Template) newAdditiveExpr(pos Pos, line int, left, right Expression, item item) *AdditiveExprNode {
+	return &AdditiveExprNode{binaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeAdditiveExpr, Pos: pos, Line: line}, Operator: item, Left: left, Right: right}}
+}
+
+func (t *Template) newList(pos Pos) *ListNode {
+	return &ListNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeList, Pos: pos}}
+}
+
+func (t *Template) newText(pos Pos, text string) *TextNode {
+	return &TextNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeText, Pos: pos}, Text: []byte(text)}
+}
+
+func (t *Template) newPipeline(pos Pos, line int) *PipeNode {
+	return &PipeNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodePipe, Pos: pos, Line: line}}
+}
+
+func (t *Template) newAction(pos Pos, line int) *ActionNode {
+	return &ActionNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeAction, Pos: pos, Line: line}}
+}
+
+func (t *Template) newCommand(pos Pos) *CommandNode {
+	return &CommandNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeCommand, Pos: pos}}
+}
+
+func (t *Template) newNil(pos Pos) *NilNode {
+	return &NilNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeNil, Pos: pos}}
+}
+
+func (t *Template) newField(pos Pos, ident string) *FieldNode {
+	return &FieldNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeField, Pos: pos}, Ident: strings.Split(ident[1:], ".")} //[1:] to drop leading period
+}
+
+func (t *Template) newChain(pos Pos, node Node) *ChainNode {
+	return &ChainNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeChain, Pos: pos}, Node: node}
+}
+
+func (t *Template) newBool(pos Pos, true bool) *BoolNode {
+	return &BoolNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeBool, Pos: pos}, True: true}
+}
+
+func (t *Template) newString(pos Pos, orig, text string) *StringNode {
+	return &StringNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeString, Pos: pos}, Quoted: orig, Text: text}
+}
+
+func (t *Template) newEnd(pos Pos) *endNode {
+	return &endNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: nodeEnd, Pos: pos}}
+}
+
+func (t *Template) newContent(pos Pos) *contentNode {
+	return &contentNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: nodeContent, Pos: pos}}
+}
+
+func (t *Template) newElse(pos Pos, line int) *elseNode {
+	return &elseNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: nodeElse, Pos: pos, Line: line}}
+}
+
+func (t *Template) newIf(pos Pos, line int, set *SetNode, pipe Expression, list, elseList *ListNode) *IfNode {
+	return &IfNode{BranchNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeIf, Pos: pos, Line: line}, Set: set, Expression: pipe, List: list, ElseList: elseList}}
+}
+
+func (t *Template) newRange(pos Pos, line int, set *SetNode, pipe Expression, list, elseList *ListNode) *RangeNode {
+	return &RangeNode{BranchNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeRange, Pos: pos, Line: line}, Set: set, Expression: pipe, List: list, ElseList: elseList}}
+}
+
+func (t *Template) newBlock(pos Pos, line int, name string, parameters *BlockParameterList, pipe Expression, listNode, contentListNode *ListNode) *BlockNode {
+	return &BlockNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeBlock, Line: line, Pos: pos}, Name: name, Parameters: parameters, Expression: pipe, List: listNode, Content: contentListNode}
+}
+
+func (t *Template) newYield(pos Pos, line int, name string, bplist *BlockParameterList, pipe Expression, content *ListNode, isContent bool) *YieldNode {
+	return &YieldNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeYield, Pos: pos, Line: line}, Name: name, Parameters: bplist, Expression: pipe, Content: content, IsContent: isContent}
+}
+
+func (t *Template) newInclude(pos Pos, line int, name, context Expression) *IncludeNode {
+	return &IncludeNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeInclude, Pos: pos, Line: line}, Name: name, Context: context}
+}
+
+func (t *Template) newReturn(pos Pos, line int, pipe Expression) *ReturnNode {
+	return &ReturnNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeReturn, Pos: pos, Line: line}, Value: pipe}
+}
+
+func (t *Template) newTry(pos Pos, line int, list *ListNode, catch *catchNode) *TryNode {
+	return &TryNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeTry, Pos: pos, Line: line}, List: list, Catch: catch}
+}
+
+func (t *Template) newCatch(pos Pos, line int, errVar *IdentifierNode, list *ListNode) *catchNode {
+	return &catchNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: nodeCatch, Pos: pos, Line: line}, Err: errVar, List: list}
+}
+
+func (t *Template) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error) {
+	n := &NumberNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeNumber, Pos: pos}, Text: text}
+	// todo: optimize
+	switch typ {
+	case itemCharConstant:
+		_rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
+		if err != nil {
+			return nil, err
+		}
+		if tail != "'" {
+			return nil, fmt.Errorf("malformed character constant: %s", text)
+		}
+		n.Int64 = int64(_rune)
+		n.IsInt = true
+		n.Uint64 = uint64(_rune)
+		n.IsUint = true
+		n.Float64 = float64(_rune) //odd but those are the rules.
+		n.IsFloat = true
+		return n, nil
+	case itemComplex:
+		//fmt.Sscan can parse the pair, so let it do the work.
+		if _, err := fmt.Sscan(text, &n.Complex128); err != nil {
+			return nil, err
+		}
+		n.IsComplex = true
+		n.simplifyComplex()
+		return n, nil
+	}
+	//Imaginary constants can only be complex unless they are zero.
+	if len(text) > 0 && text[len(text)-1] == 'i' {
+		f, err := strconv.ParseFloat(text[:len(text)-1], 64)
+		if err == nil {
+			n.IsComplex = true
+			n.Complex128 = complex(0, f)
+			n.simplifyComplex()
+			return n, nil
+		}
+	}
+	// Do integer test first so we get 0x123 etc.
+	u, err := strconv.ParseUint(text, 0, 64) // will fail for -0; fixed below.
+	if err == nil {
+		n.IsUint = true
+		n.Uint64 = u
+	}
+	i, err := strconv.ParseInt(text, 0, 64)
+	if err == nil {
+		n.IsInt = true
+		n.Int64 = i
+		if i == 0 {
+			n.IsUint = true // in case of -0.
+			n.Uint64 = u
+		}
+	}
+	// If an integer extraction succeeded, promote the float.
+	if n.IsInt {
+		n.IsFloat = true
+		n.Float64 = float64(n.Int64)
+	} else if n.IsUint {
+		n.IsFloat = true
+		n.Float64 = float64(n.Uint64)
+	} else {
+		f, err := strconv.ParseFloat(text, 64)
+		if err == nil {
+			// If we parsed it as a float but it looks like an integer,
+			// it's a huge number too large to fit in an int. Reject it.
+			if !strings.ContainsAny(text, ".eE") {
+				return nil, fmt.Errorf("integer overflow: %q", text)
+			}
+			n.IsFloat = true
+			n.Float64 = f
+			// If a floating-point extraction succeeded, extract the int if needed.
+			if !n.IsInt && float64(int64(f)) == f {
+				n.IsInt = true
+				n.Int64 = int64(f)
+			}
+			if !n.IsUint && float64(uint64(f)) == f {
+				n.IsUint = true
+				n.Uint64 = uint64(f)
+			}
+		}
+	}
+
+	if !n.IsInt && !n.IsUint && !n.IsFloat {
+		return nil, fmt.Errorf("illegal number syntax: %q", text)
+	}
+
+	return n, nil
+}
+
+func (t *Template) newIdentifier(ident string, pos Pos, line int) *IdentifierNode {
+	return &IdentifierNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeIdentifier, Pos: pos, Line: line}, Ident: ident}
+}

+ 204 - 0
vendor/github.com/CloudyKit/jet/v4/default.go

@@ -0,0 +1,204 @@
+// Copyright 2016 José Santos <henrique_1609@me.com>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+	"encoding/json"
+	"errors"
+	"html"
+	"io"
+	"io/ioutil"
+	"net/url"
+	"reflect"
+	"strings"
+	"text/template"
+)
+
+var defaultVariables map[string]reflect.Value
+
+func init() {
+	defaultVariables = map[string]reflect.Value{
+		"lower":     reflect.ValueOf(strings.ToLower),
+		"upper":     reflect.ValueOf(strings.ToUpper),
+		"hasPrefix": reflect.ValueOf(strings.HasPrefix),
+		"hasSuffix": reflect.ValueOf(strings.HasSuffix),
+		"repeat":    reflect.ValueOf(strings.Repeat),
+		"replace":   reflect.ValueOf(strings.Replace),
+		"split":     reflect.ValueOf(strings.Split),
+		"trimSpace": reflect.ValueOf(strings.TrimSpace),
+		"html":      reflect.ValueOf(html.EscapeString),
+		"url":       reflect.ValueOf(url.QueryEscape),
+		"safeHtml":  reflect.ValueOf(SafeWriter(template.HTMLEscape)),
+		"safeJs":    reflect.ValueOf(SafeWriter(template.JSEscape)),
+		"raw":       reflect.ValueOf(SafeWriter(unsafePrinter)),
+		"unsafe":    reflect.ValueOf(SafeWriter(unsafePrinter)),
+		"writeJson": reflect.ValueOf(jsonRenderer),
+		"json":      reflect.ValueOf(json.Marshal),
+		"map":       reflect.ValueOf(newMap),
+		"slice":     reflect.ValueOf(newSlice),
+		"array":     reflect.ValueOf(newSlice),
+		"isset": reflect.ValueOf(Func(func(a Arguments) reflect.Value {
+			a.RequireNumOfArguments("isset", 1, -1)
+			for i := 0; i < len(a.argExpr); i++ {
+				if !a.runtime.isSet(a.argExpr[i]) {
+					return valueBoolFALSE
+				}
+			}
+			return valueBoolTRUE
+		})),
+		"len": reflect.ValueOf(Func(func(a Arguments) reflect.Value {
+			a.RequireNumOfArguments("len", 1, 1)
+
+			expression := a.Get(0)
+			if expression.Kind() == reflect.Ptr || expression.Kind() == reflect.Interface {
+				expression = expression.Elem()
+			}
+
+			switch expression.Kind() {
+			case reflect.Array, reflect.Chan, reflect.Slice, reflect.Map, reflect.String:
+				return reflect.ValueOf(expression.Len())
+			case reflect.Struct:
+				return reflect.ValueOf(expression.NumField())
+			}
+
+			a.Panicf("len(): invalid value type %s", expression.Type())
+			return reflect.Value{}
+		})),
+		"includeIfExists": reflect.ValueOf(Func(func(a Arguments) reflect.Value {
+			a.RequireNumOfArguments("includeIfExists", 1, 2)
+			t, err := a.runtime.set.GetTemplate(a.Get(0).String())
+			// If template exists but returns an error then panic instead of failing silently
+			if t != nil && err != nil {
+				panic(err)
+			}
+			if err != nil {
+				return hiddenFalse
+			}
+
+			a.runtime.newScope()
+			defer a.runtime.releaseScope()
+
+			a.runtime.blocks = t.processedBlocks
+			root := t.Root
+			if t.extends != nil {
+				root = t.extends.Root
+			}
+
+			if a.NumOfArguments() > 1 {
+				c := a.runtime.context
+				defer func() { a.runtime.context = c }()
+				a.runtime.context = a.Get(1)
+			}
+
+			a.runtime.executeList(root)
+
+			return hiddenTrue
+		})),
+		"exec": reflect.ValueOf(Func(func(a Arguments) (result reflect.Value) {
+			a.RequireNumOfArguments("exec", 1, 2)
+			t, err := a.runtime.set.GetTemplate(a.Get(0).String())
+			if err != nil {
+				panic(err)
+			}
+
+			a.runtime.newScope()
+			defer a.runtime.releaseScope()
+
+			w := a.runtime.Writer
+			defer func() { a.runtime.Writer = w }()
+			a.runtime.Writer = ioutil.Discard
+
+			a.runtime.blocks = t.processedBlocks
+			root := t.Root
+			if t.extends != nil {
+				root = t.extends.Root
+			}
+
+			if a.NumOfArguments() > 1 {
+				c := a.runtime.context
+				defer func() { a.runtime.context = c }()
+				a.runtime.context = a.Get(1)
+			}
+			result = a.runtime.executeList(root)
+
+			return result
+		})),
+		"ints": reflect.ValueOf(Func(func(a Arguments) (result reflect.Value) {
+			var from, to int
+			err := a.ParseInto(&from, &to)
+			if err != nil {
+				panic(err)
+			}
+			// check to > from
+			if to <= from {
+				panic(errors.New("invalid range for ints ranger: 'from' must be smaller than 'to'"))
+			}
+			return reflect.ValueOf(&intsRanger{from: from, to: to})
+		})),
+	}
+}
+
+type hiddenBool bool
+
+func (m hiddenBool) Render(r *Runtime) { /* render nothing -> hidden */ }
+
+var hiddenTrue = reflect.ValueOf(hiddenBool(true))
+var hiddenFalse = reflect.ValueOf(hiddenBool(false))
+
+func jsonRenderer(v interface{}) RendererFunc {
+	return func(r *Runtime) {
+		err := json.NewEncoder(r.Writer).Encode(v)
+		if err != nil {
+			panic(err)
+		}
+	}
+}
+
+func unsafePrinter(w io.Writer, b []byte) {
+	w.Write(b)
+}
+
+// SafeWriter is a function that writes bytes directly to the render output, without going through Jet's auto-escaping phase.
+// Use/implement this if content should be escaped differently or not at all (see raw/unsafe builtins).
+type SafeWriter func(io.Writer, []byte)
+
+var stringType = reflect.TypeOf("")
+
+var newMap = Func(func(a Arguments) reflect.Value {
+	if a.NumOfArguments()%2 > 0 {
+		panic("map(): incomplete key-value pair (even number of arguments required)")
+	}
+
+	m := reflect.ValueOf(make(map[string]interface{}, a.NumOfArguments()/2))
+
+	for i := 0; i < a.NumOfArguments(); i += 2 {
+		key := a.Get(i)
+		if !key.Type().ConvertibleTo(stringType) {
+			a.Panicf("map(): can't use %+v as string key: %s is not convertible to string", key, key.Type())
+		}
+		key = key.Convert(stringType)
+		m.SetMapIndex(a.Get(i), a.Get(i+1))
+	}
+
+	return m
+})
+
+var newSlice = Func(func(a Arguments) reflect.Value {
+	arr := make([]interface{}, a.NumOfArguments())
+	for i := 0; i < a.NumOfArguments(); i++ {
+		arr[i] = a.Get(i).Interface()
+	}
+	return reflect.ValueOf(arr)
+})

+ 1581 - 0
vendor/github.com/CloudyKit/jet/v4/eval.go

@@ -0,0 +1,1581 @@
+// Copyright 2016 José Santos <henrique_1609@me.com>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"io"
+	"reflect"
+	"runtime"
+	"strconv"
+	"strings"
+	"sync"
+
+	"github.com/CloudyKit/fastprinter"
+)
+
+var (
+	funcType       = reflect.TypeOf(Func(nil))
+	stringerType   = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
+	rangerType     = reflect.TypeOf((*Ranger)(nil)).Elem()
+	rendererType   = reflect.TypeOf((*Renderer)(nil)).Elem()
+	safeWriterType = reflect.TypeOf(SafeWriter(nil))
+	pool_State     = sync.Pool{
+		New: func() interface{} {
+			return &Runtime{scope: &scope{}, escapeeWriter: new(escapeeWriter)}
+		},
+	}
+)
+
+// Renderer is used to detect if a value has its own rendering logic. If the value an action evaluates to implements this
+// interface, it will not be printed using github.com/CloudyKit/fastprinter, instead, its Render() method will be called
+// and is responsible for writing the value to the render output.
+type Renderer interface {
+	Render(*Runtime)
+}
+
+// RendererFunc func implementing interface Renderer
+type RendererFunc func(*Runtime)
+
+func (renderer RendererFunc) Render(r *Runtime) {
+	renderer(r)
+}
+
+type escapeeWriter struct {
+	Writer  io.Writer
+	escapee SafeWriter
+	set     *Set
+}
+
+func (w *escapeeWriter) Write(b []byte) (int, error) {
+	if w.set.escapee == nil {
+		w.Writer.Write(b)
+	} else {
+		w.set.escapee(w.Writer, b)
+	}
+	return 0, nil
+}
+
+// Runtime this type holds the state of the execution of an template
+type Runtime struct {
+	*escapeeWriter
+	*scope
+	content func(*Runtime, Expression)
+
+	translator Translator
+	context    reflect.Value
+}
+
+// Context returns the current context value
+func (r *Runtime) Context() reflect.Value {
+	return r.context
+}
+
+func (st *Runtime) newScope() {
+	st.scope = &scope{parent: st.scope, variables: make(VarMap), blocks: st.blocks}
+}
+
+func (st *Runtime) releaseScope() {
+	st.scope = st.scope.parent
+}
+
+type scope struct {
+	parent    *scope
+	variables VarMap
+	blocks    map[string]*BlockNode
+}
+
+// YieldBlock yields a block in the current context, will panic if the context is not available
+func (st *Runtime) YieldBlock(name string, context interface{}) {
+	block, has := st.getBlock(name)
+
+	if has == false {
+		panic(fmt.Errorf("Block %q was not found!!", name))
+	}
+
+	if context != nil {
+		current := st.context
+		st.context = reflect.ValueOf(context)
+		st.executeList(block.List)
+		st.context = current
+	}
+
+	st.executeList(block.List)
+}
+
+func (st *scope) getBlock(name string) (block *BlockNode, has bool) {
+	block, has = st.blocks[name]
+	for !has && st.parent != nil {
+		st = st.parent
+		block, has = st.blocks[name]
+	}
+	return
+}
+
+func (state *Runtime) setValue(name string, val reflect.Value) error {
+	// try changing existing variable in current or parent scope
+	sc := state.scope
+	for sc != nil {
+		if _, ok := sc.variables[name]; ok {
+			sc.variables[name] = val
+			return nil
+		}
+		sc = sc.parent
+	}
+
+	return fmt.Errorf("could not assign %q = %v because variable %q is uninitialised", name, val, name)
+}
+
+// LetGlobal sets or initialises a variable in the top-most template scope.
+func (state *Runtime) LetGlobal(name string, val interface{}) {
+	sc := state.scope
+
+	// walk up to top-most valid scope
+	for sc.parent != nil && sc.parent.variables != nil {
+		sc = sc.parent
+	}
+
+	sc.variables[name] = reflect.ValueOf(val)
+}
+
+// Set sets an existing variable in the template scope it lives in.
+func (state *Runtime) Set(name string, val interface{}) error {
+	return state.setValue(name, reflect.ValueOf(val))
+}
+
+// Let initialises a variable in the current template scope (possibly shadowing an existing variable of the same name in a parent scope).
+func (state *Runtime) Let(name string, val interface{}) {
+	state.scope.variables[name] = reflect.ValueOf(val)
+}
+
+// SetOrLet calls Set() (if a variable with the given name is visible from the current scope) or Let() (if there is no variable with the given name in the current or any parent scope).
+func (state *Runtime) SetOrLet(name string, val interface{}) {
+	_, err := state.resolve(name)
+	if err != nil {
+		state.Let(name, val)
+	} else {
+		state.Set(name, val)
+	}
+}
+
+// Resolve resolves a value from the execution context.
+func (state *Runtime) resolve(name string) (reflect.Value, error) {
+	if name == "." {
+		return state.context, nil
+	}
+
+	// try current, then parent variable scopes
+	sc := state.scope
+	for sc != nil {
+		v, ok := sc.variables[name]
+		if ok {
+			return indirectEface(v), nil
+		}
+		sc = sc.parent
+	}
+
+	// try globals
+	state.set.gmx.RLock()
+	v, ok := state.set.globals[name]
+	state.set.gmx.RUnlock()
+	if ok {
+		return indirectEface(v), nil
+	}
+
+	// try default variables
+	v, ok = defaultVariables[name]
+	if ok {
+		return indirectEface(v), nil
+	}
+
+	return reflect.Value{}, fmt.Errorf("identifier %q not available in current (%+v) or parent scope, global, or default variables", name, state.scope.variables)
+}
+
+// Resolve calls resolve() and ignores any errors, meaning it may return a zero reflect.Value.
+func (state *Runtime) Resolve(name string) reflect.Value {
+	v, _ := state.resolve(name)
+	return v
+}
+
+// Resolve calls resolve() and panics if there is an error.
+func (state *Runtime) MustResolve(name string) reflect.Value {
+	v, err := state.resolve(name)
+	if err != nil {
+		panic(err)
+	}
+	return v
+}
+
+func (st *Runtime) recover(err *error) {
+	// reset state scope and context just to be safe (they might not be cleared properly if there was a panic while using the state)
+	st.scope = &scope{}
+	st.context = reflect.Value{}
+	pool_State.Put(st)
+	if recovered := recover(); recovered != nil {
+		var ok bool
+		if _, ok = recovered.(runtime.Error); ok {
+			panic(recovered)
+		}
+		*err, ok = recovered.(error)
+		if !ok {
+			panic(recovered)
+		}
+	}
+}
+
+func (st *Runtime) executeSet(left Expression, right reflect.Value) {
+	typ := left.Type()
+	if typ == NodeIdentifier {
+		err := st.setValue(left.(*IdentifierNode).Ident, right)
+		if err != nil {
+			left.error(err)
+		}
+		return
+	}
+	var value reflect.Value
+	var fields []string
+	if typ == NodeChain {
+		chain := left.(*ChainNode)
+		value = st.evalPrimaryExpressionGroup(chain.Node)
+		fields = chain.Field
+	} else {
+		fields = left.(*FieldNode).Ident
+		value = st.context
+	}
+	lef := len(fields) - 1
+	for i := 0; i < lef; i++ {
+		var err error
+		value, err = resolveIndex(value, reflect.ValueOf(fields[i]))
+		if err != nil {
+			left.errorf("%v", err)
+		}
+	}
+
+RESTART:
+	switch value.Kind() {
+	case reflect.Ptr:
+		value = value.Elem()
+		goto RESTART
+	case reflect.Struct:
+		value = value.FieldByName(fields[lef])
+		if !value.IsValid() {
+			left.errorf("identifier %q is not available in the current scope", fields[lef])
+		}
+		value.Set(right)
+	case reflect.Map:
+		value.SetMapIndex(reflect.ValueOf(&fields[lef]).Elem(), right)
+	}
+}
+
+func (st *Runtime) executeSetList(set *SetNode) {
+	if set.IndexExprGetLookup {
+		value := st.evalPrimaryExpressionGroup(set.Right[0])
+		st.executeSet(set.Left[0], value)
+		if value.IsValid() {
+			st.executeSet(set.Left[1], valueBoolTRUE)
+		} else {
+			st.executeSet(set.Left[1], valueBoolFALSE)
+		}
+	} else {
+		for i := 0; i < len(set.Left); i++ {
+			st.executeSet(set.Left[i], st.evalPrimaryExpressionGroup(set.Right[i]))
+		}
+	}
+}
+
+func (st *Runtime) executeLetList(set *SetNode) {
+	if set.IndexExprGetLookup {
+		value := st.evalPrimaryExpressionGroup(set.Right[0])
+
+		st.variables[set.Left[0].(*IdentifierNode).Ident] = value
+
+		if value.IsValid() {
+			st.variables[set.Left[1].(*IdentifierNode).Ident] = valueBoolTRUE
+		} else {
+			st.variables[set.Left[1].(*IdentifierNode).Ident] = valueBoolFALSE
+		}
+
+	} else {
+		for i := 0; i < len(set.Left); i++ {
+			st.variables[set.Left[i].(*IdentifierNode).Ident] = st.evalPrimaryExpressionGroup(set.Right[i])
+		}
+	}
+}
+
+func (st *Runtime) executeYieldBlock(block *BlockNode, blockParam, yieldParam *BlockParameterList, expression Expression, content *ListNode) {
+
+	needNewScope := len(blockParam.List) > 0 || len(yieldParam.List) > 0
+	if needNewScope {
+		st.newScope()
+		for i := 0; i < len(yieldParam.List); i++ {
+			p := &yieldParam.List[i]
+
+			if p.Expression == nil {
+				block.errorf("missing name for block parameter '%s'", blockParam.List[i].Identifier)
+			}
+
+			st.variables[p.Identifier] = st.evalPrimaryExpressionGroup(p.Expression)
+		}
+		for i := 0; i < len(blockParam.List); i++ {
+			p := &blockParam.List[i]
+			if _, found := st.variables[p.Identifier]; !found {
+				if p.Expression == nil {
+					st.variables[p.Identifier] = valueBoolFALSE
+				} else {
+					st.variables[p.Identifier] = st.evalPrimaryExpressionGroup(p.Expression)
+				}
+			}
+		}
+	}
+
+	mycontent := st.content
+	if content != nil {
+		myscope := st.scope
+		st.content = func(st *Runtime, expression Expression) {
+			outscope := st.scope
+			outcontent := st.content
+
+			st.scope = myscope
+			st.content = mycontent
+
+			if expression != nil {
+				context := st.context
+				st.context = st.evalPrimaryExpressionGroup(expression)
+				st.executeList(content)
+				st.context = context
+			} else {
+				st.executeList(content)
+			}
+
+			st.scope = outscope
+			st.content = outcontent
+		}
+	}
+
+	if expression != nil {
+		context := st.context
+		st.context = st.evalPrimaryExpressionGroup(expression)
+		st.executeList(block.List)
+		st.context = context
+	} else {
+		st.executeList(block.List)
+	}
+
+	st.content = mycontent
+	if needNewScope {
+		st.releaseScope()
+	}
+}
+
+func (st *Runtime) executeList(list *ListNode) (returnValue reflect.Value) {
+	inNewScope := false // to use just one scope for multiple actions with variable declarations
+
+	for i := 0; i < len(list.Nodes); i++ {
+		node := list.Nodes[i]
+		switch node.Type() {
+
+		case NodeText:
+			node := node.(*TextNode)
+			_, err := st.Writer.Write(node.Text)
+			if err != nil {
+				node.error(err)
+			}
+		case NodeAction:
+			node := node.(*ActionNode)
+			if node.Set != nil {
+				if node.Set.Let {
+					if !inNewScope {
+						st.newScope()
+						inNewScope = true
+						defer st.releaseScope()
+					}
+					st.executeLetList(node.Set)
+				} else {
+					st.executeSetList(node.Set)
+				}
+			}
+			if node.Pipe != nil {
+				v, safeWriter := st.evalPipelineExpression(node.Pipe)
+				if !safeWriter && v.IsValid() {
+					if v.Type().Implements(rendererType) {
+						v.Interface().(Renderer).Render(st)
+					} else {
+						_, err := fastprinter.PrintValue(st.escapeeWriter, v)
+						if err != nil {
+							node.error(err)
+						}
+					}
+				}
+			}
+		case NodeIf:
+			node := node.(*IfNode)
+			var isLet bool
+			if node.Set != nil {
+				if node.Set.Let {
+					isLet = true
+					st.newScope()
+					st.executeLetList(node.Set)
+				} else {
+					st.executeSetList(node.Set)
+				}
+			}
+
+			if isTrue(st.evalPrimaryExpressionGroup(node.Expression)) {
+				returnValue = st.executeList(node.List)
+			} else if node.ElseList != nil {
+				returnValue = st.executeList(node.ElseList)
+			}
+			if isLet {
+				st.releaseScope()
+			}
+		case NodeRange:
+			node := node.(*RangeNode)
+			var expression reflect.Value
+
+			isSet := node.Set != nil
+			isLet := false
+			keyVarSlot := 0
+			valVarSlot := -1
+
+			context := st.context
+
+			if isSet {
+				if len(node.Set.Left) > 1 {
+					valVarSlot = 1
+				}
+				expression = st.evalPrimaryExpressionGroup(node.Set.Right[0])
+				if node.Set.Let {
+					isLet = true
+					st.newScope()
+				}
+			} else {
+				expression = st.evalPrimaryExpressionGroup(node.Expression)
+			}
+
+			ranger, cleanup := getRanger(expression)
+			if !ranger.ProvidesIndex() {
+				if len(node.Set.Left) > 1 {
+					// two-vars assignment with ranger that doesn't provide an index
+					node.error(errors.New("two-var range over ranger that does not provide an index"))
+				}
+				keyVarSlot, valVarSlot = -1, 0
+			}
+
+			indexValue, rangeValue, end := ranger.Range()
+			if !end {
+				for !end && !returnValue.IsValid() {
+					if isSet {
+						if isLet {
+							if keyVarSlot >= 0 {
+								st.variables[node.Set.Left[keyVarSlot].String()] = indexValue
+							}
+							if valVarSlot >= 0 {
+								st.variables[node.Set.Left[valVarSlot].String()] = rangeValue
+							}
+						} else {
+							if keyVarSlot >= 0 {
+								st.executeSet(node.Set.Left[keyVarSlot], indexValue)
+							}
+							if valVarSlot >= 0 {
+								st.executeSet(node.Set.Left[valVarSlot], rangeValue)
+							}
+						}
+					}
+					if valVarSlot < 0 {
+						st.context = rangeValue
+					}
+					returnValue = st.executeList(node.List)
+					indexValue, rangeValue, end = ranger.Range()
+				}
+			} else if node.ElseList != nil {
+				returnValue = st.executeList(node.ElseList)
+			}
+			cleanup()
+			st.context = context
+			if isLet {
+				st.releaseScope()
+			}
+		case NodeTry:
+			node := node.(*TryNode)
+			returnValue = st.executeTry(node)
+		case NodeYield:
+			node := node.(*YieldNode)
+			if node.IsContent {
+				if st.content != nil {
+					st.content(st, node.Expression)
+				}
+			} else {
+				block, has := st.getBlock(node.Name)
+				if has == false || block == nil {
+					node.errorf("unresolved block %q!!", node.Name)
+				}
+				st.executeYieldBlock(block, block.Parameters, node.Parameters, node.Expression, node.Content)
+			}
+		case NodeBlock:
+			node := node.(*BlockNode)
+			block, has := st.getBlock(node.Name)
+			if has == false {
+				block = node
+			}
+			st.executeYieldBlock(block, block.Parameters, block.Parameters, block.Expression, block.Content)
+		case NodeInclude:
+			node := node.(*IncludeNode)
+			returnValue = st.executeInclude(node)
+		case NodeReturn:
+			node := node.(*ReturnNode)
+			returnValue = st.evalPrimaryExpressionGroup(node.Value)
+		}
+	}
+
+	return returnValue
+}
+
+func (st *Runtime) executeTry(try *TryNode) (returnValue reflect.Value) {
+	writer := st.Writer
+	buf := new(bytes.Buffer)
+
+	defer func() {
+		r := recover()
+
+		// copy buffered render output to writer only if no panic occured
+		if r == nil {
+			io.Copy(writer, buf)
+		} else {
+			// st.Writer is already set to its original value since the later defer ran first
+			if try.Catch != nil {
+				if try.Catch.Err != nil {
+					st.newScope()
+					st.scope.variables[try.Catch.Err.Ident] = reflect.ValueOf(r)
+				}
+				if try.Catch.List != nil {
+					returnValue = st.executeList(try.Catch.List)
+				}
+				if try.Catch.Err != nil {
+					st.releaseScope()
+				}
+			}
+		}
+	}()
+
+	st.Writer = buf
+	defer func() { st.Writer = writer }()
+
+	return st.executeList(try.List)
+}
+
+func (st *Runtime) executeInclude(node *IncludeNode) (returnValue reflect.Value) {
+	var templatePath string
+	name := st.evalPrimaryExpressionGroup(node.Name)
+	if name.Type().Implements(stringerType) {
+		templatePath = name.String()
+	} else if name.Kind() == reflect.String {
+		templatePath = name.String()
+	} else {
+		node.errorf("evaluating name of template to include: unexpected expression type %q", getTypeString(name))
+	}
+
+	t, err := st.set.getSiblingTemplate(templatePath, node.TemplatePath)
+	if err != nil {
+		node.error(err)
+		return reflect.Value{}
+	}
+
+	st.newScope()
+	defer st.releaseScope()
+
+	st.blocks = t.processedBlocks
+
+	var context reflect.Value
+	if node.Context != nil {
+		context = st.context
+		defer func() { st.context = context }()
+		st.context = st.evalPrimaryExpressionGroup(node.Context)
+	}
+
+	Root := t.Root
+	for t.extends != nil {
+		t = t.extends
+		Root = t.Root
+	}
+
+	return st.executeList(Root)
+}
+
+var (
+	valueBoolTRUE  = reflect.ValueOf(true)
+	valueBoolFALSE = reflect.ValueOf(false)
+)
+
+func (st *Runtime) evalPrimaryExpressionGroup(node Expression) reflect.Value {
+	switch node.Type() {
+	case NodeAdditiveExpr:
+		return st.evalAdditiveExpression(node.(*AdditiveExprNode))
+	case NodeMultiplicativeExpr:
+		return st.evalMultiplicativeExpression(node.(*MultiplicativeExprNode))
+	case NodeComparativeExpr:
+		return st.evalComparativeExpression(node.(*ComparativeExprNode))
+	case NodeNumericComparativeExpr:
+		return st.evalNumericComparativeExpression(node.(*NumericComparativeExprNode))
+	case NodeLogicalExpr:
+		return st.evalLogicalExpression(node.(*LogicalExprNode))
+	case NodeNotExpr:
+		return reflect.ValueOf(!isTrue(st.evalPrimaryExpressionGroup(node.(*NotExprNode).Expr)))
+	case NodeTernaryExpr:
+		node := node.(*TernaryExprNode)
+		if isTrue(st.evalPrimaryExpressionGroup(node.Boolean)) {
+			return st.evalPrimaryExpressionGroup(node.Left)
+		}
+		return st.evalPrimaryExpressionGroup(node.Right)
+	case NodeCallExpr:
+		node := node.(*CallExprNode)
+		baseExpr := st.evalBaseExpressionGroup(node.BaseExpr)
+		if baseExpr.Kind() != reflect.Func {
+			node.errorf("node %q is not func kind %q", node.BaseExpr, baseExpr.Type())
+		}
+		return st.evalCallExpression(baseExpr, node.Args)
+	case NodeIndexExpr:
+		node := node.(*IndexExprNode)
+		base := st.evalPrimaryExpressionGroup(node.Base)
+		index := st.evalPrimaryExpressionGroup(node.Index)
+
+		resolved, err := resolveIndex(base, index)
+		if err != nil {
+			node.error(err)
+		}
+		return resolved
+	case NodeSliceExpr:
+		node := node.(*SliceExprNode)
+		baseExpression := st.evalPrimaryExpressionGroup(node.Base)
+
+		var index, length int
+		if node.Index != nil {
+			indexExpression := st.evalPrimaryExpressionGroup(node.Index)
+			if canNumber(indexExpression.Kind()) {
+				index = int(castInt64(indexExpression))
+			} else {
+				node.Index.errorf("non numeric value in index expression kind %s", indexExpression.Kind().String())
+			}
+		}
+
+		if node.EndIndex != nil {
+			indexExpression := st.evalPrimaryExpressionGroup(node.EndIndex)
+			if canNumber(indexExpression.Kind()) {
+				length = int(castInt64(indexExpression))
+			} else {
+				node.EndIndex.errorf("non numeric value in index expression kind %s", indexExpression.Kind().String())
+			}
+		} else {
+			length = baseExpression.Len()
+		}
+
+		return baseExpression.Slice(index, length)
+	}
+	return st.evalBaseExpressionGroup(node)
+}
+
+// notNil returns false when v.IsValid() == false
+// or when v's kind can be nil and v.IsNil() == true
+func notNil(v reflect.Value) bool {
+	if !v.IsValid() {
+		return false
+	}
+	switch v.Kind() {
+	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
+		return !v.IsNil()
+	default:
+		return true
+	}
+}
+
+func (st *Runtime) isSet(node Node) (ok bool) {
+	defer func() {
+		if r := recover(); r != nil {
+			// something panicked while evaluating node
+			ok = false
+		}
+	}()
+
+	nodeType := node.Type()
+
+	switch nodeType {
+	case NodeIndexExpr:
+		node := node.(*IndexExprNode)
+		if !st.isSet(node.Base) || !st.isSet(node.Index) {
+			return false
+		}
+
+		base := st.evalPrimaryExpressionGroup(node.Base)
+		index := st.evalPrimaryExpressionGroup(node.Index)
+
+		resolved, err := resolveIndex(base, index)
+		return err == nil && notNil(resolved)
+	case NodeIdentifier:
+		value, err := st.resolve(node.String())
+		return err == nil && notNil(value)
+	case NodeField:
+		node := node.(*FieldNode)
+		resolved := st.context
+		for i := 0; i < len(node.Ident); i++ {
+			var err error
+			resolved, err = resolveIndex(resolved, reflect.ValueOf(node.Ident[i]))
+			if err != nil || !notNil(resolved) {
+				return false
+			}
+		}
+	case NodeChain:
+		node := node.(*ChainNode)
+		resolved, err := st.evalChainNodeExpression(node)
+		return err == nil && notNil(resolved)
+	default:
+		//todo: maybe work some edge cases
+		if !(nodeType > beginExpressions && nodeType < endExpressions) {
+			node.errorf("unexpected %q node in isset clause", node)
+		}
+	}
+	return true
+}
+
+func (st *Runtime) evalNumericComparativeExpression(node *NumericComparativeExprNode) reflect.Value {
+	left, right := st.evalPrimaryExpressionGroup(node.Left), st.evalPrimaryExpressionGroup(node.Right)
+	isTrue := false
+	kind := left.Kind()
+
+	// if the left value is not a float and the right is, we need to promote the left value to a float before the calculation
+	// this is necessary for expressions like 4*1.23
+	needFloatPromotion := !isFloat(kind) && isFloat(right.Kind())
+
+	switch node.Operator.typ {
+	case itemGreat:
+		if isInt(kind) {
+			if needFloatPromotion {
+				isTrue = float64(left.Int()) > right.Float()
+			} else {
+				isTrue = left.Int() > toInt(right)
+			}
+		} else if isFloat(kind) {
+			isTrue = left.Float() > toFloat(right)
+		} else if isUint(kind) {
+			if needFloatPromotion {
+				isTrue = float64(left.Uint()) > right.Float()
+			} else {
+				isTrue = left.Uint() > toUint(right)
+			}
+		} else {
+			node.Left.errorf("a non numeric value in numeric comparative expression")
+		}
+	case itemGreatEquals:
+		if isInt(kind) {
+			if needFloatPromotion {
+				isTrue = float64(left.Int()) >= right.Float()
+			} else {
+				isTrue = left.Int() >= toInt(right)
+			}
+		} else if isFloat(kind) {
+			isTrue = left.Float() >= toFloat(right)
+		} else if isUint(kind) {
+			if needFloatPromotion {
+				isTrue = float64(left.Uint()) >= right.Float()
+			} else {
+				isTrue = left.Uint() >= toUint(right)
+			}
+		} else {
+			node.Left.errorf("a non numeric value in numeric comparative expression")
+		}
+	case itemLess:
+		if isInt(kind) {
+			if needFloatPromotion {
+				isTrue = float64(left.Int()) < right.Float()
+			} else {
+				isTrue = left.Int() < toInt(right)
+			}
+		} else if isFloat(kind) {
+			isTrue = left.Float() < toFloat(right)
+		} else if isUint(kind) {
+			if needFloatPromotion {
+				isTrue = float64(left.Uint()) < right.Float()
+			} else {
+				isTrue = left.Uint() < toUint(right)
+			}
+		} else {
+			node.Left.errorf("a non numeric value in numeric comparative expression")
+		}
+	case itemLessEquals:
+		if isInt(kind) {
+			if needFloatPromotion {
+				isTrue = float64(left.Int()) <= right.Float()
+			} else {
+				isTrue = left.Int() <= toInt(right)
+			}
+		} else if isFloat(kind) {
+			isTrue = left.Float() <= toFloat(right)
+		} else if isUint(kind) {
+			if needFloatPromotion {
+				isTrue = float64(left.Uint()) <= right.Float()
+			} else {
+				isTrue = left.Uint() <= toUint(right)
+			}
+		} else {
+			node.Left.errorf("a non numeric value in numeric comparative expression")
+		}
+	}
+	return reflect.ValueOf(isTrue)
+}
+
+func (st *Runtime) evalLogicalExpression(node *LogicalExprNode) reflect.Value {
+	truthy := isTrue(st.evalPrimaryExpressionGroup(node.Left))
+	if node.Operator.typ == itemAnd {
+		truthy = truthy && isTrue(st.evalPrimaryExpressionGroup(node.Right))
+	} else {
+		truthy = truthy || isTrue(st.evalPrimaryExpressionGroup(node.Right))
+	}
+	return reflect.ValueOf(truthy)
+}
+
+func (st *Runtime) evalComparativeExpression(node *ComparativeExprNode) reflect.Value {
+	left, right := st.evalPrimaryExpressionGroup(node.Left), st.evalPrimaryExpressionGroup(node.Right)
+	equal := checkEquality(left, right)
+	if node.Operator.typ == itemNotEquals {
+		return reflect.ValueOf(!equal)
+	}
+	return reflect.ValueOf(equal)
+}
+
+func toInt(v reflect.Value) int64 {
+	kind := v.Kind()
+	if isInt(kind) {
+		return v.Int()
+	} else if isFloat(kind) {
+		return int64(v.Float())
+	} else if isUint(kind) {
+		return int64(v.Uint())
+	} else if kind == reflect.String {
+		n, e := strconv.ParseInt(v.String(), 10, 0)
+		if e != nil {
+			panic(e)
+		}
+		return n
+	} else if kind == reflect.Bool {
+		if v.Bool() {
+			return 0
+		}
+		return 1
+	}
+	panic(fmt.Errorf("type: %q can't be converted to int64", v.Type()))
+}
+
+func toUint(v reflect.Value) uint64 {
+	kind := v.Kind()
+	if isUint(kind) {
+		return v.Uint()
+	} else if isInt(kind) {
+		return uint64(v.Int())
+	} else if isFloat(kind) {
+		return uint64(v.Float())
+	} else if kind == reflect.String {
+		n, e := strconv.ParseUint(v.String(), 10, 0)
+		if e != nil {
+			panic(e)
+		}
+		return n
+	} else if kind == reflect.Bool {
+		if v.Bool() {
+			return 0
+		}
+		return 1
+	}
+	panic(fmt.Errorf("type: %q can't be converted to uint64", v.Type()))
+}
+
+func toFloat(v reflect.Value) float64 {
+	kind := v.Kind()
+	if isFloat(kind) {
+		return v.Float()
+	} else if isInt(kind) {
+		return float64(v.Int())
+	} else if isUint(kind) {
+		return float64(v.Uint())
+	} else if kind == reflect.String {
+		n, e := strconv.ParseFloat(v.String(), 0)
+		if e != nil {
+			panic(e)
+		}
+		return n
+	} else if kind == reflect.Bool {
+		if v.Bool() {
+			return 0
+		}
+		return 1
+	}
+	panic(fmt.Errorf("type: %q can't be converted to float64", v.Type()))
+}
+
+func (st *Runtime) evalMultiplicativeExpression(node *MultiplicativeExprNode) reflect.Value {
+	left, right := st.evalPrimaryExpressionGroup(node.Left), st.evalPrimaryExpressionGroup(node.Right)
+	kind := left.Kind()
+	// if the left value is not a float and the right is, we need to promote the left value to a float before the calculation
+	// this is necessary for expressions like 4*1.23
+	needFloatPromotion := !isFloat(kind) && isFloat(right.Kind())
+	switch node.Operator.typ {
+	case itemMul:
+		if isInt(kind) {
+			if needFloatPromotion {
+				// do the promotion and calculates
+				left = reflect.ValueOf(float64(left.Int()) * right.Float())
+			} else {
+				// do not need float promotion
+				left = reflect.ValueOf(left.Int() * toInt(right))
+			}
+		} else if isFloat(kind) {
+			left = reflect.ValueOf(left.Float() * toFloat(right))
+		} else if isUint(kind) {
+			if needFloatPromotion {
+				left = reflect.ValueOf(float64(left.Uint()) * right.Float())
+			} else {
+				left = reflect.ValueOf(left.Uint() * toUint(right))
+			}
+		} else {
+			node.Left.errorf("a non numeric value in multiplicative expression")
+		}
+	case itemDiv:
+		if isInt(kind) {
+			if needFloatPromotion {
+				left = reflect.ValueOf(float64(left.Int()) / right.Float())
+			} else {
+				left = reflect.ValueOf(left.Int() / toInt(right))
+			}
+		} else if isFloat(kind) {
+			left = reflect.ValueOf(left.Float() / toFloat(right))
+		} else if isUint(kind) {
+			if needFloatPromotion {
+				left = reflect.ValueOf(float64(left.Uint()) / right.Float())
+			} else {
+				left = reflect.ValueOf(left.Uint() / toUint(right))
+			}
+		} else {
+			node.Left.errorf("a non numeric value in multiplicative expression")
+		}
+	case itemMod:
+		if isInt(kind) {
+			left = reflect.ValueOf(left.Int() % toInt(right))
+		} else if isFloat(kind) {
+			left = reflect.ValueOf(int64(left.Float()) % toInt(right))
+		} else if isUint(kind) {
+			left = reflect.ValueOf(left.Uint() % toUint(right))
+		} else {
+			node.Left.errorf("a non numeric value in multiplicative expression")
+		}
+	}
+	return left
+}
+
+func (st *Runtime) evalAdditiveExpression(node *AdditiveExprNode) reflect.Value {
+
+	isAdditive := node.Operator.typ == itemAdd
+	if node.Left == nil {
+		right := st.evalPrimaryExpressionGroup(node.Right)
+		kind := right.Kind()
+		// todo: optimize
+		if isInt(kind) {
+			if isAdditive {
+				return reflect.ValueOf(+right.Int())
+			} else {
+				return reflect.ValueOf(-right.Int())
+			}
+		} else if isUint(kind) {
+			if isAdditive {
+				return right
+			} else {
+				return reflect.ValueOf(-int64(right.Uint()))
+			}
+		} else if isFloat(kind) {
+			if isAdditive {
+				return reflect.ValueOf(+right.Float())
+			} else {
+				return reflect.ValueOf(-right.Float())
+			}
+		}
+		node.Left.errorf("additive expression: right side %s (%s) is not a numeric value (no left side)", node.Right, getTypeString(right))
+	}
+
+	left, right := st.evalPrimaryExpressionGroup(node.Left), st.evalPrimaryExpressionGroup(node.Right)
+	kind := left.Kind()
+	// if the left value is not a float and the right is, we need to promote the left value to a float before the calculation
+	// this is necessary for expressions like 4+1.23
+	needFloatPromotion := !isFloat(kind) && kind != reflect.String && isFloat(right.Kind())
+	if needFloatPromotion {
+		if isInt(kind) {
+			if isAdditive {
+				left = reflect.ValueOf(float64(left.Int()) + right.Float())
+			} else {
+				left = reflect.ValueOf(float64(left.Int()) - right.Float())
+			}
+		} else if isUint(kind) {
+			if isAdditive {
+				left = reflect.ValueOf(float64(left.Uint()) + right.Float())
+			} else {
+				left = reflect.ValueOf(float64(left.Uint()) - right.Float())
+			}
+		} else {
+			node.Left.errorf("additive expression: left side (%s (%s) needs float promotion but neither int nor uint)", node.Left, getTypeString(left))
+		}
+	} else {
+		if isInt(kind) {
+			if isAdditive {
+				left = reflect.ValueOf(left.Int() + toInt(right))
+			} else {
+				left = reflect.ValueOf(left.Int() - toInt(right))
+			}
+		} else if isFloat(kind) {
+			if isAdditive {
+				left = reflect.ValueOf(left.Float() + toFloat(right))
+			} else {
+				left = reflect.ValueOf(left.Float() - toFloat(right))
+			}
+		} else if isUint(kind) {
+			if isAdditive {
+				left = reflect.ValueOf(left.Uint() + toUint(right))
+			} else {
+				left = reflect.ValueOf(left.Uint() - toUint(right))
+			}
+		} else if kind == reflect.String {
+			if !isAdditive {
+				node.Right.errorf("minus signal is not allowed with strings")
+			}
+			// converts []byte (and alias types of []byte) to string
+			if right.Kind() == reflect.Slice && right.Type().Elem().Kind() == reflect.Uint8 {
+				right = right.Convert(left.Type())
+			}
+			left = reflect.ValueOf(left.String() + fmt.Sprint(right))
+		} else {
+			node.Left.errorf("additive expression: left side %s (%s) is not a numeric value", node.Left, getTypeString(left))
+		}
+	}
+
+	return left
+}
+
+func getTypeString(value reflect.Value) string {
+	if value.IsValid() {
+		return value.Type().String()
+	}
+	return "<invalid>"
+}
+
+func (st *Runtime) evalBaseExpressionGroup(node Node) reflect.Value {
+	switch node.Type() {
+	case NodeNil:
+		return reflect.ValueOf(nil)
+	case NodeBool:
+		if node.(*BoolNode).True {
+			return valueBoolTRUE
+		}
+		return valueBoolFALSE
+	case NodeString:
+		return reflect.ValueOf(&node.(*StringNode).Text).Elem()
+	case NodeIdentifier:
+		resolved, err := st.resolve(node.(*IdentifierNode).Ident)
+		if err != nil {
+			node.error(err)
+		}
+		return resolved
+	case NodeField:
+		node := node.(*FieldNode)
+		resolved := st.context
+		for i := 0; i < len(node.Ident); i++ {
+			field, err := resolveIndex(resolved, reflect.ValueOf(node.Ident[i]))
+			if err != nil {
+				node.errorf("%v", err)
+			}
+			if !field.IsValid() {
+				node.errorf("there is no field or method '%s' in %s (.%s)", node.Ident[i], getTypeString(resolved), strings.Join(node.Ident, "."))
+			}
+			resolved = field
+		}
+		return resolved
+	case NodeChain:
+		resolved, err := st.evalChainNodeExpression(node.(*ChainNode))
+		if err != nil {
+			node.error(err)
+		}
+		return resolved
+	case NodeNumber:
+		node := node.(*NumberNode)
+		if node.IsFloat {
+			return reflect.ValueOf(&node.Float64).Elem()
+		}
+
+		if node.IsInt {
+			return reflect.ValueOf(&node.Int64).Elem()
+		}
+
+		if node.IsUint {
+			return reflect.ValueOf(&node.Uint64).Elem()
+		}
+	}
+	node.errorf("unexpected node type %s in unary expression evaluating", node)
+	return reflect.Value{}
+}
+
+func (st *Runtime) evalCallExpression(baseExpr reflect.Value, args []Expression, values ...reflect.Value) reflect.Value {
+
+	if funcType.AssignableTo(baseExpr.Type()) {
+		return baseExpr.Interface().(Func)(Arguments{runtime: st, argExpr: args, argVal: values})
+	}
+
+	i := len(args) + len(values)
+	var returns []reflect.Value
+	if i <= 10 {
+		returns = reflect_Call10(i, st, baseExpr, args, values...)
+	} else {
+		returns = reflect_Call(make([]reflect.Value, i, i), st, baseExpr, args, values...)
+	}
+
+	if len(returns) == 0 {
+		return reflect.Value{}
+	}
+
+	return returns[0]
+}
+
+func (st *Runtime) evalCommandExpression(node *CommandNode) (reflect.Value, bool) {
+	term := st.evalPrimaryExpressionGroup(node.BaseExpr)
+	if node.Args != nil {
+		if term.Kind() == reflect.Func {
+			if term.Type() == safeWriterType {
+				st.evalSafeWriter(term, node)
+				return reflect.Value{}, true
+			}
+			return st.evalCallExpression(term, node.Args), false
+		} else {
+			node.Args[0].errorf("command %q type %s is not func", node.Args[0], term.Type())
+		}
+	}
+	return term, false
+}
+
+func (st *Runtime) evalChainNodeExpression(node *ChainNode) (reflect.Value, error) {
+	resolved := st.evalPrimaryExpressionGroup(node.Node)
+
+	for i := 0; i < len(node.Field); i++ {
+		field, err := resolveIndex(resolved, reflect.ValueOf(node.Field[i]))
+		if err != nil {
+			return reflect.Value{}, err
+		}
+		if !field.IsValid() {
+			if resolved.Kind() == reflect.Map && i == len(node.Field)-1 {
+				// return reflect.Zero(resolved.Type().Elem()), nil
+				return reflect.Value{}, nil
+			}
+			return reflect.Value{}, fmt.Errorf("there is no field or method '%s' in %s (%s)", node.Field[i], getTypeString(resolved), node)
+		}
+		resolved = field
+	}
+
+	return resolved, nil
+}
+
+type escapeWriter struct {
+	rawWriter  io.Writer
+	safeWriter SafeWriter
+}
+
+func (w *escapeWriter) Write(b []byte) (int, error) {
+	w.safeWriter(w.rawWriter, b)
+	return 0, nil
+}
+
+func (st *Runtime) evalSafeWriter(term reflect.Value, node *CommandNode, v ...reflect.Value) {
+
+	sw := &escapeWriter{rawWriter: st.Writer, safeWriter: term.Interface().(SafeWriter)}
+	for i := 0; i < len(v); i++ {
+		fastprinter.PrintValue(sw, v[i])
+	}
+	for i := 0; i < len(node.Args); i++ {
+		fastprinter.PrintValue(sw, st.evalPrimaryExpressionGroup(node.Args[i]))
+	}
+}
+
+func (st *Runtime) evalCommandPipeExpression(node *CommandNode, value reflect.Value) (reflect.Value, bool) {
+	term := st.evalPrimaryExpressionGroup(node.BaseExpr)
+	if term.Kind() == reflect.Func {
+		if term.Type() == safeWriterType {
+			st.evalSafeWriter(term, node, value)
+			return reflect.Value{}, true
+		}
+		return st.evalCallExpression(term, node.Args, value), false
+	} else {
+		node.BaseExpr.errorf("pipe command %q type %s is not func", node.BaseExpr, term.Type())
+	}
+	return term, false
+}
+
+func (st *Runtime) evalPipelineExpression(node *PipeNode) (value reflect.Value, safeWriter bool) {
+	value, safeWriter = st.evalCommandExpression(node.Cmds[0])
+	for i := 1; i < len(node.Cmds); i++ {
+		if safeWriter {
+			node.Cmds[i].errorf("unexpected command %s, writer command should be the last command", node.Cmds[i])
+		}
+		value, safeWriter = st.evalCommandPipeExpression(node.Cmds[i], value)
+	}
+	return
+}
+
+func reflect_Call(arguments []reflect.Value, st *Runtime, fn reflect.Value, args []Expression, values ...reflect.Value) []reflect.Value {
+	typ := fn.Type()
+	numIn := typ.NumIn()
+
+	isVariadic := typ.IsVariadic()
+	if isVariadic {
+		numIn--
+	}
+	i, j := 0, 0
+
+	for ; i < numIn && i < len(values); i++ {
+		in := typ.In(i)
+		term := values[i]
+		if !term.Type().AssignableTo(in) {
+			term = term.Convert(in)
+		}
+		arguments[i] = term
+	}
+
+	if isVariadic {
+		in := typ.In(numIn).Elem()
+		for ; i < len(values); i++ {
+			term := values[i]
+			if !term.Type().AssignableTo(in) {
+				term = term.Convert(in)
+			}
+			arguments[i] = term
+		}
+	}
+
+	for ; i < numIn && j < len(args); i, j = i+1, j+1 {
+		in := typ.In(i)
+		term := st.evalPrimaryExpressionGroup(args[j])
+		if !term.Type().AssignableTo(in) {
+			term = term.Convert(in)
+		}
+		arguments[i] = term
+	}
+
+	if isVariadic {
+		in := typ.In(numIn).Elem()
+		for ; j < len(args); i, j = i+1, j+1 {
+			term := st.evalPrimaryExpressionGroup(args[j])
+			if !term.Type().AssignableTo(in) {
+				term = term.Convert(in)
+			}
+			arguments[i] = term
+		}
+	}
+	return fn.Call(arguments[0:i])
+}
+
+func reflect_Call10(i int, st *Runtime, fn reflect.Value, args []Expression, values ...reflect.Value) []reflect.Value {
+	var arguments [10]reflect.Value
+	return reflect_Call(arguments[0:i], st, fn, args, values...)
+}
+
+func isUint(kind reflect.Kind) bool {
+	return kind >= reflect.Uint && kind <= reflect.Uint64
+}
+func isInt(kind reflect.Kind) bool {
+	return kind >= reflect.Int && kind <= reflect.Int64
+}
+func isFloat(kind reflect.Kind) bool {
+	return kind == reflect.Float32 || kind == reflect.Float64
+}
+
+// checkEquality of two reflect values in the semantic of the jet runtime
+func checkEquality(v1, v2 reflect.Value) bool {
+	v1 = indirectInterface(v1)
+	v2 = indirectInterface(v2)
+
+	if !v1.IsValid() || !v2.IsValid() {
+		return v1.IsValid() == v2.IsValid()
+	}
+
+	v1Type := v1.Type()
+	v2Type := v2.Type()
+
+	// fast path
+	if v1Type != v2Type && !v2Type.AssignableTo(v1Type) && !v2Type.ConvertibleTo(v1Type) {
+		return false
+	}
+
+	kind := v1.Kind()
+	if isInt(kind) {
+		return v1.Int() == toInt(v2)
+	}
+	if isFloat(kind) {
+		return v1.Float() == toFloat(v2)
+	}
+	if isUint(kind) {
+		return v1.Uint() == toUint(v2)
+	}
+
+	switch kind {
+	case reflect.Bool:
+		return v1.Bool() == isTrue(v2)
+	case reflect.String:
+		return v1.String() == v2.String()
+	case reflect.Array:
+		vlen := v1.Len()
+		if vlen == v2.Len() {
+			return false
+		}
+		for i := 0; i < vlen; i++ {
+			if !checkEquality(v1.Index(i), v2.Index(i)) {
+				return false
+			}
+		}
+		return true
+	case reflect.Slice:
+		if v1.IsNil() != v2.IsNil() {
+			return false
+		}
+
+		vlen := v1.Len()
+		if vlen != v2.Len() {
+			return false
+		}
+
+		if v1.CanAddr() && v2.CanAddr() && v1.Pointer() == v2.Pointer() {
+			return true
+		}
+
+		for i := 0; i < vlen; i++ {
+			if !checkEquality(v1.Index(i), v2.Index(i)) {
+				return false
+			}
+		}
+		return true
+	case reflect.Interface:
+		if v1.IsNil() || v2.IsNil() {
+			return v1.IsNil() == v2.IsNil()
+		}
+		return checkEquality(v1.Elem(), v2.Elem())
+	case reflect.Ptr:
+		return v1.Pointer() == v2.Pointer()
+	case reflect.Struct:
+		numField := v1.NumField()
+		for i, n := 0, numField; i < n; i++ {
+			if !checkEquality(v1.Field(i), v2.Field(i)) {
+				return false
+			}
+		}
+		return true
+	case reflect.Map:
+		if v1.IsNil() != v2.IsNil() {
+			return false
+		}
+		if v1.Len() != v2.Len() {
+			return false
+		}
+		if v1.Pointer() == v2.Pointer() {
+			return true
+		}
+		for _, k := range v1.MapKeys() {
+			val1 := v1.MapIndex(k)
+			val2 := v2.MapIndex(k)
+			if !val1.IsValid() || !val2.IsValid() || !checkEquality(v1.MapIndex(k), v2.MapIndex(k)) {
+				return false
+			}
+		}
+		return true
+	case reflect.Func:
+		return v1.IsNil() && v2.IsNil()
+	default:
+		// Normal equality suffices
+		return v1.Interface() == v2.Interface()
+	}
+}
+
+func isTrue(v reflect.Value) bool {
+	return v.IsValid() && !v.IsZero()
+}
+
+func canNumber(kind reflect.Kind) bool {
+	return isInt(kind) || isUint(kind) || isFloat(kind)
+}
+
+func castInt64(v reflect.Value) int64 {
+	kind := v.Kind()
+	switch {
+	case isInt(kind):
+		return v.Int()
+	case isUint(kind):
+		return int64(v.Uint())
+	case isFloat(kind):
+		return int64(v.Float())
+	}
+	return 0
+}
+
+var cachedStructsMutex = sync.RWMutex{}
+var cachedStructsFieldIndex = map[reflect.Type]map[string][]int{}
+
+// from text/template's exec.go:
+//
+// indirect returns the item at the end of indirection, and a bool to indicate
+// if it's nil. If the returned bool is true, the returned value's kind will be
+// either a pointer or interface.
+func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
+	for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
+		if v.IsNil() {
+			return v, true
+		}
+	}
+	return v, false
+}
+
+// indirectInterface returns the concrete value in an interface value, or else v itself.
+// That is, if v represents the interface value x, the result is the same as reflect.ValueOf(x):
+// the fact that x was an interface value is forgotten.
+func indirectInterface(v reflect.Value) reflect.Value {
+	if v.Kind() == reflect.Interface {
+		return v.Elem()
+	}
+	return v
+}
+
+// indirectEface is the same as indirectInterface, but only indirects through v if its type
+// is the empty interface and its value is not nil.
+func indirectEface(v reflect.Value) reflect.Value {
+	if v.Kind() == reflect.Interface && v.Type().NumMethod() == 0 && !v.IsNil() {
+		return v.Elem()
+	}
+	return v
+}
+
+// mostly copied from text/template's evalField() (exec.go):
+func resolveIndex(v, index reflect.Value) (reflect.Value, error) {
+	if !v.IsValid() {
+		return reflect.Value{}, fmt.Errorf("there is no field or method '%s' in %s (%s)", index, v, getTypeString(v))
+	}
+
+	v, isNil := indirect(v)
+	if v.Kind() == reflect.Interface && isNil {
+		// Calling a method on a nil interface can't work. The
+		// MethodByName method call below would panic.
+		return reflect.Value{}, fmt.Errorf("nil pointer evaluating %s.%s", v.Type(), index)
+	}
+
+	// Unless it's an interface, need to get to a value of type *T to guarantee
+	// we see all methods of T and *T.
+	if index.Kind() == reflect.String {
+		ptr := v
+		if ptr.Kind() != reflect.Interface && ptr.Kind() != reflect.Ptr && ptr.CanAddr() {
+			ptr = ptr.Addr()
+		}
+		if method := ptr.MethodByName(index.String()); method.IsValid() {
+			return method, nil
+		}
+	}
+
+	// It's not a method on v; so now:
+	//  - if v is array/slice/string, use index as numeric index
+	//  - if v is a struct, use index as field name
+	//  - if v is a map, use index as key
+	//  - if v is (still) a pointer, indexing will fail but we check for nil to get a useful error
+	switch v.Kind() {
+	case reflect.Array, reflect.Slice, reflect.String:
+		x, err := indexArg(index, v.Len())
+		if err != nil {
+			return reflect.Value{}, err
+		}
+		return indirectEface(v.Index(x)), nil
+	case reflect.Struct:
+		if index.Kind() != reflect.String {
+			return reflect.Value{}, fmt.Errorf("can't use %s (%s, not string) as field name in struct type %s", index, index.Type(), v.Type())
+		}
+		tField, ok := v.Type().FieldByName(index.String())
+		if ok {
+			field := v.FieldByIndex(tField.Index)
+			if tField.PkgPath != "" { // field is unexported
+				return reflect.Value{}, fmt.Errorf("%s is an unexported field of struct type %s", index.String(), v.Type())
+			}
+			return indirectEface(field), nil
+		}
+		return reflect.Value{}, fmt.Errorf("can't use %s as field name in struct type %s", index, v.Type())
+	case reflect.Map:
+		// If it's a map, attempt to use the field name as a key.
+		if !index.Type().ConvertibleTo(v.Type().Key()) {
+			return reflect.Value{}, fmt.Errorf("can't use %s (%s) as key for map of type %s", index, index.Type(), v.Type())
+		}
+		index = index.Convert(v.Type().Key()) // noop in most cases, but not expensive
+		return indirectEface(v.MapIndex(index)), nil
+	case reflect.Ptr:
+		etyp := v.Type().Elem()
+		if etyp.Kind() == reflect.Struct && index.Kind() == reflect.String {
+			if _, ok := etyp.FieldByName(index.String()); !ok {
+				// If there's no such field, say "can't evaluate"
+				// instead of "nil pointer evaluating".
+				break
+			}
+		}
+		if isNil {
+			return reflect.Value{}, fmt.Errorf("nil pointer evaluating %s.%s", v.Type(), index)
+		}
+	}
+	return reflect.Value{}, fmt.Errorf("can't evaluate index %s (%s) in type %s", index, index.Type(), v.Type())
+}
+
+// from Go's text/template's funcs.go:
+//
+// indexArg checks if a reflect.Value can be used as an index, and converts it to int if possible.
+func indexArg(index reflect.Value, cap int) (int, error) {
+	var x int64
+	switch index.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		x = index.Int()
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		x = int64(index.Uint())
+	case reflect.Float32, reflect.Float64:
+		x = int64(index.Float())
+	case reflect.Invalid:
+		return 0, fmt.Errorf("cannot index slice/array/string with nil")
+	default:
+		return 0, fmt.Errorf("cannot index slice/array/string with type %s", index.Type())
+	}
+	if int(x) < 0 || int(x) >= cap {
+		return 0, fmt.Errorf("index out of range: %d", x)
+	}
+	return int(x), nil
+}
+
+func buildCache(typ reflect.Type, cache map[string][]int, parent []int) {
+	numFields := typ.NumField()
+	max := len(parent) + 1
+
+	for i := 0; i < numFields; i++ {
+
+		index := make([]int, max)
+		copy(index, parent)
+		index[len(parent)] = i
+
+		field := typ.Field(i)
+		if field.Anonymous {
+			typ := field.Type
+			if typ.Kind() == reflect.Struct {
+				buildCache(typ, cache, index)
+			}
+		}
+		cache[field.Name] = index
+	}
+}

+ 160 - 0
vendor/github.com/CloudyKit/jet/v4/func.go

@@ -0,0 +1,160 @@
+// Copyright 2016 José Santos <henrique_1609@me.com>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+	"fmt"
+	"reflect"
+	"time"
+)
+
+// Arguments holds the arguments passed to jet.Func.
+type Arguments struct {
+	runtime *Runtime
+	argExpr []Expression
+	argVal  []reflect.Value
+}
+
+// IsSet checks whether an argument is set or not. It behaves like the build-in isset function.
+func (a *Arguments) IsSet(argumentIndex int) bool {
+	return a.runtime.isSet(a.argExpr[argumentIndex])
+}
+
+// Get gets an argument by index.
+func (a *Arguments) Get(argumentIndex int) reflect.Value {
+	if argumentIndex < len(a.argVal) {
+		return a.argVal[argumentIndex]
+	}
+	if argumentIndex < len(a.argVal)+len(a.argExpr) {
+		return a.runtime.evalPrimaryExpressionGroup(a.argExpr[argumentIndex-len(a.argVal)])
+	}
+	return reflect.Value{}
+}
+
+// Panicf panics with formatted error message.
+func (a *Arguments) Panicf(format string, v ...interface{}) {
+	panic(fmt.Errorf(format, v...))
+}
+
+// RequireNumOfArguments panics if the number of arguments is not in the range specified by min and max.
+// In case there is no minimum pass -1, in case there is no maximum pass -1 respectively.
+func (a *Arguments) RequireNumOfArguments(funcname string, min, max int) {
+	num := len(a.argExpr) + len(a.argVal)
+	if min >= 0 && num < min {
+		a.Panicf("unexpected number of arguments in a call to %s", funcname)
+	} else if max >= 0 && num > max {
+		a.Panicf("unexpected number of arguments in a call to %s", funcname)
+	}
+}
+
+// NumOfArguments returns the number of arguments
+func (a *Arguments) NumOfArguments() int {
+	return len(a.argExpr) + len(a.argVal)
+}
+
+// Runtime get the Runtime context
+func (a *Arguments) Runtime() *Runtime {
+	return a.runtime
+}
+
+// ParseInto parses the arguments into the provided pointers. It returns an error if the number of pointers passed in does not
+// equal the number of arguments, if any argument's value is invalid according to Go's reflect package, if an argument can't
+// be used as the value the pointer passed in at the corresponding position points to, or if an unhandled pointer type is encountered.
+// Allowed pointer types are pointers to interface{}, int, int64, float64, bool, string,  time.Time, reflect.Value, []interface{},
+// map[string]interface{}. If a pointer to a reflect.Value is passed in, the argument be assigned as-is to the value pointed to. For
+// pointers to int or float types, type conversion is performed automatically if necessary.
+func (a *Arguments) ParseInto(ptrs ...interface{}) error {
+	if len(ptrs) < a.NumOfArguments() {
+		return fmt.Errorf("have %d arguments, but only %d pointers to parse into", a.NumOfArguments(), len(ptrs))
+	}
+
+	for i := 0; i < a.NumOfArguments(); i++ {
+		arg, ptr := indirectEface(a.Get(i)), ptrs[i]
+		ok := false
+
+		if !arg.IsValid() {
+			return fmt.Errorf("argument at position %d is not a valid value", i)
+		}
+
+		switch p := ptr.(type) {
+		case *reflect.Value:
+			*p, ok = arg, true
+		case *int:
+			switch arg.Kind() {
+			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+				*p, ok = int(arg.Int()), true
+			case reflect.Float32, reflect.Float64:
+				*p, ok = int(arg.Float()), true
+			default:
+				return fmt.Errorf("could not parse %v (%s) into %v (%T)", arg, arg.Type(), ptr, ptr)
+			}
+		case *int64:
+			switch arg.Kind() {
+			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+				*p, ok = arg.Int(), true
+			case reflect.Float32, reflect.Float64:
+				*p, ok = int64(arg.Float()), true
+			default:
+				return fmt.Errorf("could not parse %v (%s) into %v (%T)", arg, arg.Type(), ptr, ptr)
+			}
+		case *float64:
+			switch arg.Kind() {
+			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+				*p, ok = float64(arg.Int()), true
+			case reflect.Float32, reflect.Float64:
+				*p, ok = arg.Float(), true
+			default:
+				return fmt.Errorf("could not parse %v (%s) into %v (%T)", arg, arg.Type(), ptr, ptr)
+			}
+		}
+
+		if ok {
+			continue
+		}
+
+		if !arg.CanInterface() {
+			return fmt.Errorf("argument at position %d can't be accessed via Interface()", i)
+		}
+		val := arg.Interface()
+
+		switch p := ptr.(type) {
+		case *interface{}:
+			*p, ok = val, true
+		case *bool:
+			*p, ok = val.(bool)
+		case *string:
+			*p, ok = val.(string)
+		case *time.Time:
+			*p, ok = val.(time.Time)
+		case *[]interface{}:
+			*p, ok = val.([]interface{})
+		case *map[string]interface{}:
+			*p, ok = val.(map[string]interface{})
+		default:
+			return fmt.Errorf("trying to parse %v into %v: unhandled value type %T", arg, p, val)
+		}
+
+		if !ok {
+			return fmt.Errorf("could not parse %v (%s) into %v (%T)", arg, arg.Type(), ptr, ptr)
+		}
+	}
+
+	return nil
+}
+
+// Func function implementing this type is called directly, which is faster than calling through reflect.
+// If a function is being called many times in the execution of a template, you may consider implementing
+// a wrapper for that function implementing a Func.
+type Func func(Arguments) reflect.Value

+ 684 - 0
vendor/github.com/CloudyKit/jet/v4/lex.go

@@ -0,0 +1,684 @@
+// Copyright 2016 José Santos <henrique_1609@me.com>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+	"fmt"
+	"strings"
+	"unicode"
+	"unicode/utf8"
+)
+
+// item represents a token or text string returned from the scanner.
+type item struct {
+	typ itemType // The type of this item.
+	pos Pos      // The starting position, in bytes, of this item in the input string.
+	val string   // The value of this item.
+}
+
+func (i item) String() string {
+	switch {
+	case i.typ == itemEOF:
+		return "EOF"
+	case i.typ == itemError:
+		return i.val
+	case i.typ > itemKeyword:
+		return fmt.Sprintf("<%s>", i.val)
+	case len(i.val) > 10:
+		return fmt.Sprintf("%.10q...", i.val)
+	}
+	return fmt.Sprintf("%q", i.val)
+}
+
+// itemType identifies the type of lex items.
+type itemType int
+
+const (
+	itemError        itemType = iota // error occurred; value is text of error
+	itemBool                         // boolean constant
+	itemChar                         // printable ASCII character; grab bag for comma etc.
+	itemCharConstant                 // character constant
+	itemComplex                      // complex constant (1+2i); imaginary is just a number
+	itemEOF
+	itemField      // alphanumeric identifier starting with '.'
+	itemIdentifier // alphanumeric identifier not starting with '.'
+	itemLeftDelim  // left action delimiter
+	itemLeftParen  // '(' inside action
+	itemNumber     // simple number, including imaginary
+	itemPipe       // pipe symbol
+	itemRawString  // raw quoted string (includes quotes)
+	itemRightDelim // right action delimiter
+	itemRightParen // ')' inside action
+	itemSpace      // run of spaces separating arguments
+	itemString     // quoted string (includes quotes)
+	itemText       // plain text
+	itemAssign
+	itemEquals
+	itemNotEquals
+	itemGreat
+	itemGreatEquals
+	itemLess
+	itemLessEquals
+	itemComma
+	itemSemicolon
+	itemAdd
+	itemMinus
+	itemMul
+	itemDiv
+	itemMod
+	itemColon
+	itemTernary
+	itemLeftBrackets
+	itemRightBrackets
+	// Keywords appear after all the rest.
+	itemKeyword // used only to delimit the keywords
+	itemExtends
+	itemImport
+	itemInclude
+	itemBlock
+	itemEnd
+	itemYield
+	itemContent
+	itemIf
+	itemElse
+	itemRange
+	itemTry
+	itemCatch
+	itemReturn
+	itemAnd
+	itemOr
+	itemNot
+	itemNil
+	itemMSG
+	itemTrans
+)
+
+var key = map[string]itemType{
+	"extends": itemExtends,
+	"import":  itemImport,
+
+	"include": itemInclude,
+	"block":   itemBlock,
+	"end":     itemEnd,
+	"yield":   itemYield,
+	"content": itemContent,
+
+	"if":   itemIf,
+	"else": itemElse,
+
+	"range": itemRange,
+
+	"try":   itemTry,
+	"catch": itemCatch,
+
+	"return": itemReturn,
+
+	"and": itemAnd,
+	"or":  itemOr,
+	"not": itemNot,
+
+	"nil": itemNil,
+
+	"msg":   itemMSG,
+	"trans": itemTrans,
+}
+
+const eof = -1
+
+const (
+	defaultLeftDelim  = "{{"
+	defaultRightDelim = "}}"
+	leftComment       = "{*"
+	rightComment      = "*}"
+)
+
+// stateFn represents the state of the scanner as a function that returns the next state.
+type stateFn func(*lexer) stateFn
+
+// lexer holds the state of the scanner.
+type lexer struct {
+	name       string    // the name of the input; used only for error reports
+	input      string    // the string being scanned
+	state      stateFn   // the next lexing function to enter
+	pos        Pos       // current position in the input
+	start      Pos       // start position of this item
+	width      Pos       // width of last rune read from input
+	lastPos    Pos       // position of most recent item returned by nextItem
+	items      chan item // channel of scanned items
+	parenDepth int       // nesting depth of ( ) exprs
+	lastType   itemType
+	leftDelim  string
+	rightDelim string
+}
+
+func (l *lexer) setDelimiters(leftDelim, rightDelim string) {
+	if leftDelim != "" {
+		l.leftDelim = leftDelim
+	}
+	if rightDelim != "" {
+		l.rightDelim = rightDelim
+	}
+}
+
+// next returns the next rune in the input.
+func (l *lexer) next() rune {
+	if int(l.pos) >= len(l.input) {
+		l.width = 0
+		return eof
+	}
+	r, w := utf8.DecodeRuneInString(l.input[l.pos:])
+	l.width = Pos(w)
+	l.pos += l.width
+	return r
+}
+
+// peek returns but does not consume the next rune in the input.
+func (l *lexer) peek() rune {
+	r := l.next()
+	l.backup()
+	return r
+}
+
+// backup steps back one rune. Can only be called once per call of next.
+func (l *lexer) backup() {
+	l.pos -= l.width
+}
+
+// emit passes an item back to the client.
+func (l *lexer) emit(t itemType) {
+	l.lastType = t
+	l.items <- item{t, l.start, l.input[l.start:l.pos]}
+	l.start = l.pos
+}
+
+// ignore skips over the pending input before this point.
+func (l *lexer) ignore() {
+	l.start = l.pos
+}
+
+// accept consumes the next rune if it's from the valid set.
+func (l *lexer) accept(valid string) bool {
+	if strings.IndexRune(valid, l.next()) >= 0 {
+		return true
+	}
+	l.backup()
+	return false
+}
+
+// acceptRun consumes a run of runes from the valid set.
+func (l *lexer) acceptRun(valid string) {
+	for strings.IndexRune(valid, l.next()) >= 0 {
+	}
+	l.backup()
+}
+
+// lineNumber reports which line we're on, based on the position of
+// the previous item returned by nextItem. Doing it this way
+// means we don't have to worry about peek double counting.
+func (l *lexer) lineNumber() int {
+	return 1 + strings.Count(l.input[:l.lastPos], "\n")
+}
+
+// errorf returns an error token and terminates the scan by passing
+// back a nil pointer that will be the next state, terminating l.nextItem.
+func (l *lexer) errorf(format string, args ...interface{}) stateFn {
+	l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
+	return nil
+}
+
+// nextItem returns the next item from the input.
+// Called by the parser, not in the lexing goroutine.
+func (l *lexer) nextItem() item {
+	item := <-l.items
+	l.lastPos = item.pos
+	return item
+}
+
+// drain drains the output so the lexing goroutine will exit.
+// Called by the parser, not in the lexing goroutine.
+func (l *lexer) drain() {
+	for range l.items {
+	}
+}
+
+// lex creates a new scanner for the input string.
+func lex(name, input string, run bool) *lexer {
+	l := &lexer{
+		name:       name,
+		input:      input,
+		items:      make(chan item),
+		leftDelim:  defaultLeftDelim,
+		rightDelim: defaultRightDelim,
+	}
+	if run {
+		l.run()
+	}
+	return l
+}
+
+// run runs the state machine for the lexer.
+func (l *lexer) run() {
+	go func() {
+		for l.state = lexText; l.state != nil; {
+			l.state = l.state(l)
+		}
+		close(l.items)
+	}()
+}
+
+// state functions
+func lexText(l *lexer) stateFn {
+	for {
+		if i := strings.IndexByte(l.input[l.pos:], l.leftDelim[0]); i == -1 {
+			l.pos = Pos(len(l.input))
+			break
+		} else {
+			l.pos += Pos(i)
+			if strings.HasPrefix(l.input[l.pos:], l.leftDelim) {
+				if l.pos > l.start {
+					l.emit(itemText)
+				}
+				return lexLeftDelim
+			}
+			if strings.HasPrefix(l.input[l.pos:], leftComment) {
+				if l.pos > l.start {
+					l.emit(itemText)
+				}
+				return lexComment
+			}
+		}
+		if l.next() == eof {
+			break
+		}
+	}
+	// Correctly reached EOF.
+	if l.pos > l.start {
+		l.emit(itemText)
+	}
+	l.emit(itemEOF)
+	return nil
+}
+
+func lexLeftDelim(l *lexer) stateFn {
+	l.pos += Pos(len(l.leftDelim))
+	l.emit(itemLeftDelim)
+	l.parenDepth = 0
+	return lexInsideAction
+}
+
+// lexComment scans a comment. The left comment marker is known to be present.
+func lexComment(l *lexer) stateFn {
+	l.pos += Pos(len(leftComment))
+	i := strings.Index(l.input[l.pos:], rightComment)
+	if i < 0 {
+		return l.errorf("unclosed comment")
+	}
+	l.pos += Pos(i + len(rightComment))
+	l.ignore()
+	return lexText
+}
+
+// lexRightDelim scans the right delimiter, which is known to be present.
+func lexRightDelim(l *lexer) stateFn {
+	l.pos += Pos(len(l.rightDelim))
+	l.emit(itemRightDelim)
+	return lexText
+}
+
+// lexInsideAction scans the elements inside action delimiters.
+func lexInsideAction(l *lexer) stateFn {
+	// Either number, quoted string, or identifier.
+	// Spaces separate arguments; runs of spaces turn into itemSpace.
+	// Pipe symbols separate and are emitted.
+	if strings.HasPrefix(l.input[l.pos:], l.rightDelim) {
+		if l.parenDepth == 0 {
+			return lexRightDelim
+		}
+		return l.errorf("unclosed left paren")
+	}
+	switch r := l.next(); {
+	case r == eof:
+		return l.errorf("unclosed action")
+	case isSpace(r):
+		return lexSpace
+	case r == ',':
+		l.emit(itemComma)
+	case r == ';':
+		l.emit(itemSemicolon)
+	case r == '*':
+		l.emit(itemMul)
+	case r == '/':
+		l.emit(itemDiv)
+	case r == '%':
+		l.emit(itemMod)
+	case r == '-':
+
+		if r := l.peek(); '0' <= r && r <= '9' &&
+			itemAdd != l.lastType &&
+			itemMinus != l.lastType &&
+			itemNumber != l.lastType &&
+			itemIdentifier != l.lastType &&
+			itemString != l.lastType &&
+			itemRawString != l.lastType &&
+			itemCharConstant != l.lastType &&
+			itemBool != l.lastType &&
+			itemField != l.lastType &&
+			itemChar != l.lastType &&
+			itemTrans != l.lastType {
+			l.backup()
+			return lexNumber
+		}
+		l.emit(itemMinus)
+	case r == '+':
+		if r := l.peek(); '0' <= r && r <= '9' &&
+			itemAdd != l.lastType &&
+			itemMinus != l.lastType &&
+			itemNumber != l.lastType &&
+			itemIdentifier != l.lastType &&
+			itemString != l.lastType &&
+			itemRawString != l.lastType &&
+			itemCharConstant != l.lastType &&
+			itemBool != l.lastType &&
+			itemField != l.lastType &&
+			itemChar != l.lastType &&
+			itemTrans != l.lastType {
+			l.backup()
+			return lexNumber
+		}
+		l.emit(itemAdd)
+	case r == '?':
+		l.emit(itemTernary)
+	case r == '&':
+		if l.next() == '&' {
+			l.emit(itemAnd)
+		} else {
+			l.backup()
+		}
+	case r == '<':
+		if l.next() == '=' {
+			l.emit(itemLessEquals)
+		} else {
+			l.backup()
+			l.emit(itemLess)
+		}
+	case r == '>':
+		if l.next() == '=' {
+			l.emit(itemGreatEquals)
+		} else {
+			l.backup()
+			l.emit(itemGreat)
+		}
+	case r == '!':
+		if l.next() == '=' {
+			l.emit(itemNotEquals)
+		} else {
+			l.backup()
+			l.emit(itemNot)
+		}
+
+	case r == '=':
+		if l.next() == '=' {
+			l.emit(itemEquals)
+		} else {
+			l.backup()
+			l.emit(itemAssign)
+		}
+	case r == ':':
+		if l.next() == '=' {
+			l.emit(itemAssign)
+		} else {
+			l.backup()
+			l.emit(itemColon)
+		}
+	case r == '|':
+		if l.next() == '|' {
+			l.emit(itemOr)
+		} else {
+			l.backup()
+			l.emit(itemPipe)
+		}
+	case r == '"':
+		return lexQuote
+	case r == '`':
+		return lexRawQuote
+	case r == '\'':
+		return lexChar
+	case r == '.':
+		// special look-ahead for ".field" so we don't break l.backup().
+		if l.pos < Pos(len(l.input)) {
+			r := l.input[l.pos]
+			if r < '0' || '9' < r {
+				return lexField
+			}
+		}
+		fallthrough // '.' can start a number.
+	case '0' <= r && r <= '9':
+		l.backup()
+		return lexNumber
+	case isAlphaNumeric(r):
+		l.backup()
+		return lexIdentifier
+	case r == '[':
+		l.emit(itemLeftBrackets)
+	case r == ']':
+		l.emit(itemRightBrackets)
+	case r == '(':
+		l.emit(itemLeftParen)
+		l.parenDepth++
+	case r == ')':
+		l.emit(itemRightParen)
+		l.parenDepth--
+		if l.parenDepth < 0 {
+			return l.errorf("unexpected right paren %#U", r)
+		}
+	case r <= unicode.MaxASCII && unicode.IsPrint(r):
+		l.emit(itemChar)
+		return lexInsideAction
+	default:
+		return l.errorf("unrecognized character in action: %#U", r)
+	}
+	return lexInsideAction
+}
+
+// lexSpace scans a run of space characters.
+// One space has already been seen.
+func lexSpace(l *lexer) stateFn {
+	for isSpace(l.peek()) {
+		l.next()
+	}
+	l.emit(itemSpace)
+	return lexInsideAction
+}
+
+// lexIdentifier scans an alphanumeric.
+func lexIdentifier(l *lexer) stateFn {
+Loop:
+	for {
+		switch r := l.next(); {
+		case isAlphaNumeric(r):
+		// absorb.
+		default:
+			l.backup()
+			word := l.input[l.start:l.pos]
+			if !l.atTerminator() {
+				return l.errorf("bad character %#U", r)
+			}
+			switch {
+			case key[word] > itemKeyword:
+				l.emit(key[word])
+			case word[0] == '.':
+				l.emit(itemField)
+			case word == "true", word == "false":
+				l.emit(itemBool)
+			default:
+				l.emit(itemIdentifier)
+			}
+			break Loop
+		}
+	}
+	return lexInsideAction
+}
+
+// lexField scans a field: .Alphanumeric.
+// The . has been scanned.
+func lexField(l *lexer) stateFn {
+
+	if l.atTerminator() {
+		// Nothing interesting follows -> "." or "$".
+		l.emit(itemIdentifier)
+		return lexInsideAction
+	}
+
+	var r rune
+	for {
+		r = l.next()
+		if !isAlphaNumeric(r) {
+			l.backup()
+			break
+		}
+	}
+	if !l.atTerminator() {
+		return l.errorf("bad character %#U", r)
+	}
+	l.emit(itemField)
+	return lexInsideAction
+}
+
+// atTerminator reports whether the input is at valid termination character to
+// appear after an identifier. Breaks .X.Y into two pieces. Also catches cases
+// like "$x+2" not being acceptable without a space, in case we decide one
+// day to implement arithmetic.
+func (l *lexer) atTerminator() bool {
+	r := l.peek()
+	if isSpace(r) {
+		return true
+	}
+	switch r {
+	case eof, '.', ',', '|', ':', ')', '=', '(', ';', '?', '[', ']', '+', '-', '/', '%', '*', '&', '!', '<', '>':
+		return true
+	}
+	// Does r start the delimiter? This can be ambiguous (with delim=="//", $x/2 will
+	// succeed but should fail) but only in extremely rare cases caused by willfully
+	// bad choice of delimiter.
+	if rd, _ := utf8.DecodeRuneInString(l.rightDelim); rd == r {
+		return true
+	}
+	return false
+}
+
+// lexChar scans a character constant. The initial quote is already
+// scanned. Syntax checking is done by the parser.
+func lexChar(l *lexer) stateFn {
+Loop:
+	for {
+		switch l.next() {
+		case '\\':
+			if r := l.next(); r != eof && r != '\n' {
+				break
+			}
+			fallthrough
+		case eof, '\n':
+			return l.errorf("unterminated character constant")
+		case '\'':
+			break Loop
+		}
+	}
+	l.emit(itemCharConstant)
+	return lexInsideAction
+}
+
+// lexNumber scans a number: decimal, octal, hex, float, or imaginary. This
+// isn't a perfect number scanner - for instance it accepts "." and "0x0.2"
+// and "089" - but when it's wrong the input is invalid and the parser (via
+// strconv) will notice.
+func lexNumber(l *lexer) stateFn {
+	if !l.scanNumber() {
+		return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
+	}
+
+	l.emit(itemNumber)
+	return lexInsideAction
+}
+
+func (l *lexer) scanNumber() bool {
+	// Optional leading sign.
+	l.accept("+-")
+	// Is it hex?
+	digits := "0123456789"
+	if l.accept("0") && l.accept("xX") {
+		digits = "0123456789abcdefABCDEF"
+	}
+	l.acceptRun(digits)
+	if l.accept(".") {
+		l.acceptRun(digits)
+	}
+	if l.accept("eE") {
+		l.accept("+-")
+		l.acceptRun("0123456789")
+	}
+	//Is it imaginary?
+	l.accept("i")
+	//Next thing mustn't be alphanumeric.
+	if isAlphaNumeric(l.peek()) {
+		l.next()
+		return false
+	}
+	return true
+}
+
+// lexQuote scans a quoted string.
+func lexQuote(l *lexer) stateFn {
+Loop:
+	for {
+		switch l.next() {
+		case '\\':
+			if r := l.next(); r != eof && r != '\n' {
+				break
+			}
+			fallthrough
+		case eof, '\n':
+			return l.errorf("unterminated quoted string")
+		case '"':
+			break Loop
+		}
+	}
+	l.emit(itemString)
+	return lexInsideAction
+}
+
+// lexRawQuote scans a raw quoted string.
+func lexRawQuote(l *lexer) stateFn {
+Loop:
+	for {
+		switch l.next() {
+		case eof:
+			return l.errorf("unterminated raw quoted string")
+		case '`':
+			break Loop
+		}
+	}
+	l.emit(itemRawString)
+	return lexInsideAction
+}
+
+// isSpace reports whether r is a space character.
+func isSpace(r rune) bool {
+	return r == ' ' || r == '\t' || r == '\r' || r == '\n'
+}
+
+// isAlphaNumeric reports whether r is an alphabetic, digit, or underscore.
+func isAlphaNumeric(r rune) bool {
+	return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
+}

+ 60 - 0
vendor/github.com/CloudyKit/jet/v4/loader.go

@@ -0,0 +1,60 @@
+// Copyright 2016 José Santos <henrique_1609@me.com>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+	"io"
+	"os"
+	"path/filepath"
+)
+
+// Loader is a minimal interface required for loading templates.
+type Loader interface {
+	// Exists checks for template existence.
+	Exists(path string) (string, bool)
+	// Open opens the underlying reader with template content.
+	Open(path string) (io.ReadCloser, error)
+}
+
+// OSFileSystemLoader implements Loader interface using OS file system (os.File).
+type OSFileSystemLoader struct {
+	dir string
+}
+
+// compile time check that we implement Loader
+var _ Loader = (*OSFileSystemLoader)(nil)
+
+// NewOSFileSystemLoader returns an initialized OSFileSystemLoader.
+func NewOSFileSystemLoader(dirPath string) *OSFileSystemLoader {
+	return &OSFileSystemLoader{
+		dir: dirPath,
+	}
+}
+
+// Open opens a file from OS file system.
+func (l *OSFileSystemLoader) Open(path string) (io.ReadCloser, error) {
+	return os.Open(filepath.Join(l.dir, path))
+}
+
+// Exists checks if the template name exists by walking the list of template paths
+// returns true if the template file was found
+func (l *OSFileSystemLoader) Exists(path string) (string, bool) {
+	path = filepath.Join(l.dir, path)
+	stat, err := os.Stat(path)
+	if err == nil && !stat.IsDir() {
+		return path, true
+	}
+	return "", false
+}

+ 695 - 0
vendor/github.com/CloudyKit/jet/v4/node.go

@@ -0,0 +1,695 @@
+// Copyright 2016 José Santos <henrique_1609@me.com>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+	"bytes"
+	"fmt"
+)
+
+var textFormat = "%s" //Changed to "%q" in tests for better error messages.
+
+type Node interface {
+	Type() NodeType
+	String() string
+	Position() Pos
+	line() int
+	error(error)
+	errorf(string, ...interface{})
+}
+
+type Expression interface {
+	Node
+}
+
+// Pos represents a byte position in the original input text from which
+// this template was parsed.
+type Pos int
+
+func (p Pos) Position() Pos {
+	return p
+}
+
+// NodeType identifies the type of a parse tree node.
+type NodeType int
+
+type NodeBase struct {
+	TemplatePath string
+	Line         int
+	NodeType
+	Pos
+}
+
+func (node *NodeBase) line() int {
+	return node.Line
+}
+
+func (node *NodeBase) error(err error) {
+	node.errorf("%s", err)
+}
+
+func (node *NodeBase) errorf(format string, v ...interface{}) {
+	panic(fmt.Errorf("Jet Runtime Error (%q:%d): %s", node.TemplatePath, node.Line, fmt.Sprintf(format, v...)))
+}
+
+// Type returns itself and provides an easy default implementation
+// for embedding in a Node. Embedded in all non-trivial Nodes.
+func (t NodeType) Type() NodeType {
+	return t
+}
+
+const (
+	NodeText       NodeType = iota //Plain text.
+	NodeAction                     //A non-control action such as a field evaluation.
+	NodeChain                      //A sequence of field accesses.
+	NodeCommand                    //An element of a pipeline.
+	NodeField                      //A field or method name.
+	NodeIdentifier                 //An identifier; always a function name.
+	NodeList                       //A list of Nodes.
+	NodePipe                       //A pipeline of commands.
+	NodeSet
+	//NodeWith                       //A with action.
+	NodeInclude
+	NodeBlock
+	nodeEnd //An end action. Not added to tree.
+	NodeYield
+	nodeContent
+	NodeIf    //An if action.
+	nodeElse  //An else action. Not added to tree.
+	NodeRange //A range action.
+	NodeTry
+	nodeCatch
+	NodeReturn
+	beginExpressions
+	NodeString //A string constant.
+	NodeNil    //An untyped nil constant.
+	NodeNumber //A numerical constant.
+	NodeBool   //A boolean constant.
+	NodeAdditiveExpr
+	NodeMultiplicativeExpr
+	NodeComparativeExpr
+	NodeNumericComparativeExpr
+	NodeLogicalExpr
+	NodeCallExpr
+	NodeNotExpr
+	NodeTernaryExpr
+	NodeIndexExpr
+	NodeSliceExpr
+	endExpressions
+)
+
+// Nodes.
+
+// ListNode holds a sequence of nodes.
+type ListNode struct {
+	NodeBase
+	Nodes []Node //The element nodes in lexical order.
+}
+
+func (l *ListNode) append(n Node) {
+	l.Nodes = append(l.Nodes, n)
+}
+
+func (l *ListNode) String() string {
+	b := new(bytes.Buffer)
+	for _, n := range l.Nodes {
+		fmt.Fprint(b, n)
+	}
+	return b.String()
+}
+
+// TextNode holds plain text.
+type TextNode struct {
+	NodeBase
+	Text []byte
+}
+
+func (t *TextNode) String() string {
+	return fmt.Sprintf(textFormat, t.Text)
+}
+
+// PipeNode holds a pipeline with optional declaration
+type PipeNode struct {
+	NodeBase                //The line number in the input. Deprecated: Kept for compatibility.
+	Cmds     []*CommandNode //The commands in lexical order.
+}
+
+func (p *PipeNode) append(command *CommandNode) {
+	p.Cmds = append(p.Cmds, command)
+}
+
+func (p *PipeNode) String() string {
+	s := ""
+	for i, c := range p.Cmds {
+		if i > 0 {
+			s += " | "
+		}
+		s += c.String()
+	}
+	return s
+}
+
+// ActionNode holds an action (something bounded by delimiters).
+// Control actions have their own nodes; ActionNode represents simple
+// ones such as field evaluations and parenthesized pipelines.
+type ActionNode struct {
+	NodeBase
+	Set  *SetNode
+	Pipe *PipeNode
+}
+
+func (a *ActionNode) String() string {
+	if a.Set != nil {
+		if a.Pipe == nil {
+			return fmt.Sprintf("{{%s}}", a.Set)
+		}
+		return fmt.Sprintf("{{%s;%s}}", a.Set, a.Pipe)
+	}
+	return fmt.Sprintf("{{%s}}", a.Pipe)
+}
+
+// CommandNode holds a command (a pipeline inside an evaluating action).
+type CommandNode struct {
+	NodeBase
+	CallExprNode
+}
+
+func (c *CommandNode) append(arg Node) {
+	c.Args = append(c.Args, arg)
+}
+
+func (c *CommandNode) String() string {
+	if c.Args == nil {
+		return c.BaseExpr.String()
+	}
+
+	arguments := ""
+	for i, expr := range c.Args {
+		if i > 0 {
+			arguments += ", "
+		}
+		arguments += expr.String()
+	}
+	return fmt.Sprintf("%s(%s)", c.BaseExpr, arguments)
+}
+
+// IdentifierNode holds an identifier.
+type IdentifierNode struct {
+	NodeBase
+	Ident string //The identifier's name.
+}
+
+func (i *IdentifierNode) String() string {
+	return i.Ident
+}
+
+// NilNode holds the special identifier 'nil' representing an untyped nil constant.
+type NilNode struct {
+	NodeBase
+}
+
+func (n *NilNode) String() string {
+	return "nil"
+}
+
+// FieldNode holds a field (identifier starting with '.').
+// The names may be chained ('.x.y').
+// The period is dropped from each ident.
+type FieldNode struct {
+	NodeBase
+	Ident []string //The identifiers in lexical order.
+}
+
+func (f *FieldNode) String() string {
+	s := ""
+	for _, id := range f.Ident {
+		s += "." + id
+	}
+	return s
+}
+
+// ChainNode holds a term followed by a chain of field accesses (identifier starting with '.').
+// The names may be chained ('.x.y').
+// The periods are dropped from each ident.
+type ChainNode struct {
+	NodeBase
+	Node  Node
+	Field []string //The identifiers in lexical order.
+}
+
+// Add adds the named field (which should start with a period) to the end of the chain.
+func (c *ChainNode) Add(field string) {
+	if len(field) == 0 || field[0] != '.' {
+		panic("no dot in field")
+	}
+	field = field[1:] //Remove leading dot.
+	if field == "" {
+		panic("empty field")
+	}
+	c.Field = append(c.Field, field)
+}
+
+func (c *ChainNode) String() string {
+	s := c.Node.String()
+	if _, ok := c.Node.(*PipeNode); ok {
+		s = "(" + s + ")"
+	}
+	for _, field := range c.Field {
+		s += "." + field
+	}
+	return s
+}
+
+// BoolNode holds a boolean constant.
+type BoolNode struct {
+	NodeBase
+	True bool //The value of the boolean constant.
+}
+
+func (b *BoolNode) String() string {
+	if b.True {
+		return "true"
+	}
+	return "false"
+}
+
+// NumberNode holds a number: signed or unsigned integer, float, or complex.
+// The value is parsed and stored under all the types that can represent the value.
+// This simulates in a small amount of code the behavior of Go's ideal constants.
+type NumberNode struct {
+	NodeBase
+
+	IsInt      bool       //Number has an integral value.
+	IsUint     bool       //Number has an unsigned integral value.
+	IsFloat    bool       //Number has a floating-point value.
+	IsComplex  bool       //Number is complex.
+	Int64      int64      //The signed integer value.
+	Uint64     uint64     //The unsigned integer value.
+	Float64    float64    //The floating-point value.
+	Complex128 complex128 //The complex value.
+	Text       string     //The original textual representation from the input.
+}
+
+// simplifyComplex pulls out any other types that are represented by the complex number.
+// These all require that the imaginary part be zero.
+func (n *NumberNode) simplifyComplex() {
+	n.IsFloat = imag(n.Complex128) == 0
+	if n.IsFloat {
+		n.Float64 = real(n.Complex128)
+		n.IsInt = float64(int64(n.Float64)) == n.Float64
+		if n.IsInt {
+			n.Int64 = int64(n.Float64)
+		}
+		n.IsUint = float64(uint64(n.Float64)) == n.Float64
+		if n.IsUint {
+			n.Uint64 = uint64(n.Float64)
+		}
+	}
+}
+
+func (n *NumberNode) String() string {
+	return n.Text
+}
+
+// StringNode holds a string constant. The value has been "unquoted".
+type StringNode struct {
+	NodeBase
+
+	Quoted string //The original text of the string, with quotes.
+	Text   string //The string, after quote processing.
+}
+
+func (s *StringNode) String() string {
+	return s.Quoted
+}
+
+// endNode represents an {{end}} action.
+// It does not appear in the final parse tree.
+type endNode struct {
+	NodeBase
+}
+
+func (e *endNode) String() string {
+	return "{{end}}"
+}
+
+// endNode represents an {{end}} action.
+// It does not appear in the final parse tree.
+type contentNode struct {
+	NodeBase
+}
+
+func (e *contentNode) String() string {
+	return "{{content}}"
+}
+
+// elseNode represents an {{else}} action. Does not appear in the final tree.
+type elseNode struct {
+	NodeBase //The line number in the input. Deprecated: Kept for compatibility.
+}
+
+func (e *elseNode) String() string {
+	return "{{else}}"
+}
+
+// SetNode represents a set action, ident( ',' ident)* '=' expression ( ',' expression )*
+type SetNode struct {
+	NodeBase
+	Let                bool
+	IndexExprGetLookup bool
+	Left               []Expression
+	Right              []Expression
+}
+
+func (set *SetNode) String() string {
+	var s = ""
+
+	for i, v := range set.Left {
+		if i > 0 {
+			s += ", "
+		}
+		s += v.String()
+	}
+
+	if set.Let {
+		s += ":="
+	} else {
+		s += "="
+	}
+
+	for i, v := range set.Right {
+		if i > 0 {
+			s += ", "
+		}
+		s += v.String()
+	}
+
+	return s
+}
+
+// BranchNode is the common representation of if, range, and with.
+type BranchNode struct {
+	NodeBase
+	Set        *SetNode
+	Expression Expression
+	List       *ListNode
+	ElseList   *ListNode
+}
+
+func (b *BranchNode) String() string {
+
+	if b.NodeType == NodeRange {
+		s := ""
+		if b.Set != nil {
+			s = b.Set.String()
+		} else {
+			s = b.Expression.String()
+		}
+
+		if b.ElseList != nil {
+			return fmt.Sprintf("{{range %s}}%s{{else}}%s{{end}}", s, b.List, b.ElseList)
+		}
+		return fmt.Sprintf("{{range %s}}%s{{end}}", s, b.List)
+	} else {
+		s := ""
+		if b.Set != nil {
+			s = b.Set.String() + ";"
+		}
+		if b.ElseList != nil {
+			return fmt.Sprintf("{{if %s%s}}%s{{else}}%s{{end}}", s, b.Expression, b.List, b.ElseList)
+		}
+		return fmt.Sprintf("{{if %s%s}}%s{{end}}", s, b.Expression, b.List)
+	}
+}
+
+// IfNode represents an {{if}} action and its commands.
+type IfNode struct {
+	BranchNode
+}
+
+// RangeNode represents a {{range}} action and its commands.
+type RangeNode struct {
+	BranchNode
+}
+
+type BlockParameter struct {
+	Identifier string
+	Expression Expression
+}
+
+type BlockParameterList struct {
+	NodeBase
+	List []BlockParameter
+}
+
+func (bplist *BlockParameterList) Param(name string) (Expression, int) {
+	for i := 0; i < len(bplist.List); i++ {
+		param := &bplist.List[i]
+		if param.Identifier == name {
+			return param.Expression, i
+		}
+	}
+	return nil, -1
+}
+
+func (bplist *BlockParameterList) String() (str string) {
+	buff := bytes.NewBuffer(nil)
+	for _, bp := range bplist.List {
+		if bp.Identifier == "" {
+			fmt.Fprintf(buff, "%s,", bp.Expression)
+		} else {
+			if bp.Expression == nil {
+				fmt.Fprintf(buff, "%s,", bp.Identifier)
+			} else {
+				fmt.Fprintf(buff, "%s=%s,", bp.Identifier, bp.Expression)
+			}
+		}
+	}
+	if buff.Len() > 0 {
+		str = buff.String()[0 : buff.Len()-1]
+	}
+	return
+}
+
+// BlockNode represents a {{block }} action.
+type BlockNode struct {
+	NodeBase        //The line number in the input. Deprecated: Kept for compatibility.
+	Name     string //The name of the template (unquoted).
+
+	Parameters *BlockParameterList
+	Expression Expression //The command to evaluate as dot for the template.
+
+	List    *ListNode
+	Content *ListNode
+}
+
+func (t *BlockNode) String() string {
+	if t.Content != nil {
+		if t.Expression == nil {
+			return fmt.Sprintf("{{block %s(%s)}}%s{{content}}%s{{end}}", t.Name, t.Parameters, t.List, t.Content)
+		}
+		return fmt.Sprintf("{{block %s(%s) %s}}%s{{content}}%s{{end}}", t.Name, t.Parameters, t.Expression, t.List, t.Content)
+	}
+	if t.Expression == nil {
+		return fmt.Sprintf("{{block %s(%s)}}%s{{end}}", t.Name, t.Parameters, t.List)
+	}
+	return fmt.Sprintf("{{block %s(%s) %s}}%s{{end}}", t.Name, t.Parameters, t.Expression, t.List)
+}
+
+// YieldNode represents a {{yield}} action
+type YieldNode struct {
+	NodeBase          //The line number in the input. Deprecated: Kept for compatibility.
+	Name       string //The name of the template (unquoted).
+	Parameters *BlockParameterList
+	Expression Expression //The command to evaluate as dot for the template.
+	Content    *ListNode
+	IsContent  bool
+}
+
+func (t *YieldNode) String() string {
+	if t.IsContent {
+		if t.Expression == nil {
+			return "{{yield content}}"
+		}
+		return fmt.Sprintf("{{yield content %s}}", t.Expression)
+	}
+
+	if t.Content != nil {
+		if t.Expression == nil {
+			return fmt.Sprintf("{{yield %s(%s) content}}%s{{end}}", t.Name, t.Parameters, t.Content)
+		}
+		return fmt.Sprintf("{{yield %s(%s) %s content}}%s{{end}}", t.Name, t.Parameters, t.Expression, t.Content)
+	}
+
+	if t.Expression == nil {
+		return fmt.Sprintf("{{yield %s(%s)}}", t.Name, t.Parameters)
+	}
+	return fmt.Sprintf("{{yield %s(%s) %s}}", t.Name, t.Parameters, t.Expression)
+}
+
+// IncludeNode represents a {{include }} action.
+type IncludeNode struct {
+	NodeBase
+	Name    Expression
+	Context Expression
+}
+
+func (t *IncludeNode) String() string {
+	if t.Context == nil {
+		return fmt.Sprintf("{{include %s}}", t.Name)
+	}
+	return fmt.Sprintf("{{include %s %s}}", t.Name, t.Context)
+}
+
+type binaryExprNode struct {
+	NodeBase
+	Operator    item
+	Left, Right Expression
+}
+
+func (node *binaryExprNode) String() string {
+	return fmt.Sprintf("%s %s %s", node.Left, node.Operator.val, node.Right)
+}
+
+// AdditiveExprNode represents an add or subtract expression
+// ex: expression ( '+' | '-' ) expression
+type AdditiveExprNode struct {
+	binaryExprNode
+}
+
+// MultiplicativeExprNode represents a multiplication, division, or module expression
+// ex: expression ( '*' | '/' | '%' ) expression
+type MultiplicativeExprNode struct {
+	binaryExprNode
+}
+
+// LogicalExprNode represents a boolean expression, 'and' or 'or'
+// ex: expression ( '&&' | '||' ) expression
+type LogicalExprNode struct {
+	binaryExprNode
+}
+
+// ComparativeExprNode represents a comparative expression
+// ex: expression ( '==' | '!=' ) expression
+type ComparativeExprNode struct {
+	binaryExprNode
+}
+
+// NumericComparativeExprNode represents a numeric comparative expression
+// ex: expression ( '<' | '>' | '<=' | '>=' ) expression
+type NumericComparativeExprNode struct {
+	binaryExprNode
+}
+
+// NotExprNode represents a negate expression
+// ex: '!' expression
+type NotExprNode struct {
+	NodeBase
+	Expr Expression
+}
+
+func (s *NotExprNode) String() string {
+	return fmt.Sprintf("!%s", s.Expr)
+}
+
+// CallExprNode represents a call expression
+// ex: expression '(' (expression (',' expression)* )? ')'
+type CallExprNode struct {
+	NodeBase
+	BaseExpr Expression
+	Args     []Expression
+}
+
+func (s *CallExprNode) String() string {
+	arguments := ""
+	for i, expr := range s.Args {
+		if i > 0 {
+			arguments += ", "
+		}
+		arguments += expr.String()
+	}
+	return fmt.Sprintf("%s(%s)", s.BaseExpr, arguments)
+}
+
+// TernaryExprNod represents a ternary expression,
+// ex: expression '?' expression ':' expression
+type TernaryExprNode struct {
+	NodeBase
+	Boolean, Left, Right Expression
+}
+
+func (s *TernaryExprNode) String() string {
+	return fmt.Sprintf("%s?%s:%s", s.Boolean, s.Left, s.Right)
+}
+
+type IndexExprNode struct {
+	NodeBase
+	Base  Expression
+	Index Expression
+}
+
+func (s *IndexExprNode) String() string {
+	return fmt.Sprintf("%s[%s]", s.Base, s.Index)
+}
+
+type SliceExprNode struct {
+	NodeBase
+	Base     Expression
+	Index    Expression
+	EndIndex Expression
+}
+
+func (s *SliceExprNode) String() string {
+	var index_string, len_string string
+	if s.Index != nil {
+		index_string = s.Index.String()
+	}
+	if s.EndIndex != nil {
+		len_string = s.EndIndex.String()
+	}
+	return fmt.Sprintf("%s[%s:%s]", s.Base, index_string, len_string)
+}
+
+type ReturnNode struct {
+	NodeBase
+	Value Expression
+}
+
+func (n *ReturnNode) String() string {
+	return fmt.Sprintf("return %v", n.Value)
+}
+
+type TryNode struct {
+	NodeBase
+	List  *ListNode
+	Catch *catchNode
+}
+
+func (n *TryNode) String() string {
+	if n.Catch != nil {
+		return fmt.Sprintf("{{try}}%s%s", n.List, n.Catch)
+	}
+	return fmt.Sprintf("{{try}}%s{{end}}", n.List)
+}
+
+type catchNode struct {
+	NodeBase
+	Err  *IdentifierNode
+	List *ListNode
+}
+
+func (n *catchNode) String() string {
+	return fmt.Sprintf("{{catch %s}}%s{{end}}", n.Err, n.List)
+}

+ 1004 - 0
vendor/github.com/CloudyKit/jet/v4/parse.go

@@ -0,0 +1,1004 @@
+// Copyright 2016 José Santos <henrique_1609@me.com>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+	"bytes"
+	"fmt"
+	"runtime"
+	"strconv"
+	"strings"
+)
+
+func unquote(text string) (string, error) {
+	return strconv.Unquote(text)
+}
+
+// Template is the representation of a single parsed template.
+type Template struct {
+	Name      string // name of the template represented by the tree.
+	ParseName string // name of the top-level template during parsing, for error messages.
+
+	set     *Set
+	extends *Template
+	imports []*Template
+
+	processedBlocks map[string]*BlockNode
+	passedBlocks    map[string]*BlockNode
+	Root            *ListNode // top-level root of the tree.
+
+	text string // text parsed to create the template (or its parent)
+
+	// Parsing only; cleared after parse.
+	lex       *lexer
+	token     [3]item // three-token lookahead for parser.
+	peekCount int
+}
+
+// next returns the next token.
+func (t *Template) next() item {
+	if t.peekCount > 0 {
+		t.peekCount--
+	} else {
+		t.token[0] = t.lex.nextItem()
+	}
+	return t.token[t.peekCount]
+}
+
+// backup backs the input stream up one token.
+func (t *Template) backup() {
+	t.peekCount++
+}
+
+// backup2 backs the input stream up two tokens.
+// The zeroth token is already there.
+func (t *Template) backup2(t1 item) {
+	t.token[1] = t1
+	t.peekCount = 2
+}
+
+// backup3 backs the input stream up three tokens
+// The zeroth token is already there.
+func (t *Template) backup3(t2, t1 item) {
+	// Reverse order: we're pushing back.
+	t.token[1] = t1
+	t.token[2] = t2
+	t.peekCount = 3
+}
+
+// peek returns but does not consume the next token.
+func (t *Template) peek() item {
+	if t.peekCount > 0 {
+		return t.token[t.peekCount-1]
+	}
+	t.peekCount = 1
+	t.token[0] = t.lex.nextItem()
+	return t.token[0]
+}
+
+// nextNonSpace returns the next non-space token.
+func (t *Template) nextNonSpace() (token item) {
+	for {
+		token = t.next()
+		if token.typ != itemSpace {
+			break
+		}
+	}
+	return token
+}
+
+// peekNonSpace returns but does not consume the next non-space token.
+func (t *Template) peekNonSpace() (token item) {
+	for {
+		token = t.next()
+		if token.typ != itemSpace {
+			break
+		}
+	}
+	t.backup()
+	return token
+}
+
+// errorf formats the error and terminates processing.
+func (t *Template) errorf(format string, args ...interface{}) {
+	t.Root = nil
+	format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.lex.lineNumber(), format)
+	panic(fmt.Errorf(format, args...))
+}
+
+// error terminates processing.
+func (t *Template) error(err error) {
+	t.errorf("%s", err)
+}
+
+// expect consumes the next token and guarantees it has the required type.
+func (t *Template) expect(expectedType itemType, context, expected string) item {
+	token := t.nextNonSpace()
+	if token.typ != expectedType {
+		t.unexpected(token, context, expected)
+	}
+	return token
+}
+
+func (t *Template) expectRightDelim(context string) item {
+	return t.expect(itemRightDelim, context, "closing delimiter")
+}
+
+// expectOneOf consumes the next token and guarantees it has one of the required types.
+func (t *Template) expectOneOf(expected1, expected2 itemType, context, expectedAs string) item {
+	token := t.nextNonSpace()
+	if token.typ != expected1 && token.typ != expected2 {
+		t.unexpected(token, context, expectedAs)
+	}
+	return token
+}
+
+// unexpected complains about the token and terminates processing.
+func (t *Template) unexpected(token item, context, expected string) {
+	switch {
+	case token.typ == itemImport,
+		token.typ == itemExtends:
+		t.errorf("parsing %s: unexpected keyword '%s' ('%s' statements must be at the beginning of the template)", context, token.val, token.val)
+	case token.typ > itemKeyword:
+		t.errorf("parsing %s: unexpected keyword '%s' (expected %s)", context, token.val, expected)
+	default:
+		t.errorf("parsing %s: unexpected token '%s' (expected %s)", context, token.val, expected)
+	}
+}
+
+// recover is the handler that turns panics into returns from the top level of Parse.
+func (t *Template) recover(errp *error) {
+	e := recover()
+	if e != nil {
+		if _, ok := e.(runtime.Error); ok {
+			panic(e)
+		}
+		if t != nil {
+			t.lex.drain()
+			t.stopParse()
+		}
+		*errp = e.(error)
+	}
+	return
+}
+
+func (s *Set) parse(name, text string) (t *Template, err error) {
+	t = &Template{
+		Name:         name,
+		ParseName:    name,
+		text:         text,
+		set:          s,
+		passedBlocks: make(map[string]*BlockNode),
+	}
+	defer t.recover(&err)
+
+	lexer := lex(name, text, false)
+	lexer.setDelimiters(s.leftDelim, s.rightDelim)
+	lexer.run()
+	t.startParse(lexer)
+	t.parseTemplate()
+	t.stopParse()
+
+	if t.extends != nil {
+		t.addBlocks(t.extends.processedBlocks)
+	}
+
+	for _, _import := range t.imports {
+		t.addBlocks(_import.processedBlocks)
+	}
+
+	t.addBlocks(t.passedBlocks)
+
+	return t, err
+}
+
+func (t *Template) expectString(context string) string {
+	token := t.expectOneOf(itemString, itemRawString, context, "string literal")
+	s, err := unquote(token.val)
+	if err != nil {
+		t.error(err)
+	}
+	return s
+}
+
+// parse is the top-level parser for a template, essentially the same
+// It runs to EOF.
+func (t *Template) parseTemplate() (next Node) {
+	t.Root = t.newList(t.peek().pos)
+	// {{ extends|import stringLiteral }}
+	for t.peek().typ != itemEOF {
+		delim := t.next()
+		if delim.typ == itemText && strings.TrimSpace(delim.val) == "" {
+			continue //skips empty text nodes
+		}
+		if delim.typ == itemLeftDelim {
+			token := t.nextNonSpace()
+			if token.typ == itemExtends || token.typ == itemImport {
+				s := t.expectString("extends|import")
+				if token.typ == itemExtends {
+					if t.extends != nil {
+						t.errorf("Unexpected extends clause: each template can only extend one template")
+					} else if len(t.imports) > 0 {
+						t.errorf("Unexpected extends clause: the 'extends' clause should come before all import clauses")
+					}
+					var err error
+					t.extends, err = t.set.getSiblingTemplate(s, t.Name)
+					if err != nil {
+						t.error(err)
+					}
+				} else {
+					tt, err := t.set.getSiblingTemplate(s, t.Name)
+					if err != nil {
+						t.error(err)
+					}
+					t.imports = append(t.imports, tt)
+				}
+				t.expect(itemRightDelim, "extends|import", "closing delimiter")
+			} else {
+				t.backup2(delim)
+				break
+			}
+		} else {
+			t.backup()
+			break
+		}
+	}
+
+	for t.peek().typ != itemEOF {
+		switch n := t.textOrAction(); n.Type() {
+		case nodeEnd, nodeElse, nodeContent:
+			t.errorf("unexpected %s", n)
+		default:
+			t.Root.append(n)
+		}
+	}
+	return nil
+}
+
+// startParse initializes the parser, using the lexer.
+func (t *Template) startParse(lex *lexer) {
+	t.Root = nil
+	t.lex = lex
+}
+
+// stopParse terminates parsing.
+func (t *Template) stopParse() {
+	t.lex = nil
+}
+
+// IsEmptyTree reports whether this tree (node) is empty of everything but space.
+func IsEmptyTree(n Node) bool {
+	switch n := n.(type) {
+	case nil:
+		return true
+	case *ActionNode:
+	case *IfNode:
+	case *ListNode:
+		for _, node := range n.Nodes {
+			if !IsEmptyTree(node) {
+				return false
+			}
+		}
+		return true
+	case *RangeNode:
+	case *IncludeNode:
+	case *TextNode:
+		return len(bytes.TrimSpace(n.Text)) == 0
+	case *BlockNode:
+	case *YieldNode:
+	default:
+		panic("unknown node: " + n.String())
+	}
+	return false
+}
+
+func (t *Template) blockParametersList(isDeclaring bool, context string) *BlockParameterList {
+	block := &BlockParameterList{}
+
+	t.expect(itemLeftParen, context, "opening parenthesis")
+	for {
+		var expression Expression
+		next := t.nextNonSpace()
+		if next.typ == itemIdentifier {
+			identifier := next.val
+			next2 := t.nextNonSpace()
+			switch next2.typ {
+			case itemComma, itemRightParen:
+				block.List = append(block.List, BlockParameter{Identifier: identifier})
+				next = next2
+			case itemAssign:
+				expression, next = t.parseExpression(context)
+				block.List = append(block.List, BlockParameter{Identifier: identifier, Expression: expression})
+			default:
+				if !isDeclaring {
+					switch next2.typ {
+					case itemComma, itemRightParen:
+					default:
+						t.backup2(next)
+						expression, next = t.parseExpression(context)
+						block.List = append(block.List, BlockParameter{Expression: expression})
+					}
+				} else {
+					t.unexpected(next2, context, "comma, assignment, or closing parenthesis")
+				}
+			}
+		} else if !isDeclaring {
+			switch next.typ {
+			case itemComma, itemRightParen:
+			default:
+				t.backup()
+				expression, next = t.parseExpression(context)
+				block.List = append(block.List, BlockParameter{Expression: expression})
+			}
+		}
+
+		if next.typ != itemComma {
+			t.backup()
+			break
+		}
+	}
+	t.expect(itemRightParen, context, "closing parenthesis")
+	return block
+}
+
+func (t *Template) parseBlock() Node {
+	const context = "block clause"
+	var pipe Expression
+
+	name := t.expect(itemIdentifier, context, "name")
+	bplist := t.blockParametersList(true, context)
+
+	if t.peekNonSpace().typ != itemRightDelim {
+		pipe = t.expression(context, "context")
+	}
+
+	t.expectRightDelim(context)
+
+	list, end := t.itemList(nodeContent, nodeEnd)
+	var contentList *ListNode
+
+	if end.Type() == nodeContent {
+		contentList, end = t.itemList(nodeEnd)
+	}
+
+	block := t.newBlock(name.pos, t.lex.lineNumber(), name.val, bplist, pipe, list, contentList)
+	t.passedBlocks[block.Name] = block
+	return block
+}
+
+func (t *Template) parseYield() Node {
+	const context = "yield clause"
+
+	var (
+		pipe    Expression
+		name    item
+		bplist  *BlockParameterList
+		content *ListNode
+	)
+
+	// parse block name
+	name = t.nextNonSpace()
+	if name.typ == itemContent {
+		// content yield {{yield content}}
+		if t.peekNonSpace().typ != itemRightDelim {
+			pipe = t.expression(context, "content context")
+		}
+		t.expectRightDelim(context)
+		return t.newYield(name.pos, t.lex.lineNumber(), "", nil, pipe, nil, true)
+	} else if name.typ != itemIdentifier {
+		t.unexpected(name, context, "block name")
+	}
+
+	// parse block parameters
+	bplist = t.blockParametersList(false, context)
+
+	// parse optional context & content
+	typ := t.peekNonSpace().typ
+	if typ == itemRightDelim {
+		t.expectRightDelim(context)
+	} else {
+		if typ != itemContent {
+			// parse context expression
+			pipe = t.expression("yield", "context")
+			typ = t.peekNonSpace().typ
+		}
+		if typ == itemRightDelim {
+			t.expectRightDelim(context)
+		} else if typ == itemContent {
+			// parse content from following nodes (until {{end}})
+			t.nextNonSpace()
+			t.expectRightDelim(context)
+			content, _ = t.itemList(nodeEnd)
+		} else {
+			t.unexpected(t.nextNonSpace(), context, "content keyword or closing delimiter")
+		}
+	}
+
+	return t.newYield(name.pos, t.lex.lineNumber(), name.val, bplist, pipe, content, false)
+}
+
+func (t *Template) parseInclude() Node {
+	var context Expression
+	name := t.expression("include", "template name")
+	if t.peekNonSpace().typ != itemRightDelim {
+		context = t.expression("include", "context")
+	}
+	t.expectRightDelim("include invocation")
+	return t.newInclude(name.Position(), t.lex.lineNumber(), name, context)
+}
+
+func (t *Template) parseReturn() Node {
+	value := t.expression("return", "value")
+	t.expectRightDelim("return")
+	return t.newReturn(value.Position(), t.lex.lineNumber(), value)
+}
+
+// itemList:
+//	textOrAction*
+// Terminates at any of the given nodes, returned separately.
+func (t *Template) itemList(terminatedBy ...NodeType) (list *ListNode, next Node) {
+	list = t.newList(t.peekNonSpace().pos)
+	for t.peekNonSpace().typ != itemEOF {
+		n := t.textOrAction()
+		for _, terminatorType := range terminatedBy {
+			if n.Type() == terminatorType {
+				return list, n
+			}
+		}
+		list.append(n)
+	}
+	t.errorf("unexpected EOF")
+	return
+}
+
+// textOrAction:
+//	text | action
+func (t *Template) textOrAction() Node {
+	switch token := t.nextNonSpace(); token.typ {
+	case itemText:
+		return t.newText(token.pos, token.val)
+	case itemLeftDelim:
+		return t.action()
+	default:
+		t.unexpected(token, "input", "text or action")
+	}
+	return nil
+}
+
+func (t *Template) action() (n Node) {
+	switch token := t.nextNonSpace(); token.typ {
+	case itemInclude:
+		return t.parseInclude()
+	case itemBlock:
+		return t.parseBlock()
+	case itemEnd:
+		return t.endControl()
+	case itemYield:
+		return t.parseYield()
+	case itemContent:
+		return t.contentControl()
+	case itemIf:
+		return t.ifControl()
+	case itemElse:
+		return t.elseControl()
+	case itemRange:
+		return t.rangeControl()
+	case itemTry:
+		return t.parseTry()
+	case itemCatch:
+		return t.parseCatch()
+	case itemReturn:
+		return t.parseReturn()
+	}
+
+	t.backup()
+	action := t.newAction(t.peek().pos, t.lex.lineNumber())
+
+	expr := t.assignmentOrExpression("command")
+	if expr.Type() == NodeSet {
+		action.Set = expr.(*SetNode)
+		expr = nil
+		if t.expectOneOf(itemSemicolon, itemRightDelim, "command", "semicolon or right delimiter").typ == itemSemicolon {
+			expr = t.expression("command", "pipeline base expression")
+		}
+	}
+	if expr != nil {
+		action.Pipe = t.pipeline("command", expr)
+	}
+	return action
+}
+
+func (t *Template) logicalExpression(context string) (Expression, item) {
+	left, endtoken := t.comparativeExpression(context)
+	for endtoken.typ == itemAnd || endtoken.typ == itemOr {
+		right, rightendtoken := t.comparativeExpression(context)
+		left, endtoken = t.newLogicalExpr(left.Position(), t.lex.lineNumber(), left, right, endtoken), rightendtoken
+	}
+	return left, endtoken
+}
+
+func (t *Template) parseExpression(context string) (Expression, item) {
+	expression, endtoken := t.logicalExpression(context)
+	if endtoken.typ == itemTernary {
+		var left, right Expression
+		left, endtoken = t.parseExpression(context)
+		if endtoken.typ != itemColon {
+			t.unexpected(endtoken, "ternary expression", "colon in ternary expression")
+		}
+		right, endtoken = t.parseExpression(context)
+		expression = t.newTernaryExpr(expression.Position(), t.lex.lineNumber(), expression, left, right)
+	}
+	return expression, endtoken
+}
+
+func (t *Template) comparativeExpression(context string) (Expression, item) {
+	left, endtoken := t.numericComparativeExpression(context)
+	for endtoken.typ == itemEquals || endtoken.typ == itemNotEquals {
+		right, rightendtoken := t.numericComparativeExpression(context)
+		left, endtoken = t.newComparativeExpr(left.Position(), t.lex.lineNumber(), left, right, endtoken), rightendtoken
+	}
+	return left, endtoken
+}
+
+func (t *Template) numericComparativeExpression(context string) (Expression, item) {
+	left, endtoken := t.additiveExpression(context)
+	for endtoken.typ >= itemGreat && endtoken.typ <= itemLessEquals {
+		right, rightendtoken := t.additiveExpression(context)
+		left, endtoken = t.newNumericComparativeExpr(left.Position(), t.lex.lineNumber(), left, right, endtoken), rightendtoken
+	}
+	return left, endtoken
+}
+
+func (t *Template) additiveExpression(context string) (Expression, item) {
+	left, endtoken := t.multiplicativeExpression(context)
+	for endtoken.typ == itemAdd || endtoken.typ == itemMinus {
+		right, rightendtoken := t.multiplicativeExpression(context)
+		left, endtoken = t.newAdditiveExpr(left.Position(), t.lex.lineNumber(), left, right, endtoken), rightendtoken
+	}
+	return left, endtoken
+}
+
+func (t *Template) multiplicativeExpression(context string) (left Expression, endtoken item) {
+	left, endtoken = t.unaryExpression(context)
+	for endtoken.typ >= itemMul && endtoken.typ <= itemMod {
+		right, rightendtoken := t.unaryExpression(context)
+		left, endtoken = t.newMultiplicativeExpr(left.Position(), t.lex.lineNumber(), left, right, endtoken), rightendtoken
+	}
+
+	return left, endtoken
+}
+
+func (t *Template) unaryExpression(context string) (Expression, item) {
+	next := t.nextNonSpace()
+	switch next.typ {
+	case itemNot:
+		expr, endToken := t.comparativeExpression(context)
+		return t.newNotExpr(expr.Position(), t.lex.lineNumber(), expr), endToken
+	case itemMinus, itemAdd:
+		return t.newAdditiveExpr(next.pos, t.lex.lineNumber(), nil, t.operand("additive expression"), next), t.nextNonSpace()
+	default:
+		t.backup()
+	}
+	operand := t.operand(context)
+	return operand, t.nextNonSpace()
+}
+
+func (t *Template) assignmentOrExpression(context string) (operand Expression) {
+	t.peekNonSpace()
+	line := t.lex.lineNumber()
+	var right, left []Expression
+
+	var isSet bool
+	var isLet bool
+	var returned item
+	operand, returned = t.parseExpression(context)
+	pos := operand.Position()
+	if returned.typ == itemComma || returned.typ == itemAssign {
+		isSet = true
+	} else {
+		if operand == nil {
+			t.unexpected(returned, context, "operand")
+		}
+		t.backup()
+		return operand
+	}
+
+	if isSet {
+	leftloop:
+		for {
+			switch operand.Type() {
+			case NodeField, NodeChain, NodeIdentifier:
+				left = append(left, operand)
+			default:
+				t.errorf("unexpected node in assign")
+			}
+
+			switch returned.typ {
+			case itemComma:
+				operand, returned = t.parseExpression(context)
+			case itemAssign:
+				isLet = returned.val == ":="
+				break leftloop
+			default:
+				t.unexpected(returned, "assignment", "comma or assignment")
+			}
+		}
+
+		if isLet {
+			for _, operand := range left {
+				if operand.Type() != NodeIdentifier {
+					t.errorf("unexpected node type %s in variable declaration", operand)
+				}
+			}
+		}
+
+		for {
+			operand, returned = t.parseExpression("assignment")
+			right = append(right, operand)
+			if returned.typ != itemComma {
+				t.backup()
+				break
+			}
+		}
+
+		var isIndexExprGetLookup bool
+
+		if context == "range" {
+			if len(left) > 2 || len(right) > 1 {
+				t.errorf("unexpected number of operands in assign on range")
+			}
+		} else {
+			if len(left) != len(right) {
+				if len(left) == 2 && len(right) == 1 && right[0].Type() == NodeIndexExpr {
+					isIndexExprGetLookup = true
+				} else {
+					t.errorf("unexpected number of operands in assign on range")
+				}
+			}
+		}
+		operand = t.newSet(pos, line, isLet, isIndexExprGetLookup, left, right)
+		return
+
+	}
+	return
+}
+
+func (t *Template) expression(context, as string) Expression {
+	expr, tk := t.parseExpression(context)
+	if expr == nil {
+		t.unexpected(tk, context, as)
+	}
+	t.backup()
+	return expr
+}
+
+func (t *Template) pipeline(context string, baseExprMutate Expression) (pipe *PipeNode) {
+	pos := t.peekNonSpace().pos
+	pipe = t.newPipeline(pos, t.lex.lineNumber())
+
+	if baseExprMutate == nil {
+		pipe.errorf("parsing pipeline: first expression cannot be nil")
+	}
+	pipe.append(t.command(baseExprMutate))
+
+	for {
+		token := t.expectOneOf(itemPipe, itemRightDelim, "pipeline", "pipe or right delimiter")
+		if token.typ == itemRightDelim {
+			break
+		}
+		token = t.nextNonSpace()
+		switch token.typ {
+		case itemField, itemIdentifier:
+			t.backup()
+			pipe.append(t.command(nil))
+		default:
+			t.unexpected(token, "pipeline", "field or identifier")
+		}
+	}
+
+	return
+}
+
+func (t *Template) command(baseExpr Expression) *CommandNode {
+	cmd := t.newCommand(t.peekNonSpace().pos)
+
+	if baseExpr == nil {
+		baseExpr = t.expression("command", "name")
+	}
+
+	if baseExpr.Type() == NodeCallExpr {
+		call := baseExpr.(*CallExprNode)
+		cmd.BaseExpr = call.BaseExpr
+		cmd.Args = call.Args
+		return cmd
+	}
+
+	cmd.BaseExpr = baseExpr
+
+	next := t.nextNonSpace()
+	switch next.typ {
+	case itemColon:
+		cmd.Args = t.parseArguments()
+	default:
+		t.backup()
+	}
+
+	if cmd.BaseExpr == nil {
+		t.errorf("empty command")
+	}
+
+	return cmd
+}
+
+// operand:
+//	term .Field*
+// An operand is a space-separated component of a command,
+// a term possibly followed by field accesses.
+// A nil return means the next item is not an operand.
+func (t *Template) operand(context string) Expression {
+	node := t.term()
+	if node == nil {
+		t.unexpected(t.next(), context, "term")
+	}
+RESET:
+	if t.peek().typ == itemField {
+		chain := t.newChain(t.peek().pos, node)
+		for t.peekNonSpace().typ == itemField {
+			chain.Add(t.next().val)
+		}
+		// Compatibility with original API: If the term is of type NodeField
+		// or NodeVariable, just put more fields on the original.
+		// Otherwise, keep the Chain node.
+		// Obvious parsing errors involving literal values are detected here.
+		// More complex error cases will have to be handled at execution time.
+		switch node.Type() {
+		case NodeField:
+			node = t.newField(chain.Position(), chain.String())
+		case NodeBool, NodeString, NodeNumber, NodeNil:
+			t.errorf("unexpected . after term %q", node.String())
+		default:
+			node = chain
+		}
+	}
+	nodeTYPE := node.Type()
+	if nodeTYPE == NodeIdentifier ||
+		nodeTYPE == NodeCallExpr ||
+		nodeTYPE == NodeField ||
+		nodeTYPE == NodeChain ||
+		nodeTYPE == NodeIndexExpr {
+		switch t.nextNonSpace().typ {
+		case itemLeftParen:
+			callExpr := t.newCallExpr(node.Position(), t.lex.lineNumber(), node)
+			callExpr.Args = t.parseArguments()
+			t.expect(itemRightParen, "call expression", "closing parenthesis")
+			node = callExpr
+			goto RESET
+		case itemLeftBrackets:
+			base := node
+			var index Expression
+			var next item
+
+			//found colon is slice expression
+			if t.peekNonSpace().typ != itemColon {
+				index, next = t.parseExpression("index|slice expression")
+			} else {
+				next = t.nextNonSpace()
+			}
+
+			switch next.typ {
+			case itemColon:
+				var endIndex Expression
+				if t.peekNonSpace().typ != itemRightBrackets {
+					endIndex = t.expression("slice expression", "end indexß")
+				}
+				node = t.newSliceExpr(node.Position(), node.line(), base, index, endIndex)
+			case itemRightBrackets:
+				node = t.newIndexExpr(node.Position(), node.line(), base, index)
+				fallthrough
+			default:
+				t.backup()
+			}
+
+			t.expect(itemRightBrackets, "index expression", "closing bracket")
+			goto RESET
+		default:
+			t.backup()
+		}
+	}
+	return node
+}
+
+func (t *Template) parseArguments() []Expression {
+	args := []Expression{}
+	context := "call expression argument list"
+loop:
+	for t.peekNonSpace().typ != itemRightParen {
+		expr, endtoken := t.parseExpression(context)
+		args = append(args, expr)
+		switch endtoken.typ {
+		case itemComma:
+			// continue with closing parens (allowed because of multiline syntax) or next arg
+		default:
+			t.backup()
+			break loop
+		}
+	}
+	return args
+}
+
+func (t *Template) parseControl(allowElseIf bool, context string) (pos Pos, line int, set *SetNode, expression Expression, list, elseList *ListNode) {
+	line = t.lex.lineNumber()
+
+	expression = t.assignmentOrExpression(context)
+	pos = expression.Position()
+	if expression.Type() == NodeSet {
+		set = expression.(*SetNode)
+		if context != "range" {
+			t.expect(itemSemicolon, context, "semicolon between assignment and expression")
+			expression = t.expression(context, "expression after assignment")
+		} else {
+			expression = nil
+		}
+	}
+
+	t.expectRightDelim(context)
+	var next Node
+	list, next = t.itemList(nodeElse, nodeEnd)
+	if next.Type() == nodeElse {
+		if allowElseIf && t.peek().typ == itemIf {
+			// Special case for "else if". If the "else" is followed immediately by an "if",
+			// the elseControl will have left the "if" token pending. Treat
+			//	{{if a}}_{{else if b}}_{{end}}
+			// as
+			//	{{if a}}_{{else}}{{if b}}_{{end}}{{end}}.
+			// To do this, parse the if as usual and stop at it {{end}}; the subsequent{{end}}
+			// is assumed. This technique works even for long if-else-if chains.
+			t.next() // Consume the "if" token.
+			elseList = t.newList(next.Position())
+			elseList.append(t.ifControl())
+			// Do not consume the next item - only one {{end}} required.
+		} else {
+			elseList, next = t.itemList(nodeEnd)
+		}
+	}
+	return pos, line, set, expression, list, elseList
+}
+
+// If:
+//	{{if expression}} itemList {{end}}
+//	{{if expression}} itemList {{else}} itemList {{end}}
+// If keyword is past.
+func (t *Template) ifControl() Node {
+	return t.newIf(t.parseControl(true, "if"))
+}
+
+// Range:
+//	{{range expression}} itemList {{end}}
+//	{{range expression}} itemList {{else}} itemList {{end}}
+// Range keyword is past.
+func (t *Template) rangeControl() Node {
+	return t.newRange(t.parseControl(false, "range"))
+}
+
+// End:
+//	{{end}}
+// End keyword is past.
+func (t *Template) endControl() Node {
+	return t.newEnd(t.expectRightDelim("end").pos)
+}
+
+// Content:
+//	{{content}}
+// Content keyword is past.
+func (t *Template) contentControl() Node {
+	return t.newContent(t.expectRightDelim("content").pos)
+}
+
+// Else:
+//	{{else}}
+// Else keyword is past.
+func (t *Template) elseControl() Node {
+	// Special case for "else if".
+	peek := t.peekNonSpace()
+	if peek.typ == itemIf {
+		// We see "{{else if ... " but in effect rewrite it to {{else}}{{if ... ".
+		return t.newElse(peek.pos, t.lex.lineNumber())
+	}
+	return t.newElse(t.expectRightDelim("else").pos, t.lex.lineNumber())
+}
+
+// Try-catch:
+//	{{try}}
+//    itemList
+//  {{catch <ident>}}
+//    itemList
+//  {{end}}
+// try keyword is past.
+func (t *Template) parseTry() *TryNode {
+	var recov *catchNode
+	line := t.lex.lineNumber()
+	pos := t.expectRightDelim("try").pos
+	list, next := t.itemList(nodeCatch, nodeEnd)
+	if next.Type() == nodeCatch {
+		recov = next.(*catchNode)
+	}
+
+	return t.newTry(pos, line, list, recov)
+}
+
+// catch:
+//  {{catch <ident>}}
+//    itemList
+//  {{end}}
+// catch keyword is past.
+func (t *Template) parseCatch() *catchNode {
+	line := t.lex.lineNumber()
+	var errVar *IdentifierNode
+	peek := t.peekNonSpace()
+	if peek.typ != itemRightDelim {
+		_errVar := t.term()
+		if typ := _errVar.Type(); typ != NodeIdentifier {
+			t.errorf("unexpected node type '%s' in catch", typ)
+		}
+		errVar = _errVar.(*IdentifierNode)
+	}
+	t.expectRightDelim("catch")
+	list, _ := t.itemList(nodeEnd)
+	return t.newCatch(peek.pos, line, errVar, list)
+}
+
+// term:
+//	literal (number, string, nil, boolean)
+//	function (identifier)
+//	.
+//	.Field
+//	variable
+//	'(' expression ')'
+// A term is a simple "expression".
+// A nil return means the next item is not a term.
+func (t *Template) term() Node {
+	switch token := t.nextNonSpace(); token.typ {
+	case itemError:
+		t.errorf("%s", token.val)
+	case itemIdentifier:
+		return t.newIdentifier(token.val, token.pos, t.lex.lineNumber())
+	case itemNil:
+		return t.newNil(token.pos)
+	case itemField:
+		return t.newField(token.pos, token.val)
+	case itemBool:
+		return t.newBool(token.pos, token.val == "true")
+	case itemCharConstant, itemComplex, itemNumber:
+		number, err := t.newNumber(token.pos, token.val, token.typ)
+		if err != nil {
+			t.error(err)
+		}
+		return number
+	case itemLeftParen:
+		pipe := t.expression("parenthesized expression", "expression")
+		if token := t.next(); token.typ != itemRightParen {
+			t.unexpected(token, "parenthesized expression", "closing parenthesis")
+		}
+		return pipe
+	case itemString, itemRawString:
+		s, err := unquote(token.val)
+		if err != nil {
+			t.error(err)
+		}
+		return t.newString(token.pos, token.val, s)
+	}
+	t.backup()
+	return nil
+}

+ 8 - 0
vendor/github.com/CloudyKit/jet/v4/profile.sh

@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+go test -run="^$" -bench="Range" -benchmem -c -cpuprofile=./pprof.out
+go test -run="^$" -bench="Range" -benchmem -cpuprofile=./pprof.out
+go tool pprof --pdf --focus="$1" jet.test pprof.out >> out.pdf
+rm jet.test
+rm pprof.out
+open out.pdf

+ 152 - 0
vendor/github.com/CloudyKit/jet/v4/ranger.go

@@ -0,0 +1,152 @@
+package jet
+
+import (
+	"fmt"
+	"reflect"
+	"sync"
+)
+
+// Ranger describes an interface for types that iterate over something.
+// Implementing this interface means the ranger will be used when it's
+// encountered on the right hand side of a range's "let" expression.
+type Ranger interface {
+	Range() (reflect.Value, reflect.Value, bool)
+	ProvidesIndex() bool
+}
+
+type intsRanger struct {
+	i, from, to int
+}
+
+var _ Ranger = &intsRanger{}
+
+func (r *intsRanger) Range() (index, value reflect.Value, end bool) {
+	index = reflect.ValueOf(r.i)
+	value = reflect.ValueOf(r.from + r.i)
+	end = r.i == r.to-r.from
+	r.i++
+	return
+}
+
+func (r *intsRanger) ProvidesIndex() bool { return true }
+
+type pooledRanger interface {
+	Ranger
+	Setup(reflect.Value)
+}
+
+type sliceRanger struct {
+	v reflect.Value
+	i int
+}
+
+var _ Ranger = &sliceRanger{}
+var _ pooledRanger = &sliceRanger{}
+
+func (r *sliceRanger) Setup(v reflect.Value) {
+	r.i = 0
+	r.v = v
+}
+
+func (r *sliceRanger) Range() (index, value reflect.Value, end bool) {
+	if r.i == r.v.Len() {
+		end = true
+		return
+	}
+	index = reflect.ValueOf(r.i)
+	value = r.v.Index(r.i)
+	r.i++
+	return
+}
+
+func (r *sliceRanger) ProvidesIndex() bool { return true }
+
+type mapRanger struct {
+	iter    *reflect.MapIter
+	hasMore bool
+}
+
+var _ Ranger = &mapRanger{}
+var _ pooledRanger = &mapRanger{}
+
+func (r *mapRanger) Setup(v reflect.Value) {
+	r.iter = v.MapRange()
+	r.hasMore = r.iter.Next()
+}
+
+func (r *mapRanger) Range() (key, value reflect.Value, end bool) {
+	if !r.hasMore {
+		end = true
+		return
+	}
+	key, value = r.iter.Key(), r.iter.Value()
+	r.hasMore = r.iter.Next()
+	return
+}
+
+func (r *mapRanger) ProvidesIndex() bool { return true }
+
+type chanRanger struct {
+	v reflect.Value
+}
+
+var _ Ranger = &chanRanger{}
+var _ pooledRanger = &chanRanger{}
+
+func (r *chanRanger) Setup(v reflect.Value) {
+	r.v = v
+}
+
+func (r *chanRanger) Range() (_, value reflect.Value, end bool) {
+	v, ok := r.v.Recv()
+	value, end = v, !ok
+	return
+}
+
+func (r *chanRanger) ProvidesIndex() bool { return false }
+
+// ranger pooling
+
+var (
+	poolSliceRanger = &sync.Pool{
+		New: func() interface{} {
+			return new(sliceRanger)
+		},
+	}
+
+	poolsByKind = map[reflect.Kind]*sync.Pool{
+		reflect.Slice: poolSliceRanger,
+		reflect.Array: poolSliceRanger,
+		reflect.Map: &sync.Pool{
+			New: func() interface{} {
+				return new(mapRanger)
+			},
+		},
+		reflect.Chan: &sync.Pool{
+			New: func() interface{} {
+				return new(chanRanger)
+			},
+		},
+	}
+)
+
+func getRanger(v reflect.Value) (r Ranger, cleanup func()) {
+	t := v.Type()
+	if t.Implements(rangerType) {
+		return v.Interface().(Ranger), func() { /* no cleanup needed */ }
+	}
+
+	v, isNil := indirect(v)
+	if isNil {
+		panic(fmt.Errorf("cannot range over nil pointer/interface (%s)", t))
+	}
+
+	pool, ok := poolsByKind[v.Kind()]
+	if !ok {
+		panic(fmt.Errorf("value %v (type %s) is not rangeable", v, t))
+	}
+
+	pr := pool.Get().(pooledRanger)
+	pr.Setup(v)
+	return pr, func() { pool.Put(pr) }
+}

+ 11 - 0
vendor/github.com/CloudyKit/jet/v4/stress.bash

@@ -0,0 +1,11 @@
+#!/usr/bin/env bash -e
+
+go test -c
+# comment above and uncomment below to enable the race builder
+#go test -c -race
+PKG=$(basename $(pwd))
+
+while true ; do
+        export GOMAXPROCS=$[ 1 + $[ RANDOM % 128 ]]
+        ./$PKG.test $@ 2>&1
+done

+ 327 - 0
vendor/github.com/CloudyKit/jet/v4/template.go

@@ -0,0 +1,327 @@
+// Copyright 2016 José Santos <henrique_1609@me.com>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Jet is a fast and dynamic template engine for the Go programming language, set of features
+// includes very fast template execution, a dynamic and flexible language, template inheritance, low number of allocations,
+// special interfaces to allow even further optimizations.
+
+package jet
+
+import (
+	"fmt"
+	"io"
+	"io/ioutil"
+	"path/filepath"
+	"reflect"
+	"sync"
+	"text/template"
+)
+
+var defaultExtensions = []string{
+	"", // in case the path is given with the correct extension already
+	".jet",
+	".html.jet",
+	".jet.html",
+}
+
+// Set is responsible to load,invoke parse and cache templates and relations
+// every jet template is associated with one set.
+// create a set with jet.NewSet(escapeeFn) returns a pointer to the Set
+type Set struct {
+	loader          Loader
+	templates       map[string]*Template // parsed templates
+	escapee         SafeWriter           // escapee to use at runtime
+	globals         VarMap               // global scope for this template set
+	tmx             *sync.RWMutex        // template parsing mutex
+	gmx             *sync.RWMutex        // global variables map mutex
+	extensions      []string
+	developmentMode bool
+	leftDelim       string
+	rightDelim      string
+}
+
+// SetDevelopmentMode set's development mode on/off, in development mode template will be recompiled on every run
+func (s *Set) SetDevelopmentMode(b bool) *Set {
+	s.developmentMode = b
+	return s
+}
+
+func (s *Set) LookupGlobal(key string) (val interface{}, found bool) {
+	s.gmx.RLock()
+	val, found = s.globals[key]
+	s.gmx.RUnlock()
+	return
+}
+
+// AddGlobal add or set a global variable into the Set
+func (s *Set) AddGlobal(key string, i interface{}) *Set {
+	s.gmx.Lock()
+	s.globals[key] = reflect.ValueOf(i)
+	s.gmx.Unlock()
+	return s
+}
+
+func (s *Set) AddGlobalFunc(key string, fn Func) *Set {
+	return s.AddGlobal(key, fn)
+}
+
+// NewSetLoader creates a new set with custom Loader
+func NewSetLoader(escapee SafeWriter, loader Loader) *Set {
+	return &Set{
+		loader:     loader,
+		templates:  map[string]*Template{},
+		escapee:    escapee,
+		globals:    VarMap{},
+		tmx:        &sync.RWMutex{},
+		gmx:        &sync.RWMutex{},
+		extensions: append([]string{}, defaultExtensions...),
+	}
+}
+
+// NewHTMLSetLoader creates a new set with custom Loader
+func NewHTMLSetLoader(loader Loader) *Set {
+	return NewSetLoader(template.HTMLEscape, loader)
+}
+
+// NewSet creates a new set, dirs is a list of directories to be searched for templates
+func NewSet(escapee SafeWriter, dir string) *Set {
+	return NewSetLoader(escapee, &OSFileSystemLoader{dir: dir})
+}
+
+// NewHTMLSet creates a new set, dirs is a list of directories to be searched for templates
+func NewHTMLSet(dir string) *Set {
+	return NewSet(template.HTMLEscape, dir)
+}
+
+// Delims sets the delimiters to the specified strings. Parsed templates will
+// inherit the settings. Not setting them leaves them at the default: {{ or }}.
+func (s *Set) Delims(left, right string) {
+	s.leftDelim = left
+	s.rightDelim = right
+}
+
+func (s *Set) getTemplateFromCache(path string) (t *Template, ok bool) {
+	// check path with all possible extensions in cache
+	for _, extension := range s.extensions {
+		canonicalPath := path + extension
+		if t, found := s.templates[canonicalPath]; found {
+			return t, true
+		}
+	}
+	return nil, false
+}
+
+func (s *Set) getTemplateFromLoader(path string) (t *Template, err error) {
+	// check path with all possible extensions in loader
+	for _, extension := range s.extensions {
+		canonicalPath := path + extension
+		if _, found := s.loader.Exists(canonicalPath); found {
+			return s.loadFromFile(canonicalPath)
+		}
+	}
+	return nil, fmt.Errorf("template %s could not be found", path)
+}
+
+// GetTemplate tries to find (and load, if not yet loaded) the template at the specified path.
+//
+// for example, GetTemplate("catalog/products.list") with extensions set to []string{"", ".html.jet",".jet"}
+// will try to look for:
+//     1. catalog/products.list
+//     2. catalog/products.list.html.jet
+//     3. catalog/products.list.jet
+// in the set's templates cache, and if it can't find the template it will try to load the same paths via
+// the loader, and, if parsed successfully, cache the template.
+func (s *Set) GetTemplate(path string) (t *Template, err error) {
+	if !s.developmentMode {
+		s.tmx.RLock()
+		t, found := s.getTemplateFromCache(path)
+		if found {
+			s.tmx.RUnlock()
+			return t, nil
+		}
+		s.tmx.RUnlock()
+	}
+
+	t, err = s.getTemplateFromLoader(path)
+	if err == nil && !s.developmentMode {
+		// load template into cache
+		s.tmx.Lock()
+		s.templates[t.Name] = t
+		s.tmx.Unlock()
+	}
+	return t, err
+}
+
+// same as GetTemplate, but assumes the reader already called s.tmx.RLock(), and
+// doesn't cache a template when found through the loader
+func (s *Set) getTemplate(path string) (t *Template, err error) {
+	if !s.developmentMode {
+		t, found := s.getTemplateFromCache(path)
+		if found {
+			return t, nil
+		}
+	}
+
+	return s.getTemplateFromLoader(path)
+}
+
+func (s *Set) getSiblingTemplate(path, siblingPath string) (t *Template, err error) {
+	if !filepath.IsAbs(filepath.Clean(path)) {
+		siblingDir := filepath.Dir(siblingPath)
+		path = filepath.Join(siblingDir, path)
+	}
+	return s.getTemplate(path)
+}
+
+// Parse parses the template without adding it to the set's templates cache.
+func (s *Set) Parse(path, content string) (*Template, error) {
+	s.tmx.RLock()
+	t, err := s.parse(path, content)
+	s.tmx.RUnlock()
+
+	return t, err
+}
+
+func (s *Set) loadFromFile(path string) (template *Template, err error) {
+	f, err := s.loader.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+	content, err := ioutil.ReadAll(f)
+	if err != nil {
+		return nil, err
+	}
+	return s.parse(path, string(content))
+}
+
+func (s *Set) LoadTemplate(path, content string) (*Template, error) {
+	if s.developmentMode {
+		s.tmx.RLock()
+		defer s.tmx.RUnlock()
+		return s.parse(path, content)
+	}
+
+	// fast path (t from cache)
+	s.tmx.RLock()
+	if t, found := s.templates[path]; found {
+		s.tmx.RUnlock()
+		return t, nil
+	}
+	s.tmx.RUnlock()
+
+	// not found, parse and cache
+	s.tmx.Lock()
+	defer s.tmx.Unlock()
+
+	t, err := s.parse(path, content)
+	if err == nil {
+		s.templates[path] = t
+	}
+	return t, err
+}
+
+// SetExtensions sets extensions.
+func (s *Set) SetExtensions(extensions []string) {
+	s.extensions = extensions
+}
+
+func (t *Template) String() (template string) {
+	if t.extends != nil {
+		if len(t.Root.Nodes) > 0 && len(t.imports) == 0 {
+			template += fmt.Sprintf("{{extends %q}}", t.extends.ParseName)
+		} else {
+			template += fmt.Sprintf("{{extends %q}}", t.extends.ParseName)
+		}
+	}
+
+	for k, _import := range t.imports {
+		if t.extends == nil && k == 0 {
+			template += fmt.Sprintf("{{import %q}}", _import.ParseName)
+		} else {
+			template += fmt.Sprintf("\n{{import %q}}", _import.ParseName)
+		}
+	}
+
+	if t.extends != nil || len(t.imports) > 0 {
+		if len(t.Root.Nodes) > 0 {
+			template += "\n" + t.Root.String()
+		}
+	} else {
+		template += t.Root.String()
+	}
+	return
+}
+
+func (t *Template) addBlocks(blocks map[string]*BlockNode) {
+	if len(blocks) == 0 {
+		return
+	}
+	if t.processedBlocks == nil {
+		t.processedBlocks = make(map[string]*BlockNode)
+	}
+	for key, value := range blocks {
+		t.processedBlocks[key] = value
+	}
+}
+
+type VarMap map[string]reflect.Value
+
+func (scope VarMap) Set(name string, v interface{}) VarMap {
+	scope[name] = reflect.ValueOf(v)
+	return scope
+}
+
+func (scope VarMap) SetFunc(name string, v Func) VarMap {
+	scope[name] = reflect.ValueOf(v)
+	return scope
+}
+
+func (scope VarMap) SetWriter(name string, v SafeWriter) VarMap {
+	scope[name] = reflect.ValueOf(v)
+	return scope
+}
+
+// Execute executes the template in the w Writer
+func (t *Template) Execute(w io.Writer, variables VarMap, data interface{}) error {
+	return t.ExecuteI18N(nil, w, variables, data)
+}
+
+type Translator interface {
+	Msg(key, defaultValue string) string
+	Trans(format, defaultFormat string, v ...interface{}) string
+}
+
+func (t *Template) ExecuteI18N(translator Translator, w io.Writer, variables VarMap, data interface{}) (err error) {
+	st := pool_State.Get().(*Runtime)
+	defer st.recover(&err)
+
+	st.blocks = t.processedBlocks
+	st.translator = translator
+	st.variables = variables
+	st.set = t.set
+	st.Writer = w
+
+	// resolve extended template
+	for t.extends != nil {
+		t = t.extends
+	}
+
+	if data != nil {
+		st.context = reflect.ValueOf(data)
+	}
+
+	st.executeList(t.Root)
+	return
+}

+ 2 - 0
vendor/github.com/CloudyKit/jet/v6/.gitignore

@@ -0,0 +1,2 @@
+.DS_Store
+.idea

Some files were not shown because too many files changed in this diff