Browse Source

Chore: update to latest versions

Gwyneth Llewelyn 1 year ago
parent
commit
ca2b5e2a4a
5 changed files with 412 additions and 355 deletions
  1. 8 1
      functions.go
  2. 83 37
      go.sum
  3. 156 153
      gosl.go
  4. 123 122
      import-database.go
  5. 42 42
      search.go

+ 8 - 1
functions.go

@@ -19,7 +19,9 @@ func checkErrPanic(err error) {
 		log.Panicf("%s:%d (%v) [ok: %v] - panic: %v\n", filepath.Base(file), line, pc, ok, err)
 	}
 }
+
 // checkErr checks if there is an error, and if yes, it logs it out and continues.
+//
 //	this is for 'normal' situations when we want to get a log if something goes wrong but do not need to panic
 func checkErr(err error) {
 	if err != nil {
@@ -39,6 +41,7 @@ func checkErrHTTP(w http.ResponseWriter, httpStatus int, errorMessage string, er
 		log.Error("(", http.StatusText(httpStatus), ") ", filepath.Base(file), ":", line, ":", pc, ok, " - error:", errorMessage, err)
 	}
 }
+
 // checkErrPanicHTTP returns an error via HTTP and logs the error with a panic.
 func checkErrPanicHTTP(w http.ResponseWriter, httpStatus int, errorMessage string, err error) {
 	if err != nil {
@@ -47,13 +50,17 @@ func checkErrPanicHTTP(w http.ResponseWriter, httpStatus int, errorMessage strin
 		log.Panic("(", http.StatusText(httpStatus), ") ", filepath.Base(file), ":", line, ":", pc, ok, " - panic:", errorMessage, err)
 	}
 }
+
 // logErrHTTP assumes that the error message was already composed and writes it to HTTP and logs it.
+//
 //	this is mostly to avoid code duplication and make sure that all entries are written similarly
 func logErrHTTP(w http.ResponseWriter, httpStatus int, errorMessage string) {
 	http.Error(w, errorMessage, httpStatus)
 	log.Error("(" + http.StatusText(httpStatus) + ") " + errorMessage)
 }
+
 // funcName is @Sonia's solution to get the name of the function that Go is currently running.
+//
 //	This will be extensively used to deal with figuring out where in the code the errors are!
 //	Source: https://stackoverflow.com/a/10743805/1035977 (20170708)
 func funcName() string {
@@ -74,4 +81,4 @@ func isValidUUID(uuid string) bool {
 func isValidUUID(u string) bool {
 	_, err := uuid.Parse(u)
 	return err == nil
- }
+}

+ 83 - 37
go.sum

@@ -37,7 +37,7 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g
 cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
 cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
-cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU=
+cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY=
 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
 cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
 cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@@ -55,14 +55,23 @@ github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOv
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
 github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnduCsavhwFUklBMoGVYUCqmCqk=
@@ -77,6 +86,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
+github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
 github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -88,6 +99,7 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
 github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20211216145620-d92e9ce0af51 h1:F6fR7MjvOIk+FLQOeBCAbbKItVgbdj0l9VWPiHeBEiY=
 github.com/cncf/xds/go v0.0.0-20211216145620-d92e9ce0af51/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@@ -125,6 +137,7 @@ github.com/envoyproxy/protoc-gen-validate v0.6.2 h1:JiO+kJTpmYGjEodY7O1Zk8oZcNz1
 github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
+github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
 github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
@@ -132,7 +145,13 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -177,8 +196,6 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
-github.com/google/flatbuffers v2.0.0+incompatible h1:dicJ2oXwypfwUGnB2/TYWYEKiuk9eYQlQO/AnOHl5mI=
-github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
 github.com/google/flatbuffers v2.0.5+incompatible h1:ANsW0idDAXIY+mNHzIHxWRfabV2x5LUEEIIWcwsYgB8=
 github.com/google/flatbuffers v2.0.5+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -195,9 +212,11 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
 github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ=
 github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -227,19 +246,22 @@ github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8
 github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720 h1:zC34cGQu69FG7qzJ3WiKW244WfhDC3xxYMeNOX2gtUQ=
 github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/h2non/filetype v1.1.1 h1:xvOwnXKAckvtLWsN398qS9QhlxlnVXBjXBydK2/UFB4=
-github.com/h2non/filetype v1.1.1/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
 github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
 github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
-github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
+github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0=
 github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
 github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
 github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
 github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
 github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
 github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
 github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
+github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
 github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
 github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
 github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
@@ -247,27 +269,34 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
 github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
-github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
-github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
-github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
+github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
+github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
+github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
 github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 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.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
 github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
 github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
 github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@@ -281,25 +310,30 @@ github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
 github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
 github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
 github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
+github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
 github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo=
-github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
 github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+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.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
@@ -309,9 +343,11 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
 github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -321,19 +357,31 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE=
+github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
 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/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
-github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
 github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
 github.com/spf13/afero v1.7.0 h1:xc1yh8vgcNB8yQ+UqY4cpD56Ogo573e+CJ/C4YmMFTg=
 github.com/spf13/afero v1.7.0/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
@@ -348,11 +396,10 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
-github.com/spf13/viper v1.9.0 h1:yR6EXjTp0y0cLN8OZg1CRZmOBdI88UcGkhgyJhu6nZk=
-github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4=
 github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk=
 github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -366,22 +413,13 @@ github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFd
 github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
 github.com/tidwall/assert v0.1.0 h1:aWcKyRBUAdLoVebxo95N7+YZVTFF/ASTr7BN4sLP6XI=
 github.com/tidwall/assert v0.1.0/go.mod h1:QLYtGyeqse53vuELQheYl9dngGCJQ+mTtlxcktb+Kj8=
-github.com/tidwall/btree v0.6.1 h1:75VVgBeviiDO+3g4U+7+BaNBNhNINxB0ULPT3fs9pMY=
-github.com/tidwall/btree v0.6.1/go.mod h1:TzIRzen6yHbibdSfK6t8QimqbUnoxUSrZfeW7Uob0q4=
 github.com/tidwall/btree v0.7.1/go.mod h1:TzIRzen6yHbibdSfK6t8QimqbUnoxUSrZfeW7Uob0q4=
 github.com/tidwall/btree v1.1.0 h1:5P+9WU8ui5uhmcg3SoPyTwoI0mVyZ1nps7YQzTZFkYM=
 github.com/tidwall/btree v1.1.0/go.mod h1:TzIRzen6yHbibdSfK6t8QimqbUnoxUSrZfeW7Uob0q4=
-github.com/tidwall/buntdb v1.2.7 h1:SIyObKAymzLyGhDeIhVk2Yc1/EwfCC75Uyu77CHlVoA=
-github.com/tidwall/buntdb v1.2.7/go.mod h1:b6KvZM27x/8JLI5hgRhRu60pa3q0Tz9c50TyD46OHUM=
 github.com/tidwall/buntdb v1.2.8 h1:Fpwx28OjYBAsZEcffLow6lDAXg4b3k0cWtPTdzArP9c=
 github.com/tidwall/buntdb v1.2.8/go.mod h1:Ksv/lHcBXW3JH8A+chohAzMwrQ51ivstZZnEb9RVXww=
-github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
-github.com/tidwall/gjson v1.11.0 h1:C16pk7tQNiH6VlCrtIXL1w8GaOsi1X3W8KDkE1BuYd4=
-github.com/tidwall/gjson v1.11.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
 github.com/tidwall/gjson v1.12.1 h1:ikuZsLdhr8Ws0IdROXUS1Gi4v9Z4pGqpX/CvJkxvfpo=
 github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
-github.com/tidwall/grect v0.1.3 h1:z9YwQAMUxVSBde3b7Sl8Da37rffgNfZ6Fq6h9t6KdXE=
-github.com/tidwall/grect v0.1.3/go.mod h1:8GMjwh3gPZVpLBI/jDz9uslCe0dpxRpWDdtN0lWAS/E=
 github.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg=
 github.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q=
 github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8=
@@ -394,6 +432,7 @@ github.com/tidwall/rtred v0.1.2 h1:exmoQtOLvDoO8ud++6LwVsAMTu0KPzLTUrMln8u1yu8=
 github.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSRxCHFQ=
 github.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE=
 github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw=
+github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -401,9 +440,9 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
-go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
-go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
+go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
+go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
+go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -416,7 +455,7 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
 go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
-golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -467,7 +506,7 @@ golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/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=
@@ -475,6 +514,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
 golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -502,10 +542,9 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
 golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211105192438-b53810dc28af h1:SMeNJG/vclJ5wyBBd4xupMsSJIHTd1coW9g7q6KOjmY=
-golang.org/x/net v0.0.0-20211105192438-b53810dc28af/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
 golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -539,13 +578,15 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190222072716-a9d3bda3a223/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-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -584,6 +625,7 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -602,8 +644,8 @@ golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42 h1:G2DDmludOQZoWbpCr7OKDxnl478ZBGMcOhrv+ooX/Q4=
-golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
@@ -712,6 +754,7 @@ google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqiv
 google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
 google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
 google.golang.org/api v0.58.0/go.mod h1:cAbP2FsxoGVNwtgNAmmn3y5G1TWAiVYRmg4yku3lv+E=
+google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU=
 google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
 google.golang.org/api v0.63.0 h1:n2bqqK895ygnBpdPDYetfy23K7fJ22wsrZKCyfuRkkA=
 google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
@@ -782,7 +825,9 @@ google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEc
 google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
 google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
 google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20211016002631-37fc39342514/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
@@ -831,6 +876,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
@@ -838,8 +884,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c=
-gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
 gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
@@ -849,6 +893,8 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.3/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.5/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=

+ 156 - 153
gosl.go

@@ -2,20 +2,20 @@
 package main
 
 import (
-//	"bufio"			// replaced by the more sophisticated readline (gwyneth 20211106)
+	//	"bufio"			// replaced by the more sophisticated readline (gwyneth 20211106)
 	"encoding/json"
 	"fmt"
 	"net/http"
 	"net/http/fcgi"
 	"os"
 	"path/filepath"
-//	"regexp"
+	//	"regexp"
 	"strings"
-//	"time"
+	//	"time"
 
 	"github.com/dgraph-io/badger/v3"
-//	"github.com/dgraph-io/badger/options"
-//	"github.com/fsnotify/fsnotify"
+	//	"github.com/dgraph-io/badger/options"
+	//	"github.com/fsnotify/fsnotify"
 	"github.com/google/uuid"
 	"github.com/op/go-logging"
 	flag "github.com/spf13/pflag"
@@ -23,15 +23,15 @@ import (
 	"github.com/syndtr/goleveldb/leveldb"
 	"github.com/tidwall/buntdb"
 	"gitlab.com/cznic/readline"
-//	"gopkg.in/go-playground/validator.v9"	// to validate UUIDs... and a lot of thinks
+	//	"gopkg.in/go-playground/validator.v9"	// to validate UUIDs... and a lot of thinks
 	"gopkg.in/natefinch/lumberjack.v2"
 )
 
 const NullUUID = "00000000-0000-0000-0000-000000000000" // always useful when we deal with SL/OpenSimulator...
-const databaseName = "gosl-database.db" // for BuntDB
+const databaseName = "gosl-database.db"                 // for BuntDB
 
 // Logging setup.
-var log = logging.MustGetLogger("gosl")	// configuration for the go-logging logger, must be available everywhere
+var log = logging.MustGetLogger("gosl") // configuration for the go-logging logger, must be available everywhere
 var logFormat logging.Formatter
 
 // Opt is used for Badger database setup.
@@ -40,12 +40,14 @@ var Opt badger.Options
 // AvatarUUID is the type that we store in the database; we keep a record from which grid it came from.
 // Field names need to be capitalised for JSON marshalling (it has to do with the way it works)
 // Note that we will store both UUID -> AvatarName *and* AvatarName -> UUID on the same database,
-//  thus the apparent redundancy in fields! (gwyneth 20211030)
+//
+//	thus the apparent redundancy in fields! (gwyneth 20211030)
+//
 // The 'validate' decorator is for usage with the go-playground validator, currently unused (gwyneth 20211031)
 type avatarUUID struct {
-	AvatarName string	`json:"name" form:"name" binding:"required" validate:"omitempty,alphanum"`
-	UUID string			`json:"key"  form:"key"  binding:"required" validate:"omitempty,uuid4_rfc4122"`
-	Grid string			`json:"grid" form:"grid" validate:"omitempty,alphanum"`
+	AvatarName string `json:"name" form:"name" binding:"required" validate:"omitempty,alphanum"`
+	UUID       string `json:"key"  form:"key"  binding:"required" validate:"omitempty,uuid4_rfc4122"`
+	Grid       string `json:"grid" form:"grid" validate:"omitempty,alphanum"`
 }
 
 /*
@@ -59,12 +61,12 @@ type avatarUUID struct {
 
 // Configuration options
 type goslConfigOptions struct {
-	BATCH_BLOCK int // how many entries to write to the database as a block; the bigger, the faster, but the more memory it consumes
-	noMemory, isServer, isShell bool
+	BATCH_BLOCK                             int // how many entries to write to the database as a block; the bigger, the faster, but the more memory it consumes
+	noMemory, isServer, isShell             bool
 	myDir, myPort, importFilename, database string
-	dbNamePath string // for BuntDB
-	logLevel, logFilename string	// for logs
-	maxSize, maxBackups, maxAge int // logs configuration option
+	dbNamePath                              string // for BuntDB
+	logLevel, logFilename                   string // for logs
+	maxSize, maxBackups, maxAge             int    // logs configuration option
 }
 
 var goslConfig goslConfigOptions
@@ -72,14 +74,14 @@ var kv *badger.DB
 
 // loadConfiguration reads our configuration from a config.toml file
 func loadConfiguration() {
-	fmt.Print("Reading gosl-basic configuration:")	// note that we might not have go-logging active as yet, so we use fmt
+	fmt.Print("Reading gosl-basic configuration:") // note that we might not have go-logging active as yet, so we use fmt
 	// Open our config file and extract relevant data from there
 	err := viper.ReadInConfig() // Find and read the config file
 	if err != nil {
 		fmt.Println("error reading config file:", err)
-		return	// we might still get away with this!
+		return // we might still get away with this!
 	}
-	viper.SetDefault("config.BATCH_BLOCK", 100000)	// NOTE(gwyneth): the authors of say that 100000 is way too much for Badger													// NOTE(gwyneth): let's see what happens with BuntDB
+	viper.SetDefault("config.BATCH_BLOCK", 100000) // NOTE(gwyneth): the authors of say that 100000 is way too much for Badger													// NOTE(gwyneth): let's see what happens with BuntDB
 	goslConfig.BATCH_BLOCK = viper.GetInt("config.BATCH_BLOCK")
 	viper.SetDefault("config.myPort", 3000)
 	goslConfig.myPort = viper.GetString("config.myPort")
@@ -112,19 +114,19 @@ func loadConfiguration() {
 func main() {
 	// Flag setup; can be overridden by config file.
 	// TODO(gwyneth): I need to fix this to be the oher way round).
-	goslConfig.myPort			= *flag.String("port", "3000", "Server port")
-	goslConfig.myDir			= *flag.String("dir", "slkvdb", "Directory where database files are stored")
-	goslConfig.isServer			= *flag.Bool("server", false, "Run as server on port " + goslConfig.myPort)
-	goslConfig.isShell			= *flag.Bool("shell", false, "Run as an interactive shell")
-	goslConfig.importFilename	= *flag.String("import", "", "Import database from W-Hat (use the csv.bz2 versions)")
-	goslConfig.database 		= *flag.String("database", "badger", "Database type (badger, buntdb, leveldb)")
-	goslConfig.noMemory 		= *flag.Bool("nomemory", true, "Attempt to use only disk to save memory on Badger (important for shared webservers)")
+	goslConfig.myPort = *flag.String("port", "3000", "Server port")
+	goslConfig.myDir = *flag.String("dir", "slkvdb", "Directory where database files are stored")
+	goslConfig.isServer = *flag.Bool("server", false, "Run as server on port "+goslConfig.myPort)
+	goslConfig.isShell = *flag.Bool("shell", false, "Run as an interactive shell")
+	goslConfig.importFilename = *flag.String("import", "", "Import database from W-Hat (use the csv.bz2 versions)")
+	goslConfig.database = *flag.String("database", "badger", "Database type (badger, buntdb, leveldb)")
+	goslConfig.noMemory = *flag.Bool("nomemory", true, "Attempt to use only disk to save memory on Badger (important for shared webservers)")
 
 	// Config viper, which reads in the configuration file every time it's needed.
 	// Note that we need some hard-coded variables for the path and config file name.
 	viper.SetConfigName("config")
-	viper.SetConfigType("toml") // just to make sure; it's the same format as OpenSimulator (or MySQL) config files
-	viper.AddConfigPath(".")               // optionally look for config in the working directory
+	viper.SetConfigType("toml")                                                              // just to make sure; it's the same format as OpenSimulator (or MySQL) config files
+	viper.AddConfigPath(".")                                                                 // optionally look for config in the working directory
 	viper.AddConfigPath("$HOME/go/src/git.gwynethllewelyn.net/GwynethLlewelyn/gosl-basics/") // that's how you'll have it
 
 	loadConfiguration()
@@ -152,49 +154,49 @@ func main() {
 
 	// Setup the lumberjack rotating logger. This is because we need it for the go-logging logger when writing to files. (20170813)
 	rotatingLogger := &lumberjack.Logger{
-		Filename:	goslConfig.logFilename,
-		MaxSize:	goslConfig.maxSize, // megabytes
-		MaxBackups:	goslConfig.maxBackups,
-		MaxAge:		goslConfig.maxAge, //days
+		Filename:   goslConfig.logFilename,
+		MaxSize:    goslConfig.maxSize, // megabytes
+		MaxBackups: goslConfig.maxBackups,
+		MaxAge:     goslConfig.maxAge, //days
 	}
 
 	// Set formatting for stderr and file (basically the same).
-	logFormat := logging.MustStringFormatter(`%{color}%{time:2006/01/02 15:04:05.0} %{shortfile} - %{shortfunc} ▶ %{level:.4s}%{color:reset} %{message}`) 	// must be initialised or all hell breaks loose
+	logFormat := logging.MustStringFormatter(`%{color}%{time:2006/01/02 15:04:05.0} %{shortfile} - %{shortfunc} ▶ %{level:.4s}%{color:reset} %{message}`) // must be initialised or all hell breaks loose
 
 	// Setup the go-logging Logger. Do **not** log to stderr if running as FastCGI!
-	backendFile				:= logging.NewLogBackend(rotatingLogger, "", 0)
-	backendFileFormatter	:= logging.NewBackendFormatter(backendFile, logFormat)
-	backendFileLeveled 		:= logging.AddModuleLevel(backendFileFormatter)
+	backendFile := logging.NewLogBackend(rotatingLogger, "", 0)
+	backendFileFormatter := logging.NewBackendFormatter(backendFile, logFormat)
+	backendFileLeveled := logging.AddModuleLevel(backendFileFormatter)
 
 	theLogLevel, err := logging.LogLevel(goslConfig.logLevel)
 	if err != nil {
 		log.Warningf("could not set log level to %q — invalid?\nlogging.LogLevel() returned error %q\n", goslConfig.logLevel, err)
 	} else {
 		log.Debugf("requested file log level: %q\n", theLogLevel.String())
-		backendFileLeveled.SetLevel(theLogLevel, "gosl")	// we just send debug data to logs if we run asshell
+		backendFileLeveled.SetLevel(theLogLevel, "gosl") // we just send debug data to logs if we run asshell
 		log.Debugf("file log level set to: %v\n", backendFileLeveled.GetLevel("gosl"))
 	}
 
 	if goslConfig.isServer || goslConfig.isShell {
-		backendStderr			:= logging.NewLogBackend(os.Stderr, "", 0)
-		backendStderrFormatter	:= logging.NewBackendFormatter(backendStderr, logFormat)
-		backendStderrLeveled 	:= logging.AddModuleLevel(backendStderrFormatter)
+		backendStderr := logging.NewLogBackend(os.Stderr, "", 0)
+		backendStderrFormatter := logging.NewBackendFormatter(backendStderr, logFormat)
+		backendStderrLeveled := logging.AddModuleLevel(backendStderrFormatter)
 		log.Debugf("requested stderr log level: %q\n", theLogLevel.String())
 		backendStderrLeveled.SetLevel(theLogLevel, "gosl")
 		log.Debugf("stderr log level set to: %v\n", backendStderrLeveled.GetLevel("gosl"))
 	}
-/*
-		// deprecated, now we set it explicitly if desired
-		if goslConfig.isShell {
-			backendStderrLeveled.SetLevel(logging.DEBUG, "gosl")	// shell is meant to be for debugging mostly
+	/*
+			// deprecated, now we set it explicitly if desired
+			if goslConfig.isShell {
+				backendStderrLeveled.SetLevel(logging.DEBUG, "gosl")	// shell is meant to be for debugging mostly
+			} else {
+				backendStderrLeveled.SetLevel(logging.INFO, "gosl")
+			}
+			logging.SetBackend(backendStderrLeveled, backendFileLeveled)
 		} else {
-			backendStderrLeveled.SetLevel(logging.INFO, "gosl")
+			logging.SetBackend(backendFileLeveled)	// FastCGI only logs to file
 		}
-		logging.SetBackend(backendStderrLeveled, backendFileLeveled)
-	} else {
-		logging.SetBackend(backendFileLeveled)	// FastCGI only logs to file
-	}
-*/
+	*/
 
 	// Check if this directory actually exists; if not, create it. Panic if something wrong happens (we cannot proceed without a valid directory for the database to be written)
 	if stat, err := os.Stat(goslConfig.myDir); err == nil && stat.IsDir() {
@@ -216,38 +218,38 @@ func main() {
 	// Currently, this is only needed for Badger v3, the others have much simpler configurations.
 	// (gwyneth 20211106)
 	switch goslConfig.database {
-		case "badger":
-			// Badger v3 - fully rewritten configuration (much simpler!!) (gwyneth 20211026)
-			if goslConfig.noMemory  {
-				// use disk; note that unlike the others, Badger generates its own filenames,
-				// we can only pass a _directory_... (gwyneth 20211027)
-				goslConfig.dbNamePath = filepath.Join(goslConfig.myDir, databaseName)
-				// try to create directory
-				if err = os.Mkdir(goslConfig.dbNamePath, 0700); err != nil {
-					if err != os.ErrExist {
-						checkErr(err)
-					} else {
-						log.Debugf("directory %q exists, no need to create it\n", goslConfig.dbNamePath)
-					}
+	case "badger":
+		// Badger v3 - fully rewritten configuration (much simpler!!) (gwyneth 20211026)
+		if goslConfig.noMemory {
+			// use disk; note that unlike the others, Badger generates its own filenames,
+			// we can only pass a _directory_... (gwyneth 20211027)
+			goslConfig.dbNamePath = filepath.Join(goslConfig.myDir, databaseName)
+			// try to create directory
+			if err = os.Mkdir(goslConfig.dbNamePath, 0700); err != nil {
+				if err != os.ErrExist {
+					checkErr(err)
 				} else {
-					log.Debugf("created new directory: %q\n", goslConfig.dbNamePath)
+					log.Debugf("directory %q exists, no need to create it\n", goslConfig.dbNamePath)
 				}
-
-				Opt = badger.DefaultOptions(goslConfig.dbNamePath)
-				log.Debugf("entering disk mode, Opt is %+v\n", Opt)
 			} else {
-				// Use only memory
-				Opt = badger.LSMOnlyOptions("").WithInMemory(true)
-				Opt.WithLevelSizeMultiplier(1)
-				Opt.WithNumMemtables(1)
-				Opt.WithValueDir(Opt.Dir)	// probably not needed
-				log.Debugf("entering memory-only mode, Opt is %+v\n", Opt)
+				log.Debugf("created new directory: %q\n", goslConfig.dbNamePath)
 			}
-			// common config
-			Opt.WithLogger(log)	// set the internal logger to our own rotating logger
-			Opt.WithLoggingLevel(badger.ERROR)
-			goslConfig.BATCH_BLOCK = 1000	// try to import less at each time, it will take longer but hopefully work
-			log.Info("trying to avoid too much memory consumption")
+
+			Opt = badger.DefaultOptions(goslConfig.dbNamePath)
+			log.Debugf("entering disk mode, Opt is %+v\n", Opt)
+		} else {
+			// Use only memory
+			Opt = badger.LSMOnlyOptions("").WithInMemory(true)
+			Opt.WithLevelSizeMultiplier(1)
+			Opt.WithNumMemtables(1)
+			Opt.WithValueDir(Opt.Dir) // probably not needed
+			log.Debugf("entering memory-only mode, Opt is %+v\n", Opt)
+		}
+		// common config
+		Opt.WithLogger(log) // set the internal logger to our own rotating logger
+		Opt.WithLoggingLevel(badger.ERROR)
+		goslConfig.BATCH_BLOCK = 1000 // try to import less at each time, it will take longer but hopefully work
+		log.Info("trying to avoid too much memory consumption")
 		// the other databases do not require any special configuration (for now)
 	} // /switch
 
@@ -267,12 +269,12 @@ func main() {
 	if goslConfig.isServer || goslConfig.isShell {
 		const testAvatarName = "Nobody Here"
 
-		log.Infof("gosl started and logging is set up. Proceeding to test database (%s) at %q\n",goslConfig.database, goslConfig.myDir)
+		log.Infof("gosl started and logging is set up. Proceeding to test database (%s) at %q\n", goslConfig.database, goslConfig.myDir)
 		// generate a random UUID (gwyneth2021103) (gwyneth 20211031)
 
 		var (
-			testUUID = uuid.New().String()	// Random UUID (gwyneth 20211031 — from )
-			testValue = avatarUUID{ testAvatarName, testUUID, "all grids" }
+			testUUID  = uuid.New().String() // Random UUID (gwyneth 20211031 — from )
+			testValue = avatarUUID{testAvatarName, testUUID, "all grids"}
 		)
 		jsonTestValue, err := json.Marshal(testValue)
 		checkErrPanic(err) // something went VERY wrong
@@ -280,38 +282,38 @@ func main() {
 		// KVDB Initialisation & Tests
 		// Each case is different
 		switch goslConfig.database {
-			case "badger":
-				// Opt has already been set earlier. (gwyneth 20211106)
-				kv, err := badger.Open(Opt)
-				checkErrPanic(err) // should probably panic, cannot prep new database
-				txn := kv.NewTransaction(true)
-				err = txn.Set([]byte(testAvatarName), jsonTestValue)
-				checkErrPanic(err)
-				err = txn.Set([]byte(testUUID), jsonTestValue)
-				checkErrPanic(err)
-				err = txn.Commit()
-				checkErrPanic(err)
-				log.Debugf("badger SET %+v (json: %v)\n", testValue, string(jsonTestValue))
-				kv.Close()
-			case "buntdb":
-				goslConfig.dbNamePath = filepath.Join(goslConfig.myDir, databaseName)
-				db, err := buntdb.Open(goslConfig.dbNamePath)
-				checkErrPanic(err)
-				err = db.Update(func(tx *buntdb.Tx) error {
-					_, _, err := tx.Set(testAvatarName, string(jsonTestValue), nil)
-					return err
-				})
-				checkErr(err)
-				log.Debugf("buntdb SET %+v (json: %v)\n", testValue, string(jsonTestValue))
-				db.Close()
-			case "leveldb":
-				goslConfig.dbNamePath = filepath.Join(goslConfig.myDir, databaseName)
-				db, err := leveldb.OpenFile(goslConfig.dbNamePath, nil)
-				checkErrPanic(err)
-				err = db.Put([]byte(testAvatarName), jsonTestValue, nil)
-				checkErrPanic(err)
-				log.Debugf("leveldb SET %+v (json: %v)\n", testValue, string(jsonTestValue))
-				db.Close()
+		case "badger":
+			// Opt has already been set earlier. (gwyneth 20211106)
+			kv, err := badger.Open(Opt)
+			checkErrPanic(err) // should probably panic, cannot prep new database
+			txn := kv.NewTransaction(true)
+			err = txn.Set([]byte(testAvatarName), jsonTestValue)
+			checkErrPanic(err)
+			err = txn.Set([]byte(testUUID), jsonTestValue)
+			checkErrPanic(err)
+			err = txn.Commit()
+			checkErrPanic(err)
+			log.Debugf("badger SET %+v (json: %v)\n", testValue, string(jsonTestValue))
+			kv.Close()
+		case "buntdb":
+			goslConfig.dbNamePath = filepath.Join(goslConfig.myDir, databaseName)
+			db, err := buntdb.Open(goslConfig.dbNamePath)
+			checkErrPanic(err)
+			err = db.Update(func(tx *buntdb.Tx) error {
+				_, _, err := tx.Set(testAvatarName, string(jsonTestValue), nil)
+				return err
+			})
+			checkErr(err)
+			log.Debugf("buntdb SET %+v (json: %v)\n", testValue, string(jsonTestValue))
+			db.Close()
+		case "leveldb":
+			goslConfig.dbNamePath = filepath.Join(goslConfig.myDir, databaseName)
+			db, err := leveldb.OpenFile(goslConfig.dbNamePath, nil)
+			checkErrPanic(err)
+			err = db.Put([]byte(testAvatarName), jsonTestValue, nil)
+			checkErrPanic(err)
+			log.Debugf("leveldb SET %+v (json: %v)\n", testValue, string(jsonTestValue))
+			db.Close()
 		} // /switch
 		// common to all databases:
 		key, grid := searchKVname(testAvatarName)
@@ -331,7 +333,7 @@ func main() {
 	if goslConfig.isShell {
 		log.Info("starting to run as interactive shell")
 		fmt.Println("Ctrl-C to quit, or just type \"quit\".")
-		var err error	// to avoid assigning text in a different scope (this is a bit awkward, but that's the problem with bi-assignment)
+		var err error // to avoid assigning text in a different scope (this is a bit awkward, but that's the problem with bi-assignment)
 		var avatarName, avatarKey, gridName string
 
 		rl, err := readline.New("enter avatar name or UUID: ")
@@ -369,8 +371,8 @@ func main() {
 		log.Debug("directory for database:", goslConfig.myDir)
 
 		log.Info("starting to run as web server on port :" + goslConfig.myPort)
-		err := http.ListenAndServe(":" + goslConfig.myPort, nil) // set listen port
-		checkErrPanic(err) // if it can't listen to all the above, then it has to abort anyway
+		err := http.ListenAndServe(":"+goslConfig.myPort, nil) // set listen port
+		checkErrPanic(err)                                     // if it can't listen to all the above, then it has to abort anyway
 	} else {
 		// default is to run as FastCGI!
 		// works like a charm thanks to http://www.dav-muz.net/blog/2013/09/how-to-use-go-and-fastcgi/
@@ -393,7 +395,8 @@ func main() {
 // Basically we check if both an avatar name and a UUID key has been received: if yes, this means a new entry;
 // -	if just the avatar name was received, it means looking up its key;
 // -	if just the key was received, it means looking up the name (not necessary since llKey2Name does that, but it's just to illustrate);
-//	-	if nothing is received, then return an error
+//   - if nothing is received, then return an error
+//
 // Note: to ensure quick lookups, we actually set *two* key/value pairs, one with avatar name/UUID,
 // the other with UUID/name — that way, we can efficiently search for *both* in the same database!
 // Theoretically, we could even have *two* KV databases, but that's too much trouble for the
@@ -404,15 +407,15 @@ func handler(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	// test first if this comes from Second Life or OpenSimulator
-/*
-	if r.Header.Get("X-Secondlife-Region") == "" {
-		logErrHTTP(w, http.StatusForbidden, "Sorry, this application only works inside Second Life.")
-		return
-	}
-*/
-	name	:= r.Form.Get("name") // can be empty
-	key		:= r.Form.Get("key") // can be empty
-	compat	:= r.Form.Get("compat") // compatibility mode with W-Hat
+	/*
+		if r.Header.Get("X-Secondlife-Region") == "" {
+			logErrHTTP(w, http.StatusForbidden, "Sorry, this application only works inside Second Life.")
+			return
+		}
+	*/
+	name := r.Form.Get("name")     // can be empty
+	key := r.Form.Get("key")       // can be empty
+	compat := r.Form.Get("compat") // compatibility mode with W-Hat
 	var uuidToInsert avatarUUID
 	messageToSL := "" // this is what we send back to SL - defined here due to scope issues.
 	if name != "" {
@@ -423,31 +426,31 @@ func handler(w http.ResponseWriter, r *http.Request) {
 			jsonUUIDToInsert, err := json.Marshal(uuidToInsert)
 			checkErr(err)
 			switch goslConfig.database {
-				case "badger":
-					kv, err := badger.Open(Opt)
-					checkErrPanic(err) // should probably panic
-					txn := kv.NewTransaction(true)
-					defer txn.Discard()
-					err = txn.Set([]byte(name), jsonUUIDToInsert)
-					checkErrPanic(err)
-					err = txn.Commit()
-					checkErrPanic(err)
-					kv.Close()
-				case "buntdb":
-					db, err := buntdb.Open(goslConfig.dbNamePath)
-					checkErrPanic(err)
-					defer db.Close()
-					err = db.Update(func(tx *buntdb.Tx) error {
-						_, _, err := tx.Set(name, string(jsonUUIDToInsert), nil)
-						return err
-					})
-					checkErr(err)
-				case "leveldb":
-					db, err := leveldb.OpenFile(goslConfig.dbNamePath, nil)
-					checkErrPanic(err)
-					err = db.Put([]byte(name), jsonUUIDToInsert, nil)
-					checkErrPanic(err)
-					db.Close()
+			case "badger":
+				kv, err := badger.Open(Opt)
+				checkErrPanic(err) // should probably panic
+				txn := kv.NewTransaction(true)
+				defer txn.Discard()
+				err = txn.Set([]byte(name), jsonUUIDToInsert)
+				checkErrPanic(err)
+				err = txn.Commit()
+				checkErrPanic(err)
+				kv.Close()
+			case "buntdb":
+				db, err := buntdb.Open(goslConfig.dbNamePath)
+				checkErrPanic(err)
+				defer db.Close()
+				err = db.Update(func(tx *buntdb.Tx) error {
+					_, _, err := tx.Set(name, string(jsonUUIDToInsert), nil)
+					return err
+				})
+				checkErr(err)
+			case "leveldb":
+				db, err := leveldb.OpenFile(goslConfig.dbNamePath, nil)
+				checkErrPanic(err)
+				err = db.Put([]byte(name), jsonUUIDToInsert, nil)
+				checkErrPanic(err)
+				db.Close()
 			}
 			messageToSL += "Added new entry for '" + name + "' which is: " + uuidToInsert.UUID + " from grid: '" + uuidToInsert.Grid + "'"
 		} else {
@@ -475,4 +478,4 @@ func handler(w http.ResponseWriter, r *http.Request) {
 	w.WriteHeader(http.StatusOK)
 	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
 	fmt.Fprint(w, messageToSL)
-}
+}

+ 123 - 122
import-database.go

@@ -20,6 +20,7 @@ import (
 )
 
 // importDatabase is essentially reading a bzip2'ed CSV file with UUID,AvatarName downloaded from http://w-hat.com/#name2key .
+//
 //	One could theoretically set a cron job to get this file, save it on disk periodically, and keep the database up-to-date
 //	see https://stackoverflow.com/questions/24673335/how-do-i-read-a-gzipped-csv-file for the actual usage of these complicated things!
 func importDatabase(filename string) {
@@ -45,157 +46,157 @@ func importDatabase(filename string) {
 		log.Error("could not rewind the file to the start position")
 	}
 
-	var cr *csv.Reader	// CSV reader needs to be declared here because of scope issues. (gwyneth 20211027)
+	var cr *csv.Reader // CSV reader needs to be declared here because of scope issues. (gwyneth 20211027)
 
 	// Technically, we could match for a lot of archives and get a io.Reader for each.
 	// However, W-Hat has a limited selection of archives available (currently gzip and bzip2)
 	// so we limit ourselves to these two, falling back to plaintext (gwyneth 20211027).
 	switch kind {
-		case matchers.TypeBz2:
-			gr := bzip2.NewReader(filehandler) // open bzip2 reader
-			cr = csv.NewReader(gr)  // open csv reader and feed the bzip2 reader into it
-		case matchers.TypeGz:
-			zr, err := gzip.NewReader(filehandler) // open gzip reader
-			checkErr(err)
-			cr = csv.NewReader(zr)  // open csv reader and feed the bzip2 reader into it
-		default:
-			// We just assume that it's a CSV (uncompressed) file and open it.
-			cr = csv.NewReader(filehandler)
+	case matchers.TypeBz2:
+		gr := bzip2.NewReader(filehandler) // open bzip2 reader
+		cr = csv.NewReader(gr)             // open csv reader and feed the bzip2 reader into it
+	case matchers.TypeGz:
+		zr, err := gzip.NewReader(filehandler) // open gzip reader
+		checkErr(err)
+		cr = csv.NewReader(zr) // open csv reader and feed the bzip2 reader into it
+	default:
+		// We just assume that it's a CSV (uncompressed) file and open it.
+		cr = csv.NewReader(filehandler)
 	}
 
-	limit := 0	// outside of for loop so that we can count how many entries we had in total
+	limit := 0               // outside of for loop so that we can count how many entries we had in total
 	time_start := time.Now() // we want to get an idea on how long this takes
 
 	switch goslConfig.database {
-		case "badger":
-			// prepare connection to KV database
-			kv, err := badger.Open(Opt)
-			checkErrPanic(err) // should probably panic
-			defer kv.Close()
+	case "badger":
+		// prepare connection to KV database
+		kv, err := badger.Open(Opt)
+		checkErrPanic(err) // should probably panic
+		defer kv.Close()
 
-			txn := kv.NewTransaction(true) // start new transaction; we will commit only every BATCH_BLOCK entries
-			defer txn.Discard()
-			for ;;limit++ {
-				record, err := cr.Read()
-				if err == io.EOF {
-					break
-				} else if err != nil {
+		txn := kv.NewTransaction(true) // start new transaction; we will commit only every BATCH_BLOCK entries
+		defer txn.Discard()
+		for ; ; limit++ {
+			record, err := cr.Read()
+			if err == io.EOF {
+				break
+			} else if err != nil {
+				log.Fatal(err)
+			}
+			// CSV: first entry is avatar key UUID, second entry is avatar name.
+			// We probably should check for valid UUIDs; we may do that at some point. (gwyneth 20211031)
+			jsonNewEntry, err := json.Marshal(avatarUUID{record[1], record[0], "Production"}) // W-Hat keys come all from the main LL grid, known as 'Production'
+			if err != nil {
+				log.Warning(err)
+			} else {
+				log.Debugf("Entry %04d - Name: %s UUID: %s - JSON: %s\n", limit, record[1], record[0], jsonNewEntry)
+				// Place this record under the avatar's name
+				if err = txn.Set([]byte(record[1]), jsonNewEntry); err != nil {
 					log.Fatal(err)
 				}
-				// CSV: first entry is avatar key UUID, second entry is avatar name.
-				// We probably should check for valid UUIDs; we may do that at some point. (gwyneth 20211031)
-				jsonNewEntry, err := json.Marshal(avatarUUID{ record[1], record[0], "Production" }) // W-Hat keys come all from the main LL grid, known as 'Production'
-				if err != nil {
-					log.Warning(err)
-				} else {
-					log.Debugf("Entry %04d - Name: %s UUID: %s - JSON: %s\n", limit, record[1], record[0], jsonNewEntry)
-					// Place this record under the avatar's name
-					if err = txn.Set([]byte(record[1]), jsonNewEntry); err != nil {
-						log.Fatal(err)
-					}
-					// Now place it again, this time under the avatar's key
-					if err = txn.Set([]byte(record[0]), jsonNewEntry); err != nil {
-						log.Fatal(err)
-					}
-				}
-				if limit % goslConfig.BATCH_BLOCK == 0 && limit != 0 { // we do not run on the first time, and then only every BATCH_BLOCK times
-					log.Info("processing:", limit)
-					if err = txn.Commit(); err != nil {
-						log.Fatal(err)
-					}
-					runtime.GC()
-					txn = kv.NewTransaction(true) // start a new transaction
-					defer txn.Discard()
+				// Now place it again, this time under the avatar's key
+				if err = txn.Set([]byte(record[0]), jsonNewEntry); err != nil {
+					log.Fatal(err)
 				}
 			}
-			// commit last batch
-			if err = txn.Commit(); err != nil {
-				log.Fatal(err)
+			if limit%goslConfig.BATCH_BLOCK == 0 && limit != 0 { // we do not run on the first time, and then only every BATCH_BLOCK times
+				log.Info("processing:", limit)
+				if err = txn.Commit(); err != nil {
+					log.Fatal(err)
+				}
+				runtime.GC()
+				txn = kv.NewTransaction(true) // start a new transaction
+				defer txn.Discard()
 			}
-		case "buntdb":
-			db, err := buntdb.Open(goslConfig.dbNamePath)
-			checkErrPanic(err)
-			defer db.Close()
+		}
+		// commit last batch
+		if err = txn.Commit(); err != nil {
+			log.Fatal(err)
+		}
+	case "buntdb":
+		db, err := buntdb.Open(goslConfig.dbNamePath)
+		checkErrPanic(err)
+		defer db.Close()
 
-			txn, err := db.Begin(true)
-			checkErrPanic(err)
-			//defer txn.Commit()
+		txn, err := db.Begin(true)
+		checkErrPanic(err)
+		//defer txn.Commit()
 
-			// very similar to Badger code...
-			for ;;limit++ {
-				record, err := cr.Read()
-				if err == io.EOF {
-					break
-				} else if err != nil {
+		// very similar to Badger code...
+		for ; ; limit++ {
+			record, err := cr.Read()
+			if err == io.EOF {
+				break
+			} else if err != nil {
+				log.Fatal(err)
+			}
+			jsonNewEntry, err := json.Marshal(avatarUUID{record[1], record[0], "Production"})
+			if err != nil {
+				log.Warning(err)
+			} else {
+				// see comments above for Badger. (gwyneth 20211031)
+				_, _, err = txn.Set(record[1], string(jsonNewEntry), nil)
+				if err != nil {
 					log.Fatal(err)
 				}
-				jsonNewEntry, err := json.Marshal(avatarUUID{ record[1], record[0], "Production" })
+				_, _, err = txn.Set(record[0], string(jsonNewEntry), nil)
 				if err != nil {
-					log.Warning(err)
-				} else {
-					// see comments above for Badger. (gwyneth 20211031)
-					_, _, err = txn.Set(record[1], string(jsonNewEntry), nil)
-					if err != nil {
-						log.Fatal(err)
-					}
-					_, _, err = txn.Set(record[0], string(jsonNewEntry), nil)
-					if err != nil {
-						log.Fatal(err)
-					}
+					log.Fatal(err)
 				}
-				if limit % goslConfig.BATCH_BLOCK == 0 && limit != 0 { // we do not run on the first time, and then only every BATCH_BLOCK times
-					log.Info("processing:", limit)
-					if err = txn.Commit(); err != nil {
-						log.Fatal(err)
-					}
-					runtime.GC()
-					txn, err = db.Begin(true)  // start a new transaction
-					checkErrPanic(err)
-					//defer txn.Commit()
+			}
+			if limit%goslConfig.BATCH_BLOCK == 0 && limit != 0 { // we do not run on the first time, and then only every BATCH_BLOCK times
+				log.Info("processing:", limit)
+				if err = txn.Commit(); err != nil {
+					log.Fatal(err)
 				}
+				runtime.GC()
+				txn, err = db.Begin(true) // start a new transaction
+				checkErrPanic(err)
+				//defer txn.Commit()
 			}
-			// commit last batch
-			if err = txn.Commit(); err != nil {
+		}
+		// commit last batch
+		if err = txn.Commit(); err != nil {
+			log.Fatal(err)
+		}
+		db.Shrink()
+	case "leveldb":
+		db, err := leveldb.OpenFile(goslConfig.dbNamePath, nil)
+		checkErrPanic(err)
+		defer db.Close()
+		batch := new(leveldb.Batch)
+
+		for ; ; limit++ {
+			record, err := cr.Read()
+			if err == io.EOF {
+				break
+			} else if err != nil {
 				log.Fatal(err)
 			}
-			db.Shrink()
-		case "leveldb":
-			db, err := leveldb.OpenFile(goslConfig.dbNamePath, nil)
-			checkErrPanic(err)
-			defer db.Close()
-			batch := new(leveldb.Batch)
-
-			for ;;limit++ {
-				record, err := cr.Read()
-				if err == io.EOF {
-					break
-				} else if err != nil {
+			jsonNewEntry, err := json.Marshal(avatarUUID{record[1], record[0], "Production"})
+			if err != nil {
+				log.Warning(err)
+			} else {
+				// see comments above for Badger. (gwyneth 20211031)
+				batch.Put([]byte(record[1]), jsonNewEntry)
+				batch.Put([]byte(record[0]), jsonNewEntry)
+			}
+			if limit%goslConfig.BATCH_BLOCK == 0 && limit != 0 {
+				log.Info("processing:", limit)
+				if err = db.Write(batch, nil); err != nil {
 					log.Fatal(err)
 				}
-				jsonNewEntry, err := json.Marshal(avatarUUID{ record[1], record[0], "Production" })
-				if err != nil {
-					log.Warning(err)
-				} else {
-					// see comments above for Badger. (gwyneth 20211031)
-					batch.Put([]byte(record[1]), jsonNewEntry)
-					batch.Put([]byte(record[0]), jsonNewEntry)
-				}
-				if limit % goslConfig.BATCH_BLOCK == 0 && limit != 0 {
-					log.Info("processing:", limit)
-					if err = db.Write(batch, nil); err != nil {
-						log.Fatal(err)
-					}
-					batch.Reset()	// unlike the others, we don't need to create a new batch every time
-					runtime.GC()	// it never hurts...
-				}
-			}
-			// commit last batch
-			if err = db.Write(batch, nil); err != nil {
-				log.Fatal(err)
+				batch.Reset() // unlike the others, we don't need to create a new batch every time
+				runtime.GC()  // it never hurts...
 			}
-			batch.Reset()	// reset it and let the garbage collector run
-			runtime.GC()
-			db.CompactRange(util.Range{Start: nil, Limit: nil})
+		}
+		// commit last batch
+		if err = db.Write(batch, nil); err != nil {
+			log.Fatal(err)
+		}
+		batch.Reset() // reset it and let the garbage collector run
+		runtime.GC()
+		db.CompactRange(util.Range{Start: nil, Limit: nil})
 	}
 	log.Info("total read", limit, "records (or thereabouts) in", time.Since(time_start))
 }

+ 42 - 42
search.go

@@ -183,55 +183,55 @@ func searchKVUUID(avatarKey string) (name string, grid string) {
 // Universal search, since we put everything in the KV database, we can basically search for anything.
 // *Way* more efficient! (gwyneth 20211031)
 func searchKV(searchItem string) (name string, uuid string, grid string) {
-	var val = avatarUUID{ "", NullUUID, "" }
+	var val = avatarUUID{"", NullUUID, ""}
 	time_start := time.Now()
 	var err error // to deal with scope issues
 	switch goslConfig.database {
-		case "badger":
-			kv, err = badger.Open(Opt)
-			checkErrPanic(err)
-			defer kv.Close()
-			err = kv.View(func(txn *badger.Txn) error {
-				item, err := txn.Get([]byte(searchItem))
-				if err != nil {
-					return err
-				}
-				data, err := item.ValueCopy(nil)
-				if err != nil {
-					log.Errorf("error %q while getting data from %v\n", err, item)
-					return err
-				}
-				if err = json.Unmarshal(data, &val); err != nil {
-					log.Errorf("error while unparsing UUID for name: %q (%v)\n", searchItem, err)
-					return err
-				}
-				return nil
-			})
-		case "buntdb":
-			db, err := buntdb.Open(goslConfig.dbNamePath)
-			checkErrPanic(err)
-			defer db.Close()
-			var data string
-			err = db.View(func(tx *buntdb.Tx) error {
-				data, err = tx.Get(searchItem)
+	case "badger":
+		kv, err = badger.Open(Opt)
+		checkErrPanic(err)
+		defer kv.Close()
+		err = kv.View(func(txn *badger.Txn) error {
+			item, err := txn.Get([]byte(searchItem))
+			if err != nil {
 				return err
-			})
-			err = json.Unmarshal([]byte(data), &val)
+			}
+			data, err := item.ValueCopy(nil)
 			if err != nil {
+				log.Errorf("error %q while getting data from %v\n", err, item)
+				return err
+			}
+			if err = json.Unmarshal(data, &val); err != nil {
 				log.Errorf("error while unparsing UUID for name: %q (%v)\n", searchItem, err)
+				return err
 			}
-		case "leveldb":
-			db, err := leveldb.OpenFile(goslConfig.dbNamePath, nil)
-			checkErrPanic(err)
-			defer db.Close()
-			data, err := db.Get([]byte(searchItem), nil)
-			if err != nil {
-				log.Errorf("error while getting UUID for name: %q (%v)\n", searchItem, err)
-			} else {
-				if err = json.Unmarshal(data, &val); err != nil {
-					log.Errorf("error while unparsing UUID for name: %q (%v)\n", searchItem, err)
-				}
+			return nil
+		})
+	case "buntdb":
+		db, err := buntdb.Open(goslConfig.dbNamePath)
+		checkErrPanic(err)
+		defer db.Close()
+		var data string
+		err = db.View(func(tx *buntdb.Tx) error {
+			data, err = tx.Get(searchItem)
+			return err
+		})
+		err = json.Unmarshal([]byte(data), &val)
+		if err != nil {
+			log.Errorf("error while unparsing UUID for name: %q (%v)\n", searchItem, err)
+		}
+	case "leveldb":
+		db, err := leveldb.OpenFile(goslConfig.dbNamePath, nil)
+		checkErrPanic(err)
+		defer db.Close()
+		data, err := db.Get([]byte(searchItem), nil)
+		if err != nil {
+			log.Errorf("error while getting UUID for name: %q (%v)\n", searchItem, err)
+		} else {
+			if err = json.Unmarshal(data, &val); err != nil {
+				log.Errorf("error while unparsing UUID for name: %q (%v)\n", searchItem, err)
 			}
+		}
 	}
 	log.Debugf("time to lookup %q: %v\n", searchItem, time.Since(time_start))
 	if err != nil {
@@ -239,4 +239,4 @@ func searchKV(searchItem string) (name string, uuid string, grid string) {
 		return "", NullUUID, ""
 	} // else:
 	return val.AvatarName, val.UUID, val.Grid
-}
+}